This commit is contained in:
zhang zhuo 2025-12-15 15:05:21 +08:00
parent 7a907ad314
commit dc1d3c1cc1
24 changed files with 793 additions and 25 deletions

View File

@ -156,7 +156,7 @@ class Login extends Base
#[Auth(needAuth: false)]
public function saveInfo()
{
$param = Param::only(['nickname', 'birthday', 'sex', 'bio', 'avatar']);
$param = Param::only(['nickname', 'birthday', 'sex', 'bio', 'avatar', 'phone', 'email']);
$res = Account::where("account_id", $this->accountId())->update($param);
return $res ? $this->success("保存成功") : $this->error("保存失败");
}

View File

@ -11,6 +11,7 @@ use App\Model\Crontab as cModel;
use App\Model\CrontabLog as clModel;
use App\Model\Dept as dModel;
use App\Model\Menu as mModel;
use App\Model\AccountMessage as amModel;
use App\Model\Online as oModel;
use App\Model\Post as pModel;
use App\Model\Role as rModel;
@ -275,7 +276,7 @@ class System extends Base
$request = $this->container->get(aRequest::class);
$request->scene('add')->validateResolved();
$account = $this->request->getAttribute("account");
$data = Param::only(['roles' => [], 'username', 'status' => 1, 'dept_id' => 0, 'posts' => [], 'password' => '123456']);
$data = Param::only(['roles' => [], 'username', 'email', 'phone', 'status' => 1, 'dept_id' => 0, 'posts' => [], 'password' => '123456']);
// 判断数据库是否存在相同的用户名
$admin = aModel::getByUsername($data['username'], ['account_id']);
if (!empty($admin)) {
@ -294,7 +295,7 @@ class System extends Base
{
$request = $this->container->get(aRequest::class);
$request->scene('edit')->validateResolved();
$data = Param::only(['roles' => [], 'username', 'status' => 1, 'dept_id' => 0, 'posts' => [], 'password' => '', 'account_id']);
$data = Param::only(['roles' => [], 'username', 'email', 'phone', 'status' => 1, 'dept_id' => 0, 'posts' => [], 'password' => '', 'account_id']);
$res = aModel::edit($data);
return $res ? $this->success("操作成功") : $this->error("操作失败");
}
@ -630,7 +631,7 @@ class System extends Base
$request->scene('edit')->validateResolved();
$data = Param::only(["config_id", "config_name", "config_key", "config_value", "remark"]);
// 删除原来的缓存
$info = scModel::getById($data['config_id'],['config_key']);
$info = scModel::getById($data['config_id'], ['config_key']);
(new ConfigCacheService())->removeItem($info['config_key']);
// 变更数据
$res = scModel::edit($data);
@ -655,7 +656,7 @@ class System extends Base
#[Auth(auth: "dict:list")]
public function dictList()
{
$param = Param::only(["dict_name", "dict_type", "limit"=>10]);
$param = Param::only(["dict_name", "dict_type", "limit" => 10]);
return $this->success("列表接口", dtModel::list($param));
}
@ -706,7 +707,7 @@ class System extends Base
#[Auth(auth: "dict_data:list")]
public function dictDataList()
{
$param = Param::only(["dict_id", "dict_label", "status", "limit"=>10]);
$param = Param::only(["dict_id", "dict_label", "status", "limit" => 10]);
return $this->success("列表接口", ddModel::list($param));
}
@ -714,7 +715,7 @@ class System extends Base
#[Auth(needAuth: false)]
public function dictDataOption()
{
$param = Param::only(["key"=>""]);
$param = Param::only(["key" => ""]);
return $this->success(ddModel::options($param));
}
@ -758,7 +759,7 @@ class System extends Base
#[Auth(auth: "translation:list")]
public function translationList()
{
$param = Param::only(["group", "translation_key", "limit"=>10]);
$param = Param::only(["group", "translation_key", "limit" => 10]);
return $this->success("列表接口", tsModel::list($param));
}
@ -789,4 +790,50 @@ class System extends Base
$ids = $this->request->input("ids");
return $this->toAjax(tsModel::del($ids));
}
#[GetMapping(path: "message/mine")]
#[Auth(needAuth: false)]
public function messageList()
{
$param = Param::only(["limit" => 10, 'type' => 'system']);
$param['account_id'] = $this->accountId();
return $this->success("列表接口", amModel::list($param));
}
#[PostMapping(path: "message/read")]
#[Auth(needAuth: false)]
public function messageRead()
{
$param = Param::only(["ids" => [], 'type' => '']);
$param['account_id'] = $this->accountId();
amModel::read($param);
// 全部已读
return $this->success();
}
#[GetMapping(path: "message/detail")]
#[Auth(needAuth: false)]
public function messageDetail()
{
$param = Param::only(["id"]);
if (!$param['id']) return $this->error();
$param['account_id'] = $this->accountId();
$info = amModel::detail($param);
if (!empty($info)) {
$info = $info->toArray();
// 设为已读
amModel::read(['ids' => [$param['id']], 'type' => $info['type'], 'account_id' => $this->accountId()]);
}
return $this->success("详情", $info);
}
#[DeleteMapping(path: "message/remove")]
#[Auth(needAuth: false)]
public function messageRemove()
{
$param = Param::only(["id"]);
if (!$param['id']) return $this->error();
$res = amModel::where(['mess_id' => $param['id'], 'account_id' => $this->accountId()])->delete();
return $this->toAjax($res);
}
}

