更新插件中心功能

This commit is contained in:
技术老胡 2025-02-28 14:23:39 +08:00
parent 3b02869b5d
commit d5c43e28af
8 changed files with 226 additions and 54 deletions

View File

@ -149,7 +149,7 @@ EOT;
`password` varchar(255) NOT NULL DEFAULT '' COMMENT '密码', `password` varchar(255) NOT NULL DEFAULT '' COMMENT '密码',
`state` tinyint(4) NOT NULL DEFAULT '1' COMMENT '启用', `state` tinyint(4) NOT NULL DEFAULT '1' COMMENT '启用',
`pattern` tinyint(4) NOT NULL DEFAULT '1' COMMENT '账号监听模式', `pattern` tinyint(4) NOT NULL DEFAULT '1' COMMENT '账号监听模式',
`params` text NOT NULL DEFAULT '' COMMENT '自定义查询', `params` text NOT NULL COMMENT '自定义查询',
`delete_time` timestamp NULL DEFAULT NULL COMMENT '软删除', `delete_time` timestamp NULL DEFAULT NULL COMMENT '软删除',
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;"; ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;";

View File

@ -227,6 +227,9 @@ class PayController
$params = $config['params']; $params = $config['params'];
// 实例监听客户端 // 实例监听客户端
$payclient_name = $config['payclass']; $payclient_name = $config['payclass'];
// 插件类文件是否存在
$payclient_path = root_path() . '/extend/payclient/' . $payclient_name . '.php';
if (!file_exists($payclient_path)) return json(['code' => 5, 'msg' => '监听客户端文件不存在']);
$payclient_path = "\\payclient\\{$payclient_name}"; $payclient_path = "\\payclient\\{$payclient_name}";
$Payclient = new $payclient_path($pay_config); $Payclient = new $payclient_path($pay_config);
// 获取支付明细 // 获取支付明细

View File

