!86 Optimization Advanced filters, taxes, currencies, etc.
* Fix region configuration province selection problem * Optimization Advanced filters, taxes, currencies, etc.
This commit is contained in:
parent
2956a536ff
commit
76b37ed867
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* AttributeController.php
|
||||
*
|
||||
* @copyright 2023 beikeshop.com - All Rights Reserved
|
||||
* @link https://beikeshop.com
|
||||
* @author TL <mengwb@guangda.work>
|
||||
* @created 2023-01-04 19:45:41
|
||||
* @modified 2023-01-04 19:45:41
|
||||
*/
|
||||
|
||||
namespace Beike\Admin\Http\Controllers;
|
||||
|
||||
use Beike\Admin\Repositories\AttributeRepo;
|
||||
use Beike\Repositories\SettingRepo;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class MultiFilterController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
$multiFilter = system_setting('base.multi_filter');
|
||||
if ($attributeIds = $multiFilter['attribute'] ?? []) {
|
||||
$multiFilter['attribute'] = AttributeRepo::getByIds($attributeIds);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'multi_filter' => $multiFilter,
|
||||
];
|
||||
|
||||
return view('admin::pages.multi_filter.index', $data);
|
||||
}
|
||||
|
||||
public function store(Request $request)
|
||||
{
|
||||
$settings = $request->all();
|
||||
foreach ($settings as $key => $value) {
|
||||
SettingRepo::storeValue($key, $value);
|
||||
}
|
||||
|
||||
return redirect(admin_route('multi_filter.index'))->with('success', trans('common.updated_success'));
|
||||
}
|
||||
}
|
||||
|
|
@ -12,7 +12,6 @@
|
|||
namespace Beike\Admin\Http\Controllers;
|
||||
|
||||
use Beike\Admin\Http\Resources\CustomerGroupDetail;
|
||||
use Beike\Admin\Repositories\AttributeRepo;
|
||||
use Beike\Repositories\CountryRepo;
|
||||
use Beike\Repositories\CurrencyRepo;
|
||||
use Beike\Repositories\CustomerGroupRepo;
|
||||
|
|
@ -35,15 +34,10 @@ class SettingController extends Controller
|
|||
['value' => 'shipping', 'label' => trans('admin/setting.shipping_address')],
|
||||
['value' => 'payment', 'label' => trans('admin/setting.payment_address')],
|
||||
];
|
||||
$multiFilter = system_setting('base.multi_filter');
|
||||
if ($attributeIds = $multiFilter['attribute'] ?? []) {
|
||||
$multiFilter['attribute'] = AttributeRepo::getByIds($attributeIds);
|
||||
}
|
||||
|
||||
$data = [
|
||||
'countries' => CountryRepo::listEnabled(),
|
||||
'currencies' => CurrencyRepo::listEnabled(),
|
||||
'multi_filter' => $multiFilter,
|
||||
'tax_address' => $taxAddress,
|
||||
'customer_groups' => CustomerGroupDetail::collection(CustomerGroupRepo::list())->jsonSerialize(),
|
||||
'themes' => $themes,
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ class PermissionRepo
|
|||
*/
|
||||
private function getProductPermissions(): array
|
||||
{
|
||||
$routes = ['products_index', 'products_create', 'products_show', 'products_update', 'products_delete', 'products_trashed', 'products_restore'];
|
||||
$routes = ['products_index', 'products_create', 'products_show', 'products_update', 'products_delete', 'products_trashed', 'products_restore', 'products_filter_index', 'products_filter_update'];
|
||||
$items = $this->getPermissionList('product', $routes);
|
||||
|
||||
return hook_filter('role.product_permissions', $items);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,10 @@ Route::prefix($adminName)
|
|||
Route::middleware('can:attributes_update')->put('attributes/{id}', [Controllers\AttributeController::class, 'update'])->name('attributes.update');
|
||||
Route::middleware('can:attributes_delete')->delete('attributes/{id}', [Controllers\AttributeController::class, 'destroy'])->name('attributes.destroy');
|
||||
|
||||
// 高级筛选
|
||||
Route::middleware('can:products_filter_index')->get('multi_filter', [Controllers\MultiFilterController::class, 'index'])->name('multi_filter.index');
|
||||
Route::middleware('can:products_filter_update')->post('multi_filter', [Controllers\MultiFilterController::class, 'store'])->name('multi_filter.store');
|
||||
|
||||
// 属性组
|
||||
Route::middleware('can:attribute_groups_index')->get('attribute_groups', [Controllers\AttributeGroupController::class, 'index'])->name('attribute_groups.index');
|
||||
Route::middleware('can:attribute_groups_create')->post('attribute_groups', [Controllers\AttributeGroupController::class, 'store'])->name('attribute_groups.store');
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ class Sidebar extends Component
|
|||
*/
|
||||
private function getProductSubPrefix()
|
||||
{
|
||||
$prefix = ['products.', 'categories.', 'brands.', 'attribute_groups.', 'attributes.'];
|
||||
$prefix = ['products.', 'multi_filter.', 'categories.', 'brands.', 'attribute_groups.', 'attributes.'];
|
||||
|
||||
return hook_filter('admin.sidebar.product.prefix', $prefix);
|
||||
}
|
||||
|
|
@ -190,11 +190,12 @@ class Sidebar extends Component
|
|||
public function getProductSubRoutes()
|
||||
{
|
||||
$routes = [
|
||||
['route' => 'categories.index', 'icon' => 'fa fa-tachometer-alt'],
|
||||
['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'],
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -13,8 +13,6 @@
|
|||
"axios": "^0.21",
|
||||
"bootstrap": "^5.2.1",
|
||||
"bootstrap-5.1.3": "npm:bootstrap@5.1.3",
|
||||
"browser-sync": "^2.27.10",
|
||||
"browser-sync-webpack-plugin": "^2.3.0",
|
||||
"laravel-mix": "^6.0.6",
|
||||
"lodash": "^4.17.19",
|
||||
"resolve-url-loader": "^4.0.0",
|
||||
|
|
|
|||
|
|
@ -524,4 +524,19 @@ table.table thead th, .fw-bold, h1,h2,h3, h4, h5, h6, b, strong, .card .card-hea
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.active-line {
|
||||
position: relative;
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: calc(100% + 1rem);
|
||||
background-color: rgba($primary, 0.04);
|
||||
border: 1px dashed rgba($primary, 0.5);
|
||||
}
|
||||
}
|
||||
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
@hookwrapper('admin.header.vip')
|
||||
<li class="nav-item vip-serve">
|
||||
<a href="{{ config('beike.api_url') }}/vip/subscription?domain={{ config('app.url') }}&developer_token={{ system_setting('base.developer_token') }}" target="_blank" class="nav-link">
|
||||
<a href="{{ config('beike.api_url') }}/vip/subscription?domain={{ config('app.url') }}&developer_token={{ system_setting('base.developer_token') }}&type=tab-vip" target="_blank" class="nav-link">
|
||||
<img src="/image/vip-icon.png" class="img-fluid">
|
||||
<span class="vip-text ms-1">VIP</span>
|
||||
<div class="expired-text text-danger ms-2" style="display: none">@lang('admin/common.expired_at'):<span class="ms-0"></span></div>
|
||||
|
|
@ -28,6 +28,14 @@
|
|||
</li>
|
||||
@endhookwrapper
|
||||
|
||||
@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>
|
||||
</a>
|
||||
</li>
|
||||
@endhookwrapper
|
||||
|
||||
@hookwrapper('admin.header.marketing')
|
||||
<li class="nav-item">
|
||||
<a href="{{ admin_route('marketing.index') }}" class="nav-link">@lang('admin/common.marketing')</a>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
@section('title', __('admin/common.currency'))
|
||||
|
||||
@section('page-title-right')
|
||||
<a href="{{ admin_route('settings.index') }}?tab=tab-checkout&line=rate_api_key" class="btn btn-outline-info" target="_blank">{{ __('admin/setting.rate_api_key') }}</a>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<div id="tax-classes-app" class="card" v-cloak>
|
||||
<div class="card-body h-min-600">
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
<th>ID</th>
|
||||
<th>{{ __('common.name') }}</th>
|
||||
<th>{{ __('admin/region.describe') }}</th>
|
||||
<th>{{ __('customer_group.level') }}</th>
|
||||
{{-- <th>{{ __('customer_group.level') }}</th> --}}
|
||||
<th>{{ __('common.created_at') }}</th>
|
||||
<th width="130px">{{ __('common.action') }}</th>
|
||||
</tr>
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
<div :title="group.description?.description || ''" class="w-max-500">
|
||||
@{{ stringLengthInte(group.description?.description || '') }}</div>
|
||||
</td>
|
||||
<td>@{{ group.level }}</td>
|
||||
{{-- <td>@{{ group.level }}</td> --}}
|
||||
<td>@{{ group.created_at }}</td>
|
||||
<td>
|
||||
<button class="btn btn-outline-secondary btn-sm" @click="checkedCustomersCreate('edit', index)">{{ __('common.edit') }}</button>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,114 @@
|
|||
@extends('admin::layouts.master')
|
||||
|
||||
@section('title', __('admin/common.multi_filter_index'))
|
||||
|
||||
@section('content')
|
||||
<div class="card">
|
||||
<div class="card-body h-min-600">
|
||||
<form action="{{ admin_route('multi_filter.store') }}" class="needs-validation" novalidate method="POST" id="app">
|
||||
@csrf
|
||||
@if (session('success'))
|
||||
<x-admin-alert type="success" msg="{{ session('success') }}" class="mt-4"/>
|
||||
@endif
|
||||
<h6 class="border-bottom pb-3 mb-4">{{ __('common.data') }}</h6>
|
||||
|
||||
<x-admin::form.row :title="__('admin/setting.filter_attribute')">
|
||||
<div class="module-edit-group wp-600">
|
||||
<div class="autocomplete-group-wrapper">
|
||||
<el-autocomplete class="inline-input" v-model="multi_filter.keyword" value-key="name" size="small"
|
||||
:fetch-suggestions="(keyword, cb) => {attributesQuerySearch(keyword, cb, 'products')}"
|
||||
placeholder="{{ __('admin/builder.modules_keywords_search') }}"
|
||||
@select="(e) => {handleSelect(e, 'product_attributes')}"></el-autocomplete>
|
||||
|
||||
<div class="item-group-wrapper" v-loading="multi_filter.loading">
|
||||
<template v-if="multi_filter.filters.attribute.length">
|
||||
<div v-for="(item, index) in multi_filter.filters.attribute" :key="index" class="item">
|
||||
<div>
|
||||
<i class="el-icon-s-unfold"></i>
|
||||
<span>@{{ item.name }}</span>
|
||||
</div>
|
||||
<i class="el-icon-delete right" @click="attributesRemoveProduct(index)"></i>
|
||||
<input type="text" :name="'multi_filter[attribute]['+ index +']'" v-model="item.id"
|
||||
class="form-control d-none">
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ __('admin/setting.please_select') }}
|
||||
<input type="text" name="multi_filter" value="" class="form-control d-none">
|
||||
</template>
|
||||
</div>
|
||||
<div class="help-text font-size-12 lh-base">{{ __('admin/setting.multi_filter_helper') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-admin::form.row>
|
||||
|
||||
<x-admin-form-switch name="multi_filter[price_filter]" :title="__('admin/multi_filter.price_filter')" :value="old('price_filter', $multi_filter['price_filter'] ?? 1)" />
|
||||
|
||||
<x-admin::form.row title="">
|
||||
<button class="btn btn-lg btn-primary mt-5">{{ __('common.save') }}</button>
|
||||
</x-admin::form.row>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('footer')
|
||||
<script>
|
||||
let app = new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
multi_filter: {
|
||||
keyword: '',
|
||||
filters: @json($multi_filter ?? null),
|
||||
loading: null,
|
||||
},
|
||||
|
||||
source: {
|
||||
mailEngines: [
|
||||
{name: '{{ __('admin/builder.text_no') }}', code: ''},
|
||||
{name: 'SMTP', code: 'smtp'},
|
||||
{name: 'Sendmail', code: 'sendmail'},
|
||||
{name: 'Mailgun', code: 'mailgun'},
|
||||
{name: 'Log', code: 'log'},
|
||||
]
|
||||
},
|
||||
},
|
||||
created() {
|
||||
const multi_filter = @json($multi_filter ?? null);
|
||||
if (multi_filter) {
|
||||
this.multi_filter.filters = multi_filter;
|
||||
} else {
|
||||
this.multi_filter.filters = {
|
||||
attribute: [],
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
attributesQuerySearch(keyword, cb, url) {
|
||||
$http.get('attributes/autocomplete?name=' + encodeURIComponent(keyword), null, {hload:true}).then((res) => {
|
||||
cb(res.data);
|
||||
})
|
||||
},
|
||||
|
||||
attributesRemoveProduct(index) {
|
||||
this.multi_filter.filters.attribute.splice(index, 1);
|
||||
},
|
||||
|
||||
handleSelect(item, key) {
|
||||
if (key == 'product_attributes') {
|
||||
if (!this.multi_filter.filters.attribute.find(v => v.id * 1 == item.id * 1)) {
|
||||
this.multi_filter.filters.attribute.push(item);
|
||||
} else {
|
||||
layer.msg('{{ __('common.no_repeat') }}', () => {})
|
||||
}
|
||||
|
||||
this.multi_filter.keyword = ""
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
|
||||
|
||||
|
|
@ -3,98 +3,108 @@
|
|||
@section('title', __('admin/region.index'))
|
||||
|
||||
@section('content')
|
||||
<div id="tax-classes-app" class="card" v-cloak>
|
||||
<div class="card-body h-min-600">
|
||||
<div class="d-flex justify-content-between mb-4">
|
||||
<button type="button" class="btn btn-primary" @click="checkedCreate('add', null)">{{ __('common.add') }}</button>
|
||||
</div>
|
||||
<div class="table-push">
|
||||
<table class="table">
|
||||
<div id="tax-classes-app" class="card" v-cloak>
|
||||
<div class="card-body h-min-600">
|
||||
<div class="d-flex justify-content-between mb-4">
|
||||
<button type="button" class="btn btn-primary" @click="checkedCreate('add', null)">{{ __('common.add') }}</button>
|
||||
</div>
|
||||
<div class="table-push">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>{{ __('admin/region.name') }}</th>
|
||||
<th>{{ __('admin/region.describe') }}</th>
|
||||
<th>{{ __('common.created_at') }}</th>
|
||||
<th>{{ __('common.updated_at') }}</th>
|
||||
<th class="text-end">{{ __('common.action') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-if="regions.length">
|
||||
<tr v-for="tax, index in regions" :key="index">
|
||||
<td>@{{ tax.id }}</td>
|
||||
<td>@{{ tax.name }}</td>
|
||||
<td :title="tax.description">@{{ stringLengthInte(tax.description) }}</td>
|
||||
<td>@{{ tax.created_at }}</td>
|
||||
<td>@{{ tax.updated_at }}</td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-outline-secondary btn-sm" @click="checkedCreate('edit', index)">{{
|
||||
__('common.edit') }}</button>
|
||||
<button class="btn btn-outline-danger btn-sm ml-1" type="button" @click="deleteCustomer(tax.id, index)">{{
|
||||
__('common.delete') }}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody v-else>
|
||||
<tr>
|
||||
<td colspan="6" class="border-0">
|
||||
<x-admin-no-data />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog title="{{ __('admin/region.regions_create') }}" :visible.sync="dialog.show" width="700px"
|
||||
@close="closeCustomersDialog('form')" :close-on-click-modal="false" @open="openDialog">
|
||||
|
||||
<el-form ref="form" :rules="rules" :model="dialog.form" label-width="120px">
|
||||
<el-form-item label="{{ __('common.name') }}" prop="name">
|
||||
<el-input v-model="dialog.form.name" placeholder="{{ __('common.name') }}"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="{{ __('admin/region.describe') }}" prop="description">
|
||||
<el-input v-model="dialog.form.description" placeholder="{{ __('admin/region.describe') }}"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="{{ __('admin/region.index') }}">
|
||||
<table class="table table-bordered" style="line-height: 1.6;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>{{ __('admin/region.name') }}</th>
|
||||
<th>{{ __('admin/region.describe') }}</th>
|
||||
<th>{{ __('common.created_at') }}</th>
|
||||
<th>{{ __('common.updated_at') }}</th>
|
||||
<th class="text-end">{{ __('common.action') }}</th>
|
||||
<th>{{ __('admin/region.country') }}</th>
|
||||
<th>{{ __('admin/region.zone') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-if="regions.length">
|
||||
<tr v-for="tax, index in regions" :key="index">
|
||||
<td>@{{ tax.id }}</td>
|
||||
<td>@{{ tax.name }}</td>
|
||||
<td :title="tax.description">@{{ stringLengthInte(tax.description) }}</td>
|
||||
<td>@{{ tax.created_at }}</td>
|
||||
<td>@{{ tax.updated_at }}</td>
|
||||
<td class="text-end">
|
||||
<button class="btn btn-outline-secondary btn-sm" @click="checkedCreate('edit', index)">{{ __('common.edit') }}</button>
|
||||
<button class="btn btn-outline-danger btn-sm ml-1" type="button" @click="deleteCustomer(tax.id, index)">{{ __('common.delete') }}</button>
|
||||
<tbody>
|
||||
<tr v-for="rule, index in dialog.form.region_zones" :key="index">
|
||||
<td>
|
||||
<el-select v-model="rule.country_id" size="mini" filterable
|
||||
placeholder="{{ __('admin/customer.choose_country') }}" @change="(e) => {countryChange(e, index)}">
|
||||
<el-option v-for="item, option_index in source.countries" :key="index + '-' + option_index" :label="item.name" :value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</td>
|
||||
<td>
|
||||
<el-select v-model="rule.zone_id" size="mini" filterable
|
||||
placeholder="{{ __('admin/customer.choose_zones') }}">
|
||||
<el-option v-for="item, option_index in rule.zones" :key="index + '-' + option_index" :label="item.name" :value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-outline-danger btn-sm ml-1" type="button" @click="deleteRates(index)">{{
|
||||
__('common.delete') }}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody v-else><tr><td colspan="6" class="border-0"><x-admin-no-data /></td></tr></tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-dialog title="{{ __('admin/region.regions_create') }}" :visible.sync="dialog.show" width="700px"
|
||||
@close="closeCustomersDialog('form')" :close-on-click-modal="false">
|
||||
|
||||
<el-form ref="form" :rules="rules" :model="dialog.form" label-width="120px">
|
||||
<el-form-item label="{{ __('common.name') }}" prop="name">
|
||||
<el-input v-model="dialog.form.name" placeholder="{{ __('common.name') }}"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="{{ __('admin/region.describe') }}" prop="description">
|
||||
<el-input v-model="dialog.form.description" placeholder="{{ __('admin/region.describe') }}"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="{{ __('admin/region.index') }}">
|
||||
<table class="table table-bordered" style="line-height: 1.6;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('admin/region.country') }}</th>
|
||||
<th>{{ __('admin/region.zone') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="rule, index in dialog.form.region_zones" :key="index">
|
||||
<td>
|
||||
<el-select v-model="rule.country_id" size="mini" filterable placeholder="{{ __('admin/customer.choose_country') }}" @change="(e) => {countryChange(e, index)}">
|
||||
<el-option v-for="item in source.countries" :key="item.id" :label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</td>
|
||||
<td>
|
||||
<el-select v-model="rule.zone_id" size="mini" filterable placeholder="{{ __('admin/customer.choose_zones') }}">
|
||||
<el-option v-for="item in rule.zones" :key="item.id" :label="item.name"
|
||||
:value="item.id">
|
||||
</el-option>
|
||||
</el-select>
|
||||
</td>
|
||||
<td>
|
||||
<button class="btn btn-outline-danger btn-sm ml-1" type="button" @click="deleteRates(index)">{{ __('common.delete') }}</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<el-button type="primary" icon="el-icon-plus" size="small" plain @click="addRates">{{ __('common.add') }}</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item class="mt-5">
|
||||
<el-button type="primary" @click="addFormSubmit('form')">{{ __('common.save') }}</el-button>
|
||||
<el-button @click="closeCustomersDialog('form')">{{ __('common.cancel') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</div>
|
||||
<el-button type="primary" icon="el-icon-plus" size="small" plain @click="addRates">{{ __('common.add') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<el-form-item class="mt-5">
|
||||
<el-button type="primary" @click="addFormSubmit('form')">{{ __('common.save') }}</el-button>
|
||||
<el-button @click="closeCustomersDialog('form')">{{ __('common.cancel') }}</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-dialog>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@push('footer')
|
||||
<script>
|
||||
new Vue({
|
||||
<script>
|
||||
new Vue({
|
||||
el: '#tax-classes-app',
|
||||
|
||||
data: {
|
||||
|
|
@ -129,7 +139,10 @@
|
|||
// 在挂载开始之前被调用:相关的 render 函数首次被调用
|
||||
beforeMount() {
|
||||
$http.get(`countries/${this.source.country_id}/zones`).then((res) => {
|
||||
this.dialog.zones = res.data.zones
|
||||
this.dialog.zones = [
|
||||
{name: '{{ __('common.please_choose') }}', id: 0},
|
||||
...res.data.zones
|
||||
]
|
||||
})
|
||||
},
|
||||
|
||||
|
|
@ -138,13 +151,16 @@
|
|||
this.dialog.show = true
|
||||
this.dialog.type = type
|
||||
this.dialog.index = index
|
||||
},
|
||||
|
||||
if (type == 'edit') {
|
||||
let tax = this.regions[index];
|
||||
openDialog() {
|
||||
if (this.dialog.type == 'edit') {
|
||||
let tax = this.regions[this.dialog.index];
|
||||
|
||||
tax.region_zones.forEach(e => {
|
||||
$http.get(`countries/${e.country_id}/zones`).then((res) => {
|
||||
this.$set(e, 'zones', res.data.zones)
|
||||
let zones = [{name: '{{ __('common.please_choose') }}', id: 0}, ...res.data.zones]
|
||||
this.$set(e, 'zones', zones)
|
||||
})
|
||||
})
|
||||
|
||||
|
|
@ -163,7 +179,7 @@
|
|||
|
||||
this.dialog.form.region_zones.push({
|
||||
country_id: this.source.country_id,
|
||||
zone_id: '',
|
||||
zone_id: 0,
|
||||
zones: this.dialog.zones,
|
||||
})
|
||||
},
|
||||
|
|
@ -196,8 +212,11 @@
|
|||
|
||||
countryChange(e, index) {
|
||||
$http.get(`countries/${e}/zones`).then((res) => {
|
||||
this.dialog.form.region_zones[index].zones = res.data.zones
|
||||
this.dialog.form.region_zones[index].zone_id = ''
|
||||
this.dialog.form.region_zones[index].zones = [
|
||||
{name: '{{ __('common.please_choose') }}', id: 0},
|
||||
...res.data.zones
|
||||
]
|
||||
this.dialog.form.region_zones[index].zone_id = 0
|
||||
})
|
||||
},
|
||||
|
||||
|
|
@ -222,5 +241,5 @@
|
|||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@endpush
|
||||
</script>
|
||||
@endpush
|
||||
|
|
@ -5,6 +5,7 @@
|
|||
@section('content')
|
||||
<div id="customer-app" class="card h-min-600">
|
||||
<div class="card-body">
|
||||
<div class="mb-2">{{ __('admin/rma.rma_list_title') }}</div>
|
||||
@if (count($rmas))
|
||||
<div class="table-push">
|
||||
<table class="table">
|
||||
|
|
|
|||
|
|
@ -30,9 +30,6 @@
|
|||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link" data-bs-toggle="tab" href="#tab-express-company">{{ __('order.express_company') }}</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link" data-bs-toggle="tab" href="#tab-multi-filter">{{ __('admin/setting.multi_filter') }}</a>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<a class="nav-link" data-bs-toggle="tab" href="#tab-mail">{{ __('admin/setting.mail_settings') }}</a>
|
||||
</li>
|
||||
|
|
@ -119,42 +116,6 @@
|
|||
@hook('admin.setting.image.after')
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="tab-multi-filter">
|
||||
<x-admin::form.row :title="__('admin/setting.filter_attribute')">
|
||||
<div class="module-edit-group wp-600">
|
||||
<div class="autocomplete-group-wrapper">
|
||||
<el-autocomplete
|
||||
class="inline-input"
|
||||
v-model="multi_filter.keyword"
|
||||
value-key="name"
|
||||
size="small"
|
||||
:fetch-suggestions="(keyword, cb) => {attributesQuerySearch(keyword, cb, 'products')}"
|
||||
placeholder="{{ __('admin/builder.modules_keywords_search') }}"
|
||||
@select="(e) => {handleSelect(e, 'product_attributes')}"
|
||||
></el-autocomplete>
|
||||
|
||||
<div class="item-group-wrapper" v-loading="multi_filter.loading">
|
||||
<template v-if="multi_filter.filters.attribute.length">
|
||||
<div v-for="(item, index) in multi_filter.filters.attribute" :key="index" class="item">
|
||||
<div>
|
||||
<i class="el-icon-s-unfold"></i>
|
||||
<span>@{{ item.name }}</span>
|
||||
</div>
|
||||
<i class="el-icon-delete right" @click="attributesRemoveProduct(index)"></i>
|
||||
<input type="text" :name="'multi_filter[attribute]['+ index +']'" v-model="item.id" class="form-control d-none">
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ __('admin/setting.please_select') }}
|
||||
<input type="text" name="multi_filter" value="" class="form-control d-none">
|
||||
</template>
|
||||
</div>
|
||||
<div class="help-text font-size-12 lh-base">{{ __('admin/setting.multi_filter_helper') }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</x-admin::form.row>
|
||||
</div>
|
||||
|
||||
<div class="tab-pane fade" id="tab-express-company">
|
||||
@hook('admin.setting.express.before')
|
||||
<x-admin::form.row title="{{ __('order.express_company') }}">
|
||||
|
|
@ -293,24 +254,31 @@
|
|||
}
|
||||
|
||||
$(function() {
|
||||
const [tab, line] = [bk.getQueryString('tab'), bk.getQueryString('line')];
|
||||
getZones(country_id);
|
||||
|
||||
$('select[name="country_id"]').on('change', function () {
|
||||
getZones($(this).val());
|
||||
});
|
||||
|
||||
if (tab) {
|
||||
$(`a[href="#${tab}"]`)[0].click()
|
||||
}
|
||||
|
||||
if (line) {
|
||||
$(`textarea[name="${line}"], select[name="${line}"], input[name="${line}"]`).parents('.row').addClass('active-line');
|
||||
|
||||
setTimeout(() => {
|
||||
$('div').removeClass('active-line');
|
||||
}, 1200);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
new Vue({
|
||||
let app = new Vue({
|
||||
el: '#app',
|
||||
data: {
|
||||
multi_filter: {
|
||||
keyword: '',
|
||||
filters: @json($multi_filter ?? null),
|
||||
loading: null,
|
||||
},
|
||||
|
||||
mail_engine: @json(old('mail_engine', system_setting('base.mail_engine', ''))),
|
||||
express_company: @json(old('express_company', system_setting('base.express_company', []))),
|
||||
|
||||
|
|
@ -324,16 +292,6 @@
|
|||
]
|
||||
},
|
||||
},
|
||||
created() {
|
||||
const multi_filter = @json($multi_filter ?? null);
|
||||
if (multi_filter) {
|
||||
this.multi_filter.filters = multi_filter;
|
||||
} else {
|
||||
this.multi_filter.filters = {
|
||||
attribute: [],
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addCompany() {
|
||||
if (typeof this.express_company == 'string') {
|
||||
|
|
@ -342,35 +300,8 @@
|
|||
|
||||
this.express_company.push({name: '', code: ''})
|
||||
},
|
||||
|
||||
attributesQuerySearch(keyword, cb, url) {
|
||||
$http.get('attributes/autocomplete?name=' + encodeURIComponent(keyword), null, {hload:true}).then((res) => {
|
||||
cb(res.data);
|
||||
})
|
||||
},
|
||||
|
||||
attributesRemoveProduct(index) {
|
||||
this.multi_filter.filters.attribute.splice(index, 1);
|
||||
},
|
||||
|
||||
handleSelect(item, key) {
|
||||
if (key == 'product_attributes') {
|
||||
if (!this.multi_filter.filters.attribute.find(v => v.id * 1 == item.id * 1)) {
|
||||
this.multi_filter.filters.attribute.push(item);
|
||||
} else {
|
||||
layer.msg('{{ __('common.no_repeat') }}', () => {})
|
||||
}
|
||||
|
||||
this.multi_filter.keyword = ""
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
const tab = bk.getQueryString('tab');
|
||||
if (tab) {
|
||||
$(`a[href="#${bk.getQueryString('tab')}"]`)[0].click()
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
@section('title', __('admin/tax_rate.tax_classes_index'))
|
||||
|
||||
@section('page-title-right')
|
||||
<a href="{{ admin_route('settings.index') }}?tab=tab-checkout&line=tax_address" class="btn btn-outline-info" target="_blank">{{ __('admin/setting.tax_address') }}</a>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<ul class="nav-bordered nav nav-tabs mb-3">
|
||||
<li class="nav-item">
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
@section('title', __('admin/tax_rate.index'))
|
||||
|
||||
@section('page-title-right')
|
||||
<a href="{{ admin_route('settings.index') }}?tab=tab-checkout&line=tax_address" class="btn btn-outline-info" target="_blank">{{ __('admin/setting.tax_address') }}</a>
|
||||
@endsection
|
||||
|
||||
@section('content')
|
||||
<ul class="nav-bordered nav nav-tabs mb-3">
|
||||
<li class="nav-item">
|
||||
|
|
|
|||
|
|
@ -49,8 +49,10 @@ return [
|
|||
'country' => 'Country',
|
||||
'file_manager' => 'File Manager',
|
||||
'access_frontend' => 'Frontend',
|
||||
'copyright_buy' => 'Copyright Buy',
|
||||
|
||||
// sidebar
|
||||
'multi_filter_index' => 'Advanced Filter',
|
||||
'theme_index' => 'Theme Setting',
|
||||
'attribute_groups_index' => 'Attribute Group',
|
||||
'attributes_index' => 'Attributes',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
/**
|
||||
* header.php
|
||||
*
|
||||
* @copyright 2022 beikeshop.com - All Rights Reserved
|
||||
* @link https://beikeshop.com
|
||||
* @author Edward Yang <yangjin@guangda.work>
|
||||
* @created 2022-08-02 19:03:19
|
||||
* @modified 2022-08-02 19:03:19
|
||||
*/
|
||||
|
||||
return [
|
||||
'price_filter' => 'Price Filter',
|
||||
];
|
||||
|
|
@ -18,6 +18,8 @@ return [
|
|||
'products_trashed' => 'Trashed',
|
||||
'products_restore' => 'Restore',
|
||||
'clear_restore' => 'Empty Recycle Bin',
|
||||
'products_filter_index' => 'View Filters',
|
||||
'products_filter_update' => 'Modify Filters',
|
||||
|
||||
'batch_delete' => 'Batch Delete',
|
||||
'batch_active' => 'Batch Active',
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ return [
|
|||
'rmas_update' => 'Update',
|
||||
'rmas_delete' => 'Delete',
|
||||
|
||||
'rma_list_title' => 'Rmas application list',
|
||||
'customers_name' => 'Customers Name',
|
||||
'quantity' => 'Quantity',
|
||||
'service_type' => 'Service Type',
|
||||
|
|
|
|||
|
|
@ -73,6 +73,6 @@ return [
|
|||
'rate_api_key' => 'Exchange rate API KEY',
|
||||
'multi_filter' => 'Multi Filter',
|
||||
'please_select' => 'Please select',
|
||||
'multi_filter_helper' => 'Please select the attributes to be displayed in the Multi Filter module.',
|
||||
'multi_filter_helper' => 'Please select the attributes that need to be displayed in the filter area of the product list at the front desk, if left blank, all will be displayed',
|
||||
'filter_attribute' => 'Attribute Filter',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -49,8 +49,10 @@ return [
|
|||
'country' => '国家管理',
|
||||
'file_manager' => '文件管理器',
|
||||
'access_frontend' => '访问前台',
|
||||
'copyright_buy' => '版权购买',
|
||||
|
||||
// sidebar
|
||||
'multi_filter_index' => '高级筛选',
|
||||
'theme_index' => '模板设置',
|
||||
'attribute_groups_index' => '属性组',
|
||||
'attributes_index' => '属性',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
/**
|
||||
* header.php
|
||||
*
|
||||
* @copyright 2022 beikeshop.com - All Rights Reserved
|
||||
* @link https://beikeshop.com
|
||||
* @author Edward Yang <yangjin@guangda.work>
|
||||
* @created 2022-08-02 19:03:19
|
||||
* @modified 2022-08-02 19:03:19
|
||||
*/
|
||||
|
||||
return [
|
||||
'price_filter' => '价格筛选',
|
||||
];
|
||||
|
|
@ -18,6 +18,8 @@ return [
|
|||
'products_trashed' => '回收站',
|
||||
'products_restore' => '恢复回收站',
|
||||
'clear_restore' => '清空回收站',
|
||||
'products_filter_index' => '查看高级筛选',
|
||||
'products_filter_update' => '修改高级筛选',
|
||||
|
||||
'batch_delete' => '批量删除',
|
||||
'batch_active' => '批量上架',
|
||||
|
|
|
|||
|
|
@ -10,17 +10,18 @@
|
|||
*/
|
||||
|
||||
return [
|
||||
'index' => '售后申请',
|
||||
'index' => '售后管理',
|
||||
|
||||
'rmas_index' => '售后服务列表',
|
||||
'rmas_show' => '售后服务详情',
|
||||
'rmas_update' => '更新售后服务',
|
||||
'rmas_delete' => '删除售后服务',
|
||||
|
||||
'rma_list_title' => '售后申请列表',
|
||||
'customers_name' => '客户姓名',
|
||||
'quantity' => '数量',
|
||||
'service_type' => '服务类型',
|
||||
'rma_details' => '售后申请详情',
|
||||
'rma_details' => '售后管理详情',
|
||||
'reasons_return' => '退货原因',
|
||||
'current_state' => '当前状态',
|
||||
'modify_status' => '修改状态',
|
||||
|
|
|
|||
|
|
@ -71,6 +71,6 @@ return [
|
|||
'rate_api_key' => '汇率 API KEY',
|
||||
'multi_filter' => '高级筛选',
|
||||
'please_select' => '请添加',
|
||||
'multi_filter_helper' => '请选择需要在筛选模块显示的属性',
|
||||
'multi_filter_helper' => '请选择需要在前台商品列表筛选区域显示的属性,留空则显示全部',
|
||||
'filter_attribute' => '属性筛选',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -49,8 +49,10 @@ return [
|
|||
'country' => '國家管理',
|
||||
'file_manager' => '文件管理器',
|
||||
'access_frontend' => '訪問前台',
|
||||
'copyright_buy' => '版權購買',
|
||||
|
||||
// sidebar
|
||||
'multi_filter_index' => '高級篩選',
|
||||
'theme_index' => '模板設置',
|
||||
'attribute_groups_index' => '屬性組',
|
||||
'attributes_index' => '屬性',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
/**
|
||||
* header.php
|
||||
*
|
||||
* @copyright 2022 beikeshop.com - All Rights Reserved
|
||||
* @link https://beikeshop.com
|
||||
* @author Edward Yang <yangjin@guangda.work>
|
||||
* @created 2022-08-02 19:03:19
|
||||
* @modified 2022-08-02 19:03:19
|
||||
*/
|
||||
|
||||
return [
|
||||
'price_filter' => '價格篩選',
|
||||
];
|
||||
|
|
@ -17,6 +17,7 @@ return [
|
|||
'rmas_update' => '更新售後服務',
|
||||
'rmas_delete' => '刪除售後服務',
|
||||
|
||||
'rma_list_title' => '售後申請列表',
|
||||
'customers_name' => '客戶姓名',
|
||||
'quantity' => '數量',
|
||||
'service_type' => '服務類型',
|
||||
|
|
|
|||
|
|
@ -72,6 +72,6 @@ return [
|
|||
'rate_api_key' => '匯率 API KEY',
|
||||
'multi_filter' => '高級篩選',
|
||||
'please_select' => '請添加',
|
||||
'multi_filter_helper' => '請選擇需要在篩選模塊顯示的屬性',
|
||||
'multi_filter_helper' => '請選擇需要在前台商品列表篩選區域顯示的屬性,留空則顯示全部',
|
||||
'filter_attribute' => '屬性篩選',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -27,28 +27,30 @@
|
|||
<link rel="stylesheet" href="{{ asset('vendor/jquery/jquery-ui/jquery-ui.min.css') }}">
|
||||
@endpush
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header p-0">
|
||||
<h4 class="mb-3">{{ __('product.price') }}</h4>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div id="price-slider" class="mb-2"><div class="slider-bg"></div></div>
|
||||
<div class="text-secondary price-range d-flex justify-content-between">
|
||||
<div>
|
||||
{{ __('common.text_form') }}
|
||||
<span class="min">{{ currency_format($filter_data['price']['select_min'], current_currency_code()) }}</span>
|
||||
</div>
|
||||
<div>
|
||||
{{ __('common.text_to') }}
|
||||
<span class="max">{{ currency_format($filter_data['price']['select_max'], current_currency_code()) }}</span>
|
||||
</div>
|
||||
@if (system_setting('base.multi_filter.price_filter', 1))
|
||||
<div class="card">
|
||||
<div class="card-header p-0">
|
||||
<h4 class="mb-3">{{ __('product.price') }}</h4>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div id="price-slider" class="mb-2"><div class="slider-bg"></div></div>
|
||||
<div class="text-secondary price-range d-flex justify-content-between">
|
||||
<div>
|
||||
{{ __('common.text_form') }}
|
||||
<span class="min">{{ currency_format($filter_data['price']['select_min'], current_currency_code()) }}</span>
|
||||
</div>
|
||||
<div>
|
||||
{{ __('common.text_to') }}
|
||||
<span class="max">{{ currency_format($filter_data['price']['select_max'], current_currency_code()) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<input value="{{ $filter_data['price']['select_min'] }}" class="price-select-min d-none">
|
||||
<input value="{{ $filter_data['price']['select_max'] }}" class="price-select-max d-none">
|
||||
<input value="{{ $filter_data['price']['min'] }}" class="price-min d-none">
|
||||
<input value="{{ $filter_data['price']['max'] }}" class="price-max d-none">
|
||||
</div>
|
||||
<input value="{{ $filter_data['price']['select_min'] }}" class="price-select-min d-none">
|
||||
<input value="{{ $filter_data['price']['select_max'] }}" class="price-select-max d-none">
|
||||
<input value="{{ $filter_data['price']['min'] }}" class="price-min d-none">
|
||||
<input value="{{ $filter_data['price']['max'] }}" class="price-max d-none">
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endhookwrapper
|
||||
@endif
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue