Files
xianyan/docs/toolsapi/application/api/controller/PluginUpdate.php
Developer 5a083bdbab feat: 新增多模块后端管理、数据同步工具与鸿蒙路由适配
本次提交新增了以下核心内容:
1. 后端管理模块:包含字体同步、插件元数据、插件用户设置、稍后读消息/共享列表的控制器、模型、验证器与多语言配置
2. Flutter数据同步模块:统一的事件总线与兼容层,替代分散的StreamController
3. 鸿蒙端路由适配:完整的路由定义、构建器与占位组件
4. 后端API接口:字体同步与插件更新的服务端API,支持自动建表与跨域请求
5. 鸿蒙权限校验脚本:用于校验module.json5与string.json的权限声明一致性
2026-06-01 05:50:13 +08:00

363 lines
13 KiB
PHP
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
namespace app\api\controller;
use app\common\controller\Api;
use think\Db;
use think\Config;
use think\exception\HttpResponseException;
/**
* 插件更新 — 服务端API
* 创建时间: 2026-06-01
* 更新时间: 2026-06-01
* 作用: 替代Supabase插件表提供插件版本检查、状态同步
* 上次更新: v1.0 初始版本
*/
class PluginUpdate extends Api
{
protected $noNeedLogin = ['checkOne', 'queryOne', 'checkAll', 'install'];
protected $noNeedRight = '*';
public function _initialize()
{
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization, Token');
if ($this->request->method() === 'OPTIONS') {
http_response_code(204);
exit;
}
parent::_initialize();
$this->ensureTables();
}
// ─── 自动建表 ──────────────────────────────────────────
private function ensureTables()
{
static $created = false;
if ($created) return;
$created = true;
$prefix = Config::get('database.prefix') ?: 'tool_';
$sqls = [];
$sqls[] = "CREATE TABLE IF NOT EXISTS `{$prefix}plugin_meta` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`plugin_id` varchar(128) NOT NULL DEFAULT '' COMMENT '插件唯一ID',
`platform` varchar(32) NOT NULL DEFAULT 'all' COMMENT '平台: ios/android/all',
`name` varchar(256) NOT NULL DEFAULT '' COMMENT '插件名称',
`version` varchar(32) NOT NULL DEFAULT '' COMMENT '最新版本号',
`version_code` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '版本数字编码',
`download_url` varchar(512) NOT NULL DEFAULT '' COMMENT '下载地址',
`changelog` text COMMENT '更新日志',
`min_app_version` varchar(32) NOT NULL DEFAULT '' COMMENT '最低应用版本',
`is_active` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
`file_size` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '文件大小(字节)',
`md5` varchar(64) NOT NULL DEFAULT '' COMMENT '文件MD5',
`created_at` int(11) unsigned NOT NULL DEFAULT 0,
`updated_at` int(11) unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_plugin_platform` (`plugin_id`, `platform`),
KEY `idx_platform` (`platform`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='插件元数据'";
$sqls[] = "CREATE TABLE IF NOT EXISTS `{$prefix}plugin_user_settings` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '用户ID',
`platform` varchar(32) NOT NULL DEFAULT 'all' COMMENT '平台',
`settings` text COMMENT '设置JSON',
`created_at` int(11) unsigned NOT NULL DEFAULT 0,
`updated_at` int(11) unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_platform` (`user_id`, `platform`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='插件用户设置'";
foreach ($sqls as $sql) {
try {
Db::execute($sql);
} catch (\Exception $e) {
}
}
}
// ─── 检查更新 ──────────────────────────────────────────
/**
* 检查单个插件更新
* GET /api/plugin_update/checkOne
* 参数: id(或pid/plugin_id/keyword), platform
* 无需登录
*/
public function checkOne()
{
return $this->queryOne();
}
/**
* 查询单个插件更新信息
* GET /api/plugin_update/queryOne
* 参数: plugin_id, platform
* 无需登录
*/
public function queryOne()
{
$pluginId = $this->request->param('keyword', '');
if (empty($pluginId)) {
$pluginId = $this->request->param('id', '');
}
if (empty($pluginId)) {
$pluginId = $this->request->param('pid', '');
}
if (empty($pluginId)) {
$pluginId = $this->request->param('plugin_id', '');
}
$platform = $this->request->param('platform', 'all');
if (empty($pluginId)) {
$this->error('plugin_id必填', null, 400);
}
try {
$plugin = Db::name('plugin_meta')
->where('plugin_id', $pluginId)
->where('platform', $platform)
->where('is_active', 1)
->find();
if (!$plugin) {
$allPlatform = Db::name('plugin_meta')
->where('plugin_id', $pluginId)
->where('platform', 'all')
->where('is_active', 1)
->find();
if ($allPlatform) {
$plugin = $allPlatform;
}
}
if (!$plugin) {
$this->error('插件不存在', null, 404);
}
$this->success('获取成功', [
'plugin_id' => $plugin['plugin_id'],
'name' => $plugin['name'],
'version' => $plugin['version'],
'version_code' => intval($plugin['version_code']),
'download_url' => $plugin['download_url'],
'changelog' => $plugin['changelog'],
'min_app_version' => $plugin['min_app_version'],
'file_size' => intval($plugin['file_size']),
'md5' => $plugin['md5'],
'platform' => $plugin['platform'],
'updated_at' => intval($plugin['updated_at']),
]);
} catch (HttpResponseException $e) {
throw $e;
} catch (\Exception $e) {
$this->error('检查更新失败: ' . $e->getMessage(), null, 500);
}
}
/**
* 检查所有插件更新
* GET /api/plugin_update/checkAll
* 参数: platform
* 无需登录
*/
public function checkAll()
{
$platform = $this->request->param('platform', 'all');
try {
$plugins = Db::name('plugin_meta')
->where(function ($query) use ($platform) {
$query->where('platform', $platform)
->whereOr('platform', 'all');
})
->where('is_active', 1)
->order('updated_at', 'desc')
->select();
$list = [];
foreach ($plugins as $plugin) {
$list[] = [
'plugin_id' => $plugin['plugin_id'],
'name' => $plugin['name'],
'version' => $plugin['version'],
'version_code' => intval($plugin['version_code']),
'download_url' => $plugin['download_url'],
'changelog' => $plugin['changelog'],
'min_app_version' => $plugin['min_app_version'],
'file_size' => intval($plugin['file_size']),
'md5' => $plugin['md5'],
'platform' => $plugin['platform'],
'updated_at' => intval($plugin['updated_at']),
];
}
$this->success('获取成功', [
'plugins' => $list,
'count' => count($list),
]);
} catch (HttpResponseException $e) {
throw $e;
} catch (\Exception $e) {
$this->error('检查更新失败: ' . $e->getMessage(), null, 500);
}
}
// ─── 状态同步 ──────────────────────────────────────────
/**
* 同步插件状态到云端
* POST /api/plugin_update/syncState
* 参数: platform, settings(JSON)
* 需登录
*/
public function syncState()
{
$userId = $this->auth->id;
$platform = $this->request->post('platform', 'all');
$settings = $this->request->post('settings', '');
if (empty($settings)) {
$this->error('settings必填', null, 400);
}
try {
$existing = Db::name('plugin_user_settings')
->where(['user_id' => $userId, 'platform' => $platform])
->find();
$now = time();
if ($existing) {
Db::name('plugin_user_settings')
->where(['user_id' => $userId, 'platform' => $platform])
->update([
'settings' => $settings,
'updated_at' => $now,
]);
} else {
Db::name('plugin_user_settings')->insert([
'user_id' => $userId,
'platform' => $platform,
'settings' => $settings,
'created_at' => $now,
'updated_at' => $now,
]);
}
$this->success('同步成功', [
'platform' => $platform,
'updated_at' => $now,
]);
} catch (HttpResponseException $e) {
throw $e;
} catch (\Exception $e) {
$this->error('同步失败: ' . $e->getMessage(), null, 500);
}
}
/**
* 从云端加载插件状态
* GET /api/plugin_update/loadState
* 参数: platform
* 需登录
*/
public function loadState()
{
$userId = $this->auth->id;
$platform = $this->request->param('platform', 'all');
try {
$record = Db::name('plugin_user_settings')
->where(['user_id' => $userId, 'platform' => $platform])
->find();
if (!$record) {
$this->success('暂无数据', [
'settings' => null,
'platform' => $platform,
'updated_at' => 0,
]);
return;
}
$this->success('获取成功', [
'settings' => $record['settings'],
'platform' => $record['platform'],
'updated_at' => intval($record['updated_at']),
]);
} catch (HttpResponseException $e) {
throw $e;
} catch (\Exception $e) {
$this->error('加载失败: ' . $e->getMessage(), null, 500);
}
}
// ─── 安装接口 ──────────────────────────────────────────
/**
* 安装/升级数据库表
* POST /api/plugin_update/install
*/
public function install()
{
$prefix = Config::get('database.prefix') ?: 'tool_';
$sqls = [];
$sqls[] = "CREATE TABLE IF NOT EXISTS `{$prefix}plugin_meta` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`plugin_id` varchar(128) NOT NULL DEFAULT '' COMMENT '插件唯一ID',
`platform` varchar(32) NOT NULL DEFAULT 'all' COMMENT '平台: ios/android/all',
`name` varchar(256) NOT NULL DEFAULT '' COMMENT '插件名称',
`version` varchar(32) NOT NULL DEFAULT '' COMMENT '最新版本号',
`version_code` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '版本数字编码',
`download_url` varchar(512) NOT NULL DEFAULT '' COMMENT '下载地址',
`changelog` text COMMENT '更新日志',
`min_app_version` varchar(32) NOT NULL DEFAULT '' COMMENT '最低应用版本',
`is_active` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
`file_size` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT '文件大小(字节)',
`md5` varchar(64) NOT NULL DEFAULT '' COMMENT '文件MD5',
`created_at` int(11) unsigned NOT NULL DEFAULT 0,
`updated_at` int(11) unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_plugin_platform` (`plugin_id`, `platform`),
KEY `idx_platform` (`platform`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='插件元数据'";
$sqls[] = "CREATE TABLE IF NOT EXISTS `{$prefix}plugin_user_settings` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '用户ID',
`platform` varchar(32) NOT NULL DEFAULT 'all' COMMENT '平台',
`settings` text COMMENT '设置JSON',
`created_at` int(11) unsigned NOT NULL DEFAULT 0,
`updated_at` int(11) unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_platform` (`user_id`, `platform`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='插件用户设置'";
$results = [];
foreach ($sqls as $sql) {
try {
Db::execute($sql);
$results[] = 'ok';
} catch (\Exception $e) {
$results[] = $e->getMessage();
}
}
$this->success('安装完成', [
'tables' => count($sqls),
'results' => $results,
]);
}
}