chore(notice): 规范修复与安装演练收尾

This commit is contained in:
augushong
2026-10-12 13:40:40 +00:00
parent 3b6cb66549
commit a756b8a1cd
23 changed files with 978 additions and 981 deletions

View File

@@ -2,11 +2,11 @@
namespace app\admin\scheme;
use app\common\scheme\BaseScheme;
use app\common\scheme\attribute\Table;
use app\common\scheme\attribute\Field;
use app\common\scheme\attribute\Component;
use app\common\scheme\attribute\Field;
use app\common\scheme\attribute\Index;
use app\common\scheme\attribute\Table;
use app\common\scheme\BaseScheme;
#[Table(name: 'ul_mall_goods', comment: '商品列表')]
#[Index(columns: ['cate_id'], name: 'cate_id', type: 'NORMAL')]
@@ -85,4 +85,4 @@ class MallGoods extends BaseScheme
#[Field(type: 'text', comment: '属性(静态字段)')]
public $property_static;
}
}

View File

@@ -2,11 +2,11 @@
namespace app\admin\scheme;
use app\common\scheme\BaseScheme;
use app\common\scheme\attribute\Table;
use app\common\scheme\attribute\Field;
use app\common\scheme\attribute\Component;
use app\common\scheme\attribute\Field;
use app\common\scheme\attribute\Index;
use app\common\scheme\attribute\Table;
use app\common\scheme\BaseScheme;
#[Table(name: 'ul_system_admin', comment: '系统用户表')]
#[Index(columns: ['username'], name: 'username', type: 'NORMAL')]
@@ -59,4 +59,4 @@ class SystemAdmin extends BaseScheme
#[Field(type: 'char', length: 100, precision: 100, default: '', comment: '电子邮箱')]
public $email;
}
}

View File

@@ -2,11 +2,10 @@
namespace app\admin\scheme;
use app\common\scheme\BaseScheme;
use app\common\scheme\attribute\Table;
use app\common\scheme\attribute\Field;
use app\common\scheme\attribute\Component;
use app\common\scheme\attribute\Index;
use app\common\scheme\attribute\Table;
use app\common\scheme\BaseScheme;
#[Table(name: 'ul_system_notice', comment: '系统通知表')]
#[Index(columns: ['scene'], name: 'idx_scene', type: 'NORMAL')]

View File

@@ -2,11 +2,10 @@
namespace app\admin\scheme;
use app\common\scheme\BaseScheme;
use app\common\scheme\attribute\Table;
use app\common\scheme\attribute\Field;
use app\common\scheme\attribute\Component;
use app\common\scheme\attribute\Index;
use app\common\scheme\attribute\Table;
use app\common\scheme\BaseScheme;
#[Table(name: 'ul_system_notice_subscribe', comment: '系统通知订阅表')]
#[Index(columns: ['admin_id', 'scene', 'channel'], name: 'uniq_admin_scene_channel', type: 'UNIQUE')]

View File

@@ -2,11 +2,10 @@
namespace app\admin\scheme;
use app\common\scheme\BaseScheme;
use app\common\scheme\attribute\Table;
use app\common\scheme\attribute\Field;
use app\common\scheme\attribute\Component;
use app\common\scheme\attribute\Index;
use app\common\scheme\attribute\Table;
use app\common\scheme\BaseScheme;
#[Table(name: 'ul_system_notice_target', comment: '系统通知投递目标表')]
#[Index(columns: ['status', 'id'], name: 'idx_status_id', type: 'NORMAL')]

View File

