Compare commits

..
Author SHA1 Message Date
dependabot[bot] 4f9147f448 Bump laravel/framework from 10.48.20 to 10.48.23 in /serve
Bumps [laravel/framework](https://github.com/laravel/framework) from 10.48.20 to 10.48.23.
- [Release notes](https://github.com/laravel/framework/releases)
- [Changelog](https://github.com/laravel/framework/blob/11.x/CHANGELOG.md)
- [Commits](https://github.com/laravel/framework/compare/v10.48.20...v10.48.23)

---
updated-dependencies:
- dependency-name: laravel/framework
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-13 00:00:46 +00:00
atshike 6395633719 Merge pull request #4 from surprise-tech/dev
Dev
2024-11-07 09:56:01 +08:00
finalz c91989e6ed Update README.md 2024-11-05 12:24:23 +08:00
finalz ee12fbcea3 Update README.md 2024-11-05 11:44:26 +08:00
finalz f95ac4a6d8 Update README.md 2024-11-05 11:36:52 +08:00
finalz 0eaf087177 Update README.md 2024-11-04 13:43:26 +08:00
finalz c8437b28af Update README.md 2024-11-04 13:42:23 +08:00
19 changed files with 524 additions and 692 deletions
+24 -2
View File
@@ -6,6 +6,20 @@
> 作为一款私域引流工具,凭借其强大的功能和灵活的应用场景,成为了推广营销领域的热门选择,它支持从抖音直接跳转到个人微信、微信群、小程序以及企业微信客服,有效打通了不同平台之间的壁垒,实现了流量的高效转化和利用,推广营销必备!
![image](https://github.com/user-attachments/assets/76f93840-4453-4aae-ac50-7b01a4010152)
### 系统演示
```
演示地址:https://open.mayilink.cn/
管理员账号:admin
管理员密码:admin123
用户账号:13999999999
用户密码:123456
```
### 目录结构
```
- admin 后台管理
@@ -76,7 +90,15 @@ let baseUrl = "https://xxx.xxxxx.xxx"; // 后台请求域名改为你的域名
## 重要信息
欢迎进群获取最新开发计划或交流技术
如需进群请添加微信号
微信号:tok4mi
添加请备注:交流群
项目合作洽谈,请联系客服微信(使用微信扫码添加好友,请注明来意)。
![](https://huoxing.tos-cn-shanghai.volces.com/2024/09/28/pehhLja89Gb0TIRWDkghVZ2mxwLd7uGiUq3NwK4P.png "微信")
<img src="https://huoxing.tos-cn-shanghai.volces.com/2024/11/05/HFiFy0AaqSLxmlFb0RScBKgLtGVzC9xXb7M9HCJ5.jpg" width="400">
-20
View File
@@ -52,26 +52,6 @@ class SystemInit extends Command
private function config_data(): array
{
return [
[
'slug' => 'web_site_title',
'value' => '蚂蚁快链-智慧引流工具',
'desc' => '网站名称',
],
[
'slug' => 'web_site_logo',
'value' => '/image/toplogo.png',
'desc' => '网站logo浅色',
],
[
'slug' => 'web_site_bottom_logo',
'value' => '/image/toplogo.png',
'desc' => '网站logo深色',
],
[
'slug' => 'web_site_customer_service',
'value' => '/image/web-qr.png',
'desc' => '客服二维码',
],
[
'slug' => 'is_give_vip',
'value' => 1,
-1
View File
@@ -10,7 +10,6 @@ enum LinkType: int
case CLI_QR = 3;
case WORK_WECHAT = 4;
case LANDING_MINI = 5;
case QR_QQ = 11; // 腾讯优码
// 获取所有的类型
public static function getAllType(): array
+1
View File
@@ -19,6 +19,7 @@ class BaseConfig implements SimpleForm
'recommend_commission_2' => 'nullable|integer',
'member_pay_commission_1' => 'nullable|integer', // 一级邀请人消费提成 1%
'member_pay_commission_2' => 'nullable|integer', // 二级邀请人消费提成 1%
'send_code_mode' => 'required|integer|in:1,2', // 1短信2邮箱
]);
}
-75
View File
@@ -1,75 +0,0 @@
<?php
namespace App\Forms;
use App\Services\SystemConfig;
use Illuminate\Http\Request;
use Ugly\Base\Contracts\SimpleForm;
class WebSite implements SimpleForm
{
public function policy(Request $request): array
{
return $request->validate([
'web_site_customer_service' => 'nullable',
'web_site_title' => 'nullable',
'web_site_logo' => 'nullable',
'web_site_bottom_logo' => 'nullable',
'verify_code_is_open' => 'required|boolean',
'send_code_mode' => 'nullable|integer|in:1,2', // 1短信2邮箱
'ali_sms_key' => 'nullable',
'ali_sms_secret' => 'nullable',
'ali_sms_sign_name' => 'nullable',
'mail_from_name' => 'nullable',
'mail_host' => 'nullable',
'mail_port' => 'nullable',
'mail_from_address' => 'nullable',
'mail_username' => 'nullable',
'mail_password' => 'nullable',
'wechat_pay_app_id' => 'nullable',
'wechat_pay_mch_id' => 'nullable',
'wechat_pay_secret_key' => 'nullable',
'wechat_pay_private_cert' => 'nullable',
'wechat_pay_certificate' => 'nullable',
]);
}
// 保存
public function handle(array $input): void
{
SystemConfig::set($input);
}
public function default(): array
{
return [
'web_site_customer_service' => SystemConfig::get('web_site_customer_service'),
'web_site_title' => SystemConfig::get('web_site_title'),
'web_site_logo' => SystemConfig::get('web_site_logo'),
'web_site_bottom_logo' => SystemConfig::get('web_site_bottom_logo'),
'verify_code_is_open' => SystemConfig::get('verify_code_is_open'), // 开启
'send_code_mode' => SystemConfig::get('send_code_mode'), //
'ali_sms_key' => SystemConfig::get('ali_sms_key'),
'ali_sms_secret' => SystemConfig::get('ali_sms_secret'),
'ali_sms_sign_name' => SystemConfig::get('ali_sms_sign_name'),
'mail_from_name' => SystemConfig::get('mail_from_name'),
'mail_host' => SystemConfig::get('mail_host'),
'mail_port' => SystemConfig::get('mail_port'),
'mail_from_address' => SystemConfig::get('mail_from_address'),
'mail_username' => SystemConfig::get('mail_username'),
'mail_password' => SystemConfig::get('mail_password'),
'wechat_pay_app_id' => SystemConfig::get('wechat_pay_app_id'),
'wechat_pay_mch_id' => SystemConfig::get('wechat_pay_mch_id'),
'wechat_pay_secret_key' => SystemConfig::get('wechat_pay_secret_key'),
'wechat_pay_private_cert' => SystemConfig::get('wechat_pay_secret_key'), // 私钥证书
'wechat_pay_certificate' => SystemConfig::get('wechat_pay_certificate'), // 公钥证书
];
}
}
@@ -3,13 +3,11 @@
namespace App\Http\Controllers\Api;
use App\Forms\BaseConfig;
use App\Forms\WebSite;
use Ugly\Base\Http\Controllers\SimpleFormController;
class ConfigController extends SimpleFormController
{
protected array $form = [
'base' => BaseConfig::class,
'web_site' => WebSite::class,
];
}
@@ -114,22 +114,19 @@ class IndexController extends Controller
$configs = [
'code_mode' => SystemConfig::get('send_code_mode'),
'package' => VipPackage::query()->orderBy('level')->get(['id', 'name', 'price', 'config']),
'web_site_customer_service' => SystemConfig::get('web_site_customer_service'),
'web_site_title' => SystemConfig::get('web_site_title'),
'web_site_logo' => SystemConfig::get('web_site_logo'),
'web_site_bottom_logo' => SystemConfig::get('web_site_bottom_logo'),
'asset_url' => Storage::url(''), // 图片路径
];
$user = auth('api')->user();
if ($user) {
// 图片路径
$configs['asset_url'] = Storage::url('');
// 安全域名
// $configs['domains'] = Domain::query()->where('enable', true)->get(['id', 'title']);
// 小程序 (区分是否有权限使用平台小程序池)
$configs['mini_programs'] = MiniProgram::query()
->where(
fn ($query) => $query->where('user_id', $user->id)
->when($user->getPackageConfig('pre_min'), fn ($query) => $query->orWhere('is_pre_min', true))
fn($query) => $query->where('user_id', $user->id)
->when($user->getPackageConfig('pre_min'), fn($query) => $query->orWhere('is_pre_min', true))
)
->get(['id', 'name']);
}
@@ -1,319 +0,0 @@
<?php
namespace App\Http\Controllers\Api;
use App\Enums\LinkType;
use App\Enums\SwitchType;
use App\Enums\UserType;
use App\Enums\UVLimitType;
use App\Http\Controllers\Controller;
use App\Models\Link;
use App\Models\LinkVisitLog;
use App\Models\MiniProgram;
use App\Models\User;
use App\Models\VipPackage;
use EasyWeChat\MiniApp\Application as WechatApp;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Psr16Cache;
use Ugly\Base\Traits\ApiResource;
class JumpController extends Controller
{
use ApiResource;
// 获取链接跳转目标
public function target(Request $request, $code): JsonResponse
{
$link = Link::query()->where('code', $code)->first();
if (empty($link)) {
return $this->failed('此链接已被删除!');
}
if ($link->expired_at < now()) {
return $this->failed('链接已过期!');
}
$user = User::query()->findOrFail($link->user_id);
if (empty($user->status)) {
return $this->failed('账号被禁用!');
}
$isAdmin = $user->type === UserType::Admin;
if (! $isAdmin && ! $user->vip_id) {
return $this->failed('会员已到期,禁止访问!');
}
$device_uid = $request->input('device_uid') ?: Str::uuid();
$cache = data_get(LinkVisitLog::query()
->where('link_id', $link->id)
->where('device_uid', $device_uid)
->orderByDesc('id')
->first(), 'cache', []);
if (empty($cache)) {
if (! $isAdmin) {
// 会员UV限制
$totalUV = LinkVisitLog::query()
->where('link_id', $link->id)
->groupBy('device_uid')
->whereBetween('created_at', [$user->start_at, $user->end_at])
->count();
$limit = (int) data_get(VipPackage::query()->find($user->vip_id), 'config.uv_limit');
if ($limit > 0 && $totalUV >= $limit) {
return $this->failed('当前访问已达上限!');
}
}
$cache = [
'title' => $link->title,
'description' => $link->description,
'icon' => Storage::url($link->icon),
];
if (
$link->type === LinkType::MINI_PROGRAM ||
$link->type === LinkType::LANDING_MINI
) {
// 跳转到小程序 参数
$mp = MiniProgram::query()->findOrFail(data_get($link, 'config.min_id'));
if (empty($mp) || ! $mp->is_enable) {
return $this->failed('当前小程序不能使用');
}
if ($link->type === LinkType::LANDING_MINI) {
$qr = $this->getWechatNextQr($link);
if (empty($qr)) {
return $this->failed('当前小程序已无可用二维码!');
}
}
$cache['params'] = [
'appid' => $mp->app_id,
'secret' => $mp->secret,
'qr' => $qr ?? null,
'path' => data_get($link, 'config.url') ?: $mp->url,
];
} elseif ($link->type === LinkType::KING_DOC) {
$cache['params']['sid'] = str_replace('https://kdocs.cn/l/', '', data_get($link, 'config.url'));
} elseif ($link->type === LinkType::CLI_QR) {
/**
* 1、电脑端访问草料二维码官网:https://cli.im/img
* 2、上传微信二维码、公众号二维码、企业微信二维码、视频号二维码等等,然后点生成活码
* 3、后台创建草料
*/
$configUrl = str_replace('https://qr61.cn/', '', data_get($link, 'config.url'));
[$userID, $cliID] = explode('/', $configUrl);
$cache['params'] = [
'userID' => $userID,
'cliID' => $cliID,
];
} elseif ($link->type === LinkType::WORK_WECHAT) {
$cache['params'] = [
'url' => data_get($link, 'config.url'),
];
} elseif ($link->type === LinkType::QR_QQ) {
$cache['params'] = [
'url' => data_get($link, 'config.url'),
];
} else {
return $this->failed('暂不支持此链接跳转!');
}
} else {
unset($cache['target']);
}
// 生成链接
if ($link->type === LinkType::WORK_WECHAT) {
$cache['target'] = data_get($cache, 'params.url');
} elseif ($link->type === LinkType::CLI_QR) {
$userID = data_get($cache, 'params.userID');
$cliID = data_get($cache, 'params.cliID');
$getTicketUrl = file_get_contents('https://nc.cli.im/api/weixin/getWxUrlScheme/?query=q=qr61.cn/'.$userID.'/'.$cliID.'&path=pages/code/code&appid=wx5db79bd23a923e8e&org_coding='.$userID);
$fetchUrlData = file_get_contents(data_get(json_decode($getTicketUrl, true), 'data.wx_url_scheme.fetchUrl'));
$arr = json_decode($fetchUrlData, true);
$cache['target'] = data_get($arr, 'data.urlScheme');
} elseif ($link->type === LinkType::QR_QQ) {
$configUrl = data_get($cache, 'params.url');
$getContent = file_get_contents($configUrl);
$pattern = '/weixin:\/\/dl\/business\/\?t=[^\\\']+/';
preg_match($pattern, $getContent, $matches);
$cache['target'] = $matches[0];
} elseif ($link->type === LinkType::KING_DOC) {
$sidUrl = data_get($cache, 'params.sid');
preg_match('/https:\/\/kdocs\.cn\/l\/([a-zA-Z0-9]+)/', $sidUrl, $matches);
$url_link = Http::withUserAgent('Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36')
->get('https://account.kdocs.cn/api/v3/miniprogram/urllink', [
'appid' => 'wx5b97b0686831c076',
'path' => 'pages/navigate/navigate',
'query' => http_build_query([
'url' => 'pages/preview/preview?from=wxminiprogram&fid=256465035925&sid='.$matches[1].'&fname='.urlencode('扫码加微信.docx'),
'scene' => '102',
'jump_from' => 'wechatlogin_guide_passive',
'comp' => 'docx',
'dw' => '1',
]),
'env_version' => 'release',
'is_expire' => 'true',
'expire_time' => time() + 7200,
])->json('url_link');
$jinShanResponse = Http::get($url_link)->throw();
preg_match("/url_scheme:\s*'([^']+)'/", $jinShanResponse, $matches);
$cache['target'] = $matches[1];
} else {
// 小程序
$miniApp = new WechatApp([
'app_id' => data_get($cache, 'params.appid'),
'secret' => data_get($cache, 'params.secret'),
]);
try {
$res = $miniApp->getClient()->postJson('wxa/generatescheme', [
'jump_wxa' => [
'path' => data_get($cache, 'params.path'),
'query' => 'code='.data_get($link, 'code').'&device_uid='.$device_uid,
],
])
->toArray();
if (isset($res['errcode']) && $res['errcode'] === 40001) {
$cache = new Psr16Cache(new FilesystemAdapter('easywechat', 1500));
$cache->clear();
}
} catch (\Exception $e) {
$res = [
'errcode' => 1,
'errmsg' => '小程序配置错误',
];
}
if (! empty($res['errcode'])) {
return $this->failed($res['errmsg']);
}
$cache['target'] = data_get($res, 'openlink');
}
if (isset($cache['target']) && $cache['target']) {
LinkVisitLog::query()->create([
'link_id' => $link->id,
'user_id' => $link->user_id,
'ip' => $request->getClientIp(),
'device_uid' => $device_uid,
'cache' => $cache,
]);
unset($cache['params']);
return $this->success($cache);
} else {
return $this->failed('访问错误!');
}
}
// 获取需要展示的二维码
public function getShowQr($code): JsonResponse
{
$link = Link::query()->where('code', $code)->first();
if (empty($link) || ! $link->status) {
return $this->success([
'id' => '',
'avatar' => '',
'title' => '数据不存在~',
'sub_title' => '',
'qr' => '',
]);
}
$config = data_get($link, 'config.wx');
$device_uid = request()->input('device_uid') ?: Str::uuid();
$cache_qr = data_get(LinkVisitLog::query()
->where('link_id', $link->id)
->where('device_uid', $device_uid)
->orderByDesc('id')
->first(), 'cache.params.qr', []);
if (empty($cache_qr)) {
return $this->failed('参数错误!');
}
return $this->success([
'id' => $link->id,
'avatar' => Storage::url(data_get($config, 'avatar')),
'title' => data_get($config, 'title'),
'sub_title' => data_get($config, 'sub_title'),
'qr' => Storage::url(data_get($cache_qr, 'path')),
]);
}
// 获取下一次访问时展示的二维码
private function getWechatNextQr($link)
{
$qrCodes = data_get($link, 'config.wx.qr', []);
// 对链接中的二维码们按照 sort 从小到大排序
usort($qrCodes, function ($a, $b) {
return $a['sort'] <=> $b['sort'];
});
$UVLimitType = (int) data_get($link, 'config.wx.uv_limit_type');
$keyPrefix = "link-wx-type{$UVLimitType}-{$link->id}";
$singleUVViews = [];
if ($UVLimitType === UVLimitType::ACCUMULATE->value) {
$key = "{$keyPrefix}-accumulate";
$singleUVViews = Redis::hgetall($key);
} elseif ($UVLimitType === UVLimitType::DAILY->value) {
$ymdDate = date('Ymd');
$key = "{$keyPrefix}-daily-{$ymdDate}";
$singleUVViews = Redis::hgetall($key);
}
// 排除掉已过期的二维码和超出访问上限的二维码
$filteredQrCodes = array_filter($qrCodes, function ($qrCode) use ($singleUVViews) {
$expiredAt = ! empty($expiredAt) ? Carbon::parse($qrCode['expired_at']) : now()->addHour();
$sort = $qrCode['sort'];
$visitUV = $singleUVViews[$sort] ?? 0;
$uvLimitNum = $qrCode['uv_limit_num'] ?? 99999999;
return $expiredAt->greaterThan(now()) && (is_null($uvLimitNum) || $visitUV < $uvLimitNum);
});
if (empty($filteredQrCodes)) {
return [];
}
$filteredQrCodes = array_values($filteredQrCodes);
// 切换方式.
$nextIndex = 0; // 默认返回第一个二维码
$switch_type = data_get($link, 'config.wx.switch_type');
if ($switch_type === SwitchType::SEQUENCE->value) {
// 顺序切换
$lockKey = "link-sequence-{$link->id}";
$indexKey = "link-sequence-index-{$link->id}";
$lock = Cache::lock($lockKey, 1);
if ($lock->get()) {
try {
$currentIndex = Cache::get($indexKey, -1);
$nextIndex = ($currentIndex + 1) % count($filteredQrCodes);
Cache::put($indexKey, $nextIndex);
} finally {
$lock->release();
}
} else {
Log::warning('获取锁失败', ['key' => $lockKey]);
}
} elseif ($switch_type === SwitchType::RANDOM->value) {
// 随机切换
$nextIndex = array_rand($filteredQrCodes);
}
$selectedQrCode = $filteredQrCodes[$nextIndex];
// 更新 Redis 中的访问计数
if ($UVLimitType === UVLimitType::ACCUMULATE->value) {
$key = "{$keyPrefix}-accumulate";
Redis::hincrby($key, $selectedQrCode['sort'], 1);
} elseif ($UVLimitType === UVLimitType::DAILY->value) {
$ymdDate = date('Ymd');
$key = "{$keyPrefix}-daily-{$ymdDate}";
Redis::hincrby($key, $selectedQrCode['sort'], 1);
}
return $selectedQrCode;
}
}
@@ -8,11 +8,25 @@ use App\Enums\UserType;
use App\Enums\UVLimitType;
use App\Models\Domain;
use App\Models\Link;
use App\Models\LinkVisitLog;
use App\Models\MiniProgram;
use App\Models\User;
use App\Models\VipPackage;
use EasyWeChat\MiniApp\Application as WechatApp;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Enum;
use Symfony\Component\Cache\Adapter\FilesystemAdapter;
use Symfony\Component\Cache\Psr16Cache;
use Ugly\Base\Http\Controllers\FormController;
use Ugly\Base\Services\FormService;
@@ -158,10 +172,6 @@ class LinkController extends FormController
$res['config.url'] = 'required|url|starts_with:https://qr61.cn/';
}
if ($iptType === LinkType::QR_QQ->value) {
$res['config.url'] = 'required|url|starts_with:https://ym.link/';
}
return $is_wx ? array_merge($res, [
'config.wx' => [
'required_if:type,'.LinkType::LANDING_MINI->value,
@@ -182,6 +192,283 @@ class LinkController extends FormController
]) : $res;
}
// 获取链接跳转目标
public function target(Request $request, $code): JsonResponse
{
$link = Link::query()->where('code', $code)->first();
if (empty($link)) {
return $this->failed('此链接已被删除!');
}
if ($link->expired_at < now()) {
return $this->failed('链接已过期!');
}
$user = User::query()->findOrFail($link->user_id);
if (empty($user->status)) {
return $this->failed('账号被禁用!');
}
$isAdmin = $user->type === UserType::Admin;
if (! $isAdmin && ! $user->vip_id) {
return $this->failed('会员已到期,禁止访问!');
}
$device_uid = $request->input('device_uid') ?: Str::uuid();
$cache = data_get(LinkVisitLog::query()
->where('link_id', $link->id)
->where('device_uid', $device_uid)
->orderByDesc('id')
->first(), 'cache', []);
if (empty($cache)) {
if (! $isAdmin) {
// 会员UV限制
$totalUV = LinkVisitLog::query()
->where('link_id', $link->id)
->groupBy('device_uid')
->whereBetween('created_at', [$user->start_at, $user->end_at])
->count();
$limit = (int) data_get(VipPackage::query()->find($user->vip_id), 'config.uv_limit');
if ($limit > 0 && $totalUV >= $limit) {
return $this->failed('当前访问已达上限!');
}
}
$cache = [
'title' => $link->title,
'description' => $link->description,
'icon' => Storage::url($link->icon),
];
if (
$link->type === LinkType::MINI_PROGRAM ||
$link->type === LinkType::LANDING_MINI
) {
// 跳转到小程序 参数
$mp = MiniProgram::query()->findOrFail(data_get($link, 'config.min_id'));
if (empty($mp) || ! $mp->is_enable) {
return $this->failed('当前小程序不能使用');
}
if ($link->type === LinkType::LANDING_MINI) {
$qr = $this->getWechatNextQr($link);
if (empty($qr)) {
return $this->failed('当前小程序已无可用二维码!');
}
}
$cache['params'] = [
'appid' => $mp->app_id,
'secret' => $mp->secret,
'qr' => $qr ?? null,
'path' => data_get($link, 'config.url') ?: $mp->url,
];
} elseif ($link->type === LinkType::KING_DOC) {
$cache['params']['sid'] = str_replace('https://kdocs.cn/l/', '', data_get($link, 'config.url'));
} elseif ($link->type === LinkType::CLI_QR) {
/**
* 1、电脑端访问草料二维码官网:https://cli.im/img
* 2、上传微信二维码、公众号二维码、企业微信二维码、视频号二维码等等,然后点生成活码
* 3、后台创建草料
*/
$configUrl = str_replace('https://qr61.cn/', '', data_get($link, 'config.url'));
[$userID, $cliID] = explode('/', $configUrl);
$cache['params'] = [
'userID' => $userID,
'cliID' => $cliID,
];
} elseif ($link->type === LinkType::WORK_WECHAT) {
$cache['params'] = [
'url' => data_get($link, 'config.url'),
];
} else {
return $this->failed('暂不支持此链接跳转!');
}
} else {
unset($cache['target']);
}
// 生成链接
if ($link->type === LinkType::WORK_WECHAT) {
$cache['target'] = data_get($cache, 'params.url');
} elseif ($link->type === LinkType::CLI_QR) {
$userID = data_get($cache, 'params.userID');
$cliID = data_get($cache, 'params.cliID');
$getTicketUrl = file_get_contents('https://nc.cli.im/api/weixin/getWxUrlScheme/?query=q=qr61.cn/'.$userID.'/'.$cliID.'&path=pages/code/code&appid=wx5db79bd23a923e8e&org_coding='.$userID);
$fetchUrlData = file_get_contents(data_get(json_decode($getTicketUrl, true), 'data.wx_url_scheme.fetchUrl'));
$arr = json_decode($fetchUrlData, true);
$cache['target'] = data_get($arr, 'data.urlScheme');
} elseif ($link->type === LinkType::KING_DOC) {
$sidUrl = data_get($cache, 'params.sid');
preg_match('/https:\/\/kdocs\.cn\/l\/([a-zA-Z0-9]+)/', $sidUrl, $matches);
$url_link = Http::withUserAgent('Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36')
->get('https://account.kdocs.cn/api/v3/miniprogram/urllink', [
'appid' => 'wx5b97b0686831c076',
'path' => 'pages/navigate/navigate',
'query' => http_build_query([
'url' => 'pages/preview/preview?from=wxminiprogram&fid=256465035925&sid='.$matches[1].'&fname='.urlencode('扫码加微信.docx'),
'scene' => '102',
'jump_from' => 'wechatlogin_guide_passive',
'comp' => 'docx',
'dw' => '1',
]),
'env_version' => 'release',
'is_expire' => 'true',
'expire_time' => time() + 7200,
])->json('url_link');
$jinShanResponse = Http::get($url_link)->throw();
preg_match("/url_scheme:\s*'([^']+)'/", $jinShanResponse, $matches);
$cache['target'] = $matches[1];
} else {
// 小程序
$miniApp = new WechatApp([
'app_id' => data_get($cache, 'params.appid'),
'secret' => data_get($cache, 'params.secret'),
]);
try {
$res = $miniApp->getClient()->postJson('wxa/generatescheme', [
'jump_wxa' => [
'path' => data_get($cache, 'params.path'),
'query' => 'code='.data_get($link, 'code').'&device_uid='.$device_uid,
],
])->toArray();
if (isset($res['errcode']) && $res['errcode'] === 40001) {
$cache = new Psr16Cache(new FilesystemAdapter('easywechat', 1500));
$cache->clear();
}
} catch (\Exception $e) {
$res = [
'errcode' => 1,
'errmsg' => '小程序配置错误',
];
}
if (! empty($res['errcode'])) {
return $this->failed($res['errmsg']);
}
$cache['target'] = data_get($res, 'openlink');
}
if (isset($cache['target']) && $cache['target']) {
LinkVisitLog::query()->create([
'link_id' => $link->id,
'user_id' => $link->user_id,
'ip' => $request->getClientIp(),
'device_uid' => $device_uid,
'cache' => $cache,
]);
unset($cache['params']);
return $this->success($cache);
} else {
return $this->failed('访问错误!');
}
}
// 获取需要展示的二维码
public function getShowQr($code): JsonResponse
{
$link = Link::query()->where('code', $code)->first();
if (empty($link) || ! $link->status) {
return $this->success([
'id' => '',
'avatar' => '',
'title' => '数据不存在~',
'sub_title' => '',
'qr' => '',
]);
}
$config = data_get($link, 'config.wx');
$device_uid = request()->input('device_uid') ?: Str::uuid();
$cache_qr = data_get(LinkVisitLog::query()
->where('link_id', $link->id)
->where('device_uid', $device_uid)
->orderByDesc('id')
->first(), 'cache.params.qr', []);
if (empty($cache_qr)) {
return $this->failed('参数错误!');
}
return $this->success([
'id' => $link->id,
'avatar' => Storage::url(data_get($config, 'avatar')),
'title' => data_get($config, 'title'),
'sub_title' => data_get($config, 'sub_title'),
'qr' => Storage::url(data_get($cache_qr, 'path')),
]);
}
// 获取下一次访问时展示的二维码
private function getWechatNextQr($link)
{
$qrCodes = data_get($link, 'config.wx.qr', []);
// 对链接中的二维码们按照 sort 从小到大排序
usort($qrCodes, function ($a, $b) {
return $a['sort'] <=> $b['sort'];
});
$UVLimitType = (int) data_get($link, 'config.wx.uv_limit_type');
$keyPrefix = "link-wx-type{$UVLimitType}-{$link->id}";
$singleUVViews = [];
if ($UVLimitType === UVLimitType::ACCUMULATE->value) {
$key = "{$keyPrefix}-accumulate";
$singleUVViews = Redis::hgetall($key);
} elseif ($UVLimitType === UVLimitType::DAILY->value) {
$ymdDate = date('Ymd');
$key = "{$keyPrefix}-daily-{$ymdDate}";
$singleUVViews = Redis::hgetall($key);
}
// 排除掉已过期的二维码和超出访问上限的二维码
$filteredQrCodes = array_filter($qrCodes, function ($qrCode) use ($singleUVViews) {
$expiredAt = ! empty($expiredAt) ? Carbon::parse($qrCode['expired_at']) : now()->addHour();
$sort = $qrCode['sort'];
$visitUV = $singleUVViews[$sort] ?? 0;
$uvLimitNum = $qrCode['uv_limit_num'] ?? 99999999;
return $expiredAt->greaterThan(now()) && (is_null($uvLimitNum) || $visitUV < $uvLimitNum);
});
if (empty($filteredQrCodes)) {
return [];
}
$filteredQrCodes = array_values($filteredQrCodes);
// 切换方式.
$nextIndex = 0; // 默认返回第一个二维码
$switch_type = data_get($link, 'config.wx.switch_type');
if ($switch_type === SwitchType::SEQUENCE->value) {
// 顺序切换
$lockKey = "link-sequence-{$link->id}";
$indexKey = "link-sequence-index-{$link->id}";
$lock = Cache::lock($lockKey, 1);
if ($lock->get()) {
try {
$currentIndex = Cache::get($indexKey, -1);
$nextIndex = ($currentIndex + 1) % count($filteredQrCodes);
Cache::put($indexKey, $nextIndex);
} finally {
$lock->release();
}
} else {
Log::warning('获取锁失败', ['key' => $lockKey]);
}
} elseif ($switch_type === SwitchType::RANDOM->value) {
// 随机切换
$nextIndex = array_rand($filteredQrCodes);
}
$selectedQrCode = $filteredQrCodes[$nextIndex];
// 更新 Redis 中的访问计数
if ($UVLimitType === UVLimitType::ACCUMULATE->value) {
$key = "{$keyPrefix}-accumulate";
Redis::hincrby($key, $selectedQrCode['sort'], 1);
} elseif ($UVLimitType === UVLimitType::DAILY->value) {
$ymdDate = date('Ymd');
$key = "{$keyPrefix}-daily-{$ymdDate}";
Redis::hincrby($key, $selectedQrCode['sort'], 1);
}
return $selectedQrCode;
}
// 获取下拉数据源
public function link_list(): JsonResponse
{
+6 -18
View File
@@ -23,29 +23,17 @@ class LoginRequest extends FormRequest
*/
public function rules(): array
{
$rules = [
$code_mode = SystemConfig::get('send_code_mode');
$rule = $code_mode == CodeMode::Email->value ? 'email' : 'regex:/^1[3-9]\d{9}$/';
return [
'username' => [
'required',
'exists:users,username',
'exclude_if:username,admin',
$rule,
],
'password' => 'required|min:6',
];
if (request('username') === 'admin') {
return $rules;
}
$is_open = SystemConfig::get('verify_code_is_open');
if ($is_open) {
$code_mode = SystemConfig::get('send_code_mode');
$rule = $code_mode == CodeMode::Email->value ? 'email' : 'regex:/^1[3-9]\d{9}$/';
$rules['username'] = [
'required',
'exists:users,username',
$rule,
];
}
return $rules;
}
public function messages(): array
+14 -31
View File
@@ -24,50 +24,33 @@ class RegisterRequest extends FormRequest
*/
public function rules(): array
{
$is_open = SystemConfig::get('verify_code_is_open');
if ($is_open) {
$code_mode = SystemConfig::get('send_code_mode');
$rule = ($code_mode == CodeMode::Email->value) ? 'email' : 'regex:/^1[3-9]\d{9}$/';
return [
'username' => [
'required',
$rule,
'unique:users,username',
],
'password' => 'required|min:6|confirmed',
'captcha' => ['required', function (string $attribute, mixed $value, \Closure $fail) {
$test_code = config('services.ali_sms.test_code');
if (empty($test_code) || $value != $test_code) {
$tel = $this->input('username');
$captcha = Cache::get('sms_captcha_'.$tel);
if ((int) $captcha !== (int) $value) {
$fail('验证码错误!');
}
}
}],
'referral_code' => '', // 推荐码
];
}
$code_mode = SystemConfig::get('send_code_mode');
$rule = $code_mode == CodeMode::Email->value ? 'email' : 'regex:/^1[3-9]\d{9}$/';
return [
'username' => [
'required',
$rule,
'unique:users,username',
],
'password' => 'required|min:6|confirmed',
'captcha' => ['required', function (string $attribute, mixed $value, \Closure $fail) {
$test_code = config('services.ali_sms.test_code');
if (empty($test_code) || $value != $test_code) {
$tel = $this->input('username');
$captcha = Cache::get('sms_captcha_'.$tel);
if ((int) $captcha !== (int) $value) {
$fail('验证码错误!');
}
}
}],
'referral_code' => '', // 推荐码
];
}
public function messages(): array
{
$code_mode = SystemConfig::get('send_code_mode');
$is_open = SystemConfig::get('verify_code_is_open');
$txt = '用户名';
if (! empty($is_open)) {
$txt = ($code_mode === CodeMode::Email->value) ? '邮箱' : '手机号';
}
$txt = CodeMode::Email->value ? '邮箱' : '手机号';
return [
'username.required' => "请输入{$txt}!",
-9
View File
@@ -4,13 +4,11 @@ namespace App\Jobs;
use App\Jobs\Middleware\RateLimited;
use App\Mail\SendEmail;
use App\Services\SystemConfig;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Mail;
use Throwable;
@@ -33,13 +31,6 @@ class SendEmailJobs implements ShouldQueue
$this->to = $to;
$this->code = $code;
$this->title = $title ?? '邮箱验证码';
Config::set('mail.mailers.smtp.host', SystemConfig::get('mail_host'));
Config::set('mail.mailers.smtp.port', SystemConfig::get('mail_port'));
Config::set('mail.mailers.smtp.username', SystemConfig::get('mail_username'));
Config::set('mail.mailers.smtp.password', SystemConfig::get('mail_password'));
Config::set('mail.from.address', SystemConfig::get('mail_from_address'));
Config::set('mail.from.name', SystemConfig::get('mail_from_name'));
}
public function middleware()
+1 -16
View File
@@ -2,7 +2,6 @@
namespace App\PayChannels;
use App\Services\SystemConfig;
use EasyWeChat\Pay\Application;
use Illuminate\Support\Carbon;
use Symfony\Component\HttpFoundation\Response;
@@ -18,21 +17,7 @@ class WeChatPayNative
public function __construct()
{
$config = [
'appid' => SystemConfig::get('wechat_pay_app_id'),
'mch_id' => SystemConfig::get('wechat_pay_mch_id'),
'secret_key' => SystemConfig::get('wechat_pay_secret_key'),
// 商户证书
'private_key' => SystemConfig::get('wechat_pay_secret_key'),
'certificate' => SystemConfig::get('wechat_pay_certificate'),
/*'platform_certs' => [
storage_path('/certs/wechatpay.pem'),
],*/
'http' => [
'throw' => false,
],
];
$this->payApp = new Application($config);
$this->payApp = new Application(config('services.wechat_pay'));
}
// 支付
+1 -7
View File
@@ -17,13 +17,7 @@ class AliDySms
public function __construct()
{
$config = [
'key' => SystemConfig::get('ali_sms_key'),
'secret' => SystemConfig::get('ali_sms_secret'),
'sign_name' => SystemConfig::get('ali_sms_sign_name'),
'test_code' => env('ALI_SMS_TEST_CODE'),
];
$this->config = $config;
$this->config = config('services.ali_sms');
}
/**
+173 -168
View File
@@ -380,16 +380,16 @@
},
{
"name": "dragonmantank/cron-expression",
"version": "v3.3.3",
"version": "v3.4.0",
"source": {
"type": "git",
"url": "https://github.com/dragonmantank/cron-expression.git",
"reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a"
"reference": "8c784d071debd117328803d86b2097615b457500"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/adfb1f505deb6384dc8b39804c5065dd3c8c8c0a",
"reference": "adfb1f505deb6384dc8b39804c5065dd3c8c8c0a",
"url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/8c784d071debd117328803d86b2097615b457500",
"reference": "8c784d071debd117328803d86b2097615b457500",
"shasum": ""
},
"require": {
@@ -402,10 +402,14 @@
"require-dev": {
"phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-webmozart-assert": "^1.0",
"phpunit/phpunit": "^7.0|^8.0|^9.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.x-dev"
}
},
"autoload": {
"psr-4": {
"Cron\\": "src/Cron/"
@@ -429,7 +433,7 @@
],
"support": {
"issues": "https://github.com/dragonmantank/cron-expression/issues",
"source": "https://github.com/dragonmantank/cron-expression/tree/v3.3.3"
"source": "https://github.com/dragonmantank/cron-expression/tree/v3.4.0"
},
"funding": [
{
@@ -437,7 +441,7 @@
"type": "github"
}
],
"time": "2023-08-10T19:36:49+00:00"
"time": "2024-10-09T13:47:03+00:00"
},
{
"name": "egulias/email-validator",
@@ -1192,16 +1196,16 @@
},
{
"name": "laravel/framework",
"version": "v10.48.20",
"version": "v10.48.23",
"source": {
"type": "git",
"url": "https://github.com/laravel/framework.git",
"reference": "be2be342d4c74db6a8d2bd18469cd6d488ab9c98"
"reference": "625269ca4881d2b50eded2045cb930960a181d98"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/framework/zipball/be2be342d4c74db6a8d2bd18469cd6d488ab9c98",
"reference": "be2be342d4c74db6a8d2bd18469cd6d488ab9c98",
"url": "https://api.github.com/repos/laravel/framework/zipball/625269ca4881d2b50eded2045cb930960a181d98",
"reference": "625269ca4881d2b50eded2045cb930960a181d98",
"shasum": ""
},
"require": {
@@ -1395,7 +1399,7 @@
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"time": "2024-08-09T07:55:45+00:00"
"time": "2024-11-12T15:39:10+00:00"
},
{
"name": "laravel/prompts",
@@ -1523,16 +1527,16 @@
},
{
"name": "laravel/serializable-closure",
"version": "v1.3.4",
"version": "v1.3.6",
"source": {
"type": "git",
"url": "https://github.com/laravel/serializable-closure.git",
"reference": "61b87392d986dc49ad5ef64e75b1ff5fee24ef81"
"reference": "f865a58ea3a0107c336b7045104c75243fa59d96"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/61b87392d986dc49ad5ef64e75b1ff5fee24ef81",
"reference": "61b87392d986dc49ad5ef64e75b1ff5fee24ef81",
"url": "https://api.github.com/repos/laravel/serializable-closure/zipball/f865a58ea3a0107c336b7045104c75243fa59d96",
"reference": "f865a58ea3a0107c336b7045104c75243fa59d96",
"shasum": ""
},
"require": {
@@ -1580,7 +1584,7 @@
"issues": "https://github.com/laravel/serializable-closure/issues",
"source": "https://github.com/laravel/serializable-closure"
},
"time": "2024-08-02T07:48:17+00:00"
"time": "2024-11-11T17:06:04+00:00"
},
{
"name": "laravel/tinker",
@@ -1838,16 +1842,16 @@
},
{
"name": "league/flysystem",
"version": "3.28.0",
"version": "3.29.1",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
"reference": "e611adab2b1ae2e3072fa72d62c62f52c2bf1f0c"
"reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/e611adab2b1ae2e3072fa72d62c62f52c2bf1f0c",
"reference": "e611adab2b1ae2e3072fa72d62c62f52c2bf1f0c",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/edc1bb7c86fab0776c3287dbd19b5fa278347319",
"reference": "edc1bb7c86fab0776c3287dbd19b5fa278347319",
"shasum": ""
},
"require": {
@@ -1915,22 +1919,22 @@
],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/3.28.0"
"source": "https://github.com/thephpleague/flysystem/tree/3.29.1"
},
"time": "2024-05-22T10:09:12+00:00"
"time": "2024-10-08T08:58:34+00:00"
},
{
"name": "league/flysystem-local",
"version": "3.28.0",
"version": "3.29.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem-local.git",
"reference": "13f22ea8be526ea58c2ddff9e158ef7c296e4f40"
"reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/13f22ea8be526ea58c2ddff9e158ef7c296e4f40",
"reference": "13f22ea8be526ea58c2ddff9e158ef7c296e4f40",
"url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/e0e8d52ce4b2ed154148453d321e97c8e931bd27",
"reference": "e0e8d52ce4b2ed154148453d321e97c8e931bd27",
"shasum": ""
},
"require": {
@@ -1964,22 +1968,22 @@
"local"
],
"support": {
"source": "https://github.com/thephpleague/flysystem-local/tree/3.28.0"
"source": "https://github.com/thephpleague/flysystem-local/tree/3.29.0"
},
"time": "2024-05-06T20:05:52+00:00"
"time": "2024-08-09T21:24:39+00:00"
},
{
"name": "league/mime-type-detection",
"version": "1.15.0",
"version": "1.16.0",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/mime-type-detection.git",
"reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301"
"reference": "2d6702ff215bf922936ccc1ad31007edc76451b9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301",
"reference": "ce0f4d1e8a6f4eb0ddff33f57c69c50fd09f4301",
"url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/2d6702ff215bf922936ccc1ad31007edc76451b9",
"reference": "2d6702ff215bf922936ccc1ad31007edc76451b9",
"shasum": ""
},
"require": {
@@ -2010,7 +2014,7 @@
"description": "Mime-type detection for Flysystem",
"support": {
"issues": "https://github.com/thephpleague/mime-type-detection/issues",
"source": "https://github.com/thephpleague/mime-type-detection/tree/1.15.0"
"source": "https://github.com/thephpleague/mime-type-detection/tree/1.16.0"
},
"funding": [
{
@@ -2022,7 +2026,7 @@
"type": "tidelift"
}
],
"time": "2024-01-28T23:22:08+00:00"
"time": "2024-09-21T08:32:55+00:00"
},
{
"name": "mews/captcha",
@@ -2099,16 +2103,16 @@
},
{
"name": "monolog/monolog",
"version": "3.7.0",
"version": "3.8.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "f4393b648b78a5408747de94fca38beb5f7e9ef8"
"reference": "32e515fdc02cdafbe4593e30a9350d486b125b67"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/f4393b648b78a5408747de94fca38beb5f7e9ef8",
"reference": "f4393b648b78a5408747de94fca38beb5f7e9ef8",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/32e515fdc02cdafbe4593e30a9350d486b125b67",
"reference": "32e515fdc02cdafbe4593e30a9350d486b125b67",
"shasum": ""
},
"require": {
@@ -2128,12 +2132,14 @@
"guzzlehttp/psr7": "^2.2",
"mongodb/mongodb": "^1.8",
"php-amqplib/php-amqplib": "~2.4 || ^3",
"phpstan/phpstan": "^1.9",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-strict-rules": "^1.4",
"phpunit/phpunit": "^10.5.17",
"php-console/php-console": "^3.1.8",
"phpstan/phpstan": "^2",
"phpstan/phpstan-deprecation-rules": "^2",
"phpstan/phpstan-strict-rules": "^2",
"phpunit/phpunit": "^10.5.17 || ^11.0.7",
"predis/predis": "^1.1 || ^2",
"ruflin/elastica": "^7",
"rollbar/rollbar": "^4.0",
"ruflin/elastica": "^7 || ^8",
"symfony/mailer": "^5.4 || ^6",
"symfony/mime": "^5.4 || ^6"
},
@@ -2184,7 +2190,7 @@
],
"support": {
"issues": "https://github.com/Seldaek/monolog/issues",
"source": "https://github.com/Seldaek/monolog/tree/3.7.0"
"source": "https://github.com/Seldaek/monolog/tree/3.8.0"
},
"funding": [
{
@@ -2196,7 +2202,7 @@
"type": "tidelift"
}
],
"time": "2024-06-28T09:40:51+00:00"
"time": "2024-11-12T13:57:08+00:00"
},
{
"name": "nesbot/carbon",
@@ -2307,24 +2313,24 @@
},
{
"name": "nette/schema",
"version": "v1.3.0",
"version": "v1.3.2",
"source": {
"type": "git",
"url": "https://github.com/nette/schema.git",
"reference": "a6d3a6d1f545f01ef38e60f375d1cf1f4de98188"
"reference": "da801d52f0354f70a638673c4a0f04e16529431d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nette/schema/zipball/a6d3a6d1f545f01ef38e60f375d1cf1f4de98188",
"reference": "a6d3a6d1f545f01ef38e60f375d1cf1f4de98188",
"url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d",
"reference": "da801d52f0354f70a638673c4a0f04e16529431d",
"shasum": ""
},
"require": {
"nette/utils": "^4.0",
"php": "8.1 - 8.3"
"php": "8.1 - 8.4"
},
"require-dev": {
"nette/tester": "^2.4",
"nette/tester": "^2.5.2",
"phpstan/phpstan-nette": "^1.0",
"tracy/tracy": "^2.8"
},
@@ -2363,9 +2369,9 @@
],
"support": {
"issues": "https://github.com/nette/schema/issues",
"source": "https://github.com/nette/schema/tree/v1.3.0"
"source": "https://github.com/nette/schema/tree/v1.3.2"
},
"time": "2023-12-11T11:54:22+00:00"
"time": "2024-10-06T23:10:23+00:00"
},
{
"name": "nette/utils",
@@ -2513,33 +2519,32 @@
},
{
"name": "nunomaduro/termwind",
"version": "v1.15.1",
"version": "v1.16.0",
"source": {
"type": "git",
"url": "https://github.com/nunomaduro/termwind.git",
"reference": "8ab0b32c8caa4a2e09700ea32925441385e4a5dc"
"reference": "dcf1ec3dfa36137b7ce41d43866644a7ab8fc257"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nunomaduro/termwind/zipball/8ab0b32c8caa4a2e09700ea32925441385e4a5dc",
"reference": "8ab0b32c8caa4a2e09700ea32925441385e4a5dc",
"url": "https://api.github.com/repos/nunomaduro/termwind/zipball/dcf1ec3dfa36137b7ce41d43866644a7ab8fc257",
"reference": "dcf1ec3dfa36137b7ce41d43866644a7ab8fc257",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": "^8.0",
"symfony/console": "^5.3.0|^6.0.0"
"php": "^8.1",
"symfony/console": "^6.4.12"
},
"require-dev": {
"ergebnis/phpstan-rules": "^1.0.",
"illuminate/console": "^8.0|^9.0",
"illuminate/support": "^8.0|^9.0",
"laravel/pint": "^1.0.0",
"pestphp/pest": "^1.21.0",
"pestphp/pest-plugin-mock": "^1.0",
"phpstan/phpstan": "^1.4.6",
"phpstan/phpstan-strict-rules": "^1.1.0",
"symfony/var-dumper": "^5.2.7|^6.0.0",
"illuminate/console": "^10.48.22",
"illuminate/support": "^10.48.22",
"laravel/pint": "^1.18.1",
"pestphp/pest": "^2",
"pestphp/pest-plugin-mock": "2.0.0",
"phpstan/phpstan": "^1.12.6",
"phpstan/phpstan-strict-rules": "^1.6.1",
"symfony/var-dumper": "^6.4.11",
"thecodingmachine/phpstan-strict-rules": "^1.0.0"
},
"type": "library",
@@ -2579,7 +2584,7 @@
],
"support": {
"issues": "https://github.com/nunomaduro/termwind/issues",
"source": "https://github.com/nunomaduro/termwind/tree/v1.15.1"
"source": "https://github.com/nunomaduro/termwind/tree/v1.16.0"
},
"funding": [
{
@@ -2595,7 +2600,7 @@
"type": "github"
}
],
"time": "2023-02-08T01:06:31+00:00"
"time": "2024-10-15T15:27:12+00:00"
},
{
"name": "nyholm/psr7",
@@ -3364,16 +3369,16 @@
},
{
"name": "psr/log",
"version": "3.0.1",
"version": "3.0.2",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "79dff0b268932c640297f5208d6298f71855c03e"
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/79dff0b268932c640297f5208d6298f71855c03e",
"reference": "79dff0b268932c640297f5208d6298f71855c03e",
"url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
"reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3",
"shasum": ""
},
"require": {
@@ -3408,9 +3413,9 @@
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/3.0.1"
"source": "https://github.com/php-fig/log/tree/3.0.2"
},
"time": "2024-08-21T13:31:24+00:00"
"time": "2024-09-11T13:17:53+00:00"
},
{
"name": "psr/simple-cache",
@@ -3941,16 +3946,16 @@
},
{
"name": "symfony/console",
"version": "v6.4.11",
"version": "v6.4.14",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "42686880adaacdad1835ee8fc2a9ec5b7bd63998"
"reference": "897c2441ed4eec8a8a2c37b943427d24dba3f26b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/42686880adaacdad1835ee8fc2a9ec5b7bd63998",
"reference": "42686880adaacdad1835ee8fc2a9ec5b7bd63998",
"url": "https://api.github.com/repos/symfony/console/zipball/897c2441ed4eec8a8a2c37b943427d24dba3f26b",
"reference": "897c2441ed4eec8a8a2c37b943427d24dba3f26b",
"shasum": ""
},
"require": {
@@ -4015,7 +4020,7 @@
"terminal"
],
"support": {
"source": "https://github.com/symfony/console/tree/v6.4.11"
"source": "https://github.com/symfony/console/tree/v6.4.14"
},
"funding": [
{
@@ -4031,20 +4036,20 @@
"type": "tidelift"
}
],
"time": "2024-08-15T22:48:29+00:00"
"time": "2024-11-05T15:34:40+00:00"
},
{
"name": "symfony/css-selector",
"version": "v6.4.8",
"version": "v6.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/css-selector.git",
"reference": "4b61b02fe15db48e3687ce1c45ea385d1780fe08"
"reference": "cb23e97813c5837a041b73a6d63a9ddff0778f5e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/4b61b02fe15db48e3687ce1c45ea385d1780fe08",
"reference": "4b61b02fe15db48e3687ce1c45ea385d1780fe08",
"url": "https://api.github.com/repos/symfony/css-selector/zipball/cb23e97813c5837a041b73a6d63a9ddff0778f5e",
"reference": "cb23e97813c5837a041b73a6d63a9ddff0778f5e",
"shasum": ""
},
"require": {
@@ -4080,7 +4085,7 @@
"description": "Converts CSS selectors to XPath expressions",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/css-selector/tree/v6.4.8"
"source": "https://github.com/symfony/css-selector/tree/v6.4.13"
},
"funding": [
{
@@ -4096,7 +4101,7 @@
"type": "tidelift"
}
],
"time": "2024-05-31T14:49:08+00:00"
"time": "2024-09-25T14:18:03+00:00"
},
{
"name": "symfony/deprecation-contracts",
@@ -4167,16 +4172,16 @@
},
{
"name": "symfony/error-handler",
"version": "v6.4.10",
"version": "v6.4.14",
"source": {
"type": "git",
"url": "https://github.com/symfony/error-handler.git",
"reference": "231f1b2ee80f72daa1972f7340297d67439224f0"
"reference": "9e024324511eeb00983ee76b9aedc3e6ecd993d9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/error-handler/zipball/231f1b2ee80f72daa1972f7340297d67439224f0",
"reference": "231f1b2ee80f72daa1972f7340297d67439224f0",
"url": "https://api.github.com/repos/symfony/error-handler/zipball/9e024324511eeb00983ee76b9aedc3e6ecd993d9",
"reference": "9e024324511eeb00983ee76b9aedc3e6ecd993d9",
"shasum": ""
},
"require": {
@@ -4222,7 +4227,7 @@
"description": "Provides tools to manage errors and ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/error-handler/tree/v6.4.10"
"source": "https://github.com/symfony/error-handler/tree/v6.4.14"
},
"funding": [
{
@@ -4238,20 +4243,20 @@
"type": "tidelift"
}
],
"time": "2024-07-26T12:30:32+00:00"
"time": "2024-11-05T15:34:40+00:00"
},
{
"name": "symfony/event-dispatcher",
"version": "v6.4.8",
"version": "v6.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher.git",
"reference": "8d7507f02b06e06815e56bb39aa0128e3806208b"
"reference": "0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/8d7507f02b06e06815e56bb39aa0128e3806208b",
"reference": "8d7507f02b06e06815e56bb39aa0128e3806208b",
"url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e",
"reference": "0ffc48080ab3e9132ea74ef4e09d8dcf26bf897e",
"shasum": ""
},
"require": {
@@ -4302,7 +4307,7 @@
"description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/event-dispatcher/tree/v6.4.8"
"source": "https://github.com/symfony/event-dispatcher/tree/v6.4.13"
},
"funding": [
{
@@ -4318,7 +4323,7 @@
"type": "tidelift"
}
],
"time": "2024-05-31T14:49:08+00:00"
"time": "2024-09-25T14:18:03+00:00"
},
{
"name": "symfony/event-dispatcher-contracts",
@@ -4398,16 +4403,16 @@
},
{
"name": "symfony/finder",
"version": "v6.4.11",
"version": "v6.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "d7eb6daf8cd7e9ac4976e9576b32042ef7253453"
"reference": "daea9eca0b08d0ed1dc9ab702a46128fd1be4958"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/d7eb6daf8cd7e9ac4976e9576b32042ef7253453",
"reference": "d7eb6daf8cd7e9ac4976e9576b32042ef7253453",
"url": "https://api.github.com/repos/symfony/finder/zipball/daea9eca0b08d0ed1dc9ab702a46128fd1be4958",
"reference": "daea9eca0b08d0ed1dc9ab702a46128fd1be4958",
"shasum": ""
},
"require": {
@@ -4442,7 +4447,7 @@
"description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/v6.4.11"
"source": "https://github.com/symfony/finder/tree/v6.4.13"
},
"funding": [
{
@@ -4458,7 +4463,7 @@
"type": "tidelift"
}
],
"time": "2024-08-13T14:27:37+00:00"
"time": "2024-10-01T08:30:56+00:00"
},
{
"name": "symfony/http-client",
@@ -4633,16 +4638,16 @@
},
{
"name": "symfony/http-foundation",
"version": "v6.4.10",
"version": "v6.4.14",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-foundation.git",
"reference": "117f1f20a7ade7bcea28b861fb79160a21a1e37b"
"reference": "ba020a321a95519303a3f09ec2824d34d601c388"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/117f1f20a7ade7bcea28b861fb79160a21a1e37b",
"reference": "117f1f20a7ade7bcea28b861fb79160a21a1e37b",
"url": "https://api.github.com/repos/symfony/http-foundation/zipball/ba020a321a95519303a3f09ec2824d34d601c388",
"reference": "ba020a321a95519303a3f09ec2824d34d601c388",
"shasum": ""
},
"require": {
@@ -4690,7 +4695,7 @@
"description": "Defines an object-oriented layer for the HTTP specification",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-foundation/tree/v6.4.10"
"source": "https://github.com/symfony/http-foundation/tree/v6.4.14"
},
"funding": [
{
@@ -4706,20 +4711,20 @@
"type": "tidelift"
}
],
"time": "2024-07-26T12:36:27+00:00"
"time": "2024-11-05T16:39:55+00:00"
},
{
"name": "symfony/http-kernel",
"version": "v6.4.11",
"version": "v6.4.14",
"source": {
"type": "git",
"url": "https://github.com/symfony/http-kernel.git",
"reference": "1ba6b89d781cb47448155cc70dd2e0f1b0584c79"
"reference": "8278a947d0369754a47b758a9e17b72cab970951"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/1ba6b89d781cb47448155cc70dd2e0f1b0584c79",
"reference": "1ba6b89d781cb47448155cc70dd2e0f1b0584c79",
"url": "https://api.github.com/repos/symfony/http-kernel/zipball/8278a947d0369754a47b758a9e17b72cab970951",
"reference": "8278a947d0369754a47b758a9e17b72cab970951",
"shasum": ""
},
"require": {
@@ -4804,7 +4809,7 @@
"description": "Provides a structured process for converting a Request into a Response",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/http-kernel/tree/v6.4.11"
"source": "https://github.com/symfony/http-kernel/tree/v6.4.14"
},
"funding": [
{
@@ -4820,20 +4825,20 @@
"type": "tidelift"
}
],
"time": "2024-08-30T16:57:20+00:00"
"time": "2024-11-06T09:45:21+00:00"
},
{
"name": "symfony/mailer",
"version": "v6.4.9",
"version": "v6.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/mailer.git",
"reference": "e2d56f180f5b8c5e7c0fbea872bb1f529b6d6d45"
"reference": "c2f7e0d8d7ac8fe25faccf5d8cac462805db2663"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mailer/zipball/e2d56f180f5b8c5e7c0fbea872bb1f529b6d6d45",
"reference": "e2d56f180f5b8c5e7c0fbea872bb1f529b6d6d45",
"url": "https://api.github.com/repos/symfony/mailer/zipball/c2f7e0d8d7ac8fe25faccf5d8cac462805db2663",
"reference": "c2f7e0d8d7ac8fe25faccf5d8cac462805db2663",
"shasum": ""
},
"require": {
@@ -4884,7 +4889,7 @@
"description": "Helps sending emails",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/mailer/tree/v6.4.9"
"source": "https://github.com/symfony/mailer/tree/v6.4.13"
},
"funding": [
{
@@ -4900,20 +4905,20 @@
"type": "tidelift"
}
],
"time": "2024-06-28T07:59:05+00:00"
"time": "2024-09-25T14:18:03+00:00"
},
{
"name": "symfony/mime",
"version": "v6.4.11",
"version": "v6.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/mime.git",
"reference": "dba5d5f6073baf7a3576b580cc4a208b4ca00553"
"reference": "1de1cf14d99b12c7ebbb850491ec6ae3ed468855"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/dba5d5f6073baf7a3576b580cc4a208b4ca00553",
"reference": "dba5d5f6073baf7a3576b580cc4a208b4ca00553",
"url": "https://api.github.com/repos/symfony/mime/zipball/1de1cf14d99b12c7ebbb850491ec6ae3ed468855",
"reference": "1de1cf14d99b12c7ebbb850491ec6ae3ed468855",
"shasum": ""
},
"require": {
@@ -4969,7 +4974,7 @@
"mime-type"
],
"support": {
"source": "https://github.com/symfony/mime/tree/v6.4.11"
"source": "https://github.com/symfony/mime/tree/v6.4.13"
},
"funding": [
{
@@ -4985,7 +4990,7 @@
"type": "tidelift"
}
],
"time": "2024-08-13T12:15:02+00:00"
"time": "2024-10-25T15:07:50+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -5701,16 +5706,16 @@
},
{
"name": "symfony/process",
"version": "v6.4.8",
"version": "v6.4.14",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "8d92dd79149f29e89ee0f480254db595f6a6a2c5"
"reference": "25214adbb0996d18112548de20c281be9f27279f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/8d92dd79149f29e89ee0f480254db595f6a6a2c5",
"reference": "8d92dd79149f29e89ee0f480254db595f6a6a2c5",
"url": "https://api.github.com/repos/symfony/process/zipball/25214adbb0996d18112548de20c281be9f27279f",
"reference": "25214adbb0996d18112548de20c281be9f27279f",
"shasum": ""
},
"require": {
@@ -5742,7 +5747,7 @@
"description": "Executes commands in sub-processes",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v6.4.8"
"source": "https://github.com/symfony/process/tree/v6.4.14"
},
"funding": [
{
@@ -5758,7 +5763,7 @@
"type": "tidelift"
}
],
"time": "2024-05-31T14:49:08+00:00"
"time": "2024-11-06T09:25:01+00:00"
},
{
"name": "symfony/psr-http-message-bridge",
@@ -5845,16 +5850,16 @@
},
{
"name": "symfony/routing",
"version": "v6.4.11",
"version": "v6.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/routing.git",
"reference": "8ee0c24c1bf61c263a26f1b9b6d19e83b1121f2a"
"reference": "640a74250d13f9c30d5ca045b6aaaabcc8215278"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/routing/zipball/8ee0c24c1bf61c263a26f1b9b6d19e83b1121f2a",
"reference": "8ee0c24c1bf61c263a26f1b9b6d19e83b1121f2a",
"url": "https://api.github.com/repos/symfony/routing/zipball/640a74250d13f9c30d5ca045b6aaaabcc8215278",
"reference": "640a74250d13f9c30d5ca045b6aaaabcc8215278",
"shasum": ""
},
"require": {
@@ -5908,7 +5913,7 @@
"url"
],
"support": {
"source": "https://github.com/symfony/routing/tree/v6.4.11"
"source": "https://github.com/symfony/routing/tree/v6.4.13"
},
"funding": [
{
@@ -5924,7 +5929,7 @@
"type": "tidelift"
}
],
"time": "2024-08-29T08:15:38+00:00"
"time": "2024-10-01T08:30:56+00:00"
},
{
"name": "symfony/service-contracts",
@@ -6011,16 +6016,16 @@
},
{
"name": "symfony/string",
"version": "v6.4.11",
"version": "v6.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/string.git",
"reference": "5bc3eb632cf9c8dbfd6529d89be9950d1518883b"
"reference": "38371c60c71c72b3d64d8d76f6b1bb81a2cc3627"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/5bc3eb632cf9c8dbfd6529d89be9950d1518883b",
"reference": "5bc3eb632cf9c8dbfd6529d89be9950d1518883b",
"url": "https://api.github.com/repos/symfony/string/zipball/38371c60c71c72b3d64d8d76f6b1bb81a2cc3627",
"reference": "38371c60c71c72b3d64d8d76f6b1bb81a2cc3627",
"shasum": ""
},
"require": {
@@ -6077,7 +6082,7 @@
"utf8"
],
"support": {
"source": "https://github.com/symfony/string/tree/v6.4.11"
"source": "https://github.com/symfony/string/tree/v6.4.13"
},
"funding": [
{
@@ -6093,20 +6098,20 @@
"type": "tidelift"
}
],
"time": "2024-08-12T09:55:28+00:00"
"time": "2024-09-25T14:18:03+00:00"
},
{
"name": "symfony/translation",
"version": "v6.4.10",
"version": "v6.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/translation.git",
"reference": "94041203f8ac200ae9e7c6a18fa6137814ccecc9"
"reference": "bee9bfabfa8b4045a66bf82520e492cddbaffa66"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/translation/zipball/94041203f8ac200ae9e7c6a18fa6137814ccecc9",
"reference": "94041203f8ac200ae9e7c6a18fa6137814ccecc9",
"url": "https://api.github.com/repos/symfony/translation/zipball/bee9bfabfa8b4045a66bf82520e492cddbaffa66",
"reference": "bee9bfabfa8b4045a66bf82520e492cddbaffa66",
"shasum": ""
},
"require": {
@@ -6172,7 +6177,7 @@
"description": "Provides tools to internationalize your application",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/translation/tree/v6.4.10"
"source": "https://github.com/symfony/translation/tree/v6.4.13"
},
"funding": [
{
@@ -6188,7 +6193,7 @@
"type": "tidelift"
}
],
"time": "2024-07-26T12:30:32+00:00"
"time": "2024-09-27T18:14:25+00:00"
},
{
"name": "symfony/translation-contracts",
@@ -6270,16 +6275,16 @@
},
{
"name": "symfony/uid",
"version": "v6.4.11",
"version": "v6.4.13",
"source": {
"type": "git",
"url": "https://github.com/symfony/uid.git",
"reference": "6a0394ad707de386547223948fac1e0f2805bc0b"
"reference": "18eb207f0436a993fffbdd811b5b8fa35fa5e007"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/uid/zipball/6a0394ad707de386547223948fac1e0f2805bc0b",
"reference": "6a0394ad707de386547223948fac1e0f2805bc0b",
"url": "https://api.github.com/repos/symfony/uid/zipball/18eb207f0436a993fffbdd811b5b8fa35fa5e007",
"reference": "18eb207f0436a993fffbdd811b5b8fa35fa5e007",
"shasum": ""
},
"require": {
@@ -6324,7 +6329,7 @@
"uuid"
],
"support": {
"source": "https://github.com/symfony/uid/tree/v6.4.11"
"source": "https://github.com/symfony/uid/tree/v6.4.13"
},
"funding": [
{
@@ -6340,20 +6345,20 @@
"type": "tidelift"
}
],
"time": "2024-08-12T09:55:28+00:00"
"time": "2024-09-25T14:18:03+00:00"
},
{
"name": "symfony/var-dumper",
"version": "v6.4.11",
"version": "v6.4.14",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-dumper.git",
"reference": "ee14c8254a480913268b1e3b1cba8045ed122694"
"reference": "93c09246038178717a9c14b809ea8151ffcf7091"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/ee14c8254a480913268b1e3b1cba8045ed122694",
"reference": "ee14c8254a480913268b1e3b1cba8045ed122694",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/93c09246038178717a9c14b809ea8151ffcf7091",
"reference": "93c09246038178717a9c14b809ea8151ffcf7091",
"shasum": ""
},
"require": {
@@ -6409,7 +6414,7 @@
"dump"
],
"support": {
"source": "https://github.com/symfony/var-dumper/tree/v6.4.11"
"source": "https://github.com/symfony/var-dumper/tree/v6.4.14"
},
"funding": [
{
@@ -6425,7 +6430,7 @@
"type": "tidelift"
}
],
"time": "2024-08-30T16:03:21+00:00"
"time": "2024-11-05T15:34:40+00:00"
},
{
"name": "symfony/var-exporter",
@@ -9484,5 +9489,5 @@
"ext-bcmath": "*"
},
"platform-dev": [],
"plugin-api-version": "2.2.0"
"plugin-api-version": "2.6.0"
}
+4 -4
View File
@@ -6,7 +6,7 @@
<script>
// window.location = '/web/#/login'
</script>
<title>{!! \App\Services\SystemConfig::get('web_site_title') !!}</title>
<title>火星快链-智慧引流工具</title>
<link rel="stylesheet" href="/css/css.css">
<link rel="stylesheet" href="/css/boot.css">
<style>
@@ -452,7 +452,7 @@
<div class="footer hide-below-1000">
<div class="mainCard d-flex justify-content-between p-4">
<div>
<img class="logo" src="{!! \App\Services\SystemConfig::get('web_site_bottom_logo') !!}">
<img class="logo" src="/image/logo.png">
</div>
<div class="d-flex justify-content-between flex-1">
<div class="line" style="margin-left: 100px"></div>
@@ -471,7 +471,7 @@
<div class="line" style="margin-right: 100px"></div>
</div>
<div>
<img class="weixin" src="{!! \App\Services\SystemConfig::get('web_site_customer_service') !!}">
<img class="weixin" src="/image/web-qr.png">
</div>
</div>
<div class="xlin"></div>
@@ -480,7 +480,7 @@
<div class="show-below-1000 phoneFooter" style="display: none">
<div class="row row-cols-sm-2 p-4">
<div>
<img class="weixin" src="{!! \App\Services\SystemConfig::get('web_site_customer_service') !!}">
<img class="weixin" src="/image/web-qr.png">
<div class="mt-3">
<div class="font-20 text-white">联系我们</div>
<div class="mt-2 text-secondary font-14">公司地址:××××××××××</div>
+2 -3
View File
@@ -7,7 +7,6 @@ use App\Http\Controllers\Api\CommissionController;
use App\Http\Controllers\Api\ConfigController;
use App\Http\Controllers\Api\DomainController;
use App\Http\Controllers\Api\IndexController;
use App\Http\Controllers\Api\JumpController;
use App\Http\Controllers\Api\LinkController;
use App\Http\Controllers\Api\MaterialCateController;
use App\Http\Controllers\Api\MaterialController;
@@ -32,8 +31,8 @@ Route::post('/captcha/sms', [CaptchaController::class, 'sms']); // 获取短信
Route::post('/wechat/payment_notify', [WeChatPayNative::class, 'notify']); // 微信支付回调
// 获取链接重定向目标
Route::get('/link-target/{code}', [JumpController::class, 'target']); // 获取链接跳转地址
Route::get('/link-show-qr/{code}', [JumpController::class, 'getShowQr']); // 显示的二维码信息
Route::get('/link-target/{code}', [LinkController::class, 'target']); // 获取链接跳转地址
Route::get('/link-show-qr/{code}', [LinkController::class, 'getShowQr']); // 显示的二维码信息
// 登录用户都访问
Route::middleware(ApiAuth::class)->group(function (Router $router) {
+3
View File
@@ -1,5 +1,8 @@
<?php
use Illuminate\Foundation\Inspiring;
use Illuminate\Support\Facades\Artisan;
/*
|--------------------------------------------------------------------------
| Console Routes
-6
View File
@@ -3,18 +3,12 @@
namespace Tests\Feature;
use App\Enums\CommissionType;
use App\Jobs\SendEmailJobs;
use App\Models\User;
use App\Models\VipPackage;
use Tests\TestCase;
class UserTest extends TestCase
{
public function test_send_mail()
{
SendEmailJobs::dispatch('724323954@qq.com', '123321');
}
public function test_get_token()
{
dd($this->get_admin_token());