Showing
36 changed files
with
1558 additions
and
98 deletions
| ... | @@ -2,14 +2,18 @@ | ... | @@ -2,14 +2,18 @@ |
| 2 | 2 | ||
| 3 | namespace App\Admin\Controllers; | 3 | namespace App\Admin\Controllers; |
| 4 | 4 | ||
| 5 | +use App\Admin\Renderable\MembershipGoodsEasyTable; | ||
| 5 | use App\Admin\Renderable\MembershipGoodsTable; | 6 | use App\Admin\Renderable\MembershipGoodsTable; |
| 6 | -use App\Admin\Repositories\Membership; | 7 | +use App\Models\Membership; |
| 7 | use App\Models\MembershipGood; | 8 | use App\Models\MembershipGood; |
| 8 | use Dcat\Admin\Form; | 9 | use Dcat\Admin\Form; |
| 9 | use Dcat\Admin\Grid; | 10 | use Dcat\Admin\Grid; |
| 10 | use Dcat\Admin\Show; | 11 | use Dcat\Admin\Show; |
| 11 | use Dcat\Admin\Http\Controllers\AdminController; | 12 | use Dcat\Admin\Http\Controllers\AdminController; |
| 12 | use Dcat\Admin\Form\NestedForm; | 13 | use Dcat\Admin\Form\NestedForm; |
| 14 | +use Illuminate\Support\Facades\DB; | ||
| 15 | +use Dcat\Admin\Widgets\Table; | ||
| 16 | + | ||
| 13 | 17 | ||
| 14 | class MembershipController extends AdminController | 18 | class MembershipController extends AdminController |
| 15 | { | 19 | { |
| ... | @@ -27,28 +31,27 @@ class MembershipController extends AdminController | ... | @@ -27,28 +31,27 @@ class MembershipController extends AdminController |
| 27 | $grid->setActionClass(Grid\Displayers\Actions::class); | 31 | $grid->setActionClass(Grid\Displayers\Actions::class); |
| 28 | 32 | ||
| 29 | $grid->column('id',__('ID'))->sortable(); | 33 | $grid->column('id',__('ID'))->sortable(); |
| 30 | - | 34 | + $grid->column('title'); |
| 31 | - $grid->column('name'); | ||
| 32 | - $grid->column('price'); | ||
| 33 | - $grid->column('line_price'); | ||
| 34 | - $grid->column('limited_days'); | ||
| 35 | - $grid->column('limit_unit'); | ||
| 36 | $grid->column('intro'); | 35 | $grid->column('intro'); |
| 37 | - $grid->column('state'); | 36 | + $grid->column('expand','展开') |
| 38 | - $grid->column('sn'); | 37 | + ->display('会员商品') |
| 39 | - | 38 | + ->expand(function (){ |
| 39 | + $th = ['id','price','line_price','limit_days','limit_unit']; | ||
| 40 | + $data = MembershipGood::query()->where('membership_id',$this->id)->get($th)->toArray(); | ||
| 41 | + return Table::make($th, $data); | ||
| 42 | + }); | ||
| 40 | $grid->column('video_url'); | 43 | $grid->column('video_url'); |
| 41 | - $grid->column('video_cover'); | 44 | + $grid->column('video_cover')->image('/storage/'); |
| 42 | - $grid->column('bg_images'); | 45 | + $grid->column('bg_images')->gallery('/storage/'); |
| 43 | - $grid->column('visits'); | 46 | + $grid->column('terminal')->using([1 => '安卓', 2 => 'iOS'], '未知'); |
| 44 | - $grid->column('virtual_sales'); | 47 | + $grid->column('state','线上展示')->switch(); |
| 45 | - $grid->column('sales'); | ||
| 46 | - | ||
| 47 | $grid->column('created_at'); | 48 | $grid->column('created_at'); |
| 48 | $grid->column('updated_at')->sortable(); | 49 | $grid->column('updated_at')->sortable(); |
| 49 | 50 | ||
| 50 | $grid->filter(function (Grid\Filter $filter) { | 51 | $grid->filter(function (Grid\Filter $filter) { |
| 51 | - $filter->equal('id'); | 52 | + $filter->equal('id')->width(2); |
| 53 | + $filter->like('terminal')->width(3); | ||
| 54 | + $filter->panel(); | ||
| 52 | 55 | ||
| 53 | }); | 56 | }); |
| 54 | }); | 57 | }); |
| ... | @@ -94,16 +97,29 @@ class MembershipController extends AdminController | ... | @@ -94,16 +97,29 @@ class MembershipController extends AdminController |
| 94 | */ | 97 | */ |
| 95 | protected function form() | 98 | protected function form() |
| 96 | { | 99 | { |
| 100 | + $css = <<<CSS | ||
| 101 | +.table tr td:first-child{ | ||
| 102 | + padding-left: 0 ; | ||
| 103 | +} | ||
| 104 | +.table tr td{ | ||
| 105 | + padding-left: 0 ; | ||
| 106 | +} | ||
| 107 | +.form-field .input-group .price{ | ||
| 108 | + width: 1% !important; | ||
| 109 | +} | ||
| 110 | +CSS; | ||
| 111 | + \Admin::style($css); | ||
| 112 | + | ||
| 97 | return Form::make(new Membership(), function (Form $form) { | 113 | return Form::make(new Membership(), function (Form $form) { |
| 98 | $form->display('id'); | 114 | $form->display('id'); |
| 99 | - $form->block(12, function (Form\BlockForm $form) { | 115 | + |
| 116 | + $form->block(8, function (Form\BlockForm $form) { | ||
| 100 | // 设置标题 | 117 | // 设置标题 |
| 101 | $form->title('基本设置'); | 118 | $form->title('基本设置'); |
| 102 | // 显示底部提交按钮 | 119 | // 显示底部提交按钮 |
| 103 | $form->showFooter(); | 120 | $form->showFooter(); |
| 104 | // 设置字段宽度 | 121 | // 设置字段宽度 |
| 105 | - $form->width(8, 2); | 122 | + $form->width(9, 2); |
| 106 | - | ||
| 107 | 123 | ||
| 108 | $form->radio('terminal')->addElementClass('terminal') | 124 | $form->radio('terminal')->addElementClass('terminal') |
| 109 | ->options([1 => 'Android', 2 => 'IOS'])->default(2); | 125 | ->options([1 => 'Android', 2 => 'IOS'])->default(2); |
| ... | @@ -112,7 +128,7 @@ class MembershipController extends AdminController | ... | @@ -112,7 +128,7 @@ class MembershipController extends AdminController |
| 112 | $form->textarea('intro')->addElementClass('intro'); | 128 | $form->textarea('intro')->addElementClass('intro'); |
| 113 | 129 | ||
| 114 | $form->radio('bg_type')->addElementClass('bg_type') | 130 | $form->radio('bg_type')->addElementClass('bg_type') |
| 115 | - ->options([1 => '单图', 2 => '轮播图', 3 => '视频'])->default(1) | 131 | + ->options([1 => '单图', 2 => '轮播图', 3 => '视频']) |
| 116 | ->when([1,2],function (Form\BlockForm $form){ | 132 | ->when([1,2],function (Form\BlockForm $form){ |
| 117 | $form->multipleImage('bg_images') | 133 | $form->multipleImage('bg_images') |
| 118 | ->limit(5) | 134 | ->limit(5) |
| ... | @@ -129,36 +145,91 @@ class MembershipController extends AdminController | ... | @@ -129,36 +145,91 @@ class MembershipController extends AdminController |
| 129 | $form->image('video_cover') | 145 | $form->image('video_cover') |
| 130 | ->uniqueName() | 146 | ->uniqueName() |
| 131 | ->addElementClass('video_cover'); | 147 | ->addElementClass('video_cover'); |
| 132 | - }); | 148 | + })->default(1); |
| 133 | 149 | ||
| 134 | $form->radio('state')->options(['不显示', '显示'])->default(0); | 150 | $form->radio('state')->options(['不显示', '显示'])->default(0); |
| 135 | 151 | ||
| 136 | - | 152 | + $form->radio('is_bind_old')->options(['新增会员商品', '选择已有未上架的商品'])->default(0) |
| 137 | - $form->radio('is_bind_old')->options(['新增会员商品', '选择已有商品'])->default(0) | ||
| 138 | ->when(0,function (Form\BlockForm $form){ | 153 | ->when(0,function (Form\BlockForm $form){ |
| 139 | - $form->table('membership_goods','新赠会员商品', function (NestedForm $table) { | 154 | + $form->table('new','新增', function (NestedForm $table) { |
| 140 | - $table->currency('price')->symbol('¥')->addElementClass('price'); | 155 | + $table->text('price')->addElementClass('price'); |
| 141 | - $table->currency('line_price')->symbol('¥')->addElementClass('line_price'); | 156 | + $table->text('line_price')->addElementClass('line_price'); |
| 142 | $table->text('limited_days')->addElementClass('limited_days'); | 157 | $table->text('limited_days')->addElementClass('limited_days'); |
| 143 | $table->text('limit_unit')->addElementClass('limit_unit'); | 158 | $table->text('limit_unit')->addElementClass('limit_unit'); |
| 144 | - | ||
| 145 | }); | 159 | }); |
| 146 | }) | 160 | }) |
| 147 | ->when(1,function (Form\BlockForm $form){ | 161 | ->when(1,function (Form\BlockForm $form){ |
| 148 | - $form->selectTable('membership_goods') | 162 | + $form->multipleSelectTable('old','已有') |
| 149 | ->title('会员商品') | 163 | ->title('会员商品') |
| 150 | ->from(MembershipGoodsTable::make()) | 164 | ->from(MembershipGoodsTable::make()) |
| 151 | ->model(MembershipGood::class, 'id', 'price'); | 165 | ->model(MembershipGood::class, 'id', 'price'); |
| 152 | }); | 166 | }); |
| 153 | }); | 167 | }); |
| 154 | 168 | ||
| 155 | -// $form->block(4, function (Form\BlockForm $form) { | 169 | + $form->block(4, function (Form\BlockForm $form) { |
| 156 | -// $form->width(9, 1); | 170 | + $form->width(9, 1); |
| 157 | -// $form->html(view('admin.form.phone')); | 171 | + $form->html(view('admin.form.membership')); |
| 158 | -// }); | 172 | + }); |
| 159 | 173 | ||
| 160 | $form->display('created_at'); | 174 | $form->display('created_at'); |
| 161 | $form->display('updated_at'); | 175 | $form->display('updated_at'); |
| 162 | }); | 176 | }); |
| 163 | } | 177 | } |
| 178 | + | ||
| 179 | + public function store() | ||
| 180 | + { | ||
| 181 | + $all = request()->all(); | ||
| 182 | + | ||
| 183 | + // | ||
| 184 | + if (isset($all['upload_column'])) return $this->form()->store(); | ||
| 185 | + | ||
| 186 | + // 检测是否已经有该平台的数据 | ||
| 187 | + $membership = Membership::query()->where('terminal',$all['terminal'])->first(); | ||
| 188 | + if ($membership && $all['state'] == '1') return $this->form()->response()->error('状态为显示会覆盖线上的设置,请修改后重试'); | ||
| 189 | + | ||
| 190 | + try{ | ||
| 191 | + DB::transaction(function ()use ($all){ | ||
| 192 | + $membership = Membership::query()->create([ | ||
| 193 | + 'title' => $all['title'], | ||
| 194 | + 'intro' => $all['intro'], | ||
| 195 | + 'bg_type' => $all['bg_type'], | ||
| 196 | + 'bg_images' => $all['bg_images'], | ||
| 197 | + 'video_url' => $all['video_url'] ?? '', | ||
| 198 | + 'video_cover' => $all['video_cover'] ?? '', | ||
| 199 | + 'terminal' => $all['terminal'], | ||
| 200 | + 'state' => $all['state'], | ||
| 201 | + ]); | ||
| 202 | + | ||
| 203 | + if ($all['is_bind_old'] === '0'){ | ||
| 204 | + // 新增 | ||
| 205 | + foreach ($all['new'] as $item) { | ||
| 206 | + if ($item['_remove_'] === '1') continue; | ||
| 207 | + | ||
| 208 | + MembershipGood::query()->create([ | ||
| 209 | + 'membership_id' => $membership->id, | ||
| 210 | + 'price' => $item['price'], | ||
| 211 | + 'line_price' => $item['line_price'], | ||
| 212 | + 'limited_days' => $item['limited_days'], | ||
| 213 | + 'limit_unit' => $item['limit_unit'] ?? '天', | ||
| 214 | + 'terminal' => $all['terminal'], | ||
| 215 | + 'state' => 1, | ||
| 216 | + ]); | ||
| 217 | + } | ||
| 218 | + }elseif ($all['is_bind_old'] === '1'){ | ||
| 219 | + $old_ids = explode(',',$all['old']); | ||
| 220 | + $membership_goods = MembershipGood::query()->whereIn('id',$old_ids)->get(); | ||
| 221 | + foreach ($membership_goods as $membership_good){ | ||
| 222 | + $membership_good->membership_id = $membership->id; | ||
| 223 | + $membership_good->state = 1; | ||
| 224 | + $membership_good->save(); | ||
| 225 | + } | ||
| 226 | + } | ||
| 227 | + }); | ||
| 228 | + | ||
| 229 | + }catch (\Exception $exception){ | ||
| 230 | + return $this->form()->response()->error($exception->getMessage()); | ||
| 231 | + } | ||
| 232 | + | ||
| 233 | + return $this->form()->response()->refresh()->success(trans('admin.save_succeeded')); | ||
| 234 | + } | ||
| 164 | } | 235 | } | ... | ... |
app/Admin/Extensions/Gallery.php
0 → 100644
| 1 | +<?php | ||
| 2 | +/** | ||
| 3 | + * Created by PhpStorm. | ||
| 4 | + * User: lishuai | ||
| 5 | + * Date: 2022/2/11 | ||
| 6 | + * Time: 5:30 PM | ||
| 7 | + */ | ||
| 8 | +namespace App\Admin\Extensions; | ||
| 9 | + | ||
| 10 | +use Dcat\Admin\Admin; | ||
| 11 | +use Dcat\Admin\Grid\Displayers\AbstractDisplayer; | ||
| 12 | +use Dcat\Admin\Support\Helper; | ||
| 13 | +use Illuminate\Contracts\Support\Arrayable; | ||
| 14 | +use Illuminate\Support\Facades\Storage; | ||
| 15 | + | ||
| 16 | +class Gallery extends AbstractDisplayer | ||
| 17 | +{ | ||
| 18 | + public function display($server = '', $width = 100, $height = 200) | ||
| 19 | + { | ||
| 20 | + | ||
| 21 | + Admin::js('@js/viewer.js'); | ||
| 22 | + | ||
| 23 | + Admin::css([ | ||
| 24 | + '@css/gallery.css', | ||
| 25 | + '@css/viewer.css' | ||
| 26 | + ]); | ||
| 27 | + | ||
| 28 | + $defaultArgs = [ | ||
| 29 | + 'server' => $server, | ||
| 30 | + 'width' => $width, | ||
| 31 | + 'height' => $height, | ||
| 32 | + ]; | ||
| 33 | + | ||
| 34 | + ['server' => $server, 'width' => $width, 'height' => $height] = $defaultArgs; | ||
| 35 | + | ||
| 36 | + if ($this->value instanceof Arrayable) { | ||
| 37 | + $this->value = $this->value->toArray(); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + $groupId = $this->grid->getTableId().'_'.$this->getKey().'_'.$this->column->getName().'_gallery_group'; | ||
| 41 | + | ||
| 42 | + $src = []; // 避免 $src 未定义 | ||
| 43 | + | ||
| 44 | + foreach (Helper::array($this->value) as $k => $v) { | ||
| 45 | + if (url()->isValidUrl($v) || mb_strpos($v, 'data:image') === 0) { | ||
| 46 | + $src[] = $v; | ||
| 47 | + } elseif ($server) { | ||
| 48 | + $src[] = rtrim($server, '/').'/'.ltrim($v, '/'); | ||
| 49 | + } else { | ||
| 50 | + $src[] = Storage::disk(config('admin.upload.disk'))->url($v); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + } | ||
| 54 | + return Admin::view('admin.grid.gallery', ['src' => $src, 'width' => $width, 'height' => $height, 'id' => $groupId]); | ||
| 55 | + } | ||
| 56 | +} |
app/Admin/Extensions/Swiper.php
0 → 100644
| 1 | +<?php | ||
| 2 | +/** | ||
| 3 | + * Created by PhpStorm. | ||
| 4 | + * User: lishuai | ||
| 5 | + * Date: 2022/2/11 | ||
| 6 | + * Time: 5:30 PM | ||
| 7 | + */ | ||
| 8 | +namespace App\Admin\Extensions; | ||
| 9 | + | ||
| 10 | +use Dcat\Admin\Admin; | ||
| 11 | +use Dcat\Admin\Grid\Displayers\AbstractDisplayer; | ||
| 12 | + | ||
| 13 | +use Illuminate\Contracts\Support\Arrayable; | ||
| 14 | +use Illuminate\Support\Facades\Storage; | ||
| 15 | + | ||
| 16 | +class Swiper extends AbstractDisplayer | ||
| 17 | +{ | ||
| 18 | + public function display($server = '', $width = 200, $height = 200) | ||
| 19 | + { | ||
| 20 | + // todo | ||
| 21 | +// if ($this->value instanceof Arrayable) { | ||
| 22 | +// $this->value = $this->value->toArray(); | ||
| 23 | +// } | ||
| 24 | +// | ||
| 25 | +// return collect((array) $this->value)->filter()->map(function ($path) use ($server, $width, $height) { | ||
| 26 | +// if (url()->isValidUrl($path) || mb_strpos($path, 'data:image') === 0) { | ||
| 27 | +// $src = $path; | ||
| 28 | +// } elseif ($server) { | ||
| 29 | +// $src = rtrim($server, '/').'/'.ltrim($path, '/'); | ||
| 30 | +// } else { | ||
| 31 | +// $src = Storage::disk(config('admin.upload.disk'))->url($path); | ||
| 32 | +// } | ||
| 33 | +// | ||
| 34 | +// return "<img data-action='preview-img' src='$src' style='max-width:{$width}px;max-height:{$height}px;cursor:pointer' class='img img-thumbnail' />"; | ||
| 35 | +// })->implode(' '); | ||
| 36 | + } | ||
| 37 | +} |
| ... | @@ -17,6 +17,8 @@ class MembershipGoodsTable extends LazyRenderable | ... | @@ -17,6 +17,8 @@ class MembershipGoodsTable extends LazyRenderable |
| 17 | public function grid(): Grid | 17 | public function grid(): Grid |
| 18 | { | 18 | { |
| 19 | return Grid::make(new MembershipGood(), function (Grid $grid) { | 19 | return Grid::make(new MembershipGood(), function (Grid $grid) { |
| 20 | + $grid->model()->where('state',0); | ||
| 21 | + | ||
| 20 | $grid->column('id', 'ID')->sortable(); | 22 | $grid->column('id', 'ID')->sortable(); |
| 21 | $grid->column('membership_id'); | 23 | $grid->column('membership_id'); |
| 22 | $grid->column('price'); | 24 | $grid->column('price'); | ... | ... |
app/Admin/Repositories/MembershipGood.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Admin\Repositories; | ||
| 4 | + | ||
| 5 | +use App\Models\MembershipGood as Model; | ||
| 6 | +use Dcat\Admin\Repositories\EloquentRepository; | ||
| 7 | + | ||
| 8 | +class MembershipGood extends EloquentRepository | ||
| 9 | +{ | ||
| 10 | + /** | ||
| 11 | + * Model. | ||
| 12 | + * | ||
| 13 | + * @var string | ||
| 14 | + */ | ||
| 15 | + protected $eloquentClass = Model::class; | ||
| 16 | +} |
app/Admin/Repositories/OrderGood.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Admin\Repositories; | ||
| 4 | + | ||
| 5 | +use App\Models\OrderGood as Model; | ||
| 6 | +use Dcat\Admin\Repositories\EloquentRepository; | ||
| 7 | + | ||
| 8 | +class OrderGood extends EloquentRepository | ||
| 9 | +{ | ||
| 10 | + /** | ||
| 11 | + * Model. | ||
| 12 | + * | ||
| 13 | + * @var string | ||
| 14 | + */ | ||
| 15 | + protected $eloquentClass = Model::class; | ||
| 16 | +} |
app/Admin/Repositories/VideoTemp.php
0 → 100755
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Admin\Repositories; | ||
| 4 | + | ||
| 5 | +use App\Models\VideoTemp as Model; | ||
| 6 | +use Dcat\Admin\Repositories\EloquentRepository; | ||
| 7 | + | ||
| 8 | +class VideoTemp extends EloquentRepository | ||
| 9 | +{ | ||
| 10 | + /** | ||
| 11 | + * Model. | ||
| 12 | + * | ||
| 13 | + * @var string | ||
| 14 | + */ | ||
| 15 | + protected $eloquentClass = Model::class; | ||
| 16 | +} |
| ... | @@ -5,6 +5,8 @@ use Dcat\Admin\Grid; | ... | @@ -5,6 +5,8 @@ use Dcat\Admin\Grid; |
| 5 | use Dcat\Admin\Form; | 5 | use Dcat\Admin\Form; |
| 6 | use Dcat\Admin\Grid\Filter; | 6 | use Dcat\Admin\Grid\Filter; |
| 7 | use Dcat\Admin\Show; | 7 | use Dcat\Admin\Show; |
| 8 | +use Dcat\Admin\Grid\Column; | ||
| 9 | +use App\Admin\Extensions\Gallery; | ||
| 8 | 10 | ||
| 9 | /** | 11 | /** |
| 10 | * Dcat-admin - admin builder based on Laravel. | 12 | * Dcat-admin - admin builder based on Laravel. |
| ... | @@ -24,3 +26,7 @@ use Dcat\Admin\Show; | ... | @@ -24,3 +26,7 @@ use Dcat\Admin\Show; |
| 24 | * Admin::js('/packages/prettydocs/js/main.js'); | 26 | * Admin::js('/packages/prettydocs/js/main.js'); |
| 25 | * | 27 | * |
| 26 | */ | 28 | */ |
| 29 | +Admin::asset()->alias('@js', '/asset/js'); | ||
| 30 | +Admin::asset()->alias('@css', '/asset/css'); | ||
| 31 | + | ||
| 32 | +Column::extend('gallery', Gallery::class); //grid列扩展 - 多图浏览 | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
app/Console/Commands/DevFFmpeg.php
0 → 100644
This diff is collapsed. Click to expand it.
app/Console/Commands/DevPinyin.php
0 → 100644
This diff is collapsed. Click to expand it.
app/Console/Commands/Pinyin.php
0 → 100644
This diff could not be displayed because it is too large.
| ... | @@ -10,4 +10,21 @@ use Illuminate\Routing\Controller as BaseController; | ... | @@ -10,4 +10,21 @@ use Illuminate\Routing\Controller as BaseController; |
| 10 | class Controller extends BaseController | 10 | class Controller extends BaseController |
| 11 | { | 11 | { |
| 12 | use AuthorizesRequests, DispatchesJobs, ValidatesRequests; | 12 | use AuthorizesRequests, DispatchesJobs, ValidatesRequests; |
| 13 | + | ||
| 14 | + public function isAppleClient() | ||
| 15 | + { | ||
| 16 | + $ua = request()->header('user-agent'); | ||
| 17 | + | ||
| 18 | + if (strpos($ua, 'iPhone') || strpos($ua, 'iPad') || strpos($ua,'Mac OS X')) { | ||
| 19 | + return true; | ||
| 20 | + } | ||
| 21 | + return false; | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + public function getClientTerminal() | ||
| 25 | + { | ||
| 26 | + $ua = request()->header('user-agent'); | ||
| 27 | + | ||
| 28 | + return 'ios'; | ||
| 29 | + } | ||
| 13 | } | 30 | } | ... | ... |
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Http\Controllers\V1; | ||
| 4 | + | ||
| 5 | +use App\Http\Controllers\Controller; | ||
| 6 | +use App\Models\Membership; | ||
| 7 | +use Illuminate\Http\Request; | ||
| 8 | +use Jiannei\Response\Laravel\Support\Facades\Response; | ||
| 9 | + | ||
| 10 | +class MembershipController extends Controller | ||
| 11 | +{ | ||
| 12 | + /** | ||
| 13 | + * Display a listing of the resource. | ||
| 14 | + * @param \Illuminate\Http\Request $request | ||
| 15 | + * @return \Illuminate\Http\JsonResponse | ||
| 16 | + */ | ||
| 17 | + public function index(Request $request) | ||
| 18 | + { | ||
| 19 | + $membership = Membership::query()->where('state',1); | ||
| 20 | + // 获取会员介绍页内容 | ||
| 21 | + if ($this->isAppleClient()){ | ||
| 22 | + $membership = $membership->where('terminal',2); | ||
| 23 | + }else{ | ||
| 24 | + $membership = $membership->where('terminal',1); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + $membership = $membership->first(); | ||
| 28 | + | ||
| 29 | + $membership->bg_images = $membership->getImage(); | ||
| 30 | + $membership->goods_list = $membership->getMembershipGoods()->get(); | ||
| 31 | + | ||
| 32 | + return Response::success($membership); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + /** | ||
| 36 | + * Show the form for creating a new resource. | ||
| 37 | + * | ||
| 38 | + * @return \Illuminate\Http\Response | ||
| 39 | + */ | ||
| 40 | + public function create() | ||
| 41 | + { | ||
| 42 | + // | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + /** | ||
| 46 | + * Store a newly created resource in storage. | ||
| 47 | + * | ||
| 48 | + * @param \Illuminate\Http\Request $request | ||
| 49 | + * @return \Illuminate\Http\Response | ||
| 50 | + */ | ||
| 51 | + public function store(Request $request) | ||
| 52 | + { | ||
| 53 | + // | ||
| 54 | + } | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * Display the specified resource. | ||
| 58 | + * | ||
| 59 | + * @param int $id | ||
| 60 | + * @return \Illuminate\Http\Response | ||
| 61 | + */ | ||
| 62 | + public function show($id) | ||
| 63 | + { | ||
| 64 | + // | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + /** | ||
| 68 | + * Show the form for editing the specified resource. | ||
| 69 | + * | ||
| 70 | + * @param int $id | ||
| 71 | + * @return \Illuminate\Http\Response | ||
| 72 | + */ | ||
| 73 | + public function edit($id) | ||
| 74 | + { | ||
| 75 | + // | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + /** | ||
| 79 | + * Update the specified resource in storage. | ||
| 80 | + * | ||
| 81 | + * @param \Illuminate\Http\Request $request | ||
| 82 | + * @param int $id | ||
| 83 | + * @return \Illuminate\Http\Response | ||
| 84 | + */ | ||
| 85 | + public function update(Request $request, $id) | ||
| 86 | + { | ||
| 87 | + // | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + /** | ||
| 91 | + * Remove the specified resource from storage. | ||
| 92 | + * | ||
| 93 | + * @param int $id | ||
| 94 | + * @return \Illuminate\Http\Response | ||
| 95 | + */ | ||
| 96 | + public function destroy($id) | ||
| 97 | + { | ||
| 98 | + // | ||
| 99 | + } | ||
| 100 | +} |
| ... | @@ -3,7 +3,13 @@ | ... | @@ -3,7 +3,13 @@ |
| 3 | namespace App\Http\Controllers\V1; | 3 | namespace App\Http\Controllers\V1; |
| 4 | 4 | ||
| 5 | use App\Http\Controllers\Controller; | 5 | use App\Http\Controllers\Controller; |
| 6 | +use App\Models\MembershipGood; | ||
| 7 | +use App\Models\Order; | ||
| 8 | +use App\Models\OrderGood; | ||
| 9 | +use Carbon\Carbon; | ||
| 6 | use Illuminate\Http\Request; | 10 | use Illuminate\Http\Request; |
| 11 | +use Illuminate\Support\Facades\Auth; | ||
| 12 | +use Illuminate\Support\Facades\DB; | ||
| 7 | use Illuminate\Support\Facades\Validator; | 13 | use Illuminate\Support\Facades\Validator; |
| 8 | use Jiannei\Response\Laravel\Support\Facades\Response; | 14 | use Jiannei\Response\Laravel\Support\Facades\Response; |
| 9 | 15 | ||
| ... | @@ -11,27 +17,104 @@ class OrderController extends Controller | ... | @@ -11,27 +17,104 @@ class OrderController extends Controller |
| 11 | { | 17 | { |
| 12 | public function index(Request $request) | 18 | public function index(Request $request) |
| 13 | { | 19 | { |
| 14 | - $validator = Validator::make($request->all(),[ | 20 | + |
| 21 | + } | ||
| 22 | + | ||
| 23 | + public function store(Request $request) | ||
| 24 | + { | ||
| 25 | + $data = $request->all(); | ||
| 26 | + | ||
| 27 | + $validator = Validator::make($data,[ | ||
| 15 | 'goods_id' => 'required|integer', | 28 | 'goods_id' => 'required|integer', |
| 16 | - 'source' => 'required|string', | ||
| 17 | ]); | 29 | ]); |
| 18 | 30 | ||
| 19 | - if ($validator->fails()){ | 31 | + if ($validator->fails()) return Response::fail('缺少参数',500,$validator->errors()); |
| 20 | - return Response::fail('缺少参数',500,$validator->errors()); | 32 | + |
| 21 | - } | 33 | + $user_id = Auth::user()->getAuthIdentifier(); |
| 22 | 34 | ||
| 35 | + $order = $this->build($user_id, $data['goods_id'], $this->getClientTerminal()); | ||
| 23 | 36 | ||
| 37 | + return Response::success($order); | ||
| 24 | } | 38 | } |
| 25 | 39 | ||
| 26 | - public function store(Request $request) | 40 | + public function show($id) |
| 27 | { | 41 | { |
| 28 | - $validator = Validator::make($request->all(),[ | ||
| 29 | - 'goods_id' => 'required|integer', | ||
| 30 | - 'source' => 'required|string', | ||
| 31 | - ]); | ||
| 32 | 42 | ||
| 33 | - if ($validator->fails()){ | 43 | + } |
| 34 | - return Response::fail('',500,$validator->errors()); | 44 | + |
| 45 | + /** | ||
| 46 | + * 创建订单 | ||
| 47 | + * @param $user_id | ||
| 48 | + * @param $member_id | ||
| 49 | + * @param $source | ||
| 50 | + * @param $number = 1 | ||
| 51 | + * @return string $order_sn | ||
| 52 | + */ | ||
| 53 | + public function build($user_id, $member_id, $source, $number = 1) | ||
| 54 | + { | ||
| 55 | + try{ | ||
| 56 | + return DB::transaction(function ()use ($user_id, $member_id, $source, $number){ | ||
| 57 | + // 获取商品信息 | ||
| 58 | + $membership_good = MembershipGood::query()->where('id',$member_id)->first(); | ||
| 59 | + $membership = $membership_good->membership()->first(); | ||
| 60 | + | ||
| 61 | + // 实付金额 = 商品金额 | ||
| 62 | + $pay_amount = $membership_good->price * $number; | ||
| 63 | + | ||
| 64 | + // 创建订单 | ||
| 65 | + $order = new Order(); | ||
| 66 | + $order_sn = $order::get_sn('osn'); | ||
| 67 | + $order->order_sn = $order_sn; | ||
| 68 | + $order->user_id = $user_id; | ||
| 69 | + $order->pay_amount = $pay_amount; | ||
| 70 | + $order->description = '一言会员' . $membership_good->limit_days . $membership_good->limit_unit; | ||
| 71 | + $order->goods_amount = $membership_good->price; | ||
| 72 | + $order->status = Order::UNPAID; | ||
| 73 | + $order->source = $source; | ||
| 74 | + | ||
| 75 | + $order->save(); | ||
| 76 | + | ||
| 77 | + $order_good = new OrderGood(); | ||
| 78 | + $order_good->order_sn = $order_sn; | ||
| 79 | + $order_good->goods_id = $member_id; | ||
| 80 | + $order_good->goods_type = OrderGood::MemberShip; | ||
| 81 | + $order_good->goods_name = $membership_good->limit_days . $membership_good->limit_unit; | ||
| 82 | + $order_good->goods_image = $membership->getSingleImage(); | ||
| 83 | + $order_good->goods_price = $membership_good->price; | ||
| 84 | + $order_good->goods_number = $number; | ||
| 85 | + | ||
| 86 | + $order_good->save(); | ||
| 87 | + | ||
| 88 | + $order->goods = $order_good; | ||
| 89 | + | ||
| 90 | + | ||
| 91 | + // todo 超时处理,建议给Job处理 | ||
| 92 | + | ||
| 93 | +// if ($pay_amount == 0) { //0元购就不执行回调了 | ||
| 94 | +// $this->freePay($order); | ||
| 95 | +// } | ||
| 96 | + return $order; | ||
| 97 | + }); | ||
| 98 | + }catch (\Exception $exception){ | ||
| 99 | + return Response::fail('', 500, $exception->getMessage()); | ||
| 35 | } | 100 | } |
| 36 | } | 101 | } |
| 102 | + | ||
| 103 | + public function freePay($order) | ||
| 104 | + { | ||
| 105 | + $order = Order::query()->find($order->id); | ||
| 106 | + | ||
| 107 | + if ($order->status < Order::PAID){ | ||
| 108 | + $order->status = Order::PAID; | ||
| 109 | + $order->pay_type = ''; | ||
| 110 | + $order->pay_time = Carbon::now(); | ||
| 111 | + if ($order->save()){ | ||
| 112 | + // 执行一些本来属于回调的逻辑 | ||
| 113 | + | ||
| 114 | + return true; | ||
| 115 | + } | ||
| 116 | + } | ||
| 117 | + return false; | ||
| 118 | + } | ||
| 119 | + | ||
| 37 | } | 120 | } | ... | ... |
app/Http/Controllers/V1/PayController.php
0 → 100644
| 1 | +<?php | ||
| 2 | + | ||
| 3 | +namespace App\Http\Controllers\V1; | ||
| 4 | + | ||
| 5 | +use App\Http\Controllers\Controller; | ||
| 6 | +use App\Models\Order; | ||
| 7 | +use App\Payment\PaymentFactory; | ||
| 8 | +use Illuminate\Http\Request; | ||
| 9 | +use Jiannei\Response\Laravel\Support\Facades\Response; | ||
| 10 | + | ||
| 11 | +class PayController extends Controller | ||
| 12 | +{ | ||
| 13 | + | ||
| 14 | + public function index(Request $request,PaymentFactory $factory) | ||
| 15 | + { | ||
| 16 | + $order_sn = $request->get('order_sn'); | ||
| 17 | + | ||
| 18 | + $pay_type = $request->get('pay_type'); | ||
| 19 | + | ||
| 20 | + | ||
| 21 | + $order = Order::query()->where('order_sn', $order_sn)->first(); | ||
| 22 | + | ||
| 23 | + if ($order->status !== Order::UNPAID) return false; | ||
| 24 | + | ||
| 25 | +// if ($order->pay_amount <= 0) return $this->paid($order_sn); 0元购应该单独写一套 | ||
| 26 | + | ||
| 27 | + $payment = $factory->init($pay_type)->prepare($order); | ||
| 28 | + | ||
| 29 | + return Response::success($payment); | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * Store a newly created resource in storage. | ||
| 34 | + * | ||
| 35 | + * @param \Illuminate\Http\Request $request | ||
| 36 | + * @return \Illuminate\Http\Response | ||
| 37 | + */ | ||
| 38 | + public function store(Request $request) | ||
| 39 | + { | ||
| 40 | + // | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + /** | ||
| 44 | + * Display the specified resource. | ||
| 45 | + * | ||
| 46 | + * @param int $id | ||
| 47 | + * @return \Illuminate\Http\Response | ||
| 48 | + */ | ||
| 49 | + public function show($id) | ||
| 50 | + { | ||
| 51 | + // | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + /** | ||
| 55 | + * Show the form for editing the specified resource. | ||
| 56 | + * | ||
| 57 | + * @param int $id | ||
| 58 | + * @return \Illuminate\Http\Response | ||
| 59 | + */ | ||
| 60 | + public function edit($id) | ||
| 61 | + { | ||
| 62 | + // | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + /** | ||
| 66 | + * Update the specified resource in storage. | ||
| 67 | + * | ||
| 68 | + * @param \Illuminate\Http\Request $request | ||
| 69 | + * @param int $id | ||
| 70 | + * @return \Illuminate\Http\Response | ||
| 71 | + */ | ||
| 72 | + public function update(Request $request, $id) | ||
| 73 | + { | ||
| 74 | + // | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + /** | ||
| 78 | + * Remove the specified resource from storage. | ||
| 79 | + * | ||
| 80 | + * @param int $id | ||
| 81 | + * @return \Illuminate\Http\Response | ||
| 82 | + */ | ||
| 83 | + public function destroy($id) | ||
| 84 | + { | ||
| 85 | + // | ||
| 86 | + } | ||
| 87 | +} |
| ... | @@ -5,20 +5,33 @@ namespace App\Models; | ... | @@ -5,20 +5,33 @@ namespace App\Models; |
| 5 | use Dcat\Admin\Traits\HasDateTimeFormatter; | 5 | use Dcat\Admin\Traits\HasDateTimeFormatter; |
| 6 | 6 | ||
| 7 | use Illuminate\Database\Eloquent\Model; | 7 | use Illuminate\Database\Eloquent\Model; |
| 8 | +use Illuminate\Support\Arr; | ||
| 9 | +use Illuminate\Support\Facades\Storage; | ||
| 8 | 10 | ||
| 9 | class Membership extends Model | 11 | class Membership extends Model |
| 10 | { | 12 | { |
| 11 | use HasDateTimeFormatter; | 13 | use HasDateTimeFormatter; |
| 12 | protected $table = 'membership'; | 14 | protected $table = 'membership'; |
| 13 | 15 | ||
| 14 | - public function getBgImagesAttribute($value) | 16 | + protected $guarded = ['']; |
| 17 | + | ||
| 18 | + | ||
| 19 | + public function getImage() | ||
| 15 | { | 20 | { |
| 16 | - return explode(',', $value); | 21 | + return collect(explode(',', $this->bg_images))->map(function ($item){ |
| 22 | + return Storage::disk('public')->url($item); | ||
| 23 | + }); | ||
| 17 | } | 24 | } |
| 18 | 25 | ||
| 19 | - public function getSingleImgAttribute() | 26 | + public function getSingleImage() |
| 20 | { | 27 | { |
| 21 | $array = explode(',', $this->bg_images); | 28 | $array = explode(',', $this->bg_images); |
| 22 | - return $array[0]; | 29 | + |
| 30 | + return Storage::disk('public')->url($array[0]); | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + public function getMembershipGoods() | ||
| 34 | + { | ||
| 35 | + return $this->hasMany('App\Models\MembershipGood','membership_id'); | ||
| 23 | } | 36 | } |
| 24 | } | 37 | } | ... | ... |
| ... | @@ -5,10 +5,25 @@ namespace App\Models; | ... | @@ -5,10 +5,25 @@ namespace App\Models; |
| 5 | use Dcat\Admin\Traits\HasDateTimeFormatter; | 5 | use Dcat\Admin\Traits\HasDateTimeFormatter; |
| 6 | 6 | ||
| 7 | use Illuminate\Database\Eloquent\Model; | 7 | use Illuminate\Database\Eloquent\Model; |
| 8 | +use Spatie\EloquentSortable\Sortable; | ||
| 9 | +use Spatie\EloquentSortable\SortableTrait; | ||
| 8 | 10 | ||
| 9 | -class MembershipGood extends Model | 11 | +class MembershipGood extends Model implements Sortable |
| 10 | { | 12 | { |
| 11 | use HasDateTimeFormatter; | 13 | use HasDateTimeFormatter; |
| 12 | protected $table = 'membership_goods'; | 14 | protected $table = 'membership_goods'; |
| 13 | - | 15 | + |
| 16 | + protected $guarded = ['']; | ||
| 17 | + | ||
| 18 | + use SortableTrait; | ||
| 19 | + | ||
| 20 | + public $sortable = [ | ||
| 21 | + 'order_column_name' => 'sn', | ||
| 22 | + 'sort_when_creating' => true, | ||
| 23 | + ]; | ||
| 24 | + | ||
| 25 | + public function membership() | ||
| 26 | + { | ||
| 27 | + return $this->belongsTo(Membership::class); | ||
| 28 | + } | ||
| 14 | } | 29 | } | ... | ... |
| ... | @@ -3,57 +3,36 @@ | ... | @@ -3,57 +3,36 @@ |
| 3 | namespace App\Models; | 3 | namespace App\Models; |
| 4 | 4 | ||
| 5 | use Dcat\Admin\Traits\HasDateTimeFormatter; | 5 | use Dcat\Admin\Traits\HasDateTimeFormatter; |
| 6 | -use Illuminate\Database\Eloquent\SoftDeletes; | ||
| 7 | use Illuminate\Database\Eloquent\Model; | 6 | use Illuminate\Database\Eloquent\Model; |
| 8 | -use Illuminate\Support\Facades\Auth; | ||
| 9 | 7 | ||
| 10 | class Order extends Model | 8 | class Order extends Model |
| 11 | { | 9 | { |
| 12 | use HasDateTimeFormatter; | 10 | use HasDateTimeFormatter; |
| 13 | - use SoftDeletes; | ||
| 14 | 11 | ||
| 15 | protected $table = 'order'; | 12 | protected $table = 'order'; |
| 16 | 13 | ||
| 17 | - public function order_goods() | 14 | + /** 未支付*/ |
| 18 | - { | 15 | + const UNPAID = 100; |
| 19 | - return $this->hasOne('App\Models\OrderGood','order_sn'); | ||
| 20 | - } | ||
| 21 | 16 | ||
| 22 | - /** | 17 | + /** 用户取消*/ |
| 23 | - * 预创建订单 | 18 | + const USER_CANCEL = 101; |
| 24 | - * @param $member_id | ||
| 25 | - * @param $source | ||
| 26 | - */ | ||
| 27 | - public function build($member_id,$source) | ||
| 28 | - { | ||
| 29 | - // 获取商品信息 | ||
| 30 | - $membership = Membership::query()->where('id',$member_id)->first(); | ||
| 31 | 19 | ||
| 32 | - // 实付金额 = 商品金额 | 20 | + /** 超时取消*/ |
| 33 | - $pay_amount = $membership->price; | 21 | + const TIMEOUT_CANCEL = 102; |
| 34 | 22 | ||
| 35 | - // 创建订单 | 23 | + /** 商户取消*/ |
| 36 | - $order = new Order(); | 24 | + const MERCHANT_CANCEL = 102; |
| 37 | - $order_sn = $this->get_sn('osn'); | ||
| 38 | - $order->order_sn = $order_sn; | ||
| 39 | - $order->user_id = Auth::user()->getAuthIdentifier(); | ||
| 40 | - $order->pay_amount = $pay_amount; | ||
| 41 | - $order->goods_amount = $membership->price; | ||
| 42 | - $order->status = 100; | ||
| 43 | - $order->source = $source; | ||
| 44 | 25 | ||
| 45 | - $order->save(); | 26 | + /** 已支付*/ // 回调 |
| 27 | + const PAID = 201; | ||
| 46 | 28 | ||
| 47 | - $order_good = new OrderGood(); | 29 | + /** 已完成*/ // 回调并且业务逻辑(加天数、加销量)执行完毕 |
| 48 | - $order_good->order_sn = $order_sn; | 30 | + const DONE = 204; |
| 49 | - $order_good->goods_id = $member_id; | ||
| 50 | - $order_good->goods_name = $membership->name; | ||
| 51 | - $order_good->goods_image = $membership->getSingleImg(); | ||
| 52 | - $order_good->goods_price = $membership->price; | ||
| 53 | - $order_good->goods_number = 1; | ||
| 54 | 31 | ||
| 55 | - $order_good->save(); | ||
| 56 | 32 | ||
| 33 | + public function order_goods() | ||
| 34 | + { | ||
| 35 | + return $this->hasOne('App\Models\OrderGood','order_sn'); | ||
| 57 | } | 36 | } |
| 58 | 37 | ||
| 59 | /** | 38 | /** |
| ... | @@ -61,7 +40,7 @@ class Order extends Model | ... | @@ -61,7 +40,7 @@ class Order extends Model |
| 61 | * @param string $prefix | 40 | * @param string $prefix |
| 62 | * @return string | 41 | * @return string |
| 63 | */ | 42 | */ |
| 64 | - public function get_sn($prefix = '') | 43 | + static public function get_sn($prefix = '') |
| 65 | { | 44 | { |
| 66 | $Sn = $prefix . strtoupper(dechex(date('m'))) . date('d') . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(0, 99)); | 45 | $Sn = $prefix . strtoupper(dechex(date('m'))) . date('d') . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(0, 99)); |
| 67 | return $Sn; | 46 | return $Sn; | ... | ... |
| ... | @@ -10,5 +10,6 @@ class OrderGood extends Model | ... | @@ -10,5 +10,6 @@ class OrderGood extends Model |
| 10 | { | 10 | { |
| 11 | use HasDateTimeFormatter; | 11 | use HasDateTimeFormatter; |
| 12 | protected $table = 'order_goods'; | 12 | protected $table = 'order_goods'; |
| 13 | - | 13 | + |
| 14 | + const MemberShip = 1001; | ||
| 14 | } | 15 | } | ... | ... |
app/Payment/AliPayment.php
0 → 100644
| 1 | +<?php | ||
| 2 | +/** | ||
| 3 | + * Created by PhpStorm. | ||
| 4 | + * User: lishuai | ||
| 5 | + * Date: 2022/2/15 | ||
| 6 | + * Time: 4:23 PM | ||
| 7 | + */ | ||
| 8 | + | ||
| 9 | +namespace App\Payment; | ||
| 10 | + | ||
| 11 | +class AliPayment implements PaymentInterface | ||
| 12 | +{ | ||
| 13 | + public function prepare() | ||
| 14 | + { | ||
| 15 | + // TODO: Implement prepare() method. | ||
| 16 | + } | ||
| 17 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
app/Payment/PaymentFactory.php
0 → 100644
| 1 | +<?php | ||
| 2 | +/** | ||
| 3 | + * Created by PhpStorm. | ||
| 4 | + * User: lishuai | ||
| 5 | + * Date: 2022/2/15 | ||
| 6 | + * Time: 4:25 PM | ||
| 7 | + */ | ||
| 8 | + | ||
| 9 | +namespace App\Payment; | ||
| 10 | + | ||
| 11 | +class PaymentFactory | ||
| 12 | +{ | ||
| 13 | + public function init($pay_type) | ||
| 14 | + { | ||
| 15 | + switch ($pay_type){ | ||
| 16 | + case 'alipay': | ||
| 17 | + return new AliPayment(); | ||
| 18 | + case 'wechat': | ||
| 19 | + return new WechatPayment(); | ||
| 20 | + default: | ||
| 21 | + throw new \Exception('未知的支付方式'); | ||
| 22 | + } | ||
| 23 | + } | ||
| 24 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
app/Payment/PaymentInterface.php
0 → 100644
| 1 | +<?php | ||
| 2 | +/** | ||
| 3 | + * Created by PhpStorm. | ||
| 4 | + * User: lishuai | ||
| 5 | + * Date: 2022/2/15 | ||
| 6 | + * Time: 4:00 PM | ||
| 7 | + */ | ||
| 8 | + | ||
| 9 | +namespace App\Payment; | ||
| 10 | + | ||
| 11 | +use App\Models\Order; | ||
| 12 | + | ||
| 13 | +interface PaymentInterface | ||
| 14 | +{ | ||
| 15 | + /** | ||
| 16 | + * @param $order | ||
| 17 | + * @return array | ||
| 18 | + */ | ||
| 19 | + public function prepare(Order $order); | ||
| 20 | + | ||
| 21 | +} | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
app/Payment/WechatPayment.php
0 → 100644
| 1 | +<?php | ||
| 2 | +/** | ||
| 3 | + * Created by PhpStorm. | ||
| 4 | + * User: lishuai | ||
| 5 | + * Date: 2022/2/15 | ||
| 6 | + * Time: 4:23 PM | ||
| 7 | + */ | ||
| 8 | + | ||
| 9 | +namespace App\Payment; | ||
| 10 | + | ||
| 11 | +use App\Models\Order; | ||
| 12 | +use GuzzleHttp\Client; | ||
| 13 | +use GuzzleHttp\Exception\GuzzleException; | ||
| 14 | + | ||
| 15 | +class WechatPayment implements PaymentInterface | ||
| 16 | +{ | ||
| 17 | + /** 支付接口基础地址 */ | ||
| 18 | + const MCH_BASE_URL = 'https://api.mch.weixin.qq.com'; | ||
| 19 | + | ||
| 20 | + /** APP支付*/ | ||
| 21 | + const APP_URL = '/v3/pay/transactions/app'; | ||
| 22 | + | ||
| 23 | + /** H5支付*/ | ||
| 24 | + const H5_URL = '/v3/pay/transactions/h5'; | ||
| 25 | + | ||
| 26 | + /** App的应用id */ | ||
| 27 | + public $appid; | ||
| 28 | + | ||
| 29 | + /** 商户身份ID */ | ||
| 30 | + public $mchid; | ||
| 31 | + | ||
| 32 | + /** 商品描述*/ | ||
| 33 | + public $description; | ||
| 34 | + | ||
| 35 | + /** 商户订单号*/ | ||
| 36 | + public $out_trade_no; | ||
| 37 | + | ||
| 38 | + /** 支付回调*/ | ||
| 39 | + public $notify_url; | ||
| 40 | + | ||
| 41 | + /** 订单金额*/ | ||
| 42 | + public $amount; | ||
| 43 | + | ||
| 44 | + /** 证书序列号*/ | ||
| 45 | + public $serial_no; | ||
| 46 | + | ||
| 47 | + /** 商户API私钥*/ | ||
| 48 | + // todo 待添加 file:///path/to/merchant/apiclient_key.pem' | ||
| 49 | + public $mch_private_key = ''; | ||
| 50 | + | ||
| 51 | + | ||
| 52 | + public function prepare(Order $order) | ||
| 53 | + { | ||
| 54 | + $body = [ | ||
| 55 | + 'appid' => env('WECHAT_APPID'), | ||
| 56 | + 'mchid' => env('WECHAT_PAY_MCH_ID'), | ||
| 57 | + 'description' => $order->description, | ||
| 58 | + 'out_trade_no' => $order->order_sn, | ||
| 59 | + 'notify_url' => env('WECHAT_PAY_NOTIFY'), | ||
| 60 | + 'amount' => [ | ||
| 61 | + 'total' => $order->pay_amount * 100, | ||
| 62 | + 'currency' => 'CNY' | ||
| 63 | + ], | ||
| 64 | + ]; | ||
| 65 | + | ||
| 66 | + $timestamp = time();//时间戳 | ||
| 67 | + | ||
| 68 | + $nonce = self::nonce(32);//随机串 | ||
| 69 | + | ||
| 70 | + $sign = $this->sign('POST', self::APP_URL, $timestamp, $nonce, json_encode($body)); | ||
| 71 | + | ||
| 72 | + //设置HTTP头 | ||
| 73 | + $token = sprintf('WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"', | ||
| 74 | + env('WECHAT_PAY_MCH_ID'), $nonce, $timestamp, env('WECHAT_PAY_SERIAL_NO'), $sign); | ||
| 75 | + $headers = [ | ||
| 76 | + 'Accept' => 'application/json, text/plain, application/x-gzip, application/pdf, image/png, image/*;q=0.5', | ||
| 77 | + 'User-Agent' => '*/*', | ||
| 78 | + 'Content-Type' => 'application/json; charset=utf-8', | ||
| 79 | + 'Authorization' => $token, | ||
| 80 | + ]; | ||
| 81 | + | ||
| 82 | + $client = new Client([ | ||
| 83 | + 'base_uri' => self::MCH_BASE_URL, | ||
| 84 | + 'timeout' => 0, | ||
| 85 | + 'allow_redirects' => false, | ||
| 86 | + 'headers' => $headers | ||
| 87 | + ]); | ||
| 88 | + | ||
| 89 | + try { | ||
| 90 | + $response = $client->request('POST', self::APP_URL, ['json' => $body]); | ||
| 91 | + dd($prepayid = $response->getBody()->getContents()); | ||
| 92 | + } catch (GuzzleException $exception) { | ||
| 93 | + dd($exception->getMessage()); | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + return [ | ||
| 97 | + 'appid' => env('WECHAT_APPID'), | ||
| 98 | + 'partnerid' => env('WECHAT_PAY_MCH_ID'), | ||
| 99 | + 'prepayid' => $prepayid, | ||
| 100 | + 'package' => 'Sign=WXPay', | ||
| 101 | + 'noncestr' => $nonce, | ||
| 102 | + 'timestamp' => $timestamp, | ||
| 103 | + 'sign' => $sign | ||
| 104 | + ]; | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + | ||
| 108 | + public function notify() | ||
| 109 | + { | ||
| 110 | + | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + | ||
| 114 | + | ||
| 115 | + | ||
| 116 | + /** | ||
| 117 | + * @param string $http_method "GET"/"POST" | ||
| 118 | + * @param string $url "/v3/certificates" | ||
| 119 | + * @param string $timestamp | ||
| 120 | + * @param string $nonce | ||
| 121 | + * @param string $body "json_encode($body)" | ||
| 122 | + * @return array | ||
| 123 | + */ | ||
| 124 | + public function sign($http_method, $url, $timestamp, $nonce, $body = '') | ||
| 125 | + { | ||
| 126 | + $mch_private_key = openssl_get_privatekey(file_get_contents($this->mch_private_key));//私钥 | ||
| 127 | + | ||
| 128 | + //构造签名串 | ||
| 129 | + $message = implode("\n", [$http_method, $url, $timestamp, $nonce, $body]); | ||
| 130 | + | ||
| 131 | + //计算签名值 | ||
| 132 | + openssl_sign($message, $signature, $mch_private_key, OPENSSL_ALGO_SHA256); | ||
| 133 | + | ||
| 134 | + return base64_encode($signature); | ||
| 135 | + } | ||
| 136 | + | ||
| 137 | + /** | ||
| 138 | + * 生成32位随机字符串 | ||
| 139 | + * @param int $size - Nonce string length, default is 32. | ||
| 140 | + * @return string - base62 random string. | ||
| 141 | + * @throws | ||
| 142 | + */ | ||
| 143 | + public static function nonce(int $size = 32): string | ||
| 144 | + { | ||
| 145 | + if ($size < 1) { | ||
| 146 | + throw new \InvalidArgumentException('Size must be a positive integer.'); | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + return implode('', array_map(static function (string $c): string { | ||
| 150 | + return '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'[ord($c) % 62]; | ||
| 151 | + }, str_split(random_bytes($size)))); | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | +} |
| ... | @@ -21,7 +21,6 @@ class CreateMembershipTable extends Migration | ... | @@ -21,7 +21,6 @@ class CreateMembershipTable extends Migration |
| 21 | $table->unsignedTinyInteger('bg_type')->default(0)->comment('背景类型,1=单图,2=轮播图,3=视频'); | 21 | $table->unsignedTinyInteger('bg_type')->default(0)->comment('背景类型,1=单图,2=轮播图,3=视频'); |
| 22 | 22 | ||
| 23 | $table->string('bg_images')->default('')->comment('介绍图'); | 23 | $table->string('bg_images')->default('')->comment('介绍图'); |
| 24 | - $table->unsignedTinyInteger('is_video')->default(0)->comment('视频开关'); | ||
| 25 | $table->string('video_url')->default('')->comment('视频地址'); | 24 | $table->string('video_url')->default('')->comment('视频地址'); |
| 26 | $table->string('video_cover')->default('')->comment('视频封面'); | 25 | $table->string('video_cover')->default('')->comment('视频封面'); |
| 27 | 26 | ... | ... |
| ... | @@ -17,6 +17,7 @@ class CreateOrderTable extends Migration | ... | @@ -17,6 +17,7 @@ class CreateOrderTable extends Migration |
| 17 | $table->increments('id'); | 17 | $table->increments('id'); |
| 18 | $table->string('order_sn')->index()->default('')->comment('订单号'); | 18 | $table->string('order_sn')->index()->default('')->comment('订单号'); |
| 19 | $table->unsignedBigInteger('user_id')->index()->comment('用户id'); | 19 | $table->unsignedBigInteger('user_id')->index()->comment('用户id'); |
| 20 | + $table->string('description')->default('')->comment('订单描述'); | ||
| 20 | $table->decimal('pay_amount')->comment('实付金额'); | 21 | $table->decimal('pay_amount')->comment('实付金额'); |
| 21 | $table->decimal('goods_amount')->comment('商品金额'); | 22 | $table->decimal('goods_amount')->comment('商品金额'); |
| 22 | $table->unsignedSmallInteger('status')->comment('订单状态:100待付款 101用户取消 102超时取消 103商户取消 201已付款 204已完成'); | 23 | $table->unsignedSmallInteger('status')->comment('订单状态:100待付款 101用户取消 102超时取消 103商户取消 201已付款 204已完成'); |
| ... | @@ -24,6 +25,7 @@ class CreateOrderTable extends Migration | ... | @@ -24,6 +25,7 @@ class CreateOrderTable extends Migration |
| 24 | $table->string('source')->comment('来源'); | 25 | $table->string('source')->comment('来源'); |
| 25 | $table->string('pay_number')->default('')->comment('支付交易号'); | 26 | $table->string('pay_number')->default('')->comment('支付交易号'); |
| 26 | $table->string('pay_type')->default('')->comment('支付类型'); | 27 | $table->string('pay_type')->default('')->comment('支付类型'); |
| 28 | + $table->string('callback')->default('')->comment('回调参数'); | ||
| 27 | $table->timestamp('pay_time')->nullable()->comment('支付时间'); | 29 | $table->timestamp('pay_time')->nullable()->comment('支付时间'); |
| 28 | $table->timestamps(); | 30 | $table->timestamps(); |
| 29 | }); | 31 | }); | ... | ... |
| ... | @@ -17,6 +17,7 @@ class CreateOrderGoodsTable extends Migration | ... | @@ -17,6 +17,7 @@ class CreateOrderGoodsTable extends Migration |
| 17 | $table->increments('id'); | 17 | $table->increments('id'); |
| 18 | $table->string('order_sn')->comment('订单编号'); | 18 | $table->string('order_sn')->comment('订单编号'); |
| 19 | $table->unsignedInteger('goods_id')->comment('商品id'); | 19 | $table->unsignedInteger('goods_id')->comment('商品id'); |
| 20 | + $table->unsignedInteger('goods_type')->comment('商品类型'); | ||
| 20 | $table->string('goods_name')->default('')->comment('商品名称'); | 21 | $table->string('goods_name')->default('')->comment('商品名称'); |
| 21 | $table->string('goods_image')->default('')->comment('商品封面'); | 22 | $table->string('goods_image')->default('')->comment('商品封面'); |
| 22 | $table->decimal('goods_price')->default('0.00')->comment('商品价格'); | 23 | $table->decimal('goods_price')->default('0.00')->comment('商品价格'); | ... | ... |
| ... | @@ -16,17 +16,17 @@ class CreateMembershipGoodsTable extends Migration | ... | @@ -16,17 +16,17 @@ class CreateMembershipGoodsTable extends Migration |
| 16 | Schema::create('membership_goods', function (Blueprint $table) { | 16 | Schema::create('membership_goods', function (Blueprint $table) { |
| 17 | $table->increments('id'); | 17 | $table->increments('id'); |
| 18 | $table->integer('membership_id')->comment('会员id'); | 18 | $table->integer('membership_id')->comment('会员id'); |
| 19 | - $table->decimal('price')->comment('价格'); | 19 | + $table->decimal('price')->default('0.00')->comment('价格'); |
| 20 | - $table->decimal('line_price')->comment('划线价格'); | 20 | + $table->decimal('line_price')->default('0.00')->comment('划线价格'); |
| 21 | - $table->integer('limit_days')->comment('有效天数'); | 21 | + $table->integer('limit_days')->default(0)->comment('有效天数'); |
| 22 | $table->string('limit_unit')->default('')->comment('有效期单位'); | 22 | $table->string('limit_unit')->default('')->comment('有效期单位'); |
| 23 | $table->unsignedTinyInteger('terminal')->comment('1=Android,2=IOS'); | 23 | $table->unsignedTinyInteger('terminal')->comment('1=Android,2=IOS'); |
| 24 | $table->unsignedTinyInteger('state')->comment('0=下架,1=售卖中'); | 24 | $table->unsignedTinyInteger('state')->comment('0=下架,1=售卖中'); |
| 25 | $table->unsignedTinyInteger('sn')->comment('SN顺序'); | 25 | $table->unsignedTinyInteger('sn')->comment('SN顺序'); |
| 26 | - $table->unsignedInteger('visits')->comment('访问量'); | 26 | + $table->unsignedInteger('visits')->default(0)->comment('访问量'); |
| 27 | - $table->unsignedInteger('virtual_sales')->comment('虚拟销售量'); | 27 | + $table->unsignedInteger('virtual_sales')->default(0)->comment('虚拟销售量'); |
| 28 | - $table->unsignedInteger('sales')->comment('销售量'); | 28 | + $table->unsignedInteger('sales')->default(0)->comment('销售量'); |
| 29 | - $table->unsignedInteger('stocks')->comment('库存数量'); | 29 | + $table->unsignedInteger('stocks')->default(0)->comment('库存数量'); |
| 30 | $table->timestamps(); | 30 | $table->timestamps(); |
| 31 | }); | 31 | }); |
| 32 | } | 32 | } | ... | ... |
This diff is collapsed. Click to expand it.
public/asset/css/gallery.css
0 → 100644
| 1 | +.extension-demo { | ||
| 2 | + font-size: 1.3rem; | ||
| 3 | + cursor: pointer; | ||
| 4 | +} | ||
| 5 | + | ||
| 6 | +.dengje-gallery-group { | ||
| 7 | + position: relative; | ||
| 8 | + margin: 5%; | ||
| 9 | +} | ||
| 10 | + | ||
| 11 | +.dengje-gallery-group.multiple .gallery-img-wrapper.bg-left { | ||
| 12 | + top: 5%; | ||
| 13 | + left: -5%; | ||
| 14 | + -webkit-transform: rotate(-5deg); | ||
| 15 | + -moz-transform: rotate(-5deg); | ||
| 16 | + -o-transform: rotate(-5deg); | ||
| 17 | + -ms-transform: rotate(-5deg); | ||
| 18 | + transform: rotate(-5deg); | ||
| 19 | +} | ||
| 20 | + | ||
| 21 | +.dengje-gallery-group.multiple .gallery-img-wrapper.bg-left:before { | ||
| 22 | + content: ""; | ||
| 23 | + width: 100%; | ||
| 24 | + height: 100%; | ||
| 25 | + background: #eff4de; | ||
| 26 | + display: block; | ||
| 27 | +} | ||
| 28 | + | ||
| 29 | +.dengje-gallery-group.multiple .gallery-img-wrapper.bg-right { | ||
| 30 | + top: 5%; | ||
| 31 | + left: 5%; | ||
| 32 | + -webkit-transform: rotate(5deg); | ||
| 33 | + -moz-transform: rotate(5deg); | ||
| 34 | + -o-transform: rotate(5deg); | ||
| 35 | + -ms-transform: rotate(5deg); | ||
| 36 | + transform: rotate(5deg); | ||
| 37 | +} | ||
| 38 | + | ||
| 39 | +.dengje-gallery-group.multiple .gallery-img-wrapper.bg-right:before { | ||
| 40 | + content: ""; | ||
| 41 | + width: 100%; | ||
| 42 | + height: 100%; | ||
| 43 | + background: #768590; | ||
| 44 | + display: block; | ||
| 45 | +} | ||
| 46 | + | ||
| 47 | +.dengje-gallery-group .gallery-img-wrapper { | ||
| 48 | + padding: 3%; | ||
| 49 | + background: #fff; | ||
| 50 | + height: 100%; | ||
| 51 | + width: 100%; | ||
| 52 | + z-index: 1; | ||
| 53 | + display: flex; | ||
| 54 | + justify-content: center; | ||
| 55 | + align-items: center; | ||
| 56 | + position: absolute; | ||
| 57 | + -webkit-box-shadow: .2em .2em .5em rgb(0 0 0 / 30%); | ||
| 58 | + -moz-box-shadow: .2em .2em .5em rgba(0, 0, 0, 0.3); | ||
| 59 | + box-shadow: .2em .2em .5em rgb(0 0 0 / 30%); | ||
| 60 | +} | ||
| 61 | + | ||
| 62 | +.dengje-gallery-group .gallery-img-wrapper > img { | ||
| 63 | + max-width: 100%; | ||
| 64 | + max-height: 100%; | ||
| 65 | +} | ||
| 66 | + | ||
| 67 | +.dengje-gallery-group .bg-multi { | ||
| 68 | + display: none; | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +.dengje-gallery-group.multiple .bg-multi { | ||
| 72 | + display: block; | ||
| 73 | +} | ||
| 74 | + | ||
| 75 | +.hide { | ||
| 76 | + display: none; | ||
| 77 | +} |
public/asset/css/viewer.css
0 → 100644
| 1 | +/*! | ||
| 2 | + * Viewer.js v1.5.0 | ||
| 3 | + * https://fengyuanchen.github.io/viewerjs | ||
| 4 | + * | ||
| 5 | + * Copyright 2015-present Chen Fengyuan | ||
| 6 | + * Released under the MIT license | ||
| 7 | + * | ||
| 8 | + * Date: 2019-11-23T05:10:21.757Z | ||
| 9 | + */ | ||
| 10 | + | ||
| 11 | +.viewer-zoom-in::before, | ||
| 12 | +.viewer-zoom-out::before, | ||
| 13 | +.viewer-one-to-one::before, | ||
| 14 | +.viewer-reset::before, | ||
| 15 | +.viewer-prev::before, | ||
| 16 | +.viewer-play::before, | ||
| 17 | +.viewer-next::before, | ||
| 18 | +.viewer-rotate-left::before, | ||
| 19 | +.viewer-rotate-right::before, | ||
| 20 | +.viewer-flip-horizontal::before, | ||
| 21 | +.viewer-flip-vertical::before, | ||
| 22 | +.viewer-fullscreen::before, | ||
| 23 | +.viewer-fullscreen-exit::before, | ||
| 24 | +.viewer-close::before { | ||
| 25 | + background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARgAAAAUCAYAAABWOyJDAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNui8sowAAAQPSURBVHic7Zs/iFxVFMa/0U2UaJGksUgnIVhYxVhpjDbZCBmLdAYECxsRFBTUamcXUiSNncgKQbSxsxH8gzAP3FU2jY0kKKJNiiiIghFlccnP4p3nPCdv3p9778vsLOcHB2bfveeb7955c3jvvNkBIMdxnD64a94GHMfZu3iBcRynN7zAOI7TG15gHCeeNUkr8zaxG2lbYDYsdgMbktBsP03jdQwljSXdtBhLOmtjowC9Mg9L+knSlcD8TNKpSA9lBpK2JF2VdDSR5n5J64m0qli399hNFMUlpshQii5jbXTbHGviB0nLNeNDSd9VO4A2UdB2fp+x0eCnaXxWXGA2X0au/3HgN9P4LFCjIANOJdrLr0zzZ+BEpNYDwKbpnQMeAw4m8HjQtM6Z9qa917zPQwFr3M5KgA6J5rTJCdFZJj9/lyvGhsDvwFNVuV2MhhjrK6b9bFiE+j1r87eBl4HDwCF7/U/k+ofAX5b/EXBv5JoLMuILzf3Ap6Z3EzgdqHMCuF7hcQf4HDgeoHnccncqdK/TvSDWffFXI/exICY/xZyqc6XLWF1UFZna4gJ7q8BsRvgd2/xXpo6P+D9dfT7PpECtA3cnWPM0GXGFZh/wgWltA+cDNC7X+AP4GzjZQe+k5dRxuYPeiuXU7e1qwLpDz7dFjXKRaSwuMLvAlG8zZlG+YmiK1HoFqT7wP2z+4Q45TfEGcMt01xLoNZEBTwRqD4BLpnMLeC1A41UmVxsXgXeBayV/Wx20rpTyrpnWRft7p6O/FdqzGrDukPNtkaMoMo3FBdBSQMOnYBCReyf05s126fU9ytfX98+mY54Kxnp7S9K3kj6U9KYdG0h6UdLbkh7poFXMfUnSOyVvL0h6VtIXHbS6nOP+s/Zm9mvyXW1uuC9ohZ72E9uDmXWLJOB1GxsH+DxPftsB8B6wlGDN02TAkxG6+4D3TWsbeC5CS8CDFce+AW500LhhOW2020TRjK3b21HEmgti9m0RonxbdMZeVzV+/4tF3cBpP7E9mKHNL5q8h5g0eYsCMQz0epq8gQrwMXAgcs0FGXGFRcB9wCemF9PkbYqM/Bas7fxLwNeJPdTdpo4itQti8lPMqTpXuozVRVXPpbHI3KkNTB1NfkL81j2mvhDp91HgV9MKuRIqrykj3WPq4rHyL+axj8/qGPmTqi6F9YDlHOvJU6oYcTsh/TYSzWmTE6JT19CtLTJt32D6CmHe0eQn1O8z5AXgT4sx4Vcu0/EQecMydB8z0hUWkTd2t4CrwNEePqMBcAR4mrBbwyXLPWJa8zrXmmLEhNBmfpkuY2102xxrih+pb+ieAb6vGhuA97UcJ5KR8gZ77K+99xxeYBzH6Q3/Z0fHcXrDC4zjOL3hBcZxnN74F+zlvXFWXF9PAAAAAElFTkSuQmCC'); | ||
| 26 | + background-repeat: no-repeat; | ||
| 27 | + background-size: 280px; | ||
| 28 | + color: transparent; | ||
| 29 | + display: block; | ||
| 30 | + font-size: 0; | ||
| 31 | + height: 20px; | ||
| 32 | + line-height: 0; | ||
| 33 | + width: 20px; | ||
| 34 | +} | ||
| 35 | + | ||
| 36 | +.viewer-zoom-in::before { | ||
| 37 | + background-position: 0 0; | ||
| 38 | + content: 'Zoom In'; | ||
| 39 | +} | ||
| 40 | + | ||
| 41 | +.viewer-zoom-out::before { | ||
| 42 | + background-position: -20px 0; | ||
| 43 | + content: 'Zoom Out'; | ||
| 44 | +} | ||
| 45 | + | ||
| 46 | +.viewer-one-to-one::before { | ||
| 47 | + background-position: -40px 0; | ||
| 48 | + content: 'One to One'; | ||
| 49 | +} | ||
| 50 | + | ||
| 51 | +.viewer-reset::before { | ||
| 52 | + background-position: -60px 0; | ||
| 53 | + content: 'Reset'; | ||
| 54 | +} | ||
| 55 | + | ||
| 56 | +.viewer-prev::before { | ||
| 57 | + background-position: -80px 0; | ||
| 58 | + content: 'Previous'; | ||
| 59 | +} | ||
| 60 | + | ||
| 61 | +.viewer-play::before { | ||
| 62 | + background-position: -100px 0; | ||
| 63 | + content: 'Play'; | ||
| 64 | +} | ||
| 65 | + | ||
| 66 | +.viewer-next::before { | ||
| 67 | + background-position: -120px 0; | ||
| 68 | + content: 'Next'; | ||
| 69 | +} | ||
| 70 | + | ||
| 71 | +.viewer-rotate-left::before { | ||
| 72 | + background-position: -140px 0; | ||
| 73 | + content: 'Rotate Left'; | ||
| 74 | +} | ||
| 75 | + | ||
| 76 | +.viewer-rotate-right::before { | ||
| 77 | + background-position: -160px 0; | ||
| 78 | + content: 'Rotate Right'; | ||
| 79 | +} | ||
| 80 | + | ||
| 81 | +.viewer-flip-horizontal::before { | ||
| 82 | + background-position: -180px 0; | ||
| 83 | + content: 'Flip Horizontal'; | ||
| 84 | +} | ||
| 85 | + | ||
| 86 | +.viewer-flip-vertical::before { | ||
| 87 | + background-position: -200px 0; | ||
| 88 | + content: 'Flip Vertical'; | ||
| 89 | +} | ||
| 90 | + | ||
| 91 | +.viewer-fullscreen::before { | ||
| 92 | + background-position: -220px 0; | ||
| 93 | + content: 'Enter Full Screen'; | ||
| 94 | +} | ||
| 95 | + | ||
| 96 | +.viewer-fullscreen-exit::before { | ||
| 97 | + background-position: -240px 0; | ||
| 98 | + content: 'Exit Full Screen'; | ||
| 99 | +} | ||
| 100 | + | ||
| 101 | +.viewer-close::before { | ||
| 102 | + background-position: -260px 0; | ||
| 103 | + content: 'Close'; | ||
| 104 | +} | ||
| 105 | + | ||
| 106 | +.viewer-container { | ||
| 107 | + bottom: 0; | ||
| 108 | + direction: ltr; | ||
| 109 | + font-size: 0; | ||
| 110 | + left: 0; | ||
| 111 | + line-height: 0; | ||
| 112 | + overflow: hidden; | ||
| 113 | + position: absolute; | ||
| 114 | + right: 0; | ||
| 115 | + -webkit-tap-highlight-color: transparent; | ||
| 116 | + top: 0; | ||
| 117 | + -ms-touch-action: none; | ||
| 118 | + touch-action: none; | ||
| 119 | + -webkit-touch-callout: none; | ||
| 120 | + -webkit-user-select: none; | ||
| 121 | + -moz-user-select: none; | ||
| 122 | + -ms-user-select: none; | ||
| 123 | + user-select: none; | ||
| 124 | +} | ||
| 125 | + | ||
| 126 | +.viewer-container::-moz-selection, | ||
| 127 | +.viewer-container *::-moz-selection { | ||
| 128 | + background-color: transparent; | ||
| 129 | +} | ||
| 130 | + | ||
| 131 | +.viewer-container::selection, | ||
| 132 | +.viewer-container *::selection { | ||
| 133 | + background-color: transparent; | ||
| 134 | +} | ||
| 135 | + | ||
| 136 | +.viewer-container img { | ||
| 137 | + display: block; | ||
| 138 | + height: auto; | ||
| 139 | + max-height: none !important; | ||
| 140 | + max-width: none !important; | ||
| 141 | + min-height: 0 !important; | ||
| 142 | + min-width: 0 !important; | ||
| 143 | + width: 100%; | ||
| 144 | +} | ||
| 145 | + | ||
| 146 | +.viewer-canvas { | ||
| 147 | + bottom: 0; | ||
| 148 | + left: 0; | ||
| 149 | + overflow: hidden; | ||
| 150 | + position: absolute; | ||
| 151 | + right: 0; | ||
| 152 | + top: 0; | ||
| 153 | +} | ||
| 154 | + | ||
| 155 | +.viewer-canvas > img { | ||
| 156 | + height: auto; | ||
| 157 | + margin: 15px auto; | ||
| 158 | + max-width: 90% !important; | ||
| 159 | + width: auto; | ||
| 160 | +} | ||
| 161 | + | ||
| 162 | +.viewer-footer { | ||
| 163 | + bottom: 0; | ||
| 164 | + left: 0; | ||
| 165 | + overflow: hidden; | ||
| 166 | + position: absolute; | ||
| 167 | + right: 0; | ||
| 168 | + text-align: center; | ||
| 169 | +} | ||
| 170 | + | ||
| 171 | +.viewer-navbar { | ||
| 172 | + background-color: rgba(0, 0, 0, 0.5); | ||
| 173 | + overflow: hidden; | ||
| 174 | +} | ||
| 175 | + | ||
| 176 | +.viewer-list { | ||
| 177 | + -webkit-box-sizing: content-box; | ||
| 178 | + box-sizing: content-box; | ||
| 179 | + height: 50px; | ||
| 180 | + margin: 0; | ||
| 181 | + overflow: hidden; | ||
| 182 | + padding: 1px 0; | ||
| 183 | +} | ||
| 184 | + | ||
| 185 | +.viewer-list > li { | ||
| 186 | + color: transparent; | ||
| 187 | + cursor: pointer; | ||
| 188 | + float: left; | ||
| 189 | + font-size: 0; | ||
| 190 | + height: 50px; | ||
| 191 | + line-height: 0; | ||
| 192 | + opacity: 0.5; | ||
| 193 | + overflow: hidden; | ||
| 194 | + -webkit-transition: opacity 0.15s; | ||
| 195 | + transition: opacity 0.15s; | ||
| 196 | + width: 30px; | ||
| 197 | +} | ||
| 198 | + | ||
| 199 | +.viewer-list > li:hover { | ||
| 200 | + opacity: 0.75; | ||
| 201 | +} | ||
| 202 | + | ||
| 203 | +.viewer-list > li + li { | ||
| 204 | + margin-left: 1px; | ||
| 205 | +} | ||
| 206 | + | ||
| 207 | +.viewer-list > .viewer-loading { | ||
| 208 | + position: relative; | ||
| 209 | +} | ||
| 210 | + | ||
| 211 | +.viewer-list > .viewer-loading::after { | ||
| 212 | + border-width: 2px; | ||
| 213 | + height: 20px; | ||
| 214 | + margin-left: -10px; | ||
| 215 | + margin-top: -10px; | ||
| 216 | + width: 20px; | ||
| 217 | +} | ||
| 218 | + | ||
| 219 | +.viewer-list > .viewer-active, | ||
| 220 | +.viewer-list > .viewer-active:hover { | ||
| 221 | + opacity: 1; | ||
| 222 | +} | ||
| 223 | + | ||
| 224 | +.viewer-player { | ||
| 225 | + background-color: #000; | ||
| 226 | + bottom: 0; | ||
| 227 | + cursor: none; | ||
| 228 | + display: none; | ||
| 229 | + left: 0; | ||
| 230 | + position: absolute; | ||
| 231 | + right: 0; | ||
| 232 | + top: 0; | ||
| 233 | +} | ||
| 234 | + | ||
| 235 | +.viewer-player > img { | ||
| 236 | + left: 0; | ||
| 237 | + position: absolute; | ||
| 238 | + top: 0; | ||
| 239 | +} | ||
| 240 | + | ||
| 241 | +.viewer-toolbar > ul { | ||
| 242 | + display: inline-block; | ||
| 243 | + margin: 0 auto 5px; | ||
| 244 | + overflow: hidden; | ||
| 245 | + padding: 3px 0; | ||
| 246 | +} | ||
| 247 | + | ||
| 248 | +.viewer-toolbar > ul > li { | ||
| 249 | + background-color: rgba(0, 0, 0, 0.5); | ||
| 250 | + border-radius: 50%; | ||
| 251 | + cursor: pointer; | ||
| 252 | + float: left; | ||
| 253 | + height: 24px; | ||
| 254 | + overflow: hidden; | ||
| 255 | + -webkit-transition: background-color 0.15s; | ||
| 256 | + transition: background-color 0.15s; | ||
| 257 | + width: 24px; | ||
| 258 | +} | ||
| 259 | + | ||
| 260 | +.viewer-toolbar > ul > li:hover { | ||
| 261 | + background-color: rgba(0, 0, 0, 0.8); | ||
| 262 | +} | ||
| 263 | + | ||
| 264 | +.viewer-toolbar > ul > li::before { | ||
| 265 | + margin: 2px; | ||
| 266 | +} | ||
| 267 | + | ||
| 268 | +.viewer-toolbar > ul > li + li { | ||
| 269 | + margin-left: 1px; | ||
| 270 | +} | ||
| 271 | + | ||
| 272 | +.viewer-toolbar > ul > .viewer-small { | ||
| 273 | + height: 18px; | ||
| 274 | + margin-bottom: 3px; | ||
| 275 | + margin-top: 3px; | ||
| 276 | + width: 18px; | ||
| 277 | +} | ||
| 278 | + | ||
| 279 | +.viewer-toolbar > ul > .viewer-small::before { | ||
| 280 | + margin: -1px; | ||
| 281 | +} | ||
| 282 | + | ||
| 283 | +.viewer-toolbar > ul > .viewer-large { | ||
| 284 | + height: 30px; | ||
| 285 | + margin-bottom: -3px; | ||
| 286 | + margin-top: -3px; | ||
| 287 | + width: 30px; | ||
| 288 | +} | ||
| 289 | + | ||
| 290 | +.viewer-toolbar > ul > .viewer-large::before { | ||
| 291 | + margin: 5px; | ||
| 292 | +} | ||
| 293 | + | ||
| 294 | +.viewer-tooltip { | ||
| 295 | + background-color: rgba(0, 0, 0, 0.8); | ||
| 296 | + border-radius: 10px; | ||
| 297 | + color: #fff; | ||
| 298 | + display: none; | ||
| 299 | + font-size: 12px; | ||
| 300 | + height: 20px; | ||
| 301 | + left: 50%; | ||
| 302 | + line-height: 20px; | ||
| 303 | + margin-left: -25px; | ||
| 304 | + margin-top: -10px; | ||
| 305 | + position: absolute; | ||
| 306 | + text-align: center; | ||
| 307 | + top: 50%; | ||
| 308 | + width: 50px; | ||
| 309 | +} | ||
| 310 | + | ||
| 311 | +.viewer-title { | ||
| 312 | + color: #ccc; | ||
| 313 | + display: inline-block; | ||
| 314 | + font-size: 12px; | ||
| 315 | + line-height: 1; | ||
| 316 | + margin: 0 5% 5px; | ||
| 317 | + max-width: 90%; | ||
| 318 | + opacity: 0.8; | ||
| 319 | + overflow: hidden; | ||
| 320 | + text-overflow: ellipsis; | ||
| 321 | + -webkit-transition: opacity 0.15s; | ||
| 322 | + transition: opacity 0.15s; | ||
| 323 | + white-space: nowrap; | ||
| 324 | +} | ||
| 325 | + | ||
| 326 | +.viewer-title:hover { | ||
| 327 | + opacity: 1; | ||
| 328 | +} | ||
| 329 | + | ||
| 330 | +.viewer-button { | ||
| 331 | + background-color: rgba(0, 0, 0, 0.5); | ||
| 332 | + border-radius: 50%; | ||
| 333 | + cursor: pointer; | ||
| 334 | + height: 80px; | ||
| 335 | + overflow: hidden; | ||
| 336 | + position: absolute; | ||
| 337 | + right: -40px; | ||
| 338 | + top: -40px; | ||
| 339 | + -webkit-transition: background-color 0.15s; | ||
| 340 | + transition: background-color 0.15s; | ||
| 341 | + width: 80px; | ||
| 342 | +} | ||
| 343 | + | ||
| 344 | +.viewer-button:focus, | ||
| 345 | +.viewer-button:hover { | ||
| 346 | + background-color: rgba(0, 0, 0, 0.8); | ||
| 347 | +} | ||
| 348 | + | ||
| 349 | +.viewer-button::before { | ||
| 350 | + bottom: 15px; | ||
| 351 | + left: 15px; | ||
| 352 | + position: absolute; | ||
| 353 | +} | ||
| 354 | + | ||
| 355 | +.viewer-fixed { | ||
| 356 | + position: fixed; | ||
| 357 | +} | ||
| 358 | + | ||
| 359 | +.viewer-open { | ||
| 360 | + overflow: hidden; | ||
| 361 | +} | ||
| 362 | + | ||
| 363 | +.viewer-show { | ||
| 364 | + display: block; | ||
| 365 | +} | ||
| 366 | + | ||
| 367 | +.viewer-hide { | ||
| 368 | + display: none; | ||
| 369 | +} | ||
| 370 | + | ||
| 371 | +.viewer-backdrop { | ||
| 372 | + background-color: rgba(0, 0, 0, 0.5); | ||
| 373 | +} | ||
| 374 | + | ||
| 375 | +.viewer-invisible { | ||
| 376 | + visibility: hidden; | ||
| 377 | +} | ||
| 378 | + | ||
| 379 | +.viewer-move { | ||
| 380 | + cursor: move; | ||
| 381 | + cursor: -webkit-grab; | ||
| 382 | + cursor: grab; | ||
| 383 | +} | ||
| 384 | + | ||
| 385 | +.viewer-fade { | ||
| 386 | + opacity: 0; | ||
| 387 | +} | ||
| 388 | + | ||
| 389 | +.viewer-in { | ||
| 390 | + opacity: 1; | ||
| 391 | +} | ||
| 392 | + | ||
| 393 | +.viewer-transition { | ||
| 394 | + -webkit-transition: all 0.3s; | ||
| 395 | + transition: all 0.3s; | ||
| 396 | +} | ||
| 397 | + | ||
| 398 | +@-webkit-keyframes viewer-spinner { | ||
| 399 | + 0% { | ||
| 400 | + -webkit-transform: rotate(0deg); | ||
| 401 | + transform: rotate(0deg); | ||
| 402 | + } | ||
| 403 | + | ||
| 404 | + 100% { | ||
| 405 | + -webkit-transform: rotate(360deg); | ||
| 406 | + transform: rotate(360deg); | ||
| 407 | + } | ||
| 408 | +} | ||
| 409 | + | ||
| 410 | +@keyframes viewer-spinner { | ||
| 411 | + 0% { | ||
| 412 | + -webkit-transform: rotate(0deg); | ||
| 413 | + transform: rotate(0deg); | ||
| 414 | + } | ||
| 415 | + | ||
| 416 | + 100% { | ||
| 417 | + -webkit-transform: rotate(360deg); | ||
| 418 | + transform: rotate(360deg); | ||
| 419 | + } | ||
| 420 | +} | ||
| 421 | + | ||
| 422 | +.viewer-loading::after { | ||
| 423 | + -webkit-animation: viewer-spinner 1s linear infinite; | ||
| 424 | + animation: viewer-spinner 1s linear infinite; | ||
| 425 | + border: 4px solid rgba(255, 255, 255, 0.1); | ||
| 426 | + border-left-color: rgba(255, 255, 255, 0.5); | ||
| 427 | + border-radius: 50%; | ||
| 428 | + content: ''; | ||
| 429 | + display: inline-block; | ||
| 430 | + height: 40px; | ||
| 431 | + left: 50%; | ||
| 432 | + margin-left: -20px; | ||
| 433 | + margin-top: -20px; | ||
| 434 | + position: absolute; | ||
| 435 | + top: 50%; | ||
| 436 | + width: 40px; | ||
| 437 | + z-index: 1; | ||
| 438 | +} | ||
| 439 | + | ||
| 440 | +@media (max-width: 767px) { | ||
| 441 | + .viewer-hide-xs-down { | ||
| 442 | + display: none; | ||
| 443 | + } | ||
| 444 | +} | ||
| 445 | + | ||
| 446 | +@media (max-width: 991px) { | ||
| 447 | + .viewer-hide-sm-down { | ||
| 448 | + display: none; | ||
| 449 | + } | ||
| 450 | +} | ||
| 451 | + | ||
| 452 | +@media (max-width: 1199px) { | ||
| 453 | + .viewer-hide-md-down { | ||
| 454 | + display: none; | ||
| 455 | + } | ||
| 456 | +} |
public/asset/js/viewer.js
0 → 100644
This diff could not be displayed because it is too large.
| ... | @@ -7,7 +7,6 @@ return [ | ... | @@ -7,7 +7,6 @@ return [ |
| 7 | 'fields' => [ | 7 | 'fields' => [ |
| 8 | 'name' => '会员名称', | 8 | 'name' => '会员名称', |
| 9 | 'origin_price' => '原价(分)', | 9 | 'origin_price' => '原价(分)', |
| 10 | - 'limited_days' => '有效天数', | ||
| 11 | 'intro' => '简介', | 10 | 'intro' => '简介', |
| 12 | 'state' => '状态', | 11 | 'state' => '状态', |
| 13 | 'membership_id' => '会员id', | 12 | 'membership_id' => '会员id', | ... | ... |
| 1 | +<style> | ||
| 2 | + .box-card { | ||
| 3 | + width: 380px; | ||
| 4 | + border: 1px solid rgb(220, 223, 230); | ||
| 5 | + border-radius: 40px; | ||
| 6 | + margin-right: 24px; | ||
| 7 | + padding: 37px 20px; | ||
| 8 | + min-height: 779px; | ||
| 9 | + } | ||
| 10 | + | ||
| 11 | + .phone-content { | ||
| 12 | + border: 1px solid rgb(220, 223, 230); | ||
| 13 | + height: 705px; | ||
| 14 | + overflow: hidden; | ||
| 15 | + position: relative; | ||
| 16 | + background: rgb(245, 245, 245); | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + .text { | ||
| 20 | + font-size: 16px; | ||
| 21 | + font-weight: 700; | ||
| 22 | + color: rgb(38, 38, 38); | ||
| 23 | + text-align: center; | ||
| 24 | + position: absolute; | ||
| 25 | + width: 100%; | ||
| 26 | + top: 50px; | ||
| 27 | + box-sizing: border-box; | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + .poem-block { | ||
| 31 | + width: 315px; | ||
| 32 | + height: 330px; | ||
| 33 | + margin: 0; | ||
| 34 | + padding: 0; | ||
| 35 | + position: absolute; | ||
| 36 | + text-align: center; | ||
| 37 | + top: 200px; | ||
| 38 | + left: 10px; | ||
| 39 | + border-radius: 5px; | ||
| 40 | + background: rgba(87, 78, 78, 0.6); | ||
| 41 | + box-shadow: 2px 2px 4px 2px rgba(0, 0, 0, .3); | ||
| 42 | + overflow: hidden; | ||
| 43 | + | ||
| 44 | + display: flex; | ||
| 45 | + flex-direction: column; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + .poem-title { | ||
| 49 | + color: #ffffff; | ||
| 50 | + font-size: 14px; | ||
| 51 | + font-weight: bold; | ||
| 52 | + margin: 10px; | ||
| 53 | + display: flex; | ||
| 54 | + flex-direction: row; | ||
| 55 | + justify-content: space-between; | ||
| 56 | + align-items: center; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + .intro-title { | ||
| 60 | + color: #ffffff; | ||
| 61 | + font-size: 14px; | ||
| 62 | + font-weight: bold; | ||
| 63 | + margin: 10px; | ||
| 64 | + text-align: start; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + .price{ | ||
| 68 | + display: flex; | ||
| 69 | + flex-direction: row; | ||
| 70 | + justify-content: flex-start; | ||
| 71 | + } | ||
| 72 | +</style> | ||
| 73 | +<div class="box-card"> | ||
| 74 | + <div class="phone-content"> | ||
| 75 | + <div class="text">会员页</div> | ||
| 76 | + <img src="{{asset('storage/image/mobile-head.png')}}" alt="" width="338" height="80"> | ||
| 77 | + <div style="min-height: 625px;"> | ||
| 78 | + <img width="338" height="625" class="bg_img" src="{{asset('storage/images/a5fe2ba2bd71b543cbf4c6fb3968ab64.png')}}"> | ||
| 79 | + </div> | ||
| 80 | + <div class="poem-block"> | ||
| 81 | + <div class="intro-title">开发者249d42a097c1944e进行了广播推送,这是一条广播</div> | ||
| 82 | + <div class="poem-title"> | ||
| 83 | + <div> 连续包月 </div> | ||
| 84 | + <div class="price"> | ||
| 85 | + <span> 29 元 </span> | ||
| 86 | + <span> / 月</span> | ||
| 87 | + </div> | ||
| 88 | + <button type="button" class="btn btn-primary">开通</button> | ||
| 89 | + </div> | ||
| 90 | + <div class="poem-title"> | ||
| 91 | + <div> 连续包年 </div> | ||
| 92 | + <div class="price"> | ||
| 93 | + <span> 299 元 </span> | ||
| 94 | + <span> / 月</span> | ||
| 95 | + </div> | ||
| 96 | + <button type="button" class="btn btn-primary">开通</button> | ||
| 97 | + </div> | ||
| 98 | + <div class="intro-title" style="min-height: 100px">开发者249d42a097c1944e进行了广播推送,这是一条广播</div> | ||
| 99 | + <div class="intro-title" style="text-align: center">服务协议 | 隐私政策 | 恢复购买</div> | ||
| 100 | + </div> | ||
| 101 | + </div> | ||
| 102 | +</div> | ||
| 103 | +<hr> | ||
| 104 | +<button type="button" class="btn btn-primary sync"><i class="feather icon-repeat"></i> 同步基本设置</button> | ||
| 105 | +<script> | ||
| 106 | + Dcat.ready(function () { | ||
| 107 | + var asset = "{{asset('/storage/')}}"; | ||
| 108 | + | ||
| 109 | + $(document).off('click', '.sync').on('click', '.sync', function () { | ||
| 110 | + let ori_top = 80; | ||
| 111 | + let top = parseInt($('.field_top').val()) + ori_top; | ||
| 112 | + let left = $('.field_left').val(); | ||
| 113 | + let font = $('.field_font_size').val(); | ||
| 114 | + let content_size = 12 + parseInt(font); | ||
| 115 | + let title_size = 14 + parseInt(font); | ||
| 116 | + let text_color = $('.text_color').val() || 'whitesmoke'; | ||
| 117 | + let text_bg_color = $('.text_bg_color').val() || '#5c6bc6'; | ||
| 118 | + let opacity = parseInt($('.opacity').val()) / 100; | ||
| 119 | + | ||
| 120 | + $('.poem-block').css('top', top + 'px').css('left', left + 'px') | ||
| 121 | + .css('background-color', text_bg_color).css('opacity', opacity); | ||
| 122 | + $('.poem-title').css('font-size', title_size + 'px').css('color', text_color); | ||
| 123 | + $('.poem-content').css('font-size', content_size + 'px').css('color', text_color); | ||
| 124 | + | ||
| 125 | + | ||
| 126 | + let bg_img_url = $('.bg_img_url').find("input[type='hidden'][name='bg_url']").val(); | ||
| 127 | + if (bg_img_url !== '') { | ||
| 128 | + $('.bg_img').attr('src', asset + '/' + bg_img_url).css('display', 'block'); | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + let bg_video_url = $('.bg_video_url').find("input[type='hidden'][name='bg_url']").val(); | ||
| 132 | + if (bg_video_url !== ''){ | ||
| 133 | + $('#bg_video').attr('src', asset + '/' + bg_video_url).css('display', 'block'); | ||
| 134 | + let bg_video = document.getElementById('bg_video'); | ||
| 135 | + bg_video.autoplay = true; | ||
| 136 | + bg_video.loop = true; | ||
| 137 | + } | ||
| 138 | + | ||
| 139 | + let bgm_url = $('.bgm_url').find("input[type='hidden'][name='bgm_url']").val(); | ||
| 140 | + if (bgm_url !== ''){ | ||
| 141 | + $('#bg_audio').attr('src', asset + '/' + bgm_url); | ||
| 142 | + let bg_audio = document.getElementById('bg_audio'); | ||
| 143 | + bg_audio.autoplay = true; | ||
| 144 | + bg_audio.loop = true; | ||
| 145 | + } | ||
| 146 | + }) | ||
| 147 | + | ||
| 148 | + }) | ||
| 149 | +</script> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
resources/views/admin/grid/gallery.blade.php
0 → 100644
| 1 | +<style> | ||
| 2 | + .dengje-gallery-group { | ||
| 3 | + height: {{ $height }}px; | ||
| 4 | + width: {{ $width }}px; | ||
| 5 | + font-size: {{ $width / 12 }}; | ||
| 6 | + } | ||
| 7 | +</style> | ||
| 8 | + | ||
| 9 | +<div id="{{ $id }}" class="dengje-gallery-group {{ count($src) > 1 ? 'multiple' : '' }}"> | ||
| 10 | + <div class="gallery-img-wrapper bg-multi bg-left"></div> | ||
| 11 | + <div class="gallery-img-wrapper bg-multi bg-right"></div> | ||
| 12 | + <div class="gallery-img-wrapper"> | ||
| 13 | + @foreach ($src as $k => $v) | ||
| 14 | + <img src="{{ $v }}" class="{{ $k >= 1 ? 'hide' : '' }}" alt=""> | ||
| 15 | + @endforeach | ||
| 16 | + </div> | ||
| 17 | +</div> | ||
| 18 | + | ||
| 19 | +<script > | ||
| 20 | + var image = new Viewer(document.getElementById('{{ $id }}')); | ||
| 21 | +</script> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| ... | @@ -35,4 +35,10 @@ Route::prefix('v1')->namespace('App\Http\Controllers\V1')->group(function (Route | ... | @@ -35,4 +35,10 @@ Route::prefix('v1')->namespace('App\Http\Controllers\V1')->group(function (Route |
| 35 | 35 | ||
| 36 | /** 创建订单 */ | 36 | /** 创建订单 */ |
| 37 | $api->apiResource('/order', 'OrderController'); | 37 | $api->apiResource('/order', 'OrderController'); |
| 38 | + | ||
| 39 | + /** 调起支付 */ | ||
| 40 | + $api->apiResource('/pay', 'PayController'); | ||
| 41 | + | ||
| 42 | + /** 会员页 */ | ||
| 43 | + $api->apiResource('/membership', 'MembershipController'); | ||
| 38 | }); | 44 | }); |
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
| ... | @@ -16,3 +16,22 @@ use Illuminate\Support\Facades\Route; | ... | @@ -16,3 +16,22 @@ use Illuminate\Support\Facades\Route; |
| 16 | Route::get('/', function () { | 16 | Route::get('/', function () { |
| 17 | return view('welcome'); | 17 | return view('welcome'); |
| 18 | }); | 18 | }); |
| 19 | + | ||
| 20 | + | ||
| 21 | +Route::get('/create_overlay', function () { | ||
| 22 | + header ('Content-Type: image/png'); | ||
| 23 | + $im = @imagecreatetruecolor(640, 1008) or die('Cannot Initialize new GD image stream'); | ||
| 24 | + $white = imagecolorallocate($im, 255, 255, 255); //创建颜色 | ||
| 25 | + imagefill($im,0,0,$white); //自定义画布的背景颜色 | ||
| 26 | + $text_color = imagecolorallocate($im, 233, 14, 91); // 文字颜色 | ||
| 27 | + $font = storage_path('app/public/ffmpeg/arialuni.ttf'); | ||
| 28 | + $text = 'A Simple Text String'; | ||
| 29 | + $box = imagettfbbox(40,0,$font,$text); | ||
| 30 | + $x = (640 - ($box[2] - $box[0])) / 2; | ||
| 31 | + $y = (1008 - ($box[7] - $box[1])) / 2; | ||
| 32 | + imagettftext($im,40,0,$x,$y,$text_color,$font,$text); | ||
| 33 | + imagepng($im); | ||
| 34 | + imagedestroy($im); | ||
| 35 | + | ||
| 36 | + dd($im); | ||
| 37 | +}); | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
-
Please register or login to post a comment