'ad', 'strict' => true, 'autoWriteTimestamp' => true, 'createTime' => 'create_at', 'updateTime' => 'update_at', 'deleteTime' => 'delete_at', ]; } protected $type = [ 'id' => 'integer', 'type' => 'integer', 'sort' => 'integer', 'status' => 'integer', 'create_at' => 'integer', 'update_at' => 'integer', 'delete_at' => 'integer', ]; protected $readonly = []; public static function typeList(): array { return [ self::TYPE_IMAGE => '图片', self::TYPE_TEXT => '文字', self::TYPE_CODE => '代码', ]; } public static function positionList(): array { return [ self::POS_HOME_TOP => '首页顶部横幅', self::POS_HOME_SIDE => '首页侧边', self::POS_POPUP => '全站弹窗', self::POS_LIST_BOTTOM => '列表底部', self::POS_HOME_BOTTOM => '首页底部', self::POS_CONTENT_TOP => '内容页顶部', self::POS_CONTENT_BOTTOM => '内容页底部', self::POS_SIDEBAR => '通用侧边栏', self::POS_FLOAT => '全站悬浮角标', ]; } /** * 运行时自愈:确保 ad 表存在 position 列,避免老库缺列导致列表/取数报错 */ public static function ensureSchema(): void { try { $p = self::currentPrefix(); $prefix = $p; $table = $prefix . 'ad'; // 缺表建表(install.sql L638 同款 DDL,运行时前缀兜底) BaseModel::ensureTable($table, "CREATE TABLE IF NOT EXISTS `{$p}ad` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `title` varchar(200) NOT NULL DEFAULT '' COMMENT '广告标题', `type` tinyint(1) NOT NULL DEFAULT 1 COMMENT '类型 1图片2文字3代码', `position` varchar(50) NOT NULL DEFAULT '' COMMENT '广告位标识 home_top首页顶部 home_side首页侧边 popup全站弹窗 list_bottom列表底部', `content` text COMMENT '广告内容/代码', `url` varchar(255) NOT NULL DEFAULT '' COMMENT '跳转链接', `image` varchar(255) NOT NULL DEFAULT '' COMMENT '图片地址', `sort` int(11) NOT NULL DEFAULT 0 COMMENT '排序', `status` tinyint(1) NOT NULL DEFAULT 1 COMMENT '状态', `create_at` int(11) NOT NULL DEFAULT 0 COMMENT '创建时间', `update_at` int(11) NOT NULL DEFAULT 0 COMMENT '更新时间', `delete_at` int(11) NOT NULL DEFAULT 0 COMMENT '删除时间', PRIMARY KEY (`id`), KEY `idx_position` (`position`), KEY `idx_status_sort` (`status`,`sort`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='站点广告'"); // 老库扩展列兜底(幂等) BaseModel::ensureColumn($table, 'position', "varchar(50) NOT NULL DEFAULT '' COMMENT '广告位标识'"); } catch (\Throwable $e) { // 自愈失败不影响主流程 } } /** * 按广告位取启用广告(按 sort 升序) * @param string $position 广告位标识 * @return array */ public static function getByPosition(string $position): array { self::ensureSchema(); $rows = Db::name('ad') ->where('status', 1) ->where('position', $position) ->where('delete_at', 0) ->order('sort', 'asc') ->order('id', 'desc') ->select() ->toArray(); $typeList = self::typeList(); foreach ($rows as &$row) { $row['type_text'] = $typeList[$row['type']] ?? '图片'; } return $rows; } /** * 取全部启用广告,按 position 分组,便于前台模板随处调用 * @return array [position => [ad, ...]] */ public static function getSlots(): array { self::ensureSchema(); $positions = array_keys(self::positionList()); $slots = array_fill_keys($positions, []); $rows = Db::name('ad') ->where('status', 1) ->where('position', 'in', $positions) ->where('delete_at', 0) ->order('sort', 'asc') ->order('id', 'desc') ->select() ->toArray(); $typeList = self::typeList(); foreach ($rows as $row) { $row['type_text'] = $typeList[$row['type']] ?? '图片'; $slots[$row['position']][] = $row; } return $slots; } }