@@ -1,7 +1,7 @@
<?php
use think\migration\Migrator;
use think\migration\db\Column;
use think\migration\Migrator;
/**
* system_admin 追加电子邮箱字段(幂等,已存在则跳过).
@@ -12,7 +12,7 @@ class SystemAdminEmail extends Migrator
{
$table = $this->table('system_admin');
if(!$table->hasColumn('email')){
if (!$table->hasColumn('email')) {
$table->addColumn(Column::char('email', 100)->setDefault('')->setComment('电子邮箱'));
$table->update();
}

View File

@@ -6,7 +6,7 @@ use think\console\Output;
use think\migration\Migrator;
/**
* 通知管理菜单与 notify 配置默认值对齐
* 通知管理菜单与 notify 配置默认值对齐.
*
* 背景:通知系统特性落地(system.notice 模块 + sysconfig notify 配置组),
* 快照变更配套迁移——adminInitData/SystemMenu.php 追加「通知管理」菜单

View File

@@ -25,7 +25,7 @@ class NoticeBase extends AdminController
*/
protected const SUBSCRIBE_CHANNELS = [
NoticeService::CHANNEL_INMAIL => '站内信',
NoticeService::CHANNEL_EMAIL => '邮箱',
NoticeService::CHANNEL_EMAIL => '邮箱',
];
/**
@@ -72,10 +72,10 @@ class NoticeBase extends AdminController
->order($this->sort)
->select();
$data = [
'code' => 0,
'msg' => '',
'code' => 0,
'msg' => '',
'count' => $count,
'data' => $list,
'data' => $list,
];
return json($data);
@@ -112,11 +112,11 @@ class NoticeBase extends AdminController
$sceneTitleMap[$scene] = $info['title'];
}
$msg = [
'id' => (int) $row->id,
'title' => (string) ($notice->title ?? '(通知已删除)'),
'id' => (int) $row->id,
'title' => (string) ($notice->title ?? '(通知已删除)'),
'scene_title' => $sceneTitleMap[(string) ($notice->scene ?? '')] ?? (string) ($notice->scene ?? '-'),
'content' => (string) ($notice->content ?? ''),
'read_time' => (int) $row->read_time,
'content' => (string) ($notice->content ?? ''),
'read_time' => (int) $row->read_time,
'create_time' => (int) $row->create_time,
];
$this->assign('msg', $msg);
@@ -192,16 +192,16 @@ class NoticeBase extends AdminController
foreach (array_keys(self::SUBSCRIBE_CHANNELS) as $channel) {
$checked = $locked || ($subscribeMap[$scene . '|' . $channel] ?? 1) === 1;
$cells[] = [
'name' => 'matrix[' . $scene . '][' . $channel . ']',
'checked' => $checked ? 'checked' : '',
'name' => 'matrix[' . $scene . '][' . $channel . ']',
'checked' => $checked ? 'checked' : '',
'disabled' => $locked ? 'disabled' : '',
];
}
$matrix[] = [
'scene' => $scene,
'title' => $info['title'],
'scene' => $scene,
'title' => $info['title'],
'locked' => $locked,
'cells' => $cells,
'cells' => $cells,
];
}
@@ -251,10 +251,10 @@ class NoticeBase extends AdminController
->update(['status' => $status, 'update_time' => $now]);
} else {
Db::name('system_notice_subscribe')->insert([
'admin_id' => $adminId,
'scene' => (string) $scene,
'channel' => (string) $channel,
'status' => $status,
'admin_id' => $adminId,
'scene' => (string) $scene,
'channel' => (string) $channel,
'status' => $status,
'create_time' => $now,
'update_time' => $now,
]);

View File

@@ -115,12 +115,12 @@ class NoticeBase extends AdminController
$delivery = [];
foreach ($statusCount as $channel => $counts) {
$delivery[] = [
'channel' => $channel,
'channel' => $channel,
'channel_name' => $channelNames[$channel] ?? $channel,
'pending' => $counts[SystemNoticeTarget::STATUS_PENDING] ?? 0,
'sending' => $counts[SystemNoticeTarget::STATUS_SENDING] ?? 0,
'success' => $counts[SystemNoticeTarget::STATUS_SUCCESS] ?? 0,
'failed' => $counts[SystemNoticeTarget::STATUS_FAILED] ?? 0,
'pending' => $counts[SystemNoticeTarget::STATUS_PENDING] ?? 0,
'sending' => $counts[SystemNoticeTarget::STATUS_SENDING] ?? 0,
'success' => $counts[SystemNoticeTarget::STATUS_SUCCESS] ?? 0,
'failed' => $counts[SystemNoticeTarget::STATUS_FAILED] ?? 0,
];
}
@@ -140,22 +140,22 @@ class NoticeBase extends AdminController
SystemNoticeTarget::STATUS_PENDING => ['name' => '待发', 'class' => 'layui-badge layui-bg-blue'],
SystemNoticeTarget::STATUS_SENDING => ['name' => '发送中', 'class' => 'layui-badge layui-bg-orange'],
SystemNoticeTarget::STATUS_SUCCESS => ['name' => '成功', 'class' => 'layui-badge layui-bg-green'],
SystemNoticeTarget::STATUS_FAILED => ['name' => '失败', 'class' => 'layui-badge'],
SystemNoticeTarget::STATUS_FAILED => ['name' => '失败', 'class' => 'layui-badge'],
];
$targetRows = [];
foreach ($targets as $target) {
$status = (int) $target->status;
$targetRows[] = [
'id' => $target->id,
'id' => $target->id,
'admin_nickname' => $nicknames[$target->admin_id] ?? ('#' . $target->admin_id),
'target_addr' => $target->target_addr,
'channel_name' => $channelNames[$target->channel] ?? $target->channel,
'status' => $status,
'status_name' => $statusMeta[$status]['name'] ?? (string) $status,
'status_class' => $statusMeta[$status]['class'] ?? 'layui-badge layui-bg-gray',
'retry_count' => (int) $target->retry_count,
'error_message' => (string) $target->error_message,
'send_time' => (int) $target->send_time,
'target_addr' => $target->target_addr,
'channel_name' => $channelNames[$target->channel] ?? $target->channel,
'status' => $status,
'status_name' => $statusMeta[$status]['name'] ?? (string) $status,
'status_class' => $statusMeta[$status]['class'] ?? 'layui-badge layui-bg-gray',
'retry_count' => (int) $target->retry_count,
'error_message' => (string) $target->error_message,
'send_time' => (int) $target->send_time,
];
}
@@ -197,9 +197,9 @@ class NoticeBase extends AdminController
$this->checkPostRequest();
$post = $this->request->post();
$rule = [
'id|ID' => 'require',
'id|ID' => 'require',
'field|字段' => 'require',
'value|值' => 'require',
'value|值' => 'require',
];
$this->validate($post, $rule);
if (!in_array($post['field'], $this->allowModifyFields)) {
@@ -238,10 +238,10 @@ class NoticeBase extends AdminController
$query->where('id', $targetId);
}
$count = $query->update([
'status' => SystemNoticeTarget::STATUS_PENDING,
'retry_count' => 0,
'status' => SystemNoticeTarget::STATUS_PENDING,
'retry_count' => 0,
'next_retry_time' => 0,
'error_message' => '',
'error_message' => '',
]);
$count > 0
@@ -274,14 +274,14 @@ class NoticeBase extends AdminController
$rows = [];
foreach (NoticeService::scenes() as $scene => $item) {
$rows[] = [
'scene' => $scene,
'title' => $item['title'],
'scene' => $scene,
'title' => $item['title'],
'channel_names' => implode('、', array_map(function ($channel) use ($channelNames) {
return $channelNames[$channel] ?? $channel;
}, $item['channels'])),
'locked' => (int) $item['locked'],
'subscribed' => $subscribeCounts[$scene] ?? 0,
'total_admins' => $totalAdmins,
'locked' => (int) $item['locked'],
'subscribed' => $subscribeCounts[$scene] ?? 0,
'total_admins' => $totalAdmins,
];
}
@@ -297,10 +297,10 @@ class NoticeBase extends AdminController
private function channelNames(): array
{
return [
NoticeService::CHANNEL_INMAIL => '站内信',
NoticeService::CHANNEL_EMAIL => '邮件',
NoticeService::CHANNEL_SMS => '短信',
NoticeService::CHANNEL_WECHAT => '公众号',
NoticeService::CHANNEL_INMAIL => '站内信',
NoticeService::CHANNEL_EMAIL => '邮件',
NoticeService::CHANNEL_SMS => '短信',
NoticeService::CHANNEL_WECHAT => '公众号',
];
}
}

View File

@@ -1,4 +1,5 @@
<?php
/**
* @internal-framework
*
@@ -9,490 +10,490 @@
*
* 注意:此文件属于框架内核,业务开发者不应修改
*/
$ul_system_config = [
[
'name' => 'alisms_access_key_id',
'group' => 'sms',
'value' => '填你的',
'remark' => '阿里大于公钥',
'sort' => 0,
],
[
'name' => 'alisms_access_key_secret',
'group' => 'sms',
'value' => '填你的',
'remark' => '阿里大鱼私钥',
'sort' => 0,
],
[
'name' => 'upload_type',
'group' => 'upload',
'value' => 'local_public',
'remark' => '当前上传方式 local_public,alioss,qnoss,txcos,s3,webdav',
'sort' => 0,
],
[
'name' => 'upload_allow_ext',
'group' => 'upload',
'value' => 'jpg,jpeg,png,gif,bmp,doc,docx,xls,xlsx,ppt,pptx,pdf,zip,rar,7z,txt,mp3,wma,wav,mid,m4a,mp4,avi,wmv,3gp,flv,webp,svg,ico',
'remark' => '允许上传的文件类型',
'sort' => 0,
],
[
'name' => 'upload_allow_size',
'group' => 'upload',
'value' => '1024000',
'remark' => '允许上传的大小',
'sort' => 0,
],
[
'name' => 'upload_allow_mime',
'group' => 'upload',
'value' => 'image/gif,image/jpeg,video/x-msvideo,text/plain,image/png',
'remark' => '允许上传的文件mime',
'sort' => 0,
],
[
'name' => 'upload_allow_type',
'group' => 'upload',
'value' => 'local_public,alioss,qnoss,txcos,s3,webdav',
'remark' => '可用的上传文件方式',
'sort' => 0,
],
[
'name' => 'alioss_access_key_id',
'group' => 'upload',
'value' => '填你的',
'remark' => '阿里云oss公钥',
'sort' => 0,
],
[
'name' => 'alioss_access_key_secret',
'group' => 'upload',
'value' => '填你的',
'remark' => '阿里云oss私钥',
'sort' => 0,
],
[
'name' => 'alioss_endpoint',
'group' => 'upload',
'value' => '填你的',
'remark' => '阿里云oss数据中心',
'sort' => 0,
],
[
'name' => 'alioss_bucket',
'group' => 'upload',
'value' => '填你的',
'remark' => '阿里云oss空间名称',
'sort' => 0,
],
[
'name' => 'alioss_domain',
'group' => 'upload',
'value' => '填你的',
'remark' => '阿里云oss访问域名',
'sort' => 0,
],
[
'name' => 'logo_title',
'group' => 'site',
'value' => 'ulthon_admin',
'remark' => 'LOGO标题',
'sort' => 0,
],
[
'name' => 'logo_image',
'group' => 'site',
'value' => '/static/common/images/logo-2.png',
'remark' => 'logo图片',
'sort' => 0,
],
[
'name' => 'site_name',
'group' => 'site',
'value' => 'ulthon_admin后台系统',
'remark' => '站点名称',
'sort' => 0,
],
[
'name' => 'site_ico',
'group' => 'site',
'value' => '/favicon.ico',
'remark' => '浏览器图标',
'sort' => 0,
],
[
'name' => 'site_copyright',
'group' => 'site',
'value' => '填你的',
'remark' => '版权信息',
'sort' => 0,
],
[
'name' => 'site_beian',
'group' => 'site',
'value' => '填你的',
'remark' => '备案信息',
'sort' => 0,
],
[
'name' => 'site_version',
'group' => 'site',
'value' => '2.0.0',
'remark' => '版本信息',
'sort' => 0,
],
[
'name' => 'sms_type',
'group' => 'sms',
'value' => 'alisms',
'remark' => '短信类型',
'sort' => 0,
],
[
'name' => 'miniapp_appid',
'group' => 'wechat',
'value' => '填你的',
'remark' => '小程序公钥',
'sort' => 0,
],
[
'name' => 'miniapp_appsecret',
'group' => 'wechat',
'value' => '填你的',
'remark' => '小程序私钥',
'sort' => 0,
],
[
'name' => 'web_appid',
'group' => 'wechat',
'value' => '填你的',
'remark' => '公众号公钥',
'sort' => 0,
],
[
'name' => 'web_appsecret',
'group' => 'wechat',
'value' => '填你的',
'remark' => '公众号私钥',
'sort' => 0,
],
[
'name' => 'txcos_secret_id',
'group' => 'upload',
'value' => '填你的',
'remark' => '腾讯云cos密钥',
'sort' => 0,
],
[
'name' => 'txcos_secret_key',
'group' => 'upload',
'value' => '填你的',
'remark' => '腾讯云cos私钥',
'sort' => 0,
],
[
'name' => 'txcos_region',
'group' => 'upload',
'value' => '填你的',
'remark' => '存储桶地域',
'sort' => 0,
],
[
'name' => 'txcos_bucket',
'group' => 'upload',
'value' => '填你的',
'remark' => '存储桶名称',
'sort' => 0,
],
[
'name' => 'qnoss_access_key',
'group' => 'upload',
'value' => '填你的',
'remark' => '访问密钥',
'sort' => 0,
],
[
'name' => 'qnoss_secret_key',
'group' => 'upload',
'value' => '填你的',
'remark' => '安全密钥',
'sort' => 0,
],
[
'name' => 'qnoss_bucket',
'group' => 'upload',
'value' => '填你的',
'remark' => '存储空间',
'sort' => 0,
],
[
'name' => 'qnoss_domain',
'group' => 'upload',
'value' => '填你的',
'remark' => '访问域名',
'sort' => 0,
],
[
'name' => 'txcos_domain',
'group' => 'upload',
'value' => '填你的',
'remark' => '访问域名',
'sort' => 0,
],
[
'name' => 'txcos_appid',
'group' => 'upload',
'value' => '填你的',
'remark' => 'APPID',
'sort' => 0,
],
[
'name' => 's3_access_key',
'group' => 'upload',
'value' => '填你的',
'remark' => 'S3公钥',
'sort' => 0,
],
[
'name' => 's3_secret_key',
'group' => 'upload',
'value' => '填你的',
'remark' => 'S3私钥',
'sort' => 0,
],
[
'name' => 's3_region',
'group' => 'upload',
'value' => '填你的',
'remark' => 'S3地域',
'sort' => 0,
],
[
'name' => 's3_bucket',
'group' => 'upload',
'value' => '填你的',
'remark' => 'S3空间名称',
'sort' => 0,
],
[
'name' => 's3_domain',
'group' => 'upload',
'value' => '填你的',
'remark' => 'S3访问域名',
'sort' => 0,
],
[
'name' => 's3_endpoint',
'group' => 'upload',
'value' => '',
'remark' => 'S3自定义端点(兼容MinIO等,留空用AWS官方)',
'sort' => 0,
],
[
'name' => 's3_path_style',
'group' => 'upload',
'value' => '0',
'remark' => 'S3路径风格(1开启,MinIO建议)',
'sort' => 0,
],
[
'name' => 'webdav_url',
'group' => 'upload',
'value' => '填你的',
'remark' => 'WebDAV服务地址',
'sort' => 0,
],
[
'name' => 'webdav_username',
'group' => 'upload',
'value' => '填你的',
'remark' => 'WebDAV账户',
'sort' => 0,
],
[
'name' => 'webdav_password',
'group' => 'upload',
'value' => '填你的',
'remark' => 'WebDAV密码',
'sort' => 0,
],
[
'name' => 'webdav_domain',
'group' => 'upload',
'value' => '填你的',
'remark' => 'WebDAV访问域名',
'sort' => 0,
],
[
'name' => 'webdav_prefix',
'group' => 'upload',
'value' => '',
'remark' => 'WebDAV存储前缀',
'sort' => 0,
],
[
'name' => 'file',
'group' => 'site',
'value' => '',
'remark' => '',
'sort' => 0,
],
[
'name' => 'site_domain',
'group' => 'site',
'value' => 'http://admin.demo.ulthon.com',
'remark' => '',
'sort' => 0,
],
[
'name' => 'raw_retention_days',
'group' => 'nginx_log',
'value' => '7',
'remark' => '原始日志保留天数(0=永久)',
'sort' => 0,
],
[
'name' => 'stat_retention_days',
'group' => 'nginx_log',
'value' => '365',
'remark' => '统计聚合保留天数(0=永久)',
'sort' => 0,
],
[
'name' => 'topn_default',
'group' => 'nginx_log',
'value' => '10',
'remark' => 'Top N 默认值(热门 URL/Referer/UA)',
'sort' => 0,
],
[
'name' => 'exclude_static',
'group' => 'nginx_log',
'value' => '1',
'remark' => '是否排除静态资源访问(0=不排除,1=排除 /css/.js/.png 等扩展名)',
'sort' => 0,
],
[
'name' => 'notify_inmail_enable',
'group' => 'notify',
'value' => '1',
'remark' => '站内信通知渠道全局总闸(1=开启,0=关闭,键缺失视为开启)',
'sort' => 0,
],
[
'name' => 'notify_login_scene_enable',
'group' => 'notify',
'value' => '0',
'remark' => '管理员登录成功提醒通知(1=开启,0=关闭,默认关闭)',
'sort' => 0,
],
[
'name' => 'notify_email_enable',
'group' => 'notify',
'value' => '0',
'remark' => '邮件通知渠道总开关(1=开启,0=关闭,开启前需配置SMTP)',
'sort' => 0,
],
[
'name' => 'notify_smtp_host',
'group' => 'notify',
'value' => '',
'remark' => 'SMTP服务器地址',
'sort' => 0,
],
[
'name' => 'notify_smtp_port',
'group' => 'notify',
'value' => '',
'remark' => 'SMTP端口(SSL 465/TLS 587/无加密 25)',
'sort' => 0,
],
[
'name' => 'notify_smtp_secure',
'group' => 'notify',
'value' => 'none',
'remark' => 'SMTP加密方式(none=无加密,ssl,tls)',
'sort' => 0,
],
[
'name' => 'notify_smtp_user',
'group' => 'notify',
'value' => '',
'remark' => 'SMTP登录账号(留空则不认证)',
'sort' => 0,
],
[
'name' => 'notify_smtp_pass',
'group' => 'notify',
'value' => '',
'remark' => 'SMTP登录密码或授权码',
'sort' => 0,
],
[
'name' => 'notify_smtp_from',
'group' => 'notify',
'value' => '',
'remark' => '发件邮箱地址(缺省notice@localhost,真实发送需合法地址)',
'sort' => 0,
],
[
'name' => 'notify_smtp_from_name',
'group' => 'notify',
'value' => '',
'remark' => '邮件发件人名称',
'sort' => 0,
],
[
'name' => 'notify_sms_enable',
'group' => 'notify',
'value' => '0',
'remark' => '短信通知开关(1=开启,0=关闭,扩展占位待对接)',
'sort' => 0,
],
[
'name' => 'notify_sms_sign',
'group' => 'notify',
'value' => '',
'remark' => '短信签名(服务商审核通过)',
'sort' => 0,
],
[
'name' => 'notify_sms_appid',
'group' => 'notify',
'value' => '',
'remark' => '短信服务商应用ID',
'sort' => 0,
],
[
'name' => 'notify_sms_secret',
'group' => 'notify',
'value' => '',
'remark' => '短信服务商密钥',
'sort' => 0,
],
[
'name' => 'notify_wechat_enable',
'group' => 'notify',
'value' => '0',
'remark' => '公众号模板消息通知开关(1=开启,0=关闭,扩展占位待对接)',
'sort' => 0,
],
[
'name' => 'notify_wechat_appid',
'group' => 'notify',
'value' => '',
'remark' => '微信公众号应用ID',
'sort' => 0,
],
[
'name' => 'notify_wechat_secret',
'group' => 'notify',
'value' => '',
'remark' => '微信公众号应用密钥',
'sort' => 0,
],
];
$ul_system_config = array(
array(
"name" => "alisms_access_key_id",
"group" => "sms",
"value" => "填你的",
"remark" => "阿里大于公钥",
"sort" => 0,
),
array(
"name" => "alisms_access_key_secret",
"group" => "sms",
"value" => "填你的",
"remark" => "阿里大鱼私钥",
"sort" => 0,
),
array(
"name" => "upload_type",
"group" => "upload",
"value" => "local_public",
"remark" => "当前上传方式 local_public,alioss,qnoss,txcos,s3,webdav",
"sort" => 0,
),
array(
"name" => "upload_allow_ext",
"group" => "upload",
"value" => "jpg,jpeg,png,gif,bmp,doc,docx,xls,xlsx,ppt,pptx,pdf,zip,rar,7z,txt,mp3,wma,wav,mid,m4a,mp4,avi,wmv,3gp,flv,webp,svg,ico",
"remark" => "允许上传的文件类型",
"sort" => 0,
),
array(
"name" => "upload_allow_size",
"group" => "upload",
"value" => "1024000",
"remark" => "允许上传的大小",
"sort" => 0,
),
array(
"name" => "upload_allow_mime",
"group" => "upload",
"value" => "image/gif,image/jpeg,video/x-msvideo,text/plain,image/png",
"remark" => "允许上传的文件mime",
"sort" => 0,
),
array(
"name" => "upload_allow_type",
"group" => "upload",
"value" => "local_public,alioss,qnoss,txcos,s3,webdav",
"remark" => "可用的上传文件方式",
"sort" => 0,
),
array(
"name" => "alioss_access_key_id",
"group" => "upload",
"value" => "填你的",
"remark" => "阿里云oss公钥",
"sort" => 0,
),
array(
"name" => "alioss_access_key_secret",
"group" => "upload",
"value" => "填你的",
"remark" => "阿里云oss私钥",
"sort" => 0,
),
array(
"name" => "alioss_endpoint",
"group" => "upload",
"value" => "填你的",
"remark" => "阿里云oss数据中心",
"sort" => 0,
),
array(
"name" => "alioss_bucket",
"group" => "upload",
"value" => "填你的",
"remark" => "阿里云oss空间名称",
"sort" => 0,
),
array(
"name" => "alioss_domain",
"group" => "upload",
"value" => "填你的",
"remark" => "阿里云oss访问域名",
"sort" => 0,
),
array(
"name" => "logo_title",
"group" => "site",
"value" => "ulthon_admin",
"remark" => "LOGO标题",
"sort" => 0,
),
array(
"name" => "logo_image",
"group" => "site",
"value" => "/static/common/images/logo-2.png",
"remark" => "logo图片",
"sort" => 0,
),
array(
"name" => "site_name",
"group" => "site",
"value" => "ulthon_admin后台系统",
"remark" => "站点名称",
"sort" => 0,
),
array(
"name" => "site_ico",
"group" => "site",
"value" => "/favicon.ico",
"remark" => "浏览器图标",
"sort" => 0,
),
array(
"name" => "site_copyright",
"group" => "site",
"value" => "填你的",
"remark" => "版权信息",
"sort" => 0,
),
array(
"name" => "site_beian",
"group" => "site",
"value" => "填你的",
"remark" => "备案信息",
"sort" => 0,
),
array(
"name" => "site_version",
"group" => "site",
"value" => "2.0.0",
"remark" => "版本信息",
"sort" => 0,
),
array(
"name" => "sms_type",
"group" => "sms",
"value" => "alisms",
"remark" => "短信类型",
"sort" => 0,
),
array(
"name" => "miniapp_appid",
"group" => "wechat",
"value" => "填你的",
"remark" => "小程序公钥",
"sort" => 0,
),
array(
"name" => "miniapp_appsecret",
"group" => "wechat",
"value" => "填你的",
"remark" => "小程序私钥",
"sort" => 0,
),
array(
"name" => "web_appid",
"group" => "wechat",
"value" => "填你的",
"remark" => "公众号公钥",
"sort" => 0,
),
array(
"name" => "web_appsecret",
"group" => "wechat",
"value" => "填你的",
"remark" => "公众号私钥",
"sort" => 0,
),
array(
"name" => "txcos_secret_id",
"group" => "upload",
"value" => "填你的",
"remark" => "腾讯云cos密钥",
"sort" => 0,
),
array(
"name" => "txcos_secret_key",
"group" => "upload",
"value" => "填你的",
"remark" => "腾讯云cos私钥",
"sort" => 0,
),
array(
"name" => "txcos_region",
"group" => "upload",
"value" => "填你的",
"remark" => "存储桶地域",
"sort" => 0,
),
array(
"name" => "txcos_bucket",
"group" => "upload",
"value" => "填你的",
"remark" => "存储桶名称",
"sort" => 0,
),
array(
"name" => "qnoss_access_key",
"group" => "upload",
"value" => "填你的",
"remark" => "访问密钥",
"sort" => 0,
),
array(
"name" => "qnoss_secret_key",
"group" => "upload",
"value" => "填你的",
"remark" => "安全密钥",
"sort" => 0,
),
array(
"name" => "qnoss_bucket",
"group" => "upload",
"value" => "填你的",
"remark" => "存储空间",
"sort" => 0,
),
array(
"name" => "qnoss_domain",
"group" => "upload",
"value" => "填你的",
"remark" => "访问域名",
"sort" => 0,
),
array(
"name" => "txcos_domain",
"group" => "upload",
"value" => "填你的",
"remark" => "访问域名",
"sort" => 0,
),
array(
"name" => "txcos_appid",
"group" => "upload",
"value" => "填你的",
"remark" => "APPID",
"sort" => 0,
),
array(
"name" => "s3_access_key",
"group" => "upload",
"value" => "填你的",
"remark" => "S3公钥",
"sort" => 0,
),
array(
"name" => "s3_secret_key",
"group" => "upload",
"value" => "填你的",
"remark" => "S3私钥",
"sort" => 0,
),
array(
"name" => "s3_region",
"group" => "upload",
"value" => "填你的",
"remark" => "S3地域",
"sort" => 0,
),
array(
"name" => "s3_bucket",
"group" => "upload",
"value" => "填你的",
"remark" => "S3空间名称",
"sort" => 0,
),
array(
"name" => "s3_domain",
"group" => "upload",
"value" => "填你的",
"remark" => "S3访问域名",
"sort" => 0,
),
array(
"name" => "s3_endpoint",
"group" => "upload",
"value" => "",
"remark" => "S3自定义端点(兼容MinIO等,留空用AWS官方)",
"sort" => 0,
),
array(
"name" => "s3_path_style",
"group" => "upload",
"value" => "0",
"remark" => "S3路径风格(1开启,MinIO建议)",
"sort" => 0,
),
array(
"name" => "webdav_url",
"group" => "upload",
"value" => "填你的",
"remark" => "WebDAV服务地址",
"sort" => 0,
),
array(
"name" => "webdav_username",
"group" => "upload",
"value" => "填你的",
"remark" => "WebDAV账户",
"sort" => 0,
),
array(
"name" => "webdav_password",
"group" => "upload",
"value" => "填你的",
"remark" => "WebDAV密码",
"sort" => 0,
),
array(
"name" => "webdav_domain",
"group" => "upload",
"value" => "填你的",
"remark" => "WebDAV访问域名",
"sort" => 0,
),
array(
"name" => "webdav_prefix",
"group" => "upload",
"value" => "",
"remark" => "WebDAV存储前缀",
"sort" => 0,
),
array(
"name" => "file",
"group" => "site",
"value" => "",
"remark" => "",
"sort" => 0,
),
array(
"name" => "site_domain",
"group" => "site",
"value" => "http://admin.demo.ulthon.com",
"remark" => "",
"sort" => 0,
),
array(
"name" => "raw_retention_days",
"group" => "nginx_log",
"value" => "7",
"remark" => "原始日志保留天数(0=永久)",
"sort" => 0,
),
array(
"name" => "stat_retention_days",
"group" => "nginx_log",
"value" => "365",
"remark" => "统计聚合保留天数(0=永久)",
"sort" => 0,
),
array(
"name" => "topn_default",
"group" => "nginx_log",
"value" => "10",
"remark" => "Top N 默认值(热门 URL/Referer/UA)",
"sort" => 0,
),
array(
"name" => "exclude_static",
"group" => "nginx_log",
"value" => "1",
"remark" => "是否排除静态资源访问(0=不排除,1=排除 /css/.js/.png 等扩展名)",
"sort" => 0,
),
array(
"name" => "notify_inmail_enable",
"group" => "notify",
"value" => "1",
"remark" => "站内信通知渠道全局总闸(1=开启,0=关闭,键缺失视为开启)",
"sort" => 0,
),
array(
"name" => "notify_login_scene_enable",
"group" => "notify",
"value" => "0",
"remark" => "管理员登录成功提醒通知(1=开启,0=关闭,默认关闭)",
"sort" => 0,
),
array(
"name" => "notify_email_enable",
"group" => "notify",
"value" => "0",
"remark" => "邮件通知渠道总开关(1=开启,0=关闭,开启前需配置SMTP)",
"sort" => 0,
),
array(
"name" => "notify_smtp_host",
"group" => "notify",
"value" => "",
"remark" => "SMTP服务器地址",
"sort" => 0,
),
array(
"name" => "notify_smtp_port",
"group" => "notify",
"value" => "",
"remark" => "SMTP端口(SSL 465/TLS 587/无加密 25)",
"sort" => 0,
),
array(
"name" => "notify_smtp_secure",
"group" => "notify",
"value" => "none",
"remark" => "SMTP加密方式(none=无加密,ssl,tls)",
"sort" => 0,
),
array(
"name" => "notify_smtp_user",
"group" => "notify",
"value" => "",
"remark" => "SMTP登录账号(留空则不认证)",
"sort" => 0,
),
array(
"name" => "notify_smtp_pass",
"group" => "notify",
"value" => "",
"remark" => "SMTP登录密码或授权码",
"sort" => 0,
),
array(
"name" => "notify_smtp_from",
"group" => "notify",
"value" => "",
"remark" => "发件邮箱地址(缺省notice@localhost,真实发送需合法地址)",
"sort" => 0,
),
array(
"name" => "notify_smtp_from_name",
"group" => "notify",
"value" => "",
"remark" => "邮件发件人名称",
"sort" => 0,
),
array(
"name" => "notify_sms_enable",
"group" => "notify",
"value" => "0",
"remark" => "短信通知开关(1=开启,0=关闭,扩展占位待对接)",
"sort" => 0,
),
array(
"name" => "notify_sms_sign",
"group" => "notify",
"value" => "",
"remark" => "短信签名(服务商审核通过)",
"sort" => 0,
),
array(
"name" => "notify_sms_appid",
"group" => "notify",
"value" => "",
"remark" => "短信服务商应用ID",
"sort" => 0,
),
array(
"name" => "notify_sms_secret",
"group" => "notify",
"value" => "",
"remark" => "短信服务商密钥",
"sort" => 0,
),
array(
"name" => "notify_wechat_enable",
"group" => "notify",
"value" => "0",
"remark" => "公众号模板消息通知开关(1=开启,0=关闭,扩展占位待对接)",
"sort" => 0,
),
array(
"name" => "notify_wechat_appid",
"group" => "notify",
"value" => "",
"remark" => "微信公众号应用ID",
"sort" => 0,
),
array(
"name" => "notify_wechat_secret",
"group" => "notify",
"value" => "",
"remark" => "微信公众号应用密钥",
"sort" => 0,
)
);
return $ul_system_config;

