update header and sidebar menus for admin panel.

fixed menus

wip

wip

get sub menus

wip

add current link

wip

fixed rma

fixed routes

fixed sub routes

wip

wip

fixed order and rmas

重构后台菜单

wip

fixed active

update languages.

wip

wip

add history links

code format

wip

fixed menus

fixed menus

fixed url

fixed sub routes

wip

update menus

wip

修复角色页面没有选中上一级目录

remove unnecessary code

wip

wip

fixed header common links

code format

add design

fixed plugin

wip

添加插件二次子菜单

修复获取更多

修复最近浏览记录 插件相关语言包

wip

调整文章菜单顺序

fixed common links

fixed common links

wip

wip

wip

default link icon.

修复插件编辑二级菜单选中

wip

wip

wip

wip

wip

wip
This commit is contained in:
Edward Yang 2023-04-26 20:20:59 +08:00
parent 1cc2bf53a5
commit 10eb858ef1
61 changed files with 1857 additions and 4167 deletions

View File

@ -5,13 +5,15 @@ namespace Beike\Admin\Http\Controllers;
use App\Http\Controllers\Controller;
use Beike\Admin\Repositories\DashboardRepo;
use Beike\Admin\Repositories\Report\OrderReportRepo;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Str;
class HomeController extends Controller
{
public function index()
{
$data = [
'products' => DashboardRepo::getProductData(),
'products' => DashboardRepo::getProductData(),
// 'views' => DashboardRepo::getCustomerViewData(),
'orders' => DashboardRepo::getOrderData(),
'customers' => DashboardRepo::getCustomerData(),
@ -25,4 +27,54 @@ class HomeController extends Controller
return view('admin::pages.home', $data);
}
/**
* 通过关键字搜索菜单
*
* @return array
*/
public function menus()
{
$keyword = trim(request('keyword'));
$menus = [];
$routes = Route::getRoutes();
foreach ($routes as $route) {
$routeName = $route->getName();
if (! Str::startsWith($routeName, 'admin')) {
continue;
}
$method = $route->methods()[0];
if ($method != 'GET') {
continue;
}
$routeName = str_replace('admin.', '', $routeName);
$permissionRoute = str_replace('.', '_', $routeName);
try {
$url = admin_route($routeName);
} catch (\Exception $e) {
$url = '';
}
if (empty($url)) {
continue;
}
$title = trans("admin/common.{$permissionRoute}");
if (stripos($title, 'admin/common.') !== false) {
continue;
}
if ($keyword && stripos($title, $keyword) !== false) {
$menus[] = [
'route' => $routeName,
'url' => admin_route($routeName),
'title' => $title,
];
}
}
return $menus;
}
}

View File

@ -32,6 +32,111 @@ class PluginController extends Controller
return view('admin::pages.plugins.index', $data);
}
/**
* @return mixed
*/
public function shipping()
{
$type = 'shipping';
$plugins = app('plugin')->getPlugins();
$plugins = $plugins->where('type', $type);
$data['plugins'] = array_values(PluginResource::collection($plugins)->jsonSerialize());
$data['type'] = $type;
$data = hook_filter('admin.plugin.index.data', $data);
return view('admin::pages.plugins.index', $data);
}
/**
* @return mixed
*/
public function payment()
{
$type = 'payment';
$plugins = app('plugin')->getPlugins();
$plugins = $plugins->where('type', $type);
$data['plugins'] = array_values(PluginResource::collection($plugins)->jsonSerialize());
$data['type'] = $type;
$data = hook_filter('admin.plugin.index.data', $data);
return view('admin::pages.plugins.index', $data);
}
/**
* @return mixed
*/
public function total()
{
$type = 'total';
$plugins = app('plugin')->getPlugins();
$plugins = $plugins->where('type', $type);
$data['plugins'] = array_values(PluginResource::collection($plugins)->jsonSerialize());
$data['type'] = $type;
$data = hook_filter('admin.plugin.index.data', $data);
return view('admin::pages.plugins.index', $data);
}
/**
* @return mixed
*/
public function social()
{
$type = 'social';
$plugins = app('plugin')->getPlugins();
$plugins = $plugins->where('type', $type);
$data['plugins'] = array_values(PluginResource::collection($plugins)->jsonSerialize());
$data['type'] = $type;
$data = hook_filter('admin.plugin.index.data', $data);
return view('admin::pages.plugins.index', $data);
}
/**
* @return mixed
*/
public function feature()
{
$type = 'feature';
$plugins = app('plugin')->getPlugins();
$plugins = $plugins->where('type', $type);
$data['plugins'] = array_values(PluginResource::collection($plugins)->jsonSerialize());
$data['type'] = $type;
$data = hook_filter('admin.plugin.index.data', $data);
return view('admin::pages.plugins.index', $data);
}
/**
* @return mixed
*/
public function language()
{
$type = 'language';
$plugins = app('plugin')->getPlugins();
$plugins = $plugins->where('type', $type);
$data['plugins'] = array_values(PluginResource::collection($plugins)->jsonSerialize());
$data['type'] = $type;
$data = hook_filter('admin.plugin.index.data', $data);
return view('admin::pages.plugins.index', $data);
}
/**
* @return mixed
*/
public function theme()
{
$type = 'theme';
$plugins = app('plugin')->getPlugins();
$plugins = $plugins->where('type', $type);
$data['plugins'] = array_values(PluginResource::collection($plugins)->jsonSerialize());
$data['type'] = $type;
$data = hook_filter('admin.plugin.index.data', $data);
return view('admin::pages.plugins.index', $data);
}
/**
* 上传插件
*/

View File

@ -22,13 +22,13 @@ class PageCategoryResource extends JsonResource
return [
'id' => $this->id,
'active' => $this->active,
'title' => $description->title,
'title_format' => sub_string($description->title, 64),
'summary' => $description->summary,
'summary_format' => sub_string($description->summary, 128),
'meta_title' => $description->meta_title,
'meta_description' => $description->meta_description,
'meta_keywords' => $description->meta_keywords,
'title' => $description->title ?? '',
'title_format' => sub_string($description->title ?? '', 64),
'summary' => $description->summary ?? '',
'summary_format' => sub_string($description->summary ?? '', 128),
'meta_title' => $description->meta_title ?? '',
'meta_description' => $description->meta_description ?? '',
'meta_keywords' => $description->meta_keywords ?? '',
'created_at' => time_format($this->created_at),
'updated_at' => time_format($this->updated_at),
];

View File

