chore: 添加静态资源文件和版本配置文件

添加大量图片、字体、音频等静态资源文件,包括用户界面图片、模板文件和安装界面素材
添加系统版本配置文件(.version)和常量定义文件(.constant)
更新供应商依赖文件,包括Symfony VarDumper组件和相关许可证文件
添加验证码配置文件(captcha.php)和.gitignore规则
This commit is contained in:
2026-03-06 20:14:23 +08:00
commit c9a98f342c
4485 changed files with 490986 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\wechat;
use app\controller\admin\AuthController;
use app\services\wechat\WechatMenuServices;
use think\annotation\Inject;
/**
* 微信菜单 控制器
* Class Menus
* @package app\admin\controller\wechat
*/
class Menus extends AuthController
{
/**
* @var WechatMenuServices
*/
#[Inject]
protected WechatMenuServices $services;
/**
* 获取菜单
* @return mixed
*/
public function index()
{
$menus = $this->services->getWechatMenu();
return $this->success(compact('menus'));
}
/**
* 保存菜单
* @return mixed
*/
public function save()
{
$buttons = request()->post('button/a', []);
if (!count($buttons)) return $this->fail('请添加至少一个按钮');
$this->services->saveMenu($buttons);
return $this->success('修改成功!');
}
}

View File

@@ -0,0 +1,156 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\wechat;
use app\services\other\QrcodeServices;
use app\controller\admin\AuthController;
use app\services\wechat\WechatReplyServices;
use app\services\wechat\WechatKeyServices;
use think\annotation\Inject;
/**
* 关键字管理 控制器
* Class Reply
* @package app\admin\controller\wechat
*/
class Reply extends AuthController
{
/**
* @var WechatReplyServices
*/
#[Inject]
protected WechatReplyServices $services;
/**
* 关注回复
* @return mixed|void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function reply()
{
$where = $this->request->getMore([
['key', ''],
]);
if ($where['key'] == '') return $this->fail('请输入参数key');
$info = $this->services->getDataByKey($where['key']);
return $this->success(compact('info'));
}
/**
* 关键字回复列表
* */
public function index()
{
$where = $this->request->getMore([
['key', ''],
['type', ''],
]);
$list = $this->services->getKeyAll($where);
return $this->success($list);
}
/**
* 关键字详情
* */
public function read($id)
{
$info = $this->services->getKeyInfo($id);
return $this->success(compact('info'));
}
/**
* 保存关键字
* */
public function save($id = 0)
{
$data = $this->request->postMore([
'key',
'type',
['status', 0],
['data', []],
]);
try {
if (!isset($data['key']) && empty($data['key']))
return $this->fail('请输入关键字');
if (!isset($data['type']) && empty($data['type']))
return $this->fail('请选择回复类型');
if (!in_array($data['type'], $this->services->replyType()))
return $this->fail('回复类型有误!');
if (!isset($data['data']) || !is_array($data['data']))
return $this->fail('回复消息参数有误!');
$res = $this->services->redact($data['data'], $id, $data['key'], $data['type'], $data['status']);
if (!$res)
return $this->fail('保存失败!');
else
return $this->success('保存成功!', $data);
} catch (\Throwable $e) {
return $this->fail($e->getMessage());
}
}
/**
* 删除关键字
* */
public function delete($id)
{
if (!$this->services->delete($id)) {
return $this->fail('删除失败,请稍候再试!');
} else {
/** @var WechatKeyServices $keyServices */
$keyServices = app()->make(WechatKeyServices::class);
$res = $keyServices->delete($id, 'reply_id');
if (!$res) {
return $this->fail('删除失败,请稍候再试!');
}
}
return $this->success('删除成功!');
}
/**
* 修改状态
* @param $id
* @param $status
* @return mixed
*/
public function set_status($id, $status)
{
if ($status == '' || $id == 0) return $this->fail('参数错误');
$this->services->update($id, ['status' => $status], 'id');
return $this->success($status == 0 ? '禁用成功' : '启用成功');
}
/**
* 生成关注回复二维码
* @param $id
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function code_reply($id)
{
if (!$id) {
return $this->fail('参数错误');
}
/** @var QrcodeServices $qrcode */
$qrcode = app()->make(QrcodeServices::class);
$code = $qrcode->getForeverQrcode('reply', $id);
if (!$code['ticket']) {
return $this->fail('获取二维码失败,请检查是否配置公众号');
}
return $this->success($code->toArray());
}
}