View File

@@ -1,4 +1,5 @@
<?php
/**
* @internal-framework
*
@@ -9,333 +10,331 @@
*
* 注意:此文件属于框架内核,业务开发者不应修改
*/
$ul_system_menu = array(
array(
"id" => 227,
"pid" => 99999999,
"title" => "欢迎页",
"icon" => "fa fa-home",
"href" => "index/welcome",
"params" => "",
"target" => "_self",
"sort" => 0,
"status" => 1,
),
array(
"id" => 228,
"pid" => 0,
"title" => "系统管理",
"icon" => "fa fa-cog",
"href" => "",
"params" => "",
"target" => "_self",
"sort" => 0,
"status" => 1,
),
array(
"id" => 234,
"pid" => 228,
"title" => "菜单管理",
"icon" => "fa fa-tree",
"href" => "system.menu/index",
"params" => "",
"target" => "_self",
"sort" => 10,
"status" => 1,
),
array(
"id" => 244,
"pid" => 228,
"title" => "管理员管理",
"icon" => "fa fa-user",
"href" => "system.admin/index",
"params" => "",
"target" => "_self",
"sort" => 12,
"status" => 1,
),
array(
"id" => 245,
"pid" => 228,
"title" => "角色管理",
"icon" => "fa fa-bitbucket-square",
"href" => "system.auth/index",
"params" => "",
"target" => "_self",
"sort" => 11,
"status" => 1,
),
array(
"id" => 246,
"pid" => 228,
"title" => "节点管理",
"icon" => "fa fa-list",
"href" => "system.node/index",
"params" => "",
"target" => "_self",
"sort" => 9,
"status" => 1,
),
array(
"id" => 247,
"pid" => 228,
"title" => "配置管理",
"icon" => "fa fa-asterisk",
"href" => "system.config/index",
"params" => "",
"target" => "_self",
"sort" => 8,
"status" => 1,
),
array(
"id" => 248,
"pid" => 228,
"title" => "上传管理",
"icon" => "fa fa-arrow-up",
"href" => "system.uploadfile/index",
"params" => "",
"target" => "_self",
"sort" => 0,
"status" => 1,
),
array(
"id" => 249,
"pid" => 0,
"title" => "商城管理",
"icon" => "fa fa-list",
"href" => "",
"params" => "",
"target" => "_self",
"sort" => 0,
"status" => 1,
),
array(
"id" => 250,
"pid" => 249,
"title" => "商品分类",
"icon" => "fa fa-calendar-check-o",
"href" => "mall.cate/index",
"params" => "",
"target" => "_self",
"sort" => 0,
"status" => 1,
),
array(
"id" => 251,
"pid" => 249,
"title" => "商品管理",
"icon" => "fa fa-list",
"href" => "mall.goods/index",
"params" => "",
"target" => "_self",
"sort" => 0,
"status" => 1,
),
array(
"id" => 252,
"pid" => 228,
"title" => "快捷入口",
"icon" => "fa fa-list",
"href" => "system.quick/index",
"params" => "",
"target" => "_self",
"sort" => 0,
"status" => 1,
),
array(
"id" => 253,
"pid" => 309,
"title" => "日志管理",
"icon" => "fa fa-connectdevelop",
"href" => "debug.log/index",
"params" => "",
"target" => "_self",
"sort" => 0,
"status" => 1,
),
array(
"id" => 255,
"pid" => 309,
"title" => "系统状态",
"icon" => "fa fa-info-circle",
"href" => "system.status/index",
"params" => "",
"target" => "_self",
"sort" => 1,
"status" => 1,
),
array(
"id" => 254,
"pid" => 249,
"title" => "商品标签",
"icon" => "fa fa-connectdevelop",
"href" => "mall.tag/index",
"params" => "",
"target" => "_self",
"sort" => 0,
"status" => 1,
),
array(
"id" => 256,
"pid" => 310,
"title" => "定时器配置",
"icon" => "fa fa-clock-o",
"href" => "system.timer_config/index",
"params" => "",
"target" => "_self",
"sort" => 0,
"status" => 1,
),
array(
"id" => 257,
"pid" => 310,
"title" => "定时器日志",
"icon" => "fa fa-history",
"href" => "system.timer_log/index",
"params" => "",
"target" => "_self",
"sort" => 0,
"status" => 1,
),
array(
"id" => 258,
"pid" => 309,
"title" => "主机列表",
"icon" => "fa fa-server",
"href" => "system.host/index",
"params" => "",
"target" => "_self",
"sort" => 0,
"status" => 1,
),
array(
"id" => 301,
"pid" => 311,
"title" => "访问统计仪表盘",
"icon" => "fa fa-line-chart",
"href" => "system.nginx_log_stat/index",
"params" => "",
"target" => "_self",
"sort" => 1,
"status" => 1,
),
array(
"id" => 302,
"pid" => 311,
"title" => "原始访问日志",
"icon" => "fa fa-file-text",
"href" => "nginx.access_log/index",
"params" => "",
"target" => "_self",
"sort" => 0,
"status" => 1,
),
array(
"id" => 314,
"pid" => 311,
"title" => "日志读取位置",
"icon" => "fa fa-map-marker",
"href" => "nginx.log_position/index",
"params" => "",
"target" => "_self",
"auth_node" => "nginx.log_position/index",
"sort" => 0,
"status" => 1,
),
array(
"id" => 304,
"pid" => 309,
"title" => "性能分析",
"icon" => "fa fa-tachometer",
"href" => "",
"params" => "",
"target" => "_self",
"sort" => 2,
"status" => 1,
),
array(
"id" => 305,
"pid" => 304,
"title" => "采样列表",
"icon" => "fa fa-list",
"href" => "xhprof.run/index",
"params" => "",
"target" => "_self",
"auth_node" => "xhprof.run/index",
"sort" => 0,
"status" => 1,
),
array(
"id" => 306,
"pid" => 304,
"title" => "命中记录",
"icon" => "fa fa-crosshairs",
"href" => "xhprof.run_watch/index",
"params" => "",
"target" => "_self",
"auth_node" => "xhprof.run_watch/index",
"sort" => 0,
"status" => 1,
),
array(
"id" => 307,
"pid" => 304,
"title" => "监控规则",
"icon" => "fa fa-eye",
"href" => "xhprof.watch/index",
"params" => "",
"target" => "_self",
"auth_node" => "xhprof.watch/index",
"sort" => 0,
"status" => 1,
),
array(
"id" => 309,
"pid" => 228,
"title" => "运行管理",
"icon" => "fa fa-heartbeat",
"href" => "",
"params" => "",
"target" => "_self",
"sort" => 1,
"status" => 1,
),
array(
"id" => 310,
"pid" => 309,
"title" => "定时任务",
"icon" => "fa fa-clock-o",
"href" => "",
"params" => "",
"target" => "_self",
"sort" => 4,
"status" => 1,
),
array(
"id" => 311,
"pid" => 309,
"title" => "Web日志",
"icon" => "fa fa-globe",
"href" => "",
"params" => "",
"target" => "_self",
"sort" => 3,
"status" => 1,
),
array(
"id" => 315,
"pid" => 228,
"title" => "通知管理",
"icon" => "fa fa-bell-o",
"href" => "system.notice/index",
"params" => "",
"target" => "_self",
"auth_node" => "system.notice/index",
"sort" => 0,
"status" => 1,
),
);
$ul_system_menu = [
[
'id' => 227,
'pid' => 99999999,
'title' => '欢迎页',
'icon' => 'fa fa-home',
'href' => 'index/welcome',
'params' => '',
'target' => '_self',
'sort' => 0,
'status' => 1,
],
[
'id' => 228,
'pid' => 0,
'title' => '系统管理',
'icon' => 'fa fa-cog',
'href' => '',
'params' => '',
'target' => '_self',
'sort' => 0,
'status' => 1,
],
[
'id' => 234,
'pid' => 228,
'title' => '菜单管理',
'icon' => 'fa fa-tree',
'href' => 'system.menu/index',
'params' => '',
'target' => '_self',
'sort' => 10,
'status' => 1,
],
[
'id' => 244,
'pid' => 228,
'title' => '管理员管理',
'icon' => 'fa fa-user',
'href' => 'system.admin/index',
'params' => '',
'target' => '_self',
'sort' => 12,
'status' => 1,
],
[
'id' => 245,
'pid' => 228,
'title' => '角色管理',
'icon' => 'fa fa-bitbucket-square',
'href' => 'system.auth/index',
'params' => '',
'target' => '_self',
'sort' => 11,
'status' => 1,
],
[
'id' => 246,
'pid' => 228,
'title' => '节点管理',
'icon' => 'fa fa-list',
'href' => 'system.node/index',
'params' => '',
'target' => '_self',
'sort' => 9,
'status' => 1,
],
[
'id' => 247,
'pid' => 228,
'title' => '配置管理',
'icon' => 'fa fa-asterisk',
'href' => 'system.config/index',
'params' => '',
'target' => '_self',
'sort' => 8,
'status' => 1,
],
[
'id' => 248,
'pid' => 228,
'title' => '上传管理',
'icon' => 'fa fa-arrow-up',
'href' => 'system.uploadfile/index',
'params' => '',
'target' => '_self',
'sort' => 0,
'status' => 1,
],
[
'id' => 249,
'pid' => 0,
'title' => '商城管理',
'icon' => 'fa fa-list',
'href' => '',
'params' => '',
'target' => '_self',
'sort' => 0,
'status' => 1,
],
[
'id' => 250,
'pid' => 249,
'title' => '商品分类',
'icon' => 'fa fa-calendar-check-o',
'href' => 'mall.cate/index',
'params' => '',
'target' => '_self',
'sort' => 0,
'status' => 1,
],
[
'id' => 251,
'pid' => 249,
'title' => '商品管理',
'icon' => 'fa fa-list',
'href' => 'mall.goods/index',
'params' => '',
'target' => '_self',
'sort' => 0,
'status' => 1,
],
[
'id' => 252,
'pid' => 228,
'title' => '快捷入口',
'icon' => 'fa fa-list',
'href' => 'system.quick/index',
'params' => '',
'target' => '_self',
'sort' => 0,
'status' => 1,
],
[
'id' => 253,
'pid' => 309,
'title' => '日志管理',
'icon' => 'fa fa-connectdevelop',
'href' => 'debug.log/index',
'params' => '',
'target' => '_self',
'sort' => 0,
'status' => 1,
],
[
'id' => 255,
'pid' => 309,
'title' => '系统状态',
'icon' => 'fa fa-info-circle',
'href' => 'system.status/index',
'params' => '',
'target' => '_self',
'sort' => 1,
'status' => 1,
],
[
'id' => 254,
'pid' => 249,
'title' => '商品标签',
'icon' => 'fa fa-connectdevelop',
'href' => 'mall.tag/index',
'params' => '',
'target' => '_self',
'sort' => 0,
'status' => 1,
],
[
'id' => 256,
'pid' => 310,
'title' => '定时器配置',
'icon' => 'fa fa-clock-o',
'href' => 'system.timer_config/index',
'params' => '',
'target' => '_self',
'sort' => 0,
'status' => 1,
],
[
'id' => 257,
'pid' => 310,
'title' => '定时器日志',
'icon' => 'fa fa-history',
'href' => 'system.timer_log/index',
'params' => '',
'target' => '_self',
'sort' => 0,
'status' => 1,
],
[
'id' => 258,
'pid' => 309,
'title' => '主机列表',
'icon' => 'fa fa-server',
'href' => 'system.host/index',
'params' => '',
'target' => '_self',
'sort' => 0,
'status' => 1,
],
[
'id' => 301,
'pid' => 311,
'title' => '访问统计仪表盘',
'icon' => 'fa fa-line-chart',
'href' => 'system.nginx_log_stat/index',
'params' => '',
'target' => '_self',
'sort' => 1,
'status' => 1,
],
[
'id' => 302,
'pid' => 311,
'title' => '原始访问日志',
'icon' => 'fa fa-file-text',
'href' => 'nginx.access_log/index',
'params' => '',
'target' => '_self',
'sort' => 0,
'status' => 1,
],
[
'id' => 314,
'pid' => 311,
'title' => '日志读取位置',
'icon' => 'fa fa-map-marker',
'href' => 'nginx.log_position/index',
'params' => '',
'target' => '_self',
'auth_node' => 'nginx.log_position/index',
'sort' => 0,
'status' => 1,
],
[
'id' => 304,
'pid' => 309,
'title' => '性能分析',
'icon' => 'fa fa-tachometer',
'href' => '',
'params' => '',
'target' => '_self',
'sort' => 2,
'status' => 1,
],
[
'id' => 305,
'pid' => 304,
'title' => '采样列表',
'icon' => 'fa fa-list',
'href' => 'xhprof.run/index',
'params' => '',
'target' => '_self',
'auth_node' => 'xhprof.run/index',
'sort' => 0,
'status' => 1,
],
[
'id' => 306,
'pid' => 304,
'title' => '命中记录',
'icon' => 'fa fa-crosshairs',
'href' => 'xhprof.run_watch/index',
'params' => '',
'target' => '_self',
'auth_node' => 'xhprof.run_watch/index',
'sort' => 0,
'status' => 1,
],
[
'id' => 307,
'pid' => 304,
'title' => '监控规则',
'icon' => 'fa fa-eye',
'href' => 'xhprof.watch/index',
'params' => '',
'target' => '_self',
'auth_node' => 'xhprof.watch/index',
'sort' => 0,
'status' => 1,
],
[
'id' => 309,
'pid' => 228,
'title' => '运行管理',
'icon' => 'fa fa-heartbeat',
'href' => '',
'params' => '',
'target' => '_self',
'sort' => 1,
'status' => 1,
],
[
'id' => 310,
'pid' => 309,
'title' => '定时任务',
'icon' => 'fa fa-clock-o',
'href' => '',
'params' => '',
'target' => '_self',
'sort' => 4,
'status' => 1,
],
[
'id' => 311,
'pid' => 309,
'title' => 'Web日志',
'icon' => 'fa fa-globe',
'href' => '',
'params' => '',
'target' => '_self',
'sort' => 3,
'status' => 1,
],
[
'id' => 315,
'pid' => 228,
'title' => '通知管理',
'icon' => 'fa fa-bell-o',
'href' => 'system.notice/index',
'params' => '',
'target' => '_self',
'auth_node' => 'system.notice/index',
'sort' => 0,
'status' => 1,
],
];
return $ul_system_menu;

