diff --git a/app/admin/view/config/storage-alioss.html b/app/admin/view/config/storage-alioss.html index a819600af..29da187f2 100644 --- a/app/admin/view/config/storage-alioss.html +++ b/app/admin/view/config/storage-alioss.html @@ -50,7 +50,7 @@ </label> <div class="layui-input-block"> <input id="storage.alioss_bucket" type="text" name="storage.alioss_bucket" required value="{:sysconf('storage.alioss_bucket')}" placeholder="请输入阿里云OSS存储 Bucket (空间名称)" class="layui-input"> - <p class="help-block">填写阿里云OSS存储空间名称,如:think-admin-oss(需要是全区唯一的值,不存在时会自动创建)</p> + <p class="help-block">填写阿里云OSS存储空间名称,如:think-admin-oss</p> </div> </div> @@ -92,7 +92,7 @@ <button class="layui-btn layui-btn-danger" type='button' data-confirm="确定要取消修改吗?" data-close>取消修改</button> </div> - <script>form.render()</script> + <script>layui.form.render()</script> </div> </form> \ No newline at end of file diff --git a/app/wechat/controller/Fans.php b/app/wechat/controller/Fans.php index 94a7298b7..bad1d0633 100644 --- a/app/wechat/controller/Fans.php +++ b/app/wechat/controller/Fans.php @@ -18,6 +18,7 @@ namespace app\wechat\controller; use app\wechat\service\WechatService; use think\admin\Controller; +use think\admin\helper\QueryHelper; use think\exception\HttpResponseException; /** @@ -37,17 +38,18 @@ class Fans extends Controller * 微信用户管理 * @auth true * @menu true - * @throws \think\admin\Exception * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\DbException * @throws \think\db\exception\ModelNotFoundException */ public function index() { - $this->title = '微信用户管理'; - $this->where = ['appid' => WechatService::instance()->getAppid()]; - $query = $this->_query($this->table)->like('nickname')->equal('subscribe,is_black'); - $query->dateBetween('subscribe_at')->where($this->where)->order('subscribe_time desc')->page(); + $this->_query($this->table)->layTable(function () { + $this->title = '微信用户管理'; + }, function (QueryHelper $query) { + $query->where(['appid' => WechatService::instance()->getAppid()]); + $query->like('nickname')->equal('subscribe,is_black')->dateBetween('subscribe_at'); + }); } /** @@ -56,13 +58,7 @@ class Fans extends Controller */ protected function _index_page_filter(array &$data) { - $tags = $this->app->db->name('WechatFansTags')->column('name', 'id'); - foreach ($data as &$vo) { - $vo['tags'] = []; - foreach (explode(',', $vo['tagid_list']) as $tagid) { - if (isset($tags[$tagid])) $vo['tags'][] = $tags[$tagid]; - } - } + foreach ($data as &$vo) $vo['subscribe_at'] = format_datetime($vo['subscribe_at']); } /** @@ -76,19 +72,34 @@ class Fans extends Controller } /** - * 清空用户数据 + * 黑名单列表操作 * @auth true */ - public function truncate() + public function black() { + $data = $this->_vali([ + 'openid.require' => '操作用户不能为空!', + 'black.require' => '操作类型不能为空!', + ]); try { - $this->_query('WechatFans')->empty(); - $this->_query('WechatFansTags')->empty(); - $this->success('清空用户数据成功!'); - } catch (\think\exception\HttpResponseException $exception) { + foreach (array_chunk(explode(',', $data['openid']), 20) as $openids) { + if ($data['black']) { + WechatService::WeChatUser()->batchBlackList($openids); + $this->app->db->name('WechatFans')->whereIn('openid', $openids)->update(['is_black' => 1]); + } else { + WechatService::WeChatUser()->batchUnblackList($openids); + $this->app->db->name('WechatFans')->whereIn('openid', $openids)->update(['is_black' => 0]); + } + } + if (empty($data['black'])) { + $this->success('移出黑名单成功!'); + } else { + $this->success('拉入黑名单成功!'); + } + } catch (HttpResponseException $exception) { throw $exception; } catch (\Exception $exception) { - $this->error("清空用户数据失败,{$exception->getMessage()}"); + $this->error("黑名单操作失败,请稍候再试!<br>{$exception->getMessage()}"); } } @@ -99,48 +110,23 @@ class Fans extends Controller */ public function remove() { - $this->_applyFormToken(); $this->_delete($this->table); } /** - * 用户拉入黑名单 + * 清空用户数据 * @auth true */ - public function blackAdd() + public function truncate() { try { - $this->_applyFormToken(); - foreach (array_chunk(explode(',', $this->request->post('openid')), 20) as $openids) { - WechatService::WeChatUser()->batchBlackList($openids); - $this->app->db->name('WechatFans')->whereIn('openid', $openids)->update(['is_black' => '1']); - } - $this->success('拉入黑名单成功!'); + $this->_query('WechatFans')->empty(); + $this->_query('WechatFansTags')->empty(); + $this->success('清空用户数据成功!'); } catch (HttpResponseException $exception) { throw $exception; } catch (\Exception $exception) { - $this->error("拉入黑名单失败,请稍候再试!<br>{$exception->getMessage()}"); + $this->error("清空用户数据失败,{$exception->getMessage()}"); } } - - /** - * 用户移出黑名单 - * @auth true - */ - public function blackDel() - { - try { - $this->_applyFormToken(); - foreach (array_chunk(explode(',', $this->request->post('openid')), 20) as $openids) { - WechatService::WeChatUser()->batchUnblackList($openids); - $this->app->db->name('WechatFans')->whereIn('openid', $openids)->update(['is_black' => '0']); - } - $this->success('移出黑名单成功!'); - } catch (HttpResponseException $exception) { - throw $exception; - } catch (\Exception $exception) { - $this->error("移出黑名单失败,请稍候再试!<br>{$exception->getMessage()}"); - } - } - } diff --git a/app/wechat/view/config/options_form_api.html b/app/wechat/view/config/options_form_api.html index adff7da78..775e4af34 100644 --- a/app/wechat/view/config/options_form_api.html +++ b/app/wechat/view/config/options_form_api.html @@ -43,24 +43,24 @@ <div class="layui-form-item"> <label class="layui-form-label"><b>PushApi</b><br><span class="nowrap color-desc">消息推送接收</span></label> <div class="layui-input-block"> - <div class="relative"> + <label class="relative block"> <input value="服务器授权IP:{$geoip}" disabled class="layui-input layui-bg-gray"> - <a data-copy="{$geoip}" class="input-right-icon"><i class="iconfont icon-copy"></i></a> - </div> - <div class="relative margin-top-5"> + <a data-copy="{$geoip}" class="layui-icon layui-icon-release input-right-icon"></a> + </label> + <label class="relative block margin-top-5"> <input value="消息推送地址:{$thrNotify}" disabled class="layui-input layui-bg-gray"> - <a data-copy="{$thrNotify}" class="input-right-icon"><i class="iconfont icon-copy"></i></a> - </div> + <a data-copy="{$thrNotify}" class="layui-icon layui-icon-release input-right-icon"></a> + </label> <p class="help-block">公众号服务平台消息推送接口及服务器授权IP地址,需在公众号接口开发处配置。</p> </div> </div> - <div class="hr-line-dashed margin-top-30"></div> - <input type="hidden" name="wechat.type" value="api"> + </div> - <div class="layui-form-item text-center"> - <button class="layui-btn" type="submit">保存配置</button> - </div> + <div class="hr-line-dashed"></div> + <input type="hidden" name="wechat.type" value="api"> + <div class="layui-form-item text-center"> + <button class="layui-btn" type="submit">保存配置</button> </div> </form> \ No newline at end of file diff --git a/app/wechat/view/config/options_form_thr.html b/app/wechat/view/config/options_form_thr.html index 28a442ee9..edc185a57 100644 --- a/app/wechat/view/config/options_form_thr.html +++ b/app/wechat/view/config/options_form_thr.html @@ -46,28 +46,29 @@ <div class="layui-form-item"> <label class="layui-form-label"><b>AppKey</b><br><span class="nowrap color-desc">服务接口密钥</span></label> <div class="layui-input-block"> - <input name="wechat.thr_appkey" required placeholder="请输入32位第三方平台接口密钥AppKey(必填)" value="{:sysconf('wechat.thr_appkey')}" maxlength="32" pattern="^[0-9a-z]{32}$" class="layui-input"> - <p class="help-block">公众号服务平台接口密钥, 通过微信第三方授权自动获取, 若没有值请进行微信第三方授权。</p> + <label class="relative block"> + <input name="wechat.thr_appkey" required placeholder="请输入32位第三方平台接口密钥AppKey(必填)" value="{:sysconf('wechat.thr_appkey')}" maxlength="32" pattern="^[0-9a-z]{32}$" class="layui-input"> + <p class="help-block">公众号服务平台接口密钥, 通过微信第三方授权自动获取, 若没有值请进行微信第三方授权。</p> + </label> </div> </div> <div class="layui-form-item"> <label class="layui-form-label"><b>PushApi</b><br><span class="nowrap color-desc">服务推送接口</span></label> <div class="layui-input-block"> - <div class="relative margin-top-5"> + <label class="relative block"> <input value="{$thrNotify}" disabled class="layui-input layui-bg-gray"> - <a data-copy="{$thrNotify}" class="input-right-icon"><i class="iconfont icon-copy"></i></a> - </div> + <a data-copy="{$thrNotify}" class="layui-icon layui-icon-release input-right-icon"></a> + </label> <p class="help-block">公众号绑定服务平台接口通知 URL, 公众号消息接收与回复等。</p> </div> </div> + </div> - <div class="hr-line-dashed margin-top-30"></div> - <input type="hidden" name="wechat.type" value="thr"> - - <div class="layui-form-item text-center"> - <button class="layui-btn" type="submit">保存配置</button> - </div> + <div class="hr-line-dashed"></div> + <input type="hidden" name="wechat.type" value="thr"> + <div class="layui-form-item text-center"> + <button class="layui-btn" type="submit">保存配置</button> </div> </form> \ No newline at end of file diff --git a/app/wechat/view/fans/index.html b/app/wechat/view/fans/index.html index 27a4c81d3..f79b5f6a3 100644 --- a/app/wechat/view/fans/index.html +++ b/app/wechat/view/fans/index.html @@ -1,12 +1,9 @@ -{extend name="../../admin/view/main"} +{extend name="../../admin/view/table"} {block name="button"} -<!--{if auth("blackAdd")}--> -<button data-action='{:url("blackAdd")}' data-rule="openid#{key}" data-csrf="{:systoken('blackAdd')}" class='layui-btn layui-btn-sm layui-btn-primary'>拉入黑名单</button> -<!--{/if}--> - -<!--{if auth("blackDel")}--> -<button data-action='{:url("blackDel")}' data-rule="openid#{key}" data-csrf="{:systoken('blackDel')}" class='layui-btn layui-btn-sm layui-btn-primary'>移出黑名单</button> +<!--{if auth("black")}--> +<button data-action='{:url("black")}' data-table-id="UserData" data-rule="openid#{openid};black#1" class='layui-btn layui-btn-sm layui-btn-primary'>拉入黑名单</button> +<button data-action='{:url("black")}' data-table-id="UserData" data-rule="openid#{openid};black#0" class='layui-btn layui-btn-sm layui-btn-primary'>移出黑名单</button> <!--{/if}--> <!--{if auth("truncate")}--> @@ -14,77 +11,66 @@ <!--{/if}--> <!--{if auth("sync")}--> -<button data-queue='{:url("sync")}' data-confirm="确定要创建同步用户数据的后台任务?" class='layui-btn layui-btn-sm layui-btn-primary'>同步用户数据</button> +<button data-queue='{:url("sync")}' data-table-id="UserData" data-confirm="确定要创建同步用户数据的后台任务?" class='layui-btn layui-btn-sm layui-btn-primary'>同步用户数据</button> <!--{/if}--> {/block} {block name="content"} <div class="think-box-shadow"> {include file='fans/index_search'} - <table class="layui-table margin-top-10" lay-skin="line"> - {notempty name='list'} - <thead> - <tr> - <th class='list-table-check-td think-checkbox'> - <label><input data-auto-none data-check-target='.list-check-box' type='checkbox'></label> - </th> - <th width="180px" class='text-left nowrap'>微信昵称</th> - <th width="180px"></th> - <th width="150px" class='text-left nowrap'>性别语言</th> - <th width="180px" class='text-left nowrap'>订阅时间</th> - <th width="80px"></th> - <th></th> - </tr> - </thead> - {/notempty} - <tbody> - {foreach $list as $key=>$vo} - <tr> - <td class='list-table-check-td think-checkbox'> - <label><input class="list-check-box" value='{$vo.openid}' type='checkbox'></label> - </td> - <td class='text-left nowrap'> - <div class="headimg" data-tips-image data-lazy-src="{$vo.headimgurl|default=''}"></div> - <div class="inline-block"> - <p>昵称:{$vo.nickname|default='--'}</p> - <p>区域:{$vo.country|default='--'} {$vo.province|default=''} {$vo.city|default=''}</p> - </div> - </td> - <td class="text-left padding-0"> - <div style="max-height:60px;overflow:auto">{foreach $vo.tags as $t}<p><span class="layui-badge layui-bg-cyan margin-right-5">{$t|default='--'}</span></p>{/foreach}</div> - </td> - <td class='text-left nowrap'> - 性别:{switch name='vo.sex'}{case value='1'}男{/case}{case value='2'}女{/case}{default}未知{/switch}<br> - 语言:{$vo.language|raw} - </td> - <td class='text-left nowrap'> - 日期:{$vo.subscribe_at|format_datetime|str_replace=' ','<br>时间:',###|raw} - </td> - <td class='text-center nowrap'> - <div class="notselect"> - {eq name='vo.subscribe' value='0'}<span class="layui-badge">未订阅</span>{else}<span class="layui-badge layui-bg-green">已订阅</span>{/eq} - {eq name='vo.is_black' value='0'}<span class="layui-badge layui-bg-green">未拉黑</span>{else}<span class="layui-badge">已拉黑</span>{/eq} - </div> - </td> - <td class="nowrap"> - - <!--{if auth('blackAdd') and $vo.is_black eq 0}--> - <a class="layui-btn layui-btn-sm" data-action="{:url('blackAdd')}" data-value="openid#{$vo.openid}" data-csrf="{:systoken('blackAdd')}">加入黑名单</a> - <!--{elseif auth('blackDel') and $vo.is_black eq 1}--> - <a class="layui-btn layui-btn-sm" data-action="{:url('blackDel')}" data-value="openid#{$vo.openid}" data-csrf="{:systoken('blackDel')}">移出黑名单</a> - <!--{/if}--> - - <!--{if auth("remove")}--> - <a class="layui-btn layui-btn-sm layui-btn-danger" data-action="{:url('remove')}" data-value="id#{$vo.id}" data-csrf="{:systoken('remove')}" data-confirm="确定要删除该用户吗?">删 除</a> - <!--{/if}--> - - </td> - </tr> - {/foreach} - </tbody> - </table> - - {empty name='list'}<span class="notdata">没有记录哦</span>{else}{$pagehtml|raw|default=''}{/empty} - + <table id="UserData" data-url="{:sysuri()}" data-target-search="form.form-search"></table> </div> {/block} + +{block name='script'} +<script> + $(function () { + $('#UserData').layTable({ + even: true, height: 'full', + sort: {field: 'subscribe_time', type: 'desc'}, + cols: [[ + {checkbox: true}, + {field: 'nickname', title: '微信昵称', minWidth: 100, align: 'center'}, + {field: 'province', title: '所在区域', 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_time', title: '关注时间', minWidth: 170, align: 'center', sort: true, templet: '<div>{{d.subscribe_at}}</div>'}, + { + field: 'subscribe', title: '订阅状态', align: "center", templet: function (d) { + if (d.subscribe > 0) return '<span class="layui-badge layui-bg-green">已订阅</span>'; + return '<span class="layui-badge">未订阅</span>'; + } + }, + {field: 'is_black', title: '是否黑名单', align: 'center', minWidth: 110, templet: '#StatusSwitchTpl'}, + {toolbar: '#toolbar', title: '操作面板', align: 'center', fixed: 'right'} + ]] + }); + + // 数据状态切换操作 + layui.form.on('switch(StatusSwitch)', function (obj) { + var data = {openid: obj.value, black: obj.elem.checked > 0 ? 1 : 0}; + $.form.load("{:url('black')}", data, 'post', function (ret) { + if (ret.code < 1) $.msg.error(ret.info, 3, function () { + $('#UserData').trigger('reload'); // 操作异常时重载数据 + }); + return false; + }, false); + }); + }); +</script> + +<!-- 数据状态切换模板 --> +<script type="text/html" id="StatusSwitchTpl"> + <!--{if auth("black")}--> + <input type="checkbox" value="{{d.openid}}" lay-skin="switch" lay-text="已拉黑|未拉黑" lay-filter="StatusSwitch" {{d.is_black>0?'checked':''}}> + <!--{else}--> + {{d.status ? '<b class="color-red">已拉黑</b>' : '<b class="color-green">未拉黑</b>'}} + <!--{/if}--> +</script> + +<script type="text/html" id="toolbar"> + <!--{if auth("remove")}--> + <a class="layui-btn layui-btn-sm layui-btn-danger" data-action="{:url('remove')}" data-value="id#{{d.id}}" data-confirm="确定要删除该用户吗?">删 除</a> + <!--{/if}--> +</script> +{/block} \ No newline at end of file