后台下单购买插件
购买插件 wip wip 购买插件微信支付 wip 优化插件购买 wip 修复插件购买 添加插件接口 返回json wip 优化插件详情页购买ui交互 添加弹出层插件 wip wip wip 插件市场设置 token 优化
This commit is contained in:
parent
ec30668fa4
commit
9f67ec43f0
|
|
@ -32,6 +32,7 @@ class MarketingController
|
|||
$plugins = MarketingService::getInstance()->getList($filters);
|
||||
$data = [
|
||||
'plugins' => $plugins,
|
||||
'domain' => str_replace(['http://', 'https://'], '', config('app.url')),
|
||||
'types' => PluginRepo::getTypes(),
|
||||
];
|
||||
|
||||
|
|
@ -52,8 +53,12 @@ class MarketingController
|
|||
$pluginCode = $request->code;
|
||||
$plugin = MarketingService::getInstance()->getPlugin($pluginCode);
|
||||
$data = [
|
||||
'domain' => str_replace(['http://', 'https://'], '', config('app.url')),
|
||||
'plugin' => $plugin,
|
||||
];
|
||||
if ($request->expectsJson()) {
|
||||
return $data;
|
||||
}
|
||||
return view('admin::pages.marketing.show', $data);
|
||||
} catch (\Exception $e) {
|
||||
return redirect(admin_route('marketing.index'))->withErrors(['error' => $e->getMessage()]);
|
||||
|
|
@ -61,6 +66,22 @@ class MarketingController
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* 下单购买插件
|
||||
*/
|
||||
public function buy(Request $request)
|
||||
{
|
||||
try {
|
||||
$postData = $request->getContent();
|
||||
$pluginCode = $request->code;
|
||||
$result = MarketingService::getInstance()->buy($pluginCode, $postData);
|
||||
return json_success('获取成功', $result);
|
||||
} catch (\Exception $e) {
|
||||
return json_fail($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 下载插件安装包到本地
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@ Route::prefix($adminName)
|
|||
// 插件市场
|
||||
Route::middleware('can:marketing_index')->get('marketing', [Controllers\MarketingController::class, 'index'])->name('marketing.index');
|
||||
Route::middleware('can:marketing_show')->get('marketing/{code}', [Controllers\MarketingController::class, 'show'])->name('marketing.show');
|
||||
Route::middleware('can:marketing_buy')->post('marketing/{code}/buy', [Controllers\MarketingController::class, 'buy'])->name('marketing.buy');
|
||||
Route::middleware('can:marketing_download')->post('marketing/{code}/download', [Controllers\MarketingController::class, 'download'])->name('marketing.download');
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,14 @@ class MarketingService
|
|||
return new self;
|
||||
}
|
||||
|
||||
public function getList($filters = [])
|
||||
|
||||
/**
|
||||
* 获取可插件市场插件列表
|
||||
*
|
||||
* @param array $filters
|
||||
* @return mixed
|
||||
*/
|
||||
public function getList(array $filters = []): mixed
|
||||
{
|
||||
$url = config('beike.api_url') . '/api/plugins';
|
||||
if (!empty($filters)) {
|
||||
|
|
@ -44,9 +51,16 @@ class MarketingService
|
|||
return $this->httpClient->get($url)->json();
|
||||
}
|
||||
|
||||
public function getPlugin($pluginCode)
|
||||
|
||||
/**
|
||||
* 获取插件市场单个插件信息
|
||||
*
|
||||
* @param $pluginCode
|
||||
* @return mixed
|
||||
*/
|
||||
public function getPlugin($pluginCode): mixed
|
||||
{
|
||||
$url = config('beike.api_url') . '/api/plugins/' . $pluginCode;
|
||||
$url = config('beike.api_url') . "/api/plugins/{$pluginCode}";
|
||||
$plugin = $this->httpClient->get($url)->json();
|
||||
if (empty($plugin)) {
|
||||
throw new NotFoundHttpException('该插件不存在或已下架');
|
||||
|
|
@ -54,6 +68,35 @@ class MarketingService
|
|||
return $plugin;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 购买插件市场单个插件
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function buy($pluginCode, $postData)
|
||||
{
|
||||
$url = config('beike.api_url') . "/api/plugins/{$pluginCode}/buy";
|
||||
|
||||
$content = $this->httpClient->withBody($postData, 'application/json')
|
||||
->post($url)
|
||||
->json();
|
||||
|
||||
$status = $content['status'] ?? '';
|
||||
if ($status == 'success') {
|
||||
return $content['data'];
|
||||
} else {
|
||||
throw new \Exception($content['message'] ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 下载插件到网站
|
||||
*
|
||||
* @param $pluginCode
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function download($pluginCode)
|
||||
{
|
||||
$datetime = date('Y-m-d');
|
||||
|
|
@ -68,5 +111,4 @@ class MarketingService
|
|||
$zipFile = Zip::open($pluginZip);
|
||||
$zipFile->extract(base_path('plugins'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 8.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 8.7 KiB |
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -324,4 +324,8 @@ body.page-seller-product {
|
|||
|
||||
table.table thead th, .fw-bold, h1,h2,h3, h4, h5, h6, b, strong, .card .card-header {
|
||||
font-family: 'Poppins-Medium', sans-serif;
|
||||
}
|
||||
|
||||
.swal2-confirm:focus {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
|
@ -30,4 +30,17 @@ body.page-marketing {
|
|||
}
|
||||
|
||||
body.page-marketing-info {
|
||||
.radio-group {
|
||||
> .el-radio {
|
||||
height: auto;
|
||||
padding: 8px 15px 8px 10px;
|
||||
|
||||
.el-radio__label {
|
||||
overflow: hidden;
|
||||
> img {
|
||||
max-height: 26px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -60,7 +60,8 @@
|
|||
class="img-fluid"></a></div>
|
||||
<div class="plugin-name fw-bold mb-2">@{{ plugin.name }}</div>
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<span class="text-success">{{ __('admin/marketing.text_free') }}</span>
|
||||
<span class="text-success" v-if="plugin.price == 0">{{ __('admin/marketing.text_free') }}</span>
|
||||
<span class="text-success" v-else>@{{ plugin.price_format }}</span>
|
||||
<span class="text-secondary">{{ __('admin/marketing.download_count') }}:@{{ plugin.downloaded }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -84,12 +85,12 @@
|
|||
width="500px">
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
:rows="3"
|
||||
placeholder="{{ __('admin/marketing.set_token') }}"
|
||||
v-model="setTokenDialog.token">
|
||||
</el-input>
|
||||
<div class="d-flex justify-content-between align-items-center mt-5">
|
||||
<a href="https://beikeshop.com/account/websites" class="link-primary" target="_blank">{{ __('admin/marketing.get_token') }}</a>
|
||||
<div class="mt-3 text-secondary fs-6">{{ __('admin/marketing.get_token_text') }} <a href="{{ config('beike.api_url') }}/account/websites?domain={{ $domain }}" class="link-primary" target="_blank">{{ __('admin/marketing.get_token') }}</a></div>
|
||||
<div class="d-flex justify-content-end align-items-center mt-4">
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="setTokenDialog.show = false">{{ __('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submitToken">{{ __('common.confirm') }}</el-button>
|
||||
|
|
|
|||
|
|
@ -4,13 +4,20 @@
|
|||
|
||||
@section('body-class', 'page-marketing-info')
|
||||
|
||||
@push('header')
|
||||
<script src="{{ asset('vendor/qrcode/qrcode.min.js') }}"></script>
|
||||
<link rel="stylesheet" href="{{ asset('vendor/sweetalert2/sweetalert2.min.css') }}">
|
||||
<script src="{{ asset('vendor/sweetalert2/sweetalert2.min.js') }}"></script>
|
||||
@endpush
|
||||
|
||||
@section('content')
|
||||
@php
|
||||
$data = $plugin['data'];
|
||||
@endphp
|
||||
<div class="card mb-4" id="app">
|
||||
<div class="card-header"><h6 class="card-title">{{ __('admin/marketing.marketing_show') }}</h6></div>
|
||||
<div class="card-body">
|
||||
<div class="d-flex mb-5">
|
||||
<div class="d-flex">
|
||||
<div class="border wp-400 hp-400 d-flex justify-content-between align-items-center"><img src="{{ $data['icon_big'] }}" class="img-fluid"></div>
|
||||
<div class="ms-5 mt-2">
|
||||
<h3 class="card-title mb-4">{{ $data['name'] }}</h3>
|
||||
|
|
@ -24,7 +31,7 @@
|
|||
<div class="mb-2 fw-bold">{{ __('admin/marketing.text_compatibility') }}:</div>
|
||||
<div>{{ $data['version_name_format'] }}</div>
|
||||
</div>
|
||||
<div class="mb-5">
|
||||
<div class="mb-4">
|
||||
<div class="mb-2 fw-bold">{{ __('admin/marketing.text_author') }}:</div>
|
||||
<div class="d-flex">
|
||||
<div class="border wh-60 d-flex justify-content-between align-items-center"><img src="{{ $data['developer']['avatar'] }}" class="img-fluid"></div>
|
||||
|
|
@ -35,17 +42,28 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button class="btn btn-primary btn-lg" @click="downloadPlugin"><i class="bi bi-cloud-arrow-down-fill"></i> {{ __('admin/marketing.download_plugin') }}</button>
|
||||
<div class="mt-3 d-none download-help"><a href="{{ admin_route('plugins.index') }}" class=""><i class="bi bi-cursor-fill"></i> <span></span></a></div>
|
||||
<div class="mb-4">
|
||||
@if ($data['downloadable'])
|
||||
<button class="btn btn-primary btn-lg" @click="downloadPlugin"><i class="bi bi-cloud-arrow-down-fill"></i> {{ __('admin/marketing.download_plugin') }}</button>
|
||||
<div class="mt-3 d-none download-help"><a href="{{ admin_route('plugins.index') }}" class=""><i class="bi bi-cursor-fill"></i> <span></span></a></div>
|
||||
@else
|
||||
<div class="mb-2 fw-bold">{{ __('admin/marketing.select_pay') }}</div>
|
||||
<div class="mb-4">
|
||||
<el-radio-group v-model="payCode" size="small" class="radio-group">
|
||||
<el-radio class="rounded-0 me-1" label="wechatpay" border><img src="{{ asset('image/wechat.png') }}" class="img-fluid"></el-radio>
|
||||
<el-radio class="rounded-0" label="alipay" border><img src="{{ asset('image/alipay.png') }}" class="img-fluid"></el-radio>
|
||||
</el-radio-group>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-lg" @click="marketingBuy">{{ __('admin/marketing.btn_buy') }} ({{ $data['price_format'] }})</button>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h5 class="text-center">{{ __('admin/marketing.download_description') }}</h5>
|
||||
<div>{{ $data['description'] }}</div>
|
||||
</div>
|
||||
<div class="code-pop" style="display: none;">
|
||||
<div class="text-center py-3 fs-5">{{ __('admin/marketing.text_pay') }}:<span class="fs-3 text-danger fw-bold">@{{ wechatpay_price }}</span></div>
|
||||
<div class="d-flex justify-content-center align-items-center" id="code-info"></div>
|
||||
</div>
|
||||
|
||||
<el-dialog
|
||||
|
|
@ -55,12 +73,12 @@
|
|||
width="500px">
|
||||
<el-input
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
:rows="3"
|
||||
placeholder="{{ __('admin/marketing.set_token') }}"
|
||||
v-model="setTokenDialog.token">
|
||||
</el-input>
|
||||
<div class="d-flex justify-content-between align-items-center mt-5">
|
||||
<a href="https://beikeshop.com/account/websites" class="link-primary" target="_blank">{{ __('admin/marketing.get_token') }}</a>
|
||||
<div class="mt-3 text-secondary fs-6">{{ __('admin/marketing.get_token_text') }} <a href="{{ config('beike.api_url') }}/account/websites?domain={{ $domain }}" class="link-primary" target="_blank">{{ __('admin/marketing.get_token') }}</a></div>
|
||||
<div class="d-flex justify-content-end align-items-center mt-4">
|
||||
<span slot="footer" class="dialog-footer">
|
||||
<el-button @click="setTokenDialog.show = false">{{ __('common.cancel') }}</el-button>
|
||||
<el-button type="primary" @click="submitToken">{{ __('common.confirm') }}</el-button>
|
||||
|
|
@ -68,6 +86,15 @@
|
|||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
||||
@if ($data['description'])
|
||||
<div class="card h-min-200">
|
||||
<div class="card-header"><h6 class="card-title">{{ __('admin/marketing.download_description') }}</h6></div>
|
||||
<div class="card-body">
|
||||
{{ $data['description'] }}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
@endsection
|
||||
|
||||
@push('footer')
|
||||
|
|
@ -76,6 +103,9 @@
|
|||
el: '#app',
|
||||
|
||||
data: {
|
||||
payCode: 'wechatpay',
|
||||
wechatpay_price: '',
|
||||
radio3: '1',
|
||||
setTokenDialog: {
|
||||
show: false,
|
||||
token: @json(system_setting('base.developer_token') ?? ''),
|
||||
|
|
@ -93,6 +123,94 @@
|
|||
})
|
||||
},
|
||||
|
||||
marketingBuy() {
|
||||
if (!this.setTokenDialog.token) {
|
||||
return this.setTokenDialog.show = true;
|
||||
}
|
||||
|
||||
$http.post('{{ admin_route('marketing.buy', ['code' => $data['code']]) }}', {
|
||||
payment_code: this.payCode, return_url: '{{ admin_route('marketing.show', ['code' => $data['code']]) }}'}).then((res) => {
|
||||
if (res.status == "fail") {
|
||||
layer.msg(res.message, () => {})
|
||||
return;
|
||||
}
|
||||
|
||||
if (res.data.payment_code == 'wechatpay') {
|
||||
this.wechatpay_price = res.data.price_format
|
||||
this.getQrcode(res.data.pay_url);
|
||||
}
|
||||
|
||||
if (res.data.payment_code == 'alipay') {
|
||||
window.open(res.data.pay_url, '_blank');
|
||||
|
||||
Swal.fire({
|
||||
title: '{{ __('admin/marketing.ali_pay_success') }}',
|
||||
text: '{{ __('admin/marketing.ali_pay_text') }}',
|
||||
icon: 'question',
|
||||
confirmButtonColor: '#fd560f',
|
||||
confirmButtonText: '{{ __('common.confirm') }}',
|
||||
willClose: function () {
|
||||
window.location.reload();
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
getQrcode(url) {
|
||||
const self = this;
|
||||
new QRCode('code-info', {
|
||||
text: url,
|
||||
width: 270,
|
||||
height: 270,
|
||||
correctLevel : QRCode.CorrectLevel.M
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
Swal.fire({
|
||||
title: '{{ __('admin/marketing.wxpay') }}',
|
||||
width: 400,
|
||||
height: 470,
|
||||
heightAuto: false,
|
||||
html: $('.code-pop').html(),
|
||||
showConfirmButton: false,
|
||||
didOpen: function () {
|
||||
// 微信支付二维码 轮询监控支付状态
|
||||
self.chekOrderStatus();
|
||||
self.timer = window.setInterval(() => {
|
||||
setTimeout(self.chekOrderStatus(), 0);
|
||||
}, 1000)
|
||||
},
|
||||
didClose: function () {
|
||||
$('#code-info').html('');
|
||||
},
|
||||
didDestroy: function () {
|
||||
window.clearInterval(self.timer)
|
||||
},
|
||||
})
|
||||
}, 100)
|
||||
},
|
||||
|
||||
chekOrderStatus() {
|
||||
$http.get('{{ admin_route('marketing.show', ['code' => $data['code']]) }}', null, {hload: true}).then((res) => {
|
||||
console.log(res.plugin.data.downloadable)
|
||||
if (res.plugin.data.downloadable) {
|
||||
window.clearInterval(this.timer)
|
||||
Swal.fire({
|
||||
title: '{{ __('admin/marketing.pay_success_title') }}',
|
||||
text: '{{ __('admin/marketing.pay_success_text') }}',
|
||||
icon: 'success',
|
||||
focusConfirm: false,
|
||||
confirmButtonColor: '#75bc4d',
|
||||
confirmButtonText: '{{ __('common.confirm') }}',
|
||||
didClose: function () {
|
||||
window.location.reload();
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
submitToken() {
|
||||
if (!this.setTokenDialog.token) {
|
||||
return;
|
||||
|
|
@ -103,6 +221,10 @@
|
|||
layer.msg(res.message);
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
window.clearInterval(this.timer)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ return [
|
|||
'marketing_list' => 'Plugin Marketing',
|
||||
'marketing_show' => 'Plugin Detail',
|
||||
'set_token' => 'Set Token',
|
||||
'get_token_text' => 'Log in to BeikeShop official website personal center - bind domain name, add current domain name',
|
||||
'get_token' => 'Get Token',
|
||||
'download_count' => 'download count',
|
||||
'last_update' => 'last update',
|
||||
|
|
@ -22,4 +23,12 @@ return [
|
|||
'download_plugin' => 'download plugin',
|
||||
'download_description' => 'Plugin description',
|
||||
'text_free' => 'free',
|
||||
'btn_buy' => 'Buy',
|
||||
'text_pay' => 'Payment Amount',
|
||||
'select_pay' => 'select payment method',
|
||||
'wxpay' => 'WeChat scan code payment!',
|
||||
'pay_success_title' => 'Payment successful!',
|
||||
'pay_success_text' => 'The plug-in purchase is successful, click OK to refresh the page',
|
||||
'ali_pay_success' => 'Payment completed? ',
|
||||
'ali_pay_text' => 'Payment has been completed, please refresh the page',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ return [
|
|||
'marketing_list' => '插件市场',
|
||||
'marketing_show' => '插件详情',
|
||||
'set_token' => '设置 Token',
|
||||
'get_token' => '获取 Token',
|
||||
'get_token_text' => '登录 BeikeShop 官网个人中心-绑定域名,添加当前域名',
|
||||
'get_token' => '点击获取 Token',
|
||||
'download_count' => '下载次数',
|
||||
'last_update' => '最后更新',
|
||||
'text_version' => '版本',
|
||||
|
|
@ -22,4 +23,12 @@ return [
|
|||
'download_plugin' => '下载插件',
|
||||
'download_description' => '插件描述',
|
||||
'text_free' => '免费',
|
||||
'btn_buy' => '购买',
|
||||
'text_pay' => '支付金额',
|
||||
'select_pay' => '选择支付方式',
|
||||
'wxpay' => '微信扫码支付!',
|
||||
'pay_success_title' => '支付成功!',
|
||||
'pay_success_text' => '插件购买成功,点击确定刷新页面',
|
||||
'ali_pay_success' => '已完成支付?',
|
||||
'ali_pay_text' => '已完成支付,请刷新页面',
|
||||
];
|
||||
|
|
|
|||
|
|
@ -13,7 +13,8 @@ return [
|
|||
'marketing_list' => '插件市場',
|
||||
'marketing_show' => '插件詳情',
|
||||
'set_token' => '設置 Token',
|
||||
'get_token' => '獲取 Token',
|
||||
'get_token_text' => '登錄 BeikeShop 官網個人中心-綁定域名,添加當前域名',
|
||||
'get_token' => '點擊獲取 Token',
|
||||
'download_count' => '下載次數',
|
||||
'last_update' => '最後更新',
|
||||
'text_version' => '版本',
|
||||
|
|
@ -22,4 +23,12 @@ return [
|
|||
'download_plugin' => '下載插件',
|
||||
'download_description' => '插件描述',
|
||||
'text_free' => '免費',
|
||||
'btn_buy' => '購買',
|
||||
'text_pay' => '支付金額',
|
||||
'select_pay' => '選擇支付方式',
|
||||
'wxpay' => '微信掃碼支付!',
|
||||
'pay_success_title' => '支付成功!',
|
||||
'pay_success_text' => '插件購買成功,點擊確定刷新頁面',
|
||||
'ali_pay_success' => '已完成支付? ',
|
||||
'ali_pay_text' => '已完成支付,請刷新頁面',
|
||||
];
|
||||
|
|
|
|||
Loading…
Reference in New Issue