View File

@@ -17,7 +17,7 @@ class NoticeEventBase
}
// 不传 channels=按场景注册渠道展开(admin_login=[inmail,email]),再经各管理员订阅矩阵过滤
NoticeService::send([$admin->id], '登录提醒', "账号 {$admin->username} 于 ".date('Y-m-d H:i').' 登录成功', ['scene' => 'admin_login']);
NoticeService::send([$admin->id], '登录提醒', "账号 {$admin->username} 于 " . date('Y-m-d H:i') . ' 登录成功', ['scene' => 'admin_login']);
} catch (\Throwable $e) {
// 通知失败不得影响登录主流程
Log::error('admin login notice failed: ' . $e->getMessage());

View File

@@ -12,9 +12,9 @@ class LogEventBase
[$notice, $targets] = $payload;
Log::info('notice sended', [
'notice_id' => (int) $notice->id,
'notice_id' => (int) $notice->id,
'target_count' => count($targets),
'channels' => array_values(array_unique(array_column($targets, 'channel'))),
'channels' => array_values(array_unique(array_column($targets, 'channel'))),
]);
}
}

View File

@@ -29,15 +29,15 @@ class EmailChannel implements NoticeChannelInterface
throw new RuntimeException('邮件发送失败: 渠道未启用(notify_email_enable != 1)');
}
$host = (string) sysconfig('notify', 'notify_smtp_host');
$port = (int) sysconfig('notify', 'notify_smtp_port');
$secure = strtolower((string) sysconfig('notify', 'notify_smtp_secure'));
$user = (string) sysconfig('notify', 'notify_smtp_user');
$pass = (string) sysconfig('notify', 'notify_smtp_pass');
$from = (string) sysconfig('notify', 'notify_smtp_from', 'notice@localhost');
$host = (string) sysconfig('notify', 'notify_smtp_host');
$port = (int) sysconfig('notify', 'notify_smtp_port');
$secure = strtolower((string) sysconfig('notify', 'notify_smtp_secure'));
$user = (string) sysconfig('notify', 'notify_smtp_user');
$pass = (string) sysconfig('notify', 'notify_smtp_pass');
$from = (string) sysconfig('notify', 'notify_smtp_from', 'notice@localhost');
$fromName = (string) sysconfig('notify', 'notify_smtp_from_name');
$title = (string) ($notice['title'] ?? '');
$title = (string) ($notice['title'] ?? '');
$content = (string) ($notice['content'] ?? '');
$mailer = new PHPMailer(true);

