添加订单列表

This commit is contained in:
youda 2025-05-02 00:24:31 +08:00
parent c3c216dbb6
commit 0109490d1c
11 changed files with 642 additions and 4 deletions

View File

@ -92,9 +92,12 @@ class Base extends MyController
'addtime' => time(),
]);
}
$app_setting = getConfig('app_setting');
View::assign("app_setting", $app_setting);
$config_list = Db::name('config')->field('value,key')->select()->toArray();
View::assign("app_config_list", $config_list);
$goods_type_list = Db::name('goods_type')->select()->toArray();
View::assign("goods_type_list", $goods_type_list);
}
/**

View File

@ -0,0 +1,78 @@
<?php
namespace app\admin\controller;
use think\facade\View;
/**
* Markdown文件查看器
*/
class Markdown extends Base
{
/**
* 显示Markdown文件
*/
public function index()
{
// 获取文件路径参数
$filePath = request()->param('file_path', '');
// 验证文件路径是否有效
if (empty($filePath) || !file_exists($filePath)) {
return $this->err('文件不存在或路径无效');
}
// 检查文件扩展名
$extension = pathinfo($filePath, PATHINFO_EXTENSION);
if (strtolower($extension) !== 'md') {
return $this->err('只支持查看Markdown文件(.md)');
}
// 读取文件内容
$content = file_get_contents($filePath);
// 将内容传递给视图
View::assign('file_path', $filePath);
View::assign('content', $content);
// 返回视图
return View::fetch("Markdown/index");
}
/**
* 显示Markdown文件
*/
public function order_info()
{
// 获取goods_id 和 order_id
$goods_id = request()->param('goods_id', '');
$order_num = request()->param('order_num', '');
if (empty($goods_id) || empty($order_num)) {
return $this->err('参数错误');
}
// 拼接文件路径
$filePath = './draw_log/' . $goods_id . '/' . $order_num . '.md';
// 获取文件路径参数
//$filePath = request()->param('file_path', '');
// 验证文件路径是否有效
if (empty($filePath) || !file_exists($filePath)) {
return $this->err('日志不存在');
}
// 检查文件扩展名
$extension = pathinfo($filePath, PATHINFO_EXTENSION);
if (strtolower($extension) !== 'md') {
return $this->err('只支持查看Markdown文件(.md)');
}
// 读取文件内容
$content = file_get_contents($filePath);
// 将内容传递给视图
View::assign('file_path', $filePath);
View::assign('content', $content);
// 返回视图
return View::fetch("Markdown/index");
}
}

View File

@ -19,6 +19,7 @@ use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Font;
use PhpOffice\PhpSpreadsheet\IOFactory;
class Order extends Base
@ -994,4 +995,117 @@ class Order extends Base
}
}
/**
* 订单列表页面
*/
public function order_list()
{
return View::fetch('Order/order_list');
}
/**
* 获取订单列表数据
*/
public function get_order_list()
{
$page = input('page', 1);
$limit = input('limit', 10);
$user_id = input('user_id', '');
$mobile = input('mobile', '');
$order_num = input('order_num', '');
$status = input('status', '');
$start_time = input('start_time', '');
$end_time = input('end_time', '');
$where = [];
$where[] = ['u.status', '=', 1];
$where[] = ['u.istest', '=', 0];
if ($user_id) {
$where[] = ['o.user_id', '=', $user_id];
}
if ($mobile) {
$where[] = ['u.mobile', 'like', '%'.$mobile.'%'];
}
if ($order_num) {
$where[] = ['o.order_num', 'like', '%'.$order_num.'%'];
}
if ($status !== '') {
$where[] = ['o.status', '=', $status];
}
if ($start_time && $end_time) {
$where[] = ['o.addtime', 'between', [$start_time, $end_time]];
} else if ($start_time) {
$where[] = ['o.addtime', '>=', $start_time];
} else if ($end_time) {
$where[] = ['o.addtime', '<=', $end_time];
}
$query = Db::table('order')
->alias('o')
->join('user u', 'o.user_id = u.id')
->field('o.id, o.goods_title, o.order_num, o.user_id, u.nickname, u.mobile,
o.order_total, o.order_zhe_total, o.price, o.use_money, o.use_integral, o.use_money2,
o.goods_id, o.num, o.goods_price, o.goods_imgurl, o.prize_num, o.status, o.addtime, o.pay_time,
o.pay_type, o.order_type, o.coupon_id, o.use_coupon, o.is_shou_zhe, o.is_flw,
CASE
WHEN o.status=1 THEN (select IFNULL(sum(goodslist_money),0) from order_list ol where ol.order_id=o.id and ol.goodslist_type<3)
ELSE 0
END as sc_money,u.status u_status,u.istest,u.uid')
->where($where)
->order('o.id desc');
$count = $query->count();
$list = $query->page($page, $limit)->select()->toArray();
// 格式化数据
foreach ($list as &$item) {
$item['addtime'] = date('Y-m-d H:i:s', $item['addtime']);
$item['pay_time'] = $item['pay_time'] ? date('Y-m-d H:i:s', $item['pay_time']) : '';
// 支付状态格式化
switch ($item['status']) {
case 0:
$item['status_text'] = '未支付';
break;
case 1:
$item['status_text'] = '已支付';
break;
case 2:
$item['status_text'] = '已失效';
break;
default:
$item['status_text'] = '未知状态';
}
// 支付类型格式化
switch ($item['pay_type']) {
case 1:
$item['pay_type_text'] = '微信支付';
break;
case 2:
$item['pay_type_text'] = '支付宝';
break;
case 3:
$item['pay_type_text'] = '钻石支付';
break;
default:
$item['pay_type_text'] = '其他';
}
}
return json([
'code' => 0,
'msg' => '获取成功',
'count' => $count,
'data' => $list
]);
}
}

