Browse Source

add - tmp 抖音小程序API

liugc 11 tháng trước cách đây
mục cha
commit
274fc025b3

+ 201 - 0
app/api/controller/DouYinController.php

@@ -0,0 +1,201 @@
+<?php
+// +----------------------------------------------------------------------
+// | likeadmin快速开发前后端分离管理后台(PHP版)
+// +----------------------------------------------------------------------
+// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
+// | 开源版本可自由商用,可去除界面版权logo
+// | gitee下载:https://gitee.com/likeshop_gitee/likeadmin
+// | github下载:https://github.com/likeshop-github/likeadmin
+// | 访问官网:https://www.likeadmin.cn
+// | likeadmin团队 版权所有 拥有最终解释权
+// +----------------------------------------------------------------------
+// | author: likeadminTeam
+// +----------------------------------------------------------------------
+
+namespace app\api\controller;
+
+use app\api\lists\GoodsLists;
+use app\api\logic\GoodsLogic;
+use app\api\service\DouYinService;
+use app\common\enum\LoginEnum;
+use app\common\enum\user\UserTerminalEnum;
+use app\common\model\user\User;
+use app\api\validate\{LoginAccountValidate, RegisterValidate, WebScanLoginValidate, WechatLoginValidate};
+use app\api\logic\LoginLogic;
+
+/**
+ * 抖音 - tmp
+ * Class DouYinController
+ * @package app\api\controller
+ */
+class DouYinController extends BaseApiController
+{
+
+    public array $notNeedLogin = ['register','account','payNotify'];
+    /*手机号注册 + 通过code获取openId绑定
+    (暂时无-试运营)授权手机号一键注册登录 - 通过code应该为getPhoneNumber返回
+
+
+    token过期-登录 + 通过code 通过服务端获取openId,通过openId登录
+                    手机号-验证码登录
+
+    token-直接调去API
+
+    所有商品
+    商品详情(分类+商品Id)
+    用户地址管理(同原来)
+    下单(待支付/已支付-未预约/已预约/服务中/服务完成/取消并退款)
+    订单各状态列表
+    支付回调
+    */
+
+    /**
+     * 手机号注册
+     * @author liugc <466014217@qq.com>
+     * @date 2025/5/20 13:39
+     */
+    public function register()
+    {
+        try {
+            $params = $this->request->post();
+            $this->validate($params,[
+                "code" => "require",
+                "mobile" => "require|mobile",
+            ]);
+            // 验证码验证
+            $res = \app\workerapi\logic\LoginLogic::confirmMobile($params);
+            if(!$res){
+                throw new \Exception('验证码错误');
+            }
+            // 注册并登录
+            $result = DouYinService::phoneLogin($params);
+            return $this->data($result);
+        } catch (\Exception $e) {
+            return $this->fail($e->getMessage());
+        }
+    }
+
+    /**
+     * @notes 账号密码/手机号密码/手机号验证码登录
+     * @return \think\response\Json
+     * @author 段誉
+     * @date 2022/9/16 10:42
+     */
+    public function account()
+    {
+        try {
+            $params = (new LoginAccountValidate())->post()->goCheck();
+            $result = LoginLogic::login($params);
+            if (false === $result) {
+                return $this->fail(LoginLogic::getError());
+            }
+            return $this->data($result);
+        } catch (\Exception $e) {
+            return $this->fail($e->getMessage());
+        }
+    }
+
+
+    /**
+     * @notes 退出登录
+     * @return \think\response\Json
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\DbException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @author 段誉
+     * @date 2022/9/16 10:42
+     */
+    public function logout()
+    {
+        LoginLogic::logout($this->userInfo);
+        return $this->success();
+    }
+
+
+    /**
+     * 所有商品
+     * @return \think\response\Json
+     * @author liugc <466014217@qq.com>
+     * @date 2025/5/20 14:35
+     */
+    public function getAllGoods()
+    {
+        $params = $this->request->get();
+        $params['platform_value'] = 6;
+        return $this->dataLists((new GoodsLists())->setParams($params));
+    }
+
+
+    /**
+     * 商品详情
+     * @return \think\response\Json
+     * @author liugc <466014217@qq.com>
+     * @date 2025/5/20 14:35
+     */
+    public function getGoodsDetail()
+    {
+        $params = $this->request->get();
+        $params['platform_value'] = 6;
+        $result = GoodsLogic::detail($params['goods_category_id'],'category',$this->userId,$params);
+        return $this->data($result);
+    }
+
+
+    /**
+     * 下单
+     * @return \think\response\Json
+     * @author liugc <466014217@qq.com>
+     * @date 2025/5/22 14:35
+     */
+    public function submitOrder()
+    {
+        try {
+            $params = $this->request->post();
+            $params['user_id'] = $this->userId;
+            $params['user_info'] = $this->userInfo;
+            DouYinService::submitOrder($params);
+            return $this->success();
+        } catch (\Exception $e) {
+            return $this->fail($e->getMessage());
+        }
+    }
+
+    /**
+     * 支付回调
+     * @return \think\response\Json
+     * @author liugc <466014217@qq.com>
+     * @date 2025/5/22 14:35
+     */
+    public function payNotify()
+    {
+        try {
+            $params = $this->request->post();
+            if(DouYinService::payNotify($params)){
+                return $this->success();
+            }
+            return $this->fail('fail');
+        } catch (\Exception $e) {
+            return $this->fail($e->getMessage());
+        }
+    }
+
+    /**
+     * 预约
+     * @return \think\response\Json
+     * @author liugc <466014217@qq.com>
+     * @date 2025/5/22 14:35
+     */
+    public function reservation()
+    {
+        try {
+            $params = $this->request->post(); // order_number
+            DouYinService::reservation($params);
+            return $this->success();
+        } catch (\Exception $e) {
+            return $this->fail($e->getMessage());
+        }
+    }
+
+
+
+}