View File

@@ -34,11 +34,11 @@ class SmsChannel implements NoticeChannelInterface
// 骨架驱动模拟发送:开关状态仅记入日志(关闭也恒成功),不拦截投递、不真实外呼
$enabled = (int) sysconfig('notify', 'notify_sms_enable');
Log::info('notice sms channel skeleton simulated send', [
'channel' => self::name(),
'enabled' => $enabled,
'notice_id' => $notice['id'] ?? 0,
'channel' => self::name(),
'enabled' => $enabled,
'notice_id' => $notice['id'] ?? 0,
'target_addr' => $target['target_addr'] ?? '',
'title' => $notice['title'] ?? '',
'title' => $notice['title'] ?? '',
]);
return true;

View File

@@ -34,11 +34,11 @@ class WechatChannel implements NoticeChannelInterface
// 骨架驱动模拟发送:开关状态仅记入日志(关闭也恒成功),不拦截投递、不真实外呼
$enabled = (int) sysconfig('notify', 'notify_wechat_enable');
Log::info('notice wechat channel skeleton simulated send', [
'channel' => self::name(),
'enabled' => $enabled,
'notice_id' => $notice['id'] ?? 0,
'channel' => self::name(),
'enabled' => $enabled,
'notice_id' => $notice['id'] ?? 0,
'target_addr' => $target['target_addr'] ?? '',
'title' => $notice['title'] ?? '',
'title' => $notice['title'] ?? '',
]);
return true;

