Add default articles & Fixed bugs in articles

- 添加 默认文章;Use php artisan db:seed --class=ArticleSeeder
- 修复 文章-分类 部分字符会影响文章正常显示的问题;
- 修正 文章-标题 部分字符显示异常的情况;
This commit is contained in:
BrettonYe
2023-01-10 23:22:11 +08:00
parent ac21eb20de
commit 034a0cd16d
9 changed files with 253 additions and 109 deletions

View File

@@ -30,23 +30,20 @@ REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=smtp #或使用 mailgun
# 发信方信息
MAIL_FROM_ADDRESS=admin@proxypanel.ml
MAIL_FROM_NAME=ProxyPanel
MAIL_MAILER=smtp
# SMTP设置
MAIL_HOST=smtp.exmail.qq.com
MAIL_PORT=465
MAIL_ENCRYPTION=ssl
MAIL_USERNAME=admin@proxypanel.ml
MAIL_PASSWORD=password
# Mailgun设置
MAILGUN_DOMAIN=
MAILGUN_SECRET=
# 发信方信息
MAIL_FROM_ADDRESS=admin@proxypanel.ml
MAIL_FROM_NAME=ProxyPanel
REDIRECT_HTTPS=true
BAIDU_APP_AK =
BAIDU_APP_AK=
API_LAYER_API_KEY=

View File

@@ -130,3 +130,27 @@ if (! function_exists('array_clean')) {
return $array;
}
}
// string url safe sanitize
if (! function_exists('string_urlsafe')) {
function string_urlsafe($string, $force_lowercase = true, $anal = false)
{
$strip = [
'~', '`', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '=', '+', '[', '{', ']', '}', '\\', '|', ';', ':', '"', "'", '‘', '’', '“',
'&#8221;', '&#8211;', '&#8212;', '—', '–', ',', '<', '.', '>', '/', '?',
];
$clean = trim(str_replace($strip, '_', strip_tags($string)));
$clean = preg_replace('/\s+/', '-', $clean);
$clean = ($anal) ? preg_replace('/[^a-zA-Z0-9]/', '', $clean) : $clean;
if ($force_lowercase) {
if (function_exists('mb_strtolower')) {
$clean = mb_strtolower($clean, 'UTF-8');
} else {
$clean = strtolower($clean);
}
}
return $clean;
}
}

View File

