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:
todayswind 2025-05-18 18:42:41 +08:00 committed by Coding
commit 8c9b769746
15 changed files with 1233 additions and 155 deletions

View File

@ -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);
} }
} }

View File

@ -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;

View 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;
}
}

View File

@ -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;
} }

View 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();
}
}

View 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' => '最后更新时间'
];

View 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');
}
}

View 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' => [],
];
}

View File

@ -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>

View 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>

View 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>

View 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>

View File

@ -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'),

View File

@ -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("图表数据加载失败");
}
}); });
} }
} }

View 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;
});