Compare commits

...

13 Commits

Author SHA1 Message Date
liutk 137512b735 0.7 2026-02-22 23:01:55 +08:00
liutk 2b4e16cfde 0.64 2026-02-22 21:11:18 +08:00
liutk a48aac714c 0.63 2026-02-22 18:05:19 +08:00
liutk 4b438defb6 0.62 2026-02-22 18:01:06 +08:00
liutk 0eeadecb45 0.61 2026-02-22 17:43:55 +08:00
liutk 1c228d21e1 0.6 2026-02-22 11:58:01 +08:00
liutk 9de912f7e5 0.5 2026-02-21 21:47:01 +08:00
liutk e9d9633f42 0.5 2026-02-21 21:45:07 +08:00
liutk c77fed7b65 0.4 2026-02-21 20:24:39 +08:00
liutk 1b926b7b9e 0.3 2026-02-21 20:00:52 +08:00
liutk 64843b6805 0.3 2026-02-21 20:00:42 +08:00
liutk a4b4fa7aca 0.2 2026-02-21 19:49:07 +08:00
liutk 2be627dd8d 0.1 2026-02-21 19:10:22 +08:00
64 changed files with 2665 additions and 40 deletions

View File

@ -115,7 +115,7 @@ class Components extends BaseRenderer {
* 标签选择
*/
public function keywordsTagControl($name = 'tags', $label= null, $pKey = null){
return amisMake()->TagControl()
return amis()->TagControl()
->name($name)->label($label ?? __('admin.components.tag'))
->maxTagLength(0)
->options(Keyword::where('parent_key', $pKey)->pluck('name', 'id')->toArray());
@ -123,7 +123,7 @@ class Components extends BaseRenderer {
public function keywordsTag($label = null, $color = null){
if($color){
$tag = amisMake()->Tag()->label($label ?? __('admin.components.tag'))
$tag = amis()->Tag()->label($label ?? __('admin.components.tag'))
->displayMode('rounded')->style([
'color' => '#fff',
'backgroundColor' =>$color,

View File

@ -30,10 +30,8 @@ class ArticleController extends AdminController
->placeholder(__('admin.id')),
amis()->TextControl('title', __('admin.articles.title'))
->placeholder(__('admin.articles.title')),
Components::make()->parentControl(admin_url('api/keywords/tree-list?parent_name=article_category&has_owner=0'), 'category', __('admin.articles.category'), 'name', 'key'),
Components::make()->keywordsTagControl('t_ids', __('admin.articles.tags'), 'article_tag'),
]),
amis()->GroupControl()->mode('horizontal')->body([
// Components::make()->parentControl(admin_url('api/keywords/tree-list?parent_name=article_category&has_owner=0'), 'category', __('admin.articles.category'), 'name', 'key'),
// Components::make()->keywordsTagControl('t_ids', __('admin.articles.tags'), 'article_tag'),
amis()->SelectControl('enable', __('admin.articles.is_enable'))
->columnRatio(3)
->options([
@ -44,10 +42,10 @@ class ArticleController extends AdminController
->options([
1=>'开启',0=>'关闭'
]),
amis()->InputDatetimeRange()->label(__('admin.articles.published_at'))->name('published_at'),
]),
amis()->GroupControl()->mode('horizontal')->body([
amis()->InputDatetimeRange()->label(__('admin.created_at'))->name('created_at')->columnRatio(6),
amis()->InputDatetimeRange()->label(__('admin.articles.published_at'))->name('published_at'),
amis()->InputDatetimeRange()->label(__('admin.created_at'))->name('created_at'),
]),
]))
->itemBadge([//行角标
@ -61,9 +59,9 @@ class ArticleController extends AdminController
->columns([
amis()->TableColumn('id', __('admin.id'))->sortable(true),
amis()->TableColumn('title', __('admin.articles.title'))->width('300px'),
amis()->TableColumn('category', __('admin.articles.category'))->type('mapping')
->map(Keyword::allChildrenOfKey('article_category')->pluck('name', 'key')->toArray())
->itemSchema(amis()->Tag()->label('${item}')->color(Admin::setting()->get('system_theme_setting')['theme_color'] ?? '#1677ff')),
// amis()->TableColumn('category', __('admin.articles.category'))->type('mapping')
// ->map(Keyword::allChildrenOfKey('article_category')->pluck('name', 'key')->toArray())
// ->itemSchema(amis()->Tag()->label('${item}')->color(Admin::setting()->get('system_theme_setting')['theme_color'] ?? '#1677ff')),
// amis()->TableColumn('tags', __('admin.articles.tags'))->type('mapping')->map(Keyword::tagsMap('article_tag')),
amis()->TableColumn('cover_url', __('admin.articles.cover'))->type('image')->height('50px')->width('50px')->enlargeAble(true),
amis()->TableColumn('published_at', __('admin.articles.published_at'))->remark(__('admin.articles.published_at_remark')),
@ -85,7 +83,7 @@ class ArticleController extends AdminController
amis()->Grid()->columns([
amis()->Wrapper()->body([
amis()->TextControl('title', __('admin.articles.title'))->required(true),
Components::make()->parentControl(admin_url('api/keywords/tree-list?parent_name=article_category&has_owner=0'), 'category', __('admin.articles.category'), 'name', 'key'),
// Components::make()->parentControl(admin_url('api/keywords/tree-list?parent_name=article_category&has_owner=0'), 'category', __('admin.articles.category'), 'name', 'key'),
// Components::make()->keywordsTagControl('t_ids', __('admin.articles.tags'), 'article_tag'),
Components::make()->cropImageControl('cover', __('admin.articles.cover')),
Components::make()->sortControl('sort', __('admin.articles.sort')),

View File

@ -0,0 +1,90 @@
<?php
namespace App\Admin\Controllers;
use Slowlyo\OwlAdmin\Renderers\Page;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use App\Services\Admin\ProjectArticleService;
use App\Traits\CustomActionTrait;
use App\Admin\Components;
use App\Models\{ProjectCate,ProjectArticle,Keyword};
/**
* 服务案例
*
* @property ProjectArticleService $service
*/
class CaseStudyController extends AdminController
{
use CustomActionTrait;
protected string $serviceName = ProjectArticleService::class;
public function list(): Page
{
$crud = $this->baseCRUD()->tableLayout('fixed')
->headerToolbar([
$this->createTypeButton('drawer', 'xl'),
...$this->baseHeaderToolBar(),
])
->filter($this->baseFilter()->body([
amis()->GroupControl()->mode('horizontal')->body([
// amis()->TextControl('id', __('admin.project_articles.id'))->columnRatio(3)
// ->placeholder(__('admin.id')),
amis()->TextControl('title', __('admin.project_articles.title'))->columnRatio(3)
->placeholder(__('admin.project_articles.title')),
// amis()->selectControl('cate', __('admin.project_articles.cate'))->options(ProjectCate::get()->pluck('title', 'id'))->columnRatio(3)
// ->placeholder(__('admin.project_articles.cate')),
Components::make()->keywordsTagControl('t_ids', __('admin.articles.tags'), 'case_study_tag')->columnRatio(3),
]),
]))
->columns([
// amis()->TableColumn('id', __('admin.id'))->sortable(true)->width('50px'),
amis()->TableColumn('title', __('admin.project_articles.title'))->width('300px'),
// amis()->TableColumn('cate', __('admin.project_articles.cate'))->type('mapping')
// ->map(ProjectCate::get()->pluck('title', 'id')->toArray())
// ->itemSchema(amis()->Tag()->label('${item}')->color(Admin::setting()->get('system_theme_setting')['theme_color'] ?? '#1677ff')),
amis()->TableColumn('tags', __('admin.project_articles.tags'))->type('mapping')->map(Keyword::tagsMap('case_study_tag')),
amis()->TableColumn('cover_url', __('admin.project_articles.cover'))->type('image')->height('50px')->width('150px')->enlargeAble(true),
// amis()->TableColumn('published_at', __('admin.project_articles.published_at'))->remark(__('admin.project_articles.published_at_remark')),
amis()->TableColumn('is_enable', __('admin.project_articles.is_enable'))->type('switch'),
// amis()->TableColumn('is_recommend', __('admin.articles.is_recommend'))->type('switch'),
amis()->TableColumn('created_at', __('admin.created_at'))->type('datetime')->sortable(true),
amis()->Operation()->label(__('admin.actions'))->buttons([
$this->rowEditTypeButton('drawer', 'xl'),
$this->rowDeleteButton(),
])
]);
return $this->baseList($crud);
}
public function form($isEdit = false): Form
{
return $this->baseForm()->panelClassName('px-0')->body([
amis()->Grid()->columns([
amis()->Wrapper()->body([
amis()->TextControl('title', __('admin.project_articles.title'))->required(true),
amis()->TextareaControl('description', __('admin.project_articles.description')),
// amis()->selectControl('cate', __('admin.project_articles.cate'))->options(ProjectCate::get()->pluck('title', 'id'))->required(true),
amis()->TextControl('type', __('admin.project_articles.type'))->value(ProjectArticle::TYPE_CASE_STUDY)->hidden(true),
Components::make()->keywordsTagControl('t_ids', __('admin.articles.tags'), 'case_study_tag')->required(true),
Components::make()->cropImageControl('cover', __('admin.project_articles.cover'), 0.775)->required(true),
Components::make()->sortControl('sort', __('admin.project_articles.sort')),
// amis()->DateTimeControl('published_at', __('admin.project_articles.published_at'))->format('YYYY-MM-DD HH:mm:ss')->description(__('admin.project_articles.published_at_remark')),
amis()->SwitchControl('is_enable', __('admin.project_articles.is_enable'))->value(false),
// amis()->SwitchControl('is_recommend', __('admin.project_articles.is_recommend'))->value(false),
// Components::make()->fileControl('appendixes', __('admin.articles.appendixes'), '.xsl,.xlsx,.txt,.doc,.docx,.pdf,.pptx'),
])->md(4),
amis()->Wrapper()->body([
Components::make()->fuEditorControl('content', __('admin.project_articles.content'))->required(true),
])->md(8)
]),
]);
}
public function detail(): Form
{
return $this->baseDetail()->body([]);
}
}

View File

@ -0,0 +1,74 @@
<?php
namespace App\Admin\Controllers;
use Slowlyo\OwlAdmin\Renderers\Page;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use App\Services\Admin\FriendLinkService;
use App\Traits\CustomActionTrait;
use App\Admin\Components;
/**
* 合作伙伴
*
* @property FriendLinkService $service
*/
class FriendLinkController extends AdminController
{
use CustomActionTrait;
protected string $serviceName = FriendLinkService::class;
public function list(): Page
{
$crud = $this->baseCRUD()->tableLayout('fixed')
->headerToolbar([
$this->createTypeButton('drawer', 'md'),
...$this->baseHeaderToolBar(),
])
->filter($this->baseFilter()->body([
amis()->GroupControl()->mode('horizontal')->body([
// amis()->TextControl('id', __('admin.friend_links.id'))->columnRatio(3)
// ->placeholder(__('admin.id')),
amis()->TextControl('title', __('admin.friend_links.title'))->columnRatio(3)
->placeholder(__('admin.friend_links.title')),
]),
]))
->columns([
amis()->TableColumn('id', 'ID')->sortable()->width('50px'),
amis()->TableColumn('title', __('admin.friend_links.title')),
amis()->TableColumn('link', __('admin.friend_links.link')),
amis()->TableColumn('cover_url', __('admin.friend_links.cover'))->type('image')->height('50px')->width('250px')->enlargeAble(true),
// amis()->TableColumn('description', __('admin.project_cates.description')),
amis()->TableColumn('is_enable', __('admin.friend_links.is_enable'))->type('switch'),
amis()->TableColumn('created_at', __('admin.created_at'))->set('type', 'datetime')->sortable()->width('150px'),
amis()->Operation()->label(__('admin.actions'))->buttons([
$this->rowEditTypeButton('drawer', 'md'),
$this->rowDeleteButton(),
])
]);
return $this->baseList($crud);
}
public function form($isEdit = false): Form
{
return $this->baseForm()->panelClassName('px-0')->body([
amis()->Grid()->columns([
amis()->Wrapper()->body([
amis()->TextControl('title', __('admin.friend_links.title'))->required(true),
amis()->TextControl('link', __('admin.friend_links.link'))->required(true),
Components::make()->cropImageControl('cover', __('admin.friend_links.cover'))->required(true),
amis()->TextareaControl('description', __('admin.friend_links.description')),
Components::make()->sortControl('sort', __('admin.friend_links.sort')),
amis()->SwitchControl('is_enable', __('admin.friend_links.is_enable'))->value(false),
])
]),
]);
}
public function detail(): Form
{
return $this->baseDetail()->body([]);
}
}

View File

@ -0,0 +1,95 @@
<?php
namespace App\Admin\Controllers;
use App\Casts\Storage;
use Slowlyo\OwlAdmin\Admin;
use Slowlyo\OwlAdmin\Renderers\Page;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use App\Services\Admin\HonorService;
use App\Admin\Components;
use App\Models\Keyword;
use App\Traits\CustomActionTrait;
class HonorController extends AdminController
{
use CustomActionTrait;
protected string $serviceName = HonorService::class;
public function list():Page
{
$crud = $this->baseCRUD()->tableLayout('fixed')
->headerToolbar([
$this->createTypeButton('drawer', 'md'),
...$this->baseHeaderToolBar(),
])
->filter($this->baseFilter()->body([
amis()->GroupControl()->mode('horizontal')->body([
amis()->TextControl('title', __('admin.honors.title'))
->placeholder(__('admin.honors.title')),
amis()->selectControl('cate', __('admin.honors.category'))->options(Keyword::allChildrenOfKey('honors')->pluck('name', 'id'))
->placeholder(__('admin.honors.category')),
amis()->SelectControl('enable', __('admin.honors.is_enable'))
->columnRatio(3)
->options([
1=>'开启',0=>'关闭'
]),
amis()->SelectControl('recommend', __('admin.honors.is_recommend'))
->columnRatio(3)
->options([
1=>'开启',0=>'关闭'
]),
]),
]))
->itemBadge([//行角标
'text' => __('admin.honors.is_recommend'),
'mode' => 'ribbon',
'position' => 'top-left',
'badgeLevel' => 'danger',
'visibleOn' => '${is_recommend > 0}',
'size' => 15
])
->columns([
amis()->TableColumn('id', __('admin.id'))->sortable(true),
amis()->TableColumn('title', __('admin.honors.title'))->width('300px'),
amis()->TableColumn('category', __('admin.honors.category'))->type('mapping')
->map(Keyword::allChildrenOfKey('honors')->pluck('name', 'id')->toArray())
->itemSchema(amis()->Tag()->label('${item}')->color(Admin::setting()->get('system_theme_setting')['theme_color'] ?? '#1677ff')),
amis()->TableColumn('cover_url', __('admin.articles.cover'))->type('image')->height('50px')->width('50px')->enlargeAble(true),
amis()->TableColumn('awarded_date', __('admin.honors.awarded_date')),
amis()->TableColumn('is_enable', __('admin.honors.is_enable'))->type('switch'),
amis()->TableColumn('is_recommend', __('admin.honors.is_recommend'))->type('switch'),
amis()->TableColumn('created_at', __('admin.created_at'))->type('datetime')->sortable(true),
amis()->Operation()->label(__('admin.actions'))->buttons([
$this->rowEditTypeButton('drawer', 'md'),
$this->rowDeleteButton(),
])
]);
return $this->baseList($crud);
}
public function form(): Form
{
return $this->baseForm()->panelClassName('px-0')->body([
amis()->Grid()->columns([
amis()->Wrapper()->body([
amis()->TextControl('title', __('admin.honors.title'))->required(true),
amis()->selectControl('cate', __('admin.honors.category'))->options(Keyword::allChildrenOfKey('honors')->pluck('name', 'id'))->required(true),
Components::make()->cropImageControl('cover', __('admin.honors.cover'))->required(true),
amis()->DateControl('awarded_date', __('admin.honors.awarded_date'))->format('YYYY-MM-DD')->required(true),
Components::make()->sortControl('sort', __('admin.honors.sort')),
amis()->SwitchControl('is_enable', __('admin.honors.is_enable'))->value(false),
amis()->SwitchControl('is_recommend', __('admin.honors.is_recommend'))->value(false),
]),
]),
]);
}
public function detail(): Form
{
return $this->baseDetail()->body([]);
}
}

View File

@ -0,0 +1,90 @@
<?php
namespace App\Admin\Controllers;
use Slowlyo\OwlAdmin\Renderers\Page;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use App\Services\Admin\ProjectArticleService;
use App\Traits\CustomActionTrait;
use App\Admin\Components;
use App\Models\{ProjectArticle,ProjectCate};
use Slowlyo\OwlAdmin\Admin;
/**
* 核心优势
*
* @property ProjectArticleService $service
*/
class ProjectAdvanceController extends AdminController
{
use CustomActionTrait;
protected string $serviceName = ProjectArticleService::class;
public function list(): Page
{
$crud = $this->baseCRUD()->tableLayout('fixed')
->headerToolbar([
$this->createTypeButton('drawer', 'md'),
...$this->baseHeaderToolBar(),
])
->filter($this->baseFilter()->body([
amis()->GroupControl()->mode('horizontal')->body([
// amis()->TextControl('id', __('admin.project_articles.id'))->columnRatio(3)
// ->placeholder(__('admin.id')),
amis()->TextControl('title', __('admin.project_articles.title'))->columnRatio(3)
->placeholder(__('admin.project_articles.title')),
amis()->selectControl('cate', __('admin.project_articles.cate'))->options(ProjectCate::get()->pluck('title', 'id'))->columnRatio(3)
->placeholder(__('admin.project_articles.cate')),
]),
]))
->columns([
// amis()->TableColumn('id', __('admin.id'))->sortable(true)->width('50px'),
amis()->TableColumn('title', __('admin.project_articles.title'))->width('300px'),
amis()->TableColumn('cate', __('admin.project_articles.cate'))->type('mapping')
->map(ProjectCate::get()->pluck('title', 'id')->toArray())
->itemSchema(amis()->Tag()->label('${item}')->color(Admin::setting()->get('system_theme_setting')['theme_color'] ?? '#1677ff')),
// amis()->TableColumn('tags', __('admin.articles.tags'))->type('mapping')->map(Keyword::tagsMap('article_tag')),
amis()->TableColumn('cover_url', __('admin.project_articles.cover'))->type('image')->height('50px')->width('150px')->enlargeAble(true),
// amis()->TableColumn('published_at', __('admin.project_articles.published_at'))->remark(__('admin.project_articles.published_at_remark')),
amis()->TableColumn('is_enable', __('admin.project_articles.is_enable'))->type('switch'),
// amis()->TableColumn('is_recommend', __('admin.articles.is_recommend'))->type('switch'),
amis()->TableColumn('created_at', __('admin.created_at'))->type('datetime')->sortable(true),
amis()->Operation()->label(__('admin.actions'))->buttons([
$this->rowEditTypeButton('drawer', 'md'),
$this->rowDeleteButton(),
])
]);
return $this->baseList($crud);
}
public function form($isEdit = false): Form
{
return $this->baseForm()->panelClassName('px-0')->body([
amis()->Grid()->columns([
amis()->Wrapper()->body([
amis()->TextControl('title', __('admin.project_articles.title'))->required(true),
amis()->TextareaControl('description', __('admin.project_articles.description')),
amis()->selectControl('cate', __('admin.project_articles.cate'))->options(ProjectCate::get()->pluck('title', 'id'))->required(true),
amis()->TextControl('type', __('admin.project_articles.type'))->value(ProjectArticle::TYPE_ADVANCE)->hidden(true),
// Components::make()->keywordsTagControl('t_ids', __('admin.articles.tags'), 'article_tag'),
Components::make()->cropImageControl('cover', __('admin.project_articles.cover'))->required(true),
Components::make()->sortControl('sort', __('admin.project_articles.sort')),
// amis()->DateTimeControl('published_at', __('admin.project_articles.published_at'))->format('YYYY-MM-DD HH:mm:ss')->description(__('admin.project_articles.published_at_remark')),
amis()->SwitchControl('is_enable', __('admin.project_articles.is_enable'))->value(false),
// amis()->SwitchControl('is_recommend', __('admin.project_articles.is_recommend'))->value(false),
// Components::make()->fileControl('appendixes', __('admin.articles.appendixes'), '.png,.jpg')->multiple(true),
])
// amis()->Wrapper()->body([
// Components::make()->fuEditorControl('content', __('admin.project_articles.content'))->required(true),
// ])->md(8)
]),
]);
}
public function detail(): Form
{
return $this->baseDetail()->body([]);
}
}

View File

@ -0,0 +1,90 @@
<?php
namespace App\Admin\Controllers;
use Slowlyo\OwlAdmin\Renderers\Page;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use App\Services\Admin\ProjectArticleService;
use App\Traits\CustomActionTrait;
use App\Admin\Components;
use App\Models\{ProjectCate,ProjectArticle};
use Slowlyo\OwlAdmin\Admin;
/**
* 业务内容
*
* @property ProjectArticleService $service
*/
class ProjectArticleController extends AdminController
{
use CustomActionTrait;
protected string $serviceName = ProjectArticleService::class;
public function list(): Page
{
$crud = $this->baseCRUD()->tableLayout('fixed')
->headerToolbar([
$this->createTypeButton('drawer', 'xl'),
...$this->baseHeaderToolBar(),
])
->filter($this->baseFilter()->body([
amis()->GroupControl()->mode('horizontal')->body([
// amis()->TextControl('id', __('admin.project_articles.id'))->columnRatio(3)
// ->placeholder(__('admin.id')),
amis()->TextControl('title', __('admin.project_articles.title'))->columnRatio(3)
->placeholder(__('admin.project_articles.title')),
amis()->selectControl('cate', __('admin.project_articles.cate'))->options(ProjectCate::get()->pluck('title', 'id'))->columnRatio(3)
->placeholder(__('admin.project_articles.cate')),
]),
]))
->columns([
// amis()->TableColumn('id', __('admin.id'))->sortable(true)->width('50px'),
amis()->TableColumn('title', __('admin.project_articles.title'))->width('300px'),
amis()->TableColumn('cate', __('admin.project_articles.cate'))->type('mapping')
->map(ProjectCate::get()->pluck('title', 'id')->toArray())
->itemSchema(amis()->Tag()->label('${item}')->color(Admin::setting()->get('system_theme_setting')['theme_color'] ?? '#1677ff')),
// amis()->TableColumn('tags', __('admin.articles.tags'))->type('mapping')->map(Keyword::tagsMap('article_tag')),
amis()->TableColumn('cover_url', __('admin.project_articles.cover'))->type('image')->height('50px')->width('150px')->enlargeAble(true),
// amis()->TableColumn('published_at', __('admin.project_articles.published_at'))->remark(__('admin.project_articles.published_at_remark')),
amis()->TableColumn('is_enable', __('admin.project_articles.is_enable'))->type('switch'),
// amis()->TableColumn('is_recommend', __('admin.articles.is_recommend'))->type('switch'),
amis()->TableColumn('created_at', __('admin.created_at'))->type('datetime')->sortable(true),
amis()->Operation()->label(__('admin.actions'))->buttons([
$this->rowEditTypeButton('drawer', 'xl'),
$this->rowDeleteButton(),
])
]);
return $this->baseList($crud);
}
public function form($isEdit = false): Form
{
return $this->baseForm()->panelClassName('px-0')->body([
amis()->Grid()->columns([
amis()->Wrapper()->body([
amis()->TextControl('title', __('admin.project_articles.title'))->required(true),
amis()->TextareaControl('description', __('admin.project_articles.description')),
amis()->selectControl('cate', __('admin.project_articles.cate'))->options(ProjectCate::get()->pluck('title', 'id'))->required(true),
amis()->TextControl('type', __('admin.project_articles.type'))->value(ProjectArticle::TYPE_ARTICLE)->hidden(true),
// Components::make()->keywordsTagControl('t_ids', __('admin.articles.tags'), 'article_tag'),
Components::make()->cropImageControl('cover', __('admin.project_articles.cover'), 0.775)->required(true),
Components::make()->sortControl('sort', __('admin.project_articles.sort')),
// amis()->DateTimeControl('published_at', __('admin.project_articles.published_at'))->format('YYYY-MM-DD HH:mm:ss')->description(__('admin.project_articles.published_at_remark')),
amis()->SwitchControl('is_enable', __('admin.project_articles.is_enable'))->value(false),
// amis()->SwitchControl('is_recommend', __('admin.project_articles.is_recommend'))->value(false),
// Components::make()->fileControl('appendixes', __('admin.articles.appendixes'), '.xsl,.xlsx,.txt,.doc,.docx,.pdf,.pptx'),
])->md(4),
amis()->Wrapper()->body([
Components::make()->fuEditorControl('content', __('admin.project_articles.content'))->required(true),
])->md(8)
]),
]);
}
public function detail(): Form
{
return $this->baseDetail()->body([]);
}
}

View File

@ -0,0 +1,72 @@
<?php
namespace App\Admin\Controllers;
use Slowlyo\OwlAdmin\Renderers\Page;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use App\Services\Admin\ProjectCateService;
use App\Traits\CustomActionTrait;
use App\Admin\Components;
/**
* 业务范围
*
* @property ProjectCateService $service
*/
class ProjectCateController extends AdminController
{
use CustomActionTrait;
protected string $serviceName = ProjectCateService::class;
public function list(): Page
{
$crud = $this->baseCRUD()->tableLayout('fixed')
->headerToolbar([
$this->createTypeButton('drawer', 'md'),
...$this->baseHeaderToolBar(),
])
->filter($this->baseFilter()->body([
amis()->GroupControl()->mode('horizontal')->body([
// amis()->TextControl('id', __('admin.project_cates.id'))->columnRatio(3)
// ->placeholder(__('admin.id')),
amis()->TextControl('title', __('admin.project_cates.title'))->columnRatio(3)
->placeholder(__('admin.project_cates.title')),
]),
]))
->columns([
amis()->TableColumn('id', 'ID')->sortable()->width('50px'),
amis()->TableColumn('title', __('admin.project_cates.title')),
amis()->TableColumn('cover_url', __('admin.project_cates.cover'))->type('image')->height('50px')->width('250px')->enlargeAble(true),
// amis()->TableColumn('description', __('admin.project_cates.description')),
amis()->TableColumn('is_enable', __('admin.project_cates.is_enable'))->type('switch'),
amis()->TableColumn('created_at', __('admin.created_at'))->set('type', 'datetime')->sortable()->width('150px'),
amis()->Operation()->label(__('admin.actions'))->buttons([
$this->rowEditTypeButton('drawer', 'md'),
$this->rowDeleteButton(),
])
]);
return $this->baseList($crud);
}
public function form($isEdit = false): Form
{
return $this->baseForm()->panelClassName('px-0')->body([
amis()->Grid()->columns([
amis()->Wrapper()->body([
amis()->TextControl('title', __('admin.project_cates.title'))->required(true),
Components::make()->cropImageControl('cover', __('admin.project_cates.cover'), 1.68)->required(true),
amis()->TextareaControl('description', __('admin.project_cates.description')),
Components::make()->sortControl('sort', __('admin.project_cates.sort')),
amis()->SwitchControl('is_enable', __('admin.project_cates.is_enable'))->value(false),
])
]),
]);
}
public function detail(): Form
{
return $this->baseDetail()->body([]);
}
}

View File

@ -0,0 +1,90 @@
<?php
namespace App\Admin\Controllers;
use Slowlyo\OwlAdmin\Renderers\Page;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use App\Services\Admin\ProjectArticleService;
use App\Traits\CustomActionTrait;
use App\Admin\Components;
use App\Models\{ProjectArticle,ProjectCate};
use Slowlyo\OwlAdmin\Admin;
/**
* 服务流程
*
* @property ProjectArticleService $service
*/
class ProjectFlowController extends AdminController
{
use CustomActionTrait;
protected string $serviceName = ProjectArticleService::class;
public function list(): Page
{
$crud = $this->baseCRUD()->tableLayout('fixed')
->headerToolbar([
$this->createTypeButton('drawer', 'md'),
...$this->baseHeaderToolBar(),
])
->filter($this->baseFilter()->body([
amis()->GroupControl()->mode('horizontal')->body([
// amis()->TextControl('id', __('admin.project_articles.id'))->columnRatio(3)
// ->placeholder(__('admin.id')),
amis()->TextControl('title', __('admin.project_articles.title'))->columnRatio(3)
->placeholder(__('admin.project_articles.title')),
amis()->selectControl('cate', __('admin.project_articles.cate'))->options(ProjectCate::get()->pluck('title', 'id'))->columnRatio(3)
->placeholder(__('admin.project_articles.cate')),
]),
]))
->columns([
// amis()->TableColumn('id', __('admin.id'))->sortable(true)->width('50px'),
amis()->TableColumn('title', __('admin.project_articles.title'))->width('300px'),
amis()->TableColumn('cate', __('admin.project_articles.cate'))->type('mapping')
->map(ProjectCate::get()->pluck('title', 'id')->toArray())
->itemSchema(amis()->Tag()->label('${item}')->color(Admin::setting()->get('system_theme_setting')['theme_color'] ?? '#1677ff')),
// amis()->TableColumn('tags', __('admin.articles.tags'))->type('mapping')->map(Keyword::tagsMap('article_tag')),
amis()->TableColumn('cover_url', __('admin.project_articles.cover'))->type('image')->height('50px')->width('150px')->enlargeAble(true),
// amis()->TableColumn('published_at', __('admin.project_articles.published_at'))->remark(__('admin.project_articles.published_at_remark')),
amis()->TableColumn('is_enable', __('admin.project_articles.is_enable'))->type('switch'),
// amis()->TableColumn('is_recommend', __('admin.articles.is_recommend'))->type('switch'),
amis()->TableColumn('created_at', __('admin.created_at'))->type('datetime')->sortable(true),
amis()->Operation()->label(__('admin.actions'))->buttons([
$this->rowEditTypeButton('drawer', 'md'),
$this->rowDeleteButton(),
])
]);
return $this->baseList($crud);
}
public function form($isEdit = false): Form
{
return $this->baseForm()->panelClassName('px-0')->body([
amis()->Grid()->columns([
amis()->Wrapper()->body([
amis()->TextControl('title', __('admin.project_articles.title'))->required(true),
// amis()->TextareaControl('description', __('admin.project_articles.description')),
amis()->selectControl('cate', __('admin.project_articles.cate'))->options(ProjectCate::get()->pluck('title', 'id'))->required(true),
amis()->TextControl('type', __('admin.project_articles.type'))->value(ProjectArticle::TYPE_FLOW)->hidden(true),
// Components::make()->keywordsTagControl('t_ids', __('admin.articles.tags'), 'article_tag'),
Components::make()->imageControl('cover', __('admin.project_articles.cover'))->required(true),
Components::make()->sortControl('sort', __('admin.project_articles.sort')),
// amis()->DateTimeControl('published_at', __('admin.project_articles.published_at'))->format('YYYY-MM-DD HH:mm:ss')->description(__('admin.project_articles.published_at_remark')),
amis()->SwitchControl('is_enable', __('admin.project_articles.is_enable'))->value(false),
// amis()->SwitchControl('is_recommend', __('admin.project_articles.is_recommend'))->value(false),
// Components::make()->fileControl('appendixes', __('admin.articles.appendixes'), '.xsl,.xlsx,.txt,.doc,.docx,.pdf,.pptx'),
])
// amis()->Wrapper()->body([
// Components::make()->fuEditorControl('content', __('admin.project_articles.content'))->required(true),
// ])->md(8)
]),
]);
}
public function detail(): Form
{
return $this->baseDetail()->body([]);
}
}

View File

@ -0,0 +1,90 @@
<?php
namespace App\Admin\Controllers;
use Slowlyo\OwlAdmin\Renderers\Page;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use App\Services\Admin\ProjectArticleService;
use App\Traits\CustomActionTrait;
use App\Admin\Components;
use App\Models\{ProjectArticle,ProjectCate};
use Slowlyo\OwlAdmin\Admin;
/**
* 服务流程
*
* @property ProjectArticleService $service
*/
class ProjectPhotoController extends AdminController
{
use CustomActionTrait;
protected string $serviceName = ProjectArticleService::class;
public function list(): Page
{
$crud = $this->baseCRUD()->tableLayout('fixed')
->headerToolbar([
$this->createTypeButton('drawer', 'md'),
...$this->baseHeaderToolBar(),
])
->filter($this->baseFilter()->body([
amis()->GroupControl()->mode('horizontal')->body([
// amis()->TextControl('id', __('admin.project_articles.id'))->columnRatio(3)
// ->placeholder(__('admin.id')),
amis()->TextControl('title', __('admin.project_articles.title'))->columnRatio(3)
->placeholder(__('admin.project_articles.title')),
amis()->selectControl('cate', __('admin.project_articles.cate'))->options(ProjectCate::get()->pluck('title', 'id'))->columnRatio(3)
->placeholder(__('admin.project_articles.cate')),
]),
]))
->columns([
// amis()->TableColumn('id', __('admin.id'))->sortable(true)->width('50px'),
amis()->TableColumn('title', __('admin.project_articles.title'))->width('300px'),
amis()->TableColumn('cate', __('admin.project_articles.cate'))->type('mapping')
->map(ProjectCate::get()->pluck('title', 'id')->toArray())
->itemSchema(amis()->Tag()->label('${item}')->color(Admin::setting()->get('system_theme_setting')['theme_color'] ?? '#1677ff')),
// amis()->TableColumn('tags', __('admin.articles.tags'))->type('mapping')->map(Keyword::tagsMap('article_tag')),
amis()->TableColumn('cover_url', __('admin.project_articles.cover'))->type('image')->height('50px')->width('150px')->enlargeAble(true),
// amis()->TableColumn('published_at', __('admin.project_articles.published_at'))->remark(__('admin.project_articles.published_at_remark')),
amis()->TableColumn('is_enable', __('admin.project_articles.is_enable'))->type('switch'),
// amis()->TableColumn('is_recommend', __('admin.articles.is_recommend'))->type('switch'),
amis()->TableColumn('created_at', __('admin.created_at'))->type('datetime')->sortable(true),
amis()->Operation()->label(__('admin.actions'))->buttons([
$this->rowEditTypeButton('drawer', 'md'),
$this->rowDeleteButton(),
])
]);
return $this->baseList($crud);
}
public function form($isEdit = false): Form
{
return $this->baseForm()->panelClassName('px-0')->body([
amis()->Grid()->columns([
amis()->Wrapper()->body([
amis()->TextControl('title', __('admin.project_articles.title'))->required(true),
// amis()->TextareaControl('description', __('admin.project_articles.description')),
amis()->selectControl('cate', __('admin.project_articles.cate'))->options(ProjectCate::get()->pluck('title', 'id'))->required(true),
amis()->TextControl('type', __('admin.project_articles.type'))->value(ProjectArticle::TYPE_PHOTO)->hidden(true),
// Components::make()->keywordsTagControl('t_ids', __('admin.articles.tags'), 'article_tag'),
Components::make()->cropImageControl('cover', __('admin.project_articles.cover'), 1.67)->required(true),
Components::make()->sortControl('sort', __('admin.project_articles.sort')),
// amis()->DateTimeControl('published_at', __('admin.project_articles.published_at'))->format('YYYY-MM-DD HH:mm:ss')->description(__('admin.project_articles.published_at_remark')),
amis()->SwitchControl('is_enable', __('admin.project_articles.is_enable'))->value(false),
// amis()->SwitchControl('is_recommend', __('admin.project_articles.is_recommend'))->value(false),
// Components::make()->fileControl('appendixes', __('admin.articles.appendixes'), '.png,.jpg')->multiple(true),
])
// amis()->Wrapper()->body([
// Components::make()->fuEditorControl('content', __('admin.project_articles.content'))->required(true),
// ])->md(8)
]),
]);
}
public function detail(): Form
{
return $this->baseDetail()->body([]);
}
}

View File

@ -0,0 +1,72 @@
<?php
namespace App\Admin\Controllers;
use Slowlyo\OwlAdmin\Renderers\Page;
use Slowlyo\OwlAdmin\Renderers\Form;
use Slowlyo\OwlAdmin\Controllers\AdminController;
use App\Services\Admin\TimelineService;
use App\Traits\CustomActionTrait;
use App\Admin\Components;
use Slowlyo\OwlAdmin\Admin;
/**
* 发展历程
*
* @property ProjectArticleService $service
*/
class TimelineController extends AdminController
{
use CustomActionTrait;
protected string $serviceName = TimelineService::class;
public function list(): Page
{
$crud = $this->baseCRUD()->tableLayout('fixed')
->headerToolbar([
$this->createTypeButton('drawer', 'md'),
...$this->baseHeaderToolBar(),
])
->filter($this->baseFilter()->body([
amis()->GroupControl()->mode('horizontal')->body([
amis()->TextControl('title', __('admin.timelines.title'))->columnRatio(3)
->placeholder(__('admin.timelines.title')),
]),
]))
->columns([
// amis()->TableColumn('id', __('admin.id'))->sortable(true)->width('50px'),
amis()->TableColumn('title', __('admin.timelines.title'))->width('300px'),
amis()->TableColumn('cover_url', __('admin.timelines.cover'))->type('image')->height('50px')->width('150px')->enlargeAble(true),
amis()->TableColumn('awarded_date', __('admin.timelines.awarded_date')),
amis()->TableColumn('is_enable', __('admin.timelines.is_enable'))->type('switch'),
amis()->TableColumn('created_at', __('admin.created_at'))->type('datetime')->sortable(true),
amis()->Operation()->label(__('admin.actions'))->buttons([
$this->rowEditTypeButton('drawer', 'md'),
$this->rowDeleteButton(),
])
]);
return $this->baseList($crud);
}
public function form($isEdit = false): Form
{
return $this->baseForm()->panelClassName('px-0')->body([
amis()->Grid()->columns([
amis()->Wrapper()->body([
amis()->TextControl('title', __('admin.timelines.title'))->required(true),
amis()->TextareaControl('description', __('admin.timelines.description')),
Components::make()->cropImageControl('cover', __('admin.timelines.cover')),
amis()->DateControl('awarded_date', __('admin.timelines.awarded_date'))->format('YYYY-MM-DD')->required(true),
Components::make()->sortControl('sort', __('admin.timelines.sort')),
amis()->SwitchControl('is_enable', __('admin.timelines.is_enable'))->value(false),
])
]),
]);
}
public function detail(): Form
{
return $this->baseDetail()->body([]);
}
}

View File

@ -32,6 +32,17 @@ Route::group([
$router->resource('ads', \App\Admin\Controllers\AdController::class);
//新站调整;
$router->resource('project_cates', \App\Admin\Controllers\ProjectCateController::class);
$router->resource('project_articles', \App\Admin\Controllers\ProjectArticleController::class);
$router->resource('project_flows', \App\Admin\Controllers\ProjectFlowController::class);
$router->resource('project_photos', \App\Admin\Controllers\ProjectPhotoController::class);
$router->resource('project_advances', \App\Admin\Controllers\ProjectAdvanceController::class);
$router->resource('case_studies', \App\Admin\Controllers\CaseStudyController::class);
$router->resource('friend_links', \App\Admin\Controllers\FriendLinkController::class);
$router->resource('honors', \App\Admin\Controllers\HonorController::class);
$router->resource('timelines', \App\Admin\Controllers\TimelineController::class);
//修改上传
$router->post('upload_file', [\App\Admin\Controllers\IndexController::class, 'uploadFile']);
$router->post('upload_image', [\App\Admin\Controllers\IndexController::class, 'uploadImage']);

View File

@ -0,0 +1,42 @@
<?php
namespace App\Exceptions;
use Exception;
class BizException extends Exception
{
public function __construct(string $message, int $code = 400)
{
parent::__construct($message, $code);
}
/**
* 用于响应的 HTTP 状态代码
*
* @var int
*/
public $status = 200;
/**
* 设置用于响应的 HTTP 状态代码
*
* @param int $status
* @return $this
*/
public function status(int $status)
{
$this->status = $status;
return $this;
}
/**
* 报告异常
*
* @return mixed
*/
public function report()
{
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Traits\PaginatorTrait;
use App\Models\Ad;
use App\Models\Filters\AdFilter;
use App\Http\Resources\AdResource;
class AdController extends Controller
{
use PaginatorTrait;
public function index(Request $request){
$query = Ad::filter($request->all(), AdFilter::class)->sort();
$list = $query->show()->sort()->paginate($this->resolvePerPage('per_page', 20));
return $this->json(AdResource::collection($list));
}
}

View File

@ -0,0 +1,72 @@
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Services\CaptchaService;
use Gregwar\Captcha\CaptchaBuilder;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
class CaptchaController extends Controller
{
/**
* 创建图形验证码
*/
public function store(Request $request, CaptchaService $captchaService)
{
$request->validate([
'key' => ['bail', 'filled', 'string', 'max:32'],
'w' => ['bail', 'int'],
'h' => ['bail', 'int'],
]);
$builder = $this->builder();
$builder->build($request->input('w', 150), $request->input('h', 40));
$captchaService->put(
$key = $request->input('key', Str::random(16)),
$builder->getPhrase()
);
return response()->json([
'key' => $key,
'img' => $builder->inline(),
]);
}
/**
* 查看图形验证码
*
* @param string $key
* @param \Illuminate\Http\Request $request
* @param \App\Services\CaptchaService $captchaService
* @return \Illuminate\Http\Response
*/
public function show($key, Request $request, CaptchaService $captchaService)
{
$builder = $this->builder();
$builder->build(
(int) $request->query('w', 150),
(int) $request->query('h', 40),
);
if (strlen($key) <= 32) {
$captchaService->put($key, $builder->getPhrase());
}
return response($builder->get())
->header('Content-Type', 'image/jpeg')
->header('Cache-Control', 'no-cache');
}
/**
* 图形验证码生成器
*
* @return \Gregwar\Captcha\CaptchaBuilder
*/
protected function builder(): CaptchaBuilder
{
return new CaptchaBuilder(Str::random(5));
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Http\Resources\{CaseStudyResource,KeywordResource};
use App\Traits\PaginatorTrait;
use App\Models\ProjectArticle;
use App\Models\Filters\ProjectArticleFilter;
use App\Models\Keyword;
class CaseStudyController extends Controller
{
use PaginatorTrait;
public function index(Request $request){
$query = ProjectArticle::filter($request->all(), ProjectArticleFilter::class)->sort();
$list = $query->caseStudies()->show()->sort()->paginate($this->resolvePerPage('per_page', 20));
return $this->json(CaseStudyResource::collection($list));
}
public function show(ProjectArticle $caseStudy){
request()->merge(['include_content' => true]);
return $this->json(CaseStudyResource::make($caseStudy));
}
/**
* 标签列表
*/
public function tags(Request $request){
$query = Keyword::allChildrenOfKey('case_study_tag');
$list = $query->sort()->get();
return $this->json(KeywordResource::collection($list));
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Traits\PaginatorTrait;
use App\Models\FriendLink;
use App\Models\Filters\FriendLinkFilter;
use App\Http\Resources\FriendLinkResource;
class FriendLinkController extends Controller
{
use PaginatorTrait;
public function index(Request $request){
$query = FriendLink::filter($request->all(), FriendLinkFilter::class)->sort();
$list = $query->show()->sort()->paginate($this->resolvePerPage('per_page', 20));
return $this->json(FriendLinkResource::collection($list));
}
}

View File

@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Traits\PaginatorTrait;
use App\Models\Filters\ProjectArticleFilter;
use App\Http\Resources\ProjectChildrenResource;
use App\Models\ProjectArticle;
class ProjectChildrenController extends Controller
{
use PaginatorTrait;
public function show(ProjectArticle $child){
request()->merge(['include_content' => true]);
return $this->json(ProjectChildrenResource::make($child));
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\Traits\PaginatorTrait;
use App\Models\ProjectCate;
use App\Models\Filters\ProjectCateFilter;
use App\Http\Resources\ProjectResource;
use App\Models\ProjectArticle;
class ProjectController extends Controller
{
use PaginatorTrait;
public function index(Request $request)
{
$query = ProjectCate::filter($request->all(), ProjectCateFilter::class)->sort();
$list = $query->show()->sort()->paginate($this->resolvePerPage('per_page', 20));
return $this->json(ProjectResource::collection($list));
}
public function show(ProjectCate $projectCate, Request $request)
{
$projectCate->load(['children', 'flows', 'photos', 'advances']);
return $this->json(ProjectResource::make($projectCate));
}
}

View File

@ -2,11 +2,13 @@
namespace App\Http\Controllers;
use App\Traits\JsonResponse;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
use AuthorizesRequests, ValidatesRequests;
use AuthorizesRequests, DispatchesJobs, ValidatesRequests, JsonResponse;
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class AdResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'resource_url' => $this->resource_url,
'jump_type' => $this->jump_type,
'jump_config' => $this->jump_config,
];
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\Http\Resources;
use App\Models\Keyword;
use Illuminate\Http\Resources\Json\JsonResource;
class CaseStudyResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'cover' => $this->cover,
'description' => $this->description,
'tags' => KeywordResource::collection(Keyword::whereIn('id', $this->tags)->get()),
'content' => $this->when($request->boolean('include_content'), $this->content),
];
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class FriendLinkResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'title' => $this->title,
'cover' => $this->cover,
'link' => $this->link,
];
}
}

View File

@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class KeywordResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'key' => $this->key,
'value' => $this->value,
];
}
}

View File

@ -0,0 +1,22 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ProjectAdvanceResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'title' => $this->title,
'cover' => $this->cover,
'description' => $this->description,
];
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ProjectChildrenResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'cover' => $this->cover,
'description' => $this->description,
'content' => $this->when($request->boolean('include_content'), $this->content),
];
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ProjectFlowResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'title' => $this->title,
'cover' => $this->cover,
];
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ProjectPhotoResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'title' => $this->title,
'cover' => $this->cover,
];
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class ProjectResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array|\Illuminate\Contracts\Support\Arrayable|\JsonSerializable
*/
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'cover' => $this->cover,
'children' => ProjectChildrenResource::collection($this->whenLoaded('children')),
'flows' => ProjectFlowResource::make($this->whenLoaded('flows')),
'photos' => ProjectPhotoResource::collection($this->whenLoaded('photos')),
'advances' => ProjectAdvanceResource::collection($this->whenLoaded('advances')),
];
}
}

View File

@ -49,8 +49,8 @@ class Ad extends Model
{
return [
self::TYPE_WEB => '网页跳转',
self::TYPE_APP => '应用跳转',
self::TYPE_MINI => '小程序跳转',
// self::TYPE_APP => '应用跳转',
// self::TYPE_MINI => '小程序跳转',
self::TYPE_OFF => '无跳转',
];
}

View File

@ -0,0 +1,11 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Contact extends Model
{
use HasFactory;
}

View File

@ -0,0 +1,24 @@
<?php
namespace App\Models\Filters;
use EloquentFilter\ModelFilter;
use Illuminate\Support\Arr;
class FriendLinkFilter extends ModelFilter
{
/**
* 主键
*/
public function id($id)
{
return $this->where('id', $id);
}
/**
* 标题
*/
public function title($title)
{
return $this->where('title','like', '%'.$title.'%');
}
}

View File

@ -0,0 +1,40 @@
<?php
namespace App\Models\Filters;
use Illuminate\Support\Arr;
use EloquentFilter\ModelFilter;
class HonorFilter extends ModelFilter
{
/**
* 主键
*/
public function id($id)
{
return $this->where('id', $id);
}
/**
* 标题
*/
public function title($title)
{
return $this->where('title','like', '%'.$title.'%');
}
/**
* 获取分类下的荣誉
*/
public function category($category)
{
return $this->where('category', $category);
}
public function enable($enable){
return $this->where('is_enable', $enable);
}
public function recommend($recommend){
return $this->where('is_recommend', $recommend);
}
}

View File

@ -0,0 +1,77 @@
<?php
namespace App\Models\Filters;
use EloquentFilter\ModelFilter;
use Illuminate\Support\Arr;
class ProjectArticleFilter extends ModelFilter
{
/**
* 主键
*/
public function id($id)
{
return $this->where('id', $id);
}
/**
* 标题
*/
public function title($title)
{
return $this->where('title','like', '%'.$title.'%');
}
/**
* 类型
*/
public function type($type)
{
return $this->where('type', $type);
}
public function tIds($tIds){
$tIds = explode(',',$tIds);
return $this->where(function($q) use ($tIds) {
foreach ($tIds as $tId) {
$q->whereRaw("FIND_IN_SET('".$tId."',t_ids)");
}
});
}
public function publishedAt($publishedAt){
$publishedAt = explode(',',$publishedAt);
return $this->where(function($q) use ($publishedAt) {
$startAt = Arr::get($publishedAt, 0) ?? null;
$endAt = Arr::get($publishedAt, 1) ?? null;
if(!empty($startAt)){
$q->where('published_at', '>=', $startAt);
}
if(!empty($endAt)){
$q->where('published_at', '<=', $endAt);
}
});
}
public function createdAt($createdAt){
$createdAt = explode(',',$createdAt);
return $this->where(function($q) use ($createdAt) {
$startAt = Arr::get($createdAt, 0) ?? null;
$endAt = Arr::get($createdAt, 1) ?? null;
if(!empty($startAt)){
$q->where('created_at', '>=', $startAt);
}
if(!empty($endAt)){
$q->where('created_at', '<=', $endAt);
}
});
}
public function enable($enable){
return $this->where('is_enable', $enable);
}
public function recommend($recommend){
return $this->where('is_recommend', $recommend);
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace App\Models\Filters;
use EloquentFilter\ModelFilter;
use Illuminate\Support\Arr;
class ProjectCateFilter extends ModelFilter
{
/**
* 主键
*/
public function id($id)
{
return $this->where('id', $id);
}
/**
* 标题
*/
public function title($title)
{
return $this->where('title','like', '%'.$title.'%');
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Models\Filters;
use Illuminate\Support\Arr;
use EloquentFilter\ModelFilter;
class TimelineFilter extends ModelFilter
{
/**
* 主键
*/
public function id($id)
{
return $this->where('id', $id);
}
/**
* 标题
*/
public function title($title)
{
return $this->where('title','like', '%'.$title.'%');
}
public function enable($enable){
return $this->where('is_enable', $enable);
}
}

View File

@ -0,0 +1,45 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use EloquentFilter\Filterable;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Storage;
class FriendLink extends Model
{
use HasFactory;
use Filterable;
protected $appends = ['cover_url'];
protected function serializeDate(\DateTimeInterface $date)
{
return $date->format('Y-m-d H:i:s');
}
protected $casts = [
'created_at' => 'datetime:Y-m-d H:i:s',
'updated_at' => 'datetime:Y-m-d H:i:s',
];
protected function coverUrl():Attribute {
return Attribute::make(
get: fn($value) => $this->cover ? (Str::startsWith($this->cover, ['http://', 'https://']) ? $this->cover : Storage::url($this->cover)) : null,
);
}
public function scopeShow($q){
$q->where('is_enable', true);
}
public function scopeSort($q)
{
$q->orderBy('sort', 'asc')
->orderBy('created_at', 'desc');
}
}

View File

@ -0,0 +1,42 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use EloquentFilter\Filterable;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Casts\Attribute;
class Honor extends Model
{
use HasFactory;
use Filterable;
protected function serializeDate(\DateTimeInterface $date)
{
return $date->format('Y-m-d H:i:s');
}
protected function coverUrl():Attribute {
return Attribute::make(
get: fn($value) => $this->cover ? (Str::startsWith($this->cover, ['http://', 'https://']) ? $this->cover : Storage::url($this->cover)) : null,
);
}
public function scopeRecommend($q){
$q->where('is_recommend', true);
}
public function scopeShow($q){
$q->where('is_enable', true);
}
public function scopeSort($q)
{
$q->orderBy('awarded_date', 'desc')
->orderBy('sort', 'asc')
->orderBy('created_at', 'desc');
}
}

View File

@ -65,6 +65,12 @@ class Keyword extends Model
. '-%' ?? '');
}
public function scopeSort($q)
{
$q->orderBy('sort', 'asc')
->orderBy('created_at', 'desc');
}
public static function tagsMap(String $key)
{
$mapArr = [];

View File

@ -0,0 +1,87 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use EloquentFilter\Filterable;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Casts\Attribute;
class ProjectArticle extends Model
{
use HasFactory;
use Filterable;
public const TYPE_ARTICLE = 1; //服务子类
public const TYPE_FLOW = 2; //服务流程
public const TYPE_PHOTO = 3; //相关图片
public const TYPE_ADVANCE = 4; //核心优势
public const TYPE_CASE_STUDY = 5; //服务案例
protected function serializeDate(\DateTimeInterface $date)
{
return $date->format('Y-m-d H:i:s');
}
protected $appends = ['tags', 'cover_url'];
protected $casts = [
'created_at' => 'datetime:Y-m-d H:i:s',
'updated_at' => 'datetime:Y-m-d H:i:s',
'published_at' => 'datetime:Y-m-d H:i:s',
'is_enable' => 'boolean',
'is_recommend' => 'boolean',
'appendixes' => 'array',
];
protected $fillable = [
'title',
'description',
'content',
'cover',
'cate',
'type',
't_ids',
'published_at',
'is_enable',
'is_recommend',
'sort',
'appendixes',
];
protected function coverUrl():Attribute {
return Attribute::make(
get: fn($value) => $this->cover ? (Str::startsWith($this->cover, ['http://', 'https://']) ? $this->cover : Storage::url($this->cover)) : null,
);
}
public function scopeRecommend($q){
$q->where('is_recommend', true);
}
public function scopeShow($q){
$q->where('is_enable', true)->where('published_at', '<=', now());
}
public function scopeSort($q)
{
$q->orderBy('is_recommend', 'desc')
->orderBy('sort', 'asc')
->orderBy('published_at', 'desc')
->orderBy('created_at', 'desc');
}
public function scopeCaseStudies($q)
{
$q->where('type', self::TYPE_CASE_STUDY);
}
protected function tags():Attribute
{
return Attribute::make(
get: fn($value) => $this->t_ids ? explode(',', $this->t_ids) : [],
);
}
}

View File

@ -0,0 +1,66 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Model;
use EloquentFilter\Filterable;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Storage;
class ProjectCate extends Model
{
use HasFactory;
use Filterable;
protected $appends = ['cover_url'];
protected function serializeDate(\DateTimeInterface $date)
{
return $date->format('Y-m-d H:i:s');
}
protected $casts = [
'created_at' => 'datetime:Y-m-d H:i:s',
'updated_at' => 'datetime:Y-m-d H:i:s',
];
protected function coverUrl():Attribute {
return Attribute::make(
get: fn($value) => $this->cover ? (Str::startsWith($this->cover, ['http://', 'https://']) ? $this->cover : Storage::url($this->cover)) : null,
);
}
public function scopeShow($q){
$q->where('is_enable', true);
}
public function scopeSort($q)
{
$q->orderBy('sort', 'asc')
->orderBy('created_at', 'desc');
}
//服务子类
public function children()
{
return $this->hasMany(ProjectArticle::class, 'cate')->where('type', ProjectArticle::TYPE_ARTICLE)->show()->sort();
}
//服务流程
public function flows()
{
return $this->hasOne(ProjectArticle::class, 'cate')->where('type', ProjectArticle::TYPE_FLOW)->show()->sort();
}
//相关图片
public function photos()
{
return $this->hasMany(ProjectArticle::class, 'cate')->where('type', ProjectArticle::TYPE_PHOTO)->show()->sort();
}
//核心优势
public function advances()
{
return $this->hasMany(ProjectArticle::class, 'cate')->where('type', ProjectArticle::TYPE_ADVANCE)->show()->sort();
}
}

View File

@ -0,0 +1,38 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use EloquentFilter\Filterable;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Illuminate\Database\Eloquent\Casts\Attribute;
class Timeline extends Model
{
use HasFactory;
use Filterable;
protected function serializeDate(\DateTimeInterface $date)
{
return $date->format('Y-m-d H:i:s');
}
protected function coverUrl():Attribute {
return Attribute::make(
get: fn($value) => $this->cover ? (Str::startsWith($this->cover, ['http://', 'https://']) ? $this->cover : Storage::url($this->cover)) : null,
);
}
public function scopeShow($q){
$q->where('is_enable', true);
}
public function scopeSort($q)
{
$q->orderBy('awarded_date', 'desc')
->orderBy('sort', 'asc')
->orderBy('created_at', 'desc');
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace App\Services\Admin;
use App\Models\FriendLink;
use App\Models\Filters\FriendLinkFilter;
use App\Traits\UploadTrait;
use Illuminate\Support\Arr;
/**
* @method FriendLink getModel()
* @method FriendLink|\Illuminate\Database\Query\Builder query()
*/
class FriendLinkService extends BaseService
{
use UploadTrait;
protected string $modelName = FriendLink::class;
protected string $modelFilterName = FriendLinkFilter::class;
public function store($data): bool
{
$columns = $this->getTableColumns();
$model = $this->getModel();
$data['cover'] = $this->saveImage('cover', 'friend_links/cover')[0] ?? '';
foreach ($data as $k => $v) {
if (!in_array($k, $columns)) {
continue;
}
$model->setAttribute($k, $v);
}
return $model->save();
}
public function update($primaryKey, $data): bool
{
$columns = $this->getTableColumns();
$model = $this->query()->whereKey($primaryKey)->first();
if(isset($data['cover'])){
$data['cover'] = $this->saveImage('cover', 'friend_links/cover')[0] ?? '';
}
foreach ($data as $k => $v) {
if (!in_array($k, $columns)) {
continue;
}
$model->setAttribute($k, $v);
}
return $model->save();
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace App\Services\Admin;
use App\Models\Filters\HonorFilter;
use App\Models\Honor;
use App\Traits\UploadTrait;
use Illuminate\Support\Arr;
/**
* @method Article getModel()
* @method Article|\Illuminate\Database\Query\Builder query()
*/
class HonorService extends BaseService
{
use UploadTrait;
protected string $modelName = Honor::class;
protected string $modelFilterName = HonorFilter::class;
protected bool $modelSortAble = true;
public function store($data): bool
{
$columns = $this->getTableColumns();
$model = $this->getModel();
$data['cover'] = $this->saveImage('cover', 'honors/cover')[0] ?? '';
foreach ($data as $k => $v) {
if (!in_array($k, $columns)) {
continue;
}
$model->setAttribute($k, $v);
}
return $model->save();
}
public function update($primaryKey, $data): bool
{
$columns = $this->getTableColumns();
$model = $this->query()->whereKey($primaryKey)->first();
if(isset($data['cover'])){
$data['cover'] = $this->saveImage('cover', 'honors/cover')[0] ?? '';
}
foreach ($data as $k => $v) {
if (!in_array($k, $columns)) {
continue;
}
$model->setAttribute($k, $v);
}
return $model->save();
}
}

View File

@ -0,0 +1,96 @@
<?php
namespace App\Services\Admin;
use App\Models\ProjectArticle;
use App\Models\Filters\ProjectArticleFilter;
use App\Traits\UploadTrait;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
/**
* @method ProjectArticle getModel()
* @method ProjectArticle|\Illuminate\Database\Query\Builder query()
*/
class ProjectArticleService extends BaseService
{
use UploadTrait;
protected string $modelName = ProjectArticle::class;
protected string $modelFilterName = ProjectArticleFilter::class;
public function listQuery()
{
$currentUrl = url()->current();
$query= parent::listQuery();
if(Str::contains($currentUrl, 'project_articles')){
$query->where('type', ProjectArticle::TYPE_ARTICLE);
}elseif(Str::contains($currentUrl, 'project_flows')){
$query->where('type', ProjectArticle::TYPE_FLOW);
}elseif(Str::contains($currentUrl, 'project_photos')){
$query->where('type', ProjectArticle::TYPE_PHOTO);
}elseif(Str::contains($currentUrl, 'project_advances')){
$query->where('type', ProjectArticle::TYPE_ADVANCE);
}elseif(Str::contains($currentUrl, 'case_studies')){
$query->where('type', ProjectArticle::TYPE_CASE_STUDY);
}
return $query;
}
public function store($data): bool
{
$columns = $this->getTableColumns();
$model = $this->getModel();
$isEnable = Arr::get($data, 'is_enable');
$publishedAt = Arr::get($data, 'published_at');
if ($isEnable && empty($publishedAt)) {
$data['published_at'] = now();
}
$data['cover'] = $this->saveImage('cover', 'project_articles/cover')[0] ?? '';
$data['appendixes'] = $this->saveFile('appendixes', 'project_articles/appendixes');
foreach ($data as $k => $v) {
if (!in_array($k, $columns)) {
continue;
}
$model->setAttribute($k, $v);
}
return $model->save();
}
public function update($primaryKey, $data): bool
{
$columns = $this->getTableColumns();
$model = $this->query()->whereKey($primaryKey)->first();
$isEnable = Arr::get($data, 'is_enable');
$publishedAt = Arr::get($data, 'published_at');
if ($isEnable && empty($publishedAt) && empty($model->published_at)) {
$data['published_at'] = now();
}
if(isset($data['cover'])){
$data['cover'] = $this->saveImage('cover', 'project_articles/covers')[0] ?? '';
}
if(isset($data['appendixes'])){
$data['appendixes'] = $this->saveFile('appendixes', 'project_articles/appendixes');
}
foreach ($data as $k => $v) {
if (!in_array($k, $columns)) {
continue;
}
$model->setAttribute($k, $v);
}
return $model->save();
}
}

View File

@ -0,0 +1,60 @@
<?php
namespace App\Services\Admin;
use App\Models\ProjectCate;
use App\Models\Filters\ProjectCateFilter;
use App\Traits\UploadTrait;
use Illuminate\Support\Arr;
/**
* @method ProjectCate getModel()
* @method ProjectCate|\Illuminate\Database\Query\Builder query()
*/
class ProjectCateService extends BaseService
{
use UploadTrait;
protected string $modelName = ProjectCate::class;
protected string $modelFilterName = ProjectCateFilter::class;
public function store($data): bool
{
$columns = $this->getTableColumns();
$model = $this->getModel();
$data['cover'] = $this->saveImage('cover', 'project_cates/cover')[0] ?? '';
foreach ($data as $k => $v) {
if (!in_array($k, $columns)) {
continue;
}
$model->setAttribute($k, $v);
}
return $model->save();
}
public function update($primaryKey, $data): bool
{
$columns = $this->getTableColumns();
$model = $this->query()->whereKey($primaryKey)->first();
if(isset($data['cover'])){
$data['cover'] = $this->saveImage('cover', 'project_cates/cover')[0] ?? '';
}
foreach ($data as $k => $v) {
if (!in_array($k, $columns)) {
continue;
}
$model->setAttribute($k, $v);
}
return $model->save();
}
}

View File

@ -0,0 +1,61 @@
<?php
namespace App\Services\Admin;
use App\Models\Filters\TimelineFilter;
use App\Models\Timeline;
use App\Traits\UploadTrait;
use Illuminate\Support\Arr;
/**
* @method Article getModel()
* @method Article|\Illuminate\Database\Query\Builder query()
*/
class TimelineService extends BaseService
{
use UploadTrait;
protected string $modelName = Timeline::class;
protected string $modelFilterName = TimelineFilter::class;
protected bool $modelSortAble = true;
public function store($data): bool
{
$columns = $this->getTableColumns();
$model = $this->getModel();
$data['cover'] = $this->saveImage('cover', 'honors/cover')[0] ?? '';
foreach ($data as $k => $v) {
if (!in_array($k, $columns)) {
continue;
}
$model->setAttribute($k, $v);
}
return $model->save();
}
public function update($primaryKey, $data): bool
{
$columns = $this->getTableColumns();
$model = $this->query()->whereKey($primaryKey)->first();
if(isset($data['cover'])){
$data['cover'] = $this->saveImage('cover', 'honors/cover')[0] ?? '';
}
foreach ($data as $k => $v) {
if (!in_array($k, $columns)) {
continue;
}
$model->setAttribute($k, $v);
}
return $model->save();
}
}

View File

@ -0,0 +1,82 @@
<?php
namespace App\Services;
use App\Exceptions\BizException;
use Illuminate\Contracts\Cache\Repository as Cache;
class CaptchaService
{
/**
* @var string
*/
protected $cachePrefix = 'captchas_';
/**
* @param \Illuminate\Contracts\Cache\Repository $cache
*/
public function __construct(
protected Cache $cache,
) {
}
/**
* 将验证码存入缓存中
*
* @param string $key
* @param string $phrase
* @param integer $ttl
* @return void
*/
public function put(string $key, string $phrase, int $ttl = 300): void
{
$this->cache->put($this->cacheKey($key), $phrase, $ttl);
}
/**
* 校验验证码是否正确
*
* @param string $key
* @param string $phrase
* @return bool
*/
public function testPhrase(string $key, string $phrase): bool
{
if ($phrase === '') {
return false;
}
$value = (string) $this->cache->pull(
$this->cacheKey($key)
);
return strtolower($value) === strtolower($phrase);
}
/**
* 校验验证码是否正确
*
* @param string $key
* @param string $phrase
* @return void
*
* @throws \App\Exceptions\BizException
*/
public function validatePhrase(string $key, string $phrase): void
{
if (! $this->testPhrase($key, $phrase)) {
throw new BizException(__('Invalid captcha'));
}
}
/**
* 生成验证码缓存的 key
*
* @param string $key
* @return string
*/
protected function cacheKey(string $key): string
{
return $this->cachePrefix.$key;
}
}

View File

@ -0,0 +1,57 @@
<?php
namespace App\Traits;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
use Illuminate\Support\Facades\Auth;
trait JsonResponse
{
public function json($data, $code = 200, $message = '')
{
$meta = null;
if ($data instanceof AnonymousResourceCollection) {
$resource = $data->resource;
if ($resource instanceof LengthAwarePaginator) {
$meta = [
'current_page' => $resource->currentPage(),
'last_page' => $resource->lastPage(),
'per_page' => $resource->perPage(),
'total' => $resource->total(),
];
}
}
$result = ['data' => $data, 'code' => $code, 'message' => $message];
if ($meta) {
$result['meta'] = $meta;
}
return response()->json($result);
}
public function success($message = '', $data = null)
{
return $this->json($data, 200, $message);
}
public function error($message = '', $code = 400, $data = null)
{
return $this->json($data, $code, $message);
}
public function include($include = [], $key = 'include')
{
$request = request();
if ($request->filled($key)) {
$include1 = $request->input($key);
$include1 = is_array($include1) ? $include1 : explode(',', $include1);
$include = array_merge($include, $include1);
}
return $include;
}
protected function user($guard = null)
{
return Auth::guard($guard)->user();
}
}

View File

@ -0,0 +1,29 @@
<?php
namespace App\Traits;
trait PaginatorTrait
{
/**
* 解析每页显示的条数
*
* @param string $perPageName
* @param int $default
* @param int|null $max
* @return int
*/
public function resolvePerPage(string $perPageName = 'per_page', int $default = 20, ?int $max = null): int
{
$perPage = (int) request()->input($perPageName);
if ($perPage >= 1) {
if ($max !== null && $max >= 1 && $perPage >= $max) {
return $max;
}
return $perPage;
}
return $default;
}
}

View File

@ -96,6 +96,10 @@ trait UploadTrait
switch($file['state']){
case 'init':
if(strpos($file['value'], 'temporary') !== false){
if(!isset($file['name'])){
$filePathInfo = pathinfo($file['value']);
$file['name'] = $filePathInfo['basename'];
}
$filePath = $path.'/'.$file['name'];
Storage::disk(Admin::config('admin.upload.disk'))->move($file['value'], $filePath);
$fileArr[] = Storage::disk(Admin::config('admin.upload.disk'))->url($filePath);

View File

@ -7,6 +7,7 @@
"require": {
"php": "^8.1",
"alphasnow/aliyun-oss-laravel": "^4.7",
"gregwar/captcha": "^1.3",
"guzzlehttp/guzzle": "^7.2",
"laravel/framework": "^10.10",
"laravel/sanctum": "^3.3",

62
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "6ce90738fadc40a447dfead6b131ec62",
"content-hash": "097769e6f2cd7e3bab775e47a9cce358",
"packages": [
{
"name": "aliyuncs/oss-sdk-php",
@ -599,6 +599,64 @@
],
"time": "2023-11-12T22:16:48+00:00"
},
{
"name": "gregwar/captcha",
"version": "v1.3.0",
"source": {
"type": "git",
"url": "https://github.com/Gregwar/Captcha.git",
"reference": "4edbcd09fde4353b94ce550f43460eba73baf2cc"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Gregwar/Captcha/zipball/4edbcd09fde4353b94ce550f43460eba73baf2cc",
"reference": "4edbcd09fde4353b94ce550f43460eba73baf2cc",
"shasum": ""
},
"require": {
"ext-fileinfo": "*",
"ext-gd": "*",
"ext-mbstring": "*",
"php": ">=5.3.0",
"symfony/finder": "*"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35 || ^5.7.21 || ^6.4 || ^7.0 || ^8.0 || ^9.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Gregwar\\": "src/Gregwar"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Grégoire Passault",
"email": "g.passault@gmail.com",
"homepage": "http://www.gregwar.com/"
},
{
"name": "Jeremy Livingston",
"email": "jeremy.j.livingston@gmail.com"
}
],
"description": "Captcha generator",
"homepage": "https://github.com/Gregwar/Captcha",
"keywords": [
"bot",
"captcha",
"spam"
],
"support": {
"issues": "https://github.com/Gregwar/Captcha/issues",
"source": "https://github.com/Gregwar/Captcha/tree/v1.3.0"
},
"time": "2025-06-23T12:25:54+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "7.8.1",
@ -6575,5 +6633,5 @@
"php": "^8.1"
},
"platform-dev": [],
"plugin-api-version": "2.3.0"
"plugin-api-version": "2.6.0"
}

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('project_cates', function (Blueprint $table) {
$table->id();
$table->string('title')->comment('标题');
$table->text('description')->nullable()->comment('简介');
$table->string('cover')->nullable()->comment('封面');
$table->unsignedInteger('sort')->default(0)->comment('排序');
$table->text('content')->nullable()->comment('内容');
$table->unsignedTinyInteger('is_enable')->default(1)->comment('显示开关');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('project_cates');
}
};

View File

@ -0,0 +1,43 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('project_articles', function (Blueprint $table) {
$table->id();
$table->string('title')->comment('标题');
$table->text('description')->nullable()->comment('简介');
$table->text('content')->nullable()->comment('内容');
$table->string('cover')->nullable()->comment('封面');
$table->unsignedInteger('cate')->nullable()->comment('业务范围');
$table->unsignedTinyInteger('type')->nullable()->comment('分类:1业务子类2服务流程3相关图片4核心优势5服务案例');
$table->string('t_ids')->nullable()->comment('标签');
$table->timestamp('published_at')->nullable()->comment('发布时间');
$table->unsignedTinyInteger('is_enable')->default(1)->comment('显示开关');
$table->unsignedTinyInteger('is_recommend')->default(0)->comment('推荐开关');
$table->unsignedInteger('sort')->default(0)->comment('排序');
$table->text('appendixes')->nullable()->comment('附件');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('project_articles');
}
};

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('contacts', function (Blueprint $table) {
$table->id();
$table->string('name')->nullable()->comment('姓名');
$table->string('phone')->nullable()->comment('电话');
$table->string('company')->nullable()->comment('公司名称');
$table->unsignedTinyInteger('type')->nullable()->comment('业务需求');
$table->string('content')->nullable()->comment('项目概况与备注');
$table->unsignedTinyInteger('status')->default(0)->comment('状态0未处理1已处理');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('contacts');
}
};

View File

@ -0,0 +1,33 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('friend_links', function (Blueprint $table) {
$table->id();
$table->string('title')->comment('标题');
$table->text('description')->nullable()->comment('简介');
$table->string('cover')->nullable()->comment('封面');
$table->unsignedInteger('sort')->default(0)->comment('排序');
$table->string('link')->nullable()->comment('链接地址');
$table->unsignedTinyInteger('is_enable')->default(1)->comment('显示开关');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('friend_links');
}
};

View File

@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('honors', function (Blueprint $table) {
$table->id();
$table->string('title')->comment('标题');
$table->string('cover')->nullable()->comment('封面');
$table->unsignedInteger('category')->nullable()->comment('分类');
$table->date('awarded_date')->nullable()->comment('获得日期');
$table->unsignedTinyInteger('is_enable')->default(1)->comment('显示开关');
$table->unsignedTinyInteger('is_recommend')->default(0)->comment('推荐开关');
$table->unsignedInteger('sort')->default(0)->comment('排序');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('honors');
}
};

View File

@ -0,0 +1,34 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('timelines', function (Blueprint $table) {
$table->id();
$table->string('title')->comment('标题');
$table->text('description')->nullable()->comment('简介');
$table->string('cover')->nullable()->comment('封面');
$table->date('awarded_date')->nullable()->comment('日期');
$table->unsignedTinyInteger('is_enable')->default(1)->comment('显示开关');
$table->unsignedInteger('sort')->default(0)->comment('排序');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('timelines');
}
};

View File

@ -20,22 +20,37 @@ class AdminMenuSeeder extends Seeder
//
$menus = [
['title' => 'index', 'icon' => 'line-md:home-twotone-alt', 'url' => '/index', 'is_home'=>1, 'order'=>1],
['title' => 'admin_system', 'icon' => 'material-symbols:settings-outline', 'url' => '/system', 'order'=>2,
'children' => [
['title' => 'admin_users', 'icon' => 'ph:user-gear', 'url' => '/system/admin_users', 'order'=>1],
['title' => 'admin_roles', 'icon' => 'carbon:user-role', 'url' => '/system/admin_roles', 'order'=>2],
['title' => 'admin_permission', 'icon' => 'carbon:user-role', 'url' => '/system/admin_permissions', 'order'=>3],
['title' => 'admin_menu', 'icon' => 'fluent-mdl2:permissions', 'url' => '/system/admin_menus', 'order'=>4],
['title' => 'admin_setting', 'icon' => 'akar-icons:settings-horizontal', 'url' => '/system/settings', 'order'=>5],
['title' => 'keywords', 'icon' => 'ph:codesandbox-logo-light', 'url' => '/system/keywords', 'order'=>6]
['title'=>'projects', 'icon'=>'ic:outline-article','url'=>'/projects', 'order'=>2, //业务范围
'children'=>[
['title'=> 'project_cates', 'icon'=>'', 'url'=>'/project_cates', 'order'=>1, ],
['title'=> 'project_articles', 'icon'=>'', 'url'=>'/project_articles', 'order'=>2],
['title'=> 'project_flows', 'icon'=>'', 'url'=>'/project_flows', 'order'=>3],
['title'=> 'project_photos', 'icon'=>'', 'url'=>'/project_photos', 'order'=>4],
['title'=> 'project_advances', 'icon'=>'', 'url'=>'/project_advances', 'order'=>5],
]
],
],
['title' => 'web_content', 'icon' => 'ic:outline-collections-bookmark', 'url' => '', 'order'=>3,
// ['title'=>'case_studies', 'icon'=>'carbon:cloud-satellite-services','url'=>'/case_studies', 'order'=>3],
['title' => 'web_content', 'icon' => 'ic:outline-collections-bookmark', 'url' => '/web_content', 'order'=>4,
'children' =>[
['title'=>'articles', 'icon'=>'ic:outline-article','url'=>'/articles', 'order'=>1],
['title'=>'ads', 'icon'=>'lets-icons:img-box','url'=>'/ads', 'order'=>2],
]
['title'=>'news', 'icon'=>'','url'=>'/articles', 'order'=>1],
['title'=>'honors', 'icon'=>'','url'=>'/honors', 'order'=>2],
['title'=>'case_studies', 'icon'=>'','url'=>'/case_studies', 'order'=>3],
['title'=>'timelines', 'icon'=>'','url'=>'/timelines', 'order'=>4],
['title'=>'ads', 'icon'=>'','url'=>'/ads', 'order'=>5],
]
],
['title'=> 'contacts', 'icon'=>'fluent-mdl2:chat-invite-friend','url'=>'/contacts', 'order'=>5],
['title'=> 'friend_links' , 'icon'=>'carbon:ibm-cloud-direct-link-2-connect','url'=>'/friend_links', 'order'=>6],
['title' => 'admin_system', 'icon' => 'material-symbols:settings-outline', 'url' => '/system', 'order'=>7,
'children' => [
['title' => 'admin_users', 'icon' => '', 'url' => '/system/admin_users', 'order'=>1],
['title' => 'admin_roles', 'icon' => '', 'url' => '/system/admin_roles', 'order'=>2],
['title' => 'admin_permission', 'icon' => '', 'url' => '/system/admin_permissions', 'order'=>3],
['title' => 'admin_menu', 'icon' => '', 'url' => '/system/admin_menus', 'order'=>4],
['title' => 'admin_setting', 'icon' => '', 'url' => '/system/settings', 'order'=>5],
['title' => 'keywords', 'icon' => '', 'url' => '/system/keywords', 'order'=>6]
],
],
];
DB::table('admin_menus')->truncate();
try {

View File

@ -17,14 +17,18 @@ class KeywordSeeder extends Seeder
{
Keyword::truncate();
$list = [
['key' => 'article_category', 'name' => '文章分类', 'list' => [
'examples'=>'案例', 'services' =>'服务', 'news'=> '资讯动态'
]],
// ['key' => 'article_tag', 'name' => '文章标签', 'list' => [//标签value填写色号指定标签颜色
// ['key' => 'article_category', 'name' => '文章分类', 'list' => [
// 'news'=> '企业资讯', 'honors'=>'资质荣誉',
// ]],
['key' => 'banner_address', 'name' => '广告位置', 'list' => [
'index-top'=>'首页', 'service-top' =>'服务项目', 'examples-top'=> '案例展示', 'companny-top'=>'公司介绍','contactus-top'=>'联系我们','news-top'=>'资讯动态'
'index-top'=>'首页', 'companny-top' =>'关于我们', 'project-top'=>'业务范围', 'examples-top'=> '案例展示', 'news-top'=>'资讯动态','contactus-top'=>'联系我们'
]],
['key' => 'honors', 'name' => '资质荣誉', 'list' => [
]],
['key' => 'case_study_tag', 'name' => '服务案例标签', 'list' => [//标签value填写色号指定标签颜色
]],
];

View File

@ -256,6 +256,20 @@ return [
'invalid_package' => '无效的扩展包',
],
],
'components'=>[
'parent_select' => '父级',
'order' => '排序',
'content' => '内容',
'files' => '文件',
'tag' => '标签',
'status' => '状态',
'status_map' => [
'enabled' => '开启',
'disabled'=> '关闭'
],
'decimal' => '金额',
],
'export' => [
'title' => '导出',
'all' => '全部',
@ -303,5 +317,61 @@ return [
'mini_id' => '小程序ID',
'mini_link'=> '小程序路径'
],
]
],
'project_cates' => [
'id' => '主键ID',
'title' => '标题',
'description'=> '简介',
'content' => '内容',
'cover' =>'封面',
'sort' => '排序',
'is_enable' => '显示',
],
'project_articles' => [
'id' => '主键ID',
'title' => '标题',
'description'=> '简介',
'content' => '内容',
'cover' =>'封面',
'cate' => '业务范围',
'tags' => '标签',
't_ids' => '标签',
'published_at' => '定时发布',
'published_at_g' => '发布时间',
'is_enable' => '显示',
'is_recommend' => '推荐',
'sort' => '排序',
'appendixes' => '附件',
'published_at_remark' => '*若未设置发布时间且操作设置为显示,则默认生成发布时间',
],
'friend_links' => [
'id' => '主键ID',
'title' => '标题',
'description'=> '简介',
'content' => '内容',
'cover' =>'封面',
'sort' => '排序',
'is_enable' => '显示',
'link'=>'链接地址'
],
'honors' => [
'id' => '主键ID',
'title' => '标题',
'cover' =>'封面',
'category' => '分类',
'awarded_date' => '获奖日期',
'is_enable' => '显示',
'is_recommend' => '推荐',
'sort' => '排序',
],
'timelines' => [
'id' => '主键ID',
'title' => '标题',
'description'=> '简介',
'cover' =>'封面',
'awarded_date' => '日期',
'is_enable' => '显示',
'is_recommend' => '推荐',
'sort' => '排序',
],
];

View File

@ -12,5 +12,21 @@ return [
'keywords' => '数据字典',
'web_content' => '内容管理',
'articles' => '文章管理',
'ads' => '广告管理',
'ads' => 'Banner管理',
'web_manager' => '网站管理',
'projects' => '主营业务',
'project_cates' => '业务范围',
'project_articles' => '服务子类',
'project_flows' => '服务流程',
'project_photos' => '相关图片',
'project_advances' => '核心优势',
'case_studies' => '服务案例',
'case_study_tags' => '案例标签',
'case_study_articles' => '案例内容',
'honors' => '荣誉资质',
'timelines' => '发展历程',
'news' => '企业资讯',
'contacts' => '在线询价',
'friend_links' => '合作伙伴'
];

View File

@ -1,5 +1,7 @@
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
@ -17,3 +19,24 @@ use Illuminate\Support\Facades\Route;
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
Route::middleware('api')->group(function () {
Route::post('captchas', [CaptchaController::class, 'store']);
Route::get('captchas/{captcha}', [CaptchaController::class, 'show']);
//广告
Route::get('/ads', [AdController::class, 'index']);
//业务范围
Route::get('/project_cates', [ProjectController::class, 'index']);
Route::get('/project_cates/{project_cate}', [ProjectController::class, 'show']);//服务详情
//业务子类详情
Route::get('/project_children/{child}', [ProjectChildrenController::class, 'show']);
//合作伙伴
Route::get('/friend_links', [FriendLinkController::class, 'index']);
//服务案例
Route::get('/case_study_tags', [CaseStudyController::class, 'tags']);
Route::get('/case_studies', [CaseStudyController::class, 'index']);
Route::get('/case_studies/{case_study}', [CaseStudyController::class, 'show']);
//企业资讯
});