Accept Merge Request #53: (feature/hant -> develop)
Merge Request: 运营补单 Created By: @todayswind Accepted By: @todayswind URL: https://g-bcrc3009.coding.net/p/allocatr/d/allocatr/git/merge/53?initial=true
This commit is contained in:
commit
8c9b769746
|
|
@ -3,12 +3,26 @@
|
||||||
namespace app\admin\command;
|
namespace app\admin\command;
|
||||||
|
|
||||||
use app\admin\addresmart\Address;
|
use app\admin\addresmart\Address;
|
||||||
|
use app\admin\controller\orders\DispatchLogic;
|
||||||
|
use app\admin\model\Order;
|
||||||
|
use app\admin\model\OrderDispatch;
|
||||||
|
use app\admin\model\OrderReview;
|
||||||
|
use app\admin\model\Worker;
|
||||||
|
use app\admin\model\WorkerItem;
|
||||||
|
use think\Collection;
|
||||||
use think\console\Command;
|
use think\console\Command;
|
||||||
use think\console\Input;
|
use think\console\Input;
|
||||||
use think\console\Output;
|
use think\console\Output;
|
||||||
|
use think\Db;
|
||||||
|
use think\exception\DbException;
|
||||||
|
use think\Hook;
|
||||||
|
use think\Model;
|
||||||
|
use function Symfony\Component\Clock\now;
|
||||||
|
|
||||||
class Test extends Command
|
class Test extends Command
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
protected function configure()
|
protected function configure()
|
||||||
{
|
{
|
||||||
$this->setName('test')
|
$this->setName('test')
|
||||||
|
|
@ -17,10 +31,12 @@ class Test extends Command
|
||||||
|
|
||||||
protected function execute(Input $input, Output $output)
|
protected function execute(Input $input, Output $output)
|
||||||
{
|
{
|
||||||
$string = '张三 13800138000 120113196808214821深圳市龙华区龙华街道1980科技文化产业园3栋317 地板';
|
$order = (new Order())->find(110);
|
||||||
$r = Address::smart($string);
|
$id = (new DispatchLogic())->getMaxScoreWorker($order);
|
||||||
dd($r);
|
dd($id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
namespace app\admin\controller;
|
namespace app\admin\controller;
|
||||||
|
|
||||||
use app\admin\addresmart\Address;
|
use app\admin\addresmart\Address;
|
||||||
use app\admin\model\AuthGroupAccess;
|
use app\admin\controller\orders\DispatchLogic;
|
||||||
use app\admin\model\order\Invoice;
|
use app\admin\model\order\Invoice;
|
||||||
use app\admin\model\OrderDispatch;
|
use app\admin\model\OrderDispatch;
|
||||||
use app\admin\model\Worker;
|
use app\admin\model\Worker;
|
||||||
|
|
@ -27,7 +27,6 @@ use function Symfony\Component\Clock\now;
|
||||||
*/
|
*/
|
||||||
class Order extends Backend
|
class Order extends Backend
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Order模型对象
|
* Order模型对象
|
||||||
* @var \app\admin\model\Order
|
* @var \app\admin\model\Order
|
||||||
|
|
@ -347,24 +346,13 @@ class Order extends Backend
|
||||||
|
|
||||||
private function autoDispatch($order)
|
private function autoDispatch($order)
|
||||||
{
|
{
|
||||||
if ($order->dispatch_type != 2) {
|
//
|
||||||
return false;
|
// if ($order->dispatch_type != 2) {
|
||||||
}
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
$worker_ids = (new Worker())->where('area_id', $order->area_id)
|
|
||||||
->where('status', 1)
|
|
||||||
->field(['id', 'area_id', 'lng'], 'lat')
|
|
||||||
->column('id');
|
|
||||||
|
|
||||||
$worker_items_ids = (new WorkerItem())
|
$worker_id = (new DispatchLogic())->getMaxScoreWorker($order);
|
||||||
->where('item_id', $order->item_id)
|
|
||||||
->whereIn('worker_id', $worker_ids)
|
|
||||||
->field(['worker_id'], 'lat')
|
|
||||||
->column('worker_id');
|
|
||||||
|
|
||||||
$out_workers = array_intersect($worker_ids, $worker_items_ids);
|
|
||||||
|
|
||||||
$worker_id = $out_workers[0] ?? false;
|
|
||||||
|
|
||||||
if (!$worker_id) {
|
if (!$worker_id) {
|
||||||
$order->dispatch_type = 1;
|
$order->dispatch_type = 1;
|
||||||
|
|
|
||||||
310
application/admin/controller/orders/DispatchLogic.php
Normal file
310
application/admin/controller/orders/DispatchLogic.php
Normal file
|
|
@ -0,0 +1,310 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\admin\controller\orders;
|
||||||
|
|
||||||
|
use app\admin\model\Order;
|
||||||
|
use app\admin\model\OrderDispatch;
|
||||||
|
use app\admin\model\OrderReview;
|
||||||
|
use app\admin\model\Worker;
|
||||||
|
use app\admin\model\WorkerItem;
|
||||||
|
use think\Collection;
|
||||||
|
use think\Db;
|
||||||
|
use think\exception\DbException;
|
||||||
|
use function Symfony\Component\Clock\now;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动派单
|
||||||
|
*
|
||||||
|
* @icon
|
||||||
|
*/
|
||||||
|
class DispatchLogic
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
function getMaxScoreWorker($order){
|
||||||
|
$worker_info = Db::query("SELECT id, `name`, lng, lat, distance,star
|
||||||
|
FROM (
|
||||||
|
SELECT id, `name`, lng, lat,star,
|
||||||
|
ST_Distance_Sphere(
|
||||||
|
point(lng, lat),
|
||||||
|
point(?, ?)
|
||||||
|
) AS distance
|
||||||
|
FROM fa_worker
|
||||||
|
) AS t
|
||||||
|
WHERE distance < 40000
|
||||||
|
ORDER BY distance;",[$order->lng,$order->lat]);
|
||||||
|
|
||||||
|
$worker_ids = array_column($worker_info,'id');
|
||||||
|
|
||||||
|
|
||||||
|
$worker_items_ids = (new WorkerItem())
|
||||||
|
->where('item_id', $order->item_id)
|
||||||
|
->whereIn('worker_id', $worker_ids)
|
||||||
|
->field(['worker_id'])
|
||||||
|
->column('worker_id');
|
||||||
|
|
||||||
|
$out_worker_ids = array_intersect($worker_ids, $worker_items_ids);
|
||||||
|
|
||||||
|
$worker_doings = (new OrderDispatch())
|
||||||
|
->whereIn('worker_id', $out_worker_ids)
|
||||||
|
->group('worker_id')
|
||||||
|
->field(['worker_id','count(if(status > 0 & status < 60,1,null)) count'])
|
||||||
|
->select();
|
||||||
|
|
||||||
|
$worker_doing_map = [];
|
||||||
|
foreach ($worker_doings as $item){
|
||||||
|
$worker_doing_map[$item->worker_id] = $item->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取工人信息;
|
||||||
|
$worker_rate = $this->getWorkerRate($out_worker_ids);
|
||||||
|
|
||||||
|
$worker_scores = [];
|
||||||
|
$worker_rate_map = array_column($worker_rate,null,'worker_id');
|
||||||
|
|
||||||
|
foreach ($worker_info as $item){
|
||||||
|
if (in_array($item['id'],$out_worker_ids)){
|
||||||
|
$worker_scores [] = [
|
||||||
|
'id' => $item['id'],
|
||||||
|
'distance' => $item['distance'],
|
||||||
|
// 'star' => $item['star'],
|
||||||
|
'doing' => $worker_doing_map[$item['id']]['count'] ?? 0,
|
||||||
|
'status' => $worker_rate_map[$item['id']] ?? [
|
||||||
|
'arrive_rate' => 0,
|
||||||
|
'refuse_rate' => 0,
|
||||||
|
'trans_rate' => 0,
|
||||||
|
'good_rate' => 0,
|
||||||
|
'avg_time_diff' => 0,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$worker_score_map = [];
|
||||||
|
|
||||||
|
foreach ($worker_scores as $worker_score){
|
||||||
|
$worker_score_map [$worker_score['id']] = $this->scoreWorker($worker_score);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据得分排序(从高到低)
|
||||||
|
arsort($worker_score_map); // 保持键名不变
|
||||||
|
|
||||||
|
// 取出第一个 key(就是得分最高的 ID)
|
||||||
|
return array_key_first($worker_score_map);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function scoreWorker($worker, $maxDistance = 10000, $requiredSkills = []) {
|
||||||
|
// 距离得分(越近分数越高)
|
||||||
|
$geoScore = max(0, 1 - ($worker['distance'] / $maxDistance)); // 范围 [0,1]
|
||||||
|
|
||||||
|
// 技能得分(假设这个人不匹配)
|
||||||
|
$skillScore = count($requiredSkills) ? 0 : 1;
|
||||||
|
|
||||||
|
// 当前状态得分(未完成订单越少越好)
|
||||||
|
$doing = $worker['doing'];
|
||||||
|
$statusScore = $doing >= 10 ? 0 : (10 - $doing) / 10;
|
||||||
|
|
||||||
|
// 历史表现得分(各项 0~1)
|
||||||
|
$s = $worker['status'];
|
||||||
|
|
||||||
|
$historyScore = (
|
||||||
|
0.4 * (floatval($s['good_rate']) / 100) +
|
||||||
|
0.25 * (floatval($s['trans_rate']) / 100) +
|
||||||
|
0.2 * (floatval($s['arrive_rate']) / 100) +
|
||||||
|
0.1 * (1 - min(floatval($s['avg_time_diff']) / 10, 1)) + // 联系时间越短越好
|
||||||
|
0.05 * (1 - floatval($s['refuse_rate']) / 100) // 拒单率越低越好
|
||||||
|
);
|
||||||
|
|
||||||
|
// 综合得分(加权)
|
||||||
|
$totalScore =
|
||||||
|
0.3 * $geoScore +
|
||||||
|
0.2 * $skillScore +
|
||||||
|
0.2 * $statusScore +
|
||||||
|
0.3 * $historyScore;
|
||||||
|
|
||||||
|
return round($totalScore, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private function getWorkerRate($worker_ids){
|
||||||
|
|
||||||
|
$filter = [
|
||||||
|
'start_time' => now()->modify('-31 days')->format('Y-m-d H:i:s'),
|
||||||
|
'end_timne'=> now()->format('Y-m-d H:i:s')
|
||||||
|
];
|
||||||
|
|
||||||
|
//派单表
|
||||||
|
$dispatchSubsql = $this->dispatchSubsql($filter);
|
||||||
|
//订单表
|
||||||
|
$orderSubsql = $this->oderSubsql($filter);
|
||||||
|
//评分表
|
||||||
|
$viewSubsql = $this->viewSubsql($filter);
|
||||||
|
|
||||||
|
$list = (new Worker())->alias('fa_worker')
|
||||||
|
->whereIn('id',$worker_ids)
|
||||||
|
->field([
|
||||||
|
'fa_worker.*',
|
||||||
|
'IFNULL(a.dispatch_count, 0) AS dispatch_count',
|
||||||
|
'IFNULL(a.get_count, 0) AS get_count',
|
||||||
|
'IFNULL(a.refuse_count, 0) AS refuse_count',
|
||||||
|
'IFNULL(a.arrive_count, 0) AS arrive_count',
|
||||||
|
'IFNULL(a.avg_time_diff, 0) AS avg_time_diff',
|
||||||
|
'IFNULL(b.finish_num, 0) AS finish_num',
|
||||||
|
'IFNULL(b.total, 0) AS total',
|
||||||
|
'IFNULL(b.performance, 0) AS performance',
|
||||||
|
'IFNULL(b.refund_total, 0) AS refund_total',
|
||||||
|
'IFNULL(b.refund_count, 0) AS refund_count',
|
||||||
|
'IFNULL(b.cost, 0) AS cost',
|
||||||
|
'IFNULL(c.good_count, 0) AS good_count'
|
||||||
|
])
|
||||||
|
->join([$dispatchSubsql => 'a'], 'fa_worker.id = a.worker_id', 'LEFT')
|
||||||
|
->join([$orderSubsql => 'b'], 'fa_worker.id = b.worker_id', 'LEFT')
|
||||||
|
->join([$viewSubsql => 'c'], 'fa_worker.id = c.worker_id', 'LEFT')
|
||||||
|
->select();
|
||||||
|
|
||||||
|
|
||||||
|
$this->_toList($list);
|
||||||
|
$out = [];
|
||||||
|
foreach ($list as $item){
|
||||||
|
$out [] = [
|
||||||
|
'worker_id' => $item->id,
|
||||||
|
'arrive_rate' => $item->arrive_rate,
|
||||||
|
'refuse_rate' => $item->refuse_rate,
|
||||||
|
'trans_rate' => $item->trans_rate,
|
||||||
|
'good_rate' => $item->good_rate,
|
||||||
|
'avg_time_diff' => $item->avg_time_diff,
|
||||||
|
|
||||||
|
|
||||||
|
];
|
||||||
|
}
|
||||||
|
return $out;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool|Collection|PDOStatement|string
|
||||||
|
* @throws DbException
|
||||||
|
*/
|
||||||
|
public function viewSubsql($filter=[]){
|
||||||
|
//评分表
|
||||||
|
$viewSubsql = OrderReview::where('worker_star',5)->field(['worker_id','count(*) as good_count']);
|
||||||
|
|
||||||
|
if(!empty($filter['start_time'])){
|
||||||
|
$viewSubsql->where('create_time','>=',$filter['start_time']);
|
||||||
|
}
|
||||||
|
if(!empty($filter['end_time'])){
|
||||||
|
$viewSubsql->where('create_time','<=',$filter['start_time']);
|
||||||
|
}
|
||||||
|
return $viewSubsql->group('worker_id')->buildSql();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool|PDOStatement|string|Collection
|
||||||
|
* @throws DbException
|
||||||
|
*/
|
||||||
|
public function dispatchSubsql($filter): Collection|bool|string|PDOStatement
|
||||||
|
{
|
||||||
|
$builder = new OrderDispatch();
|
||||||
|
$fields = [
|
||||||
|
'worker_id',
|
||||||
|
// 使用 IFNULL 确保结果为 null 时返回 0
|
||||||
|
"IFNULL(COUNT(*), 0) AS dispatch_count", //分配数
|
||||||
|
"IFNULL(COUNT(CASE WHEN status NOT IN (0, -10) THEN 1 END), 0) AS get_count", //接单数
|
||||||
|
//"COUNT(CASE WHEN status IN (60) THEN 1 END) AS finish_count", //完成数
|
||||||
|
"IFNULL(COUNT(CASE WHEN status NOT IN (-10) THEN 1 END), 0) AS refuse_count", //拒绝数
|
||||||
|
"IFNULL(COUNT(arrive_time), 0) AS arrive_count", //上门数
|
||||||
|
"IFNULL(AVG(CASE WHEN status = 60 AND arrive_time IS NOT NULL THEN UNIX_TIMESTAMP(arrive_time) - UNIX_TIMESTAMP(create_time) END), 0) AS avg_time_diff", //联系时效
|
||||||
|
];
|
||||||
|
$builder->field($fields);
|
||||||
|
|
||||||
|
if(!empty($filter['start_time'])){
|
||||||
|
$builder->where('create_time','>=',$filter['start_time']);
|
||||||
|
}
|
||||||
|
if(!empty($filter['end_time'])){
|
||||||
|
$builder->where('create_time','<=',$filter['start_time']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$builder->group('worker_id');
|
||||||
|
return $builder->buildSql();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//图表统计
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws DbException
|
||||||
|
*/
|
||||||
|
public function oderSubsql($filter = []): Collection|bool|string|PDOStatement
|
||||||
|
{
|
||||||
|
|
||||||
|
$orderValid = implode(',',(new Order())->tabStatus(Order::TAB_VALID));
|
||||||
|
|
||||||
|
//"COUNT(CASE WHEN status IN (".$orderValid.") THEN 1 END) AS ing_num",
|
||||||
|
$fields = [
|
||||||
|
'worker_id',
|
||||||
|
// 使用 IFNULL 确保结果为 null 时返回 0
|
||||||
|
"IFNULL(COUNT(CASE WHEN status = 60 THEN 1 END), 0) AS finish_num", //完成数
|
||||||
|
//"COUNT(CASE WHEN status IN (".$orderValid.") THEN 1 END) AS count_num", //总订单数 (排除取消 和草稿)
|
||||||
|
"IFNULL(SUM(CASE WHEN status = 60 THEN total END), 0) AS total", //成效额
|
||||||
|
"IFNULL(SUM(CASE WHEN status = 60 THEN performance END), 0) AS performance", //业绩
|
||||||
|
"IFNULL(SUM(CASE WHEN status = 60 THEN cost END), 0) AS cost", //成效额
|
||||||
|
|
||||||
|
// "SUM(CASE WHEN status = 60 THEN (cost + material_cost) END) AS cost_total", //总成本
|
||||||
|
|
||||||
|
"IFNULL(SUM(CASE WHEN status = 60 THEN (refund_amount + worker_refund_amount) END), 0) AS refund_total", //退款总数
|
||||||
|
"IFNULL(COUNT(CASE WHEN refund_amount > 0 OR worker_refund_amount > 0 THEN 1 END), 0) AS refund_count", //退款订单数量
|
||||||
|
//"AVG(CASE WHEN status > 10 THEN UNIX_TIMESTAMP(dispatch_time) - UNIX_TIMESTAMP(create_time) END) AS avg_time_diff", //派单时效
|
||||||
|
// "SUM(CASE WHEN status = 60 THEN (field1 + field2) END) AS performance",
|
||||||
|
];
|
||||||
|
|
||||||
|
$builder = (new Order())->field($fields);
|
||||||
|
|
||||||
|
if(!empty($filter['start_time'])){
|
||||||
|
$builder->where('create_time','>=',$filter['start_time']);
|
||||||
|
}
|
||||||
|
if(!empty($filter['end_time'])){
|
||||||
|
$builder->where('create_time','<=',$filter['start_time']);
|
||||||
|
}
|
||||||
|
|
||||||
|
//->where('dispatch_admin_id','>',0);
|
||||||
|
return $builder->group('worker_id')->buildSql();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _toList($list)
|
||||||
|
{
|
||||||
|
foreach ($list as &$datum){
|
||||||
|
//利润率 = 总业绩/总成效额
|
||||||
|
$datum->performance_rate = $this->_calc($datum->performance,$datum->total,4,true);
|
||||||
|
//转化率 = 完单数 / 总接单数
|
||||||
|
$datum->trans_rate = $this->_calc($datum->finish_num,$datum->get_count,4,true);
|
||||||
|
//变现值 = 总业绩 / 总接单数
|
||||||
|
$datum->cash_value = $this->_calc($datum->performance,$datum->get_count,2);
|
||||||
|
//拒单率 = 拒绝数 / 派单数
|
||||||
|
$datum->refuse_rate = $this->_calc($datum->refuse_count,$datum->dispatch_count,4,true);
|
||||||
|
//上门率 = 打卡数 / 接单数
|
||||||
|
$datum->arrive_rate = $this->_calc($datum->arrive_count,$datum->get_count,4,true);
|
||||||
|
//好评率
|
||||||
|
$datum->good_rate = $this->_calc($datum->good_count,$datum->finish_num,4,true);
|
||||||
|
|
||||||
|
$datum->avg_time_diff = $this->_calc($datum->avg_time_diff,3600,2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function _calc($a, $b, int $scale=4, bool $is_percent=false): int|string
|
||||||
|
{
|
||||||
|
$a = $a??0;
|
||||||
|
$b = $b??0;
|
||||||
|
$val = $b > 0 ? bcdiv($a,$b,$scale) : '0.00';
|
||||||
|
|
||||||
|
if($is_percent){
|
||||||
|
return bcmul($val,100,2);
|
||||||
|
}
|
||||||
|
return $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -42,13 +42,12 @@ class Item extends Backend
|
||||||
{
|
{
|
||||||
$build = new Order();
|
$build = new Order();
|
||||||
|
|
||||||
$start = now()->modify('-14 days')->format('Y-m-d');
|
$start = now()->modify('-7 days')->format('Y-m-d');
|
||||||
$end_at = now()->format('Y-m-d 23:29:59');
|
$end_at = now()->format('Y-m-d 23:29:59');
|
||||||
|
|
||||||
$filter = json_decode(request()->get('filter','[]'),true);
|
$filter = request()->get('range','');
|
||||||
|
if (!empty($filter)){
|
||||||
if (!empty($filter['daterange'])) {
|
$arr = explode(' - ', $filter);
|
||||||
$arr = explode(' - ', $filter['daterange']);
|
|
||||||
if (trim($arr[0])) {
|
if (trim($arr[0])) {
|
||||||
$start = trim($arr[0]);
|
$start = trim($arr[0]);
|
||||||
}
|
}
|
||||||
|
|
@ -56,8 +55,14 @@ class Item extends Backend
|
||||||
$end_at = trim($arr[1]) . ' 23:29:59';
|
$end_at = trim($arr[1]) . ' 23:29:59';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$offset = request()->get('offset',0);
|
$area_id = request()->get('area_id');
|
||||||
$limit = request()->get('limit',15);
|
|
||||||
|
if ($area_id) {
|
||||||
|
$area_id = $this->trimSpecialZeros($area_id);
|
||||||
|
$build->where('area_id', 'like', $area_id . '%');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$build->whereBetween('create_time', [$start, $end_at])
|
$build->whereBetween('create_time', [$start, $end_at])
|
||||||
->field([
|
->field([
|
||||||
'item_title name', // 类型
|
'item_title name', // 类型
|
||||||
|
|
@ -101,6 +106,21 @@ class Item extends Backend
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function trimSpecialZeros($str) {
|
||||||
|
if (strlen($str) !== 6) {
|
||||||
|
return $str; // 非6位字符串直接返回
|
||||||
|
}
|
||||||
|
|
||||||
|
if (substr($str, -4) === "0000") {
|
||||||
|
return substr($str, 0, 2); // 去掉后4位
|
||||||
|
} elseif (substr($str, -2) === "00") {
|
||||||
|
return substr($str, 0, 4); // 去掉后2位
|
||||||
|
}
|
||||||
|
|
||||||
|
return $str; // 不符合条件则原样返回
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function chartData()
|
public function chartData()
|
||||||
{
|
{
|
||||||
$build = new Order();
|
$build = new Order();
|
||||||
|
|
@ -161,6 +181,8 @@ class Item extends Backend
|
||||||
$refundRate[] = $total > 0 ? round($refund / $total * 100, 2) : 0;
|
$refundRate[] = $total > 0 ? round($refund / $total * 100, 2) : 0;
|
||||||
$monetizedValue[] = $total / $count;
|
$monetizedValue[] = $total / $count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($totalPerformance){
|
||||||
$result = [
|
$result = [
|
||||||
'xAxis' => $xAxis,
|
'xAxis' => $xAxis,
|
||||||
'series' => [
|
'series' => [
|
||||||
|
|
@ -171,6 +193,20 @@ class Item extends Backend
|
||||||
['name' => '变现值(¥)', 'type' => 'line', 'yAxisIndex' => 0, 'data' => $monetizedValue],
|
['name' => '变现值(¥)', 'type' => 'line', 'yAxisIndex' => 0, 'data' => $monetizedValue],
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
}else{
|
||||||
|
$result = [
|
||||||
|
'xAxis' => ['无'],
|
||||||
|
'series' => [
|
||||||
|
['name' => '总业绩(¥)', 'type' => 'bar', 'yAxisIndex' => 0, 'data' => [0]],
|
||||||
|
['name' => '转化率(%)', 'type' => 'bar', 'yAxisIndex' => 1, 'data' => [0]],
|
||||||
|
['name' => '利润率(%)', 'type' => 'bar', 'yAxisIndex' => 1, 'data' => [0]],
|
||||||
|
['name' => '退款率(%)', 'type' => 'bar', 'yAxisIndex' => 1, 'data' => [0]],
|
||||||
|
['name' => '变现值(¥)', 'type' => 'line', 'yAxisIndex' => 0, 'data' => [0]],
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
241
application/admin/controller/supplement/Orders.php
Normal file
241
application/admin/controller/supplement/Orders.php
Normal file
|
|
@ -0,0 +1,241 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\admin\controller\supplement;
|
||||||
|
|
||||||
|
use app\common\controller\Backend;
|
||||||
|
use think\Db;
|
||||||
|
use think\exception\PDOException;
|
||||||
|
use think\exception\ValidateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 补单记录管理
|
||||||
|
*
|
||||||
|
* @icon fa fa-circle-o
|
||||||
|
*/
|
||||||
|
class Orders extends Backend
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Orders模型对象
|
||||||
|
* @var \app\admin\model\supplement\Orders
|
||||||
|
*/
|
||||||
|
protected $model = null;
|
||||||
|
protected $sources = null;
|
||||||
|
protected $items = null;
|
||||||
|
protected $itemsformattedTree = null;
|
||||||
|
|
||||||
|
public function _initialize()
|
||||||
|
{
|
||||||
|
parent::_initialize();
|
||||||
|
$this->model = new \app\admin\model\supplement\Orders;
|
||||||
|
|
||||||
|
|
||||||
|
$sources = Db::name('source')
|
||||||
|
->where('status', 1)
|
||||||
|
->field(['id', 'title', 'key_word', 'pid'])
|
||||||
|
->order('pid', 'asc')
|
||||||
|
->order('sort', 'desc')
|
||||||
|
->select();
|
||||||
|
$this->sources = $sources;
|
||||||
|
$filtered = array_filter($sources, function ($item) {
|
||||||
|
return $item['pid'] == 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
$pid_map = array_column($filtered, null, 'id');
|
||||||
|
$res = [];
|
||||||
|
foreach ($sources as $item) {
|
||||||
|
if ($item['pid'] != 0 && isset($pid_map[$item['pid']])) {
|
||||||
|
$res [] = [
|
||||||
|
...$item, 'ptitle' => $pid_map[$item['pid']]['title']
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$items = Db::name('item')
|
||||||
|
->where('status', 1)
|
||||||
|
->field(['id', 'title', 'key_word', 'pid'])
|
||||||
|
->order('pid', 'asc')
|
||||||
|
->order('sort', 'desc')
|
||||||
|
->select();
|
||||||
|
$tree = $this->buildTree($items);
|
||||||
|
$formattedTree = $this->formatTree($tree);
|
||||||
|
|
||||||
|
$this->items = $items;
|
||||||
|
$this->itemsformattedTree = $formattedTree;
|
||||||
|
|
||||||
|
|
||||||
|
$this->view->assign("sources", $res);
|
||||||
|
$this->view->assign("items", $formattedTree);
|
||||||
|
|
||||||
|
|
||||||
|
$this->view->assign("statusList", $this->model->getStatusList());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
//设置过滤方法
|
||||||
|
$this->request->filter(['strip_tags', 'trim']);
|
||||||
|
if (false === $this->request->isAjax()) {
|
||||||
|
return $this->view->fetch();
|
||||||
|
}
|
||||||
|
//如果发送的来源是 Selectpage,则转发到 Selectpage
|
||||||
|
if ($this->request->request('keyField')) {
|
||||||
|
return $this->selectpage();
|
||||||
|
}
|
||||||
|
[$where, $sort, $order, $offset, $limit] = $this->buildparams();
|
||||||
|
|
||||||
|
|
||||||
|
$list = $this->model
|
||||||
|
->where($where)
|
||||||
|
->with(['user' => function ($q) {
|
||||||
|
$q->field('id,nickname');
|
||||||
|
},
|
||||||
|
'area' => function ($q) {
|
||||||
|
$q->field('id,area_code,merge_name');
|
||||||
|
},
|
||||||
|
])
|
||||||
|
->order($sort, $order)
|
||||||
|
->paginate($limit);
|
||||||
|
$result = ['total' => $list->total(), 'rows' => $list->items()];
|
||||||
|
return json($result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
|
||||||
|
* 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
|
||||||
|
* 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
public function add()
|
||||||
|
{
|
||||||
|
if (false === $this->request->isPost()) {
|
||||||
|
return $this->view->fetch();
|
||||||
|
}
|
||||||
|
$params = $this->request->post('row/a');
|
||||||
|
if (empty($params)) {
|
||||||
|
$this->error(__('Parameter %s can not be empty', ''));
|
||||||
|
}
|
||||||
|
$params = $this->preExcludeFields($params);
|
||||||
|
|
||||||
|
if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
|
||||||
|
$params[$this->dataLimitField] = $this->auth->id;
|
||||||
|
}
|
||||||
|
$result = false;
|
||||||
|
Db::startTrans();
|
||||||
|
try {
|
||||||
|
//是否采用模型验证
|
||||||
|
if ($this->modelValidate) {
|
||||||
|
$name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
|
||||||
|
$validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate;
|
||||||
|
$this->model->validateFailException()->validate($validate);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sources = $this->sources;
|
||||||
|
$sources = array_column($sources, 'title', 'id');
|
||||||
|
$params['source_name'] = $sources[$params['source']] ?? null;
|
||||||
|
$params['source_id'] = $params['source'];
|
||||||
|
|
||||||
|
$params['item_name'] = $this->findElementByValue($this->itemsformattedTree, $params['item_id'] ?? null);
|
||||||
|
|
||||||
|
|
||||||
|
$params['admin_id'] = ($params['admin_id'] ?? -1) == -1 ? $this->auth->id : $params['admin_id'];
|
||||||
|
if (empty($params['admin_id'])) {
|
||||||
|
$params['admin_id'] = $this->auth->id;
|
||||||
|
}
|
||||||
|
$params['status'] = 0;
|
||||||
|
$params['created_at'] = date('Y-m-d H:i:s');
|
||||||
|
$params['updated_at'] = date('Y-m-d H:i:s');
|
||||||
|
// dd($params);
|
||||||
|
$result = $this->model->allowField(true)->save($params);
|
||||||
|
Db::commit();
|
||||||
|
} catch (ValidateException | PDOException | Exception $e) {
|
||||||
|
Db::rollback();
|
||||||
|
$this->error($e->getMessage());
|
||||||
|
}
|
||||||
|
if ($result === false) {
|
||||||
|
$this->error(__('No rows were inserted'));
|
||||||
|
}
|
||||||
|
$this->success();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function findElementByValue($data, $targetValue, $path = [])
|
||||||
|
{
|
||||||
|
foreach ($data as $item) {
|
||||||
|
// 将当前节点的 label 添加到路径中
|
||||||
|
$newPath = array_merge($path, [$item['label']]);
|
||||||
|
|
||||||
|
// 如果找到目标值,返回路径
|
||||||
|
if ($item['value'] == $targetValue) {
|
||||||
|
return implode(' / ', $newPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果当前节点有 children,递归搜索
|
||||||
|
if (isset($item['children']) && is_array($item['children'])) {
|
||||||
|
$result = $this->findElementByValue($item['children'], $targetValue, $newPath);
|
||||||
|
if ($result) {
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null; // 如果找不到返回 null
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit($ids = null)
|
||||||
|
{
|
||||||
|
if (!$ids) {
|
||||||
|
if (request()->isPost()) {
|
||||||
|
$ids = input('id');
|
||||||
|
if (!$ids) {
|
||||||
|
$this->error('缺少订单ID');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->error('缺少订单ID');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取当前ID对应的订单信息
|
||||||
|
$order = $this->model->get($ids);
|
||||||
|
if (!$order) {
|
||||||
|
$this->error('订单不存在');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否为POST请求,进行更新操作
|
||||||
|
if (request()->isPost()) {
|
||||||
|
// 获取表单提交的数据
|
||||||
|
$params = input('post.row/a');
|
||||||
|
|
||||||
|
$sources = $this->sources;
|
||||||
|
$sources = array_column($sources, 'title', 'id');
|
||||||
|
$params['source_name'] = $sources[$params['source']] ?? null;
|
||||||
|
$params['source_id'] = $params['source'];
|
||||||
|
|
||||||
|
$params['item_name'] = $this->findElementByValue($this->itemsformattedTree, $params['item_id'] ?? null);
|
||||||
|
|
||||||
|
unset($params['source']);
|
||||||
|
|
||||||
|
$params['admin_id'] = ($params['admin_id'] ?? -1) == -1 ? $this->auth->id : $params['admin_id'];
|
||||||
|
if (empty($params['admin_id'])) {
|
||||||
|
$params['admin_id'] = $this->auth->id;
|
||||||
|
}
|
||||||
|
$params['updated_at'] = date('Y-m-d H:i:s');
|
||||||
|
// 更新订单信息
|
||||||
|
$order->save($params);
|
||||||
|
|
||||||
|
// 返回成功信息
|
||||||
|
$this->success('更新成功', 'index');
|
||||||
|
}
|
||||||
|
$area = new \app\admin\model\Area();
|
||||||
|
$area_name = $area->getNameByCode($order->area_id);
|
||||||
|
$order->area_name = str_replace(',', '/', $area_name);
|
||||||
|
|
||||||
|
// 将订单数据传递到视图
|
||||||
|
$this->assign('row', $order);
|
||||||
|
// 渲染编辑页面
|
||||||
|
return $this->fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
27
application/admin/lang/zh-cn/supplement/orders.php
Normal file
27
application/admin/lang/zh-cn/supplement/orders.php
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'Id' => 'ID',
|
||||||
|
'Area_id' => '区域 ID',
|
||||||
|
'Area_name' => '地址',
|
||||||
|
'Source_id' => '所属店铺 ID',
|
||||||
|
'Source_name' => '所属店铺 ID',
|
||||||
|
'Platform_order_no' => '平台订单编号',
|
||||||
|
'Item_id' => '服务类型 ID',
|
||||||
|
'Item_name' => '服务类型 ID',
|
||||||
|
'Buyer_account' => '刷手账号',
|
||||||
|
'Amount' => '支付金额',
|
||||||
|
'Commission' => '刷单佣金',
|
||||||
|
'Screenshots' => '截图 JSON(下单图、评价图等)',
|
||||||
|
'Status' => '订单状态',
|
||||||
|
'Status 0' => '待发货',
|
||||||
|
'Set status to 0' => '设为待发货',
|
||||||
|
'Status 1' => '待评价',
|
||||||
|
'Set status to 1' => '设为待评价',
|
||||||
|
'Status 2' => '评价超时',
|
||||||
|
'Set status to 2' => '设为评价超时',
|
||||||
|
'Admin_id' => '运营人员 ID',
|
||||||
|
'Remark' => '备注信息',
|
||||||
|
'Created_at' => '创建时间',
|
||||||
|
'Updated_at' => '最后更新时间'
|
||||||
|
];
|
||||||
51
application/admin/model/supplement/Orders.php
Normal file
51
application/admin/model/supplement/Orders.php
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\admin\model\supplement;
|
||||||
|
|
||||||
|
use app\admin\model\Admin;
|
||||||
|
use app\admin\model\Area;
|
||||||
|
use think\Model;
|
||||||
|
|
||||||
|
|
||||||
|
class Orders extends Model
|
||||||
|
{
|
||||||
|
|
||||||
|
// 表名
|
||||||
|
protected $name = 'supplement_orders';
|
||||||
|
|
||||||
|
// 自动写入时间戳字段
|
||||||
|
protected $autoWriteTimestamp = false;
|
||||||
|
|
||||||
|
// 定义时间戳字段名
|
||||||
|
protected $createTime = false;
|
||||||
|
protected $updateTime = false;
|
||||||
|
protected $deleteTime = false;
|
||||||
|
|
||||||
|
// 追加属性
|
||||||
|
protected $append = [
|
||||||
|
'status_text'
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function getStatusList()
|
||||||
|
{
|
||||||
|
return ['0' => __('Status 0'), '1' => __('Status 1'), '2' => __('Status 2'), '3' => '被驳回'];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getStatusTextAttr($value, $data)
|
||||||
|
{
|
||||||
|
$value = $value ?: ($data['status'] ?? '');
|
||||||
|
$list = $this->getStatusList();
|
||||||
|
return $list[$value] ?? '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function area(){
|
||||||
|
return $this->belongsTo(Area::class,'area_id','area_code');
|
||||||
|
}
|
||||||
|
public function user(){
|
||||||
|
return $this->belongsTo(Admin::class,'admin_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
27
application/admin/validate/supplement/Orders.php
Normal file
27
application/admin/validate/supplement/Orders.php
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace app\admin\validate\supplement;
|
||||||
|
|
||||||
|
use think\Validate;
|
||||||
|
|
||||||
|
class Orders extends Validate
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 验证规则
|
||||||
|
*/
|
||||||
|
protected $rule = [
|
||||||
|
];
|
||||||
|
/**
|
||||||
|
* 提示消息
|
||||||
|
*/
|
||||||
|
protected $message = [
|
||||||
|
];
|
||||||
|
/**
|
||||||
|
* 验证场景
|
||||||
|
*/
|
||||||
|
protected $scene = [
|
||||||
|
'add' => [],
|
||||||
|
'edit' => [],
|
||||||
|
];
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -43,6 +43,18 @@
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane fade" id="second">
|
<div class="tab-pane fade" id="second">
|
||||||
|
<div id="chart-filter-table" style="margin-top:20px;margin-bottom: 30px;">
|
||||||
|
<div style="display: inline-block;width: 300px;position: relative">
|
||||||
|
<input class="form-control" data-toggle="city-picker" type="text" placeholder="地区" id="area-table">
|
||||||
|
<input style="display: none" type="text" id="area_id">
|
||||||
|
</div>
|
||||||
|
<div style="display: inline-block;width: 200px;position: relative">
|
||||||
|
<input type="text" class="form-control datetimerange" data-locale='{"format":"YYYY-MM-DD"}'
|
||||||
|
placeholder="指定日期" name="filter[daterange]" id="daterange-table" autocomplete="off" style="width: 180px;">
|
||||||
|
</div>
|
||||||
|
<!-- 查询按钮 -->
|
||||||
|
<button class="btn btn-default" id="filter-btn-table" style="margin-left: 15px;">查询</button>
|
||||||
|
</div>
|
||||||
<table id="table2" class="table table-striped table-bordered table-hover">
|
<table id="table2" class="table table-striped table-bordered table-hover">
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
98
application/admin/view/supplement/orders/add.html
Normal file
98
application/admin/view/supplement/orders/add.html
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">店铺:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<select id="c-source" data-live-search="true" title="请选择" data-rule="required" name="row[source]" class="form-control selectpicker show-tick">
|
||||||
|
{foreach $sources as $item}
|
||||||
|
<option data-subtext="{$item['ptitle']}" value="{$item['id']}">{$item['title']}</option>
|
||||||
|
{/foreach}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">区域:</label>
|
||||||
|
<div class='col-xs-12 col-sm-8'>
|
||||||
|
<input id="c-city" data-rule="required" class="form-control" data-toggle="city-picker" type="text" value="" />
|
||||||
|
<input id="area_id" style="display: none" class="form-control" name="row[area_id]" hidden type="text" value="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">{:__('Platform_order_no')}:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<input id="c-platform_order_no" data-rule="required" class="form-control" name="row[platform_order_no]" type="text">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">服务类型:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<input type="text" id="item_id" class="zd-input__inner">
|
||||||
|
<input type="text" id="item_id_value" style="display: none" name="row[item_id]" class="zd-input__inner">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">{:__('Buyer_account')}:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<input id="c-buyer_account" data-rule="required" class="form-control" name="row[buyer_account]" type="text">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">{:__('Amount')}:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<input id="c-amount" data-rule="required" class="form-control" step="0.01" name="row[amount]" type="number" value="0.00">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">{:__('Commission')}:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<input id="c-commission" data-rule="required" class="form-control" step="0.01" name="row[commission]" type="number" value="0.00">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">图片:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="c-images" class="form-control" size="50" name="row[screenshots]" type="text">
|
||||||
|
<div class="input-group-addon no-border no-padding">
|
||||||
|
<span><button type="button" id="faupload-images" class="btn btn-danger faupload" data-input-id="c-images" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="true" data-preview-id="p-images"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
|
||||||
|
<span><button type="button" id="fachoose-images" class="btn btn-primary fachoose" data-input-id="c-images" data-mimetype="image/*" data-multiple="true"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
|
||||||
|
</div>
|
||||||
|
<span class="msg-box n-right" for="c-images"></span>
|
||||||
|
</div>
|
||||||
|
<ul class="row list-inline faupload-preview" id="p-images"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
|
||||||
|
<div class="radio">
|
||||||
|
{foreach name="statusList" item="vo"}
|
||||||
|
<label for="row[status]-{$key}"><input id="row[status]-{$key}" name="row[status]" type="radio" value="{$key}" {in name="key" value="0"}checked{/in} /> {$vo}</label>
|
||||||
|
{/foreach}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">{:__('Remark')}:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<textarea id="c-remark" class="form-control " rows="5" name="row[remark]" cols="50"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group layer-footer">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2"></label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<link rel="stylesheet" href="/assets/css/select.css">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var items = {:json_encode($items); };
|
||||||
|
</script>
|
||||||
98
application/admin/view/supplement/orders/edit.html
Normal file
98
application/admin/view/supplement/orders/edit.html
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">店铺:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<select id="c-source" data-live-search="true" title="请选择" data-rule="required" name="row[source]" class="form-control selectpicker show-tick">
|
||||||
|
{foreach $sources as $item}
|
||||||
|
<option {if $item['id'] == $row.source_id} selected {/if} data-subtext="{$item['ptitle']}" value="{$item['id']}">{$item['title']}</option>
|
||||||
|
{/foreach}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">区域:</label>
|
||||||
|
<div class='col-xs-12 col-sm-8'>
|
||||||
|
<input id="c-city" value="{$row.area_name}" data-rule="required" class="form-control" data-toggle="city-picker" type="text" value="" />
|
||||||
|
<input id="area_id" value="{$row.area_id}" style="display: none" class="form-control" name="row[area_id]" hidden type="text" value="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">{:__('Platform_order_no')}:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<input id="c-platform_order_no" value="{$row.platform_order_no}" data-rule="required" class="form-control" name="row[platform_order_no]" type="text">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">服务类型:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<input type="text" id="item_id" value="{$row.item_name}" data-value="{$row.item_name}" class="zd-input__inner">
|
||||||
|
<input type="text" id="item_id_value" value="{$row.item_id}" style="display: none" name="row[item_id]" class="zd-input__inner">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">{:__('Buyer_account')}:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<input id="c-buyer_account" value="{$row.buyer_account}" data-rule="required" class="form-control" name="row[buyer_account]" type="text">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">{:__('Amount')}:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<input id="c-amount" data-rule="required" value="{$row.amount}" class="form-control" step="0.01" name="row[amount]" type="number" value="0.00">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">{:__('Commission')}:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<input id="c-commission" data-rule="required" value="{$row.commission}" class="form-control" step="0.01" name="row[commission]" type="number" value="0.00">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">图片:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<div class="input-group">
|
||||||
|
<input id="c-images" class="form-control" size="50" name="row[screenshots]" type="text">
|
||||||
|
<div class="input-group-addon no-border no-padding">
|
||||||
|
<span><button type="button" id="faupload-images" class="btn btn-danger faupload" data-input-id="c-images" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp,image/webp" data-multiple="true" data-preview-id="p-images"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
|
||||||
|
<span><button type="button" id="fachoose-images" class="btn btn-primary fachoose" data-input-id="c-images" data-mimetype="image/*" data-multiple="true"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
|
||||||
|
</div>
|
||||||
|
<span class="msg-box n-right" for="c-images"></span>
|
||||||
|
</div>
|
||||||
|
<ul class="row list-inline faupload-preview" id="p-images"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
|
||||||
|
<div class="radio">
|
||||||
|
{foreach name="statusList" item="vo"}
|
||||||
|
<label for="row[status]-{$key}"><input id="row[status]-{$key}" name="row[status]" type="radio" value="{$key}" {in name="key" value="0"}checked{/in} /> {$vo}</label>
|
||||||
|
{/foreach}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2">{:__('Remark')}:</label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<textarea id="c-remark" value="{$row.remark}" class="form-control " rows="5" name="row[remark]" cols="50"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group layer-footer">
|
||||||
|
<label class="control-label col-xs-12 col-sm-2"></label>
|
||||||
|
<div class="col-xs-12 col-sm-8">
|
||||||
|
<button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<link rel="stylesheet" href="/assets/css/select.css">
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var items = {:json_encode($items); };
|
||||||
|
</script>
|
||||||
46
application/admin/view/supplement/orders/index.html
Normal file
46
application/admin/view/supplement/orders/index.html
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
<div class="panel panel-default panel-intro">
|
||||||
|
|
||||||
|
<div class="panel-heading">
|
||||||
|
{:build_heading(null,FALSE)}
|
||||||
|
<ul class="nav nav-tabs" data-field="status">
|
||||||
|
<li class="{:$Think.get.status === null ? 'active' : ''}"><a href="#t-all" data-value="" data-toggle="tab">{:__('All')}</a></li>
|
||||||
|
{foreach name="statusList" item="vo"}
|
||||||
|
<li class="{:$Think.get.status === (string)$key ? 'active' : ''}"><a href="#t-{$key}" data-value="{$key}" data-toggle="tab">{$vo}</a></li>
|
||||||
|
{/foreach}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="panel-body">
|
||||||
|
<div id="myTabContent" class="tab-content">
|
||||||
|
<div class="tab-pane fade active in" id="one">
|
||||||
|
<div class="widget-body no-padding">
|
||||||
|
<div id="toolbar" class="toolbar">
|
||||||
|
<a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a>
|
||||||
|
<a href="javascript:;" class="btn btn-success btn-add {:$auth->check('supplement/orders/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>
|
||||||
|
<a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('supplement/orders/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a>
|
||||||
|
<a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('supplement/orders/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="dropdown btn-group {:$auth->check('supplement/orders/multi')?'':'hide'}">
|
||||||
|
<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>
|
||||||
|
<ul class="dropdown-menu text-left" role="menu">
|
||||||
|
{foreach name="statusList" item="vo"}
|
||||||
|
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:" data-params="status={$key}">{:__('Set status to ' . $key)}</a></li>
|
||||||
|
{/foreach}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<table id="table" class="table table-striped table-bordered table-hover table-nowrap"
|
||||||
|
data-operate-edit="{:$auth->check('supplement/orders/edit')}"
|
||||||
|
data-operate-del="{:$auth->check('supplement/orders/del')}"
|
||||||
|
width="100%">
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
@ -110,7 +110,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
|
||||||
{field: 'order_no', title: __('Order_no'), operate: 'LIKE'},
|
{field: 'order_no', title: __('Order_no'), operate: 'LIKE'},
|
||||||
{field: 'customer', title: __('Customer'), operate: 'LIKE'},
|
{field: 'customer', title: __('Customer'), operate: 'LIKE'},
|
||||||
{field: 'tel', title: __('Tel'), operate: 'LIKE'},
|
{field: 'tel', title: __('Tel'), operate: 'LIKE'},
|
||||||
{field: 'area.merge_name', title: __('Area_id')},
|
{field: 'area.merge_name', title: __('Area_id'),searchable:false},
|
||||||
{
|
{
|
||||||
field: 'address',
|
field: 'address',
|
||||||
title: __('Address'),
|
title: __('Address'),
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-theme', 'template','addtabs','moment'], function ($, undefined, Backend, Table, Form,echarts,undefined,Template,Datatable,Moment) {
|
define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-theme', 'template', 'addtabs', 'moment','citypicker'], function ($, undefined, Backend, Table, Form, echarts, undefined, Template, Datatable, Moment) {
|
||||||
|
|
||||||
var Controller = {
|
var Controller = {
|
||||||
|
|
||||||
index: function () {
|
index: function () {
|
||||||
//绑定事件
|
//绑定事件
|
||||||
|
Controller.api.datepicker();
|
||||||
|
Controller.api.areapicker();
|
||||||
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||||
var $targetPanel = $($(this).attr("href"));
|
var $targetPanel = $($(this).attr("href"));
|
||||||
var tabVal = $(this).data('val');
|
var tabVal = $(this).data('val');
|
||||||
|
|
@ -16,23 +18,23 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t
|
||||||
// 表格2
|
// 表格2
|
||||||
var table2 = $("#table2");
|
var table2 = $("#table2");
|
||||||
table2.bootstrapTable({
|
table2.bootstrapTable({
|
||||||
url: 'statistics/item/list' + location.search,
|
url: 'statistics/item/list',
|
||||||
toolbar: '#toolbar1',
|
toolbar: '#toolbar1',
|
||||||
sortName: 'id',
|
sortName: 'id',
|
||||||
search: false,
|
search: false,
|
||||||
commonSearch:true,
|
commonSearch: false,
|
||||||
visible: false,
|
visible: false,
|
||||||
showToggle: false,
|
showToggle: false,
|
||||||
showColumns: false,
|
showColumns: false,
|
||||||
showExport: true,
|
showExport: true,
|
||||||
searchFormVisible:true,
|
searchFormVisible: true,
|
||||||
columns: [
|
columns: [
|
||||||
[
|
[
|
||||||
// {field: 'id', title: __('ID'),visible:true,operate: false},
|
// {field: 'id', title: __('ID'),visible:true,operate: false},
|
||||||
{field: 'name', title: '项目类型',operate: false},
|
{field: 'name', title: '项目类型', operate: false},
|
||||||
{field: 'total', title: __('成效额(¥)'), operate: false},
|
{field: 'total', title: __('成效额(¥)'), operate: false},
|
||||||
{field: 'performance', title: __('总业绩(¥)'), operate: false},
|
{field: 'performance', title: __('总业绩(¥)'), operate: false},
|
||||||
{field: 'count_num', title: __('总订单数'),operate: false},
|
{field: 'count_num', title: __('总订单数'), operate: false},
|
||||||
|
|
||||||
{field: 'performance_rate', title: __('利润率(%)'), operate: false},
|
{field: 'performance_rate', title: __('利润率(%)'), operate: false},
|
||||||
|
|
||||||
|
|
@ -45,40 +47,10 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t
|
||||||
{field: 'avg_time_diff', title: __('派单时效(小时)'), operate: false},
|
{field: 'avg_time_diff', title: __('派单时效(小时)'), operate: false},
|
||||||
|
|
||||||
{field: 'cost_total', title: __('总成本(¥)'), operate: false},
|
{field: 'cost_total', title: __('总成本(¥)'), operate: false},
|
||||||
{field: 'finish_num', title: __('完单数'),operate: false},
|
{field: 'finish_num', title: __('完单数'), operate: false},
|
||||||
|
|
||||||
{field: 'refund_count', title: __('退款单数'), operate: false},
|
{field: 'refund_count', title: __('退款单数'), operate: false},
|
||||||
{field: 'refund_total', title: __('退款金额(¥)'), operate: false},
|
{field: 'refund_total', title: __('退款金额(¥)'), operate: false},
|
||||||
|
|
||||||
{field: 'daterange', title: __('时间筛选'), addclass:'datetimerange',
|
|
||||||
autocomplete:false,
|
|
||||||
operate: "RANGE",
|
|
||||||
datetimeFormat: "YYYY-MM-DD",
|
|
||||||
//defaultValue:today()+' - '+today(),
|
|
||||||
data:'autocomplete="off" data-local={"format":"YYYY-MM-DD"}',
|
|
||||||
visible:false,
|
|
||||||
defaultValue: Config.default_daterange
|
|
||||||
},
|
|
||||||
// {field: 'operate', title: __('Operate'), table: table2, events:
|
|
||||||
// Table.api.events.operate,
|
|
||||||
// formatter: Table.api.formatter.operate,
|
|
||||||
// buttons: [
|
|
||||||
// {
|
|
||||||
// name: 'aftersales',
|
|
||||||
// text:"售后列表",
|
|
||||||
// title:"售后列表",
|
|
||||||
// icon: 'fa fa-list',
|
|
||||||
// url: function(row){
|
|
||||||
// return 'aftersales/aftersale/index?from=2&man_id='+row.id;
|
|
||||||
// },
|
|
||||||
// extend: 'data-toggle="tooltip" data-container="body"',
|
|
||||||
// classname: 'btn btn-xs btn-default btn-dialog',
|
|
||||||
// visible:function(row){
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
@ -87,40 +59,81 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// 触发 tab 后发起 ajax 获取图表数据
|
// 触发 tab 后发起 ajax 获取图表数据
|
||||||
$('ul.nav-tabs li.active a[data-toggle="tab"]').on("shown.bs.tab", function () {
|
$('ul.nav-tabs li.active a[data-toggle="tab"]').on("shown.bs.tab", function () {
|
||||||
getChartData();
|
Controller.api.getChartData();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
function getChartData(){
|
// 手动触发一次激活 tab 的 shown.bs.tab
|
||||||
// 获取日期范围值
|
Controller.api.getChartData();
|
||||||
var daterange = $('#daterange').val();
|
// 绑定查询按钮的点击事件
|
||||||
|
$('#filter-btn').on('click', function () {
|
||||||
|
Controller.api.getChartData();
|
||||||
|
});
|
||||||
|
|
||||||
// 构建查询参数
|
$('#filter-btn-table').on('click', function () {
|
||||||
var params = {
|
|
||||||
'daterange': daterange,
|
|
||||||
};
|
|
||||||
|
|
||||||
$.ajax({
|
const area_id = $('#area_id').val();
|
||||||
url: "statistics/item/chartData", //
|
const range = $('#daterange-table').val();
|
||||||
type: "POST",
|
let data = '';
|
||||||
dataType: "json",
|
if (area_id !== ''){
|
||||||
data:params,
|
data += 'area_id=' + area_id+'&';
|
||||||
success: function (response) {
|
}
|
||||||
Controller.api.chart(response);
|
if (area_id !== ''){
|
||||||
|
data += 'range=' + range;
|
||||||
|
}
|
||||||
|
// data = encodeURIComponent(data);
|
||||||
|
$("#table2").bootstrapTable('refresh',{
|
||||||
|
url:'statistics/item/list?' + data,
|
||||||
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
error: function () {
|
|
||||||
console.error("图表数据加载失败");
|
add: function () {
|
||||||
}
|
Controller.api.bindevent();
|
||||||
|
},
|
||||||
|
edit: function () {
|
||||||
|
Controller.api.bindevent();
|
||||||
|
},
|
||||||
|
|
||||||
|
aftersales: function () {
|
||||||
|
Controller.api.bindevent();
|
||||||
|
},
|
||||||
|
|
||||||
|
api: {
|
||||||
|
bindevent: function () {
|
||||||
|
Form.api.bindevent($("form[role=form]"));
|
||||||
|
},
|
||||||
|
chart(chartData) {
|
||||||
|
const option = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {type: 'shadow'}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: chartData.series.map(s => s.name)
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: chartData.xAxis
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{type: 'value', name: '金额 (¥)'},
|
||||||
|
{type: 'value', name: '比率 (%)'}
|
||||||
|
],
|
||||||
|
series: chartData.series
|
||||||
|
};
|
||||||
|
// 初始化图表
|
||||||
|
const myChart = echarts.init(document.getElementById('bar-chart'));
|
||||||
|
myChart.setOption(option);
|
||||||
|
|
||||||
|
// 监听窗口大小变化,自动重新绘制图表
|
||||||
|
window.addEventListener('resize', function () {
|
||||||
|
myChart.resize();
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
|
datepicker: function () {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var form = $("#chart-filter");
|
|
||||||
var ranges = {};
|
var ranges = {};
|
||||||
ranges[__('Today')] = [Moment().startOf('day'), Moment().endOf('day')];
|
ranges[__('Today')] = [Moment().startOf('day'), Moment().endOf('day')];
|
||||||
ranges[__('Yesterday')] = [Moment().subtract(1, 'days').startOf('day'), Moment().subtract(1, 'days').endOf('day')];
|
ranges[__('Yesterday')] = [Moment().subtract(1, 'days').startOf('day'), Moment().subtract(1, 'days').endOf('day')];
|
||||||
|
|
@ -147,7 +160,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t
|
||||||
$(this.element).val(start.format(options.locale.format) + " - " + end.format(options.locale.format));
|
$(this.element).val(start.format(options.locale.format) + " - " + end.format(options.locale.format));
|
||||||
};
|
};
|
||||||
require(['bootstrap-daterangepicker'], function () {
|
require(['bootstrap-daterangepicker'], function () {
|
||||||
$(".datetimerange", form).each(function () {
|
$(".datetimerange").each(function () {
|
||||||
$(this).on('apply.daterangepicker', function (ev, picker) {
|
$(this).on('apply.daterangepicker', function (ev, picker) {
|
||||||
callback.call(picker, picker.startDate, picker.endDate);
|
callback.call(picker, picker.startDate, picker.endDate);
|
||||||
var label = picker.chosenLabel;
|
var label = picker.chosenLabel;
|
||||||
|
|
@ -159,57 +172,38 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'echarts', 'echarts-t
|
||||||
$(this).daterangepicker($.extend({}, options), callback);
|
$(this).daterangepicker($.extend({}, options), callback);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
areapicker: function () {
|
||||||
|
$("#area-table").citypicker();
|
||||||
|
|
||||||
// 手动触发一次激活 tab 的 shown.bs.tab
|
$("#area-table").on("cp:updated", function() {
|
||||||
getChartData();
|
var citypicker = $(this).data("citypicker");
|
||||||
// 绑定查询按钮的点击事件
|
var code = citypicker.getCode("district") || citypicker.getCode("city") || citypicker.getCode("province");
|
||||||
$('#filter-btn').on('click', function() {
|
// table.bootstrapTable('refresh',{query: {area_code: code}});
|
||||||
getChartData();
|
$('#area_id').val(code);
|
||||||
});
|
});
|
||||||
},
|
|
||||||
|
|
||||||
add: function () {
|
|
||||||
Controller.api.bindevent();
|
|
||||||
},
|
|
||||||
edit: function () {
|
|
||||||
Controller.api.bindevent();
|
|
||||||
},
|
},
|
||||||
|
getChartData: function () {
|
||||||
|
// 获取日期范围值
|
||||||
|
var daterange = $('#daterange').val();
|
||||||
|
|
||||||
aftersales: function () {
|
// 构建查询参数
|
||||||
Controller.api.bindevent();
|
var params = {
|
||||||
},
|
'daterange': daterange,
|
||||||
|
|
||||||
api: {
|
|
||||||
bindevent: function () {
|
|
||||||
Form.api.bindevent($("form[role=form]"));
|
|
||||||
},
|
|
||||||
chart(chartData){
|
|
||||||
const option = {
|
|
||||||
tooltip: {
|
|
||||||
trigger: 'axis',
|
|
||||||
axisPointer: { type: 'shadow' }
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
data: chartData.series.map(s => s.name)
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
type: 'category',
|
|
||||||
data: chartData.xAxis
|
|
||||||
},
|
|
||||||
yAxis: [
|
|
||||||
{ type: 'value', name: '金额 (¥)' },
|
|
||||||
{ type: 'value', name: '比率 (%)' }
|
|
||||||
],
|
|
||||||
series: chartData.series
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 初始化图表
|
$.ajax({
|
||||||
const myChart = echarts.init(document.getElementById('bar-chart'));
|
url: "statistics/item/chartData", //
|
||||||
myChart.setOption(option);
|
type: "POST",
|
||||||
|
dataType: "json",
|
||||||
// 监听窗口大小变化,自动重新绘制图表
|
data: params,
|
||||||
window.addEventListener('resize', function() {
|
success: function (response) {
|
||||||
myChart.resize();
|
Controller.api.chart(response);
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
console.error("图表数据加载失败");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
134
public/assets/js/backend/supplement/orders.js
Normal file
134
public/assets/js/backend/supplement/orders.js
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
define(['jquery', 'bootstrap', 'backend', 'table', 'form','cascader'], function ($, undefined, Backend, Table, Form) {
|
||||||
|
|
||||||
|
var Controller = {
|
||||||
|
index: function () {
|
||||||
|
// 初始化表格参数配置
|
||||||
|
Table.api.init({
|
||||||
|
extend: {
|
||||||
|
index_url: 'supplement/orders/index' + location.search,
|
||||||
|
add_url: 'supplement/orders/add',
|
||||||
|
edit_url: 'supplement/orders/edit',
|
||||||
|
del_url: 'supplement/orders/del',
|
||||||
|
multi_url: 'supplement/orders/multi',
|
||||||
|
import_url: 'supplement/orders/import',
|
||||||
|
table: 'supplement_orders',
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var table = $("#table");
|
||||||
|
|
||||||
|
// 初始化表格
|
||||||
|
table.bootstrapTable({
|
||||||
|
url: $.fn.bootstrapTable.defaults.extend.index_url,
|
||||||
|
pk: 'id',
|
||||||
|
sortName: 'id',
|
||||||
|
fixedColumns: true,
|
||||||
|
fixedRightNumber: 1,
|
||||||
|
columns: [
|
||||||
|
[
|
||||||
|
{checkbox: true},
|
||||||
|
{field: 'id', title: __('Id')},
|
||||||
|
{field: 'user.nickname', title: '创建人'},
|
||||||
|
{field: 'area.merge_name', title: '地区',searchable:false},
|
||||||
|
{field: 'item_name', title: __('Item_name')},
|
||||||
|
{field: 'source_name', title: __('Source_name')},
|
||||||
|
{field: 'platform_order_no', title: __('Platform_order_no'), operate: 'LIKE'},
|
||||||
|
{field: 'buyer_account', title: __('Buyer_account'), operate: 'LIKE'},
|
||||||
|
{field: 'amount', title: __('Amount'), operate:'BETWEEN'},
|
||||||
|
{field: 'commission', title: __('Commission'), operate:'BETWEEN'},
|
||||||
|
{field: 'screenshots', title: '图片', operate: 'LIKE', table: table, class: 'autocontent', formatter: Table.api.formatter.content},
|
||||||
|
{field: 'status', title: __('Status'), searchList: {"0":__('Status 0'),"1":__('Status 1'),"2":__('Status 2')}, formatter: Table.api.formatter.status},
|
||||||
|
{field: 'created_at', title: __('Created_at'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
|
||||||
|
{field: 'updated_at', title: __('Updated_at'), operate:'RANGE', addclass:'datetimerange', autocomplete:false},
|
||||||
|
{field: 'operate', title: __('Operate'), table: table, events: Table.api.events.operate, formatter: Table.api.formatter.operate}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// 为表格绑定事件
|
||||||
|
Table.api.bindevent(table);
|
||||||
|
},
|
||||||
|
add: function () {
|
||||||
|
Controller.api.bindevent();
|
||||||
|
Controller.api.map();
|
||||||
|
},
|
||||||
|
edit: function () {
|
||||||
|
Controller.api.bindevent();
|
||||||
|
Controller.api.map();
|
||||||
|
},
|
||||||
|
api: {
|
||||||
|
bindevent: function () {
|
||||||
|
Form.api.bindevent($("form[role=form]"));
|
||||||
|
},
|
||||||
|
map:function () {
|
||||||
|
$("#c-city").on("cp:updated", function () {
|
||||||
|
var citypicker = $(this).data("citypicker");
|
||||||
|
var code = citypicker.getCode("district") || citypicker.getCode("city") || citypicker.getCode("province");
|
||||||
|
|
||||||
|
$("#area_id").val(code);
|
||||||
|
$("#area_name").val(citypicker.getVal());
|
||||||
|
});
|
||||||
|
// $("#area_map").data("callback", function (res) {
|
||||||
|
// Form.api.target($('#c-address'));
|
||||||
|
// });
|
||||||
|
$(document).on('click', "#area_map", function (e) {
|
||||||
|
const data = $("#c-city").val();
|
||||||
|
if (!data){
|
||||||
|
Toastr.error('请先选择区域');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var that = this;
|
||||||
|
var callback = $(that).data('callback');
|
||||||
|
var input_id = $(that).data("input-id") ? $(that).data("input-id") : "";
|
||||||
|
var lat_id = $(that).data("lat-id") ? $(that).data("lat-id") : "";
|
||||||
|
var lng_id = $(that).data("lng-id") ? $(that).data("lng-id") : "";
|
||||||
|
var zoom_id = $(that).data("zoom-id") ? $(that).data("zoom-id") : "";
|
||||||
|
var lat = lat_id ? $("#" + lat_id).val() : '';
|
||||||
|
var lng = lng_id ? $("#" + lng_id).val() : '';
|
||||||
|
var city_code = $("#c-city").val();
|
||||||
|
var zoom = zoom_id ? $("#" + zoom_id).val() : '';
|
||||||
|
var url = "/addons/address/index/select?a=1";
|
||||||
|
url += (lat && lng) ? 'lat=' + lat + '&lng=' + lng +
|
||||||
|
(input_id ? "&address=" + $("#" + input_id).val() : "")
|
||||||
|
+(zoom ? "&zoom=" + zoom : "") : ''
|
||||||
|
;
|
||||||
|
if (city_code){
|
||||||
|
url += city_code ? "&city_code=" + city_code : "";
|
||||||
|
}
|
||||||
|
// console.log(url);
|
||||||
|
Fast.api.open(url, '位置选择', {
|
||||||
|
callback: function (res) {
|
||||||
|
input_id && $("#" + input_id).val(res.address).trigger("change");
|
||||||
|
lat_id && $("#" + lat_id).val(res.lat).trigger("change");
|
||||||
|
lng_id && $("#" + lng_id).val(res.lng).trigger("change");
|
||||||
|
zoom_id && $("#" + zoom_id).val(res.zoom).trigger("change");
|
||||||
|
|
||||||
|
try {
|
||||||
|
//执行回调函数
|
||||||
|
if (typeof callback === 'function') {
|
||||||
|
callback.call(that, res);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
var _data = items;
|
||||||
|
|
||||||
|
$('#item_id').zdCascader({
|
||||||
|
data: _data,
|
||||||
|
onChange: function ($this, data, allPathData) {
|
||||||
|
// console.log(data,allPathData);
|
||||||
|
$('#item_id_value').val(data.value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$('#item_id').val($('#item_id').data('value')).focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return Controller;
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user