View File

@@ -0,0 +1,435 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\wechat;
use app\jobs\notice\template\RoutineTemplateJob;
use app\services\message\SystemNotificationServices;
use app\services\message\TemplateMessageServices;
use app\services\other\QrcodeServices;
use app\services\system\attachment\SystemAttachmentServices;
use crmeb\exceptions\AdminException;
use think\annotation\Inject;
use think\exception\ValidateException;
use think\Request;
use think\facade\Route as Url;
use app\controller\admin\AuthController;
use crmeb\services\{FileService,
FormBuilder as Form,
template\Template,
UploadService,
wechat\MiniProgram
};
use crmeb\services\CacheService;
use function Swoole\Coroutine\batch;
/**
* Class RoutineTemplate
* @package app\controller\admin\v1\application\routine
*/
class RoutineTemplate extends AuthController
{
/**
* @var string
*/
protected string $cacheTag = 'system_routine';
/**
* @var TemplateMessageServices
*/
#[Inject]
protected TemplateMessageServices $services;
/**
* 显示资源列表
*
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$where = $this->request->getMore([
['name', ''],
['status', '']
]);
$where['type'] = 0;
$data = $this->services->getTemplateList($where);
$industry = CacheService::get($this->cacheTag . '_wechat_industry', function () {
try {
$cache = (new Template('wechat'))->getIndustry();
if (!$cache) return [];
return $cache->toArray();
} catch (\Exception $e) {
return $e->getMessage();
}
}, 0) ?: [];
!is_array($industry) && $industry = [];
$industry['primary_industry'] = isset($industry['primary_industry']) ? $industry['primary_industry']['first_class'] . ' | ' . $industry['primary_industry']['second_class'] : '未选择';
$industry['secondary_industry'] = isset($industry['secondary_industry']) ? $industry['secondary_industry']['first_class'] . ' | ' . $industry['secondary_industry']['second_class'] : '未选择';
$lst = [
'industry' => $industry,
'count' => $data['count'],
'list' => $data['list']
];
return $this->success($lst);
}
/**
* 显示创建资源表单页.
*
* @return \think\Response
*/
public function create()
{
$f = array();
$f[] = Form::input('tempkey', '模板编号');
$f[] = Form::input('tempid', '模板ID');
$f[] = Form::input('name', '模板名');
$f[] = Form::input('content', '回复内容')->type('textarea');
$f[] = Form::radio('status', '状态', 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
return $this->makePostForm('添加模板消息', $f, Url::buildUrl('/app/routine'), 'POST');
}
/**
* 保存新建的资源
*
* @param \think\Request $request
* @return \think\Response
*/
public function save(Request $request)
{
$data = $this->request->postMore([
'tempkey',
'tempid',
'name',
'content',
['status', 0]
]);
if ($data['tempkey'] == '') return $this->fail('请输入模板编号');
if ($data['tempkey'] != '' && $this->services->getOne(['tempkey' => $data['tempkey']]))
return $this->fail('请输入模板编号已存在,请重新输入');
if ($data['tempid'] == '') return $this->fail('请输入模板ID');
if ($data['name'] == '') return $this->fail('请输入模板名');
if ($data['content'] == '') return $this->fail('请输入回复内容');
$data['add_time'] = time();
$this->services->save($data);
return $this->success('添加模板消息成功!');
}
/**
* 显示指定的资源
*
* @param int $id
* @return \think\Response
*/
public function read($id)
{
//
}
/**
* 显示编辑资源表单页.
*
* @param int $id
* @return \think\Response
*/
public function edit($id)
{
if (!$id) return $this->fail('数据不存在');
$product = $this->services->get($id);
if (!$product) return $this->fail('数据不存在!');
$f = array();
$f[] = Form::input('tempkey', '模板编号', $product->getData('tempkey'))->disabled(1);
$f[] = Form::input('name', '模板名', $product->getData('name'))->disabled(1);
$f[] = Form::input('tempid', '模板ID', $product->getData('tempid'));
$f[] = Form::radio('status', '状态', $product->getData('status'))->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
return $this->makePostForm('编辑模板消息', $f, Url::buildUrl('/app/routine/' . $id), 'PUT');
}
/**
* 保存更新的资源
*
* @param \think\Request $request
* @param int $id
* @return \think\Response
*/
public function update(Request $request, $id)
{
$data = $this->request->postMore([
'tempid',
['status', 0]
]);
if ($data['tempid'] == '') return $this->fail('请输入模板ID');
if (!$id) return $this->fail('数据不存在');
$product = $this->services->get($id);
if (!$product) return $this->fail('数据不存在!');
$this->services->update($id, $data, 'id');
return $this->success('修改成功!');
}
/**
* 删除指定资源
*
* @param int $id
* @return \think\Response
*/
public function delete($id)
{
if (!$id) return $this->fail('数据不存在!');
if (!$this->services->delete($id))
return $this->fail('删除失败,请稍候再试!');
else
return $this->success('删除成功!');
}
/**
* 修改状态
* @param $id
* @param $status
* @return mixed
*/
public function set_status($id, $status)
{
if ($status == '' || $id == 0) return $this->fail('参数错误');
$this->services->update($id, ['status' => $status], 'id');
return $this->success($status == 0 ? '关闭成功' : '开启成功');
}
/**
* 同步订阅消息
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function syncSubscribe()
{
if (!sys_config('routine_appId') || !sys_config('routine_appsecret')) {
return $this->fail('请先配置小程序appid、appSecret等参数');
}
$all = $this->services->getTemplateList(['status' => 1, 'type' => 0]);
$errMessage = [
'-1' => '系统繁忙,此时请稍候再试',
'40001' => 'AppSecret错误或者AppSecret不属于这个小程序,请确认AppSecret 的正确性',
'40002' => '请确保grant_type字段值为client_credential',
'40013' => '不合法的AppID,请检查AppID的正确性,避免异常字符,注意大小写',
'40125' => '小程序配置无效,请检查配置',
'41002' => '缺少appid参数',
'41004' => '缺少secret参数',
'43104' => 'appid与openid不匹配',
'45009' => '达到微信api每日限额上限',
'200011' => '此账号已被封禁,无法操作',
'200012' => '个人模版数已达上限,上限25个',
];
if ($all['list']) {
$i = 0;
foreach ($all['list'] as $template) {
if (!$template['tempkey']) {
continue;
}
if (!isset($template['kid'])) {
return $this->fail('数据库模版表(template_message)缺少字段:kid');
}
if (isset($template['kid']) && $template['kid']) {
continue;
}
RoutineTemplateJob::dispatch([$template, $errMessage]);
$i++;
}
/** @var SystemNotificationServices $systemNotificationServices */
$systemNotificationServices = app()->make(SystemNotificationServices::class);
//清空模版缓存
$systemNotificationServices->clearTemplateCache();
}
return $this->success($i ? '队列执行中,请稍后查看,小程序需要选择:生活服务/百货/超市/便利店类目' : '已同步成功,请不要重复同步');
}
/**
* 下载小程序
* @return mixed
*/
public function downloadTemp()
{
[$name, $is_live] = $this->request->postMore([
['name', ''],
['is_live', 0]
], true);
if (!sys_config('routine_appId', '')) {
return $this->fail('请先在设置->系统设置->应用设置,配置小程序相关信息');
}
if (!file_exists(public_path() . 'statics/mp_view') || count(scandir(public_path() . 'statics/mp_view')) == 2) {
return $this->fail('请先上传小程序打包文件,路径:' . public_path() . 'statics/mp_view');
}
try {
@unlink(public_path() . 'statics/download/routine.zip');
//拷贝源文件
/** @var FileService $fileService */
$fileService = app(FileService::class);
$fileService->copyDir(public_path() . 'statics/mp_view', public_path() . 'statics/download');
$baseUrl = sys_config('site_url');
batch([
'appId' => function () use ($name) {
try {
$this->updateConfigJson(sys_config('routine_appId'), $name != '' ? $name : sys_config('routine_name'));
} catch (\Throwable $e) {
}
return true;
},
'updateApp' => function () use ($is_live) {
$res1 = true;
//是否开启直播
if ($is_live == 0) {
//pages.json 替换直播组件
try {
$this->updateAppJson();
} catch (\Throwable $e) {
}
}
return $res1;
},
'updateProductDetail' => function () use ($is_live) {
$res1 = true;
//是否开启直播
if ($is_live == 0) {
//商品详情页 替换直播组件
try {
$this->updateProductDetailJson();
} catch (\Throwable $e) {
}
}
return $res1;
},
'url' => function () use ($baseUrl) {
//替换url
try {
$this->updateUrl($baseUrl);
} catch (\Throwable $e) {
}
return true;
}
]);
//压缩文件
$fileService->addZip(public_path() . 'statics/download', public_path() . 'statics/download/routine.zip', public_path() . 'statics/download');
$data['url'] = $baseUrl . '/statics/download/routine.zip';
return app('json')->success($data);
} catch (\Throwable $e) {
return $this->fail($e->getMessage());
}
}
/**
* 替换url
* @param $url
*/
public function updateUrl($url)
{
$fileUrl = app()->getRootPath() . "public/statics/download/common/vendor.js";
$string = file_get_contents($fileUrl); //加载配置文件
$url = parse_url($url)['host'] ?? $url;
$string = str_replace('demo.crmeb.com', $url, $string); // 正则查找然后替换
$newFileUrl = app()->getRootPath() . "public/statics/download/common/vendor.js";
@file_put_contents($newFileUrl, $string); // 写入配置文件
}
/**
* 判断是否开启直播(弃用)
* @param int $iszhibo
*/
public function updateAppJson()
{
$fileUrl = app()->getRootPath() . "public/statics/download/app.json";
$string = file_get_contents($fileUrl); //加载配置文件
$pats = '/,
"plugins": {
"live-player-plugin": {
"version": "(.*?)",
"provider": "(.*?)"
}
}/';
$string = preg_replace($pats, '', $string); // 正则查找然后替换
$newFileUrl = app()->getRootPath() . "public/statics/download/app.json";
@file_put_contents($newFileUrl, $string); // 写入配置文件
}
/**
* 替换appid
* @param string $appid
* @param string $projectanme
*/
public function updateConfigJson($appId = '', $projectName = '')
{
$fileUrl = app()->getRootPath() . "public/statics/download/project.config.json";
$string = file_get_contents($fileUrl); //加载配置文件
// 替换appid
$appIdOld = '/"appid"(.*?),/';
$appIdNew = '"appid"' . ': ' . '"' . $appId . '",';
$string = preg_replace($appIdOld, $appIdNew, $string); // 正则查找然后替换
// 替换小程序名称
$projectNameOld = '/"projectname"(.*?),/';
$projectNameNew = '"projectname"' . ': ' . '"' . $projectName . '",';
$string = preg_replace($projectNameOld, $projectNameNew, $string); // 正则查找然后替换
$newFileUrl = app()->getRootPath() . "public/statics/download/project.config.json";
@file_put_contents($newFileUrl, $string); // 写入配置文件
}
/**
* 替换商品详情直播
*/
public function updateProductDetailJson()
{
$fileUrl = app()->getRootPath() . "public/statics/download/common/main.js";
$string = file_get_contents($fileUrl); //加载配置文件
$string = str_replace('requirePlugin("live-player-plugin")', 'null', $string);
$pats = '/onShow:function\(e\)\{(.*?)},/';
$string = preg_replace($pats, '', $string); // 正则查找然后替换
$newFileUrl = app()->getRootPath() . "public/statics/download/common/main.js";
@file_put_contents($newFileUrl, $string); // 写入配置文件
}
/**
* 获取下载小程序模版页面数据
* @return \think\Response
* @throws \think\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
*/
public function getDownloadInfo()
{
$data['routine_name'] = sys_config('routine_name', '');
$appid = sys_config('routine_appId', '');
if (!$appid) {
return $this->fail('请先在设置->系统设置->应用设置,配置小程序相关信息');
}
$name = $data['routine_name'] . '.jpg';
/** @var QrcodeServices $qrcode */
$qrcode = app()->make(QrcodeServices::class);
$resForever = $qrcode->qrCodeForever(0, 'code');
$id = (int)$resForever['id'];
/** @var QrcodeServices $QrcodeService */
$QrcodeService = app()->make(QrcodeServices::class);
//生成小程序地址
$urlCode = $QrcodeService->getRoutineQrcodePath($id, 0, -1, $name);
if ($urlCode) {
$qrcode->update($id, ['status' => 1, 'time' => time(), 'qrcode_url' => $urlCode]);
}
$data['code'] = $urlCode;
$data['appId'] = $appid;
$data['help'] = 'https://doc.crmeb.com/web/pro/crmebprov2/1192';
return $this->success($data);
}
}