View File

@@ -47,10 +47,10 @@ class NoticeServiceBase
public static function scenes(): array
{
return [
'system' => ['title' => '系统公告', 'channels' => [self::CHANNEL_INMAIL], 'locked' => true],
'common' => ['title' => '通用通知', 'channels' => [self::CHANNEL_INMAIL, self::CHANNEL_EMAIL], 'locked' => false],
'system' => ['title' => '系统公告', 'channels' => [self::CHANNEL_INMAIL], 'locked' => true],
'common' => ['title' => '通用通知', 'channels' => [self::CHANNEL_INMAIL, self::CHANNEL_EMAIL], 'locked' => false],
'admin_login' => ['title' => '登录提醒', 'channels' => [self::CHANNEL_INMAIL, self::CHANNEL_EMAIL], 'locked' => false],
'mall_stock' => ['title' => '库存预警', 'channels' => [self::CHANNEL_INMAIL, self::CHANNEL_EMAIL], 'locked' => false],
'mall_stock' => ['title' => '库存预警', 'channels' => [self::CHANNEL_INMAIL, self::CHANNEL_EMAIL], 'locked' => false],
];
}
@@ -64,8 +64,8 @@ class NoticeServiceBase
{
return [
self::CHANNEL_INMAIL => InMailChannel::class,
self::CHANNEL_EMAIL => EmailChannel::class,
self::CHANNEL_SMS => SmsChannel::class,
self::CHANNEL_EMAIL => EmailChannel::class,
self::CHANNEL_SMS => SmsChannel::class,
self::CHANNEL_WECHAT => WechatChannel::class,
];
}
@@ -117,10 +117,10 @@ class NoticeServiceBase
$now = time();
$notice = SystemNotice::create([
'scene' => $scene,
'title' => $title,
'content' => $content,
'biz_id' => (string) ($options['biz_id'] ?? ''),
'scene' => $scene,
'title' => $title,
'content' => $content,
'biz_id' => (string) ($options['biz_id'] ?? ''),
'send_admin_id' => (int) ($options['send_admin_id'] ?? 0),
]);
$noticeId = (int) $notice->id;
@@ -196,13 +196,13 @@ class NoticeServiceBase
$status = $isInmail ? SystemNoticeTargetBase::STATUS_SUCCESS : SystemNoticeTargetBase::STATUS_PENDING;
$targets[] = [
'notice_id' => $noticeId,
'admin_id' => $adminId,
'channel' => $channel,
'notice_id' => $noticeId,
'admin_id' => $adminId,
'channel' => $channel,
'target_addr' => $targetAddr,
'status' => $status,
'send_time' => $isInmail ? $now : 0,
'read_time' => 0,
'status' => $status,
'send_time' => $isInmail ? $now : 0,
'read_time' => 0,
'create_time' => $now,
'update_time' => $now,
];