@ -25,42 +25,76 @@ class PluginController extends BaseController
return json(['code' => 1, 'msg' => '无数据记录', 'count' => 0, 'data' => []]); return json(['code' => 1, 'msg' => '无数据记录', 'count' => 0, 'data' => []]);
} }
} }
// 安装插件
public function installPlugin()
{
$platform = $this->request->post('platform');
if (!$platform) return json(backMsg(1, '请选择插件'));
$intall_info = \Plugin::installPlugin($platform);
if ($intall_info['code'] !== 0) return json(backMsg(1, $intall_info['msg']));
// 需要授权
if ($intall_info['data']['status'] === 0) {
return json(['code' => 0, 'msg' => '请支付', 'state' => 0, 'data' => $intall_info['data']]);
}
$saved = $this->saveNewPluginConfig($intall_info['data']);
if ($saved['code'] !== 0) return json(backMsg(1, $saved['msg']));
return json(['code' => 0, 'msg' => '授权成功', 'state' => 1]);
}
// 更新插件
public function updatePlugin()
{
$platform = $this->request->post('platform');
if (!$platform) return json(backMsg(1, '请选择插件'));
$update_info = \Plugin::updatePlugin($platform);
if ($update_info['code'] !== 0) return json(backMsg(1, $update_info['msg']));
$saved = $this->saveNewPluginConfig($update_info['data']);
if ($saved['code'] !== 0) return json(backMsg(1, $saved['msg']));
return json(['code' => 0, 'msg' => '更新成功']);
}
// 保存全部插件信息
private function saveNewPluginConfig(array $config = [])
{
$plugin_config = $config['config'];
$plugin_auth = $config['authcode'];
$plugin_file = $config['file'];
if (!$this->savePluginFile($plugin_file, $plugin_config)) return backMsg(1, '保存插件文件失败');
if (!$this->saveAuthCode($plugin_auth, $plugin_config)) return backMsg(1, '保存插件授权码失败');
if (!$this->addPlugin($plugin_config)) return backMsg(1, '保存插件配置失败');
return backMsg(0, 'ok');
}
// 卸载插件 // 卸载插件
public function uninstallPlugin() public function uninstallPlugin()
{ {
$platform = $this->request->post('platform'); $platform = $this->request->post('platform');
$classname = $this->request->post('classname'); if (!$platform) return json(backMsg(1, '请选择插件'));
if (!$platform || !$classname) { $res2 = $this->delPluginFile($platform);
return json(backMsg(1, '请选择插件')); if (!$res2) return json(backMsg(1, '插件文件不存在'));
}
$res1 = $this->delPlugin($platform); $res1 = $this->delPlugin($platform);
$res2 = $this->delPluginFile($classname); if (!$res1) return json(backMsg(1, '插件配置不存在'));
if ($res1 && $res2) { return json(backMsg(0, '卸载成功'));
return json(backMsg(0, '卸载成功'));
} else {
return json(backMsg(1, '插件不存在'));
}
} }
// 添加插件 // 添加或更新插件
public function addPlugin(array $option = []) public function addPlugin(array $option = [])
{ {
$keys = ['platform', 'name', 'class_name', 'price', 'describe', 'website', 'state']; $keys = ['platform', 'name', 'class_name', 'price', 'describe', 'website', 'helplink', 'version'];
$config = []; $config = [];
foreach ($option as $key => $value) { foreach ($option as $key => $value) {
if (in_array($key, $keys)) { if (in_array($key, $keys)) $config[$key] = $value;
$config[$key] = $value;
}
} }
$config['state'] = 1;
$plugin_config = self::getPluginConfig(); $plugin_config = self::getPluginConfig();
$plugin_platform = $config['platform'] ?: ''; $plugin_platform = $config['platform'] ?: '';
foreach ($plugin_config as $value) { foreach ($plugin_config as $i => $value) {
if ($plugin_platform == $value['platform']) { if ($plugin_platform == $value['platform']) {
return 1; //'插件已存在' $plugin_config[$i] = $config;
$this->savePluginConfig($plugin_config, '支付插件列表');
return true;
} }
} }
$plugin_config[] = $config; $plugin_config[] = $config;
$this->savePluginConfig($plugin_config, '支付插件列表'); $this->savePluginConfig($plugin_config, '支付插件列表');
return 0; return true;
} }
// 删除插件配置 // 删除插件配置
private function delPlugin(string $plugin_name = '') private function delPlugin(string $plugin_name = '')
@ -70,37 +104,31 @@ class PluginController extends BaseController
foreach ($plugin_config as $i => $value) { foreach ($plugin_config as $i => $value) {
if ($value['platform'] == $plugin_name) { if ($value['platform'] == $plugin_name) {
$index = $i; $index = $i;
break;
} }
} }
if ($index === null) { if ($index === null) return false;
return false; // 插件不存在
}
unset($plugin_config[$index]); unset($plugin_config[$index]);
$config = array_values($plugin_config); $config = array_values($plugin_config);
$this->savePluginConfig($config, '支付插件列表'); $this->savePluginConfig($config, '支付插件列表');
return true; return true;
} }
// 删除插件类库文件 // 删除插件类库文件
private function delPluginFile(string $file_name = '') private function delPluginFile(string $platform = '')
{ {
$file_name = self::getPluginInfo($platform)['class_name'];
if (!$file_name) return false;
$plugin_path = root_path() . '/extend/payclient/' . $file_name . '.php'; $plugin_path = root_path() . '/extend/payclient/' . $file_name . '.php';
if (file_exists($plugin_path)) { if (!file_exists($plugin_path)) return false;
unlink($plugin_path); unlink($plugin_path);
return true; return true;
} else {
return false;
}
} }
// 修改插件 // 修改插件
public function setPlugin($platform = '', $option = []) public function setPlugin($platform = '', $option = [])
{ {
$config = self::getPluginConfig(); $config = self::getPluginConfig();
if (!$platform) { if (!$platform) return 1;
return 1; // 请选择插件 if (!$option) return 2;
}
if (!$option) {
return 2; // 请添加插件配置
}
foreach ($config as $index => $options) { foreach ($config as $index => $options) {
if ($options['platform'] == $platform) { if ($options['platform'] == $platform) {
foreach ($options as $key => $value) { foreach ($options as $key => $value) {
@ -166,6 +194,25 @@ class PluginController extends BaseController
} }
return $info; return $info;
} }
// 保存授权码
private function saveAuthCode(string $authcode = '', array $config = [])
{
$dir_path = runtime_path() . "auth/";
if (!is_dir($dir_path)) mkdir($dir_path, 755, true);
$auth_path = $dir_path . md5($config['platform'] . $config['class_name']) . '.json';
return file_put_contents($auth_path, json_encode(['authcode' => $authcode])) !== false ? true : false;
}
// 保存插件类库文件
private function savePluginFile($file_url = '', array $config = [])
{
if (empty($file_url)) return false;
$file_content = @file_get_contents($file_url);
if ($file_content === false) return false;
$save_dir = root_path() . 'extend/payclient/';
if (!is_dir($save_dir)) mkdir($save_dir, 0755, true);
$save_path = $save_dir . $config['class_name'] . '.php';
return file_put_contents($save_path, $file_content) !== false ? true : false;
}
// 获取插件配置 // 获取插件配置
private static function getPluginConfig(): array private static function getPluginConfig(): array
{ {

View File

@ -3,4 +3,29 @@
// | 支付插件列表 // | 支付插件列表
// +---------------------------------------------------------------------- // +----------------------------------------------------------------------
return array(); return array (
0 =>
array (
'platform' => 'wxpay',
'name' => '微信支付',
'class_name' => 'WxPay',
'price' => NULL,
'describe' => '支持微信个人收款码、赞赏码、经营码、商家码收款,监听回调',
'website' => 'https://weixin.qq.com',
'helplink' => '',
'version' => '1.0',
'state' => 1,
),
1 =>
array (
'platform' => 'ysepay',
'name' => '小Y经营',
'class_name' => 'YsePay',
'price' => NULL,
'describe' => '为商户和消费者提供安全、便捷、高效的支付产品与服务助力商户提升运营效率,实现数字化运营',
'website' => 'https://xym.ysepay.com',
'helplink' => '',
'version' => '1.0',
'state' => 1,
),
);

View File

@ -54,7 +54,7 @@ class Plugin
{ {
$app_plugin = cache('app_plugin'); $app_plugin = cache('app_plugin');
if ($app_plugin) return $app_plugin; if ($app_plugin) return $app_plugin;
$app_plugin = self::getHttpResponse(self::$siteUrl . '/mpayapi', ['action' => 'getPluginList']); $app_plugin = self::getHttpResponse(self::$siteUrl . '/MpayApi', ['action' => 'getPluginList']);
$info = json_decode($app_plugin, true); $info = json_decode($app_plugin, true);
if ($info['code'] === 0) cache('app_plugin', $info['data'], 36000); if ($info['code'] === 0) cache('app_plugin', $info['data'], 36000);
return $info['data']; return $info['data'];
@ -63,13 +63,24 @@ class Plugin
public static function getNotifyMessage(): array public static function getNotifyMessage(): array
{ {
$message = cache('message'); $message = cache('message');
if ($message) { if ($message) return json_decode($message, true);
return json_decode($message, true); $message = self::getHttpResponse(self::$siteUrl . '/MpayApi', ['action' => 'message']);
}
$message = self::getHttpResponse(self::$siteUrl . '/mpay/message');
cache('message', $message, 36000); cache('message', $message, 36000);
return json_decode($message, true); return json_decode($message, true);
} }
// 安装插件
public static function installPlugin($platform): array
{
$res = self::getHttpResponse(self::$siteUrl . '/MpayApi', ['action' => 'installPlugin', 'platform' => $platform, 'host' => parse_url(request()->domain(), PHP_URL_HOST)]);
// halt($res);
return json_decode($res, true);
}
// 更新插件
public static function updatePlugin($platform): array
{
$res = self::getHttpResponse(self::$siteUrl . '/MpayApi', ['action' => 'updatePlugin', 'platform' => $platform, 'host' => parse_url(request()->domain(), PHP_URL_HOST)]);
return json_decode($res, true);
}
// 请求外部资源 // 请求外部资源
private static function getHttpResponse($url, $post = null, $header = [], $timeout = 10) private static function getHttpResponse($url, $post = null, $header = [], $timeout = 10)
{ {

Binary file not shown.

View File

@ -349,7 +349,8 @@
type: 2, type: 2,
title: '订单详细', title: '订单详细',
shade: 0.1, shade: 0.1,
area: [common.isModile() ? '100%' : '500px', common.isModile() ? '100%' : '800px'], offset: '10px',
area: [common.isModile() ? '100%' : '500px', common.isModile() ? '100%' : '640px'],
content: `/Order/showOrder?id=${id}`, content: `/Order/showOrder?id=${id}`,
}); });
} }

View File

@ -57,15 +57,36 @@
<a href="javascript:;" class="layui-font-green" lay-event="pluginInstall">立即安装</a> <a href="javascript:;" class="layui-font-green" lay-event="pluginInstall">立即安装</a>
{{# } }} {{# } }}
</script> </script>
<script type="text/html" id="plugin-pay">
<div class="layui-bg-gray layui-padding-3" style="height: 100%;">
<div class="layui-card" style="max-width: 320px;min-width: 240px;margin: 0 auto;text-align: center;">
<div class="layui-card-header">
<strong>请使用<span>{{= d.paytype==='alipay'?' 支付宝 ':' 微信支付 ' }}</span>付款</strong>
</div>
<div class="layui-card-body">
<div class="price"><p><strong>{{= d.money }}</strong></p><p>商品:{{= d.name }}</p><p>订单:{{= d.orderid }}</p></div>
<div class="layui-padding-3 paycode"><img id="qrcode" src="/static/img/loading.gif" width="100%" /></div>
<div class="note">
<p>支付<span>{{= d.money }}</span>元,不要多付或少付</p>
<p><span>{{= d.closetime }}</span> 前支付</p>
<p>支付完成点击确认支付,过期请不要支付</p>
</div>
</div>
</div>
</div>
</script>
<script src="/component/layui/layui.js"></script> <script src="/component/layui/layui.js"></script>
<script src="/component/pear/pear.js"></script> <script src="/component/pear/pear.js"></script>
<script src="/static/js/awesome-qr.min.js"></script>
<script> <script>
layui.use(['layer', 'form', 'common', 'layer'], function () { const QR = AwesomeQR.AwesomeQR;
layui.use(['layer', 'form', 'common', 'layer', 'laytpl'], function () {
let table = layui.table; let table = layui.table;
let layer = layui.layer; let layer = layui.layer;
let form = layui.form; let form = layui.form;
let common = layui.common; let common = layui.common;
let util = layui.util; let util = layui.util;
let laytpl = layui.laytpl;
const cols = [[ const cols = [[
{ title: '收款平台名称', field: 'name', align: 'center', maxWidth: 180 }, { title: '收款平台名称', field: 'name', align: 'center', maxWidth: 180 },
@ -102,17 +123,13 @@
table.on('tool(plugin-table)', function (obj) { table.on('tool(plugin-table)', function (obj) {
const id = obj.data.id; const id = obj.data.id;
if (obj.event === 'pluginInstall') { if (obj.event === 'pluginInstall') {
layer.msg('功能开发中,有需要请联系作者'); plugin.install({ platform: obj.data.platform });
} else if (obj.event === 'pluginUpdate') { } else if (obj.event === 'pluginUpdate') {
layer.msg('功能开发中,有需要请联系作者'); plugin.update({ platform: obj.data.platform });
} else if (obj.event === 'pluginUninstall') { } else if (obj.event === 'pluginUninstall') {
layer.confirm('卸载之后无法恢复,确认吗?', { icon: 3, title: '卸载插件' }, function (index) { layer.confirm('卸载之后无法恢复,确认吗?', { icon: 3, title: '卸载插件' }, function (index) {
layer.close(index); layer.close(index);
config = { plugin.uninstall({ platform: obj.data.platform });
platform: obj.data.platform,
classname: obj.data.class_name
}
plugin.uninstall(config);
}); });
} }
}); });
@ -169,25 +186,93 @@
} }
} }
// 安装插件 // 安装插件
plugin.install = async (config) => { plugin.install = async (config, step = 0) => {
const res = await fetch('/api/Plugin/installPlugin', { method: 'post', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(config) }); const res = await fetch('/api/Plugin/installPlugin', { method: 'post', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(config) });
if (res.status !== 200) { if (res.status !== 200) {
layer.msg('请求失败,请重试!', { tips: 2, time: 1200 }); layer.msg('请求失败,请重试!', { tips: 2, time: 1200 });
return false; return false;
} }
const rec_info = await res.json(); const rec_info = await res.json();
// 错误信息
if (rec_info.code !== 0) {
layer.msg(rec_info.msg, { icon: 2, time: 1200 });
return false;
}
const info = rec_info.data;
if (rec_info.state === 0) {
plugin.pay(info, config.platform, step);
return false;
} else {
// 安装成功
layer.msg(rec_info.msg, { icon: 1, time: 1200 }, () => { table.reload('plugin-table'); });
return false;
}
} }
// 更新插件 // 更新插件
plugin.update = async (config) => { plugin.update = async (config) => {
const res = await fetch('/api/Plugin/updatePlugin', { method: 'post', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(config) }); const res = await fetch('/api/Plugin/updatePlugin', { method: 'post', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(config) });
if (res.status!== 200) { if (res.status !== 200) {
layer.msg('请求失败,请重试!', { tips: 2, time: 1200 }); layer.msg('请求失败,请重试!', { tips: 2, time: 1200 });
return false; return false;
} }
const rec_info = await res.json(); const rec_info = await res.json();
if (rec_info.code === 0) {
layer.msg(rec_info.msg, { icon: 1, time: 1200 }, () => { table.reload('plugin-table'); });
} else {
layer.msg(rec_info.msg, { icon: 2, time: 1200 });
}
}
// 支付费用
plugin.pay = (config, platform, step) => {
if (step == 0) {
plugin.payPage(config, platform);
} else {
layer.alert('支付失败,请重试!', { icon: 0, title: '提示' }, function (index) {
layer.close(index);
plugin.payPage(config, platform);
});
}
}
plugin.payPage = async (config, platform) => {
layer.open({
type: 1,
title: '支付费用',
area: [common.isModile() ? '100%' : '360px', common.isModile() ? '100%' : 'auto'],
content: laytpl(document.getElementById('plugin-pay').innerHTML).render(config),
offset: '16px',
anim: 1,
btn: ['确认支付', '取消'],
success: function () {
plugin.setQrcode(config.codetype, config.payurl);
},
yes: (index) => {
layer.close(index);
plugin.install({ platform: platform }, 1);
},
btn2: (index) => {
layer.close(index);
}
})
}
// 设置二维码
plugin.setQrcode = async (codeType, payCode) => {
if (codeType == 0) {
document.getElementById('qrcode').src = await getQrcode(payCode);
} else {
document.getElementById('qrcode').src = payCode;
}
} }
}); });
// 生成二维码
async function getQrcode(text) {
const qrcodeUrl = await new Promise((resolve) => {
new QR({
text: text,
size: 500,
}).draw().then((dataURL) => { resolve(dataURL); });
})
return qrcodeUrl;
}
</script> </script>
</body> </body>