fuc-new/src/Controllers/Api/Nasa/V1/Base/ListController.php
2026-07-07 18:48:21 +08:00

525 lines
17 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
declare(strict_types=1);
namespace App\Controllers\Api\Nasa\V1\Base;
//use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use InvalidArgumentException;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\DB;
use Slim\Http\Response;
//use Slim\Http\ServerRequest;
use Slim\Http\ServerRequest as Request;
abstract class ListController
{
private string $sOperatorDefault = 'eq';
private string $sSortDefault = 'asc';
private array $aFilterParams = [
'c' => [],
'cc' => [],
'ob' => [],
];
protected $oModel;
protected string $sPageName = '';
protected string $sModelName = '';
protected array $aFilterFields = []; // 允许where的字段
// protected array $aArticleFields = []; // 文章字段
protected array $aFieldTypes = [];
protected array $aValueFields = [];
protected array $aLenthFields = []; // 限制长度的字段
protected array $aSelectFields = []; // 默认作为select的字段
protected array $aListFields = []; // list展示的字段和名字映射
protected array $aDateFields = []; // date字段
protected array $aJsonFields = []; // json字段
protected array $aValueStyle = []; // 特定文字渲染样式
protected int $iLimitMax = 300; // 默认limit限制
protected int $iLimit = 30; // 默认显示行数
protected array $aCcExtFields = []; // 自定义条件字段追加在listFields后
protected array $aCcFields = [];
protected int $iOrderByMax = 3;
protected array $aOrderBy = [
[
"sField" => "id",
"sSort" => "desc"
]
];
public function __construct()
{
if ($this->sModelName) {
$sFullNamespace = "App\Models\\{$this->sModelName}";
if (! class_exists($sFullNamespace)) {
throw new InvalidArgumentException("【系统架构错误】: 找不到领域模型 {$sFullNamespace}");
}
$this->oModel = new $sFullNamespace();
$this->aCcFields = array_merge($this->aListFields, $this->aCcExtFields);
}
}
public function getMapAll()
{
$a = [];
if (method_exists($this->oModel, 'getMapAll')) {
$a = $this->oModel->getMapAll();
}
$b = array_merge($a, $this->aValueFields);
return $b;
}
public function index(Request $oRequest, Response $oResponse, $args)
{
if (! $this->oModel) {
return $oResponse->withJson(['code' => 500, 'msg' => '未绑定核心领域模型'], 500);
}
$oQuery = $this->oModel->newQuery();
$aParams = $oRequest->getParams();
$iLimit = $aParams['limit'] ?? $this->iLimit;
$iPage = $aParams['page'] ?? 1;
foreach ($aParams as $k => $v) {
if (!empty($this->aFilterFields)) {
if (!in_array($k, $this->aFilterFields)) {
continue;
}
}
// w__name__eq=1
$aK = explode("__", $k);
$sType = $aK[0] ?? '';
$sField = $aK[1] ?? '';
$sOperator = $aK[2] ?? $this->sOperatorDefault;
$sSqlOperator = $this->mapOperator($sOperator);
if (!isset($this->aFilterParams[$sType])) {
continue;
}
if (!$sType || !$sField) {
continue;
}
$this->aFilterParams[$k] = $v;
if ($sType === 'ob') {
$this->aFilterParams[$sType][] = [
'sField' => $sField,
'sSort' => $v ?? $this->sSortDefault
];
continue;
}
if ($sType === 'c') { // 预制条件,字典式
$this->aFilterParams[$sType][$sField] = [
'sOperator' => $sOperator,
'sValue' => $v
];
}
if ($sType === 'cc') { // 自定义条件,集合式
$this->aFilterParams[$sType][] = [
'sField' => $sField,
'sOperator' => $sOperator,
'sValue' => $v
];
}
if (blank($v)) continue; // 空v可以back但不加入sql查询
$sSqlValue = $v;
if ($sSqlOperator === 'like') {
$sSqlValue = "%{$v}%";
}
if (in_array($sField, $this->aDateFields)) {
$oQuery->whereDate($sField, $sSqlOperator, $sSqlValue);
} else {
$oQuery->where($sField, $sSqlOperator, $sSqlValue);
}
}
$iLimit = max(1, $iLimit);
$iLimit = min($this->iLimitMax, $iLimit);
if (!empty($this->aFilterParams['ob'])) {
$this->aOrderBy = $this->aFilterParams['ob'];
}
foreach ($this->aOrderBy as $aOrderBy) {
$oQuery->orderBy($aOrderBy['sField'], $aOrderBy['sSort']);
}
// $oPaginatedData = $oQuery->paginate($iLimit, array_keys($this->aListFields));
$oPaginatedData = $oQuery->paginate(
$iLimit,
array_keys($this->aListFields),
'page',
$iPage
);
return $oResponse->withJson([
'iCode' => 200,
'aData' => [
'cList' => $oPaginatedData->items(),
'aListField' => $this->getListFields(),
'aFieldTypes' => $this->aFieldTypes,
'aMap' => $this->getMapAll(),
'aValueStyle' => $this->aValueStyle,
'aSelectField' => $this->aSelectFields,
'aFilterParam' => $this->aFilterParams,
'aCcField' => $this->aCcFields,
'sCcLast' => $this->getCcLast(),
'sPageName' => $this->sPageName,
'aPager' => [
'aOrderBySchema'=> $this->getOrderBySchema(),
'aOrderBy' => $this->getOrderBy(),
'iTotal' => $oPaginatedData->total(),
'iLimit' => min($this->iLimitMax, $iLimit),
'iCurrentPage' => $oPaginatedData->currentPage(),
'iLastPage' => $oPaginatedData->lastPage(),
'iPerPage' => $oPaginatedData->perPage(),
'iPrevPage' => max(1, $oPaginatedData->currentPage() - 1),
'iNextPage' => min($oPaginatedData->lastPage(), $oPaginatedData->currentPage() + 1)
]
]
], 200);
}
private function mapOperator($sOperator)
{
$sSqlOperator = match ($sOperator) {
'like' => 'like',
'eq' => '=',
'ne' => '!=',
'gt' => '>',
'gte' => '>=',
'lt' => '<',
'lte' => '<=',
default => '',
};
return $sSqlOperator;
}
private function getOrderBySchema()
{
$iOrderByCount = count($this->aOrderBy);
$iDiff = $this->iOrderByMax - $iOrderByCount;
$a = $this->aOrderBy;
for ($i=0; $i<$iDiff; $i++) {
$a[] = [];
}
return $a;
}
private function getOrderBy()
{
return $this->aOrderBy;
}
public function getListFields()
{
$a = [];
foreach ($this->aListFields as $k => $v) {
if ($v) {
$a[$k] = $v;
} else {
$a[$k] = $k;
}
}
return $a;
}
private function getCcLast()
{
$aCcFieldsTmp = $this->aCcFields;
foreach ($this->aFilterParams['cc'] as $ACC) {
unset($aCcFieldsTmp[$ACC['sField']]);
}
$s = head(array_keys($aCcFieldsTmp));
return $s;
}
public function add(Request $oRequest, Response $oResponse, $args)
{
// 1. 获取表名
$sTableName = $this->oModel->getTable();
// 2. 修复 500 报错:改用连接对象的 Schema 构建器,彻底解耦门面
// 变量命名oSchemaBuilder (Schema构建器对象) -> 【欧 斯基玛 标德儿】
$oSchemaBuilder = $this->oModel->getConnection()->getSchemaBuilder();
$aRawFields = $oSchemaBuilder->getColumnListing($sTableName);
// 3. 大厂正统手法:利用模型原生方法安全获取时间戳字段名(自动处理关闭时间戳的情况)
// 变量命名aKickFields (要剔除的字段数组) -> 【诶 踢客 费尔茨】
$aKickFields = ['id'];
if ($this->oModel->timestamps) {
$aKickFields[] = $this->oModel->getCreatedAtColumn();
$aKickFields[] = $this->oModel->getUpdatedAtColumn();
}
// 4. 高效数组过滤:干掉 foreach改用内置函数完成差集计算
// 变量命名aCleanFields (干净的字段数组) -> 【诶 克林 费尔茨】
$aCleanFields = array_values(array_diff($aRawFields, $aKickFields));
// 5. 标准响应返回
return $oResponse->withJson([
'iCode' => 200,
'aData' => [
'cList' => $aCleanFields, // 保持你原有的前端 Key 兼容
'sPageName' => $this->sPageName
]
], 200);
}
public function clone(Request $oRequest, Response $oResponse, $args)
{
// 1. 安全获取参数并查询
$iId = $args['id'] ?? 0;
// 确保使用 findOrFail找不到直接抛出 404 异常(由框架底层捕获)
$oModelResult = $this->oModel->findOrFail($iId);
// 2. 匈牙利命名法修正:获取原始属性数组
// 变量命名aRowAttributes (行属性数组) -> 【诶 柔 艾特里比茨】
$aRowAttributes = $oModelResult->getRawOriginal();
// 3. 修复 500 报错:抛弃 DB 门面,改用解耦的实例调用
// 变量命名oConnection (连接对象) -> 【欧 康内克闪】
$oConnection = $this->oModel->getConnection();
$sTableName = $this->oModel->getTable();
// 防御性编程:将原生 SQL 占位绑定,防止潜在注入风险
// 直接把表名变量拼进单引号里
$aStatus = $oConnection->select("SHOW TABLE STATUS LIKE '{$sTableName}'");
$iNextId = $aStatus[0]->Auto_increment ?? 1;
// 4. 移除旧主键,赋予预测的自增 ID若无特殊业务强需求大厂更倾向于 unset($aRowAttributes['id'])
$aRowAttributes['id'] = (int)$iNextId; // 强制强类型转换
// 5. 健壮的方法存在性检查(呼应你上一条的需求)
// 变量命名aMapData (映射数据数组) -> 【诶 迈普 数据】
$aMapData = $this->getMapAll();
// 6. 统一标准的 JSON 响应输出
return $oResponse->withJson([
'iCode' => 200,
'aData' => [
'cList' => $aRowAttributes, // 保持你前端需要的 Key 命名不变
'aMap' => $aMapData,
'aListField' => $this->getListFields(),
'sPageName' => $this->sPageName
]
], 200);
}
// public function clone(Request $oRequest, Response $oResponse, $args)
// {
// $iId = $args['id'];
// $oModelResult = $this->oModel->findOrFail($iId);
// $cList = $oModelResult->getRawOriginal();
//
// $sTableName = $this->oModel->getTable();
// $aStatus = DB::select("SHOW TABLE STATUS LIKE '{$sTableName}'");
// $iNextId = $aStatus[0]->Auto_increment ?? 1;
//
// $cList['id'] = $iNextId;
//
// return $oResponse->withJson([
// 'iCode' => 200,
// 'aData' => [
// 'cList' => $cList,
// 'aMap' => $this->oModel->getMapAll(),
// 'aListField' => $this->getListFields(),
// 'sPageName' => $this->sPageName
// ]
// ], 200);
// } // 原代码是这样
// public function cloneSave(Request $oRequest, Response $oResponse, $args)
// {
//// tt(123);
// $iId = $args['id'];
////dd(123);
// $aParams = $oRequest->getParams();
//
// foreach ($aParams as $k => $v) {
// $this->oModel->{$k} = $v;
// }
// $this->oModel->create();
//
// return $oResponse->withJson([
// 'iCode' => 200,
// 'aData' => [],
// 'sMsg' => "保存成功id ".$this->oModel->id
// ], 200);
// } // 也不行?
public function detail(Request $oRequest, Response $oResponse, $args)
{
$iId = $args['id'];
$oModelResult = $this->oModel->findOrFail($iId);
$cList = $oModelResult->getRawOriginal();
return $oResponse->withJson([
'iCode' => 200,
'aData' => [
'cList' => $cList,
'aMap' => $this->getMapAll(),
'aListField' => $this->getListFields(),
'sPageName' => $this->sPageName
]
], 200);
}
public function hit(Request $oRequest, Response $oResponse, $args)
{
$iId = $args['id'];
$sField = $args['field'];
$sHitType = $this->aFieldTypes[$sField] ?? '';
$sHit = $this->oModel->find($iId)?->{$sField};
if ($sHitType) {
if ($sHitType == 'json') {
$aHit = json_decode($sHit);
$sHit = json_encode($aHit, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}
}
return $oResponse->withJson([
'iCode' => 200,
'aData' => [
'sHit' => $sHit
]
], 200);
}
public function delete(Request $oRequest, Response $oResponse, $args)
{
$iId = $args['id'];
$this->oModel->findOrFail($iId)->delete();
return $oResponse->withJson([
'iCode' => 200,
'aData' => [],
'sMsg' => '删除成功'
], 200);
}
public function addSave(Request $oRequest, Response $oResponse, $args)
{
$aParams = $oRequest->getParams();
foreach ($aParams as $k => $v) {
$this->oModel->{$k} = $v;
}
if (!$this->oModel->save()) {
return $oResponse->withJson(['code' => 500, 'msg' => '保存失败?'], 500);
}
return $oResponse->withJson([
'iCode' => 200,
'aData' => [],
'sMsg' => '保存成功'
], 200);
}
public function detailSave(Request $oRequest, Response $oResponse, $args)
{
$iId = $args['id'];
$oThisModel = $this->oModel->find($iId);
$aParams = $oRequest->getParams();
unset($aParams['id'], $aParams['_method']);
foreach ($aParams as $k => &$v) {
if (empty($v) && empty($oThisModel->{$k})) {
continue;
}
if (empty($v) && $v !== 0 && $v !== '0') {
$v = '';
}
if ($oThisModel->{$k} != $v) {
$oThisModel->{$k} = $v;
}
}
$oThisModel->save();
$aChangeField = $oThisModel->getChanges();
/// 排除update_at
$sClassName = get_class($this->oModel);
if (
defined($sClassName . '::UPDATED_AT')
&& ($sUpdateColumn = constant($sClassName . '::UPDATED_AT'))
&& !isset($aParams[$sUpdateColumn])
&& isset($aChangeField[$sUpdateColumn])
) {
unset($aChangeField[$sUpdateColumn]);
}
/// 构造msg
$sMsg = "";
$sJiantou = " -> ";
foreach ($aChangeField as $k => $v) {
if (mb_strlen($v, 'UTF-8') > 60 ) {
$sJiantou = '';
// $v = mb_substr($v, 0, 60, 'UTF-8');
$v = '';
}
if (!isset($aParams[$k])) {
$sMsg .= "⚠️ ".$k . $sJiantou . $v . "<br><br>";
} else {
$sMsg .= "".$k . $sJiantou . $v . "<br><br>";
unset($aParams[$k]);
}
}
foreach ($aParams as $k => $v) {
if (mb_strlen($v, 'UTF-8') > 60 ) {
$sJiantou = '';
// $v = mb_substr($v, 0, 60, 'UTF-8');
$v = '';
}
$sMsg .= "".$k . $sJiantou . $v . "<br><br>";
}
$sMsg = rtrim($sMsg, "<br><br>");
return $oResponse->withJson([
'iCode' => 200,
'aData' => $aChangeField,
'sMsg' => $sMsg
], 200);
}
}