From 76cfa6b27807c9b44e833a65155ec8df29bf9a75 Mon Sep 17 00:00:00 2001 From: gitfjn <2860488097@qq.com> Date: Fri, 30 Jan 2026 18:48:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/controller/BulletinBoard.php | 247 ++++++++++++++ application/admin/controller/Order.php | 54 ++-- application/admin/controller/Staff.php | 7 + application/admin/logic/GoodsLogic.php | 3 +- application/admin/logic/OrderLogic.php | 14 +- application/admin/logic/OrderautoLogic.php | 10 +- application/admin/logic/StaffLogic.php | 41 +++ .../admin/view/bulletin_board/index.html | 303 +++++++++--------- application/admin/view/order/eidt.html | 149 ++++++++- application/admin/view/order/lists.html | 86 ++++- application/admin/view/staff/wages.html | 8 +- application/api/controller/Order.php | 6 +- application/api/controller/Points.php | 45 ++- application/api/controller/Share.php | 2 +- application/api/logic/GoodsLogic.php | 2 +- application/api/logic/OrderLogic.php | 48 +-- application/api/logic/PointsLogic.php | 102 ++++-- application/api/model/Goods.php | 13 + application/api/model/GoodsPoints.php | 10 + application/api/model/OrderPoints.php | 24 ++ application/api/model/UserAddress.php | 10 + application/common/logic/OrderRefundLogic.php | 4 +- application/common/logic/PayNotifyLogic.php | 36 +-- application/common/model/Ad.php | 6 +- .../common/server/storage/engine/Aliyun.php | 2 +- 25 files changed, 943 insertions(+), 289 deletions(-) create mode 100644 application/api/model/GoodsPoints.php create mode 100644 application/api/model/OrderPoints.php create mode 100644 application/api/model/UserAddress.php diff --git a/application/admin/controller/BulletinBoard.php b/application/admin/controller/BulletinBoard.php index bf70c2af..62719ebe 100644 --- a/application/admin/controller/BulletinBoard.php +++ b/application/admin/controller/BulletinBoard.php @@ -6,6 +6,7 @@ use app\admin\model\OrderRecharge; use app\admin\model\OrderYearcard; use app\admin\model\User; use app\common\server\UrlServer; +use think\Db; use think\facade\Url; use app\admin\model\Order; @@ -15,6 +16,14 @@ class BulletinBoard extends AdminBase //看板统计 public function index() { + // 本月与上月时间范围 + $monthStart = date('Y-m-01 00:00:00'); + $monthEnd = date('Y-m-t 23:59:59'); + $lastMonthStart = date('Y-m-01 00:00:00', strtotime('-1 month')); + $lastMonthEnd = date('Y-m-t 23:59:59', strtotime('-1 month')); + $monthStartTs = strtotime($monthStart); + $monthEndTs = strtotime($monthEnd); + //查询商品订单 $orderMoney = Order::where('status','<>', 0)->sum('order_amount'); //年卡订单 @@ -104,6 +113,243 @@ class BulletinBoard extends AdminBase // 本月注册但没下过单的(新客户) $newCustomerCount = count($monthUsers) - $oldCustomerCount; } + + // ========== 目标完成率与客服进度 ========== + // 销售目标(可以后续做成后台可配置,这里先写死为 100000) + $monthlyTarget = 100000; + $overallCompletion = $monthlyTarget > 0 ? round(($monthlySales / $monthlyTarget) * 100, 2) : 0; + + // 按客服统计本月与上月销售额 + $staffCurrent = Db::name('order') + ->alias('o') + ->join('admin a', 'o.admin_id = a.id', 'LEFT') + ->where('o.status', '<>', 0) + ->whereTime('o.create_time', 'between', [$monthStart, $monthEnd]) + ->field('o.admin_id,a.name as staff_name,SUM(o.order_amount) as total') + ->group('o.admin_id') + ->select(); + + $staffLast = Db::name('order') + ->alias('o') + ->join('admin a', 'o.admin_id = a.id', 'LEFT') + ->where('o.status', '<>', 0) + ->whereTime('o.create_time', 'between', [$lastMonthStart, $lastMonthEnd]) + ->field('o.admin_id,SUM(o.order_amount) as total') + ->group('o.admin_id') + ->select(); + + $staffLastMap = []; + foreach ($staffLast as $row) { + $staffLastMap[$row['admin_id']] = $row['total']; + } + + $staffProgress = []; + foreach ($staffCurrent as $row) { + $adminId = $row['admin_id']; + $staffSales = (float)$row['total']; + $lastSales = isset($staffLastMap[$adminId]) ? (float)$staffLastMap[$adminId] : 0; + $percent = $monthlySales > 0 ? round(($staffSales / $monthlySales) * 100, 2) : 0; + $yoy = $lastSales > 0 ? round((($staffSales - $lastSales) / $lastSales) * 100, 2) : 0; + + $staffProgress[] = [ + 'name' => $row['staff_name'] ?: '未分配', + 'sales' => $staffSales, + 'percent' => $percent, + 'yoy' => $yoy, + ]; + } + + // ========== 渠道分析(当月订单数按渠道) ========== + $channelRows = Db::name('order') + ->alias('o') + ->join('orderchannel c', 'o.channel_id = c.id', 'LEFT') + ->where('o.status', '<>', 0) + ->whereTime('o.create_time', 'month') + ->field('c.name as channel_name, COUNT(*) as total') + ->group('o.channel_id') + ->select(); + + $channelPie = []; + foreach ($channelRows as $row) { + $name = $row['channel_name'] ?: '其他'; + $value = (int)$row['total']; + $channelPie[] = [ + 'name' => $name, + 'value' => $value, + ]; + } + + // ========== 每日销售趋势(仅商品订单,按天汇总) ========== + $trendRows = Db::name('order') + ->where('status', '<>', 0) + ->whereTime('create_time', 'between', [$monthStart, $monthEnd]) + ->field("FROM_UNIXTIME(create_time,'%Y-%m-%d') as day, SUM(order_amount) as total") + ->group('day') + ->order('day asc') + ->select(); + + $trendDates = []; + $trendValues = []; + $trendTotal = 0; + foreach ($trendRows as $row) { + $trendDates[] = $row['day']; + $amount = (float)$row['total']; + $trendValues[] = $amount; + $trendTotal += $amount; + } + + // 上月总销售额(用于计算趋势图上的“上月同比”) + $lastTrendTotal = Db::name('order') + ->where('status', '<>', 0) + ->whereTime('create_time', 'between', [$lastMonthStart, $lastMonthEnd]) + ->sum('order_amount'); + + $trendCompare = $lastTrendTotal > 0 ? round((($trendTotal - $lastTrendTotal) / $lastTrendTotal) * 100, 2) : 0; + + // ========== 区域月销售额(通过地址模糊匹配简单统计) ========== + $regions = ['南明区', '云岩区', '白云区', '乌当区', '花溪区', '龙里']; + $regionTotals = []; + foreach ($regions as $regionName) { + $total = Db::name('order') + ->where('status', '<>', 0) + ->whereTime('create_time', 'month') + ->whereLike('address', '%' . $regionName . '%') + ->sum('order_amount'); + $regionTotals[] = (float)$total; + } + + // ========== 本月销售情况(单次/年卡/次卡/其它服务) ========== + // 复用统计图表控制器中的规则:根据 number 字段区分不同卡类型 + $salesSituation = [ + ['value' => 0, 'name' => '单次服务'], + ['value' => 0, 'name' => '年卡销量'], + ['value' => 0, 'name' => '次卡销量'], + ['value' => 0, 'name' => '其它服务'], + ]; + $kaWhere = [ + ['del', '=', 0], + ['create_time', '>=', $monthStartTs], + ['create_time', '<=', $monthEndTs], + ]; + // 单次服务:number = 1 + $salesSituation[0]['value'] = Db::name('order') + ->where($kaWhere) + ->where('number', '=', 1) + ->sum('total_amount'); + // 年卡:number > 6 + $salesSituation[1]['value'] = Db::name('order') + ->where($kaWhere) + ->where('number', '>', 6) + ->sum('total_amount'); + // 次卡:2 <= number <= 6 + $salesSituation[2]['value'] = Db::name('order') + ->where($kaWhere) + ->where('number', '>=', 2) + ->where('number', '<=', 6) + ->sum('total_amount'); + // 其它服务:number = 0 + $salesSituation[3]['value'] = Db::name('order') + ->where($kaWhere) + ->where('number', '=', 0) + ->sum('total_amount'); + + // ========== 渠道 & 区域详细拆分(总额 / 年卡 / 次卡 / 单次 / 其它) ========== + $serviceTypes = [ + 'total' => [], + 'year' => [['number', '>', 6]], + 'times' => [['number', '>=', 2], ['number', '<=', 6]], + 'single'=> [['number', '=', 1]], + 'other' => [['number', '=', 0]], + ]; + + // 渠道关键字到列 key 的映射 + $channelBuckets = [ + 'meituan' => '美团', + 'gzh' => '公众号', + 'douyin' => '抖音', + 'staff' => '员工', + 'yeye' => '异业', + 'other' => '渠道', + ]; + + $channelDetail = []; + foreach ($serviceTypes as $typeKey => $extraWhere) { + $totals = [ + 'meituan' => 0, + 'gzh' => 0, + 'douyin' => 0, + 'staff' => 0, + 'yeye' => 0, + 'other' => 0, + ]; + + $query = Db::name('order') + ->alias('o') + ->join('orderchannel c', 'o.channel_id = c.id', 'LEFT') + ->where('o.status', '<>', 0) + ->whereBetween('o.create_time', [$monthStartTs, $monthEndTs]); + + if (!empty($extraWhere)) { + $query->where($extraWhere); + } + + $rows = $query + ->field('c.name as channel_name, SUM(o.order_amount) as total') + ->group('o.channel_id') + ->select(); + + foreach ($rows as $row) { + $name = $row['channel_name'] ?? ''; + $value = (float)($row['total'] ?? 0); + $bucket = 'other'; + if (mb_strpos($name, '美团') !== false) { + $bucket = 'meituan'; + } elseif (mb_strpos($name, '公众号') !== false || mb_strpos($name, '公') !== false) { + $bucket = 'gzh'; + } elseif (mb_strpos($name, '抖音') !== false) { + $bucket = 'douyin'; + } elseif (mb_strpos($name, '员工') !== false) { + $bucket = 'staff'; + } elseif (mb_strpos($name, '异业') !== false) { + $bucket = 'yeye'; + } + $totals[$bucket] += $value; + } + + $channelDetail[$typeKey] = $totals; + } + + // 区域明细:每种服务类型在各区域的销售额 + $regionDetail = []; + foreach ($serviceTypes as $typeKey => $extraWhere) { + $regionDetail[$typeKey] = []; + foreach ($regions as $regionName) { + $q = Db::name('order') + ->where('status', '<>', 0) + ->whereBetween('create_time', [$monthStartTs, $monthEndTs]) + ->whereLike('address', '%' . $regionName . '%'); + if (!empty($extraWhere)) { + $q->where($extraWhere); + } + $regionDetail[$typeKey][$regionName] = (float)$q->sum('order_amount'); + } + } + + // 汇总仪表盘数据供前端使用 + $dashboardData = [ + 'monthlyTarget' => $monthlyTarget, + 'overallCompletion' => $overallCompletion, + 'staffProgress' => $staffProgress, + 'channelPie' => $channelPie, + 'trendDates' => $trendDates, + 'trendValues' => $trendValues, + 'trendCompare' => $trendCompare, + 'regions' => $regions, + 'regionTotals' => $regionTotals, + 'salesSituation' => $salesSituation, + 'channelDetail' => $channelDetail, + 'regionDetail' => $regionDetail, + ]; // 传递数据到视图 $this->assign([ @@ -115,6 +361,7 @@ class BulletinBoard extends AdminBase 'customersCompare' => $customersCompare, 'oldCustomers' => $oldCustomerCount, // 老客户数量(本月注册且下过单的) 'newCustomers' => $newCustomerCount, // 新客户数量(本月注册但没下过单的) + 'dashboardData' => json_encode($dashboardData, JSON_UNESCAPED_UNICODE), ]); return $this->fetch(); diff --git a/application/admin/controller/Order.php b/application/admin/controller/Order.php index 0c887287..ea427adf 100644 --- a/application/admin/controller/Order.php +++ b/application/admin/controller/Order.php @@ -100,26 +100,42 @@ class Order extends AdminBase */ public function del() { - if ($this->request->isAjax()) { - dump(123);die; - // $post = $this->request->post(''); - // $order=Db::name('order')->where('id',$post['order_id'])->find();//查询订单信息 - - // if($this->admin_id!=6){ - // $this->_error('无权限删除'); - // }else{ - // $orderdel=Db::name('order_exe')->where('order_sn',$order['order_sn'])->find(); - // if($orderdel){ - // $this->_error('无法删除,存在主订单'); - // }else{ - // $del=Db::name('order')->where('id',$post['order_id'])->delete(); - // $this->_success('删除成功'); - // } - - // } - + $id = $this->request->get('id'); + $order = Db::name('order')->find($id);//查询订单信息 + if ($order == null){ + $this->_error('订单不存在'); + } + $del = Db::name('order')->where('id',$id)->update(['del' => 1]); + if($del){ + $this->_success('删除成功'); + }else{ + $this->_error('删除失败'); + } + } + } + /** + * User: 恢复已删除订单 + * Desc: 将 del 从 1 恢复为 0 + */ + public function recover() + { + if ($this->request->isAjax()) { + $id = $this->request->get('id'); + $order = Db::name('order')->find($id);// 查询订单信息 + if ($order == null){ + $this->_error('订单不存在'); + } + if ($order['del'] == 0) { + $this->_error('订单未删除,无需恢复'); + } + $res = Db::name('order')->where('id',$id)->update(['del' => 0]); + if ($res) { + $this->_success('恢复成功'); + } else { + $this->_error('恢复失败'); + } } } @@ -268,7 +284,7 @@ class Order extends AdminBase $this->_success('修改订单成功', OrderLogic::edit($post)); } - $this->assign('info', json_encode(OrderLogic::orderinfoid($id), JSON_UNESCAPED_UNICODE)); + $this->assign('info', json_encode(OrderLogic::orderinfoid($id), JSON_UNESCAPED_UNICODE)); $brand_lists=Db::name('orderchannel')->select(); $this->assign('brand_lists', json_encode($brand_lists, JSON_UNESCAPED_UNICODE)); $this->assign('category_lists', json_encode(StaffLogic::getAllTree(), JSON_UNESCAPED_UNICODE)); diff --git a/application/admin/controller/Staff.php b/application/admin/controller/Staff.php index 433ac8f7..2f6a5a50 100644 --- a/application/admin/controller/Staff.php +++ b/application/admin/controller/Staff.php @@ -659,6 +659,13 @@ public function group_del(){ $this->assign('goods_brand',StaffLogic::goods_brand()); return $this->fetch(); } + + // 员工工资导出 + public function exportWages() + { + $get = $this->request->get(); + $this->_success('', StaffLogic::wagesExport($get)); + } //删除员工的工资 public function wagesdel(){ diff --git a/application/admin/logic/GoodsLogic.php b/application/admin/logic/GoodsLogic.php index cf6c6c16..425e5da7 100644 --- a/application/admin/logic/GoodsLogic.php +++ b/application/admin/logic/GoodsLogic.php @@ -291,7 +291,8 @@ class GoodsLogic 'give_integral_type' => $give_integral_type, 'give_integral' => $give_integral, 'spec_type' => $post['spec_type'], - 'create_time' => $time + 'create_time' => $time, + 'type' => $post['type'] ]; $goods_id = Db::name('goods')->insertGetId($data); diff --git a/application/admin/logic/OrderLogic.php b/application/admin/logic/OrderLogic.php index 435a73f1..0eb413b7 100644 --- a/application/admin/logic/OrderLogic.php +++ b/application/admin/logic/OrderLogic.php @@ -34,10 +34,14 @@ class OrderLogic public static function getListsCondition($get) { $where = []; - - //订单状态 - if ($get['type'] != '') { - $where[] = ['pay_status', '=', $get['type']]; + if ($get['type'] != 66){ + //订单状态 + if ($get['type'] != '') { + $where[] = ['pay_status', '=', $get['type']]; + } + $where[] = ['del', '=', 0]; + }else{ + $where[] = ['del', '=', 1]; } //订单编号查询 if (isset($get['order_sn']) && $get['order_sn'] != '') { @@ -117,7 +121,7 @@ class OrderLogic $order = new Order(); $where = self::getListsCondition($get); $field = 'o.*,order_status as order_status_text,pay_way as pay_way_text'; - $brand = Db::name('goods_brand')->where(['del' => 0])->column('name', 'id'); //订单类型 + $brand = Db::name('goods_brand')->column('name', 'id'); //订单类型 $admin = Db::name('admin')->column('name', 'id'); $count = $order ->where($where) diff --git a/application/admin/logic/OrderautoLogic.php b/application/admin/logic/OrderautoLogic.php index e4f7859a..ed25d5d5 100644 --- a/application/admin/logic/OrderautoLogic.php +++ b/application/admin/logic/OrderautoLogic.php @@ -14,7 +14,9 @@ class OrderautoLogic{ public static function lists($get){ $where = []; //判断已经支付的订单 - $where[] = ['pay_status', '=', 1]; +// $where[] = ['pay_status', '=', 1]; + $where[] = ['refund_status', '=', 0]; + $where[] = ['del', '=', 0]; if(isset($get['type']) && $get['type'] != ''){ $where[] = ['static','=',$get['type']]; } @@ -38,10 +40,8 @@ class OrderautoLogic{ $where[] = ['status','=',$get['status']]; } - // 执行状态查询 - if(isset($get['admin']) && $get['admin']!= ''){ - $where[] = ['admin_id','=',$get['admin']]; - } + // 如果订单的admin_id不等于空,不需要限制支付状态;如果admin_id等于空,只查询已支付的订单 + $where[] = ['', 'exp', Db::raw("(admin_id IS NOT NULL AND admin_id != '') OR pay_status = 1")]; // 订单的来源查询 if(isset($get['pid']) && $get['pid']!= ''){ $where[] = ['channel_id','=',$get['pid']]; diff --git a/application/admin/logic/StaffLogic.php b/application/admin/logic/StaffLogic.php index 0aa8b68d..e14a37a3 100644 --- a/application/admin/logic/StaffLogic.php +++ b/application/admin/logic/StaffLogic.php @@ -624,6 +624,47 @@ class StaffLogic{ public static function adder($post){ return Db::name('staff')->where('id',$post['id'])->update(['lng'=>$post['store_longitude'],'lat'=>$post['store_latitude']]); } + + // 员工工资导出数据(基于 wages 列表结果,避免重复重算导致超时) + public static function wagesExport($get) + { + // 导出时最多导出 5000 条,且沿用 wages 的统计逻辑 + $get['page'] = 1; + $get['limit'] = isset($get['limit']) && (int)$get['limit'] > 0 ? (int)$get['limit'] : 5000; + + $data = self::wages($get); + $lists = $data['lists'] ?? []; + + // 组装导出数据 + $exportTitle = ['员工姓名', '员工电话', '服务总订单', '上午订单', '下午订单', '财务报销', '上午加时', '下午加时', '请假天数', '出勤天数', '罚款金额', '异常订单', '年卡订单', '物料金额']; + $exportData = []; + foreach ($lists as $row) { + $exportData[] = [ + $row['name'] ?? '', + $row['mobile'] ?? '', + $row['total_orders'] ?? 0, + $row['sw_orders'] ?? 0, + $row['xw_orders'] ?? 0, + $row['finance'] ?? 0, + $row['sw_addtimes'] ?? 0, + $row['xw_addtimes'] ?? 0, + $row['leaves'] ?? 0, + $row['attendance'] ?? 0, + $row['fine'] ?? 0, + $row['abnormal'] ?? 0, + $row['annual'] ?? 0, + $row['erp_staff'] ?? 0, + ]; + } + + $exportExt = 'xls'; + return [ + 'exportTitle' => $exportTitle, + 'exportData' => $exportData, + 'exportExt' => $exportExt, + 'exportName' => '员工工资-' . date('Y-m-d H:i:s'), + ]; + } //获取员工积分记录 public static function points($get){ diff --git a/application/admin/view/bulletin_board/index.html b/application/admin/view/bulletin_board/index.html index 3daf8b21..33ae0518 100644 --- a/application/admin/view/bulletin_board/index.html +++ b/application/admin/view/bulletin_board/index.html @@ -200,57 +200,24 @@
当月目标完成率
-
本月销售目标: 10万
+
+ 本月销售目标: + -- +
总体完成率 - 84% + --
-
+
客服目标完成率(N个客服的目标陈列)
- -
-
- 啦啦 - 销售额: XXX | 百分比: xx% | 同比: xx% -
-
-
-
-
-
-
- 小喵 - 销售额: XXX | 百分比: xx% | 同比: xx% -
-
-
-
-
-
-
- 哆哆 - 销售额: XXX | 百分比: xx% | 同比: xx% -
-
-
-
-
-
-
- 大猫 - 销售额: XXX | 百分比: xx% | 同比: xx% -
-
-
-
-
+
@@ -263,8 +230,8 @@
每日销售趋势
-
- ▼ 29.23% 上月同比 +
+ --
@@ -296,52 +263,8 @@ 渠道 - - - 总额 - - - - - - - - - - - - - - - 年卡 - - - - - - - - - - - - - - - 次卡 - - - - - - - - - - - - - - - 单次服务 - - - - - - - - - - - - - - - 其他服务 - - - - - - - - - - - - - + +
@@ -365,52 +288,8 @@ 龙里 - - - 总额 - - - - - - - - - - - - - - - 年卡 - - - - - - - - - - - - - - - 次卡 - - - - - - - - - - - - - - - 单次服务 - - - - - - - - - - - - - - - 其他服务 - - - - - - - - - - - - - + +
@@ -441,6 +320,10 @@ layui.config({ newCustomers: parseInt('{$newCustomers|default=0}') || 0 }; + // 仪表盘其它统计数据(目标、客服进度、渠道、趋势、区域等) + // 这里直接输出后端已经 json_encode 好的字符串,避免模板语法冲突 + var dashboardData = {$dashboardData|raw} || {}; + // 渲染统计数据 renderStatistics(); @@ -451,8 +334,13 @@ layui.config({ format: 'yyyy-MM-dd' }); - // 初始化所有图表(仅样式,不填充数据) + // 初始化所有图表(使用数据库数据渲染) initCharts(); + + // 渲染目标完成率和客服进度条 + renderTargetsAndStaff(); + // 渲染渠道与区域明细表格 + renderChannelAndRegionTables(); // 渲染统计数据 function renderStatistics() { @@ -486,6 +374,99 @@ layui.config({ $('#customers-compare').html(formatCompare(statisticsData.customersCompare)); } + // 渲染销售目标、总体完成率和客服进度条 + function renderTargetsAndStaff() { + if (!dashboardData) { + return; + } + + // 销售目标与总体完成率 + var target = dashboardData.monthlyTarget || 0; + var completion = dashboardData.overallCompletion || 0; + + $('#monthly-target-text').text(target > 0 ? (target / 10000).toFixed(2) + ' 万' : '--'); + $('#overall-completion-text').text(completion.toFixed ? completion.toFixed(2) + '%' : (completion + '%')); + $('#overall-completion-bar').css('width', (completion > 100 ? 100 : completion) + '%'); + + // 客服进度条 + var list = $('#staff-progress-list'); + list.empty(); + if (dashboardData.staffProgress && dashboardData.staffProgress.length) { + dashboardData.staffProgress.forEach(function (item) { + var percentText = (item.percent || 0).toFixed(2) + '%'; + var yoy = item.yoy || 0; + var yoyHtml; + if (yoy > 0) { + yoyHtml = '同比: ↑ ' + yoy.toFixed(2) + '%'; + } else if (yoy < 0) { + yoyHtml = '同比: ↓ ' + Math.abs(yoy).toFixed(2) + '%'; + } else { + yoyHtml = '同比: 持平'; + } + var html = '' + + '
' + + '
' + + ' ' + (item.name || '未分配') + '' + + ' 销售额: ' + (item.sales || 0) + ' | 百分比: ' + percentText + ' | ' + yoyHtml + '' + + '
' + + '
' + + '
' + + '
' + + '
'; + list.append(html); + }); + } else { + list.append('
暂无客服统计数据
'); + } + } + + // 渠道&区域月销售明细表格渲染(只处理“总额”这一行) + function renderChannelAndRegionTables() { + if (!dashboardData) { + return; + } + + // ===== 渠道月销售详情(总额 / 年卡 / 次卡 / 单次 / 其它) ===== + var channelBody = $('#channel-month-table-body'); + channelBody.empty(); + var channelHeaders = ['美团','公众号','抖音','员工','异业','渠道']; + var rowLabels = [ + {key: 'total', text: '总额'}, + {key: 'year', text: '年卡'}, + {key: 'times', text: '次卡'}, + {key: 'single',text: '单次服务'}, + {key: 'other', text: '其他服务'} + ]; + var keyToCol = ['meituan','gzh','douyin','staff','yeye','other']; + rowLabels.forEach(function (row) { + var data = (dashboardData.channelDetail && dashboardData.channelDetail[row.key]) || {}; + var tr = '' + row.text + ''; + keyToCol.forEach(function (colKey) { + var v = parseFloat(data[colKey] || 0).toFixed(2); + tr += '' + v + ''; + }); + tr += ''; + channelBody.append(tr); + }); + + // ===== 区域月销售详情(总额 / 年卡 / 次卡 / 单次 / 其它) ===== + var regionBody = $('#region-month-table-body'); + regionBody.empty(); + if (dashboardData.regions && dashboardData.regions.length) { + var regionNames = dashboardData.regions; + rowLabels.forEach(function (row) { + var rowData = (dashboardData.regionDetail && dashboardData.regionDetail[row.key]) || {}; + var tr2 = '' + row.text + ''; + regionNames.forEach(function (rName) { + var val = parseFloat(rowData[rName] || 0).toFixed(2); + tr2 += '' + val + ''; + }); + tr2 += ''; + regionBody.append(tr2); + }); + } + } + function initCharts() { // 月客户分析 - 饼图 var customerChart = echarts.init(document.getElementById('customer-analysis-chart')); @@ -519,7 +500,7 @@ layui.config({ }] }); - // 月销售情况 - 饼图 + // 月销售情况 - 饼图(使用数据库汇总结果) var salesChart = echarts.init(document.getElementById('sales-situation-chart')); salesChart.setOption({ tooltip: { @@ -544,16 +525,18 @@ layui.config({ show: true, formatter: '{b}: {c}' }, - data: [ - {value: 8.2, name: '年卡销售', itemStyle: {color: '#4A70F4'}}, - {value: 3.2, name: '次卡销售', itemStyle: {color: '#6DD047'}}, - {value: 1.4, name: '单次服务', itemStyle: {color: '#F6A23F'}}, - {value: 1.2, name: '其他服务', itemStyle: {color: '#87CEEB'}} - ] + data: (dashboardData.salesSituation && dashboardData.salesSituation.length) + ? dashboardData.salesSituation + : [ + {value: 0, name: '单次服务', itemStyle: {color: '#F6A23F'}}, + {value: 0, name: '年卡销量', itemStyle: {color: '#4A70F4'}}, + {value: 0, name: '次卡销量', itemStyle: {color: '#6DD047'}}, + {value: 0, name: '其它服务', itemStyle: {color: '#87CEEB'}} + ] }] }); - // 当月客户渠道分析 - 环形图 + // 当月客户渠道分析 - 环形图(使用数据库统计的渠道订单数) var channelChart = echarts.init(document.getElementById('channel-analysis-chart')); channelChart.setOption({ tooltip: { @@ -578,19 +561,13 @@ layui.config({ show: true, formatter: '{b}: {d}%' }, - data: [ - {value: 0, name: '美团'}, - {value: 24, name: '公众号-企业客户'}, - {value: 0, name: '抖音'}, - {value: 0, name: '渠道'}, - {value: 0, name: '员工'}, - {value: 0, name: '异业'}, - {value: 0, name: '普通客户'} - ] + data: (dashboardData.channelPie && dashboardData.channelPie.length) + ? dashboardData.channelPie + : [] }] }); - // 每日销售趋势 - 折线图 + // 每日销售趋势 - 折线图(使用数据库按天汇总的数据) var trendChart = echarts.init(document.getElementById('daily-sales-trend-chart')); trendChart.setOption({ tooltip: { @@ -605,7 +582,7 @@ layui.config({ xAxis: { type: 'category', boundaryGap: false, - data: [] + data: dashboardData.trendDates || [] }, yAxis: { type: 'value', @@ -635,11 +612,21 @@ layui.config({ itemStyle: { color: '#4A70F4' }, - data: [] + data: dashboardData.trendValues || [] }] }); + // 渲染“上月同比”文字 + var trendCompare = dashboardData.trendCompare || 0; + var trendTextDom = $('#trend-compare-text'); + if (trendCompare > 0) { + trendTextDom.css('color', '#52c41a').html('▲ ' + trendCompare.toFixed(2) + '% 上月同比'); + } else if (trendCompare < 0) { + trendTextDom.css('color', '#f56c6c').html('▼ ' + Math.abs(trendCompare).toFixed(2) + '% 上月同比'); + } else { + trendTextDom.css('color', '#999').html('持平 上月同比'); + } - // 区域月销售额 - 柱状图 + // 区域月销售额 - 柱状图(根据地址简单按区域统计) var regionalChart = echarts.init(document.getElementById('regional-sales-chart')); regionalChart.setOption({ tooltip: { @@ -656,7 +643,7 @@ layui.config({ }, xAxis: { type: 'category', - data: ['区域1', '区域2', '区域3', '区域4', '区域5', '区域6', '区域7', '区域8'] + data: dashboardData.regions || [] }, yAxis: { type: 'value', @@ -668,7 +655,7 @@ layui.config({ itemStyle: { color: '#4A70F4' }, - data: [4668, 3775, 2912, 2200, 1259, 700, 403, 0] + data: dashboardData.regionTotals || [] }] }); diff --git a/application/admin/view/order/eidt.html b/application/admin/view/order/eidt.html index 46419210..f6fc9512 100644 --- a/application/admin/view/order/eidt.html +++ b/application/admin/view/order/eidt.html @@ -298,43 +298,86 @@ setSelectFirst(); function setSelectFirst(default_id) { + console.log('setSelectFirst 被调用,default_id:', default_id); var category_select_html = ''; + var foundMatch = false; for (var i in categorys) { if (categorys[i]['level'] == 1) { - category_select_html += ''; + var selected = ''; + if (default_id && String(categorys[i]['id']) == String(default_id)) { + selected = ' selected'; + foundMatch = true; + console.log('找到匹配的省份:', categorys[i]['name'], 'ID:', categorys[i]['id']); + } + category_select_html += ''; } } $('select[name="first_category_id"]').html(category_select_html); - $('select[name="first_category_id"]').val(default_id); + if (default_id) { + $('select[name="first_category_id"]').val(String(default_id)); + console.log('设置省份值:', String(default_id), '是否找到匹配:', foundMatch); + } form.render('select'); } function setSelectSecond(default_id, parent_id) { + console.log('setSelectSecond 被调用,default_id:', default_id, 'parent_id:', parent_id); parent_id = parent_id === undefined ? $('select[name="first_category_id"]').val() : parent_id; + if (!parent_id) { + console.log('setSelectSecond: parent_id 为空,返回'); + return; + } + parent_id = String(parent_id); $('select[name="second_category_id"]').html(''); $('select[name="third_category_id"]').html(''); var category_select_html = ''; + var foundMatch = false; for (var i in categorys) { - if (categorys[i]['parent_id'] == parent_id) { - category_select_html += ''; + if (String(categorys[i]['parent_id']) == parent_id) { + var selected = ''; + if (default_id && String(categorys[i]['id']) == String(default_id)) { + selected = ' selected'; + foundMatch = true; + console.log('找到匹配的城市:', categorys[i]['name'], 'ID:', categorys[i]['id']); + } + category_select_html += ''; } } $('select[name="second_category_id"]').html(category_select_html); - $('select[name="second_category_id"]').val(default_id); + if (default_id) { + $('select[name="second_category_id"]').val(String(default_id)); + console.log('设置城市值:', String(default_id), '是否找到匹配:', foundMatch); + } form.render('select'); } function setSelectThird(default_id, parent_id) { + console.log('setSelectThird 被调用,default_id:', default_id, 'parent_id:', parent_id); parent_id = parent_id === undefined ? $('select[name="second_category_id"]').val() : parent_id; + if (!parent_id) { + console.log('setSelectThird: parent_id 为空,返回'); + return; + } + parent_id = String(parent_id); $('select[name="third_category_id"]').html(''); - var first_category_id = $('select[name="first_category_id"]').val(); var category_select_html = ''; + var foundMatch = false; + for (var i in categorys) { - if (categorys[i]['parent_id'] == parent_id) { - category_select_html += ''; + if (String(categorys[i]['parent_id']) == parent_id) { + var selected = ''; + if (default_id && String(categorys[i]['id']) == String(default_id)) { + selected = ' selected'; + foundMatch = true; + console.log('找到匹配的区县:', categorys[i]['name'], 'ID:', categorys[i]['id']); + } + category_select_html += ''; } } $('select[name="third_category_id"]').html(category_select_html); - $('select[name="third_category_id"]').val(default_id); + if (default_id) { + $('select[name="third_category_id"]').val(String(default_id)); + console.log('设置区县值:', String(default_id), '是否找到匹配:', foundMatch); + } form.render('select'); } @@ -465,7 +508,7 @@ } {notempty name='info'} var goods_info= {$info|raw|default=''}; - console.log(goods_info); + console.log('订单数据:', goods_info); $('input[name="id"]').val(goods_info['id']); $('input[name="address"]').val(goods_info['address']); $('input[name="total_amount"]').val(goods_info['total_amount']); @@ -474,9 +517,89 @@ $('input[name="phone"]').val(goods_info['mobile']); $('input[name="store_latitude"]').val(goods_info['lng']); $('input[name="store_longitude"]').val(goods_info['lat']); - setSelectFirst(goods_info['province']); - setSelectSecond(goods_info['city']); - setSelectThird(goods_info['district']); + + // 设置地区选择器,根据返回的 province、city、district 字段 + // 注意:需要检查值是否存在,包括0的情况(0是有效的ID值) + var province_id = ''; + var city_id = ''; + var district_id = ''; + + // 检查province字段(包括0值) + if (goods_info['province'] !== undefined && goods_info['province'] !== null && goods_info['province'] !== '') { + province_id = goods_info['province']; + } + // 检查city字段(包括0值) + if (goods_info['city'] !== undefined && goods_info['city'] !== null && goods_info['city'] !== '') { + city_id = goods_info['city']; + } + // 检查district字段(包括0值) + if (goods_info['district'] !== undefined && goods_info['district'] !== null && goods_info['district'] !== '') { + district_id = goods_info['district']; + } + + console.log('地区数据:', { + province: goods_info['province'], + city: goods_info['city'], + district: goods_info['district'], + province_id: province_id, + city_id: city_id, + district_id: district_id + }); + + // 初始化地区选择器的函数 + function initRegionSelectors() { + if (province_id !== '') { + // 转换为字符串,确保类型匹配 + province_id = String(province_id); + + // 先设置省份 + setSelectFirst(province_id); + + // 等待省份选择器渲染完成后再设置城市 + setTimeout(function() { + // 验证省份值是否设置成功 + var selectedProvince = $('select[name="first_category_id"]').val(); + console.log('已选省份ID:', selectedProvince, '期望:', province_id); + + if (city_id !== '' && selectedProvince == province_id) { + city_id = String(city_id); + setSelectSecond(city_id, province_id); + + // 等待城市选择器渲染完成后再设置区县 + setTimeout(function() { + // 验证城市值是否设置成功 + var selectedCity = $('select[name="second_category_id"]').val(); + console.log('已选城市ID:', selectedCity, '期望:', city_id); + + if (district_id !== '' && selectedCity == city_id) { + district_id = String(district_id); + setSelectThird(district_id, city_id); + + setTimeout(function() { + var selectedDistrict = $('select[name="third_category_id"]').val(); + console.log('已选区县ID:', selectedDistrict, '期望:', district_id); + // 最后重新渲染一次,确保所有选择器都正确显示 + form.render('select'); + }, 100); + } else { + form.render('select'); + } + }, 300); + } else { + form.render('select'); + } + }, 300); + } else { + form.render('select'); + } + } + + // 延迟执行,确保页面完全加载和选择器初始化完成 + setTimeout(function() { + console.log('开始初始化地区选择器...'); + initRegionSelectors(); + }, 200); + setBrand(goods_info['channel_id']); //部门的修改 setBrandss(goods_info['gord_id']); //部门的修改 diff --git a/application/admin/view/order/lists.html b/application/admin/view/order/lists.html index 30210722..2c3b47f4 100644 --- a/application/admin/view/order/lists.html +++ b/application/admin/view/order/lists.html @@ -73,12 +73,19 @@ height: 62px; margin-bottom: 5px; } - /* 退款状态标红样式 */ - .refund-status-row { - background-color: #ffebee !important; + /* 退款中状态绿色背景 */ + .refunding-row { + background-color: #c8e6c9 !important; } - .refund-status-row:hover { - background-color: #ffcdd2 !important; + .refunding-row:hover { + background-color: #a5d6a7 !important; + } + /* 同意退款后淡绿色背景 */ + .order-status-4-row { + background-color: #e8f5e9 !important; + } + .order-status-4-row:hover { + background-color: #c8e6c9 !important; } @@ -206,6 +213,7 @@
  • 已支付
  • 已退款
  • 拒退款
  • +
  • 已删除
  • @@ -338,7 +346,11 @@ 渠道 备注 分配 + {{# if(d.del == 0){ }} 删除 + {{# } else { }} + 恢复 + {{# } }} {{# if(d.order_status == 1){ }} 发货 {{# } }} @@ -637,19 +649,36 @@ $($(".layui-table-fixed-r .layui-table-body tbody tr")[index]).height($(val).height()); }); - // 如果 refund_status > 0,整行标红显示 + // 如果 order_status == 4(同意退款),整行淡绿色显示 + // 如果 refund_status > 0 但 order_status != 4(退款中),整行绿色显示 if (res && res.data && res.data.length > 0) { res.data.forEach(function(item, index) { - if (item.refund_status && parseInt(item.refund_status) > 0) { - // 给主表格行添加红色背景 + var orderStatus = item.order_status ? parseInt(item.order_status) : 0; + var refundStatus = item.refund_status ? parseInt(item.refund_status) : 0; + + // 同意退款后,order_status == 4,显示淡绿色 + if (orderStatus == 4) { + // 给主表格行添加淡绿色背景 var $mainRow = $(".layui-table-main tbody tr").eq(index); - $mainRow.addClass('refund-status-row'); + $mainRow.addClass('order-status-4-row'); - // 给固定列的行也添加红色背景 + // 给固定列的行也添加淡绿色背景 var $fixedLeftRow = $(".layui-table-fixed-l .layui-table-body tbody tr").eq(index); var $fixedRightRow = $(".layui-table-fixed-r .layui-table-body tbody tr").eq(index); - $fixedLeftRow.addClass('refund-status-row'); - $fixedRightRow.addClass('refund-status-row'); + $fixedLeftRow.addClass('order-status-4-row'); + $fixedRightRow.addClass('order-status-4-row'); + } + // 退款中,refund_status > 0 但 order_status != 4,显示绿色 + else if (refundStatus > 0) { + // 给主表格行添加绿色背景 + var $mainRow = $(".layui-table-main tbody tr").eq(index); + $mainRow.addClass('refunding-row'); + + // 给固定列的行也添加绿色背景 + var $fixedLeftRow = $(".layui-table-fixed-l .layui-table-body tbody tr").eq(index); + var $fixedRightRow = $(".layui-table-fixed-r .layui-table-body tbody tr").eq(index); + $fixedLeftRow.addClass('refunding-row'); + $fixedRightRow.addClass('refunding-row'); } }); } @@ -835,7 +864,7 @@ }); } - //取消订单 + // 退款订单 if(obj.event === 'cancelss'){ layer.confirm('确认订单退款吗?', { btn: ['确认','取消'] //按钮 @@ -860,7 +889,7 @@ } - //取消订单 + // 删除订单(逻辑删除,del 设置为 1) if(obj.event === 'cancel'){ layer.confirm('确定删除订单的数据?', { btn: ['确认','取消'] //按钮 @@ -882,6 +911,35 @@ }); } + // 恢复订单(del 设置为 0) + if(obj.event === 'recover'){ + layer.confirm('确定恢复该订单吗?', { + btn: ['确认','取消'] //按钮 + }, function(){ + like.ajax({ + url: '{:url("order/recover")}?id='+id + , type: 'get' + , success: function (res) { + if (res.code == 1) { + layui.layer.msg(res.msg, { + offset: '15px' + , icon: 1 + , time: 1000 + },function () { + table.reload('order-lists'); + }); + } else { + layui.layer.msg(res.msg || '恢复失败', { + offset: '15px' + , icon: 2 + , time: 1500 + }); + } + }, + }); + }); + } + //商家备注 if(obj.event === 'remarks') { like.ajax({ diff --git a/application/admin/view/staff/wages.html b/application/admin/view/staff/wages.html index 2906e2fa..b15be13f 100644 --- a/application/admin/view/staff/wages.html +++ b/application/admin/view/staff/wages.html @@ -90,7 +90,9 @@ - +
    @@ -161,7 +163,7 @@ form.on('submit(export-file)', function(data){ var field = data.field; $.ajax({ - url: '{:url("order/exportFile")}?type=' + listType, + url: '{:url("staff/exportWages")}', type: 'get', data: field, dataType: 'json', @@ -171,7 +173,7 @@ success: function(res) { table.exportFile(res.data.exportTitle,res.data.exportData, res.data.exportExt, res.data.exportName); }, - timeout: 15000 + timeout: 60000 }); layer.msg('导出中请耐心等待~'); }); diff --git a/application/api/controller/Order.php b/application/api/controller/Order.php index f2b533b6..b71f0a0e 100644 --- a/application/api/controller/Order.php +++ b/application/api/controller/Order.php @@ -91,8 +91,11 @@ class Order extends ApiBase $order = OrderLogic::add($this->user_id, $info['data'], $post); + if ($order['code'] == 0) { + $this->_error($order['msg']); + } - return $order; + $this->_success('', $order['data']); } @@ -572,6 +575,7 @@ class Order extends ApiBase public function putday() { + $this->_error('该时间内无法自主预约,请联系客服'); $post = $this->request->post(); $hourLists = $post['data']['hourLists'] ?? []; $orderid = $post['data']['id'] ?? 0; diff --git a/application/api/controller/Points.php b/application/api/controller/Points.php index 5b5e34cc..5a4fb012 100644 --- a/application/api/controller/Points.php +++ b/application/api/controller/Points.php @@ -22,7 +22,8 @@ class Points extends ApiBase * @return mixed */ public function goodslist(){ - $lists = PointsLogic::goodslist(); + $clsssId = $this->request->get('classify_id'); + $lists = PointsLogic::goodslist($clsssId); $this->_success('获取数据成功',$lists); } /** @@ -38,16 +39,42 @@ class Points extends ApiBase } public function goodsSub(){ - $data = $this->request->get(); - $data['user_id']= $this->user_id; - $user_jf=UserLogic::getUserInfo($this->user_id); - if($user_jf['user_integral']<$data['price']){ + $data = $this->request->post(); + + // 参数校验 + if(empty($data) || !is_array($data)){ + $this->_error('参数错误'); + } + if(empty($data['id']) || empty($data['name']) || !isset($data['price'])){ + $this->_error('参数不完整'); + } + + $data['user_id'] = $this->user_id; + $user_jf = UserLogic::getUserInfo($this->user_id); + + if($user_jf['user_integral'] < $data['price']){ $this->_error('积分不足'); }else{ - $data = PointsLogic::goodsSub($data); - $this->_success('兑换成功',$data); + $result = PointsLogic::goodsSub($data); + if($result['code'] == 1){ + $this->_success('兑换成功'); + }else{ + $this->_error($result['msg']); + } } - - + } + + //积分订单列表 + public function orderList() + { + $data = $this->request->post(); + // 参数校验 + if(empty($data) || !is_array($data)){ + $this->_error('参数错误'); + } + $userId = $this->user_id; + $state = isset($data['state']) ? $data['state'] : null; + $result = PointsLogic::orderList($userId, $state); + $this->_success('获取数据成功',$result); } } \ No newline at end of file diff --git a/application/api/controller/Share.php b/application/api/controller/Share.php index 30b1271e..be7808ef 100644 --- a/application/api/controller/Share.php +++ b/application/api/controller/Share.php @@ -26,7 +26,7 @@ class Share extends ApiBase public function shareGoods() { $id = $this->request->get('id'); - $url = $this->request->get('url'); + $url = $this->request->get('page'); $client = $this->client; if ($id && $url) { $result = ShareLogic::shareGoods($this->user_id, $id, $url, $client); diff --git a/application/api/logic/GoodsLogic.php b/application/api/logic/GoodsLogic.php index 37f3cb7b..c17bfc2b 100644 --- a/application/api/logic/GoodsLogic.php +++ b/application/api/logic/GoodsLogic.php @@ -38,7 +38,7 @@ class GoodsLogic{ $goods = new Goods(); //品牌筛选 if(isset($get['brand_id']) && $get['brand_id']) { - $where[] = ['brand_id', '=', $get['brand_id']]; + $where[] = ['third_category_id', '=', $get['brand_id']]; } //分类筛选 if(isset($get['category_id']) && $get['category_id']){ diff --git a/application/api/logic/OrderLogic.php b/application/api/logic/OrderLogic.php index 1390fae4..1e052998 100644 --- a/application/api/logic/OrderLogic.php +++ b/application/api/logic/OrderLogic.php @@ -491,8 +491,8 @@ class OrderLogic extends LogicBase // 拆分后每个订单的金额需要重新计算,这里先验证原始总金额 // 实际拆分时每个订单会独立计算 } else { - if($user_money < $data['order_amount']){ - throw new Exception('账户余额不足'); + if($user_money < $data['order_amount']){ + throw new Exception('账户余额不足'); } } } @@ -556,10 +556,13 @@ class OrderLogic extends LogicBase // 创建单个订单 $single_goods_lists = $single_order_data['goods_lists']; + if (empty($single_goods_lists)) { + throw new Exception('商品信息获取失败'); + } $single_goods_id = $single_goods_lists[0]['goods_id']; - + $order = self::addOrder($user_id, $single_order_data, $order_source, $user_address, $single_goods_id); - $order_id = $order['order_id']; + $order_id = $order['order_id']; $order_ids[] = $order_id; self::addOrderGoods($order_id, $single_goods_lists); @@ -590,6 +593,9 @@ class OrderLogic extends LogicBase } $single_goods_lists = $single_order_data['goods_lists']; + if (empty($single_goods_lists)) { + throw new Exception('商品信息获取失败'); + } $single_goods_id = $single_goods_lists[0]['goods_id']; $order = self::addOrder($user_id, $single_order_data, $order_source, $user_address, $single_goods_id); @@ -607,30 +613,36 @@ class OrderLogic extends LogicBase } } else { // 普通商品:保持原有逻辑 + if (empty($goods_lists)) { + throw new Exception('商品信息获取失败'); + } $goods_id = $goods_lists[0]['goods_id']; $order = self::addOrder($user_id, $data, $order_source, $user_address, $goods_id); $order_id = $order['order_id']; $order_ids[] = $order_id; + + self::addOrderGoods($order_id, $goods_lists); + self::addOrderAfter($order_id, $user_id, $type, $data); + + //支付方式为余额支付,扣除余额,更新订单状态,支付状态 + if ($data['pay_way'] == Pay::BALANCE_PAY || $data['order_amount'] == 0) { + PayNotifyLogic::handle('order', $order['order_sn'], []); + } - self::addOrderGoods($order_id, $goods_lists); - self::addOrderAfter($order_id, $user_id, $type, $data); - - //支付方式为余额支付,扣除余额,更新订单状态,支付状态 - if ($data['pay_way'] == Pay::BALANCE_PAY || $data['order_amount'] == 0) { - PayNotifyLogic::handle('order', $order['order_sn'], []); - } - - // 砍价订单处理 - if (isset($post['bargain_launch_id']) and $post['bargain_launch_id'] > 0) { - $bargainLaunchModel = new BargainLaunch(); - $bargainLaunchModel->where(['id'=>(int)$post['bargain_launch_id']]) - ->update(['order_id'=>$order_id, 'status'=>1]); + // 砍价订单处理 + if (isset($post['bargain_launch_id']) and $post['bargain_launch_id'] > 0) { + $bargainLaunchModel = new BargainLaunch(); + $bargainLaunchModel->where(['id'=>(int)$post['bargain_launch_id']]) + ->update(['order_id'=>$order_id, 'status'=>1]); } } Db::commit(); - return self::dataSuccess('', ['order_id' => $order_ids[0] ?? 0, 'order_ids' => $order_ids, 'type' => 'order']); + if (empty($order_ids)) { + throw new Exception('订单创建失败'); + } + return self::dataSuccess('', ['order_id' => $order_ids[0], 'order_ids' => $order_ids, 'type' => 'order']); } catch (Exception $e) { Db::rollback(); diff --git a/application/api/logic/PointsLogic.php b/application/api/logic/PointsLogic.php index 2e3c742e..02a8e328 100644 --- a/application/api/logic/PointsLogic.php +++ b/application/api/logic/PointsLogic.php @@ -1,5 +1,6 @@ select(); + return Db::name('printer_type')->where('del',0)->select(); } //获取到积分的商品列表 - public static function goodslist(){ - $where=[]; + public static function goodslist($clsssId){ + $where=[ + 'brand_id'=>$clsssId, + 'del'=>0 + ]; $goods = Db::name('printer_goods') ->where($where) ->select(); @@ -34,21 +38,83 @@ class PointsLogic return $data; } + /** + * 积分商品下单(扣减积分并生成订单) + * @param array $data ['id','name','price','user_id','number'(可选)] + * @return array + */ public static function goodsSub($data){ - - $data=[ - 'name' =>$data['name'], - 'goods_id' =>$data['id'], - 'price' =>$data['price'], - 'number' =>1, - 'user_id' =>$data['user_id'], - 'create_time'=>time() - ]; - $insert=Db::name('printer_order')->data($data)->insert(); - if($insert){ - $user=UserLogic::getUserInfo($data['user_id']); - db::name('user')->where('id',$data['user_id'])->update(['user_integral'=>$user['user_integral']-$data['price']]); - // Db::name('printer_goods')->where('') - } + if(empty($data) || !is_array($data)){ + return ['code'=>0,'msg'=>'参数错误']; + } + // 基础校验 + if(empty($data['id']) || empty($data['user_id']) || !isset($data['price'])){ + return ['code'=>0,'msg'=>'参数不完整']; + } + $number = isset($data['number']) && intval($data['number'])>0 ? intval($data['number']) : 1; + $price = floatval($data['price']); + $needIntegral = $price * $number; + + Db::startTrans(); + try{ + // 加锁读取用户积分 + $user = Db::name('user')->where('id',$data['user_id'])->lock(true)->find(); + if(!$user){ + throw new Exception('用户不存在'); + } + if($user['user_integral'] < $needIntegral){ + throw new Exception('积分不足'); + } + + $orderData = [ + 'name' => $data['name'] ?? '', + 'goods_id' => $data['id'], + 'price' => $price, + 'number' => $number, + 'user_id' => $data['user_id'], + 'create_time' => time(), + 'address_id' => $data['addressId'], + 'state' => 1 + ]; + + $insert = Db::name('printer_order')->insert($orderData); + if(!$insert){ + throw new Exception('下单失败'); + } + + // 扣减积分 + Db::name('user') + ->where('id',$data['user_id']) + ->setDec('user_integral', $needIntegral); + + Db::commit(); + return ['code'=>1,'msg'=>'兑换成功']; + }catch (\Exception $e){ + Db::rollback(); + return ['code'=>0,'msg'=>$e->getMessage()]; + } + } + + + //获取积分订单 + public static function orderList($userId, $state = null) + { + $order = new OrderPoints(); + $query = $order->with([ + 'address' => function($query){ + $query->where('del',0)->field('id,address'); + }, + 'pointsGoods' => function($query){ + $query->where('del',0)->field('id,images'); + } + ])->where('user_id', $userId); + + // 如果传了state参数,才添加state条件,否则查询全部 + if($state !== null && $state !== ''){ + $query = $query->where('state', $state); + } + + $orderArray = $query->paginate(10); + return $orderArray; } } \ No newline at end of file diff --git a/application/api/model/Goods.php b/application/api/model/Goods.php index ba96d458..3f4143a5 100644 --- a/application/api/model/Goods.php +++ b/application/api/model/Goods.php @@ -77,9 +77,22 @@ class Goods extends Model{ $this->setAttr('price',$goods_item[0]['price']); $this->setAttr('market_price',$goods_item[0]['market_price']); + //创建规格值ID到商品项ID的映射 + $spec_value_to_item = []; + foreach ($goods_item as $item) { + $spec_value_ids = $item['spec_value_ids']; + // spec_value_ids 存储的是规格值ID,可能是一个或多个(逗号分隔) + $spec_value_id_array = explode(',', $spec_value_ids); + foreach ($spec_value_id_array as $spec_value_id) { + $spec_value_to_item[$spec_value_id] = $item['id']; + } + } + //拼接规格 foreach ($spec_value as $item){ if(isset($spec[$item['spec_id']])){ + //添加对应的商品项ID + $item['item_id'] = $spec_value_to_item[$item['id']] ?? 0; $spec[$item['spec_id']]['spec_value'][]= $item; } } diff --git a/application/api/model/GoodsPoints.php b/application/api/model/GoodsPoints.php new file mode 100644 index 00000000..59b3a8fa --- /dev/null +++ b/application/api/model/GoodsPoints.php @@ -0,0 +1,10 @@ +hasOne(UserAddress::class, 'id', 'address_id'); + } + + //关联积分商品 + public function pointsGoods(): HasOne + { + return $this->hasOne(GoodsPoints::class, 'id', 'goods_id'); + } +} \ No newline at end of file diff --git a/application/api/model/UserAddress.php b/application/api/model/UserAddress.php new file mode 100644 index 00000000..5b452e34 --- /dev/null +++ b/application/api/model/UserAddress.php @@ -0,0 +1,10 @@ +where(['id' => $refund_id])->find(); - + if ($order['transaction_id'] == ''){ + throw new Exception('微信订单不存在'); + } $data = [ 'transaction_id' => $order['transaction_id'], 'refund_sn' => $refund_log['refund_sn'], diff --git a/application/common/logic/PayNotifyLogic.php b/application/common/logic/PayNotifyLogic.php index 980e1d95..cbc8dd39 100644 --- a/application/common/logic/PayNotifyLogic.php +++ b/application/common/logic/PayNotifyLogic.php @@ -115,27 +115,27 @@ class PayNotifyLogic //发送通知 - Hook::listen('notice', [ - 'user_id' => $user['id'], - 'order_id' => $order['id'], - 'scene' => NoticeSetting::ORDER_PAY_NOTICE, - ]); +// Hook::listen('notice', [ +// 'user_id' => $user['id'], +// 'order_id' => $order['id'], +// 'scene' => NoticeSetting::ORDER_PAY_NOTICE, +// ]); //短信通知 - Hook::listen('sms_send', [ - 'key' => NoticeSetting::ORDER_PAY_NOTICE, - 'mobile' => $order->mobile, - 'user_id' => $user->id, - 'params' => [ - 'nickname' => $user->nickname, - 'order_sn' => $order->order_sn, - 'order_amount' => $order->order_amount, - 'time' => $order->create_time, - 'total_num' => $order->total_num.'件', - 'goods_name' => omit_str(($order->order_goods[0]['goods_name'] ?? '商品'), 8) - ] - ]); +// Hook::listen('sms_send', [ +// 'key' => NoticeSetting::ORDER_PAY_NOTICE, +// 'mobile' => $order->mobile, +// 'user_id' => $user->id, +// 'params' => [ +// 'nickname' => $user->nickname, +// 'order_sn' => $order->order_sn, +// 'order_amount' => $order->order_amount, +// 'time' => $order->create_time, +// 'total_num' => $order->total_num.'件', +// 'goods_name' => omit_str(($order->order_goods[0]['goods_name'] ?? '商品'), 8) +// ] +// ]); $order_contact_mobile = ConfigServer::get('order_message', 'order_contact_mobile'); //平台短信通知 diff --git a/application/common/model/Ad.php b/application/common/model/Ad.php index dd38fa1b..bca064e2 100644 --- a/application/common/model/Ad.php +++ b/application/common/model/Ad.php @@ -40,7 +40,7 @@ class Ad extends Model{ self::mobile => [ [ 'name' => '商品分类', - 'path' => '/pages/sort/sort', + 'path' => '/pages/category/index', 'is_tab' => 1, ], [ @@ -57,7 +57,7 @@ class Ad extends Model{ self::pc => [ [ 'name' => '商品分类', - 'path' => '/category', + 'path' => '/category/index', 'is_tab' => 0, ], [ @@ -67,7 +67,7 @@ class Ad extends Model{ ], [ 'name' => '个人中心', - 'path' => '/user/profile', + 'path' => '/user/user', 'is_tab' => 0, ], ], diff --git a/application/common/server/storage/engine/Aliyun.php b/application/common/server/storage/engine/Aliyun.php index 02745b79..c49ce82e 100644 --- a/application/common/server/storage/engine/Aliyun.php +++ b/application/common/server/storage/engine/Aliyun.php @@ -24,7 +24,7 @@ class Aliyun extends Server parent::__construct(); $this->config = $config; } - + /** * 创建并配置 OssClient * @return OssClient