Secondary.php 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930
  1. <?php
  2. namespace app\api\controller;
  3. use Alipay\EasySDK\Kernel\Util\ResponseChecker;
  4. use app\common\library\AliPay;
  5. use app\common\library\Shande;
  6. use app\common\library\ShandeRapid;
  7. use EasyWeChat\Factory;
  8. use think\cache\driver\Redis;
  9. use think\Db;
  10. use think\Exception;
  11. use function EasyWeChat\Kernel\Support\get_client_ip;
  12. use function Symfony\Component\String\length;
  13. /**
  14. * @title 二级市场
  15. * @controller secondary
  16. * @package app\api\controller
  17. */
  18. class Secondary extends Base
  19. {
  20. public function initialize(){
  21. parent::initialize();
  22. parent::check_login();
  23. }
  24. /**
  25. * @title 藏品出售
  26. * @desc 藏品出售
  27. * @author Gavin
  28. * @url /api/Secondary/sell
  29. * @method POST
  30. * @header name:Authorization require:1 desc:Token
  31. *
  32. * @param name:id type:int require:1 default:1 desc:藏品ID
  33. * @param name:resale_price type:decimal require:1 default:1 desc:出售价格
  34. * @param name:second_password type:int require:1 default:-- desc:支付密码
  35. *
  36. */
  37. public function sell(){
  38. $this->checkSwitch(1);
  39. $id = input('id');
  40. //$this->error('暂时关闭');
  41. $user = getMemberInfoHash($this->uid); //获取用户信息
  42. if ($user['is_auth']==0) $this->error('请先实名认证!');
  43. $resale_price = input('resale_price');
  44. $second_password = input('second_password');
  45. if (!$id || !$resale_price) $this->error('参数错误');
  46. //if ($resale_price<'1') $this->error('最低1元');
  47. if ($resale_price<'0.1') $this->error('最低0.1元');
  48. if ($resale_price>'99999') $this->error('最高99999元');
  49. $info = Db::name('store_order_info')
  50. ->where('mid',$this->uid)
  51. ->where('id',$id)
  52. ->find();
  53. if (!$info || $info['status']==2) $this->error('藏品不存在');
  54. if ($info['resale_status']!=1) $this->error('挂售状态错误');
  55. if ($user['second_password']!=md5($second_password)) $this->error('密码错误');
  56. $update_data = [
  57. 'resale_status'=>2,
  58. 'resale_time'=>date('Y-m-d H:i:s'),
  59. 'resale_price'=>$resale_price
  60. ];
  61. if (Db::name('store_order_info')->where('id',$id)->update($update_data)){
  62. $this->success('成功');
  63. }
  64. $this->error('失败');
  65. }
  66. /**
  67. * @title 藏品取消出售
  68. * @desc 藏品取消出售
  69. * @author Gavin
  70. * @url /api/Secondary/cancel_sell
  71. * @method POST
  72. * @header name:Authorization require:1 desc:Token
  73. *
  74. * @param name:id type:int require:1 default:1 desc:藏品ID
  75. */
  76. public function cancel_sell(){
  77. $this->checkSwitch(1);
  78. $id = input('id');
  79. if (!$id) $this->error('参数错误');
  80. $info = Db::name('store_order_info')
  81. ->where('mid',$this->uid)
  82. ->where('id',$id)
  83. ->find();
  84. if (!$info || $info['status']==2) $this->error('藏品不存在');
  85. if ($info['resale_status']!=2) $this->error('挂售状态错误');
  86. //判断是否有待支付订单
  87. $count = Db::name('store_order_info_order')->where('info_id',$id)->where('status',0)->count();
  88. if ($count) $this->error('支付中,无法取消');
  89. $update_data = [
  90. 'resale_status'=>1,
  91. ];
  92. if (Db::name('store_order_info')->where('id',$id)->update($update_data)){
  93. $this->success('成功');
  94. }
  95. $this->error('失败');
  96. }
  97. /**
  98. * @title 标签列表
  99. * @desc 标签列表
  100. * @author Gavin
  101. * @url /api/Secondary/label_list
  102. * @method POST
  103. * @header name:Authorization require:1 desc:Token
  104. */
  105. public function label_list(){
  106. $list = Db::name('store_collection')->whereNotIn('label','测试,测试勿拍')->group('label')->column('label');
  107. $list = array_merge(['全部'],$list);
  108. $this->success('成功',['label_list'=>$list]);
  109. }
  110. /**
  111. * @title 二级市场列表
  112. * @desc 二级市场列表
  113. * @author Gavin
  114. * @url /api/Secondary/sell_list
  115. * @method POST
  116. * @header name:Authorization require:1 desc:Token
  117. * @param name:page type:int : default:1 desc:页数
  118. * @param name:page_num type:int : default:20 desc:每页数
  119. *
  120. * @param name:keyword type:string require:0 default: desc:关键词
  121. * @param name:label type:string require:0 default: desc:标签
  122. * @param name:type type:int require:0 default: desc:0全部1普通藏品3盲盒
  123. * @param name:time_order type:string require:0 default: desc:时间排序(asc:正序desc:倒序)
  124. * @param name:price_order type:string require:0 default: desc:价格排序(asc:正序desc:倒序)
  125. *
  126. * @return name:name type:string require:0 default:0 desc:藏品名称
  127. * @return name:cover type:string require:0 default:0 desc:图片
  128. * @return name:member_name type:string require:0 default:0 desc:出售人名称
  129. * @return name:member_headimg type:string require:0 default:0 desc:出售人头像
  130. * @return name:resale_price type:string require:0 default:0 desc:出售价格
  131. */
  132. public function sell_list(){
  133. $keyword = input('keyword');
  134. $label = input('label');
  135. $time_order = input('time_order');
  136. $price_order = input('price_order');
  137. $type = input('type',0);
  138. $count = Db::name('store_order_info')
  139. ->where('status','neq',2)
  140. ->where('resale_status',2)
  141. ->where('is_destruction',1)
  142. ->when($keyword,function ($query) use ($keyword){
  143. $query->whereLike('name','%'.$keyword.'%');
  144. })
  145. ->when($label,function ($query) use ($label){
  146. if ($label!='全部'){
  147. $ids = Db::name('store_collection')->where('label',$label)->column('id');
  148. $query->whereIn('c_id',$ids);
  149. }
  150. })->when($type,function ($query)use ($type){
  151. if($type > 0) $query->where('type',$type);
  152. })->count();
  153. $list = Db::name('store_order_info')
  154. ->where('status','neq',2)
  155. ->where('resale_status',2)
  156. ->where('is_destruction',1)
  157. ->when($keyword,function ($query) use ($keyword){
  158. $query->whereLike('name','%'.$keyword.'%');
  159. })
  160. ->when($label,function ($query) use ($label){
  161. if ($label!='全部'){
  162. $ids = Db::name('store_collection')->where('label',$label)->column('id');
  163. $query->whereIn('c_id',$ids);
  164. }
  165. })->when($type,function ($query)use ($type){
  166. if($type > 0) $query->where('type',$type);
  167. })
  168. ->when($price_order,function ($query) use ($price_order){
  169. $query->order('resale_price '.$price_order);
  170. })
  171. ->when($time_order,function ($query) use ($time_order){
  172. $query->order('resale_time '.$time_order);
  173. })
  174. ->limit($this->off_set,$this->page_num)
  175. ->order('id desc')
  176. ->select();
  177. $sql = '';
  178. foreach ($list as &$v){
  179. $member = getMemberInfoHash($v['mid']); //获取用户信息
  180. $v['member_name'] = $member['name'];
  181. $v['member_headimg'] = $member['headimg'];
  182. $v['pro_info'] = json_decode($v['pro_info'],true);
  183. $buy_count = Db::name('store_order_info_order')->where('info_id',$v['id'])->where('status',0)->count();
  184. $v['is_buy'] = $buy_count>0 ? 1 : 0;
  185. }
  186. $this->success('成功',compact('count','list','sql'));
  187. }
  188. /**
  189. * @title 二级市场详情
  190. * @desc 二级市场详情
  191. * @author Gavin
  192. * @url /api/Secondary/sell_list_detail
  193. * @method POST
  194. * @header name:Authorization require:1 desc:Token
  195. * @param name:id type:int : default: desc:id
  196. * @return name:id type:int require:0 default:0 desc:藏品ID
  197. * @return name:tag type:string require:0 default:0 desc:唯一标签
  198. * @return name:collectors_name type:string require:0 default:0 desc:收藏者
  199. * @return name:collectors_hash type:string require:0 default:0 desc:收藏者hash
  200. * @return name:create_at type:string require:0 default:0 desc:收藏时间
  201. * @return name:company type:string require:0 default:0 desc:流转公司
  202. * @return name:company_hash type:string require:0 default:0 desc:流转公司hash
  203. * @return name:resale_status type:string require:0 default:0 desc:1:未挂售2挂售中3已出售
  204. * @return name:resale_price type:float require:0 default:0 desc:二级市场挂售价格
  205. * @return name:pro_info@name type:string require:0 default:0 desc:藏品名称
  206. * @return name:pro_info@price type:string require:0 default:0 desc:藏品价格
  207. * @return name:pro_info@label type:string require:0 default:0 desc:藏品标签
  208. * @return name:pro_info@cover type:string require:0 default:0 desc:藏品图片
  209. * @return name:pro_info@auth_img type:string require:0 default:0 desc:作者头像
  210. * @return name:pro_info@auth_name type:string require:0 default:0 desc:作者姓名
  211. * @return name:pro_info@warm_prompt type:string require:0 default:0 desc:温馨提示
  212. * @return name:pro_info@share_img type:string require:0 default:0 desc:分享二维码
  213. * @return name:member_name type:string require:0 default:0 desc:用户名
  214. * @return name:member_headimg type:string require:0 default:0 desc:用户头像
  215. * @return name:is_buy type:int require:0 default:0 desc:是否可以购买【1是0否】
  216. */
  217. public function sell_list_detail(){
  218. $id = input('id');
  219. if (!$id) $this->error('参数错误');
  220. $info = Db::name('store_order_info')
  221. ->where('status','neq',2)
  222. ->where('resale_status',2)
  223. ->where('is_destruction',1)
  224. ->where('id',$id)
  225. ->find();
  226. if (!$info) $this->error('藏品不存在');
  227. $member = getMemberInfoHash($info['mid']); //获取用户信息
  228. $info['member_name'] = $member['name'];
  229. $info['member_headimg'] = $member['headimg'];
  230. $info['pro_info'] = json_decode($info['pro_info'],true);
  231. //判断是否有待支付订单
  232. $count = Db::name('store_order_info_order')->where('info_id',$id)->where('status',0)->count();
  233. $info['is_buy'] = $count>0 ? 1 : 0;
  234. $this->success('成功',$info);
  235. }
  236. /**
  237. * @title 购买
  238. * @desc 购买
  239. * @author Gavin
  240. * @url /api/Secondary/createOrder
  241. * @method POST
  242. * @header name:Authorization require:1 desc:Token
  243. * @param name:id type:int require:1 default: desc:主键ID
  244. * @param name:pay_type type:string require:1 default:wx desc:wx:微信,zfb:支付宝,sd:杉德h5,wallet余额,sd_rapid:杉德快捷支付
  245. * @param name:from type:string require:1 default:wx desc:wx:微信公众号h5:网页【微信支付用的着,其他支付忽略】
  246. *
  247. * @return name:order_no type:int require:0 default:0 desc:订单号
  248. * @return name:pay type:string require:0 default:0 desc:支付信息
  249. */
  250. public function createOrder(){
  251. if (redisSetNx('SecondaryCreateOrder'.$this->uid,3)) {
  252. $this->checkSwitch(1);
  253. $id = input('id');
  254. $orderinfoid = input('id');
  255. //redis原子锁
  256. if (redisSetNx('SecondaryOrderCid'.$orderinfoid,5)) {
  257. $pay_type = input('pay_type','wx');
  258. $this->checkSwitch(2,$pay_type);
  259. $from = input('from','wx');
  260. $user = getMemberInfoHash($this->uid); //获取用户信息
  261. if (!$id) $this->error('参数错误');
  262. if ($user['is_auth']==0) $this->error('请先实名认证!');
  263. $info = Db::name('store_order_info')->where('id',$id)->find();
  264. if (!$info) $this->error('藏品不存在');
  265. if ($info['resale_status']==3) $this->error('藏品已出售');
  266. if ($info['resale_status']==1) $this->error('藏品已撤销出售');
  267. if ($info['mid']==$this->uid) $this->error('不能购买自己出售的藏品');
  268. //if (isset($user['buy_time']) && $user['buy_time']>date('Y-m-d H:i:s')) $this->error('一小时取消3次以上,24小时内禁止下单');
  269. //判断是否有未支付订单
  270. $order_count = Db::name('store_order_info_order')->where('mid',$this->uid)->where('status',0)->count();
  271. if ($order_count) $this->error('有未支付订单,无法下单');
  272. //判断是否有待支付订单
  273. $count = Db::name('store_order_info_order')->where('info_id',$id)->where('status',0)->count();
  274. if ($count) $this->error('支付中,无法下单');
  275. $service_fee = getConfigValue('service_fee');
  276. $royalties = getConfigValue('royalties');
  277. $com = true;
  278. $retrun_data = [];
  279. $error_msg = '失败,请稍后重试';
  280. Db::startTrans();
  281. try {
  282. $order_no = get_order_sn();
  283. //获取价格
  284. $price = $info['resale_price'];
  285. $num = 1;
  286. $discount = getMemberServiceCharge($this->uid);// 折扣
  287. $proportion = sprintf("%.2f",$price *($service_fee/100) * $discount); //四舍五入保留两位小数点
  288. $roya = sprintf("%.2f",$price *($royalties/100) * $discount); //四舍五入保留两位小数点
  289. $total_fee = bcmul($price,$num,2);
  290. $real_money = $price-$proportion-$roya;
  291. if($pay_type == 'wallet' && $user['money'] < $total_fee) throw new Exception('余额不足');
  292. $data = [
  293. 'order_no'=>$order_no,
  294. 'mid'=>$this->uid,
  295. 'info_id'=>$id,
  296. 'num'=>$num,
  297. 'pro_info'=>json_encode($info,true),
  298. 'pay_price'=>$total_fee,
  299. 'service_fee'=>$service_fee,
  300. 'royalties'=>$royalties,
  301. 'to_account'=>$real_money,
  302. 'pay_type'=>$pay_type
  303. ];
  304. $id = Db::name('store_order_info_order')->insertGetId($data);
  305. $body = '象链数藏购买二级市场藏品';
  306. switch ($pay_type){
  307. case 'wx':
  308. $config = retrunWxConfig();
  309. $total_fee = $total_fee * 100;
  310. $config['notify_url'] = 'https://'.$_SERVER['HTTP_HOST'].'/index.php/api/Pay/SecondaryWxOrderNotify';
  311. $app = Factory::payment($config);
  312. $post_data = [
  313. 'body' => $body,
  314. 'out_trade_no' => $order_no,
  315. 'total_fee' => $total_fee,
  316. 'attach'=>$this->uid, //自定义传值
  317. ];
  318. //trade_type SAPI--JSAPI支付(或小程序支付)、NATIVE--Native支付、APP--app支付,MWEB--H5支付
  319. if ($from=='wx'){
  320. $post_data['openid'] = $user['openid'];
  321. $post_data['trade_type'] = 'JSAPI';
  322. }elseif ($from=='h5'){
  323. $post_data['trade_type'] = 'MWEB';
  324. }
  325. $result = $app->order->unify($post_data);
  326. if ($result['return_msg']=='OK'){
  327. if ($result['result_code']=='FAIL'){
  328. $com = false;
  329. Db::rollback();
  330. }else{
  331. $order1 = $app->jssdk->bridgeConfig($result['prepay_id']);//执行二次签名返回参数
  332. $retrun_data['order_no'] = $order_no;
  333. $retrun_data['id'] = $id;
  334. $retrun_data['pay'] = json_decode($order1,true);
  335. Db::commit();
  336. }
  337. }else{
  338. $com = false;
  339. Db::rollback();
  340. }
  341. break;
  342. case 'zfb':
  343. $zfb = new AliPay();
  344. $notify_url = 'https://'.$_SERVER['HTTP_HOST'].'/index.php/api/Pay/alipaySecondaryNotify';//回调地址
  345. $order = $zfb->ali_pay_pc($body, $total_fee, $order_no, $notify_url,'https://'.$_SERVER['HTTP_HOST'].'/h5/pages/shop/order');//调用支付宝支付的方法
  346. $retrun_data['order_no'] = $order_no;
  347. $retrun_data['id'] = $id;
  348. $retrun_data['pay'] = $order;
  349. Db::commit();
  350. break;
  351. case 'wallet':
  352. if($user['money'] < $total_fee) throw new Exception('余额不足');
  353. $pay_res = (new Pay())->dealSecondary(['out_trade_no' => $order_no,'attach'=>$this->uid]);
  354. if(!$pay_res) throw new Exception('支付失败');
  355. memberMoneyChange($total_fee,3,$this->uid,'二级市场余额支付',0,$id,4);
  356. setMemberInfoHash($this->uid);
  357. $retrun_data = null;
  358. Db::commit();
  359. break;
  360. case 'sd':
  361. $client = new Shande();
  362. $notify_url = 'https://'.$_SERVER['HTTP_HOST'].'/api/Pay/shandeSecondaryNotify';//回调地址
  363. $total_fee = $total_fee*100;
  364. $lenth = strlen($total_fee);
  365. $total_fee = get0number($lenth).$total_fee;
  366. $result = $client->orderPay($order_no,$total_fee,$body,$notify_url,'https://'.$_SERVER['HTTP_HOST'].'/h5/pages/shop/order',$user['bank_num']);
  367. $retrun_data['order_no'] = $order_no;
  368. $retrun_data['id'] = $id;
  369. $retrun_data['pay'] = json_decode($result['data'],true);
  370. Db::commit();
  371. break;
  372. case 'sd_rapid':
  373. if(!$user['true_name'] || !$user['id_card']) throw new Exception('请实名认证,在进行订单支付');
  374. $rapid = new ShandeRapid();
  375. $notify_url = 'https://'.$_SERVER['HTTP_HOST'].'/api/Pay/shandeSecondaryNotify';//回调地址
  376. $order_nos = get_order_sn();
  377. Db::name('store_order_info_order')->where('order_no',$order_no)->where('mid',$this->uid)->update(['order_no'=>$order_nos]);
  378. $return_url ='https://'.$_SERVER['HTTP_HOST']."/h5/pages/mine/mine?id={$id}&orderNo={$order_nos}";//回调地址
  379. $pay_extra = json_encode(['userId'=>"$this->uid",'userName'=>$user['true_name'],'idCard'=>$user['id_card']]);
  380. $pay_url = $rapid->payOrder($order_nos,$total_fee,$notify_url,$return_url,$pay_extra,$body);
  381. parse_str(parse_url($pay_url)['query'],$pay_query);
  382. $retrun_data['parse_url'] = parse_url($pay_url)['query'];
  383. $retrun_data['order_no'] = $order_nos;
  384. $retrun_data['extend'] = $this->uid;
  385. $retrun_data['pay_url'] = $pay_url;
  386. $retrun_data['pay_query'] = $pay_query;
  387. Db::commit();
  388. break;
  389. default:
  390. throw new Exception('支付方式错误');
  391. break;
  392. }
  393. }catch (\Exception $e){
  394. $com=false;
  395. $error_msg = $e->getMessage();
  396. Db::rollback();
  397. }
  398. DelRedisSetNx('SecondaryCreateOrder' . $this->uid);
  399. DelRedisSetNx('SecondaryOrderCid'.$orderinfoid);
  400. if ($com) $this->success('成功',$retrun_data);
  401. $this->error($error_msg);
  402. }else{
  403. $this->error('服务器繁忙,请稍后重试11');
  404. }
  405. }else{
  406. $this->error('服务器繁忙,请稍后重试');
  407. }
  408. }
  409. /**
  410. * @title 二级市场我的转售列表
  411. * @desc 二级市场我的转售列表
  412. * @author Gavin
  413. * @url /api/Secondary/my_sell_list
  414. * @method POST
  415. * @header name:Authorization require:1 desc:Token
  416. * @param name:page type:int : default:1 desc:页数
  417. * @param name:page_num type:int : default:20 desc:每页数
  418. *
  419. * @param name:keyword type:string require:0 default: desc:关键词
  420. * @param name:time_order type:string require:0 default: desc:时间排序(asc:正序desc:倒序)
  421. * @param name:price_order type:string require:0 default: desc:价格排序(asc:正序desc:倒序)
  422. *
  423. * @return name:name type:string require:0 default:0 desc:藏品名称
  424. * @return name:cover type:string require:0 default:0 desc:图片
  425. * @return name:member_name type:string require:0 default:0 desc:出售人名称
  426. * @return name:member_headimg type:string require:0 default:0 desc:出售人头像
  427. * @return name:resale_price type:string require:0 default:0 desc:出售价格
  428. */
  429. public function my_sell_list(){
  430. $keyword = input('keyword');
  431. $time_order = input('time_order');
  432. $price_order = input('price_order');
  433. $count = Db::name('store_order_info')
  434. ->where('mid',$this->uid)
  435. ->where('resale_status','neq',1)
  436. ->when($keyword,function ($query) use ($keyword){
  437. $query->whereLike('name','%'.$keyword.'%');
  438. })
  439. ->count();
  440. $list = Db::name('store_order_info')
  441. ->where('mid',$this->uid)
  442. ->where('resale_status','neq',1)
  443. ->when($keyword,function ($query) use ($keyword){
  444. $query->whereLike('name','%'.$keyword.'%');
  445. })
  446. ->when($price_order,function ($query) use ($price_order){
  447. $query->order('resale_price '.$price_order);
  448. })
  449. ->when($time_order,function ($query) use ($time_order){
  450. $query->order('resale_time '.$time_order);
  451. })
  452. ->order('id desc')
  453. ->limit($this->off_set,$this->page_num)
  454. ->select();
  455. foreach ($list as &$v){
  456. $member = getMemberInfoHash($v['mid']); //获取用户信息
  457. $v['member_name'] = $member['name'];
  458. $v['member_headimg'] = $member['headimg'];
  459. $v['pro_info'] = json_decode($v['pro_info'],true);
  460. }
  461. $this->success('成功',compact('count','list'));
  462. }
  463. /**
  464. * @title 二级市场订单【列表】
  465. * @desc 二级市场订单
  466. * @author Gavin
  467. * @url /api/Secondary/secondaryOrderList
  468. * @method POST
  469. * @header name:Authorization require:1 desc:Token
  470. * @param name:page type:int : default:1 desc:页数
  471. * @param name:page_num type:int : default:20 desc:每页数
  472. * @param name:status type:int require:0 default:0 desc:0:待支付1:已购买2:转售中3:已转售
  473. *
  474. * @return name:name type:string require:0 default:0 desc:藏品名称
  475. * @return name:cover type:string require:0 default:0 desc:图片
  476. * @return name:status type:int require:0 default:0 desc:[订单状态:0待支付,1已支付,2取消],
  477. * @return name:resale_status type:int require:0 default:0 desc:[寄售状态:1:未挂售 2:挂售中 3:已出售]
  478. * @return name:member_name type:string require:0 default:0 desc:出售人名称
  479. * @return name:member_headimg type:string require:0 default:0 desc:出售人头像
  480. * @return name:pay_price type:string require:0 default:0 desc:出售价格(已购买、待支付使用)
  481. * @return name:resale_price type:string require:0 default:0 desc:出售价格(转售中、已转售使用)
  482. * @return name:cancel_time type:string require:0 default:0 desc:取消时间【status=0有用】
  483. * @return name:pro_info@name type:string default:-- desc:藏品名称
  484. * @return name:pro_info@price type:string default:-- desc:藏品价格
  485. * @return name:pro_info@cover type:string default:-- desc:藏品封面
  486. * @return name:pro_info@auth_img type:string default:-- desc:藏品作者头像
  487. * @return name:pro_info@auth_name type:string default:-- desc:藏品作者名称
  488. */
  489. public function secondaryOrderList(){
  490. $status = input('status',0);
  491. switch ($status){
  492. case 0:case 1:
  493. $count = Db::name('store_order_info_order')
  494. ->where('mid',$this->uid)
  495. ->where('status',$status)
  496. ->count();
  497. $list = Db::name('store_order_info_order')
  498. ->where('mid',$this->uid)
  499. ->where('status',$status)
  500. ->order('id desc')
  501. ->limit($this->off_set,$this->page_num)
  502. ->select();
  503. //自动取消分钟数
  504. $cancel_time = getCancelTime();
  505. foreach ($list as &$v){
  506. $v['pro_info'] = json_decode($v['pro_info'],true);
  507. $member = getMemberInfoHash($v['mid']); //获取用户信息
  508. $v['member_name'] = $member['name'];
  509. $v['member_headimg'] = $member['headimg'];
  510. if ($v['status']==0){
  511. $v['cancel_time'] = date('Y-m-d H:i:s',strtotime($v['create_at'])+($cancel_time*60));
  512. }
  513. }
  514. break;
  515. case 2:case 3:
  516. $count = Db::name('store_order_info')
  517. ->where('mid',$this->uid)
  518. ->where('resale_status',$status)
  519. ->where('is_destruction',1)
  520. ->count();
  521. $list = Db::name('store_order_info')
  522. ->where('mid',$this->uid)
  523. ->where('resale_status',$status)
  524. ->where('is_destruction',1)
  525. ->order('id desc')
  526. ->limit($this->off_set,$this->page_num)
  527. ->select();
  528. foreach ($list as &$v){
  529. $v['pro_info'] = json_decode($v['pro_info'],true);
  530. $member = getMemberInfoHash($v['mid']); //获取用户信息
  531. $v['member_name'] = $member['name'];
  532. $v['member_headimg'] = $member['headimg'];
  533. }
  534. break;
  535. default:
  536. $count = Db::name('store_order_info_order')
  537. ->where('mid',$this->uid)
  538. ->count();
  539. $list = Db::name('store_order_info_order')
  540. ->where('mid',$this->uid)
  541. ->order('id desc')
  542. ->limit($this->off_set,$this->page_num)
  543. ->select();
  544. $cancel_time = getCancelTime();
  545. foreach ($list as &$v){
  546. $v['pro_info'] = json_decode($v['pro_info'],true);
  547. $member = getMemberInfoHash($v['mid']); //获取用户信息
  548. $v['member_name'] = $member['name'];
  549. $v['member_headimg'] = $member['headimg'];
  550. if ($v['status']==0) $v['cancel_time'] = date('Y-m-d H:i:s',strtotime($v['create_at'])+($cancel_time*60));
  551. }
  552. break;
  553. }
  554. $this->success('成功',compact('count','list'));
  555. }
  556. /**
  557. * @title 二级市场订单【详情】
  558. * @desc 二级市场订单
  559. * @author Qc
  560. * @url /api/Secondary/secondaryOrderDetail
  561. * @method POST
  562. * @header name:Authorization require:1 desc:Token
  563. * @param name:id type:int require:0 default:-- desc:二级市场订单id
  564. * @return name:name type:string require:0 default:0 desc:藏品名称
  565. * @return name:cover type:string require:0 default:0 desc:图片
  566. * @return name:status type:int require:0 default:0 desc:0待支付,1已支付,2取消
  567. * @return name:pay_type type:string require:0 default:0 desc:支付方式:wx:微信zfb:支付宝wallet:余额
  568. * @return name:order_no type:string require:0 default:0 desc:单号
  569. * @return name:create_at type:string require:0 default:0 desc:下单时间
  570. *
  571. * @return name:pay_at type:string require:0 default:0 desc:支付时间
  572. * @return name:user_name type:string require:0 default:0 desc:售卖人名称
  573. * @return name:member_name type:string require:0 default:0 desc:买方名称
  574. * @return name:member_headimg type:string require:0 default:0 desc:买方头像
  575. * @return name:pay_price type:string require:0 default:0 desc:出售价格(已购买、待支付使用)
  576. * @return name:resale_price type:string require:0 default:0 desc:出售价格(转售中、已转售使用)
  577. * @return name:cancel_time type:string require:0 default:0 desc:取消时间【status=0有用】
  578. * @return name:pro_info@name type:string default:-- desc:藏品名称
  579. * @return name:pro_info@price type:string default:-- desc:藏品价格
  580. * @return name:pro_info@cover type:string default:-- desc:藏品封面
  581. * @return name:pro_info@auth_img type:string default:-- desc:藏品作者头像
  582. * @return name:pro_info@auth_name type:string default:-- desc:藏品作者名称
  583. */
  584. public function secondaryOrderDetail()
  585. {
  586. $detail = Db::name('store_order_info_order')->where('mid',$this->uid)->where('id',input('id'))->find();
  587. if(empty($detail)) $this->error('订单不存在');
  588. $member = getMemberInfoHash($detail['mid']); //获取用户信息
  589. $cancel_time = getCancelTime();
  590. $detail['member_name'] = $member['name'];
  591. $detail['member_headimg'] = $member['headimg'];
  592. if ($detail['status']==0) $detail['cancel_time'] = date('Y-m-d H:i:s',strtotime($detail['create_at'])+($cancel_time*60));
  593. $detail['pro_info'] = json_decode($detail['pro_info'],true);
  594. $sell_info = Db::name('store_order_info')->alias('o')
  595. ->field('o.*,m.name user_name,m.headimg')
  596. ->where('o.id',$detail['info_id'])
  597. ->leftJoin('store_member m','m.id = o.mid')
  598. ->find();
  599. $detail['user_name'] = $sell_info['user_name'];
  600. $this->success('ok',$detail);
  601. }
  602. /**
  603. * @title 根据藏品id获取二级市场订单【流转订单:已转售转售订单】
  604. * @desc 二级市场订单
  605. * @author Qc
  606. * @url /api/Secondary/getSecondaryOrderDetailByCollect
  607. * @method POST
  608. * @header name:Authorization require:1 desc:Token
  609. * @param name:id type:int require:0 default:-- desc:已转售记录id
  610. * @return name:name type:string require:0 default:0 desc:藏品名称
  611. * @return name:cover type:string require:0 default:0 desc:图片
  612. * @return name:status type:int require:0 default:0 desc:0待支付,1已支付,2取消
  613. * @return name:pay_type type:string require:0 default:0 desc:支付方式:wx:微信zfb:支付宝wallet:余额,sd:杉德h5,sd_rapid:杉德快捷充值
  614. * @return name:order_no type:string require:0 default:0 desc:单号
  615. * @return name:create_at type:string require:0 default:0 desc:下单时间
  616. * @return name:pay_at type:string require:0 default:0 desc:支付时间
  617. * @return name:member_name type:string require:0 default:0 desc:买方名称
  618. * @return name:member_headimg type:string require:0 default:0 desc:买方头像
  619. * @return name:pay_price type:string require:0 default:0 desc:出售价格(已购买、待支付使用)
  620. * @return name:resale_price type:string require:0 default:0 desc:出售价格(转售中、已转售使用)
  621. * @return name:cancel_time type:string require:0 default:0 desc:取消时间
  622. * @return name:pro_info@name type:string default:-- desc:藏品名称
  623. * @return name:pro_info@price type:string default:-- desc:藏品价格
  624. * @return name:pro_info@cover type:string default:-- desc:藏品封面
  625. * @return name:pro_info@auth_img type:string default:-- desc:藏品作者头像
  626. * @return name:pro_info@auth_name type:string default:-- desc:藏品作者名称
  627. */
  628. public function getSecondaryOrderDetailByCollect()
  629. {
  630. $collect_id = input('id');
  631. $collect_info = Db::name('store_order_info')->where('mid',$this->uid)
  632. ->where('id',$collect_id)->where('resale_status',3)->find();
  633. if(!$collect_info ) $this->error('藏品记录有误');
  634. $order_info = Db::name('store_order_info_order')
  635. ->where('info_id',$collect_id)->where('status',1)->find();
  636. if(!$order_info) $this->error('订单不存在');
  637. $member = getMemberInfoHash($order_info['mid']); //获取用户信息
  638. $order_info['member_name'] = $member['name'];
  639. $order_info['member_headimg'] = $member['headimg'];
  640. $order_info['pro_info'] = json_decode($order_info['pro_info'],true);
  641. $pro_info = json_decode($order_info['pro_info']['pro_info'],true);
  642. $order_info['pro_info']['cover'] =$pro_info['cover'];
  643. $order_info['pro_info']['name'] =$pro_info['name'];
  644. $this->success('ok',$order_info);
  645. }
  646. /**
  647. * @title 取消订单
  648. * @desc 取消订单
  649. * @author Gavin
  650. * @url /api/Secondary/cancelOrder
  651. * @method POST
  652. * @header name:Authorization require:1 desc:Token
  653. * @param name:order_no type:string require:1 default:-- desc:订单号
  654. */
  655. public function cancelOrder(){
  656. $order_no = input('order_no');
  657. if (!$order_no) $this->error('参数错误');
  658. $order = Db::name('store_order_info_order')
  659. ->where('order_no',$order_no)
  660. ->where('mid',$this->uid)
  661. ->find();
  662. if (!$order) $this->error('订单不存在');
  663. if ($order['status']!=0) $this->error('订单已支付或已取消');
  664. $com = true;
  665. Db::startTrans();
  666. try {
  667. $up_data = [
  668. 'status'=>2,
  669. 'cancel_at'=>date('Y-m-d H:i:s'),
  670. 'cancel_state'=>2
  671. ];
  672. Db::name('store_order_info_order')->where('order_no',$order_no)->update($up_data);
  673. $cancle = [
  674. 'mid'=>$this->uid,
  675. 'order_id'=>$order['id']
  676. ];
  677. Db::name('store_order_info_cancel_log')->insert($cancle);
  678. $time = date('Y-m-d H:i:s',time()-(60*60));
  679. $count = Db::name('store_order_info_cancel_log')->where('mid',$this->uid)->where('create_at','gt',$time)->count();
  680. if ($count>2){
  681. $buy_time = date('Y-m-d H:i:s',time()+(24*60*60));
  682. Db::name('store_member')->where('id',$this->uid)->update(['buy_time'=>$buy_time]);
  683. }
  684. Db::commit();
  685. }catch (\Exception $e){
  686. $com=false;
  687. Db::rollback();
  688. }
  689. if ($com){
  690. setMemberInfoHash($this->uid);
  691. $this->success('取消成功');
  692. }else{
  693. $this->error('取消失败,请稍后重试');
  694. }
  695. }
  696. /**
  697. * @title 待支付订单支付
  698. * @desc 待支付订单支付
  699. * @author Gavin
  700. * @url /api/Secondary/payOrder
  701. * @method POST
  702. * @header name:Authorization require:1 desc:Token
  703. * @param name:id type:string require:1 default:-- desc:订单id
  704. * @param name:order_no type:string require:1 default:-- desc:订单号
  705. * @param name:from type:string require:1 default:wx desc:wx:微信公众号h5:网页
  706. *
  707. * @return name:order_no type:int require:0 default:0 desc:订单号
  708. * @return name:pay type:string require:0 default:0 desc:支付信息
  709. * @return name:order_no type:string default:0 desc:支付单号(sd)
  710. * @return name:extend type:int default:0 desc:用户id(sd)
  711. * @return name:pay type:array default:0 desc:支付信息(sd)
  712. * @return name:pay.body type:array default:0 desc:支付信息(sd)
  713. * @return name:pay.totalAmount type:string default:0 desc:支付金额【000000010000是100元】(sd)
  714. * @return name:pay.orderCode type:string default:0 desc:支付单号(sd)
  715. * @return name:pay.credential type:string default:0 desc:正书(sd)
  716. */
  717. public function payOrder(){
  718. $this->checkSwitch(1);
  719. $user = getMemberInfoHash($this->uid); //获取用户信息
  720. $order_no = input('order_no'); //订单号
  721. $id = input('id');
  722. $from = input('from','wx');
  723. if (!$order_no) $this->error('参数错误');
  724. if (!$id) $this->error('参数错误');
  725. $order = Db::name('store_order_info_order')
  726. // ->where('order_no',$order_no)
  727. ->where('id',$id)
  728. ->where('mid',$this->uid)
  729. ->find();
  730. if (!$order) $this->error('订单不存在');
  731. $order_no = $order['order_no'];
  732. $pay_type = $order['pay_type'];
  733. $this->checkSwitch(2,$pay_type);
  734. if ($order['status']!=0) $this->error('订单已支付或已取消');
  735. $CancelTime = getCancelTime();
  736. if (strtotime($order['create_at']) + $CancelTime * 60 < time()) $this->error('订单超时');
  737. $info = Db::name('store_order_info')->where('id',$order['info_id'])->find();
  738. if ($info['resale_status']!=2) $this->error('藏品已出售或已撤销出售');
  739. $com = true;
  740. $retrun_data=[];
  741. $retrun_data['user_id'] = $this->uid;
  742. $error_msg = '失败,请稍后重试';
  743. Db::startTrans();
  744. try {
  745. //获取价格
  746. $total_fee = $order['pay_price'];
  747. $body = '象链数藏购买二级市场藏品';
  748. switch ($pay_type){
  749. case 'wx':
  750. $config = retrunWxConfig();
  751. $total_fee = $total_fee * 100;
  752. $config['notify_url'] = 'https://'.$_SERVER['HTTP_HOST'].'/api/Pay/SecondaryWxOrderNotify';
  753. $app = Factory::payment($config);
  754. $post_data = [
  755. 'body' => $body,
  756. 'out_trade_no' => $order_no,
  757. 'total_fee' => $total_fee,
  758. 'attach'=>$this->uid, //自定义传值
  759. ];
  760. //trade_type SAPI--JSAPI支付(或小程序支付)、NATIVE--Native支付、APP--app支付,MWEB--H5支付
  761. if ($from=='wx'){
  762. $post_data['openid'] = $user['openid'];
  763. $post_data['trade_type'] = 'JSAPI';
  764. }elseif ($from=='h5'){
  765. $post_data['trade_type'] = 'MWEB';
  766. }
  767. $result = $app->order->unify($post_data);
  768. if ($result['return_msg']=='OK'){
  769. if ($result['result_code']=='FAIL'){
  770. $com = false;
  771. Db::rollback();
  772. }else{
  773. $order1 = $app->jssdk->bridgeConfig($result['prepay_id']);//执行二次签名返回参数
  774. $retrun_data['order_no'] = $order_no;
  775. $retrun_data['id'] = $order['id'];
  776. $retrun_data['pay'] = json_decode($order1,true);
  777. Db::commit();
  778. }
  779. }else{
  780. $com = false;
  781. Db::rollback();
  782. }
  783. break;
  784. case 'zfb':
  785. $zfb = new AliPay();
  786. $notify_url = 'https://'.$_SERVER['HTTP_HOST'].'/api/Pay/alipaySecondaryNotify';//回调地址
  787. $order = $zfb->ali_pay_pc($body, $total_fee, $order_no, $notify_url,'https://'.$_SERVER['HTTP_HOST'].'/h5/pages/shop/order');//调用支付宝支付的方法
  788. $retrun_data['order_no'] = $order_no;
  789. $retrun_data['id'] = $order['id'];
  790. $retrun_data['pay'] = $order;
  791. Db::commit();
  792. break;
  793. case 'sd':
  794. $client = new Shande();
  795. $notify_url = 'https://'.$_SERVER['HTTP_HOST'].'/api/Pay/shandeSecondaryNotify';//回调地址
  796. $total_fee = $total_fee*100;
  797. $lenth = strlen($total_fee);
  798. $total_fee = get0number($lenth).$total_fee;
  799. $order_nos = get_order_sn();
  800. if (Db::name('store_order_info_order')
  801. ->where('order_no',$order_no)
  802. ->where('mid',$this->uid)
  803. ->update(['order_no'=>$order_nos])){
  804. $result = $client->orderPay($order_nos,$total_fee,$body,$notify_url,'https://'.$_SERVER['HTTP_HOST'].'/h5/pages/mine/mine',$user['bank_num']);
  805. $retrun_data['order_no'] = $order_nos;
  806. $retrun_data['id'] = $order['id'];
  807. $retrun_data['pay'] = json_decode($result['data'],true);
  808. if( $retrun_data['pay']['head']['respCode'] != '00000') throw new Exception($retrun_data['pay']['head']['respMsg'].'请重新下单');
  809. Db::commit();
  810. }else{
  811. $com=false;
  812. Db::rollback();
  813. }
  814. break;
  815. case 'wallet':
  816. if($user['money'] < $total_fee) throw new Exception('余额不足');
  817. $pay_res = (new Pay())->dealSecondary(['out_trade_no' => $order_no,'attach'=>$this->uid]);
  818. if(!$pay_res) throw new Exception('支付失败');
  819. memberMoneyChange($total_fee,3,$this->uid,'二级市场余额支付',0,$order['id'],4);
  820. setMemberInfoHash($this->uid);
  821. $retrun_data = null;
  822. Db::commit();
  823. break;
  824. case 'sd_rapid' :
  825. if(!$user['true_name'] || !$user['id_card']) throw new Exception('请实名认证,在进行订单支付');
  826. $rapid = new ShandeRapid();
  827. $notify_url = 'https://'.$_SERVER['HTTP_HOST'].'/api/Pay/shandeSecondaryNotify';//回调地址
  828. $order_nos = get_order_sn();
  829. Db::name('store_order_info_order')->where('order_no',$order_no)->where('mid',$this->uid)->update(['order_no'=>$order_nos]);
  830. $return_url ='https://'.$_SERVER['HTTP_HOST']."/h5/pages/mine/mine?id={$order['id']}&orderNo={$order_nos}";//回调地址
  831. $pay_extra = json_encode(['userId'=>"$this->uid",'userName'=>$user['true_name'],'idCard'=>$user['id_card']]);
  832. $pay_url = $rapid->payOrder($order_nos,$total_fee,$notify_url,$return_url,$pay_extra,$body);
  833. parse_str(parse_url($pay_url)['query'],$pay_query);
  834. $retrun_data['parse_url'] = parse_url($pay_url)['query'];
  835. $retrun_data['order_no'] = $order_nos;
  836. $retrun_data['extend'] = $this->uid;
  837. $retrun_data['pay_url'] = $pay_url;
  838. $retrun_data['pay_query'] = $pay_query;
  839. Db::commit();
  840. break;
  841. }
  842. }catch (\Exception $e){
  843. $com=false;
  844. $error_msg= $e->getMessage();
  845. Db::rollback();
  846. }
  847. if ($com){
  848. $this->success('成功',$retrun_data);
  849. }
  850. $this->error($error_msg);
  851. }
  852. /**
  853. * @param 判断开关
  854. * @param string $pay_type
  855. * @return bool
  856. * @throws \think\db\exception\DataNotFoundException
  857. * @throws \think\db\exception\ModelNotFoundException
  858. * @throws \think\exception\DbException
  859. */
  860. public function checkSwitch($type,$pay_type=''){
  861. if ($type==1){
  862. $v = getConfigValue('secondary_sell_switch');
  863. if (!$v) $this->error('维护中,暂时关闭');
  864. }elseif ($type==2){
  865. $nameArray = ['secondary_wx_switch','secondary_zfb_switch','secondary_sd_switch'];
  866. $values = getConfig($nameArray);
  867. if ($pay_type=='wx'){
  868. if (!$values['secondary_wx_switch']) $this->error('微信支付暂时关闭');
  869. }elseif ($pay_type=='zfb'){
  870. if (!$values['secondary_zfb_switch']) $this->error('支付宝支付暂时关闭');
  871. }elseif ($pay_type=='sd'){
  872. if (!$values['secondary_sd_switch']) $this->error('杉德支付暂时关闭');
  873. }
  874. }
  875. return true;
  876. }
  877. }