初始化提交
This commit is contained in:
568
app/manager/view/error.php
Normal file
568
app/manager/view/error.php
Normal file
@@ -0,0 +1,568 @@
|
||||
<?php
|
||||
|
||||
if (!function_exists('parse_padding')) {
|
||||
function parse_padding($source)
|
||||
{
|
||||
$length = strlen(strval(count($source['source']) + $source['first']));
|
||||
return 40 + ($length - 1) * 8;
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('parse_class')) {
|
||||
function parse_class($name): string
|
||||
{
|
||||
$names = explode('\\', $name);
|
||||
return '<abbr title="' . $name . '">' . end($names) . '</abbr>';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('parse_file')) {
|
||||
function parse_file($file, $line): string
|
||||
{
|
||||
return '<a class="toggle" title="' . "{$file} line {$line}" . '">' . basename($file) . " line {$line}" . '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
if (!function_exists('parse_args')) {
|
||||
function parse_args($args): string
|
||||
{
|
||||
$result = [];
|
||||
foreach ($args as $key => $item) {
|
||||
switch (true) {
|
||||
case is_object($item):
|
||||
$value = sprintf('<em>object</em>(%s)', parse_class(get_class($item)));
|
||||
break;
|
||||
case is_array($item):
|
||||
if (count($item) > 3) {
|
||||
$value = sprintf('[%s, ...]', parse_args(array_slice($item, 0, 3)));
|
||||
} else {
|
||||
$value = sprintf('[%s]', parse_args($item));
|
||||
}
|
||||
break;
|
||||
case is_string($item):
|
||||
if (strlen($item) > 20) {
|
||||
$value = sprintf(
|
||||
'\'<a class="toggle" title="%s">%s...</a>\'',
|
||||
htmlentities($item),
|
||||
htmlentities(substr($item, 0, 20))
|
||||
);
|
||||
} else {
|
||||
$value = sprintf("'%s'", htmlentities($item));
|
||||
}
|
||||
break;
|
||||
case is_int($item):
|
||||
case is_float($item):
|
||||
$value = $item;
|
||||
break;
|
||||
case is_null($item):
|
||||
$value = '<em>null</em>';
|
||||
break;
|
||||
case is_bool($item):
|
||||
$value = '<em>' . ($item ? 'true' : 'false') . '</em>';
|
||||
break;
|
||||
case is_resource($item):
|
||||
$value = '<em>resource</em>';
|
||||
break;
|
||||
default:
|
||||
$value = htmlentities(str_replace("\n", '', var_export(strval($item), true)));
|
||||
break;
|
||||
}
|
||||
|
||||
$result[] = is_int($key) ? $value : "'{$key}' => {$value}";
|
||||
}
|
||||
|
||||
return implode(', ', $result);
|
||||
}
|
||||
}
|
||||
if (!function_exists('echo_value')) {
|
||||
function echo_value($val)
|
||||
{
|
||||
if (is_array($val) || is_object($val)) {
|
||||
echo htmlentities(json_encode($val, JSON_PRETTY_PRINT));
|
||||
} elseif (is_bool($val)) {
|
||||
echo $val ? 'true' : 'false';
|
||||
} elseif (is_scalar($val)) {
|
||||
echo htmlentities($val);
|
||||
} else {
|
||||
echo 'Resource';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>系统发生错误</title>
|
||||
<meta name="robots" content="noindex,nofollow"/>
|
||||
<style>
|
||||
/* Base */
|
||||
body {
|
||||
color: #333;
|
||||
font: 16px Verdana, "Helvetica Neue", helvetica, Arial, 'Microsoft YaHei', sans-serif;
|
||||
margin: 0;
|
||||
padding: 0 20px 20px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 10px 0 0;
|
||||
font-size: 28px;
|
||||
font-weight: 500;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: #4288ce;
|
||||
font-weight: 400;
|
||||
padding: 6px 0;
|
||||
margin: 6px 0 0;
|
||||
font-size: 18px;
|
||||
border-bottom: 1px solid #eee;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 12px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
abbr {
|
||||
cursor: help;
|
||||
text-decoration: underline;
|
||||
text-decoration-style: dotted;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #868686;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.line-error {
|
||||
background: #f8cbcb;
|
||||
}
|
||||
|
||||
.echo table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.echo pre {
|
||||
padding: 16px;
|
||||
overflow: auto;
|
||||
font-size: 85%;
|
||||
line-height: 1.45;
|
||||
background-color: #f7f7f7;
|
||||
border: 0;
|
||||
border-radius: 3px;
|
||||
font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
||||
}
|
||||
|
||||
.echo pre > pre {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Exception Info */
|
||||
.exception {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.exception .message {
|
||||
padding: 12px;
|
||||
border: 1px solid #ddd;
|
||||
border-bottom: 0 none;
|
||||
line-height: 18px;
|
||||
font-size: 16px;
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
font-family: Consolas, "Liberation Mono", Courier, Verdana, "微软雅黑", serif;
|
||||
}
|
||||
|
||||
.exception .code {
|
||||
float: left;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
margin-right: 12px;
|
||||
padding: 16px;
|
||||
border-radius: 4px;
|
||||
background: #999;
|
||||
}
|
||||
|
||||
.exception .source-code {
|
||||
padding: 6px;
|
||||
border: 1px solid #ddd;
|
||||
|
||||
background: #f9f9f9;
|
||||
overflow-x: auto;
|
||||
|
||||
}
|
||||
|
||||
.exception .source-code pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.exception .source-code pre ol {
|
||||
margin: 0;
|
||||
color: #4288ce;
|
||||
display: inline-block;
|
||||
min-width: 100%;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
font-family: "Century Gothic", Consolas, "Liberation Mono", Courier, Verdana, serif;
|
||||
padding-left: <?php echo (isset($source) && ! empty($source)) ? parse_padding($source): 40;?> px;
|
||||
}
|
||||
|
||||
.exception .source-code pre li {
|
||||
border-left: 1px solid #ddd;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.exception .source-code pre code {
|
||||
color: #333;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
border-left: 1px solid #fff;
|
||||
font-size: 14px;
|
||||
font-family: Consolas, "Liberation Mono", Courier, Verdana, "微软雅黑", serif;
|
||||
}
|
||||
|
||||
.exception .trace {
|
||||
padding: 6px;
|
||||
border: 1px solid #ddd;
|
||||
border-top: 0 none;
|
||||
line-height: 16px;
|
||||
font-size: 14px;
|
||||
font-family: Consolas, "Liberation Mono", Courier, Verdana, "微软雅黑", serif;
|
||||
}
|
||||
|
||||
.exception .trace h2:hover {
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.exception .trace ol {
|
||||
margin: 12px;
|
||||
}
|
||||
|
||||
.exception .trace ol li {
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
.exception div:last-child {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
/* Exception Variables */
|
||||
.exception-var table {
|
||||
width: 100%;
|
||||
margin: 12px 0;
|
||||
box-sizing: border-box;
|
||||
table-layout: fixed;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.exception-var table caption {
|
||||
text-align: left;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
.exception-var table caption small {
|
||||
font-weight: 300;
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.exception-var table tbody {
|
||||
font-size: 13px;
|
||||
font-family: Consolas, "Liberation Mono", Courier, "微软雅黑", serif;
|
||||
}
|
||||
|
||||
.exception-var table td {
|
||||
padding: 0 6px;
|
||||
vertical-align: top;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.exception-var table td:first-child {
|
||||
width: 28%;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.exception-var table td pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Copyright Info */
|
||||
.copyright {
|
||||
margin-top: 24px;
|
||||
padding: 12px 0;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
|
||||
/* SPAN elements with the classes below are added by prettyprint. */
|
||||
pre.prettyprint .pln {
|
||||
color: #000
|
||||
}
|
||||
|
||||
/* plain text */
|
||||
pre.prettyprint .str {
|
||||
color: #080
|
||||
}
|
||||
|
||||
/* string content */
|
||||
pre.prettyprint .kwd {
|
||||
color: #008
|
||||
}
|
||||
|
||||
/* a keyword */
|
||||
pre.prettyprint .com {
|
||||
color: #800
|
||||
}
|
||||
|
||||
/* a comment */
|
||||
pre.prettyprint .typ {
|
||||
color: #606
|
||||
}
|
||||
|
||||
/* a type name */
|
||||
pre.prettyprint .lit {
|
||||
color: #066
|
||||
}
|
||||
|
||||
/* a literal value */
|
||||
/* punctuation, lisp open bracket, lisp close bracket */
|
||||
pre.prettyprint .pun, pre.prettyprint .opn, pre.prettyprint .clo {
|
||||
color: #660
|
||||
}
|
||||
|
||||
pre.prettyprint .tag {
|
||||
color: #008
|
||||
}
|
||||
|
||||
/* a markup tag name */
|
||||
pre.prettyprint .atn {
|
||||
color: #606
|
||||
}
|
||||
|
||||
/* a markup attribute name */
|
||||
pre.prettyprint .atv {
|
||||
color: #080
|
||||
}
|
||||
|
||||
/* a markup attribute value */
|
||||
pre.prettyprint .dec, pre.prettyprint .var {
|
||||
color: #606
|
||||
}
|
||||
|
||||
/* a declaration; a variable name */
|
||||
pre.prettyprint .fun {
|
||||
color: red
|
||||
}
|
||||
|
||||
/* a function name */
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php if (\think\facade\App::isDebug()) { ?>
|
||||
<?php foreach ($traces as $index => $trace) { ?>
|
||||
<div class="exception">
|
||||
<div class="message">
|
||||
<div class="info">
|
||||
<div>
|
||||
<h2><?php echo "#{$index} [{$trace['code']}]" . sprintf('%s in %s', parse_class($trace['name']), parse_file($trace['file'], $trace['line'])); ?></h2>
|
||||
</div>
|
||||
<div><h1><?php echo nl2br(htmlentities($trace['message'])); ?></h1></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php if (!empty($trace['source'])) { ?>
|
||||
<div class="source-code">
|
||||
<pre class="prettyprint lang-php">
|
||||
<ol start="<?php echo $trace['source']['first']; ?>"><!--<?php foreach ((array)$trace['source']['source'] as $key => $value) { ?>--><li class="line-<?php echo " {$index}-" . ($key + $trace['source']['first']) . ($trace['line'] === $key + $trace['source']['first'] ? ' line-error' : ''); ?>"><code><?php echo htmlentities($value); ?></code></li><!--<?php } ?>--></ol>
|
||||
</pre>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<div class="trace">
|
||||
<h2 data-expand="<?php echo 0 === $index ? '1' : '0'; ?>">Call Stack</h2>
|
||||
<ol>
|
||||
<li><?php echo sprintf('in %s', parse_file($trace['file'], $trace['line'])); ?></li>
|
||||
<?php foreach ((array)$trace['trace'] as $value) { ?>
|
||||
<li>
|
||||
<?php
|
||||
// Show Function
|
||||
if ($value['function']) {
|
||||
echo sprintf('at %s%s%s(%s)', isset($value['class']) ? parse_class($value['class']) : '', $value['type'] ?? '', $value['function'], isset($value['args']) ? parse_args($value['args']) : '');
|
||||
}
|
||||
|
||||
// Show line
|
||||
if (isset($value['file']) && isset($value['line'])) {
|
||||
echo sprintf(' in %s', parse_file($value['file'], $value['line']));
|
||||
}
|
||||
?>
|
||||
</li>
|
||||
<?php } ?>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<?php } else { ?>
|
||||
<div class="exception">
|
||||
<div class="info"><h1><?php echo htmlentities(isset($message) ? $message : ''); ?></h1></div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<?php if (!empty($datas)) { ?>
|
||||
<div class="exception-var">
|
||||
<h2>Exception Datas</h2>
|
||||
<?php foreach ((array)$datas as $label => $value) { ?>
|
||||
<table>
|
||||
<?php if (empty($value)) { ?>
|
||||
<caption><?php echo $label; ?><small>empty</small></caption>
|
||||
<?php } else { ?>
|
||||
<caption><?php echo $label; ?></caption>
|
||||
<tbody>
|
||||
<?php foreach ((array)$value as $key => $val) { ?>
|
||||
<tr>
|
||||
<td><?php echo htmlentities($key); ?></td>
|
||||
<td><?php echo_value($val); ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
<?php } ?>
|
||||
</table>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<?php if (!empty($tables)) { ?>
|
||||
<div class="exception-var">
|
||||
<h2>Environment Variables</h2>
|
||||
<?php foreach ((array)$tables as $label => $value) { ?>
|
||||
<table>
|
||||
<?php if (empty($value)) { ?>
|
||||
<caption><?php echo $label; ?><small>empty</small></caption>
|
||||
<?php } else { ?>
|
||||
<caption><?php echo $label; ?></caption>
|
||||
<tbody>
|
||||
<?php foreach ((array)$value as $key => $val) { ?>
|
||||
<tr>
|
||||
<td><?php echo htmlentities($key); ?></td>
|
||||
<td><?php echo_value($val); ?></td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
<?php } ?>
|
||||
</table>
|
||||
<?php } ?>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<?php if (\think\facade\App::isDebug()) { ?>
|
||||
<script>
|
||||
function $(selector, node) {
|
||||
var elements;
|
||||
node = node || document;
|
||||
if (document.querySelectorAll) {
|
||||
elements = node.querySelectorAll(selector);
|
||||
} else {
|
||||
switch (selector.substr(0, 1)) {
|
||||
case '#':
|
||||
elements = [node.getElementById(selector.substr(1))];
|
||||
break;
|
||||
case '.':
|
||||
if (document.getElementsByClassName) {
|
||||
elements = node.getElementsByClassName(selector.substr(1));
|
||||
} else {
|
||||
elements = get_elements_by_class(selector.substr(1), node);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
elements = node.getElementsByTagName();
|
||||
}
|
||||
}
|
||||
return elements;
|
||||
|
||||
function get_elements_by_class(search_class, node, tag) {
|
||||
var elements = [], eles,
|
||||
pattern = new RegExp('(^|\\s)' + search_class + '(\\s|$)');
|
||||
|
||||
node = node || document;
|
||||
tag = tag || '*';
|
||||
|
||||
eles = node.getElementsByTagName(tag);
|
||||
for (var i = 0; i < eles.length; i++) {
|
||||
if (pattern.test(eles[i].className)) {
|
||||
elements.push(eles[i])
|
||||
}
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
}
|
||||
|
||||
$.getScript = function (src, func) {
|
||||
var script = document.createElement('script');
|
||||
|
||||
script.async = 'async';
|
||||
script.src = src;
|
||||
script.onload = func || function () {
|
||||
};
|
||||
|
||||
$('head')[0].appendChild(script);
|
||||
}
|
||||
|
||||
;(function () {
|
||||
var files = $('.toggle');
|
||||
var ol = $('ol', $('.prettyprint')[0]);
|
||||
var li = $('li', ol[0]);
|
||||
|
||||
// 短路径和长路径变换
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
files[i].ondblclick = function () {
|
||||
var title = this.title;
|
||||
|
||||
this.title = this.innerHTML;
|
||||
this.innerHTML = title;
|
||||
}
|
||||
}
|
||||
|
||||
(function () {
|
||||
var expand = function (dom, expand) {
|
||||
var ol = $('ol', dom.parentNode)[0];
|
||||
expand = undefined === expand ? dom.attributes['data-expand'].value === '0' : undefined;
|
||||
if (expand) {
|
||||
dom.attributes['data-expand'].value = '1';
|
||||
ol.style.display = 'none';
|
||||
dom.innerText = 'Call Stack (展开)';
|
||||
} else {
|
||||
dom.attributes['data-expand'].value = '0';
|
||||
ol.style.display = 'block';
|
||||
dom.innerText = 'Call Stack (折叠)';
|
||||
}
|
||||
};
|
||||
var traces = $('.trace');
|
||||
for (var i = 0; i < traces.length; i++) {
|
||||
var h2 = $('h2', traces[i])[0];
|
||||
expand(h2);
|
||||
h2.onclick = function () {
|
||||
expand(this);
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
$.getScript('//cdn.bootcss.com/prettify/r298/prettify.min.js', function () {
|
||||
prettyPrint();
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
<?php } ?>
|
||||
</body>
|
||||
</html>
|
||||
32
app/manager/view/full.html
Normal file
32
app/manager/view/full.html
Normal file
@@ -0,0 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<title>{block name="title"}{$title|default=''}{if !empty($title)} · {/if}{:sysconf('site_name')}{/block}</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="renderer" content="webkit">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=0.4">
|
||||
<link rel="stylesheet" href="__ROOT__/static/plugs/layui/css/layui.css?at={:date('md')}">
|
||||
<link rel="stylesheet" href="__ROOT__/static/theme/css/iconfont.css?at={:date('md')}">
|
||||
<link rel="stylesheet" href="__ROOT__/static/theme/css/console.css?at={:date('md')}">
|
||||
<link rel="stylesheet" href="__ROOT__/static/extra/style.css?at={:date('md')}">
|
||||
{block name="style"}{/block}
|
||||
<script src="__ROOT__/static/plugs/jquery/pace.min.js"></script>
|
||||
<script src="{:url('admin/api.plugs/script',[],false,false)}"></script>
|
||||
</head>
|
||||
<body class="layui-layout-body">
|
||||
{block name='body'}
|
||||
<div class="layui-layout layui-layout-admin layui-layout-left-hide">
|
||||
<div class="layui-body think-bg-white margin-0 padding-0" style="top:0">{block name='content'}{/block}</div>
|
||||
</div>
|
||||
{/block}
|
||||
<script src="__ROOT__/static/plugs/layui/layui.js"></script>
|
||||
<script src="__ROOT__/static/plugs/require/require.js"></script>
|
||||
<script src="__ROOT__/static/admin.js"></script>
|
||||
<script src="__ROOT__/static/extra/script.js"></script>
|
||||
{block name='script'}{/block}
|
||||
</body>
|
||||
</html>
|
||||
16
app/manager/view/index/index.html
Normal file
16
app/manager/view/index/index.html
Normal file
@@ -0,0 +1,16 @@
|
||||
{extend name="main"}
|
||||
|
||||
{block name="content"}
|
||||
<div class="layui-fluid">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<div class="layui-col-md12">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">欢迎页面</div>
|
||||
<div class="layui-card-body">
|
||||
欢迎使用管理系统{$userid}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/block}
|
||||
23
app/manager/view/main.html
Normal file
23
app/manager/view/main.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<div class="layui-card">
|
||||
{block name='style'}{/block}
|
||||
{block name='header'}
|
||||
{notempty name='title'}
|
||||
<div class="layui-card-header">
|
||||
<span class="layui-icon font-s10 color-desc margin-right-5"></span>{$title|lang}
|
||||
<div class="pull-right">{block name='button'}{/block}</div>
|
||||
</div>
|
||||
{/notempty}
|
||||
{/block}
|
||||
<div class="layui-card-line"></div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-card-html">
|
||||
{notempty name='showErrorMessage'}
|
||||
<div class="think-box-notify" type="error">
|
||||
<b>{:lang('系统提示:')}</b><span>{$showErrorMessage|raw}</span>
|
||||
</div>
|
||||
{/notempty}
|
||||
{block name='content'}{/block}
|
||||
</div>
|
||||
</div>
|
||||
{block name='script'}{/block}
|
||||
</div>
|
||||
74
app/manager/view/member/form.html
Normal file
74
app/manager/view/member/form.html
Normal file
@@ -0,0 +1,74 @@
|
||||
{extend name='../../admin/view/main'}
|
||||
|
||||
{block name='content'}
|
||||
<form class="layui-form" action="{:sysuri()}" data-auto="true" method="post" autocomplete="off" onsubmit="return false" lay-filter="FormData">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">邮箱</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="email" value='{$member.email|default=""}' required lay-verify="required|email" placeholder="请输入邮箱" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">闲鱼订单号</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="order_id" value='{$member.order_id|default=""}' required lay-verify="required" placeholder="请输入闲鱼订单号" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">有效期</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="expire_time" value='{$member.expire_time|default=""}' required lay-verify="required" placeholder="请选择有效期" class="layui-input" id="expire_time">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">可用次数</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="usage_limit" value='{$member.usage_limit|default="0"}' required lay-verify="required|number" placeholder="请输入可用次数" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">已用次数</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="number" name="used_count" value='{$member.used_count|default="0"}' lay-verify="number" placeholder="请输入已用次数" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" value="1" title="正常" {if !isset($member.status) or $member.status eq 1}checked{/if}>
|
||||
<input type="radio" name="status" value="0" title="禁用" {if isset($member.status) and $member.status eq 0}checked{/if}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
||||
<div class="layui-form-item text-center">
|
||||
{notempty name='member.id'}<input type='hidden' value='{$member.id}' name='id'>{/notempty}
|
||||
<button class="layui-btn" type="submit" lay-submit lay-filter="*">保存数据</button>
|
||||
<button type="reset" class="layui-btn layui-btn-primary">重置数据</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{/block}
|
||||
|
||||
{block name='script'}
|
||||
<script>
|
||||
layui.use(['form', 'laydate'], function(){
|
||||
var form = layui.form;
|
||||
|
||||
// 渲染日期时间选择器
|
||||
layui.laydate.render({
|
||||
elem: '#expire_time',
|
||||
type: 'datetime'
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
92
app/manager/view/member/index.html
Normal file
92
app/manager/view/member/index.html
Normal file
@@ -0,0 +1,92 @@
|
||||
{extend name='../../admin/view/main'}
|
||||
|
||||
{block name='button'}
|
||||
<!-- 表格工具栏 -->
|
||||
<div class="layui-btn-container">
|
||||
<button class='layui-btn layui-btn-sm layui-btn-primary' data-modal='{:url("add")}' data-width="800px" data-height="600px">添加会员</button>
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{block name='content'}
|
||||
<div class="think-box-shadow">
|
||||
<form class="layui-form layui-form-pane form-search" action="">
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">搜索</label>
|
||||
<div class="layui-input-inline">
|
||||
<input name="keyword" value="{$get.keyword|default=''}" placeholder="请输入邮箱/订单号" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="status">
|
||||
<option value=''>-- 全部 --</option>
|
||||
<option value='1'>正常</option>
|
||||
<option value='0'>禁用</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<button class="layui-btn layui-btn-primary" lay-submit lay-filter="search"><i class="layui-icon"></i> 搜 索</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<table id="TableList" lay-filter="TableList"></table>
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{block name='script'}
|
||||
<script type="text/html" id="toolbar">
|
||||
<a class="layui-btn layui-btn-sm" data-modal='{:url("edit")}?id={{d.id}}' data-width="800px" data-height="600px">编辑</a>
|
||||
|
||||
<a class="layui-btn layui-btn-sm layui-btn-danger" data-confirm="确定要删除此会员吗?" data-action='{:url("remove")}' data-value="id#{{d.id}}">删除</a>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['table','form'], function(){
|
||||
var table = layui.table;
|
||||
var form = layui.form;
|
||||
|
||||
// 表格渲染
|
||||
table.render({
|
||||
elem: '#TableList'
|
||||
,url: '{:sysuri()}?output=layui.table'
|
||||
,page: true
|
||||
,cellMinWidth: 200
|
||||
,cols: [[
|
||||
{field: 'id', title: 'ID', width: 70, align: 'center'},
|
||||
{field: 'email', title: '邮箱', minWidth: 80},
|
||||
{field: 'order_id', title: '闲鱼订单号', minWidth: 100},
|
||||
{field: 'expire_time', title: '有效期', minWidth: 100},
|
||||
{field: 'usage_limit', title: '可用次数', width: 70, align: 'center'},
|
||||
{field: 'used_count', title: '已用次数', width: 70, align: 'center'},
|
||||
{field: 'last_login_time', title: '最后登录时间', minWidth: 100},
|
||||
{field: 'status', title: '状态', width: 100, align: 'center', templet: function(d){
|
||||
return '<input type="checkbox" name="status" value="'+d.id+'" lay-skin="switch" lay-text="正常|禁用" lay-filter="statusSwitch" '+(d.status == 1 ? 'checked' : '')+'>';
|
||||
}},
|
||||
{field: 'create_time', title: '创建时间', minWidth: 180},
|
||||
{title: '操作', toolbar: '#toolbar', width: 250, align: 'center', fixed: 'right'}
|
||||
]]
|
||||
});
|
||||
|
||||
// 搜索提交
|
||||
form.on('submit(search)', function(data){
|
||||
table.reload('TableList', {where: data.field});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 监听状态切换
|
||||
form.on('switch(statusSwitch)', function(obj){
|
||||
let id = this.value;
|
||||
let status = obj.elem.checked ? 1 : 0;
|
||||
$.post('{:url("state")}', {id: id, status: status}, function(res){
|
||||
if (res.code != 1) {
|
||||
obj.elem.checked = !obj.elem.checked;
|
||||
form.render('checkbox');
|
||||
layer.msg(res.info, {icon: 2});
|
||||
}
|
||||
}, 'json');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
32
app/manager/view/member/index_search.html
Normal file
32
app/manager/view/member/index_search.html
Normal file
@@ -0,0 +1,32 @@
|
||||
{if isset($list)}
|
||||
<fieldset>
|
||||
<legend>条件搜索</legend>
|
||||
<form class="layui-form layui-form-pane form-search" action="{:request()->url()}" onsubmit="return false" method="get" autocomplete="off">
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">搜索关键词</label>
|
||||
<div class="layui-input-inline">
|
||||
<input name="keyword" value="{$get.keyword|default=''}" placeholder="请输入用户名/昵称/手机/邮箱" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">会员状态</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="status">
|
||||
<option value=''>-- 全部状态 --</option>
|
||||
<option value='1' {if isset($get.status) and $get.status eq 1}selected{/if}>正常</option>
|
||||
<option value='0' {if isset($get.status) and $get.status eq 0}selected{/if}>禁用</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">注册时间</label>
|
||||
<div class="layui-input-inline">
|
||||
<input data-date-range name="create_time" value="{$get.create_time|default=''}" placeholder="请选择注册时间" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<button class="layui-btn layui-btn-primary"><i class="layui-icon"></i> 搜 索</button>
|
||||
</div>
|
||||
</form>
|
||||
</fieldset>
|
||||
{/if}
|
||||
294
app/manager/view/package/index.html
Normal file
294
app/manager/view/package/index.html
Normal file
@@ -0,0 +1,294 @@
|
||||
{extend name="../../admin/view/main"}
|
||||
|
||||
{block name='content'}
|
||||
<div class="think-box-shadow">
|
||||
<!-- 表单搜索 -->
|
||||
<form class="layui-form layui-form-pane form-search" action="">
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">包名</label>
|
||||
<div class="layui-input-inline">
|
||||
<input name="package_name" placeholder="请输入包名" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">应用名称</label>
|
||||
<div class="layui-input-inline">
|
||||
<input name="name" placeholder="请输入应用名称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="status">
|
||||
<option value="">所有状态</option>
|
||||
<option value="1">启用</option>
|
||||
<option value="0">禁用</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">创建人</label>
|
||||
<div class="layui-input-inline">
|
||||
<input name="username" placeholder="请输入创建人" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">添加时间</label>
|
||||
<div class="layui-input-inline">
|
||||
<input name="add_time" id="add_time" placeholder="请选择添加时间" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<button class="layui-btn layui-btn-primary" type="button" lay-submit lay-filter="search-btn">
|
||||
<i class="layui-icon"></i> 搜 索
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-primary" type="reset" id="resetSearch">重置</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- 数据表格 -->
|
||||
<table id="currentTable" lay-filter="currentTable"></table>
|
||||
</div>
|
||||
|
||||
<!-- 表单模板 -->
|
||||
<script type="text/html" id="editForm">
|
||||
<form class="layui-form" lay-filter="editForm" style="padding: 30px;">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="width: 100px;">应用名称</label>
|
||||
<div class="layui-input-block" style="margin-left: 130px;">
|
||||
<input type="text" name="name" lay-verify="required" placeholder="请输入应用名称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="width: 100px;">包名</label>
|
||||
<div class="layui-input-block" style="margin-left: 130px;">
|
||||
<input type="text" name="package_name" lay-verify="required" placeholder="请输入包名" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label" style="width: 100px;">状态</label>
|
||||
<div class="layui-input-block" style="margin-left: 130px;">
|
||||
<input type="radio" name="status" value="1" title="启用" checked>
|
||||
<input type="radio" name="status" value="0" title="禁用">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item text-center" style="margin-top: 40px;">
|
||||
<input type="hidden" name="id">
|
||||
<button class="layui-btn layui-btn-lg" lay-submit lay-filter="formSubmit">保存</button>
|
||||
<button type="button" class="layui-btn layui-btn-lg layui-btn-danger" onclick="layer.closeAll()">取消</button>
|
||||
</div>
|
||||
</form>
|
||||
</script>
|
||||
{/block}
|
||||
|
||||
{block name='script'}
|
||||
<!-- 表格操作列 -->
|
||||
<script type="text/html" id="toolbar">
|
||||
<div class="layui-btn-container">
|
||||
{if auth("edit")}
|
||||
<a class="layui-btn layui-btn-sm" lay-event="edit">编辑</a>
|
||||
{/if}
|
||||
{if auth("remove")}
|
||||
<a class="layui-btn layui-btn-sm layui-btn-danger" lay-event="delete">删除</a>
|
||||
{/if}
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script>
|
||||
layui.use(['table', 'form', 'laydate'], function () {
|
||||
var table = layui.table;
|
||||
var form = layui.form;
|
||||
var laydate = layui.laydate;
|
||||
|
||||
// 日期范围
|
||||
laydate.render({
|
||||
elem: '#add_time',
|
||||
type: 'date',
|
||||
range: true,
|
||||
trigger: 'click'
|
||||
});
|
||||
|
||||
// 数据表格初始化
|
||||
table.render({
|
||||
elem: '#currentTable',
|
||||
url: '{:request()->url()}',
|
||||
method: 'post',
|
||||
defaultToolbar: ['filter', 'print', 'exports'],
|
||||
toolbar: ['<div class="layui-btn-container">',
|
||||
'{if auth("add")}',
|
||||
'<button class="layui-btn layui-btn-sm layui-btn-normal" lay-event="add"><i class="layui-icon"></i> 添加包名</button>',
|
||||
'{/if}',
|
||||
'</div>'
|
||||
].join(''),
|
||||
cols: [[
|
||||
{type: "checkbox"},
|
||||
{field: 'id', width: 80, title: 'ID', sort: true},
|
||||
{field: 'name', minWidth: 150, title: '应用名称'},
|
||||
{field: 'package_name', minWidth: 200, title: '包名'},
|
||||
{field: 'username', width: 100, title: '创建人'},
|
||||
{field: 'status', width: 100, title: '状态', templet: function(d){
|
||||
return '<input type="checkbox" name="status" value="' + d.id + '" lay-skin="switch" lay-text="启用|禁用" lay-filter="status" ' + (d.status == 1 ? 'checked' : '') + '>';
|
||||
}},
|
||||
{field: 'add_time', minWidth: 170, title: '添加时间', templet: function(d){
|
||||
return d.add_time ? layui.util.toDateString(d.add_time * 1000, 'yyyy-MM-dd HH:mm:ss') : '';
|
||||
}},
|
||||
{field: 'update_time', minWidth: 170, title: '更新时间', templet: function(d){
|
||||
return d.update_time ? layui.util.toDateString(d.update_time * 1000, 'yyyy-MM-dd HH:mm:ss') : '';
|
||||
}},
|
||||
{title: '操作', minWidth: 120, toolbar: '#toolbar', align: "center", fixed: 'right'}
|
||||
]],
|
||||
page: true,
|
||||
limit: 15,
|
||||
limits: [10, 15, 20, 25, 50, 100]
|
||||
});
|
||||
|
||||
// 搜索提交
|
||||
form.on('submit(search-btn)', function (data) {
|
||||
table.reload('currentTable', {
|
||||
page: {curr: 1},
|
||||
where: data.field,
|
||||
method: 'post'
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 重置搜索
|
||||
$('#resetSearch').click(function() {
|
||||
// 重置表单
|
||||
$('.form-search')[0].reset();
|
||||
// 重载表格
|
||||
table.reload('currentTable', {
|
||||
page: {curr: 1},
|
||||
where: {},
|
||||
method: 'post'
|
||||
});
|
||||
});
|
||||
|
||||
// 监听表单提交
|
||||
form.on('submit(formSubmit)', function (data) {
|
||||
var url = data.field.id ? '{:url("edit")}' : '{:url("add")}';
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'post',
|
||||
data: data.field,
|
||||
success: function(res) {
|
||||
if (res.code === 1) {
|
||||
layer.closeAll();
|
||||
layer.msg(res.info, {icon: 1, time: 1000});
|
||||
table.reload('currentTable');
|
||||
} else {
|
||||
layer.msg(res.info, {icon: 2, time: 2000});
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
layer.msg('网络错误,请稍后重试!', {icon: 2, time: 2000});
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 监听工具条
|
||||
table.on('tool(currentTable)', function (obj) {
|
||||
var data = obj.data;
|
||||
if (obj.event === 'edit') {
|
||||
showForm('编辑包名', data);
|
||||
} else if (obj.event === 'delete') {
|
||||
layer.confirm('确定要删除该包名吗?', {
|
||||
title: '删除确认',
|
||||
btn: ['确定', '取消']
|
||||
}, function (index) {
|
||||
$.ajax({
|
||||
url: '{:url("remove")}',
|
||||
type: 'post',
|
||||
data: {id: data.id},
|
||||
success: function(res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.info, {icon: 1, time: 1000});
|
||||
table.reload('currentTable');
|
||||
} else {
|
||||
layer.msg(res.info, {icon: 2, time: 2000});
|
||||
}
|
||||
layer.close(index);
|
||||
},
|
||||
error: function() {
|
||||
layer.msg('网络错误,请稍后重试!', {icon: 2, time: 2000});
|
||||
layer.close(index);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 监听头工具栏事件
|
||||
table.on('toolbar(currentTable)', function(obj){
|
||||
if(obj.event === 'add'){
|
||||
showForm('添加包名');
|
||||
}
|
||||
});
|
||||
|
||||
// 显示表单
|
||||
function showForm(title, data) {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: title,
|
||||
area: ['800px', '500px'],
|
||||
offset: '50px',
|
||||
shadeClose: true,
|
||||
content: $('#editForm').html(),
|
||||
success: function(layero, index) {
|
||||
$(layero).find('.layui-form').css('margin', '15px');
|
||||
$(layero).find('.layui-input-block').css('max-width', '500px');
|
||||
|
||||
form.render();
|
||||
if(data) {
|
||||
form.val('editForm', data);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 监听状态切换
|
||||
form.on('switch(status)', function(obj){
|
||||
var id = this.value;
|
||||
var status = obj.elem.checked ? 1 : 0;
|
||||
|
||||
layer.confirm('确定要' + (status == 1 ? '启用' : '禁用') + '该包名吗?', {
|
||||
title: '操作确认',
|
||||
btn: ['确定', '取消']
|
||||
}, function(index){
|
||||
$.ajax({
|
||||
url: '{:url("state")}',
|
||||
type: 'post',
|
||||
data: {
|
||||
id: id,
|
||||
status: status
|
||||
},
|
||||
success: function(res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.info, {icon: 1, time: 1000});
|
||||
table.reload('currentTable');
|
||||
} else {
|
||||
layer.msg(res.info, {icon: 2, time: 2000});
|
||||
// 状态切换失败,恢复开关状态
|
||||
obj.elem.checked = !obj.elem.checked;
|
||||
form.render('checkbox');
|
||||
}
|
||||
layer.close(index);
|
||||
},
|
||||
error: function() {
|
||||
layer.msg('网络错误,请稍后重试!2', {icon: 2, time: 2000});
|
||||
// 发生错误,恢复开关状态
|
||||
obj.elem.checked = !obj.elem.checked;
|
||||
form.render('checkbox');
|
||||
layer.close(index);
|
||||
}
|
||||
});
|
||||
}, function(){
|
||||
// 取消操作,恢复开关状态
|
||||
obj.elem.checked = !obj.elem.checked;
|
||||
form.render('checkbox');
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
451
app/manager/view/package_auth/auth_detail.html
Normal file
451
app/manager/view/package_auth/auth_detail.html
Normal file
@@ -0,0 +1,451 @@
|
||||
<!-- 权限详情弹窗模板 -->
|
||||
<div class="detail-container" style="padding: 20px;" data-user-id="{{d.userId}}">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<!-- 左侧已授权包名列表 -->
|
||||
<div class="layui-col-md6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
授权的包名列表
|
||||
<div class="layui-inline" style="width: 200px; margin-left: 10px;">
|
||||
<input type="text" id="searchAuthorized" placeholder="输入包名或应用名称搜索" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body auth-table-container">
|
||||
<table id="authorizedTable" lay-filter="authorizedTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧可授权包名列表 -->
|
||||
<div class="layui-col-md6">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
可授权的包名列表
|
||||
<span class="layui-badge layui-bg-blue">仅显示启用状态的包名</span>
|
||||
<div class="layui-inline" style="width: 200px; margin-left: 10px;">
|
||||
<input type="text" id="searchPackage" placeholder="输入包名或应用名称搜索" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body auth-table-container">
|
||||
<table id="unauthorizedTable" lay-filter="unauthorizedTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部按钮 -->
|
||||
<div class="layui-form-item text-center" style="margin-top:15px;">
|
||||
<button class="layui-btn layui-btn-primary" onclick="closeAndRefresh()">关闭窗口</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 已授权表格工具栏 -->
|
||||
<script type="text/html" id="authDetailAuthorizedToolbar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="batchRemove" lay-tips="移除选中的包名权限">
|
||||
<i class="layui-icon"></i> 批量移除
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="removeAll" lay-tips="移除该管理员的所有包名权限">
|
||||
<i class="layui-icon"></i> 一键全部移除
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 未授权表格工具栏 -->
|
||||
<script type="text/html" id="authDetailUnauthorizedToolbar">
|
||||
<div class="layui-btn-container">
|
||||
<button class="layui-btn layui-btn-sm layui-btn-normal" lay-event="batchAuth" lay-tips="授权选中的包名">
|
||||
<i class="layui-icon"></i> 批量授权
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-sm layui-btn-warm" lay-event="authAll" lay-tips="授权所有未授权的包名">
|
||||
<i class="layui-icon"></i> 一键全部授权
|
||||
</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- 表格行工具条 -->
|
||||
<script type="text/html" id="authDetailTableBar">
|
||||
<a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="remove">移除</a>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="authDetailUnAuthTableBar">
|
||||
<a class="layui-btn layui-btn-normal layui-btn-xs" lay-event="auth">授权</a>
|
||||
</script>
|
||||
|
||||
<!-- 表格初始化脚本 -->
|
||||
<script>
|
||||
window.initAuthDetailTables = function(userId) {
|
||||
layui.use(['table', 'form'], function() {
|
||||
let table = layui.table;
|
||||
|
||||
// 初始化已授权表格
|
||||
table.render({
|
||||
elem: '#authorizedTable',
|
||||
url: '{:url("getAuthDetailData")}',
|
||||
where: {
|
||||
user_id: userId,
|
||||
type: 'authorized'
|
||||
},
|
||||
toolbar: '#authDetailAuthorizedToolbar',
|
||||
defaultToolbar: ['filter'],
|
||||
page: true,
|
||||
limit: 10,
|
||||
limits: [10, 20, 50, 100],
|
||||
cols: [[
|
||||
{type: 'checkbox', width: 50},
|
||||
{field: 'package_name', title: '包名', minWidth: 250},
|
||||
{field: 'name', title: '名称', minWidth: 200},
|
||||
{field: 'create_at', title: '授权时间', width: 160},
|
||||
{title: '操作', toolbar: '#authDetailTableBar', width: 80, align: 'center', fixed: 'right'}
|
||||
]]
|
||||
});
|
||||
|
||||
// 初始化未授权表格
|
||||
table.render({
|
||||
elem: '#unauthorizedTable',
|
||||
url: '{:url("getAuthDetailData")}',
|
||||
where: {
|
||||
user_id: userId,
|
||||
type: 'unauthorized'
|
||||
},
|
||||
toolbar: '#authDetailUnauthorizedToolbar',
|
||||
defaultToolbar: ['filter'],
|
||||
page: true,
|
||||
limit: 10,
|
||||
limits: [10, 20, 50, 100],
|
||||
cols: [[
|
||||
{type: 'checkbox', width: 50},
|
||||
{field: 'package_name', title: '包名', minWidth: 250},
|
||||
{field: 'name', title: '名称', minWidth: 200},
|
||||
{title: '操作', toolbar: '#authDetailUnAuthTableBar', width: 80, align: 'center', fixed: 'right'}
|
||||
]]
|
||||
});
|
||||
|
||||
// 绑定搜索事件
|
||||
bindSearchEvents(table, userId);
|
||||
// 绑定工具条事件
|
||||
bindTableEvents(table, userId);
|
||||
});
|
||||
};
|
||||
|
||||
// 绑定搜索事件
|
||||
function bindSearchEvents(table, userId) {
|
||||
let searchTimeout;
|
||||
$('#searchAuthorized').on('input', function() {
|
||||
clearTimeout(searchTimeout);
|
||||
let value = this.value;
|
||||
searchTimeout = setTimeout(function() {
|
||||
table.reload('authorizedTable', {
|
||||
where: {
|
||||
user_id: userId,
|
||||
type: 'authorized',
|
||||
keyword: value
|
||||
},
|
||||
page: {curr: 1}
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
|
||||
$('#searchPackage').on('input', function() {
|
||||
clearTimeout(searchTimeout);
|
||||
let value = this.value;
|
||||
searchTimeout = setTimeout(function() {
|
||||
table.reload('unauthorizedTable', {
|
||||
where: {
|
||||
user_id: userId,
|
||||
type: 'unauthorized',
|
||||
keyword: value
|
||||
},
|
||||
page: {curr: 1}
|
||||
});
|
||||
}, 300);
|
||||
});
|
||||
}
|
||||
|
||||
// 绑定工具条事件
|
||||
function bindTableEvents(table, userId) {
|
||||
// 已授权表格工具条事件
|
||||
table.on('toolbar(authorizedTable)', function(obj) {
|
||||
if (obj.event === 'batchRemove') {
|
||||
let checkStatus = table.checkStatus('authorizedTable');
|
||||
if (checkStatus.data.length === 0) {
|
||||
layer.msg('请选择要移除的包名', {icon: 2});
|
||||
return;
|
||||
}
|
||||
|
||||
layer.confirm('确定要移除选中的 ' + checkStatus.data.length + ' 个包名权限吗?', {
|
||||
title: '批量移除确认',
|
||||
btn: ['确定移除', '取消操作'],
|
||||
skin: 'layer-danger'
|
||||
}, function(index) {
|
||||
let loadIndex = layer.load(2);
|
||||
let packageIds = checkStatus.data.map(item => item.id);
|
||||
$.post('{:url("batchRemoveAuth")}', {
|
||||
user_id: userId,
|
||||
package_ids: packageIds
|
||||
}, function(res) {
|
||||
layer.close(loadIndex);
|
||||
layer.msg(res.info);
|
||||
if (res.code === 1) {
|
||||
// 刷新两个表格
|
||||
table.reload('authorizedTable');
|
||||
table.reload('unauthorizedTable');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
} else if (obj.event === 'removeAll') {
|
||||
layer.confirm('确定要移除该管理员的所有包名权限吗?<br>此操作不可恢复!', {
|
||||
title: '危险操作',
|
||||
btn: ['确定移除', '取消操作'],
|
||||
icon: 2,
|
||||
skin: 'layer-danger'
|
||||
}, function(index) {
|
||||
let loadIndex = layer.load(2);
|
||||
$.post('{:url("clearAuth")}', {
|
||||
user_ids: [userId]
|
||||
}, function(res) {
|
||||
layer.close(loadIndex);
|
||||
layer.msg(res.info);
|
||||
if (res.code === 1) {
|
||||
// 刷新两个表格
|
||||
table.reload('authorizedTable');
|
||||
table.reload('unauthorizedTable');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 未授权表格工具条事件
|
||||
table.on('toolbar(unauthorizedTable)', function(obj) {
|
||||
if (obj.event === 'batchAuth') {
|
||||
let checkStatus = table.checkStatus('unauthorizedTable');
|
||||
if (checkStatus.data.length === 0) {
|
||||
layer.msg('请选择要授权的包名', {icon: 2});
|
||||
return;
|
||||
}
|
||||
|
||||
layer.confirm('确定要授权选中的 ' + checkStatus.data.length + ' 个包名吗?', {
|
||||
title: '批量授权确认',
|
||||
btn: ['确定授权', '取消操作']
|
||||
}, function(index) {
|
||||
let loadIndex = layer.load(2);
|
||||
let packageIds = checkStatus.data.map(item => item.id);
|
||||
$.post('{:url("addAuth")}', {
|
||||
user_id: userId,
|
||||
package_ids: packageIds
|
||||
}, function(res) {
|
||||
layer.close(loadIndex);
|
||||
layer.msg(res.info);
|
||||
if (res.code === 1) {
|
||||
// 刷新两个表格
|
||||
table.reload('authorizedTable');
|
||||
table.reload('unauthorizedTable');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
} else if (obj.event === 'authAll') {
|
||||
layer.confirm('确定要授权所有可用的包名吗?', {
|
||||
title: '一键全部授权',
|
||||
btn: ['确定授权', '取消操作'],
|
||||
icon: 3
|
||||
}, function(index) {
|
||||
let loadIndex = layer.load(2);
|
||||
$.post('{:url("addAuth")}', {
|
||||
user_id: userId,
|
||||
is_all: 1
|
||||
}, function(res) {
|
||||
layer.close(loadIndex);
|
||||
layer.msg(res.info);
|
||||
if (res.code === 1) {
|
||||
// 刷新两个表格
|
||||
table.reload('authorizedTable');
|
||||
table.reload('unauthorizedTable');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 单个移除事件
|
||||
table.on('tool(authorizedTable)', function(obj) {
|
||||
if (obj.event === 'remove') {
|
||||
layer.confirm('确定要移除此包名权限吗?', function(index) {
|
||||
let loadIndex = layer.load(2);
|
||||
$.post('{:url("removeAuth")}', {
|
||||
user_id: userId,
|
||||
package_id: obj.data.id
|
||||
}, function(res) {
|
||||
layer.close(loadIndex);
|
||||
layer.msg(res.info);
|
||||
if (res.code === 1) {
|
||||
obj.del();
|
||||
// 刷新未授权表格
|
||||
table.reload('unauthorizedTable');
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 单个授权事件
|
||||
table.on('tool(unauthorizedTable)', function(obj) {
|
||||
if (obj.event === 'auth') {
|
||||
let loadIndex = layer.load(2);
|
||||
$.post('{:url("addAuth")}', {
|
||||
user_id: userId,
|
||||
package_ids: [obj.data.id]
|
||||
}, function(res) {
|
||||
layer.close(loadIndex);
|
||||
layer.msg(res.info);
|
||||
if (res.code === 1) {
|
||||
// 刷新两个表格
|
||||
table.reload('authorizedTable');
|
||||
table.reload('unauthorizedTable');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 添加关闭并刷新的函数
|
||||
function closeAndRefresh() {
|
||||
// 关闭当前弹窗
|
||||
layer.closeAll();
|
||||
// 刷新父页面
|
||||
parent.location.reload();
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- 弹窗专用样式 -->
|
||||
<style>
|
||||
.detail-container {
|
||||
min-height: 600px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.detail-container .layui-row {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.detail-container .layui-card {
|
||||
margin-bottom: 0;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.detail-container .layui-card-body {
|
||||
flex: 1;
|
||||
padding: 15px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.auth-table-container {
|
||||
min-height: 550px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* 搜索框样式 */
|
||||
.detail-container .layui-inline {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.detail-container .layui-input {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
|
||||
/* 底部按钮样式 */
|
||||
.detail-container .layui-form-item.text-center {
|
||||
padding: 10px 0 0;
|
||||
margin: 0;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
/* 表格美化样式 */
|
||||
.auth-table-container .layui-table-tool {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.auth-table-container .layui-table-page {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
/* 表格头部样式 */
|
||||
.auth-table-container .layui-table-header {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
/* 表格内容区域样式 */
|
||||
.auth-table-container .layui-table-body {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
/* 工具栏按钮样式优化 */
|
||||
.auth-table-container .layui-table-tool {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.auth-table-container .layui-table-tool .layui-btn {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0 15px;
|
||||
font-size: 12px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.auth-table-container .layui-table-tool .layui-btn:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.auth-table-container .layui-table-tool .layui-btn .layui-icon {
|
||||
font-size: 14px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
/* 危险操作按钮样式 */
|
||||
.auth-table-container .layui-table-tool .layui-btn-danger {
|
||||
background-color: #FF5722;
|
||||
}
|
||||
|
||||
.auth-table-container .layui-table-tool .layui-btn-danger:hover {
|
||||
background-color: #ff4208;
|
||||
}
|
||||
|
||||
/* 一键全部授权按钮样式 */
|
||||
.auth-table-container .layui-table-tool .layui-btn-warm {
|
||||
background-color: #FFB800;
|
||||
}
|
||||
|
||||
.auth-table-container .layui-table-tool .layui-btn-warm:hover {
|
||||
background-color: #ff9900;
|
||||
}
|
||||
|
||||
/* 弹窗样式 */
|
||||
.layer-danger .layui-layer-title {
|
||||
background-color: #FF5722 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.layer-danger .layui-layer-btn0 {
|
||||
background-color: #FF5722 !important;
|
||||
border-color: #FF5722 !important;
|
||||
}
|
||||
|
||||
/* 确保弹窗控制按钮在正确位置 */
|
||||
.layui-layer-page .layui-layer-setwin {
|
||||
position: absolute !important;
|
||||
right: 15px !important;
|
||||
top: 16px !important;
|
||||
}
|
||||
</style>
|
||||
786
app/manager/view/package_auth/index.html
Normal file
786
app/manager/view/package_auth/index.html
Normal file
@@ -0,0 +1,786 @@
|
||||
{extend name="../../admin/view/main"}
|
||||
|
||||
{block name='content'}
|
||||
<style>
|
||||
/* 基础样式 */
|
||||
.layui-card-body {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.layui-table-tool {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.layui-table-page {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.layui-table-box {
|
||||
background: #fff;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,.1);
|
||||
}
|
||||
|
||||
/* 时间选择器样式 */
|
||||
#dateRange {
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.layui-inline .layui-input {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.layui-inline .layui-btn {
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- 在主容器前添加操作指南 -->
|
||||
<div class="think-box-shadow" style="margin-bottom: 15px; padding: 15px;">
|
||||
<h3 class="layui-inline" style="margin-right: 15px;">操作指南</h3>
|
||||
<button class="layui-btn layui-btn-sm" id="showGuide">展开/收起</button>
|
||||
<div class="guide-content layui-hide" style="margin-top: 10px;">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-elem-quote" style="border-left: 5px solid #009688;">
|
||||
<h4>基本说明:</h4>
|
||||
<p>本页面用于管理不同管理员的包名权限,可以进行查看、添加、移除等操作。</p>
|
||||
</div>
|
||||
|
||||
<div class="layui-elem-quote" style="border-left: 5px solid #FFB800;">
|
||||
<h4>操作步骤:</h4>
|
||||
<ol>
|
||||
<li>左侧列表显示所有可配置权限的管理员</li>
|
||||
<li>绿色标签表示已授权包名数量,灰色表示未授权</li>
|
||||
<li>点击【查看权限】可以查看和修改该管理员的包名权限</li>
|
||||
<li>击【批量授权】可以同时给多个管理员授权相同的包名</li>
|
||||
<li>点击【清空权限】可以清除选中管理员的所有包名权限</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="layui-elem-quote" style="border-left: 5px solid #FF5722;">
|
||||
<h4>权限配置窗口说明:</h4>
|
||||
<ol>
|
||||
<li>左侧显示已授权的包名列表,可以搜索和移除</li>
|
||||
<li>右侧显示可授权的包名列表,仅显示启用状态的包名</li>
|
||||
<li>在右侧勾选包名后点击【保存配置】即可添加授权</li>
|
||||
<li>两侧都支持搜索功能,可以快速查找包名</li>
|
||||
<li>所有操作都会实时更新显示结果</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="layui-elem-quote" style="border-left: 5px solid #01AAED;">
|
||||
<h4>注意事项:</h4>
|
||||
<ol>
|
||||
<li>批量授权会覆盖已有的权限配置,请谨慎操作</li>
|
||||
<li>清空权限操作不可恢复,请确认后再操作</li>
|
||||
<li>建议先使用搜索功能查找包名,再进行授权作</li>
|
||||
<li>可以使用全选功能快速选择多个管理员或包名</li>
|
||||
<li>如有疑问请联系技术支持</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="think-box-shadow main-container">
|
||||
<div class="layui-row layui-col-space15">
|
||||
<!-- 左侧管理员列表 -->
|
||||
<div class="layui-col-md3">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
管理员列表
|
||||
<div class="layui-layout-right" style="margin:5px;">
|
||||
<span class="layui-badge layui-bg-blue" style="padding: 5px 10px;">共 {$users|count} 人</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body user-list-container">
|
||||
<form class="layui-form" lay-filter="userForm">
|
||||
<!-- 添加搜索框 -->
|
||||
<div class="search-box">
|
||||
<div class="layui-form-item" style="margin-bottom: 10px;">
|
||||
<div class="layui-input-block" style="margin-left: 0;">
|
||||
<input type="text" id="searchUsers" placeholder="输入管理员名称搜索" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 全选复选框 -->
|
||||
<div class="layui-form-item" style="padding: 10px;">
|
||||
<input type="checkbox" lay-filter="checkAllUsers" title="全选" lay-skin="primary" lay-tips="选中/取消选中所有管理员">
|
||||
</div>
|
||||
|
||||
<!-- 管理员列表 -->
|
||||
<div class="user-list">
|
||||
{foreach $users as $user}
|
||||
<div class="layui-form-item">
|
||||
<input type="checkbox" name="user_ids[]" value="{$user.id}" title="{$user.username}" lay-skin="primary">
|
||||
{if isset($authMap[$user.id])}
|
||||
<span class="layui-badge layui-bg-green" style="margin-left:10px; padding: 4px 8px;">已授权 {$authMap[$user.id]|count} 个包名</span>
|
||||
<a class="layui-btn layui-btn-normal layui-btn-sm" data-user="{$user.id}" lay-event="showAuth" style="margin-left:5px;" lay-tips="点击查看和修改该管理员的包名权限配置">
|
||||
<i class="layui-icon layui-icon-edit"></i> 查看权限
|
||||
</a>
|
||||
{else}
|
||||
<span class="layui-badge layui-bg-gray" style="margin-left:10px; padding: 4px 8px;">未授权</span>
|
||||
<a class="layui-btn layui-btn-warm layui-btn-sm" data-user="{$user.id}" lay-event="showAuth" style="margin-left:5px;" lay-tips="点击为该管理员添加包名权限">
|
||||
<i class="layui-icon layui-icon-add-1"></i> 添加权限
|
||||
</a>
|
||||
{/if}
|
||||
</div>
|
||||
{/foreach}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧包名列表 -->
|
||||
<div class="layui-col-md9">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-header">
|
||||
包名权限配置
|
||||
<div class="layui-layout-right header-btns">
|
||||
<button class="layui-btn layui-btn-normal" lay-submit lay-filter="batchAuth" lay-tips="选中管理员和包名后,点击此处进行批量授权操作">
|
||||
<i class="layui-icon layui-icon-add-circle"></i> 批量授权
|
||||
</button>
|
||||
<button class="layui-btn layui-btn-danger" id="clearAuth" lay-tips="清空选中管理员的所有包名权限,请谨慎操作">
|
||||
<i class="layui-icon layui-icon-delete"></i> 清空权限
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-card-body">
|
||||
<!-- 搜索框 -->
|
||||
<div class="layui-form-item" style="margin-bottom: 10px;">
|
||||
<div class="layui-inline" style="width: 250px;">
|
||||
<input type="text" id="searchPackages" placeholder="输入包名或应用名称搜索" class="layui-input">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<input type="text" id="dateRange" placeholder="选择时间范围" class="layui-input" readonly lay-tips="选择时间范围进行筛选">
|
||||
</div>
|
||||
<div class="layui-inline">
|
||||
<button class="layui-btn layui-btn-primary" id="resetFilter" lay-tips="清空所有筛选条件">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 表格 -->
|
||||
<table id="packageTable" lay-filter="packageTable"></table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 修改权限详情模板引用 -->
|
||||
<script type="text/html" id="authDetailTpl">
|
||||
{include file="package_auth/auth_detail"}
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
<!-- JavaScript 部分 -->
|
||||
<script>
|
||||
// 全局配置
|
||||
var CONFIG = {
|
||||
pageSize: 10,
|
||||
loadingTime: 1000,
|
||||
debounceDelay: 300
|
||||
};
|
||||
|
||||
// 消息提示
|
||||
var MSG = {
|
||||
networkError: '网络错误,请稍后重试!',
|
||||
selectAdmin: '请选择管理员',
|
||||
selectPackage: '请选择包名',
|
||||
confirmClear: '确定要清空权限吗?此操作不可恢复!',
|
||||
confirmBatchAuth: '确定要批量授权吗?<br>此操作将覆盖已有权限!',
|
||||
getUserFailed: '获取用户信息失败',
|
||||
authSuccess: '授权成功!',
|
||||
clearSuccess: '清空成功!'
|
||||
};
|
||||
|
||||
// 防抖函数
|
||||
function debounce(fn, delay) {
|
||||
let timer = null;
|
||||
return function() {
|
||||
let context = this, args = arguments;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(function() {
|
||||
fn.apply(context, args);
|
||||
}, delay);
|
||||
};
|
||||
}
|
||||
|
||||
// 成功提示
|
||||
function showSuccess(msg, callback) {
|
||||
layer.msg(msg, {
|
||||
icon: 1,
|
||||
time: CONFIG.loadingTime,
|
||||
shade: 0.3
|
||||
}, callback);
|
||||
}
|
||||
|
||||
// 错误提示
|
||||
function showError(msg) {
|
||||
layer.msg(msg, {
|
||||
icon: 2,
|
||||
time: 2000,
|
||||
shade: 0.3
|
||||
});
|
||||
}
|
||||
|
||||
// 表格事件处理对象
|
||||
var TableEventHandler = {
|
||||
// 工具条事件
|
||||
tool: function(obj, callback) {
|
||||
var event = obj.event;
|
||||
var handlers = {
|
||||
remove: function() {
|
||||
layer.confirm('确定要移除此包名权限吗?', {
|
||||
title: '操作确认',
|
||||
btn: ['确定', '取消']
|
||||
}, function(index) {
|
||||
callback && callback(obj, index);
|
||||
});
|
||||
}
|
||||
};
|
||||
handlers[event] && handlers[event]();
|
||||
},
|
||||
|
||||
// 表头工具栏事件
|
||||
toolbar: function(obj, callback) {
|
||||
var event = obj.event;
|
||||
var handlers = {
|
||||
batchRemove: function() {
|
||||
var checkStatus = table.checkStatus(obj.config.id);
|
||||
if (!checkStatus.data.length) {
|
||||
layer.msg('请选择要移除的包名', {icon: 2});
|
||||
return;
|
||||
}
|
||||
layer.confirm('确定要移除选中的 ' + checkStatus.data.length + ' 个包名权限吗?', {
|
||||
title: '批量移除确认',
|
||||
btn: ['确定', '取消']
|
||||
}, function(index) {
|
||||
callback && callback(checkStatus.data, index);
|
||||
});
|
||||
}
|
||||
};
|
||||
handlers[event] && handlers[event]();
|
||||
}
|
||||
};
|
||||
|
||||
// 表格缓存对象
|
||||
var TableCache = {
|
||||
data: {},
|
||||
set: function(key, value) {
|
||||
this.data[key] = value;
|
||||
// 最多缓存100条数据
|
||||
var keys = Object.keys(this.data);
|
||||
if (keys.length > 100) {
|
||||
delete this.data[keys[0]];
|
||||
}
|
||||
},
|
||||
get: function(key) {
|
||||
return this.data[key];
|
||||
},
|
||||
clear: function() {
|
||||
this.data = {};
|
||||
}
|
||||
};
|
||||
|
||||
// 基础表格配置
|
||||
var baseTableConfig = {
|
||||
page: true,
|
||||
limit: 15,
|
||||
loading: true,
|
||||
text: {
|
||||
none: '暂无数据'
|
||||
},
|
||||
size: 'sm'
|
||||
};
|
||||
|
||||
layui.use(['table', 'form', 'laydate'], function() {
|
||||
let table = layui.table,
|
||||
form = layui.form,
|
||||
laydate = layui.laydate;
|
||||
|
||||
// 将 table 绑定到全局,以便其他函数使用
|
||||
window.packageAuthTable = table;
|
||||
|
||||
// 初始化时间选择器
|
||||
laydate.render({
|
||||
elem: '#dateRange',
|
||||
type: 'datetime',
|
||||
range: true,
|
||||
trigger: 'click',
|
||||
done: function(value, date){
|
||||
if(value) {
|
||||
var dates = value.split(' - ');
|
||||
table.reload('packageTable', {
|
||||
where: {
|
||||
start_time: dates[0],
|
||||
end_time: dates[1]
|
||||
},
|
||||
page: {curr: 1}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 重置筛选
|
||||
$('#resetFilter').on('click', function(){
|
||||
$('#searchPackages').val('');
|
||||
$('#dateRange').val('');
|
||||
table.reload('packageTable', {
|
||||
where: {
|
||||
keyword: '',
|
||||
start_time: '',
|
||||
end_time: ''
|
||||
},
|
||||
page: {curr: 1}
|
||||
});
|
||||
});
|
||||
|
||||
// 优化搜索功能
|
||||
$('#searchPackages').on('input', debounce(function(){
|
||||
var value = this.value;
|
||||
var dateRange = $('#dateRange').val();
|
||||
var dates = dateRange ? dateRange.split(' - ') : ['', ''];
|
||||
|
||||
table.reload('packageTable', {
|
||||
where: {
|
||||
keyword: value,
|
||||
start_time: dates[0],
|
||||
end_time: dates[1]
|
||||
},
|
||||
page: {curr: 1}
|
||||
});
|
||||
}, 300));
|
||||
|
||||
// 初始化包名权限配置表格
|
||||
table.render({
|
||||
elem: '#packageTable',
|
||||
url: '{:url("getPackageList")}',
|
||||
method: 'post',
|
||||
toolbar: true,
|
||||
defaultToolbar: ['filter', 'exports'],
|
||||
cols: [[
|
||||
{type: 'checkbox', width: 50},
|
||||
{field: 'package_name', title: '包名', sort: true},
|
||||
{field: 'name', title: '应用名称'}
|
||||
]],
|
||||
page: true,
|
||||
limit: 20,
|
||||
limits: [10, 20, 50, 100],
|
||||
height: 'full-120',
|
||||
text: {
|
||||
none: '暂无包名数据'
|
||||
},
|
||||
size: 'sm'
|
||||
});
|
||||
|
||||
// 管理员全选
|
||||
form.on('checkbox(checkAllUsers)', function(data){
|
||||
var checked = data.elem.checked;
|
||||
$('input[name="user_ids[]"]').prop('checked', checked);
|
||||
form.render('checkbox');
|
||||
});
|
||||
|
||||
// 启用包名全选
|
||||
form.on('checkbox(checkAllEnabled)', function(data){
|
||||
var checked = data.elem.checked;
|
||||
$(data.elem).closest('.layui-form-item').nextUntil('.layui-form-item:has(label:contains("禁用包名"))')
|
||||
.find('input[type="checkbox"]').prop('checked', checked);
|
||||
form.render('checkbox');
|
||||
});
|
||||
|
||||
// 禁用包全选
|
||||
form.on('checkbox(checkAllDisabled)', function(data){
|
||||
var checked = data.elem.checked;
|
||||
$(data.elem).closest('.layui-form-item').nextAll()
|
||||
.find('input[type="checkbox"]').prop('checked', checked);
|
||||
form.render('checkbox');
|
||||
});
|
||||
|
||||
// 批量授权按钮事件
|
||||
form.on('submit(batchAuth)', function(data) {
|
||||
let userIds = [];
|
||||
$('input[name="user_ids[]"]:checked').each(function() {
|
||||
userIds.push($(this).val());
|
||||
});
|
||||
|
||||
if(userIds.length === 0) {
|
||||
layer.msg('请选择要授权的管理员', {icon: 2});
|
||||
return false;
|
||||
}
|
||||
|
||||
// 使用全局的 table 变量
|
||||
let checkStatus = window.packageAuthTable.checkStatus('packageTable');
|
||||
let packageIds = checkStatus.data.map(item => item.id);
|
||||
|
||||
if(packageIds.length === 0) {
|
||||
layer.msg('请选择要授权的包名', {icon: 2});
|
||||
return false;
|
||||
}
|
||||
|
||||
layer.confirm('确定要批量授权吗?<br>此操作将覆盖已有权限!', {
|
||||
title: '操作确认',
|
||||
btn: ['确定', '取消'],
|
||||
icon: 3
|
||||
}, function(index) {
|
||||
let loadIndex = layer.load(2);
|
||||
$.ajax({
|
||||
url: '{:url("batchAuth")}',
|
||||
type: 'post',
|
||||
data: {
|
||||
user_ids: userIds,
|
||||
package_ids: packageIds
|
||||
},
|
||||
success: function(res) {
|
||||
layer.close(loadIndex);
|
||||
if(res.code === 1) {
|
||||
layer.msg(res.info, {icon: 1, time: 1000}, function() {
|
||||
location.reload();
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.info, {icon: 2, time: 2000});
|
||||
}
|
||||
layer.close(index);
|
||||
}
|
||||
});
|
||||
});
|
||||
return false;
|
||||
});
|
||||
|
||||
// 清空权限按钮事件
|
||||
$('#clearAuth').click(function() {
|
||||
let userIds = [];
|
||||
$('input[name="user_ids[]"]:checked').each(function() {
|
||||
userIds.push($(this).val());
|
||||
});
|
||||
|
||||
if(userIds.length === 0) {
|
||||
layer.msg('请选择要清空权限的管理员', {icon: 2});
|
||||
return false;
|
||||
}
|
||||
|
||||
layer.confirm('确定要清空所选管理员的权限吗?<br>此操作不可恢复!', {
|
||||
title: '危险操作',
|
||||
btn: ['确定清空', '取消'],
|
||||
icon: 2
|
||||
}, function(index) {
|
||||
let loadIndex = layer.load(2);
|
||||
$.ajax({
|
||||
url: '{:url("clearAuth")}',
|
||||
type: 'post',
|
||||
data: {
|
||||
user_ids: userIds
|
||||
},
|
||||
success: function(res) {
|
||||
layer.close(loadIndex);
|
||||
if(res.code === 1) {
|
||||
layer.msg(res.info, {icon: 1, time: 1000}, function() {
|
||||
location.reload();
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.info, {icon: 2, time: 2000});
|
||||
}
|
||||
layer.close(index);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 操作指南展开/收起
|
||||
$('#showGuide').click(function(){
|
||||
var $content = $('.guide-content');
|
||||
if ($content.hasClass('layui-hide')) {
|
||||
$content.removeClass('layui-hide').hide().slideDown();
|
||||
// 存储状态到 localStorage
|
||||
localStorage.setItem('packageAuthGuideShow', '1');
|
||||
} else {
|
||||
$content.slideUp(function(){
|
||||
$(this).addClass('layui-hide');
|
||||
});
|
||||
// 存储状态到 localStorage
|
||||
localStorage.setItem('packageAuthGuideShow', '0');
|
||||
}
|
||||
});
|
||||
|
||||
// 页面加载时检查是否需要显示操作指南
|
||||
if (localStorage.getItem('packageAuthGuideShow') === '1') {
|
||||
$('.guide-content').removeClass('layui-hide');
|
||||
}
|
||||
|
||||
// 初始化按钮提示
|
||||
$('[lay-tips]').each(function(){
|
||||
var tips = $(this).attr('lay-tips');
|
||||
if(tips) {
|
||||
layui.use('layer', function(){
|
||||
var layer = layui.layer;
|
||||
$(this).on('mouseenter', function(){
|
||||
this.index = layer.tips(tips, this, {
|
||||
tips: [1, '#3595CC'],
|
||||
time: 0
|
||||
});
|
||||
}).on('mouseleave', function(){
|
||||
layer.close(this.index);
|
||||
});
|
||||
}.bind(this));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 辅助函数
|
||||
function viewAuth(userId, username){
|
||||
$('[data-user="' + userId + '"][lay-event="showAuth"]').click();
|
||||
}
|
||||
|
||||
function clearSingleAuth(userId){
|
||||
layer.confirm('确定要清空此管理员的权限吗?', {
|
||||
title: '操作确认',
|
||||
btn: ['确定', '取消'],
|
||||
icon: 3,
|
||||
skin: 'layui-layer-molv'
|
||||
}, function(index){
|
||||
var loadIndex = layer.load(2);
|
||||
$.ajax({
|
||||
url: '{:url("clearAuth")}',
|
||||
type: 'post',
|
||||
data: {
|
||||
user_ids: [userId]
|
||||
},
|
||||
success: function(res){
|
||||
layer.close(loadIndex);
|
||||
if(res.code === 1){
|
||||
layer.msg(res.info, {icon: 1, time: 1000}, function(){
|
||||
location.reload();
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.info, {icon: 2, time: 2000});
|
||||
}
|
||||
layer.close(index);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 将权限详情相关的函数抽取出来
|
||||
function showAuthDetail(userId, username) {
|
||||
layer.open({
|
||||
type: 1,
|
||||
title: username + ' 的权限配置',
|
||||
area: ['1200px', '80%'],
|
||||
offset: '50px',
|
||||
moveType: 1,
|
||||
content: $('#authDetailTpl').html(),
|
||||
success: function(layero) {
|
||||
window.initAuthDetailTables(userId);
|
||||
// 隐藏默认的关闭按钮
|
||||
$(layero).find('.layui-layer-setwin').css({
|
||||
'display': 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 绑定查看权限按钮事件
|
||||
$(document).on('click', '[lay-event="showAuth"]', function() {
|
||||
let userId = $(this).data('user');
|
||||
let username = $(this).closest('.layui-form-item').find('input[type="checkbox"]').attr('title');
|
||||
showAuthDetail(userId, username);
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- 添加一些样式 -->
|
||||
<style>
|
||||
.guide-content ol {
|
||||
padding-left: 20px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
.guide-content ol li {
|
||||
line-height: 28px;
|
||||
color: #666;
|
||||
}
|
||||
.guide-content h4 {
|
||||
margin: 5px 0;
|
||||
color: #333;
|
||||
}
|
||||
.layui-elem-quote {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.context-menu-layer {
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,.1);
|
||||
background: none;
|
||||
}
|
||||
.context-menu {
|
||||
background: #fff;
|
||||
border-radius: 2px;
|
||||
padding: 5px 0;
|
||||
}
|
||||
.context-menu .menu-item {
|
||||
padding: 8px 15px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
color: #666;
|
||||
transition: all .2s;
|
||||
}
|
||||
.context-menu .menu-item:hover {
|
||||
background: #f2f2f2;
|
||||
color: #009688;
|
||||
}
|
||||
.context-menu .menu-item .layui-icon {
|
||||
margin-right: 5px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.context-menu .menu-item[onclick*="clearSingleAuth"] {
|
||||
color: #FF5722;
|
||||
}
|
||||
.context-menu .menu-item[onclick*="clearSingleAuth"]:hover {
|
||||
background: #fff1f0;
|
||||
}
|
||||
|
||||
/* 管理员列表样式优化 */
|
||||
.user-list .layui-form-item {
|
||||
padding: 8px 0;
|
||||
margin-bottom: 5px;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.user-list .layui-form-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.user-list .layui-btn-sm {
|
||||
height: 28px;
|
||||
line-height: 28px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
|
||||
.user-list .layui-badge {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.user-list .layui-btn-normal {
|
||||
background-color: #1E9FFF;
|
||||
}
|
||||
|
||||
.user-list .layui-btn-warm {
|
||||
background-color: #FFB800;
|
||||
}
|
||||
|
||||
.user-list .layui-icon {
|
||||
font-size: 14px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
/* 美化搜索框 */
|
||||
.search-box .layui-input {
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* 美化全选框 */
|
||||
.layui-form-item .layui-form-checkbox[lay-skin=primary] {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
/* 右侧顶部按钮样式优化 */
|
||||
.header-btns {
|
||||
margin: 3px 0;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
.header-btns .layui-btn {
|
||||
height: 34px;
|
||||
line-height: 34px;
|
||||
padding: 0 15px;
|
||||
font-size: 13px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.header-btns .layui-btn .layui-icon {
|
||||
font-size: 14px;
|
||||
margin-right: 3px;
|
||||
}
|
||||
|
||||
.header-btns .layui-btn-normal {
|
||||
background-color: #1E9FFF;
|
||||
}
|
||||
|
||||
.header-btns .layui-btn-normal:hover {
|
||||
background-color: #0d8aff;
|
||||
}
|
||||
|
||||
.header-btns .layui-btn-danger {
|
||||
background-color: #FF5722;
|
||||
}
|
||||
|
||||
.header-btns .layui-btn-danger:hover {
|
||||
background-color: #ff4208;
|
||||
}
|
||||
|
||||
/* 提示框样式优化 */
|
||||
.layui-layer-tips {
|
||||
font-size: 13px !important;
|
||||
}
|
||||
|
||||
.layui-layer-tips .layui-layer-content {
|
||||
padding: 8px 12px !important;
|
||||
line-height: 1.5 !important;
|
||||
border-radius: 2px !important;
|
||||
}
|
||||
|
||||
.layui-layer-tips i.layui-layer-TipsT {
|
||||
border-right-color: #3595CC !important;
|
||||
}
|
||||
|
||||
/* 危险操作弹窗样式 */
|
||||
.layer-danger .layui-layer-title {
|
||||
background-color: #FF5722 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.layer-danger .layui-layer-btn0 {
|
||||
background-color: #FF5722 !important;
|
||||
border-color: #FF5722 !important;
|
||||
}
|
||||
|
||||
/* 工具栏按钮样式 */
|
||||
.auth-table-container .layui-table-tool .layui-btn {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.auth-table-container .layui-table-tool .layui-btn:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.auth-table-container .layui-table-tool .layui-btn-danger:hover {
|
||||
background-color: #ff4208;
|
||||
}
|
||||
|
||||
/* 正常操作弹窗样式 */
|
||||
.layer-normal .layui-layer-title {
|
||||
background-color: #1E9FFF !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.layer-normal .layui-layer-btn0 {
|
||||
background-color: #1E9FFF !important;
|
||||
border-color: #1E9FFF !important;
|
||||
}
|
||||
|
||||
/* 工具栏按钮样式补充 */
|
||||
.auth-table-container .layui-table-tool .layui-btn-normal {
|
||||
background-color: #1E9FFF;
|
||||
}
|
||||
|
||||
.auth-table-container .layui-table-tool .layui-btn-normal:hover {
|
||||
background-color: #0d8aff;
|
||||
}
|
||||
</style>
|
||||
{/block}
|
||||
258
app/manager/view/package_callback/add.html
Normal file
258
app/manager/view/package_callback/add.html
Normal file
@@ -0,0 +1,258 @@
|
||||
{extend name="../../admin/view/main"}
|
||||
|
||||
{block name="content"}
|
||||
<form class="layui-form layui-card" action="{:request()->url()}" data-auto="true" method="post">
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">选择包名</label>
|
||||
<div class="layui-input-block">
|
||||
<div id="packageSelect"></div>
|
||||
<input type="hidden" name="package_id" id="selectedPackageId">
|
||||
<input type="hidden" name="package_name" id="selectedPackageName">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">事件名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="event_name" required lay-verify="required" placeholder="请输入事件名称" class="layui-input">
|
||||
<tip>例如:install, register, purchase 等</tip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">回传地址</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="callback_url" required lay-verify="required|callback_url" placeholder="请输入回传地址" class="layui-input">
|
||||
<tip>
|
||||
完整的回传接口地址,例如:http://api.example.com/callback<br>
|
||||
支持变量替换,如 {package_name}, {event_name} 等<br>
|
||||
详细说明请查看完整回传指南
|
||||
</tip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" value="1" title="启用" checked>
|
||||
<input type="radio" name="status" value="0" title="停用">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
||||
<div class="layui-form-item text-center">
|
||||
<button class="layui-btn" lay-submit lay-filter="formSubmit">保存数据</button>
|
||||
<button class="layui-btn layui-btn-danger" type="button" data-close>取消添加</button>
|
||||
</div>
|
||||
</form>
|
||||
{/block}
|
||||
|
||||
{block name="script"}
|
||||
<style>
|
||||
.layui-form tip {
|
||||
display: block;
|
||||
padding: 10px;
|
||||
margin-top: 10px;
|
||||
color: #666;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 2px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
.layui-badge {
|
||||
margin: 2px;
|
||||
font-family: Consolas, monospace;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
$(function () {
|
||||
layui.use(['form', 'xmSelect', 'layer'], function () {
|
||||
let form = layui.form;
|
||||
let layer = layui.layer;
|
||||
let existingConfig = null; // 用于存储已存在的配置信息
|
||||
|
||||
// 定义包名选择器
|
||||
const packageSelect = xmSelect.render({
|
||||
el: '#packageSelect',
|
||||
name: 'package_id',
|
||||
radio: true,
|
||||
clickClose: true,
|
||||
filterable: true,
|
||||
tips: '请选择包名',
|
||||
data: [],
|
||||
direction: 'auto',
|
||||
model: { label: { type: 'text' } },
|
||||
on: function(data) {
|
||||
if(data.arr.length > 0) {
|
||||
let selected = data.arr[0];
|
||||
$('#selectedPackageId').val(selected.value);
|
||||
$('#selectedPackageName').val(selected.package_name);
|
||||
// 选择包名后,如果已有事件名称,则检查是否存在
|
||||
checkEventExists();
|
||||
} else {
|
||||
$('#selectedPackageId').val('');
|
||||
$('#selectedPackageName').val('');
|
||||
}
|
||||
form.render();
|
||||
}
|
||||
});
|
||||
|
||||
let checkTimer = null; // 添加防抖定时器
|
||||
|
||||
// 监听事件名称输入框
|
||||
$('input[name="event_name"]').on('input propertychange', function() {
|
||||
let currentValue = $(this).val();
|
||||
console.log('事件名称输入:', currentValue);
|
||||
|
||||
// 使用防抖,避免频繁请求
|
||||
if (checkTimer) clearTimeout(checkTimer);
|
||||
checkTimer = setTimeout(function() {
|
||||
checkEventExists(currentValue);
|
||||
}, 300);
|
||||
});
|
||||
|
||||
// 检查事件是否存在
|
||||
function checkEventExists(eventValue) {
|
||||
// 获取当前弹窗内的元素
|
||||
let $dialog = $('.layui-layer-page').last();
|
||||
let packageId = $('#selectedPackageId').val();
|
||||
let $eventInput = $dialog.find('input[name="event_name"]');
|
||||
|
||||
// 清除现有提示和验证状态
|
||||
$eventInput.removeClass('layui-form-danger');
|
||||
$eventInput.nextAll('.layui-form-mid,.layui-word-aux').remove();
|
||||
$dialog.find('tip').show();
|
||||
|
||||
// 重置existingConfig
|
||||
existingConfig = null;
|
||||
|
||||
if (packageId && eventValue) {
|
||||
// 直接获取配置详情
|
||||
$.ajax({
|
||||
url: '{:url("getExistingConfig")}',
|
||||
type: 'POST',
|
||||
data: {
|
||||
package_id: packageId,
|
||||
event_name: eventValue
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function(configRes) {
|
||||
if (configRes.code === 1 && configRes.data) {
|
||||
// 保存已存在的配置信息
|
||||
existingConfig = configRes.data; // 保存完整的配置信息
|
||||
|
||||
// 添加验证失败样式
|
||||
$eventInput.addClass('layui-form-danger');
|
||||
// 隐藏当前弹窗内的tip
|
||||
$dialog.find('.layui-input-block tip').hide();
|
||||
// 添加提示信息
|
||||
$eventInput.after(`
|
||||
<div class="layui-form-mid" style="margin-top: 5px;">
|
||||
<div style="color: #FF5722; font-weight: bold; margin-bottom: 5px;">
|
||||
<i class="layui-icon layui-icon-warning" style="font-size: 16px; margin-right: 5px;"></i>
|
||||
该包名下已存在此事件名称的配置,提交时将覆盖现有配置
|
||||
</div>
|
||||
<div style="color: #666; background: #f8f8f8; padding: 8px; border-radius: 2px; margin-top: 5px;">
|
||||
<i class="layui-icon layui-icon-link" style="margin-right: 5px;"></i>
|
||||
已配置的回调地址:${configRes.data.callback_url}
|
||||
</div>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 加载包名列表
|
||||
function loadPackageList() {
|
||||
$.get('{:url("searchPackages")}', {
|
||||
init: 1
|
||||
}, function(res) {
|
||||
if (res.code === 1) {
|
||||
let data = res.data.map(function(item) {
|
||||
return {
|
||||
name: item.package_name + ' (' + item.name + ')',
|
||||
value: item.id,
|
||||
package_name: item.package_name
|
||||
};
|
||||
});
|
||||
packageSelect.update({
|
||||
data: data,
|
||||
autoRow: true
|
||||
});
|
||||
}
|
||||
}, 'json');
|
||||
}
|
||||
|
||||
// 初始加载包名列表
|
||||
loadPackageList();
|
||||
|
||||
// 表单验证
|
||||
form.verify({
|
||||
callback_url: function(value) {
|
||||
if (!/^https?:\/\/.+/.test(value)) {
|
||||
return '请输入正确的URL地址';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 修改表单提交处理
|
||||
form.on('submit(formSubmit)', function(data) {
|
||||
// 如果存在配置,显示确认框
|
||||
if (existingConfig) {
|
||||
layer.confirm('该包名下已存在此事件配置,是否确认覆盖?', {
|
||||
title: '覆盖确认',
|
||||
btn: ['确认覆盖', '取消'],
|
||||
icon: 3
|
||||
}, function(index) {
|
||||
// 确认覆盖,将请求转为更新操作
|
||||
let formData = data.field;
|
||||
formData.id = existingConfig.id; // 添加已存在配置的ID
|
||||
|
||||
$.ajax({
|
||||
url: '{:url("edit")}',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
success: function(res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.info, {icon: 1, time: 1500}, function() {
|
||||
parent.layer.close(parent.layer.getFrameIndex(window.name));
|
||||
parent.location.reload();
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.info, {icon: 2, time: 1500});
|
||||
}
|
||||
}
|
||||
});
|
||||
layer.close(index);
|
||||
});
|
||||
} else {
|
||||
// 如果不存在配置,使用默认表单提交
|
||||
let formData = data.field;
|
||||
$.ajax({
|
||||
url: '{:url("add")}',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
success: function(res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.info, {icon: 1, time: 1500}, function() {
|
||||
parent.layer.close(parent.layer.getFrameIndex(window.name));
|
||||
parent.location.reload();
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.info, {icon: 2, time: 1500});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return false; // 阻止表单默认提交
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
160
app/manager/view/package_callback/edit.html
Normal file
160
app/manager/view/package_callback/edit.html
Normal file
@@ -0,0 +1,160 @@
|
||||
{extend name="../../admin/view/main"}
|
||||
|
||||
{block name="content"}
|
||||
<form class="layui-form layui-card" action="{:request()->url()}" data-auto="true" method="post">
|
||||
<div class="layui-card-body">
|
||||
<input type="hidden" name="id" value="{$vo.id|default=''}">
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">选择包名</label>
|
||||
<div class="layui-input-block">
|
||||
<div id="packageSelect"></div>
|
||||
<input type="hidden" name="package_id" id="selectedPackageId" value="{$vo.package_id|default=''}">
|
||||
<input type="hidden" name="package_name" id="selectedPackageName" value="{$vo.package_name|default=''}">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">事件名称</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="event_name" required lay-verify="required" placeholder="请输入事件名称" class="layui-input" value="{$vo.event_name|default=''}">
|
||||
<tip>例如:install, register, purchase 等</tip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">回传地址</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="text" name="callback_url" required lay-verify="required|callback_url" placeholder="请输入回传地址" class="layui-input" value="{$vo.callback_url|default=''}">
|
||||
<tip>
|
||||
完整的回传接口地址,例如:http://api.example.com/callback<br>
|
||||
支持变量替换,如 {package_name}, {event_name} 等<br>
|
||||
详细说明请查看完整回传指南
|
||||
</tip>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-block">
|
||||
<input type="radio" name="status" value="1" title="启用" {if $vo.status eq 1}checked{/if}>
|
||||
<input type="radio" name="status" value="0" title="停用" {if $vo.status eq 0}checked{/if}>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="hr-line-dashed"></div>
|
||||
|
||||
<div class="layui-form-item text-center">
|
||||
<button class="layui-btn" lay-submit lay-filter="formSubmit">保存数据</button>
|
||||
<button class="layui-btn layui-btn-danger" type="button" data-close>取消编辑</button>
|
||||
</div>
|
||||
</form>
|
||||
{/block}
|
||||
|
||||
{block name="script"}
|
||||
<style>
|
||||
.layui-form tip {
|
||||
display: block;
|
||||
padding: 10px;
|
||||
margin-top: 10px;
|
||||
color: #666;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 2px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
.layui-badge {
|
||||
margin: 2px;
|
||||
font-family: Consolas, monospace;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
$(function () {
|
||||
layui.use(['form', 'xmSelect'], function () {
|
||||
let form = layui.form;
|
||||
|
||||
// 定义包名选择器
|
||||
const packageSelect = xmSelect.render({
|
||||
el: '#packageSelect',
|
||||
name: 'package_id',
|
||||
radio: true,
|
||||
clickClose: true,
|
||||
filterable: true,
|
||||
tips: '请选择包名',
|
||||
data: [],
|
||||
direction: 'auto',
|
||||
model: { label: { type: 'text' } },
|
||||
initValue: [{$vo.package_id|default=0}], // 设置初始选中值
|
||||
on: function(data) {
|
||||
if(data.arr.length > 0) {
|
||||
let selected = data.arr[0];
|
||||
$('#selectedPackageId').val(selected.value);
|
||||
$('#selectedPackageName').val(selected.package_name);
|
||||
} else {
|
||||
$('#selectedPackageId').val('');
|
||||
$('#selectedPackageName').val('');
|
||||
}
|
||||
form.render();
|
||||
}
|
||||
});
|
||||
|
||||
// 加载包名列表并选中当前包名
|
||||
function loadPackageList() {
|
||||
$.get('{:url("searchPackages")}', {
|
||||
init: 1,
|
||||
edit_id: '{$vo.id|default=0}' // 传递当前编辑的ID
|
||||
}, function(res) {
|
||||
if (res.code === 1) {
|
||||
let data = res.data.map(function(item) {
|
||||
return {
|
||||
name: item.package_name + ' (' + item.name + ')',
|
||||
value: item.id,
|
||||
package_name: item.package_name,
|
||||
selected: item.id == '{$vo.package_id|default=0}' // 标记当前选中项
|
||||
};
|
||||
});
|
||||
packageSelect.update({
|
||||
data: data,
|
||||
autoRow: true
|
||||
});
|
||||
}
|
||||
}, 'json');
|
||||
}
|
||||
|
||||
// 初始加载包名列表
|
||||
loadPackageList();
|
||||
|
||||
// 表单验证
|
||||
form.verify({
|
||||
callback_url: function(value) {
|
||||
if (!/^https?:\/\/.+/.test(value)) {
|
||||
return '请输入正确的URL地址';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 表单提交
|
||||
form.on('submit(formSubmit)', function(data) {
|
||||
let formData = data.field;
|
||||
$.ajax({
|
||||
url: '{:url("edit")}',
|
||||
type: 'POST',
|
||||
data: formData,
|
||||
dataType: 'json',
|
||||
success: function(res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.info, {icon: 1, time: 1500}, function() {
|
||||
parent.layer.close(parent.layer.getFrameIndex(window.name));
|
||||
parent.location.reload();
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.info, {icon: 2, time: 1500});
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{/block}
|
||||
232
app/manager/view/package_callback/index.html
Normal file
232
app/manager/view/package_callback/index.html
Normal file
@@ -0,0 +1,232 @@
|
||||
{extend name="../../admin/view/main"}
|
||||
|
||||
|
||||
{block name="content"}
|
||||
<!-- 操作指南开始 -->
|
||||
<div class="think-box-shadow" style="margin-bottom: 15px; padding: 15px;">
|
||||
<h3 class="layui-inline" style="margin-right: 15px;">回传配置指南</h3>
|
||||
<button class="layui-btn layui-btn-sm" id="showGuide">展开/收起</button>
|
||||
<div class="guide-content layui-hide" style="margin-top: 10px;">
|
||||
<div class="layui-card">
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-elem-quote" style="border-left: 5px solid #009688;">
|
||||
<h4>基本说明:</h4>
|
||||
<p>本页面用于管理事件回传配置,支持变量替换功能,可以灵活配置回传地址。</p>
|
||||
</div>
|
||||
|
||||
<div class="layui-elem-quote" style="border-left: 5px solid #FFB800;">
|
||||
<h4>支持的变量:</h4>
|
||||
<ol>
|
||||
<li><code>{package_name}</code> - 应用包名,如:com.example.app</li>
|
||||
<li><code>{event_name}</code> - 事件名称,如:install, register</li>
|
||||
<li><code>{event_time}</code> - 事件发生时间,格式:YYYY-MM-DD HH:mm:ss</li>
|
||||
<li><code>{gaid}</code> - 广告ID</li>
|
||||
<li><code>{network_name}</code> - 网络名称,如:AppsFlyer, Kochava</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="layui-elem-quote" style="border-left: 5px solid #FF5722;">
|
||||
<h4>配置示例:</h4>
|
||||
<ol>
|
||||
<li>基础URL:http://api.example.com/callback</li>
|
||||
<li>
|
||||
完整示例:http://api.example.com/callback?package={package_name}&event={event_name}&time={event_time}&gaid={gaid}&network={network_name}
|
||||
</li>
|
||||
<li>实际回传时,花括号中的变量会被替换为实际值</li>
|
||||
<li>所有特殊字符会自动进行URL编码</li>
|
||||
</ol>
|
||||
</div>
|
||||
|
||||
<div class="layui-elem-quote" style="border-left: 5px solid #01AAED;">
|
||||
<h4>注意事项:</h4>
|
||||
<ol>
|
||||
<li>变量名称必须使用大括号{}包裹,且区分大小写</li>
|
||||
<li>同一个包名下不能配置重复的事件名称</li>
|
||||
<li>回传地址必须以http://或https://开头</li>
|
||||
<li>建议在测试环境验证回传地址的正确性</li>
|
||||
<li>可以通过状态开关临时停用某个回传配置</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 操作指南结束 -->
|
||||
|
||||
<!-- 表单搜索区域 -->
|
||||
<div class="think-box-shadow">
|
||||
<div class="layui-row">
|
||||
<div class="layui-col-md11">
|
||||
<form class="layui-form layui-form-pane form-search" action="">
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">包名</label>
|
||||
<div class="layui-input-inline">
|
||||
<input name="package_name" placeholder="请输入包名" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">事件名称</label>
|
||||
<div class="layui-input-inline">
|
||||
<input name="event_name" placeholder="请输入事件名称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="status" lay-search>
|
||||
<option value="">所有状态</option>
|
||||
<option value="1">启用</option>
|
||||
<option value="0">停用</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="layui-form-item layui-inline">
|
||||
<button class="layui-btn layui-btn-primary" lay-submit lay-filter="search_form">
|
||||
<i class="layui-icon"></i> 搜 索
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="layui-col-md1 text-right">
|
||||
<!--{if auth("add")}-->
|
||||
<button class='layui-btn layui-btn-normal' data-modal='{:url("add")}'
|
||||
data-title="添加回传配置">
|
||||
<i class="layui-icon layui-icon-add-circle"></i> 添加事件
|
||||
</button>
|
||||
<!--{/if}-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据表格区域 -->
|
||||
<div class="think-box-shadow">
|
||||
<table class="layui-table" id="CallbackTable" data-url="{:url('get_list')}"
|
||||
data-target-search="form.form-search"></table>
|
||||
</div>
|
||||
|
||||
<!-- 数据操作工具条模板 -->
|
||||
<script type="text/html" id="toolbar">
|
||||
<!--{if auth("edit")}-->
|
||||
<a class="layui-btn layui-btn-sm" data-modal="{:url('edit')}?id={{d.id}}" data-title="编辑回传配置">
|
||||
<i class="layui-icon layui-icon-edit"></i> 编辑
|
||||
</a>
|
||||
<!--{/if}-->
|
||||
<!--{if auth("remove")}-->
|
||||
<a class="layui-btn layui-btn-sm layui-btn-danger" data-action="{:url('remove')}" data-value="id#{{d.id}}"
|
||||
data-confirm="确定要删除此配置吗?">
|
||||
<i class="layui-icon layui-icon-delete"></i> 删除
|
||||
</a>
|
||||
<!--{/if}-->
|
||||
</script>
|
||||
|
||||
<!-- 数据状态切换模板 -->
|
||||
<script type="text/html" id="statusTpl">
|
||||
<!--{if auth("state")}-->
|
||||
<input type="checkbox" value="{{d.id}}" lay-skin="switch" lay-text="启用|停用" lay-filter="status"
|
||||
{{d.status>0?'checked':''}}>
|
||||
<!--{else}-->
|
||||
{{d.status ? '<b class="color-green">启用</b>' : '<b class="color-red">停用</b>'}}
|
||||
<!--{/if}-->
|
||||
</script>
|
||||
{/block}
|
||||
|
||||
{block name="script"}
|
||||
<script>
|
||||
$(function () {
|
||||
let table; // 定义表格变量
|
||||
|
||||
// 初始化表格组件
|
||||
table = $('#CallbackTable').layTable({
|
||||
url: '{:url("get_list")}',
|
||||
method: 'get',
|
||||
even: true,
|
||||
page: true,
|
||||
limit: 15,
|
||||
limits: [10, 15, 20, 25, 50, 100],
|
||||
cols: [[
|
||||
{field: 'id', title: 'ID', width: 80, align: 'center'},
|
||||
{field: 'package_name', title: '包名', minWidth: 200},
|
||||
{field: 'event_name', title: '事件名称', minWidth: 150},
|
||||
{field: 'callback_url', title: '回传地址', minWidth: 300},
|
||||
{field: 'status', title: '状态', width: 100, align: 'center', templet: '#statusTpl'},
|
||||
{field: 'create_at', title: '创建时间', width: 180, align: 'center'},
|
||||
{title: '操作', toolbar: '#toolbar', width: 180, align: 'center', fixed: 'right'}
|
||||
]],
|
||||
text: {
|
||||
none: '暂无回传配置数据'
|
||||
}
|
||||
});
|
||||
|
||||
// 数据状态切换操作
|
||||
form.on('switch(status)', function (obj) {
|
||||
$.ajax({
|
||||
url: '{:url("state")}',
|
||||
type: 'POST',
|
||||
data: {
|
||||
id: obj.value,
|
||||
status: obj.elem.checked ? 1 : 0
|
||||
},
|
||||
dataType: 'json',
|
||||
success: function (res) {
|
||||
if (res.code === 1) {
|
||||
layer.msg(res.info, {icon: 1});
|
||||
// 仅重载表格数据
|
||||
table.reload('CallbackTable', {
|
||||
page: {
|
||||
curr: $(".layui-laypage-em").next().html() // 保持在当前页
|
||||
}
|
||||
});
|
||||
} else {
|
||||
layer.msg(res.info, {icon: 2});
|
||||
// 状态切换失败,回滚switch状态
|
||||
obj.elem.checked = !obj.elem.checked;
|
||||
form.render('checkbox');
|
||||
}
|
||||
},
|
||||
error: function () {
|
||||
layer.msg('操作失败,请重试', {icon: 2});
|
||||
// 发生错误时也回滚switch状态
|
||||
obj.elem.checked = !obj.elem.checked;
|
||||
form.render('checkbox');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 操作指南展开/收起
|
||||
$('#showGuide').on('click', function () {
|
||||
$('.guide-content').toggleClass('layui-hide');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* 操作指南样式 */
|
||||
.guide-content .layui-elem-quote {
|
||||
margin: 10px 0;
|
||||
padding: 15px;
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.guide-content h4 {
|
||||
margin-bottom: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.guide-content code {
|
||||
padding: 2px 4px;
|
||||
background-color: #f1f1f1;
|
||||
border-radius: 3px;
|
||||
color: #333;
|
||||
font-family: Consolas, monospace;
|
||||
}
|
||||
|
||||
.guide-content ol li {
|
||||
margin: 5px 0;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
{/block}
|
||||
58
app/manager/view/package_callback_records/detail.html
Normal file
58
app/manager/view/package_callback_records/detail.html
Normal file
@@ -0,0 +1,58 @@
|
||||
{extend name="../../admin/view/main"}
|
||||
|
||||
{block name="content"}
|
||||
<form class="layui-form layui-card" action="javascript:void(0)" autocomplete="off">
|
||||
<div class="layui-card-body padding-left-40">
|
||||
<div class="layui-form-item layui-row layui-col-space15">
|
||||
<label class="layui-col-xs2 text-right">包名</label>
|
||||
<div class="layui-col-xs10">
|
||||
<div class="layui-input-line">{$vo.package_name|default=''}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-row layui-col-space15">
|
||||
<label class="layui-col-xs2 text-right">事件名称</label>
|
||||
<div class="layui-col-xs10">
|
||||
<div class="layui-input-line">{$vo.event_name|default=''}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-row layui-col-space15">
|
||||
<label class="layui-col-xs2 text-right">回传URL模板</label>
|
||||
<div class="layui-col-xs10">
|
||||
<div class="layui-input-line">{$vo.callback_url|default=''}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-row layui-col-space15">
|
||||
<label class="layui-col-xs2 text-right">实际回传URL</label>
|
||||
<div class="layui-col-xs10">
|
||||
<div class="layui-input-line">{$vo.final_url|default=''}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-row layui-col-space15">
|
||||
<label class="layui-col-xs2 text-right">响应状态码</label>
|
||||
<div class="layui-col-xs10">
|
||||
<div class="layui-input-line">{$vo.response_code|default=''}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-row layui-col-space15">
|
||||
<label class="layui-col-xs2 text-right">响应内容</label>
|
||||
<div class="layui-col-xs10">
|
||||
<pre class="layui-code">{$vo.response_body|default=''}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-row layui-col-space15">
|
||||
<label class="layui-col-xs2 text-right">状态</label>
|
||||
<div class="layui-col-xs10">
|
||||
<div class="layui-input-line">
|
||||
{if $vo.status==1}<span class="layui-badge layui-bg-green">成功</span>{else}<span class="layui-badge layui-bg-red">失败</span>{/if}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-row layui-col-space15">
|
||||
<label class="layui-col-xs2 text-right">回传时间</label>
|
||||
<div class="layui-col-xs10">
|
||||
<div class="layui-input-line">{$vo.callback_time|default=''}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{/block}
|
||||
87
app/manager/view/package_callback_records/index.html
Normal file
87
app/manager/view/package_callback_records/index.html
Normal file
@@ -0,0 +1,87 @@
|
||||
{extend name="../../admin/view/main"}
|
||||
|
||||
{block name="button"}
|
||||
{/block}
|
||||
|
||||
{block name="content"}
|
||||
<div class="think-box-shadow">
|
||||
<fieldset>
|
||||
<legend>条件搜索</legend>
|
||||
<form class="layui-form layui-form-pane form-search" action="javascript:void(0)" method="get" autocomplete="off">
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">包名</label>
|
||||
<div class="layui-input-inline">
|
||||
<input name="package_name" value="{$get.package_name|default=''}" placeholder="请输入包名" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">事件名称</label>
|
||||
<div class="layui-input-inline">
|
||||
<input name="event_name" value="{$get.event_name|default=''}" placeholder="请输入事件名称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">推送ID</label>
|
||||
<div class="layui-input-inline">
|
||||
<input name="push_record_id" value="{$get.push_record_id|default=''}" placeholder="请输入推送ID" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">状态</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="status" class="layui-select">
|
||||
<option value="">所有状态</option>
|
||||
<option value="1">成功</option>
|
||||
<option value="0">失败</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">回传时间</label>
|
||||
<div class="layui-input-inline">
|
||||
<input data-date-range name="callback_time" value="{$get.callback_time|default=''}" placeholder="请选择回传时间" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<button class="layui-btn layui-btn-primary"><i class="layui-icon"></i> 搜 索</button>
|
||||
</div>
|
||||
</form>
|
||||
</fieldset>
|
||||
<table id="RecordTable" data-url="{:sysuri('get_list')}" data-target-search="form.form-search"></table>
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{block name="script"}
|
||||
<script>
|
||||
$(function () {
|
||||
$('#RecordTable').layTable({
|
||||
even: true, height: 'full',
|
||||
sort: {field: 'id', type: 'desc'},
|
||||
cols: [[
|
||||
{field: 'id', title: 'ID', width: 80, sort: true},
|
||||
{field: 'push_record_id', title: '推送ID', width: 150, templet: function(d){
|
||||
var source = d.source_type || '-';
|
||||
return '<a class="layui-link" data-title="查看推送详情" data-open="{:url("package_push_records/detail")}?id='+ d.push_record_id +'">'+ d.push_record_id +'('+ source +')</a>';
|
||||
}},
|
||||
{field: 'package_name', title: '包名', minWidth: 100},
|
||||
{field: 'event_name', title: '事件名称', minWidth: 100},
|
||||
{field: 'callback_url', title: '回传URL模板', minWidth: 200, templet: function(d){
|
||||
return '<div class="layui-elip" title="'+ d.callback_url +'">'+ d.callback_url +'</div>';
|
||||
}},
|
||||
{field: 'final_url', title: '实际回传URL', minWidth: 200, templet: function(d){
|
||||
return '<div class="layui-elip" title="'+ d.final_url +'">'+ d.final_url +'</div>';
|
||||
}},
|
||||
{field: 'response_code', title: '响应码', width: 100},
|
||||
{field: 'status', title: '状态', width: 100, templet: function(d){
|
||||
return d.status == 1 ? '<span class="layui-badge layui-bg-green">成功</span>' : '<span class="layui-badge layui-bg-red">失败</span>';
|
||||
}},
|
||||
{field: 'callback_time', title: '回传时间', width: 180, sort: true},
|
||||
{title: '操作', toolbar: '#toolbar', width: 100, align: 'center', fixed: 'right'}
|
||||
]]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script type="text/html" id="toolbar">
|
||||
<a class="layui-btn layui-btn-xs" data-title="查看详情" data-open="{:url('detail')}?id={{d.id}}">详情</a>
|
||||
</script>
|
||||
{/block}
|
||||
44
app/manager/view/package_push_records/detail.html
Normal file
44
app/manager/view/package_push_records/detail.html
Normal file
@@ -0,0 +1,44 @@
|
||||
{extend name="../../admin/view/main"}
|
||||
|
||||
{block name="content"}
|
||||
<form class="layui-form layui-card" action="javascript:void(0)" autocomplete="off">
|
||||
<div class="layui-card-body padding-left-40">
|
||||
<div class="layui-form-item layui-row layui-col-space15">
|
||||
<label class="layui-col-xs2 text-right">来源</label>
|
||||
<div class="layui-col-xs10">
|
||||
<div class="layui-input-line">{$vo.source_type|default=''}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-row layui-col-space15">
|
||||
<label class="layui-col-xs2 text-right">包名</label>
|
||||
<div class="layui-col-xs10">
|
||||
<div class="layui-input-line">{$vo.package_name|default=''}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-row layui-col-space15">
|
||||
<label class="layui-col-xs2 text-right">事件名称</label>
|
||||
<div class="layui-col-xs10">
|
||||
<div class="layui-input-line">{$vo.event_name|default=''}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-row layui-col-space15">
|
||||
<label class="layui-col-xs2 text-right">原始请求URL</label>
|
||||
<div class="layui-col-xs10">
|
||||
<div class="layui-input-line">{$vo.original_url|default=''}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-row layui-col-space15">
|
||||
<label class="layui-col-xs2 text-right">接收时间</label>
|
||||
<div class="layui-col-xs10">
|
||||
<div class="layui-input-line">{$vo.receive_time|default=''}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-row layui-col-space15">
|
||||
<label class="layui-col-xs2 text-right">创建时间</label>
|
||||
<div class="layui-col-xs10">
|
||||
<div class="layui-input-line">{$vo.created_at|default=''}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{/block}
|
||||
72
app/manager/view/package_push_records/index.html
Normal file
72
app/manager/view/package_push_records/index.html
Normal file
@@ -0,0 +1,72 @@
|
||||
{extend name="../../admin/view/main"}
|
||||
|
||||
{block name="button"}
|
||||
{/block}
|
||||
|
||||
{block name="content"}
|
||||
<div class="think-box-shadow">
|
||||
<fieldset>
|
||||
<legend>条件搜索</legend>
|
||||
<form class="layui-form layui-form-pane form-search" action="javascript:void(0)" method="get" autocomplete="off">
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">包名</label>
|
||||
<div class="layui-input-inline">
|
||||
<input name="package_name" value="{$get.package_name|default=''}" placeholder="请输入包名" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">事件名称</label>
|
||||
<div class="layui-input-inline">
|
||||
<input name="event_name" value="{$get.event_name|default=''}" placeholder="请输入事件名称" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">来源</label>
|
||||
<div class="layui-input-inline">
|
||||
<select name="source_type" class="layui-select">
|
||||
<option value="">所有来源</option>
|
||||
<option value="AppsFlyer">AppsFlyer</option>
|
||||
<option value="Kochava">Kochava</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<label class="layui-form-label">接收时间</label>
|
||||
<div class="layui-input-inline">
|
||||
<input data-date-range name="receive_time" value="{$get.receive_time|default=''}" placeholder="请选择接收时间" class="layui-input">
|
||||
</div>
|
||||
</div>
|
||||
<div class="layui-form-item layui-inline">
|
||||
<button class="layui-btn layui-btn-primary"><i class="layui-icon"></i> 搜 索</button>
|
||||
</div>
|
||||
</form>
|
||||
</fieldset>
|
||||
<table id="RecordTable" data-url="{:sysuri('get_list')}" data-target-search="form.form-search"></table>
|
||||
</div>
|
||||
{/block}
|
||||
|
||||
{block name="script"}
|
||||
<script>
|
||||
$(function () {
|
||||
$('#RecordTable').layTable({
|
||||
even: true, height: 'full',
|
||||
sort: {field: 'id', type: 'desc'},
|
||||
cols: [[
|
||||
{field: 'id', title: 'ID', width: 80, sort: true},
|
||||
{field: 'source_type', title: '来源', width: 100},
|
||||
{field: 'package_name', title: '包名', minWidth: 100},
|
||||
{field: 'event_name', title: '事件名称', minWidth: 100},
|
||||
{field: 'original_url', title: '原始请求URL', minWidth: 200, templet: function(d){
|
||||
return '<div class="layui-elip" title="'+ d.original_url +'">'+ d.original_url +'</div>';
|
||||
}},
|
||||
{field: 'receive_time', title: '接收时间', width: 180, sort: true},
|
||||
{field: 'created_at', title: '创建时间', width: 180},
|
||||
{title: '操作', toolbar: '#toolbar', width: 100, align: 'center', fixed: 'right'}
|
||||
]]
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<script type="text/html" id="toolbar">
|
||||
<a class="layui-btn layui-btn-xs" data-title="查看详情" data-open="{:url('detail')}?id={{d.id}}">详情</a>
|
||||
</script>
|
||||
{/block}
|
||||
23
app/manager/view/table.html
Normal file
23
app/manager/view/table.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<div class="layui-card">
|
||||
{block name='style'}{/block}
|
||||
{block name='header'}
|
||||
{notempty name='title'}
|
||||
<div class="layui-card-header">
|
||||
<span class="layui-icon font-s10 color-desc margin-right-5"></span>{$title|lang}
|
||||
<div class="pull-right">{block name='button'}{/block}</div>
|
||||
</div>
|
||||
{/notempty}
|
||||
{/block}
|
||||
<div class="layui-card-line"></div>
|
||||
<div class="layui-card-body">
|
||||
<div class="layui-card-table">
|
||||
{notempty name='showErrorMessage'}
|
||||
<div class="think-box-notify" type="error">
|
||||
<b>{:lang('系统提示:')}</b><span>{$showErrorMessage|raw}</span>
|
||||
</div>
|
||||
{/notempty}
|
||||
{block name='content'}{/block}
|
||||
</div>
|
||||
</div>
|
||||
{block name='script'}{/block}
|
||||
</div>
|
||||
Reference in New Issue
Block a user