代码功能更新

This commit is contained in:
root
2025-05-18 07:42:27 +00:00
parent 7fc1d422a1
commit 4a90c41da2
2083 changed files with 695218 additions and 3 deletions
+187
View File
@@ -0,0 +1,187 @@
<?php
namespace plugin\apidoc\library;
use app\service\ConfServiceFacade;
use laytp\traits\Error;
use plugin\apidoc\library\apidoc\library\Builder;
use plugin\apidoc\library\apidoc\library\Extractor;
use laytp\library\DirFile;
use think\facade\Env;
use think\facade\View;
class Apidoc
{
use Error;
protected $template = 'index.html';
protected $output = 'api.html';
protected $force = true;
/**
* 执行生成程序
* @param $title
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function execute($title)
{
// $addon = $input->getOption('addon');
// if($addon){
// $addon_service = new Addons();
// $addon_info = $addon_service->_info->getPluginInfo($addon);
// $controllerDir = Env::get('root_path') . DS . 'addons' . DS . $addon . DS . $addon_info['api_module'] . DS;
// }else{
$controllerDir = app()->getRootPath() . DS . 'app' . DS . 'controller' . DS . 'api' . DS;
// }
$files = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($controllerDir), \RecursiveIteratorIterator::LEAVES_ONLY
);
$weighs = [];
$k = 0;
foreach ($files as $name => $file) {
if (!$file->isDir()) {
$filePath = $file->getRealPath();
$className = $this->getClassFromFile($filePath);
$classAnnotations = Extractor::getClassAnnotations($className);
if (isset($classAnnotations['ApiInternal'])) {
continue;
}
$weigh = isset($classAnnotations['ApiWeigh']) ? intval($classAnnotations['ApiWeigh'][0]) : $k;
$weighs[$this->getClassFromFile($filePath)] = $weigh;
$k++;
}
}
uasort($weighs, function ($a, $b) {
if ($a == $b) return 0;
return ($a > $b) ? -1 : 1;
});
$classes = array_flip($weighs);
$builder = new Builder($classes);
$apiDir = __DIR__ . DS . 'apidoc' . DS;
$templateDir = $apiDir . 'template' . DS;
$templateFile = $templateDir . $this->template;
$var['plugin'] = '';
$var['title'] = $title;
$var['apiDomain'] = Env::get('domain.api');
$var['createSignKey'] = ConfServiceFacade::get('system.basic.signKey');
$var['apidocList'] = \plugin\apidoc\model\Apidoc::select()->toArray();
// $content = $builder->render($templateFile, $var);
$docslist = $builder->render($templateFile, $var);
$menu = [];
$menu[] = [
'id' => 0,
'title' => '全局说明',
'docType' => 'meditor'
];
$key = 0;
foreach($var['apidocList'] as $k=>$v){
$key++;
$temp = [];
$temp['id'] = $key;
$temp['title'] = $v['title'];
$temp['docType'] = 'meditor';
$menu[0]['children'][] = $temp;
}
foreach($docslist as $k=>$v){
$key++;
$temp = [];
$temp['id'] = $key;
$temp['title'] = $k;
$temp['docType'] = 'api';
foreach($v as $api){
$key++;
$children = [];
$children['id'] = $key;
$children['title'] = $api['title'];
$children['docType'] = 'api';
$temp['children'][] = $children;
}
$menu[] = $temp;
}
$menuOutputFile = app()->getRootPath() . 'public' . DS . 'static' . DS . 'admin' . DS . 'data' . DS . 'apidocMenu.json';
file_put_contents($menuOutputFile, json_encode($menu, JSON_UNESCAPED_UNICODE));
View::engine()->layout(false);
$content = View::display(file_get_contents($templateFile), array_merge($var, ['docslist' => $docslist]));
$outputDir = app()->getRootPath() . DS . 'public' . DS;
$outputFile = $outputDir . $this->output;
DirFile::createDir(dirname($outputFile));
if (!file_put_contents($outputFile, $content)) {
$this->setError('Cannot save the content to ' . $outputFile);
return false;
}
return true;
}
/**
* get full qualified class name
*
* @param string $path_to_file
* @return string
* @author JBYRNE http://jarretbyrne.com/2015/06/197/
*/
protected function getClassFromFile($path_to_file)
{
//Grab the contents of the file
$contents = file_get_contents($path_to_file);
//Start with a blank namespace and class
$namespace = $class = "";
//Set helper values to know that we have found the namespace/class token and need to collect the string values after them
$getting_namespace = $getting_class = false;
//Go through each token and evaluate it as necessary
foreach (token_get_all($contents) as $token) {
//If this token is the namespace declaring, then flag that the next tokens will be the namespace name
if (is_array($token) && $token[0] == T_NAMESPACE) {
$getting_namespace = true;
}
//If this token is the class declaring, then flag that the next tokens will be the class name
if (is_array($token) && $token[0] == T_CLASS) {
$getting_class = true;
}
//While we're grabbing the namespace name...
if ($getting_namespace === true) {
//If the token is a string or the namespace separator...
if (is_array($token) && in_array($token[0], [T_STRING, T_NS_SEPARATOR])) {
//Append the token's value to the name of the namespace
$namespace .= $token[1];
} else if ($token === ';') {
//If the token is the semicolon, then we're done with the namespace declaration
$getting_namespace = false;
}
}
//While we're grabbing the class name...
if ($getting_class === true) {
//If the token is a string, it's the name of the class
if (is_array($token) && $token[0] == T_STRING) {
//Store the token's value as the class name
$class = $token[1];
//Got what we need, stope here
break;
}
}
}
//Build the fully-qualified class name and return it
return $namespace ? $namespace . '\\' . $class : $class;
}
}
@@ -0,0 +1,209 @@
<?php
namespace plugin\apidoc\library\apidoc\library;
use think\facade\View;
/**
* @website https://github.com/calinrada/php-apidoc
* @author Calin Rada <rada.calin@gmail.com>
* @author Karson <karsonzhang@163.com>
*/
class Builder
{
/**
*
* @var \think\View
*/
public $view = null;
/**
* parse classes
* @var array
*/
protected $classes = [];
/**
*
* @param array $classes
*/
public function __construct($classes = [])
{
$this->classes = array_merge($this->classes, $classes);
}
protected function extractAnnotations()
{
$st_output = [];
foreach ($this->classes as $class) {
$st_output[] = Extractor::getAllClassAnnotations($class);
}
return end($st_output);
}
protected function generateHeadersTemplate($docs)
{
if (!isset($docs['ApiHeaders'])) {
return [];
}
$headerslist = [];
foreach ($docs['ApiHeaders'] as $params) {
$tr = [
'name' => $params['name'],
'type' => $params['type'],
'sample' => isset($params['sample']) ? $params['sample'] : '',
'required' => isset($params['required']) ? $params['required'] : false,
'description' => isset($params['description']) ? $params['description'] : '',
];
$headerslist[] = $tr;
}
return $headerslist;
}
protected function generateParamsTemplate($docs)
{
if (!isset($docs['ApiParams'])) {
return [];
}
$paramslist = [];
foreach ($docs['ApiParams'] as $params) {
$tr = [
'name' => $params['name'],
'type' => isset($params['type']) ? $params['type'] : 'string',
'sample' => isset($params['sample']) ? $params['sample'] : '',
'required' => isset($params['required']) ? $params['required'] : true,
'description' => isset($params['description']) ? $params['description'] : '',
];
$paramslist[] = $tr;
}
return $paramslist;
}
protected function generateReturnHeadersTemplate($docs)
{
if (!isset($docs['ApiReturnHeaders'])) {
return [];
}
$headerslist = [];
foreach ($docs['ApiReturnHeaders'] as $params) {
$tr = [
'name' => $params['name'],
'type' => 'string',
'sample' => isset($params['sample']) ? $params['sample'] : '',
'required' => isset($params['required']) && $params['required'] ? 'Yes' : 'No',
'description' => isset($params['description']) ? $params['description'] : '',
];
$headerslist[] = $tr;
}
return $headerslist;
}
protected function generateReturnParamsTemplate($st_params)
{
if (!isset($st_params['ApiReturnParams'])) {
return [];
}
$paramslist = [];
foreach ($st_params['ApiReturnParams'] as $params) {
$tr = [
'name' => $params['name'],
'type' => isset($params['type']) ? $params['type'] : 'string',
'sample' => isset($params['sample']) ? $params['sample'] : '',
'description' => isset($params['description']) ? $params['description'] : '',
];
$paramslist[] = $tr;
}
return $paramslist;
}
protected function generateBadgeForMethod($data)
{
$method = strtoupper(is_array($data['ApiMethod'][0]) ? $data['ApiMethod'][0]['data'] : $data['ApiMethod'][0]);
$labes = [
'POST' => 'label-primary',
'GET' => 'label-success',
'PUT' => 'label-warning',
'DELETE' => 'label-danger',
'PATCH' => 'label-default',
'OPTIONS' => 'label-info',
];
return isset($labes[$method]) ? $labes[$method] : $labes['GET'];
}
public function parse()
{
$annotations = $this->extractAnnotations();
$counter = 0;
$section = null;
$docslist = [];
foreach ($annotations as $class => $methods) {
foreach ($methods as $name => $docs) {
if (isset($docs['ApiSector'][0])) {
$section = is_array($docs['ApiSector'][0]) ? $docs['ApiSector'][0]['data'] : $docs['ApiSector'][0];
} else {
$section = $class;
}
if (0 === count($docs)) {
continue;
}
$docslist[$section][] = [
'id' => $counter,
'title' => $docs['ApiTitle'][0],
'method' => is_array($docs['ApiMethod'][0]) ? $docs['ApiMethod'][0]['data'] : $docs['ApiMethod'][0],
'method_label' => $this->generateBadgeForMethod($docs),
'section' => $section,
'route' => is_array($docs['ApiRoute'][0]) ? $docs['ApiRoute'][0]['data'] : $docs['ApiRoute'][0],
'summary' => is_array($docs['ApiSummary'][0]) ? $docs['ApiSummary'][0]['data'] : $docs['ApiSummary'][0],
'body' => isset($docs['ApiBody'][0]) ? is_array($docs['ApiBody'][0]) ? $docs['ApiBody'][0]['data'] : $docs['ApiBody'][0] : '',
'headerslist' => $this->generateHeadersTemplate($docs),
'paramslist' => $this->generateParamsTemplate($docs),
'returnheaderslist' => $this->generateReturnHeadersTemplate($docs),
'returnparamslist' => $this->generateReturnParamsTemplate($docs),
'return' => isset($docs['ApiReturn']) ? is_array($docs['ApiReturn'][0]) ? $docs['ApiReturn'][0]['data'] : $docs['ApiReturn'][0] : '',
];
$counter++;
}
}
return $docslist;
}
public function getView()
{
return $this->view;
}
/**
* 渲染
* @param $template
* @param array $vars
* @return array|string
*/
public function render($template, $vars = [])
{
$docslist = $this->parse();
$ids = [];
foreach ($docslist as $v) {
foreach ($v as $api) {
$ids[] = $api['id'];
}
}
return $docslist;
return View::display(file_get_contents($template), array_merge($vars, ['docslist' => $docslist, 'ids' => json_encode($ids)]));
}
}
@@ -0,0 +1,510 @@
<?php
namespace plugin\apidoc\library\apidoc\library;
use Exception;
/**
* Class imported from https://github.com/eriknyk/Annotations
* @author Erik Amaru Ortiz https://github.com/eriknyk
*
* @license http://opensource.org/licenses/bsd-license.php The BSD License
* @author Calin Rada <rada.calin@gmail.com>
*/
class Extractor
{
/**
* Static array to store already parsed annotations
* @var array
*/
private static $annotationCache;
/**
* Indicates that annotations should has strict behavior, 'false' by default
* @var boolean
*/
private $strict = false;
/**
* Stores the default namespace for Objects instance, usually used on methods like getMethodAnnotationsObjects()
* @var string
*/
public $defaultNamespace = '';
/**
* Sets strict variable to true/false
* @param bool $value boolean value to indicate that annotations to has strict behavior
*/
public function setStrict($value)
{
$this->strict = (bool)$value;
}
/**
* Sets default namespace to use in object instantiation
* @param string $namespace default namespace
*/
public function setDefaultNamespace($namespace)
{
$this->defaultNamespace = $namespace;
}
/**
* Gets default namespace used in object instantiation
* @return string $namespace default namespace
*/
public function getDefaultAnnotationNamespace()
{
return $this->defaultNamespace;
}
/**
* Gets all anotations with pattern @SomeAnnotation() from a given class
*
* @param string $className class name to get annotations
* @return array self::$annotationCache all annotated elements
*/
public static function getClassAnnotations($className)
{
if (!isset(self::$annotationCache[$className])) {
$class = new \ReflectionClass($className);
self::$annotationCache[$className] = self::parseAnnotations($class->getDocComment());
}
return self::$annotationCache[$className];
}
public static function getAllClassAnnotations($className)
{
$class = new \ReflectionClass($className);
foreach ($class->getMethods() as $object) {
self::$annotationCache['annotations'][$className][$object->name] = self::getMethodAnnotations($className, $object->name);
}
return self::$annotationCache['annotations'];
}
/**
* Gets all anotations with pattern @SomeAnnotation() from a determinated method of a given class
*
* @param string $className class name
* @param string $methodName method name to get annotations
* @return array self::$annotationCache all annotated elements of a method given
*/
public static function getMethodAnnotations($className, $methodName)
{
if (!isset(self::$annotationCache[$className . '::' . $methodName])) {
try {
$method = new \ReflectionMethod($className, $methodName);
$class = new \ReflectionClass($className);
if ($className == $method->class) {
if (!$method->isPublic() || $method->isConstructor()) {
$annotations = [];
} else {
$annotations = self::consolidateAnnotations($method, $class);
}
} else {
$annotations = [];
}
} catch (\ReflectionException $e) {
$annotations = [];
}
self::$annotationCache[$className . '::' . $methodName] = $annotations;
}
return self::$annotationCache[$className . '::' . $methodName];
}
/**
* Gets all anotations with pattern @SomeAnnotation() from a determinated method of a given class
* and instance its abcAnnotation class
*
* @param string $className class name
* @param string $methodName method name to get annotations
* @return array self::$annotationCache all annotated objects of a method given
*/
public function getMethodAnnotationsObjects($className, $methodName)
{
$annotations = $this->getMethodAnnotations($className, $methodName);
$objects = [];
$i = 0;
foreach ($annotations as $annotationClass => $listParams) {
$annotationClass = ucfirst($annotationClass);
$class = $this->defaultNamespace . $annotationClass . 'Annotation';
// verify is the annotation class exists, depending if Annotations::strict is true
// if not, just skip the annotation instance creation.
if (!class_exists($class)) {
if ($this->strict) {
throw new Exception(sprintf('Runtime Error: Annotation Class Not Found: %s', $class));
} else {
// silent skip & continue
continue;
}
}
if (empty($objects[$annotationClass])) {
$objects[$annotationClass] = new $class();
}
foreach ($listParams as $params) {
if (is_array($params)) {
foreach ($params as $key => $value) {
$objects[$annotationClass]->set($key, $value);
}
} else {
$objects[$annotationClass]->set($i++, $params);
}
}
}
return $objects;
}
private static function consolidateAnnotations($method, $class)
{
$dockblockClass = $class->getDocComment();
$docblockMethod = $method->getDocComment();
$methodName = $method->getName();
$methodAnnotations = self::parseAnnotations($docblockMethod);
$classAnnotations = self::parseAnnotations($dockblockClass);
if (isset($methodAnnotations['ApiInternal']) || $methodName == '_initialize' || $methodName == '_empty') {
return [];
}
$properties = $class->getDefaultProperties();
$noNeedLogin = isset($properties['noNeedLogin']) ? is_array($properties['noNeedLogin']) ? $properties['noNeedLogin'] : [$properties['noNeedLogin']] : [];
$noNeedRight = isset($properties['noNeedRight']) ? is_array($properties['noNeedRight']) ? $properties['noNeedRight'] : [$properties['noNeedRight']] : [];
preg_match_all("/\*[\s]+(.*)(\\r\\n|\\r|\\n)/U", str_replace('/**', '', $docblockMethod), $methodArr);
preg_match_all("/\*[\s]+(.*)(\\r\\n|\\r|\\n)/U", str_replace('/**', '', $dockblockClass), $classArr);
$methodTitle = isset($methodArr[1]) && isset($methodArr[1][0]) ? $methodArr[1][0] : '';
$classTitle = isset($classArr[1]) && isset($classArr[1][0]) ? $classArr[1][0] : '';
if (!isset($methodAnnotations['ApiMethod'])) {
$methodAnnotations['ApiMethod'] = ['get'];
}
if (!isset($methodAnnotations['ApiSummary'])) {
$methodAnnotations['ApiSummary'] = [$methodTitle];
}
if ($methodAnnotations) {
foreach ($classAnnotations as $name => $valueClass) {
if (count($valueClass) !== 1) {
continue;
}
if ($name === 'ApiRoute') {
if (isset($methodAnnotations[$name])) {
$methodAnnotations[$name] = [rtrim($valueClass[0], '/') . $methodAnnotations[$name][0]];
} else {
$methodAnnotations[$name] = [rtrim($valueClass[0], '/') . '/' . $method->getName()];
}
}
if ($name === 'ApiSector') {
$methodAnnotations[$name] = $valueClass;
}
}
}
if (!isset($methodAnnotations['ApiTitle'])) {
$methodAnnotations['ApiTitle'] = [$methodTitle];
}
if (!isset($methodAnnotations['ApiRoute'])) {
$urlArr = [];
$className = $class->getName();
list($prefix, $suffix) = explode('\\controller\\', $className);
$prefixArr = explode('\\', $prefix);
$suffixArr = explode('\\', $suffix);
if ($prefixArr[0] == 'app') {
$prefixArr[0] = '';
} else if ($prefixArr[0] == 'plugin') {
$tempPrefixArr = [];
$tempPrefixArr[0] = '';
$tempPrefixArr[1] = $prefixArr[2];
$prefixArr = $tempPrefixArr;
}
$urlArr = array_merge($urlArr, $prefixArr);
$urlArr[] = implode('.', array_map(function ($item) {
return self::parseName($item);
}, $suffixArr));
$urlArr[] = $method->getName();
$methodAnnotations['ApiRoute'] = [implode('/', $urlArr)];
}
if (!isset($methodAnnotations['ApiSector'])) {
$methodAnnotations['ApiSector'] = isset($classAnnotations['ApiSector']) ? $classAnnotations['ApiSector'] : [$classTitle];
}
if (!isset($methodAnnotations['ApiParams'])) {
$params = self::parseCustomAnnotations($docblockMethod, 'param');
foreach ($params as $k => $v) {
$arr = explode(' ', preg_replace("/[\s]+/", " ", $v));
$methodAnnotations['ApiParams'][] = [
'name' => isset($arr[1]) ? str_replace('$', '', $arr[1]) : '',
'nullable' => false,
'type' => isset($arr[0]) ? $arr[0] : 'string',
'description' => isset($arr[2]) ? $arr[2] : '',
];
}
}
$methodAnnotations['ApiPermissionLogin'] = [!in_array('*', $noNeedLogin) && !in_array($methodName, $noNeedLogin)];
$methodAnnotations['ApiPermissionRight'] = [!in_array('*', $noNeedRight) && !in_array($methodName, $noNeedRight)];
return $methodAnnotations;
}
/**
* 字符串命名风格转换
* type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格
* @access public
* @param string $name 字符串
* @param integer $type 转换类型
* @param bool $ucfirst 首字母是否大写(驼峰规则)
* @return string
*/
private static function parseName($name, $type = 0, $ucfirst = true)
{
if ($type) {
$name = preg_replace_callback('/_([a-zA-Z])/', function ($match) {
return strtoupper($match[1]);
}, $name);
return $ucfirst ? ucfirst($name) : lcfirst($name);
}
return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
}
/**
* Parse annotations
*
* @param string $docblock
* @param string $name
* @return array parsed annotations params
*/
private static function parseCustomAnnotations($docblock, $name = 'param')
{
$annotations = [];
$docblock = substr($docblock, 3, -2);
if (preg_match_all('/@' . $name . '(?:\s*(?:\(\s*)?(.*?)(?:\s*\))?)??\s*(?:\n|\*\/)/', $docblock, $matches)) {
foreach ($matches[1] as $k => $v) {
$annotations[] = $v;
}
}
return $annotations;
}
/**
* Parse annotations
*
* @param string $docblock
* @return array parsed annotations params
*/
private static function parseAnnotations($docblock)
{
$annotations = [];
// Strip away the docblock header and footer to ease parsing of one line annotations
$docblock = substr($docblock, 3, -2);
if (preg_match_all('/@(?<name>[A-Za-z_-]+)[\s\t]*\((?<args>(?:(?!\)).)*)\)\r?/s', $docblock, $matches)) {
$numMatches = count($matches[0]);
for ($i = 0; $i < $numMatches; ++$i) {
// annotations has arguments
if (isset($matches['args'][$i])) {
$argsParts = trim($matches['args'][$i]);
$name = $matches['name'][$i];
if ($name == 'ApiReturn') {
$value = $argsParts;
} else {
$argsParts = preg_replace("/\{(\w+)\}/", '#$1#', $argsParts);
$value = self::parseArgs($argsParts);
if (is_string($value)) {
$value = preg_replace("/\#(\w+)\#/", '{$1}', $argsParts);
}
}
} else {
$value = [];
}
$annotations[$name][] = $value;
}
}
return $annotations;
}
/**
* Parse individual annotation arguments
*
* @param string $content arguments string
* @return array annotated arguments
*/
private static function parseArgs($content)
{
// Replace initial stars
$content = preg_replace('/^\s*\*/m', '', $content);
$data = [];
$len = strlen($content);
$i = 0;
$var = '';
$val = '';
$level = 1;
$prevDelimiter = '';
$nextDelimiter = '';
$nextToken = '';
$composing = false;
$type = 'plain';
$delimiter = null;
$quoted = false;
$tokens = ['"', '"', '{', '}', ',', '='];
while ($i <= $len) {
$prev_c = substr($content, $i - 1, 1);
$c = substr($content, $i++, 1);
if ($c === '"' && $prev_c !== "\\") {
$delimiter = $c;
//open delimiter
if (!$composing && empty($prevDelimiter) && empty($nextDelimiter)) {
$prevDelimiter = $nextDelimiter = $delimiter;
$val = '';
$composing = true;
$quoted = true;
} else {
// close delimiter
if ($c !== $nextDelimiter) {
throw new Exception(sprintf(
"Parse Error: enclosing error -> expected: [%s], given: [%s]", $nextDelimiter, $c
));
}
// validating syntax
if ($i < $len) {
if (',' !== substr($content, $i, 1) && '\\' !== $prev_c) {
throw new Exception(sprintf(
"Parse Error: missing comma separator near: ...%s<--", substr($content, ($i - 10), $i)
));
}
}
$prevDelimiter = $nextDelimiter = '';
$composing = false;
$delimiter = null;
}
} elseif (!$composing && in_array($c, $tokens)) {
switch ($c) {
case '=':
$prevDelimiter = $nextDelimiter = '';
$level = 2;
$composing = false;
$type = 'assoc';
$quoted = false;
break;
case ',':
$level = 3;
// If composing flag is true yet,
// it means that the string was not enclosed, so it is parsing error.
if ($composing === true && !empty($prevDelimiter) && !empty($nextDelimiter)) {
throw new Exception(sprintf(
"Parse Error: enclosing error -> expected: [%s], given: [%s]", $nextDelimiter, $c
));
}
$prevDelimiter = $nextDelimiter = '';
break;
case '{':
$subc = '';
$subComposing = true;
while ($i <= $len) {
$c = substr($content, $i++, 1);
if (isset($delimiter) && $c === $delimiter) {
throw new Exception(sprintf(
"Parse Error: Composite variable is not enclosed correctly."
));
}
if ($c === '}') {
$subComposing = false;
break;
}
$subc .= $c;
}
// if the string is composing yet means that the structure of var. never was enclosed with '}'
if ($subComposing) {
throw new Exception(sprintf(
"Parse Error: Composite variable is not enclosed correctly. near: ...%s'", $subc
));
}
$val = self::parseArgs($subc);
break;
}
} else {
if ($level == 1) {
$var .= $c;
} elseif ($level == 2) {
$val .= $c;
}
}
if ($level === 3 || $i === $len) {
if ($type == 'plain' && $i === $len) {
$data = self::castValue($var);
} else {
$data[trim($var)] = self::castValue($val, !$quoted);
}
$level = 1;
$var = $val = '';
$composing = false;
$quoted = false;
}
}
return $data;
}
/**
* Try determinate the original type variable of a string
*
* @param string $val string containing possibles variables that can be cast to bool or int
* @param boolean $trim indicate if the value passed should be trimmed after to try cast
* @return mixed returns the value converted to original type if was possible
*/
private static function castValue($val, $trim = false)
{
if (is_array($val)) {
foreach ($val as $key => $value) {
$val[$key] = self::castValue($value);
}
} elseif (is_string($val)) {
if ($trim) {
$val = trim($val);
}
$val = stripslashes($val);
$tmp = strtolower($val);
if ($tmp === 'false' || $tmp === 'true') {
$val = $tmp === 'true';
} elseif (is_numeric($val)) {
return $val + 0;
}
unset($tmp);
}
return $val;
}
}
@@ -0,0 +1,744 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Cache" content="no-cache">
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>Api文档</title>
<!-- 依 赖 样 式 -->
<link rel="stylesheet" href="/static/component/laytp/css/laytp.css" />
<!-- 加 载 样 式-->
<link rel="stylesheet" href="/static/admin/css/load.css" />
<!-- 布 局 样 式 -->
<link rel="stylesheet" href="/static/admin/css/apidoc.css" />
</head>
<style>
.api-page-tab-content {
background-color: #fff;
overflow: auto;
min-height: 100%;
}
.api-url {
/*position: relative;*/
color: rgb(221, 17, 68);
background: #f6f6f6;
border: 1px solid #ddd;
}
.layui-form-pane .layui-form-label {
width: 280px;
/*height: 34px;*/
padding: 6px 15px;
}
.layui-form-pane .layui-input-block {
margin-left: 280px;
}
.editormd-preview-container, .editormd-html-preview {
width: 98% !important;
font-size: 16px;
}
.markdown-body li {
/* 使md编辑器中的li取消样式none */
list-style: unset;
}
.api-tab-title {
position: fixed;
left: 230px;
right: 0;
z-index: 999999;
background-color: #fff;
}
.layui-tab-bar{
display:none;
}
</style>
<!-- 结 构 代 码 -->
<body class="layui-layout-body laytp-admin">
<!-- 布 局 框 架 -->
<div class="layui-layout layui-layout-admin">
<div class="layui-header">
<!-- 顶 部 左 侧 功 能 -->
<ul class="layui-nav layui-layout-left">
<li class="collaspe layui-nav-item"><a href="javascript:void(0);" class="layui-icon layui-icon-shrink-right"></a></li>
</ul>
<!-- 顶 部 右 侧 菜 单 -->
<div id="control" class="layui-layout-control"></div>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item layui-hide-xs"><a href="javascript:void(0);" class="fullScreen layui-icon layui-icon-screen-full"></a></li>
<!-- 主 题 配 置 -->
<li class="layui-nav-item apiSet"><a href="javascript:void(0);" class="layui-icon layui-icon-set"></a></li>
<li class="layui-nav-item setting"><a href="javascript:void(0);" class="layui-icon layui-icon-more-vertical"></a></li>
</ul>
</div>
<!-- 侧 边 区 域 -->
<div class="layui-side layui-bg-black">
<!-- 菜 单 顶 部 -->
<div class="layui-logo">
<!-- 图 标 -->
<img class="logo" />
<!-- 标 题 -->
<span class="title"></span>
</div>
<!-- 菜 单 内 容 -->
<div>
<ul class="layui-nav arrow layui-nav-tree laytp-nav-tree" style="display: block;">
<li class="layui-nav-item">
<div class="search" style="padding: 5px;">
<input type="text" class="layui-input search-menu" placeholder="搜索文档">
</div>
</li>
</ul>
</div>
<div class="layui-side-scroll">
<div id="sideMenu"></div>
</div>
</div>
<!-- 视 图 页 面 -->
<div class="layui-body">
{php}$key = 0;{/php}
{foreach $apidocList as $k=>$v}
{php}$key++;{/php}
<div class="api-page-tab-content" id="meditor_{$key}" style="display:none;">
<div class="layui-tab layui-tab-brief">
<ul class="layui-tab-title api-tab-title">
<li class="layui-this">
{$v.title}
</li>
</ul>
<div class="layui-tab-content meditorContent api-content" id="meditor_{$v.id}_content">
<textarea style="display:none;">{$v.des}</textarea>
</div>
</div>
</div>
{/foreach}
{foreach $docslist as $k=>$v}
{php}$key++;{/php}
{foreach $v as $ak=>$api}
{php}$key++;{/php}
<div class="api-page-tab-content" id="api_{$key}" style="display:none;">
<div class="layui-tab layui-tab-brief">
<ul class="layui-tab-title api-tab-title">
<li class="layui-this">接口说明</li>
<li>在线测试</li>
</ul>
<div class="layui-tab-content markdown-body api-content">
<div class="layui-tab-item layui-show editormd-html-preview">
<p><strong>简要说明</strong></p>
<ul>
<li>{$api.summary}</li>
</ul>
<p><strong>请求方式</strong></p>
<ul>
<li><code class="api-url">{$api.method}</code></li>
</ul>
<p><strong>请求地址</strong></p>
<ul>
<li><code class="api-url" route="{if $apiDomain && substr($api['route'],0,5) === '/api.'}/{:substr($api['route'],5)}{else /}{$api.route}{/if}">{if $apiDomain && substr($api['route'],0,5) === '/api.'}/{:substr($api['route'],5)}{else /}{$api.route}{/if}</code></li>
</ul>
<p><strong>Headers参数</strong></p>
{if $api.headerslist}
<div style="width: 100%;overflow-x: auto;">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th style="text-align: left;">名称</th>
<th style="text-align: left;">类型</th>
<th style="text-align: left;">必选</th>
<th style="text-align: left;">描述</th>
</tr>
</thead>
<tbody>
{foreach $api.headerslist as $hk=>$hv}
<tr>
<td style="text-align:left">{$hv.name}</td>
<td style="text-align:left">{$hv.type}</td>
<td style="text-align:left">{if $hv.required}是{else}否{/if}</td>
<td>{$hv.description}</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{else}
<ul>
<li></li>
</ul>
{/if}
<p><strong>Body参数</strong></p>
{if $api.paramslist}
<div style="width: 100%;overflow-x: auto;">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th style="text-align: left;">名称</th>
<th style="text-align: left;">类型</th>
<th style="text-align: left;">必选</th>
<th style="text-align: left;">描述</th>
</tr>
</thead>
<tbody>
{foreach $api.paramslist as $pk=>$pv}
<tr>
<td style="text-align:left">{$pv.name}</td>
<td style="text-align:left">{$pv.type}</td>
<td style="text-align:left">{if $pv.required}是{else}否{/if}</td>
<td>{if $pv.sample}{$pv.description} -
例:{$pv.sample}{else}{$pv.description}{/if}
</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{else}
<ul>
<li></li>
</ul>
{/if}
<p><strong>返回示例</strong></p>
{if $api.return}
<pre><code class="json">{$api.return}</code></pre>
{else}
<ul>
<li></li>
</ul>
{/if}
<p><strong>返回说明</strong></p>
{if $api.returnparamslist}
<div style="width: 100%;overflow-x: auto;">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th style="text-align: left;">名称</th>
<th style="text-align: left;">类型</th>
<th style="text-align: left;">描述</th>
</tr>
</thead>
<tbody>
{foreach $api.returnparamslist as $pk=>$pv}
<tr>
<td style="text-align:left">{$pv.name}</td>
<td style="text-align:left">{$pv.type}</td>
<td style="text-align:left">{$pv.description}</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
{else}
<ul>
<li></li>
</ul>
{/if}
</div>
<div class="layui-tab-item editormd-html-preview">
<div class="layui-card">
<div class="layui-card-header" style="background-color: #F2F2F2;">Body传参</div>
<div class="layui-card-body main-container">
<form class="layui-form layui-form-pane" method="{$api.method}"
route="{if $apiDomain && substr($api['route'],0,5) === '/api.'}/{:substr($api['route'],5)}{else /}{$api.route}{/if}"
lay-filter="test_inline_{$key}" id="test_inline_{$key}">
{foreach $api.paramslist as $pk=>$pv}
<div class="layui-form-item">
<label class="layui-form-label">{$pv.name}</label>
<div class="layui-input-block">
{if($pv.type == 'array')}
<table class="layui-table">
<tbody>
<tr>
<td align="right" style="width:400px">
<input type="text" class="layui-input" name="{$pv.name}[]" autocomplete="off" placeholder="{if $pv.sample}{$pv.description} - 例:{$pv.sample}{else}请输入{$pv.description}{/if}" />
</td>
<td>
<a class="layui-btn layui-btn-primary layui-btn-sm layui-icon layui-icon-delete del-array-param"></a>
</td>
</tr>
<tr>
<td colspan="4">
<a class="layui-btn layui-btn-primary layui-btn-sm layui-icon layui-icon-add-1 add-array-param" data-field="{$pv.name}">追加参数</a>
</td>
</tr>
</tbody>
</table>
{else}
<input type="{if ($pv.type == 'file')}file{else}text{/if}"
name="{$pv.name}" autocomplete="off"
placeholder="{if $pv.sample}{$pv.description} - 例:{$pv.sample}{else}请输入{$pv.description}{/if}"
class="layui-input">
{/if}
</div>
</div>
{/foreach}
<div class="layui-form-item">
<div class="layui-input-block">
<button type="button" class="laytp-btn laytp-btn-primary"
href="javascript:void(0);"
onclick="api.testInline({$key})">提 交
</button>
</div>
</div>
</form>
</div>
</div>
<div class="layui-card" id="response_card_{$key}">
<div class="layui-card-header" style="background-color: #F2F2F2;">响应输出</div>
<div class="layui-card-body">
<pre><code class="json" id="response_{$key}"></code></pre>
<pre class="layui-code" id="response_headers_{$key}"></pre>
</div>
</div>
</div>
</div>
</div>
</div>
{/foreach}
{/foreach}
</div>
<!-- 遮 盖 层 -->
<div class="laytp-cover"></div>
<!-- 加 载 动 画-->
<div class="loader-main">
<div class="loader"></div>
</div>
</div>
<!-- 移 动 端 便 捷 操 作 -->
<div class="laytp-collasped-pe collaspe">
<a href="javascript:void(0);" class="layui-icon layui-icon-shrink-right"></a>
</div>
<!-- 请求配置弹出层内容开始 -->
<script type="text/html" id="set">
<div class="popup-content">
<div class="api-page-tab-content">
<form class="layui-form" lay-filter="setDataForm" id="setDataForm">
<div class="layui-form-item">
<label class="layui-form-label">Api请求域名</label>
<div class="layui-input-block">
<input type="text" name="apiUrl"
placeholder="完整的请求前缀,以http://或者https://开头,不以/结尾" autocomplete="off" class="layui-input"
value="{{d.apiUrl}}">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" title="开关">签名验证</label>
<div class="layui-input-block">
<!-- 隐藏域设置开关未选中时需要传递的参数值 -->
<input type="hidden" name="createSign" id="createSign-2" value="2"/>
<input type="checkbox" name="createSign" id="createSign-1" lay-skin="switch" lay-text="验证|不验证"
{{# if(d.createSign== 1){ }}checked="checked" {{# } }} value="1"/>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label" title="Header参数">Header参数</label>
<div class="layui-input-block">
<table class="layui-table">
<thead>
<tr>
<th>参数Key</th>
<th>参数Value</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td align="right">
<input type="text" class="layui-input" value="token" readonly="readonly"/>
</td>
<td>
<input type="text" class="layui-input" name="token" value="{{d.headerJson.token}}"
autocomplete="off"/>
</td>
<td></td>
</tr>
{{# let k; }}
{{# for(k in d.headerJson){ }}
{{# if(k !== "token" && k !== "sign" && k !== "request-time"){ }}
<tr>
<td align="right">
<input type="text" class="layui-input" name="header[key][]" value="{{k}}"
autocomplete="off"/>
</td>
<td>
<input type="text" class="layui-input" name="header[value][]"
value="{{d.headerJson[k]}}" autocomplete="off"/>
</td>
<td>
<a class="layui-btn layui-btn-primary layui-btn-sm layui-icon layui-icon-delete del-header-param"></a>
</td>
</tr>
{{# } }}
{{# } }}
<tr>
<td colspan="4">
<a class="layui-btn layui-btn-primary layui-btn-sm layui-icon layui-icon-add-1 add-header-param">追加参数</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</form>
</div>
</div>
</script>
<!-- 请求配置弹出层内容结束 -->
<script type="text/html" id="arrayParam">
<table class="layui-table">
<tbody>
<tr>
<td align="right">
<input type="text" class="layui-input" name="{{d.field}}[]" autocomplete="off"/>
</td>
<td>
<a class="layui-btn layui-btn-primary layui-btn-sm layui-icon layui-icon-delete del-array-param"></a>
</td>
</tr>
<tr>
<td colspan="4">
<a class="layui-btn layui-btn-primary layui-btn-sm layui-icon layui-icon-add-1 add-array-param">追加参数</a>
</td>
</tr>
</tbody>
</table>
</script>
<!-- 依 赖 脚 本 -->
<script type="text/javascript" src="/static/component/jquery_3.3.1.js" charset="utf-8"></script>
<script type="text/javascript" src="/static/component/jquery.serializejson.min.js" charset="utf-8"></script>
<script type="text/javascript" src="/static/component/highlight/highlight.pack.js" charset="utf-8"></script>
<link rel="stylesheet" type="text/css" href="/static/component/highlight/styles/docco.css"/>
<link rel="stylesheet" href="/static/plugin/meditor/css/editormd.css"/>
<script src="/static/plugin/meditor/lib/marked.min.js"></script>
<script src="/static/plugin/meditor/lib/prettify.min.js"></script>
<script src="/static/plugin/meditor/lib/flowchart.min.js"></script>
<script src="/static/plugin/meditor/lib/raphael.min.js"></script>
<script src="/static/plugin/meditor/lib/underscore.min.js"></script>
<script src="/static/plugin/meditor/lib/sequence-diagram.min.js"></script>
<script src="/static/plugin/meditor/lib/jquery.flowchart.min.js"></script>
<script src="/static/plugin/meditor/editormd.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.18.0/js/md5.js"></script>
<script>
// 初始化静态文件版本号
localStorage.setItem("version","1.0.2.Release");
document.write("<script src='/static/component/layui/layui.js?v="+localStorage.getItem("version")+"'><\/script>");
document.write("<script src='/static/component/laytp/layuiConfig.js?v="+localStorage.getItem("version")+"'><\/script>");
</script>
<!-- 框 架 初 始 化 -->
<script>
//定义storage
let storage = (function () {
let storage;
try {
storage = window.localStorage;
return storage;
} catch (exception) {
return false;
}
}());
layui.use(['laytp','apidoc','popup'], function() {
let createSignKey = "{$createSignKey}";
let apiDomain = "{$apiDomain}";
let apiUrl = (apiDomain.length > 0) ? apiDomain : window.location.protocol + "//" + window.location.host;
//请求配置
let nowSetJson = storage.getItem("setJson") ? JSON.parse(storage.getItem("setJson")) : {
apiUrl: apiUrl,
createSign: 2,
headerJson: {token: ""}
};
//渲染所有的meditor编辑器内容
layui.each($(".meditorContent"), function (key, item) {
editormd.markdownToHTML($(item).attr('id'), {
htmlDecode: "style,script,iframe", // you can filter tags decode
emoji: true,
taskList: true,
tex: true, // 默认不解析
flowChart: true, // 默认不解析
sequenceDiagram: true, // 默认不解析
});
});
//当表格列数过长时将自动出现滚动条
var themeColorContext = layui.context.get('theme-color-context');
$.each($('table'), function (i, item) {
if($(this).attr('class') !== 'layui-table'){
$('thead > tr', this).attr('style', 'background-color: '+themeColorContext+';color:white;');
$(this).prop('outerHTML', '<div style="width: 95%;overflow-x: auto;">' + $(this).prop('outerHTML') + '</div>');
}
});
//弹窗展示请求配置
$(document).off("click", ".apiSet").on("click", ".apiSet", function () {
let layerDiv = layui.layer.open({
type: 1,
offset: 'r',
area: ['600px', '100%'],
title: "请求配置",
content: layui.laytpl($("#set").html()).render(nowSetJson),
shade: 0.1,
closeBtn: 0,
shadeClose: false,
anim: -1,
skin: 'layer-anim-right',
move: false,
success: function (layero, index) {
$(document).off("click", '#layui-layer-shade' + index).on("click", '#layui-layer-shade' + index, function () {
var $layero = $('#layui-layer' + index);
$layero.animate({
left: $layero.offset().left + $layero.width()
}, 200, function() {
let formJson = $('#setDataForm').serializeJSON();
let headerJson = {
token: formJson.token
};
let keyJson = {};
if (formJson.hasOwnProperty("header") && formJson.header.hasOwnProperty("key")) {
keyJson = formJson.header.key;
}
let valueJson = {};
if (formJson.hasOwnProperty("header") && formJson.header.hasOwnProperty("value")) {
valueJson = formJson.header.value;
}
$.each(keyJson, function (key, item) {
if(keyJson[key]){
headerJson[keyJson[key]] = valueJson[key];
}
});
let setJson = {
apiUrl: formJson.apiUrl,
createSign: formJson.createSign,
headerJson: headerJson
};
nowSetJson = setJson;
storage.setItem("setJson", JSON.stringify(setJson));
facade.success("保存成功");
layer.close(index);
});
});
},
btn: ['保 存', '取 消'],
yes: function (index, layero) {
let formJson = $('#setDataForm').serializeJSON();
let headerJson = {
token: formJson.token
};
let keyJson = {};
if (formJson.hasOwnProperty("header") && formJson.header.hasOwnProperty("key")) {
keyJson = formJson.header.key;
}
let valueJson = {};
if (formJson.hasOwnProperty("header") && formJson.header.hasOwnProperty("value")) {
valueJson = formJson.header.value;
}
$.each(keyJson, function (key, item) {
if(keyJson[key]){
headerJson[keyJson[key]] = valueJson[key];
}
});
let setJson = {
apiUrl: formJson.apiUrl,
createSign: formJson.createSign,
headerJson: headerJson
};
nowSetJson = setJson;
storage.setItem("setJson", JSON.stringify(setJson));
facade.success("保存成功");
layer.close(index);
}
});
layui.laytpForm.render("#layui-layer" + layerDiv);
});
//追加Header参数
$(document).off("click", ".add-header-param").on("click", ".add-header-param", function () {
let clickObj = $(this);
let template = '<tr>' +
'<td align="right">' +
'<input type="text" class="layui-input" name="header[key][]" autocomplete="off" />' +
'</td>' +
'<td>' +
'<input type="text" class="layui-input" name="header[value][]" autocomplete="off" />' +
'</td>' +
'<td>' +
'<a class="layui-btn layui-btn-primary layui-btn-sm layui-icon layui-icon-delete del-header-param"></a>' +
'</td>' +
'</tr>';
clickObj.parent().parent().before(template);
});
//追加数组参数
$(document).off("click", ".add-array-param").on("click", ".add-array-param", function () {
let clickObj = $(this);
let field = clickObj.data('field');
let template = '<tr>' +
'<td align="right">' +
'<input type="text" class="layui-input" name="' + field + '[]" autocomplete="off" />' +
'</td>' +
'<td>' +
'<a class="layui-btn layui-btn-primary layui-btn-sm layui-icon layui-icon-delete del-array-param"></a>' +
'</td>' +
'</tr>';
clickObj.parent().parent().before(template);
});
//删除header参数
$(document).off("click", ".del-header-param").on("click", ".del-header-param", function () {
let clickObj = $(this);
clickObj.parent().parent().remove();
});
//删除array参数
$(document).off("click", ".del-array-param").on("click", ".del-array-param", function () {
let clickObj = $(this);
clickObj.parent().parent().remove();
});
layui.apidoc.setConfigType("yml");
layui.apidoc.setConfigPath("/static/component/laytp/config/api.config.yml?v=" + localStorage.getItem("version"));
layui.apidoc.render();
// 搜索菜单功能添加在这里,不要添加到js组件里面,因为会在子页面进行调用,这里只会在父页面执行
// 这里被注释的代码,触发搜索菜单要按下回车键
$(".search-menu").focus(
function(){
$(document).on("keydown",
function(event){
if( event.keyCode === 13 ){
window.searchMenuData = [];
var searchKey = $(".search-menu").val();
if(searchKey){
searchMenu(window.menuData, searchKey);
layui.apidoc.setConfigType("yml");
layui.apidoc.setConfigPath("/static/component/laytp/config/api.config.yml?v=" + localStorage.getItem("version"));
var param = layui.apidoc.readConfig();
param.menu.async = false;
param.menu.data = window.searchMenuData;
param.isSearch = true;
layui.apidoc.render(param);
}else{
$("#sideMenu").show();
$("#searchSideMenu").hide();
renderMenu();
}
}
}
);
$(".search-menu").unbind();
}
);
// 递归搜索菜单
window.searchMenu = function(menuData, searchKey){
searchKey = searchKey.toLowerCase();
$.each(menuData, function(i, item) {
var oldTitle = item.title;
item.title = item.title.toLowerCase();
if(item.title.indexOf(searchKey) > -1){
item.title = oldTitle;
window.searchMenuData.push(item);
}else{
item.title = oldTitle;
if(item.children && item.children.length > 0){
searchMenu(item.children, searchKey);
}
}
});
};
// 重新渲染菜单
window.renderMenu = function(){
$(".search-menu").val('');
layui.apidoc.setConfigType("yml");
layui.apidoc.setConfigPath("/static/component/laytp/config/api.config.yml?v=" + localStorage.getItem("version"));
var config = layui.apidoc.readConfig();
layui.apidoc.menuRender(config);
};
window.api = {
testInline: function (id) {
let route = $("#test_inline_" + id).attr('route');
let url = nowSetJson.apiUrl + route;
let method = $("#test_inline_" + id).attr('method');
if (nowSetJson.createSign === "1") {
nowSetJson.headerJson['request-time'] = Date.now();
nowSetJson.headerJson.sign = api.createSign(nowSetJson.headerJson['request-time']);
}
let formData = new FormData();
$('#test_inline_'+id).find('input').each(function (i, input) {
if ($(input).attr('type') == 'file') {
formData.append($(input).attr('name'), $(input)[0].files[0]);
} else {
formData.append($(input).attr('name'), $(input).val())
}
});
$.ajax({
url: url,
headers: nowSetJson.headerJson,
data: $('#test_inline_'+id).prop('method').toLowerCase() == 'get' ? $('#test_inline_'+id).serialize() : formData,
type: method,
dataType: 'json',
contentType: false,
processData: false,
success: function (data, textStatus, xhr) {
if (typeof data === 'object') {
var str = JSON.stringify(data, null, 2);
if(str) {
$('#response_' + id).html(hljs.highlightAuto(str).value);
}
} else {
$('#response_' + id).html(data || '');
}
$('#response_headers_' + id).html('HTTP ' + xhr.status + ' ' + xhr.statusText + '<br/><br/>' + xhr.getAllResponseHeaders());
$('#response_card_' + id).show();
facade.success('请求成功');
},
error: function (xhr) {
try {
var str = JSON.stringify($.parseJSON(xhr.responseText), null, 2);
} catch (e) {
var str = xhr.responseText;
}
$('#response_headers_' + id).html('HTTP ' + xhr.status + ' ' + xhr.statusText + '<br/><br/>' + xhr.getAllResponseHeaders());
if(str){
$('#response_' + id).html(hljs.highlightAuto(str).value);
}
$('#response_card_' + id).show();
facade.error('请求失败');
}
});
return false;
},
createSign: function (requestTime) {
return md5(md5(requestTime) + md5(createSignKey)).toUpperCase();
},
};
});
</script>
</body>
</html>