提交 04f6f468 作者: 刘飞飞

Initial commit

上级
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^$ public/ [L]
RewriteRule (.*) public/$1 [L]
</IfModule>
\ No newline at end of file
<?php
/**
* This file is part of the Phalcon Developer Tools.
*
* (c) Phalcon Team <team@phalcon.io>
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
$uri = urldecode(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH));
if ($uri !== '/' && file_exists(__DIR__ . '/public' . $uri)) {
return false;
}
$_GET['_url'] = $_SERVER['REQUEST_URI'];
require_once __DIR__ . '/public/index.php';
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/gradeManageSystem.iml" filepath="$PROJECT_DIR$/.idea/gradeManageSystem.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MessDetectorOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCSFixerOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="PHPCodeSnifferOptionsConfiguration">
<option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" />
</component>
<component name="PhpCodeSniffer">
<phpcs_settings>
<phpcs_by_interpreter asDefaultInterpreter="true" interpreter_id="2f27d9f9-abea-4f57-a81b-f2f9fc4a813a" timeout="30000" />
</phpcs_settings>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="7.1">
<option name="suggestChangeDefaultLanguageLevel" value="false" />
</component>
<component name="PhpStan">
<PhpStan_settings>
<phpstan_by_interpreter asDefaultInterpreter="true" interpreter_id="2f27d9f9-abea-4f57-a81b-f2f9fc4a813a" timeout="60000" />
</PhpStan_settings>
</component>
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
<component name="Psalm">
<Psalm_settings>
<psalm_fixer_by_interpreter asDefaultInterpreter="true" interpreter_id="2f27d9f9-abea-4f57-a81b-f2f9fc4a813a" timeout="60000" />
</Psalm_settings>
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>
</project>
\ No newline at end of file
<?php
/*
* Modified: prepend directory path of current file, because of this file own different ENV under between Apache and command line.
* NOTE: please remove this comment.
*/
defined('BASE_PATH') || define('BASE_PATH', getenv('BASE_PATH') ?: realpath(dirname(__FILE__) . '/../..'));
defined('APP_PATH') || define('APP_PATH', BASE_PATH . '/app');
return new \Phalcon\Config\Config([
'database' => [
'adapter' => 'Mysql',
'host' => 'rm-bp18k55bv9osa6u1vmo.mysql.rds.aliyuncs.com:3306',
'username' => 'develop_local',
'password' => 'gN2!MZzl0ukOpKYZdP',
'dbname' => 'develop_local',
'charset' => 'utf8',
],
'application' => [
'appDir' => APP_PATH . '/',
'controllersDir' => APP_PATH . '/controllers/',
'modelsDir' => APP_PATH . '/models/',
'migrationsDir' => APP_PATH . '/migrations/',
'viewsDir' => APP_PATH . '/views/',
'pluginsDir' => APP_PATH . '/plugins/',
'libraryDir' => APP_PATH . '/library/',
'cacheDir' => BASE_PATH . '/cache/',
'baseUri' => '/',
]
]);
<?php
$loader = new \Phalcon\Autoload\Loader();
/**
* We're a registering a set of directories taken from the configuration file
*/
$loader->setDirectories(
[
$config->application->controllersDir,
$config->application->modelsDir
]
)->register();
<?php
$router = $di->getRouter();
// Define your routes here
$router->handle($_SERVER['REQUEST_URI']);
<?php
declare(strict_types=1);
use Phalcon\Html\Escaper;
use Phalcon\Flash\Direct as Flash;
use Phalcon\Mvc\Model\Metadata\Memory as MetaDataAdapter;
use Phalcon\Mvc\View;
use Phalcon\Mvc\View\Engine\Php as PhpEngine;
use Phalcon\Mvc\View\Engine\Volt as VoltEngine;
use Phalcon\Session\Adapter\Stream as SessionAdapter;
use Phalcon\Session\Manager as SessionManager;
use Phalcon\Mvc\Url as UrlResolver;
/**
* Shared configuration service
*/
$di->setShared('config', function () {
return include APP_PATH . "/config/config.php";
});
/**
* The URL component is used to generate all kind of urls in the application
*/
$di->setShared('url', function () {
$config = $this->getConfig();
$url = new UrlResolver();
$url->setBaseUri($config->application->baseUri);
return $url;
});
/**
* Setting up the view component
*/
$di->setShared('view', function () {
$config = $this->getConfig();
$view = new View();
$view->setDI($this);
$view->setViewsDir($config->application->viewsDir);
$view->registerEngines([
'.volt' => function ($view) {
$config = $this->getConfig();
$volt = new VoltEngine($view, $this);
$volt->setOptions([
'path' => $config->application->cacheDir,
'separator' => '_'
]);
return $volt;
},
'.phtml' => PhpEngine::class
]);
return $view;
});
/**
* Database connection is created based in the parameters defined in the configuration file
*/
$di->setShared('db', function () {
$config = $this->getConfig();
$class = 'Phalcon\Db\Adapter\Pdo\\' . $config->database->adapter;
$params = [
'host' => $config->database->host,
'username' => $config->database->username,
'password' => $config->database->password,
'dbname' => $config->database->dbname,
'charset' => $config->database->charset
];
if ($config->database->adapter == 'Postgresql') {
unset($params['charset']);
}
return new $class($params);
});
/**
* If the configuration specify the use of metadata adapter use it or use memory otherwise
*/
$di->setShared('modelsMetadata', function () {
return new MetaDataAdapter();
});
/**
* Register the session flash service with the Twitter Bootstrap classes
*/
$di->set('flash', function () {
$escaper = new Escaper();
$flash = new Flash($escaper);
$flash->setImplicitFlush(false);
$flash->setCssClasses([
'error' => 'alert alert-danger',
'success' => 'alert alert-success',
'notice' => 'alert alert-info',
'warning' => 'alert alert-warning'
]);
return $flash;
});
/**
* Start the session the first time some component request the session service
*/
$di->setShared('session', function () {
$session = new SessionManager();
$files = new SessionAdapter([
'savePath' => sys_get_temp_dir(),
]);
$session->setAdapter($files);
$session->start();
return $session;
});
<?php
declare(strict_types=1);
use Phalcon\Mvc\Controller;
class ControllerBase extends Controller
{
public function initialize()
{
// 1. 检查是否登录
$auth = $this->session->get('auth');
if (empty($auth) || !isset($auth['identity'])) {
$this->flashSession->error('请先登录');
return $this->response->redirect('login/index'); // 未登录 → 跳登录页
}
// 2. 获取当前访问的控制器和方法
$currentController = $this->dispatcher->getControllerName(); // 如 'lff_admin'、'index'
$currentAction = $this->dispatcher->getActionName();
$identity = $auth['identity'];
// 3. 允许所有已登录用户访问首页(index 控制器)
if ($currentController === 'index') {
return true; // 跳过后续权限检查,直接允许访问
}
// 4. 超级管理员(0):无限制(除首页外的其他控制器)
if ($identity == 0) {
return true;
}
// 5. 普通管理员(1):限制
if ($identity == 1) {
$allowedControllers = ['lff_admin', 'lff_course', 'lff_college','lff_student','lff_teacher'];
if (!in_array($currentController, $allowedControllers)) {
echo 111;die;
$this->flashSession->error('权限不足:无法访问该功能');
return $this->response->redirect('index/index');
}
if ($currentController == 'lff_admin' && $currentAction == 'acaAdminList') {
$this->flashSession->error('权限不足:无法访问教学管理员账号管理');
return $this->response->redirect('index/index');
}
}
// 6. 教师(2):限制
if ($identity == 2) {
$allowedControllers = ['lff_score'];
if (!in_array($currentController, $allowedControllers)) {
$this->flashSession->error('权限不足:无法访问该功能');
return $this->response->redirect('index/index');
}
}
// 7. 学生(3):限制
if ($identity == 3) {
$allowedControllers = [''];
if (!in_array($currentController, $allowedControllers)) {
$this->flashSession->error('权限不足:无法访问该功能');
return $this->response->redirect('index/index');
}
}
}
}
\ No newline at end of file
<?php
declare(strict_types=1);
use Phalcon\Mvc\Controller;
class IndexController extends Controller
{
public function indexAction()
{
$this->view->setVar('pageTitle', '教学管理系统首页');
}
}
<?php
class LffCollegeController extends ControllerBase
{
public function indexAction()
{
}
public function collegeListAction()
{
$keyword = $this->request->getQuery('keyword', 'string', '');
$conditions = '';
$bind = [];
if (!empty($keyword)) {
$conditions = '(college_id LIKE :keyword: OR college_name LIKE :keyword:)';
$bind['keyword'] = "%{$keyword}%";
}
$colleges = LffCollege::find([
'conditions' => $conditions,
'bind' => $bind,
'order' => 'create_time DESC'
]);
// var_dump($colleges->toArray());die;
$this->view->colleges = $colleges;
$this->view->keyword = $keyword;
}
public function addCollegeAction()
{
}
public function createAction()
{
$college_code = $this->request->getPost('college_code');
$college_name = $this->request->getPost('college_name');
if (empty($college_code) || empty($college_name)) {
$this->flashSession->error("学院编号或者学院名称为空");
return $this->response->redirect("lff_college/addCollege");
}
$nameExist = LffCollege::findFirst([
'college_code = :college_code:',
'bind' => [
'college_code' => $college_code]]);
// var_dump($nameExist);die;
if(!empty($nameExist)){
$this->flashSession->error("学院编号已存在");
return $this->response->redirect("lff_college/addCollege");
}
$college = new LffCollege();
$college->college_code = $college_code;
$college->college_name = $college_name;
if(!$college->save()){
$this->flashSession->error("创建学院信息失败");
return $this->response->redirect("lff_college/addCollege");
}
$this->flashSession->success("创建学院信息成功");
return $this->response->redirect("lff_college/collegeList");
}
public function editCollegeAction($id)
{
$collegeInfo = LffCollege::findFirst([
"college_id = :college_id:",
"bind" => ["college_id" => $id],
]);
// var_dump($collegeInfo->toArray());die;
if (!$collegeInfo) {
$this->flashSession->error('学院不存在');
return $this->response->redirect('lff_college/collegeList');
}
$this->view->collegeInfo = $collegeInfo;
}
public function saveAction()
{
$college_id = $this->request->getPost('college_id');
$college_name = $this->request->getPost('college_name');
if ($college_id <= 0) {
$this->flashSession->error('无效的学院ID');
return $this->response->redirect('lff_college/collegeList');
}
$college = LffCollege::findFirst([
"college_id = :id:",
"bind" => ["id" => $college_id]
]);
if (!$college) {
throw new Exception('学院不存在或已被删除');
}
$nameExist = LffCollege::findFirst([
"college_name = :name: AND college_id != :id:",
"bind" => [
"name" => $college_name,
"id" => $college_id
]
]);
if ($nameExist) {
throw new Exception('该学院名称已存在,请更换');
}
$college->college_name = $college_name;
if (!$college->save()) {
$errors = implode(';', $college->getMessages());
throw new Exception("修改失败:{$errors}");
}
$this->flashSession->success('学院信息修改成功');
return $this->response->redirect('lff_college/collegeList');
}
public function deleteCollegeAction($id)
{
$college_id = (int)$id;
// var_dump($college_id);die;
if (empty($college_id)) {
throw new Exception('无效的学院ID');
}
$college = LffCollege::findFirst([
"college_id = :id:",
"bind" => ["id" => $college_id]
]);
if (!$college) {
throw new Exception('学院不存在或已被删除');
}
$students = LffStudent::find([
'college_id = :cid:',
'bind' => ['cid' => $college_id]
]);
foreach ($students as $student) {
$student->delete();
}
if (!$college->delete()) {
$errors = implode(';', $college->getMessages());
throw new Exception("删除失败:{$errors}");
}
$this->flashSession->success("学院已成功删除");
return $this->response->redirect('lff_college/collegeList');
}
}
\ No newline at end of file
<?php
class LffCourseController extends ControllerBase
{
public function indexAction()
{
}
public function courseListAction()
{
$keyword = $this->request->getQuery('keyword', 'string', '');
$queryBuilder = $this->modelsManager->createBuilder()
->columns([
'c.course_id',
'c.course_name',
'c.course_type',
'c.college_id',
'c.credit',
'c.class_hour',
'c.create_time',
't.teacher_id',
't.user_id',
'u.username as teacher_name',
'col.college_name'
])
->from(['c' => 'LffCourse'])
->leftJoin('LffTeacher', 'c.teacher_id = t.teacher_id', 't')
->leftJoin('LffUsers', 't.user_id = u.user_id', 'u')
->leftJoin('LffCollege', 'c.college_id = col.college_id', 'col');
if (!empty($keyword)) {
$queryBuilder->andWhere(
'(c.course_id LIKE :keyword: OR c.course_name LIKE :keyword:)',
['keyword' => "%{$keyword}%"]
);
}
$queryBuilder->orderBy('c.create_time DESC');
$courses = $queryBuilder->getQuery()->execute();
// var_dump($courses->toArray());die;
$this->view->courseInfo = $courses;
$this->view->keyword = $keyword;
}
public function addCourseAction()
{
$this->view->colleges = LffCollege::find([
'order' => 'college_name ASC'
]);
$this->view->teachers = $this->modelsManager->createBuilder()
->columns([
't.teacher_id',
'u.username as teacher_name'
])
->from(['t' => 'LffTeacher'])
->leftJoin('LffUsers', 't.user_id = u.user_id', 'u')
->orderBy('u.username ASC')
->getQuery()
->execute();
}
public function createAction()
{
$course_code = $this->request->getPost('course_code');
$course_name = $this->request->getPost('course_name');
$course_type = $this->request->getPost('course_type');
$college_id = $this->request->getPost('college_id');
$credit = $this->request->getPost('credit');
$class_hour = $this->request->getPost('class_hour');
$teacher_name = $this->request->getPost('teacher_name');
$description = $this->request->getPost('description');
if(!empty($course_code)){
$college_code = substr($course_code, 0, 2);
$course_type = substr($course_code, 2, 3);
$sequence = substr($course_code, 5, 3);
$college = LffCollege::findFirst([
'college_code = :college_code:',
'bind' => [
'college_code' => $college_code
]]);
if($college->count() < 0){
$this->flashSession->error("课程编码不正确");
return $this->response->redirect("lff_course/addCourse");
}
$existingCourse = LffCourse::findFirst([
'course_code = :course_code:',
'bind' => [
'course_code' => $course_code]]);
if ($existingCourse) {
$this->flashSession->error("课程编码已存在");
return $this->response->redirect("lff_course/addCourse");
}
}
$teachers = $this->modelsManager->createBuilder()
->columns([
't.teacher_id',
'u.username as teacher_name',
'c.college_id',
'c.college_name'
])
->from(['t' => 'LffTeacher'])
->leftJoin('LffUsers', 't.user_id = u.user_id', 'u')
->leftJoin('LffCollege', 't.college_id = c.college_id', 'c')
->where('u.username = :username:', ['username' => $teacher_name])
->andWhere('c.college_id = :college_id:', ['college_id' => $college_id])
->getQuery()
->execute();
if($teachers->getFirst()){
$teacher_id = $teachers->getFirst()->teacher_id;
}else{
$this->flashSession->error("该教师不存在");
return $this->response->redirect("lff_course/addCourse");
}
$course = new LffCourse();
$course->course_code = $course_code;
$course->course_name = $course_name;
$course->course_type = $course_type;
$course->college_id = $college_id;
$course->credit = $credit;
$course->class_hour = $class_hour;
$course->teacher_id = $teacher_id;
$course->description = $description;
if(!$course->save()){
$this->flashSession->error("课程创建失败");
return $this->response->redirect("lff_course/addCourse");
}
$this->flashSession->error("课程创建成功");
return $this->response->redirect("lff_course/courseList");
}
public function editCourseAction($id)
{
$course_id = (int)$id;
if($course_id < 0){
$this->flashSession->error("该课程不存在");
return $this->response->redirect("lff_course/courseList");
}
$courseInfo = $this->modelsManager->createBuilder()
->columns([
// 课程表字段
'c.course_id',
'c.course_code',
'c.course_name',
'c.course_type',
'c.credit',
'c.class_hour',
'c.college_id',
'c.description',
'col.college_name',
't.teacher_id',
't.user_id',
'u.username as teacher_name'
])
->from(['c' => 'LffCourse'])
->leftJoin('LffCollege', 'c.college_id = col.college_id', 'col')
->leftJoin('LffTeacher', 'c.teacher_id = t.teacher_id', 't')
->leftJoin('LffUsers', 't.user_id = u.user_id', 'u')
->where('c.course_id = :course_id:', ['course_id' => $course_id])
->getQuery()
->getSingleResult();
$colleges = LffCollege::find();
// var_dump($colleges->toArray());die;
// var_dump($courseInfo->toArray());die;
$this->view->courseInfo = $courseInfo;
// var_dump($courseInfo->toArray());die;
$this->view->colleges = $colleges;
}
public function saveAction()
{
$course_id = $this->request->getPost('course_id');
$course_code = $this->request->getPost('course_code');
$course_name = $this->request->getPost('course_name');
$course_type = $this->request->getPost('course_type');
$college_id = $this->request->getPost('college_id');
$credit = $this->request->getPost('credit');
$class_hour = $this->request->getPost('class_hour');
$teacher_name = $this->request->getPost('teacher_name');
$description = $this->request->getPost('description');
$teacher = $this->modelsManager->createBuilder()
->columns([
't.teacher_id',
'u.username as teacher_name',
'c.college_id',
'c.college_name'
])
->from(['t' => 'LffTeacher'])
->leftJoin('LffUsers', 't.user_id = u.user_id', 'u')
->leftJoin('LffCollege', 't.college_id = c.college_id', 'c')
->where('u.username = :username:', ['username' => $teacher_name])
->andWhere('c.college_id = :college_id:', ['college_id' => $college_id])
->getQuery()
->getSingleResult();
if($teacher){
$teacher_id = $teacher->teacher_id;
// var_dump($teacher_id);die;
}else{
$this->flashSession->error("该教师不存在");
return $this->response->redirect("lff_course/addCourse");
}
$course = LffCourse::findFirst([
'course_id = :course_id:',
'bind' => [
'course_id' => $course_id
]
]);
$course->course_code = $course_code;
$course->course_name = $course_name;
$course->course_type = $course_type;
$course->college_id = $college_id;
$course->credit = $credit;
$course->class_hour = $class_hour;
$course->teacher_id = $teacher_id;
$course->description = $description;
// var_dump($course->save());die;
if(!$course->save()){
$this->flashSession->error("课程更新失败");
return $this->response->redirect("lff_course/editCourse" . $course_id);
}
$this->flashSession->error("课程更新成功");
return $this->response->redirect("lff_course/courseList");
}
public function deleteCourseAction($id)
{
$course_id = (int)$id;
if($course_id < 0){
$this->flashSession->error("该课程ID无效");
return $this->response->redirect("lff_course/courseList");
}
$course = LffCourse::findFirst([
'course_id = :course_id:',
'bind' => [
'course_id' => $course_id
]
]);
if (!$course) {
$this->flashSession->error("该课程不存在或已被删除");
return $this->response->redirect("lff_course/courseList");
}
if (!$course->delete()) {
$this->flashSession->error("该课程不存在或已被删除");
return $this->response->redirect("lff_course/courseList");
}
$this->flashSession->error("该课程删除成功");
return $this->response->redirect("lff_course/courseList");
}
}
\ No newline at end of file
<?php
declare(strict_types=1);
use Phalcon\Mvc\Model\Criteria;
use Phalcon\Paginator\Adapter\Model;
class LffCustomersController extends ControllerBase
{
/**
* Index action
*/
public function indexAction()
{
$this->view->setVar('lff_customer', new LffCustomers());
}
/**
* Searches for lff_customers
*/
public function searchAction()
{
$numberPage = $this->request->getQuery('page', 'int', 1);
$parameters = Criteria::fromInput($this->di, 'LffCustomers', $_GET)->getParams();
$parameters['order'] = "cst_id";
$paginator = new Model(
[
'model' => 'LffCustomers',
'parameters' => $parameters,
'limit' => 10,
'page' => $numberPage,
]
);
$paginate = $paginator->paginate();
if (0 === $paginate->getTotalItems()) {
$this->flashSessionSession->notice("The search did not find any lff_customers");
$this->dispatcher->forward([
"controller" => "lff_customers",
"action" => "index"
]);
return;
}
$this->view->page = $paginate;
}
/**
* Displays the creation form
*/
public function newAction()
{
$this->view->setVar('lff_customer', new LffCustomers());
}
/**
* Edits a lff_customer
*
* @param string $cst_id
*/
public function editAction($cst_id)
{
if (!$this->request->isPost()) {
$lff_customer = LffCustomers::findFirstBycst_id($cst_id);
if (!$lff_customer) {
$this->flashSession->error("lff_customer was not found");
$this->dispatcher->forward([
'controller' => "lff_customers",
'action' => 'index'
]);
return;
}
$this->view->cst_id = $lff_customer->cst_id;
$this->view->setVar('lff_customer', $lff_customer);
//$assignTagDefaults$
}
}
/**
* Creates a new lff_customer
*/
public function createAction()
{
if (!$this->request->isPost()) {
$this->dispatcher->forward([
'controller' => "lff_customers",
'action' => 'index'
]);
return;
}
$lff_customer = new LffCustomers();
$lff_customer->cst_status_flag = $this->request->getPost("cst_status_flag");
$lff_customer->cst_name_last = $this->request->getPost("cst_name_last");
$lff_customer->cst_name_first = $this->request->getPost("cst_name_first");
// // 获取 POST 请求数据
// $postData = $this->request->getPost();
// // 使用 print_r 输出数据
// echo "<pre>";
// print_r($lff_customer->cstNameLast);
// echo "</pre>";
// die; // 阻止后续代码执行,方便查看输出结果
// $lff_customer->save();
if (!$lff_customer->save()) {
foreach ($lff_customer->getMessages() as $message) {
$this->flashSession->error($message);
}
$this->dispatcher->forward([
'controller' => "lff_customers",
'action' => 'new'
]);
return;
}
$this->flashSession->success("lff_customer was created successfully");
$this->dispatcher->forward([
'controller' => "lff_customers",
'action' => 'index'
]);
}
/**
* Saves a lff_customer edited
*
*/
public function saveAction()
{
if (!$this->request->isPost()) {
$this->dispatcher->forward([
'controller' => "lff_customers",
'action' => 'index'
]);
return;
}
$cst_id = $this->request->getPost("cst_id");
$lff_customer = LffCustomers::findFirstBycst_id($cst_id);
if (!$lff_customer) {
$this->flashSession->error("lff_customer does not exist " . $cst_id);
$this->dispatcher->forward([
'controller' => "lff_customers",
'action' => 'index'
]);
return;
}
$lff_customer->cstStatusFlag = $this->request->getPost("cst_status_flag");
$lff_customer->cstNameLast = $this->request->getPost("cst_name_last");
$lff_customer->cstNameFirst = $this->request->getPost("cst_name_first");
if (!$lff_customer->save()) {
foreach ($lff_customer->getMessages() as $message) {
$this->flashSession->error($message);
}
$this->dispatcher->forward([
'controller' => "lff_customers",
'action' => 'edit',
'params' => [$lff_customer->cst_id]
]);
return;
}
$this->flashSession->success("lff_customer was updated successfully");
$this->dispatcher->forward([
'controller' => "lff_customers",
'action' => 'index'
]);
}
/**
* Deletes a lff_customer
*
* @param string $cst_id
*/
public function deleteAction($cst_id)
{
$lff_customer = LffCustomers::findFirstBycst_id($cst_id);
if (!$lff_customer) {
$this->flashSession->error("lff_customer was not found");
$this->dispatcher->forward([
'controller' => "lff_customers",
'action' => 'index'
]);
return;
}
if (!$lff_customer->delete()) {
foreach ($lff_customer->getMessages() as $message) {
$this->flashSession->error($message);
}
$this->dispatcher->forward([
'controller' => "lff_customers",
'action' => 'search'
]);
return;
}
$this->flashSession->success("lff_customer was deleted successfully");
$this->dispatcher->forward([
'controller' => "lff_customers",
'action' => "index"
]);
}
}
<?php
class LffScoreController extends ControllerBase
{
public function indexAction()
{
}
public function getCoursesByTermAction()
{
// echo 111;die;
$teacherId = $this->request->getPost('teacher_id', 'int');
$courses = LffCourse::find([
'conditions' => 'teacher_id = :teacher_id',
'bind' => [
'teacher_id' => $teacherId
]
])->toArray();
return $this->response->setJsonContent([
'code' => 200,
'msg' => $courses ? '查询成功' : '该教师暂无授课课程',
'courses' => $courses
]);
}
public function scoreManageAction()
{
// echo 111;die;
$terms = LffTerm::find();
$this->view->setVar("terms", $terms);
}
}
\ No newline at end of file
<?php
use Phalcon\Mvc\Model\Criteria;
use Phalcon\Paginator\Adapter\Model;
use Phalcon\Mvc\Controller;
class LoginController extends ControllerBase
{
public function initialize()
{
}
public function indexAction()
{
}
public function doLoginAction()
{
$auth = $this->session->get('auth');
if (!empty($auth) && isset($auth['identity'])) {
$this->flashSession->error('该用户已登录');
$this->redirectByIdentity($auth['identity']);
}
$user_account = $this->request->getPost('user_account');
$password = $this->request->getPost('password');
$rememberAccount = $this->request->getPost('remember_account', 'int', 0);
$autoLogin = $this->request->getPost('auto_login', 'int', 0);
// var_dump($user_account, $password);
if (empty($user_account) || empty($password)) {
$this->flashSession->error('用户名或者密码不能为空');
// return $this->dispatcher->forward([
// 'controller' => "login",
// 'action' => 'index'
// ]);
return $this->response->redirect('login/index');
}
// $user = LffUsers::findFirst(
// [
// "user_account" => ":user_account:",
// "bind" => ['user_account' => $user_account]
// ]
// );
// 正确的查询方式:条件字符串 + 绑定参数数组
$user = LffUsers::findFirst([
// 条件字符串:使用 :占位符: 格式
"user_account = :user_account:",
// 绑定参数:键名对应占位符(不带冒号)
"bind" => [
'user_account' => $user_account
]
]);
// echo 111;
// die;
if (!$user) {
$this->flashSession->error("该用户不存在");
// return $this->dispatcher->forward([
// 'controller' => "login",
// 'action' => 'index'
// ]);
return $this->response->redirect('login/index');
} elseif ($user->is_enable != 1) {
$this->flashSession->error("账号被禁用");
// return $this->dispatcher->forward([
// 'controller' => "login",
// 'action' => 'index'
// ]);
return $this->response->redirect('login/index');
} elseif ($user->is_lock == 1) {
$this->flashSession->error("账号被锁定");
// return $this->dispatcher->forward([
// 'controller' => "login",
// 'action' => 'index'
// ]);
return $this->response->redirect('login/index');
}
// echo 111;
// die;
if (!$this->security->checkHash($password, $user->password)) {
$this->flashSession->error('密码错误');
// return $this->dispatcher->forward([
// 'controller' => "login",
// 'action' => 'index'
// ]);
return $this->response->redirect('login/index');
}
// 登录成功,保存会话
$this->session->set('auth', [
'user_id' => $user->user_id,
'user_account' => $user->user_account,
'identity' => $user->identity
]);
// if ($rememberAccount) {
// $this->cookies->set(
// 'remember_account',
// $user_account,
// time() + 7 * 24 * 3600
// );
// } else {
// $this->cookies->get('remember_account')->delete();
// }
//
// if ($autoLogin) {
// $token = $this->security->getRandom()->base64Safe(32);
// $this->cookies->set(
// 'auto_login_token',
// $token,
// time() + 24 * 3600
// );
// $user->auto_login_token = $token;
// $user->token_expire_time = date('Y-m-d H:i:s', time() + 24 * 3600);
// $user->save();
// } else {
// // 未勾选则清除自动登录Cookie和数据库令牌
// $this->cookies->get('auto_login_token')->delete();
// $user->auto_login_token = '';
// $user->token_expire_time = null;
// $user->save();
// }
$this->flashSession->success('登录成功');
switch ($user->identity) {
case 0:
case 1:
// return $this->dispatcher->forward([
// 'controller' => "lff_teacher",
// 'action' => 'index'
// ]);
$this->response->redirect('lff_admin/index');
break;
case 2:
// return $this->dispatcher->forward([
// 'controller' => "lff_student",
// 'action' => 'index'
// ]);
$this->response->redirect('lff_score/scoreManage');
break;
default:
$this->response->redirect('lff_student/index');
break;
}
}
public function redirectByIdentity($identity)
{
switch ($identity) {
case 0:
case 1:
return $this->response->redirect('lff_admin/index');
case 2:
return $this->response->redirect('lff_score/scoreManage');
default:
return $this->response->redirect('lff_student/index');
}
}
public function logoutAction()
{
$this->session->remove('auth');
if(!$this->session->has('auth')){
$this->flashSession->success("用户已退出");
return $this->response->redirect('login/index');
}
}
}
\ No newline at end of file
<?php
class LffAdmin extends \Phalcon\Mvc\Model
{
public $admin_id;
public $user_id;
public $admin_email;
public function initialize()
{
$this->setSchema("develop_local");
$this->setSource("lff_admin");
}
public static function find($parameters = null): \Phalcon\Mvc\Model\ResultsetInterface
{
return parent::find($parameters);
}
public static function findFirst($parameters = null): ?\Phalcon\Mvc\ModelInterface
{
return parent::findFirst($parameters);
}
}
\ No newline at end of file
<?php
class LffCollege extends \Phalcon\Mvc\Model
{
public $college_id;
public $college_name;
public $college_code;
public $create_time;
public $update_time;
public function initialize()
{
$this->setSchema("develop_local");
$this->setSource("lff_college");
}
public static function find($parameters = null): \Phalcon\Mvc\Model\ResultsetInterface
{
return parent::find($parameters);
}
public static function findFirst($parameters = null): ?\Phalcon\Mvc\ModelInterface
{
return parent::findFirst($parameters);
}
}
\ No newline at end of file
<?php
class LffCourse extends \Phalcon\Mvc\Model
{
public $course_id;
public $course_code;
public $college_id;
public $course_name;
public $course_type;
public $teacher_id;
public $credit;
public $class_hour;
public $description;
public $create_time;
public $update_time;
public function initialize()
{
$this->setSchema("develop_local");
$this->setSource("lff_course");
}
public static function find($parameters = null): \Phalcon\Mvc\Model\ResultsetInterface
{
return parent::find($parameters);
}
public static function findFirst($parameters = null): ?\Phalcon\Mvc\ModelInterface
{
return parent::findFirst($parameters);
}
}
\ No newline at end of file
<?php
class LffCustomers extends \Phalcon\Mvc\Model
{
/**
*
* @var integer
*/
public $cst_id;
/**
*
* @var integer
*/
public $cst_status_flag;
/**
*
* @var string
*/
public $cst_name_last;
/**
*
* @var string
*/
public $cst_name_first;
/**
* Initialize method for model.
*/
public function initialize()
{
$this->setSchema("develop_local");
$this->setSource("lff_customers");
}
/**
* Allows to query a set of records that match the specified conditions
*
* @param mixed $parameters
* @return LffCustomers[]|LffCustomers|\Phalcon\Mvc\Model\ResultSetInterface
*/
public static function find($parameters = null): \Phalcon\Mvc\Model\ResultsetInterface
{
return parent::find($parameters);
}
/**
* Allows to query the first record that match the specified conditions
*
* @param mixed $parameters
* @return LffCustomers|\Phalcon\Mvc\Model\ResultInterface|\Phalcon\Mvc\ModelInterface|null
*/
public static function findFirst($parameters = null): ?\Phalcon\Mvc\ModelInterface
{
return parent::findFirst($parameters);
}
}
<?php
class LffOrderItems extends \Phalcon\Mvc\Model
{
/**
*
* @var integer
*/
public $item_id;
/**
*
* @var integer
*/
public $order_id;
/**
*
* @var integer
*/
public $prod_id;
/**
*
* @var integer
*/
public $item_quantity;
/**
*
* @var double
*/
public $item_price;
/**
*
* @var double
*/
public $item_total;
/**
* Initialize method for model.
*/
public function initialize()
{
$this->setSchema("develop_local");
$this->setSource("lff_order_items");
}
/**
* Allows to query a set of records that match the specified conditions
*
* @param mixed $parameters
* @return LffOrderItems[]|LffOrderItems|\Phalcon\Mvc\Model\ResultSetInterface
*/
public static function find($parameters = null): \Phalcon\Mvc\Model\ResultsetInterface
{
return parent::find($parameters);
}
/**
* Allows to query the first record that match the specified conditions
*
* @param mixed $parameters
* @return LffOrderItems|\Phalcon\Mvc\Model\ResultInterface|\Phalcon\Mvc\ModelInterface|null
*/
public static function findFirst($parameters = null): ?\Phalcon\Mvc\ModelInterface
{
return parent::findFirst($parameters);
}
}
<?php
class LffOrders extends \Phalcon\Mvc\Model
{
/**
*
* @var integer
*/
public $order_id;
/**
*
* @var integer
*/
public $cst_id;
/**
*
* @var double
*/
public $order_total;
/**
*
* @var integer
*/
public $order_status;
/**
*
* @var string
*/
public $order_time;
/**
*
* @var string
*/
public $pay_time;
/**
* Initialize method for model.
*/
public function initialize()
{
$this->setSchema("develop_local");
$this->setSource("lff_orders");
}
/**
* Allows to query a set of records that match the specified conditions
*
* @param mixed $parameters
* @return LffOrders[]|LffOrders|\Phalcon\Mvc\Model\ResultSetInterface
*/
public static function find($parameters = null): \Phalcon\Mvc\Model\ResultsetInterface
{
return parent::find($parameters);
}
/**
* Allows to query the first record that match the specified conditions
*
* @param mixed $parameters
* @return LffOrders|\Phalcon\Mvc\Model\ResultInterface|\Phalcon\Mvc\ModelInterface|null
*/
public static function findFirst($parameters = null): ?\Phalcon\Mvc\ModelInterface
{
return parent::findFirst($parameters);
}
}
<?php
class LffProducts extends \Phalcon\Mvc\Model
{
/**
*
* @var integer
*/
public $prod_id;
/**
*
* @var string
*/
public $prod_name;
/**
*
* @var double
*/
public $prod_price;
/**
*
* @var integer
*/
public $prod_stock;
/**
*
* @var integer
*/
public $prod_status;
/**
*
* @var string
*/
public $created_at;
/**
*
* @var string
*/
public $updated_at;
/**
* Initialize method for model.
*/
public function initialize()
{
$this->setSchema("develop_local");
$this->setSource("lff_products");
}
/**
* Allows to query a set of records that match the specified conditions
*
* @param mixed $parameters
* @return LffProducts[]|LffProducts|\Phalcon\Mvc\Model\ResultSetInterface
*/
public static function find($parameters = null): \Phalcon\Mvc\Model\ResultsetInterface
{
return parent::find($parameters);
}
/**
* Allows to query the first record that match the specified conditions
*
* @param mixed $parameters
* @return LffProducts|\Phalcon\Mvc\Model\ResultInterface|\Phalcon\Mvc\ModelInterface|null
*/
public static function findFirst($parameters = null): ?\Phalcon\Mvc\ModelInterface
{
return parent::findFirst($parameters);
}
}
<?php
class LffScore extends \Phalcon\Mvc\Model
{
public $score_id;
public $student_id;
public $course_id;
public $term_id;
public $create_by;
public $score;
public $create_time;
public $update_time;
public function initialize()
{
$this->setSchema('develop_local');
$this->setSource('lff_score');
}
public static function find($parameters = null): \Phalcon\Mvc\Model\ResultsetInterface
{
return parent::find($parameters);
}
public static function findFirst($parameters = null): ?\Phalcon\Mvc\ModelInterface
{
return parent::findfirst($parameters);
}
}
\ No newline at end of file
<?php
class LffStudent extends \Phalcon\Mvc\Model
{
public $student_id;
public $user_id;
public $college_id;
public $clazz;
public $admission_year;
public $create_time;
public $update_time;
public function initialize()
{
$this->setSchema("develop_local");
$this->setSource("lff_student");
}
public static function find($parameters = null): \Phalcon\Mvc\Model\ResultsetInterface
{
return parent::find($parameters);
}
public static function findFirst($parameters = null): ?\Phalcon\Mvc\ModelInterface
{
return parent::findFirst($parameters);
}
}
\ No newline at end of file
<?php
class LffTeacher extends \Phalcon\Mvc\Model
{
public $teacher_id;
public $user_id;
public $college_id;
public $email;
public $admission_year;
public $create_time;
public $update_time;
public function initialize()
{
$this->setSchema("develop_local");
$this->setSource("lff_teacher");
}
public static function find($parameters = null): \Phalcon\Mvc\Model\ResultsetInterface
{
return parent::find($parameters);
}
public static function findFirst($parameters = null): ?\Phalcon\Mvc\ModelInterface
{
return parent::findFirst($parameters);
}
}
\ No newline at end of file
<?php
class LffTerm extends \Phalcon\Mvc\Model
{
public $term_id;
public $term_name;
public $start_date;
public $end_date;
public $is_current;
public $create_time;
public function initialize()
{
$this->setSchema('develop_local');
$this->setSource('lff_term');
}
public static function find($parameters = null): \Phalcon\Mvc\Model\ResultsetInterface
{
return parent::find($parameters);
}
public static function findFirst($parameters = null): ?\Phalcon\Mvc\ModelInterface
{
return parent::findFirst($parameters);
}
}
\ No newline at end of file
<?php
class LffUsers extends \Phalcon\Mvc\Model
{
public $user_id;
public $user_account;
public $username;
public $password;
public $identity;
public $is_enable;
public $is_lock;
public $create_time;
public $last_login_time;
public function initialize()
{
$this->setSchema("develop_local");
$this->setSource("lff_users");
}
public static function find($parameters = null): \Phalcon\Mvc\Model\ResultsetInterface
{
return parent::find($parameters);
}
public static function findFirst($parameters = null): ?\Phalcon\Mvc\ModelInterface
{
return parent::findFirst($parameters);
}
}
\ No newline at end of file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Phalcon Framework</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0-alpha1/css/bootstrap.min.css" integrity="sha512-72OVeAaPeV8n3BdZj7hOkaPSEk/uwpDkaGyP4W2jSzAC8tfiO4LMEDWoL3uFp5mcZu+8Eehb4GhZWFwvrss69Q==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="shortcut icon" type="image/x-icon" href="<?php echo $this->url->get('img/favicon.ico')?>"/>
</head>
<body>
<div class="container">
<?php echo $this->getContent(); ?>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/2.11.6/umd/popper.min.js" integrity="sha512-6UofPqm0QupIL0kzS/UIzekR73/luZdC6i/kXDbWnLOJoqwklBK6519iUnShaYceJ0y4FaiPtX/hRnV/X/xlUQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0-alpha1/js/bootstrap.min.js" integrity="sha512-eHx4nbBTkIr2i0m9SANm/cczPESd0DUEcfl84JpIuutE6oDxPhXvskMR08Wmvmfx5wUpVjlWdi82G5YLvqqJdA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</body>
</html>
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<h1>教学管理系统 - 管理员后台</h1>
<hr>
<!-- 用户信息 -->
<div>
<?php
$auth = $this->session->get('auth');
$identity = $auth['identity'] ?? -1;
?>
<p>当前登录:<?php echo $auth['user_account'] ?? '未知用户' ?></p>
<a href="<?php echo $this->url->get('login/logout') ?>">退出登录</a>
</div>
<hr>
<div>
<!-- 【用户管理】:超级管理员可见全部,普通管理员可见部分 -->
<?php if ($identity === 0 || $identity === 1): ?>
<div>
<p>【用户管理】</p>
<ul>
<!-- 仅超级管理员可见“教学管理员账号管理” -->
<?php if ($identity === 0): ?>
<li><a href="<?php echo $this->url->get('lff_admin/acaAdminList') ?>">教学管理员账号管理</a></li>
<?php endif; ?>
<!-- 超级管理员和普通管理员都可见以下两项 -->
<li><a href="<?php echo $this->url->get('lff_teacher/teacherList') ?>">教师信息管理</a></li>
<li><a href="<?php echo $this->url->get('lff_student/studentList') ?>">学生信息管理</a></li>
</ul>
</div>
<?php endif; ?>
<!-- 【课程管理】:超级管理员和普通管理员都可见 -->
<?php if ($identity === 0 || $identity === 1): ?>
<div>
<p>【课程管理】</p>
<ul>
<li><a href="<?php echo $this->url->get('lff_course/courseList') ?>">课程列表</a></li>
</ul>
</div>
<?php endif; ?>
<!-- 【学院管理】:超级管理员和普通管理员都可见 -->
<?php if ($identity === 0 || $identity === 1): ?>
<div>
<p>【学院管理】</p>
<ul>
<li><a href="<?php echo $this->url->get('lff_college/collegeList') ?>">学院列表</a></li>
</ul>
</div>
<?php endif; ?>
<!-- 【成绩管理】:仅教师(identity=2)可见 -->
<?php if ($identity === 2): ?>
<div>
<p>【成绩管理】</p>
<ul>
<li><a href="<?php echo $this->url->get('lff_score/scoreManage') ?>">成绩录入</a></li>
<li><a href="<?php echo $this->url->get('lff_score/') ?>">成绩展示</a></li>
</ul>
</div>
<?php endif; ?>
<!-- 【个人成绩管理】:仅学生(identity=3)可见 -->
<?php if ($identity === 3): ?>
<div>
<p>【个人成绩管理】</p>
<ul>
<li><a href="<?php echo $this->url->get('') ?>">成绩查看</a></li>
</ul>
</div>
<?php endif; ?>
</div>
\ No newline at end of file
<div class="center-block">
<?php echo $this->getContent(); ?>
</div>
\ No newline at end of file
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<div class="admin-management">
<h2>教学管理员账号管理</h2>
<p><?php echo isset($totalCount) ? $totalCount : 0 ?> 位教师</p>
<!-- 新增教师按钮 -->
<a href="<?php echo $this->url->get('lff_admin/addAdmin') ?>" class="btn-add">
<button>新增教学管理员</button>
</a>
<!-- 教师列表表格 -->
<table class="teacher-table" border="1" cellpadding="8" cellspacing="0" width="100%">
<tr>
<th>ID</th>
<th>账号</th>
<th>姓名</th>
<th>状态</th>
<th>创建时间</th>
<th>操作</th>
</tr>
<?php if (!empty($teachers)) { ?>
<?php foreach ($teachers as $teacher) { ?>
<tr>
<td><?php echo htmlspecialchars($teacher->user_id ?? '') ?></td>
<td><?php echo htmlspecialchars($teacher->user_account ?? '') ?></td>
<td><?php echo htmlspecialchars($teacher->username ?? '') ?></td>
<td>
<?php if (isset($teacher->is_enable) && $teacher->is_enable == 1) { ?>
<span class="status-normal" style="color: green;">正常</span>
<?php } else { ?>
<span class="status-disabled" style="color: red;">禁用</span>
<?php } ?>
</td>
<td><?php if (isset($teacher->is_lock) && $teacher->is_lock == 1) { ?>
<span class="status-normal" style="color: red;">锁定</span>
<?php } else { ?>
<span class="status-disabled" style="color: green;">未锁定</span>
<?php } ?>
</td>
<td><?php echo htmlspecialchars($teacher->create_time ?? '') ?></td>
<td class="operation-buttons">
<!-- 编辑按钮 -->
<a href="<?php echo $this->url->get("lff_admin/editAdmin/" . $teacher->user_id) ?>">
编辑
</a>
|
<!-- 启用/禁用按钮 -->
<?php if (isset($teacher->is_enable) && $teacher->is_enable == 1) { ?>
<a href="<?php echo $this->url->get('lff_admin/adminDisable/' . $teacher->user_id) ?>"
onclick="return confirm('确定要禁用该管理员吗?')">
禁用
</a>
<?php } else { ?>
<a href="<?php echo $this->url->get('lff_admin/adminEnable/'. $teacher->user_id ) ?>"
onclick="return confirm('确定要启用该管理员吗?')">
启用
</a>
<?php } ?>
<!-- 新增删除按钮 -->
<a href="<?php echo $this->url->get('lff_admin/deleteAdmin/' . ($teacher->user_id ?? 0)) ?>"
onclick="return confirm('确定要删除该管理员吗?删除后数据不可恢复!')"
style="color: #dc3545;">
删除
</a>
</td>
</tr>
<?php } ?>
<?php } else { ?>
<tr>
<td colspan="6" align="center">暂无教师数据</td>
</tr>
<?php } ?>
</table>
<!-- 移除分页控件 -->
</div>
\ No newline at end of file
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<div class="admin-add-container">
<h2>添加管理员</h2>
<form action="<?php echo $this->url->get('lff_admin/create') ?>" method="post" class="admin-add-form">
<!-- 1. 管理员账号(存储在users表) -->
<div class="form-group">
<label for="user_account">管理员账号 <span class="required">*</span></label>
<input type="text"
id="user_account"
name="user_account"
required
placeholder="请输入6-20位字母/数字组合"
maxlength="20"
minlength="6"
pattern="^[A-Za-z0-9!@#$%^&*()_+\-=\[\]{};':\"
title="账号支持字母、数字和特殊符号(!@#$%^&*)">
</div>
<div class="form-group">
<label for="username">管理员姓名 <span class="required">*</span></label>
<input type="text"
id="username"
name="username"
required
placeholder="请输入真实姓名"
maxlength="10"
pattern="^[\u4e00-\u9fa5]+$"
title="姓名仅支持中文">
</div>
<div class="form-group">
<label for="email">联系邮箱 <span class="required">*</span></label>
<input type="email"
id="email"
name="email"
required
placeholder="请输入有效的邮箱地址"
maxlength="50"
title="请输入正确的邮箱格式(例如:admin@example.com)">
</div>
<div class="form-group">
<label for="password">初始密码 <span class="required">*</span></label>
<input type="password"
id="password"
name="password"
required
placeholder="请设置8-16位密码(含字母和数字)"
maxlength="16"
minlength="8"
pattern="^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]+$"
title="密码需包含字母和数字,长度8-16位">
</div>
<div class="form-group">
<label>管理员角色 <span class="required">*</span></label>
<div class="role-radio">
<label>
<input type="radio"
name="identity"
value="0"
checked
required>
超级管理员(拥有全部权限)
</label>
<label>
<input type="radio"
name="identity"
value="1"
required>
教学管理员(仅管理教师/课程相关)
</label>
</div>
</div>
<div class="form-group">
<label>账号状态</label>
<select name="is_enable" id="is_enable">
<option value="1" selected>启用(创建后可直接登录)</option>
<option value="0">禁用(需手动启用后才能登录)</option>
</select>
</div>
<div class="form-group">
<label>锁定状态</label>
<select name="is_locke" id="is_locke">
<option value="0" selected>未锁定(正常使用)</option>
<option value="1">锁定(禁止登录,需解锁后使用)</option>
</select>
</div>
<div class="form-submit">
<button type="submit" class="btn-submit">创建管理员</button>
<a href="<?php echo $this->url->get('lff_admin/acaAdminList') ?>" class="btn-cancel">取消</a>
</div>
</form>
</div>
\ No newline at end of file
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<div class="admin-edit-container">
<h2>修改教学管理员信息</h2>
<p class="subtitle">账号为唯一标识,不可修改</p>
<!-- 管理员信息修改表单:使用 adminInfo 的 user_id 传参 -->
<form action="<?php echo $this->url->get("lff_admin/save") ?>" method="post" class="admin-edit-form">
<input type="hidden" name="user_id" value="<?php echo $adminInfo->user_id ?? 0 ?>">
<!-- 1. 管理员账号(不可修改,补充展示,来自 adminInfo 的 users 表字段) -->
<div class="form-group">
<label>管理员账号</label>
<input type="text"
value="<?php echo htmlspecialchars($adminInfo->user_account ?? '') ?>"
id="user_account"
name="user_account"
readonly
class="readonly-input"
title="账号为唯一标识,不可修改">
</div>
<div class="form-group">
<label for="username">管理员姓名 <span class="required">*</span></label>
<input type="text"
id="username"
name="username"
required
value="<?php echo htmlspecialchars($adminInfo->username ?? '') ?>"
placeholder="请输入真实姓名"
maxlength="20"
pattern="^[\u4e00-\u9fa5]+$"
title="姓名仅支持中文"
</div>
<div class="form-group">
<label for="email">联系邮箱 <span class="required">*</span></label>
<input type="email"
id="email"
name="email"
required
value="<?php echo htmlspecialchars($adminInfo->admin_email ?? '') ?>"
placeholder="请输入有效的邮箱地址"
maxlength="50">
</div>
<div class="form-group">
<label for="is_enable">账号状态</label>
<select name="is_enable" id="is_enable" required>
<option value="1" <?php echo (isset($adminInfo->is_enable) && $adminInfo->is_enable == 1) ? 'selected' : '' ?>>
启用(可正常登录)
</option>
<option value="0" <?php echo (isset($adminInfo->is_enable) && $adminInfo->is_enable == 0) ? 'selected' : '' ?>>
禁用(禁止登录)
</option>
</select>
</div>
<div class="form-group">
<label for="is_lock">账号锁定状态</label>
<select name="is_lock" id="is_lock" required>
<option value="0" <?php echo (isset($adminInfo->is_lock) && $adminInfo->is_lock == 0) ? 'selected' : '' ?>>
未锁定(正常使用)
</option>
<option value="1" <?php echo (isset($adminInfo->is_lock) && $adminInfo->is_lock == 1) ? 'selected' : '' ?>>
已锁定(禁止登录,需解锁后使用)
</option>
</select>
</div>
<div class="password-reset-section">
<h3>密码重置</h3>
<p class="reset-hint">勾选后将密码重置为系统默认初始密码(默认密码:123456a?),需重新告知管理员</p>
<div class="form-group">
<label>
<input type="checkbox" name="reset_password" id="reset_password" value="1">
确认重置密码
</label>
</div>
</div>
<!-- 6. 操作按钮 -->
<div class="form-actions">
<button type="submit" class="btn-save">保存修改</button>
<a href="<?php echo $this->url->get('lff_admin/adminList') ?>" class="btn-cancel">取消</a>
</div>
</form>
</div>
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<h3>新增学院信息</h3>
<div class="card-body">
<form id="addCollegeForm" action="<?= $this->url->get('lff_college/create') ?>" method="post">
<div class="form-group">
<label for="college_code" class="form-label">
学院编号 <span class="required-mark">*</span>
</label>
<input type="text" class="form-control" id="college_code" name="college_code"
placeholder="请输入2位学院编号(如01、02)" maxlength="2" required
value="<?= htmlspecialchars($this->data['college_code'] ?? '') ?>">
<div class="form-text">限2位数字,作为学院的唯一标识编码(如01代表文学院)</div>
<?php if (isset($this->errors['college_code'])): ?>
<div class="error-message"><?= $this->errors['college_code'] ?></div>
<?php endif; ?>
</div>
<div class="form-group">
<label for="college_name" class="form-label">
学院名称 <span class="required-mark">*</span>
</label>
<input type="text" class="form-control" id="college_name" name="college_name"
placeholder="请输入学院名称" maxlength="50" required
value="<?= htmlspecialchars($this->data['college_name'] ?? '') ?>">
<div class="form-text">限50字以内,填写标准学院名称(如文学院、计算机学院)</div>
<?php if (isset($this->errors['college_name'])): ?>
<div class="error-message"><?= $this->errors['college_name'] ?></div>
<?php endif; ?>
</div>
<div class="btn-group">
<button type="submit" class="btn btn-primary">提交保存</button>
<a href="<?= $this->url->get('lff_college/collegeList') ?>" class="btn btn-secondary ms-2">取消返回</a>
</div>
</form>
</div>
\ No newline at end of file
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<h2>学院信息管理</h2>
<a href="<?php echo $this->url->get('lff_college/addCollege') ?>" class="btn btn-primary mb-3">添加学院</a>
<form action="<?php echo $this->url->get('lff_college/collegeList') ?>" method="get" class="search-form row">
<div class="col-10">
<input type="text" name="keyword" class="form-control"
placeholder="输入学院编号或名称查询"
value="<?php echo htmlspecialchars($keyword ?? '') ?>">
</div>
<div class="col-2">
<button type="submit" class="btn btn-secondary w-100">查询</button>
</div>
</form>
<table class="table table-striped table-bordered">
<thead class="table-light">
<tr>
<th>学院编号</th>
<th>学院名称</th>
<th>创建时间</th>
<th>更新时间</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php if (isset($colleges) && $colleges->count() > 0): ?>
<?php foreach ($colleges as $college): ?>
<tr>
<td><?php echo htmlspecialchars($college->college_id) ?></td>
<td><?php echo htmlspecialchars($college->college_name) ?></td>
<td><?php echo htmlspecialchars($college->create_time) ?></td>
<td><?php echo htmlspecialchars($college->update_time) ?></td>
<td>
<!-- 修改按钮 -->
<a href="<?php echo $this->url->get("lff_college/editCollege/" . $college->college_id) ?>"
class="btn btn-sm btn-outline-primary operation-btn">修改</a>
<!-- 删除按钮(修正学院ID和提示文本) -->
<a href="<?php echo $this->url->get("lff_college/deleteCollege/" . $college->college_id) ?>"
onclick="return confirm('确定要删除该学院吗?删除后数据不可恢复!')"
class="btn btn-sm btn-outline-danger operation-btn">
删除
</a>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr>
<td colspan="6" class="text-center py-3">暂无学院数据</td>
</tr>
<?php endif; ?>
</tbody>
</table>
\ No newline at end of file
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<h3>修改学院信息</h3>
<div class="card-body">
<form action="<?php echo $this->url->get('lff_college/save') ?>" method="post" id="editForm">
<input type="hidden" name="college_id"
value="<?php echo htmlspecialchars($collegeInfo->college_id ?? '') ?>">
<div class="form-group">
<label for="collegeId" class="form-label">学院编号</label>
<input type="text" class="form-control" id="collegeId"
value="<?php echo htmlspecialchars($collegeInfo->college_id ?? '') ?>"
readonly
style="background-color: #f8f9fa; cursor: not-allowed;">
<div class="form-text">学院编号为唯一标识,不可修改</div>
</div>
<div class="form-group">
<label for="collegeName" class="form-label">
学院名称 <span class="text-danger">*</span>
</label>
<input type="text" class="form-control" id="collegeName"
name="college_name"
value="<?php echo htmlspecialchars($collegeInfo->college_name ?? '') ?>"
required
maxlength="50"
placeholder="请输入学院名称(如:计算机科学与技术学院)">
<div class="invalid-feedback">学院名称为必填项,最多50个字符</div>
</div>
<div class="btn-group">
<button type="submit" class="btn btn-primary">保存修改</button>
<a href="<?php echo $this->url->get('lff_college/collegeList') ?>"
class="btn btn-secondary ms-2">取消</a>
</div>
</form>
</div>
\ No newline at end of file
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<h3>添加课程信息</h3>
<div class="card-body">
<form id="addCourseForm" action="<?php echo $this->url->get('lff_course/create') ?>" method="post">
<div class="form-group">
<label for="course_id" class="form-label">
课程编号 <span class="required-mark">*</span>
</label>
<input type="text" class="form-control" id="course_code" name="course_code"
placeholder="格式:2位学院编号+3位课程类别码+3位序号(如01001001)"
maxlength="8" required
value="<?php echo htmlspecialchars($this->data['course_code'] ?? '') ?>">
<div class="form-text">
示例:01(学院编号)001(课程类别码)001(序号)→ 01001001,总长度8位
</div>
<?php if (isset($this->errors['course_code'])): ?>
<div class="error-message show"><?php echo $this->errors['course_code'] ?></div>
<?php endif; ?>
</div>
<div class="form-group">
<label for="course_name" class="form-label">
课程名称 <span class="required-mark">*</span>
</label>
<input type="text" class="form-control" id="course_name" name="course_name"
placeholder="请输入课程名称" maxlength="50" required
value="<?php echo htmlspecialchars($this->data['course_name'] ?? '') ?>">
<div class="form-text">限50字以内,禁止包含特殊符号(如@#$%^&*等)</div>
<?php if (isset($this->errors['course_name'])): ?>
<div class="error-message show"><?php echo $this->errors['course_name'] ?></div>
<?php endif; ?>
</div>
<!-- 课程类型 -->
<div class="form-group">
<label for="course_type" class="form-label">
课程类型 <span class="required-mark">*</span>
</label>
<select class="form-select" id="course_type" name="course_type" required>
<option value="">请选择课程类型</option>
<option value="1" <?php echo isset($this->data['course_type']) && $this->data['course_type'] == 'required' ? 'selected' : '' ?>>必修课</option>
<option value="2" <?php echo isset($this->data['course_type']) && $this->data['course_type'] == 'elective' ? 'selected' : '' ?>>选修课</option>
<option value="3" <?php echo isset($this->data['course_type']) && $this->data['course_type'] == 'practice' ? 'selected' : '' ?>>实践课</option>
</select>
<?php if (isset($this->errors['course_type'])): ?>
<div class="error-message show"><?php echo $this->errors['course_type'] ?></div>
<?php endif; ?>
</div>
<!-- 所属学院 -->
<div class="form-group">
<label for="college_id" class="form-label">
所属学院 <span class="required-mark">*</span>
</label>
<select class="form-select" id="college_id" name="college_id" required>
<option value="">请选择所属学院</option>
<?php if (isset($colleges) && $colleges->count() > 0): ?>
<?php foreach ($colleges as $college): ?>
<option value="<?php echo htmlspecialchars($college->college_id ?? '') ?>"
<?php echo isset($this->data['college_id']) && $this->data['college_id'] == $college->college_id ? 'selected' : '' ?>>
<?php echo htmlspecialchars($college->college_name ?? '') ?>
</option>
<?php endforeach; ?>
<?php endif; ?>
</select>
<?php if (isset($this->errors['college_id'])): ?>
<div class="error-message show"><?php echo $this->errors['college_id'] ?></div>
<?php endif; ?>
</div>
<div class="form-group">
<label for="credit" class="form-label">
学分 <span class="required-mark">*</span>
</label>
<input type="number" class="form-control" id="credit" name="credit"
placeholder="请输入学分" min="0.5" max="6.0" step="0.5" required
value="<?php echo htmlspecialchars($this->data['credit'] ?? '') ?>">
<div class="form-text">数值范围0.5-6.0,支持0.5为步长(如0.5、1.0、1.5...)</div>
<?php if (isset($this->errors['credit'])): ?>
<div class="error-message show"><?php echo $this->errors['credit'] ?></div>
<?php endif; ?>
</div>
<div class="form-group">
<label for="class_hour" class="form-label">
学时 <span class="required-mark">*</span>
</label>
<input type="number" class="form-control" id="class_hour" name="class_hour"
placeholder="请输入学时" min="16" max="128" step="1" required
value="<?php echo htmlspecialchars($this->data['class_hour'] ?? '') ?>">
<div class="form-text">整数范围16-128(如16、32、48...)</div>
<?php if (isset($this->errors['class_hour'])): ?>
<div class="error-message show"><?php echo $this->errors['class_hour'] ?></div>
<?php endif; ?>
</div>
<div class="form-group">
<label for="teacher_name" class="form-label">
授课教师 <span class="required-mark">*</span>
</label>
<input type="text" class="form-control" id="teacher_name" name="teacher_name"
placeholder="请输入授课教师姓名(需与系统中教师姓名一致)" maxlength="50" required
value="<?php echo htmlspecialchars($this->data['teacher_name'] ?? '') ?>">
<div class="form-text">请输入真实姓名,系统将自动匹配教师信息</div>
<?php if (isset($this->errors['teacher_name'])): ?>
<div class="error-message show"><?php echo $this->errors['teacher_name'] ?></div>
<?php endif; ?>
</div>
<div class="form-group">
<label for="description" class="form-label">课程描述</label>
<textarea class="form-control" id="description" name="description"
placeholder="请输入课程描述(可选)" maxlength="200" rows="3"><?php echo htmlspecialchars($this->data['description'] ?? '') ?></textarea>
</div>
<div class="btn-group">
<button type="submit" class="btn btn-primary">提交课程</button>
<a href="<?php echo $this->url->get('lff_course/courseList') ?>" class="btn btn-secondary ms-2">取消</a>
</div>
</form>
</div>
\ No newline at end of file
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<h2>课程管理</h2>
<a href="<?php echo $this->url->get('lff_course/addCourse') ?>" class="btn btn-primary">
<i class="bi bi-plus-circle"></i> 添加课程
</a>
<form action="<?php echo $this->url->get('lff_course/courseList') ?>" method="get" class="search-form mb-4">
<div class="input-group">
<input type="text" name="keyword" class="form-control"
placeholder="输入课程编号/名称搜索"
value="<?php echo htmlspecialchars($this->keyword ?? '') ?>">
<button type="submit" class="btn btn-secondary">搜索</button>
<?php if (!empty($this->keyword)): ?>
<a href="<?php echo $this->url->get('lff_course/courseList') ?>" class="btn btn-outline-secondary">重置</a>
<?php endif; ?>
</div>
</form>
<table class="table table-striped table-bordered">
<thead class="table-light">
<tr>
<th>课程编号</th>
<th>课程名称</th>
<th>课程类型</th>
<th>所属学院</th>
<th>学分</th>
<th>学时</th>
<th>授课教师</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<?php if (isset($courseInfo) && $courseInfo->count() > 0): ?>
<?php foreach ($courseInfo as $course): ?>
<tr>
<td><?php echo htmlspecialchars($course->course_id) ?></td>
<td><?php echo htmlspecialchars($course->course_name) ?></td>
<td>
<?php
// 转换课程类型为中文显示
$typeMap = [
'1' => '必修课',
'2' => '选修课',
'3' => '实践课'
];
echo $typeMap[$course->course_type] ?? $course->course_type;
?>
</td>
<td><?php echo htmlspecialchars($course->college_name) ?></td>
<td><?php echo htmlspecialchars($course->credit) ?></td>
<td><?php echo htmlspecialchars($course->class_hour) ?></td>
<td><?php echo htmlspecialchars($course->teacher_name) ?></td>
<td>
<div class="operation-btns">
<a href="<?php echo $this->url->get("lff_course/editCourse/" . $course->course_id ?? 0) ?>"
class="btn btn-sm btn-outline-primary">修改</a>
<a href="<?php echo $this->url->get("lff_course/deleteCourse/" . $course->course_id ?? 0) ?>"
onclick="return confirm('确定删除课程【<?php echo htmlspecialchars($course->course_name) ?>】吗?删除后不可恢复!')"
class="btn btn-sm btn-outline-danger">删除</a>
</div>
</td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr>
<td colspan="9" class="text-center py-4">
<div>暂无课程数据</div>
<a href="<?php echo $this->url->get('admin/addCourse') ?>" class="text-primary">点击添加课程</a>
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
\ No newline at end of file
<?php if ($this->flashSession->output()) ?>
<h3>编辑课程信息</h3>
<form id="editCourseForm" action="<?= $this->url->get('lff_course/save') ?>" method="post">
<input type="hidden" name="course_id" value="<?= htmlspecialchars($courseInfo->course_id ?? '') ?>">
<input type="hidden" name="course_code" value="<?= htmlspecialchars($courseInfo->course_code ?? '') ?>">
<div class="form-group">
<label for="course_id" class="form-label">
课程编号 <span class="required-mark">*</span>
</label>
<input type="text" class="form-control" id="course_id"
value="<?= htmlspecialchars($courseInfo->course_id ?? '') ?>"
readonly disabled>
<div class="form-text">课程唯一标识,不可修改</div>
</div>
<div class="form-group">
<label for="course_name" class="form-label">
课程名称 <span class="required-mark">*</span>
</label>
<input type="text" class="form-control" id="course_name" name="course_name"
placeholder="请输入课程名称" maxlength="50" required
value="<?= htmlspecialchars($this->data['course_name'] ?? $courseInfo->course_name ?? '') ?>">
<div class="form-text">限50字以内,禁止包含特殊符号(如@#$%^&*等)</div>
</div>
<div class="form-group">
<label for="course_type" class="form-label">
课程类型 <span class="required-mark">*</span>
</label>
<select class="form-select" id="course_type" name="course_type" required>
<option value="">请选择课程类型</option>
<option value="1" <?= (isset($this->data['course_type']) ? $this->data['course_type'] : $courseInfo->course_type ?? '') == '1' ? 'selected' : '' ?>>必修课</option>
<option value="2" <?= (isset($this->data['course_type']) ? $this->data['course_type'] : $courseInfo->course_type ?? '') == '2' ? 'selected' : '' ?>>选修课</option>
<option value="3" <?= (isset($this->data['course_type']) ? $this->data['course_type'] : $courseInfo->course_type ?? '') == '3' ? 'selected' : '' ?>>实践课</option>
</select>
</div>
<div class="form-group">
<label for="college_id" class="form-label">
所属学院 <span class="required-mark">*</span>
</label>
<select class="form-select" id="college_id" name="college_id" required>
<option value="">请选择所属学院</option>
<?php if (isset($colleges) && $colleges->count() > 0): ?>
<?php foreach ($colleges as $college): ?>
<option value="<?= htmlspecialchars($college->college_id ?? '') ?>"
<?= (isset($this->data['college_id']) ? $this->data['college_id'] : $courseInfo->college_id ?? '') == $college->college_id ? 'selected' : '' ?>>
<?= htmlspecialchars($college->college_name ?? '') ?>
</option>
<?php endforeach; ?>
<?php endif; ?>
</select>
<?php if (isset($this->errors['college_id'])): ?>
<div class="error-message show"><?= $this->errors['college_id'] ?></div>
<?php endif; ?>
</div>
<!-- 学分 -->
<div class="form-group">
<label for="credit" class="form-label">
学分 <span class="required-mark">*</span>
</label>
<input type="number" class="form-control" id="credit" name="credit"
placeholder="请输入学分" min="0.5" max="6.0" step="0.5" required
value="<?= htmlspecialchars($this->data['credit'] ?? $courseInfo->credit ?? '') ?>">
<div class="form-text">数值范围0.5-6.0,支持0.5为步长(如0.5、1.0、1.5...)</div>
<?php if (isset($this->errors['credit'])): ?>
<div class="error-message show"><?= $this->errors['credit'] ?></div>
<?php endif; ?>
</div>
<div class="form-group">
<label for="class_hour" class="form-label">
学时 <span class="required-mark">*</span>
</label>
<input type="number" class="form-control" id="class_hour" name="class_hour"
placeholder="请输入学时" min="16" max="128" step="1" required
value="<?= htmlspecialchars($this->data['class_hour'] ??$courseInfo->class_hour ?? '') ?>">
<div class="form-text">整数范围16-128(如16、32、48...)</div>
<?php if (isset($this->errors['class_hour'])): ?>
<div class="error-message show"><?= $this->errors['class_hour'] ?></div>
<?php endif; ?>
</div>
<div class="form-group">
<label for="teacher_name" class="form-label">
授课教师 <span class="required-mark">*</span>
</label>
<input type="text" class="form-control" id="teacher_name" name="teacher_name"
placeholder="请输入授课教师姓名(需属于所选学院)" maxlength="50" required
value="<?= htmlspecialchars($this->data['teacher_name'] ?? $courseInfo->teacher_name ?? '') ?>">
<div class="form-text">请输入真实姓名,系统将验证该教师是否属于所选学院</div>
<?php if (isset($this->errors['teacher_name'])): ?>
<div class="error-message show"><?= $this->errors['teacher_name'] ?></div>
<?php endif; ?>
</div>
<div class="form-group">
<label for="description" class="form-label">课程描述</label>
<textarea class="form-control" id="description" name="description"
placeholder="请输入课程描述(可选)" maxlength="200" rows="3"><?= htmlspecialchars($this->data['description'] ?? $courseInfo->description ?? '') ?></textarea>
</div>
<div class="btn-group">
<button type="submit" class="btn btn-primary">保存修改</button>
<a href="<?= $this->url->get('lff_course/courseList') ?>" class="btn btn-secondary ms-2">取消返回</a>
</div>
</form>
\ No newline at end of file
<?php
/**
* @var \Phalcon\Mvc\View\Engine\Php $this
*/
?>
<div class="row">
<nav>
<ul class="pager">
<li class="previous"><?php echo $this->tag->a($this->url->get("lff_customers"), "Go Back") ?></li>
</ul>
</nav>
</div>
<div class="page-header">
<h1>Edit lff_customers</h1>
</div>
<?php echo $this->getContent(); ?>
<form action="<?= $this->url->get('lff_customers/save') ?>" class="form-horizontal" method="post">
<div class="form-group">
<label for="fieldCstStatusFlag" class="col-sm-2 control-label">Cst Of Status Of Flag</label>
<div class="col-sm-10">
<?= $this->tag->inputText("cst_status_flag", $lff_customer->cst_status_flag, ["size" => 30, "class" => "form-control", "id" => "fieldCstStatusFlag"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldCstNameLast" class="col-sm-2 control-label">Cst Of Name Of Last</label>
<div class="col-sm-10">
<?= $this->tag->inputText("cst_name_last", $lff_customer->cst_name_last, ["size" => 30, "class" => "form-control", "id" => "fieldCstNameLast"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldCstNameFirst" class="col-sm-2 control-label">Cst Of Name Of First</label>
<div class="col-sm-10">
<?= $this->tag->inputText("cst_name_first", $lff_customer->cst_name_first, ["size" => 30, "class" => "form-control", "id" => "fieldCstNameFirst"]) ?>
</div>
</div>
<?php echo $this->tag->inputHidden("id", $lff_customer->cst_id) ?>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<?php echo $this->tag->inputSubmit("save", "Save", ['class' => "btn btn-primary"]) ?>
</div>
</div>
</form>
<?php
/**
* @var \Phalcon\Mvc\View\Engine\Php $this
*/
?>
<div class="page-header">
<h1>Search lff_customers</h1>
<p><?php echo $this->tag->a($this->url->get("lff_customers/new"), "Create lff_customers") ?></p>
</div>
<?php echo $this->getContent() ?>
<?php echo $this->flashSession->output() ?>
<form action="<?= $this->url->get('lff_customers/search') ?>" class="form-horizontal" method="get">
<div class="form-group">
<label for="fieldCstId" class="col-sm-2 control-label">Cst</label>
<div class="col-sm-10">
<?= $this->tag->inputNumeric("cst_id", $lff_customer->cst_id, ["class" => "form-control", "id" => "fieldCstId"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldCstStatusFlag" class="col-sm-2 control-label">Cst Of Status Of Flag</label>
<div class="col-sm-10">
<?= $this->tag->inputText("cst_status_flag", $lff_customer->cst_status_flag, ["size" => 30, "class" => "form-control", "id" => "fieldCstStatusFlag"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldCstNameLast" class="col-sm-2 control-label">Cst Of Name Of Last</label>
<div class="col-sm-10">
<?= $this->tag->inputText("cst_name_last", $lff_customer->cst_name_last, ["size" => 30, "class" => "form-control", "id" => "fieldCstNameLast"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldCstNameFirst" class="col-sm-2 control-label">Cst Of Name Of First</label>
<div class="col-sm-10">
<?= $this->tag->inputText("cst_name_first", $lff_customer->cst_name_first, ["size" => 30, "class" => "form-control", "id" => "fieldCstNameFirst"]) ?>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<?php echo $this->tag->inputSubmit("search", "Search", ["class" => "btn btn-primary"]) ?>
</div>
</div>
</form>
<?php
/**
* @var \Phalcon\Mvc\View\Engine\Php $this
*/
?>
<div class="row">
<nav>
<ul class="pager">
<li class="previous"><?php echo $this->tag->a($this->url->get("lff_customers"), "Go Back") ?></li>
</ul>
</nav>
</div>
<div class="page-header">
<h1>Create lff_customers</h1>
</div>
<?php echo $this->getContent(); ?>
<form action="<?= $this->url->get('lff_customers/create') ?>" class="form-horizontal" method="post">
<div class="form-group">
<label for="fieldCstStatusFlag" class="col-sm-2 control-label">Cst Of Status Of Flag</label>
<div class="col-sm-10">
<?= $this->tag->inputText("cst_status_flag", $lff_customer->cst_status_flag, ["size" => 30, "class" => "form-control", "id" => "fieldCstStatusFlag"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldCstNameLast" class="col-sm-2 control-label">Cst Of Name Of Last</label>
<div class="col-sm-10">
<?= $this->tag->inputText("cst_name_last", $lff_customer->cst_name_last, ["size" => 30, "class" => "form-control", "id" => "fieldCstNameLast"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldCstNameFirst" class="col-sm-2 control-label">Cst Of Name Of First</label>
<div class="col-sm-10">
<?= $this->tag->inputText("cst_name_first", $lff_customer->cst_name_first, ["size" => 30, "class" => "form-control", "id" => "fieldCstNameFirst"]) ?>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<?php echo $this->tag->inputSubmit("save", "Save", ['class' => "btn btn-primary"]) ?>
</div>
</div>
</form>
<?php
/**
* @var \Phalcon\Mvc\View\Engine\Php $this
*/
?>
<div class="row">
<nav>
<ul class="pager">
<li class="previous"><?php echo $this->tag->a($this->url->get("lff_customers/index"), "Go Back"); ?></li>
<li class="next"><?php echo $this->tag->a($this->url->get("lff_customers/new"), "Create"); ?></li>
</ul>
</nav>
</div>
<div class="page-header">
<h1>Search result</h1>
</div>
<?php echo $this->getContent(); ?>
<div class="row">
<table class="table table-bordered">
<thead>
<tr>
<th>Cst</th>
<th>Cst Of Status Of Flag</th>
<th>Cst Of Name Of Last</th>
<th>Cst Of Name Of First</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($page->getItems() as $lff_customer): ?>
<tr>
<td><?php echo $lff_customer->cst_id; ?></td>
<td><?php echo $lff_customer->cst_status_flag; ?></td>
<td><?php echo $lff_customer->cst_name_last; ?></td>
<td><?php echo $lff_customer->cst_name_first; ?></td>
<td><?php echo $this->tag->a($this->url->get("lff_customers/edit/" . $lff_customer->cst_id), "Edit"); ?></td>
<td><?php echo $this->tag->a($this->url->get("lff_customers/delete/" . $lff_customer->cst_id), "Delete"); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="row">
<div class="col-sm-1">
<p class="pagination" style="line-height: 1.42857;padding: 6px 12px;">
<?php echo $page->getCurrent(), "/", $page->getTotalItems() ?>
</p>
</div>
<div class="col-sm-11">
<nav>
<ul class="pagination">
<li><?php echo $this->tag->a($this->url->get("lff_customers/search"), "First", ['class' => 'page-link', 'id' => 'first']) ?></li>
<li><?php echo $this->tag->a($this->url->get("lff_customers/search?page=" . $page->getPrevious()), "Previous", ['class' => 'page-link', 'id' => 'previous']) ?></li>
<li><?php echo $this->tag->a($this->url->get("lff_customers/search?page=" . $page->getNext()), "Next", ['class' => 'page-link', 'id' => 'next']) ?></li>
<li><?php echo $this->tag->a($this->url->get("lff_customers/search?page=" . $page->getLast()), "Last", ['class' => 'page-link', 'id' => 'last']) ?></li>
</ul>
</nav>
</div>
</div>
<?php
/**
* @var \Phalcon\Mvc\View\Engine\Php $this
*/
?>
<div class="row">
<nav>
<ul class="pager">
<li class="previous"><?php echo $this->tag->a($this->url->get("lff_products"), "Go Back") ?></li>
</ul>
</nav>
</div>
<div class="page-header">
<h1>Edit lff_products</h1>
</div>
<?php echo $this->getContent(); ?>
<form action="<?= $this->url->get('lff_products/save') ?>" class="form-horizontal" method="post">
<div class="form-group">
<label for="fieldProdName" class="col-sm-2 control-label">Prod Of Name</label>
<div class="col-sm-10">
<?= $this->tag->inputText("prod_name", $lff_product->prod_name, ["size" => 30, "class" => "form-control", "id" => "fieldProdName"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldProdPrice" class="col-sm-2 control-label">Prod Of Price</label>
<div class="col-sm-10">
<?= $this->tag->inputNumeric("prod_price", $lff_product->prod_price, ["class" => "form-control", "id" => "fieldProdPrice"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldProdStock" class="col-sm-2 control-label">Prod Of Stock</label>
<div class="col-sm-10">
<?= $this->tag->inputNumeric("prod_stock", $lff_product->prod_stock, ["class" => "form-control", "id" => "fieldProdStock"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldProdStatus" class="col-sm-2 control-label">Prod Of Status</label>
<div class="col-sm-10">
<?= $this->tag->inputText("prod_status", $lff_product->prod_status, ["size" => 30, "class" => "form-control", "id" => "fieldProdStatus"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldCreatedAt" class="col-sm-2 control-label">Created</label>
<div class="col-sm-10">
<?= $this->tag->inputText("created_at", $lff_product->created_at, ["size" => 30, "class" => "form-control", "id" => "fieldCreatedAt"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldUpdatedAt" class="col-sm-2 control-label">Updated</label>
<div class="col-sm-10">
<?= $this->tag->inputText("updated_at", $lff_product->updated_at, ["size" => 30, "class" => "form-control", "id" => "fieldUpdatedAt"]) ?>
</div>
</div>
<?php echo $this->tag->inputHidden("id", $lff_product->prod_id) ?>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<?php echo $this->tag->inputSubmit("save", "Save", ['class' => "btn btn-primary"]) ?>
</div>
</div>
</form>
<?php
/**
* @var \Phalcon\Mvc\View\Engine\Php $this
*/
?>
<div class="page-header">
<h1>Search lff_products</h1>
<p><?php echo $this->tag->a($this->url->get("lff_products/new"), "Create lff_products") ?></p>
</div>
<?php echo $this->getContent() ?>
<?php echo $this->flashSession->output() ?>
<form action="<?= $this->url->get('lff_products/search') ?>" class="form-horizontal" method="get">
<div class="form-group">
<label for="fieldProdId" class="col-sm-2 control-label">Prod</label>
<div class="col-sm-10">
<?= $this->tag->inputNumeric("prod_id", $lff_product->prod_id, ["class" => "form-control", "id" => "fieldProdId"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldProdName" class="col-sm-2 control-label">Prod Of Name</label>
<div class="col-sm-10">
<?= $this->tag->inputText("prod_name", $lff_product->prod_name, ["size" => 30, "class" => "form-control", "id" => "fieldProdName"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldProdPrice" class="col-sm-2 control-label">Prod Of Price</label>
<div class="col-sm-10">
<?= $this->tag->inputNumeric("prod_price", $lff_product->prod_price, ["class" => "form-control", "id" => "fieldProdPrice"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldProdStock" class="col-sm-2 control-label">Prod Of Stock</label>
<div class="col-sm-10">
<?= $this->tag->inputNumeric("prod_stock", $lff_product->prod_stock, ["class" => "form-control", "id" => "fieldProdStock"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldProdStatus" class="col-sm-2 control-label">Prod Of Status</label>
<div class="col-sm-10">
<?= $this->tag->inputText("prod_status", $lff_product->prod_status, ["size" => 30, "class" => "form-control", "id" => "fieldProdStatus"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldCreatedAt" class="col-sm-2 control-label">Created</label>
<div class="col-sm-10">
<?= $this->tag->inputText("created_at", $lff_product->created_at, ["size" => 30, "class" => "form-control", "id" => "fieldCreatedAt"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldUpdatedAt" class="col-sm-2 control-label">Updated</label>
<div class="col-sm-10">
<?= $this->tag->inputText("updated_at", $lff_product->updated_at, ["size" => 30, "class" => "form-control", "id" => "fieldUpdatedAt"]) ?>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<?php echo $this->tag->inputSubmit("search", "Search", ["class" => "btn btn-primary"]) ?>
</div>
</div>
</form>
<?php
/**
* @var \Phalcon\Mvc\View\Engine\Php $this
*/
?>
<div class="row">
<nav>
<ul class="pager">
<li class="previous"><?php echo $this->tag->a($this->url->get("lff_products"), "Go Back") ?></li>
</ul>
</nav>
</div>
<div class="page-header">
<h1>Create lff_products</h1>
</div>
<?php echo $this->getContent(); ?>
<form action="<?= $this->url->get('lff_products/create') ?>" class="form-horizontal" method="post">
<div class="form-group">
<label for="fieldProdName" class="col-sm-2 control-label">Prod Of Name</label>
<div class="col-sm-10">
<?= $this->tag->inputText("prod_name", $lff_product->prod_name, ["size" => 30, "class" => "form-control", "id" => "fieldProdName"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldProdPrice" class="col-sm-2 control-label">Prod Of Price</label>
<div class="col-sm-10">
<?= $this->tag->inputNumeric("prod_price", $lff_product->prod_price, ["class" => "form-control", "id" => "fieldProdPrice"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldProdStock" class="col-sm-2 control-label">Prod Of Stock</label>
<div class="col-sm-10">
<?= $this->tag->inputNumeric("prod_stock", $lff_product->prod_stock, ["class" => "form-control", "id" => "fieldProdStock"]) ?>
</div>
</div>
<div class="form-group">
<label for="fieldProdStatus" class="col-sm-2 control-label">Prod Of Status</label>
<div class="col-sm-10">
<?= $this->tag->inputText("prod_status", $lff_product->prod_status, ["size" => 30, "class" => "form-control", "id" => "fieldProdStatus"]) ?>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<?php echo $this->tag->inputSubmit("save", "Save", ['class' => "btn btn-primary"]) ?>
</div>
</div>
</form>
<?php
/**
* @var \Phalcon\Mvc\View\Engine\Php $this
*/
?>
<div class="row">
<nav>
<ul class="pager">
<li class="previous"><?php echo $this->tag->a($this->url->get("lff_products/index"), "Go Back"); ?></li>
<li class="next"><?php echo $this->tag->a($this->url->get("lff_products/new"), "Create"); ?></li>
</ul>
</nav>
</div>
<div class="page-header">
<h1>Search result</h1>
</div>
<?php echo $this->getContent(); ?>
<div class="row">
<table class="table table-bordered">
<thead>
<tr>
<th>Prod</th>
<th>Prod Of Name</th>
<th>Prod Of Price</th>
<th>Prod Of Stock</th>
<th>Prod Of Status</th>
<th>Created</th>
<th>Updated</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($page->getItems() as $lff_product): ?>
<tr>
<td><?php echo $lff_product->prod_id; ?></td>
<td><?php echo $lff_product->prod_name; ?></td>
<td><?php echo $lff_product->prod_price; ?></td>
<td><?php echo $lff_product->prod_stock; ?></td>
<td><?php echo $lff_product->prod_status; ?></td>
<td><?php echo $lff_product->created_at; ?></td>
<td><?php echo $lff_product->updated_at; ?></td>
<td><?php echo $this->tag->a($this->url->get("lff_products/edit/" . $lff_product->prod_id), "Edit"); ?></td>
<td><?php echo $this->tag->a($this->url->get("lff_products/delete/" . $lff_product->prod_id), "Delete"); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="row">
<div class="col-sm-1">
<p class="pagination" style="line-height: 1.42857;padding: 6px 12px;">
<?php echo $page->getCurrent(), "/", $page->getTotalItems() ?>
</p>
</div>
<div class="col-sm-11">
<nav>
<ul class="pagination">
<li><?php echo $this->tag->a($this->url->get("lff_products/search"), "First", ['class' => 'page-link', 'id' => 'first']) ?></li>
<li><?php echo $this->tag->a($this->url->get("lff_products/search?page=" . $page->getPrevious()), "Previous", ['class' => 'page-link', 'id' => 'previous']) ?></li>
<li><?php echo $this->tag->a($this->url->get("lff_products/search?page=" . $page->getNext()), "Next", ['class' => 'page-link', 'id' => 'next']) ?></li>
<li><?php echo $this->tag->a($this->url->get("lff_products/search?page=" . $page->getLast()), "Last", ['class' => 'page-link', 'id' => 'last']) ?></li>
</ul>
</nav>
</div>
</div>
<div class="card">
<div class="card-header">
<h3>成绩管理</h3>
</div>
<div class="card-body">
<form id="scoreManageForm">
<!-- 学期选择 -->
<div class="form-group mb-4">
<label for="term_id" class="form-label">
选择学期 <span class="required-mark">*</span>
</label>
<select class="form-select" id="term_id" name="term_id" required>
<option value="">请选择学期</option>
<?php if (isset($terms) && count($terms) > 0): ?>
<?php foreach ($terms as $term): ?>
<option value="<?= htmlspecialchars($term->term_id) ?>">
<?= htmlspecialchars($term->term_name) ?>
</option>
<?php endforeach; ?>
<?php endif; ?>
</select>
</div>
<!-- 课程选择(初始禁用) -->
<div class="form-group mb-4">
<label for="course_id" class="form-label">
选择课程 <span class="required-mark">*</span>
</label>
<select class="form-select" id="course_id" name="course_id" disabled required>
<option value="">请先选择学期</option>
</select>
</div>
<!-- 操作按钮 -->
<div class="btn-group">
<button type="submit" class="btn btn-primary" id="enterScoreBtn" disabled>
成绩录入
</button>
</div>
</form>
</div>
</div>
\ No newline at end of file
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<form action="<?php echo $this->url->get('lff_student/create') ?>" method="post" class="mt-3">
<div class="mb-3">
<label for="username" class="form-label">学生姓名 <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="username" name="username"
required placeholder="请输入真实姓名" pattern="^[\u4e00-\u9fa5]{2,20}$">
</div>
<div class="mb-3">
<label for="college_id" class="form-label">所属学院 <span class="text-danger">*</span></label>
<select class="form-select" id="college_id" name="college_id" required>
<option value="">请选择学院</option>
<?php foreach ($colleges as $college): ?>
<option value="<?php echo $college->college_id ?>">
<?php echo htmlspecialchars($college->college_name) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="mb-3">
<label for="clazz" class="form-label">班级 <span class="text-danger">*</span></label>
<input type="text" class="form-control" id="clazz" name="clazz"
required placeholder="如:计科2401班">
</div>
<button type="submit" class="btn btn-primary">提交</button>
<a href="<?php echo $this->url->get('lff_student/studentList') ?>" class="btn btn-secondary ms-2">取消</a>
</form>
\ No newline at end of file
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<div class="admin-edit-container">
<h2>修改学生信息</h2>
<form action="<?php echo $this->url->get("lff_student/save") ?>" method="post" class="admin-edit-form">
<input type="hidden" name="user_id" value="<?php echo $studentInfo->user_id ?? 0 ?>">
<div class="form-group">
<label>管理员账号</label>
<input type="text"
value="<?php echo htmlspecialchars($studentInfo->user_account ?? '') ?>"
id="user_account"
name="user_account"
readonly
class="readonly-input"
title="账号为唯一标识,不可修改">
</div>
<div class="form-group">
<label for="username">管理员姓名 <span class="required">*</span></label>
<input type="text"
id="username"
name="username"
required
value="<?php echo htmlspecialchars($studentInfo->username ?? '') ?>"
placeholder="请输入真实姓名"
maxlength="20"
pattern="^[\u4e00-\u9fa5]+$"
title="姓名仅支持中文">
</div>
<div class="form-group">
<label for="college_id">所属学院 <span class="required">*</span></label>
<select name="college_id" id="college_id" required>
<!-- 后端传递的学院列表,循环渲染选项 -->
<?php foreach ($collegeList as $college): ?>
<option value="<?php echo $college->college_id ?>"
<?php echo (isset($studentInfo->college_id) && $studentInfo->college_id == $college->college_id) ? 'selected' : '' ?>>
<?php echo htmlspecialchars($college->college_name) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="form-group">
<label for="clazz">班级 <span class="required">*</span></label>
<input type="text"
id="clazz"
name="clazz"
required
value="<?php echo htmlspecialchars($studentInfo->clazz ?? '') ?>"
placeholder="请输入班级(如:计科2401班)"
maxlength="50"
title="班级名称支持中文、数字和字符组合">
</div>
<div class="form-group">
<label>入学年份</label>
<input type="text"
value="<?php echo htmlspecialchars($studentInfo->admission_year ?? '') ?>"
readonly
class="readonly-input"
title="入学年份不可修改">
</div>
<div class="password-reset-section">
<h3>密码重置</h3>
<p class="reset-hint">勾选后将密码重置为系统默认初始密码(默认密码:Xs@ + 入学年份),需重新告知学生</p>
<div class="form-group">
<label>
<input type="checkbox" name="reset_password" id="reset_password" value="1">
确认重置密码
</label>
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn-save">保存修改</button>
<a href="<?php echo $this->url->get('lff_student/studentList') ?>" class="btn-cancel">取消</a>
</div>
</form>
</div>
\ No newline at end of file
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<div class="student-management">
<h2>学生账号管理</h2>
<p><?php echo isset($totalCount) ? $totalCount : 0 ?> 名学生</p>
<a href="<?php echo $this->url->get('lff_student/addStudent') ?>" class="btn-add">
<button>新增学生</button>
</a>
<table class="student-table" border="1" cellpadding="8" cellspacing="0" width="100%">
<tr>
<th>ID</th>
<th>姓名</th>
<th>学院</th>
<th>入学年份</th>
<th>班级</th>
<th>账号状态</th>
<th>锁定状态</th>
<th>操作</th>
</tr>
<?php if (!empty($students)) { ?>
<?php foreach ($students as $student) { ?>
<tr>
<td><?php echo htmlspecialchars($student->user_id ?? '') ?></td>
<td><?php echo htmlspecialchars($student->username ?? '') ?></td>
<td><?php echo htmlspecialchars($student->college_name ?? '未分配') ?></td>
<td><?php echo htmlspecialchars($student->admission_year ?? '未填写') ?></td>
<td><?php echo htmlspecialchars($student->clazz ?? '未分配') ?></td>
<td>
<?php if (isset($student->is_enable) && $student->is_enable == 1) { ?>
<span class="status-normal" style="color: green;">启用</span>
<?php } else { ?>
<span class="status-disabled" style="color: red;">禁用</span>
<?php } ?>
</td>
<td>
<?php if (isset($student->is_lock) && $student->is_lock == 1) { ?>
<span class="status-locked" style="color: red;">已锁定</span>
<?php } else { ?>
<span class="status-unlocked" style="color: green;">未锁定</span>
<?php } ?>
</td>
<td class="operation-buttons">
<!-- 编辑按钮 -->
<a href="<?php echo $this->url->get("lff_student/editStudent/" . $student->user_id) ?>">
编辑
</a>
|
<!-- 启用/禁用按钮 -->
<?php if (isset($student->is_enable) && $student->is_enable == 1) { ?>
<a href="<?php echo $this->url->get('lff_student/studentDisable/' . $student->user_id ) ?>"
onclick="return confirm('确定要禁用该学生账号吗?')">
禁用
</a>
<?php } else { ?>
<a href="<?php echo $this->url->get('lff_student/studentEnable/' . $student->user_id ) ?>"
onclick="return confirm('确定要启用该学生账号吗?')">
启用
</a>
<?php } ?>
|
<!-- 锁定/解锁按钮 -->
<?php if (isset($student->is_lock) && $student->is_lock == 1) { ?>
<a href="<?php echo $this->url->get('lff_student/studentUnlock', ['id' => $student->user_id ?? 0]) ?>"
onclick="return confirm('确定要解锁该学生账号吗?')">
解锁
</a>
<?php } else { ?>
<a href="<?php echo $this->url->get('lff_student/studentLock', ['id' => $student->user_id ?? 0]) ?>"
onclick="return confirm('确定要锁定该学生账号吗?')">
锁定
</a>
<?php } ?>
|
<!-- 删除按钮 -->
<a href="<?php echo $this->url->get('lff_student/deleteStudent/' . ($student->user_id ?? 0)) ?>"
onclick="return confirm('确定要删除该学生吗?删除后数据不可恢复!')"
style="color: #dc3545;">
删除
</a>
</td>
</tr>
<?php } ?>
<?php } else { ?>
<tr>
<td colspan="8" align="center">暂无学生数据</td>
</tr>
<?php } ?>
</table>
</div>
\ No newline at end of file
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<h1>教学管理系统 - 添加教师</h1>
<div style="margin-bottom: 20px;">
<?php $auth = $this->session->get('auth'); ?>
<p>当前登录:<?php echo $auth['user_account'] ?? '未知用户' ?></p>
<a href="<?php echo $this->url->get('login/logout') ?>">退出登录</a>
</div>
<form method="post" action="<?php echo $this->url->get('lff_teacher/create') ?>" style="max-width: 800px; margin: 0 auto;">
<table border="0" cellpadding="10" cellspacing="0" style="width: 100%;">
<!-- 教师姓名(必填) -->
<tr>
<td style="width: 150px; text-align: right; font-weight: bold;">教师姓名:</td>
<td>
<input type="text" name="username" required
style="padding: 6px; width: 300px;"
placeholder="请输入教师姓名(必填)">
</td>
</tr>
<tr>
<td style="text-align: right; font-weight: bold;">所属学院:</td>
<td>
<select name="college_id" required
style="padding: 6px; width: 314px;">
<option value="">请选择学院</option>
<?php foreach ($colleges as $college): ?>
<option value="<?php echo $college['college_id'] ?>">
<?php echo $college['college_name'] ?>
</option>
<?php endforeach; ?>
</select>
</td>
</tr>
<tr>
<td style="text-align: right; font-weight: bold;">联系邮箱:</td>
<td>
<input type="email" name="email"
style="padding: 6px; width: 300px;"
placeholder="请输入联系邮箱(选填)">
</td>
</tr>
<tr>
<td style="text-align: right; font-weight: bold;">账号状态:</td>
<td>
<label style="margin-right: 20px;">
<input type="radio" name="is_enable" value="1" checked> 启用
</label>
<label>
<input type="radio" name="is_enable" value="0"> 禁用
</label>
</td>
</tr>
<tr>
<td colspan="2" style="text-align: center;">
<button type="submit" style="padding: 8px 20px; background: #4CAF50; color: white; border: none; border-radius: 4px; cursor: pointer;">
提交添加
</button>
<a href="<?php echo $this->url->get('lff_teacher/teacherList') ?>"
style="margin-left: 20px; padding: 8px 20px; background: #f0f0f0; text-decoration: none; border-radius: 4px;">
返回教师列表
</a>
</td>
</tr>
</table>
</form>
\ No newline at end of file
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<div class="admin-edit-container">
<h2>修改教师信息</h2>
<p class="subtitle">账号为唯一标识,不可修改</p>
<form action="<?php echo $this->url->get("lff_teacher/save") ?>" method="post" class="admin-edit-form">
<input type="hidden" name="user_id" value="<?php echo $teacherInfo->user_id ?? 0 ?>">
<div class="form-group">
<label>管理员账号</label>
<input type="text"
value="<?php echo htmlspecialchars($teacherInfo->user_account ?? '') ?>"
id="user_account"
name="user_account"
readonly
class="readonly-input"
title="账号为唯一标识,不可修改">
</div>
<div class="form-group">
<label for="username">管理员姓名 <span class="required">*</span></label>
<input type="text"
id="username"
name="username"
required
value="<?php echo htmlspecialchars($teacherInfo->username ?? '') ?>"
placeholder="请输入真实姓名"
maxlength="20"
pattern="^[\u4e00-\u9fa5]+$"
title="姓名仅支持中文">
</div>
<div class="form-group">
<label for="email">联系邮箱 <span class="required">*</span></label>
<input type="email"
id="email"
name="email"
required
value="<?php echo htmlspecialchars($teacherInfo->email ?? '') ?>"
placeholder="请输入有效的邮箱地址"
maxlength="50">
</div>
<!-- 4. 所属学院(可修改,改为下拉框) -->
<div class="form-group">
<label for="college_id">所属学院 <span class="required">*</span></label>
<select name="college_id" id="college_id" required>
<!-- 后端传递的学院列表,循环渲染选项 -->
<?php foreach ($collegeList as $college): ?>
<option value="<?php echo $college->college_id ?>"
<?php echo (isset($teacherInfo->college_id) && $teacherInfo->college_id == $college->college_id) ? 'selected' : '' ?>>
<?php echo htmlspecialchars($college->college_name) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<!-- 5. 入学年份(不可修改,保留展示) -->
<div class="form-group">
<label>入学年份</label>
<input type="text"
value="<?php echo htmlspecialchars($teacherInfo->admission_year ?? '') ?>"
readonly
class="readonly-input"
title="入学年份不可修改">
</div>
<!-- 6. 账号状态(可修改:启用/禁用) -->
<div class="form-group">
<label for="is_enable">账号状态</label>
<select name="is_enable" id="is_enable" required>
<option value="1" <?php echo (isset($teacherInfo->is_enable) && $teacherInfo->is_enable == 1) ? 'selected' : '' ?>>
启用(可正常登录)
</option>
<option value="0" <?php echo (isset($teacherInfo->is_enable) && $teacherInfo->is_enable == 0) ? 'selected' : '' ?>>
禁用(禁止登录)
</option>
</select>
</div>
<!-- 7. 账号锁定状态(可修改:未锁定/已锁定) -->
<div class="form-group">
<label for="is_lock">账号锁定状态</label>
<select name="is_lock" id="is_lock" required>
<option value="0" <?php echo (isset($teacherInfo->is_lock) && $teacherInfo->is_lock == 0) ? 'selected' : '' ?>>
未锁定(正常使用)
</option>
<option value="1" <?php echo (isset($teacherInfo->is_lock) && $teacherInfo->is_lock == 1) ? 'selected' : '' ?>>
已锁定(禁止登录,需解锁后使用)
</option>
</select>
</div>
<!-- 8. 密码重置区域(保留原有功能) -->
<div class="password-reset-section">
<h3>密码重置</h3>
<p class="reset-hint">勾选后将密码重置为系统默认初始密码(默认密码:Js@ + 入职年份),需重新告知管理员</p>
<div class="form-group">
<label>
<input type="checkbox" name="reset_password" id="reset_password" value="1">
确认重置密码
</label>
</div>
</div>
<!-- 9. 操作按钮 -->
<div class="form-actions">
<button type="submit" class="btn-save">保存修改</button>
<a href="<?php echo $this->url->get('lff_teacher/teacherList') ?>" class="btn-cancel">取消</a>
</div>
</form>
</div>
\ No newline at end of file
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<div class="teacher-management">
<h2>教师信息管理</h2>
<p><?php echo isset($totalCount) ? $totalCount : 0 ?> 位教师</p>
<a href="<?php echo $this->url->get('lff_teacher/addTeacher') ?>" class="btn-add">
<button>新增教师</button>
</a>
<table class="teacher-table" border="1" cellpadding="8" cellspacing="0" width="100%">
<tr>
<th>姓名</th>
<th>所属学院</th>
<th>邮箱</th>
<th>入学年份</th>
<th>状态</th>
<th>锁定状态</th>
<th>创建时间</th>
<th>操作</th>
</tr>
<?php if (!empty($teachers)) { ?>
<?php foreach ($teachers as $teacher) { ?>
<tr>
<td><?php echo htmlspecialchars($teacher->username ?? '') ?></td>
<!-- 新增:所属学院名称 -->
<td><?php echo htmlspecialchars($teacher->college_name ?? '未设置') ?></td>
<!-- 新增:邮箱 -->
<td><?php echo htmlspecialchars($teacher->email ?? '未设置') ?></td>
<!-- 新增:入学年份 -->
<td><?php echo htmlspecialchars($teacher->admission_year ?? '未设置') ?></td>
<!-- 状态列(原状态列调整为启用/禁用状态) -->
<td>
<?php if (isset($teacher->is_enable) && $teacher->is_enable == 1) { ?>
<span class="status-normal" style="color: green;">正常</span>
<?php } else { ?>
<span class="status-disabled" style="color: red;">禁用</span>
<?php } ?>
</td>
<!-- 锁定状态列(拆分原状态列) -->
<td>
<?php if (isset($teacher->is_lock) && $teacher->is_lock == 1) { ?>
<span class="status-normal" style="color: red;">锁定</span>
<?php } else { ?>
<span class="status-disabled" style="color: green;">未锁定</span>
<?php } ?>
</td>
<td><?php echo htmlspecialchars($teacher->create_time ?? '') ?></td>
<td class="operation-buttons">
<!-- 编辑按钮 -->
<a href="<?php echo $this->url->get("lff_teacher/editTeacher/" . $teacher->user_id) ?>">
编辑
</a>
|
<!-- 启用/禁用按钮 -->
<?php if (isset($teacher->is_enable) && $teacher->is_enable == 1) { ?>
<a href="<?php echo $this->url->get('lff_teacher/teacherDisable/' . $teacher->user_id) ?>"
onclick="return confirm('确定要禁用该教师吗?')">
禁用
</a>
<?php } else { ?>
<a href="<?php echo $this->url->get('lff_teacher/teacherEnable/' . $teacher->user_id) ?>"
onclick="return confirm('确定要启用该教师吗?')">
启用
</a>
<?php } ?>
|
<!-- 删除按钮 -->
<a href="<?php echo $this->url->get('lff_teacher/deleteTeacher/' . ($teacher->user_id ?? 0)) ?>"
onclick="return confirm('确定要删除该教师吗?删除后数据不可恢复!')"
style="color: #dc3545;">
删除
</a>
</td>
</tr>
<?php } ?>
<?php } else { ?>
<tr>
<td colspan="10" align="center">暂无教师数据</td>
</tr>
<?php } ?>
</table>
</div>
\ No newline at end of file
<div style="color: red;">
<?php echo $this->flashSession->output() ?>
</div>
<h1>用户登录</h1>
<form action="<?php echo $this->url->get('login/doLogin') ?>" method="post">
<div>
<label>用户名:</label>
<!-- 从Cookie自动填充账号(若存在) -->
<input type="text" name="user_account"
value="<?php echo $this->cookies->has('remember_account') ? $this->cookies->get('remember_account')->getValue() : '' ?>"
required>
</div>
<div>
<label>密码:</label>
<input type="password" name="password" required>
</div>
<div>
<label>
<input type="checkbox" name="remember_account" value="1"> 记住账号(7天)
</label>
</div>
<div>
<label>
<input type="checkbox" name="auto_login" value="1"> 自动登录(24小时,个人设备推荐)
</label>
</div>
<div>
<button type="submit">登录</button>
</div>
</form>
\ No newline at end of file
<html><body><h1>Mod-Rewrite is not enabled</h1><p>Please enable rewrite module on your web server to continue</body></html>
\ No newline at end of file
AddDefaultCharset UTF-8
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?_url=/$1 [QSA,L]
</IfModule>
\ No newline at end of file
<?php
declare(strict_types=1);
use Phalcon\Di\FactoryDefault;
error_reporting(E_ALL);
ini_set('display_errors', "1"); // 允许在浏览器中显示错误
define('BASE_PATH', dirname(__DIR__));
define('APP_PATH', BASE_PATH . '/app');
try {
/**
* The FactoryDefault Dependency Injector automatically registers
* the services that provide a full stack framework.
*/
$di = new FactoryDefault();
/**
* Read services
*/
include APP_PATH . '/config/services.php';
/**
* Handle routes
*/
include APP_PATH . '/config/router.php';
/**
* Get config service for use in inline setup below
*/
$config = $di->getConfig();
// public/index.php 中添加(通常在文件顶部)
require_once __DIR__ . '/../vendor/autoload.php';
/**
* Include Autoloader
*/
include APP_PATH . '/config/loader.php';
/**
* Handle the request
*/
$application = new \Phalcon\Mvc\Application($di);
echo $application->handle($_SERVER['REQUEST_URI'])->getContent();
} catch (\Exception $e) {
echo $e->getMessage() . '<br>';
echo '<pre>' . $e->getTraceAsString() . '</pre>';
}
<?php
// autoload.php @generated by Composer
if (PHP_VERSION_ID < 50600) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
$err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL;
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, $err);
} elseif (!headers_sent()) {
echo $err;
}
}
throw new RuntimeException($err);
}
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInit3b41b5a9e577b9df749d30b01302c2df::getLoader();
#!/usr/bin/env php
<?php
/**
* Proxy PHP file generated by Composer
*
* This file includes the referenced bin path (../overtrue/pinyin/bin/pinyin)
* using a stream wrapper to prevent the shebang from being output on PHP<8
*
* @generated
*/
namespace Composer;
$GLOBALS['_composer_bin_dir'] = __DIR__;
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';
if (PHP_VERSION_ID < 80000) {
if (!class_exists('Composer\BinProxyWrapper')) {
/**
* @internal
*/
final class BinProxyWrapper
{
private $handle;
private $position;
private $realpath;
public function stream_open($path, $mode, $options, &$opened_path)
{
// get rid of phpvfscomposer:// prefix for __FILE__ & __DIR__ resolution
$opened_path = substr($path, 17);
$this->realpath = realpath($opened_path) ?: $opened_path;
$opened_path = $this->realpath;
$this->handle = fopen($this->realpath, $mode);
$this->position = 0;
return (bool) $this->handle;
}
public function stream_read($count)
{
$data = fread($this->handle, $count);
if ($this->position === 0) {
$data = preg_replace('{^#!.*\r?\n}', '', $data);
}
$this->position += strlen($data);
return $data;
}
public function stream_cast($castAs)
{
return $this->handle;
}
public function stream_close()
{
fclose($this->handle);
}
public function stream_lock($operation)
{
return $operation ? flock($this->handle, $operation) : true;
}
public function stream_seek($offset, $whence)
{
if (0 === fseek($this->handle, $offset, $whence)) {
$this->position = ftell($this->handle);
return true;
}
return false;
}
public function stream_tell()
{
return $this->position;
}
public function stream_eof()
{
return feof($this->handle);
}
public function stream_stat()
{
return array();
}
public function stream_set_option($option, $arg1, $arg2)
{
return true;
}
public function url_stat($path, $flags)
{
$path = substr($path, 17);
if (file_exists($path)) {
return stat($path);
}
return false;
}
}
}
if (
(function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true))
|| (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper'))
) {
return include("phpvfscomposer://" . __DIR__ . '/..'.'/overtrue/pinyin/bin/pinyin');
}
}
return include __DIR__ . '/..'.'/overtrue/pinyin/bin/pinyin';
Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
);
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
);
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
return array(
'Overtrue\\Pinyin\\' => array($vendorDir . '/overtrue/pinyin/src'),
);
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit3b41b5a9e577b9df749d30b01302c2df
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
require __DIR__ . '/platform_check.php';
spl_autoload_register(array('ComposerAutoloaderInit3b41b5a9e577b9df749d30b01302c2df', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit3b41b5a9e577b9df749d30b01302c2df', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInit3b41b5a9e577b9df749d30b01302c2df::getInitializer($loader));
$loader->register(true);
return $loader;
}
}
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInit3b41b5a9e577b9df749d30b01302c2df
{
public static $prefixLengthsPsr4 = array (
'O' =>
array (
'Overtrue\\Pinyin\\' => 16,
),
);
public static $prefixDirsPsr4 = array (
'Overtrue\\Pinyin\\' =>
array (
0 => __DIR__ . '/..' . '/overtrue/pinyin/src',
),
);
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixLengthsPsr4 = ComposerStaticInit3b41b5a9e577b9df749d30b01302c2df::$prefixLengthsPsr4;
$loader->prefixDirsPsr4 = ComposerStaticInit3b41b5a9e577b9df749d30b01302c2df::$prefixDirsPsr4;
$loader->classMap = ComposerStaticInit3b41b5a9e577b9df749d30b01302c2df::$classMap;
}, null, ClassLoader::class);
}
}
{
"packages": [
{
"name": "overtrue/pinyin",
"version": "6.0.0",
"version_normalized": "6.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/overtrue/pinyin.git",
"reference": "729422bec2c9d3aa1e54e8d65afdab954f52014f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/overtrue/pinyin/zipball/729422bec2c9d3aa1e54e8d65afdab954f52014f",
"reference": "729422bec2c9d3aa1e54e8d65afdab954f52014f",
"shasum": ""
},
"require": {
"php": ">=8.1"
},
"require-dev": {
"brainmaestro/composer-git-hooks": "^3.0",
"laravel/pint": "^1.10",
"nunomaduro/termwind": "^2.0",
"phpunit/phpunit": "^12.0.21"
},
"time": "2025-09-08T10:34:18+00:00",
"bin": [
"bin/pinyin"
],
"type": "library",
"extra": {
"hooks": {
"pre-push": [
"composer pint",
"composer test"
],
"pre-commit": [
"composer pint",
"composer test"
]
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Overtrue\\Pinyin\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "overtrue",
"email": "anzhengchao@gmail.com",
"homepage": "http://github.com/overtrue"
}
],
"description": "Chinese to pinyin translator.",
"homepage": "https://github.com/overtrue/pinyin",
"keywords": [
"Chinese",
"Pinyin",
"cn2pinyin"
],
"support": {
"issues": "https://github.com/overtrue/pinyin/issues",
"source": "https://github.com/overtrue/pinyin/tree/6.0.0"
},
"funding": [
{
"url": "https://github.com/overtrue",
"type": "github"
}
],
"install-path": "../overtrue/pinyin"
}
],
"dev": true,
"dev-package-names": []
}
<?php return array(
'root' => array(
'name' => '__root__',
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => null,
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev' => true,
),
'versions' => array(
'__root__' => array(
'pretty_version' => '1.0.0+no-version-set',
'version' => '1.0.0.0',
'reference' => null,
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev_requirement' => false,
),
'overtrue/pinyin' => array(
'pretty_version' => '6.0.0',
'version' => '6.0.0.0',
'reference' => '729422bec2c9d3aa1e54e8d65afdab954f52014f',
'type' => 'library',
'install_path' => __DIR__ . '/../overtrue/pinyin',
'aliases' => array(),
'dev_requirement' => false,
),
),
);
<?php
// platform_check.php @generated by Composer
$issues = array();
if (!(PHP_VERSION_ID >= 80100)) {
$issues[] = 'Your Composer dependencies require a PHP version ">= 8.1.0". You are running ' . PHP_VERSION . '.';
}
if ($issues) {
if (!headers_sent()) {
header('HTTP/1.1 500 Internal Server Error');
}
if (!ini_get('display_errors')) {
if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') {
fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL);
} elseif (!headers_sent()) {
echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL;
}
}
throw new \RuntimeException(
'Composer detected issues in your platform: ' . implode(' ', $issues)
);
}
version: 2
updates:
- package-ecosystem: composer
directory: "/"
schedule:
interval: daily
time: "21:00"
open-pull-requests-limit: 10
ignore:
- dependency-name: phpunit/phpunit
versions:
- ">= 8.a, < 9"
name: Test
on: [push, pull_request]
jobs:
phpunit:
name: PHP-${{ matrix.php_version }}-${{ matrix.perfer }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
php_version:
- 8.1
- 8.2
- 8.3
- 8.4
- 8.5
perfer:
- stable
- lowest
steps:
- uses: actions/checkout@master
- name: Install Dependencies
run: composer update --prefer-dist --no-interaction --no-suggest --prefer-${{ matrix.perfer }}
- name: Run PHPUnit
run: ./vendor/bin/phpunit
## [6.0.0] - 2025-09-09
### 🚀 Major Features
- **性能优化策略系统**: 全新的转换策略架构,针对不同使用场景提供最优性能
- **内存优化策略** (Memory Optimized): 占用 ~400KB 内存,适合 Web 请求和内存受限环境
- **缓存策略** (Cached): 占用 ~4MB 内存,重复转换性能提升 2-3 倍,适合批处理任务
- **智能策略** (Smart): 占用 600KB-1.5MB 内存,根据文本复杂度自适应加载
- **ConverterFactory**: 新的工厂模式管理转换器实例和策略选择
- **自动策略选择**: 根据运行环境(Web/CLI/内存限制)自动推荐最佳策略
- **性能基准测试工具**: 内置的策略性能对比和监控工具
- **内存监控**: 支持实时监控内存使用情况和性能指标
### 🔧 API Changes
- 新增 `Pinyin::useMemoryOptimized()` - 切换到内存优化策略
- 新增 `Pinyin::useCached()` - 切换到缓存策略
- 新增 `Pinyin::useSmart()` - 切换到智能策略
- 新增 `Pinyin::useAutoStrategy()` - 自动选择最佳策略
- 新增 `Pinyin::clearCache()` - 清理所有转换器缓存
- 新增 `ConverterFactory::make($strategy)` - 创建指定策略的转换器
- 新增 `ConverterFactory::recommend()` - 获取推荐策略
- 新增 `ConverterFactory::getStrategiesInfo()` - 获取所有策略信息
### ⚡ Performance Improvements
- **内存使用优化**: 默认内存占用从 ~4MB 降低到 ~400KB
- **转换速度提升**: 缓存策略下重复转换速度提升 2-3 倍
- **智能加载**: 根据文本复杂度动态调整数据加载策略
- **按需加载**: 内存优化策略仅在需要时加载转换数据
### 📊 Benchmark & Monitoring
- 新增 `php benchmark/run.php` - 运行性能基准测试
- 新增 `php benchmark/compare-strategies.php` - 策略对比测试
- 新增基准测试文档 `docs/benchmark-guide.md`
- 支持内存使用情况实时监控
#### 运行基准测试
```bash
# 运行标准基准测试,显示所有方法的性能表现
php benchmark/run.php
# 详细的策略对比测试,对比三种策略的性能差异
php benchmark/compare-strategies.php
```
基准测试会显示:
- 每种策略的执行时间和内存使用情况
- 不同文本长度下的性能表现
- 策略之间的性能对比和推荐场景
### 🔄 Breaking Changes
- **默认策略变更**: 从全缓存改为内存优化策略,降低默认内存占用
- **转换器架构重构**: 引入策略模式,旧的直接实例化转换器方式仍兼容
- **性能特征变化**: 首次转换可能略慢,但内存占用显著降低
### 🔧 Backward Compatibility
- 完全兼容 5.x API,现有代码无需修改即可使用
- `heteronym()` 方法(5.3.3+ 引入)继续保持兼容
- 所有原有的转换方法 (`sentence`, `phrase`, `chars` 等) 保持不变
### 📚 Documentation
- 更新 README.md 增加性能优化策略说明
- 新增性能对比表格和使用建议
- 新增基准测试指南
- 新增性能优化最佳实践
### 🔧 Development Tools
- 新增性能基准测试脚本
- 新增策略对比工具
- 增强命令行工具支持策略选择
### 🛠️ Migration Guide
从 5.x 升级到 6.0 非常简单,所有现有代码都能正常工作:
#### 无需任何修改(推荐)
```php
// 5.x 和 6.x 都能正常工作
Pinyin::sentence('你好世界');
// 6.x 默认使用内存优化策略,内存占用更低
```
#### 保持 5.x 完全相同的性能特征
```php
// 如果你需要与 5.x 完全相同的高性能(高内存占用)
Pinyin::useCached(); // 一次设置,全局生效
Pinyin::sentence('你好世界');
```
#### 使用新的性能优化特性
```php
// 自动选择最佳策略(推荐用于新项目)
Pinyin::useAutoStrategy();
// 或者根据场景手动选择:
// Web 应用(内存受限)
Pinyin::useMemoryOptimized();
// 批处理任务(性能优先)
Pinyin::useCached();
// 通用场景(平衡)
Pinyin::useSmart();
```
#### 性能监控和优化
```php
// 监控内存使用
$initialMemory = memory_get_usage();
$result = Pinyin::sentence('测试文本');
$memoryUsed = memory_get_usage() - $initialMemory;
echo "内存使用: " . round($memoryUsed / 1024, 2) . " KB";
// 批处理完成后清理缓存
Pinyin::useCached();
// ... 批量处理 ...
Pinyin::clearCache(); // 释放内存
```
### 💡 Performance Comparison
| 策略 | 内存占用 | 首次转换 | 重复转换 | 推荐场景 |
|-----|---------|---------|---------|---------|
| Memory Optimized | ~400KB | 中等 | 中等 | Web 请求、内存受限环境 |
| Cached | ~4MB | 慢 | **最快** (2-3x) | 批处理、长时运行进程 |
| Smart | 600KB-1.5MB | 快 | 快 | 通用场景、自动优化 |
基于 1000 次转换的基准测试结果:
| 文本长度 | Memory Optimized | Cached | Smart |
|---------|-----------------|--------|-------|
| 短文本 (<10字) | 1.2ms | 0.5ms | 0.8ms |
| 中等文本 (10-50字) | 3.5ms | 1.2ms | 2.1ms |
| 长文本 (>100字) | 8.7ms | 3.1ms | 5.2ms |
## [5.3.4] - 2025-03-16
### 🚀 Features
- Resolved #211
### ⚙️ Miscellaneous Tasks
- Format
## [5.3.3] - 2024-08-01
### 🚀 Features
- 使用 heteronym 代替 polyphonic 多音字 #184
- 取首字母时,能否保留完整的英文 #199
### 🐛 Bug Fixes
- 修复 琢 的音频顺序 #207
- 补充案例 #207
- Tests
- Tests
## [5.3.2] - 2024-03-19
### 🚀 Features
- 取首字母时,能否保留完整的英文 #199
## [5.3.1] - 2024-03-19
### 🐛 Bug Fixes
- 「仆区」应该读 pú ōu 而非 pú qū #200
- Tests #200
## [5.3.0] - 2023-10-27
### 🚀 Features
- 添加sentenceFull,支持保留其他字符 (#198)
- Full sentence, #198
## [5.2.2] - 2023-09-27
### ⚙️ Miscellaneous Tasks
- Bin
## [5.2.1] - 2023-06-17
### 🐛 Bug Fixes
- Bin
## [5.2.0] - 2023-06-12
### 🚀 Features
- 增加 Pinyin::polyphonesAsArray. fixed #195
### 📚 Documentation
- 更新文档提示
- 更新文档提示
- 更新文档提示
## [5.1.0] - 2023-04-27
### 💼 Other
- 移除错误语法 (#190)
## [5.0.0] - 2022-07-24
### 🐛 Bug Fixes
- 优化符号匹配规则
## [1.0-beta] - 2014-07-16
The MIT License (MIT)
Copyright (c) 2014 安正超
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
\ No newline at end of file
#!/usr/bin/env php
<?php
require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/utils.php';
use Overtrue\Pinyin\Pinyin;
$methods = ['sentence','fullSentence','name','passportName','phrase','permalink','heteronym','heteronymAsList','chars','abbr','nameAbbr'];
$method = 'sentence';
$inputOptions = [];
$methodAsString = implode('/', $methods);
$help = <<<"HELP"
Usage:
./pinyin [chinese] [method] [options]
Options:
-j, --json 输出 JSON 格式.
-c, --compact 不格式化输出 JSON.
-m, --method=[method] 转换方式可选{$methodAsString}.
--no-tone 不使用音调.
--tone-style=[style] 音调风格可选值symbol/none/number, default: none.
-h, --help 显示帮助.
HELP;
function has_option($option, $alias = null): bool
{
global $inputOptions;
if ($alias) {
return array_key_exists($option, $inputOptions) || array_key_exists($alias, $inputOptions);
}
return array_key_exists($option, $inputOptions);
}
function get_option($option, $default = null, $alias = null): ?string
{
global $inputOptions;
if ($alias) {
return $inputOptions[$option] ?? $inputOptions[$alias] ?? $default;
}
return $inputOptions[$option] ?? $default;
}
$inputOptions = parse_options($argv);
$input = $inputOptions[0] ?? null;
if (empty($input) || has_option('help', 'h')) {
echo $help;
exit(0);
}
$method = get_option('method', $method, 'm');
$toneStyle = has_option('no-tone') ? 'none' : get_option('tone-style', 'none');
if (! in_array($method, $methods)) {
echo "Method '{$method}' is not supported.\n";
exit(1);
}
$result = Pinyin::$method($input, $method === 'permalink' ? '-' : $toneStyle);
$toJson = has_option('json', 'j') || in_array($method, ['heteronym', 'heteronymAsList']);
if ($toJson) {
$options = JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT;
if (has_option('compact', 'c')) {
$options = 0;
}
$result = json_encode($result, $options);
}
echo $result, "\n";
{
"name": "overtrue/pinyin",
"description": "Chinese to pinyin translator.",
"keywords": [
"chinese",
"pinyin",
"cn2pinyin"
],
"homepage": "https://github.com/overtrue/pinyin",
"license": "MIT",
"authors": [
{
"name": "overtrue",
"homepage": "http://github.com/overtrue",
"email": "anzhengchao@gmail.com"
}
],
"autoload": {
"psr-4": {
"Overtrue\\Pinyin\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Overtrue\\Pinyin\\Tests\\": "tests/"
}
},
"require": {
"php": ">=8.1"
},
"require-dev": {
"phpunit/phpunit": "^12.0.21",
"brainmaestro/composer-git-hooks": "^3.0",
"nunomaduro/termwind": "^2.0",
"laravel/pint": "^1.10"
},
"bin": [
"bin/pinyin"
],
"extra": {
"hooks": {
"pre-commit": [
"composer pint",
"composer test"
],
"pre-push": [
"composer pint",
"composer test"
]
}
},
"scripts": {
"post-update-cmd": [
"cghooks update"
],
"post-merge": "composer install",
"post-install-cmd": [
"cghooks remove",
"cghooks add --ignore-lock"
],
"cghooks": "vendor/bin/cghooks",
"pint": "vendor/bin/pint ./src ./tests",
"fix-style": "vendor/bin/pint ./src ./tests",
"test": "vendor/bin/phpunit --colors=always",
"build": "php ./bin/build",
"benchmark": "php ./benchmark/run.php"
},
"scripts-descriptions": {
"test": "Run all tests.",
"fix-style": "Run style checks and fix violations."
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
<?php
return array (
'万俟' => ' mò qí ',
'尉迟' => ' yù chí ',
'单于' => ' chán yú ',
'重' => ' chóng ',
'秘' => ' bì ',
'冼' => ' xiǎn ',
'华' => ' huà ',
'过' => ' guō ',
'纪' => ' jǐ ',
'燕' => ' yān ',
'种' => ' chóng ',
'繁' => ' pó ',
'幺' => ' yāo ',
'覃' => ' qín ',
'冯' => ' féng ',
'石' => ' shí ',
'缪' => ' miào ',
'瞿' => ' qú ',
'曾' => ' zēng ',
'解' => ' xiè ',
'折' => ' shè ',
'那' => ' nā ',
'佴' => ' nài ',
'难' => ' nàn ',
'粘' => ' niàn ',
'藏' => ' zàng ',
'扎' => ' zā ',
'翟' => ' zhái ',
'都' => ' dū ',
'六' => ' lù ',
'薄' => ' bó ',
'贾' => ' jiǎ ',
'的' => ' dē ',
'哈' => ' hǎ ',
'居' => ' jū ',
'盖' => ' gě ',
'查' => ' zhā ',
'盛' => ' shèng ',
'塔' => ' tǎ ',
'和' => ' hé ',
'柏' => ' bǎi ',
'朴' => ' piáo ',
'蓝' => ' lán ',
'牟' => ' móu ',
'殷' => ' yīn ',
'陆' => ' lù ',
'乜' => ' niè ',
'乐' => ' yuè ',
'阚' => ' kàn ',
'叶' => ' yè ',
'强' => ' qiáng ',
'不' => ' fǒu ',
'丁' => ' dīng ',
'阿' => ' ā ',
'汤' => ' tāng ',
'万' => ' wàn ',
'车' => ' chē ',
'称' => ' chēng ',
'沈' => ' shěn ',
'区' => ' ōu ',
'仇' => ' qiú ',
'宿' => ' sù ',
'南' => ' nán ',
'单' => ' shàn ',
'卜' => ' bǔ ',
'鸟' => ' niǎo ',
'思' => ' sī ',
'殳' => ' shū ',
'寻' => ' xún ',
'於' => ' yú ',
'烟' => ' yān ',
'余' => ' yú ',
'浅' => ' qiǎn ',
'艾' => ' ài ',
'浣' => ' wǎn ',
'无' => ' wú ',
'信' => ' xìn ',
'许' => ' xǔ ',
'齐' => ' qí ',
'俞' => ' yú ',
'若' => ' ruò ',
'贠' => ' yùn ',
'貟' => ' yùn ',
'么' => ' yāo ',
);
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
# 基准测试指南
## 运行基准测试
```bash
php benchmark/run.php
```
## 输出说明
### Strategy Comparison 表格
这个表格对比了三种转换策略的性能:
```
Method Memory Cached Smart Fastest Speedup
sentence 20.5 ms 8.2 ms 12.3 ms Cached 2.5x
fullSentence 18.3 ms 7.5 ms 11.2 ms Cached 2.4x
...
────────────────────────────────────────────────
TOTAL 190.26ms 119.33ms 194.38ms Cached 1.6x
```
#### 列说明:
- **Method**: 测试的方法名称
- **Memory**: 内存优化策略的执行时间
- **Cached**: 缓存策略的执行时间
- **Smart**: 智能策略的执行时间
- **Fastest**: 该方法最快的策略名称(用颜色高亮)
- **Speedup**: 最慢与最快之间的速度差异倍数
#### TOTAL 行:
- 使用分隔线与数据行区分
- 显示所有方法的总执行时间
- 最快的策略会用对应颜色高亮显示
- Speedup 显示总体的加速比
### Performance Summary
性能总结部分提供了策略之间的直观对比:
```
📊 Performance Summary:
• Cached strategy is 1.59x faster than Memory Optimized
• Smart strategy is 0.98x faster than Memory, 1.63x slower than Cached
```
这让您可以快速了解:
- Cached 策略比 Memory Optimized 快多少倍
- Smart 策略相对于其他两种策略的性能表现
### Memory Usage 表格
显示每种策略的内存使用情况:
```
Strategy Peak Memory Description
Memory Optimized 2.5 MB Minimal memory, loads on demand
Cached 15.8 MB All data cached, fastest repeated access
Smart 8.2 MB Adaptive loading based on text complexity
```
## 如何解读结果
1. **选择合适的策略**
- 如果内存有限(如 Web 请求):选择 Memory Optimized
- 如果需要批量处理大量文本:选择 Cached
- 如果需要平衡性能和内存:选择 Smart
2. **Speedup 值的含义**
- 1.5x = 快 50%
- 2.0x = 快 1 倍(速度是原来的 2 倍)
- 3.0x = 快 2 倍(速度是原来的 3 倍)
3. **TOTAL 行的重要性**
- 这是所有方法执行的总时间
- 最能反映实际使用场景的整体性能
- 用于评估策略的整体效果
\ No newline at end of file
parameters:
level: 9
paths:
- src
inferPrivatePropertyTypeFromConstructor: true
checkMissingIterableValueType: false
\ No newline at end of file
<?php
namespace Overtrue\Pinyin;
use ArrayAccess;
use JsonSerializable;
use Stringable;
use function array_map;
use function implode;
use function is_array;
class Collection implements ArrayAccess, JsonSerializable, Stringable
{
public function __construct(protected $items = []) {}
public function join(string $separator = ' '): string
{
return implode($separator, array_map(
fn ($item) => is_array($item) ? '['.implode(', ', $item).']' : $item,
$this->items
));
}
public function map(callable $callback): Collection
{
return new static(array_map($callback, $this->all()));
}
public function all(): array
{
return $this->items;
}
public function toArray(): array
{
return $this->all();
}
public function toJson(int $options = 0): string
{
return json_encode($this->all(), $options);
}
public function __toString(): string
{
return $this->join();
}
public function offsetExists(mixed $offset): bool
{
return isset($this->items[$offset]);
}
public function offsetGet(mixed $offset): mixed
{
return $this->items[$offset] ?? null;
}
public function offsetSet(mixed $offset, mixed $value): void
{
if ($offset === null) {
$this->items[] = $value;
} else {
$this->items[$offset] = $value;
}
}
public function offsetUnset(mixed $offset): void
{
unset($this->items[$offset]);
}
public function jsonSerialize(): array
{
return $this->items;
}
}
<?php
namespace Overtrue\Pinyin\Contracts;
use Overtrue\Pinyin\Collection;
use Overtrue\Pinyin\ToneStyle;
interface ConverterInterface
{
public function convert(string $string): Collection;
public function heteronym(bool $asList = false): static;
public function surname(): static;
public function noWords(): static;
public function noCleanup(): static;
public function onlyHans(): static;
public function noAlpha(): static;
public function noNumber(): static;
public function noPunctuation(): static;
public function withToneStyle(string|ToneStyle $toneStyle): static;
public function noTone(): static;
public function useNumberTone(): static;
public function yuToV(): static;
public function yuToU(): static;
public function yuToYu(): static;
public function when(bool $condition, callable $callback): static;
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论