View File

@@ -0,0 +1,123 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\wechat;
use app\controller\admin\AuthController;
use app\services\wechat\WechatCardServices;
use think\annotation\Inject;
/**
* 微信卡券
* Class WechatCard
* @package app\controller\admin\v1\application\wechat
*/
class WechatCard extends AuthController
{
/**
* @var WechatCardServices
*/
#[Inject]
protected WechatCardServices $services;
/**
* @return \think\Response
* @author 等风来
* @email 136327134@qq.com
* @date 2023/9/19
*/
public function index()
{
$where = $this->request->postMore([
['kerword', ''],
['status', '']
]);
return app('json')->success($this->services->getList($where));
}
/**
* 获取微信会员卡信息
* @return mixed
*/
public function info()
{
return $this->success($this->services->getInfo());
}
public function create()
{
return $this->success($this->services->createForm());
}
/**
* 添加|编辑会员卡
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function save()
{
$data = $this->request->postMore([
['brand_name', ''],
['title', ''],
['logo_url', ''],
['service_phone', ''],
['background_pic_url', ''],
['color', ''],
['notice', ''],
['description', ''],
['center_title', ''],
['center_sub_title', ''],
['center_url', ''],
['prerogative', ''],
['custom_cell', []],
]);
if (!$data['brand_name']) return app('json')->fail('请输入商户名称');
if (!$data['title']) return app('json')->fail('请输入卡券名称');
if (!$data['logo_url']) return app('json')->fail('请选择LOGO');
if (!$data['service_phone']) return app('json')->fail('请输入正确手机号');
$this->services->save($data);
return app('json')->success('设置成功');
}
public function edit($id)
{
if (!$id) {
return $this->fail('缺少参数');
}
$card = $this->dao->get($id);
if (!$card) {
return $this->fail('卡券不存在!');
}
return $this->success($this->services->createForm($card));
}
public function setShow($id, $is_show)
{
if (!$id)
return app('json')->fail('数据不存在');
return app('json')->success($this->services->isShow((int)$id, $is_show));
}
public function delete($id)
{
if (!$id)
return app('json')->fail('数据不存在');
$this->services->delete($id);
return app('json')->success('删除成功');
}
}

View File

@@ -0,0 +1,50 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\wechat;
use app\controller\admin\AuthController;
/**
* 用户扫码点击事件
* Class SystemMessage
* @package app\admin\controller\system
*/
class WechatMessage extends AuthController
{
/**
* 显示操作记录
*/
public function index()
{
$where = $this->getMore([
['page', 1],
['limit', 20],
['nickname', ''],
['type', ''],
['data', ''],
]);
return $this->success([]);
}
/**
* 操作名称列表
* @return mixed
*/
public function operate()
{
return $this->success([]);
}
}

View File

@@ -0,0 +1,207 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\wechat;
use app\controller\admin\AuthController;
use crmeb\services\wechat\Messages;
use crmeb\services\wechat\OfficialAccount;
use think\annotation\Inject;
use think\facade\Log;
use app\services\wechat\WechatNewsCategoryServices;
use app\services\article\ArticleServices;
/**
* 图文信息
* Class WechatNewsCategory
* @package app\admin\controller\wechat
*
*/
class WechatNewsCategory extends AuthController
{
/**
* @var WechatNewsCategoryServices
*/
#[Inject]
protected WechatNewsCategoryServices $services;
/**
* 图文消息列表
* @return mixed
*/
public function index()
{
$where = $this->request->getMore([
['page', 1],
['limit', 20],
['cate_name', '']
]);
$list = $this->services->getAll($where);
return $this->success($list);
}
/**
* 图文详情
* @param $id
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public function read($id)
{
$info = $this->services->get($id);
/** @var ArticleServices $services */
$services = app()->make(ArticleServices::class);
$new = $services->articlesList($info['new_id']);
if ($new) $new = $new->toArray();
$info['new'] = $new;
return $this->success(compact('info'));
}
/**
* 删除图文
* @param $id
* @return mixed
*/
public function delete($id)
{
if (!$this->services->delete($id))
return $this->fail('删除失败,请稍候再试!');
else
return $this->success('删除成功!');
}
/**
* 新增或编辑保存
* @return mixed
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public function save()
{
$data = $this->request->postMore([
['id', 0]
]);
$data['list'] = $this->request->param('list', []);
try {
$id = [];
$countList = count($data['list']);
if (!$countList) return $this->fail('请添加图文');
/** @var ArticleServices $services */
$services = app()->make(ArticleServices::class);
foreach ($data['list'] as $k => $v) {
if ($v['title'] == '') return $this->fail('标题不能为空');
if ($v['author'] == '') return $this->fail('作者不能为空');
if ($v['content'] == '') return $this->fail('正文不能为空');
if ($v['synopsis'] == '') return $this->fail('摘要不能为空');
$v['status'] = 1;
$v['add_time'] = time();
if ($v['id']) {
$idC = $v['id'];
$services->save($v);
unset($v['id']);
$data['list'][$k]['id'] = $idC;
$id[] = $idC;
} else {
$res = $services->save($v);
unset($v['id']);
$id[] = $res['id'];
$data['list'][$k]['id'] = $res['id'];
}
}
$countId = count($id);
if ($countId != $countList) {
if ($data['id']) return $this->fail('修改失败');
else return $this->fail('添加失败');
} else {
$newsCategory['cate_name'] = $data['list'][0]['title'];
$newsCategory['new_id'] = implode(',', $id);
$newsCategory['sort'] = 0;
$newsCategory['add_time'] = time();
$newsCategory['status'] = 1;
if ($data['id']) {
$this->services->update($data['id'], $newsCategory, 'id');
return $this->success('修改成功');
} else {
$this->services->save($newsCategory);
return $this->success('添加成功');
}
}
} catch (\Exception $e) {
return $this->fail($e->getMessage());
}
}
/**
* 发送消息
* @param int $id
* @param string $wechat
* $wechat 不为空 发消息 / 空 群发消息
*/
public function push()
{
$data = $this->request->postMore([
['id', 0],
['user_ids', '']
]);
if (!$data['id']) return $this->fail('参数错误');
$list = $this->services->getWechatNewsItem($data['id']);
$wechatNews = [];
if ($list) {
if (is_array($list['new']) && count($list['new'])) {
$wechatNews['title'] = $list['new'][0]['title'];
$wechatNews['image_input'] = $list['new'][0]['image_input'];
$wechatNews['date'] = date('m月d日', time());
$wechatNews['description'] = $list['new'][0]['synopsis'];
$wechatNews['id'] = $list['new'][0]['id'];
}
}
if ($data['user_ids'] != '') {//客服消息
$wechatNews = $this->services->wechatPush($wechatNews);
$message = Messages::newsMessage($wechatNews);
$errorLog = [];//发送失败的用户
$user = $this->services->getWechatUser($data['user_ids'], 'nickname,subscribe,openid', 'uid');
if ($user) {
foreach ($user as $v) {
if ($v['subscribe'] && $v['openid']) {
try {
OfficialAccount::staffSend($message, $v['openid']);
} catch (\Exception $e) {
Log::error($v['nickname'] . '发送失败,原因:' . $e->getMessage());
$errorLog[] = $v['nickname'] . '发送失败';
}
} else {
$errorLog[] = $v['nickname'] . '没有关注发送失败(不是微信公众号用户)';
}
}
} else return $this->fail('发送失败,参数不正确');
if (!count($errorLog)) return $this->success('全部发送成功');
else return $this->success(implode(',', $errorLog) . ',剩余的发送成功');
}
}
/**
* 发送消息图文列表
* @return mixed
*/
public function send_news()
{
$where = $this->request->getMore([
['cate_name', ''],
['page', 1],
['limit', 10]
]);
return $this->success($this->services->list($where));
}
}

