mirror of
https://gitee.com/technical-laohu/mpay.git
synced 2025-09-18 01:36:40 +08:00
1、更新通道统计,可以查看每个通道的收入情况,可以查询指定时间段的通道收入情况
2、账号管理列表交互优化,添加操作下拉框 3、修复二维码图片上传功能可能导致的漏洞
This commit is contained in:
parent
98c90dffcf
commit
5826a7f6e1
BIN
app/app.zip
Normal file
BIN
app/app.zip
Normal file
Binary file not shown.
@ -74,4 +74,9 @@ class PayManageController extends BaseController
|
|||||||
View::assign(['id' => $id]);
|
View::assign(['id' => $id]);
|
||||||
return View::fetch();
|
return View::fetch();
|
||||||
}
|
}
|
||||||
|
// 收款统计
|
||||||
|
public function payStatistics()
|
||||||
|
{
|
||||||
|
return View::fetch();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,8 @@ namespace app\controller\api;
|
|||||||
use app\BaseController;
|
use app\BaseController;
|
||||||
use app\model\PayAccount;
|
use app\model\PayAccount;
|
||||||
use app\model\PayChannel;
|
use app\model\PayChannel;
|
||||||
|
use app\model\Order;
|
||||||
|
use think\facade\Db;
|
||||||
use \think\facade\Log;
|
use \think\facade\Log;
|
||||||
|
|
||||||
class PayManageController extends BaseController
|
class PayManageController extends BaseController
|
||||||
@ -208,4 +210,73 @@ class PayManageController extends BaseController
|
|||||||
return json(['code' => 1, 'msg' => $records['msg']]);
|
return json(['code' => 1, 'msg' => $records['msg']]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function payStatisticsList()
|
||||||
|
{
|
||||||
|
$query = $this->request->get();
|
||||||
|
$limit = $query['limit'] ?? 10;
|
||||||
|
$page = $query['page'] ?? 1;
|
||||||
|
$start_time = $query['time_start'] ?? date('Y-m-d H:i:s', strtotime('today'));
|
||||||
|
$end_time = $query['time_end'] ?? date('Y-m-d H:i:s', strtotime('tomorrow') - 1);
|
||||||
|
// 确保日期时间格式正确
|
||||||
|
$start_time = date('Y-m-d H:i:s', strtotime($start_time));
|
||||||
|
$end_time = date('Y-m-d H:i:s', strtotime($end_time));
|
||||||
|
|
||||||
|
$accounts = Db::table('mpay_pay_account', 'PayAccount')
|
||||||
|
->alias('PayAccount')
|
||||||
|
->join('mpay_order Order', 'PayAccount.id = Order.aid AND Order.delete_time IS NULL AND Order.state = 1', 'LEFT')
|
||||||
|
->field([
|
||||||
|
'PayAccount.*',
|
||||||
|
'SUM(CASE WHEN DATE(Order.pay_time) = CURDATE() THEN Order.really_price ELSE 0 END) as day',
|
||||||
|
'SUM(CASE WHEN DATE(Order.pay_time) = DATE_SUB(CURDATE(), INTERVAL 1 DAY) THEN Order.really_price ELSE 0 END) as yesterday',
|
||||||
|
'SUM(CASE WHEN YEARWEEK(Order.pay_time, 1) = YEARWEEK(CURDATE(), 1) THEN Order.really_price ELSE 0 END) as week',
|
||||||
|
'SUM(CASE WHEN DATE_FORMAT(Order.pay_time, "%Y-%m") = DATE_FORMAT(CURDATE(), "%Y-%m") THEN Order.really_price ELSE 0 END) as month',
|
||||||
|
'SUM(CASE WHEN YEAR(Order.pay_time) = YEAR(CURDATE()) THEN Order.really_price ELSE 0 END) as year',
|
||||||
|
'SUM(IFNULL(Order.really_price, 0)) as total',
|
||||||
|
"SUM(CASE WHEN Order.pay_time BETWEEN '$start_time' AND '$end_time' THEN Order.really_price ELSE 0 END) as income"
|
||||||
|
])
|
||||||
|
->where('PayAccount.delete_time IS NULL')
|
||||||
|
->group('PayAccount.id')
|
||||||
|
->order('PayAccount.id', 'DESC')
|
||||||
|
->paginate(['list_rows' => $limit, 'page' => $page]);
|
||||||
|
|
||||||
|
return json([
|
||||||
|
'code' => 0,
|
||||||
|
'msg' => 'OK',
|
||||||
|
'count' => $accounts->total(),
|
||||||
|
'data' => $accounts->items()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 收款统计
|
||||||
|
// public function payStatisticsList()
|
||||||
|
// {
|
||||||
|
// $query = $this->request->get();
|
||||||
|
// // 定义统计字段
|
||||||
|
// $fields = [
|
||||||
|
// "SUM(IF(DATE(pay_time) = CURDATE(), really_price, 0)) as day",
|
||||||
|
// "SUM(IF(DATE(pay_time) = CURDATE() - INTERVAL 1 DAY, really_price, 0)) as yesterday",
|
||||||
|
// "SUM(IF(YEARWEEK(pay_time, 1) = YEARWEEK(CURDATE(), 1), really_price, 0)) as week",
|
||||||
|
// "SUM(IF(DATE_FORMAT(pay_time, '%Y-%m') = DATE_FORMAT(CURDATE(), '%Y-%m'), really_price, 0)) as month",
|
||||||
|
// "SUM(IF(YEAR(pay_time) = YEAR(CURDATE()), really_price, 0)) as year",
|
||||||
|
// "SUM(really_price) as total"
|
||||||
|
// ];
|
||||||
|
|
||||||
|
// $where = ['state', 1;
|
||||||
|
|
||||||
|
// // 合并 pay_account 表字段和统计字段
|
||||||
|
// $allFields = array_merge([PayAccount::getTable() . '.*'], $fields);
|
||||||
|
|
||||||
|
// $accounts = PayAccount::hasWhere('order', $where, '*', 'LEFT')
|
||||||
|
// ->field($allFields)
|
||||||
|
// ->group(PayAccount::getTable() . '.id')
|
||||||
|
// ->order('id', 'desc')
|
||||||
|
// ->paginate(['list_rows' => $query['limit'] ?? 10, 'page' => $query['page'] ?? 1]);
|
||||||
|
|
||||||
|
// if ($accounts) {
|
||||||
|
// return json(['code' => 0, 'msg' => PayAccount::getLastSql(), 'count' => $accounts->total(), 'data' => $accounts->items()]);
|
||||||
|
// } else {
|
||||||
|
// return json(['code' => 1, 'msg' => '无数据记录', 'count' => 0, 'data' => []]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
@ -210,6 +210,6 @@ class Order extends BaseModel
|
|||||||
// 模型多对一关联
|
// 模型多对一关联
|
||||||
public function payAccount()
|
public function payAccount()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(PayAccount::class, 'aid', 'id');
|
return $this->belongsTo(PayAccount::class, 'id', 'aid');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,25 @@ class PayAccount extends BaseModel
|
|||||||
$select[] = [$key, '=', $value];
|
$select[] = [$key, '=', $value];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self::withCount(['payChannel' => 'channel'])->where($select);
|
return self::withCount(['payChannel' => 'channel_num'])->withSum(['order' => function ($query, &$alias) {
|
||||||
|
$query->whereDay('pay_time')->where('state', 1);
|
||||||
|
$alias = 'income';
|
||||||
|
}], 'really_price')->where($select);
|
||||||
|
}
|
||||||
|
public static function findAccount($query)
|
||||||
|
{
|
||||||
|
$select = [];
|
||||||
|
$allow_field = ['state', 'platform', 'account', 'pattern'];
|
||||||
|
foreach ($query as $key => $value) {
|
||||||
|
if (in_array($key, $allow_field) && isset($value)) {
|
||||||
|
if ($key === 'account') {
|
||||||
|
$select[] = [$key, 'like', '%' . $value . '%'];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$select[] = [$key, '=', $value];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return self::where($select);
|
||||||
}
|
}
|
||||||
// 获取账号配置
|
// 获取账号配置
|
||||||
public static function getAccountConfig($aid, $pid = null): array|bool
|
public static function getAccountConfig($aid, $pid = null): array|bool
|
||||||
@ -86,4 +104,9 @@ class PayAccount extends BaseModel
|
|||||||
{
|
{
|
||||||
return $this->hasMany(PayChannel::class, 'account_id', 'id');
|
return $this->hasMany(PayChannel::class, 'account_id', 'id');
|
||||||
}
|
}
|
||||||
|
// 一对多关联
|
||||||
|
public function order()
|
||||||
|
{
|
||||||
|
return $this->hasMany(Order::class, 'aid', 'id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ class Plugin
|
|||||||
{
|
{
|
||||||
$message = cache('message');
|
$message = cache('message');
|
||||||
if ($message) return $message;
|
if ($message) return $message;
|
||||||
$message = self::getHttpResponse(self::$siteUrl . '/MpayApi', ['action' => 'message']);
|
$message = self::getHttpResponse(self::$siteUrl . '/MpayApi', ['action' => 'message'], [], 3);
|
||||||
$info = json_decode($message, true);
|
$info = json_decode($message, true);
|
||||||
if ($info === null) return [];
|
if ($info === null) return [];
|
||||||
if ($info['code'] === 0) cache('message', $info['data'], 36000);
|
if ($info['code'] === 0) cache('message', $info['data'], 36000);
|
||||||
|
BIN
public/files/qrcode/img_1747104593_6822b351cab62.jpg
Normal file
BIN
public/files/qrcode/img_1747104593_6822b351cab62.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 47 KiB |
@ -219,6 +219,11 @@
|
|||||||
let platformName = platforms[d.platform] || '已卸载';
|
let platformName = platforms[d.platform] || '已卸载';
|
||||||
return `${platformName} [${d.aid}:${d.cid}]`;
|
return `${platformName} [${d.aid}:${d.cid}]`;
|
||||||
}
|
}
|
||||||
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const where = {};
|
||||||
|
urlParams.forEach((value, key) => {
|
||||||
|
where[key] = value;
|
||||||
|
});
|
||||||
// 表格列参数
|
// 表格列参数
|
||||||
let cols = [[
|
let cols = [[
|
||||||
{ type: 'checkbox' },
|
{ type: 'checkbox' },
|
||||||
@ -239,6 +244,7 @@
|
|||||||
id: 'orders-table',
|
id: 'orders-table',
|
||||||
elem: '#orders-table',
|
elem: '#orders-table',
|
||||||
url: '/api/Order/getOrders',
|
url: '/api/Order/getOrders',
|
||||||
|
where: where,
|
||||||
page: true,
|
page: true,
|
||||||
cols: cols,
|
cols: cols,
|
||||||
skin: 'line',
|
skin: 'line',
|
||||||
|
@ -106,10 +106,11 @@
|
|||||||
<script src="/component/layui/layui.js"></script>
|
<script src="/component/layui/layui.js"></script>
|
||||||
<script src="/component/pear/pear.js"></script>
|
<script src="/component/pear/pear.js"></script>
|
||||||
<script>
|
<script>
|
||||||
layui.use(['table', 'form', 'common', 'util'], function () {
|
layui.use(['table', 'form', 'common', 'dropdown', 'util'], function () {
|
||||||
let table = layui.table;
|
let table = layui.table;
|
||||||
let form = layui.form;
|
let form = layui.form;
|
||||||
let common = layui.common;
|
let common = layui.common;
|
||||||
|
let dropdown = layui.dropdown;
|
||||||
let util = layui.util;
|
let util = layui.util;
|
||||||
|
|
||||||
// 渲染插件选项
|
// 渲染插件选项
|
||||||
@ -130,10 +131,11 @@
|
|||||||
{ title: '账 号', field: 'account', align: 'center' },
|
{ title: '账 号', field: 'account', align: 'center' },
|
||||||
{ title: '启用状态', field: 'state', align: 'center', templet: '#account-state' },
|
{ title: '启用状态', field: 'state', align: 'center', templet: '#account-state' },
|
||||||
{ title: '监听模式', field: 'pattern', align: 'center' },
|
{ title: '监听模式', field: 'pattern', align: 'center' },
|
||||||
{ title: '监听地址 / 自定义模版', field: 'checkUrl', align: 'center', minWidth: 300, event: 'copy', templet: '#account-checkUrl' },
|
{ title: '监听地址 / 自定义模版', field: 'checkUrl', align: 'center', minWidth: 240, event: 'copy', templet: '#account-checkUrl' },
|
||||||
{ title: '收款平台流水', field: 'trade', align: 'center', templet: '#account-trade' },
|
{ title: '收款平台流水', field: 'trade', align: 'center', templet: '#account-trade' },
|
||||||
{ title: '收款码数量', field: 'channel', align: 'center', templet: '<div><a href="javascript:;" lay-event="channelList"><span class="layui-badge layui-bg-green">{{= d.channel }}</span></a></div>' },
|
{ title: '收款码数量', field: 'channel_num', align: 'center', templet: '<div><a href="javascript:;" lay-event="channelList"><span class="layui-badge layui-bg-green">{{= d.channel_num }}</span></a></div>' },
|
||||||
{ title: '操作', align: 'center', fixed: 'right', templet: '<div><a href="javascript:;" class="layui-font-green" lay-event="edit"><strong>编辑</strong></a></div>' }
|
{ title: '今日收款', field: 'income', align: 'center', templet: '<div><strong>{{# return d.income ?? 0 }}</strong></div>' },
|
||||||
|
{ title: '操作', align: 'center', fixed: 'right', templet: '<div><a href="javascript:;" class="layui-font-green edit" data-aid="{{= d.id }}"><strong>编辑</strong></a></div>' }
|
||||||
]]
|
]]
|
||||||
|
|
||||||
table.render({
|
table.render({
|
||||||
@ -148,7 +150,17 @@
|
|||||||
title: '刷新',
|
title: '刷新',
|
||||||
layEvent: 'refresh',
|
layEvent: 'refresh',
|
||||||
icon: 'layui-icon-refresh',
|
icon: 'layui-icon-refresh',
|
||||||
}, 'filter', 'print', 'exports']
|
}, 'filter', 'print', 'exports'],
|
||||||
|
done: function () {
|
||||||
|
dropdown.render({
|
||||||
|
elem: '.edit',
|
||||||
|
align: 'center',
|
||||||
|
data: [{ title: '编辑', id: 1 }, { type: '-' }, { title: '二维码', id: 2 }, { title: '收款统计', id: 3 }, { title: '收款明细', id: 4 }],
|
||||||
|
click: function (data, othis) {
|
||||||
|
account.doEdit(data, this.elem);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 事件处理
|
// 事件处理
|
||||||
@ -226,6 +238,27 @@
|
|||||||
// 操作方法
|
// 操作方法
|
||||||
let account = {};
|
let account = {};
|
||||||
|
|
||||||
|
// 编辑操作
|
||||||
|
account.doEdit = function (data, elem) {
|
||||||
|
const type = data.id;
|
||||||
|
const id = elem.attr('data-aid');
|
||||||
|
switch (type) {
|
||||||
|
case 1:
|
||||||
|
account.editAccount(id);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
account.channelList(id);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
alert('收款统计');
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
account.orderList(id);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// 编辑
|
// 编辑
|
||||||
account.editAccount = function (id) {
|
account.editAccount = function (id) {
|
||||||
layer.open({
|
layer.open({
|
||||||
@ -238,6 +271,18 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
// 终端列表
|
// 终端列表
|
||||||
|
account.orderList = function (aid) {
|
||||||
|
// 先尝试关闭已存在的标签
|
||||||
|
if (parent.layui.tab) {
|
||||||
|
parent.layui.tab.delTabByElem('content', 'order');
|
||||||
|
}
|
||||||
|
// 重新打开标签
|
||||||
|
parent.layui.tab.addTabOnlyByElem('content',
|
||||||
|
{ id: 'order', title: '订单管理', url: `/Order/index?aid=${aid}`, close: true }
|
||||||
|
)
|
||||||
|
parent.layui.tab.changeTabTitleById('content', 'order', `【${aid}】订单明细`);
|
||||||
|
}
|
||||||
|
// 终端列表
|
||||||
account.channelList = function (id) {
|
account.channelList = function (id) {
|
||||||
layer.open({
|
layer.open({
|
||||||
id: 'iframe-channel-list',
|
id: 'iframe-channel-list',
|
||||||
|
133
view/pay_manage/pay_statistics.html
Normal file
133
view/pay_manage/pay_statistics.html
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>收款管理</title>
|
||||||
|
<link rel="stylesheet" href="/component/pear/css/pear.css" />
|
||||||
|
<style>
|
||||||
|
.account-trade {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="pear-container">
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-body">
|
||||||
|
<form class="layui-form layui-form-pane" action="" id="serch-form">
|
||||||
|
<div class="layui-form-item">
|
||||||
|
<div class="layui-inline">
|
||||||
|
<label class="layui-form-label">时间段</label>
|
||||||
|
<div class="layui-inline" id="create_time">
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="text" name="time_start" autocomplete="off" placeholder="开始"
|
||||||
|
class="layui-input">
|
||||||
|
</div>
|
||||||
|
<div class="layui-form-mid">-</div>
|
||||||
|
<div class="layui-input-inline">
|
||||||
|
<input type="text" name="time_end" autocomplete="off" placeholder="结束"
|
||||||
|
class="layui-input">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-inline">
|
||||||
|
<button type="submit" class="pear-btn pear-btn-md pear-btn-primary" lay-submit
|
||||||
|
lay-filter="query">
|
||||||
|
<i class="layui-icon layui-icon-search"></i>
|
||||||
|
查询
|
||||||
|
</button>
|
||||||
|
<button type="button" lay-on="reset" class="pear-btn pear-btn-md">
|
||||||
|
<i class="layui-icon layui-icon-refresh"></i>
|
||||||
|
重置
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layui-card">
|
||||||
|
<div class="layui-card-body">
|
||||||
|
<table id="account-table" lay-filter="account-table"></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script src="/component/layui/layui.js"></script>
|
||||||
|
<script src="/component/pear/pear.js"></script>
|
||||||
|
<script>
|
||||||
|
layui.use(['table', 'form', 'common', 'dropdown', 'util'], function () {
|
||||||
|
let table = layui.table;
|
||||||
|
let form = layui.form;
|
||||||
|
let common = layui.common;
|
||||||
|
let dropdown = layui.dropdown;
|
||||||
|
let util = layui.util;
|
||||||
|
let laydate = layui.laydate;
|
||||||
|
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
const startOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0);
|
||||||
|
const endOfDay = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 23, 59, 59);
|
||||||
|
laydate.render({
|
||||||
|
elem: '#create_time',
|
||||||
|
range: ['input[name="time_start"]', 'input[name="time_end"]'],
|
||||||
|
rangeLinked: true,
|
||||||
|
type: 'datetime',
|
||||||
|
fullPanel: true,
|
||||||
|
weekStart: 1,
|
||||||
|
// 当天开始日期 - 当天结束日期
|
||||||
|
value: util.toDateString(startOfDay, 'yyyy-MM-dd HH:mm:ss') + ' - ' + util.toDateString(endOfDay, 'yyyy-MM-dd HH:mm:ss')
|
||||||
|
});
|
||||||
|
|
||||||
|
let cols = [[
|
||||||
|
{ type: 'checkbox' },
|
||||||
|
{ title: '平 台', field: 'platform', align: 'center', templet: '' },
|
||||||
|
{ title: '账 号', field: 'account', align: 'center' },
|
||||||
|
{ title: '时段查询收款', field: 'income', align: 'center', templet: '<div><strong>{{# return d.income ?? 0 }}</strong></div>' },
|
||||||
|
{ title: '今日收款', field: 'day', align: 'center', templet: '<div><strong>{{# return d.day ?? 0 }}</strong></div>' },
|
||||||
|
{ title: '昨日收款', field: 'yesterday', align: 'center', templet: '<div><strong>{{# return d.yesterday ?? 0 }}</strong></div>' },
|
||||||
|
{ title: '本周收款', field: 'week', align: 'center', templet: '<div><strong>{{# return d.week ?? 0 }}</strong></div>' },
|
||||||
|
{ title: '本月收款', field: 'month', align: 'center', templet: '<div><strong>{{# return d.month ?? 0 }}</strong></div>' },
|
||||||
|
{ title: '当年收款', field: 'year', align: 'center', templet: '<div><strong>{{# return d.year ?? 0 }}</strong></div>' },
|
||||||
|
{ title: '总计收款', field: 'total', align: 'center', templet: '<div><strong>{{# return d.total ?? 0 }}</strong></div>' },
|
||||||
|
]]
|
||||||
|
|
||||||
|
table.render({
|
||||||
|
id: 'account-table',
|
||||||
|
elem: '#account-table',
|
||||||
|
url: '/api/PayManage/payStatisticsList',
|
||||||
|
page: true,
|
||||||
|
cols: cols,
|
||||||
|
skin: 'line',
|
||||||
|
defaultToolbar: [{
|
||||||
|
title: '刷新',
|
||||||
|
layEvent: 'refresh',
|
||||||
|
icon: 'layui-icon-refresh',
|
||||||
|
}, 'filter', 'print', 'exports'],
|
||||||
|
});
|
||||||
|
|
||||||
|
// 表单自定义事件监听
|
||||||
|
form.on('submit(query)', function (obj) {
|
||||||
|
const field = obj.field;
|
||||||
|
let new_field = {};
|
||||||
|
for (const key in field) {
|
||||||
|
if (field.hasOwnProperty.call(field, key)) {
|
||||||
|
const value = field[key];
|
||||||
|
if (value) {
|
||||||
|
new_field[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
table.reload('account-table', { where: new_field });
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
// 监听重置按钮
|
||||||
|
util.on({
|
||||||
|
reset: function () {
|
||||||
|
document.querySelector('#serch-form').reset();
|
||||||
|
table.reload('account-table', { where: {} });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
BIN
view/view.zip
Normal file
BIN
view/view.zip
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user