View File

@@ -114,9 +114,9 @@ class NoticeConsumerBase extends TimerController
->where('id', 'in', $candidates)
->where('status', SystemNoticeTargetBase::STATUS_PENDING)
->update([
'status' => SystemNoticeTargetBase::STATUS_SENDING,
'status' => SystemNoticeTargetBase::STATUS_SENDING,
'claim_token' => $token,
'claim_time' => time(),
'claim_time' => time(),
'update_time' => time(),
]);
@@ -161,8 +161,8 @@ class NoticeConsumerBase extends TimerController
->where('claim_token', $token)
->where('status', SystemNoticeTargetBase::STATUS_SENDING)
->update([
'status' => SystemNoticeTargetBase::STATUS_SUCCESS,
'send_time' => time(),
'status' => SystemNoticeTargetBase::STATUS_SUCCESS,
'send_time' => time(),
'update_time' => time(),
]);
} catch (\Throwable $e) {
@@ -198,10 +198,10 @@ class NoticeConsumerBase extends TimerController
->where('claim_token', $token)
->where('status', SystemNoticeTargetBase::STATUS_SENDING)
->update([
'status' => SystemNoticeTargetBase::STATUS_FAILED,
'retry_count' => $retry_count,
'status' => SystemNoticeTargetBase::STATUS_FAILED,
'retry_count' => $retry_count,
'error_message' => $error_message,
'update_time' => time(),
'update_time' => time(),
]);
return;
@@ -212,11 +212,11 @@ class NoticeConsumerBase extends TimerController
->where('claim_token', $token)
->where('status', SystemNoticeTargetBase::STATUS_SENDING)
->update([
'status' => SystemNoticeTargetBase::STATUS_PENDING,
'retry_count' => $retry_count,
'status' => SystemNoticeTargetBase::STATUS_PENDING,
'retry_count' => $retry_count,
'next_retry_time' => time() + self::RETRY_BASE_SECONDS * (2 ** $retry_count),
'error_message' => $error_message,
'update_time' => time(),
'error_message' => $error_message,
'update_time' => time(),
]);
}
}

View File

@@ -45,9 +45,9 @@ class NoticeReclaimBase extends TimerController
->where('status', SystemNoticeTargetBase::STATUS_SENDING)
->where('claim_time', '<', time() - self::RECLAIM_TIMEOUT)
->update([
'status' => SystemNoticeTargetBase::STATUS_PENDING,
'status' => SystemNoticeTargetBase::STATUS_PENDING,
'claim_token' => '',
'claim_time' => 0,
'claim_time' => 0,
'update_time' => time(),
]);

View File