@@ -0,0 +1,116 @@
<?php
use App\Models\Article;
use Illuminate\Database\Seeder;
class ArticleSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$articles = [
'账号&服务' => [
255 => [
'不运行软件,就连不上网,怎么办?', '<h4>方法一</h4>
<p>电脑有安装任何电脑管家类的软件,都可以使用他们自带的网络修复工具来重置网络。</p>
<h4>方法二</h4>
<ol>
<li>键盘操作<code>Win</code> + <code>X</code>,或右击左下角开始菜单键 Win键看起来像 <i class="fa-brands fa-windows" aria-hidden="true"></i> 这样)</li>
<li>按下 <code>A</code>键 或者 手动选择 <code>命令提示符(管理员)/ Windows PowerShell(管理员)</code></li>
<li>输入<code>Netsh winsock reset</code> 后回车,再输入 <code>netsh advfirewall reset</code> 后回车;</li>
</ol>',
],
254 => [
'为什么我的账号状态显示是禁用?', '<p>账号在2种情况下会显示禁用</p>
<ol>
<li>套餐过期/流量枯竭;此情况您需要重新购买/重置 <a href="services">【服 务】</a></li>
<li>近期流量使用异常;在<code>1小时</code>内使用流量超过 <code>10GB</code> ,即会触发本站的流量异常保护;保护时长为 <code>60分钟</code></li>
</ol>
<p>如您对禁用情况有疑问,可以创建<a href="tickets">【工 单】</a>,联系售后人员。</p>',
],
253 => [
'为什么我的订阅链接被禁用了?', '<p>订阅地址对于账号来说非常重要。所以本站对此设置了严格的限制措施,以防止用户无意间泄露给他人后,无法挽回。</p>
<p>限制为: <code>24小时</code>内,订阅地址只允许请求 <code>20次</code></p>
<p>解封,请在过一段时间并确定无误后,创建<a href="tickets">【工 单】</a>,联系售后人员</p>
<p>小知识:如果您无意间的截图忘记将订阅地址打码了,您可以 点击上方 更换按钮</p>',
],
252 => [
'我想续费/购买服务,该怎么操作?', '<ol>
<li>在线支付,本支付方式支持支付宝。支付后即开即用。前往 <a href="services">【服 务】</a> 选择想要购买的套餐,在订单界面选择<code>在线支付</code>即可。</li>
<li>余额支付,本支付方法支持微信,支付宝。支付后需要等待充值到账,再购买服务。 ,充值后等待充值到账,一般会在<code>24小时</code>内到账,到账后可以在 <a href="services">【服 务】</a>页面查看您的账号余额。 在<a href="services">【服 务】</a> 选择想要购买的套餐,在订单界面选择<code>余额支付</code>即可。</li>
</ol>',
], 251 => [
'怎么样才能快速的联系上客服?', '<blockquote class="blockquote custom-blockquote blockquote-warning">请选择其一种方式联系客服,请勿重复发送请求!!!</blockquote>
<ol>
<li>在<a href="tickets">【工 单】</a>界面,创建新的工单,客服人员在上线后会在第一时刻处理。</li>
</ol>',
],
],
'下载&教程' => [
99 => [
'Windows', '<ol>
<li><a href="clients/ShadowsocksR-win.zip" target="_blank" rel="noopener">点击此处</a>下载客户端并启动</li>
<li>运行 ShadowsocksR 文件夹内的 ShadowsocksR.exe</li>
<li>右击桌面右下角状态栏(或系统托盘)纸飞机 -&gt; 服务器订阅 -&gt; SSR服务器订阅设置</li>
<li>点击窗口左下角 &ldquo;Add&rdquo; 新增订阅,完整复制本页上方 &ldquo;订阅服务&rdquo; 处地址,将其粘贴至&ldquo;网址&rdquo;栏,点击&ldquo;确定&rdquo;</li>
<li>右击纸飞机 -&gt; 服务器订阅 -&gt; 更新SSR服务器订阅不通过代理</li>
<li>右击纸飞机 -&gt; 服务器,选定合适服务器</li>
<li>右击纸飞机 -&gt; 系统代理模式 -&gt; PAC模式</li>
<li>右击纸飞机 -&gt; PAC -&gt; 更新PAC为GFWList</li>
<li>右击纸飞机 -&gt; 代理规则 -&gt; 绕过局域网和大陆</li>
<li>右击纸飞机,取消勾选&ldquo;服务器负载均衡&rdquo;</li>
</ol>',
], 98 => [
'安卓', '<ol>
<li><a href="https://github.com/shadowsocksrr/shadowsocksr-android/releases/download/3.5.3/shadowsocksr-android-3.5.3.apk" target="_blank" rel="noopener">点击此处</a>下载客户端并启动</li>
<li>单击左上角的shadowsocksR进入配置文件页点击右下角的&ldquo;+&rdquo;号,点击&ldquo;添加/升级SSR订阅&rdquo;,完整复制本页上方&ldquo;订阅服务&rdquo;处地址,填入订阅信息并保存</li>
<li>选中任意一个节点,返回软件首页</li>
<li>在软件首页处找到&ldquo;路由&rdquo;选项,并将其改为&ldquo;绕过局域网及中国大陆地址&rdquo;</li>
<li>点击右上角的小飞机图标进行连接提示是否添加或创建VPN连接点同意或允许</li>
</ol>',
], 97 => [
'iOS', '<ol>
<li>请从站长处获取 App Store 账号密码</li>
<li>打开 Shadowrocket点击右上角 &ldquo;+&rdquo;号 添加节点,类型选择 Subscribe</li>
<li>完整复制本页上方 &ldquo;订阅服务&rdquo; 处地址,将其粘贴至 &ldquo;URL&rdquo;栏,点击右上角 &ldquo;完成&rdquo;</li>
<li>左划新增的服务器订阅,点击 &ldquo;更新&rdquo;</li>
<li>选定合适服务器节点,点击右上角连接开关,屏幕上方状态栏出现&ldquo;VPN&rdquo;图标</li>
<li>当进行海外游戏时请将 Shadowrocket &ldquo;首页&rdquo; 页面中的 &ldquo;全局路由&rdquo; 切换至 &ldquo;代理&rdquo;,并确保&ldquo;设置&rdquo;页面中的&ldquo;UDP&rdquo;已开启转发</li>
</ol>',
], 96 => [
'Mac', '<ol>
<li><a href="clients/ShadowsocksX-NG-R8-1.4.6.dmg" target="_blank" rel="noopener">点击此处</a>下载客户端并启动</li>
<li>点击状态栏纸飞机 -&gt; 服务器 -&gt; 编辑订阅</li>
<li>点击窗口左下角 &ldquo;+&rdquo;号 新增订阅,完整复制本页上方&ldquo;订阅服务&rdquo;处地址,将其粘贴至&ldquo;订阅地址&rdquo;栏,点击右下角&ldquo;OK&rdquo;</li>
<li>点击纸飞机 -&gt; 服务器 -&gt; 手动更新订阅</li>
<li>点击纸飞机 -&gt; 服务器,选定合适服务器</li>
<li>点击纸飞机 -&gt; 打开Shadowsocks</li>
<li>点击纸飞机 -&gt; PAC自动模式</li>
<li>点击纸飞机 -&gt; 代理设置-&gt;从 GFW List 更新 PAC</li>
<li>打开系统偏好设置 -&gt; 网络,在窗口左侧选定显示为&ldquo;已连接&rdquo;的网络,点击右下角&ldquo;高级...&rdquo;</li>
<li>切换至&ldquo;代理&rdquo;选项卡,勾选&ldquo;自动代理配置&rdquo;和&ldquo;不包括简单主机名&rdquo;,点击右下角&ldquo;好&rdquo;,再次点击右下角&ldquo;应用&rdquo;</li>
</ol>',
], 95 => [
'Linux', '<ol>
<li><a href="clients/Shadowsocks-qt5-3.0.1.zip" target="_blank" rel="noopener">点击此处</a>下载客户端并启动</li>
<li>单击状态栏小飞机,找到服务器 -&gt; 编辑订阅,复制黏贴订阅地址</li>
<li>更新订阅设置即可</li>
</ol>',
],
],
];
foreach ($articles as $category => $article) {
foreach ($article as $sort => $body) {
Article::create(['title' => $body[0], 'content' => $body[1], 'type' => 1, 'sort' => $sort, 'language' => 'zh_CN', 'category' => $category]);
}
}
Article::create(['title' => 'Welcome 欢迎!', 'content' => 'Welcome to ProxyPanel!<br> 欢迎使用ProxyPanel', 'type' => 2, 'language' => 'zh_CN']);
}
}

