15 Commits

Author SHA1 Message Date
技术老胡
748356cc6b 更新店员码收款 2025-04-16 15:39:14 +08:00
技术老胡
e4952f6389 安装程序优化,移除无用参数 2025-03-31 12:41:19 +08:00
技术老胡
ba8df721d7 更新文件 2025-03-31 12:29:46 +08:00
技术老胡
a3d15ee7e2 1. 订单列表添加平台流水号查询
2. 修临订单查询功能异常问题
3. 优化订单数据表结构
2025-03-31 12:21:00 +08:00
技术老胡
2cd473019b 修复非HTTP环境无法点击复制的问题 2025-03-31 10:34:57 +08:00
技术老胡
a8bb0d7513 更新数据库 2025-03-29 08:47:31 +08:00
技术老胡
ee49c2a0d0 1. 开发文档加载速度优化
2. 浏览器跳转支付宝异常修复
2025-03-19 23:17:58 +08:00
技术老胡
374fc75423 1. 更新收款通知处理逻辑
2. 数据库字段长度调整512
2025-03-19 19:45:03 +08:00
技术老胡
fa75d580b8 修复手机监听通知配置aid信息错误导致的报错 2025-03-18 18:07:18 +08:00
技术老胡
1ac1c2fd13 修改用户中心移动端排版问题 2025-03-18 13:53:07 +08:00
技术老胡
d570aa88b3 更新接口文档 2025-03-18 12:47:04 +08:00
技术老胡
a05a5710af 1. 优化数据库结构,增强兼容性
2. 添加手机浏览器跳转支付宝收银
3. 添加手机浏览器跳转微信支付提示信息
2025-03-18 11:49:00 +08:00
技术老胡
b3dd6ba3f0 Merge branch 'setconfig' of https://gitee.com/technical-laohu/mpay into setconfig 2025-03-14 16:06:50 +08:00
技术老胡
d0dd5a3f9b 更新文档 2025-03-14 16:06:46 +08:00
技术老胡
ccb94768d3 update README.md.
Signed-off-by: 技术老胡 <1094551889@qq.com>
2025-03-10 11:32:08 +00:00
19 changed files with 911 additions and 1304 deletions

3
.env
View File

@@ -1,4 +1,4 @@
APP_DEBUG = true
APP_DEBUG = false
DB_TYPE = mysql
DB_HOST = 127.0.0.1
@@ -6,7 +6,6 @@ DB_NAME = mpay
DB_USER = mpay
DB_PASS = 123456
DB_PORT = 3306
DB_CHARSET = utf8mb4
DB_PREFIX = mpay_
DEFAULT_LANG = zh-cn

View File

@@ -408,7 +408,7 @@ V免签是一款开源免费适用于个人收款使用的收款程序原理
码支付微信PC监听是老胡使用python写的小工具可以监听电脑桌面打开的窗口和内容信息非侵入微信应用内部版本升级不影响监听。需要将被监听的微信聊天界面单独拖出来成独立窗口。
[PC监听软件下载wxmonitor_v1.2.zip](assets/20250217_103606_wxmonitor_v1.2.zip)
[PC监听软件下载wxmonitor_v1.2.zip](assets/wxmonitor_v1.4.zip)
##### 配置信息
@@ -462,6 +462,7 @@ V免签是一款开源免费适用于个人收款使用的收款程序原理
| 零零 | 200 |
| 子染 | 88 |
| John | 100 |
| 辰起 | 8.88 |
## 🔗 友情链接

View File

@@ -28,6 +28,12 @@ class ConsoleController extends BaseController
{
// 加载菜单配置
$message = \Plugin::getNotifyMessage();
if (empty($message)) {
$message = [
["id" => 1, "title" => "应用更新", "children" => []],
["id" => 2, "title" => "官方消息", "children" => []],
];
}
return json($message);
}
// 首页仪表盘

View File

