| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 |
- <?php
- declare(strict_types=1);
- namespace App\Crontab;
- use App\Model\RRobotAutoOrderModel;
- use App\Model\RRobotAutoUserModel;
- use App\Model\RTradeOrderModel;
- use App\Model\TEmployeeMemberModel;
- use Hyperf\Contract\StdoutLoggerInterface;
- use Hyperf\Crontab\Annotation\Crontab;
- use Hyperf\DbConnection\Db;
- use Hyperf\Di\Annotation\Inject;
- /**
- * Desc:自动生成订单任务每天一次
- * Author: Spt <2864934511@qq.com>
- * Date: 2024-03-13 08:36
- */
- #[Crontab(rule: "30 23 * * *", name: "SckwChgrobot", callback: "execute", memo: "自动生成订单任务每天一次", enable: "isEnable")]
- class SckwChgrobotCrontab
- {
- // /**
- // * 定时任务唯一标识
- // */
- // protected const code = 'auto_order_crontab';
- #[Inject]
- private StdoutLoggerInterface $logger;
- /**
- * 充电最低标准电量
- * @var int
- */
- private static int $charge_minimum_power = 3;
- /**
- * Desc: 是否随开机启动
- * Author: Spt <2864934511@qq.com>
- * Date: 2024-03-12 16:08
- * @return bool
- */
- public function isEnable(): bool
- {
- return true;
- }
- public function execute(): void
- {
- $this->logger->info(__CLASS__ . ' 自动生成订单任务开始 ' . datetime());
- $this->task();
- }
- private function task(): bool
- {
- //获取所有任务
- $list = RRobotAutoOrderModel::with(['robot', 'site', 'price'])
- ->where('num', '<', 2)//执行次数0无限1一次超过1则不执行
- ->where('del_flag', 0)
- ->get();
- if ($list->isNotEmpty()) {
- //获取所有可用人员
- $user_list = RRobotAutoUserModel::where('status', 1)->get();
- if ($user_list->isEmpty()) {
- $this->logger->error(' 查无任务可用用户');
- return false;
- }
- $users = array_column($user_list->toArray(), 'open_id');
- //获取所有可用人员
- $userLists = TEmployeeMemberModel::with(['user'])
- ->whereIn('open_id', $users)//openid 范围查询
- ->where('del_flag', 0)//是否删除0否 1是
- ->get();
- if ($userLists->isEmpty()) {
- $this->logger->error(' 查无会员用户:' . json_encode($users, JSON_UNESCAPED_UNICODE));
- return false;
- } else {
- $userLists = $userLists->toArray();
- }
- foreach ($list as $robot) {
- //本轮充放电概率确认
- //充
- $c_efficiency = $this->randApproximateRate($robot);
- // //放
- // $d_efficiency = $this->randApproximateRate($robot);
- $this->logger->info($robot->id . '本轮充放电概率确认, 充:' . $c_efficiency);// . ' 放:' . $d_efficiency
- //总电量:
- $total_power = $robot->full_charge;
- $this->logger->info($robot->id . "总电量 :" . $total_power);
- //本轮机器人充电和放电时间时长确认 满电量*波动概率 (单位:秒)
- //充
- $charging_c = ceil($total_power * $c_efficiency * 60);
- // //放
- // $efficiency_f = $total_power * $d_efficiency * 60;
- // $this->logger->info($robot->id . "本轮机器人充电放电时间时长确认(单位:秒):" . $charging_c . ' ' . $efficiency_f);
- //所差时段开始时间 和 所差时段结束时间 ,循环放电
- if ($robot->num == 1) {
- $bad_start_periods_time = strtotime($robot->bad_start_periods);
- $bad_end_periods_time = strtotime($robot->bad_end_periods);
- } else {
- $bad_start_periods_time = strtotime(date('Y-m-d') . $robot->bad_start_periods);
- $bad_end_periods_time = strtotime(date('Y-m-d') . $robot->bad_end_periods);
- }
- //电价
- if (!$robot->price || empty($robot->price)) {
- $this->logger->info('注意当前充电站点无单价配置,将用默认配置:' . $robot->id);
- $site_price[] = [
- 'site_id' => $robot->site_id,
- 'start_time' => '00:00:00',
- 'ent_time' => '23:59:59',
- 'price' => 0,
- 'serve_price' => 0,
- ];
- } else {
- $site_price = $robot->price->toArray();
- }
- $is_charge = false;//机器人是否需要充电
- //默认组装
- $dat = [
- // "robot" => $robot->robot->imei,
- // "order" => "",
- // "user" => '',
- // "start_time" => $bad_start_periods_time,
- // "end_time" => "",
- // "time" => 0,//时长
- // "soc" => "",//电量占比
- // "billing" => "",
- // "c_type" => 1,//充电模式
- // "start_soc" => 0,//充电开始度数
- // "end_soc" => 0,//充电结束度数
- "user_id" => '',//用户id
- "open_id" => '',//微信appid
- "customer_phone" => '',//客户电话
- "type" => 2,//1预购订单2点卡充值订单
- "buy_order_id" => '',//预缴费订单id/点卡充值订单id(memberOrderId)
- "site_id" => $robot->site_id,//站点id
- "robot_id" => $robot->robot_id,//机器人id
- "order_no" => '',//系统订单号(必须)
- "charging_pile_id" => $robot->robot->imei,//充电桩id
- "pile_imei" => $robot->robot->imei,//终端 IMEI
- "charge_model" => 5,//充电模式(5 自然充满、10 按电\r\n量、15 按金额)
- // "plan_power"=>null,//计划充电量(kwh) 非自然充满模\r\n式必填
- // "plan_amount"=>null,//计划充电金额,自然充满模式则\r\n为用户余额
- "status" => 2,//订单状态(1进行中,2已结算,3未支付(预留),4完成)
- // "third_order_no"=>'',//三方订单号(记录 ID)
- "duration" => 0,//充电时长(分钟)向上取整-
- "voltage" => 220,//电压
- "electric_current" => 6,//电流
- "power" => 0,//充电量(kwh)-
- "amount" => 0,//订单金额-
- "charging_status" => 15,//充电状态(5: 待充电,10: 充电中,15: 已结束,20: 已取消)
- // "stop_reason"=>'',//结束原因
- // "remark"=>'',//备注
- // "seq"=>'',//三方下发序列号
- // "soc"=>'',//被充车辆 SOC 不一定有
- "create_time" => datetime(),//创建时间
- "update_time" => datetime(),//创建时间
- ];
- //第二步,根据所差时段开始时间 和 所差时段结束时间 ,循环放电
- $start_time = $bad_start_periods_time;
- // $end_time = $dat['start_time'];
- $charging_interval = rand($robot->charging_interval_min * 60, $robot->charging_interval_max * 60);//随机间隔充电时间 单位(秒)
- while (true) {
- $this->logger->info("循环充电");
- $data = $dat;
- $start_time += $charging_interval;//本次机器人放电时间,即车辆充电开始时间
- //本次充电结束时间大于预定时间段,则充电订单生成结束
- if ($start_time > $bad_end_periods_time) {
- break;
- }
- //获取此次充电量KWH
- $rand_soc = rand($robot->charging_time_start * 100, $robot->charging_time_end * 100) / 100;//乘除是为了创造小数
- $this->logger->info($robot->id . '本轮获取此次充电量KWH:' . $rand_soc);
- //获取此次充电效率
- //本轮放电概率确认
- $lde = $this->randApproximateRate($robot);;
- $this->logger->info($robot->id . '本轮充放电概率确认, 放:' . $lde);
- //判断机器人电量是否足够此次放电,要不超出放电
- if ($rand_soc > $total_power) {
- $rand_soc = $total_power;
- //提示本次放完电机器人就需要充电了
- $is_charge = true;
- }
- //如果本次充电量小于3kwh,直接给机器人充电
- if ($rand_soc > self::$charge_minimum_power) {
- //获取本次充电时间 时长 = 电量 * 放电率
- $fc = floatval(bcmul((string)$rand_soc, (string)$lde, 2));
- $duration = ceil($fc);//所需分钟
- $end_time = $start_time + ceil($fc * 60);//所需秒钟
- //电费 = 站点规定当前时段(电费单价 + 服务单价)* 电量
- $amount = 0;
- //根据当前时段,判断电费单价和服务费单价
- //有配置就有配置单价,没有配置用默认
- $t_date_ymd = date('Y-m-d', intval($start_time));
- foreach ($site_price as $v) {
- $t_start_time = strtotime($t_date_ymd . ' ' . $v['start_time']);
- $t_ent_time = strtotime($t_date_ymd . ' ' . $v['ent_time']);
- if ($start_time >= $t_start_time && $t_start_time <= $t_ent_time) {
- $t_price = ($v['price'] == 0) ? $robot->default_electricity_bill : $v['price'];
- $t_serve_price = ($v['serve_price'] == 0) ? $robot->default_service_price : $v['serve_price'];
- $amount = floatval(bcmul((string)$rand_soc, bcadd((string)$t_price, (string)$t_serve_price, 2), 2));
- }
- }
- //如果没有计算,则用默认规定的单价
- if ($amount == 0) {
- $amount = floatval(bcmul((string)$rand_soc, bcadd((string)$robot->default_electricity_bill, (string)$robot->default_service_price, 2), 2));
- }
- //确认用户
- $this_user = $userLists[array_rand($userLists, 1)];
- $data['user_id'] = $this_user['user_id'];//
- $data['open_id'] = $this_user['open_id'];//
- $data['customer_phone'] = $this_user['user']['phone'];//
- $data['buy_order_id'] = $this_user['member_number'];//
- $data['order_no'] = 'TR' . $this->getPrefixData();//
- $data['duration'] = $duration;//
- $data['power'] = $rand_soc;//
- $data['amount'] = $amount;//
- $data['create_time'] = datetime($start_time);//
- $data['update_time'] = datetime($end_time);//
- //机器人容量减少
- $total_power = floatval(bcsub((string)$total_power, (string)$rand_soc, 2));
- //根据占比判断是否保存生成订单:
- if (rand(0, 100) > $robot->occupancy) {
- $this->logger->info("本轮跳过...");
- continue;
- } else {
- $res_data[] = $data;
- }
- }
- //判断是否需要充电
- if ($is_charge) {
- $start_time += $charging_c;
- //刷新 下轮充放电概率确认
- //充
- $c_efficiency = $this->randApproximateRate($robot);
- // //放
- // $d_efficiency = $this->randApproximateRate($robot);
- //总电量:
- $total_power = $robot->full_charge;
- //下轮机器人充电和放电时间时长确认 满电量*波动概率 (单位:秒)
- //充
- $charging_c = ceil($total_power * $c_efficiency * 60);
- // //放
- // $efficiency_f = $total_power * $d_efficiency * 60;
- $this->logger->info(PHP_EOL . $robot->id . '下轮充放电概率确认, 充:' . $c_efficiency);
- $is_charge = false;
- }
- }
- if (!empty($res_data)) {
- Db::beginTransaction();
- try {
- $t_id = 0;
- foreach ($res_data as $da) {
- $t_id = RTradeOrderModel::insertGetId($da);
- }
- $this->logger->info(datetime() . ' ' . $robot->id . ' 生成成功: ' . ($t_id ? 'true' : 'false') . PHP_EOL . PHP_EOL);
- if ($robot->num == 1) {
- RRobotAutoOrderModel::where('id', $robot->id)->update(['num' => 2]);
- }
- Db::commit();
- } catch (\Exception $e) {
- Db::rollBack();
- $this->logger->error(datetime() . ' ' . $robot->id . '生成失败: ' . $e->getMessage() . PHP_EOL . PHP_EOL);
- }
- }
- }
- }
- return true;
- }
- /**
- * Desc: 随机概率
- * Author: Spt <2864934511@qq.com>
- * Date: 2024-03-13 15:57
- * @param $robot
- * @return float|int
- */
- private function randApproximateRate($robot): float|int
- {
- return (rand(intval($robot->charging_efficiency_min * 100), intval($robot->charging_efficiency_max * 100))) / 100;
- }
- /**
- * Desc: 自动生成前缀
- * Author: Spt <2864934511@qq.com>
- * Date: 2024-03-12 15:41
- * @param string $prefix
- * @return string
- */
- private function getPrefixData(string $prefix = ''): string
- {
- return $prefix . date("YmdHis") . rand(0, 9999);
- }
- /**
- * Desc: 格式化时间格式为: *分*秒
- * Author: Spt <2864934511@qq.com>
- * Date: 2024-03-13 16:39
- * @param $seconds
- * @return string
- */
- private function convertSecondsToMinutesAndSeconds($seconds): string
- {
- $minutes = intval($seconds / 60);
- $remainingSeconds = $seconds % 60;
- $paddedSeconds = str_pad((string)$remainingSeconds, 2, '0', STR_PAD_LEFT); // 在左侧用0填充,直到长度为2
- return $minutes . '分' . $paddedSeconds . '秒';
- }
- }
|