|
@@ -0,0 +1,344 @@
|
|
|
|
|
+<?php
|
|
|
|
|
+declare(strict_types=1);
|
|
|
|
|
+
|
|
|
|
|
+namespace App\Crontab;
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+use App\Model\RRobotAutoOrderModel;
|
|
|
|
|
+use App\Model\RTradeOrderModel;
|
|
|
|
|
+use App\Model\TEmployeeMemberModel;
|
|
|
|
|
+use App\Model\TEmployeeModel;
|
|
|
|
|
+use Carbon\Carbon;
|
|
|
|
|
+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: "0 *\/1 * * *", name: "SckwChgrobot", callback: "execute", memo: "自动生成订单任务每天一次", enable: "isEnable")]
|
|
|
|
|
+class SckwChgrobotCrontab
|
|
|
|
|
+{
|
|
|
|
|
+// /**
|
|
|
|
|
+// * 定时任务唯一标识
|
|
|
|
|
+// */
|
|
|
|
|
+// protected const code = 'auto_order_crontab';
|
|
|
|
|
+
|
|
|
|
|
+ #[Inject]
|
|
|
|
|
+ private StdoutLoggerInterface $logger;
|
|
|
|
|
+
|
|
|
|
|
+ private static array $users = [
|
|
|
|
|
+ 'oJdn-7JDOOCzlOgS6rE5CsXw_PbM',//pdy
|
|
|
|
|
+// '',//
|
|
|
|
|
+ ];
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 充电最低标准电量
|
|
|
|
|
+ * @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
|
|
|
|
|
+ {
|
|
|
|
|
+
|
|
|
|
|
+ //插入测试员工 - ok
|
|
|
|
|
+ //INSERT INTO `t_employee`(`employee_id`, `system_type`, `login_name`, `login_pwd`, `open_id`, `actual_name`, `birthday`, `phone`, `remark`) VALUES (87, 5, '18589088034', '18589088034', 'oJdn-7JDOOCzlOgS6rE5CsXw_PbM', 'pdy', '2001-02-01 14:37:37', '18589088034', '测试号,不删除');
|
|
|
|
|
+ //插入测试员工会员卡 - ok
|
|
|
|
|
+ //INSERT INTO `r_member_order`(`id`, `open_id`, `type`, `user_id`, `order_no`, `member_no`, `end_time`, `create_time`, `update_time`, `status`, `del_flag`, `member_facility_id`) VALUES (NULL, 'oJdn-7JDOOCzlOgS6rE5CsXw_PbM', 1, 87, 'M2024031316352413', '202403131437082', '2024-03-15 16:35:24', '2024-03-08 16:35:24', '2024-03-08 16:35:24', 0, 0, NULL);
|
|
|
|
|
+ //INSERT INTO `r_employee_member`(`open_id`, `user_id`, `member_number`, `create_time`, `update_time`, `end_time`) VALUES ('oJdn-7JDOOCzlOgS6rE5CsXw_PbM', 87,'202403131437082','2024-03-13 14:34:01','2024-03-13 14:34:03','2029-04-01 14:34:05') ;
|
|
|
|
|
+ //
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ //获取所有任务
|
|
|
|
|
+ $list = RRobotAutoOrderModel::with(['robot', 'site', 'price'])
|
|
|
|
|
+ ->where('num', '<', 2)//执行次数0无限1一次超过1则不执行
|
|
|
|
|
+ ->where('del_flag', 0)
|
|
|
|
|
+ ->get();
|
|
|
|
|
+ if ($list->isNotEmpty()) {
|
|
|
|
|
+ //获取所有可用人员
|
|
|
|
|
+ $userLists = TEmployeeMemberModel::with(['user'])
|
|
|
|
|
+ ->whereIn('open_id', self::$users)//openid 范围查询
|
|
|
|
|
+ ->where('del_flag', 0)//是否删除0否 1是
|
|
|
|
|
+ ->get();
|
|
|
|
|
+ if ($userLists->isEmpty()) {
|
|
|
|
|
+ $this->logger->error(' 查无会员用户:' . json_encode(self::$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" => 4,//订单状态(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 . PHP_EOL . $robot->id . '下轮充放电概率确认, 充:' . $c_efficiency);
|
|
|
|
|
+
|
|
|
|
|
+ $is_charge = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!empty($res_data)) {
|
|
|
|
|
+ Db::beginTransaction();
|
|
|
|
|
+ try {
|
|
|
|
|
+ var_dump(json_encode($res_data, JSON_UNESCAPED_UNICODE));
|
|
|
|
|
+// $res = (new \App\Model\RTradeOrderModel)->save($res_data);
|
|
|
|
|
+ $t_id = 0;
|
|
|
|
|
+ foreach ($res_data as $da) {
|
|
|
|
|
+ $t_id = RTradeOrderModel::insertGetId($da);
|
|
|
|
|
+ }
|
|
|
|
|
+ $this->logger->info(datetime() . ' ' . $robot->id . ' 生成成功: ' . ($t_id ? 'true' : 'false'));
|
|
|
|
|
+ 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());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ 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 . '秒';
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|