Accept Merge Request #168: (feature/hant -> develop)
Merge Request: 退单统计 Created By: @todayswind Accepted By: @todayswind URL: https://g-bcrc3009.coding.net/p/allocatr/d/allocatr/git/merge/168?initial=true
This commit is contained in:
commit
e4ce0feef3
|
|
@ -19,7 +19,7 @@ class Aftersale extends Backend
|
|||
{
|
||||
|
||||
protected $noNeedRight = ['*'];
|
||||
protected $relationSearch = true,$items,$itemsformattedTree;
|
||||
protected $relationSearch = true,$items,$itemsformattedTree,$sources;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
|
|
@ -42,6 +42,29 @@ class Aftersale extends Backend
|
|||
$this->itemsformattedTree = $formattedTree;
|
||||
$this->view->assign("items", $formattedTree);
|
||||
$this->view->assign("default_daterange", $default_daterange);
|
||||
|
||||
$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'],'name'=>$item['title'].' - '.$pid_map[$item['pid']]['title'],
|
||||
];
|
||||
}
|
||||
}
|
||||
$this->view->assign("sources", $res);
|
||||
|
||||
parent::_initialize();
|
||||
}
|
||||
|
||||
|
|
@ -128,6 +151,7 @@ class Aftersale extends Backend
|
|||
$start = now()->modify('-30 days')->format('Y-m-d');
|
||||
$end_at = now()->format('Y-m-d 23:29:59');
|
||||
$area_code = request()->get('area_id');
|
||||
$source = request()->get('source');
|
||||
$filter = request()->get('range', '');
|
||||
if (!empty($filter)) {
|
||||
$arr = explode(' - ', $filter);
|
||||
|
|
@ -140,15 +164,19 @@ class Aftersale extends Backend
|
|||
}
|
||||
$build->where('audit_time', '>=', $start);
|
||||
$build->where('audit_time', '<=', $end_at);
|
||||
$build->group('a.area_id');
|
||||
$build->group('a.source,a.area_id');
|
||||
|
||||
|
||||
if ($area_code) {
|
||||
$build->where('area_id', 'like', $this->getSelectAreaCode($area_code) . '%');
|
||||
}
|
||||
if ($source) {
|
||||
$build->where('source', $source);
|
||||
}
|
||||
|
||||
$build->field(
|
||||
[
|
||||
'a.source',
|
||||
'a.area_id',
|
||||
'count(a.id) order_total',
|
||||
'count(c.id) after_total',
|
||||
|
|
@ -157,7 +185,10 @@ class Aftersale extends Backend
|
|||
)->with([
|
||||
'area' => function ($q) {
|
||||
$q->field('id,area_code,merge_name');
|
||||
}
|
||||
},
|
||||
'source' => function ($q) {
|
||||
$q->field('id,title');
|
||||
},
|
||||
]);
|
||||
|
||||
$res = $build->paginate();
|
||||
|
|
@ -189,6 +220,7 @@ class Aftersale extends Backend
|
|||
$start = now()->modify('-30 days')->format('Y-m-d');
|
||||
$end_at = now()->format('Y-m-d 23:29:59');
|
||||
$item_id = request()->get('item_id');
|
||||
$source = request()->get('source');
|
||||
$filter = request()->get('range', '');
|
||||
if (!empty($filter)) {
|
||||
$arr = explode(' - ', $filter);
|
||||
|
|
@ -201,7 +233,7 @@ class Aftersale extends Backend
|
|||
}
|
||||
$build->where('audit_time', '>=', $start);
|
||||
$build->where('audit_time', '<=', $end_at);
|
||||
$build->group('a.item_id,a.item_title');
|
||||
$build->group('a.source,a.item_id,a.item_title');
|
||||
|
||||
|
||||
|
||||
|
|
@ -210,16 +242,24 @@ class Aftersale extends Backend
|
|||
$item_ids [] = $item_id;
|
||||
$build->whereIn('item_id', $item_ids);
|
||||
}
|
||||
if ($source) {
|
||||
$build->where('source', $source);
|
||||
}
|
||||
|
||||
$build->field(
|
||||
[
|
||||
'a.source',
|
||||
'a.item_id',
|
||||
'a.item_title',
|
||||
'count(a.id) order_total',
|
||||
'count(c.id) after_total',
|
||||
'sum(c.refund_amount) refund_amount',
|
||||
]
|
||||
);
|
||||
)->with([
|
||||
'source' => function ($q) {
|
||||
$q->field('id,title');
|
||||
},
|
||||
]);
|
||||
|
||||
$res = $build->paginate();
|
||||
$total = $res->total();
|
||||
|
|
|
|||
|
|
@ -199,6 +199,9 @@ class Order extends Model
|
|||
public function item(){
|
||||
return $this->belongsTo(Item::class,'item_id',);
|
||||
}
|
||||
public function source(){
|
||||
return $this->belongsTo(Source::class,'source');
|
||||
}
|
||||
|
||||
public function area(){
|
||||
return $this->belongsTo(Area::class,'area_id','area_code');
|
||||
|
|
|
|||
|
|
@ -195,14 +195,23 @@
|
|||
<div id="chart-filter-table2" style="margin-top:20px;margin-bottom: 30px;">
|
||||
<div style="display: flex;position: relative" class="col-sm-6 row">
|
||||
|
||||
<div style="display: inline-block;width: 300px;position: absolute">
|
||||
<select id="table2-source" title="请选择订单渠道" name="row[source]" class="form-control"
|
||||
style="display: inline-block;width: 150px;position: absolute">
|
||||
<option value="">全部</option>
|
||||
{foreach $sources as $item}
|
||||
<option value="{$item['id']}">{$item['name']}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
|
||||
<div style="display: inline-block;width: 300px;position: absolute;left: 170px">
|
||||
<input id="city-search" data-rule="required" class="form-control" data-toggle="city-picker" type="text" />
|
||||
<input id="area_id" style="display: none" class="form-control" name="area_id" hidden type="text" />
|
||||
</div>
|
||||
|
||||
<input type="text" class="form-control datetimerange" value="{$default_daterange}" data-locale='{"format":"YYYY-MM-DD"}'
|
||||
placeholder="指定日期" name="filter[daterange]" id="daterange-table2" autocomplete="off" style="position: absolute;left: 320px;width: 180px;">
|
||||
<button class="btn btn-default ml-2" id="first-search2" style="position: absolute;left: 500px;">查询</button>
|
||||
placeholder="指定日期" name="filter[daterange]" id="daterange-table2" autocomplete="off" style="position: absolute;left: 475px;width: 180px;">
|
||||
<button class="btn btn-default ml-2" id="first-search2" style="position: absolute;left: 650px;">查询</button>
|
||||
<button class="btn btn-default ml-2" id="reset2" style="position: absolute;left: 705px;">重置</button>
|
||||
</div>
|
||||
<!-- 查询按钮 -->
|
||||
|
||||
|
|
@ -216,6 +225,13 @@
|
|||
<div id="chart-filter-table3" style="margin-top:20px;margin-bottom: 30px;">
|
||||
<div style="display: flex;position: relative" class="col-lg-6 col-sm-8 row">
|
||||
|
||||
<select id="table3-source" title="请选择订单渠道" name="row[source]" class="form-control"
|
||||
style="display: inline-block;width: 150px; margin-right: 10px">
|
||||
<option value="">全部</option>
|
||||
{foreach $sources as $item}
|
||||
<option value="{$item['id']}">{$item['name']}</option>
|
||||
{/foreach}
|
||||
</select>
|
||||
<div style="max-width: 275px">
|
||||
<input type="text" id="item_id" class="zd-input__inner mr-2" style="width: 275px">
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -28,21 +28,39 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
|
|||
|
||||
// 拼装文本
|
||||
function assembleOrderMessage(data) {
|
||||
const message = `订单编号: ${data.order_no}
|
||||
let message = '';
|
||||
if (!data.coupon) {
|
||||
message = `订单编号: ${data.order_no}
|
||||
服务名称: ${data.item_title}
|
||||
客户昵称: ${data.customer}
|
||||
客户电话: ${data.tel}
|
||||
客户地址: ${data.address}
|
||||
收款金额: ${data.receive_type === 1 ? '已收定金 ' + data.online_amount : '已收全款 ' + data.online_amount}
|
||||
优惠活动: ${data.coupon?.description || '无'}
|
||||
订单详情: ${data.detail || '无'}
|
||||
订单备注: ${data.remark}
|
||||
下单金额: ${data.receive_type === 1 ? '已收定金 ' + formatNumber(data.online_amount) : '已收全款 ' + formatNumber(data.online_amount)}
|
||||
订单备注: ${data.remark || '无'}
|
||||
预约时间: ${data.plan_time || '无'}
|
||||
`;
|
||||
} else {
|
||||
message = `订单编号: ${data.order_no}
|
||||
服务名称: ${data.item_title}
|
||||
客户昵称: ${data.customer}
|
||||
客户电话: ${data.tel}
|
||||
客户地址: ${data.address}
|
||||
下单金额: ${data.receive_type === 1 ? '已收定金 ' + formatNumber(data.online_amount) : '已收全款 ' + formatNumber(data.online_amount)}
|
||||
优惠活动: ${data.coupon?.description || '无'}
|
||||
订单备注: ${data.remark ||'无'}
|
||||
预约时间: ${data.plan_time || '无'}
|
||||
`;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
function formatNumber(value, decimals = 1) {
|
||||
let num = parseFloat(value);
|
||||
if (isNaN(num)) return '0.0'.slice(0, decimals + 2); // e.g. '0.0' or '0.00'
|
||||
return num.toFixed(decimals);
|
||||
}
|
||||
|
||||
|
||||
var Controller = {
|
||||
index: function () {
|
||||
|
|
@ -83,7 +101,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
|
|||
fixed: true,
|
||||
searchList: {
|
||||
"0": __('Status 0'),
|
||||
"10": __('Status 10'),
|
||||
"10": __('Status 10'),
|
||||
"20": __('Status 20'),
|
||||
"30": __('Status 30'),
|
||||
"40": __('Status 40'),
|
||||
|
|
@ -115,7 +133,8 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
|
|||
var now = new Date();
|
||||
var diffMinutes = (now - createTime) / (1000 * 60); // 计算分钟差
|
||||
|
||||
return diffMinutes > 20 ? '<span style="color: red;">超时</span>' : '<span class="label label-success">未超时</span>';;
|
||||
return diffMinutes > 20 ? '<span style="color: red;">超时</span>' : '<span class="label label-success">未超时</span>';
|
||||
;
|
||||
},
|
||||
searchList: {
|
||||
"1": '超时',
|
||||
|
|
@ -211,13 +230,15 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
|
|||
autocomplete: false
|
||||
},
|
||||
|
||||
{field: 'area_id', title: __('地区'), searchList: function (column) {
|
||||
{
|
||||
field: 'area_id', title: __('地区'), searchList: function (column) {
|
||||
return Template('categorytpl', {});
|
||||
}, formatter: function (value, row, index) {
|
||||
return '无';
|
||||
}, visible: false
|
||||
},
|
||||
{field: 'item_id', title: '服务项目', searchList: function (column) {
|
||||
{
|
||||
field: 'item_id', title: '服务项目', searchList: function (column) {
|
||||
return Template('items_picker', {});
|
||||
}, formatter: function (value, row, index) {
|
||||
return '无';
|
||||
|
|
@ -470,7 +491,6 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
|
|||
resetIdleTimer();
|
||||
|
||||
|
||||
|
||||
var _data = items;
|
||||
$('#select_item').zdCascader({
|
||||
data: _data,
|
||||
|
|
@ -478,7 +498,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
|
|||
// console.log(data,allPathData);
|
||||
$('#select_item_id').val(data.value);
|
||||
},
|
||||
clear:true,
|
||||
clear: true,
|
||||
clickParent: true
|
||||
});
|
||||
|
||||
|
|
@ -486,14 +506,14 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
|
|||
add: function () {
|
||||
$("#mybuttom").on("click", function () {
|
||||
const res = $("form[role=form]").isValid();
|
||||
if ($('#lng').val() && $('#lng').val() !== ''){
|
||||
if ($('#lng').val() && $('#lng').val() !== '') {
|
||||
if (res) {
|
||||
Form.api.submit($("form[role=form]"),function (data){
|
||||
Form.api.submit($("form[role=form]"), function (data) {
|
||||
copyToClipboard(assembleOrderMessage(data));
|
||||
});
|
||||
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
Toastr.success('请选择有效地址');
|
||||
}
|
||||
|
||||
|
|
@ -503,7 +523,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
|
|||
$("#mysubmit").on("click", function () {
|
||||
const res = $("form[role=form]").isValid();
|
||||
|
||||
if ($('#lng').val() && $('#lng').val() !== ''){
|
||||
if ($('#lng').val() && $('#lng').val() !== '') {
|
||||
if (res) {
|
||||
Form.api.submit($("form[role=form]"), function (data, ret) {
|
||||
clearInfo();
|
||||
|
|
@ -511,7 +531,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
|
|||
return false;
|
||||
});
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
Toastr.success('请选择有效地址');
|
||||
}
|
||||
return false;
|
||||
|
|
@ -519,54 +539,54 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
|
|||
|
||||
$("#smart").on("click", function () {
|
||||
Fast.api.ajax({
|
||||
url: "order/smart", // 你的 API 地址
|
||||
type: "post",
|
||||
contentType: 'application/json',
|
||||
dataType: "json",
|
||||
data: JSON.stringify({
|
||||
str: $('#smart_text').val()
|
||||
})
|
||||
}, function (data) {
|
||||
if (data.mobile !== '') {
|
||||
$('#c-tel').val(data.mobile);
|
||||
}
|
||||
if (data.name !== '') {
|
||||
$('#c-customer').val(data.name);
|
||||
}
|
||||
if (data.item.id !== 0) {
|
||||
$('#item_id_value').val(data.item.id);
|
||||
$('#item_id').val(data.item.item);
|
||||
}
|
||||
if (data.idn) {
|
||||
$('#c-source-id').val(data.idn);
|
||||
}
|
||||
// $city.citypicker({
|
||||
// province: data.province,
|
||||
// city: data.city,
|
||||
// district: data.region
|
||||
// });
|
||||
if (data.area_id) {
|
||||
$("#area_id").val(data.area_id);
|
||||
}
|
||||
if (data.lat) {
|
||||
$("#lat").val(data.lat);
|
||||
}
|
||||
if (data.lng) {
|
||||
$("#lng").val(data.lng);
|
||||
}
|
||||
if (data.area_id) {
|
||||
$("#area_id").val(data.area_id);
|
||||
}
|
||||
if (data.plan_time) {
|
||||
$("#time").val(data.plan_time);
|
||||
}
|
||||
if (data.addr && data.addr !== '') {
|
||||
$("#c-address").val(data.addr);
|
||||
$("#area_name").val(data.addr);
|
||||
}
|
||||
Toastr.info('识别成功');
|
||||
return false;
|
||||
});
|
||||
url: "order/smart", // 你的 API 地址
|
||||
type: "post",
|
||||
contentType: 'application/json',
|
||||
dataType: "json",
|
||||
data: JSON.stringify({
|
||||
str: $('#smart_text').val()
|
||||
})
|
||||
}, function (data) {
|
||||
if (data.mobile !== '') {
|
||||
$('#c-tel').val(data.mobile);
|
||||
}
|
||||
if (data.name !== '') {
|
||||
$('#c-customer').val(data.name);
|
||||
}
|
||||
if (data.item.id !== 0) {
|
||||
$('#item_id_value').val(data.item.id);
|
||||
$('#item_id').val(data.item.item);
|
||||
}
|
||||
if (data.idn) {
|
||||
$('#c-source-id').val(data.idn);
|
||||
}
|
||||
// $city.citypicker({
|
||||
// province: data.province,
|
||||
// city: data.city,
|
||||
// district: data.region
|
||||
// });
|
||||
if (data.area_id) {
|
||||
$("#area_id").val(data.area_id);
|
||||
}
|
||||
if (data.lat) {
|
||||
$("#lat").val(data.lat);
|
||||
}
|
||||
if (data.lng) {
|
||||
$("#lng").val(data.lng);
|
||||
}
|
||||
if (data.area_id) {
|
||||
$("#area_id").val(data.area_id);
|
||||
}
|
||||
if (data.plan_time) {
|
||||
$("#time").val(data.plan_time);
|
||||
}
|
||||
if (data.addr && data.addr !== '') {
|
||||
$("#c-address").val(data.addr);
|
||||
$("#area_name").val(data.addr);
|
||||
}
|
||||
Toastr.info('识别成功');
|
||||
return false;
|
||||
});
|
||||
});
|
||||
Controller.api.bindevent();
|
||||
Controller.api.map();
|
||||
|
|
@ -739,26 +759,27 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
|
|||
$('#suggestionList').show();
|
||||
})
|
||||
.on('keydown', function (e) {
|
||||
const $items = $('#suggestionList li');
|
||||
const len = $items.length;
|
||||
const $items = $('#suggestionList li');
|
||||
const len = $items.length;
|
||||
|
||||
if (!len) return;
|
||||
if (!len) return;
|
||||
|
||||
if (e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
selectedIndex = (selectedIndex + 1) % len;
|
||||
updateActiveItem($items);
|
||||
} else if (e.key === 'ArrowUp') {
|
||||
e.preventDefault();
|
||||
selectedIndex = (selectedIndex - 1 + len) % len;
|
||||
updateActiveItem($items);
|
||||
} else if (e.key === 'Enter') {
|
||||
if (selectedIndex >= 0 && selectedIndex < len) {
|
||||
if (e.key === 'ArrowDown') {
|
||||
e.preventDefault();
|
||||
$items.eq(selectedIndex).trigger('mousedown');
|
||||
selectedIndex = (selectedIndex + 1) % len;
|
||||
updateActiveItem($items);
|
||||
} else if (e.key === 'ArrowUp') {
|
||||
e.preventDefault();
|
||||
selectedIndex = (selectedIndex - 1 + len) % len;
|
||||
updateActiveItem($items);
|
||||
} else if (e.key === 'Enter') {
|
||||
if (selectedIndex >= 0 && selectedIndex < len) {
|
||||
e.preventDefault();
|
||||
$items.eq(selectedIndex).trigger('mousedown');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function updateActiveItem($items) {
|
||||
$items.removeClass('active');
|
||||
if (selectedIndex >= 0) {
|
||||
|
|
@ -836,7 +857,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
|
|||
addressSelected = true;
|
||||
});
|
||||
|
||||
function choseFirst(){
|
||||
function choseFirst() {
|
||||
const first = $('#suggestionList li').first();
|
||||
const name = first.data('name');
|
||||
const location = first.data('location'); // "经度,纬度"
|
||||
|
|
|
|||
|
|
@ -48,12 +48,30 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template', 'addtabs'
|
|||
e.preventDefault();
|
||||
const range = $('#daterange-table2').val();
|
||||
const area_id = $('#area_id').val();
|
||||
const source = $('#table2-source').val();
|
||||
let data = '';
|
||||
if (range !== ''){
|
||||
data += 'range=' + range;
|
||||
}
|
||||
if (area_id !== ''){
|
||||
data += 'area_id=' + area_id;
|
||||
data += '&area_id=' + area_id;
|
||||
}
|
||||
if (source !== ''){
|
||||
data += '&source=' + source;
|
||||
}
|
||||
// data = encodeURIComponent(data);
|
||||
$("#table2").bootstrapTable('refresh',{
|
||||
url:'statistics/aftersale/city?' + data,
|
||||
});
|
||||
});
|
||||
$('#reset2').on('click', function (e) {
|
||||
$("#city-search").citypicker('reset');
|
||||
$("#area_id").val('');
|
||||
$('#table2-source option:first').prop('selected', true);
|
||||
const range = $('#daterange-table2').val();
|
||||
let data = '';
|
||||
if (range !== ''){
|
||||
data += 'range=' + range;
|
||||
}
|
||||
// data = encodeURIComponent(data);
|
||||
$("#table2").bootstrapTable('refresh',{
|
||||
|
|
@ -65,6 +83,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template', 'addtabs'
|
|||
|
||||
const range = $('#daterange-table3').val();
|
||||
const item_id = $('#item_id_value').val();
|
||||
const source = $('#table3-source').val();
|
||||
let data = '';
|
||||
if (range !== ''){
|
||||
data += 'range=' + range;
|
||||
|
|
@ -72,6 +91,9 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template', 'addtabs'
|
|||
if (item_id !== ''){
|
||||
data += '&item_id=' + item_id;
|
||||
}
|
||||
if (source !== ''){
|
||||
data += '&source=' + source;
|
||||
}
|
||||
// data = encodeURIComponent(data);
|
||||
$("#table3").bootstrapTable('refresh',{
|
||||
url:'statistics/aftersale/item?' + data,
|
||||
|
|
@ -156,6 +178,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template', 'addtabs'
|
|||
searchFormVisible: true,
|
||||
columns: [
|
||||
[
|
||||
{field: 'source.title', title: '渠道', operate: false},
|
||||
{field: 'area.merge_name', title: '城市', operate: false},
|
||||
{field: 'order_total', title: '订单总数', operate: false},
|
||||
{field: 'after_total', title: '退款订单数', operate: false},
|
||||
|
|
@ -205,6 +228,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'template', 'addtabs'
|
|||
searchFormVisible: true,
|
||||
columns: [
|
||||
[
|
||||
{field: 'source.title', title: '渠道', operate: false},
|
||||
{field: 'item_title', title: '服务项目', operate: false},
|
||||
{field: 'order_total', title: '订单总数', operate: false},
|
||||
{field: 'refund_amount', title: '退款金额', operate: false},
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user