@@ -2,22 +2,16 @@
namespace think;
use app\common\command\Curd;
use app\common\command\OssStatic;
use app\common\command\Timer;
use app\common\command\admin\Clear;
use app\common\command\admin\MigrateFileData;
use app\common\command\admin\ResetPassword;
use app\common\command\admin\Update;
use app\common\command\admin\UpdateCode;
use app\common\command\admin\Version;
use app\common\command\admin\menu\AdminMenuCreate;
use app\common\command\admin\menu\AdminMenuDelete;
use app\common\command\admin\menu\AdminMenuExport;
use app\common\command\admin\menu\AdminMenuList;
use app\common\command\admin\menu\AdminMenuUpdate;
use app\common\command\admin\MigrateFileData;
use app\common\command\admin\permission\AdminPermissionNodes;
use app\common\command\admin\permission\PermissionUser;
use app\common\command\admin\ResetPassword;
use app\common\command\admin\role\AdminRoleCreate;
use app\common\command\admin\role\AdminRoleDelete;
use app\common\command\admin\role\AdminRoleInfo;
@@ -26,24 +20,30 @@ use app\common\command\admin\role\AdminRolePermissionAssign;
use app\common\command\admin\role\AdminRolePermissionList;
use app\common\command\admin\role\AdminRolePermissionRevoke;
use app\common\command\admin\timer\TimerLogClean;
use app\common\command\admin\Update;
use app\common\command\admin\UpdateCode;
use app\common\command\admin\user\AdminUserRoleAssign;
use app\common\command\admin\user\AdminUserRoleList;
use app\common\command\admin\user\AdminUserRoleRevoke;
use app\common\command\admin\Version;
use app\common\command\Curd;
use app\common\command\curd\Migrate;
use app\common\command\OssStatic;
use app\common\command\scheme\Backup;
use app\common\command\scheme\Make;
use app\common\command\scheme\Sync;
use app\common\command\tools\http\ToolsHttpCall;
use app\common\command\Test;
use app\common\command\Timer;
use app\common\command\tools\db\ToolsDbCount;
use app\common\command\tools\db\ToolsDbDesc;
use app\common\command\tools\db\ToolsDbExecute;
use app\common\command\tools\db\ToolsDbInfo;
use app\common\command\tools\db\ToolsDbQuery;
use app\common\command\tools\db\ToolsDbTable;
use app\common\command\tools\http\ToolsHttpCall;
use app\common\command\tools\log\ToolsLogSearch;
use app\common\command\tools\log\ToolsLogShow;
use app\common\command\tools\log\ToolsLogStats;
use app\common\command\Test;
use app\common\event\AdminLoginSuccess\LogEvent;
use app\common\event\AdminLoginSuccess\NoticeEvent;
use app\common\event\AdminLoginType\DemoEvent;

View File

@@ -4,11 +4,11 @@ declare(strict_types=1);
namespace tests\Feature;
use app\common\service\NoticeService;
use app\common\test\TestCase;
use base\common\notice\channel\EmailChannel;
use base\common\notice\channel\SmsChannel;
use base\common\notice\channel\WechatChannel;
use app\common\service\NoticeService;
use think\facade\Cache;
use think\facade\Db;
@@ -101,11 +101,11 @@ class NoticeChannelTest extends TestCase
private function setNotifyConfig(string $name, string $value): void
{
Db::name('system_config')->insert([
'name' => $name,
'group' => 'notify',
'value' => $value,
'remark' => 'NoticeChannelTest fixture',
'sort' => 100,
'name' => $name,
'group' => 'notify',
'value' => $value,
'remark' => 'NoticeChannelTest fixture',
'sort' => 100,
'create_time' => time(),
'update_time' => time(),
]);

View File

@@ -77,9 +77,9 @@ class NoticeEventTest extends TestCase
// inmail 行直接成功终态(无 email 地址的管理员 email 渠道被跳过)
$this->assertDatabaseHas('system_notice_target', [
'notice_id' => $row['id'],
'admin_id' => $adminId,
'channel' => 'inmail',
'status' => 2,
'admin_id' => $adminId,
'channel' => 'inmail',
'status' => 2,
]);
$this->assertSame(
1,
@@ -119,11 +119,11 @@ class NoticeEventTest extends TestCase
private function createAdmin(array $overrides = []): int
{
$data = array_merge([
'username' => 'evt_' . uniqid(),
'password' => 'not-a-real-password',
'nickname' => '事件测试用户',
'email' => '',
'status' => 1,
'username' => 'evt_' . uniqid(),
'password' => 'not-a-real-password',
'nickname' => '事件测试用户',
'email' => '',
'status' => 1,
'create_time' => time(),
'update_time' => time(),
'delete_time' => 0,
@@ -138,11 +138,11 @@ class NoticeEventTest extends TestCase
private function setLoginSceneSwitch(string $value): void
{
Db::name('system_config')->insert([
'name' => 'notify_login_scene_enable',
'group' => 'notify',
'value' => $value,
'remark' => 'NoticeEventTest fixture',
'sort' => 100,
'name' => 'notify_login_scene_enable',
'group' => 'notify',
'value' => $value,
'remark' => 'NoticeEventTest fixture',
'sort' => 100,
'create_time' => time(),
'update_time' => time(),
]);

View File

@@ -42,11 +42,11 @@ class NoticeServiceTest extends TestCase
$this->assertGreaterThan(0, $noticeId);
$this->assertDatabaseHas('system_notice', [
'id' => $noticeId,
'scene' => 'common',
'title' => '测试标题',
'content' => '测试内容',
'biz_id' => '',
'id' => $noticeId,
'scene' => 'common',
'title' => '测试标题',
'content' => '测试内容',
'biz_id' => '',
'send_admin_id' => 0,
]);
@@ -130,11 +130,11 @@ class NoticeServiceTest extends TestCase
$this->assertSame(2, Db::name('system_notice_target')
->where('notice_id', $noticeId)->where('admin_id', $adminWithMail)->count());
$this->assertDatabaseHas('system_notice_target', [
'notice_id' => $noticeId,
'admin_id' => $adminWithMail,
'channel' => 'email',
'notice_id' => $noticeId,
'admin_id' => $adminWithMail,
'channel' => 'email',
'target_addr' => 'scene@test.com',
'status' => 0,
'status' => 0,
]);
}
@@ -220,8 +220,8 @@ class NoticeServiceTest extends TestCase
$this->assertSame(1, Db::name('system_notice_target')->where('notice_id', $noticeId)->count());
$this->assertDatabaseHas('system_notice_target', [
'notice_id' => $noticeId,
'channel' => 'inmail',
'status' => 2,
'channel' => 'inmail',
'status' => 2,
]);
}
@@ -269,8 +269,8 @@ class NoticeServiceTest extends TestCase
$noticeId2 = NoticeService::send([$adminId], '总闸恢复', '内容');
$this->assertDatabaseHas('system_notice_target', [
'notice_id' => $noticeId2,
'channel' => 'inmail',
'status' => 2,
'channel' => 'inmail',
'status' => 2,
]);
}
@@ -348,11 +348,11 @@ class NoticeServiceTest extends TestCase
private function createAdmin(array $overrides = []): int
{
$data = array_merge([
'username' => 'ntc_' . uniqid(),
'password' => 'not-a-real-password',
'nickname' => '通知测试用户',
'email' => '',
'status' => 1,
'username' => 'ntc_' . uniqid(),
'password' => 'not-a-real-password',
'nickname' => '通知测试用户',
'email' => '',
'status' => 1,
'create_time' => time(),
'update_time' => time(),
'delete_time' => 0,
@@ -367,10 +367,10 @@ class NoticeServiceTest extends TestCase
private function insertSubscribe(int $adminId, string $scene, string $channel, int $status): void
{
Db::name('system_notice_subscribe')->insert([
'admin_id' => $adminId,
'scene' => $scene,
'channel' => $channel,
'status' => $status,
'admin_id' => $adminId,
'scene' => $scene,
'channel' => $channel,
'status' => $status,
'create_time' => time(),
'update_time' => time(),
]);
@@ -385,11 +385,11 @@ class NoticeServiceTest extends TestCase
private function setInmailSwitch(string $value): void
{
Db::name('system_config')->insert([
'name' => 'notify_inmail_enable',
'group' => 'notify',
'value' => $value,
'remark' => 'NoticeServiceTest fixture',
'sort' => 100,
'name' => 'notify_inmail_enable',
'group' => 'notify',
'value' => $value,
'remark' => 'NoticeServiceTest fixture',
'sort' => 100,
'create_time' => time(),
'update_time' => time(),
]);