+ 3 - 0
app/api/lists/GoodsLists.php

@@ -51,6 +51,9 @@ class GoodsLists  extends BaseApiDataLists implements ListsSearchInterface
         $where['user_id'] = 0;//常规商品
         $where['is_agent'] = 0;//常规商品
         $where['platform_value'] = 0;//自平台商品
+        if (isset($this->params['platform_value']) && !empty($this->params['platform_value'])) {
+            $where['platform_value'] = $this->params['platform_value'];//外部平台商品
+        }
         if (!empty($this->params['goods_category_id'])) {
             $goodsCategoryId = end($this->params['goods_category_id']);
             $goodsCategoryData = GoodsCategory::where(['status'=>1])->order(['pid' => 'asc','weigh' => 'desc', 'id' => 'desc'])

+ 2 - 2
app/api/logic/GoodsLogic.php

@@ -30,7 +30,7 @@ class GoodsLogic extends BaseLogic
         $where = [];
         $service_work_id = $params['service_work_id']??0;
         $platform_appid = $params['platform_appid']??0;
-        $platform_value = 0;
+        $platform_value = $params['platform_value']??0;
         if($type == 'category'){
             $where[] = ['goods_category_id','=',$id];
             $where[] = ['user_id','=',0];
@@ -43,7 +43,7 @@ class GoodsLogic extends BaseLogic
                 $platform_value = ExternalPlatform::where('appid',$platform_appid)->value('id');
                 $where[] = ['platform_value','=',$platform_value];
             }else{
-                $where[] = ['platform_value','=',0];
+                $where[] = ['platform_value','=',$platform_value];
             }
             $goods = Goods::where($where)->visible([
                 'id','goods_image','goods_name','goods_banners','good_unit','sell_num','base_service_fee',

+ 193 - 0
app/api/service/DouYinService.php

@@ -0,0 +1,193 @@
+<?php
+
+namespace app\api\service;
+
+use app\adminapi\logic\external\ExternalConsultationLogic;
+use app\common\model\Config;
+use app\common\model\external\DouyinOrder;
+use app\common\model\external\ExternalConsultation;
+use app\common\model\external\ExternalConsultationOrder;
+use app\common\model\goods\Goods;
+use app\common\model\user\User;
+use app\common\model\user\UserAuth;
+use app\common\model\works\ServiceWork;
+use app\common\service\ConfigService;
+use app\common\service\FileService;
+use think\facade\Db;
+use think\facade\Log;
+
+class DouYinService
+{
+    protected static int $terminal = \app\common\enum\user\UserTerminalEnum::DOUYIN;
+    protected static int $external_platform_id = 7;
+    public static function register(array $params)
+    {
+        $userSn = User::createUserSn();
+        $params['password'] = !empty($params['password'])?$params['password']:rand(100000,999999);
+        $passwordSalt = \think\facade\Config::get('project.unique_identification');
+        $password = create_password($params['password'], $passwordSalt);
+        $avatar = ConfigService::get('default_image', 'user_avatar');
+        $user = User::create([
+            'sn' => $userSn,
+            'avatar' => $avatar,
+            'nickname' => '用户' . $userSn,
+            'account' => $params['account'],
+            'mobile' => !empty($params['mobile'])?$params['mobile']:'',
+            'password' => $password,
+            'channel' => self::$terminal,
+            'user_type' => $params['user_type']??0,
+        ]);
+
+        return $user;
+    }
+    public static function phoneLogin(array $params)
+    {
+        try {
+            $where = ['mobile' => $params['mobile']];
+            $params['account'] = $params['mobile'];
+            $user = User::where($where)->findOrEmpty();
+            if ($user->isEmpty()) {
+                //直接注册用户
+                $params['channel'] = self::$terminal;
+                $user = self::register($params);
+            }
+            //更新登录信息
+            $user->login_time = time();
+            $user->login_ip = request()->ip();
+            $user->save();
+
+            $userInfo = UserTokenService::setToken($user->id, self::$terminal);
+
+            //返回登录信息
+            $avatar = $user->avatar ?: Config::get('project.default_image.user_avatar');
+            $avatar = FileService::getFileUrl($avatar);
+
+            return [
+                'nickname' => $userInfo['nickname'],
+                'sn' => $userInfo['sn'],
+                'mobile' => $userInfo['mobile'],
+                'avatar' => $avatar,
+                'token' => $userInfo['token'],
+            ];
+        } catch (\Exception $e) {
+            throw new \Exception($e->getMessage());
+        }
+    }
+
+    /**
+     * 提交订单
+     * @param array $params
+     * @return array|false
+     */
+    public static function submitOrder($params)
+    {
+        Db::startTrans();
+        try {
+
+            $goods = Goods::findOrEmpty($params['goods_id']);
+            if($goods->isEmpty()){
+                throw new \Exception('产品不存在!');
+            }
+            if(empty($params['user_info']['mobile'])){
+                throw new \Exception('请先补充您的联系方式后在提交订单');
+            }
+            // TODO tmp防抖1m
+            $isExist = DouyinOrder::where(['user_id'=>$params['user_id'],'goods_id'=>$goods['goods_id']])->where('create_time','>',(time() - 60))->findOrEmpty();
+            if(!$isExist->isEmpty()){
+                throw new \Exception('请勿重复下单!');
+            }
+            $quantity = $params['quantity']??1;
+            //生成订单
+            $create_data = [
+                'user_id' => $params['user_id'],
+                'mobile' => $params['user_info']['mobile'],
+                'title' => $goods['goods_name'],
+
+                'goods_id'=>$goods['goods_id'],
+                'unit_price' => $goods['service_fee'],
+                'quantity' => $quantity,
+                'total_amount' => $goods['service_fee'] * $quantity,
+                'order_number' => generate_sn(DouyinOrder::class, 'order_number'),
+            ];
+            $order = DouyinOrder::create($create_data);
+            Db::commit();
+            return $order['id'];
+        } catch (\Exception $e) {
+            Db::rollback();
+            throw new \Exception($e->getMessage());
+        }
+    }
+
+    public static function payNotify($params)
+    {
+            Log::write($params,JSON_UNESCAPED_UNICODE);
+
+            // 查询抖音订单是否完成支付
+
+            if ($params['trade_state'] === 'SUCCESS') {
+                $transaction_id = '';
+                $paid_amount = '';
+                $out_trade_no = $params['out_trade_no'];
+                $order = DouyinOrder::where('order_number', $out_trade_no)->findOrEmpty();
+                if(!$order->isEmpty()){
+                    // 更新充值订单状态
+                    $order->transaction_id = $transaction_id;
+                    $order->order_status = 2;
+                    $order->pay_time = time();
+                    $order->paid_amount = $paid_amount;
+
+                    $user = User::where('id',$order->user_id)->findOrEmpty()->toArray();
+                    $form_detail = [
+                        'user_name' => $user['real_name']??'',
+                        'mobile' => $user['mobile'],
+                        'transaction_id' => $transaction_id,
+                        'out_trade_no' => $out_trade_no,
+                        'paid_amount' => $paid_amount,
+                    ];
+                    $consultation = ExternalConsultation::create([
+                        'external_platform_id' => self::$external_platform_id,
+                        'form_detail' => $form_detail,
+                        'user_name' => $user['real_name']??'',
+                        'mobile' => $user['mobile'],
+                        'goods_id' => $order->goods_id,
+                        'amount' => $paid_amount
+                    ]);
+                    $order->consultation_id = $consultation['id'];
+                    $order->save();
+                    return true;
+                }
+            }
+            return false;
+    }
+    public static function reservation($params)
+    {
+        // $params['order_number']
+        Db::startTrans();
+        try {
+            $order = DouyinOrder::where('order_number', $params['order_number'])->findOrEmpty();
+            if(!$order->isEmpty()){
+                $consultation = ExternalConsultation::where('id', $order->consultation_id)->findOrEmpty()->toArray();
+                $consultation['user_address'] = $params['user_address'];
+                $consultation['lon'] = $params['lon'];
+                $consultation['lat'] = $params['lat'];
+                $consultation['appointment_time'] = $params['appointment_time'];
+                $result = ExternalConsultationLogic::order($consultation);
+                if (false === $result) {
+                    throw new \Exception('预约失败');
+                }
+                $consultationOrder = ExternalConsultationOrder::where('consultation_id', $order->consultation_id)->where('goods_id', $order->goods_id)->where('amount', $order->paid_amount)
+                    ->findOrEmpty()->toArray();
+                $work_status = ServiceWork::where('id', $consultationOrder['work_id'])->value('work_status');
+                $order->work_id = $consultationOrder['work_id'];
+                $order->fulfillment_status = $work_status;
+                $order->save();
+            }
+            Db::commit();
+            return $order['id'];
+        } catch (\Exception $e) {
+            Db::rollback();
+            throw new \Exception($e->getMessage());
+        }
+    }
+
+}

+ 2 - 1
app/api/validate/LoginAccountValidate.php

@@ -36,7 +36,8 @@ class LoginAccountValidate extends BaseValidate
     protected $rule = [
         'terminal' => 'require|in:' . UserTerminalEnum::WECHAT_MMP . ',' . UserTerminalEnum::WECHAT_OA . ','
             . UserTerminalEnum::H5 . ',' . UserTerminalEnum::PC . ',' . UserTerminalEnum::IOS .
-            ',' . UserTerminalEnum::ANDROID,
+            ',' . UserTerminalEnum::ANDROID.
+            ',' . UserTerminalEnum::DOUYIN,
         'scene' => 'require|in:' . LoginEnum::ACCOUNT_PASSWORD . ',' . LoginEnum::MOBILE_CAPTCHA . '|checkConfig',
         'account' => 'require',
     ];

+ 3 - 0
app/common/enum/user/UserTerminalEnum.php

@@ -28,6 +28,7 @@ class UserTerminalEnum
     const PC         = 4;//电脑PC
     const IOS        = 5;//苹果app
     const ANDROID    = 6;//安卓app
+    const DOUYIN    = 7;//抖音小程序
 
 
     const ALL_TERMINAL = [
@@ -37,6 +38,7 @@ class UserTerminalEnum
         self::PC,
         self::IOS,
         self::ANDROID,
+        self::DOUYIN,
     ];
 
     /**
@@ -55,6 +57,7 @@ class UserTerminalEnum
             self::PC            => '电脑PC',
             self::IOS           => '苹果APP',
             self::ANDROID       => '安卓APP',
+            self::DOUYIN       => '抖音小程序',
         ];
         if(true === $from){
             return $desc;

+ 10 - 0
app/common/model/external/DouyinOrder.php

@@ -0,0 +1,10 @@
+<?php
+
+namespace app\common\model\external;
+
+use app\common\model\BaseModel;
+
+class DouyinOrder extends BaseModel
+{
+    protected $name = 'douyin_order';
+}