This commit is contained in:
parent
ea7ad218c6
commit
9f05d996e7
|
@ -18,6 +18,9 @@
|
|||
<!-- <div class="right-menu-item hover-effect">
|
||||
<el-button @click="drawer = true">QA常见问题</el-button>
|
||||
</div>-->
|
||||
<div v-if="$store.getters.is_anchor" class="right-menu-item hover-effect">
|
||||
<el-button @click="dialogWorks = true">预约待处理(10)</el-button>
|
||||
</div>
|
||||
<div v-if="$store.getters.is_anchor" class="right-menu-item hover-effect">
|
||||
<el-button @click="dialogWorks = true">排班{{ $store.getters.name }}</el-button>
|
||||
</div>
|
||||
|
|
|
@ -94,8 +94,9 @@
|
|||
style="width: 120px"
|
||||
>
|
||||
<el-option key="" label="请选择" value="" />
|
||||
<el-option key="1" label="已预约" value="1" />
|
||||
<el-option key="0" label="未预约" value="0" />
|
||||
<el-option key="1" label="已预约(未处理)" value="1" />
|
||||
<el-option key="2" label="已预约(已处理)" value="2" />
|
||||
</el-select>
|
||||
|
||||
<el-button
|
||||
|
@ -169,6 +170,14 @@
|
|||
>
|
||||
同步
|
||||
</el-button>
|
||||
|
||||
<el-button v-if="scope.row.appointment_status == 1"
|
||||
size="small"
|
||||
icon="el-icon-edit"
|
||||
@click="onOneClickYyHandle(scope.row)"
|
||||
>
|
||||
预约已处理
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -240,7 +249,7 @@
|
|||
}"
|
||||
type="primary"
|
||||
>
|
||||
{{ scope.row.appointment_status == 1 ? "已预约" : "未预约" }}
|
||||
{{ scope.row.appointment_status == 1 ? "已预约(未处理)" : (scope.row.appointment_status == 2 ? "已预约(已处理)":"未预约") }}
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
@ -462,6 +471,13 @@
|
|||
}}</el-radio>
|
||||
</template>
|
||||
</el-form-item>
|
||||
<el-form-item label="预约跟进状态">
|
||||
<template v-for="(v, k) in status_arr">
|
||||
<el-radio v-if="k > 0" v-model="item.status" :label="k" border>{{
|
||||
v
|
||||
}}</el-radio>
|
||||
</template>
|
||||
</el-form-item>
|
||||
<!-- <el-form-item label="快捷跟进" style="width: 600px;">
|
||||
<el-select v-model="value" placeholder="请选择" @change="onChange">
|
||||
<el-form-item style="display: inline-flex;text-align: left;width: 770px;">
|
||||
|
@ -926,6 +942,25 @@ export default {
|
|||
});
|
||||
});
|
||||
},
|
||||
onOneClickYyHandle(item) {
|
||||
this.$axios
|
||||
.post("/admin/order/changeAppointmentStatus", { id: item.id })
|
||||
.then((res) => {
|
||||
this.dialogVisible = false;
|
||||
this.$notify({
|
||||
title: "成功",
|
||||
message: "已处理",
|
||||
type: "success",
|
||||
});
|
||||
// this.getList();
|
||||
})
|
||||
.catch((err) => {
|
||||
this.$notify.error({
|
||||
title: "错误",
|
||||
message: err,
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -38,8 +38,8 @@ module.exports = {
|
|||
},
|
||||
proxy: {
|
||||
'/dev-api': { // 接口地址 以 api开头的都走下面的配置
|
||||
target: 'https://www.szjinao.cn', // 代理目标地址为后端服务器地址 127.0.0.1 192.168.1.2
|
||||
// target: 'http://192.168.1.4:8787', // 代理目标地址为后端服务器地址 127.0.0.1 192.168.1.2
|
||||
// target: 'https://www.szjinao.cn', // 代理目标地址为后端服务器地址 127.0.0.1 192.168.1.2
|
||||
target: 'http://192.168.0.6:8787', // 代理目标地址为后端服务器地址 127.0.0.1 192.168.1.2
|
||||
ws: true, // 是否支持 websocket 请求 支持
|
||||
changeOrigin: true, // 是否启用跨域
|
||||
pathRewrite: {
|
||||
|
|
|
@ -71,6 +71,7 @@ class IndexController extends base
|
|||
// 跟进提醒
|
||||
$followMessage = 0;
|
||||
$followOrderId = '';
|
||||
$appointmentNum = 1;
|
||||
if ($request->admin->id > 1) {
|
||||
$start = strtotime(date('Y-m-d')) * 1000;
|
||||
$end = strtotime(date('Y-m-d', strtotime('+1 days'))) * 1000 - 1;
|
||||
|
@ -82,9 +83,14 @@ class IndexController extends base
|
|||
if ($followMessage) {
|
||||
$followOrderId = $followMessageList[0]['id'];
|
||||
}
|
||||
|
||||
// 预约未处理数量
|
||||
$appointmentNum = Orders::where(['admin_id' => $request->admin->id])
|
||||
->where('appointment_status', 1)
|
||||
->count();
|
||||
}
|
||||
|
||||
return $this->success(['new' => $new ?? 0, 'follow' => $follow, 'back' => $backs, 'order_write_off' => $orderWriteOff, 'follow_message' => $followMessage, 'follow_order_id' => $followOrderId]);
|
||||
return $this->success(['new' => $new ?? 0, 'follow' => $follow, 'back' => $backs, 'order_write_off' => $orderWriteOff, 'follow_message' => $followMessage, 'follow_order_id' => $followOrderId, 'appointment_num' => $appointmentNum]);
|
||||
}
|
||||
|
||||
public function line()
|
||||
|
|
|
@ -165,6 +165,8 @@ class OrderController extends base
|
|||
$statss = Orders::AllOssStatus;
|
||||
}elseif($key ==5) {
|
||||
$statss = Orders::DouyinStatus;
|
||||
}elseif($key ==6) {
|
||||
$statss = Orders::TongchengStatus;
|
||||
}
|
||||
|
||||
$_ch = [];
|
||||
|
@ -585,4 +587,39 @@ class OrderController extends base
|
|||
return $this->error(2006, '出错了:' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 预约处理
|
||||
* @param Request $request
|
||||
* @return \support\Response
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
public function changeAppointmentStatus(Request $request)
|
||||
{
|
||||
try {
|
||||
$ids = $request->post('id', 0);
|
||||
$idArr = explode(',', $ids);
|
||||
|
||||
$flow = [];
|
||||
foreach ($idArr as $id) {
|
||||
Log::info('同步订单ID:' . $id);
|
||||
|
||||
$order = Orders::where('id', $id)->find();
|
||||
|
||||
if (empty($order)) {
|
||||
return $this->error(2004, '记录没有找到.');
|
||||
}
|
||||
|
||||
// 订单是待使用状态,先同步第三方状态
|
||||
$order['appointment_status'] = 2;
|
||||
$order->save();
|
||||
}
|
||||
|
||||
return $this->success(implode("\n", $flow));
|
||||
}catch(\Exception $e) {
|
||||
return $this->error(2006, '出错了:' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -425,7 +425,7 @@ class SpiderDy extends Command
|
|||
{
|
||||
$back = Redis::set('SpiderMt:reload:dy:lock', time(), 'EX', 3600 * 8, 'NX');
|
||||
if (!$back) return;
|
||||
$orders = Orders::where('create_at', '<=', (time() - 15 * 24 * 3600) * 1000)->where('os', 3)->wherein('status', [1, 2, 3])->select();
|
||||
$orders = Orders::where('create_at', '<=', (time() - 15 * 24 * 3600) * 1000)->whereIn('os', [3, 5])->wherein('status', [1, 2, 3])->select();
|
||||
foreach ($orders as $order) {
|
||||
$this->reloadStatus($order->sn, $order->os, $output);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,408 @@
|
|||
<?php
|
||||
|
||||
namespace app\command;
|
||||
|
||||
use app\admin\controller\AdminController;
|
||||
use app\model\Admins;
|
||||
use app\model\Blacks;
|
||||
use app\model\Finances;
|
||||
use app\model\Logs;
|
||||
use app\model\Orders;
|
||||
use app\server\Douyin;
|
||||
use app\server\Meituan;
|
||||
use app\server\Kuaishou;
|
||||
use app\server\Orders as ServerOrders;
|
||||
use app\server\SMS;
|
||||
use app\server\Tongcheng;
|
||||
use stdClass;
|
||||
use support\Log;
|
||||
use support\Redis;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputDefinition;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* 同程数据拉取
|
||||
*/
|
||||
class SpiderTc extends Command
|
||||
{
|
||||
protected static $defaultName = 'spider:tc';
|
||||
protected static $defaultDescription = '同程订单拉取器';
|
||||
|
||||
protected $_users = [];
|
||||
|
||||
protected function configure()
|
||||
{
|
||||
$this->setName('spider:tc')
|
||||
->setDescription('同程订单拉取器')
|
||||
->setDefinition(
|
||||
new InputDefinition(array(
|
||||
new InputOption('sn', 'sn', InputOption::VALUE_REQUIRED),
|
||||
new InputOption('os', 'os', InputOption::VALUE_REQUIRED),
|
||||
new InputOption('day', 'day', InputOption::VALUE_REQUIRED)
|
||||
))
|
||||
);
|
||||
}
|
||||
|
||||
protected function users($routeType)
|
||||
{
|
||||
// if (count($this->_users) > 0) return $this->_users;
|
||||
$users = Admins::where('status', 1)->where('is_order', 1)->where('route_type', $routeType)->select();
|
||||
$us = [];
|
||||
foreach ($users as $u) {
|
||||
$ru = Redis::get('CRM:USER:ONLINE:' . $u->id);
|
||||
if (empty($ru)) continue;
|
||||
|
||||
$_u = new stdClass();
|
||||
$_u->username = $u->id;
|
||||
$us[] = $_u;
|
||||
};
|
||||
$this->_users = $us;
|
||||
return $this->_users;
|
||||
}
|
||||
|
||||
protected $_redis_pool = [];
|
||||
|
||||
protected function poolUser($status = 0, $categoryDesc = '')
|
||||
{
|
||||
$routeType = AdminController::ROUTE_LISTS[mb_substr($categoryDesc, 0, 2)] ?? 10;
|
||||
$status .= $routeType;
|
||||
if (empty($this->_redis_pool[$status])) {
|
||||
$this->_redis_pool[$status] = Redis::hGetAll('CRM:Pool:' . $status);
|
||||
$users = $this->users($routeType);
|
||||
$_users = [];
|
||||
if (empty($this->_redis_pool[$status])) {
|
||||
foreach ($users as $user) {
|
||||
$_users[$user->username] = 0;
|
||||
Redis::hSet('CRM:Pool:' . $status, $user->username, 0);
|
||||
}
|
||||
$this->_redis_pool[$status] = $_users;
|
||||
} else {
|
||||
asort($this->_redis_pool[$status]);
|
||||
$key_users = array_keys($this->_redis_pool[$status]);
|
||||
$username = $key_users[0];
|
||||
$max = $this->_redis_pool[$status][$username];
|
||||
$_users = [];
|
||||
foreach ($users as $user) {
|
||||
$_users[] = $user->username;
|
||||
if (!in_array($user->username, $key_users)) {
|
||||
$this->_redis_pool[$status][$username] = $max;
|
||||
Redis::hSet('CRM:Pool:' . $status, $user->username, $max);
|
||||
}
|
||||
}
|
||||
foreach ($this->_redis_pool[$status] as $username => $val) {
|
||||
if (!in_array($username, $_users)) {
|
||||
unset($this->_redis_pool[$status][$username]);
|
||||
Redis::hDel('CRM:Pool:' . $status, $username);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$username = null;
|
||||
try {
|
||||
$pool = $this->_redis_pool[$status];
|
||||
if (empty($pool)) $pool = [];
|
||||
asort($pool);
|
||||
$keys = array_keys($pool);
|
||||
// if(!!config('app.debug', true)) return 1;
|
||||
if (empty($keys)) {
|
||||
Log::error(dirname(__FILE__) . __LINE__ . '没有可以分配的用户');
|
||||
throw new \Exception('没有可以分配的用户');
|
||||
}
|
||||
$username = $keys[0];
|
||||
$this->_redis_pool[$status][$username] += 1;
|
||||
Redis::hIncrBy('CRM:Pool:' . $status, $username, 1);
|
||||
} catch (\Exception $e) {
|
||||
Log::error(dirname(__FILE__) . __LINE__ . '没有可以分配的用户', (array)json_encode($e));
|
||||
throw new \Exception('没有可以分配的用户');
|
||||
}
|
||||
return $username;
|
||||
}
|
||||
|
||||
/** @var InputInterface $output */
|
||||
protected $output;
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param OutputInterface $output
|
||||
* @return int
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
// $name = $input->getArgument('name');
|
||||
$this->output = $output;
|
||||
$output->writeln('START spider:tc:'.date('Y-m-d H:i:s'));
|
||||
|
||||
$os = $input->getOption('os');
|
||||
$orderid = $input->getOption('sn');
|
||||
$d = $input->getOption('day');
|
||||
if (empty($d)) {
|
||||
$d = 40;
|
||||
}
|
||||
|
||||
if ($orderid) {
|
||||
$this->reloadStatus($orderid, $os, $output);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// echo "状态1\n";
|
||||
// $this->poolUser(1);
|
||||
// echo "状态2\n";
|
||||
// $this->poolUser(2);
|
||||
// echo "状态3\n";
|
||||
// $this->poolUser(3);
|
||||
// echo "状态4\n";
|
||||
// $this->poolUser(4);
|
||||
// echo "状态5\n";
|
||||
// $this->poolUser(5);
|
||||
// return 1;
|
||||
|
||||
// $this->checks($output);
|
||||
// $output->writeln('CHECK spider:dy');
|
||||
|
||||
// $day = new Douyin();
|
||||
// print_r($day->get(1));
|
||||
// return 1;
|
||||
|
||||
// sleep(5);
|
||||
// $time = strtotime(date('Y-m-d'));
|
||||
// for ($i = 0; $i <= $d; $i++) {
|
||||
// $day = $time - $i * 24 * 3600;
|
||||
// $start = date('Y-m-d', $day);
|
||||
// $end = date('Y-m-d 23:59:59', $day);
|
||||
// $this->orders($start, $end, false);
|
||||
// // $this->_kuaishouOrder($start, $end, false);
|
||||
// }
|
||||
|
||||
// 8点20 开始分配订单
|
||||
date_default_timezone_set('Asia/Shanghai');
|
||||
$startTime = strtotime(date('Y-m-d 08:20'));
|
||||
if (time() > $startTime) {
|
||||
$start = date('Y-m-d 00:00:00', strtotime("-{$d} days"));
|
||||
$end = date('Y-m-d 23:59:59');
|
||||
$this->orders($start, $end, false);
|
||||
}
|
||||
|
||||
if (date('H') >= 1 && date('H') <= 7) {
|
||||
$this->reload($output);
|
||||
}
|
||||
|
||||
$output->writeln('END spider:tc:'.date('Y-m-d H:i:s'));
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
private function orders($start = null, $end = null, $order_id = false)
|
||||
{
|
||||
foreach (Orders::OSS as $k => $os) {
|
||||
$pages = 6;
|
||||
$page = 1;
|
||||
while (true) {
|
||||
if ($page > $pages) break;
|
||||
$list = [];
|
||||
|
||||
switch ($k) {
|
||||
case 6:
|
||||
try {
|
||||
$dou = new Tongcheng($k);
|
||||
$list = $dou->get($page, $start, $end, '');
|
||||
$this->output->writeln('test:' . json_encode($list));
|
||||
$pages = $dou->totalPage;
|
||||
} catch (\Exception $e) {
|
||||
$this->output->writeln('error:' . $e->getMessage());
|
||||
Log::error(dirname(__FILE__) . __LINE__ . $e);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
# code...
|
||||
break;
|
||||
}
|
||||
|
||||
foreach ($list as $order) {
|
||||
$item = Orders::where('os', $order->os)->where('sn', $order->sn)->find();
|
||||
|
||||
if (empty($item)) {
|
||||
$order->is_zhibo = 2;
|
||||
|
||||
$oldMobile = orders::where("os", $order->os)->where("mobile", $order->mobile)
|
||||
->where("create_time", '>=', time() - 24 * 3600 * 3)->find();
|
||||
|
||||
if (!empty($oldMobile)) {
|
||||
$admin_id = $oldMobile->admin_id;
|
||||
} else {
|
||||
$admin_id = $this->poolUser($order->orderStatus, $order->category_desc);
|
||||
}
|
||||
|
||||
if (empty($admin_id)) return null;
|
||||
$order->admin_id = $admin_id;
|
||||
$order->give_time = time();
|
||||
|
||||
//判断是否需要发短信 200-待使用,205-预约中(抖音),210-已预约(抖音),310-已履约(抖音),300-已完成
|
||||
if (in_array($order->order_status, [200, 205, 210, 310, 300]) ) {
|
||||
$this->sms($admin_id, $order);
|
||||
}
|
||||
//新获得一个用户的,提示管理员有新的订单
|
||||
Redis::incrBy('CRM:USER:ONLINE:NEW:' . $admin_id, 1);
|
||||
$item = new Orders();
|
||||
}
|
||||
|
||||
if ($order->travel_date && empty($order->travel_end)) {
|
||||
$days = $this->_days($order);
|
||||
if ($days) {
|
||||
$order->travel_end = date('Y-m-d 00:00:00', strtotime($order->travel_date) + $days * 24 * 3600);
|
||||
}
|
||||
}
|
||||
|
||||
if ($item->order_status !== 2 && $order->order_status == 2) {
|
||||
Redis::incrBy('CRM:USER:WRITE:OFF:' . $item->admin_id, 1);
|
||||
}
|
||||
|
||||
$back = $item->save($order->toArray());
|
||||
|
||||
if ($back) {
|
||||
$this->_finance(0, $item->id, $item->asset_price);
|
||||
}
|
||||
}
|
||||
|
||||
// 数据小于50, 结束
|
||||
if (count($list) < 50) {
|
||||
break;
|
||||
}
|
||||
$page++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function reload($output)
|
||||
{
|
||||
$back = Redis::set('SpiderMt:reload:dy:lock', time(), 'EX', 3600 * 8, 'NX');
|
||||
if (!$back) return;
|
||||
$orders = Orders::where('create_at', '<=', (time() - 15 * 24 * 3600) * 1000)->where('os', 6)->wherein('status', [1, 2, 3])->select();
|
||||
foreach ($orders as $order) {
|
||||
$this->reloadStatus($order->sn, $order->os, $output);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $admin_id
|
||||
* @param $order
|
||||
* @throws \think\db\exception\DataNotFoundException
|
||||
* @throws \think\db\exception\DbException
|
||||
* @throws \think\db\exception\ModelNotFoundException
|
||||
*/
|
||||
private function sms($admin_id, $order) {
|
||||
$user = Admins::cache(true)->where('id', $admin_id)->find();
|
||||
$templateId = 264956;// 261607
|
||||
if ((!config('app.debug', true) || config('app.debug', true) === 'false') && (time() * 1000 - $order->create_at) / 1000 < 2 * 24 * 3600) {
|
||||
echo "发送短信\n";
|
||||
print_r([$order->mobile, $templateId, ['title' => $order->product_name, 'mobile' => $user->mobile]]);
|
||||
$has = Blacks::where('mobile', $order->mobile)->find();
|
||||
if (empty($has) && !empty($order->mobile)) {
|
||||
SMS::juhe_sms_send($order->mobile, $templateId, ['title' => $order->product_name, 'mobile' => $user->mobile]);
|
||||
} else {
|
||||
echo "黑名单不发送短信\n";
|
||||
sleep(10);
|
||||
}
|
||||
|
||||
} else {
|
||||
echo "不发送短信\n";
|
||||
print_r([$order->mobile, $templateId, ['title' => $order->product_name, 'mobile' => $user->mobile]]);
|
||||
}
|
||||
}
|
||||
|
||||
private function reloadStatus($orderid, $os, $output)
|
||||
{
|
||||
$w[] = ['sn', '=', $orderid];
|
||||
if ($os) $w[] = ['os', '=', $os];
|
||||
$item = Orders::where($w)->find();
|
||||
if (empty($item)) {
|
||||
$output->writeln('没有找到订单');
|
||||
}
|
||||
|
||||
$m = new Tongcheng($os);
|
||||
$it = $m->get(1, null, null, $item->sn);
|
||||
|
||||
|
||||
if ($it) {
|
||||
$back = $item->save($it[0]);
|
||||
if ($back) {
|
||||
$this->_finance(0, $item->id, $item->asset_price);
|
||||
}
|
||||
} else {
|
||||
$output->writeln('没有拉取到数据:' . $orderid);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function _days($order)
|
||||
{
|
||||
if (stripos($order->product_name, '一日') !== false) {
|
||||
return 1;
|
||||
}
|
||||
preg_match('/(\d)天/', $order->product_name, $all);
|
||||
if (!empty($all) && intval($all[1]) > 0) {
|
||||
return $all[1];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function zhibo($title, $os = 0)
|
||||
{
|
||||
if ($os == 3) {
|
||||
|
||||
return 2;
|
||||
}
|
||||
if (
|
||||
strlen($title) - 3 == strripos($title, "!")
|
||||
|| strlen($title) - 1 == strripos($title, "!")
|
||||
) {
|
||||
return 1;
|
||||
} elseif (strlen($title) - 3 == strripos($title, "甄")) {
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function _finance($type = 1, $order_id = 0, $price = 0)
|
||||
{
|
||||
// $fa = Finances::where('order_id', $order_id)->where('type', $type)->find();
|
||||
$back = Redis::set('CRM:ORDER:LOCK:' . $order_id, time(), 'EX', 6, 'NX');
|
||||
if (!$back) return;
|
||||
|
||||
$total = Finances::where('order_id', $order_id)->sum('total'); //总的关于这个订单的金额
|
||||
//如果总金额大于提交上来的核销金额,那就是退费的
|
||||
//如果提交上来的金额小于总金额,那就是核销的
|
||||
if ($total > $price) {
|
||||
$type = 2;
|
||||
$fee = -($total - $price);
|
||||
} elseif ($total < $price) {
|
||||
$type = 1;
|
||||
$fee = $price - $total;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
Finances::create([
|
||||
'order_id' => $order_id,
|
||||
'type' => $type,
|
||||
'total' => $fee,
|
||||
'status' => 1
|
||||
]);
|
||||
return;
|
||||
|
||||
// if(empty($fa)) {
|
||||
// if($type == 2) {
|
||||
// $has = Finances::where('order_id', $order_id)->where('type', 1)->find();
|
||||
// if(empty($has)) return;
|
||||
// }
|
||||
// Finances::create([
|
||||
// 'order_id' => $order_id,
|
||||
// 'type' => $type,
|
||||
// 'total' => $price,
|
||||
// 'status' => 1
|
||||
// ]);
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -16,6 +16,9 @@ class Orders extends base
|
|||
const DouyinReservationStatus = [1 => '未预约', 2 => '待接单', 3 => '已预约', 4 => '已取消', 5 => '已完成', 6 => '取消/退款申请'];
|
||||
const DouyinStatus = [1 => '未核销', 2 => '已核销', 3 => '申请退款中', 4 => '已退款', 5 => '部分核销'];
|
||||
|
||||
// 订单状态(100 - 待付款,150-用户取消,200-待使用,205-预约中(抖音),210-已预约(抖音),310-已履约(抖音),300-已完成,400-已关闭)
|
||||
const TongchengStatus = [100 => '待付款', 150 => '用户取消', 200 => '待使用', 205 => '预约中(抖音)', 210 => '已预约(抖音)', 310 => '已履约(抖音)', 300 => '已完成', 400 => '已关闭'];
|
||||
|
||||
const AllOssStatus = [1 => '待使用', 2 => '已核销', 3 => '已退款'];
|
||||
// 全部 未核销 已核销 已退款 未付款 已取消 待支付 申请退款中 部分核销
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
|
@ -27,7 +30,7 @@ class Orders extends base
|
|||
];
|
||||
|
||||
const StatusName = ['待跟进', '跟进中', '已核销', '核销失败', '放弃跟单'];
|
||||
const OSS = [1 => '美团', 2 => '快手', 3 => '抖音(甄选)', '5' => '抖音(新国旅)', 4 => '全平台'];
|
||||
const OSS = [1 => '美团', 2 => '快手', 3 => '抖音(甄选)', '5' => '抖音(新国旅)', '6' => '同程', 4 => '全平台'];
|
||||
|
||||
const timeType = ['create_time' => '添加记录时间', 'update_time' => '修改记录时间', 'last_follow' => '最后跟进时间', 'next_follow' => '下次跟进时间', 'travel_date' => '出行时间', 'create_at' => '下单时间'];
|
||||
|
||||
|
@ -39,6 +42,10 @@ class Orders extends base
|
|||
return self::OrderStatus[$this->order_status] ?? '未知';
|
||||
elseif ($this->os == 3)
|
||||
return self::DouyinStatus[$this->order_status] ?? '未知';
|
||||
elseif ($this->os == 5)
|
||||
return self::DouyinStatus[$this->order_status] ?? '未知';
|
||||
elseif ($this->os == 6)
|
||||
return self::TongchengStatus[$this->order_status] ?? '未知';
|
||||
else
|
||||
return self::KuaishouStatus[$this->order_status] ?? '未知';
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ class Orders {
|
|||
$got = $it[0];
|
||||
|
||||
// 查询未预约状态
|
||||
if ($order->appointment_status != 1) {
|
||||
if ($order->appointment_status == 0) {
|
||||
$appointment_status = $dy->_orderMakeAppointmentStatus($order->sn);
|
||||
if ($appointment_status !== null) {
|
||||
$got['appointment_status'] = 1;
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
<?php
|
||||
|
||||
namespace app\server;
|
||||
|
||||
use app\model\Orders;
|
||||
use Exception;
|
||||
use support\Log;
|
||||
use support\Redis;
|
||||
use think\db\exception\DataNotFoundException;
|
||||
use think\db\exception\DbException;
|
||||
use think\db\exception\ModelNotFoundException;
|
||||
|
||||
/**
|
||||
* 同程订单处理
|
||||
*/
|
||||
class Tongcheng {
|
||||
private $os = '';
|
||||
protected $cookie;
|
||||
private $gate = 'https://ebk.17u.cn';
|
||||
public $totalPage = 6;
|
||||
|
||||
public function __construct($os = 6)
|
||||
{
|
||||
$this->cookie = $this->_cookie();
|
||||
$this->os = $os;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ModelNotFoundException
|
||||
* @throws DataNotFoundException
|
||||
* @throws DbException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function get($page, $start = null, $end = null, $orderId = '')
|
||||
{
|
||||
if (empty($start) || empty($end)) {
|
||||
$start = date('Y-m-d 00:00:00');
|
||||
$end = date('Y-m-d 23:59:59');
|
||||
}
|
||||
|
||||
if ($orderId) {
|
||||
$start = $end = null;
|
||||
}
|
||||
|
||||
$_list = [];
|
||||
$list = $this->_certificateList($start, $end, $page, $orderId);
|
||||
if (empty($list->data->list) || $list->code != 1000) {
|
||||
$this->totalPage = 1;
|
||||
return $_list;
|
||||
}
|
||||
Log::info($start . '--' . $end . " 同程 page:{$page} total_count:" . $list->data->totalCount . " page_count:" . $list->data->totalPage);
|
||||
|
||||
foreach ($list->data->list as $order) {
|
||||
Log::info("同程 订单号:{$order->orderId} \n\n");
|
||||
|
||||
// $orderDetail = $this->_orderDetail($order->order_id, $order->status);
|
||||
// if (empty($orderDetail)) {
|
||||
// Log::info("同程 订单详情拉取失败:{$order->order_id}");
|
||||
// throw new Exception("同程拉单{$order->order_id}详情获取失败");
|
||||
// }
|
||||
|
||||
$item = new Orders();
|
||||
$item->os = $this->os;
|
||||
$item->sn = $order->orderId;
|
||||
$item->product_id = $order->lineId;
|
||||
$item->product_name = $order->title;
|
||||
$item->category_id = $order->agentFinderId;
|
||||
$item->category_desc = $order->agentFinderNickname;
|
||||
$item->create_at = strtotime($order->createTime) * 1000;
|
||||
$item->mobile = $order->mobile;
|
||||
$item->travel_date = null;
|
||||
$item->total_price = $order->orderAmount;
|
||||
$item->quantity = $order->productCount;
|
||||
$item->unit_price = bcdiv($order->orderAmount, $order->productCount, 2);
|
||||
$item->actual_price = $order->orderAmount;
|
||||
$item->order_status = $order->orderStatus; // 订单状态(100 - 待付款,150-用户取消,200-待使用,205-预约中(抖音),210-已预约(抖音),310-已履约(抖音),300-已完成,400-已关闭)
|
||||
$item->appointment_status = in_array($order->orderStatus, [210, 310, 300]) ? 1 : 0; // 是否已预约
|
||||
|
||||
$item->asset_status = $order->status ?? 0; // 核销状态
|
||||
$item->asset_price = $order->orderStatus == 300 ? $order->orderAmount : 0; // 核销金额
|
||||
//抖音的核销金额需要查核销订单
|
||||
|
||||
$_list[] = $item;
|
||||
}
|
||||
|
||||
return $_list; //返回半成品
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function _certificateList($start, $end, $page, $orderId)
|
||||
{
|
||||
$params = [
|
||||
'begin' => $start,// 开始时间,格式:2024-09-01 00:00:00
|
||||
'end' => $end,// 结束时间 格式:2024-09-01 00:00:00
|
||||
'orderStatus' => "",// 订单状态
|
||||
'current' => $page, // 当前数量
|
||||
'size' => 50, // 显示数量
|
||||
'orderId' => $orderId, // 订单号
|
||||
];
|
||||
$this->_getRetriesLock();
|
||||
|
||||
$list = $this->_curl("/merchant/api/market-live/wxVideoV2/supplierOrderByPage", $params, 'POST');
|
||||
if (empty($list) || $list->code != 1000) {
|
||||
$this->_getRetriesLock();
|
||||
$list = $this->_curl("/merchant/api/market-live/wxVideoV2/supplierOrderByPage", $params, 'POST');
|
||||
if (empty($list) || $list->status_code != 0) {
|
||||
Log::error('===查询时间:' . $start . '--' . $end . '====certificate_list: ' . json_encode($list));
|
||||
throw new Exception("同程拉单失败,Err:" . json_encode($list));
|
||||
}
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function _getRetriesLock(): bool
|
||||
{
|
||||
$pattern = 'php webman spider:tc';
|
||||
$maxProcesses = 8;
|
||||
$this->_killMiddleProcesses($pattern, $maxProcesses);
|
||||
|
||||
|
||||
$maxRetries = 5;
|
||||
$retries = 0;
|
||||
while ($retries < $maxRetries) {
|
||||
$back = Redis::set('SpiderTc:CertificateList:lock', time(), 'EX', 1, 'NX');
|
||||
if ($back) {
|
||||
break;
|
||||
}
|
||||
$retries++;
|
||||
sleep(1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function _killMiddleProcesses($pattern, $maxProcesses)
|
||||
{
|
||||
// 检查操作系统是否为 Linux
|
||||
if (PHP_OS !== 'Linux') {
|
||||
echo "当前系统不是 Linux,跳过执行。\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// 获取当前进程的 PID
|
||||
$currentPid = getmypid();
|
||||
|
||||
// 获取进程列表
|
||||
$command = "ps aux | grep '$pattern' | grep -v grep | grep -v '$currentPid' | awk '{print $2,$10}'";
|
||||
$output = [];
|
||||
exec($command, $output);
|
||||
|
||||
$processList = [];
|
||||
foreach ($output as $line) {
|
||||
list($pid, $runtime) = explode(' ', $line);
|
||||
$runtimeParts = explode(':', $runtime);
|
||||
$hours = intval($runtimeParts[0]);
|
||||
$minutes = intval($runtimeParts[1]);
|
||||
$totalMinutes = $hours * 60 + $minutes;
|
||||
$processList[] = ['pid' => $pid, 'runtime' => $totalMinutes];
|
||||
}
|
||||
|
||||
// 按运行时间排序
|
||||
usort($processList, function ($a, $b) {
|
||||
return $a['runtime'] <=> $b['runtime'];
|
||||
});
|
||||
|
||||
// 过滤掉当前 PID 和运行时间最短的 PID
|
||||
if (!empty($processList)) {
|
||||
array_shift($processList); // 移除运行时间最短的
|
||||
}
|
||||
$processList = array_filter($processList, function ($process) use ($currentPid) {
|
||||
return $process['pid'] != $currentPid;
|
||||
});
|
||||
|
||||
$processCount = count($processList);
|
||||
|
||||
// 如果进程数量超过最大值,则终止中间部分的进程
|
||||
if ($processCount > $maxProcesses) {
|
||||
$processesToKill = $processCount - $maxProcesses;
|
||||
$processesKilled = 0;
|
||||
|
||||
// 杀死运行时间最短的进程
|
||||
foreach ($processList as $process) {
|
||||
if ($processesKilled >= $processesToKill) {
|
||||
break;
|
||||
}
|
||||
|
||||
exec("kill -9 {$process['pid']}");
|
||||
$processesKilled++;
|
||||
|
||||
echo "Killed process with PID: {$process['pid']}\n";
|
||||
}
|
||||
|
||||
if ($processesKilled === 0) {
|
||||
echo "No processes to kill.\n";
|
||||
}
|
||||
} else {
|
||||
echo "Process count is not over the limit.\n";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public function _orderDetail($orderId = null, $status = null)
|
||||
{
|
||||
$orderDetail = $this->_curl("/life/trip/v2/travel_agency/book/detail", [
|
||||
'order_id' => $orderId,
|
||||
'book_order_id' => '',
|
||||
'status' => $status,
|
||||
]);
|
||||
return $orderDetail->data ?? null;
|
||||
}
|
||||
|
||||
public function _cookie($data = '')
|
||||
{
|
||||
$key = 'Tongcheng:cookie-' . $this->os;
|
||||
if ($data) Redis::set($key, $data);
|
||||
return Redis::get($key);
|
||||
}
|
||||
|
||||
public function _curl($url, $params, $method = 'GET')
|
||||
{
|
||||
// 请求次数统计
|
||||
$key = sprintf("Tongcheng:ReqiestCount:%s", date('Y-m-d'));
|
||||
$requestCount = Redis::incrBy($key, 1);
|
||||
if ($requestCount == 1) {
|
||||
Redis::expire($key, 604800); // 7天
|
||||
}
|
||||
$cookiePath = sprintf(runtime_path() . '%s_tc_cookie.txt', $this->os);
|
||||
|
||||
$http = $this->gate . $url;
|
||||
if ($method == 'GET') {
|
||||
$http = $http . '?' . http_build_query($params);
|
||||
}
|
||||
|
||||
$ch = curl_init($http);
|
||||
|
||||
$header = [
|
||||
'Content-type: application/json'
|
||||
];
|
||||
if ($method == 'GET' || $method == 'POST') {
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
} else {
|
||||
curl_setopt($ch, CURLOPT_HEADER, 1);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiePath);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||
curl_setopt($ch, CURLOPT_COOKIE, $this->_cookie());
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
|
||||
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiePath);
|
||||
if ($method == 'POST') {
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
|
||||
}
|
||||
$body = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
if (!in_array($method, ['GET', 'POST'])) {
|
||||
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
|
||||
$header = substr($body, 0, $header_size);
|
||||
$in = explode("\n", $body);
|
||||
foreach ($in as $i) {
|
||||
if (stripos($i, 'x-ware-csrf-token') !== false) {
|
||||
$inn = explode(',', $i);
|
||||
return $inn[1];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return json_decode($body);
|
||||
}
|
||||
}
|
|
@ -1 +1,4 @@
|
|||
{"status":200,"message":"\u6210\u529f","data":{"sellerOrderResultDOS":[],"showVerify":false,"page":{"currentPage":2,"pageSize":10,"totalCount":0,"noMore":false},"canVerify":false,"canBatchDelivery":false,"canAsyncExportOrder":true},"success":true,"traceId":"EL2AgICAsoKsChjdAyDS_sLB8TEowpfGgQ8="}
|
||||
|
||||
ALTER TABLE `travel`.`orders`
|
||||
MODIFY COLUMN `appointment_status` tinyint NOT NULL DEFAULT 0 COMMENT '是否已预约(0-未预约,1-已预约未处理,2-已预约已处理)' AFTER `next_remind_time`;
|
Loading…
Reference in New Issue