@ -19,6 +19,7 @@ Route::prefix($adminName)
Route::middleware('admin_auth:' . \Beike\Models\AdminUser::AUTH_GUARD)
->group(function () {
Route::get('/', [Controllers\HomeController::class, 'index'])->name('home.index');
Route::get('/menus', [Controllers\HomeController::class, 'menus'])->name('home.menus');
//个人中心
Route::middleware('can:account_index')->get('account', [Controllers\AccountController::class, 'index'])->name('account.index');
@ -161,6 +162,15 @@ Route::prefix($adminName)
Route::middleware('can:plugins_install')->post('plugins/{code}/install', [Controllers\PluginController::class, 'install'])->name('plugins.install');
Route::middleware('can:plugins_uninstall')->post('plugins/{code}/uninstall', [Controllers\PluginController::class, 'uninstall'])->name('plugins.uninstall');
// 插件分组
Route::middleware('can:plugins_index')->get('plugins/shipping', [Controllers\PluginController::class, 'shipping'])->name('plugins.shipping');
Route::middleware('can:plugins_index')->get('plugins/payment', [Controllers\PluginController::class, 'payment'])->name('plugins.payment');
Route::middleware('can:plugins_index')->get('plugins/total', [Controllers\PluginController::class, 'total'])->name('plugins.total');
Route::middleware('can:plugins_index')->get('plugins/social', [Controllers\PluginController::class, 'social'])->name('plugins.social');
Route::middleware('can:plugins_index')->get('plugins/feature', [Controllers\PluginController::class, 'feature'])->name('plugins.feature');
Route::middleware('can:plugins_index')->get('plugins/language', [Controllers\PluginController::class, 'language'])->name('plugins.language');
Route::middleware('can:plugins_index')->get('plugins/theme', [Controllers\PluginController::class, 'theme'])->name('plugins.theme');
// 插件市场
Route::middleware('can:marketing_index')->get('marketing', [Controllers\MarketingController::class, 'index'])->name('marketing.index');
Route::middleware('can:marketing_show')->get('marketing/{code}', [Controllers\MarketingController::class, 'show'])->name('marketing.show');

View File

@ -3,6 +3,7 @@
namespace Beike\Admin\View\Components;
use Beike\Models\AdminUser;
use Illuminate\Support\Facades\View;
use Illuminate\View\Component;
class Header extends Component
@ -11,6 +12,10 @@ class Header extends Component
private ?AdminUser $adminUser;
public array $commonLinks;
public array $historyLinks;
/**
* Create a new component instance.
*
@ -28,81 +33,102 @@ class Header extends Component
*/
public function render()
{
$sidebar = new Sidebar();
$preparedMenus = $this->prepareMenus();
foreach ($preparedMenus as $menu) {
$menuCode = $menu['code'] ?? '';
if ($menuCode) {
$routes = [];
$subRoutesMethod = "get{$menu['code']}SubRoutes";
if (method_exists($sidebar, $subRoutesMethod)) {
$sideMenuRoutes = $sidebar->{"get{$menu['code']}SubRoutes"}();
foreach ($sideMenuRoutes as $route) {
$routeFirst = explode('.', $route['route'])[0] ?? '';
$routes[] = 'admin.' . $route['route'];
$routes[] = 'admin.' . $routeFirst . '.edit';
$routes[] = 'admin.' . $routeFirst . '.show';
}
}
$data = [
'menu_code' => $menuCode,
'routes' => $routes,
];
$filterRoutes = hook_filter('admin.components.header.routes', $data);
$routes = $filterRoutes['routes'] ?? [];
if (empty($routes)) {
$is_route = equal_route('admin.' . $menu['route']);
} else {
$is_route = equal_route($routes);
}
} else {
$is_route = equal_route('admin.' . $menu['route']);
}
$this->addLink($menu['name'], $menu['route'], $is_route);
}
$this->commonLinks = $this->getCommonLinks();
$this->historyLinks = $this->handleHistoryLinks();
return view('admin::components.header');
}
/**
* 默认菜单
* 常用功能链接
*/
private function prepareMenus()
private function getCommonLinks()
{
$menus = [
['name' => trans('admin/common.home'), 'route' => 'home.index', 'code' => ''],
['name' => trans('admin/common.order'), 'route' => 'orders.index', 'code' => 'Order'],
['name' => trans('admin/common.product'), 'route' => 'products.index', 'code' => 'Product'],
['name' => trans('admin/common.customer'), 'route' => 'customers.index', 'code' => 'Customer'],
['name' => trans('admin/common.page'), 'route' => 'pages.index', 'code' => 'Page'],
['name' => trans('admin/common.setting'), 'route' => 'settings.index', 'code' => 'Setting'],
$commonLinks = [
['route' => 'design.index', 'icon' => 'bi bi-palette', 'blank' => true],
['route' => 'design_footer.index', 'icon' => 'bi bi-palette', 'blank' => true],
['route' => 'design_menu.index', 'icon' => 'bi bi-list', 'blank' => false],
['route' => 'languages.index', 'icon' => 'bi bi-globe2', 'blank' => false],
['route' => 'currencies.index', 'icon' => 'bi bi-currency-dollar', 'blank' => false],
['route' => 'plugins.index', 'icon' => 'bi bi-plug', 'blank' => false],
];
return hook_filter('admin.header_menus', $menus);
foreach ($commonLinks as $index => $commonLink) {
$route = $commonLink['route'];
$permissionRoute = str_replace('.', '_', $route);
$commonLinks[$index]['url'] = admin_route($route);
$commonLinks[$index]['title'] = trans("admin/common.{$permissionRoute}");
}
return hook_filter('admin.components.header.common_links', $commonLinks);
}
/**
* 添加后台顶部菜单链接
*
* @param $title
* @param $route
* @param false $active
* 处理最近访问链接
*/
private function addLink($title, $route, bool $active = false)
private function handleHistoryLinks(): array
{
$permissionRoute = str_replace('.', '_', $route);
if ($this->adminUser->cannot($permissionRoute) && $route != 'home.index') {
return;
$links = [];
$histories = $this->getHistoryRoutesFromSession();
foreach ($histories as $history) {
$routeName = str_replace('admin.', '', $history);
$permissionRoute = str_replace('.', '_', $routeName);
if (stripos($routeName, 'plugins.') !== false) {
$type = str_replace('plugins.', '', $routeName);
if ($type == 'index') {
$title = trans("admin/common.{$permissionRoute}");
} else {
$title = trans("admin/plugin.{$type}");
}
} else {
$title = trans("admin/common.{$permissionRoute}");
}
if (stripos($title, 'admin/common.') !== false) {
$tempRouteName = str_replace('s.index', '', $routeName);
$title = trans("admin/common.{$tempRouteName}");
}
try {
$url = admin_route($routeName);
} catch (\Exception $e) {
$url = '';
}
if (empty($url)) {
continue;
}
$links[] = [
'route' => $routeName,
'url' => $url,
'title' => $title,
];
}
$url = admin_route($route);
$this->links[] = [
'title' => $title,
'url' => $url,
'active' => $active,
];
return $links;
}
/**
* session 获取最近访问的链接
*
* @return array
*/
private function getHistoryRoutesFromSession(): array
{
$histories = session('histories', []);
$currentRoute = request()->route()->getName();
$routeName = str_replace('admin.', '', $currentRoute);
if (in_array($routeName, ['edit.locale', 'home.menus'])) {
return $histories;
}
array_unshift($histories, $currentRoute);
$histories = array_slice(array_unique($histories), 0, 6);
session(['histories' => $histories]);
return $histories;
}
}

View File

@ -3,17 +3,23 @@
namespace Beike\Admin\View\Components;
use Beike\Models\AdminUser;
use Illuminate\Support\Str;
use Beike\Plugin\Plugin;
use Illuminate\View\Component;
class Sidebar extends Component
{
public array $links = [];
public ?array $currentLink;
private string $adminName;
private ?string $routeNameWithPrefix;
private ?string $currentRouteName;
private ?string $currentPrefix;
private ?AdminUser $adminUser;
/**
@ -23,9 +29,14 @@ class Sidebar extends Component
*/
public function __construct()
{
$this->adminName = admin_name();
$this->adminName = admin_name();
$this->adminUser = current_user();
$this->routeNameWithPrefix = request()->route()->getName();
$this->adminUser = current_user();
$this->currentRouteName = str_replace($this->adminName . '.', '', $this->routeNameWithPrefix);
$routeData = explode('.', $this->currentRouteName);
$this->currentPrefix = $routeData[0] ?? '';
}
/**
@ -35,76 +46,161 @@ class Sidebar extends Component
*/
public function render()
{
$adminName = $this->adminName;
$routeNameWithPrefix = request()->route()->getName();
$routeName = str_replace($adminName . '.', '', $routeNameWithPrefix);
if (Str::startsWith($routeName, $this->getHomeSubPrefix())) {
$routes = $this->getHomeSubRoutes();
foreach ($routes as $route) {
$this->addLink($route, $this->equalRoute($route['route']), (bool) ($route['blank'] ?? false), $route['hide_mobile'] ?? 0);
}
} elseif (Str::startsWith($routeName, $this->getProductSubPrefix())) {
$routes = $this->getProductSubRoutes();
foreach ($routes as $route) {
$this->addLink($route, $this->equalRoute($route['route']), (bool) ($route['blank'] ?? false), $route['hide_mobile'] ?? 0);
}
} elseif (Str::startsWith($routeName, $this->getCustomerSubPrefix())) {
$routes = $this->getCustomerSubRoutes();
foreach ($routes as $route) {
$this->addLink($route, $this->equalRoute($route['route']), (bool) ($route['blank'] ?? false), $route['hide_mobile'] ?? 0);
}
} elseif (Str::startsWith($routeName, $this->getOrderSubPrefix())) {
$routes = $this->getOrderSubRoutes();
foreach ($routes as $route) {
$this->addLink($route, $this->equalRoute($route['route']), (bool) ($route['blank'] ?? false), $route['hide_mobile'] ?? 0);
}
} elseif (Str::startsWith($routeName, $this->getPageSubPrefix())) {
$routes = $this->getPageSubRoutes();
foreach ($routes as $route) {
$this->addLink($route, $this->equalRoute($route['route']), (bool) ($route['blank'] ?? false), $route['hide_mobile'] ?? 0);
}
} elseif (Str::startsWith($routeName, $this->getSettingSubPrefix())) {
$routes = $this->getSettingSubRoutes();
foreach ($routes as $route) {
$this->addLink($route, $this->equalRoute($route['route']), (bool) ($route['blank'] ?? false), $route['hide_mobile'] ?? 0);
}
}
$this->links = $this->getMenus();
$this->handleMenus();
$this->currentLink = $this->getCurrentLink();
return view('admin::components.sidebar');
}
/**
* 添加左侧菜单链接
* 返回所有菜单
* 小图标地址 https://icons.getbootstrap.com/
*
* @param $routeData
* @param $active
* @param false $newWindow
* @param int $hide_mobile
* @return mixed
*/
private function addLink($routeData, $active, bool $newWindow = false, int $hide_mobile = 0)
private function getMenus(): mixed
{
$route = $routeData['route'];
$icon = $routeData['icon'] ?? '';
$title = $routeData['title'] ?? '';
$permissionRoute = str_replace('.', '_', $route);
if ($this->adminUser->cannot($permissionRoute)) {
return;
}
if (empty($title)) {
$title = trans("admin/common.{$permissionRoute}");
}
$url = admin_route($route);
$this->links[] = [
'title' => $title,
'url' => $url,
'icon' => $icon,
'active' => $active,
'hide_mobile' => $hide_mobile,
'new_window' => $newWindow,
$menus = [
[
'route' => 'home.index',
'title' => trans('admin/common.home'),
'icon' => 'bi bi-house',
'prefixes' => $this->getHomeSubPrefix(),
],
[
'route' => 'orders.index',
'title' => trans('admin/common.order'),
'icon' => 'bi bi-clipboard-check',
'prefixes' => $this->getOrderSubPrefix(),
'children' => $this->getOrderSubRoutes(),
],
[
'route' => 'products.index',
'title' => trans('admin/common.product'),
'icon' => 'bi bi-box-seam',
'prefixes' => $this->getProductSubPrefix(),
'children' => $this->getProductSubRoutes(),
],
[
'route' => 'customers.index',
'title' => trans('admin/common.customer'),
'icon' => 'bi bi-person-circle',
'prefixes' => $this->getCustomerSubPrefix(),
'children' => $this->getCustomerSubRoutes(),
],
[
'route' => 'pages.index',
'title' => trans('admin/common.page'),
'icon' => 'bi bi-file-earmark-text',
'prefixes' => $this->getPageSubPrefix(),
'children' => $this->getPageSubRoutes(),
],
[
'route' => 'theme.index',
'title' => trans('admin/common.design'),
'icon' => 'bi bi-palette',
'prefixes' => $this->getDesignSubPrefix(),
'children' => $this->getDesignSubRoutes(),
],
[
'route' => 'plugins.index',
'title' => trans('admin/common.plugin'),
'icon' => 'bi bi-shop',
'prefixes' => $this->getPluginSubPrefix(),
'children' => $this->getPluginSubRoutes(),
],
[
'route' => 'settings.index',
'title' => trans('admin/common.setting'),
'icon' => 'bi bi-gear',
'prefixes' => $this->getSettingSubPrefix(),
'children' => $this->getSettingSubRoutes(),
],
];
return hook_filter('admin.components.sidebar.menus', $menus);
}
/**
* 获取二级菜单
*
* @return array|null
*/
private function getCurrentLink(): array|null
{
foreach ($this->links as $link) {
$prefixes = $link['prefixes'] ?? [];
if ($prefixes && in_array($this->currentPrefix, $prefixes)) {
return $link;
}
}
return null;
}
/**
* 处理是否选中等数据
*/
private function handleMenus()
{
foreach ($this->links as $index => $link) {
$prefixes = $link['prefixes'] ?? [];
if ($prefixes && in_array($this->currentPrefix, $prefixes)) {
$this->links[$index]['active'] = true;
} else {
$this->links[$index]['active'] = false;
}
$url = $link['url'] ?? '';
if (empty($url)) {
$this->links[$index]['url'] = admin_route($link['route']);
}
$title = $link['title'] ?? '';
if (empty($title)) {
$permissionRoute = str_replace('.', '_', $this->currentRouteName);
$this->links[$index]['title'] = trans("admin/common.{$permissionRoute}");
}
if (! isset($link['blank'])) {
$this->links[$index]['blank'] = false;
}
$icon = $link['icon'] ?? '';
if (empty($icon)) {
$this->links[$index]['icon'] = 'bi bi-link-45deg';
}
$children = $link['children'] ?? [];
if ($children) {
foreach ($children as $key => $item) {
$childPrefixes = $item['prefixes'] ?? [];
$excludes = $item['excludes'] ?? [];
if ($prefixes && in_array($this->currentPrefix, $childPrefixes)
&& (! $excludes || ! in_array($this->currentRouteName, $excludes))) {
$this->links[$index]['children'][$key]['active'] = true;
} else {
$this->links[$index]['children'][$key]['active'] = false;
}
$url = $item['url'] ?? '';
if (empty($url)) {
$this->links[$index]['children'][$key]['url'] = admin_route($item['route']);
}
$title = $item['title'] ?? '';
if (empty($title)) {
$permissionRoute = str_replace('.', '_', $item['route']);
$this->links[$index]['children'][$key]['title'] = trans("admin/common.{$permissionRoute}");
}
if (! isset($item['blank'])) {
$this->links[$index]['children'][$key]['blank'] = false;
}
}
}
}
}
/**
@ -112,7 +208,7 @@ class Sidebar extends Component
*/
private function getHomeSubPrefix()
{
$prefix = ['home.'];
$prefix = ['home'];
return hook_filter('admin.sidebar.home.prefix', $prefix);
}
@ -122,7 +218,7 @@ class Sidebar extends Component
*/
private function getProductSubPrefix()
{
$prefix = ['products.', 'multi_filter.', 'categories.', 'brands.', 'attribute_groups.', 'attributes.'];
$prefix = ['products', 'multi_filter', 'categories', 'brands', 'attribute_groups', 'attributes'];
return hook_filter('admin.sidebar.product.prefix', $prefix);
}
@ -132,7 +228,7 @@ class Sidebar extends Component
*/
private function getCustomerSubPrefix()
{
$prefix = ['customers.', 'customer_groups.'];
$prefix = ['customers', 'customer_groups'];
return hook_filter('admin.sidebar.customer.prefix', $prefix);
}
@ -142,7 +238,7 @@ class Sidebar extends Component
*/
private function getOrderSubPrefix()
{
$prefix = ['orders.', 'rmas.', 'rma_reasons.'];
$prefix = ['orders', 'rmas', 'rma_reasons'];
return hook_filter('admin.sidebar.order.prefix', $prefix);
}
@ -152,17 +248,40 @@ class Sidebar extends Component
*/
private function getPageSubPrefix()
{
$prefix = ['pages.', 'page_categories.'];
$prefix = ['pages', 'page_categories'];
return hook_filter('admin.sidebar.page.prefix', $prefix);
}
/**
* 获取后台设计子页面路由前缀列表
*/
private function getDesignSubPrefix()
{
$prefix = ['theme', 'design_menu'];
return hook_filter('admin.sidebar.design.prefix', $prefix);
}
/**
* 获取后台设计子页面路由前缀列表
*/
private function getPluginSubPrefix()
{
$prefix = ['plugins', 'marketing'];
return hook_filter('admin.sidebar.plugin.prefix', $prefix);
}
/**
* 获取后台系统设置子页面路由前缀列表
*/
private function getSettingSubPrefix()
{
$prefix = ['settings.', 'account.', 'admin_users.', 'admin_roles.', 'plugins.', 'theme.', 'marketing.', 'tax_classes', 'tax_rates', 'regions', 'currencies', 'languages', 'design_menu', 'countries', 'zones'];
$prefix = [
'settings', 'admin_users', 'admin_roles', 'tax_classes', 'tax_rates',
'regions', 'currencies', 'languages', 'countries', 'zones', 'account',
];
return hook_filter('admin.sidebar.setting.prefix', $prefix);
}
@ -172,14 +291,7 @@ class Sidebar extends Component
*/
public function getHomeSubRoutes()
{
$routes = [
['route' => 'design.index', 'icon' => 'fa fa-tachometer-alt', 'blank' => 1, 'hide_mobile' => 1],
['route' => 'design_footer.index', 'icon' => 'fa fa-tachometer-alt', 'blank' => 1, 'hide_mobile' => 1],
['route' => 'design_menu.index', 'icon' => 'fa fa-tachometer-alt', 'hide_mobile' => 1],
['route' => 'languages.index', 'icon' => 'fa fa-tachometer-alt', 'hide_mobile' => 1],
['route' => 'currencies.index', 'icon' => 'fa fa-tachometer-alt', 'hide_mobile' => 1],
['route' => 'plugins.index', 'icon' => 'fa fa-tachometer-alt', 'hide_mobile' => 1],
];
$routes = [];
return hook_filter('admin.sidebar.home_routes', $routes);
}
@ -190,13 +302,13 @@ class Sidebar extends Component
public function getProductSubRoutes()
{
$routes = [
['route' => 'products.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'categories.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'brands.index', 'icon' => 'fa fa-tachometer-alt', 'hide_mobile' => 1],
['route' => 'attribute_groups.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'attributes.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'multi_filter.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'products.trashed', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'products.index', 'prefixes' => ['products'], 'excludes' => ['products.trashed']],
['route' => 'categories.index', 'prefixes' => ['categories']],
['route' => 'brands.index', 'prefixes' => ['brands']],
['route' => 'attribute_groups.index', 'prefixes' => ['attribute_groups']],
['route' => 'attributes.index', 'prefixes' => ['attributes']],
['route' => 'multi_filter.index', 'prefixes' => ['multi_filter']],
['route' => 'products.trashed', 'prefixes' => ['products'], 'excludes' => ['products.index', 'products.edit']],
];
return hook_filter('admin.sidebar.product_routes', $routes);
@ -208,9 +320,9 @@ class Sidebar extends Component
public function getCustomerSubRoutes()
{
$routes = [
['route' => 'customers.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'customer_groups.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'customers.trashed', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'customers.index', 'prefixes' => ['customers'], 'excludes' => ['customers.trashed']],
['route' => 'customer_groups.index', 'prefixes' => ['customer_groups']],
['route' => 'customers.trashed', 'prefixes' => ['customers'], 'excludes' => ['customers.index', 'customers.edit']],
];
return hook_filter('admin.sidebar.customer_routes', $routes);
@ -222,9 +334,9 @@ class Sidebar extends Component
public function getOrderSubRoutes()
{
$routes = [
['route' => 'orders.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'rmas.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'rma_reasons.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'orders.index', 'prefixes' => ['orders']],
['route' => 'rmas.index', 'prefixes' => ['rmas']],
['route' => 'rma_reasons.index', 'prefixes' => ['rma_reasons']],
];
return hook_filter('admin.sidebar.order_routes', $routes);
@ -237,13 +349,53 @@ class Sidebar extends Component
public function getPageSubRoutes()
{
$routes = [
['route' => 'page_categories.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'pages.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'pages.index', 'prefixes' => ['pages']],
['route' => 'page_categories.index', 'prefixes' => ['page_categories']],
];
return hook_filter('admin.sidebar.pages_routes', $routes);
}
/**
* 获取设计子页面路由
* @return mixed
*/
public function getDesignSubRoutes()
{
$routes = [
['route' => 'theme.index', 'prefixes' => ['theme'], 'hide_mobile' => true],
['route' => 'design_menu.index', 'prefixes' => ['design_menu'], 'hide_mobile' => 1],
['route' => 'design.index', 'prefixes' => ['design'], 'blank' => true, 'hide_mobile' => true],
['route' => 'design_footer.index', 'prefixes' => ['design_footer'], 'blank' => true, 'hide_mobile' => true],
];
return hook_filter('admin.sidebar.design_routes', $routes);
}
/**
* 获取插件子页面路由
* @return mixed
*/
public function getPluginSubRoutes()
{
$types = collect(Plugin::TYPES);
$types = $types->map(function ($item) {
return 'plugins.' . $item;
});
$routes[] = ['route' => 'plugins.index', 'prefixes' => ['plugins'], 'excludes' => $types->toArray()];
$originTypes = $types->push('plugins.index', 'plugins.edit')->push();
foreach (Plugin::TYPES as $type) {
$types = $originTypes->reject("plugins.{$type}");
$routes[] = ['route' => "plugins.{$type}", 'prefixes' => ['plugins'], 'title' => trans("admin/plugin.{$type}"), 'excludes' => $types->toArray()];
}
$routes[] = ['route' => 'marketing.index', 'prefixes' => ['marketing']];
return hook_filter('admin.sidebar.plugins_routes', $routes);
}
/**
* 获取系统设置子页面路由
* @return mixed
@ -251,37 +403,18 @@ class Sidebar extends Component
public function getSettingSubRoutes()
{
$routes = [
['route' => 'settings.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'account.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'admin_users.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'plugins.index', 'icon' => 'fa fa-tachometer-alt', 'hide_mobile' => 1],
['route' => 'theme.index', 'icon' => 'fa fa-tachometer-alt', 'hide_mobile' => 1],
['route' => 'marketing.index', 'icon' => 'fa fa-tachometer-alt', 'hide_mobile' => 1],
['route' => 'regions.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'tax_rates.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'tax_classes.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'currencies.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'languages.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'countries.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'zones.index', 'icon' => 'fa fa-tachometer-alt'],
['route' => 'design.index', 'icon' => 'fa fa-tachometer-alt', 'blank' => true, 'hide_mobile' => 1],
['route' => 'design_footer.index', 'icon' => 'fa fa-tachometer-alt', 'blank' => true, 'hide_mobile' => 1],
['route' => 'design_menu.index', 'icon' => 'fa fa-tachometer-alt', 'hide_mobile' => 1],
['route' => 'settings.index', 'prefixes' => ['settings']],
['route' => 'account.index', 'prefixes' => ['account']],
['route' => 'admin_users.index', 'prefixes' => ['admin_users', 'admin_roles']],
['route' => 'regions.index', 'prefixes' => ['regions']],
['route' => 'tax_rates.index', 'prefixes' => ['tax_rates']],
['route' => 'tax_classes.index', 'prefixes' => ['tax_classes']],
['route' => 'currencies.index', 'prefixes' => ['currencies']],
['route' => 'languages.index', 'prefixes' => ['languages']],
['route' => 'countries.index', 'prefixes' => ['countries']],
['route' => 'zones.index', 'prefixes' => ['zones']],
];
return hook_filter('admin.sidebar.setting_routes', $routes);
}
/**
* 是否为当前访问路由
*
* @param $routeName
* @return bool
*/
private function equalRoute($routeName): bool
{
$currentRouteName = str_replace($this->adminName . '.', '', $this->routeNameWithPrefix);
return $routeName == $currentRouteName;
}
}

View File

@ -15,8 +15,8 @@
<script src="{{ asset('vendor/jquery/jquery-3.6.0.min.js') }}"></script>
<script src="{{ asset('vendor/layer/3.5.1/layer.js') }}"></script>
<link rel="shortcut icon" href="{{ asset('/image/favicon.png') }}">
{{-- <script src="{{ asset('vendor/bootstrap/5.1.3/js/bootstrap.min.js') }}"></script> --}}
<script src="{{ asset('vendor/bootstrap/5.1.3/js/bootstrap.bundle.min.js') }}"></script>
{{-- <script src="{{ asset('vendor/bootstrapjs/bootstrap.min.js') }}"></script> --}}
<script src="{{ asset('vendor/bootstrapjs/bootstrap.bundle.min.js') }}"></script>
<link rel="stylesheet" type="text/css" href="{{ asset('/install/css/app.css') }}">
@yield('style')
</head>

View File

@ -189,20 +189,6 @@ class PluginRepo
}
}
/**
* Get plugin by code
*
* @param $code
* @return mixed
*/
public static function getPlugin($code): mixed
{
$code = Str::camel($code);
$plugins = self::getPluginsByCode();
return $plugins->get($code);
}
/**
* 判断插件是否安装
*

View File

@ -11,8 +11,7 @@
},
"devDependencies": {
"axios": "^0.21",
"bootstrap": "^5.2.1",
"bootstrap-5.1.3": "npm:bootstrap@5.1.3",
"bootstrap": "^5.2.2",
"laravel-mix": "^6.0.6",
"lodash": "^4.17.19",
"resolve-url-loader": "^4.0.0",

BIN
public/image/admin-menu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -60,12 +60,12 @@ hr.horizontal.dark {
.nav-link {
color: #6c757d;
border: none;
padding: 0 .2rem 0.7rem;
padding: 0 .6rem 0.7rem;
&.active {
// color: $primary;
color: $primary;
// color: #12263f;
color: #1a1a1a;
// color: #1a1a1a;
font-weight: bold;
background-color: transparent;
border-bottom: 2px solid $primary;
@ -75,11 +75,13 @@ hr.horizontal.dark {
}
.card {
box-shadow: rgba(0, 0, 0, .1) 0px 1px 4px 0px;
border: none;
// box-shadow: rgba(0, 0, 0, .1) 0px 1px 4px 0px;
box-shadow: 0 0.375rem 0.75rem rgba(140,152,164,.075);
.card-header {
padding: 1rem 1rem .3rem;
// padding: 1rem 1rem .3rem;
padding-top: 1.3rem;
padding-bottom: 0;
background-color: #fff;
font-weight: bold;
// font-size: .8rem;
@ -98,7 +100,7 @@ hr.horizontal.dark {
}
.card-body {
padding: 1rem;
// padding: 1rem;
}
}
@ -238,4 +240,17 @@ table.table {
background-repeat: no-repeat;
background-position: right calc(0.375em + 0.1875rem) center;
background-size: calc(0.75em + 0.375rem) calc(0.75em + 0.375rem);
}
.input-for-group {
span.input-group-text {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
input {
border-top-left-radius: 0 !important;
border-bottom-left-radius: 0 !important;
margin-left: -1px;
}
}

View File

@ -135,11 +135,20 @@
border-radius: 0.5rem;
// box-shadow: 0 0.6125rem 2.5rem 0.6125rem rgba(140,152,164,.175);
box-shadow: 0 0.8rem 2.5rem 0.6125rem rgba(140, 152, 164, 0.286);
.dropdown-wrap {
max-height: 380px;
.search-ing {
height: 80px;
text-align: center;
line-height: 80px;
display: none;
}
.dropdown-search {
padding: 0 0.5rem;
max-height: 460px;
overflow-y: auto;
overflow-x: hidden;
padding: 0 0.5rem;
display: none;
// 修改滚动条样式
&::-webkit-scrollbar {
@ -154,7 +163,34 @@
}
}
.header-search-no-data {
display: none;
height: 80px;
text-align: center;
line-height: 80px;
}
.dropdown-wrap {
padding: 0 0.5rem;
}
.link-item {
&::after {
content: '';
display: block;
padding-bottom: 0.5rem;
margin-bottom: 0.5rem;
border-bottom: 1px solid rgba(0, 0, 0, 0.07);
width: calc(100% + 1rem);
margin-left: -0.5rem;
}
&:last-of-type:after {
border-bottom: none;
padding-bottom: 0;
margin-bottom: 0;
}
a {
color: #333;
}
@ -181,6 +217,7 @@
padding: 0 1rem;
display: flex;
flex-wrap: wrap;
margin-right: -0.6rem;
a {
background-color: rgba(19,33,68,.1);
@ -188,7 +225,7 @@
padding: 0.3rem 0.7rem;
font-size: .75rem;
margin-bottom: 0.5rem;
margin-right: 0.3rem;
margin-right: 0.6rem;
&:hover {
background-color: $primary;
color: #fff;
@ -205,8 +242,23 @@
a.dropdown-item {
border-radius: 0.3rem;
padding: 0.5rem 1rem;
&:hover {
padding: 0.5rem 1.2rem 0.5rem 1rem;
position: relative;
&.active {
&::after {
content: '\F131';
position: absolute;
right: 4px;
top: 50%;
color: #666;
margin-top: -9px;
font-family: 'bootstrap-icons';
}
}
&.active, &:hover {
color: #333;
background-color: rgba(189, 197, 209, 0.2);
}
}
@ -249,45 +301,6 @@
}
.navbar {
&.navbar-left {
li {
html[lang="zh_cn"] &, html[lang="zh_hk"] &, html[lang="en"] &, html[lang="ja"] & {
padding: 0 1rem;
}
@media screen and (max-width: 1200px) {
html[lang="zh_cn"] &, html[lang="zh_hk"] &, html[lang="en"] &, html[lang="ja"] & {
padding: 0 .2rem;
}
}
a.nav-link {
position: relative;
&:after {
content: '';
position: absolute;
left: 0;
display: none;
bottom: 0;
width: 100%;
height: 3px;
background-color: $primary;
}
}
&.active, &:hover {
font-weight: bold;
a {
&:after {
display: block;
}
}
}
}
}
&.navbar-right {
> li {
&.vip-serve {
@ -400,90 +413,4 @@
}
}
}
}
#offcanvas-mobile-menu {
width: 80%;
.offcanvas-header {
padding: 10px 20px 10px 10px;
border-bottom: 1px solid #e5e5e5;
}
.mobile-menu-wrap {
padding: 0;
ul.mobile-navbar {
list-style: none;
padding: 0;
margin-bottom: 0;
> .nav-item {
&.active {
background-color: #f9f9f9;
& > a {
background-color: #e2e2e2;
}
}
}
.nav-link:active {
background-color: #eee;
}
.navbar-nav {
a {
padding-left: 36px;
}
>.nav-item {
&:last-of-type {
border: none;
}
&.active {
& > a {
background-color: #eee;
}
}
}
}
}
.navbar-nav,.mobile-navbar {
.nav-item {
border-bottom: 1px solid #e5e5e5;
a {
color: var(--bs-body-color);
flex: 1;
height: 44px;
padding-left: 20px;
display: flex;
align-items: center;
}
}
}
}
.offcanvas-footer {
.offcanvas-btns {
display: flex;
justify-content: space-between;
.nav-link{
padding: 10px;
}
.dropdown-toggle::after {
color: var(--bs-body-color);
}
.dropdown-menu {
border-color: rgba(0, 0, 0, .2);;
}
}
}
}

View File

@ -37,6 +37,33 @@ body.page-marketing {
}
body.page-marketing-info {
.plugin-info {
align-items: flex-start;
}
.plugin-icon-wrap {
position: relative;
.plugin-icon {
border-radius: 6%;
position: relative;
z-index: 1;
box-shadow: 0 1px 2px 0 rgba(60, 64, 67, .3), 0 1px 3px 1px rgba(60, 64, 67, .15);
}
.plugin-icon-shadow {
bottom: -14px;
filter: blur(10px);
left: 50%;
border-radius: 4%;
transform: translateX(-50%);
width: 88%;
opacity: 50%;
position: absolute;
// z-index: -1;
}
}
.radio-group {
> .el-radio {
height: auto;

View File

@ -8,61 +8,177 @@
* @LastEditTime 2022-09-16 19:05:52
*/
.sidebar {
background: #293042;
.sidebar-box {
direction: ltr;
width: 220px;
transition: all .2s ease-in-out;
background: #fff;
border-right: 1px solid #f1f1f1;
html[lang="zh_cn"] &, html[lang="zh_hk"] &, html[lang="en"] & {
width: 190px;
@media (max-width: 768px) {
position: absolute;
width: 100%;
left: 0;
bottom: 0;
visibility: hidden;
z-index: 99;
height: calc(100% - 54px);
background-color: rgba(0, 0, 0, 0.5);
}
// @media screen and (max-width: 991px) {
// position: fixed;
// top: 0;
// bottom: 0;
// }
&.active {
@media (max-width: 768px) {
visibility: visible;
}
.navbar-nav {
> li.nav-item {
position: relative;
.sidebar-info {
left: 0;
}
}
a {
padding: .7rem 1rem .7rem 1.5rem;
// color: rgba(58,65,111, .9);
color: #333;
transition: all .1s ease-in-out;
.sidebar-info {
display: flex;
height: 100%;
transition: all .2s ease-in-out;
i {
margin-right: 7px;
@media (max-width: 768px) {
position: absolute;
left: -100%;
bottom: 0;
z-index: 999;
border-top: 1px solid #eee;
}
> .left {
padding-top: 8px;
min-width: 92px;
background-color: #eff3f7;
max-width: 130px;
// 背景图
background-image: url('/image/admin-menu.png');
background-repeat: no-repeat;
background-position: bottom;
background-size: contain;
ul {
li {
position: relative;
a {
padding: 1rem .5rem 1rem .8rem;
color: #333;
display: flex;
text-decoration: none;
&::after {
content: '';
display: inline-block;
width: 3px;
height: 3px;
}
i {
margin-right: 7px;
}
}
&.active, &:hover {
background-color: #fff;
a {
font-weight: bold;
&::after {
display: none;
}
}
body.admin-home & {
background-color: #f9fbfd;
}
&:before, &:after {
display: block;
}
}
&:before, &:after {
content: "";
position: absolute;
right: 0;
width: 8px;
height: 8px;
overflow: hidden;
display: none;
background: radial-gradient(circle closest-side,transparent 0,transparent 50%,#fff 0) 200% 200%/400% 400%;
}
&:before {
top: -8px;
}
&:after {
bottom: -8px;
transform: scaleY(-1);
// transform:rotate(180deg);
}
}
}
}
&:hover {
background-color: #f4f4f4;
> .right {
min-width: 120px;
padding: 0 .5rem;
background-color: #fff;
overflow-y: auto;
max-width: 200px;
@media (min-width: 768px) {
border-right: 1px solid #f1f1f1;
}
&.active {
a {
// color: $primary;
background-color: #eee;
> .title {
padding: 1rem;
margin-top: .3rem;
margin-bottom: 0;
}
.navbar-nav {
> li.nav-item {
position: relative;
margin-bottom: .7rem;
a {
padding: .5rem 1rem;
color: #333;
transition: all .1s ease-in-out;
border-radius: .3rem;
&:hover {
background-color: rgba(189, 197, 209, 0.2);
}
i {
margin-right: 7px;
}
}
&.active {
a {
// background-color: rgba(189, 197, 209, 0.2);
position: relative;
color: $primary;
&::after {
// content: "\F138";
content: "\F135";
position: absolute;
right: 0;
top: 50%;
line-height: 1;
margin-top: -6px;
font-family: "bootstrap-icons";
}
}
}
}
}
// &.active {
// &:before {
// content: '';
// position: absolute;
// left: 0;
// top: 0;
// width: 2px;
// height: 100%;
// z-index: 1;
// background: $primary;
// }
// }
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -13,12 +13,11 @@ $success: #71c20b;
$info: #1a8eff;
$body-bg: #f9fbfd;
$font-family-base: 'poppins',
sans-serif;
$border-radius: 0;
$btn-border-radius: 0;
$btn-border-radius-sm: 0;
$btn-border-radius-lg: 0;
$font-family-base: 'poppins', sans-serif;
$border-radius: 0.2rem;
$btn-border-radius: 0.2rem;
$btn-border-radius-sm: 0.2rem;
$btn-border-radius-lg: 0.2rem;
$input-btn-focus-box-shadow: 0 0 11px 0 rgba($color: $primary, $alpha: .1);
$input-bg: #fff;
$form-select-focus-box-shadow: 0 0 11px 0 rgba($color: $primary, $alpha: .1);
@ -40,13 +39,23 @@ $input-border-color: #e2e2e2;
$badge-border-radius: 2px;
$text-muted: #95aac9;
$card-border-radius: .4rem;
$card-border-color: rgba(231, 234, 243, 0.7);
$card-box-shadow: 0 0.375rem 0.75rem rgba(140,152,164,.075);
$card-spacer-y: 1.2rem;
$card-spacer-x: 1.2rem;
$form-feedback-icon-valid: none;
$form-feedback-icon-valid-color: inherit;
$alert-padding-y: 0.5rem;
$nav-link-color: #555;
$nav-link-hover-color: #555;
$nav-tabs-link-active-color: #222;
@import './bootstrap-icons';
@import 'node_modules/bootstrap-5.1.3/scss/bootstrap';
@import 'node_modules/bootstrap/scss/bootstrap';
// @import 'node_modules/bootstrap/scss/bootstrap';
.table> :not(:first-child) {

View File

@ -8,14 +8,6 @@
* @LastEditTime 2022-09-16 19:06:18
*/
.el-input__inner {
border-radius: 0;
}
.el-button {
border-radius: 0;
}
.el-tabs__header {
margin-bottom: 25px;
}
@ -24,10 +16,6 @@
padding: 0 10px;
}
.el-input-group__append, .el-input-group__prepend {
border-radius: 0;
}
.language-inputs {
.el-form-item__content {
line-height: 1 !important;

View File

@ -3,14 +3,20 @@
* @link https://beikeshop.com
* @Author pu shuo <pushuo@guangda.work>
* @Date 2022-08-16 18:47:18
* @LastEditTime 2023-04-26 19:45:54
* @LastEditTime 2023-04-28 11:18:47
*/
$(function () {
// 响应式下弹窗菜单交互
$(document).on("click", ".mobile-open-menu", function () {
const offcanvasMobileMenu = new bootstrap.Offcanvas('#offcanvas-mobile-menu')
offcanvasMobileMenu.show()
$('.sidebar-box').toggleClass('active');
});
// 点击 sidebar-box 内 除 sidebar-info 以外的地方关闭弹窗
$('.sidebar-box').on("click", function (e) {
if (!$(e.target).parents(".sidebar-info").length) {
$(".sidebar-box").removeClass("active");
}
});
$(document).on("focus", ".search-wrap .input-wrap input", function () {
@ -18,14 +24,121 @@ $(function () {
});
$(document).on("focus", ".search-wrap .input-wrap .close-icon", function () {
$(this).parents('.input-wrap').removeClass("active");
$(this).siblings('input').val('');
$(this).parents('.input-wrap').removeClass("active");
$('.dropdown-search .common-links').html('');
$('.dropdown-search').hide().siblings('.dropdown-wrap').show();
});
let timer = null;
let searchLinksLength = 0;
$('#header-search-input').on("keyup", function (key) {
const val = $(this).val();
// 排除方向键
if (key.keyCode == 38 || key.keyCode == 40 || key.keyCode == 37 || key.keyCode == 39) {
return;
}
// 回车键
if (key.keyCode == 13) {
const $activeItem = $('.dropdown-search .common-links .dropdown-item.active');
if ($activeItem.length) {
window.location.href = $activeItem.attr('href');
}
return;
}
$('.dropdown-search').hide().find('.common-links').html('');
if (val == '') {
$('.search-ing').hide().siblings('.dropdown-wrap').show();
return;
}
$('.search-ing').show().siblings('.dropdown-wrap').hide();
clearTimeout(timer);
timer = setTimeout(() => {
if (!$('#header-search-input').val()) return;
searchApi(val)
}, 300);
})
$('#header-search-input').on("keydown", function (key) {
if (key.keyCode == 38 || key.keyCode == 40) {
const $dropdownItem = $('.dropdown-search .common-links .dropdown-item');
const dropdownSearchLinksTop = $('.dropdown-search .common-links').offset().top;
const dropdownSearchHeight = $('.dropdown-search').height() - 34;
const dropdownSearchTop = $('.dropdown-search').offset().top + dropdownSearchHeight;
const index = $dropdownItem.index($('.dropdown-search .common-links .dropdown-item.active'));
if (key.keyCode == 38) {
if (index == '-1' || index == 0) {
$dropdownItem.removeClass('active').eq(searchLinksLength - 1).addClass('active');
$('.dropdown-search').scrollTop($('.dropdown-search .common-links').height());
} else {
$dropdownItem.removeClass('active').eq(index - 1).addClass('active');
const activeTop = $('.dropdown-search .common-links .dropdown-item.active').offset().top;
if (activeTop < dropdownSearchTop - dropdownSearchHeight) {
$('.dropdown-search').scrollTop(activeTop - dropdownSearchLinksTop + 30);
}
}
}
if (key.keyCode == 40) {
if (index == '-1' || index == searchLinksLength - 1) {
$dropdownItem.removeClass('active').eq(0).addClass('active');
$('.dropdown-search').scrollTop(0);
} else {
$dropdownItem.removeClass('active').eq(index + 1).addClass('active');
const activeTop = $('.dropdown-search .common-links .dropdown-item.active').offset().top;
if (activeTop > dropdownSearchTop) {
$('.dropdown-search').scrollTop(activeTop - dropdownSearchLinksTop - dropdownSearchHeight + 40);
}
}
}
}
})
const searchApi = (val) => {
$http.get(`menus?keyword=${val}`, null, {hload: true}).then((res) => {
searchLinksLength = res.length;
$('.dropdown-search').show().siblings('.dropdown-wrap').hide();
$('.header-search-no-data').hide();
if (res.length) {
$('.dropdown-search .common-links').html(res.map((item) => {
return `<a href="${item.url}" class="dropdown-item"><span><i class="bi bi-link-45deg"></i></span> ${item.title}</a>`
}).join(''))
} else {
$('.header-search-no-data').show();
}
}).finally(() => {
$('.search-ing').hide();
})
}
// 点击 search-wrap 以外的地方关闭搜索框
$(document).on("click", function (e) {
if (!$(e.target).parents(".search-wrap").length) {
$(".search-wrap .input-wrap").removeClass("active");
}
});
let updatePop = null;
$('.update-btn').click(function() {
updatePop = layer.open({
type: 1,
title: lang.text_hint,
area: ['400px'],
content: $('.update-pop'),
});
});
$('.update-pop .btn-outline-secondary').click(function() {
layer.close(updatePop)
});
});

View File

@ -1,6 +1,6 @@
<x-admin::form.row :title="$title" :required="$required">
@foreach (locales() as $index => $locale)
<div class="d-flex wp-{{ $width }}">
<div class="d-flex wp-{{ $width }} input-for-group">
<span class="input-group-text wp-100 px-1" id="basic-addon1">{{ $locale['name'] }}</span>
<input type="text" name="{{ $formatName($locale['code']) }}" value="{{ $formatValue($locale['code']) }}"
class="form-control short" placeholder="{{ $placeholder ?: $locale['name'] }}" @if ($required) required @endif>

View File

@ -6,51 +6,39 @@
</div>
</div>
<div class="header-right">
{{-- <ul class="navbar navbar-left">
@foreach ($links as $link)
<li class="nav-item {{ $link['active'] ? 'active' : '' }}"><a href="{{ $link['url'] }}" class="nav-link">{{ $link['title'] }}</a></li>
@endforeach
</ul> --}}
<div class="search-wrap">
<div class="input-wrap">
<div class="search-icon"><i class="bi bi-search"></i></div>
<input type="text" class="form-control" placeholder="Search in front">
<input type="text" id="header-search-input" autocomplete="off" class="form-control" placeholder="{{ __('admin/common.header_search_input') }}">
<button class="btn close-icon" type="button"><i class="bi bi-x-lg"></i></button>
</div>
<div class="dropdown-menu">
<div class="search-ing"><i class="el-icon-loading"></i></div>
<div class="dropdown-search">
<div class="dropdown-header fw-bold">{{ __('admin/common.header_search_title') }}</div>
<div class="common-links"></div>
<div class="header-search-no-data"><i class="bi bi-file-earmark"></i> {{ __('common.no_data') }}</div>
</div>
<div class="dropdown-wrap">
<div class="link-item recent-search">
<div class="dropdown-header fw-bold mb-2">最近搜索</div>
<div class="recent-search-links">
<a href="{{ admin_route('design_menu.index') }}"><i class="bi bi-search"></i> {{ __('admin/common.design_menu_index') }}</a>
<a href="{{ admin_route('languages.index') }}"><i class="bi bi-search"></i> {{ __('admin/common.languages_index') }}</a>
<a href="{{ admin_route('currencies.index') }}"><i class="bi bi-search"></i> {{ __('admin/common.currencies_index') }}</a>
<a href="{{ admin_route('plugins.index') }}"><i class="bi bi-search"></i> {{ __('admin/common.plugins_index') }}</a>
@if ($historyLinks)
<div class="link-item recent-search">
<div class="dropdown-header fw-bold mb-2">{{ __('admin/common.recent_view') }}</div>
<div class="recent-search-links">
@foreach ($historyLinks as $link)
<a href="{{ $link['url'] }}"><i class="bi bi-search"></i> {{ $link['title'] }}</a>
@endforeach
</div>
</div>
</div>
<div class="dropdown-divider"></div>
@endif
<div class="link-item">
<div class="dropdown-header fw-bold">常用链接</div>
<div class="dropdown-header fw-bold">{{ __('admin/common.common_link') }}</div>
<div class="common-links">
<a class="dropdown-item" href="{{ admin_route('design.index') }}" target="_blank">
<span><i class="bi bi-palette"></i></span> {{ __('admin/common.design_index') }}
</a>
<a class="dropdown-item" href="{{ admin_route('design_footer.index') }}" target="_blank">
<span><i class="bi bi-palette"></i></span> {{ __('admin/common.design_footer_index') }}
</a>
<a class="dropdown-item" href="{{ admin_route('design_menu.index') }}">
<span><i class="bi bi-list"></i></span> {{ __('admin/common.design_menu_index') }}
</a>
<a class="dropdown-item" href="{{ admin_route('languages.index') }}">
<span><i class="bi bi-globe2"></i></span> {{ __('admin/common.languages_index') }}
</a>
<a class="dropdown-item" href="{{ admin_route('currencies.index') }}">
<span><i class="bi bi-currency-dollar"></i></span> {{ __('admin/common.currencies_index') }}
</a>
<a class="dropdown-item" href="{{ admin_route('plugins.index') }}">
<span><i class="bi bi-plug"></i></span> {{ __('admin/common.plugins_index') }}
</a>
@foreach ($commonLinks as $link)
<a class="dropdown-item" href="{{ $link['url'] }}" target="{{ $link['blank'] ? '_blank' : '_self' }}">
<span><i class="{{ $link['icon'] }}"></i></span> {{ $link['title'] }}
</a>
@endforeach
</div>
</div>
</div>
@ -76,7 +64,7 @@
@hookwrapper('admin.header.license')
<li class="nav-item">
<a href="{{ config('beike.api_url') }}/vip/subscription?domain={{ config('app.url') }}&developer_token={{ system_setting('base.developer_token') }}&type=tab-license" target="_blank" class="nav-link">
<span class="vip-text ms-1">@lang('admin/common.copyright_buy')</span>
@lang('admin/common.copyright_buy')
</a>
</li>
@endhookwrapper
@ -110,11 +98,21 @@
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="dropdownMenuLink">
<li>
<a target="_blank" href="{{ shop_route('home.index') }}" class="dropdown-item"><i class="bi bi-send me-1"></i> @lang('admin/common.access_frontend')</a>
<a target="_blank" href="{{ shop_route('home.index') }}" class="dropdown-item py-2">
<i class="bi bi-send me-1"></i> {{ __('admin/common.access_frontend') }}
</a>
</li>
<li>
<a href="{{ admin_route('account.index') }}" class="dropdown-item py-2">
<i class="bi bi-person-circle me-1"></i> {{ __('admin/common.account_index') }}
</a>
</li>
<li><a href="{{ admin_route('account.index') }}" class="dropdown-item"><i class="bi bi-person-circle"></i> {{ __('admin/common.account_index') }}</a></li>
<li><hr class="dropdown-divider"></li>
<li><a href="{{ admin_route('logout.index') }}" class="dropdown-item"><i class="bi bi-box-arrow-left me-1"></i> {{ __('common.sign_out') }}</a></li>
<li>
<a href="{{ admin_route('logout.index') }}" class="dropdown-item py-2">
<i class="bi bi-box-arrow-left me-1"></i> {{ __('common.sign_out') }}
</a>
</li>
</ul>
</div>
</li>
@ -140,45 +138,6 @@
</div>
</div>
<div class="offcanvas offcanvas-start" tabindex="-1" id="offcanvas-mobile-menu">
<div class="offcanvas-header">
<h5 class="offcanvas-title fw-bold" id="offcanvasWithBothOptionsLabel">{{ __('common.menu') }}</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body mobile-menu-wrap">
@if (is_mobile())
<ul class="mobile-navbar">
@foreach ($links as $link)
<li class="nav-item {{ $link['active'] ? 'active' : '' }}">
<a href="{{ $link['url'] }}" class="nav-link">{{ $link['title'] }}</a>
@if ($link['active'])
<x-admin-sidebar />
@endif
</li>
@endforeach
</ul>
@endif
</div>
<div class="offcanvas-footer">
<div class="offcanvas-btns">
<div class="lang">
<div class="dropdown">
<a class="nav-link dropdown-toggle text-dark" href="javascript:void(0)" data-bs-toggle="dropdown">{{ $admin_language['name'] }}</a>
<ul class="dropdown-menu" aria-labelledby="dropdownMenuLink">
@foreach ($admin_languages as $language)
<li><a href="{{ admin_route('edit.locale', ['locale' => $language['code']]) }}" class="dropdown-item">{{ $language['name'] }}</a></li>
@endforeach
</ul>
</div>
</div>
<div class="user">
<a href="{{ admin_route('logout.index') }}" class="nav-link text-dark"><i class="bi bi-box-arrow-left"></i> {{ __('common.sign_out') }}</a>
</div>
</div>
</div>
</div>
<div class="update-pop p-3" style="display: none">
<div class="mb-4 fs-5 fw-bold text-center">{{ __('admin/common.update_title') }}</div>
<div class="py-3 px-4 bg-light mx-3 lh-lg mb-4">
@ -192,23 +151,3 @@
<a href="https://beikeshop.com/download" target="_blank" class="btn btn-primary">{{ __('admin/common.update_btn') }}</a>
</div>
</div>
@push('footer')
<script>
let updatePop = null;
$('.update-btn').click(function() {
updatePop = layer.open({
type: 1,
title: '{{ __('common.text_hint') }}',
area: ['400px'],
content: $('.update-pop'),
});
});
$('.update-pop .btn-outline-secondary').click(function() {
layer.close(updatePop)
});
</script>
@endpush

View File

@ -1,4 +1,4 @@
<div class="d-flex flex-column align-center align-items-center mb-4">
<img src="{{ asset('image/no-data.svg') }}" class="img-fluid wp-400">
<div class="text-secondary fs-4">{{ $text }}</div>
<div class="text-secondary fs-5">{{ $text }}</div>
</div>

View File

@ -1,16 +1,31 @@
<ul class="list-unstyled navbar-nav">
@foreach ($links as $link)
@if (is_mobile())
@if (!$link['hide_mobile'])
<aside class="sidebar-box navbar-expand-xs border-radius-xl">
<div class="sidebar-info">
<div class="left">
<ul class="list-unstyled navbar-nav">
@foreach ($links as $link)
<li class="nav-item {{ $link['active'] ? 'active' : '' }}">
<a target="{{ $link['new_window'] ? '_blank' : '_self' }}" class="nav-link" href="{{ $link['url'] }}"> {{ $link['title'] }}</a>
<a target="{{ $link['blank'] ? '_blank' : '_self' }}" class="nav-link" href="{{ $link['url'] }}">
<i class="{{ $link['icon'] }}"></i> <span>{{ $link['title'] }}</span>
</a>
</li>
@endif
@else
<li class="nav-item {{ $link['active'] ? 'active' : '' }}">
<a target="{{ $link['new_window'] ? '_blank' : '_self' }}" class="nav-link" href="{{ $link['url'] }}"> {{ $link['title'] }}</a>
</li>
@endif
@endforeach
</ul>
@endforeach
</ul>
</div>
@if ($currentLink['children'] ?? [])
<div class="right">
<h4 class="title">{{ $currentLink['title'] }}</h4>
<ul class="list-unstyled navbar-nav">
@foreach ($currentLink['children'] as $link)
<li class="nav-item {{ $link['active'] ? 'active' : '' }}">
<a target="{{ $link['blank'] ? '_blank' : '_self' }}" class="nav-link" href="{{ $link['url'] }}">
{{ $link['title'] }}
</a>
</li>
@endforeach
</ul>
</div>
@endif
</div>
</aside>

View File

@ -12,7 +12,7 @@
<script src="{{ asset('vendor/element-ui/2.15.6/js.js') }}"></script>
<script src="{{ asset('vendor/jquery/jquery-3.6.0.min.js') }}"></script>
<script src="{{ asset('vendor/layer/3.5.1/layer.js') }}"></script>
<script src="{{ asset('vendor/bootstrap/5.1.3/js/bootstrap.bundle.min.js') }}"></script>
<script src="{{ asset('vendor/bootstrap/js/bootstrap.bundle.min.js') }}"></script>
<script src="{{ asset('vendor/cookie/js.cookie.min.js') }}"></script>
<link href="{{ mix('/build/beike/admin/css/bootstrap.css') }}" rel="stylesheet">
<link rel="stylesheet" href="{{ asset('vendor/element-ui/2.15.6/css.css') }}">
@ -31,9 +31,7 @@
<x-admin-header />
<div class="main-content">
<aside class="sidebar navbar-expand-xs border-radius-xl d-none d-lg-block">
<x-admin-sidebar />
</aside>
<x-admin-sidebar />
<div id="content">
<div class="page-title-box py-1 d-flex align-items-center justify-content-between">
<h5 class="page-title">@yield('title')</h5>
@ -57,6 +55,7 @@
const lang = {
file_manager: '{{ __('admin/file_manager.file_manager') }}',
error_form: '{{ __('common.error_form') }}',
text_hint: '{{ __('common.text_hint') }}',
}
const config = {

View File

@ -15,30 +15,46 @@
$data = $plugin['data'];
@endphp
<div class="card mb-4" id="app">
<div class="card-header"><h6 class="card-title">{{ __('admin/marketing.marketing_show') }}</h6></div>
<div class="card-header"><h5 class="card-title">{{ __('admin/marketing.marketing_show') }}</h5></div>
<div class="card-body">
<div class="d-lg-flex">
<div class="border wp-400 hp-400 d-flex justify-content-between align-items-center"><img src="{{ $data['icon_big'] }}" class="img-fluid"></div>
<div class="d-lg-flex plugin-info">
<div class="d-flex justify-content-between align-items-center plugin-icon-wrap">
<img src="{{ $data['icon_big'] }}" class="img-fluid plugin-icon">
<img src="{{ $data['icon_big'] }}" class="img-fluid plugin-icon-shadow">
</div>
<div class="ms-lg-5 mt-2">
<h3 class="card-title mb-4">{{ $data['name'] }}</h3>
<h2 class="card-title mb-4">{{ $data['name'] }}</h2>
<div class="plugin-item d-lg-flex align-items-center mb-4 lh-1 text-secondary">
<div class="mx-3 ms-0">{{ __('admin/marketing.download_count') }}{{ $data['downloaded'] }}</div><span class="vr lh-1 bg-secondary"></span>
<div class="mx-3">{{ __('admin/marketing.last_update') }}{{ $data['updated_at'] }}</div><span class="vr lh-1 bg-secondary"></span>
<div class="mx-3">{{ __('admin/marketing.text_version') }}{{ $data['version'] }}</div>
<div class="mx-3">{{ __('page_category.views') }}{{ $data['viewed'] }}</div><span class="vr lh-1 bg-secondary"></span>
<div class="mx-3">{{ __('admin/marketing.last_update') }}{{ $data['updated_at'] }}</div><span class="lh-1 bg-secondary"></span>
</div>
<div class="mb-4">
<div class="mb-2 fw-bold">{{ __('product.price') }}</div>
<div class="fs-3 fw-bold">{{ $data['price_format'] }}</div>
</div>
<div class="mb-4">
<div class="mb-2 fw-bold">{{ __('admin/marketing.text_version') }}</div>
<div>{{ $data['version'] }}</div>
</div>
<div class="mb-4">
<div class="mb-2 fw-bold">{{ __('admin/marketing.text_compatibility') }}</div>
<div>{{ $data['version_name_format'] }}</div>
</div>
<div class="mb-4">
<div class="mb-2 fw-bold">{{ __('admin/marketing.text_author') }}</div>
<div class="d-flex">
<div class="border wh-60 d-flex justify-content-between align-items-center"><img src="{{ $data['developer']['avatar'] }}" class="img-fluid"></div>
<div class="ms-3">
<div class="mb-2 fw-bold">{{ $data['developer']['name'] }}</div>
<div>{{ $data['developer']['email'] }}</div>
</div>
<div class="d-inline-block">
<a href="{{ config('app.url') }}/account/{{ $data['developer']['id'] }}" target="_blank" class="d-flex align-items-center text-dark">
<div class="border wh-50 rounded-5 d-flex justify-content-between align-items-center"><img src="{{ $data['developer']['avatar'] }}" class="img-fluid rounded-5"></div>
<div class="ms-2">
<div class="mb-1 fw-bold">{{ $data['developer']['name'] }}</div>
<div>{{ $data['developer']['email'] }}</div>
</div>
</a>
</div>
</div>
@ -51,11 +67,11 @@
<div class="mb-2 fw-bold">{{ __('admin/marketing.select_pay') }}</div>
<div class="mb-4">
<el-radio-group v-model="payCode" size="small" class="radio-group">
<el-radio class="rounded-0 me-1" label="wechatpay" border><img src="{{ asset('image/wechat.png') }}" class="img-fluid"></el-radio>
<el-radio class="rounded-0" label="alipay" border><img src="{{ asset('image/alipay.png') }}" class="img-fluid"></el-radio>
<el-radio class="me-1" label="wechatpay" border><img src="{{ asset('image/wechat.png') }}" class="img-fluid"></el-radio>
<el-radio class="" label="alipay" border><img src="{{ asset('image/alipay.png') }}" class="img-fluid"></el-radio>
</el-radio-group>
</div>
<button class="btn btn-primary btn-lg" @click="marketingBuy">{{ __('admin/marketing.btn_buy') }} ({{ $data['price_format'] }})</button>
<button class="btn btn-primary btn-lg w-min-100 fw-bold" @click="marketingBuy">{{ __('admin/marketing.btn_buy') }}</button>
@endif
@else
<div class="alert alert-warning" role="alert">
@ -95,7 +111,7 @@
@if ($data['description'])
<div class="card h-min-200">
<div class="card-header"><h6 class="card-title">{{ __('admin/marketing.download_description') }}</h6></div>
<div class="card-header"><h5 class="card-title">{{ __('admin/marketing.download_description') }}</h5></div>
<div class="card-body">
{!! $data['description'] !!}
</div>

View File

@ -3,84 +3,84 @@
@section('title', __('admin/page_category.index'))
@section('content')
@if ($errors->has('error'))
<x-admin-alert type="danger" msg="{{ $errors->first('error') }}" class="mt-4" />
@endif
{{-- {{ dd($page_categories_format) }} --}}
<div class="card" id="app">
<div class="card-body h-min-600">
<div class="d-flex justify-content-between mb-4">
<a href="{{ admin_route('page_categories.create') }}" class="btn btn-primary">{{ __('common.add') }}</a>
</div>
<div class="table-push">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>{{ __('common.title') }}</th>
<th>{{ __('common.status') }}</th>
<th>{{ __('common.created_at') }}</th>
<th>{{ __('common.updated_at') }}</th>
@hook('admin.page.list.column')
<th class="text-end">{{ __('common.action') }}</th>
</tr>
</thead>
<tbody>
@if (count($page_categories_format))
@foreach ($page_categories_format as $item)
<tr>
<td>{{ $item['id'] }}</td>
<td>
<div title="{{ $item['title'] ?? '' }}"><a class="text-dark" href="{{ shop_route('pages.show', $item['id']) }}" target="_blank">{{ $item['title_format'] ?? '' }}</a></div>
</td>
<td class="{{ $item['active'] ? 'text-success' : 'text-secondary' }}">
{{ $item['active'] ? __('common.enable') : __('common.disable') }}
</td>
<td>{{ $item['created_at'] }}</td>
<td>{{ $item['updated_at'] }}</td>
@hook('admin.page.list.column_value')
<td class="text-end">
<a href="{{ admin_route('page_categories.edit',$item['id']) }}" class="btn btn-outline-secondary btn-sm" >{{ __('common.edit') }}</a>
<button class="btn btn-outline-danger btn-sm delete-btn" type='button' data-id="{{ $item['id'] }}">{{ __('common.delete') }}</button>
@hook('admin.page.list.action')
</td>
</tr>
@endforeach
@else
<tr><td colspan="5" class="border-0"><x-admin-no-data /></td></tr>
@endif
</tbody>
</table>
</div>
{{ $page_categories->links('admin::vendor/pagination/bootstrap-4') }}
@if ($errors->has('error'))
<x-admin-alert type="danger" msg="{{ $errors->first('error') }}" class="mt-4" />
@endif
<div class="card" id="app">
<div class="card-body h-min-600">
<div class="d-flex justify-content-between mb-4">
<a href="{{ admin_route('page_categories.create') }}" class="btn btn-primary">{{ __('common.add') }}</a>
</div>
<div class="table-push">
@if (count($page_categories_format))
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>{{ __('common.title') }}</th>
<th>{{ __('common.status') }}</th>
<th>{{ __('common.created_at') }}</th>
<th>{{ __('common.updated_at') }}</th>
@hook('admin.page.list.column')
<th class="text-end">{{ __('common.action') }}</th>
</tr>
</thead>
<tbody>
@foreach ($page_categories_format as $item)
<tr>
<td>{{ $item['id'] }}</td>
<td>
<div title="{{ $item['title'] ?? '' }}"><a class="text-dark"
href="{{ shop_route('pages.show', $item['id']) }}" target="_blank">{{ $item['title_format'] ?? ''
}}</a></div>
</td>
<td class="{{ $item['active'] ? 'text-success' : 'text-secondary' }}">
{{ $item['active'] ? __('common.enable') : __('common.disable') }}
</td>
<td>{{ $item['created_at'] }}</td>
<td>{{ $item['updated_at'] }}</td>
@hook('admin.page.list.column_value')
<td class="text-end">
<a href="{{ admin_route('page_categories.edit',$item['id']) }}"
class="btn btn-outline-secondary btn-sm">{{ __('common.edit') }}</a>
<button class="btn btn-outline-danger btn-sm delete-btn" type='button' data-id="{{ $item['id'] }}">{{
__('common.delete') }}</button>
@hook('admin.page.list.action')
</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div><x-admin-no-data /></div>
@endif
</div>
</div>
@hook('admin.page.list.content.footer')
{{ $page_categories->links('admin::vendor/pagination/bootstrap-4') }}
</div>
</div>
@hook('admin.page.list.content.footer')
@endsection
@push('footer')
<script>
$('.delete-btn').click(function(event) {
const id = $(this).data('id');
const self = $(this);
<script>
$('.delete-btn').click(function(event) {
const id = $(this).data('id');
const self = $(this);
layer.confirm('{{ __('common.confirm_delete') }}', {
title: "{{ __('common.text_hint') }}",
btn: ['{{ __('common.cancel') }}', '{{ __('common.confirm') }}'],
area: ['400px'],
btn2: () => {
$http.delete(`page_categories/${id}`).then((res) => {
layer.msg(res.message);
window.location.reload();
})
}
})
});
</script>
@endpush
layer.confirm('{{ __('common.confirm_delete') }}', {
title: "{{ __('common.text_hint') }}",
btn: ['{{ __('common.cancel') }}', '{{ __('common.confirm') }}'],
area: ['400px'],
btn2: () => {
$http.delete(`page_categories/${id}`).then((res) => {
layer.msg(res.message);
window.location.reload();
})
}
})
});
</script>
@endpush

View File

@ -4,83 +4,84 @@
@section('content')
@if ($errors->has('error'))
<x-admin-alert type="danger" msg="{{ $errors->first('error') }}" class="mt-4" />
@endif
<div class="card">
<div class="card-body h-min-600">
<div class="d-flex justify-content-between mb-4">
<a href="{{ admin_route('pages.create') }}" class="btn btn-primary">{{ __('common.add') }}</a>
</div>
<div class="table-push">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>{{ __('common.title') }}</th>
<th>{{ __('common.status') }}</th>
<th>{{ __('common.created_at') }}</th>
<th>{{ __('common.updated_at') }}</th>
@hook('admin.page.list.column')
<th class="text-end">{{ __('common.action') }}</th>
</tr>
</thead>
<tbody>
@if (count($pages_format))
@foreach ($pages_format as $page)
<tr>
<td>{{ $page['id'] }}</td>
<td>
<div title="{{ $page['title'] ?? '' }}"><a class="text-dark" href="{{ shop_route('pages.show', $page['id']) }}" target="_blank">{{ $page['title_format'] ?? '' }}</a></div>
</td>
<td class="{{ $page['active'] ? 'text-success' : 'text-secondary' }}">
{{ $page['active'] ? __('common.enable') : __('common.disable') }}
</td>
<td>{{ $page['created_at'] }}</td>
<td>{{ $page['updated_at'] }}</td>
@hook('admin.page.list.column_value')
<td class="text-end">
<a href="{{ admin_route('pages.edit', [$page['id']]) }}"
class="btn btn-outline-secondary btn-sm">{{ __('common.edit') }}</a>
<button class="btn btn-outline-danger btn-sm delete-btn" type='button'
data-id="{{ $page['id'] }}">{{ __('common.delete') }}</button>
@hook('admin.page.list.action')
</td>
</tr>
@endforeach
@else
<tr><td colspan="5" class="border-0"><x-admin-no-data /></td></tr>
@endif
</tbody>
</table>
</div>
{{ $pages->links('admin::vendor/pagination/bootstrap-4') }}
@if ($errors->has('error'))
<x-admin-alert type="danger" msg="{{ $errors->first('error') }}" class="mt-4" />
@endif
<div class="card">
<div class="card-body h-min-600">
<div class="d-flex justify-content-between mb-4">
<a href="{{ admin_route('pages.create') }}" class="btn btn-primary">{{ __('common.add') }}</a>
</div>
<div class="table-push">
@if (count($pages_format))
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>{{ __('common.title') }}</th>
<th>{{ __('common.status') }}</th>
<th>{{ __('common.created_at') }}</th>
<th>{{ __('common.updated_at') }}</th>
@hook('admin.page.list.column')
<th class="text-end">{{ __('common.action') }}</th>
</tr>
</thead>
<tbody>
@foreach ($pages_format as $page)
<tr>
<td>{{ $page['id'] }}</td>
<td>
<div title="{{ $page['title'] ?? '' }}"><a class="text-dark"
href="{{ shop_route('pages.show', $page['id']) }}" target="_blank">{{ $page['title_format'] ?? ''
}}</a></div>
</td>
<td class="{{ $page['active'] ? 'text-success' : 'text-secondary' }}">
{{ $page['active'] ? __('common.enable') : __('common.disable') }}
</td>
<td>{{ $page['created_at'] }}</td>
<td>{{ $page['updated_at'] }}</td>
@hook('admin.page.list.column_value')
<td class="text-end">
<a href="{{ admin_route('pages.edit', [$page['id']]) }}" class="btn btn-outline-secondary btn-sm">{{
__('common.edit') }}</a>
<button class="btn btn-outline-danger btn-sm delete-btn" type='button' data-id="{{ $page['id'] }}">{{
__('common.delete') }}</button>
@hook('admin.page.list.action')
</td>
</tr>
@endforeach
</tbody>
</table>
@else
<div><x-admin-no-data /></div>
@endif
</div>
</div>
@hook('admin.page.list.content.footer')
{{ $pages->links('admin::vendor/pagination/bootstrap-4') }}
</div>
</div>
@hook('admin.page.list.content.footer')
@endsection
@push('footer')
<script>
$('.delete-btn').click(function(event) {
const id = $(this).data('id');
const self = $(this);
<script>
$('.delete-btn').click(function(event) {
const id = $(this).data('id');
const self = $(this);
layer.confirm('{{ __('common.confirm_delete') }}', {
title: "{{ __('common.text_hint') }}",
btn: ['{{ __('common.cancel') }}', '{{ __('common.confirm') }}'],
area: ['400px'],
btn2: () => {
$http.delete(`pages/${id}`).then((res) => {
layer.msg(res.message);
window.location.reload();
})
}
})
});
</script>
@endpush
layer.confirm('{{ __('common.confirm_delete') }}', {
title: "{{ __('common.text_hint') }}",
btn: ['{{ __('common.cancel') }}', '{{ __('common.confirm') }}'],
area: ['400px'],
btn2: () => {
$http.delete(`pages/${id}`).then((res) => {
layer.msg(res.message);
window.location.reload();
})
}
})
});
</script>
@endpush

View File

@ -4,7 +4,7 @@
@section('page-title-right')
@hookwrapper('admin.plugin.marketing')
<a href="{{ admin_route('marketing.index') }}" class="btn btn-outline-info">{{ __('admin/marketing.marketing_list') }}</a>
<a href="{{ admin_route('marketing.index', isset($type) ? ['type' => $type]: '') }}" class="btn btn-outline-info">{{ __('common.get_more') }}</a>
@endhookwrapper
@endsection
@ -13,7 +13,7 @@
<div id="plugins-app" class="card" v-cloak>
<div class="card-body h-min-600">
<div class="mt-4 table-push" style="">
<table class="table">
<table class="table" v-if="plugins.length">
<thead>
<tr>
<th>{{ __('admin/plugin.plugin_code') }}</th>
@ -24,7 +24,7 @@
</tr>
</thead>
<tbody>
<tr v-for="plugin, index in plugins" :key="index" v-if="plugins.length">
<tr v-for="plugin, index in plugins" :key="index">
<td>@{{ plugin.code }}</td>
<td>@{{ plugin.type_format }}</td>
<td>
@ -54,6 +54,13 @@
</tr>
</tbody>
</table>
<div v-else>
<x-admin-no-data>
<x-slot:text>
{{ __('common.no_data') }} <a href="{{ admin_route('marketing.index', isset($type) ? ['type' => $type]: '') }}" ><i class="bi bi-link-45deg"></i> {{ __('common.get_more') }}</a>
</x-slot>
</x-admin-no-data>
</div>
</div>
</div>
</div>

View File

@ -63,11 +63,13 @@
<div class="d-flex justify-content-between my-4">
@if ($type != 'trashed')
<a href="{{ admin_route('products.create') }}" class="me-1 nowrap">
<button class="btn btn-primary">{{ __('admin/product.products_create') }}</button>
</a>
<a href="{{ admin_route('products.create') }}" class="me-1 nowrap">
<button class="btn btn-primary">{{ __('admin/product.products_create') }}</button>
</a>
@else
<button class="btn btn-primary" @click="clearRestore">{{ __('admin/product.clear_restore') }}</button>
@if ($products->total())
<button class="btn btn-primary" @click="clearRestore">{{ __('admin/product.clear_restore') }}</button>
@endif
@endif
@if ($type != 'trashed' && $products->total())

View File

@ -6,7 +6,10 @@
@section('content')
<div id="customer-app" class="card h-min-600">
<div class="card-header"><h5 class="card-title">{{ __('admin/theme.page_title') }}</h5></div>
<div class="card-header d-flex justify-content-between align-items-start">
<h5 class="card-title">{{ __('admin/theme.page_title') }}</h5>
<a href="{{ admin_route('marketing.index') }}?type=theme" class="btn btn-outline-info">{{ __('common.get_more') }}</a>
</div>
<div class="card-body">
<div class="theme-wrap">
<div class="row">

File diff suppressed because it is too large Load Diff

View File

@ -22,30 +22,30 @@ return [
'has_no_permission' => 'Sie sind nicht berechtigt, auf diese Seite zuzugreifen, wenden Sie sich bitte an Ihren Systemadministrator.',
// header
'home' => 'Startseite verwalten',
'order' => 'Auftragsverwaltung',
'rma' => 'Kundendienstverwaltung',
'rma_reason' => 'Rücksendegrundverwaltung',
'product' => 'Produktmanagement',
'home' => 'Titelseite',
'order' => 'Befehl',
'rma' => 'Kundendienst',
'rma_reason' => 'Rücksendegrund',
'product' => 'Produkt',
'brand' => 'Markenführung',
'attribute' => 'attribute',
'attribute_group' => 'attribute group',
'category' => 'category management',
'customer_group' => 'Kundengruppenverwaltung',
'customer' => 'Kundenverwaltung',
'page' => 'Inhaltsverwaltung',
'customer_group' => 'Kundengruppen',
'customer' => 'Kunden',
'page' => 'Inhalts',
'page_category' => 'Page Category',
'setting' => 'system settings',
'plugin' => 'plugin-verwaltung',
'setting' => 'System',
'plugin' => 'plugin',
'admin_user' => 'Backend-Benutzer',
'admin_role' => 'Benutzerrolle',
'region' => 'Regionsgruppierung',
'tax_rate' => 'Steuersatzverwaltung',
'tax_class' => 'Steuerverwaltung',
'currency' => 'Währungsverwaltung',
'language' => 'Sprachverwaltung',
'zone' => 'Provinzverwaltung',
'country' => 'Landesverwaltung',
'tax_rate' => 'Steuersatz',
'tax_class' => 'Steuer',
'currency' => 'Währungs',
'language' => 'Sprach',
'zone' => 'Provinz',
'country' => 'Landes',
'file_manager' => 'Dateimanager',
'access_frontend' => 'Zugang zum Frontend',
@ -63,11 +63,11 @@ return [
'page_categories_index' => 'Artikelklassifizierung',
'design_footer_index' => 'Fußzeilendekoration',
'design_menu_index' => 'Navigationskonfiguration',
'categories_index' => 'Produktkategorie',
'products_index' => 'Produktverwaltung',
'categories_index' => 'Kategorie',
'products_index' => 'Produkt',
'products_trashed' => 'Papierkorb',
'customers_trashed' => 'Papierkorb',
'brands_index' => 'Produktmarke',
'brands_index' => 'Marke',
'orders_index' => 'Bestellliste',
'rmas_index' => 'Kundendienstverwaltung',
'rma_reasons_index' => 'Nachverkaufsgrund',

View File

@ -10,6 +10,7 @@
*/
return [
'product_total' => 'Product Total',
'customer_view' => 'Benutzerbesuche',
'order_total' => 'Bestellmenge',
'customer_new' => 'Benutzer hinzufügen',

View File

@ -23,6 +23,7 @@ return [
// header
'home' => 'Home',
'home_index' => 'Home',
'order' => 'Orders',
'rma' => 'RMA',
'rma_reason' => 'RMA Reason',
@ -37,6 +38,7 @@ return [
'page_category' => 'Page Category',
'setting' => 'Settings',
'plugin' => 'Plugin',
'design' => 'Design',
'marketing' => 'Plugin Marketing',
'admin_user' => 'Admin User',
'admin_role' => 'Admin Role',
@ -50,6 +52,10 @@ return [
'file_manager' => 'File Manager',
'access_frontend' => 'Frontend',
'copyright_buy' => 'Copyright Buy',
'recent_view' => 'Recently Visited',
'common_link' => 'Common Links',
'header_search_input' => 'Search Features',
'header_search_title' => 'Search Results',
// sidebar
'account_index' => 'Personal Center',

View File

@ -10,6 +10,7 @@
*/
return [
'product_total' => 'Product Total',
'customer_view' => 'Customer View',
'order_total' => 'Order Total',
'customer_new' => 'Customer New',

View File

@ -78,6 +78,7 @@ return [
'text_to' => 'To',
'batch_setting' => 'Batch setting',
'show_all' => 'View all',
'get_more' => 'Get More',
'id' => 'ID',
'created_at' => 'Created At',

View File

@ -10,6 +10,7 @@
*/
return [
'product_total' => 'Product Total',
'customer_view' => 'Visitas de usuarios',
'order_total' => 'Volumen de pedidos',
'customer_new' => 'Usuarios nuevos',

View File

@ -10,6 +10,7 @@
*/
return [
'product_total' => 'Product Total',
'customer_view' => 'visites des utilisateurs',
'order_total' => 'montant de la commande',
'customer_new' => 'Ajouter un utilisateur',

View File

@ -10,6 +10,7 @@
*/
return [
'product_total' => 'Product Total',
'customer_view' => 'Kunjungan pengguna',
'order_total' => 'Volume pesanan',
'customer_new' => 'Tambahkan Pengguna',

View File

@ -10,6 +10,7 @@
*/
return [
'product_total' => 'Product Total',
'customer_view' => 'visite degli utenti',
'order_total' => 'importo dell\'ordine',
'customer_new' => 'Aggiungi utente',

View File

@ -10,6 +10,7 @@
*/
return [
'product_total' => 'Product Total',
'customer_view' => 'ユーザーの訪問',
'order_total' => '注文金額',
'customer_new' => 'ユーザーを追加',

View File

@ -10,6 +10,7 @@
*/
return [
'product_total' => 'Product Total',
'customer_view' => 'посещения пользователей',
'order_total' => 'сумма заказа',
'customer_new' => 'Добавить пользователя',

View File

@ -22,21 +22,23 @@ return [
'has_no_permission' => '您没有权限访问该页面, 请联系系统管理员。',
// header
'home' => '管理首页',
'order' => '订单管理',
'home' => '首页',
'home_index' => '首页',
'order' => '订单',
'rma' => '售后服务管理',
'rma_reason' => '退换货原因管理',
'product' => '商品管理',
'product' => '商品',
'brand' => '品牌管理',
'attribute' => '属性管理',
'attribute_group' => '属性组管理',
'category' => '分类管理',
'customer_group' => '客户组管理',
'customer' => '客户管理',
'page' => '文章管理',
'customer' => '客户',
'page' => '文章',
'page_category' => '文章分类',
'setting' => '系统设置',
'plugin' => '插件管理',
'setting' => '系统',
'plugin' => '插件',
'design' => '设计',
'marketing' => '插件市场',
'admin_user' => '后台用户',
'admin_role' => '用户角色',
@ -50,6 +52,10 @@ return [
'file_manager' => '文件管理器',
'access_frontend' => '访问前台',
'copyright_buy' => '版权购买',
'recent_view' => '最近访问',
'common_link' => '常用链接',
'header_search_input' => '搜索后台功能',
'header_search_title' => '搜索结果',
// sidebar
'account_index' => '个人中心',

View File

@ -20,7 +20,7 @@ return [
'get_token' => '点击获取 Token',
'download_count' => '下载次数',
'last_update' => '最后更新',
'text_version' => '版本',
'text_version' => '插件版本',
'text_compatibility' => '兼容性',
'text_author' => '插件作者',
'download_plugin' => '下载插件',

View File

@ -66,6 +66,7 @@ return [
'favicon' => 'favicon',
'favicon_info' => '显示在浏览器选项卡上的小图标必须为PNG格式大小为32*32',
'placeholder_image' => '占位图',
'placeholder_image_info' => '没有图片或找不到图片时显示的占位图片推荐尺寸500*500',
'head_code' => '插入代码',
'head_code_info' => '会将输入框中的代码插入到前端页面 head 中,可用于统计代码或者添加特殊插件等',
'rate_api_key' => '汇率 API KEY',

View File

@ -77,6 +77,7 @@ return [
'text_to' => '到',
'batch_setting' => '批量设置',
'show_all' => '查看所有',
'get_more' => '获取更多',
'id' => 'ID',
'created_at' => '创建时间',

View File

@ -22,21 +22,23 @@ return [
'has_no_permission' => '您沒有權限訪問該頁面, 請聯繫系統管理員。 ',
// header
'home' => '管理首頁',
'order' => '訂單管理',
'home' => '首頁',
'home_index' => '首頁',
'order' => '訂單',
'rma' => '售後服務管理',
'rma_reason' => '退換貨原因管理',
'product' => '商品管理',
'product' => '商品',
'brand' => '品牌管理',
'attribute' => '屬性管理',
'attribute_group' => '屬性組管理',
'category' => '分類管理',
'customer_group' => '客戶組管理',
'customer' => '客戶管理',
'page' => '文章管理',
'customer' => '客戶',
'page' => '文章',
'page_category' => '文章分類',
'setting' => '系統設置',
'plugin' => '插件管理',
'setting' => '系統',
'plugin' => '插件',
'design' => '設計',
'marketing' => '插件市場',
'admin_user' => '後台用戶',
'admin_role' => '用戶角色',
@ -50,8 +52,13 @@ return [
'file_manager' => '文件管理器',
'access_frontend' => '訪問前台',
'copyright_buy' => '版權購買',
'recent_view' => '最近訪問',
'common_link' => '常用鏈接',
'header_search_input' => '搜索後台功能',
'header_search_title' => '搜索結果',
// sidebar
'account_index' => '個人中心',
'multi_filter_index' => '高級篩選',
'theme_index' => '模板設置',
'attribute_groups_index' => '屬性組',

View File

@ -10,6 +10,7 @@
*/
return [
'product_total' => '產品總數',
'customer_view' => '用戶訪問量',
'order_total' => '訂單量',
'customer_new' => '新增用戶',

View File

@ -77,6 +77,7 @@ return [
'text_to' => '到',
'batch_setting' => '批量設置',
'show_all' => '查看所有',
'get_more' => '獲取更多',
'id' => 'ID',
'created_at' => '創建時間',

View File

@ -14,7 +14,7 @@
<script src="{{ asset('vendor/jquery/jquery-3.6.0.min.js') }}"></script>
<script src="{{ asset('vendor/layer/3.5.1/layer.js') }}"></script>
<link rel="shortcut icon" href="{{ image_origin(system_setting('base.favicon')) }}">
<script src="{{ asset('vendor/bootstrap/5.1.3/js/bootstrap.bundle.min.js') }}"></script>
<script src="{{ asset('vendor/bootstrap/js/bootstrap.bundle.min.js') }}"></script>
<script src="{{ mix('/build/beike/shop/'.system_setting('base.theme').'/js/app.js') }}"></script>
<link rel="stylesheet" type="text/css" href="{{ mix('/build/beike/shop/'.system_setting('base.theme').'/css/app.css') }}">
@if (system_setting('base.head_code'))

View File

@ -415,5 +415,14 @@
$('#zoom').trigger('zoom.destroy');
$('#zoom').zoom({url: $('#swiper a').attr('data-zoom-image')});
});
const selectedVariantsIndex = app.selectedVariantsIndex;
const variables = app.source.variables;
const selectedVariants = variables.map((variable, index) => {
return variable.values[selectedVariantsIndex[index]]
});
console.log(selectedVariants);
</script>
@endpush