本次提交新增了以下核心内容: 1. 后端管理模块:包含字体同步、插件元数据、插件用户设置、稍后读消息/共享列表的控制器、模型、验证器与多语言配置 2. Flutter数据同步模块:统一的事件总线与兼容层,替代分散的StreamController 3. 鸿蒙端路由适配:完整的路由定义、构建器与占位组件 4. 后端API接口:字体同步与插件更新的服务端API,支持自动建表与跨域请求 5. 鸿蒙权限校验脚本:用于校验module.json5与string.json的权限声明一致性
363 lines
13 KiB
PHP
363 lines
13 KiB
PHP
<?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,
|
||
]);
|
||
}
|
||
}
|