@@ -132,7 +132,6 @@ class InstallController
'user' => 'require',
'pass' => 'require',
'port' => 'require|integer',
'charset' => 'require'
];
if (!$validate->rule($rule)->check($dbConfig)) {
throw new ValidateException($validate->getError());
@@ -187,7 +186,6 @@ DB_NAME = {$dbConfig['name']}
DB_USER = {$dbConfig['user']}
DB_PASS = {$dbConfig['pass']}
DB_PORT = {$dbConfig['port']}
DB_CHARSET = {$dbConfig['charset']}
DB_PREFIX = mpay_
DEFAULT_LANG = zh-cn
@@ -221,75 +219,69 @@ EOT;
private function getTableCreationSqls(): array
{
return [
'mpay_order' => "
CREATE TABLE `mpay_order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pid` int(11) NOT NULL DEFAULT 0 COMMENT '商户 ID',
`order_id` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '订单号',
`type` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '支付类型',
`out_trade_no` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '商户订单号',
`notify_url` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '异步通知地址',
`return_url` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '跳转通知地址',
`name` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '商品名称',
`really_price` decimal(10, 2) NOT NULL DEFAULT 0 COMMENT '实际支付金额',
`money` decimal(10, 2) NOT NULL DEFAULT 0 COMMENT '订单价格',
`clientip` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '用户 IP 地址',
`device` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '设备类型',
`param` varchar(720) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '扩展参数',
`state` tinyint(4) NOT NULL DEFAULT 0 COMMENT '订单状态',
`patt` tinyint(4) NOT NULL DEFAULT 0 COMMENT '开启回调监听',
`create_time` datetime COMMENT '订单创建时间',
`close_time` datetime NULL DEFAULT NULL COMMENT '订单关闭时间',
`pay_time` datetime NULL DEFAULT NULL COMMENT '支付时间',
`platform_order` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '收款平台订单号',
`aid` int(11) NOT NULL DEFAULT 0 COMMENT '收款账号 ID',
`cid` int(11) NOT NULL DEFAULT 0 COMMENT '收款码 ID',
`delete_time` datetime NULL DEFAULT NULL COMMENT '软删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
",
'mpay_pay_account' => "
CREATE TABLE `mpay_pay_account` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '收款平台 ID',
`pid` int(11) NOT NULL DEFAULT 0 COMMENT '用户 ID',
`platform` varchar(255) NOT NULL DEFAULT '' COMMENT '收款平台',
`account` varchar(255) NOT NULL DEFAULT '' COMMENT '账号',
`password` varchar(255) NOT NULL DEFAULT '' COMMENT '密码',
`state` tinyint(4) NOT NULL DEFAULT 1 COMMENT '启用',
`pattern` tinyint(4) NOT NULL DEFAULT 1 COMMENT '账号监听模式',
`params` text NOT NULL COMMENT '自定义查询',
`delete_time` datetime NULL DEFAULT NULL COMMENT '软删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
",
'mpay_pay_channel' => "
CREATE TABLE `mpay_pay_channel` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '渠道 ID',
`account_id` int(11) NOT NULL DEFAULT 0 COMMENT '收款平台 ID',
`channel` varchar(255) NOT NULL DEFAULT '' COMMENT '收款通道',
`type` tinyint(4) NOT NULL DEFAULT 0 COMMENT '保存类型',
`qrcode` varchar(255) NOT NULL DEFAULT '' COMMENT '二维码',
`last_time` datetime COMMENT '最近使用',
`state` tinyint(4) NOT NULL DEFAULT 1 COMMENT '启用',
`delete_time` datetime NULL DEFAULT NULL COMMENT '软删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
",
'mpay_user' => "
CREATE TABLE `mpay_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pid` int(11) NOT NULL DEFAULT 0 COMMENT '商户 ID',
`secret_key` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '商户秘钥',
`nickname` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '用户昵称',
`username` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '账号',
`password` varchar(255) CHARACTER SET utf8mb4 NOT NULL DEFAULT '' COMMENT '密码',
`state` tinyint(4) NOT NULL DEFAULT 1 COMMENT '启用状态 0:禁用 1:启用',
`role` tinyint(4) NOT NULL DEFAULT 0 COMMENT '用户角色 0:普通用户 1:管理员',
`create_time` datetime COMMENT '创建时间',
`delete_time` datetime NULL DEFAULT NULL COMMENT '软删除',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;
"
'mpay_order' => "CREATE TABLE `mpay_order` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pid` int(11) NOT NULL DEFAULT 0,
`order_id` varchar(255) NOT NULL DEFAULT '',
`type` varchar(255) NOT NULL DEFAULT '',
`out_trade_no` varchar(255) NOT NULL DEFAULT '',
`notify_url` varchar(512) NOT NULL DEFAULT '',
`return_url` varchar(512) NOT NULL DEFAULT '',
`name` varchar(255) NOT NULL DEFAULT '',
`really_price` decimal(10, 2) NOT NULL DEFAULT 0.00,
`money` decimal(10, 2) NOT NULL DEFAULT 0.00,
`clientip` varchar(255) NOT NULL DEFAULT '',
`device` varchar(255) NOT NULL DEFAULT '',
`param` varchar(720) NOT NULL DEFAULT '',
`state` tinyint(4) NOT NULL DEFAULT 0,
`patt` tinyint(4) NOT NULL DEFAULT 0,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`close_time` datetime DEFAULT NULL,
`pay_time` datetime DEFAULT NULL,
`platform` varchar(15) NOT NULL DEFAULT '',
`platform_order` varchar(255) NOT NULL DEFAULT '',
`aid` int(11) NOT NULL DEFAULT 0,
`cid` int(11) NOT NULL DEFAULT 0,
`delete_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `idx_order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;",
'mpay_pay_account' => "CREATE TABLE `mpay_pay_account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pid` int(11) NOT NULL DEFAULT 0,
`platform` varchar(255) NOT NULL DEFAULT '',
`account` varchar(255) NOT NULL DEFAULT '',
`password` varchar(255) NOT NULL DEFAULT '',
`state` tinyint(4) NOT NULL DEFAULT 1,
`pattern` tinyint(4) NOT NULL DEFAULT 1,
`params` text NOT NULL,
`delete_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;",
'mpay_pay_channel' => "CREATE TABLE `mpay_pay_channel` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`account_id` int(11) NOT NULL DEFAULT 0,
`channel` varchar(255) NOT NULL DEFAULT '',
`type` tinyint(4) NOT NULL DEFAULT 0,
`qrcode` varchar(512) NOT NULL DEFAULT '',
`last_time` datetime DEFAULT CURRENT_TIMESTAMP,
`state` tinyint(4) NOT NULL DEFAULT 1,
`delete_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;",
'mpay_user' => "CREATE TABLE `mpay_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pid` int(11) NOT NULL DEFAULT 0,
`secret_key` varchar(255) NOT NULL DEFAULT '',
`nickname` varchar(255) NOT NULL DEFAULT '',
`username` varchar(255) NOT NULL DEFAULT '',
`password` varchar(255) NOT NULL DEFAULT '',
`state` tinyint(4) NOT NULL DEFAULT 1,
`role` tinyint(4) NOT NULL DEFAULT 0,
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`delete_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;",
];
}
@@ -340,31 +332,4 @@ EOT;
throw new \Exception("无法写入安装锁文件");
}
}
/**
* 更新数据库结构
* @return \think\response\Json
*/
public function update()
{
if ($this->checkLock()) {
return json(backMsg(1, '已经安装'));
}
$db = $this->connectDatabase();
try {
$result = $db->query("SHOW COLUMNS FROM `mpay_pay_account` WHERE Field = 'params'");
if ($result && $result[0]['Type'] != 'text') {
$sql = "ALTER TABLE `mpay_pay_account` MODIFY COLUMN `params` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '自定义查询' AFTER `pattern`;";
$is_succ = $db->execute($sql);
if (!$is_succ) {
throw new \Exception("修改 mpay_pay_account 表 params 列类型失败");
}
}
return json(backMsg(0, '数据库结构检查并更新完成'));
} catch (\Exception $e) {
Log::error("更新数据库结构失败: " . $e->getMessage());
return json(backMsg(1, '数据库结构更新失败'));
}
}
}

View File

@@ -165,6 +165,7 @@ class PayController
foreach ($activeOrders as $order) {
// 支付方式核对
$is_payway = $order->type == $new_order['payway'];
if ($new_order['payway'] == '') $is_payway = true;
// 支付渠道核对
$is_channel = $cids[$order->cid] == $new_order['channel'];
// 金额核对

View File

@@ -70,41 +70,32 @@ class Order extends BaseModel
public static function serchOrders($query)
{
$select = [];
$_select = [];
$allow_field = ['id', 'order_id', 'pid', 'type', 'out_trade_no', 'notify_url', 'return_url', 'name', 'really_price', 'money', 'clientip', 'device', 'state', 'create_time_start', 'create_time_end', 'close_time', 'pay_time', 'platform', 'platform_order', 'aid', 'cid',];
$allow_field = ['id', 'order_id', 'pid', 'type', 'out_trade_no', 'name', 'really_price', 'money', 'state', 'create_time_start', 'create_time_end', 'close_time', 'pay_time', 'platform', 'platform_order', 'aid', 'cid',];
foreach ($query as $key => $value) {
if (in_array($key, $allow_field) && isset($value)) {
if ($key === 'name') {
$select[] = ['Order.' . $key, 'like', '%' . $value . '%'];
$select[] = [$key, 'like', '%' . $value . '%'];
continue;
}
if ($key === 'create_time_start') {
$select[] = ['Order.' . 'create_time', '>', $value];
$select[] = ['create_time', '>', $value];
continue;
}
if ($key === 'create_time_end') {
$select[] = ['Order.' . 'create_time', '<', $value];
$select[] = ['create_time', '<', $value];
continue;
}
if ($key === 'platform') {
$_select['platform'] = $value;
continue;
}
$select[] = ['Order.' . $key, '=', $value];
$select[] = [$key, '=', $value];
}
}
return self::with('payAccount')
->hasWhere('payAccount', function ($query) use ($_select) {
$query->where($_select);
})
->where($select);
return self::where($select);
}
// 查询订单详细
public static function showOrderDetail($id)
{
$order = self::find($id);
$a_list = PayAccount::find($order->aid);
$c_list = PayChannel::find($order->cid);
$a_list = PayAccount::withTrashed()->find($order->aid);
$c_list = PayChannel::withTrashed()->find($order->cid);
if (!$order) {
return [];
}

View File

@@ -30,6 +30,7 @@ class PayAccount extends BaseModel
public static function getAccountConfig($aid, $pid = null): array|bool
{
$aid_info = self::find($aid);
if (!$aid_info) return false;
// 插件配置
$platform = PluginController::getPluginInfo($aid_info->getData('platform'));
// 查询参数

View File

@@ -12,7 +12,7 @@ return array (
'price' => NULL,
'describe' => '支持微信个人收款码、赞赏码、经营码、商家码收款,监听回调',
'website' => 'https://weixin.qq.com',
'helplink' => '',
'helplink' => 'https://f0bmwzqjtq2.feishu.cn/docx/JBshdZWokoWzLmxSKQWcSd4Jncg',
'version' => '1.0',
'state' => 1,
),
@@ -24,7 +24,7 @@ return array (
'price' => NULL,
'describe' => '支持支付宝个人收款码、经营码收款,监听回调',
'website' => 'https://www.alipay.com',
'helplink' => '',
'helplink' => 'https://f0bmwzqjtq2.feishu.cn/docx/GfltdDrjxoYXwexhtX8ckDCBn9f',
'version' => '1.0',
'state' => 1,
),

View File

@@ -66,6 +66,7 @@ class Plugin
if ($message) return $message;
$message = self::getHttpResponse(self::$siteUrl . '/MpayApi', ['action' => 'message']);
$info = json_decode($message, true);
if($info === null) return [];
if ($info['code'] === 0) cache('message', $info['data'], 36000);
return $info['data'];
}

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

@@ -54,17 +54,10 @@
<div class="layui-form-item">
<label class="layui-form-label">端口</label>
<div class="layui-input-block">
<input type="text" name="port" required lay-verify="required" placeholder="请输入数据库名称"
<input type="text" name="port" required lay-verify="required" placeholder="请输入端口号"
autocomplete="off" class="layui-input" value="3306">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">编码</label>
<div class="layui-input-block">
<input type="text" name="charset" required lay-verify="required" placeholder="请输入数据库名称"
autocomplete="off" class="layui-input" value="utf8mb4">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">数据库</label>
<div class="layui-input-block">
@@ -76,7 +69,7 @@
<label class="layui-form-label">用户名</label>
<div class="layui-input-block">
<input type="text" name="user" required lay-verify="required" placeholder="请输入数据库用户名"
autocomplete="off" class="layui-input" value="root">
autocomplete="off" class="layui-input" value="">
</div>
</div>
<div class="layui-form-item">
@@ -90,21 +83,21 @@
<div class="layui-form-item">
<label class="layui-form-label">管理员昵称</label>
<div class="layui-input-block">
<input type="text" name="nickname" required lay-verify="required" placeholder="请输入管理员昵称"
autocomplete="off" class="layui-input" value="勇敢牛牛">
<input type="text" name="nickname" required lay-verify="required" placeholder="设置管理员昵称"
autocomplete="off" class="layui-input" value="Mpay">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">管理员账号</label>
<div class="layui-input-block">
<input type="text" name="username" required lay-verify="required" placeholder="请输入管理员用户名"
<input type="text" name="username" required lay-verify="required" placeholder="设置管理员用户名"
autocomplete="off" class="layui-input" value="admin">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">管理员密码</label>
<div class="layui-input-block">
<input type="password" name="password" required lay-verify="required" placeholder="请输入管理员密码"
<input type="password" name="password" required lay-verify="required" placeholder="设置登陆密码"
autocomplete="off" class="layui-input">
</div>
</div>

File diff suppressed because it is too large Load Diff

View File

@@ -39,9 +39,10 @@
</div>
</div>
<div class="layui-inline">
<label class="layui-form-label">用户ID</label>
<label class="layui-form-label">平台流水号</label>
<div class="layui-input-inline">
<input type="text" name="pid" autocomplete="off" class="layui-input" placeholder="请输入">
<input type="text" name="platform_order" autocomplete="off" class="layui-input"
placeholder="请输入">
</div>
</div>
<div class="layui-inline">
@@ -127,6 +128,15 @@
清空过期
</button>
</script>
<script type="text/html" id="platformTpl">
<div>
{{#
let platforms = JSON.parse(sessionStorage.getItem('platforms')) || {};
let platformName = platforms[d.platform] || '已卸载';
return `${platformName} [${d.aid}:${d.cid}]`;
}}
</div>
</script>
<script src="/component/layui/layui.js"></script>
<script src="/component/pear/pear.js"></script>
<script>
@@ -203,60 +213,63 @@
(async () => {
const data = await fetch('/api/Plugin/pluginOption').then(res => res.json());
let option_str = `<option value="">收款平台</option>`;
let platforms = {};
data.forEach(val => {
option_str += `<option value="${val.platform}">${val.name}</option>`;
platforms[val.platform] = val.name;
});
const select = document.querySelector('select[name="platform"]');
select.innerHTML = option_str;
form.render('select');
// 会话存储
sessionStorage.setItem('platforms', JSON.stringify(platforms));
// 表格列参数
let cols = [[
{ type: 'checkbox' },
{ title: '订单号', field: 'order_id', align: 'center', minWidth: 165, templet: '<div><a href="javascript:;" class="layui-font-blue" lay-event="showOrder">{{= d.order_id }}</a></div>' },
// { title: '用户', field: 'pid', align: 'center', width: 85 },
{ title: '商家订单号', field: 'out_trade_no', align: 'center', minWidth: 180 },
{ title: '商品', field: 'name', align: 'center', minWidth: 180 },
{ title: '订单金额', field: 'money', align: 'center', minWidth: 85 },
{ title: '成交金额', field: 'really_price', align: 'center', minWidth: 85 },
{ title: '支付状态', field: 'state', align: 'center', minWidth: 85, templet: '<div>{{# if(d.state==1){return`<span class="layui-badge layui-bg-green">成功</span>`}else{if(new Date(d.close_time)>new Date("<?php echo $servertime ?>")){return`<span class="layui-badge layui-bg-orange">等待</span>`}else{return`<span class="layui-badge layui-bg-gray">过期</span>`} } }}</div>' },
{ title: '支付时间', field: 'pay_time', align: 'center', minWidth: 160, templet: '<div>{{= d.pay_time == d.create_time ? "- -" : d.pay_time}}</div>' },
{ title: '支付平台', field: 'type', align: 'center', width: 120, templet: '<div>{{# if(d.type=="wxpay"){return`<div class="paytype"><img src="/static/img/wxpay.ico"width="15"><span>微信支付</span></div>`}if(d.type=="alipay"){return`<div class="paytype"><img src="/static/img/alipay.ico"width="15"><span>支付宝</span></div>`}if(d.type=="unionpay"){return`<div class="paytype"><img src="/static/img/unionpay.ico"width="15"><span>云闪付</span></div>`} }}</div>' },
{ title: '收款平台[账号:终端]', field: 'platform', align: 'center', minWidth: 160, templet: '#platformTpl' },
{ title: '操作', align: 'center', width: 120, fixed: 'right', templet: '<div><strong><a href="javascript:;" data-id="{{= d.id }}" class="layui-font-green {{= d.state==1 ? "orderSet-paid" : "orderSet-paying" }}">设置</a></strong></div>' }
]]
// 表格渲染
table.render({
id: 'orders-table',
elem: '#orders-table',
url: '/api/Order/getOrders',
page: true,
cols: cols,
skin: 'line',
toolbar: '#order-toolbar',
defaultToolbar: [{
title: '刷新',
layEvent: 'refresh',
icon: 'layui-icon-refresh',
}, 'filter', 'print', 'exports'],
done: function () {
dropdown.render({
elem: '.orderSet-paying',
data: [{ title: '改已支付', type: 1 }, { type: '-' }, { title: '手动补单', type: 3 }, { title: '删除订单', type: 0 }],
click: function (data, othis) {
order.setOrder(data, this.elem);
}
});
dropdown.render({
elem: '.orderSet-paid',
data: [{ title: '改未支付', type: 2 }, { type: '-' }, { title: '重新通知', type: 4 }, { title: '删除订单', type: 0 }],
click: function (data, othis) {
order.setOrder(data, this.elem);
}
});
},
});
})()
// 表格列参数
let cols = [[
{ type: 'checkbox' },
{ title: '订单号', field: 'order_id', align: 'center', minWidth: 165, templet: '<div><a href="javascript:;" class="layui-font-blue" lay-event="showOrder">{{= d.order_id }}</a></div>' },
// { title: '用户', field: 'pid', align: 'center', width: 85 },
{ title: '商家订单号', field: 'out_trade_no', align: 'center', minWidth: 180 },
{ title: '商品', field: 'name', align: 'center', minWidth: 180 },
{ title: '订单金额', field: 'money', align: 'center', minWidth: 85 },
{ title: '成交金额', field: 'really_price', align: 'center', minWidth: 85 },
{ title: '支付状态', field: 'state', align: 'center', minWidth: 85, templet: '<div>{{# if(d.state==1){return`<span class="layui-badge layui-bg-green">成功</span>`}else{if(new Date(d.close_time)>new Date("<?php echo $servertime ?>")){return`<span class="layui-badge layui-bg-orange">等待</span>`}else{return`<span class="layui-badge layui-bg-gray">过期</span>`} } }}</div>' },
{ title: '支付时间', field: 'pay_time', align: 'center', minWidth: 160, templet: '<div>{{= d.pay_time == d.create_time ? "- -" : d.pay_time}}</div>' },
{ title: '支付平台', field: 'type', align: 'center', width: 120, templet: '<div>{{# if(d.type=="wxpay"){return`<div class="paytype"><img src="/static/img/wxpay.ico"width="15"><span>微信支付</span></div>`}if(d.type=="alipay"){return`<div class="paytype"><img src="/static/img/alipay.ico"width="15"><span>支付宝</span></div>`}if(d.type=="unionpay"){return`<div class="paytype"><img src="/static/img/unionpay.ico"width="15"><span>云闪付</span></div>`} }}</div>' },
{ title: '收款平台[账号:终端]', field: 'platform', align: 'center', minWidth: 160, templet: '<div>{{# return`${d.payAccount.platform} [${d.aid}:${d.cid}]` }}</div>' },
{ title: '操作', align: 'center', width: 120, fixed: 'right', templet: '<div><strong><a href="javascript:;" data-id="{{= d.id }}" class="layui-font-green {{= d.state==1 ? "orderSet-paid" : "orderSet-paying" }}">设置</a></strong></div>' }
]]
// 表格渲染
table.render({
id: 'orders-table',
elem: '#orders-table',
url: '/api/Order/getOrders',
page: true,
cols: cols,
skin: 'line',
toolbar: '#order-toolbar',
defaultToolbar: [{
title: '刷新',
layEvent: 'refresh',
icon: 'layui-icon-refresh',
}, 'filter', 'print', 'exports'],
done: function () {
dropdown.render({
elem: '.orderSet-paying',
data: [{ title: '改已支付', type: 1 }, { type: '-' }, { title: '手动补单', type: 3 }, { title: '删除订单', type: 0 }],
click: function (data, othis) {
order.setOrder(data, this.elem);
}
});
dropdown.render({
elem: '.orderSet-paid',
data: [{ title: '改未支付', type: 2 }, { type: '-' }, { title: '重新通知', type: 4 }, { title: '删除订单', type: 0 }],
click: function (data, othis) {
order.setOrder(data, this.elem);
}
});
},
});
// 事件处理
// 表格单元格事件

View File

@@ -134,6 +134,12 @@
</span><span></span></div>
<div class="qrcode"><img id="qrcode" src="/static/img/loading.gif">
</div>
<!-- 添加跳转按钮 -->
<div style="margin: 16px auto;display: none;">
<button id="openApp" class="layui-btn layui-btn-normal">
打开支付应用
</button>
</div>
<div class="msg">
<p>请付款 <span class="note">
<?php echo htmlentities($really_price); ?>
@@ -284,6 +290,30 @@
} else if (payType === 'alipay' && environment === 'wxphone') {
layer.alert('请使用支付宝打开此页面');
}
// 添加按钮控制逻辑
const openAppBtn = document.getElementById('openApp');
if (environment === 'phone') {
openAppBtn.parentNode.style.display = 'block';
if (payType === 'wxpay') {
openAppBtn.innerText = '截图并打开微信';
openAppBtn.className = 'layui-btn layui-btn-green';
openAppBtn.onclick = function () {
window.location.href = 'weixin://';
};
} else if (payType === 'alipay') {
openAppBtn.innerText = '打开支付宝付款';
openAppBtn.className = 'layui-btn layui-btn-normal';
openAppBtn.onclick = function () {
if (codeType == 0) {
const payUrl = encodeURIComponent(payCode);
window.location.href = 'alipays://platformapi/startapp?appId=20000067&&url=' + payUrl;
} else {
const currentUrl = encodeURIComponent(window.location.href);
window.location.href = 'alipays://platformapi/startapp?appId=20000067&&url=' + currentUrl;
}
};
}
}
// 生成二维码
async function getQrcode(text, QR) {
const qrcodeUrl = await new Promise((resolve) => {

View File

@@ -32,6 +32,7 @@
<option value="wxpay2">赞赏码</option>
<option value="wxpay3">经营码</option>
<option value="wxpay4">商家码</option>
<option value="wxpay5">店员码</option>
<!-- <?php } ?> -->
<!-- <?php if ($platform == 'alipay') { ?> -->
<option value="alipay1">收钱码</option>
@@ -60,7 +61,7 @@
<div class="layui-form-item">
<blockquote class="layui-elem-quote">
<!-- <?php if ($platform == 'wxpay') { ?> -->
<p><strong>手机监控:</strong>微信个人码与经营码只能二选一,不能同时添加,商家码监听需要关注“微信收款商业版”公众号,赞赏码正常添加。</p>
<p><strong>手机监控:</strong>微信个人码与经营码只能二选一,不能同时添加,且经营码只能通过个人码通道1添加成功不然不回调商家码监听需要关注“微信收款商业版”公众号,赞赏码和店员码正常添加。</p>
<p><strong>电脑监控:</strong>所有收款码均可监控,需要将收款通知聊天窗口单独拖出来</p>
<!-- <?php } ?> -->
<!-- <?php if ($platform == 'alipay') { ?> -->

View File

@@ -168,13 +168,7 @@
table.on('toolDouble(account-table)', function (obj) {
if (obj.event === 'copy') {
const text = obj.tr[0].querySelector('td[data-field="checkUrl"]>div').innerText;
if (navigator.clipboard) {
navigator.clipboard.writeText(text).then(() => {
layer.msg('复制成功');
});
} else {
layer.msg('复制失败,请手动复制');
}
copyText(text);
}
});
// 表格头部按钮事件
@@ -331,6 +325,34 @@
}
}
})
// 复制文本到剪贴板
function copyText(text) {
if (navigator.clipboard && window.isSecureContext === false) {
navigator.clipboard.writeText(text).then(() => {
layer.msg('复制成功');
}).catch(err => {
copyToClipboardFallback(text);
});
} else {
copyToClipboardFallback(text);
}
}
// 传统复制文本到剪贴板
function copyToClipboardFallback(text) {
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand('copy');
layer.msg('复制成功');
} catch (err) {
layer.msg('复制失败,请手动复制');
} finally {
document.body.removeChild(textarea);
}
}
</script>
</body>

View File

@@ -19,6 +19,23 @@
align-items: center;
justify-content: center;
}
.infomsg {
display: flex;
align-items: center;
justify-content: space-between;
margin-left: 10px;
width: calc(100% - 20px);
}
.infomsg div:first-child {
width: 100%;
word-break: break-all;
}
.infomsg div:last-child {
text-align: center;
}
</style>
</head>
@@ -55,22 +72,26 @@
<div class="layui-form-item" pane>
<label class="layui-form-label">API 接口</label>
<div class="layui-input-block">
<div class="layui-form-mid" style="margin-left: 10px;color: #5f5f5f;float: none;">
<?php echo $url ?>
<a href="javascript:;" lay-on="copyinfo" data-info="<?php echo $url ?>"
style="float: right;" title="复制"><span
class="icon pear-icon pear-icon-survey"></span></a>
<div class="layui-form-mid infomsg">
<div>
<?php echo $url ?>
</div>
<div><a href="javascript:;" lay-on="copyinfo" data-info="<?php echo $url ?>"
title="复制"><span class="icon pear-icon pear-icon-survey"></span></a>
</div>
</div>
</div>
</div>
<div class="layui-form-item" pane>
<label class="layui-form-label">商户 PID</label>
<div class="layui-input-block">
<div class="layui-form-mid" style="margin-left: 10px;color: #5f5f5f;float: none;">
<?php echo $pid ?>
<a href="javascript:;" lay-on="copyinfo" data-info="<?php echo $pid ?>"
style="float: right;" title="复制"><span
class="icon pear-icon pear-icon-survey"></span></a>
<div class="layui-form-mid infomsg">
<div>
<?php echo $pid ?>
</div>
<div><a href="javascript:;" lay-on="copyinfo" data-info="<?php echo $pid ?>"
title="复制"><span class="icon pear-icon pear-icon-survey"></span></a>
</div>
</div>
</div>
</div>
@@ -78,12 +99,15 @@
<label class="layui-form-label">商户密钥 <a href="javascript:;" lay-on="resetKey"
title="重置密钥"><span class="icon pear-icon pear-icon-refresh"></span></a></label>
<div class="layui-input-block">
<div class="layui-form-mid layui-elip"
style="margin-left: 10px;color: #5f5f5f;float: none;">
<?php echo $secret_key ?>
<a href="javascript:;" lay-on="copyinfo" data-info="<?php echo $secret_key ?>"
style="float: right;" title="复制"><span
class="icon pear-icon pear-icon-survey"></span></a>
<div class="layui-form-mid infomsg">
<div>
<?php echo $secret_key ?>
</div>
<div>
<a href="javascript:;" lay-on="copyinfo"
data-info="<?php echo $secret_key ?>" title="复制"><span
class="icon pear-icon pear-icon-survey"></span></a>
</div>
</div>
</div>
</div>
@@ -98,12 +122,14 @@
<div class="layui-form-item" pane>
<label class="layui-form-label">订单监控</label>
<div class="layui-input-block">
<div class="layui-form-mid layui-elip"
style="margin-left: 10px;color: #5f5f5f;float: none;">
<?php echo $orderurl ?>
<a href="javascript:;" lay-on="copyinfo" data-info="<?php echo $orderurl ?>"
style="float: right;" title="复制"><span
class="icon pear-icon pear-icon-survey"></span></a>
<div class="layui-form-mid infomsg">
<div>
<?php echo $orderurl ?>
</div>
<div><a href="javascript:;" lay-on="copyinfo"
data-info="<?php echo $orderurl ?>" title="复制"><span
class="icon pear-icon pear-icon-survey"></span></a>
</div>
</div>
</div>
</div>
@@ -123,94 +149,103 @@
<div class="layui-form-item" pane>
<label class="layui-form-label">Webhook</label>
<div class="layui-input-block">
<div class="layui-form-mid layui-elip"
style="margin-left: 10px;color: #5f5f5f;float: none;">
<?php echo $url . 'mpayNotify' ?>
<a href="javascript:;" lay-on="copyinfo"
data-info="<?php echo $url . 'mpayNotify' ?>" style="float: right;"
title="复制"><span class="icon pear-icon pear-icon-survey"></span></a>
<div class="layui-form-mid infomsg">
<div>
<?php echo $url . 'mpayNotify' ?>
</div>
<div><a href="javascript:;" lay-on="copyinfo"
data-info="<?php echo $url . 'mpayNotify' ?>" title="复制"><span
class="icon pear-icon pear-icon-survey"></span></a>
</div>
</div>
</div>
</div>
<div class="layui-form-item" pane>
<label class="layui-form-label">消息模版</label>
<div class="layui-input-block">
<div class="layui-form-mid layui-elip"
style="margin-left: 10px;color: #5f5f5f;float: none;">
{"action": "mpay","data": "[msg]","time":"[timestamp]","sign": "[sign]"}
<a href="javascript:;" lay-on="copyinfo"
data-info='{"action": "mpay","data": "[msg]","time":"[timestamp]","sign": "[sign]"}'
style="float: right;" title="复制"><span
class="icon pear-icon pear-icon-survey"></span></a>
<div class="layui-form-mid infomsg">
<div>{"action": "mpay","data": "[msg]","time":"[timestamp]","sign":
"[sign]"}
</div>
<div><a href="javascript:;" lay-on="copyinfo"
data-info='{"action": "mpay","data": "[msg]","time":"[timestamp]","sign": "[sign]"}'
title="复制"><span
class="icon pear-icon pear-icon-survey"></span></a>
</div>
</div>
</div>
</div>
<div class="layui-form-item" pane>
<label class="layui-form-label">Secret</label>
<div class="layui-input-block">
<div class="layui-form-mid layui-elip"
style="margin-left: 10px;color: #5f5f5f;float: none;">
<?php echo $secret_key ?>
<a href="javascript:;" lay-on="copyinfo"
data-info="<?php echo $secret_key ?>" style="float: right;"
title="复制"><span class="icon pear-icon pear-icon-survey"></span></a>
<div class="layui-form-mid infomsg">
<div>
<?php echo $secret_key ?>
</div>
<div><a href="javascript:;" lay-on="copyinfo"
data-info="<?php echo $secret_key ?>" title="复制"><span
class="icon pear-icon pear-icon-survey"></span></a>
</div>
</div>
</div>
</div>
<div class="layui-form-item" pane>
<label class="layui-form-label">成功关键字</label>
<div class="layui-input-block">
<div class="layui-form-mid layui-elip"
style="margin-left: 10px;color: #5f5f5f;float: none;">
200
<a href="javascript:;" lay-on="copyinfo" data-info="200"
style="float: right;" title="复制"><span
class="icon pear-icon pear-icon-survey"></span></a>
<div class="layui-form-mid infomsg">
<div>200</div>
<div><a href="javascript:;" lay-on="copyinfo" data-info="200"
title="复制"><span
class="icon pear-icon pear-icon-survey"></span></a>
</div>
</div>
</div>
</div>
</div>
</div>
</fieldset>
<fieldset class="layui-elem-field">
<legend style="font-size: 14px;">应用转发规则·多重匹配</legend>
<div class="layui-field-box">
<div class="layui-form layui-form-pane">
<div class="layui-form-item" pane>
<label class="layui-form-label">微信支付</label>
<div class="layui-input-block">
<div class="layui-form-mid layui-elip"
style="margin-left: 10px;color: #5f5f5f;float: none;">
<?php echo '并且 是 APP包名 相等 com.tencent.mm<br />并且 是 通知标题 相等 微信支付<br />[空格]或者 是 通知标题 相等 微信收款助手<br />[空格]或者 是 通知标题 相等 微信收款商业版' ?>
<a href="javascript:;" lay-on="copyinfo"
data-info='<?php echo "并且 是 APP包名 相等 com.tencent.mm\n并且 是 通知标题 相等 微信支付\n[空格]或者 是 通知标题 相等 微信收款助手\n[空格]或者 是 通知标题 相等 微信收款商业版" ?>'
style="float: right;" title="复制"><span
class="icon pear-icon pear-icon-survey"></span></a>
</div>
</div>
</div>
<div class="layui-form-item" pane>
<label class="layui-form-label">支付宝</label>
<div class="layui-input-block">
<div class="layui-form-mid layui-elip"
style="margin-left: 10px;color: #5f5f5f;float: none;">
<?php echo '并且 是 APP包名 相等 com.eg.android.AlipayGphone<br />并且 是 通知标题 包含 元<br />[空格]或者 是 通知内容 包含 元' ?>
<a href="javascript:;" lay-on="copyinfo"
data-info='<?php echo "并且 是 APP包名 相等 com.eg.android.AlipayGphone\n并且 是 通知标题 包含 元\n[空格]或者 是 通知内容 包含 元" ?>'
style="float: right;" title="复制"><span
class="icon pear-icon pear-icon-survey"></span></a>
</div>
</div>
</div>
</div>
</div>
</fieldset>
</div>
</fieldset>
<fieldset class="layui-elem-field">
<legend style="font-size: 14px;">应用转发规则·多重匹配</legend>
<div class="layui-field-box">
<div class="layui-form layui-form-pane">
<div class="layui-form-item" pane>
<label class="layui-form-label">微信支付</label>
<div class="layui-input-block">
<div class="layui-form-mid infomsg">
<div>
<?php echo '并且 是 APP包名 相等 com.tencent.mm<br />并且 是 通知标题 相等 微信支付<br />[空格]或者 是 通知标题 相等 微信收款助手<br />[空格]或者 是 通知标题 相等 微信收款商业版' ?>
</div>
<div><a href="javascript:;" lay-on="copyinfo"
data-info='<?php echo "并且 是 APP包名 相等 com.tencent.mm\n并且 是 通知标题 相等 微信支付\n[空格]或者 是 通知标题 相等 微信收款助手\n[空格]或者 是 通知标题 相等 微信收款商业版" ?>'
title="复制"><span class="icon pear-icon pear-icon-survey"></span></a>
</div>
</div>
</div>
</div>
<div class="layui-form-item" pane>
<label class="layui-form-label">支付宝</label>
<div class="layui-input-block">
<div class="layui-form-mid infomsg">
<div>
<?php echo '并且 是 APP包名 相等 com.eg.android.AlipayGphone<br />并且 是 通知标题 包含 元<br />[空格]或者 是 通知内容 包含 元' ?>
</div>
<div><a href="javascript:;" lay-on="copyinfo"
data-info='<?php echo "并且 是 APP包名 相等 com.eg.android.AlipayGphone\n并且 是 通知标题 包含 元\n[空格]或者 是 通知内容 包含 元" ?>'
title="复制"><span class="icon pear-icon pear-icon-survey"></span></a>
</div>
</div>
</div>
</div>
</div>
</div>
</fieldset>
</div>
</div>
</div>
</div>
</div>
<script src="/component/layui/layui.js"></script>
<script src="/component/pear/pear.js"></script>
<script>
@@ -221,13 +256,7 @@
util.on({
'copyinfo': (ele) => {
const info = ele.attr('data-info');
if (navigator.clipboard) {
navigator.clipboard.writeText(info).then(() => {
layer.msg('复制成功');
});
} else {
layer.msg('复制失败,请手动复制');
}
copyText(info);
},
'resetKey': (ele) => {
layer.confirm('重置密钥后,将无法使用原密钥,是否继续?', { icon: 3, title: '重置密钥' }, function (index) {
@@ -262,8 +291,34 @@
});
fetch('https://v1.hitokoto.cn?c=d&c=i&c=k&encode=text').then(res => res.text()).then(data => { document.getElementById('yiyan').innerHTML = data || '人无横财不富,马无夜草不肥'; })
// 复制文本到剪贴板
function copyText(text) {
if (navigator.clipboard && window.isSecureContext === false) {
navigator.clipboard.writeText(text).then(() => {
layer.msg('复制成功');
}).catch(err => {
copyToClipboardFallback(text);
});
} else {
copyToClipboardFallback(text);
}
}
// 传统复制文本到剪贴板
function copyToClipboardFallback(text) {
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.position = 'fixed';
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand('copy');
layer.msg('复制成功');
} catch (err) {
layer.msg('复制失败,请手动复制');
} finally {
document.body.removeChild(textarea);
}
}
</script>
</body>