View File

@ -223,6 +223,8 @@ Route::rule('send_order_daochu', 'Order/send_order_daochu');
Route::rule('send_order_dandufahuo', 'Order/send_order_dandufahuo');
Route::rule('unpaid_order', 'Order/unpaid_order');
Route::rule('delete_order_item', 'Order/delete_order_item');
Route::rule('order_list', 'Order/order_list', 'GET|POST');
Route::rule('order/get_order_list', 'Order/get_order_list', 'GET|POST');
#============================
@ -451,4 +453,10 @@ Route::get('goods_offshelf_unread_count', 'GoodsOffshelfController/getUnreadCoun
# dynamicJs
#============================
Route::get('dynamicJs.js', 'Config/dynamicJs')->ext('js');
#============================
#Markdown.php Markdown查看器
#============================
Route::rule('markdown/index', 'Markdown/index', 'GET|POST');
Route::rule('markdown/order_info', 'Markdown/order_info', 'GET|POST');

View File

@ -0,0 +1,70 @@
{include file="Public/header2" /}
<div class="page-container">
<div class="markdown-container">
<div class="markdown-content" id="markdown-content">
</div>
</div>
</div>
{include file="Public/footer" /}
<!-- 引入markdown-it库 -->
<script src="/js/markdown-it.min.js"></script>
<style>
.markdown-container {
padding: 20px;
padding-top: 5px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 1px 1px rgba(0,0,0,.05);
}
.markdown-content {
margin-top: 20px;
border-top: 1px solid #eee;
padding-top: 20px;
}
.markdown-content img {
max-width: 100%;
}
.markdown-content table {
border-collapse: collapse;
width: 100%;
margin-bottom: 15px;
}
.markdown-content table, .markdown-content th, .markdown-content td {
border: 1px solid #ddd;
}
.markdown-content th, .markdown-content td {
padding: 8px;
text-align: left;
}
.markdown-content th {
background-color: #f5f5f5;
}
.markdown-content pre {
background-color: #f8f8f8;
padding: 10px;
border-radius: 3px;
overflow-x: auto;
}
.markdown-content code {
font-family: Consolas, Monaco, 'Andale Mono', monospace;
background-color: #f8f8f8;
padding: 2px 4px;
border-radius: 3px;
}
</style>
<script>
// 初始化markdown-it
var md = window.markdownit({
html: true, // 启用HTML标签
breaks: true, // 转换回车符为<br>
linkify: true, // 自动转换URL为链接
typographer: true // 启用一些语言中立的替换 + 引号美化
});
// 获取markdown内容并渲染
var content = `{$content|raw}`;
document.getElementById('markdown-content').innerHTML = md.render(content);
</script>

View File

@ -0,0 +1,269 @@
{include file="Public:header3" /}
<div class="layui-fluid">
<div class="layui-card">
<div class="layui-card-body">
<!-- 搜索条件 -->
<form class="layui-form layui-form-pane">
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">用户ID</label>
<div class="layui-input-inline">
<input type="text" name="user_id" placeholder="请输入用户ID" autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">手机号</label>
<div class="layui-input-inline">
<input type="text" name="mobile" placeholder="请输入手机号" autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">订单号</label>
<div class="layui-input-inline">
<input type="text" name="order_num" placeholder="请输入订单号" autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">支付状态</label>
<div class="layui-input-inline">
<select name="status">
<option value="">全部</option>
<option value="0">未支付</option>
<option value="1">已支付</option>
<option value="2">已失效</option>
</select>
</div>
</div>
</div>
<div class="layui-form-item">
<div class="layui-inline">
<label class="layui-form-label">购买时间</label>
<div class="layui-input-inline">
<input type="text" name="start_time" id="start_time" placeholder="开始时间" autocomplete="off"
class="layui-input">
</div>
<div class="layui-form-mid">-</div>
<div class="layui-input-inline">
<input type="text" name="end_time" id="end_time" placeholder="结束时间" autocomplete="off"
class="layui-input">
</div>
</div>
<div class="layui-inline">
<button class="layui-btn" lay-submit lay-filter="search-order">
<i class="layui-icon layui-icon-search"></i> 搜索
</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
<!-- 数据表格 -->
<table id="order-table" lay-filter="order-table"></table>
</div>
</div>
</div>
<!-- 操作栏模板 -->
<script type="text/html" id="operator-toolbar">
<div style="white-space: nowrap;">
<a class="layui-btn layui-btn-xs" lay-event="detail">详情</a>
{{# if(d.status == 1){ }}
<a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="prize_log">日志</a>
{{# } }}
</div>
</script>
<!-- 订单号模板 -->
<script type="text/html" id="order-num-tpl">
<div>
<p>{{d.order_num}}</p>
<p><b>支付商户:{{appConfigManager.getWxPayConfigByType(d.order_num)?.name}}</b></p>
<p><b>商户Id{{appConfigManager.getWxPayConfigByType(d.order_num)?.mch_id}}</b></p>
</div>
</script>
<!-- 盒子图片模板 -->
<script type="text/html" id="goods-img-tpl">
<img src="{{d.goods_imgurl}}" style="max-width: 50px; max-height: 50px;" onerror="this.src='/static/admin/images/nopic.jpg'">
</script>
<!-- 盒子详情模板(合并图片和信息) -->
<script type="text/html" id="goods-detail-tpl">
<div style="display: flex; width: 100%;">
<div style="width: 30%; margin-right: 10px; display: flex; align-items: center; justify-content: center;">
<img src="{{d.goods_imgurl}}" style="max-width: 100%; max-height: 80px;" onerror="this.src='/static/admin/images/nopic.jpg'">
</div>
<div style="width: 70%;">
<p><b>名称:</b>{{d.goods_title}}</p>
<p><b>价格:</b>{{d.goods_price}}</p>
<p><b>类型:</b>{{appConfigManager.getGoodsTypeName(d.order_type)}}</p>
<p><b>套数:</b>{{d.num}}</p>
</div>
</div>
</script>
<!-- 金额详情模板 -->
<script type="text/html" id="money-info-tpl">
<div style="font-size: 15px;">
<p style="margin: 2px 0; line-height: 1.4;"><b>订单金额:</b>{{d.order_zhe_total}}</p>
<p style="margin: 2px 0; line-height: 1.4;"><b>RMB支付</b>{{d.price}}</p>
<p style="margin: 2px 0; line-height: 1.4;"><b>钻石支付:</b>{{d.use_money}}</p>
<p style="margin: 2px 0; line-height: 1.4;"><b>UU币支付</b>{{d.use_integral}}</p>
<p style="margin: 2px 0; line-height: 1.4;"><b>达达券支付:</b>{{d.use_money2}}</p>
<p style="margin: 2px 0; line-height: 1.4;"><b>优惠券抵扣:</b>{{d.use_coupon}}</p>
</div>
</script>
<!-- 用户信息模板 -->
<script type="text/html" id="user-info-tpl">
<div>
<p style="margin: 2px 0; line-height: 1.4;"><b>ID</b>{{d.user_id}}</p>
<p style="margin: 2px 0; line-height: 1.4;"><b>真实ID</b>{{d.id}}</p>
<p style="margin: 2px 0; line-height: 1.4;"><b>昵称:</b>{{d.nickname}}</p>
<p style="margin: 2px 0; line-height: 1.4;"><b>手机:</b>{{d.mobile}}</p>
<p style="margin: 2px 0; line-height: 1.4;"><b>账号状态:</b>
{{# if(d.u_status == 1){ }}
<span>正常</span>
{{# }else if(d.u_status == 2){ }}
<span style="color: #FF5722;">封号</span>
{{# }else{ }}
<span>未知</span>
{{# } }}
</p>
<p style="margin: 2px 0; line-height: 1.4;"><b>账号类型:</b>
{{# if(d.istest == 0){ }}
<span>正常</span>
{{# }else if(d.istest == 1){ }}
<span>推广</span>
{{# }else if(d.istest == 2){ }}
<span>测试</span>
{{# }else{ }}
<span>未知</span>
{{# } }}
</p>
</div>
</script>
<!-- 抽奖情况模板 -->
<script type="text/html" id="prize-info-tpl">
<div>
<p><b>抽奖数量:</b>{{d.prize_num}}</p>
<p><b>出货金额:</b>{{d.sc_money}}</p>
</div>
</script>
<!-- 支付信息模板 -->
<script type="text/html" id="payment-info-tpl">
<div>
<p>
<b>支付状态:</b>
{{# if(d.status == 1){ }}
<span class="layui-btn layui-btn-xs" style="background-color: #FF8C00;">{{d.status_text}}</span>
{{# }else if(d.status == 0){ }}
<span class="layui-btn layui-btn-xs layui-btn-normal">{{d.status_text}}</span>
{{# }else if(d.status == 2){ }}
<span class="layui-btn layui-btn-xs layui-btn-danger">{{d.status_text}}</span>
{{# }else{ }}
<span class="layui-btn layui-btn-xs layui-btn-primary">{{d.status_text}}</span>
{{# } }}
</p>
<p><b>购买时间:</b>{{d.addtime}}</p>
<p><b>支付时间:</b>{{d.pay_time || '-'}}</p>
</div>
</script>
{include file="Public:footer3" /}
<script>
layui.use(['table', 'form', 'laydate'], function () {
var table = layui.table,
form = layui.form,
laydate = layui.laydate,
$ = layui.jquery;
// 日期时间选择器
laydate.render({
elem: '#start_time',
type: 'datetime'
});
laydate.render({
elem: '#end_time',
type: 'datetime'
});
// 初始化表格
table.render({
elem: '#order-table',
url: "{:url('get_order_list')}",
page: true,
height: 'full-140',
lineStyle: 'height:170px',
limit: 10,
limits: [10, 20, 50, 100],
cols: [[
{ type: 'numbers', title: '序号', width: 60, fixed: 'left' },
{ field: 'order_num', title: '订单号', minWidth: 300, templet: '#order-num-tpl' },
{ field: 'user_info', title: '用户信息', width: 180, templet: '#user-info-tpl' },
{ field: 'goods_detail', title: '盒子详情', width: 280, templet: '#goods-detail-tpl' },
{ field: 'money_info', title: '金额详情', width: 200, templet: '#money-info-tpl' },
{ field: 'prize_info', title: '抽奖情况', width: 150, templet: '#prize-info-tpl' },
{ field: 'payment_info', title: '支付信息', width: 230, templet: '#payment-info-tpl' },
{ title: '操作', width: 120, toolbar: '#operator-toolbar', fixed: 'right' }
]],
response: {
statusCode: 0
},
parseData: function (res) {
return {
"code": res.code,
"msg": res.msg,
"count": res.count,
"data": res.data
};
}
});
// 搜索表单提交
form.on('submit(search-order)', function (data) {
table.reload('order-table', {
page: {
curr: 1
},
where: data.field
});
return false;
});
// 监听工具条事件
table.on('tool(order-table)', function (obj) {
var data = obj.data;
if (obj.event === 'detail') {
// 弹出订单详情窗口
layer.open({
type: 2,
title: '订单详情',
area: ['90%', '90%'],
content: "/admin/buy_order_detail?id=" + data.id, // iframe的url
maxmin: true,
shadeClose: true
});
} else if (obj.event === 'prize_log') {
// 查看抽奖日志
layer.open({
type: 2,
title: '操作日志',
area: ['90%', '90%'],
content: "/admin/markdown/order_info?goods_id=" + data.goods_id + "&order_num=" + data.order_num,
maxmin: true,
shadeClose: true
});
}
});
});
</script>

View File

@ -1,3 +1,15 @@
</body>
<script src="/js/AppConfigManager.js"></script>
<script>
var app_config_list = <?php echo json_encode($app_config_list, JSON_UNESCAPED_UNICODE); ?>;
var goods_type_list= <?php echo json_encode($goods_type_list, JSON_UNESCAPED_UNICODE); ?>;
console.log(goods_type_list);
var appConfigManager = new AppConfigManager(app_config_list,goods_type_list);
window.appConfigManager = appConfigManager;
console.log(appConfigManager);
</script>
<script src="/js/v2.10.3/layui/layui.js"></script>
<script src="/js/jquery-3.1.1.min.js"></script>
<script src="/js/reward-component.js"></script>

View File

@ -10,4 +10,5 @@
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=0">
<link rel="stylesheet" href="/js/v2.10.3/layui/css/layui.css" media="all">
</head>
</head>
<body>

View File

@ -129,8 +129,8 @@ return [
'name' => '发货列表',
],
[
'url' => '/admin/unpaid_order',
'name' => '未支付订单',
'url' => '/admin/order_list',
'name' => '订单列表',
]
],
],

View File

@ -0,0 +1,81 @@
class AppConfigManager {
constructor(configList, goodsTypeList) {
this.rawList = configList;
this.goodsTypeList = goodsTypeList;
this.configMap = this._parseConfigList(configList);
}
getGoodsType(key) {
if (this.goodsTypeList == null || key == null) {
return null;
}
return this.goodsTypeList.find(it => it.value == key);
}
getGoodsTypeName(key) {
return this.getGoodsType(key)?.name;
}
/**
* 内部方法将原始列表转为对象映射结构
* @param {Array} configList 原始配置数组
* @returns {Object} 映射后的对象
*/
_parseConfigList(configList) {
const result = {};
configList.forEach(item => {
try {
result[item.key] = JSON.parse(item.value);
} catch (e) {
result[item.key] = {}; // 解析失败设为空对象
console.warn(`配置项 ${item.key} JSON解析失败`, e);
}
});
return result;
}
/**
* 获取指定 key 的配置项对象
* @param {String} key 要获取的键名
* @returns {Object|null} 对应的配置对象
*/
get(key) {
return this.configMap.hasOwnProperty(key) ? this.configMap[key] : null;
}
/**
* 获取全部配置映射对象
* @returns {Object}
*/
getAll() {
return this.configMap;
}
/**
* 获取微信支付配置列表
* @returns {Object}
*/
getWxPayConfig() {
return this.get("weixinpay_setting")?.merchants;
}
getWxPayConfigByType(order_num) {
if (!order_num || order_num.length < 6) {
console.warn('订单号无效');
return null;
}
// 取第 3~6 位字符作为前缀DEA、DEC、DED...
const order_key = order_num.substr(3, 3);
// console.log('订单号:', order_num, '订单前缀:', order_key);
const wxPayConfigList = this.getWxPayConfig();
if (!Array.isArray(wxPayConfigList)) {
console.warn('微信支付配置无效');
return null;
}
// 在配置中查找匹配的 order_prefix
const match = wxPayConfigList.find(cfg => cfg.order_prefix === order_key);
return match || null; // 找不到返回 null
}
}

2
public/js/markdown-it.min.js vendored Normal file

File diff suppressed because one or more lines are too long