<?php namespace app\api\controller; use addons\shopro\model\Config; use app\common\exception\UploadException; use app\common\library\Upload; use Qiniu\Auth; use Qiniu\Storage\ResumeUploader; use Qiniu\Storage\UploadManager; use think\Db; use think\Config as FaConfig; use fast\Random; use app\api\model\Banner; use addons\shopro\model\Category; /** * 首页接口 */ class Index extends Base { protected $noNeedLogin = ['*']; protected $noNeedRight = ['*']; /** * @ApiWeigh (99) * @ApiTitle (首页) * @ApiSummary (首页) * @ApiMethod (GET) * * @ApiHeaders (name=token, type=string, required=false, description="请求的token") * * @ApiReturn({ "code": 1, "msg": "首页", "time": "1608036399", "data": { "banner_list": [{ //轮播图 "id": 3, //轮播图ID "image": "http://www.ant.top/uploads/20201214/b655ea4dc4779222ab7a4e2b95feb3a4.png" //图片地址 "type" : '1', //跳转类型:1=无跳转,2=商品,3=开通会员 "goods_id" : 1, //商品ID }], "category_list": [{ //一级分类 "id": 1, //分类ID "name": "商品分类", //分类名称 "image": "http://www.ant.top/uploads/20201221/559d2a240ec20b096590a902217009ff.png", //分类图片 }], "seckill_list": { "type": "ing", // 类型:ing=进行中,nostart=即将开始,tomorrow=明日预告 "current_endtime": { //距离本场结束 "hour": 10, "minute": 12, "second": 19 }, "soon_starttime": { //即将开始时间 "hour": 14, "minute": 00 }, "goodsList": [{ "id": 1, //商品ID "type": "normal", "title": "测试商品", //标题 "subtitle": "测试啊", //副标题 "weigh": 0, "category_ids": "3", //所属分类ID "image": "http://www.ant.top/assets/img/qrcode.png", //商品主图 "price": "0.01", //商品价格 "original_price": "10000.00", //原价 "is_sku": 0, "likes": 0, "views": 3, "sales": 0, //销量 "show_sales": 0, //显示销量 "dispatch_type": "express", "dispatch_ids": "1", "deletetime": null, "activity": { "id": 7, "title": "秒杀测试", "type": "seckill", "richtext_id": 0, "richtext_title": "", "starttime": 1607616000, "endtime": 1607702400, "rules": { "limit_buy": "1", "order_auto_close": "", "activity_auto_close": "" } }, "activity_type": "seckill", "sku_price": [{ "id": 1, "goods_sku_ids": null, "goods_id": 1, "weigh": 0, "image": null, "stock": 20, "sales": 0, "sn": "", "weight": 0, "price": "0.01", "goods_sku_text": null, "status": "up", "activity_type": "seckill", "activity_id": 7, "item_goods_sku_price": { "id": 4, "activity_id": 7, "sku_price_id": 1, "goods_id": 1, "stock": 20, "sales": 0, "price": "0.01", "status": "up" }, "goods_sku_id_arr": [ "" ] }], "stock": 20, "dispatch_type_arr": [ "express" ] }] }, "groupon_list": { "type": "ing", // 类型:ing=进行中,nostart=即将开始,tomorrow=明日预告 "current_endtime": { "hour": 10, "minute": 12, "second": 19 }, "soon_starttime": { //即将开始时间 "hour": 14, "minute": 00 }, "goodsList":[{ "id": 2, //商品ID "type": "normal", "title": "测试商品2", //商品标题 "subtitle": "测试啊啊", //商品副标题 "weigh": 0, "category_ids": "3", "image": "http://www.ant.top/uploads/20201211/8894d62100f2f920ffb2f38063b63f2d.jpg", //商品主图 "price": "0.02", //现价 "original_price": "1000.00", //原价 "is_sku": 0, //是否多规格:0=否,1=是 "likes": 0, "views": 1, "sales": 0, "show_sales": 0, //显示销量 "dispatch_type": "express", "dispatch_ids": "1", "deletetime": null, "activity": { "id": 9, //活动ID "title": "拼团测试", //活动标题 "type": "groupon", //活动类型:seckill=秒杀,groupon=拼团 "richtext_id": 0, "richtext_title": "", "starttime": 1607616000, "endtime": 1607702400, "rules": { //活动规则 "limit_buy": "1", //每人限购件数 "order_auto_close": "", "activity_auto_close": "", "team_num": "2", //成团人数 "is_alone": "0", //是否允许单独购买 "is_fictitious": "0", "fictitious_num": "", "valid_time": "", "team_card": "0" } }, "activity_type": "groupon", "groupon_price": "0.01", "sku_price": [{ "id": 2, "goods_sku_ids": null, "goods_id": 2, "weigh": 0, "image": null, "stock": 10, "sales": 0, "sn": "", "weight": 0, "price": "0.02", "goods_sku_text": null, "status": "up", "groupon_price": "0.01", "activity_type": "groupon", "activity_id": 9, "item_goods_sku_price": { "id": 5, "activity_id": 9, "sku_price_id": 2, "goods_id": 2, "stock": 10, "sales": 0, "price": "0.01", "status": "up" }, "goods_sku_id_arr": [ "" ] }], "stock": 10, "dispatch_type_arr": [ "express" ] }] } } }) */ public function index() { $banner_list = Banner::field('id,image,type,goods_id')->select(); $category_list = Category::where('pid',1)->field('id,name,image')->limit(9)->select(); $seckill_list = \addons\shopro\model\Goods::indexActivityGoodsList('seckill'); $groupon_list = \addons\shopro\model\Goods::indexActivityGoodsList('groupon'); $this->success('首页', compact('banner_list','category_list','seckill_list','groupon_list')); } /** * @ApiWeigh (97) * @ApiTitle (分享标题和图片) * @ApiSummary (分享标题和图片) * @ApiMethod (GET) * * @ApiReturn({ "code": 1, "msg": "首页", "time": "1610097015", "data": { "title": "邀请有好礼", //分享标题 "image": "http://api.7wpp.com/uploads/20200414/4be7c944935a0fd6fc890f0214e6c3e0.jpg" //分享图片 } }) */ public function share() { $share = json_decode(Config::where(['name' => 'share'])->value('value'), true); $this->success('首页', [ 'title' => $share['title'], 'image' => isset($share['image']) ? cdnurl($share['image'], true) : '', ]); } /** * @ApiInternal * 初始化商城数据 */ public function init() { $params = $this->request->get(); $platform = $this->request->header('platform'); $config = new \addons\shopro\model\Config; $platformConfig = json_decode($config->where(['name' => $platform])->value('value'), true); $paymentConfig = $config->where('group', 'payment')->select(); $payment = []; foreach ($paymentConfig as $key => $config) { $val = json_decode($config->value, true); if ($val && in_array($platform, $val['platform'])) { $payment[] = $config->name; } } $data['payment'] = $payment; // 平台支持的支付方式 $shopro = json_decode(Config::where(['name' => 'shopro'])->value('value'), true); $data['info'] = $shopro; $data['info']['logo'] = cdnurl($data['info']['logo'], true); $autologin = false; if (isset($platformConfig['auto_login']) && $platformConfig['auto_login'] == 1) { $autologin = true; } $data['wechat'] = [ 'appid' => isset($platformConfig['app_id']) ? $platformConfig['app_id'] : '', 'autologin' => $autologin, ]; $share = json_decode(Config::where(['name' => 'share'])->value('value'), true); $data['share'] = [ 'title' => $share['title'], 'image' => isset($share['image']) ? cdnurl($share['image'], true) : '', 'goods_poster_bg' => isset($share['goods_poster_bg']) ? cdnurl($share['goods_poster_bg'], true) : '', 'user_poster_bg' => isset($share['user_poster_bg']) ? cdnurl($share['user_poster_bg'], true) : '', 'groupon_poster_bg' => isset($share['groupon_poster_bg']) ? cdnurl($share['groupon_poster_bg'], true) : '', ]; $data['addons'] = array_keys(get_addon_list()); $this->success('初始化数据', $data); } /** * @ApiInternal * 商城模板数据 */ public function template() { $get = $this->request->get(); $platform = $this->request->header('platform'); if (isset($get['shop_id'])) { $template = \addons\shopro\model\Decorate::getCurrentPlatformDecorate('preview', $get['shop_id']); } else { $template = \addons\shopro\model\Decorate::getCurrentPlatformDecorate($platform); } $this->success('模板数据', $template); } /** * @ApiInternal * 自定义页面 */ public function custom() { $get = $this->request->get(); $decorate = \addons\shopro\model\Decorate::get($get['id']); if (!$decorate) { $this->error('未找到自定义页面'); } $decorate->template = \addons\shopro\model\Decorate::getCustomDecorate($get['id']); $this->success('自定义模板数据', $decorate); } /** * @ApiInternal * 富文本详情 */ public function richtext() { $id = $this->request->get('id'); $data = \addons\shopro\model\Richtext::get(['id' => $id]); $this->success($data->title, $data); } /** * @ApiInternal * 同步前端所有页面链接 */ public function asyncLink() { $post = $this->request->post(); $newLink = $post['data']; $existLink = Db::name('shopro_link')->select(); $newLinkPath = array_column($newLink, 'path'); $existLinkPath = array_flip(array_column($existLink, 'path')); $insertData = []; $count = 1; foreach ($newLinkPath as $key => $item) { if (!isset($existLinkPath[$item]) && isset($newLink[$key]['meta']['async']) && $newLink[$key]['meta']['async']) { $insertData[] = [ 'name' => isset($newLink[$key]['meta']['title']) ? $newLink[$key]['meta']['title'] : '新链接' . $count, 'path' => $item, 'group' => isset($newLink[$key]['meta']['group']) ? $newLink[$key]['meta']['group'] : '其它', 'createtime' => time(), 'updatetime' => time() ]; $count++; } } if ($insertData !== []) { Db::name('shopro_link')->insertAll($insertData); } } /** * @ApiInternal * 前端获取轮播图平均色 * 1.0.7以后此接口作废 */ public function asyncBannerBgColor() { $params = $this->request->post(); $platform = $this->request->header('platform'); $data['template'] = \addons\shopro\model\Decorate::asyncBannerBgColor($platform, $params); } /** * @ApiInternal * 店铺装修 截图商城首页 */ public function asyncDecorateScreenShot() { $params = $this->request->post(); \addons\shopro\model\Decorate::asyncDecorateScreenShot($params); } /** * 中转上传文件 * 上传分片 * 合并分片 * @ApiMethod (POST) * @param File $file 文件流 */ public function upload() { FaConfig::set('default_return_type', 'json'); // $this->check(); $config = get_addon_config('qiniu'); $config['savekey'] = str_replace(['{year}', '{mon}', '{day}', '{filemd5}', '{.suffix}'], ['$(year)', '$(mon)', '$(day)', '$(etag)', '$(ext)'], $config['savekey']); // 构建鉴权对象 $auth = new Auth($config['accessKey'], $config['secretKey']); // 生成上传 Token $token = $auth->uploadToken($config['bucket'], null, 3600, ['saveKey' => ltrim($config['savekey'], '/')]); // 初始化 UploadManager 对象并进行文件的上传。 $uploadMgr = new UploadManager(); $chunkid = $this->request->post("chunkid"); if ($chunkid) { $action = $this->request->post("action"); $chunkindex = $this->request->post("chunkindex/d"); $chunkcount = $this->request->post("chunkcount/d"); $filesize = $this->request->post("filesize"); $filename = $this->request->post("filename"); if ($action == 'merge') { if ($config['uploadmode'] == 'server') { $attachment = null; //合并分片文件 try { $upload = new Upload(); $attachment = $upload->merge($chunkid, $chunkcount, $filename); } catch (UploadException $e) { $this->error($e->getMessage()); } } $contexts = $this->request->post("contexts/a", []); $uploader = new ResumeUploader($token, null, null, $filesize); list($ret, $err) = $uploader->setContexts($contexts)->makeFile($filename); if ($err !== null) { $this->error("上传失败"); } else { $this->success("上传成功", '', ['url' => '/' . $ret['key'], 'fullurl' => cdnurl('/' . $ret['key'], true), 'hash' => $ret['hash']]); } } else { //默认普通上传文件 $file = $this->request->file('file'); try { $upload = new Upload($file); $file = $upload->chunk($chunkid, $chunkindex, $chunkcount); } catch (UploadException $e) { $this->error($e->getMessage()); } //上传分片文件 //$file = $this->request->file('file'); $filesize = $file->getSize(); //合并分片文件 $uploader = new ResumeUploader($token, null, fopen($file->getRealPath(), 'rb'), $filesize); $ret = $uploader->uploadChunk($chunkindex, $file, $filesize); $this->success("上传成功", "", $ret); } } else { $attachment = null; //默认普通上传文件 $file = $this->request->file('file'); try { $upload = new Upload($file); $suffix = $upload->getSuffix(); $md5 = md5_file($file->getRealPath()); $search = ['$(year)', '$(mon)', '$(day)', '$(etag)', '$(ext)']; $replace = [date("Y"), date("m"), date("d"), $md5, '.' . $suffix]; $savekey = ltrim(str_replace($search, $replace, $config['savekey']), '/'); $attachment = $upload->upload($savekey); } catch (UploadException $e) { $this->error($e->getMessage()); } //文件绝对路径 $filePath = $upload->getFile()->getRealPath() ?: $upload->getFile()->getPathname(); //上传到七牛后保存的文件名 $saveKey = ltrim($attachment->url, '/'); try { // 调用 UploadManager 的 putFile 方法进行文件的上传。 list($ret, $err) = $uploadMgr->putFile($token, $saveKey, $filePath); if ($err !== null) { throw new \Exception("上传失败"); } //成功不做任何操作 } catch (\Exception $e) { $attachment->delete(); @unlink($filePath); $this->error("上传失败"); } $this->success("上传成功", ['url' => $attachment->url, 'fullurl' => cdnurl($attachment->url, true)]); } } /** * 上传 base64 图片 * @ApiMethod (POST) * @param base64 内容 */ public function uploadBase64() { $content = $this->request->post('content', ''); if (empty($content) || !preg_match('/^(data:\s*image\/(\w+);base64,)/', $content, $matches)) { $this->error(__('No file upload or server upload limit exceeded')); } $upload = FaConfig::get('upload'); $suffix = $matches[2]; //图片后缀 $mimetypeArr = explode(',', strtolower($upload['mimetype'])); // 判断是否允许的后缀 if ($upload['mimetype'] !== '*' && !in_array($suffix, $mimetypeArr)) { $this->error(__('Uploaded file format is limited')); } $replaceArr = [ '{year}' => date("Y"), '{mon}' => date("m"), '{day}' => date("d"), '{hour}' => date("H"), '{min}' => date("i"), '{sec}' => date("s"), '{random}' => Random::alnum(16), '{random32}' => Random::alnum(32), '{filename}' => "店铺装修截图", '{suffix}' => $suffix, '{.suffix}' => $suffix ? '.' . $suffix : '', '{filemd5}' => md5($content), ]; $savekey = $upload['savekey']; $savekey = str_replace(array_keys($replaceArr), array_values($replaceArr), $savekey); $uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1); $fileName = substr($savekey, strripos($savekey, '/') + 1); $fullDir = ROOT_PATH . '/public' . $uploadDir; $uploadPath = $uploadDir . $fileName; $fullPath = $fullDir . $fileName; if (!is_dir($fullDir)) { mkdir($fullDir, 0777, true); } $imageContent = base64_decode(str_replace($matches[1], '', $content)); if (file_put_contents($fullPath, $imageContent)) { $imgInfo = getimagesize($fullPath); $imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : 0; $imageheight = isset($imgInfo[1]) ? $imgInfo[1] : 0; $params = array( 'admin_id' => 0, 'user_id' => (int) $this->auth->id, 'filesize' => strlen($content), 'imagewidth' => $imagewidth, 'imageheight' => $imageheight, 'imagetype' => $suffix, 'imageframes' => 0, 'mimetype' => isset($imgInfo['mime']) ? $imgInfo['mime'] : 'image/' . $suffix, 'url' => $uploadPath, 'uploadtime' => time(), 'storage' => 'local', 'sha1' => hash_file('sha1', $fullPath), ); $attachment = new \app\common\model\Attachment; $attachment->data(array_filter($params)); $attachment->save(); \think\Hook::listen("upload_after", $attachment); $this->success(__('Upload successful'), [ 'url' => $uploadPath, 'full_url' => request()->domain() . $uploadPath ]); } else { $this->error("文件上传失败"); } } /** * @ApiInternal * 写调试日志 */ public function debugLog() { $params = $this->request->post(); \think\Log::write($params, 'notice'); } }