View File

@@ -1,5 +1,6 @@
<?php
use App\Models\Article;
use App\Models\User;
use Illuminate\Database\Seeder;
@@ -15,5 +16,9 @@ class DatabaseSeeder extends Seeder
if (User::doesntExist()) {
$this->call(PresetSeeder::class);
}
if (Article::doesntExist()) {
$this->call(ArticleSeeder::class);
}
}
}

View File

@@ -14,7 +14,7 @@
content="An account management Panel based on Laravel7 framework. Include multiple payment, account management, system caching, admin notification, products models, and more.">
<meta name="keywords" content="ProxyPanel Laravel Shadowsocks ShadowsocksR V2Ray Trojan VNET VPN">
<meta name="author" content="ZBrettonYe">
<meta name="copyright" content="2017-2022©ProxyPanel">
<meta name="copyright" content="2017-2023©ProxyPanel">
<title>@yield('title')</title>
<link href="{{asset('favicon.ico')}}" rel="shortcut icon apple-touch-icon">
<!-- 样式表/Stylesheets -->

View File

@@ -71,7 +71,7 @@
<div class="form-group row article">
<label class="col-form-label col-md-2" for="sort"> </label>
<div class="col-md-2">
<input type="number" class="form-control" name="sort" id="sort" value="10" required/>
<input type="number" class="form-control" name="sort" id="sort" value="10" min="0" max="255" required/>
<span class="text-help"> 值越高显示时越靠前 </span>
</div>
</div>
@@ -85,7 +85,11 @@
<div class="form-group row">
<label class="col-form-label col-md-2" for="content"> </label>
<div class="col-md-10">
<textarea class="form-control" name="content">@isset($article) {!! $article->content !!} @endisset</textarea>
<textarea class="form-control" name="content">
@isset($article)
{!! $article->content !!}
@endisset
</textarea>
</div>
</div>
<div class="form-actions text-right">
@@ -109,8 +113,8 @@
@isset($article)
$(document).ready(function() {
$("input[name='type'][value='{{$article->type}}']").click();
$('#title').val('{!! $article->title !!}');
$('#category').val('{{$article->category}}');
$('#title').val(@json($article->title));
$('#category').val(@json($article->category));
$('#language').selectpicker('val', '{{$article->language}}');
$('#sort').val('{{$article->sort}}');
});