View File

@@ -0,0 +1,190 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\wechat;
use app\controller\admin\AuthController;
use app\services\wechat\WechatQrcodeCateServices;
use app\services\wechat\WechatQrcodeRecordServices;
use app\services\wechat\WechatQrcodeServices;
use think\annotation\Inject;
class WechatQrcode extends AuthController
{
/**
* @var WechatQrcodeCateServices
*/
#[Inject]
protected WechatQrcodeCateServices $qrcodeCateServices;
/**
* @var WechatQrcodeServices
*/
#[Inject]
protected WechatQrcodeServices $wechatQrcodeServices;
/**
* @var WechatQrcodeRecordServices
*/
#[Inject]
protected WechatQrcodeRecordServices $qrcodeRecordServices;
/**
* 分类列表
* @return mixed
*/
public function getCateList()
{
$data = $this->qrcodeCateServices->getCateList(['is_del' => 0]);
$count = $this->qrcodeCateServices->count(['is_del' => 0]);
return app('json')->success(compact('data', 'count'));
}
/**
* 添加编辑表单
* @param $id
* @return mixed
* @throws \FormBuilder\Exception\FormBuilderException
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function createForm($id)
{
return app('json')->success($this->qrcodeCateServices->createForm($id));
}
/**
* 保存数据
* @return mixed
*/
public function saveCate()
{
$data = $this->request->postMore([
['id', 0],
['cate_name', '']
]);
$this->qrcodeCateServices->saveData($data);
return app('json')->success('保持成功');
}
/**
* 删除分类
* @param $id
* @return mixed
*/
public function delCate($id)
{
$this->qrcodeCateServices->delCate((int)$id);
return app('json')->success('删除成功');
}
/**
* 保存渠道码
* @param $id
* @return mixed
*/
public function saveQrcode($id = 0)
{
$data = $this->request->postMore([
['uid', 0],
['name', ''],
['image', ''],
['cate_id', 0],
['label_id', []],
['type', 0],
['content', ''],
['time', 0],
]);
$this->wechatQrcodeServices->saveQrcode($id, $data);
return app('json')->success('保存成功');
}
/**
* 获取渠道码列表
* @return mixed
*/
public function qrcodeList()
{
$where = $this->request->getMore([
['name', ''],
['cate_id', 0]
]);
$where['is_del'] = 0;
$data = $this->wechatQrcodeServices->qrcodeList($where);
return app('json')->success($data);
}
/**
* 获取详情
* @param int $id
* @return mixed
*/
public function qrcodeInfo($id = 0)
{
if (!$id) return app('json')->fail('参数错误');
$info = $this->wechatQrcodeServices->qrcodeInfo($id);
return app('json')->success($info);
}
/**
* 删除渠道码
* @param int $id
* @return mixed
*/
public function delQrcode($id = 0)
{
if (!$id) return app('json')->fail('参数错误');
$this->wechatQrcodeServices->update($id, ['is_del' => 1]);
return app('json')->success('删除成功');
}
/**
* 切换状态
* @param $id
* @param $status
* @return mixed
*/
public function setStatus($id, $status)
{
if (!$id) return app('json')->fail('参数错误');
$this->wechatQrcodeServices->update($id, ['status' => $status]);
return app('json')->success('切换成功');
}
/**
* 用户列表
* @param $qid
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function userList($qid)
{
return app('json')->success($this->qrcodeRecordServices->userList($qid));
}
/**
* 渠道码统计
* @param $qid
* @return mixed
*/
public function qrcodeStatistic($qid)
{
[$time] = $this->request->getMore([
['time', ''],
], true);
$where['qid'] = $qid;
return app('json')->success($this->qrcodeRecordServices->qrcodeStatistic($where, $time));
}
}

