同步更新插件代码

This commit is contained in:
邹景立 2023-04-27 19:35:51 +08:00
parent 5ca548c2d4
commit 87c63b21e5
10 changed files with 185 additions and 137 deletions

View File

@ -70,7 +70,7 @@ class Base extends Controller
* @param array $data
* @throws \think\db\exception\DbException
*/
protected function _form_filter(array $data)
protected function _form_filter(array &$data)
{
if ($this->request->isGet()) {
$this->types = SystemBase::types();

View File

@ -19,6 +19,7 @@ namespace app\wechat\controller;
use app\wechat\service\WechatService;
use think\admin\Builder;
use think\admin\Controller;
use think\admin\Storage;
use think\admin\storage\LocalStorage;
/**
@ -134,15 +135,6 @@ class Config extends Controller
}
}
/**
* 微信支付测试
* @auth true
*/
public function payment_test()
{
$this->fetch();
}
/**
* 微信支付修改
* @auth true
@ -151,27 +143,53 @@ class Config extends Controller
public function payment_save()
{
if ($this->request->isPost()) {
if ($this->request->post('wechat.mch_ssl_type') === 'p12') {
if (!LocalStorage::instance()->has(input('wechat.mch_ssl_p12', '-'), true)) {
$this->error('商户证书 P12 证书不能为空!');
}
$content = LocalStorage::instance()->get(input('wechat.mch_ssl_p12', '-'), true);
if (!openssl_pkcs12_read($content, $certs, input('wechat.mch_id'))) {
$this->error('商户账号与 P12 证书不匹配!');
}
} elseif ($this->request->post('wechat.mch_ssl_type') === 'pem') {
if (!LocalStorage::instance()->has(input('wechat.mch_ssl_key', '-'), true)) {
$local = LocalStorage::instance();
$wechat = $this->request->post('wechat');
if ($wechat['mch_ssl_type'] === 'pem') {
if (empty($wechat['mch_ssl_key']) || !$local->has($wechat['mch_ssl_key'], true)) {
$this->error('商户证书 KEY 不能为空!');
}
if (!LocalStorage::instance()->has(input('wechat.mch_ssl_cer', '-'), true)) {
if (empty($wechat['mch_ssl_cer']) || !$local->has($wechat['mch_ssl_cer'], true)) {
$this->error('商户证书 CERT 不能为空!');
}
}
foreach ($this->request->post() as $k => $v) sysconf($k, $v);
if ($wechat['mch_ssl_type'] === 'p12') {
if (empty($wechat['mch_ssl_p12']) || !$local->has($wechat['mch_ssl_p12'], true)) {
$this->error('商户证书 P12 不能为空!');
}
$content = $local->get($wechat['mch_ssl_p12'], true);
if (openssl_pkcs12_read($content, $certs, $wechat['mch_id'])) {
$wechat['mch_ssl_key'] = $local->set(Storage::name($certs['pkey'], 'pem'), $certs['pkey'], true)['url'];
$wechat['mch_ssl_cer'] = $local->set(Storage::name($certs['cert'], 'pem'), $certs['cert'], true)['url'];
} else {
$this->error('商户账号与 P12 证书不匹配!');
}
}
// 记录文本格式参数,兼容分布式部署
sysdata('plugin.wechat.payment.config', [
'appid' => WechatService::getAppid(),
'mch_id' => $wechat['mch_id'],
'mch_key' => $wechat['mch_key'],
'mch_v3_key' => $wechat['mch_v3_key'],
'ssl_key_text' => $local->get($wechat['mch_ssl_key'], true),
'ssl_cer_text' => $local->get($wechat['mch_ssl_cer'], true),
]);
// 记录证书路径参数,兼容历史参数
foreach ($wechat as $k => $v) sysconf("wechat.{$k}", $v);
// 记录操作历史并返回保存结果
sysoplog('微信授权配置', '修改微信支付配置成功');
$this->success('微信支付配置成功!');
} else {
$this->error('抱歉,访问方式错误!');
}
}
/**
* 微信支付测试
* @auth true
*/
public function payment_test()
{
$this->fetch();
}
}

View File

@ -73,7 +73,7 @@ class News extends Controller
public function add()
{
if ($this->request->isGet()) {
$this->title = '新建图文';
$this->title = '新建微信图文';
$this->fetch('form');
} else {
$update = [
@ -103,14 +103,14 @@ class News extends Controller
if ($this->request->get('output') === 'json') {
$this->success('获取数据成功!', MediaService::news($this->id));
} else {
$this->title = '编辑图文';
$this->title = '编辑微信图文';
$this->fetch('form');
}
} else {
$ids = $this->_buildArticle($this->request->post('data', []));
[$map, $data] = [['id' => $this->id], ['article_id' => $ids]];
if (WechatNews::mk()->where($map)->update($data)) {
$this->success('更新成功!', 'javascript:history.back()');
if (WechatNews::mk()->where($map)->update($data) !== false) {
$this->success('图文更新成功!', 'javascript:history.back()');
} else {
$this->error('更新失败,请稍候再试!');
}
@ -136,7 +136,7 @@ class News extends Controller
$ids = [];
foreach ($data as $vo) {
if (empty($vo['digest'])) {
$vo['digest'] = mb_substr(strip_tags(str_replace(["\s", ' '], '', $vo['content'])), 0, 120);
$vo['digest'] = mb_substr(strip_tags(preg_replace('#(\s+| )#', '', $vo['content'])), 0, 120);
}
$vo['create_at'] = date('Y-m-d H:i:s');
if (empty($vo['id'])) {

View File

@ -20,6 +20,7 @@ use think\admin\Exception;
use think\admin\extend\JsonRpcClient;
use think\admin\Library;
use think\admin\Service;
use think\admin\Storage;
use think\admin\storage\LocalStorage;
use think\exception\HttpResponseException;
@ -181,17 +182,53 @@ class WechatService extends Service
'mch_v3_key' => sysconf('wechat.mch_v3_key'),
'cache_path' => syspath('runtime/wechat'),
];
if (in_array($sslType = strtolower(sysconf('wechat.mch_ssl_type')), ['p12', 'pem'])) {
[$local = LocalStorage::instance(), $options = static::withWxpayCert($options)];
if ((empty($options['ssl_cer']) || empty($options['ssl_key'])) && $sslType === 'p12') {
if (openssl_pkcs12_read($local->get(sysconf('wechat.mch_ssl_p12'), true), $certs, $options['mch_id'])) {
sysconf('wechat.mch_ssl_cer', $local->set(Storage::name($certs['pkey'], 'pem'), $certs['pkey'], true)['url']);
sysconf('wechat.mch_ssl_key', $local->set(Storage::name($certs['cert'], 'pem'), $certs['cert'], true)['url']);
static::withWxpayCert($options);
} else {
throw new Exception('商户账号与 P12 证书不匹配!');
}
}
}
return $options;
}
/**
* 处理支付证书配置
* @param array $options
* @return array
* @throws \think\admin\Exception
*/
private static function withWxpayCert(array &$options): array
{
// 文本模式主要是为了解决分布式部署
$local = LocalStorage::instance();
switch (strtolower(sysconf('wechat.mch_ssl_type'))) {
case 'p12':
$options['ssl_p12'] = $local->path(sysconf('wechat.mch_ssl_p12'), true);
break;
case 'pem':
$options['ssl_cer'] = $local->path(sysconf('wechat.mch_ssl_cer'), true);
$options['ssl_key'] = $local->path(sysconf('wechat.mch_ssl_key'), true);
$options['cert_public'] = $local->path(sysconf('wechat.mch_ssl_cer'), true);
$options['cert_private'] = $local->path(sysconf('wechat.mch_ssl_key'), true);
break;
if (!empty($data = sysdata('plugin.wechat.payment.config'))) {
if (empty($data['ssl_key_text']) || empty($data['ssl_cer_text'])) {
throw new Exception('商户证书不能为空!');
}
$name1 = Storage::name($data['ssl_cer_text'], 'pem');
$name2 = Storage::name($data['ssl_key_text'], 'pem');
if ($local->has($name1, true) && $local->has($name2, true)) {
$sslCer = $local->set($name1, $data['ssl_cer_text'], true)['file'];
$sslKey = $local->set($name2, $data['ssl_key_text'], true)['file'];
} else {
$sslCer = $local->path($name1, true);
$sslKey = $local->path($name2, true);
}
$options['ssl_cer'] = $sslCer;
$options['ssl_key'] = $sslKey;
$options['cert_public'] = $sslCer;
$options['cert_private'] = $sslKey;
} else {
$sslCer = $local->path(sysconf('wechat.mch_ssl_cer'), true);
$sslKey = $local->path(sysconf('wechat.mch_ssl_key'), true);
if (is_file($sslCer)) $options['cert_public'] = $options['ssl_cer'] = $sslCer;
if (is_file($sslKey)) $options['cert_private'] = $options['ssl_key'] = $sslKey;
}
return $options;
}

View File

@ -7,72 +7,66 @@
{/block}
{block name="content"}
<div class="think-box-shadow">
<div class="layui-anim layui-anim-fadein padding-top-20" style="width:850px">
<form action="{:url('payment_save')}" method="post" data-auto="true" class='layui-form layui-card shadow-none' lay-filter="payment">
<div class="layui-card-header border-0">
<div class="layui-bg-gray padding-col-20 border-radius-5 padding-left-20">
微信商户参数配置,此处交易的商户号需要与微信公众号对接的公众号 APPID 匹配。
</div>
<div class="think-box-notify margin-bottom-15">
<b>温馨提示:</b>微信商户参数配置,此处交易的商户号需要与微信公众号对接的公众号 APPID 匹配。
</div>
<div class="layui-card-body">
<div class="layui-form-item margin-top-15">
<label class="layui-form-label"><b>MCH_ID</b><br><span class="nowrap color-desc">微信商户账号</span></label>
<div class="layui-input-block">
<form action="{:url('payment_save')}" method="post" data-auto="true" class='layui-form layui-card' lay-filter="payment">
<div class="layui-card-body padding-left-40">
<label class="layui-form-item relative block">
<span class="help-label"><b>微信商户账号</b>MCH_ID</span>
<input name="wechat.mch_id" required vali-name="微信商户号" placeholder="请输入微信商户账号(必填)" value="{:sysconf('wechat.mch_id')}" class="layui-input">
<p class="help-block">微信商户账号需要在微信商户平台获取MCH_ID 与 APPID 匹配</p>
</div>
</div>
<span class="help-block">微信商户账号需要在微信商户平台获取MCH_ID 与 APPID 匹配</span>
</label>
<div class="layui-form-item">
<label class="layui-form-label"><b>MCH_KEY</b><br><span class="nowrap color-desc">微信商户密钥</span></label>
<div class="layui-input-block">
<input name="wechat.mch_key" vali-name="微信商户密钥" placeholder="请输入微信商户密钥(必填)" maxlength="32" pattern=".{32}" required value="{:sysconf('wechat.mch_key')}" class="layui-input">
<p class="help-block">微信商户密钥,需要在微信商户平台操作设置操作密码并获取商户接口密钥</p>
</div>
</div>
<label class="layui-form-item relative block">
<span class="help-label"><b>微信商户 V2 密钥</b>MCH_KEY</span>
<input name="wechat.mch_key" vali-name="微信商户V2密钥" placeholder="请输入微信商户V2密钥必填" maxlength="32" pattern=".{32}" required value="{:sysconf('wechat.mch_key')}" class="layui-input">
<span class="help-block">微信商户 V2 密钥,需要在微信商户平台操作设置操作密码并获取商户接口密钥</span>
</label>
<div class="layui-form-item">
<label class="layui-form-label"><b>MCH_V3_KEY</b><br><span class="nowrap color-desc">微信商户V3密钥</span></label>
<div class="layui-input-block">
<label class="layui-form-item relative block">
<span class="help-label"><b>微信商户 V3 密钥</b>MCH_V3_KEY</span>
<input name="wechat.mch_v3_key" vali-name="微信商户V3密钥" placeholder="请输入微信商户V3密钥必填" maxlength="32" pattern=".{32}" required value="{:sysconf('wechat.mch_v3_key')}" class="layui-input">
<p class="help-block">微信商户密钥,需要在微信商户平台操作设置操作密码并获取商户接口密钥</p>
</div>
</div>
<span class="help-block">微信商户 V3 密钥,需要在微信商户平台操作设置操作密码并获取商户接口密钥</span>
</label>
<div class="hr-line-dashed"></div>
<div class="layui-form-item">
<label class="layui-form-label"><b>MCH_CERT</b><br><span class="nowrap color-desc">微信商户证书</span></label>
<div class="layui-input-block">
{foreach ['none'=>'暂不使用证书', 'pem'=>'上传 PEM 证书', 'p12'=>'上传 P12 证书'] as $k=>$v}
<span class="help-label label-required-prev"><b>微信商户证书文件</b>MCH_CERT_FILE</span>
<div class="margin-top-10">
<!-- 'none'=>'暂不使用证书' -->
{foreach ['pem'=>'上传 PEM 证书', 'p12'=>'上传 P12 证书'] as $k=>$v}
<input type="radio" data-pem-type="{$k}" name="wechat.mch_ssl_type" value="{$k}" title="{$v}" lay-filter="data-mch-type">
{/foreach}
<p class="help-block font-code">请选择需要上传证书类型P12 或 PEM 二选一,证书需要从微信商户平台获取</p>
<div class="padding-top-10">
<div data-mch-type="none"></div>
<p class="help-block">请选择需要上传证书类型P12 或 PEM 二选一,证书需要从微信商户平台获取</p>
<div data-mch-type="p12" class="layui-tab-item padding-top-15 padding-bottom-15">
<div data-mch-type="p12" class="layui-tab-item">
<input name="wechat.mch_ssl_p12" value="{$mch_ssl_p12|default=''}" type="hidden">
<button data-file="btn" data-uptype="local" data-safe="true" data-type="p12" data-field="wechat.mch_ssl_p12" type="button" class="layui-btn layui-btn-primary">
<button data-file="btn" data-uptype="local" data-safe="true" data-type="p12" data-field="wechat.mch_ssl_p12" type="button" class="layui-btn font-code layui-btn-primary">
<i class="layui-icon layui-icon-vercode"></i> 上传 P12 证书
</button>
<p class="help-block margin-top-10">微信商户支付 P12 证书,实现订单退款、打款、发红包等支出功能都使用证书</p>
</div>
<div data-mch-type="pem" class="layui-tab-item padding-top-15 padding-bottom-15">
<input name="wechat.mch_ssl_key" value="{$mch_ssl_key|default=''}" type="hidden">
<button data-file="btn" data-uptype="local" data-safe="true" data-type="pem" data-field="wechat.mch_ssl_key" type="button" class="layui-btn layui-btn-primary margin-right-5">
<div data-mch-type="pem" class="layui-tab-item">
<input type="hidden" name="wechat.mch_ssl_key" value="{$mch_ssl_key|default=''}">
<button data-file="btn" data-uptype="local" data-safe="true" data-type="pem" data-field="wechat.mch_ssl_key" type="button" class="layui-btn font-code layui-btn-primary margin-right-10">
<i class="layui-icon layui-icon-vercode"></i> 上传 KEY 证书
</button>
<input name="wechat.mch_ssl_cer" value="{$mch_ssl_cer|default=''}" type="hidden">
<button data-file="btn" data-uptype="local" data-safe="true" data-type="pem" data-field="wechat.mch_ssl_cer" type="button" class="layui-btn layui-btn-primary">
<input type="hidden" name="wechat.mch_ssl_cer" value="{$mch_ssl_cer|default=''}">
<button data-file="btn" data-uptype="local" data-safe="true" data-type="pem" data-field="wechat.mch_ssl_cer" type="button" class="layui-btn font-code layui-btn-primary">
<i class="layui-icon layui-icon-vercode"></i> 上传 CERT 证书
</button>
<p class="help-block margin-top-10">微信商户支付 PEM 双向证书,实现订单退款、打款、发红包等支出功能都使用证书</p>
</div>
</div>
</div>
<!--{if auth('paymentsave')}-->
</div>
<!--{if auth('payment_save')}-->
<div class="hr-line-dashed margin-top-30"></div>
<div class="layui-form-item text-center">
<button class="layui-btn" type="submit">保存配置</button>
@ -80,31 +74,27 @@
<!--{/if}-->
</div>
</form>
</div>
</div>
{/block}
{block name="script"}
<script>
(new function (type) {
type = "{:sysconf('wechat.mch_ssl_type')}" || 'none';
(function (type) {
layui.form.val('payment', {'wechat.mch_ssl_type': type});
layui.form.on('radio(data-mch-type)', apply), apply.call(this, {value: type});
layui.form.on('radio(data-mch-type)', apply) && apply({value: type});
['wechat.mch_ssl_p12', 'wechat.mch_ssl_key', 'wechat.mch_ssl_cer'].forEach(function (type) {
$('input[name="' + type + '"]').on('change', function (that) {
that = this, that.$button = $(this).next('button'), setTimeout(function () {
$('input[name="' + type + '"]').on('change', function () {
let that = this, $button = $(this).next('button');
if (typeof that.value === 'string' && that.value.length > 5) {
that.$button.find('i').addClass('color-green layui-icon-vercode').removeClass('layui-icon-upload-drag');
$button.removeClass('layui-btn-primary').find('i').addClass('layui-icon-vercode').removeClass('layui-icon-upload-drag');
} else {
that.$button.find('i').removeClass('color-green layui-icon-vercode').addClass('layui-icon-upload-drag');
$button.addClass('layui-btn-primary').find('i').removeClass('layui-icon-vercode').addClass('layui-icon-upload-drag');
}
}, 100);
}).trigger('change');
});
function apply(data) {
$('[data-mch-type="' + data.value + '"]').show().siblings('[data-mch-type]').hide();
return $('[data-mch-type="' + data.value + '"]').show().siblings('[data-mch-type]').hide();
}
});
})("{:sysconf('wechat.mch_ssl_type')}" || 'pem');
</script>
{/block}

View File

@ -27,21 +27,17 @@
$(function () {
$('#UserData').layTable({
even: true, height: 'full',
sort: {field: 'subscribe_time', type: 'desc'},
sort: {field: 'id', type: 'desc'},
cols: [[
{checkbox: true},
{
field: 'headimg', title: '头像', width: 65, align: "center", templet: function (d) {
d.headimgurl = d.headimgurl || '';
return d.headimgurl ? '<div class="headimg headimg-xs margin-0" data-tips-image data-tips-hover data-lazy-src="' + d.headimgurl + '" style="background-image:url(' + d.headimgurl + ')"></div>' : '-';
}
},
{field: 'id', hide: true},
{field: 'headimg', title: '头像', width: 65, align: "center", templet: '<div>{{-$.layTable.showImage(d.headimgurl)}}</div>'},
{field: 'nickname', title: '微信昵称', align: "center", minWidth: 100, templet: '<div>{{d.nickname||"-"}}</div>'},
{field: 'province', title: '所在区域', align: "center", minWidth: 120, templet: '<div>{{d.country||"-"}} {{d.province}} {{d.city}}</div>'},
{field: 'sex', title: '性别', align: 'center', minWidth: 80, templet: '<div>{{d.sex==1 ? "男" : (d.sex==2 ? "女" : "未知")}}</div>'},
{field: 'language', title: '使用语言', align: 'center', minWidth: 100, templet: '<div>{{d.language}}</div>'},
{
field: 'subscribe', title: '订阅状态', align: "center", templet: function (d) {
field: 'subscribe', title: '订阅状态', align: "center", minWidth: 80, templet: function (d) {
if (d.subscribe > 0) return '<span class="layui-badge layui-bg-green">已订阅</span>';
else return '<span class="layui-badge">未订阅</span>';
}

View File

@ -71,7 +71,7 @@
<div class="layui-form-item margin-top-20" ng-if="item.type==='view'">
<label class="layui-form-label">跳转链接</label>
<div class="layui-input-block">
<textarea required pattern="url" class="layui-textarea" vali-name="跳转链接" ng-model="item.url" placeholder="请输入跳转链接"></textarea>
<input type="text" required vali-name="跳转链接" class="layui-input" ng-model="item.url" placeholder="请输入跳转链接">
</div>
</div>
<div ng-if="item.type==='miniprogram'">

View File

@ -619,7 +619,14 @@ $(function () {
});
};
$.layTable = new function () {
this.render = function (tabldId) {
this.showImage = function (image, circle, size, title) {
if (typeof image !== 'string' || image.length < 5) {
return '<span class="color-desc">-</span>' + (title ? laytpl('<span class="margin-left-5">{{d.title}}</span>').render({title: title}) : '');
}
return laytpl('<div class="headimg {{d.class}} headimg-{{d.size}}" data-tips-image data-tips-hover data-lazy-src="{{d.image}}" style="{{d.style}}"></div>').render({
size: size || 'ss', class: circle ? 'shadow-inset' : 'headimg-no', image: image, style: 'background-image:url(' + image + ');margin-right:0'
}) + (title ? laytpl('<span class="margin-left-5">{{d.title}}</span>').render({title: title}) : '');
}, this.render = function (tabldId) {
return this.reload(tabldId, true);
}, this.reload = function (tabldId, force) {
return typeof tabldId === 'string' ? $('#' + tabldId).trigger(force ? 'render' : 'reload') : $.form.reload();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long