View File

@ -5,7 +5,10 @@ namespace App\Controller\Admin;
use App\Annotation\Auth;
use App\Model\GenTable as gtModel;
use App\Request\GenTable as gtRequest;
use App\Model\Message as mModel;
use App\Request\Message as mRequest;
use App\Utils\Param;
use App\Utils\QueueClient;
use Hyperf\DbConnection\Db;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\DeleteMapping;
@ -216,4 +219,54 @@ class Tools extends Base
}
return $this->success("表单信息", $data);
}
#[GetMapping(path: "message/list")]
#[Auth(auth: "message:list")]
public function messageList()
{
$param = Param::only(["title", "limit" => 10]);
return $this->success("列表接口", mModel::list($param));
}
#[PostMapping(path: "message/add")]
#[Auth(auth: "message:add")]
public function messageAdd()
{
$request = $this->container->get(mRequest::class);
$request->scene('add')->validateResolved();
$data = Param::only(["title", "content"]);
$data['create_id'] = $this->accountId();
$data['type'] = 'system';
$res = mModel::add($data);
if (!$res) return $this->error();
QueueClient::push("App\Job\NotifyJob", ['messageId' => $res, 'channels' => ['websocket', 'email']]);
return $this->success();
}
#[PutMapping(path: "message/edit")]
#[Auth(auth: "message:edit")]
public function messageEdit()
{
$request = $this->container->get(mRequest::class);
$request->scene('edit')->validateResolved();
$data = Param::only(["message_id", "title", "content"]);
return $this->toAjax(mModel::edit($data));
}
#[DeleteMapping(path: "message/del")]
#[Auth(auth: "message:del")]
public function messageDel()
{
$ids = $this->request->input("ids");
return $this->toAjax(mModel::del($ids));
}
#[PutMapping(path: "message/recalled")]
#[Auth(auth: "message:recalled")]
public function messageRecalled()
{
$data = Param::only(["id"]);
if (!$data['id']) return $this->error();
return $this->toAjax(mModel::edit(['message_id' => $data['id'], 'recalled_flag' => 1]));
}
}

64
app/Job/NotifyJob.php Normal file
View File

@ -0,0 +1,64 @@
<?php
namespace App\Job;
use App\Utils\QueueClient;
use Hyperf\AsyncQueue\Job;
use App\Model\Message as mModel;
use App\Model\Account as aModel;
use App\Model\AccountMessage as amModel;
use App\Model\MessageChannel as mcModel;
class NotifyJob extends Job
{
// 重试次数
protected int $maxAttempts = 1;
protected int|null $messageId;
protected array|null $userIds;
protected array|null $channels;
public function __construct(array $params)
{
$this->messageId = $params["messageId"] ?? null;
$this->userIds = $params["userIds"] ?? null;
$this->channels = $params["channels"] ?? null;
}
public function handle()
{
// 查询消息信息
$message = mModel::getById($this->messageId);
if (empty($message)) return true;
if (empty($this->userIds) && $message['type'] == "system") {
// 系统消息推送给所有用户
$this->userIds = aModel::pluck("account_id")->toArray();
}
if (empty($this->userIds)) return true;
// 批量插入数据
$mess = [];
foreach ($this->userIds as $id) {
$mess[] = [
'account_id' => $id,
'message_id' => $this->messageId,
'create_time' => date("Y-m-d H:i:s")
];
}
amModel::insert($mess);
// 多渠道推送
if (empty($this->channels)) return true;
foreach ($this->userIds as $id) {
foreach ($this->channels as $channel) {
mcModel::add([
'account_id' => $id,
'message_id' => $this->messageId,
'channel' => $channel
]);
// 队列多渠道推送
QueueClient::push("App\Job\SendChannelJob", ["userId" => $id, "messageId" => $this->messageId, "channel" => $channel]);
}
}
return true;
}
}