View File

@@ -0,0 +1,226 @@
<?php
// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
namespace app\controller\admin\v1\wechat;
use app\controller\admin\AuthController;
use app\jobs\notice\template\WechatTemplateJob;
use app\services\message\SystemNotificationServices;
use app\services\message\TemplateMessageServices;
use crmeb\services\{FormBuilder as Form, template\Template};
use crmeb\services\CacheService;
use think\annotation\Inject;
use think\facade\Route as Url;
use think\Request;
/**
* 微信模板消息
* Class WechatTemplate
* @package app\controller\admin\v1\application\wechat
*/
class WechatTemplate extends AuthController
{
/**
* @var string
*/
protected string $cacheTag = 'system_wechat';
/**
* @var TemplateMessageServices
*/
#[Inject]
protected TemplateMessageServices $services;
/**
* 显示资源列表
*
* @return \think\Response
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$where = $this->request->getMore([
['name', ''],
['status', '']
]);
$where['type'] = 1;
$data = $this->services->getTemplateList($where);
$industry = CacheService::get($this->cacheTag . '_wechat_industry', function () {
try {
$cache = (new Template('wechat'))->getIndustry();
if (!$cache) return [];
return $cache->toArray();
} catch (\Exception $e) {
return $e->getMessage();
}
}, 0) ?: [];
!is_array($industry) && $industry = [];
$industry['primary_industry'] = isset($industry['primary_industry']) ? $industry['primary_industry']['first_class'] . ' | ' . $industry['primary_industry']['second_class'] : '未选择';
$industry['secondary_industry'] = isset($industry['secondary_industry']) ? $industry['secondary_industry']['first_class'] . ' | ' . $industry['secondary_industry']['second_class'] : '未选择';
$lst = array(
'industry' => $industry,
'count' => $data['count'],
'list' => $data['list']
);
return $this->success($lst);
}
/**
* 显示创建资源表单页.
*
* @return \think\Response
*/
public function create()
{
$f = array();
$f[] = Form::input('tempkey', '模板编号');
$f[] = Form::input('tempid', '模板ID');
$f[] = Form::input('name', '模板名');
$f[] = Form::input('content', '回复内容')->type('textarea');
$f[] = Form::radio('status', '状态', 1)->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
return $this->makePostForm('添加模板消息', $f, Url::buildUrl('/app/wechat/template'), 'POST');
}
/**
* 保存新建的资源
*
* @param \think\Request $request
* @return \think\Response
*/
public function save(Request $request)
{
$data = $this->request->postMore([
'tempkey',
'tempid',
'name',
'content',
['status', 0],
['type', 1]
]);
if ($data['tempkey'] == '') return $this->fail('请输入模板编号');
if ($data['tempkey'] != '' && $this->services->getOne(['tempkey' => $data['tempkey']]))
return $this->fail('请输入模板编号已存在,请重新输入');
if ($data['tempid'] == '') return $this->fail('请输入模板ID');
if ($data['name'] == '') return $this->fail('请输入模板名');
if ($data['content'] == '') return $this->fail('请输入回复内容');
$data['add_time'] = time();
$this->services->save($data);
return $this->success('添加模板消息成功!');
}
/**
* 显示指定的资源
*
* @param int $id
* @return \think\Response
*/
public function read($id)
{
//
}
/**
* 显示编辑资源表单页.
*
* @param int $id
* @return \think\Response
*/
public function edit($id)
{
if (!$id) return $this->fail('数据不存在');
$product = $this->services->get($id);
if (!$product) return $this->fail('数据不存在!');
$f = array();
$f[] = Form::input('tempkey', '模板编号', $product->getData('tempkey'))->disabled(1);
$f[] = Form::input('name', '模板名', $product->getData('name'))->disabled(1);
$f[] = Form::input('tempid', '模板ID', $product->getData('tempid'));
$f[] = Form::radio('status', '状态', $product->getData('status'))->options([['label' => '开启', 'value' => 1], ['label' => '关闭', 'value' => 0]]);
return $this->makePostForm('编辑模板消息', $f, Url::buildUrl('/app/wechat/template/' . $id), 'PUT');
}
/**
* 保存更新的资源
*
* @param \think\Request $request
* @param int $id
* @return \think\Response
*/
public function update(Request $request, $id)
{
$data = $this->request->postMore([
'tempid',
['status', 0],
['type', 1]
]);
if ($data['tempid'] == '') return $this->fail('请输入模板ID');
if (!$id) return $this->fail('数据不存在');
$product = $this->services->get($id);
if (!$product) return $this->fail('数据不存在!');
$this->services->update($id, $data, 'id');
return $this->success('修改成功!');
}
/**
* 删除指定资源
*
* @param int $id
* @return \think\Response
*/
public function delete($id)
{
if (!$id) return $this->fail('数据不存在!');
if (!$this->services->delete($id))
return $this->fail('删除失败,请稍候再试!');
else
return $this->success('删除成功!');
}
/**
* 修改状态
* @param $id
* @param $status
* @return mixed
*/
public function set_status($id, $status)
{
if ($status == '' || $id == 0) return $this->fail('参数错误');
$this->services->update($id, ['status' => $status], 'id');
return $this->success($status == 0 ? '关闭成功' : '开启成功');
}
/**
* 同步订阅消息
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function syncSubscribe()
{
if (!sys_config('wechat_appid') || !sys_config('wechat_appsecret')) {
return $this->fail('请先配置微信公众号appid、appSecret等参数');
}
$tempall = $this->services->getTemplateList(['status' => 1, 'type' => 1]);
$temp = $tempall['list'] ?? [];
if (!$temp) {
return $this->fail('请先检查`eb_template_message`数据完整性,完整sql路径/public/install/crmeb.sql');
}
WechatTemplateJob::dispatch([$temp]);
/** @var SystemNotificationServices $systemNotificationServices */
$systemNotificationServices = app()->make(SystemNotificationServices::class);
//清空模版缓存
$systemNotificationServices->clearTemplateCache();
return $this->success('队列执行中,请稍后查看');
}
}