!123 Add video function
* Optimize shopping cart entries * File manager selection type judgment * video function * Support video for file manager * Optimize file manager
This commit is contained in:
parent
523b8a3e7c
commit
e7019a9722
|
|
@ -33,7 +33,7 @@ class UploadRequest extends FormRequest
|
|||
public function rules()
|
||||
{
|
||||
return [
|
||||
'file' => 'required|image|mimes:jpg,png,jpeg,gif,svg|max:10240',
|
||||
'file' => 'required|mimes:jpg,png,jpeg,gif,svg,mp4|max:20480',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,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,
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ class Order extends Base
|
|||
public function getStatusFormatAttribute()
|
||||
{
|
||||
$statusMap = array_column(StateMachineService::getAllStatuses(), 'name', 'status');
|
||||
|
||||
return $statusMap[$this->status];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ class OrderHistory extends Base
|
|||
public function getStatusFormatAttribute()
|
||||
{
|
||||
$statusMap = array_column(StateMachineService::getAllStatuses(), 'name', 'status');
|
||||
|
||||
return $statusMap[$this->status];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ class CategoryRepo
|
|||
$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 . "' ";
|
||||
if (!$includeInactive) {
|
||||
if (! $includeInactive) {
|
||||
$sql .= ' AND c1.active = 1 ';
|
||||
}
|
||||
$sql .= ' GROUP BY cp.category_id ORDER BY c1.position ASC';
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ class OrderController extends Controller
|
|||
}
|
||||
|
||||
$order = Order::query()->where('number', $number)->where('email', $email)->firstOrFail();
|
||||
$data = hook_filter('order.show.data', ['order' => $order, 'html_items' => []]);
|
||||
$data = hook_filter('order.show.data', ['order' => $order, 'html_items' => []]);
|
||||
|
||||
return view('order_info', $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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
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-05-18 15:33:10
|
||||
* @LastEditTime 2023-06-08 19:18:24
|
||||
*/
|
||||
|
||||
import http from "../../../js/http";
|
||||
|
|
@ -95,21 +95,17 @@ const tinymceInit = () => {
|
|||
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,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) {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -107,19 +107,18 @@ Vue.component('rich-text-i18n', {
|
|||
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" />`);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -73,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"
|
||||
|
|
@ -114,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>
|
||||
|
|
@ -143,7 +146,6 @@
|
|||
</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"
|
||||
|
|
@ -161,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>
|
||||
|
|
@ -186,13 +190,10 @@
|
|||
paneLengthPercent: 26,
|
||||
triggerLength: 10,
|
||||
isShift: false,
|
||||
|
||||
ssss: [],
|
||||
mime: @json(request('mime')),
|
||||
loading: false,
|
||||
isBatchSelect: false,
|
||||
|
||||
selectImageIndex: [],
|
||||
|
||||
filter: {
|
||||
sort: 'created',
|
||||
order: 'desc'
|
||||
|
|
@ -330,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) {
|
||||
|
|
@ -442,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);
|
||||
}
|
||||
|
|
@ -513,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 = '';
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -322,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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ return [
|
|||
'g' => 'Gram',
|
||||
'oz' => 'Ounce',
|
||||
'lb' => 'Pound',
|
||||
'video' => 'Video',
|
||||
|
||||
'active' => 'Active',
|
||||
'inactive' => 'Inactive',
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ return [
|
|||
'index' => 'Cart',
|
||||
'added_to_cart' => 'Added To Cart',
|
||||
'select_all' => 'Select All',
|
||||
'commodity' => 'Commodity',
|
||||
'commodity' => 'Product',
|
||||
'quantity' => 'Quantity',
|
||||
'subtotal' => 'Subtotal',
|
||||
'product_total' => 'Product Total',
|
||||
|
|
|
|||
|
|
@ -33,12 +33,15 @@ return [
|
|||
'no_file' => '没有文件',
|
||||
'picture_space' => '图片空间',
|
||||
'show_pc' => '请到PC端操作',
|
||||
'verify_select_image' => '请选择图片',
|
||||
'verify_select_video' => '请选择视频',
|
||||
|
||||
'confirm_delete_file' => '是否要删除选中文件',
|
||||
'confirm_delete_folder' => '正在进行删除文件夹操作,文件夹内所有文件都将被删除,是否确认?',
|
||||
'new_folder' => '新建文件夹',
|
||||
'can_empty' => '不能为空',
|
||||
'finish' => '完成',
|
||||
'uploading' => '上传中',
|
||||
'file_manager' => '图片管理器',
|
||||
'confirm_delete_file' => '是否要删除选中文件',
|
||||
'confirm_delete_folder' => '正在进行删除文件夹操作,文件夹内所有文件都将被删除,是否确认?',
|
||||
'new_folder' => '新建文件夹',
|
||||
'can_empty' => '不能为空',
|
||||
'finish' => '完成',
|
||||
'uploading' => '上传中',
|
||||
'upload_fail' => '上传失败',
|
||||
'file_manager' => '图片管理器',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ return [
|
|||
'quantity' => '数量',
|
||||
'enable_multi_spec' => '启用多规格',
|
||||
'image_help' => '第一张图片将作为商品主图,支持同时上传多张图片,多张图片之间可随意调整位置',
|
||||
'video_help' => '如果提示超出系统大小限制,请修改 php.ini 参数 post_max_size',
|
||||
'add_variable' => '添加规格',
|
||||
'add_variable_value' => '添加规格值',
|
||||
'add_variable_image' => '添加规格图片',
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ return [
|
|||
'g' => '克',
|
||||
'oz' => '盎司',
|
||||
'lb' => '磅',
|
||||
'video' => '视频',
|
||||
|
||||
'active' => '上架',
|
||||
'inactive' => '下架',
|
||||
|
|
|
|||
|
|
@ -14,40 +14,41 @@
|
|||
<h5 class="card-title">{{ __('shop/account.rma.index') }}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ __('shop/account.rma.commodity') }}</th>
|
||||
<th>{{ __('shop/account.rma.quantity') }}</th>
|
||||
<th>{{ __('shop/account.rma.service_type') }}</th>
|
||||
<th>{{ __('shop/account.rma.return_reason') }}</th>
|
||||
<th>{{ __('shop/account.rma.creation_time') }}</th>
|
||||
{{-- <th>状态</th> --}}
|
||||
<th class="text-end">{{ __('common.action') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if (count($rmas))
|
||||
@foreach ($rmas as $rma)
|
||||
<tr>
|
||||
<td>{{ sub_string($rma['product_name'], 80) }}</td>
|
||||
<td>{{ $rma['quantity'] }}</td>
|
||||
<td>{{ $rma['type'] }}</td>
|
||||
<td>{{ $rma['reason'] }}</td>
|
||||
<td>{{ $rma['created_at'] }}</td>
|
||||
<td class="text-end"><a href="{{ shop_route('account.rma.show', [$rma['id']]) }}"
|
||||
class="btn btn-outline-secondary btn-sm">{{ __('shop/account.rma.check') }}</a> </td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@else
|
||||
<div class="table-responsive">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td colspan="6" class="border-0">
|
||||
<x-shop-no-data />
|
||||
</td>
|
||||
<th>{{ __('shop/account.rma.commodity') }}</th>
|
||||
<th class="text-nowrap">{{ __('shop/account.rma.quantity') }}</th>
|
||||
<th class="text-nowrap">{{ __('shop/account.rma.service_type') }}</th>
|
||||
<th class="text-nowrap">{{ __('shop/account.rma.creation_time') }}</th>
|
||||
<th class="text-end">{{ __('common.action') }}</th>
|
||||
</tr>
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
@if (count($rmas))
|
||||
@foreach ($rmas as $rma)
|
||||
<tr>
|
||||
<td>
|
||||
<div class="text-ellipsis line-2 w-min-100 w-max-300">{{ sub_string($rma['product_name'], 80) }}</div>
|
||||
</td>
|
||||
<td>{{ $rma['quantity'] }}</td>
|
||||
<td>{{ $rma['type'] }}</td>
|
||||
<td class="text-nowrap">{{ $rma['created_at'] }}</td>
|
||||
<td class="text-end"><a href="{{ shop_route('account.rma.show', [$rma['id']]) }}"
|
||||
class="btn text-nowrap btn-outline-secondary btn-sm">{{ __('shop/account.rma.check') }}</a> </td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@else
|
||||
<tr>
|
||||
<td colspan="6" class="border-0">
|
||||
<x-shop-no-data />
|
||||
</td>
|
||||
</tr>
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{-- {{ $rmas->links('shared/pagination/bootstrap-4') }} --}}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
<div class="row mt-5" v-if="products.length">
|
||||
<div class="col-12 col-md-9 left-column">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card shadow-sm h-min-600">
|
||||
<div class="card-body p-lg-4">
|
||||
<div class="p-lg-0"><h4 class="mb-3">{{ __('shop/carts.commodity') }}</h4></div>
|
||||
<div class="cart-products-wrap table-responsive">
|
||||
|
|
@ -36,8 +36,8 @@
|
|||
{{ __('shop/carts.select_all') }}
|
||||
</label>
|
||||
</th>
|
||||
<th width="40%">{{ __('shop/carts.index') }}</th>
|
||||
<th width="170">{{ __('shop/carts.commodity') }}</th>
|
||||
<th width="40%">{{ __('shop/carts.commodity') }}</th>
|
||||
<th width="170">{{ __('shop/carts.quantity') }}</th>
|
||||
<th width="170">{{ __('shop/carts.subtotal') }}</th>
|
||||
<th width="100" class="text-end">{{ __('common.action') }}</th>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
@if ($product['video'])
|
||||
<div class="video-wrap">
|
||||
<video
|
||||
id="product-video"
|
||||
class="video-js vjs-big-play-centered vjs-fluid vjs-16-9"
|
||||
controls loop muted
|
||||
>
|
||||
<source src="{{ image_origin($product['video']) }}" type="video/mp4" />
|
||||
</video>
|
||||
<div class="close-video d-none"><i class="bi bi-x-circle"></i></div>
|
||||
<div class="open-video d-none"><i class="bi bi-play-circle"></i></div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@push('add-scripts')
|
||||
<script>
|
||||
let pVideo = null;
|
||||
|
||||
$(function () {
|
||||
if ($('#product-video').length) {
|
||||
pVideo = videojs("product-video");
|
||||
|
||||
pVideo.on('loadedmetadata', function(e) {
|
||||
$('.open-video').removeClass('d-none');
|
||||
});
|
||||
|
||||
$(document).on('click', '.open-video', function () {
|
||||
pVideo.play();
|
||||
pVideo.currentTime(0);
|
||||
$(this).addClass('d-none');
|
||||
$('#product-video').fadeIn();
|
||||
$('.close-video').removeClass('d-none');
|
||||
});
|
||||
|
||||
$(document).on('click', '.close-video', function () {
|
||||
closeVideo()
|
||||
});
|
||||
}
|
||||
})
|
||||
|
||||
function closeVideo() {
|
||||
if (pVideo) {
|
||||
pVideo.pause();
|
||||
$('#product-video').fadeOut();
|
||||
$('.close-video').addClass('d-none');
|
||||
$('.open-video').removeClass('d-none');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@endpush
|
||||
|
|
@ -9,6 +9,10 @@
|
|||
<script src="{{ asset('vendor/swiper/swiper-bundle.min.js') }}"></script>
|
||||
<script src="{{ asset('vendor/zoom/jquery.zoom.min.js') }}"></script>
|
||||
<link rel="stylesheet" href="{{ asset('vendor/swiper/swiper-bundle.min.css') }}">
|
||||
@if ($product['video'])
|
||||
<script src="{{ asset('vendor/video/video.min.js') }}"></script>
|
||||
<link rel="stylesheet" href="{{ asset('vendor/video/video-js.min.css') }}">
|
||||
@endif
|
||||
@endpush
|
||||
|
||||
@php
|
||||
|
|
@ -41,9 +45,11 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="right" id="zoom">
|
||||
@include('product.product-video')
|
||||
<img :src="images.length ? images[0].preview : '{{ asset('image/placeholder.png') }}'" class="img-fluid">
|
||||
</div>
|
||||
@else
|
||||
@include('product.product-video')
|
||||
<div class="swiper" id="swiper-mobile">
|
||||
<div class="swiper-wrapper">
|
||||
<div class="swiper-slide" v-for="image, index in images">
|
||||
|
|
@ -324,6 +330,8 @@
|
|||
$('#zoom').trigger('zoom.destroy');
|
||||
$('#zoom').zoom({url: $('#swiper a').attr('data-zoom-image')});
|
||||
})
|
||||
|
||||
closeVideo()
|
||||
},
|
||||
|
||||
addCart(isBuyNow = false) {
|
||||
|
|
@ -385,6 +393,7 @@
|
|||
$('#zoom').trigger('zoom.destroy');
|
||||
$('#zoom img').attr('src', $(this).attr('data-image'));
|
||||
$('#zoom').zoom({url: $(this).attr('data-zoom-image')});
|
||||
closeVideo()
|
||||
});
|
||||
|
||||
var swiper = new Swiper("#swiper", {
|
||||
Loading…
Reference in New Issue