View File

@ -0,0 +1,51 @@
<?php
namespace App\Job;
use App\Service\Message\ChannelFactory;
use App\Utils\Log;
use Hyperf\AsyncQueue\Job;
use App\Model\Message as mModel;
use App\Model\Account as aModel;
use App\Model\MessageChannel as mchModel;
use function Hyperf\Support\make;
class SendChannelJob extends Job
{
protected int $maxAttempts = 2;
protected ChannelFactory $factory;
protected int $userId;
protected int $messageId;
protected string $channel;
public function __construct($params)
{
$this->userId = $params['userId'];
$this->messageId = $params['messageId'];
$this->channel = $params['channel'];
}
public function handle()
{
try {
$channel = make(ChannelFactory::class)->get($this->channel);
$account = aModel::find($this->userId);
$message = mModel::find($this->messageId);
$channel->send($account, $message);
mchModel::query()
->where('message_id', $this->messageId)
->where('account_id', $this->userId)
->where('channel', $this->channel)
->update(['status' => 1]);
} catch (\Exception $e) {
Log::record("消息投递失败:" . $e->getMessage(), "SendChannelJob");
mchModel::query()
->where('message_id', $this->messageId)
->where('account_id', $this->userId)
->where('channel', $this->channel)
->update(['status' => 2, 'fail_reason' => $e->getMessage()]);
}
}
}

View File

@ -22,6 +22,8 @@ use Hyperf\DbConnection\Db;
* @property string $bio
* @property string $tags
* @property int $sex
* @property string $email
* @property string $phone
* @property string $birthday
* @property string $deleted_at
* @property string $create_time
@ -60,14 +62,14 @@ class Account extends Model
{
$info = self::with('roles')
->with('posts')
->select(['account_id', 'username', 'nickname', 'avatar', 'bio', 'tags', 'sex', 'birthday', 'create_time', 'dept_id'])
->select(['account_id', 'username', 'nickname', 'avatar', 'bio', 'tags', 'sex', 'birthday', 'create_time', 'dept_id', 'email', 'phone'])
->find($account_id);
if ($info) {
$info = $info->toArray();
// 获取所有上级
$dept = [];
Dept::getTop($info['dept_id'], $dept);
$info['dept'] = array_reverse(array_column($dept,"dept_name"));
$info['dept'] = array_reverse(array_column($dept, "dept_name"));
}
return $info;
}
@ -108,7 +110,7 @@ class Account extends Model
$model = $model->where('dept_id', $where['dept_id']);
}
$paginate = $model->orderByDesc("account_id")
->paginate((int)$where['limit'], ['account_id', 'username', 'avatar', 'create_time', 'dept_id']);
->paginate((int)$where['limit'], ['account_id', 'username', 'avatar', 'create_time', 'dept_id', 'email', 'phone', 'nickname']);
$count = $paginate->total();
$data = $paginate->items();
foreach ($data as &$item) {

View File

@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace App\Model;
/**
* @property int $mess_id
* @property int $account_id
* @property int $message_id
* @property int $read_flag
* @property string $read_time
* @property string $deleted_at
* @property string $create_time
* @property string $update_time
*/
class AccountMessage extends Model
{
/**
* The table associated with the model.
*/
protected ?string $table = 'account_message';
protected string $primaryKey = 'mess_id';
/**
* The attributes that are mass assignable.
*/
protected array $fillable = [];
/**
* The attributes that should be cast to native types.
*/
protected array $casts = ['mess_id' => 'integer', 'account_id' => 'integer', 'message_id' => 'integer', 'read_flag' => 'integer'];
public static function list(array $param)
{
return (new self())->setTable("am")
->from("account_message as am")
->leftJoin("message as m", "m.message_id", "=", "am.message_id")
->where("m.recalled_flag", 0)
->where("m.type", $param['type'])
->where("am.account_id", $param['account_id'])
->whereNull("m.deleted_at")
->orderBy("am.read_flag")
->orderByDesc("am.mess_id")
->select(['am.mess_id', 'am.read_flag', 'am.create_time', 'm.title', 'm.extra'])
->paginate($param['limit']);
}
public static function read(array $param)
{
return (new self())->setTable("am")
->from("account_message as am")
->leftJoin("message as m", "m.message_id", "=", "am.message_id")
->where("m.recalled_flag", 0)
->whereNull("m.deleted_at")
->where("am.account_id", $param['account_id'])
->where("m.type", $param['type'])
->where("am.read_flag", 0)
->when(!empty($param['ids']), function ($query) use ($param) {
$query->whereIn("am.mess_id", $param['ids']);
})
->update([
'read_flag' => 1
]);
}
public static function detail(array $param)
{
return (new self())->setTable("am")
->from("account_message as am")
->leftJoin("message as m", "m.message_id", "=", "am.message_id")
->leftJoin("account as a", "a.account_id", "=", "m.create_id")
->where("m.recalled_flag", 0)
->whereNull("m.deleted_at")
->where("am.account_id", $param['account_id'])
->where("am.mess_id", $param['id'])
->select(['am.mess_id', 'am.create_time', 'm.title', 'm.content', 'm.extra', 'm.type', 'a.nickname'])
->first();
}
}

61
app/Model/Message.php Normal file
View File

@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace App\Model;
/**
* @property int $message_id
* @property string $title
* @property string $content
* @property string $type
* @property string $extra
* @property int $recalled_flag
* @property int $create_id
* @property string $deleted_at
* @property string $create_time
* @property string $update_time
*/
class Message extends Model
{
/**
* The table associated with the model.
*/
protected ?string $table = 'message';
protected string $primaryKey = 'message_id';
/**
* The attributes that are mass assignable.
*/
protected array $fillable = [];
/**
* The attributes that should be cast to native types.
*/
protected array $casts = ['message_id' => 'integer', 'recalled_flag' => 'integer', 'create_id' => 'integer'];
/**
* 仅管理系统消息
* @param array $param
* @return \Hyperf\Contract\LengthAwarePaginatorInterface
*/
public static function list(array $param)
{
$model = self::query()->with(["account" => function ($query) {
$query->select(['account_id', 'username']);
}]);
if (isset($param['title']) && $param['title'] != '') {
$model = $model->where('title', "like", "%{$param['title']}%");
}
return $model->where("type", "system")
->orderByDesc("message_id")
->select(["message_id", "title", "content", "recalled_flag", "create_id", "create_time", "update_time"])
->paginate((int)$param['limit']);
}
public function account()
{
return $this->hasOne(Account::class, 'account_id', 'create_id');
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace App\Model;
/**
* @property int $channel_id
* @property int $account_id
* @property int $message_id
* @property string $channel
* @property int $status
* @property string $fail_reason
* @property string $deleted_at
* @property string $create_time
* @property string $update_time
*/
class MessageChannel extends Model
{
/**
* The table associated with the model.
*/
protected ?string $table = 'message_channel';
protected string $primaryKey = 'channel_id';
/**
* The attributes that are mass assignable.
*/
protected array $fillable = [];
/**
* The attributes that should be cast to native types.
*/
protected array $casts = ['channel_id' => 'integer', 'account_id' => 'integer', 'message_id' => 'integer', 'status' => 'integer'];
}

View File

@ -4,9 +4,6 @@ declare(strict_types=1);
namespace App\Model;
use App\Utils\Ip;
use Swoole\Http\Request;
/**
* @property int $online_id
* @property string $session_id
@ -92,4 +89,12 @@ class Online extends Model
{
return $this->hasOne(Account::class, 'account_id', 'account_id');
}
public static function getFds($accountId): array
{
return self::where("status", 1)
->where("account_id", $accountId)
->pluck("fd")
->toArray();
}
}

50
app/Request/Message.php Normal file
View File

@ -0,0 +1,50 @@
<?php
namespace App\Request;
use Hyperf\Validation\Request\FormRequest;
class Message extends FormRequest
{
protected array $scenes = [
'add' => ["title", "content"],
'edit' => ["message_id", "title", "content"],
];
/**
* Determine if the user is authorized to make this request.
*/
public function authorize(): bool
{
return true;
}
/**
* Get the validation rules that apply to the request.
*/
public function rules(): array
{
return [
'message_id' => 'required',
'title' => 'required',
'content' => 'required',
'type' => 'required',
'extra' => 'required',
'recalled_flag' => 'required',
'create_id' => 'required',
'deleted_at' => 'required',
'create_time' => 'required',
'update_time' => 'required'
];
}
public function messages(): array
{
return [
'message_id.required' => 'ID必传',
'title.required' => '标题必传!',
'content.required' => '内容必传!',
'recalled_flag.required' => '是否撤回必传!'
];
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace App\Service\Message\Channel;
use App\Model\Account;
use App\Model\Message;
use App\Service\Message\Exception\ChannelFailException;
use App\Service\Message\Interface\ChannelInterface;
use Symfony\Component\Mailer\Mailer;
use Symfony\Component\Mailer\Transport;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use function Hyperf\Config\config;
class EmailChannel implements ChannelInterface
{
protected Mailer $mailer;
public function __construct()
{
$config = config('mailer.default');
// 创建传输器
$transport = Transport::fromDsn(sprintf(
'smtp://%s:%s@%s:%d?encryption=%s',
$config['username'],
$config['password'],
$config['host'],
$config['port'],
$config['encryption']
));
$this->mailer = new Mailer($transport);
}
public function send(Account $account, Message $message): bool
{
try {
if (!$account->email) {
throw new ChannelFailException("用户邮箱地址不存在");
}
$email = (new Email())
->from(new Address(config("mailer.default.username"), config("mailer.default.name")))
->to($account->email)
->subject($message->title)
->html($message->content);
$this->mailer->send($email);
return true;
} catch (\Exception $exception) {
throw new ChannelFailException($exception->getMessage());
}
}
public function getName(): string
{
return "email";
}
}

View File

@ -0,0 +1,90 @@
<?php
namespace App\Service\Message\Channel;
use App\Model\Account;
use App\Model\Message;
use App\Model\Online as oModel;
use App\Service\Message\Exception\ChannelFailException;
use App\Service\Message\Interface\ChannelInterface;
use Hyperf\Di\Annotation\Inject;
use Hyperf\WebSocketServer\Sender;
use function Hyperf\Coroutine\go;
class WebsocketChannel implements ChannelInterface
{
#[Inject]
protected Sender $sender;
public function send(Account $account, Message $message): bool
{
try {
$lines = oModel::getFds($account->account_id);
foreach ($lines as $fd) {
$this->sendOk($fd, $message->title, $message->type, $message->extra);
}
return true;
} catch (\Exception $exception) {
throw new ChannelFailException($exception->getMessage());
}
}
public function getName(): string
{
return "websocket";
}
/**
* 推送信息
* Author: cfn <cfn@leapy.cn>
* @param int $fd
* @param string $msg
* @param string $type
* @param string|null $extra
* @return void
*/
public function sendOk(int $fd, string $msg, string $type = "msg", string $extra = null): void
{
$resp = [
'code' => 200,
'msg' => $msg,
'type' => $type,
'extra' => $extra
];
$this->sender->push($fd, json_encode($resp, true));
}
/**
* 推送信息
* Author: cfn <cfn@leapy.cn>
* @param int $fd
* @param string $msg
* @param string $type
* @param string|null $extra
* @return void
*/
public function sendErr(int $fd, string $msg, string $type = "msg", string $extra = null): void
{
$resp = [
'code' => 400,
'msg' => $msg,
'type' => $type,
'extra' => $extra
];
$this->sender->push($fd, json_encode($resp, true));
}
/**
* 关闭连接
* Author: cfn <cfn@leapy.cn>
* @param int $fd
* @return void
*/
public function close(int $fd): void
{
go(function () use ($fd) {
sleep(1);
$this->sender->disconnect($fd);
});
}
}

View File

@ -0,0 +1,50 @@
<?php
namespace App\Service\Message;
use App\Service\Message\Channel\EmailChannel;
use App\Service\Message\Channel\WebsocketChannel;
use App\Service\Message\Exception\ChannelNotFoundException;
use App\Service\Message\Interface\ChannelInterface;
use Hyperf\Di\Container;
class ChannelFactory
{
protected Container $container;
/**
* 渠道映射表(可配置)
*/
protected array $channels = [
'email' => EmailChannel::class,
'websocket' => WebsocketChannel::class,
];
public function __construct(Container $container)
{
$this->container = $container;
}
/**
* 获取渠道实例
*/
public function get(string $name): ChannelInterface
{
if (!isset($this->channels[$name])) {
throw new ChannelNotFoundException("Channel [$name] not found");
}
return $this->container->get($this->channels[$name]);
}
/**
* 获取所有可用渠道
*/
public function all(): array
{
$list = [];
foreach ($this->channels as $class) {
$list[] = $this->container->get($class);
}
return $list;
}
}

View File

@ -0,0 +1,8 @@
<?php
namespace App\Service\Message\Exception;
class ChannelFailException extends \RuntimeException
{
}

View File

@ -0,0 +1,8 @@
<?php
namespace App\Service\Message\Exception;
class ChannelNotFoundException extends \RuntimeException
{
}

View File

@ -0,0 +1,13 @@
<?php
namespace App\Service\Message\Interface;
use App\Model\Account;
use App\Model\Message;
interface ChannelInterface
{
public function send(Account $account, Message $message): bool;
public function getName(): string;
}

View File

@ -0,0 +1,34 @@
<?php
namespace App\Service;
use Hyperf\AsyncQueue\Driver\DriverFactory;
use Hyperf\AsyncQueue\Driver\DriverInterface;
/**
* 消息投递
*/
class QueueService
{
/**
* @var DriverInterface
*/
protected DriverInterface $driver;
public function __construct(DriverFactory $driverFactory)
{
$this->driver = $driverFactory->get('default');
}
/**
* 生产消息.
* @param array $params 数据
* @param int $delay 延时时间 单位秒
* @param string $queue_name
* @return bool
*/
public function push(string $queue_name, array $params, int $delay = 0): bool
{
return $this->driver->push(new $queue_name($params), $delay);
}
}

43
app/Utils/QueueClient.php Normal file
View File

@ -0,0 +1,43 @@
<?php
/**
* Author: cfn <cfn@leapy.cn>
*/
namespace App\Utils;
use App\Service\QueueService;
use Hyperf\Di\Annotation\Inject;
/**
* Author: cfn <cfn@leapy.cn>
*/
class QueueClient
{
#[Inject]
protected QueueService $queueService;
/**
* 静态调用
* Author: cfn <cfn@leapy.cn>
* @param $name
* @param $arguments
* @return void
*/
public static function __callStatic($name, $arguments)
{
(new self())->$name(...$arguments);
}
/**
* 异步队列推送
* Author: cfn <cfn@leapy.cn>
* @param string $queue_name
* @param array $params
* @param int $delay
* @return void
*/
protected function push(string $queue_name, array $params, int $delay = 0): void
{
$this->queueService->push($queue_name, $params, $delay);
}
}

View File

@ -36,6 +36,7 @@
"hyperf/view": "^3.1",
"hyperf/websocket-server": "^3.1",
"phpoffice/phpspreadsheet": "^4.5",
"symfony/mailer": "^7.4",
"twig/twig": "^3.22",
"zoujingli/ip2region": "^3.0"
},

View File

@ -0,0 +1,13 @@
<?php
return [
'default' => [
'transport' => 'smtp',
'host' => 'smtp.ym.163.com', // SMTP 服务器地址
'port' => 465, // SMTP 端口
'encryption' => 'ssl', // 加密方式,支持 ssl 或 tls
'username' => 'mail@leapy.cn', // 邮箱地址
'password' => 'e!@3j9wjri2', // SMTP 授权码
'name' => '里派科技', // 发件人名称
],
];

View File

@ -11,4 +11,5 @@ declare(strict_types=1);
*/
return [
App\Process\CrontabDispatcherProcess::class,
Hyperf\AsyncQueue\Process\ConsumerProcess::class,
];

View File

@ -1,17 +1,17 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
use Hyperf\HttpMessage\Server\Response;
use Hyperf\HttpServer\Router\Router;
Router::addRoute(['GET', 'POST', 'HEAD'], '/', 'App\Controller\IndexController@index');
Router::addRoute(['POST', 'HEAD'], '/', 'App\Controller\IndexController@index');
Router::get('/', function () {
return (new Response())
->withStatus(302)
->withHeader('Location', '/super/');
});
Router::get('/favicon.ico', function () {
return '';

View File

@ -1,5 +1,5 @@
<template>
<el-dialog :title="titleMap[mode]" v-model="visible" :width="500" destroy-on-close @closed="$emit('closed')">
<pi-dialog :title="titleMap[mode]" v-model="visible" :width="500" destroy-on-close @closed="$emit('closed')">
<el-form :model="form" :rules="rules" :disabled="mode==='show'" ref="formRef" label-width="100px">
{% for field in insert_fields %}
{% if field.html_type == 'select' %}
@ -45,7 +45,7 @@
<el-button @click="visible=false" >取 消</el-button>
<el-button v-if="mode!=='show'" type="primary" :loading="isSaveing" @click="submit()">保 存</el-button>
</template>
</el-dialog>
</pi-dialog>
</template>
<script setup>