李帅

1.会员模板页面完成。

2.订单还在构思。
......@@ -2,14 +2,18 @@
namespace App\Admin\Controllers;
use App\Admin\Renderable\MembershipGoodsEasyTable;
use App\Admin\Renderable\MembershipGoodsTable;
use App\Admin\Repositories\Membership;
use App\Models\Membership;
use App\Models\MembershipGood;
use Dcat\Admin\Form;
use Dcat\Admin\Grid;
use Dcat\Admin\Show;
use Dcat\Admin\Http\Controllers\AdminController;
use Dcat\Admin\Form\NestedForm;
use Illuminate\Support\Facades\DB;
use Dcat\Admin\Widgets\Table;
class MembershipController extends AdminController
{
......@@ -27,28 +31,27 @@ class MembershipController extends AdminController
$grid->setActionClass(Grid\Displayers\Actions::class);
$grid->column('id',__('ID'))->sortable();
$grid->column('name');
$grid->column('price');
$grid->column('line_price');
$grid->column('limited_days');
$grid->column('limit_unit');
$grid->column('title');
$grid->column('intro');
$grid->column('state');
$grid->column('sn');
$grid->column('expand','展开')
->display('会员商品')
->expand(function (){
$th = ['id','price','line_price','limit_days','limit_unit'];
$data = MembershipGood::query()->where('membership_id',$this->id)->get($th)->toArray();
return Table::make($th, $data);
});
$grid->column('video_url');
$grid->column('video_cover');
$grid->column('bg_images');
$grid->column('visits');
$grid->column('virtual_sales');
$grid->column('sales');
$grid->column('video_cover')->image('/storage/');
$grid->column('bg_images')->gallery('/storage/');
$grid->column('terminal')->using([1 => '安卓', 2 => 'iOS'], '未知');
$grid->column('state','线上展示')->switch();
$grid->column('created_at');
$grid->column('updated_at')->sortable();
$grid->filter(function (Grid\Filter $filter) {
$filter->equal('id');
$filter->equal('id')->width(2);
$filter->like('terminal')->width(3);
$filter->panel();
});
});
......@@ -94,16 +97,29 @@ class MembershipController extends AdminController
*/
protected function form()
{
$css = <<<CSS
.table tr td:first-child{
padding-left: 0 ;
}
.table tr td{
padding-left: 0 ;
}
.form-field .input-group .price{
width: 1% !important;
}
CSS;
\Admin::style($css);
return Form::make(new Membership(), function (Form $form) {
$form->display('id');
$form->block(12, function (Form\BlockForm $form) {
$form->block(8, function (Form\BlockForm $form) {
// 设置标题
$form->title('基本设置');
// 显示底部提交按钮
$form->showFooter();
// 设置字段宽度
$form->width(8, 2);
$form->width(9, 2);
$form->radio('terminal')->addElementClass('terminal')
->options([1 => 'Android', 2 => 'IOS'])->default(2);
......@@ -112,7 +128,7 @@ class MembershipController extends AdminController
$form->textarea('intro')->addElementClass('intro');
$form->radio('bg_type')->addElementClass('bg_type')
->options([1 => '单图', 2 => '轮播图', 3 => '视频'])->default(1)
->options([1 => '单图', 2 => '轮播图', 3 => '视频'])
->when([1,2],function (Form\BlockForm $form){
$form->multipleImage('bg_images')
->limit(5)
......@@ -129,36 +145,91 @@ class MembershipController extends AdminController
$form->image('video_cover')
->uniqueName()
->addElementClass('video_cover');
});
})->default(1);
$form->radio('state')->options(['不显示', '显示'])->default(0);
$form->radio('is_bind_old')->options(['新增会员商品', '选择已有商品'])->default(0)
$form->radio('is_bind_old')->options(['新增会员商品', '选择已有未上架的商品'])->default(0)
->when(0,function (Form\BlockForm $form){
$form->table('membership_goods','新赠会员商品', function (NestedForm $table) {
$table->currency('price')->symbol('¥')->addElementClass('price');
$table->currency('line_price')->symbol('¥')->addElementClass('line_price');
$form->table('new','新增', function (NestedForm $table) {
$table->text('price')->addElementClass('price');
$table->text('line_price')->addElementClass('line_price');
$table->text('limited_days')->addElementClass('limited_days');
$table->text('limit_unit')->addElementClass('limit_unit');
});
})
->when(1,function (Form\BlockForm $form){
$form->selectTable('membership_goods')
$form->multipleSelectTable('old','已有')
->title('会员商品')
->from(MembershipGoodsTable::make())
->model(MembershipGood::class, 'id', 'price');
});
});
// $form->block(4, function (Form\BlockForm $form) {
// $form->width(9, 1);
// $form->html(view('admin.form.phone'));
// });
$form->block(4, function (Form\BlockForm $form) {
$form->width(9, 1);
$form->html(view('admin.form.membership'));
});
$form->display('created_at');
$form->display('updated_at');
});
}
public function store()
{
$all = request()->all();
//
if (isset($all['upload_column'])) return $this->form()->store();
// 检测是否已经有该平台的数据
$membership = Membership::query()->where('terminal',$all['terminal'])->first();
if ($membership && $all['state'] == '1') return $this->form()->response()->error('状态为显示会覆盖线上的设置,请修改后重试');
try{
DB::transaction(function ()use ($all){
$membership = Membership::query()->create([
'title' => $all['title'],
'intro' => $all['intro'],
'bg_type' => $all['bg_type'],
'bg_images' => $all['bg_images'],
'video_url' => $all['video_url'] ?? '',
'video_cover' => $all['video_cover'] ?? '',
'terminal' => $all['terminal'],
'state' => $all['state'],
]);
if ($all['is_bind_old'] === '0'){
// 新增
foreach ($all['new'] as $item) {
if ($item['_remove_'] === '1') continue;
MembershipGood::query()->create([
'membership_id' => $membership->id,
'price' => $item['price'],
'line_price' => $item['line_price'],
'limited_days' => $item['limited_days'],
'limit_unit' => $item['limit_unit'] ?? '天',
'terminal' => $all['terminal'],
'state' => 1,
]);
}
}elseif ($all['is_bind_old'] === '1'){
$old_ids = explode(',',$all['old']);
$membership_goods = MembershipGood::query()->whereIn('id',$old_ids)->get();
foreach ($membership_goods as $membership_good){
$membership_good->membership_id = $membership->id;
$membership_good->state = 1;
$membership_good->save();
}
}
});
}catch (\Exception $exception){
return $this->form()->response()->error($exception->getMessage());
}
return $this->form()->response()->refresh()->success(trans('admin.save_succeeded'));
}
}
......
<?php
/**
* Created by PhpStorm.
* User: lishuai
* Date: 2022/2/11
* Time: 5:30 PM
*/
namespace App\Admin\Extensions;
use Dcat\Admin\Admin;
use Dcat\Admin\Grid\Displayers\AbstractDisplayer;
use Dcat\Admin\Support\Helper;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Facades\Storage;
class Gallery extends AbstractDisplayer
{
public function display($server = '', $width = 100, $height = 200)
{
Admin::js('@js/viewer.js');
Admin::css([
'@css/gallery.css',
'@css/viewer.css'
]);
$defaultArgs = [
'server' => $server,
'width' => $width,
'height' => $height,
];
['server' => $server, 'width' => $width, 'height' => $height] = $defaultArgs;
if ($this->value instanceof Arrayable) {
$this->value = $this->value->toArray();
}
$groupId = $this->grid->getTableId().'_'.$this->getKey().'_'.$this->column->getName().'_gallery_group';
$src = []; // 避免 $src 未定义
foreach (Helper::array($this->value) as $k => $v) {
if (url()->isValidUrl($v) || mb_strpos($v, 'data:image') === 0) {
$src[] = $v;
} elseif ($server) {
$src[] = rtrim($server, '/').'/'.ltrim($v, '/');
} else {
$src[] = Storage::disk(config('admin.upload.disk'))->url($v);
}
}
return Admin::view('admin.grid.gallery', ['src' => $src, 'width' => $width, 'height' => $height, 'id' => $groupId]);
}
}
<?php
/**
* Created by PhpStorm.
* User: lishuai
* Date: 2022/2/11
* Time: 5:30 PM
*/
namespace App\Admin\Extensions;
use Dcat\Admin\Admin;
use Dcat\Admin\Grid\Displayers\AbstractDisplayer;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Facades\Storage;
class Swiper extends AbstractDisplayer
{
public function display($server = '', $width = 200, $height = 200)
{
// todo
// if ($this->value instanceof Arrayable) {
// $this->value = $this->value->toArray();
// }
//
// return collect((array) $this->value)->filter()->map(function ($path) use ($server, $width, $height) {
// if (url()->isValidUrl($path) || mb_strpos($path, 'data:image') === 0) {
// $src = $path;
// } elseif ($server) {
// $src = rtrim($server, '/').'/'.ltrim($path, '/');
// } else {
// $src = Storage::disk(config('admin.upload.disk'))->url($path);
// }
//
// return "<img data-action='preview-img' src='$src' style='max-width:{$width}px;max-height:{$height}px;cursor:pointer' class='img img-thumbnail' />";
// })->implode('&nbsp;');
}
}
......@@ -17,6 +17,8 @@ class MembershipGoodsTable extends LazyRenderable
public function grid(): Grid
{
return Grid::make(new MembershipGood(), function (Grid $grid) {
$grid->model()->where('state',0);
$grid->column('id', 'ID')->sortable();
$grid->column('membership_id');
$grid->column('price');
......
<?php
namespace App\Admin\Repositories;
use App\Models\MembershipGood as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class MembershipGood extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}
<?php
namespace App\Admin\Repositories;
use App\Models\OrderGood as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class OrderGood extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}
<?php
namespace App\Admin\Repositories;
use App\Models\VideoTemp as Model;
use Dcat\Admin\Repositories\EloquentRepository;
class VideoTemp extends EloquentRepository
{
/**
* Model.
*
* @var string
*/
protected $eloquentClass = Model::class;
}
......@@ -5,6 +5,8 @@ use Dcat\Admin\Grid;
use Dcat\Admin\Form;
use Dcat\Admin\Grid\Filter;
use Dcat\Admin\Show;
use Dcat\Admin\Grid\Column;
use App\Admin\Extensions\Gallery;
/**
* Dcat-admin - admin builder based on Laravel.
......@@ -24,3 +26,7 @@ use Dcat\Admin\Show;
* Admin::js('/packages/prettydocs/js/main.js');
*
*/
Admin::asset()->alias('@js', '/asset/js');
Admin::asset()->alias('@css', '/asset/css');
Column::extend('gallery', Gallery::class); //grid列扩展 - 多图浏览
\ No newline at end of file
......
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff could not be displayed because it is too large.
......@@ -10,4 +10,21 @@ use Illuminate\Routing\Controller as BaseController;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function isAppleClient()
{
$ua = request()->header('user-agent');
if (strpos($ua, 'iPhone') || strpos($ua, 'iPad') || strpos($ua,'Mac OS X')) {
return true;
}
return false;
}
public function getClientTerminal()
{
$ua = request()->header('user-agent');
return 'ios';
}
}
......
<?php
namespace App\Http\Controllers\V1;
use App\Http\Controllers\Controller;
use App\Models\Membership;
use Illuminate\Http\Request;
use Jiannei\Response\Laravel\Support\Facades\Response;
class MembershipController extends Controller
{
/**
* Display a listing of the resource.
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function index(Request $request)
{
$membership = Membership::query()->where('state',1);
// 获取会员介绍页内容
if ($this->isAppleClient()){
$membership = $membership->where('terminal',2);
}else{
$membership = $membership->where('terminal',1);
}
$membership = $membership->first();
$membership->bg_images = $membership->getImage();
$membership->goods_list = $membership->getMembershipGoods()->get();
return Response::success($membership);
}
/**
* Show the form for creating a new resource.
*
* @return \Illuminate\Http\Response
*/
public function create()
{
//
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
......@@ -3,7 +3,13 @@
namespace App\Http\Controllers\V1;
use App\Http\Controllers\Controller;
use App\Models\MembershipGood;
use App\Models\Order;
use App\Models\OrderGood;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Jiannei\Response\Laravel\Support\Facades\Response;
......@@ -11,27 +17,104 @@ class OrderController extends Controller
{
public function index(Request $request)
{
$validator = Validator::make($request->all(),[
}
public function store(Request $request)
{
$data = $request->all();
$validator = Validator::make($data,[
'goods_id' => 'required|integer',
'source' => 'required|string',
]);
if ($validator->fails()){
return Response::fail('缺少参数',500,$validator->errors());
if ($validator->fails()) return Response::fail('缺少参数',500,$validator->errors());
$user_id = Auth::user()->getAuthIdentifier();
$order = $this->build($user_id, $data['goods_id'], $this->getClientTerminal());
return Response::success($order);
}
public function show($id)
{
}
public function store(Request $request)
/**
* 创建订单
* @param $user_id
* @param $member_id
* @param $source
* @param $number = 1
* @return string $order_sn
*/
public function build($user_id, $member_id, $source, $number = 1)
{
$validator = Validator::make($request->all(),[
'goods_id' => 'required|integer',
'source' => 'required|string',
]);
try{
return DB::transaction(function ()use ($user_id, $member_id, $source, $number){
// 获取商品信息
$membership_good = MembershipGood::query()->where('id',$member_id)->first();
$membership = $membership_good->membership()->first();
// 实付金额 = 商品金额
$pay_amount = $membership_good->price * $number;
// 创建订单
$order = new Order();
$order_sn = $order::get_sn('osn');
$order->order_sn = $order_sn;
$order->user_id = $user_id;
$order->pay_amount = $pay_amount;
$order->description = '一言会员' . $membership_good->limit_days . $membership_good->limit_unit;
$order->goods_amount = $membership_good->price;
$order->status = Order::UNPAID;
$order->source = $source;
if ($validator->fails()){
return Response::fail('',500,$validator->errors());
$order->save();
$order_good = new OrderGood();
$order_good->order_sn = $order_sn;
$order_good->goods_id = $member_id;
$order_good->goods_type = OrderGood::MemberShip;
$order_good->goods_name = $membership_good->limit_days . $membership_good->limit_unit;
$order_good->goods_image = $membership->getSingleImage();
$order_good->goods_price = $membership_good->price;
$order_good->goods_number = $number;
$order_good->save();
$order->goods = $order_good;
// todo 超时处理,建议给Job处理
// if ($pay_amount == 0) { //0元购就不执行回调了
// $this->freePay($order);
// }
return $order;
});
}catch (\Exception $exception){
return Response::fail('', 500, $exception->getMessage());
}
}
public function freePay($order)
{
$order = Order::query()->find($order->id);
if ($order->status < Order::PAID){
$order->status = Order::PAID;
$order->pay_type = '';
$order->pay_time = Carbon::now();
if ($order->save()){
// 执行一些本来属于回调的逻辑
return true;
}
}
return false;
}
}
......
<?php
namespace App\Http\Controllers\V1;
use App\Http\Controllers\Controller;
use App\Models\Order;
use App\Payment\PaymentFactory;
use Illuminate\Http\Request;
use Jiannei\Response\Laravel\Support\Facades\Response;
class PayController extends Controller
{
public function index(Request $request,PaymentFactory $factory)
{
$order_sn = $request->get('order_sn');
$pay_type = $request->get('pay_type');
$order = Order::query()->where('order_sn', $order_sn)->first();
if ($order->status !== Order::UNPAID) return false;
// if ($order->pay_amount <= 0) return $this->paid($order_sn); 0元购应该单独写一套
$payment = $factory->init($pay_type)->prepare($order);
return Response::success($payment);
}
/**
* Store a newly created resource in storage.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
//
}
/**
* Display the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function edit($id)
{
//
}
/**
* Update the specified resource in storage.
*
* @param \Illuminate\Http\Request $request
* @param int $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
......@@ -5,20 +5,33 @@ namespace App\Models;
use Dcat\Admin\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Storage;
class Membership extends Model
{
use HasDateTimeFormatter;
protected $table = 'membership';
public function getBgImagesAttribute($value)
protected $guarded = [''];
public function getImage()
{
return explode(',', $value);
return collect(explode(',', $this->bg_images))->map(function ($item){
return Storage::disk('public')->url($item);
});
}
public function getSingleImgAttribute()
public function getSingleImage()
{
$array = explode(',', $this->bg_images);
return $array[0];
return Storage::disk('public')->url($array[0]);
}
public function getMembershipGoods()
{
return $this->hasMany('App\Models\MembershipGood','membership_id');
}
}
......
......@@ -5,10 +5,25 @@ namespace App\Models;
use Dcat\Admin\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\Model;
use Spatie\EloquentSortable\Sortable;
use Spatie\EloquentSortable\SortableTrait;
class MembershipGood extends Model
class MembershipGood extends Model implements Sortable
{
use HasDateTimeFormatter;
protected $table = 'membership_goods';
protected $guarded = [''];
use SortableTrait;
public $sortable = [
'order_column_name' => 'sn',
'sort_when_creating' => true,
];
public function membership()
{
return $this->belongsTo(Membership::class);
}
}
......
......@@ -3,57 +3,36 @@
namespace App\Models;
use Dcat\Admin\Traits\HasDateTimeFormatter;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
class Order extends Model
{
use HasDateTimeFormatter;
use SoftDeletes;
protected $table = 'order';
public function order_goods()
{
return $this->hasOne('App\Models\OrderGood','order_sn');
}
/** 未支付*/
const UNPAID = 100;
/**
* 预创建订单
* @param $member_id
* @param $source
*/
public function build($member_id,$source)
{
// 获取商品信息
$membership = Membership::query()->where('id',$member_id)->first();
/** 用户取消*/
const USER_CANCEL = 101;
// 实付金额 = 商品金额
$pay_amount = $membership->price;
/** 超时取消*/
const TIMEOUT_CANCEL = 102;
// 创建订单
$order = new Order();
$order_sn = $this->get_sn('osn');
$order->order_sn = $order_sn;
$order->user_id = Auth::user()->getAuthIdentifier();
$order->pay_amount = $pay_amount;
$order->goods_amount = $membership->price;
$order->status = 100;
$order->source = $source;
/** 商户取消*/
const MERCHANT_CANCEL = 102;
$order->save();
/** 已支付*/ // 回调
const PAID = 201;
$order_good = new OrderGood();
$order_good->order_sn = $order_sn;
$order_good->goods_id = $member_id;
$order_good->goods_name = $membership->name;
$order_good->goods_image = $membership->getSingleImg();
$order_good->goods_price = $membership->price;
$order_good->goods_number = 1;
/** 已完成*/ // 回调并且业务逻辑(加天数、加销量)执行完毕
const DONE = 204;
$order_good->save();
public function order_goods()
{
return $this->hasOne('App\Models\OrderGood','order_sn');
}
/**
......@@ -61,7 +40,7 @@ class Order extends Model
* @param string $prefix
* @return string
*/
public function get_sn($prefix = '')
static public function get_sn($prefix = '')
{
$Sn = $prefix . strtoupper(dechex(date('m'))) . date('d') . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(0, 99));
return $Sn;
......
......@@ -11,4 +11,5 @@ class OrderGood extends Model
use HasDateTimeFormatter;
protected $table = 'order_goods';
const MemberShip = 1001;
}
......
<?php
/**
* Created by PhpStorm.
* User: lishuai
* Date: 2022/2/15
* Time: 4:23 PM
*/
namespace App\Payment;
class AliPayment implements PaymentInterface
{
public function prepare()
{
// TODO: Implement prepare() method.
}
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: lishuai
* Date: 2022/2/15
* Time: 4:25 PM
*/
namespace App\Payment;
class PaymentFactory
{
public function init($pay_type)
{
switch ($pay_type){
case 'alipay':
return new AliPayment();
case 'wechat':
return new WechatPayment();
default:
throw new \Exception('未知的支付方式');
}
}
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: lishuai
* Date: 2022/2/15
* Time: 4:00 PM
*/
namespace App\Payment;
use App\Models\Order;
interface PaymentInterface
{
/**
* @param $order
* @return array
*/
public function prepare(Order $order);
}
\ No newline at end of file
<?php
/**
* Created by PhpStorm.
* User: lishuai
* Date: 2022/2/15
* Time: 4:23 PM
*/
namespace App\Payment;
use App\Models\Order;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
class WechatPayment implements PaymentInterface
{
/** 支付接口基础地址 */
const MCH_BASE_URL = 'https://api.mch.weixin.qq.com';
/** APP支付*/
const APP_URL = '/v3/pay/transactions/app';
/** H5支付*/
const H5_URL = '/v3/pay/transactions/h5';
/** App的应用id */
public $appid;
/** 商户身份ID */
public $mchid;
/** 商品描述*/
public $description;
/** 商户订单号*/
public $out_trade_no;
/** 支付回调*/
public $notify_url;
/** 订单金额*/
public $amount;
/** 证书序列号*/
public $serial_no;
/** 商户API私钥*/
// todo 待添加 file:///path/to/merchant/apiclient_key.pem'
public $mch_private_key = '';
public function prepare(Order $order)
{
$body = [
'appid' => env('WECHAT_APPID'),
'mchid' => env('WECHAT_PAY_MCH_ID'),
'description' => $order->description,
'out_trade_no' => $order->order_sn,
'notify_url' => env('WECHAT_PAY_NOTIFY'),
'amount' => [
'total' => $order->pay_amount * 100,
'currency' => 'CNY'
],
];
$timestamp = time();//时间戳
$nonce = self::nonce(32);//随机串
$sign = $this->sign('POST', self::APP_URL, $timestamp, $nonce, json_encode($body));
//设置HTTP头
$token = sprintf('WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
env('WECHAT_PAY_MCH_ID'), $nonce, $timestamp, env('WECHAT_PAY_SERIAL_NO'), $sign);
$headers = [
'Accept' => 'application/json, text/plain, application/x-gzip, application/pdf, image/png, image/*;q=0.5',
'User-Agent' => '*/*',
'Content-Type' => 'application/json; charset=utf-8',
'Authorization' => $token,
];
$client = new Client([
'base_uri' => self::MCH_BASE_URL,
'timeout' => 0,
'allow_redirects' => false,
'headers' => $headers
]);
try {
$response = $client->request('POST', self::APP_URL, ['json' => $body]);
dd($prepayid = $response->getBody()->getContents());
} catch (GuzzleException $exception) {
dd($exception->getMessage());
}
return [
'appid' => env('WECHAT_APPID'),
'partnerid' => env('WECHAT_PAY_MCH_ID'),
'prepayid' => $prepayid,
'package' => 'Sign=WXPay',
'noncestr' => $nonce,
'timestamp' => $timestamp,
'sign' => $sign
];
}
public function notify()
{
}
/**
* @param string $http_method "GET"/"POST"
* @param string $url "/v3/certificates"
* @param string $timestamp
* @param string $nonce
* @param string $body "json_encode($body)"
* @return array
*/
public function sign($http_method, $url, $timestamp, $nonce, $body = '')
{
$mch_private_key = openssl_get_privatekey(file_get_contents($this->mch_private_key));//私钥
//构造签名串
$message = implode("\n", [$http_method, $url, $timestamp, $nonce, $body]);
//计算签名值
openssl_sign($message, $signature, $mch_private_key, OPENSSL_ALGO_SHA256);
return base64_encode($signature);
}
/**
* 生成32位随机字符串
* @param int $size - Nonce string length, default is 32.
* @return string - base62 random string.
* @throws
*/
public static function nonce(int $size = 32): string
{
if ($size < 1) {
throw new \InvalidArgumentException('Size must be a positive integer.');
}
return implode('', array_map(static function (string $c): string {
return '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'[ord($c) % 62];
}, str_split(random_bytes($size))));
}
}
......@@ -21,7 +21,6 @@ class CreateMembershipTable extends Migration
$table->unsignedTinyInteger('bg_type')->default(0)->comment('背景类型,1=单图,2=轮播图,3=视频');
$table->string('bg_images')->default('')->comment('介绍图');
$table->unsignedTinyInteger('is_video')->default(0)->comment('视频开关');
$table->string('video_url')->default('')->comment('视频地址');
$table->string('video_cover')->default('')->comment('视频封面');
......
......@@ -17,6 +17,7 @@ class CreateOrderTable extends Migration
$table->increments('id');
$table->string('order_sn')->index()->default('')->comment('订单号');
$table->unsignedBigInteger('user_id')->index()->comment('用户id');
$table->string('description')->default('')->comment('订单描述');
$table->decimal('pay_amount')->comment('实付金额');
$table->decimal('goods_amount')->comment('商品金额');
$table->unsignedSmallInteger('status')->comment('订单状态:100待付款 101用户取消 102超时取消 103商户取消 201已付款 204已完成');
......@@ -24,6 +25,7 @@ class CreateOrderTable extends Migration
$table->string('source')->comment('来源');
$table->string('pay_number')->default('')->comment('支付交易号');
$table->string('pay_type')->default('')->comment('支付类型');
$table->string('callback')->default('')->comment('回调参数');
$table->timestamp('pay_time')->nullable()->comment('支付时间');
$table->timestamps();
});
......
......@@ -17,6 +17,7 @@ class CreateOrderGoodsTable extends Migration
$table->increments('id');
$table->string('order_sn')->comment('订单编号');
$table->unsignedInteger('goods_id')->comment('商品id');
$table->unsignedInteger('goods_type')->comment('商品类型');
$table->string('goods_name')->default('')->comment('商品名称');
$table->string('goods_image')->default('')->comment('商品封面');
$table->decimal('goods_price')->default('0.00')->comment('商品价格');
......
......@@ -16,17 +16,17 @@ class CreateMembershipGoodsTable extends Migration
Schema::create('membership_goods', function (Blueprint $table) {
$table->increments('id');
$table->integer('membership_id')->comment('会员id');
$table->decimal('price')->comment('价格');
$table->decimal('line_price')->comment('划线价格');
$table->integer('limit_days')->comment('有效天数');
$table->decimal('price')->default('0.00')->comment('价格');
$table->decimal('line_price')->default('0.00')->comment('划线价格');
$table->integer('limit_days')->default(0)->comment('有效天数');
$table->string('limit_unit')->default('')->comment('有效期单位');
$table->unsignedTinyInteger('terminal')->comment('1=Android,2=IOS');
$table->unsignedTinyInteger('state')->comment('0=下架,1=售卖中');
$table->unsignedTinyInteger('sn')->comment('SN顺序');
$table->unsignedInteger('visits')->comment('访问量');
$table->unsignedInteger('virtual_sales')->comment('虚拟销售量');
$table->unsignedInteger('sales')->comment('销售量');
$table->unsignedInteger('stocks')->comment('库存数量');
$table->unsignedInteger('visits')->default(0)->comment('访问量');
$table->unsignedInteger('virtual_sales')->default(0)->comment('虚拟销售量');
$table->unsignedInteger('sales')->default(0)->comment('销售量');
$table->unsignedInteger('stocks')->default(0)->comment('库存数量');
$table->timestamps();
});
}
......
This diff is collapsed. Click to expand it.
.extension-demo {
font-size: 1.3rem;
cursor: pointer;
}
.dengje-gallery-group {
position: relative;
margin: 5%;
}
.dengje-gallery-group.multiple .gallery-img-wrapper.bg-left {
top: 5%;
left: -5%;
-webkit-transform: rotate(-5deg);
-moz-transform: rotate(-5deg);
-o-transform: rotate(-5deg);
-ms-transform: rotate(-5deg);
transform: rotate(-5deg);
}
.dengje-gallery-group.multiple .gallery-img-wrapper.bg-left:before {
content: "";
width: 100%;
height: 100%;
background: #eff4de;
display: block;
}
.dengje-gallery-group.multiple .gallery-img-wrapper.bg-right {
top: 5%;
left: 5%;
-webkit-transform: rotate(5deg);
-moz-transform: rotate(5deg);
-o-transform: rotate(5deg);
-ms-transform: rotate(5deg);
transform: rotate(5deg);
}
.dengje-gallery-group.multiple .gallery-img-wrapper.bg-right:before {
content: "";
width: 100%;
height: 100%;
background: #768590;
display: block;
}
.dengje-gallery-group .gallery-img-wrapper {
padding: 3%;
background: #fff;
height: 100%;
width: 100%;
z-index: 1;
display: flex;
justify-content: center;
align-items: center;
position: absolute;
-webkit-box-shadow: .2em .2em .5em rgb(0 0 0 / 30%);
-moz-box-shadow: .2em .2em .5em rgba(0, 0, 0, 0.3);
box-shadow: .2em .2em .5em rgb(0 0 0 / 30%);
}
.dengje-gallery-group .gallery-img-wrapper > img {
max-width: 100%;
max-height: 100%;
}
.dengje-gallery-group .bg-multi {
display: none;
}
.dengje-gallery-group.multiple .bg-multi {
display: block;
}
.hide {
display: none;
}
/*!
* Viewer.js v1.5.0
* https://fengyuanchen.github.io/viewerjs
*
* Copyright 2015-present Chen Fengyuan
* Released under the MIT license
*
* Date: 2019-11-23T05:10:21.757Z
*/
.viewer-zoom-in::before,
.viewer-zoom-out::before,
.viewer-one-to-one::before,
.viewer-reset::before,
.viewer-prev::before,
.viewer-play::before,
.viewer-next::before,
.viewer-rotate-left::before,
.viewer-rotate-right::before,
.viewer-flip-horizontal::before,
.viewer-flip-vertical::before,
.viewer-fullscreen::before,
.viewer-fullscreen-exit::before,
.viewer-close::before {
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');
background-repeat: no-repeat;
background-size: 280px;
color: transparent;
display: block;
font-size: 0;
height: 20px;
line-height: 0;
width: 20px;
}
.viewer-zoom-in::before {
background-position: 0 0;
content: 'Zoom In';
}
.viewer-zoom-out::before {
background-position: -20px 0;
content: 'Zoom Out';
}
.viewer-one-to-one::before {
background-position: -40px 0;
content: 'One to One';
}
.viewer-reset::before {
background-position: -60px 0;
content: 'Reset';
}
.viewer-prev::before {
background-position: -80px 0;
content: 'Previous';
}
.viewer-play::before {
background-position: -100px 0;
content: 'Play';
}
.viewer-next::before {
background-position: -120px 0;
content: 'Next';
}
.viewer-rotate-left::before {
background-position: -140px 0;
content: 'Rotate Left';
}
.viewer-rotate-right::before {
background-position: -160px 0;
content: 'Rotate Right';
}
.viewer-flip-horizontal::before {
background-position: -180px 0;
content: 'Flip Horizontal';
}
.viewer-flip-vertical::before {
background-position: -200px 0;
content: 'Flip Vertical';
}
.viewer-fullscreen::before {
background-position: -220px 0;
content: 'Enter Full Screen';
}
.viewer-fullscreen-exit::before {
background-position: -240px 0;
content: 'Exit Full Screen';
}
.viewer-close::before {
background-position: -260px 0;
content: 'Close';
}
.viewer-container {
bottom: 0;
direction: ltr;
font-size: 0;
left: 0;
line-height: 0;
overflow: hidden;
position: absolute;
right: 0;
-webkit-tap-highlight-color: transparent;
top: 0;
-ms-touch-action: none;
touch-action: none;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.viewer-container::-moz-selection,
.viewer-container *::-moz-selection {
background-color: transparent;
}
.viewer-container::selection,
.viewer-container *::selection {
background-color: transparent;
}
.viewer-container img {
display: block;
height: auto;
max-height: none !important;
max-width: none !important;
min-height: 0 !important;
min-width: 0 !important;
width: 100%;
}
.viewer-canvas {
bottom: 0;
left: 0;
overflow: hidden;
position: absolute;
right: 0;
top: 0;
}
.viewer-canvas > img {
height: auto;
margin: 15px auto;
max-width: 90% !important;
width: auto;
}
.viewer-footer {
bottom: 0;
left: 0;
overflow: hidden;
position: absolute;
right: 0;
text-align: center;
}
.viewer-navbar {
background-color: rgba(0, 0, 0, 0.5);
overflow: hidden;
}
.viewer-list {
-webkit-box-sizing: content-box;
box-sizing: content-box;
height: 50px;
margin: 0;
overflow: hidden;
padding: 1px 0;
}
.viewer-list > li {
color: transparent;
cursor: pointer;
float: left;
font-size: 0;
height: 50px;
line-height: 0;
opacity: 0.5;
overflow: hidden;
-webkit-transition: opacity 0.15s;
transition: opacity 0.15s;
width: 30px;
}
.viewer-list > li:hover {
opacity: 0.75;
}
.viewer-list > li + li {
margin-left: 1px;
}
.viewer-list > .viewer-loading {
position: relative;
}
.viewer-list > .viewer-loading::after {
border-width: 2px;
height: 20px;
margin-left: -10px;
margin-top: -10px;
width: 20px;
}
.viewer-list > .viewer-active,
.viewer-list > .viewer-active:hover {
opacity: 1;
}
.viewer-player {
background-color: #000;
bottom: 0;
cursor: none;
display: none;
left: 0;
position: absolute;
right: 0;
top: 0;
}
.viewer-player > img {
left: 0;
position: absolute;
top: 0;
}
.viewer-toolbar > ul {
display: inline-block;
margin: 0 auto 5px;
overflow: hidden;
padding: 3px 0;
}
.viewer-toolbar > ul > li {
background-color: rgba(0, 0, 0, 0.5);
border-radius: 50%;
cursor: pointer;
float: left;
height: 24px;
overflow: hidden;
-webkit-transition: background-color 0.15s;
transition: background-color 0.15s;
width: 24px;
}
.viewer-toolbar > ul > li:hover {
background-color: rgba(0, 0, 0, 0.8);
}
.viewer-toolbar > ul > li::before {
margin: 2px;
}
.viewer-toolbar > ul > li + li {
margin-left: 1px;
}
.viewer-toolbar > ul > .viewer-small {
height: 18px;
margin-bottom: 3px;
margin-top: 3px;
width: 18px;
}
.viewer-toolbar > ul > .viewer-small::before {
margin: -1px;
}
.viewer-toolbar > ul > .viewer-large {
height: 30px;
margin-bottom: -3px;
margin-top: -3px;
width: 30px;
}
.viewer-toolbar > ul > .viewer-large::before {
margin: 5px;
}
.viewer-tooltip {
background-color: rgba(0, 0, 0, 0.8);
border-radius: 10px;
color: #fff;
display: none;
font-size: 12px;
height: 20px;
left: 50%;
line-height: 20px;
margin-left: -25px;
margin-top: -10px;
position: absolute;
text-align: center;
top: 50%;
width: 50px;
}
.viewer-title {
color: #ccc;
display: inline-block;
font-size: 12px;
line-height: 1;
margin: 0 5% 5px;
max-width: 90%;
opacity: 0.8;
overflow: hidden;
text-overflow: ellipsis;
-webkit-transition: opacity 0.15s;
transition: opacity 0.15s;
white-space: nowrap;
}
.viewer-title:hover {
opacity: 1;
}
.viewer-button {
background-color: rgba(0, 0, 0, 0.5);
border-radius: 50%;
cursor: pointer;
height: 80px;
overflow: hidden;
position: absolute;
right: -40px;
top: -40px;
-webkit-transition: background-color 0.15s;
transition: background-color 0.15s;
width: 80px;
}
.viewer-button:focus,
.viewer-button:hover {
background-color: rgba(0, 0, 0, 0.8);
}
.viewer-button::before {
bottom: 15px;
left: 15px;
position: absolute;
}
.viewer-fixed {
position: fixed;
}
.viewer-open {
overflow: hidden;
}
.viewer-show {
display: block;
}
.viewer-hide {
display: none;
}
.viewer-backdrop {
background-color: rgba(0, 0, 0, 0.5);
}
.viewer-invisible {
visibility: hidden;
}
.viewer-move {
cursor: move;
cursor: -webkit-grab;
cursor: grab;
}
.viewer-fade {
opacity: 0;
}
.viewer-in {
opacity: 1;
}
.viewer-transition {
-webkit-transition: all 0.3s;
transition: all 0.3s;
}
@-webkit-keyframes viewer-spinner {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes viewer-spinner {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.viewer-loading::after {
-webkit-animation: viewer-spinner 1s linear infinite;
animation: viewer-spinner 1s linear infinite;
border: 4px solid rgba(255, 255, 255, 0.1);
border-left-color: rgba(255, 255, 255, 0.5);
border-radius: 50%;
content: '';
display: inline-block;
height: 40px;
left: 50%;
margin-left: -20px;
margin-top: -20px;
position: absolute;
top: 50%;
width: 40px;
z-index: 1;
}
@media (max-width: 767px) {
.viewer-hide-xs-down {
display: none;
}
}
@media (max-width: 991px) {
.viewer-hide-sm-down {
display: none;
}
}
@media (max-width: 1199px) {
.viewer-hide-md-down {
display: none;
}
}
This diff could not be displayed because it is too large.
......@@ -7,7 +7,6 @@ return [
'fields' => [
'name' => '会员名称',
'origin_price' => '原价(分)',
'limited_days' => '有效天数',
'intro' => '简介',
'state' => '状态',
'membership_id' => '会员id',
......
<style>
.box-card {
width: 380px;
border: 1px solid rgb(220, 223, 230);
border-radius: 40px;
margin-right: 24px;
padding: 37px 20px;
min-height: 779px;
}
.phone-content {
border: 1px solid rgb(220, 223, 230);
height: 705px;
overflow: hidden;
position: relative;
background: rgb(245, 245, 245);
}
.text {
font-size: 16px;
font-weight: 700;
color: rgb(38, 38, 38);
text-align: center;
position: absolute;
width: 100%;
top: 50px;
box-sizing: border-box;
}
.poem-block {
width: 315px;
height: 330px;
margin: 0;
padding: 0;
position: absolute;
text-align: center;
top: 200px;
left: 10px;
border-radius: 5px;
background: rgba(87, 78, 78, 0.6);
box-shadow: 2px 2px 4px 2px rgba(0, 0, 0, .3);
overflow: hidden;
display: flex;
flex-direction: column;
}
.poem-title {
color: #ffffff;
font-size: 14px;
font-weight: bold;
margin: 10px;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.intro-title {
color: #ffffff;
font-size: 14px;
font-weight: bold;
margin: 10px;
text-align: start;
}
.price{
display: flex;
flex-direction: row;
justify-content: flex-start;
}
</style>
<div class="box-card">
<div class="phone-content">
<div class="text">会员页</div>
<img src="{{asset('storage/image/mobile-head.png')}}" alt="" width="338" height="80">
<div style="min-height: 625px;">
<img width="338" height="625" class="bg_img" src="{{asset('storage/images/a5fe2ba2bd71b543cbf4c6fb3968ab64.png')}}">
</div>
<div class="poem-block">
<div class="intro-title">开发者249d42a097c1944e进行了广播推送,这是一条广播</div>
<div class="poem-title">
<div> 连续包月 </div>
<div class="price">
<span> 29 元 </span>
<span> / 月</span>
</div>
<button type="button" class="btn btn-primary">开通</button>
</div>
<div class="poem-title">
<div> 连续包年 </div>
<div class="price">
<span> 299 元 </span>
<span> / 月</span>
</div>
<button type="button" class="btn btn-primary">开通</button>
</div>
<div class="intro-title" style="min-height: 100px">开发者249d42a097c1944e进行了广播推送,这是一条广播</div>
<div class="intro-title" style="text-align: center">服务协议 | 隐私政策 | 恢复购买</div>
</div>
</div>
</div>
<hr>
<button type="button" class="btn btn-primary sync"><i class="feather icon-repeat"></i> 同步基本设置</button>
<script>
Dcat.ready(function () {
var asset = "{{asset('/storage/')}}";
$(document).off('click', '.sync').on('click', '.sync', function () {
let ori_top = 80;
let top = parseInt($('.field_top').val()) + ori_top;
let left = $('.field_left').val();
let font = $('.field_font_size').val();
let content_size = 12 + parseInt(font);
let title_size = 14 + parseInt(font);
let text_color = $('.text_color').val() || 'whitesmoke';
let text_bg_color = $('.text_bg_color').val() || '#5c6bc6';
let opacity = parseInt($('.opacity').val()) / 100;
$('.poem-block').css('top', top + 'px').css('left', left + 'px')
.css('background-color', text_bg_color).css('opacity', opacity);
$('.poem-title').css('font-size', title_size + 'px').css('color', text_color);
$('.poem-content').css('font-size', content_size + 'px').css('color', text_color);
let bg_img_url = $('.bg_img_url').find("input[type='hidden'][name='bg_url']").val();
if (bg_img_url !== '') {
$('.bg_img').attr('src', asset + '/' + bg_img_url).css('display', 'block');
}
let bg_video_url = $('.bg_video_url').find("input[type='hidden'][name='bg_url']").val();
if (bg_video_url !== ''){
$('#bg_video').attr('src', asset + '/' + bg_video_url).css('display', 'block');
let bg_video = document.getElementById('bg_video');
bg_video.autoplay = true;
bg_video.loop = true;
}
let bgm_url = $('.bgm_url').find("input[type='hidden'][name='bgm_url']").val();
if (bgm_url !== ''){
$('#bg_audio').attr('src', asset + '/' + bgm_url);
let bg_audio = document.getElementById('bg_audio');
bg_audio.autoplay = true;
bg_audio.loop = true;
}
})
})
</script>
\ No newline at end of file
<style>
.dengje-gallery-group {
height: {{ $height }}px;
width: {{ $width }}px;
font-size: {{ $width / 12 }};
}
</style>
<div id="{{ $id }}" class="dengje-gallery-group {{ count($src) > 1 ? 'multiple' : '' }}">
<div class="gallery-img-wrapper bg-multi bg-left"></div>
<div class="gallery-img-wrapper bg-multi bg-right"></div>
<div class="gallery-img-wrapper">
@foreach ($src as $k => $v)
<img src="{{ $v }}" class="{{ $k >= 1 ? 'hide' : '' }}" alt="">
@endforeach
</div>
</div>
<script >
var image = new Viewer(document.getElementById('{{ $id }}'));
</script>
\ No newline at end of file
......@@ -35,4 +35,10 @@ Route::prefix('v1')->namespace('App\Http\Controllers\V1')->group(function (Route
/** 创建订单 */
$api->apiResource('/order', 'OrderController');
/** 调起支付 */
$api->apiResource('/pay', 'PayController');
/** 会员页 */
$api->apiResource('/membership', 'MembershipController');
});
\ No newline at end of file
......
......@@ -16,3 +16,22 @@ use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Route::get('/create_overlay', function () {
header ('Content-Type: image/png');
$im = @imagecreatetruecolor(640, 1008) or die('Cannot Initialize new GD image stream');
$white = imagecolorallocate($im, 255, 255, 255); //创建颜色
imagefill($im,0,0,$white); //自定义画布的背景颜色
$text_color = imagecolorallocate($im, 233, 14, 91); // 文字颜色
$font = storage_path('app/public/ffmpeg/arialuni.ttf');
$text = 'A Simple Text String';
$box = imagettfbbox(40,0,$font,$text);
$x = (640 - ($box[2] - $box[0])) / 2;
$y = (1008 - ($box[7] - $box[1])) / 2;
imagettftext($im,40,0,$x,$y,$text_color,$font,$text);
imagepng($im);
imagedestroy($im);
dd($im);
});
\ No newline at end of file
......