View File

@@ -157,7 +157,7 @@
<div class="form-group row">
<label class="col-md-2 col-form-label" for="sort">排序</label>
<div class="col-md-4">
<input type="number" class="form-control" name="sort" id="sort" value="0"/>
<input type="number" class="form-control" name="sort" id="sort" value="0" min="0" max="255"/>
<span class="text-help"> 排序值越大排越前 </span>
</div>
</div>

View File

@@ -17,116 +17,114 @@
<h1 class="page-title">{{ __('user.knowledge.title') }}</h1>
</div>
<div class="page-content container-fluid">
<div class="row">
<div class="col-xxl-2 col-lg-4 col-md-12">
<div class="panel">
<div class="panel-body">
<div class="list-group faq-list" role="tablist">
<a class="list-group-item list-group-item-action active" data-toggle="tab"
href="#basic" aria-controls="basic" role="tab">{{ __('user.knowledge.basic') }}</a>
@foreach($knowledges as $category => $articles)
<a class="list-group-item list-group-item-action" data-toggle="tab"
href="#{{$category}}" aria-controls="{{$category}}" role="tab">{{$category}}</a>
@endforeach
@if ($knowledges->isNotEmpty())
<div class="row">
<div class="col-xxl-2 col-lg-4 col-md-12">
<div class="panel">
<div class="panel-body">
<div class="list-group faq-list" role="tablist">
@foreach($knowledges as $category => $articles)
@php $str = string_urlsafe($category) @endphp
<a class="list-group-item list-group-item-action @if($loop->first) active @endif" data-toggle="tab"
href="#{{$str}}" aria-controls="{{$str}}" role="tab">{{$category}}</a>
@endforeach
</div>
</div>
</div>
</div>
</div>
<div class="col-xxl-8 col-lg-8 col-md-12">
<div class="panel">
<div class="panel-heading progress" id="loading_article" style="display: none;">
<div class="progress-bar progress-bar-striped active" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%" role="progressbar">
<span class="sr-only">100% Complete</span>
<div class="col-xxl-8 col-lg-8 col-md-12">
<div class="panel">
<div class="panel-heading progress" id="loading_article" style="display: none;">
<div class="progress-bar progress-bar-striped active" aria-valuenow="100" aria-valuemin="0" aria-valuemax="100" style="width: 100%" role="progressbar">
<span class="sr-only">100% Complete</span>
</div>
</div>
</div>
<div class="panel-body pt-30">
<div class="tab-content">
<div class="tab-pane animation-fade active" id="basic" role="tabpanel">
<div class="panel-group panel-group-simple panel-group-continuous" id="category_basic" aria-multiselectable="true" role="tablist">
<div class="panel">
<div class="panel-heading" id="question_1" role="tab">
<a class="panel-title cyan-600" aria-controls="answer_1" aria-expanded="true" data-toggle="collapse" href="#answer_1"
data-parent="#category_basic">
<i class="icon wb-link" aria-hidden="true"></i>{{trans('user.subscribe.link')}}
</a>
</div>
<div class="panel-collapse collapse show" id="answer_1" aria-labelledby="question_1" role="tabpanel">
<div class="panel-body">
@if($subStatus)
<x-alert type="warning" :message="trans('user.subscribe.tips')"/>
<div class="input-group">
<input type="text" class="form-control" id="sub_link" value="{{$subUrl}}"/>
<div class="input-group-btn btn-group" role="group">
@if(count($subType) > 1)
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary dropdown-toggle" id="sublink" data-toggle="dropdown"
aria-expanded="false">
{{ __('user.subscribe.custom') }}
</button>
<div class="dropdown-menu" aria-labelledby="sublink" role="menu">
@if(in_array('ss', $subType, true))
<a class="dropdown-item" onclick="linkManager('0')"
role="menuitem">{{ __('user.subscribe.ss_only') }}</a>
@endif
@if(in_array('ssr', $subType, true))
<a class="dropdown-item" onclick="linkManager('1')"
role="menuitem">{{ __('user.subscribe.ssr_only') }}</a>
@endif
@if(in_array('v2', $subType, true))
<a class="dropdown-item" onclick="linkManager('2')"
role="menuitem">{{ __('user.subscribe.v2ray_only') }}</a>
@endif
@if(in_array('trojan', $subType, true))
<a class="dropdown-item" onclick="linkManager('3')"
role="menuitem">{{ __('user.subscribe.trojan_only') }}</a>
<div class="panel-body pt-30">
<div class="tab-content">
@foreach($knowledges as $category => $articles)
<div class="tab-pane animation-fade @if($loop->first) active @endif" id="{{string_urlsafe($category)}}" role="tabpanel">
<div class="panel-group panel-group-simple panel-group-continuous" id="category_{{$loop->iteration}}" aria-multiselectable="true"
role="tablist">
@if ($loop->first)
<div class="panel">
<div class="panel-heading" id="question_1" role="tab">
<a class="panel-title cyan-600" aria-controls="answer_1" aria-expanded="true" data-toggle="collapse" href="#answer_1"
data-parent="#category_{{$loop->iteration}}">
<i class="icon wb-link" aria-hidden="true"></i>{{trans('user.subscribe.link')}}
</a>
</div>
<div class="panel-collapse collapse show" id="answer_1" aria-labelledby="question_1" role="tabpanel">
<div class="panel-body">
@if($subStatus)
<x-alert type="warning" :message="trans('user.subscribe.tips')"/>
<div class="input-group">
<input type="text" class="form-control" id="sub_link" value="{{$subUrl}}"/>
<div class="input-group-btn btn-group" role="group">
@if(count($subType) > 1)
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary dropdown-toggle" id="sublink" data-toggle="dropdown"
aria-expanded="false">
{{ __('user.subscribe.custom') }}
</button>
<div class="dropdown-menu" aria-labelledby="sublink" role="menu">
@if(in_array('ss', $subType, true))
<a class="dropdown-item" onclick="linkManager('0')"
role="menuitem">{{ __('user.subscribe.ss_only') }}</a>
@endif
@if(in_array('ssr', $subType, true))
<a class="dropdown-item" onclick="linkManager('1')"
role="menuitem">{{ __('user.subscribe.ssr_only') }}</a>
@endif
@if(in_array('v2', $subType, true))
<a class="dropdown-item" onclick="linkManager('2')"
role="menuitem">{{ __('user.subscribe.v2ray_only') }}</a>
@endif
@if(in_array('trojan', $subType, true))
<a class="dropdown-item" onclick="linkManager('3')"
role="menuitem">{{ __('user.subscribe.trojan_only') }}</a>
@endif
</div>
</div>
@endif
<button class="btn btn-outline-info" onclick="exchangeSubscribe();">
<i class="icon wb-refresh" aria-hidden="true"></i>
{{trans('common.replace')}}</button>
<button class="btn btn-outline-info mt-clipboard" data-clipboard-action="copy"
data-clipboard-target="#sub_link">
<i class="icon wb-copy" aria-hidden="true"></i>
{{trans('common.copy.attribute')}}</button>
</div>
</div>
@else
<x-alert type="danger" :message="trans('user.subscribe.baned')"/>
@endif
<button class="btn btn-outline-info" onclick="exchangeSubscribe();">
<i class="icon wb-refresh" aria-hidden="true"></i>
{{trans('common.replace')}}</button>
<button class="btn btn-outline-info mt-clipboard" data-clipboard-action="copy" data-clipboard-target="#sub_link">
<i class="icon wb-copy" aria-hidden="true"></i>
{{trans('common.copy.attribute')}}</button>
</div>
</div>
@else
<x-alert type="danger" :message="trans('user.subscribe.baned')"/>
@endif
</div>
</div>
</div>
</div>
</div>
@foreach($knowledges as $category => $articles)
@php
$outLoop = $loop->iteration;
@endphp
<div class="tab-pane animation-fade" id="{{$category}}" role="tabpanel">
<div class="panel-group panel-group-simple panel-group-continuous" id="category_{{$outLoop}}" aria-multiselectable="true" role="tablist">
@foreach ($articles as $article)
<div class="panel">
<div class="panel-heading" id="article_Q{{$article->id}}" role="tab">
<a class="panel-title" onclick="fetch('{{$article->id}}')" aria-controls="article_A{{$article->id}}"
aria-expanded="false"
data-toggle="collapse" href="#article_A{{$article->id}}" data-parent="#category_{{$outLoop}}">
{{$article->title}}
</a>
<div class="panel-collapse" id="article_A{{$article->id}}" aria-labelledby="article_Q{{$article->id}}" role="tabpanel">
<div class="panel-body" id="article_B{{$article->id}}"></div>
</div>
@endif
@foreach ($articles as $article)
<div class="panel">
<div class="panel-heading" id="article_Q{{$article->id}}" role="tab">
<a class="panel-title" onclick="fetch('{{$article->id}}')" aria-controls="article_A{{$article->id}}"
aria-expanded="false"
data-toggle="collapse" href="#article_A{{$article->id}}" data-parent="#category_{{$loop->parent->iteration}}">
{{$article->title}}
</a>
<div class="panel-collapse" id="article_A{{$article->id}}" aria-labelledby="article_Q{{$article->id}}" role="tabpanel">
<div class="panel-body" id="article_B{{$article->id}}"></div>
</div>
</div>
</div>
</div>
@endforeach
@endforeach
</div>
</div>
</div>
@endforeach
@endforeach
</div>
</div>
</div>
</div>
</div>
</div>
@endif
</div>
@endsection
@section('javascript')

View File

@@ -193,7 +193,7 @@
</div>
<footer class="site-footer">
<div class="site-footer-legal">
© 2017 - 2022 <a href="https://github.com/ProxyPanel/ProxyPanel" target="_blank">{{config('version.name')}} {{__('All rights reserved.')}}</a>
© 2017 - 2023 <a href="https://github.com/ProxyPanel/ProxyPanel" target="_blank">{{config('version.name')}} {{__('All rights reserved.')}}</a>
🚀 Version: <code> {{config('version.number')}} </code>
</div>
<div class="site-footer-right">