[],
'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 . "
";
} else {
$sMsg .= "✅ ".$k . $sJiantou . $v . "
";
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 . "
";
}
$sMsg = rtrim($sMsg, "
");
return $oResponse->withJson([
'iCode' => 200,
'aData' => $aChangeField,
'sMsg' => $sMsg
], 200);
}
}