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:
todayswind 2025-06-22 18:42:28 +08:00 committed by Coding
commit e4ce0feef3
5 changed files with 194 additions and 90 deletions

View File

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

View File

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

View File

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

View File

@ -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 () {
@ -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,
@ -759,6 +779,7 @@ define(['jquery', 'bootstrap', 'backend', 'table', 'form', 'cascader'], function
}
}
});
function updateActiveItem($items) {
$items.removeClass('active');
if (selectedIndex >= 0) {

View File

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