Merge branch 'dev' of https://gitee.com/what520/beikeshop into dev
Conflicts: themes/default/checkout/success.blade.php themes/default/product/product.blade.php
This commit is contained in:
commit
b86cee3b3e
|
|
@ -63,7 +63,7 @@ class ProductController
|
|||
* 创建商品
|
||||
*
|
||||
* @param ProductRequest $request
|
||||
* @return array
|
||||
* @return mixed
|
||||
*/
|
||||
public function store(ProductRequest $request)
|
||||
{
|
||||
|
|
@ -88,7 +88,7 @@ class ProductController
|
|||
*
|
||||
* @param ProductRequest $request
|
||||
* @param Product $product
|
||||
* @return array
|
||||
* @return mixed
|
||||
*/
|
||||
public function update(ProductRequest $request, Product $product)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ class FileManagerController extends Controller
|
|||
$savePath = $request->get('path');
|
||||
|
||||
$originName = $file->getClientOriginalName();
|
||||
$filePath = $file->storeAs($savePath, $originName, 'catalog');
|
||||
$filePath = (new FileManagerService)->uploadFile($file, $savePath, $originName);
|
||||
|
||||
return [
|
||||
'name' => $originName,
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ class MultiFilterController extends Controller
|
|||
{
|
||||
public function index()
|
||||
{
|
||||
$multiFilter = system_setting('base.multi_filter');
|
||||
$multiFilter = system_setting('base.multi_filter') ?: [];
|
||||
$multiFilter['attribute'] = $multiFilter['attribute'] ?? [];
|
||||
|
||||
if ($attributeIds = $multiFilter['attribute'] ?? []) {
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ class OrderController extends Controller
|
|||
*/
|
||||
public function show(Request $request, Order $order)
|
||||
{
|
||||
$order->load(['orderTotals', 'orderHistories', 'orderShipments']);
|
||||
$order->load(['orderTotals', 'orderHistories', 'orderShipments', 'orderPayments']);
|
||||
$data = hook_filter('admin.order.show.data', ['order' => $order, 'html_items' => []]);
|
||||
$data['statuses'] = StateMachineService::getInstance($order)->nextBackendStatuses();
|
||||
$data = hook_filter('admin.order.show.data', $data);
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ class ProductController extends Controller
|
|||
'tax_classes' => $taxClasses,
|
||||
'weight_classes' => Weight::getWeightUnits(),
|
||||
'source' => [
|
||||
'categories' => CategoryRepo::flatten(locale()),
|
||||
'categories' => CategoryRepo::flatten(locale(), false),
|
||||
],
|
||||
'_redirect' => $this->getRedirect(),
|
||||
];
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ class PageRequest extends FormRequest
|
|||
{
|
||||
$rules = [
|
||||
'descriptions.*.title' => 'required|string|min:3|max:128',
|
||||
'descriptions.*.summary' => 'string|max:180',
|
||||
'descriptions.*.content' => 'required|string',
|
||||
'descriptions.*.locale' => 'required|string',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class TaxRateRequest extends FormRequest
|
|||
public function rules(): array
|
||||
{
|
||||
$rule = [
|
||||
'name' => 'required|string|max:10',
|
||||
'name' => 'required|string|max:32',
|
||||
'rate' => 'required|numeric',
|
||||
'type' => 'required|in:percent,flat',
|
||||
'region_id' => 'required|int',
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class UploadRequest extends FormRequest
|
|||
public function rules()
|
||||
{
|
||||
return [
|
||||
'file' => 'required|image|mimes:jpg,png,jpeg,gif,svg|max:2048',
|
||||
'file' => 'required|mimes:jpg,png,jpeg,gif,svg,mp4|max:20480',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,6 +83,8 @@ class PageRepo
|
|||
$page->descriptions()->createMany($data['descriptions']);
|
||||
|
||||
$products = $data['products'] ?? [];
|
||||
$page->pageProducts()->delete();
|
||||
|
||||
if ($products) {
|
||||
$items = [];
|
||||
foreach ($products as $item) {
|
||||
|
|
@ -90,7 +92,6 @@ class PageRepo
|
|||
'product_id' => $item,
|
||||
];
|
||||
}
|
||||
$page->pageProducts()->delete();
|
||||
$page->pageProducts()->createMany($items);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,11 +13,13 @@ namespace Beike\Admin\Services;
|
|||
|
||||
class FileManagerService
|
||||
{
|
||||
private $fileBasePath = '';
|
||||
protected $fileBasePath = '';
|
||||
|
||||
protected $basePath = '';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->fileBasePath = public_path('catalog');
|
||||
$this->fileBasePath = public_path('catalog') . $this->basePath;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -26,6 +28,7 @@ class FileManagerService
|
|||
public function getDirectories($baseFolder = '/'): array
|
||||
{
|
||||
$currentBasePath = rtrim($this->fileBasePath . $baseFolder, '/');
|
||||
|
||||
$directories = glob("{$currentBasePath}/*", GLOB_ONLYDIR);
|
||||
|
||||
$result = [];
|
||||
|
|
@ -84,7 +87,7 @@ class FileManagerService
|
|||
if ($baseName == 'index.html') {
|
||||
continue;
|
||||
}
|
||||
$fileName = str_replace($this->fileBasePath, '', $file);
|
||||
$fileName = str_replace(public_path('catalog'), '', $file);
|
||||
if (is_file($file)) {
|
||||
$images[] = $this->handleImage($fileName, $baseName);
|
||||
}
|
||||
|
|
@ -114,7 +117,7 @@ class FileManagerService
|
|||
*/
|
||||
public function createDirectory($folderName)
|
||||
{
|
||||
$catalogFolderPath = "catalog/{$folderName}";
|
||||
$catalogFolderPath = "catalog{$this->basePath}/{$folderName}";
|
||||
$folderPath = public_path($catalogFolderPath);
|
||||
if (is_dir($folderPath)) {
|
||||
throw new \Exception(trans('admin/file_manager.directory_already_exist'));
|
||||
|
|
@ -130,7 +133,7 @@ class FileManagerService
|
|||
*/
|
||||
public function deleteDirectoryOrFile($filePath)
|
||||
{
|
||||
$filePath = public_path("catalog/{$filePath}");
|
||||
$filePath = public_path("catalog{$this->basePath}/{$filePath}");
|
||||
if (is_dir($filePath)) {
|
||||
$files = glob($filePath . '/*');
|
||||
if ($files) {
|
||||
|
|
@ -154,7 +157,7 @@ class FileManagerService
|
|||
return;
|
||||
}
|
||||
foreach ($files as $file) {
|
||||
$filePath = public_path("catalog/{$basePath}/$file");
|
||||
$filePath = public_path("catalog{$this->basePath}/{$basePath}/$file");
|
||||
if (file_exists($filePath)) {
|
||||
@unlink($filePath);
|
||||
}
|
||||
|
|
@ -170,7 +173,7 @@ class FileManagerService
|
|||
*/
|
||||
public function updateName($originPath, $newPath)
|
||||
{
|
||||
$originPath = public_path("catalog/{$originPath}");
|
||||
$originPath = public_path("catalog{$this->basePath}/{$originPath}");
|
||||
if (! is_dir($originPath) && ! file_exists($originPath)) {
|
||||
throw new \Exception(trans('admin/file_manager.target_not_exist'));
|
||||
}
|
||||
|
|
@ -182,6 +185,13 @@ class FileManagerService
|
|||
@rename($originPath, $newPath);
|
||||
}
|
||||
|
||||
public function uploadFile($file, $savePath, $originName)
|
||||
{
|
||||
$savePath = $this->basePath . $savePath;
|
||||
|
||||
return $file->storeAs($savePath, $originName, 'catalog');
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文件夹
|
||||
*
|
||||
|
|
@ -205,7 +215,7 @@ class FileManagerService
|
|||
*/
|
||||
private function hasSubFolders($folderPath): bool
|
||||
{
|
||||
$path = public_path("catalog/{$folderPath}");
|
||||
$path = public_path("catalog{$this->basePath}/{$folderPath}");
|
||||
$subFiles = glob($path . '/*');
|
||||
foreach ($subFiles as $subFile) {
|
||||
if (is_dir($subFile)) {
|
||||
|
|
@ -226,12 +236,19 @@ class FileManagerService
|
|||
*/
|
||||
private function handleImage($filePath, $baseName): array
|
||||
{
|
||||
$path = "catalog{$filePath}";
|
||||
$path = "catalog{$filePath}";
|
||||
$realPath = $this->fileBasePath . $filePath;
|
||||
|
||||
$mime = '';
|
||||
if(file_exists($realPath)) {
|
||||
$mime = mime_content_type($realPath);
|
||||
}
|
||||
|
||||
return [
|
||||
'path' => $path,
|
||||
'name' => $baseName,
|
||||
'origin_url' => image_origin($path),
|
||||
'mime' => $mime,
|
||||
'selected' => false,
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
|
||||
return [
|
||||
'api_url' => env('BEIKE_API_URL', 'https://beikeshop.com'),
|
||||
'version' => '1.3.6',
|
||||
'build' => '20230510',
|
||||
'version' => '1.3.7',
|
||||
'build' => '20230614',
|
||||
|
||||
'admin_name' => env('ADMIN_NAME'),
|
||||
'force_url_https' => env('APP_FORCE_HTTPS', false),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* CartException.php
|
||||
*
|
||||
* @copyright 2023 beikeshop.com - All Rights Reserved
|
||||
* @link https://beikeshop.com
|
||||
* @author Edward Yang <yangjin@guangda.work>
|
||||
* @created 2023-06-02 17:08:18
|
||||
* @modified 2023-06-02 17:08:18
|
||||
*/
|
||||
|
||||
namespace Beike\Exceptions;
|
||||
|
||||
class CartException extends \Exception
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
/**
|
||||
* InvalidException.php
|
||||
*
|
||||
* @copyright 2023 beikeshop.com - All Rights Reserved
|
||||
* @link https://beikeshop.com
|
||||
* @author Edward Yang <yangjin@guangda.work>
|
||||
* @created 2023-05-25 14:48:12
|
||||
* @modified 2023-05-25 14:48:12
|
||||
*/
|
||||
|
||||
namespace Beike\Exceptions;
|
||||
|
||||
class InvalidException extends \Exception
|
||||
{
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ use Beike\Repositories\CurrencyRepo;
|
|||
use Beike\Repositories\LanguageRepo;
|
||||
use Beike\Services\CurrencyService;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\Facades\Session;
|
||||
|
|
@ -520,25 +521,28 @@ function quantity_format($quantity)
|
|||
/**
|
||||
* 返回json序列化结果
|
||||
*/
|
||||
function json_success($message, $data = []): array
|
||||
function json_success($message, $data = [])
|
||||
{
|
||||
return [
|
||||
'status' => 'success',
|
||||
'message' => $message,
|
||||
'data' => $data,
|
||||
];
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回json序列化结果
|
||||
*/
|
||||
function json_fail($message, $data = []): array
|
||||
function json_fail($message, $data = [], $status = 422): JsonResponse
|
||||
{
|
||||
return [
|
||||
$data = [
|
||||
'status' => 'fail',
|
||||
'message' => $message,
|
||||
'data' => $data,
|
||||
];
|
||||
|
||||
return response()->json($data, $status);
|
||||
}
|
||||
|
||||
if (! function_exists('sub_string')) {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,11 @@ class Order extends Base
|
|||
return $this->hasMany(OrderShipment::class);
|
||||
}
|
||||
|
||||
public function orderPayments(): HasMany
|
||||
{
|
||||
return $this->hasMany(OrderPayment::class);
|
||||
}
|
||||
|
||||
public function subTotal()
|
||||
{
|
||||
$totals = $this->orderTotals;
|
||||
|
|
@ -68,10 +73,9 @@ class Order extends Base
|
|||
|
||||
public function getStatusFormatAttribute()
|
||||
{
|
||||
$status_format = trans('order.' . $this->status);
|
||||
$status_format = hook_filter('order.status_format', $status_format);
|
||||
$statusMap = array_column(StateMachineService::getAllStatuses(), 'name', 'status');
|
||||
|
||||
return $status_format;
|
||||
return $statusMap[$this->status];
|
||||
}
|
||||
|
||||
public function getTotalFormatAttribute()
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
namespace Beike\Models;
|
||||
|
||||
use Beike\Services\StateMachineService;
|
||||
|
||||
class OrderHistory extends Base
|
||||
{
|
||||
protected $fillable = [
|
||||
|
|
@ -21,6 +23,8 @@ class OrderHistory extends Base
|
|||
|
||||
public function getStatusFormatAttribute()
|
||||
{
|
||||
return trans("order.{$this->status}");
|
||||
$statusMap = array_column(StateMachineService::getAllStatuses(), 'name', 'status');
|
||||
|
||||
return $statusMap[$this->status];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
/**
|
||||
* OrderPayment.php
|
||||
*
|
||||
* @copyright 2023 beikeshop.com - All Rights Reserved
|
||||
* @link https://beikeshop.com
|
||||
* @author Edward Yang <yangjin@guangda.work>
|
||||
* @created 2023-05-25 10:02:52
|
||||
* @modified 2023-05-25 10:02:52
|
||||
*/
|
||||
|
||||
namespace Beike\Models;
|
||||
|
||||
class OrderPayment extends Base
|
||||
{
|
||||
protected $table = 'order_payments';
|
||||
|
||||
protected $fillable = [
|
||||
'order_id', 'transaction_id', 'request', 'response', 'callback', 'receipt',
|
||||
];
|
||||
}
|
||||
|
|
@ -171,6 +171,13 @@ class Plugin implements Arrayable, \ArrayAccess
|
|||
$item['label'] = trans($languageKey);
|
||||
}
|
||||
|
||||
$descriptionKey = $item['description_key'] ?? '';
|
||||
$description = $item['description'] ?? '';
|
||||
if (empty($description) && $descriptionKey) {
|
||||
$languageKey = "{$this->dirName}::{$descriptionKey}";
|
||||
$item['description'] = trans($languageKey);
|
||||
}
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -55,14 +55,18 @@ class CategoryRepo
|
|||
}
|
||||
}
|
||||
|
||||
public static function flatten(string $locale, $separator = ' > '): array
|
||||
public static function flatten(string $locale, $includeInactive = true, $separator = ' > '): array
|
||||
{
|
||||
$sql = "SELECT cp.category_id AS id, TRIM(LOWER(GROUP_CONCAT(cd1.name ORDER BY cp.level SEPARATOR '{$separator}'))) AS name, c1.parent_id, c1.position";
|
||||
$sql .= ' FROM category_paths cp';
|
||||
$sql .= ' LEFT JOIN categories c1 ON (cp.category_id = c1.id)';
|
||||
$sql .= ' LEFT JOIN categories c2 ON (cp.path_id = c2.id)';
|
||||
$sql .= ' LEFT JOIN category_descriptions cd1 ON (cp.path_id = cd1.category_id)';
|
||||
$sql .= " WHERE cd1.locale = '" . $locale . "' GROUP BY cp.category_id ORDER BY name ASC";
|
||||
$sql .= " WHERE cd1.locale = '" . $locale . "' ";
|
||||
if (! $includeInactive) {
|
||||
$sql .= ' AND c1.active = 1 ';
|
||||
}
|
||||
$sql .= ' GROUP BY cp.category_id ORDER BY c1.position ASC';
|
||||
|
||||
return DB::select($sql);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
/**
|
||||
* OrderPaymentRepo.php
|
||||
*
|
||||
* @copyright 2023 beikeshop.com - All Rights Reserved
|
||||
* @link https://beikeshop.com
|
||||
* @author Edward Yang <yangjin@guangda.work>
|
||||
* @created 2023-05-25 10:02:39
|
||||
* @modified 2023-05-25 10:02:39
|
||||
*/
|
||||
|
||||
namespace Beike\Repositories;
|
||||
|
||||
use Beike\Models\OrderPayment;
|
||||
|
||||
class OrderPaymentRepo
|
||||
{
|
||||
/**
|
||||
* @param $orderId
|
||||
* @param $data
|
||||
* @return mixed
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public static function createOrUpdatePayment($orderId, $data): mixed
|
||||
{
|
||||
$orderId = (int) $orderId;
|
||||
if (empty($orderId) || empty($data)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$orderPayment = OrderPayment::query()->where('order_id', $orderId)->first();
|
||||
if (empty($orderPayment)) {
|
||||
$orderPayment = new OrderPayment();
|
||||
}
|
||||
|
||||
$paymentData = [
|
||||
'order_id' => $orderId,
|
||||
];
|
||||
|
||||
if (isset($data['transaction_id'])) {
|
||||
$paymentData['transaction_id'] = $data['transaction_id'];
|
||||
}
|
||||
if (isset($data['request'])) {
|
||||
$paymentData['request'] = json_encode($data['request'] ?? []);
|
||||
}
|
||||
if (isset($data['response'])) {
|
||||
$paymentData['response'] = json_encode($data['response'] ?? []);
|
||||
}
|
||||
if (isset($data['callback'])) {
|
||||
$paymentData['callback'] = json_encode($data['callback'] ?? []);
|
||||
}
|
||||
if (isset($data['receipt'])) {
|
||||
$paymentData['receipt'] = $data['receipt'];
|
||||
}
|
||||
|
||||
$orderPayment->fill($paymentData);
|
||||
$orderPayment->saveOrFail();
|
||||
|
||||
return $orderPayment;
|
||||
}
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ class OrderRepo
|
|||
*/
|
||||
public static function filterAll(array $filters = [])
|
||||
{
|
||||
$builder = self::getListBuilder($filters)->orderByDesc('created_at');
|
||||
$builder = static::getListBuilder($filters)->orderByDesc('created_at');
|
||||
|
||||
return $builder->get();
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ class OrderRepo
|
|||
*/
|
||||
public static function getListByCustomer($customer): LengthAwarePaginator
|
||||
{
|
||||
$builder = self::getListBuilder(['customer' => $customer])->orderByDesc('created_at');
|
||||
$builder = static::getListBuilder(['customer' => $customer])->orderByDesc('created_at');
|
||||
|
||||
return $builder->paginate(perPage());
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ class OrderRepo
|
|||
*/
|
||||
public static function getLatestOrders($customer, $limit)
|
||||
{
|
||||
return self::getListBuilder(['customer' => $customer])
|
||||
return static::getListBuilder(['customer' => $customer])
|
||||
->orderByDesc('created_at')
|
||||
->take($limit)
|
||||
->get();
|
||||
|
|
@ -68,7 +68,7 @@ class OrderRepo
|
|||
*/
|
||||
public static function filterOrders(array $filters = []): LengthAwarePaginator
|
||||
{
|
||||
$builder = self::getListBuilder($filters)->orderByDesc('created_at');
|
||||
$builder = static::getListBuilder($filters)->orderByDesc('created_at');
|
||||
|
||||
return $builder->paginate(perPage());
|
||||
}
|
||||
|
|
@ -79,7 +79,7 @@ class OrderRepo
|
|||
*/
|
||||
public static function getListBuilder(array $filters = []): Builder
|
||||
{
|
||||
$builder = Order::query()->with(['orderProducts']);
|
||||
$builder = Order::query()->with(['orderProducts'])->where('status', '<>', StateMachineService::CREATED);
|
||||
|
||||
$number = $filters['number'] ?? 0;
|
||||
if ($number) {
|
||||
|
|
@ -266,6 +266,8 @@ class OrderRepo
|
|||
OrderProductRepo::createOrderProducts($order, $carts['carts']);
|
||||
OrderTotalRepo::createTotals($order, $totals);
|
||||
|
||||
hook_filter('repository.order.create.after', ['order' => $order, 'data' => $data]);
|
||||
|
||||
return $order;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -154,13 +154,17 @@ class PageCategoryRepo
|
|||
}
|
||||
|
||||
/**
|
||||
* @param $page
|
||||
* @param $pageCategory
|
||||
* @return string
|
||||
*/
|
||||
public static function getName($pageCategoryId)
|
||||
public static function getName($pageCategory): string
|
||||
{
|
||||
// 根据 pageCategoryId 获取 name,判断是否存在
|
||||
$pageCategory = PageCategory::query()->whereHas('description', function ($query) use ($pageCategoryId) {
|
||||
if ($pageCategory instanceof PageCategory) {
|
||||
return $pageCategory->description->title ?? '';
|
||||
}
|
||||
|
||||
$pageCategoryId = (int) $pageCategory;
|
||||
$pageCategory = PageCategory::query()->whereHas('description', function ($query) use ($pageCategoryId) {
|
||||
$query->where('page_category_id', $pageCategoryId);
|
||||
})->first();
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ class ProductRepo
|
|||
*/
|
||||
public static function getProductsByCategory($categoryId, $filterData)
|
||||
{
|
||||
$builder = self::getBuilder(array_merge(['category_id' => $categoryId, 'active' => 1], $filterData));
|
||||
$builder = static::getBuilder(array_merge(['category_id' => $categoryId, 'active' => 1], $filterData));
|
||||
|
||||
return $builder->with('inCurrentWishlist')
|
||||
->paginate($filterData['per_page'] ?? perPage())
|
||||
|
|
@ -72,7 +72,7 @@ class ProductRepo
|
|||
if (! $productIds) {
|
||||
return ProductSimple::collection(new Collection());
|
||||
}
|
||||
$builder = self::getBuilder(['product_ids' => $productIds])->whereHas('masterSku');
|
||||
$builder = static::getBuilder(['product_ids' => $productIds])->whereHas('masterSku');
|
||||
$products = $builder->with('inCurrentWishlist')->get();
|
||||
|
||||
return ProductSimple::collection($products);
|
||||
|
|
@ -220,7 +220,7 @@ class ProductRepo
|
|||
|
||||
public static function getFilterAttribute($data): array
|
||||
{
|
||||
$builder = self::getBuilder(array_diff_key($data, ['attr' => '', 'price' => '']))
|
||||
$builder = static::getBuilder(array_diff_key($data, ['attr' => '', 'price' => '']))
|
||||
->select(['pa.attribute_id', 'pa.attribute_value_id'])
|
||||
->with(['attributes.attribute.description', 'attributes.attribute_value.description'])
|
||||
->leftJoin('product_attributes as pa', 'pa.product_id', 'products.id')
|
||||
|
|
@ -274,7 +274,7 @@ class ProductRepo
|
|||
{
|
||||
$selectPrice = $data['price'] ?? '-';
|
||||
// unset($data['price']);
|
||||
$builder = self::getBuilder(['category_id' => $data['category_id']])->leftJoin('product_skus as ps', 'products.id', 'ps.product_id')
|
||||
$builder = static::getBuilder(['category_id' => $data['category_id']])->leftJoin('product_skus as ps', 'products.id', 'ps.product_id')
|
||||
->where('ps.is_default', 1);
|
||||
$min = $builder->min('ps.price');
|
||||
$max = $builder->max('ps.price');
|
||||
|
|
@ -293,7 +293,7 @@ class ProductRepo
|
|||
|
||||
public static function list($data = [])
|
||||
{
|
||||
return self::getBuilder($data)->paginate($data['per_page'] ?? 20);
|
||||
return static::getBuilder($data)->paginate($data['per_page'] ?? 20);
|
||||
}
|
||||
|
||||
public static function autocomplete($name)
|
||||
|
|
@ -353,7 +353,7 @@ class ProductRepo
|
|||
}
|
||||
|
||||
$items = [];
|
||||
$products = self::getBuilder()->select('id')->get();
|
||||
$products = static::getBuilder()->select('id')->get();
|
||||
foreach ($products as $product) {
|
||||
$items[$product->id] = [
|
||||
'id' => $product->id,
|
||||
|
|
|
|||
|
|
@ -95,9 +95,9 @@ class RmaRepo
|
|||
|
||||
/**
|
||||
* @param $data
|
||||
* @return LengthAwarePaginator
|
||||
* @return Builder
|
||||
*/
|
||||
public static function list($data): LengthAwarePaginator
|
||||
public static function getBuilder($data): Builder
|
||||
{
|
||||
$builder = Rma::query();
|
||||
|
||||
|
|
@ -124,7 +124,16 @@ class RmaRepo
|
|||
}
|
||||
$builder->orderBy('id', 'DESC');
|
||||
|
||||
return $builder->paginate(perPage())->withQueryString();
|
||||
return $builder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $data
|
||||
* @return LengthAwarePaginator
|
||||
*/
|
||||
public static function list($data): LengthAwarePaginator
|
||||
{
|
||||
return self::getBuilder($data)->paginate(perPage())->withQueryString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ use Beike\Models\Order;
|
|||
use Beike\Models\OrderHistory;
|
||||
use Beike\Models\OrderShipment;
|
||||
use Beike\Models\Product;
|
||||
use Beike\Repositories\OrderPaymentRepo;
|
||||
use Throwable;
|
||||
|
||||
class StateMachineService
|
||||
|
|
@ -29,6 +30,8 @@ class StateMachineService
|
|||
|
||||
private array $shipment;
|
||||
|
||||
private array $payment;
|
||||
|
||||
public const CREATED = 'created'; // 已创建
|
||||
|
||||
public const UNPAID = 'unpaid'; // 待支付
|
||||
|
|
@ -116,6 +119,19 @@ class StateMachineService
|
|||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置支付信息
|
||||
*
|
||||
* @param array $payment
|
||||
* @return $this
|
||||
*/
|
||||
public function setPayment(array $payment = []): self
|
||||
{
|
||||
$this->payment = $payment;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有订单状态列表
|
||||
*
|
||||
|
|
@ -136,7 +152,25 @@ class StateMachineService
|
|||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
return hook_filter('service.state_machine.all_statuses', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有有效订单状态
|
||||
* @return string[]
|
||||
*/
|
||||
public static function getValidStatuses(): array
|
||||
{
|
||||
$statuses = [
|
||||
self::CREATED,
|
||||
self::UNPAID,
|
||||
self::PAID,
|
||||
self::SHIPPED,
|
||||
self::COMPLETED,
|
||||
self::CANCELLED,
|
||||
];
|
||||
|
||||
return $statuses;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -198,6 +232,8 @@ class StateMachineService
|
|||
}
|
||||
$this->{$function}($oldStatusCode, $status);
|
||||
}
|
||||
|
||||
hook_filter('service.state_machine.change_status.after', ['order' => $order, 'status' => $status, 'comment' => $comment, 'notify' => $notify]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -208,11 +244,6 @@ class StateMachineService
|
|||
*/
|
||||
private function validStatusCode($statusCode)
|
||||
{
|
||||
if (! in_array($statusCode, self::ORDER_STATUS)) {
|
||||
$statusCodeString = implode(', ', self::ORDER_STATUS);
|
||||
|
||||
throw new \Exception("Invalid order status, must be one of the '{$statusCodeString}'");
|
||||
}
|
||||
$orderId = $this->orderId;
|
||||
$orderNumber = $this->order->number;
|
||||
$currentStatusCode = $this->order->status;
|
||||
|
|
@ -340,6 +371,18 @@ class StateMachineService
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加发货单号
|
||||
* @throws Throwable
|
||||
*/
|
||||
private function addPayment($oldCode, $newCode)
|
||||
{
|
||||
if (empty($this->payment)) {
|
||||
return;
|
||||
}
|
||||
OrderPaymentRepo::createOrUpdatePayment($this->orderId, $this->payment);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送新订单通知
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -57,21 +57,6 @@ class OrderController extends Controller
|
|||
return view('account/order_info', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单提交成功页
|
||||
*
|
||||
* @param Request $request
|
||||
* @param $number
|
||||
* @return View
|
||||
*/
|
||||
public function success(Request $request, $number): View
|
||||
{
|
||||
$customer = current_customer();
|
||||
$order = OrderRepo::getOrderByNumber($number, $customer);
|
||||
|
||||
return view('account/order_success', ['order' => $order]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单支付页面
|
||||
*
|
||||
|
|
|
|||
|
|
@ -33,9 +33,9 @@ class CheckoutController extends Controller
|
|||
* 更改结算信息
|
||||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
* @return mixed
|
||||
*/
|
||||
public function update(Request $request): array
|
||||
public function update(Request $request): mixed
|
||||
{
|
||||
try {
|
||||
$requestData = $request->all();
|
||||
|
|
@ -56,9 +56,13 @@ class CheckoutController extends Controller
|
|||
*/
|
||||
public function confirm()
|
||||
{
|
||||
$data = (new CheckoutService)->confirm();
|
||||
try {
|
||||
$data = (new CheckoutService)->confirm();
|
||||
|
||||
return hook_filter('checkout.confirm.data', $data);
|
||||
return hook_filter('checkout.confirm.data', $data);
|
||||
} catch (\Exception $e) {
|
||||
return json_fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function success()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
/**
|
||||
* OrderController.php
|
||||
*
|
||||
* @copyright 2023 beikeshop.com - All Rights Reserved
|
||||
* @link https://beikeshop.com
|
||||
* @author Edward Yang <yangjin@guangda.work>
|
||||
* @created 2023-06-06 10:47:27
|
||||
* @modified 2023-06-06 10:47:27
|
||||
*/
|
||||
|
||||
namespace Beike\Shop\Http\Controllers;
|
||||
|
||||
use Beike\Models\Order;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class OrderController extends Controller
|
||||
{
|
||||
public function show(Request $request, int $number)
|
||||
{
|
||||
$email = trim($request->get('email'));
|
||||
if (empty($email)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$order = Order::query()->where('number', $number)->where('email', $email)->firstOrFail();
|
||||
$data = hook_filter('order.show.data', ['order' => $order, 'html_items' => []]);
|
||||
|
||||
return view('order_info', $data);
|
||||
}
|
||||
}
|
||||
|
|
@ -32,10 +32,6 @@ class PageController extends Controller
|
|||
|
||||
$data = hook_filter('page.show.data', $data);
|
||||
|
||||
if ($page->category) {
|
||||
return view('pages/article', $data);
|
||||
}
|
||||
|
||||
return view('pages/single', $data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ class ProductController extends Controller
|
|||
|
||||
$data = hook_filter('product.show.data', $data);
|
||||
|
||||
return view('product', $data);
|
||||
return view('product/product', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ class AddressRequest extends FormRequest
|
|||
{
|
||||
return [
|
||||
'name' => 'required|min:2|max:16',
|
||||
'phone' => 'required|min:6|max:16',
|
||||
'country_id' => 'required|exists:countries,id',
|
||||
'zone_id' => 'required|exists:zones,id',
|
||||
'address_1' => 'required',
|
||||
|
|
@ -36,7 +35,6 @@ class AddressRequest extends FormRequest
|
|||
{
|
||||
return [
|
||||
'name' => trans('address.name'),
|
||||
'phone' => trans('address.phone'),
|
||||
'country_id' => trans('address.country_id'),
|
||||
'zone_id' => trans('address.zone_id'),
|
||||
'address_1' => trans('address.address_1'),
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class ProductDetail extends JsonResource
|
|||
'meta_description' => $this->description->meta_description ?? '',
|
||||
'brand_id' => $this->brand->id ?? 0,
|
||||
'brand_name' => $this->brand->name ?? '',
|
||||
'video' => $this->video ?? '',
|
||||
'images' => array_map(function ($image) {
|
||||
return [
|
||||
'preview' => image_resize($image, 500, 500),
|
||||
|
|
|
|||
|
|
@ -30,12 +30,8 @@ class ProductSimple extends JsonResource
|
|||
throw new \Exception("invalid master sku for product {$this->id}");
|
||||
}
|
||||
|
||||
$name = $this->description->name ?? '';
|
||||
if ($masterSku && $masterSku->images) {
|
||||
$images = $masterSku->images;
|
||||
} else {
|
||||
$images = $this->images ?? [];
|
||||
}
|
||||
$name = $this->description->name ?? '';
|
||||
$images = $this->images;
|
||||
|
||||
$data = [
|
||||
'id' => $this->id,
|
||||
|
|
|
|||
|
|
@ -56,6 +56,8 @@ Route::prefix('/')
|
|||
Route::post('login', [LoginController::class, 'store'])->name('login.store');
|
||||
Route::get('logout', [LogoutController::class, 'index'])->name('logout');
|
||||
|
||||
Route::get('orders/{number}', [\Beike\Shop\Http\Controllers\OrderController::class, 'show'])->name('orders.show');
|
||||
|
||||
Route::get('page_categories', [PageCategoryController::class, 'home'])->name('page_categories.home');
|
||||
Route::get('page_categories/{page_category}', [PageCategoryController::class, 'show'])->name('page_categories.show');
|
||||
Route::get('pages/{page}', [PageController::class, 'show'])->name('pages.show');
|
||||
|
|
@ -80,7 +82,6 @@ Route::prefix('/')
|
|||
Route::put('checkout', [CheckoutController::class, 'update'])->name('checkout.update');
|
||||
Route::get('checkout/success', [CheckoutController::class, 'success'])->name('checkout.success');
|
||||
Route::post('checkout/confirm', [CheckoutController::class, 'confirm'])->name('checkout.confirm');
|
||||
Route::get('orders/{number}/success', [OrderController::class, 'success'])->name('orders.success');
|
||||
Route::get('orders/{number}/pay', [OrderController::class, 'pay'])->name('orders.pay');
|
||||
Route::post('orders/{number}/cancel', [OrderController::class, 'cancel'])->name('orders.cancel');
|
||||
Route::post('orders/{number}/complete', [OrderController::class, 'complete'])->name('orders.complete');
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ use Exception;
|
|||
|
||||
class CartService
|
||||
{
|
||||
private static $cartList = null;
|
||||
|
||||
/**
|
||||
* 获取购物车商品列表
|
||||
*
|
||||
|
|
@ -27,6 +29,10 @@ class CartService
|
|||
*/
|
||||
public static function list($customer, bool $selected = false): array
|
||||
{
|
||||
if (self::$cartList !== null) {
|
||||
return self::$cartList;
|
||||
}
|
||||
|
||||
$cartBuilder = CartRepo::allCartProductsBuilder($customer->id ?? 0);
|
||||
if ($selected) {
|
||||
$cartBuilder->where('selected', true);
|
||||
|
|
@ -50,7 +56,9 @@ class CartService
|
|||
return $description && $product;
|
||||
});
|
||||
|
||||
return CartDetail::collection($cartItems)->jsonSerialize();
|
||||
$cartList = CartDetail::collection($cartItems)->jsonSerialize();
|
||||
|
||||
return self::$cartList = hook_filter('service.cart.list', $cartList);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -183,6 +191,6 @@ class CartService
|
|||
'amount_format' => currency_format($amount),
|
||||
];
|
||||
|
||||
return hook_filter('cart.data', $data);
|
||||
return hook_filter('service.cart.data', $data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@
|
|||
|
||||
namespace Beike\Shop\Services;
|
||||
|
||||
use Beike\Exceptions\CartException;
|
||||
use Beike\Libraries\Weight;
|
||||
use Beike\Models\Address;
|
||||
use Beike\Models\Country;
|
||||
use Beike\Models\Customer;
|
||||
use Beike\Models\Order;
|
||||
use Beike\Models\Zone;
|
||||
use Beike\Repositories\AddressRepo;
|
||||
|
|
@ -46,13 +46,11 @@ class CheckoutService
|
|||
if (is_int($customer) || empty($customer)) {
|
||||
$this->customer = current_customer();
|
||||
}
|
||||
// if (empty($this->customer) || !($this->customer instanceof Customer)) {
|
||||
// // throw new \Exception(trans('shop/carts.invalid_customer'));
|
||||
// }
|
||||
|
||||
$this->cart = CartRepo::createCart($this->customer);
|
||||
$this->selectedProducts = CartRepo::selectedCartProducts($this->customer->id ?? 0);
|
||||
if ($this->selectedProducts->count() == 0) {
|
||||
throw new \Exception(trans('shop/carts.empty_selected_products'));
|
||||
throw new CartException(trans('shop/carts.empty_selected_products'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -96,9 +94,10 @@ class CheckoutService
|
|||
$this->updateGuestPaymentAddress($guestPaymentAddress);
|
||||
}
|
||||
|
||||
hook_action('service.checkout.update.after', ['request_data' => $requestData, 'cart' => $this->cart]);
|
||||
hook_action('service.checkout.update.after', ['request_data' => $requestData, 'checkout' => $this]);
|
||||
$data = $this->checkoutData();
|
||||
|
||||
return $this->checkoutData();
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -219,6 +218,14 @@ class CheckoutService
|
|||
$this->cart->update(['payment_method_code' => $paymentMethodCode]);
|
||||
}
|
||||
|
||||
public function initTotalService()
|
||||
{
|
||||
$customer = $this->customer;
|
||||
$totalClass = hook_filter('service.checkout.total_service', 'Beike\Shop\Services\TotalService');
|
||||
$totalService = (new $totalClass($this->cart, CartService::list($customer, true)));
|
||||
$this->totalService = $totalService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取结账页数据
|
||||
*
|
||||
|
|
@ -232,8 +239,10 @@ class CheckoutService
|
|||
|
||||
$cartList = CartService::list($customer, true);
|
||||
$carts = CartService::reloadData($cartList);
|
||||
$totalService = (new TotalService($currentCart, $cartList));
|
||||
$this->totalService = $totalService;
|
||||
|
||||
if (! $this->totalService) {
|
||||
$this->initTotalService();
|
||||
}
|
||||
|
||||
$addresses = AddressRepo::listByCustomer($customer);
|
||||
$shipments = ShippingMethodService::getShippingMethods($this);
|
||||
|
|
@ -265,10 +274,10 @@ class CheckoutService
|
|||
'shipping_methods' => $shipments,
|
||||
'payment_methods' => $payments,
|
||||
'carts' => $carts,
|
||||
'totals' => $totalService->getTotals($this),
|
||||
'totals' => $this->totalService->getTotals($this),
|
||||
];
|
||||
|
||||
return hook_filter('checkout.data', $data);
|
||||
return hook_filter('service.checkout.data', $data);
|
||||
}
|
||||
|
||||
public static function formatAddress($address)
|
||||
|
|
|
|||
|
|
@ -17,17 +17,16 @@ use Illuminate\Support\Str;
|
|||
|
||||
class TotalService
|
||||
{
|
||||
private const TOTAL_CODES = [
|
||||
protected const TOTAL_CODES = [
|
||||
'subtotal',
|
||||
'tax',
|
||||
'shipping',
|
||||
'customer_discount',
|
||||
'order_total',
|
||||
];
|
||||
|
||||
public Cart $currentCart;
|
||||
protected Cart $currentCart;
|
||||
|
||||
public array $cartProducts;
|
||||
protected array $cartProducts;
|
||||
|
||||
public array $taxes = [];
|
||||
|
||||
|
|
@ -35,7 +34,7 @@ class TotalService
|
|||
|
||||
public float $amount = 0;
|
||||
|
||||
public string $shippingMethod = '';
|
||||
protected string|array $shippingMethod = '';
|
||||
|
||||
public function __construct($currentCart, $cartProducts)
|
||||
{
|
||||
|
|
@ -55,6 +54,11 @@ class TotalService
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function getShippingMethod(): string
|
||||
{
|
||||
return $this->shippingMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取税费数据
|
||||
*
|
||||
|
|
@ -112,11 +116,14 @@ class TotalService
|
|||
{
|
||||
$maps = [];
|
||||
foreach (self::TOTAL_CODES as $code) {
|
||||
$serviceName = Str::studly($code) . 'Service';
|
||||
$maps[$code] = "\Beike\\Shop\\Services\\TotalServices\\{$serviceName}";
|
||||
$serviceName = Str::studly($code) . 'Service';
|
||||
$maps[$code] = "\Beike\\Shop\\Services\\TotalServices\\{$serviceName}";
|
||||
}
|
||||
|
||||
return hook_filter('service.total.maps', $maps);
|
||||
$maps = hook_filter('service.total.maps', $maps);
|
||||
$maps['order_total'] = "\Beike\\Shop\\Services\\TotalServices\\OrderTotalService";
|
||||
|
||||
return $maps;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -130,4 +137,36 @@ class TotalService
|
|||
|
||||
return collect($carts)->sum('subtotal');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Cart Products
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getCartProducts(): array
|
||||
{
|
||||
return $this->cartProducts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Current Cart
|
||||
*
|
||||
* @return Cart
|
||||
*/
|
||||
public function getCurrentCart()
|
||||
{
|
||||
return $this->currentCart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Cart Product Amount
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function countProducts(): mixed
|
||||
{
|
||||
$cartProducts = $this->getCartProducts();
|
||||
|
||||
return collect($cartProducts)->sum('quantity');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class ShippingService
|
|||
public static function getTotal(CheckoutService $checkout): ?array
|
||||
{
|
||||
$totalService = $checkout->totalService;
|
||||
$shippingMethod = $totalService->shippingMethod;
|
||||
$shippingMethod = $totalService->getShippingMethod();
|
||||
if (empty($shippingMethod)) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
"ext-fileinfo": "*",
|
||||
"ext-iconv": "*",
|
||||
"ext-json": "*",
|
||||
"ext-openssl": "*",
|
||||
"ext-pdo": "*",
|
||||
"ext-simplexml": "*",
|
||||
"ext-zip": "*",
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration {
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('order_payments', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->integer('order_id');
|
||||
$table->string('transaction_id')->nullable();
|
||||
$table->string('request')->nullable();
|
||||
$table->string('response')->nullable();
|
||||
$table->string('callback')->nullable();
|
||||
$table->string('receipt')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('order_payments');
|
||||
}
|
||||
};
|
||||
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
namespace Plugin\Paypal\Controllers;
|
||||
|
||||
use Beike\Repositories\OrderPaymentRepo;
|
||||
use Beike\Repositories\OrderRepo;
|
||||
use Beike\Services\StateMachineService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
|
|
@ -96,8 +97,10 @@ class PaypalController
|
|||
$customer = current_customer();
|
||||
$order = OrderRepo::getOrderByNumber($orderNumber, $customer);
|
||||
|
||||
OrderPaymentRepo::createOrUpdatePayment($order->id, ['request' => $data]);
|
||||
$paypalOrderId = $data['paypalOrderId'];
|
||||
$result = $this->paypalClient->capturePaymentOrder($paypalOrderId);
|
||||
OrderPaymentRepo::createOrUpdatePayment($order->id, ['response' => $result]);
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
namespace Plugin\Stripe\Controllers;
|
||||
|
||||
use Beike\Repositories\OrderPaymentRepo;
|
||||
use Beike\Repositories\OrderRepo;
|
||||
use Beike\Services\StateMachineService;
|
||||
use Beike\Shop\Http\Controllers\Controller;
|
||||
|
|
@ -24,6 +25,7 @@ class StripeController extends Controller
|
|||
*
|
||||
* @param Request $request
|
||||
* @return array
|
||||
* @throws \Throwable
|
||||
*/
|
||||
public function capture(Request $request): array
|
||||
{
|
||||
|
|
@ -32,14 +34,18 @@ class StripeController extends Controller
|
|||
$customer = current_customer();
|
||||
$order = OrderRepo::getOrderByNumber($number, $customer);
|
||||
$creditCardData = $request->all();
|
||||
$result = (new StripePaymentService($order))->capture($creditCardData);
|
||||
|
||||
OrderPaymentRepo::createOrUpdatePayment($order->id, ['request' => $creditCardData]);
|
||||
$result = (new StripePaymentService($order))->capture($creditCardData);
|
||||
OrderPaymentRepo::createOrUpdatePayment($order->id, ['response' => $result]);
|
||||
|
||||
if ($result) {
|
||||
StateMachineService::getInstance($order)->changeStatus(StateMachineService::PAID);
|
||||
StateMachineService::getInstance($order)->setShipment()->changeStatus(StateMachineService::PAID);
|
||||
|
||||
return json_success(trans('Stripe::common.capture_success'));
|
||||
}
|
||||
|
||||
return json_success(trans('Stripe::common.capture_fail'));
|
||||
return json_success(trans('Stripe::common.capture_fail'));
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return json_fail($e->getMessage());
|
||||
|
|
|
|||
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
Binary file not shown.
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
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.
|
|
@ -0,0 +1,45 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<!--
|
||||
2013-9-30: Created.
|
||||
-->
|
||||
<svg>
|
||||
<metadata>
|
||||
Created by iconfont
|
||||
</metadata>
|
||||
<defs>
|
||||
|
||||
<font id="laydate-icon" horiz-adv-x="1024" >
|
||||
<font-face
|
||||
font-family="laydate-icon"
|
||||
font-weight="500"
|
||||
font-stretch="normal"
|
||||
units-per-em="1024"
|
||||
ascent="896"
|
||||
descent="-128"
|
||||
/>
|
||||
<missing-glyph />
|
||||
|
||||
<glyph glyph-name="x" unicode="x" horiz-adv-x="1001"
|
||||
d="M281 543q-27 -1 -53 -1h-83q-18 0 -36.5 -6t-32.5 -18.5t-23 -32t-9 -45.5v-76h912v41q0 16 -0.5 30t-0.5 18q0 13 -5 29t-17 29.5t-31.5 22.5t-49.5 9h-133v-97h-438v97zM955 310v-52q0 -23 0.5 -52t0.5 -58t-10.5 -47.5t-26 -30t-33 -16t-31.5 -4.5q-14 -1 -29.5 -0.5
|
||||
t-29.5 0.5h-32l-45 128h-439l-44 -128h-29h-34q-20 0 -45 1q-25 0 -41 9.5t-25.5 23t-13.5 29.5t-4 30v167h911zM163 247q-12 0 -21 -8.5t-9 -21.5t9 -21.5t21 -8.5q13 0 22 8.5t9 21.5t-9 21.5t-22 8.5zM316 123q-8 -26 -14 -48q-5 -19 -10.5 -37t-7.5 -25t-3 -15t1 -14.5
|
||||
t9.5 -10.5t21.5 -4h37h67h81h80h64h36q23 0 34 12t2 38q-5 13 -9.5 30.5t-9.5 34.5q-5 19 -11 39h-368zM336 498v228q0 11 2.5 23t10 21.5t20.5 15.5t34 6h188q31 0 51.5 -14.5t20.5 -52.5v-227h-327z" />
|
||||
|
||||
|
||||
|
||||
<glyph glyph-name="youyou" unicode="" d="M283.648 721.918976 340.873216 780.926976 740.352 383.997952 340.876288-12.925952 283.648 46.077952 619.52 383.997952Z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="zuozuo" unicode="" d="M740.352 721.918976 683.126784 780.926976 283.648 383.997952 683.123712-12.925952 740.352 46.077952 404.48 383.997952Z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="xiayiye" unicode="" d="M62.573 384.103l423.401 423.662c18.985 18.985 49.757 18.985 68.727 0 18.982-18.972 18.985-49.746 0-68.729l-355.058-355.067 356.796-356.796c18.977-18.971 18.976-49.746 0-68.727-18.982-18.976-49.751-18.976-68.727 0l-39.753 39.753 0.269 0.246-385.655 385.661zM451.365 384.103l423.407 423.662c18.985 18.985 49.757 18.985 68.727 0 18.982-18.972 18.985-49.746 0-68.729l-355.058-355.067 356.796-356.796c18.977-18.971 18.976-49.746 0-68.727-18.982-18.976-49.757-18.977-68.727 0l-39.762 39.754 0.273 0.249-385.662 385.661zM451.365 384.103z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="xiayiye1" unicode="" d="M948.066926 382.958838l-411.990051-412.24426c-18.47333-18.47333-48.417689-18.47333-66.875207 0-18.47333 18.461167-18.47333 48.405526 0 66.875207L814.691135 383.088983 467.512212 730.269123c-18.466032 18.458735-18.466032 48.405526 0 66.873991 18.468465 18.464816 48.410391 18.464816 66.872774 0l38.682336-38.682336-0.261507-0.239614 375.259894-375.265975v0.003649m-378.312834 0L157.756743-29.285422c-18.47333-18.47333-48.415256-18.47333-66.872775 0-18.47333 18.461167-18.47333 48.405526 0 66.875207L436.369787 383.088983 89.19208 730.269123c-18.4636 18.458735-18.4636 48.405526 0 66.873991 18.470898 18.464816 48.415256 18.464816 66.872774 0l38.692067-38.682336-0.266372-0.239614 375.267191-375.265975-0.004865 0.003649m0 0z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
|
||||
|
||||
</font>
|
||||
</defs></svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
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
File diff suppressed because one or more lines are too long
|
|
@ -171,26 +171,21 @@ body.page-filemanager {
|
|||
|
||||
.content-center {
|
||||
height: calc(100% - 56px);
|
||||
// display: flex;
|
||||
// align-items: flex-start;
|
||||
// flex-wrap: wrap;
|
||||
// align-items: center; // flex-start | center
|
||||
background: #f7f9fc;
|
||||
padding: 16px 6px;
|
||||
// justify-content: space-between; // flex-end | center | space-between
|
||||
// flex-wrap: wrap;
|
||||
// margin-right: -20px;
|
||||
overflow-y: auto;
|
||||
align-content: flex-start;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
width: 8px;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 2px;
|
||||
background: $primary;
|
||||
border-radius: 4px;
|
||||
background: #ccc;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
|
@ -199,27 +194,10 @@ body.page-filemanager {
|
|||
// display: flex;
|
||||
// flex-direction: column;
|
||||
display: inline-block;
|
||||
// align-items: center;
|
||||
// margin-bottom: 20px;
|
||||
background: #fff;
|
||||
margin: 0 8px 16px;
|
||||
box-shadow: 0 0 2px 1px rgba(0, 0, 0, .07);
|
||||
cursor: pointer;
|
||||
// width: calc(20% - 20px);
|
||||
|
||||
// @media (min-width: 600px) {
|
||||
// width: calc(25% - 20px);
|
||||
// }
|
||||
|
||||
// @media (min-width: 1000px) {
|
||||
// width: calc(20% - 20px);
|
||||
// }
|
||||
|
||||
// @media (min-width: 1300px) {
|
||||
// width: calc(16.666% - 20px);
|
||||
// }
|
||||
|
||||
// border: 1px solid transparent;
|
||||
|
||||
.img {
|
||||
width: 137px;
|
||||
|
|
@ -232,6 +210,12 @@ body.page-filemanager {
|
|||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 86px;
|
||||
color: #333;
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
&.active {
|
||||
|
|
@ -295,22 +279,34 @@ body.page-filemanager {
|
|||
}
|
||||
|
||||
.upload-image {
|
||||
height: 200px;
|
||||
min-height: 200px;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
margin-right: -4px;
|
||||
padding-right: 6px;
|
||||
|
||||
// 滚动条 透明背景
|
||||
&::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 4px;
|
||||
background: #ddd;
|
||||
}
|
||||
|
||||
.list {
|
||||
background-color: #f2f2f2;
|
||||
padding: 6px 10px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 8px;
|
||||
margin-bottom: 12px;
|
||||
padding-bottom: 14px;
|
||||
font-size: 12px;
|
||||
border-bottom: 1px solid #f1f1f1;
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
align-items: center; // flex-start | center
|
||||
justify-content: space-between; // flex-end | center | space-between
|
||||
margin-bottom: 6px;
|
||||
|
||||
}
|
||||
|
||||
.name {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* @link https://beikeshop.com
|
||||
* @Author pu shuo <pushuo@guangda.work>
|
||||
* @Date 2022-08-26 18:18:22
|
||||
* @LastEditTime 2023-02-08 15:35:25
|
||||
* @LastEditTime 2023-06-08 19:18:24
|
||||
*/
|
||||
|
||||
import http from "../../../js/http";
|
||||
|
|
@ -92,23 +92,20 @@ const tinymceInit = () => {
|
|||
toolbar_mode: 'wrap',
|
||||
font_formats:
|
||||
"微软雅黑='Microsoft YaHei';黑体=黑体;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Georgia=georgia,palatino;Helvetica=helvetica;Times New Roman=times new roman,times;Verdana=verdana,geneva",
|
||||
fontsize_formats: "10px 12px 14px 18px 24px 36px",
|
||||
fontsize_formats: "10px 12px 14px 18px 24px 36px 48px 56px 72px 96px",
|
||||
lineheight_formats: "1 1.1 1.2 1.3 1.4 1.5 1.7 2.4 3 4",
|
||||
setup: function(ed) {
|
||||
const height = ed.getElement().dataset.tinymceHeight;
|
||||
// console.log(ed);
|
||||
// 修改 tinymce 的高度
|
||||
// if (height) {
|
||||
// ed.theme.resizeTo(null, height);
|
||||
// }
|
||||
|
||||
ed.ui.registry.addButton('toolbarImageButton',{
|
||||
// text: '',
|
||||
icon: 'image',
|
||||
onAction:function() {
|
||||
bk.fileManagerIframe(images => {
|
||||
if (images.length) {
|
||||
images.forEach(e => {
|
||||
ed.insertContent(`<img src='/${e.path}' class="img-fluid" />`);
|
||||
if (e.mime == 'video/mp4') {
|
||||
ed.insertContent(`<video src='/${e.path}' controls loop muted class="img-fluid" />`);
|
||||
} else {
|
||||
ed.insertContent(`<img src='/${e.path}' class="img-fluid" />`);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* @link https://beikeshop.com
|
||||
* @Author pu shuo <pushuo@guangda.work>
|
||||
* @Date 2022-08-17 15:42:46
|
||||
* @LastEditTime 2023-04-11 09:28:34
|
||||
* @LastEditTime 2023-06-13 17:27:49
|
||||
*/
|
||||
|
||||
// Example starter JavaScript for disabling form submissions if there are invalid fields
|
||||
|
|
@ -33,12 +33,13 @@ $(function () {
|
|||
|
||||
form.classList.add("was-validated");
|
||||
$('.nav-link, .nav-item').removeClass('error-invalid');
|
||||
|
||||
$('.invalid-feedback').hide();
|
||||
|
||||
// 如果错误输入框在 tab 页面,则高亮显示对应的选项卡
|
||||
$('.invalid-feedback').each(function(index, el) {
|
||||
if ($(el).css('display') == 'block') {
|
||||
layer.msg(lang.error_form, () => {});
|
||||
|
||||
// 兼容使用 element ui input、autocomplete 组件,在传统提交报错ui显示
|
||||
if ($(el).siblings('div[class^="el-"]')) {
|
||||
$(el).siblings('div[class^="el-"]').find('.el-input__inner').addClass('error-invalid-input')
|
||||
|
|
|
|||
|
|
@ -3,13 +3,14 @@
|
|||
* @link https://beikeshop.com
|
||||
* @Author pu shuo <pushuo@guangda.work>
|
||||
* @Date 2022-08-22 18:32:26
|
||||
* @LastEditTime 2023-04-19 15:26:41
|
||||
* @LastEditTime 2023-06-09 08:53:52
|
||||
*/
|
||||
|
||||
export default {
|
||||
// 打开文件管理器
|
||||
fileManagerIframe(callback) {
|
||||
fileManagerIframe(callback, params) {
|
||||
const base = document.querySelector('base').href;
|
||||
params = params ? `?${Object.keys(params).map(key => `${key}=${params[key]}`).join('&')}` : '';
|
||||
|
||||
layer.open({
|
||||
type: 2,
|
||||
|
|
@ -19,7 +20,7 @@ export default {
|
|||
scrollbar: false,
|
||||
shade: 0.4,
|
||||
area: ['1060px', '680px'],
|
||||
content: `${base}/file_manager`,
|
||||
content: `${base}/file_manager${params}`,
|
||||
success: function(layerInstance, index) {
|
||||
var iframeWindow = window[layerInstance.find("iframe")[0]["name"]];
|
||||
iframeWindow.callback = function(images) {
|
||||
|
|
@ -145,7 +146,7 @@ export default {
|
|||
setVipUi(data)
|
||||
|
||||
function setVipUi(data) {
|
||||
if (data.vip) {
|
||||
if (data && data.vip) {
|
||||
$('.vip-serve').addClass('active');
|
||||
|
||||
if (data.expiring) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<div class="row g-3 mb-3">
|
||||
<label for="" class="wp-200 col-form-label text-end {{ isset($required) && $required ? 'required' : '' }}">{{ $title ?? '' }}</label>
|
||||
<label class="wp-200 col-form-label text-end {{ isset($required) && $required ? 'required' : '' }}">{{ $title ?? '' }}</label>
|
||||
<div class="col-auto wp-200-">
|
||||
{{ $slot }}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@
|
|||
<meta name="asset" content="{{ asset('/') }}">
|
||||
<meta name="editor_language" content="{{ locale() }}">
|
||||
<script src="{{ asset('vendor/vue/2.7/vue' . (!config('app.debug') ? '.min' : '') . '.js') }}"></script>
|
||||
<script src="{{ asset('vendor/element-ui/2.15.6/js.js') }}"></script>
|
||||
<script src="{{ asset('vendor/element-ui/index.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/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') }}">
|
||||
<link rel="stylesheet" href="{{ asset('vendor/element-ui/index.css') }}">
|
||||
@if (locale() != 'zh_cn')
|
||||
<script src="{{ asset('vendor/element-ui/language/' . locale() . '.js') }}"></script>
|
||||
@endif
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@
|
|||
</el-form-item>
|
||||
|
||||
<el-form-item label="{{ __('shop/login.password') }}" :prop="dialog.form.id === null || dialog.form.id == '' ? 'password' : ''">
|
||||
<el-input v-model="dialog.form.password" placeholder="{{ __('common.password') }}"></el-input>
|
||||
<el-input v-model="dialog.form.password" placeholder="{{ __('shop/login.password') }}"></el-input>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item label="{{ __('common.language') }}">
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
<x-admin-form-input-locale name="descriptions.*.name" title="{{ __('common.name') }}" :value="$descriptions" :required="true" />
|
||||
<x-admin-form-input-locale name="descriptions.*.content" title="{{ __('admin/builder.modules_content') }}" :value="$descriptions" />
|
||||
|
||||
{{-- <x-admin-form-select title="上级分类" name="parent_id" :value="old('parent_id', $category->parent_id ?? 0)" :options="$categories->toArray()" key="id" label="name" /> --}}
|
||||
<x-admin-form-input name="position" title="{{ __('common.sort_order') }}" :value="old('position', $category->position ?? 0)" />
|
||||
|
||||
<x-admin::form.row title="{{ __('admin/category.parent_category') }}">
|
||||
@php
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>{{ __('common.name') }}</th>
|
||||
<th>{{ __('address.name') }}</th>
|
||||
<th>{{ __('common.phone') }}</th>
|
||||
<th>{{ __('common.created_at') }}</th>
|
||||
<th>{{ __('common.action') }}</th>
|
||||
|
|
@ -76,7 +76,7 @@
|
|||
<el-dialog title="{{ __('admin/customer.edit_address') }}" :visible.sync="dialogAddress.show" width="650px"
|
||||
@close="closeAddressDialog('addressForm')">
|
||||
<el-form ref="addressForm" :rules="addressRules" :model="dialogAddress.form" label-width="100px">
|
||||
<el-form-item label="{{ __('common.name') }}" prop="name">
|
||||
<el-form-item label="{{ __('address.name') }}" prop="name">
|
||||
<el-input v-model="dialogAddress.form.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="{{ __('common.phone') }}" prop="phone">
|
||||
|
|
|
|||
|
|
@ -104,21 +104,21 @@ Vue.component('rich-text-i18n', {
|
|||
toolbar_mode: 'wrap',
|
||||
font_formats:
|
||||
"微软雅黑='Microsoft YaHei';黑体=黑体;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Georgia=georgia,palatino;Helvetica=helvetica;Times New Roman=times new roman,times;Verdana=verdana,geneva",
|
||||
fontsize_formats: "10px 12px 14px 18px 24px 36px",
|
||||
fontsize_formats: "10px 12px 14px 18px 24px 36px 48px 56px 72px 96px",
|
||||
lineheight_formats: "1 1.1 1.2 1.3 1.4 1.5 1.7 2.4 3 4",
|
||||
relative_urls : true,
|
||||
// init_instance_callback: function (ed) {
|
||||
// let code = ed.getElement().dataset.code
|
||||
// ed.setContent(self.value[code])
|
||||
// },
|
||||
setup: function(ed) {
|
||||
ed.ui.registry.addButton('toolbarImageButton', {
|
||||
// text: '',
|
||||
icon: 'image',
|
||||
onAction:function() {
|
||||
bk.fileManagerIframe(images => {
|
||||
if (images.length) {
|
||||
images.forEach(e => {
|
||||
ed.insertContent(`<img src='/${e.path}' class="img-fluid" />`);
|
||||
if (e.mime == 'video/mp4') {
|
||||
ed.insertContent(`<video src='/${e.path}' controls loop muted class="img-fluid" />`);
|
||||
} else {
|
||||
ed.insertContent(`<img src='/${e.path}' class="img-fluid" />`);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
<script src="{{ asset('vendor/vue/Sortable.min.js') }}"></script>
|
||||
<script src="{{ asset('vendor/vue/vuedraggable.js') }}"></script>
|
||||
<script src="{{ asset('vendor/tinymce/5.9.1/tinymce.min.js') }}"></script>
|
||||
<script src="{{ asset('vendor/element-ui/2.15.6/js.js') }}"></script>
|
||||
<link rel="stylesheet" href="{{ asset('vendor/element-ui/2.15.6/css.css') }}">
|
||||
<script src="{{ asset('vendor/element-ui/index.js') }}"></script>
|
||||
<link rel="stylesheet" href="{{ asset('vendor/element-ui/index.css') }}">
|
||||
<link rel="stylesheet" type="text/css" href="{{ asset('/build/beike/admin/css/design.css') }}">
|
||||
@stack('header')
|
||||
<script>
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@
|
|||
<script src="{{ asset('vendor/vue/Sortable.min.js') }}"></script>
|
||||
<script src="{{ asset('vendor/vue/vuedraggable.js') }}"></script>
|
||||
<script src="{{ asset('vendor/tinymce/5.9.1/tinymce.min.js') }}"></script>
|
||||
<script src="{{ asset('vendor/element-ui/2.15.6/js.js') }}"></script>
|
||||
<link rel="stylesheet" href="{{ asset('vendor/element-ui/2.15.6/css.css') }}">
|
||||
<script src="{{ asset('vendor/element-ui/index.js') }}"></script>
|
||||
<link rel="stylesheet" href="{{ asset('vendor/element-ui/index.css') }}">
|
||||
@if (locale() != 'zh_cn')
|
||||
<script src="{{ asset('vendor/element-ui/language/' . locale() . '.js') }}"></script>
|
||||
@endif
|
||||
|
|
|
|||
|
|
@ -8,14 +8,13 @@
|
|||
<meta name="csrf-token" content="{{ csrf_token() }}">
|
||||
<meta name="asset" content="{{ asset('/') }}">
|
||||
<script src="{{ asset('vendor/vue/2.7/vue.js') }}"></script>
|
||||
<script src="{{ asset('vendor/element-ui/2.15.9/index.js') }}"></script>
|
||||
{{-- <script src="{{ asset('vendor/element-ui/2.15.6/js.js') }}"></script> --}}
|
||||
<script src="{{ asset('vendor/element-ui/index.js') }}"></script>
|
||||
<script src="{{ asset('vendor/cookie/js.cookie.min.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/vue/batch_select.js') }}"></script>
|
||||
<link href="{{ mix('/build/beike/admin/css/bootstrap.css') }}" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{{ asset('vendor/element-ui/2.15.9/index.css') }}">
|
||||
<link rel="stylesheet" href="{{ asset('vendor/element-ui/index-blue.css') }}">
|
||||
<link href="{{ mix('build/beike/admin/css/filemanager.css') }}" rel="stylesheet">
|
||||
<script src="{{ mix('build/beike/admin/js/app.js') }}"></script>
|
||||
@if (locale() != 'zh_cn')
|
||||
|
|
@ -74,8 +73,8 @@
|
|||
<div class="content-head">
|
||||
<div class="left d-lg-flex">
|
||||
<el-button class="me-5 mb-1 mb-lg-0" size="small" icon="el-icon-check" type="primary" @click="fileChecked" :disabled="!!!selectImageIndex.length">{{ __('admin/builder.modules_choose') }}</el-button>
|
||||
<el-link :underline="false" :disabled="!!!selectImageIndex.length" icon="el-icon-download"
|
||||
@click="downloadImages">{{ __('admin/file_manager.download') }}</el-link>
|
||||
<el-link :underline="false" :disabled="!!!selectImageIndex.length" icon="el-icon-view"
|
||||
@click="viewImages">{{ __('common.view') }}</el-link>
|
||||
<el-link :underline="false" :disabled="!!!selectImageIndex.length" @click="deleteFile"
|
||||
icon="el-icon-delete">{{ __('common.delete') }}</el-link>
|
||||
<el-link :underline="false" :disabled="selectImageIndex.length == 1 ? false : true"
|
||||
|
|
@ -115,7 +114,10 @@
|
|||
v-batch-select="{ className: '.image-list', selectImageIndex, setSelectStatus: updateSelectStatus }">
|
||||
<div :class="['image-list', file.selected ? 'active' : '']" v-for="file, index in images"
|
||||
:key="index" @click="checkedImage(index)">
|
||||
<div class="img"><img :src="file.url"></div>
|
||||
<div class="img">
|
||||
<i class="el-icon-video-play" v-if="file.mime == 'video/mp4'"></i>
|
||||
<img v-else :src="file.url">
|
||||
</div>
|
||||
<div class="text">
|
||||
<span :title="file.name">@{{ file.name }}</span>
|
||||
<i v-if="file.selected" class="el-icon-check"></i>
|
||||
|
|
@ -144,14 +146,13 @@
|
|||
</div>
|
||||
@else
|
||||
<div class="text-center mt-5 w-100 fs-4">{{ __('admin/file_manager.show_pc') }}</div>
|
||||
|
||||
@endif
|
||||
|
||||
<el-dialog title="{{ __('admin/file_manager.upload_files') }}" top="12vh" :visible.sync="uploadFileDialog.show" width="500px"
|
||||
@close="uploadFileDialogClose" custom-class="upload-wrap">
|
||||
<el-upload class="photos-upload" target="photos-upload" id="photos-upload" element-loading-text="{{ __('admin/file_manager.image_uploading') }}..."
|
||||
element-loading-background="rgba(0, 0, 0, 0.6)" drag action="" :show-file-list="false"
|
||||
accept=".jpg,.jpeg,.png,.JPG,.JPEG,.PNG,.mp4,.MP4" :before-upload="beforePhotoUpload"
|
||||
accept=".jpg,.jpeg,.png,.JPG,.JPEG,.PNG,.mp4,.MP4,.gif,.webp" :before-upload="beforePhotoUpload"
|
||||
:on-success="handlePhotoSuccess" :on-change="handleUploadChange" :http-request="uploadFile"
|
||||
:multiple="true">
|
||||
<i class="el-icon-upload"></i>
|
||||
|
|
@ -162,11 +163,13 @@
|
|||
<div class="info">
|
||||
<div class="name">@{{ index + 1 }}. @{{ image.name }}</div>
|
||||
<div class="status">
|
||||
<span v-if="image.status == 'complete'">{{ __('admin/file_manager.finish') }}</span>
|
||||
<span v-if="image.status == 'complete'" class="text-success">{{ __('admin/file_manager.finish') }}</span>
|
||||
<span v-else-if="image.status == 'fail'" class="text-danger">{{ __('admin/file_manager.upload_fail') }}</span>
|
||||
<span v-else>{{ __('admin/file_manager.uploading') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-progress :percentage="image.progre" :show-text="false" :stroke-width="4"></el-progress>
|
||||
<el-progress :percentage="image.progre" :status="image.status == 'fail' ? 'exception' : 'success'" :show-text="false" :stroke-width="4"></el-progress>
|
||||
<div v-if="image.fail_text" class="mt-1 text-danger" v-text="image.fail_text"></div>
|
||||
</div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
|
@ -187,13 +190,10 @@
|
|||
paneLengthPercent: 26,
|
||||
triggerLength: 10,
|
||||
isShift: false,
|
||||
|
||||
ssss: [],
|
||||
mime: @json(request('mime')),
|
||||
loading: false,
|
||||
isBatchSelect: false,
|
||||
|
||||
selectImageIndex: [],
|
||||
|
||||
filter: {
|
||||
sort: 'created',
|
||||
order: 'desc'
|
||||
|
|
@ -299,10 +299,6 @@
|
|||
this.uploadFileDialog.show = true
|
||||
},
|
||||
|
||||
openFileSort() {
|
||||
console.log(11);
|
||||
},
|
||||
|
||||
beforePhotoUpload(file) {
|
||||
// this.editing.photoLoading = true;
|
||||
},
|
||||
|
|
@ -319,9 +315,6 @@
|
|||
uploadFile(file) {
|
||||
const that = this;
|
||||
let newFile = {};
|
||||
if (file.file.type != 'image/png' && file.file.type != 'image/jpeg') {
|
||||
return;
|
||||
}
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append("file", file.file, file.file.name);
|
||||
|
|
@ -338,12 +331,16 @@
|
|||
|
||||
let index = this.uploadFileDialog.images.length - 1;
|
||||
|
||||
$http.post('file_manager/upload', formData).then((res) => {
|
||||
$http.post('file_manager/upload', formData, {hmsg: true}).then((res) => {
|
||||
this.uploadFileDialog.images[index].status = 'complete';
|
||||
this.uploadFileDialog.images[index].progre = 100;
|
||||
}).catch((err) => {
|
||||
this.uploadFileDialog.images[index].status = 'fail';
|
||||
this.uploadFileDialog.images[index].progre = 80;
|
||||
this.uploadFileDialog.images[index].fail_text = err.response.data.message;
|
||||
}).finally(() => {
|
||||
index += 1
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
handleUploadChange(e) {
|
||||
|
|
@ -450,6 +447,20 @@
|
|||
fileChecked() {
|
||||
let typedFiles = this.images.filter(e => e.selected)
|
||||
|
||||
if (this.mime) {
|
||||
// 判断 typedFiles 数组内 mime 是否有不是 image 开头的
|
||||
if (this.mime == 'image' && typedFiles.some(e => !e.mime.startsWith('image'))) {
|
||||
layer.msg('{{ __('admin/file_manager.verify_select_image') }}', () => {});
|
||||
return;
|
||||
}
|
||||
|
||||
// 判断 typedFiles 数组内 mime 是否有不是 video 开头的
|
||||
if (this.mime == 'video' && typedFiles.some(e => !e.mime.startsWith('video'))) {
|
||||
layer.msg('{{ __('admin/file_manager.verify_select_video') }}', () => {});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (callback !== null) {
|
||||
callback(typedFiles);
|
||||
}
|
||||
|
|
@ -521,6 +532,13 @@
|
|||
});
|
||||
},
|
||||
|
||||
viewImages() {
|
||||
const selectedImages = this.images.filter(e => e.selected);
|
||||
selectedImages.forEach(e => {
|
||||
window.open(e.origin_url);
|
||||
});
|
||||
},
|
||||
|
||||
openInputBox(type, node, data) {
|
||||
let fileSuffix, fileName = '';
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ $data = $plugin['data'];
|
|||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-lg-flex plugin-info">
|
||||
<div class="d-flex justify-content-between align-items-center plugin-icon-wrap">
|
||||
<div class="d-flex justify-content-between align-items-center plugin-icon-wrap w-max-400">
|
||||
<img src="{{ $data['icon_big'] }}" class="img-fluid plugin-icon">
|
||||
<img src="{{ $data['icon_big'] }}" class="img-fluid plugin-icon-shadow">
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@
|
|||
<el-form-item label="{{ __('order.current_status') }}">
|
||||
{{ $order->status_format }}
|
||||
</el-form-item>
|
||||
@if ($order->status != 'completed')
|
||||
@if (count($statuses))
|
||||
<el-form-item label="{{ __('order.change_to_status') }}" prop="status">
|
||||
<el-select class="wp-200" size="small" v-model="form.status" placeholder="{{ __('common.please_choose') }}">
|
||||
<el-option
|
||||
|
|
@ -184,7 +184,7 @@
|
|||
<td>{{ $product->product_id }}</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="wh-60 me-2"><img src="{{ $product->image }}" class="img-fluid"></div>{{ $product->name }}
|
||||
<div class="wh-60 me-2"><img src="{{ $product->image }}" class="img-fluid max-h-100"></div>{{ $product->name }}
|
||||
</div>
|
||||
</td>
|
||||
<td class="">{{ $product->product_sku }}</td>
|
||||
|
|
@ -208,6 +208,50 @@
|
|||
</div>
|
||||
@endhookwrapper
|
||||
|
||||
@if ($order->orderPayments)
|
||||
@hookwrapper('admin.order.form.payments')
|
||||
<div class="card mb-4">
|
||||
<div class="card-header"><h6 class="card-title">{{ __('admin/order.payments_history') }}</h6></div>
|
||||
<div class="card-body">
|
||||
<div class="table-push">
|
||||
<table class="table ">
|
||||
<thead class="">
|
||||
<tr>
|
||||
<th>{{ __('admin/order.order_id') }}</th>
|
||||
<th>{{ __('admin/order.text_transaction_id') }}</th>
|
||||
<th>{{ __('admin/order.text_request') }}</th>
|
||||
<th>{{ __('admin/order.text_response') }}</th>
|
||||
<th>{{ __('admin/order.text_callback') }}</th>
|
||||
<th>{{ __('admin/order.text_receipt') }}</th>
|
||||
<th>{{ __('order.created_at') }}</th>
|
||||
<th>{{ __('order.updated_at') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($order->orderPayments as $payment)
|
||||
<tr>
|
||||
<td>{{ $payment->order_id }}</td>
|
||||
<td>{{ $payment->transaction_id }}</td>
|
||||
<td>{{ $payment->request }}</td>
|
||||
<td>{{ $payment->response }}</td>
|
||||
<td>{{ $payment->callback }}</td>
|
||||
<td>
|
||||
@if ($payment->receipt)
|
||||
<a href="{{ image_origin($payment->receipt) }}" target="_blank">{{ __('admin/order.text_click_view') }}</a>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $payment->created_at }}</td>
|
||||
<td>{{ $payment->updated_at }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endhookwrapper
|
||||
@endif
|
||||
|
||||
@if ($order->orderShipments)
|
||||
@hookwrapper('admin.order.form.shipments')
|
||||
<div class="card mb-4">
|
||||
|
|
@ -219,7 +263,7 @@
|
|||
<tr>
|
||||
<th>{{ __('order.express_company') }}</th>
|
||||
<th>{{ __('order.express_number') }}</th>
|
||||
<th>{{ __('order.history_created_at') }}</th>
|
||||
<th>{{ __('order.updated_at') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
@ -265,7 +309,7 @@
|
|||
<tr>
|
||||
<th>{{ __('order.history_status') }}</th>
|
||||
<th>{{ __('order.history_comment') }}</th>
|
||||
<th>{{ __('order.history_created_at') }}</th>
|
||||
<th>{{ __('order.updated_at') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
<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'] ?? ''
|
||||
href="{{ shop_route('page_categories.show', $item['id']) }}" target="_blank">{{ $item['title_format'] ?? ''
|
||||
}}</a></div>
|
||||
</td>
|
||||
<td class="{{ $item['active'] ? 'text-success' : 'text-secondary' }}">
|
||||
|
|
|
|||
|
|
@ -79,7 +79,19 @@
|
|||
</draggable>
|
||||
<div class="help-text mb-1 mt-1">{{ __('admin/product.image_help') }}</div>
|
||||
</x-admin::form.row>
|
||||
{{-- <x-admin-form-input name="video" title="视频" :value="old('video', $product->video ?? '')" /> --}}
|
||||
|
||||
<x-admin::form.row title="{{ __('product.video') }}">
|
||||
<div class="d-flex align-items-end">
|
||||
<div class="set-product-img wh-80 rounded-2 me-2" @click="addProductVideo">
|
||||
<i v-if="form.video.path" class="bi bi-play-circle fs-1"></i>
|
||||
<i v-else class="bi bi-plus fs-1 text-muted"></i>
|
||||
</div>
|
||||
<input type="hidden" name="video" :value="form.video.path">
|
||||
<a v-if="form.video.path" target="_blank" :href="form.video.url">{{ __('common.view') }}</a>
|
||||
</div>
|
||||
<div class="help-text mb-1 mt-1">{{ __('admin/product.video_help') }}</div>
|
||||
</x-admin::form.row>
|
||||
|
||||
<x-admin-form-input name="position" :title="__('common.sort_order')" :value="old('position', $product->position ?? '0')" />
|
||||
|
||||
<x-admin::form.row :title="__('admin/product.weight_text')">
|
||||
|
|
@ -516,6 +528,10 @@
|
|||
form: {
|
||||
attributes: @json(old('pickups', $product_attributes) ?? []),
|
||||
images: @json(old('images', $product->images) ?? []),
|
||||
video: {
|
||||
path: @json(old('video', $product->video ?? '')),
|
||||
url: @json(image_origin(old('video', $product->video ?? ''))),
|
||||
},
|
||||
model: @json($product->skus[0]['model'] ?? ''),
|
||||
price: @json($product->skus[0]['price'] ?? ''),
|
||||
quantity: @json($product->skus[0]['quantity'] ?? ''),
|
||||
|
|
@ -678,7 +694,13 @@
|
|||
return;
|
||||
}
|
||||
this.form.images.push(...images.map(e => e.path))
|
||||
})
|
||||
}, {mime: 'image'})
|
||||
},
|
||||
|
||||
addProductVideo() {
|
||||
bk.fileManagerIframe(images => {
|
||||
this.form.video = {path: images[0].path, url: images[0].url}
|
||||
}, {mime: 'video'})
|
||||
},
|
||||
|
||||
removeImages(index) {
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@
|
|||
</td>
|
||||
@endif
|
||||
@hook('admin.product.list.column_value')
|
||||
<td class="text-end">
|
||||
<td class="text-end text-nowrap">
|
||||
@if ($product['deleted_at'] == '')
|
||||
<a href="{{ admin_route('products.edit', [$product['id']]) }}" class="btn btn-outline-secondary btn-sm">{{ __('common.edit') }}</a>
|
||||
<a href="javascript:void(0)" class="btn btn-outline-danger btn-sm" @click.prevent="deleteProduct({{ $loop->index }})">{{ __('common.delete') }}</a>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@
|
|||
<td>{{ $rma['type'] }}</td>
|
||||
<td>{{ $rma['status'] }}</td>
|
||||
<td><a href="{{ admin_route('rmas.show', [$rma['id']]) }}"
|
||||
class="btn btn-outline-secondary btn-sm">{{ __('common.view') }}</a>
|
||||
class="btn btn-outline-secondary btn-sm text-nowrap">{{ __('common.view') }}</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
|
|
|
|||
|
|
@ -7,11 +7,11 @@
|
|||
<div class="card-header"><h6 class="card-title">{{ __('admin/rma.rma_details') }}</h6></div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-lg-4 col-12">
|
||||
<div class="col-lg-4 col-12 order-top-info">
|
||||
<table class="table table-borderless">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width:40%">ID:</td>
|
||||
<td>ID:</td>
|
||||
<td>{{ $rma['id'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
@ -25,11 +25,11 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-lg-4 col-12">
|
||||
<div class="col-lg-4 col-12 order-top-info">
|
||||
<table class="table table-borderless">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="width:40%">{{ __('admin/builder.modules_product') }}:</td>
|
||||
<td>{{ __('admin/builder.modules_product') }}:</td>
|
||||
<td>{{ $rma['product_name'] }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@
|
|||
<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/vue/2.7/vue' . (!config('app.debug') ? '.min' : '') . '.js') }}"></script>
|
||||
<script src="{{ asset('vendor/element-ui/2.15.6/js.js') }}"></script>
|
||||
<link rel="stylesheet" href="{{ asset('vendor/element-ui/2.15.6/css.css') }}">
|
||||
<script src="{{ asset('vendor/element-ui/index.js') }}"></script>
|
||||
<link rel="stylesheet" href="{{ asset('vendor/element-ui/index.css') }}">
|
||||
{{-- <link href="{{ mix('build/css/admin/login.css') }}" rel="stylesheet"> --}}
|
||||
<script src="{{ mix('build/beike/admin/js/app.js') }}"></script>
|
||||
<link href="{{ mix('build/beike/admin/css/app.css') }}" rel="stylesheet">
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ h1,h2,h3, h4, h5, h6, b, strong {
|
|||
|
||||
img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
|
|
@ -321,4 +322,25 @@ img {
|
|||
padding-top: .8rem;
|
||||
padding-bottom: .8rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 溢出隐藏 显示省略号
|
||||
.text-ellipsis {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
// 加一个 line
|
||||
&.line-2 {
|
||||
white-space: normal;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
&.line-3 {
|
||||
white-space: normal;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,32 +9,25 @@
|
|||
*/
|
||||
|
||||
header {
|
||||
// box-shadow: 0px 1px 10px rgba(0, 0, 0, .04);
|
||||
background: #fff;
|
||||
body:not(.page-home) & {
|
||||
box-shadow: 0 6px 12px 0 rgba(0, 0, 0, .04);
|
||||
// border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
|
||||
.top-wrap {
|
||||
// padding: 10px;
|
||||
height: 40px;
|
||||
// max-height: 50px;
|
||||
background: #F7F8FA;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.top-wrap, .header-content {
|
||||
.dropdown {
|
||||
&:hover {
|
||||
background-color: #fff;
|
||||
|
||||
.dropdown-menu {
|
||||
margin: 0;
|
||||
display: block;
|
||||
box-shadow: 0 0 15px rgb(0, 0, 0, .1);
|
||||
border: none;
|
||||
box-shadow: 0 0 15px rgb(0, 0, 0, .1);
|
||||
|
||||
&.dropdown-menu-end {
|
||||
right: 0;
|
||||
|
|
@ -44,6 +37,38 @@ header {
|
|||
}
|
||||
}
|
||||
|
||||
.header-content {
|
||||
.nav-item {
|
||||
&:hover {
|
||||
> a {
|
||||
color: $primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown {
|
||||
.dropdown-menu {
|
||||
border: none;
|
||||
left: 50%;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
display: block;
|
||||
transform-origin: top center;
|
||||
transition: all .2s ease-in-out;
|
||||
transform: translate(-50%, 0.5rem);
|
||||
box-shadow: 0 0 15px rgb(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.dropdown-menu {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transform: translate(-50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.header-content {
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
|
|
@ -59,36 +84,6 @@ header {
|
|||
max-width: 1140px;
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
.navbar-nav {
|
||||
.dropdown {
|
||||
|
||||
&.position-static >.dropdown-menu {
|
||||
// top: 100%;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.dropdown-menu {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transform: translate(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
>.dropdown-menu {
|
||||
left: 50%;
|
||||
transform: translate(-50%, 0.5rem);
|
||||
transition: all .2s ease-in-out;
|
||||
transition-property: visibility,transform,opacity;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
display: block;
|
||||
transform-origin: top center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> .navbar-nav {
|
||||
> .nav-item {
|
||||
background-color: transparent;
|
||||
|
|
@ -384,12 +379,17 @@ header {
|
|||
|
||||
.children-group {
|
||||
.children-title {
|
||||
height: 44px;
|
||||
span {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
margin-right: -10px;
|
||||
width: 44px;
|
||||
height: 42px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
&:active {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
&[aria-expanded="true"] {
|
||||
i::before {
|
||||
|
|
|
|||
|
|
@ -12,14 +12,15 @@ body.page-account-address, body.page-checkout {
|
|||
.addresses-wrap {
|
||||
.item {
|
||||
position: relative;
|
||||
padding: 14px 14px 14px 18px;
|
||||
padding: 14px;
|
||||
margin-bottom: 1.3rem;
|
||||
border: 1px solid #e8e8e8;
|
||||
height: 130px;
|
||||
border: 1px solid #e5e5e5;
|
||||
height: 140px;
|
||||
cursor: pointer;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
padding: 10px 10px 10px 14px;
|
||||
padding: 10px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
|
|
@ -58,6 +59,7 @@ body.page-account-address, body.page-checkout {
|
|||
|
||||
.zipcode {
|
||||
margin-bottom: .3rem;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
.address-info {
|
||||
|
|
@ -67,13 +69,11 @@ body.page-account-address, body.page-checkout {
|
|||
}
|
||||
|
||||
.address-bottom {
|
||||
min-height: 28px;
|
||||
display: flex;
|
||||
align-items: center; // flex-start | center
|
||||
justify-content: space-between; // flex-end | center | space-between
|
||||
// flex-wrap: wrap;
|
||||
a {
|
||||
color: #2d68a8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -170,9 +170,8 @@ body.page-checkout, body.page-bk-stripe {
|
|||
align-items: center; // flex-start | center
|
||||
padding-right: 4px;
|
||||
|
||||
img {
|
||||
width: 40px;
|
||||
margin-right: 10px;
|
||||
.img {
|
||||
flex: 0 0 40px;
|
||||
}
|
||||
|
||||
.quantity {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ body.page-product {
|
|||
}
|
||||
|
||||
.product-image {
|
||||
position: relative;
|
||||
|
||||
#swiper {
|
||||
height: 250px;
|
||||
@media (min-width: 480px) {
|
||||
|
|
@ -117,6 +119,68 @@ body.page-product {
|
|||
|
||||
.right {
|
||||
border: 1px solid #eee;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#product-video {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 99;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.open-video {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
z-index: 99;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
transform: translateX(-50%);
|
||||
left: 50%;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
i {
|
||||
color: #fff;
|
||||
background-color: rgba(0, 0, 0, 0.648);
|
||||
}
|
||||
}
|
||||
|
||||
i {
|
||||
font-size: 3.5rem;
|
||||
line-height: 1;
|
||||
border-radius: 50%;
|
||||
font-weight: 400;
|
||||
display: inline-block;
|
||||
color: rgba(255, 255, 255, 0.948);
|
||||
background-color: rgba(0, 0, 0, 0.348);
|
||||
|
||||
@media (max-width: 768px) {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.close-video {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 10px;
|
||||
z-index: 9999;
|
||||
color: #aaa;
|
||||
font-size: 30px;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* @link https://beikeshop.com
|
||||
* @Author pu shuo <pushuo@guangda.work>
|
||||
* @Date 2022-08-29 17:32:51
|
||||
* @LastEditTime 2023-02-02 11:06:01
|
||||
* @LastEditTime 2023-05-18 10:18:09
|
||||
*/
|
||||
|
||||
import http from "../../../../js/http";
|
||||
|
|
@ -19,22 +19,6 @@ import './header'
|
|||
import './bootstrap-validation'
|
||||
|
||||
$(document).ready(function ($) {
|
||||
$(document).on('click', '.offcanvas-products-delete', function () {
|
||||
const id = $(this).data('id');
|
||||
|
||||
$http.delete(`carts/${id}`).then((res) => {
|
||||
$(this).parents('.product-list').remove();
|
||||
if (!res.data.quantity) {
|
||||
$('.cart-badge-quantity').hide();
|
||||
} else {
|
||||
$('.cart-badge-quantity').show().html(res.data.quantity > 99 ? '99+' : res.data.quantity);
|
||||
}
|
||||
|
||||
$('.offcanvas-right-cart-count').text(res.data.quantity);
|
||||
$('.offcanvas-right-cart-amount').text(res.data.amount_format);
|
||||
})
|
||||
})
|
||||
|
||||
if ($(window).width() > 992 && $('.x-fixed-top').length) {
|
||||
$('.x-fixed-top').scrollToFixed({
|
||||
zIndex: 999,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* @link https://beikeshop.com
|
||||
* @Author pu shuo <pushuo@guangda.work>
|
||||
* @Date 2022-09-09 19:16:39
|
||||
* @LastEditTime 2023-02-13 09:26:05
|
||||
* @LastEditTime 2023-05-18 09:02:44
|
||||
*/
|
||||
|
||||
export default {
|
||||
|
|
@ -31,7 +31,7 @@ export default {
|
|||
* @param {*} isBuyNow 是否立即购买
|
||||
* @return {*} 返回Promise
|
||||
*/
|
||||
addCart({sku_id, quantity = 1, isBuyNow = false}, event) {
|
||||
addCart({sku_id, quantity = 1, isBuyNow = false}, event, callback) {
|
||||
if (!config.isLogin && !config.guestCheckout) {
|
||||
this.openLogin()
|
||||
return;
|
||||
|
|
@ -46,8 +46,9 @@ export default {
|
|||
$http.post('/carts', {sku_id, quantity, buy_now: isBuyNow}, {hload: !!event}).then((res) => {
|
||||
this.getCarts();
|
||||
layer.msg(res.message)
|
||||
if (isBuyNow) {
|
||||
location.href = 'checkout'
|
||||
|
||||
if (callback) {
|
||||
callback(res)
|
||||
}
|
||||
}).finally(() => {$btn.html(btnHtml).prop('disabled', false)})
|
||||
},
|
||||
|
|
@ -96,6 +97,18 @@ export default {
|
|||
});
|
||||
},
|
||||
|
||||
productQuickView(id, callback) {
|
||||
layer.open({
|
||||
type: 2,
|
||||
title: '',
|
||||
shadeClose: true,
|
||||
scrollbar: false,
|
||||
area: ['1000px', '600px'],
|
||||
skin: 'login-pop-box',
|
||||
content: `products/${id}?iframe=true`
|
||||
});
|
||||
},
|
||||
|
||||
getQueryString(name, defaultValue) {
|
||||
const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)');
|
||||
const r = window.location.search.substr(1).match(reg);
|
||||
|
|
@ -129,4 +142,35 @@ export default {
|
|||
+ ',width=' + iWidth + ',innerWidth=' + iWidth + ',top=' + iTop + ',left=' + iLeft
|
||||
+ ',toolbar=no,menubar=no,scrollbars=auto,resizeable=no,location=no,status=no');
|
||||
},
|
||||
|
||||
// 判断 js 插件是否加载,如果未加载则往页面添加 script 标签
|
||||
loadScript(url, callback) {
|
||||
// 判断页面中是否已经存在指定的 js 插件
|
||||
if (!document.querySelector(`script[src="${url}"]`)) {
|
||||
// 创建一个新的 script 标签
|
||||
const script = document.createElement('script');
|
||||
script.src = url;
|
||||
// 将 script 标签添加到 head 标签中
|
||||
document.head.appendChild(script);
|
||||
// 监听 js 插件加载完成事件
|
||||
script.onload = function () {
|
||||
callback && callback();
|
||||
}
|
||||
} else {
|
||||
callback && callback();
|
||||
}
|
||||
},
|
||||
|
||||
// 判断 css 插件是否加载,如果未加载则往页面添加 link 标签
|
||||
loadStyle(url) {
|
||||
// 判断页面中是否已经存在指定的 css 插件
|
||||
if (!document.querySelector(`link[href="${url}"]`)) {
|
||||
// 创建一个新的 link 标签
|
||||
const link = document.createElement('link');
|
||||
link.href = url;
|
||||
link.rel = 'stylesheet';
|
||||
// 将 link 标签添加到 head 标签中
|
||||
document.head.appendChild(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* @link https://beikeshop.com
|
||||
* @Author pu shuo <pushuo@guangda.work>
|
||||
* @Date 2022-08-16 18:47:18
|
||||
* @LastEditTime 2023-03-16 17:30:20
|
||||
* @LastEditTime 2023-05-18 10:27:58
|
||||
*/
|
||||
|
||||
$(function () {
|
||||
|
|
@ -22,6 +22,35 @@ $(function () {
|
|||
});
|
||||
}
|
||||
|
||||
// 购物车侧边栏弹出
|
||||
$(document).on("click", ".btn-right-cart", function () {
|
||||
const currentUrl = window.location.pathname;
|
||||
if (currentUrl == '/checkout' || currentUrl == '/carts') {
|
||||
return;
|
||||
}
|
||||
|
||||
const offcanvasRightCart = new bootstrap.Offcanvas('#offcanvas-right-cart')
|
||||
offcanvasRightCart.show()
|
||||
});
|
||||
|
||||
// 侧边栏购物车删除商品
|
||||
$(document).on('click', '.offcanvas-products-delete', function () {
|
||||
const id = $(this).data('id');
|
||||
|
||||
$http.delete(`carts/${id}`).then((res) => {
|
||||
$(this).parents('.product-list').remove();
|
||||
if (!res.data.quantity) {
|
||||
$('.cart-badge-quantity').hide();
|
||||
$('.empty-cart').removeClass('d-none');
|
||||
} else {
|
||||
$('.cart-badge-quantity').show().html(res.data.quantity > 99 ? '99+' : res.data.quantity);
|
||||
}
|
||||
|
||||
$('.offcanvas-right-cart-count').text(res.data.quantity);
|
||||
$('.offcanvas-right-cart-amount').text(res.data.amount_format);
|
||||
})
|
||||
})
|
||||
|
||||
// 响应式下弹窗菜单交互
|
||||
$(document).on("click", ".mobile-open-menu", function () {
|
||||
const offcanvasMobileMenu = new bootstrap.Offcanvas('#offcanvas-mobile-menu')
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* @link https://beikeshop.com
|
||||
* @Author pu shuo <pushuo@guangda.work>
|
||||
* @Date 2022-08-02 19:19:52
|
||||
* @LastEditTime 2022-09-16 20:58:16
|
||||
* @LastEditTime 2023-05-29 18:56:35
|
||||
*/
|
||||
|
||||
window.axios = require('axios');
|
||||
|
|
@ -25,8 +25,8 @@ export default {
|
|||
* @param url 接口路由
|
||||
* @returns {AxiosPromise<any>}
|
||||
*/
|
||||
get (url, params, {hmsg, hload}={}) {
|
||||
return this.request('get', url, params = params, {hmsg, hload});
|
||||
get (url, params, {hmsg, hload, base}={}) {
|
||||
return this.request('get', url, params = params, {hmsg, hload, base});
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -37,8 +37,8 @@ export default {
|
|||
* @returns {AxiosPromise<any>}
|
||||
*/
|
||||
|
||||
post (url, params, {hmsg, hload}={}) {
|
||||
return this.request('post', url, params, {hmsg, hload});
|
||||
post (url, params, {hmsg, hload, base}={}) {
|
||||
return this.request('post', url, params, {hmsg, hload, base});
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -48,8 +48,8 @@ export default {
|
|||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
delete (url, params, {hmsg, hload}={}) {
|
||||
return this.request('delete', url, params, {hmsg, hload});
|
||||
delete (url, params, {hmsg, hload, base}={}) {
|
||||
return this.request('delete', url, params, {hmsg, hload, base});
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -59,8 +59,8 @@ export default {
|
|||
* @returns {Promise}
|
||||
*/
|
||||
|
||||
put (url, params, {hmsg, hload}={}) {
|
||||
return this.request('put', url, params, {hmsg, hload});
|
||||
put (url, params, {hmsg, hload, base}={}) {
|
||||
return this.request('put', url, params, {hmsg, hload, base});
|
||||
},
|
||||
|
||||
|
||||
|
|
@ -73,11 +73,15 @@ export default {
|
|||
* @returns {Promise<any>}
|
||||
*/
|
||||
// 错误和失败信息都在这里进行处理,界面中调用的时候只处理正确数据即可
|
||||
request(method, url, params = {}, {hmsg, hload} = {}) {
|
||||
request(method, url, params = {}, {hmsg, hload, base} = {}) {
|
||||
if (!hload) {
|
||||
layer.load(2, {shade: [0.3,'#fff'] })
|
||||
}
|
||||
|
||||
if (base) {
|
||||
axios.defaults.baseURL = base;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
axios({method: method, url: url, [method == 'get' ? 'params' : 'data']: params}).then((res) => {
|
||||
if (res) {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
return [
|
||||
'index' => 'Edit Address',
|
||||
'name' => 'Name',
|
||||
'name' => 'Full name',
|
||||
'phone' => 'Phone',
|
||||
'country_id' => 'Country ID',
|
||||
'zone' => 'Zone',
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@ return [
|
|||
'no_file' => 'No File',
|
||||
'picture_space' => 'Picture Space',
|
||||
'show_pc' => 'Please go to the PC side to operate',
|
||||
'verify_select_image' => 'Please select a picture',
|
||||
'verify_select_video' => 'Please select video',
|
||||
|
||||
'confirm_delete_file' => 'Do you want to delete the selected file',
|
||||
'confirm_delete_folder' => 'The folder deletion operation is in progress, all files in the folder will be deleted, do you want to confirm?',
|
||||
|
|
@ -40,5 +42,6 @@ return [
|
|||
'can_empty' => 'Can not be empty',
|
||||
'finish' => 'Finish',
|
||||
'uploading' => 'loading...',
|
||||
'upload_fail' => 'Upload failed',
|
||||
'file_manager' => 'File Manager',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -12,15 +12,24 @@
|
|||
return [
|
||||
'list' => 'Order List',
|
||||
|
||||
'order_quantity' => 'Order Quantity',
|
||||
'order_amount' => 'Order Amount',
|
||||
'orders_index' => 'Index',
|
||||
'orders_create' => 'Create',
|
||||
'orders_show' => 'Detail',
|
||||
'orders_export' => 'Export',
|
||||
'orders_update' => 'Update',
|
||||
'orders_delete' => 'Delete',
|
||||
'notify' => 'Whether to remind',
|
||||
'orders_update_status' => 'Update Status',
|
||||
'error_status' => 'Please select a status',
|
||||
'order_quantity' => 'Order Quantity',
|
||||
'order_amount' => 'Order Amount',
|
||||
'orders_index' => 'Index',
|
||||
'orders_create' => 'Create',
|
||||
'orders_show' => 'Detail',
|
||||
'orders_export' => 'Export',
|
||||
'orders_update' => 'Update',
|
||||
'orders_delete' => 'Delete',
|
||||
'notify' => 'Whether to remind',
|
||||
'orders_update_status' => 'Update Status',
|
||||
'error_status' => 'Please select a status',
|
||||
'payments_history' => 'Payment History',
|
||||
'text_response' => 'Pesponse',
|
||||
'text_request' => 'Pequest',
|
||||
'text_callback' => 'Callback',
|
||||
'text_callback' => 'Callback',
|
||||
'text_receipt' => 'Receipt',
|
||||
'order_id' => 'Order Id',
|
||||
'text_transaction_id' => 'Transaction Id',
|
||||
'text_click_view' => 'Click To View',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ return [
|
|||
'quantity' => 'Quantity',
|
||||
'enable_multi_spec' => 'Enable multi-spec',
|
||||
'image_help' => 'The first picture will be used as the main picture of the product, and multiple pictures can be uploaded at the same time, and the position of multiple pictures can be adjusted at will',
|
||||
'video_help' => 'If the prompt exceeds the system size limit, please modify the php.ini parameter post_max_size',
|
||||
'add_variable' => 'Add Specs',
|
||||
'add_variable_value' => 'Add Specification Value',
|
||||
'add_variable_image' => 'Add Spec Image',
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ return [
|
|||
'get_more' => 'Get More',
|
||||
'view_more' => 'View more',
|
||||
'view_details' => 'Check Details',
|
||||
'quick_view' => 'Quick View',
|
||||
|
||||
'id' => 'ID',
|
||||
'created_at' => 'Created At',
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ return [
|
|||
'g' => 'Gram',
|
||||
'oz' => 'Ounce',
|
||||
'lb' => 'Pound',
|
||||
'video' => 'Video',
|
||||
|
||||
'active' => 'Active',
|
||||
'inactive' => 'Inactive',
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ return [
|
|||
'addresses' => [
|
||||
'index' => 'Addresses',
|
||||
'add_address' => 'Add New Address',
|
||||
'default_address' => 'Default Address',
|
||||
'default_address' => 'Default',
|
||||
'delete' => 'Delete',
|
||||
'edit' => 'Edit',
|
||||
'enter_name' => 'Please type in your name',
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue