初始化
This commit is contained in:
@@ -0,0 +1,603 @@
|
||||
<?php
|
||||
namespace app\models;
|
||||
|
||||
use core\base\Model;
|
||||
|
||||
/**
|
||||
* 工位定义模型 - 统一管理所有内置工位的元数据
|
||||
*
|
||||
* 替代之前分散在 7 个独立 Model 文件中的硬编码配置。
|
||||
* 所有内置工位的数据表名、时间列名、筛选开关等统一在此管理。
|
||||
*
|
||||
* 数据库表:DGZXY_station_definitions
|
||||
*/
|
||||
class StationDefinition extends Model
|
||||
{
|
||||
protected $table = 'station_definitions';
|
||||
|
||||
/** @var array 缓存已加载的定义 */
|
||||
private static $cache = [];
|
||||
|
||||
/**
|
||||
* 获取工位定义(表不存在时自动创建并初始化)
|
||||
* @param string $stationType
|
||||
* @return array|null
|
||||
*/
|
||||
public function getByType($stationType)
|
||||
{
|
||||
if (isset(self::$cache[$stationType])) {
|
||||
return self::$cache[$stationType];
|
||||
}
|
||||
try {
|
||||
$row = $this->where(['station_type = :type'], [':type' => $stationType])->fetch();
|
||||
} catch (\Throwable $e) {
|
||||
error_log('[StationDefinition] getByType(' . $stationType . ') failed: ' . $e->getMessage());
|
||||
// 表不存在,自动创建并初始化
|
||||
if ($this->autoCreateTable()) {
|
||||
try {
|
||||
$row = $this->where(['station_type = :type'], [':type' => $stationType])->fetch();
|
||||
} catch (\Throwable $e2) {
|
||||
error_log('[StationDefinition] getByType retry failed: ' . $e2->getMessage());
|
||||
$row = null;
|
||||
}
|
||||
} else {
|
||||
$row = null;
|
||||
}
|
||||
}
|
||||
if ($row && !empty($row['extra_config'])) {
|
||||
$row['extra'] = json_decode($row['extra_config'], true) ?: [];
|
||||
} elseif ($row) {
|
||||
$row['extra'] = [];
|
||||
}
|
||||
self::$cache[$stationType] = $row ?: null;
|
||||
return self::$cache[$stationType];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取完整表名(带前缀)
|
||||
*/
|
||||
public function getFullTableName($stationType)
|
||||
{
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) {
|
||||
// 尝试自动重建
|
||||
$this->autoCreateTable();
|
||||
self::clearCache();
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) return null;
|
||||
}
|
||||
return self::TABLE_PREFIX . $def['db_table'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取时间列名
|
||||
*/
|
||||
public function getTimeColumn($stationType)
|
||||
{
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) {
|
||||
$this->autoCreateTable();
|
||||
self::clearCache();
|
||||
$def = $this->getByType($stationType);
|
||||
}
|
||||
return $def ? $def['time_column'] : 'created_at';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取记录列表(支持按类型和型号筛选)
|
||||
*
|
||||
* 如果 station_definitions 记录缺失,自动尝试重建。
|
||||
*/
|
||||
public function getRecords($stationType, $filterType = '', $filterModel = '', $limit = 100)
|
||||
{
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) {
|
||||
error_log("[StationDefinition] getRecords: no definition for '{$stationType}', auto-initializing...");
|
||||
$this->autoCreateTable();
|
||||
self::clearCache();
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) return [];
|
||||
}
|
||||
|
||||
$table = self::TABLE_PREFIX . $def['db_table'];
|
||||
$conditions = [];
|
||||
$params = [];
|
||||
|
||||
if ($def['has_product_type'] && !empty($filterType)) {
|
||||
$conditions[] = 'product_type = :pt';
|
||||
$params[':pt'] = $filterType;
|
||||
}
|
||||
if ($def['has_product_model'] && !empty($filterModel)) {
|
||||
$conditions[] = 'product_model = :pm';
|
||||
$params[':pm'] = $filterModel;
|
||||
}
|
||||
|
||||
$timeCol = $def['time_column'];
|
||||
$sql = "SELECT * FROM `{$table}`";
|
||||
if (!empty($conditions)) {
|
||||
$sql .= ' WHERE ' . implode(' AND ', $conditions);
|
||||
}
|
||||
$sql .= " ORDER BY `{$timeCol}` DESC LIMIT " . intval($limit);
|
||||
|
||||
try {
|
||||
return $this->query($sql, $params);
|
||||
} catch (\Throwable $e) {
|
||||
error_log("[StationDefinition] getRecords query failed for {$stationType}: " . $e->getMessage());
|
||||
// 表可能不存在,尝试创建
|
||||
$fieldConfigs = $GLOBALS['fieldConfigs'] ?? [];
|
||||
if ($this->ensureTable($stationType, $fieldConfigs)) {
|
||||
try {
|
||||
return $this->query($sql, $params);
|
||||
} catch (\Throwable $e2) {
|
||||
error_log("[StationDefinition] getRecords retry failed for {$stationType}: " . $e2->getMessage());
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有记录
|
||||
*/
|
||||
public function getAllRecords($stationType, $limit = 100)
|
||||
{
|
||||
return $this->getRecords($stationType, '', '', $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计今日某操作员的录入数量
|
||||
*/
|
||||
public function countTodayByOperator($stationType, $operator)
|
||||
{
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) {
|
||||
error_log("[StationDefinition] countTodayByOperator: no definition for '{$stationType}', auto-initializing...");
|
||||
$this->autoCreateTable();
|
||||
self::clearCache();
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) return 0;
|
||||
}
|
||||
|
||||
$table = self::TABLE_PREFIX . $def['db_table'];
|
||||
$timeCol = $def['time_column'];
|
||||
|
||||
try {
|
||||
$sql = "SELECT COUNT(*) as cnt FROM `{$table}` WHERE operator = :op AND DATE(`{$timeCol}`) = CURDATE()";
|
||||
$result = $this->query($sql, [':op' => $operator]);
|
||||
return $result[0]['cnt'] ?? 0;
|
||||
} catch (\Throwable $e) {
|
||||
error_log("[StationDefinition] countTodayByOperator failed for {$stationType}: " . $e->getMessage());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计总记录数(可按型号筛选)
|
||||
*/
|
||||
public function countTotal($stationType, $filterType = '', $filterModel = '')
|
||||
{
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) {
|
||||
error_log("[StationDefinition] countTotal: no definition for '{$stationType}', auto-initializing...");
|
||||
$this->autoCreateTable();
|
||||
self::clearCache();
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) return 0;
|
||||
}
|
||||
|
||||
$table = self::TABLE_PREFIX . $def['db_table'];
|
||||
$conditions = [];
|
||||
$params = [];
|
||||
|
||||
if ($def['has_product_type'] && !empty($filterType)) {
|
||||
$conditions[] = 'product_type = :pt';
|
||||
$params[':pt'] = $filterType;
|
||||
}
|
||||
if ($def['has_product_model'] && !empty($filterModel)) {
|
||||
$conditions[] = 'product_model = :pm';
|
||||
$params[':pm'] = $filterModel;
|
||||
}
|
||||
|
||||
try {
|
||||
$sql = "SELECT COUNT(*) as cnt FROM `{$table}`";
|
||||
if (!empty($conditions)) {
|
||||
$sql .= ' WHERE ' . implode(' AND ', $conditions);
|
||||
}
|
||||
$result = $this->query($sql, $params);
|
||||
return $result[0]['cnt'] ?? 0;
|
||||
} catch (\Throwable $e) {
|
||||
error_log("[StationDefinition] countTotal failed for {$stationType}: " . $e->getMessage());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加记录到工位专用表
|
||||
*
|
||||
* 如果 station_definitions 中没有该工位记录,自动尝试重建。
|
||||
* 如果数据表不存在,自动创建后再插入。
|
||||
*/
|
||||
public function addRecord($stationType, $data)
|
||||
{
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) {
|
||||
// 尝试自动重建 station_definitions 数据
|
||||
error_log("[StationDefinition] addRecord: no definition for '{$stationType}', auto-initializing...");
|
||||
$this->autoCreateTable();
|
||||
self::clearCache();
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) {
|
||||
error_log("[StationDefinition] addRecord: still no definition for '{$stationType}' after re-init");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$table = self::TABLE_PREFIX . $def['db_table'];
|
||||
|
||||
// 确保数据表存在(不存在则创建)
|
||||
try {
|
||||
$fields = implode('`, `', array_keys($data));
|
||||
$placeholders = ':' . implode(', :', array_keys($data));
|
||||
$sql = "INSERT INTO `{$table}` (`{$fields}`) VALUES ({$placeholders})";
|
||||
return $this->execute($sql, $data);
|
||||
} catch (\Throwable $e) {
|
||||
$msg = $e->getMessage();
|
||||
error_log("[StationDefinition] addRecord failed for {$stationType}: {$msg}");
|
||||
// 表不存在时自动创建
|
||||
if (stripos($msg, 'exist') !== false || stripos($msg, 'not found') !== false || stripos($msg, '1146') !== false) {
|
||||
// 需要 fieldConfigs 来创建表,从全局获取
|
||||
$fieldConfigs = $GLOBALS['fieldConfigs'] ?? [];
|
||||
if ($this->ensureTable($stationType, $fieldConfigs)) {
|
||||
// 重试插入
|
||||
try {
|
||||
return $this->execute($sql, $data);
|
||||
} catch (\Throwable $e2) {
|
||||
error_log("[StationDefinition] addRecord retry failed for {$stationType}: " . $e2->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查记录是否已存在(防重复)
|
||||
*/
|
||||
public function findByField($stationType, $fieldName, $value)
|
||||
{
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) {
|
||||
error_log("[StationDefinition] findByField: no definition for '{$stationType}', auto-initializing...");
|
||||
$this->autoCreateTable();
|
||||
self::clearCache();
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) return null;
|
||||
}
|
||||
|
||||
$table = self::TABLE_PREFIX . $def['db_table'];
|
||||
try {
|
||||
$sql = "SELECT * FROM `{$table}` WHERE `{$fieldName}` = :val LIMIT 1";
|
||||
$result = $this->query($sql, [':val' => $value]);
|
||||
return $result[0] ?? null;
|
||||
} catch (\Throwable $e) {
|
||||
error_log("[StationDefinition] findByField failed for {$stationType}: " . $e->getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查工位是否启用筛选
|
||||
*/
|
||||
public function isFilterEnabled($stationType)
|
||||
{
|
||||
$def = $this->getByType($stationType);
|
||||
return $def ? (bool)$def['filter_enabled'] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否显示今日计数
|
||||
*/
|
||||
public function showTodayCount($stationType)
|
||||
{
|
||||
$def = $this->getByType($stationType);
|
||||
return $def ? (bool)$def['show_today_count'] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否显示总计数
|
||||
*/
|
||||
public function showTotalCount($stationType)
|
||||
{
|
||||
$def = $this->getByType($stationType);
|
||||
return $def ? (bool)$def['show_total_count'] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保工位数据表存在,不存在则自动创建
|
||||
*
|
||||
* 通用工位表结构(参考 station_inbound):
|
||||
* id, product_type, product_model, operator, created_at + 动态字段
|
||||
*
|
||||
* @param string $stationType 工位类型标识
|
||||
* @param array $fieldConfigs 字段配置(从 fields_config 解析)
|
||||
* @return bool 表是否已存在/创建成功
|
||||
*/
|
||||
public function ensureTable($stationType, $fieldConfigs = [])
|
||||
{
|
||||
// 先尝试获取工位定义,如果失败则尝试重建 station_definitions 表数据
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) {
|
||||
// station_definitions 表中没有该工位的记录,尝试重新插入
|
||||
error_log("[StationDefinition] ensureTable: no definition for '{$stationType}', trying to re-initialize built-in data");
|
||||
$this->autoCreateTable();
|
||||
// 清除缓存后重试
|
||||
self::clearCache();
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) {
|
||||
error_log("[StationDefinition] ensureTable: still no definition for '{$stationType}' after re-init");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$fullTable = self::TABLE_PREFIX . $def['db_table'];
|
||||
|
||||
// 检查表是否已存在
|
||||
$exists = $this->query("SHOW TABLES LIKE '{$fullTable}'");
|
||||
if (!empty($exists)) return true;
|
||||
|
||||
// 基础列:所有通用工位表都有的字段
|
||||
$columns = [
|
||||
"`id` INT AUTO_INCREMENT PRIMARY KEY",
|
||||
"`product_type` VARCHAR(100) DEFAULT NULL COMMENT '产品类型'",
|
||||
"`product_model` VARCHAR(100) DEFAULT NULL COMMENT '产品型号'",
|
||||
"`operator` VARCHAR(50) DEFAULT NULL COMMENT '操作人'",
|
||||
"`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '录入时间'",
|
||||
];
|
||||
|
||||
// 索引
|
||||
$indexes = [
|
||||
"KEY `idx_product_type` (`product_type`)",
|
||||
"KEY `idx_product_model` (`product_model`)",
|
||||
"KEY `idx_created_at` (`created_at`)",
|
||||
];
|
||||
|
||||
// 从 fields_config 派生额外字段(排除已存在的基础字段和隐藏字段)
|
||||
$baseFields = ['product_type', 'product_model', 'operator', 'created_at', 'id'];
|
||||
$addedFields = [];
|
||||
foreach ($fieldConfigs as $field) {
|
||||
$name = $field['name'] ?? '';
|
||||
$type = $field['type'] ?? 'text';
|
||||
if (in_array($name, $baseFields) || empty($name)) continue;
|
||||
|
||||
// 跳过纯虚拟字段(没有实际存储意义的)
|
||||
if (in_array($name, ['_meta'])) continue;
|
||||
|
||||
// 根据字段类型确定 MySQL 列类型
|
||||
$colType = 'VARCHAR(200)';
|
||||
if ($type === 'number') {
|
||||
$colType = 'VARCHAR(50)';
|
||||
} elseif ($type === 'textarea') {
|
||||
$colType = 'TEXT';
|
||||
}
|
||||
|
||||
$label = $field['label'] ?? $name;
|
||||
$comment = addslashes($label);
|
||||
$columns[] = "`{$name}` {$colType} DEFAULT NULL COMMENT '{$comment}'";
|
||||
|
||||
// 为序列号类字段添加索引
|
||||
if (!empty($field['is_scan']) || stripos($name, 'serial') !== false) {
|
||||
$indexes[] = "KEY `idx_{$name}` (`{$name}`)";
|
||||
}
|
||||
|
||||
$addedFields[] = $name;
|
||||
}
|
||||
|
||||
// 从 station_business_helper 的 dataMapping 补充可能缺失的列
|
||||
// 确保 helper 文件已加载
|
||||
if (!function_exists('getStationBusinessConfig')) {
|
||||
@include_once APP_PATH . 'app/helpers/station_business_helper.php';
|
||||
}
|
||||
if (function_exists('getStationBusinessConfig')) {
|
||||
$bizConfig = getStationBusinessConfig($stationType);
|
||||
if ($bizConfig && !empty($bizConfig['dataMapping'])) {
|
||||
foreach ($bizConfig['dataMapping'] as $dbField => $postKey) {
|
||||
if ($postKey === '__operator__') continue;
|
||||
if (in_array($dbField, $baseFields) || in_array($dbField, $addedFields)) continue;
|
||||
$columns[] = "`{$dbField}` VARCHAR(200) DEFAULT NULL COMMENT '{$dbField}'";
|
||||
$addedFields[] = $dbField;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$allColumns = implode(",\n ", $columns);
|
||||
$allIndexes = !empty($indexes) ? ",\n " . implode(",\n ", $indexes) : '';
|
||||
|
||||
$sql = "CREATE TABLE `{$fullTable}` (\n {$allColumns}{$allIndexes}\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='{$stationType} 工位数据表'";
|
||||
|
||||
try {
|
||||
$this->execute($sql);
|
||||
error_log("[StationDefinition] Auto-created table: {$fullTable} for station_type={$stationType}, extra fields: " . implode(', ', $addedFields));
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
error_log("[StationDefinition] Failed to create table {$fullTable}: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 确保工位列存在(表已存在时补充缺失的列)
|
||||
* 当 fields_config 新增字段后,自动 ALTER TABLE 添加
|
||||
*/
|
||||
public function ensureColumns($stationType, $fieldConfigs = [])
|
||||
{
|
||||
$def = $this->getByType($stationType);
|
||||
if (!$def) return;
|
||||
|
||||
$fullTable = self::TABLE_PREFIX . $def['db_table'];
|
||||
|
||||
// 检查表是否存在
|
||||
$exists = $this->query("SHOW TABLES LIKE '{$fullTable}'");
|
||||
if (empty($exists)) {
|
||||
// 表不存在,走建表流程
|
||||
return $this->ensureTable($stationType, $fieldConfigs);
|
||||
}
|
||||
|
||||
// 获取现有列
|
||||
$existingCols = $this->query("SHOW COLUMNS FROM `{$fullTable}`");
|
||||
$existingNames = [];
|
||||
foreach ($existingCols as $col) {
|
||||
$existingNames[] = strtolower($col['Field']);
|
||||
}
|
||||
|
||||
// 基础字段名
|
||||
$baseFields = ['product_type', 'product_model', 'operator', 'created_at', 'id'];
|
||||
|
||||
foreach ($fieldConfigs as $field) {
|
||||
$name = $field['name'] ?? '';
|
||||
$type = $field['type'] ?? 'text';
|
||||
if (in_array($name, $baseFields) || empty($name)) continue;
|
||||
if (in_array($name, ['_meta'])) continue;
|
||||
if (in_array(strtolower($name), $existingNames)) continue;
|
||||
|
||||
$colType = 'VARCHAR(200)';
|
||||
if ($type === 'number') {
|
||||
$colType = 'VARCHAR(50)';
|
||||
} elseif ($type === 'textarea') {
|
||||
$colType = 'TEXT';
|
||||
}
|
||||
|
||||
$label = $field['label'] ?? $name;
|
||||
$comment = addslashes($label);
|
||||
|
||||
try {
|
||||
$this->execute("ALTER TABLE `{$fullTable}` ADD COLUMN `{$name}` {$colType} DEFAULT NULL COMMENT '{$comment}'");
|
||||
error_log("[StationDefinition] Added column `{$name}` to {$fullTable}");
|
||||
} catch (\Throwable $e) {
|
||||
error_log("[StationDefinition] Failed to add column `{$name}` to {$fullTable}: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动创建 station_definitions 表并初始化内置工位数据
|
||||
* @return bool 是否成功
|
||||
*/
|
||||
/**
|
||||
* 获取所有内置工位的默认定义数据
|
||||
*/
|
||||
private function getBuiltinDefaults()
|
||||
{
|
||||
return [
|
||||
['station_type' => 'inbound', 'db_table' => 'station_inbound', 'time_column' => 'created_at', 'has_product_type' => 1, 'has_product_model' => 1, 'filter_enabled' => 1, 'show_today_count' => 1, 'show_total_count' => 1, 'extra_config' => '{"alt_table":"warehouse_in","alt_time_column":"in_time","alt_condition_field":"product_type","alt_condition_value":"成品"}'],
|
||||
['station_type' => 'pcb_test', 'db_table' => 'pcb_test', 'time_column' => 'created_at', 'has_product_type' => 1, 'has_product_model' => 1, 'filter_enabled' => 1, 'show_today_count' => 1, 'show_total_count' => 1, 'extra_config' => ''],
|
||||
['station_type' => 'battery', 'db_table' => 'battery_status', 'time_column' => 'created_at', 'has_product_type' => 1, 'has_product_model' => 1, 'filter_enabled' => 1, 'show_today_count' => 1, 'show_total_count' => 1, 'extra_config' => ''],
|
||||
['station_type' => 'assembly', 'db_table' => 'product_assembly', 'time_column' => 'assembly_time', 'has_product_type' => 0, 'has_product_model' => 1, 'filter_enabled' => 1, 'show_today_count' => 1, 'show_total_count' => 1, 'extra_config' => ''],
|
||||
['station_type' => 'finished_test','db_table' => 'finished_test', 'time_column' => 'test_time', 'has_product_type' => 0, 'has_product_model' => 1, 'filter_enabled' => 1, 'show_today_count' => 1, 'show_total_count' => 1, 'extra_config' => ''],
|
||||
['station_type' => 'delivery', 'db_table' => 'delivery', 'time_column' => 'delivery_time', 'has_product_type' => 0, 'has_product_model' => 1, 'filter_enabled' => 1, 'show_today_count' => 1, 'show_total_count' => 1, 'extra_config' => ''],
|
||||
['station_type' => 'warehouse', 'db_table' => 'warehouse_in', 'time_column' => 'in_time', 'has_product_type' => 0, 'has_product_model' => 1, 'filter_enabled' => 0, 'show_today_count' => 0, 'show_total_count' => 0, 'extra_config' => ''],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入/更新内置工位默认数据(ON DUPLICATE KEY UPDATE)
|
||||
*
|
||||
* 使用 ON DUPLICATE KEY UPDATE 而非 INSERT IGNORE,确保即使表中有旧数据,
|
||||
* 也能更新为正确的默认值(修复数据损坏/不完整的情况)。
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function insertBuiltinDefaults()
|
||||
{
|
||||
$fullTable = $this->getTable();
|
||||
$defaults = $this->getBuiltinDefaults();
|
||||
$insertSql = "INSERT INTO `{$fullTable}`
|
||||
(`station_type`, `db_table`, `time_column`, `has_product_type`, `has_product_model`,
|
||||
`filter_enabled`, `show_today_count`, `show_total_count`, `extra_config`)
|
||||
VALUES (:st, :dt, :tc, :hpt, :hpm, :fe, :stc, :sttc, :ec)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`db_table` = VALUES(`db_table`),
|
||||
`time_column` = VALUES(`time_column`),
|
||||
`has_product_type` = VALUES(`has_product_type`),
|
||||
`has_product_model` = VALUES(`has_product_model`),
|
||||
`filter_enabled` = VALUES(`filter_enabled`),
|
||||
`show_today_count` = VALUES(`show_today_count`),
|
||||
`show_total_count` = VALUES(`show_total_count`),
|
||||
`extra_config` = VALUES(`extra_config`)";
|
||||
try {
|
||||
// 使用 $this->execute() 而非直接访问 $this->pdo,
|
||||
// 确保在 Model 构造链完整的情况下执行
|
||||
$affected = 0;
|
||||
foreach ($defaults as $d) {
|
||||
$params = [
|
||||
':st' => $d['station_type'],
|
||||
':dt' => $d['db_table'],
|
||||
':tc' => $d['time_column'],
|
||||
':hpt' => $d['has_product_type'],
|
||||
':hpm' => $d['has_product_model'],
|
||||
':fe' => $d['filter_enabled'],
|
||||
':stc' => $d['show_today_count'],
|
||||
':sttc' => $d['show_total_count'],
|
||||
':ec' => $d['extra_config'],
|
||||
];
|
||||
// execute() 返回 bool,rowCount() 需要通过 pdo 获取
|
||||
if ($this->execute($insertSql, $params)) {
|
||||
$affected++;
|
||||
}
|
||||
}
|
||||
if ($affected > 0) {
|
||||
error_log('[StationDefinition] Upserted ' . $affected . ' built-in station definitions');
|
||||
}
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
error_log('[StationDefinition] insertBuiltinDefaults failed: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function autoCreateTable()
|
||||
{
|
||||
$fullTable = $this->getTable();
|
||||
try {
|
||||
// 检查表是否存在
|
||||
$exists = $this->query("SHOW TABLES LIKE '{$fullTable}'");
|
||||
if (empty($exists)) {
|
||||
// 创建表
|
||||
$sql = "CREATE TABLE IF NOT EXISTS `{$fullTable}` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`station_type` VARCHAR(50) NOT NULL UNIQUE COMMENT '工位类型标识',
|
||||
`db_table` VARCHAR(100) NOT NULL COMMENT '数据表名(不含前缀)',
|
||||
`time_column` VARCHAR(50) NOT NULL DEFAULT 'created_at' COMMENT '时间列名',
|
||||
`has_product_type` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否有 product_type 列',
|
||||
`has_product_model` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否有 product_model 列',
|
||||
`filter_enabled` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用筛选',
|
||||
`show_today_count` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '显示今日计数',
|
||||
`show_total_count` TINYINT(1) NOT NULL DEFAULT 1 COMMENT '显示总计数',
|
||||
`extra_config` TEXT COMMENT '额外配置(JSON)',
|
||||
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
INDEX `idx_station_type` (`station_type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='工位定义统一配置表'";
|
||||
$this->execute($sql);
|
||||
error_log('[StationDefinition] Auto-created table: ' . $fullTable);
|
||||
}
|
||||
|
||||
// 无论表是否刚创建,确保内置工位数据存在
|
||||
// (表可能已存在但数据不完整,例如之前创建失败只建了表没插入数据)
|
||||
$this->insertBuiltinDefaults();
|
||||
|
||||
return true;
|
||||
} catch (\Throwable $e) {
|
||||
error_log('[StationDefinition] autoCreateTable failed: ' . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存(数据更新后调用)
|
||||
*/
|
||||
public static function clearCache()
|
||||
{
|
||||
self::$cache = [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user