execute .gitignore
This commit is contained in:
14
.bowerrc
14
.bowerrc
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"directory": "public/assets/libs",
|
||||
"ignoredDependencies": [
|
||||
"es6-promise",
|
||||
"file-saver",
|
||||
"html2canvas",
|
||||
"jspdf",
|
||||
"jspdf-autotable",
|
||||
"pdfmake"
|
||||
],
|
||||
"scripts":{
|
||||
"postinstall": "node bower-cleanup.js"
|
||||
}
|
||||
}
|
||||
11
.env.sample
11
.env.sample
@@ -1,11 +0,0 @@
|
||||
[app]
|
||||
debug = false
|
||||
trace = false
|
||||
|
||||
[database]
|
||||
hostname = 127.0.0.1
|
||||
database = fast
|
||||
username = root
|
||||
password = root
|
||||
hostport = 3306
|
||||
prefix =
|
||||
14
.gitignore
vendored
14
.gitignore
vendored
@@ -1,14 +0,0 @@
|
||||
/runtime/*
|
||||
/public/uploads/*
|
||||
.DS_Store
|
||||
.idea
|
||||
composer.lock
|
||||
*.log
|
||||
*.css.map
|
||||
!.gitkeep
|
||||
.env
|
||||
.svn
|
||||
.vscode
|
||||
node_modules
|
||||
.user.ini
|
||||
/addons/*/config.php
|
||||
4
.npmrc
4
.npmrc
@@ -1,4 +0,0 @@
|
||||
# 使用自定义镜像源
|
||||
registry=http://mirrors.tencent.com/npm/
|
||||
#关闭SSL验证
|
||||
strict-ssl=false
|
||||
139
Gruntfile.js
139
Gruntfile.js
@@ -1,139 +0,0 @@
|
||||
module.exports = function (grunt) {
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON('package.json'),
|
||||
copy: {
|
||||
main: {
|
||||
files: []
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var build = function (module, type, callback) {
|
||||
var config = {
|
||||
compile: {
|
||||
options: type === 'js' ? {
|
||||
optimizeCss: "standard",
|
||||
optimize: "uglify", //可使用uglify|closure|none
|
||||
preserveLicenseComments: true,
|
||||
removeCombined: false,
|
||||
baseUrl: "./public/assets/js/", //JS文件所在的基础目录
|
||||
name: "require-" + module, //来源文件,不包含后缀
|
||||
out: "./public/assets/js/require-" + module + ".min.js" //目标文件
|
||||
} : {
|
||||
optimizeCss: "default",
|
||||
optimize: "uglify", //可使用uglify|closure|none
|
||||
cssIn: "./public/assets/css/" + module + ".css", //CSS文件所在的基础目录
|
||||
out: "./public/assets/css/" + module + ".min.css" //目标文件
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
var content = grunt.file.read("./public/assets/js/require-" + module + ".js"),
|
||||
pattern = /^require\.config\(\{[\r\n]?[\n]?(.*?)[\r\n]?[\n]?}\);/is;
|
||||
|
||||
var matches = content.match(pattern);
|
||||
if (matches) {
|
||||
if (type === 'js') {
|
||||
var data = matches[1].replaceAll(/(urlArgs|baseUrl):(.*)\n/gi, '');
|
||||
const parse = require('parse-config-file'), fs = require('fs');
|
||||
require('jsonminify');
|
||||
|
||||
data = JSON.minify("{\n" + data + "\n}");
|
||||
let options = parse(data);
|
||||
options.paths.tableexport = "empty:";
|
||||
Object.assign(config.compile.options, options);
|
||||
}
|
||||
let requirejs = require("./application/admin/command/Min/r");
|
||||
|
||||
try {
|
||||
requirejs.optimize(config.compile.options, function (buildResponse) {
|
||||
// var contents = require('fs').readFileSync(config.compile.options.out, 'utf8');
|
||||
callback();
|
||||
}, function (err) {
|
||||
console.error(err);
|
||||
callback();
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
callback();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 加载 "copy" 插件
|
||||
grunt.loadNpmTasks('grunt-contrib-copy');
|
||||
|
||||
grunt.registerTask('frontend:js', 'build frontend js', function () {
|
||||
var done = this.async();
|
||||
build('frontend', 'js', done);
|
||||
});
|
||||
|
||||
grunt.registerTask('backend:js', 'build backend js', function () {
|
||||
var done = this.async();
|
||||
build('backend', 'js', done);
|
||||
});
|
||||
|
||||
grunt.registerTask('frontend:css', 'build frontend css', function () {
|
||||
var done = this.async();
|
||||
build('frontend', 'css', done);
|
||||
});
|
||||
|
||||
grunt.registerTask('backend:css', 'build frontend css', function () {
|
||||
var done = this.async();
|
||||
build('backend', 'css', done);
|
||||
});
|
||||
|
||||
// 注册部署JS和CSS任务
|
||||
grunt.registerTask('deploy', 'deploy', function () {
|
||||
const fs = require('fs');
|
||||
const path = require("path")
|
||||
const nodeModulesDir = path.resolve(__dirname, "./node_modules");
|
||||
|
||||
const getAllFiles = function (dirPath, arrayOfFiles) {
|
||||
files = fs.readdirSync(dirPath)
|
||||
|
||||
arrayOfFiles = arrayOfFiles || []
|
||||
|
||||
files.forEach(function (file) {
|
||||
if (fs.statSync(dirPath + "/" + file).isDirectory()) {
|
||||
arrayOfFiles = getAllFiles(dirPath + "/" + file, arrayOfFiles)
|
||||
} else {
|
||||
arrayOfFiles.push(path.join(__dirname, dirPath, "/", file))
|
||||
}
|
||||
});
|
||||
|
||||
return arrayOfFiles
|
||||
};
|
||||
const mainPackage = grunt.config.get('pkg');
|
||||
let dists = mainPackage.dists || [];
|
||||
let files = [];
|
||||
|
||||
// 兼容旧版本bower使用的目录
|
||||
let specialKey = {
|
||||
'fastadmin-bootstraptable': 'bootstrap-table',
|
||||
'sortablejs': 'Sortable',
|
||||
'tableexport.jquery.plugin': 'tableExport.jquery.plugin',
|
||||
};
|
||||
Object.keys(dists).forEach(key => {
|
||||
let src = ["**/*LICENSE*", "**/*license*"];
|
||||
src = src.concat(Array.isArray(dists[key]) ? dists[key] : [dists[key]]);
|
||||
files.push({expand: true, cwd: nodeModulesDir + "/" + key, src: src, dest: 'public/assets/libs/' + (specialKey[key] || key) + "/"});
|
||||
});
|
||||
|
||||
// 兼容bower历史路径文件
|
||||
files = [...files,
|
||||
{src: nodeModulesDir + "/toastr/build/toastr.min.css", dest: "public/assets/libs/toastr/toastr.min.css"},
|
||||
{src: nodeModulesDir + "/bootstrap-slider/dist/css/bootstrap-slider.css", dest: "public/assets/libs/bootstrap-slider/slider.css"},
|
||||
{expand: true, cwd: nodeModulesDir + "/bootstrap-slider/dist", src: ["*.js"], dest: "public/assets/libs/bootstrap-slider/"}
|
||||
]
|
||||
|
||||
grunt.config.set('copy.main.files', files);
|
||||
grunt.task.run("copy:main");
|
||||
});
|
||||
|
||||
// 注册默认任务
|
||||
grunt.registerTask('default', ['deploy', 'frontend:js', 'backend:js', 'frontend:css', 'backend:css']);
|
||||
|
||||
};
|
||||
191
LICENSE
191
LICENSE
@@ -1,191 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, "control" means (i) the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
"submitted" means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||
Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||
such license applies only to those patent claims licensable by such Contributor
|
||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||
submitted. If You institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||
Contribution incorporated within the Work constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to You under this License
|
||||
for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution.
|
||||
|
||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||
in any medium, with or without modifications, and in Source or Object form,
|
||||
provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source form
|
||||
of the Work, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works; and
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any
|
||||
Derivative Works that You distribute must include a readable copy of the
|
||||
attribution notices contained within such NOTICE file, excluding those notices
|
||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||
following places: within a NOTICE text file distributed as part of the
|
||||
Derivative Works; within the Source form or documentation, if provided along
|
||||
with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents of
|
||||
the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works that
|
||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||
provided that such additional attribution notices cannot be construed as
|
||||
modifying the License.
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction, or
|
||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||
with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions.
|
||||
|
||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||
conditions of this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||
any separate license agreement you may have executed with Licensor regarding
|
||||
such Contributions.
|
||||
|
||||
6. Trademarks.
|
||||
|
||||
This License does not grant permission to use the trade names, trademarks,
|
||||
service marks, or product names of the Licensor, except as required for
|
||||
reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||
including, without limitation, any warranties or conditions of TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||
solely responsible for determining the appropriateness of using or
|
||||
redistributing the Work and assume any risks associated with Your exercise of
|
||||
permissions under this License.
|
||||
|
||||
8. Limitation of Liability.
|
||||
|
||||
In no event and under no legal theory, whether in tort (including negligence),
|
||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special, incidental,
|
||||
or consequential damages of any character arising as a result of this License or
|
||||
out of the use or inability to use the Work (including but not limited to
|
||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||
any and all other commercial damages or losses), even if such Contributor has
|
||||
been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability.
|
||||
|
||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||
other liability obligations and/or rights consistent with this License. However,
|
||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason of your
|
||||
accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets "{}" replaced with your own
|
||||
identifying information. (Don't include the brackets!) The text should be
|
||||
enclosed in the appropriate comment syntax for the file format. We also
|
||||
recommend that a file or class name and description of purpose be included on
|
||||
the same "printed page" as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright 2017 Karson
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,5 +0,0 @@
|
||||
FastAdmin是一款基于ThinkPHP+Bootstrap的极速后台开发框架。
|
||||
|
||||
### 队列启动命令
|
||||
- php think queue:work --daemon --queue shopro
|
||||
- php think queue:work --daemon --queue shopro-high
|
||||
7
add.sql
7
add.sql
@@ -1,7 +0,0 @@
|
||||
ALTER TABLE `zy_club` ADD COLUMN `intro` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '介绍' AFTER `blurb`;
|
||||
ALTER TABLE `zy_club` ADD COLUMN `contect` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '联系方式' AFTER `img`;
|
||||
ALTER TABLE `zy_club` ADD COLUMN `attention` int(11) NOT NULL DEFAULT 0 COMMENT '关注人数' AFTER `contect`;
|
||||
-- 已执行 2025-05-18
|
||||
|
||||
ALTER TABLE `zy_circle` ADD COLUMN `top` int NOT NULL DEFAULT 0 COMMENT '置顶' AFTER `status`;
|
||||
-- 已执行 2025-05-31
|
||||
@@ -1 +0,0 @@
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
deny from all
|
||||
@@ -1 +0,0 @@
|
||||
{"files":["public\\assets\\addons\\address\\js\\gcoord.min.js","public\\assets\\addons\\address\\js\\jquery.autocomplete.js"],"license":"regular","licenseto":"34485","licensekey":"Fr1gIoX2PBbGmMnp GFErXGAvLGllzXV\/ASjNRQ==","domains":["localhost"],"licensecodes":[],"validations":["757319b447175b6ca1882635b132a594"]}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\address;
|
||||
|
||||
use think\Addons;
|
||||
|
||||
/**
|
||||
* 地址选择
|
||||
* @author [MiniLing] <[laozheyouxiang@163.com]>
|
||||
*/
|
||||
class Address extends Addons
|
||||
{
|
||||
|
||||
/**
|
||||
* 插件安装方法
|
||||
* @return bool
|
||||
*/
|
||||
public function install()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件卸载方法
|
||||
* @return bool
|
||||
*/
|
||||
public function uninstall()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
34
addons/address/bootstrap.js
vendored
34
addons/address/bootstrap.js
vendored
@@ -1,34 +0,0 @@
|
||||
require([], function () {
|
||||
//绑定data-toggle=addresspicker属性点击事件
|
||||
|
||||
$(document).on('click', "[data-toggle='addresspicker']", function () {
|
||||
var that = this;
|
||||
var callback = $(that).data('callback');
|
||||
var input_id = $(that).data("input-id") ? $(that).data("input-id") : "";
|
||||
var lat_id = $(that).data("lat-id") ? $(that).data("lat-id") : "";
|
||||
var lng_id = $(that).data("lng-id") ? $(that).data("lng-id") : "";
|
||||
var zoom_id = $(that).data("zoom-id") ? $(that).data("zoom-id") : "";
|
||||
var lat = lat_id ? $("#" + lat_id).val() : '';
|
||||
var lng = lng_id ? $("#" + lng_id).val() : '';
|
||||
var zoom = zoom_id ? $("#" + zoom_id).val() : '';
|
||||
var url = "/addons/address/index/select";
|
||||
url += (lat && lng) ? '?lat=' + lat + '&lng=' + lng + (input_id ? "&address=" + $("#" + input_id).val() : "") + (zoom ? "&zoom=" + zoom : "") : '';
|
||||
Fast.api.open(url, '位置选择', {
|
||||
callback: function (res) {
|
||||
input_id && $("#" + input_id).val(res.address).trigger("change");
|
||||
lat_id && $("#" + lat_id).val(res.lat).trigger("change");
|
||||
lng_id && $("#" + lng_id).val(res.lng).trigger("change");
|
||||
zoom_id && $("#" + zoom_id).val(res.zoom).trigger("change");
|
||||
|
||||
try {
|
||||
//执行回调函数
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(that, res);
|
||||
}
|
||||
} catch (e) {
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,132 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
[
|
||||
'name' => 'maptype',
|
||||
'title' => '默认地图类型',
|
||||
'type' => 'radio',
|
||||
'content' => [
|
||||
'baidu' => '百度地图',
|
||||
'amap' => '高德地图',
|
||||
'tencent' => '腾讯地图',
|
||||
],
|
||||
'value' => 'amap',
|
||||
'rule' => 'required',
|
||||
'msg' => '',
|
||||
'tip' => '',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'zoom',
|
||||
'title' => '默认缩放级别',
|
||||
'type' => 'string',
|
||||
'content' => [],
|
||||
'value' => '11',
|
||||
'rule' => 'required',
|
||||
'msg' => '',
|
||||
'tip' => '',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'lat',
|
||||
'title' => '默认Lat',
|
||||
'type' => 'string',
|
||||
'content' => [],
|
||||
'value' => '23.002569',
|
||||
'rule' => 'required',
|
||||
'msg' => '',
|
||||
'tip' => '',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'lng',
|
||||
'title' => '默认Lng',
|
||||
'type' => 'string',
|
||||
'content' => [],
|
||||
'value' => '113.752215',
|
||||
'rule' => 'required',
|
||||
'msg' => '',
|
||||
'tip' => '',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'baidukey',
|
||||
'title' => '百度地图KEY',
|
||||
'type' => 'string',
|
||||
'content' => [],
|
||||
'value' => '',
|
||||
'rule' => '',
|
||||
'msg' => '',
|
||||
'tip' => '',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'amapkey',
|
||||
'title' => '高德地图KEY',
|
||||
'type' => 'string',
|
||||
'content' => [],
|
||||
'value' => '78c9a922ba2d29f005eaa89e3f1b00bb',
|
||||
'rule' => '',
|
||||
'msg' => '',
|
||||
'tip' => '',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'amapsecurityjscode',
|
||||
'title' => '高德地图安全密钥',
|
||||
'type' => 'string',
|
||||
'content' => [],
|
||||
'value' => '',
|
||||
'rule' => '',
|
||||
'msg' => '',
|
||||
'tip' => '',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'tencentkey',
|
||||
'title' => '腾讯地图KEY',
|
||||
'type' => 'string',
|
||||
'content' => [],
|
||||
'value' => '',
|
||||
'rule' => '',
|
||||
'msg' => '',
|
||||
'tip' => '',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'coordtype',
|
||||
'title' => '坐标系类型',
|
||||
'type' => 'select',
|
||||
'content' => [
|
||||
'DEFAULT' => '默认(使用所选地图默认坐标系)',
|
||||
'GCJ02' => 'GCJ-02',
|
||||
'BD09' => 'BD-09',
|
||||
],
|
||||
'value' => 'DEFAULT',
|
||||
'rule' => 'required',
|
||||
'msg' => '',
|
||||
'tip' => '',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
[
|
||||
'name' => '__tips__',
|
||||
'title' => '温馨提示',
|
||||
'type' => '',
|
||||
'content' => [],
|
||||
'value' => '请先申请对应地图的Key,配置后再使用',
|
||||
'rule' => '',
|
||||
'msg' => '',
|
||||
'tip' => '',
|
||||
'ok' => '',
|
||||
'extend' => 'alert-danger-light',
|
||||
],
|
||||
];
|
||||
@@ -1,64 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\address\controller;
|
||||
|
||||
use think\addons\Controller;
|
||||
use think\Config;
|
||||
use think\Hook;
|
||||
|
||||
class Index extends Controller
|
||||
{
|
||||
|
||||
// 首页
|
||||
public function index()
|
||||
{
|
||||
// 语言检测
|
||||
$lang = $this->request->langset();
|
||||
$lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
|
||||
|
||||
$site = Config::get("site");
|
||||
|
||||
// 配置信息
|
||||
$config = [
|
||||
'site' => array_intersect_key($site, array_flip(['name', 'cdnurl', 'version', 'timezone', 'languages'])),
|
||||
'upload' => null,
|
||||
'modulename' => 'addons',
|
||||
'controllername' => 'index',
|
||||
'actionname' => 'index',
|
||||
'jsname' => 'addons/address',
|
||||
'moduleurl' => '',
|
||||
'language' => $lang
|
||||
];
|
||||
$config = array_merge($config, Config::get("view_replace_str"));
|
||||
|
||||
// 配置信息后
|
||||
Hook::listen("config_init", $config);
|
||||
// 加载当前控制器语言包
|
||||
$this->view->assign('site', $site);
|
||||
$this->view->assign('config', $config);
|
||||
|
||||
return $this->view->fetch();
|
||||
}
|
||||
|
||||
// 选择地址
|
||||
public function select()
|
||||
{
|
||||
$config = get_addon_config('address');
|
||||
$zoom = (int)$this->request->get('zoom', $config['zoom']);
|
||||
$lng = (float)$this->request->get('lng');
|
||||
$lat = (float)$this->request->get('lat');
|
||||
$address = $this->request->get('address');
|
||||
$lng = $lng ?: $config['lng'];
|
||||
$lat = $lat ?: $config['lat'];
|
||||
$this->view->assign('zoom', $zoom);
|
||||
$this->view->assign('lng', $lng);
|
||||
$this->view->assign('lat', $lat);
|
||||
$this->view->assign('address', $address);
|
||||
$maptype = $config['maptype'];
|
||||
if (!isset($config[$maptype . 'key']) || !$config[$maptype . 'key']) {
|
||||
$this->error("请在配置中配置对应类型地图的密钥");
|
||||
}
|
||||
return $this->view->fetch('index/' . $maptype);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
name = address
|
||||
title = 地址位置选择插件
|
||||
intro = 地图位置选择插件,可返回地址和经纬度
|
||||
author = FastAdmin
|
||||
website = https://www.fastadmin.net
|
||||
version = 1.1.8
|
||||
state = 1
|
||||
url = /addons/address
|
||||
license = regular
|
||||
licenseto = 34485
|
||||
@@ -1,258 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
|
||||
<title>地址选择器</title>
|
||||
<link rel="stylesheet" href="__CDN__/assets/css/frontend.min.css"/>
|
||||
<link rel="stylesheet" href="__CDN__/assets/libs/font-awesome/css/font-awesome.min.css"/>
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#container {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.confirm {
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
right: 4%;
|
||||
z-index: 99;
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
line-height: 50px;
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
background-color: white;
|
||||
background: #1ABC9C;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.search {
|
||||
position: absolute;
|
||||
width: 400px;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
padding: 5px;
|
||||
margin-left: -200px;
|
||||
}
|
||||
|
||||
.amap-marker-label {
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.info {
|
||||
padding: .75rem 1.25rem;
|
||||
margin-bottom: 1rem;
|
||||
border-radius: .25rem;
|
||||
position: fixed;
|
||||
top: 2rem;
|
||||
background-color: white;
|
||||
width: auto;
|
||||
min-width: 22rem;
|
||||
border-width: 0;
|
||||
left: 1.8rem;
|
||||
box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="search">
|
||||
<div class="input-group">
|
||||
<input type="text" id="place" name="q" class="form-control" placeholder="输入地点"/>
|
||||
<span class="input-group-btn">
|
||||
<button type="submit" name="search" id="search-btn" class="btn btn-success">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="confirm">确定</div>
|
||||
<div id="container"></div>
|
||||
<script type="text/javascript">
|
||||
window._AMapSecurityConfig = {
|
||||
securityJsCode: "{$config.amapsecurityjscode|default=''}",
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript" src="//webapi.amap.com/maps?v=1.4.11&key={$config.amapkey|default=''}&plugin=AMap.ToolBar,AMap.Autocomplete,AMap.PlaceSearch,AMap.Geocoder"></script>
|
||||
<!-- UI组件库 1.0 -->
|
||||
<script src="//webapi.amap.com/ui/1.0/main.js?v=1.0.11"></script>
|
||||
<script src="__CDN__/assets/libs/jquery/dist/jquery.min.js"></script>
|
||||
<script src="__CDN__/assets/addons/address/js/gcoord.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var as, map, geocoder, address, fromtype, totype;
|
||||
address = "{$address|htmlentities}";
|
||||
var lng = Number("{$lng}");
|
||||
var lat = Number("{$lat}");
|
||||
fromtype = "GCJ02";
|
||||
totype = "{$config.coordtype|default='DEFAULT'}"
|
||||
totype = totype === 'DEFAULT' ? "GCJ02" : totype;
|
||||
|
||||
if (lng && lat && fromtype !== totype) {
|
||||
var result = gcoord.transform([lng, lat], gcoord[totype], gcoord[fromtype]);
|
||||
lng = result[0] || lng;
|
||||
lat = result[1] || lat;
|
||||
}
|
||||
|
||||
var init = function () {
|
||||
AMapUI.loadUI(['misc/PositionPicker', 'misc/PoiPicker'], function (PositionPicker, PoiPicker) {
|
||||
//加载PositionPicker,loadUI的路径参数为模块名中 'ui/' 之后的部分
|
||||
map = new AMap.Map('container', {
|
||||
zoom: parseInt('{$zoom}'),
|
||||
center: [lng, lat]
|
||||
});
|
||||
geocoder = new AMap.Geocoder({
|
||||
radius: 1000 //范围,默认:500
|
||||
});
|
||||
var positionPicker = new PositionPicker({
|
||||
mode: 'dragMarker',//设定为拖拽地图模式,可选'dragMap'、'dragMarker',默认为'dragMap'
|
||||
map: map//依赖地图对象
|
||||
});
|
||||
//输入提示
|
||||
var autoOptions = {
|
||||
input: "place"
|
||||
};
|
||||
|
||||
var relocation = function (lnglat, addr) {
|
||||
lng = lnglat.lng;
|
||||
lat = lnglat.lat;
|
||||
map.panTo([lng, lat]);
|
||||
positionPicker.start(lnglat);
|
||||
if (addr) {
|
||||
// var label = '<div class="info">地址:' + addr + '<br>经度:' + lng + '<br>纬度:' + lat + '</div>';
|
||||
var label = '<div class="info">地址:' + addr + '</div>';
|
||||
positionPicker.marker.setLabel({
|
||||
content: label //显示内容
|
||||
});
|
||||
} else {
|
||||
geocoder.getAddress(lng + ',' + lat, function (status, result) {
|
||||
if (status === 'complete' && result.regeocode) {
|
||||
var address = result.regeocode.formattedAddress;
|
||||
// var label = '<div class="info">地址:' + address + '<br>经度:' + lng + '<br>纬度:' + lat + '</div>';
|
||||
var label = '<div class="info">地址:' + address + '</div>';
|
||||
positionPicker.marker.setLabel({
|
||||
content: label //显示内容
|
||||
});
|
||||
} else {
|
||||
console.log(JSON.stringify(result));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
var auto = new AMap.Autocomplete(autoOptions);
|
||||
|
||||
//构造地点查询类
|
||||
var placeSearch = new AMap.PlaceSearch({
|
||||
map: map
|
||||
});
|
||||
//注册监听,当选中某条记录时会触发
|
||||
AMap.event.addListener(auto, "select", function (e) {
|
||||
placeSearch.setCity(e.poi.adcode);
|
||||
placeSearch.search(e.poi.name, function (status, result) {
|
||||
$(map.getAllOverlays("marker")).each(function (i, j) {
|
||||
j.on("click", function () {
|
||||
relocation(j.De.position);
|
||||
});
|
||||
});
|
||||
}); //关键字查询查询
|
||||
});
|
||||
AMap.event.addListener(map, 'click', function (e) {
|
||||
relocation(e.lnglat);
|
||||
});
|
||||
|
||||
//加载工具条
|
||||
var tool = new AMap.ToolBar();
|
||||
map.addControl(tool);
|
||||
|
||||
var poiPicker = new PoiPicker({
|
||||
input: 'place',
|
||||
placeSearchOptions: {
|
||||
map: map,
|
||||
pageSize: 6 //关联搜索分页
|
||||
}
|
||||
});
|
||||
poiPicker.on('poiPicked', function (poiResult) {
|
||||
poiPicker.hideSearchResults();
|
||||
$('.poi .nearpoi').text(poiResult.item.name);
|
||||
$('.address .info').text(poiResult.item.address);
|
||||
$('#address').val(poiResult.item.address);
|
||||
$("#place").val(poiResult.item.name);
|
||||
|
||||
relocation(poiResult.item.location);
|
||||
});
|
||||
|
||||
positionPicker.on('success', function (positionResult) {
|
||||
console.log(positionResult);
|
||||
as = positionResult.position;
|
||||
address = positionResult.address;
|
||||
lat = as.lat;
|
||||
lng = as.lng;
|
||||
});
|
||||
positionPicker.on('fail', function (positionResult) {
|
||||
address = '';
|
||||
});
|
||||
positionPicker.start();
|
||||
|
||||
if (address) {
|
||||
// 添加label
|
||||
var label = '<div class="info">地址:' + address + '</div>';
|
||||
positionPicker.marker.setLabel({
|
||||
content: label //显示内容
|
||||
});
|
||||
}
|
||||
|
||||
//点击搜索按钮
|
||||
$(document).on('click', '#search-btn', function () {
|
||||
if ($("#place").val() == '')
|
||||
return;
|
||||
placeSearch.search($("#place").val(), function (status, result) {
|
||||
$(map.getAllOverlays("marker")).each(function (i, j) {
|
||||
j.on("click", function () {
|
||||
relocation(j.De.position);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
//点击确定后执行回调赋值
|
||||
var close = function (data) {
|
||||
var index = parent.Layer.getFrameIndex(window.name);
|
||||
var callback = parent.$("#layui-layer" + index).data("callback");
|
||||
//再执行关闭
|
||||
parent.Layer.close(index);
|
||||
//再调用回传函数
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(undefined, data);
|
||||
}
|
||||
};
|
||||
|
||||
//点击搜索按钮
|
||||
$(document).on('click', '.confirm', function () {
|
||||
var zoom = map.getZoom();
|
||||
var data = {lat: lat, lng: lng, zoom: zoom, address: address};
|
||||
if (fromtype !== totype) {
|
||||
var result = gcoord.transform([data.lng, data.lat], gcoord[fromtype], gcoord[totype]);
|
||||
data.lng = (result[0] || data.lng).toFixed(5);
|
||||
data.lat = (result[1] || data.lat).toFixed(5);
|
||||
console.log(data, result, fromtype, totype);
|
||||
}
|
||||
close(data);
|
||||
});
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,243 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
|
||||
<title>地址选择器</title>
|
||||
<link rel="stylesheet" href="__CDN__/assets/css/frontend.min.css"/>
|
||||
<link rel="stylesheet" href="__CDN__/assets/libs/font-awesome/css/font-awesome.min.css"/>
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#container {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.confirm {
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
right: 4%;
|
||||
z-index: 99;
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
line-height: 50px;
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
background-color: white;
|
||||
background: #1ABC9C;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.search {
|
||||
position: absolute;
|
||||
width: 400px;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
padding: 5px;
|
||||
margin-left: -200px;
|
||||
}
|
||||
|
||||
label.BMapLabel {
|
||||
max-width: inherit;
|
||||
padding: .75rem 1.25rem;
|
||||
margin-bottom: 1rem;
|
||||
background-color: white;
|
||||
width: auto;
|
||||
min-width: 22rem;
|
||||
border: none;
|
||||
box-shadow: 0 2px 6px 0 rgba(114, 124, 245, .5);
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="search">
|
||||
<div class="input-group">
|
||||
<input type="text" id="place" name="q" class="form-control" placeholder="输入地点"/>
|
||||
<div id="searchResultPanel" style="border:1px solid #C0C0C0;width:150px;height:auto; display:none;"></div>
|
||||
<span class="input-group-btn">
|
||||
<button type="button" name="search" id="search-btn" class="btn btn-success">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="confirm">确定</div>
|
||||
<div id="container"></div>
|
||||
<script type="text/javascript" src="//api.map.baidu.com/api?v=2.0&ak={$config.baidukey|default=''}"></script>
|
||||
<script src="__CDN__/assets/libs/jquery/dist/jquery.min.js"></script>
|
||||
<script src="__CDN__/assets/addons/address/js/gcoord.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var map, marker, point, fromtype, totype;
|
||||
var zoom = parseInt("{$zoom}");
|
||||
var address = "{$address|htmlentities}";
|
||||
var lng = Number("{$lng}");
|
||||
var lat = Number("{$lat}");
|
||||
fromtype = "BD09";
|
||||
totype = "{$config.coordtype|default='DEFAULT'}"
|
||||
totype = totype === 'DEFAULT' ? "BD09" : totype;
|
||||
|
||||
if (lng && lat && fromtype !== totype) {
|
||||
var result = gcoord.transform([lng, lat], gcoord[totype], gcoord[fromtype]);
|
||||
lng = result[0] || lng;
|
||||
lat = result[1] || lat;
|
||||
}
|
||||
|
||||
var geocoder = new BMap.Geocoder();
|
||||
|
||||
var addPointMarker = function (point, addr) {
|
||||
deletePoint();
|
||||
addPoint(point);
|
||||
|
||||
if (addr) {
|
||||
addMarker(point, addr);
|
||||
} else {
|
||||
geocoder.getLocation(point, function (rs) {
|
||||
addMarker(point, rs.address);
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
var addPoint = function (point) {
|
||||
lng = point.lng;
|
||||
lat = point.lat;
|
||||
marker = new BMap.Marker(point);
|
||||
map.addOverlay(marker);
|
||||
map.panTo(point);
|
||||
};
|
||||
|
||||
var addMarker = function (point, addr) {
|
||||
address = addr;
|
||||
// var labelhtml = '<div class="info">地址:' + address + '<br>经度:' + point.lng + '<br>纬度:' + point.lat + '</div>';
|
||||
var labelhtml = '<div class="info">地址:' + address + '</div>';
|
||||
var label = new BMap.Label(labelhtml, {offset: new BMap.Size(16, 20)});
|
||||
label.setStyle({
|
||||
border: 'none',
|
||||
padding: '.75rem 1.25rem'
|
||||
});
|
||||
marker.setLabel(label);
|
||||
};
|
||||
|
||||
var deletePoint = function () {
|
||||
var allOverlay = map.getOverlays();
|
||||
for (var i = 0; i < allOverlay.length; i++) {
|
||||
map.removeOverlay(allOverlay[i]);
|
||||
}
|
||||
};
|
||||
|
||||
var init = function () {
|
||||
map = new BMap.Map("container"); // 创建地图实例
|
||||
var point = new BMap.Point(lng, lat); // 创建点坐标
|
||||
map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放
|
||||
map.centerAndZoom(point, zoom); // 初始化地图,设置中心点坐标和地图级别
|
||||
|
||||
var size = new BMap.Size(10, 20);
|
||||
map.addControl(new BMap.CityListControl({
|
||||
anchor: BMAP_ANCHOR_TOP_LEFT,
|
||||
offset: size,
|
||||
}));
|
||||
|
||||
if ("{$lng}" != '' && "{$lat}" != '') {
|
||||
addPointMarker(point, address);
|
||||
}
|
||||
|
||||
ac = new BMap.Autocomplete({"input": "place", "location": map}); //建立一个自动完成的对象
|
||||
ac.addEventListener("onhighlight", function (e) { //鼠标放在下拉列表上的事件
|
||||
var str = "";
|
||||
var _value = e.fromitem.value;
|
||||
var value = "";
|
||||
if (e.fromitem.index > -1) {
|
||||
value = _value.province + _value.city + _value.district + _value.street + _value.business;
|
||||
}
|
||||
str = "FromItem<br />index = " + e.fromitem.index + "<br />value = " + value;
|
||||
|
||||
value = "";
|
||||
if (e.toitem.index > -1) {
|
||||
_value = e.toitem.value;
|
||||
value = _value.province + _value.city + _value.district + _value.street + _value.business;
|
||||
}
|
||||
str += "<br />ToItem<br />index = " + e.toitem.index + "<br />value = " + value;
|
||||
$("#searchResultPanel").html(str);
|
||||
});
|
||||
ac.addEventListener("onconfirm", function (e) { //鼠标点击下拉列表后的事件
|
||||
var _value = e.item.value;
|
||||
myValue = _value.province + _value.city + _value.district + _value.street + _value.business;
|
||||
$("#searchResultPanel").html("onconfirm<br />index = " + e.item.index + "<br />myValue = " + myValue);
|
||||
setPlace();
|
||||
});
|
||||
|
||||
function setPlace(text) {
|
||||
map.clearOverlays(); //清除地图上所有覆盖物
|
||||
function myFun() {
|
||||
var results = local.getResults();
|
||||
var result = local.getResults().getPoi(0);
|
||||
var point = result.point; //获取第一个智能搜索的结果
|
||||
map.centerAndZoom(point, 18);
|
||||
// map.addOverlay(new BMap.Marker(point)); //添加标注
|
||||
if (result.type != 0) {
|
||||
address = results.province + results.city + result.address;
|
||||
} else {
|
||||
address = result.address;
|
||||
}
|
||||
addPointMarker(point, address);
|
||||
}
|
||||
|
||||
var local = new BMap.LocalSearch(map, { //智能搜索
|
||||
onSearchComplete: myFun
|
||||
});
|
||||
local.search(text || myValue);
|
||||
}
|
||||
|
||||
map.addEventListener("click", function (e) {
|
||||
//通过点击百度地图,可以获取到对应的point, 由point的lng、lat属性就可以获取对应的经度纬度
|
||||
addPointMarker(e.point);
|
||||
});
|
||||
|
||||
//点击搜索按钮
|
||||
$(document).on('click', '#search-btn', function () {
|
||||
if ($("#place").val() == '')
|
||||
return;
|
||||
setPlace($("#place").val());
|
||||
});
|
||||
};
|
||||
|
||||
var close = function (data) {
|
||||
var index = parent.Layer.getFrameIndex(window.name);
|
||||
var callback = parent.$("#layui-layer" + index).data("callback");
|
||||
//再执行关闭
|
||||
parent.Layer.close(index);
|
||||
//再调用回传函数
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(undefined, data);
|
||||
}
|
||||
};
|
||||
|
||||
//点击确定后执行回调赋值
|
||||
$(document).on('click', '.confirm', function () {
|
||||
var zoom = map.getZoom();
|
||||
var data = {lat: lat, lng: lng, zoom: zoom, address: address};
|
||||
if (fromtype !== totype) {
|
||||
var result = gcoord.transform([data.lng, data.lat], gcoord[fromtype], gcoord[totype]);
|
||||
data.lng = (result[0] || data.lng).toFixed(5);
|
||||
data.lat = (result[1] || data.lat).toFixed(5);
|
||||
console.log(data, result, fromtype, totype);
|
||||
}
|
||||
close(data);
|
||||
});
|
||||
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,132 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
|
||||
<title>地图位置(经纬度)选择插件</title>
|
||||
<link rel="stylesheet" href="__CDN__/assets/css/frontend.min.css"/>
|
||||
<link rel="stylesheet" href="__CDN__/assets/libs/font-awesome/css/font-awesome.min.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
|
||||
<div class="bs-docs-section clearfix">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="page-header">
|
||||
<h2>地图位置(经纬度)选择示例</h2>
|
||||
</div>
|
||||
|
||||
<div class="bs-component">
|
||||
<form action="" method="post" role="form">
|
||||
<div class="form-group">
|
||||
<label for=""></label>
|
||||
<input type="text" class="form-control" name="" id="address" placeholder="地址">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for=""></label>
|
||||
<input type="text" class="form-control" name="" id="lng" placeholder="经度">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for=""></label>
|
||||
<input type="text" class="form-control" name="" id="lat" placeholder="纬度">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for=""></label>
|
||||
<input type="text" class="form-control" name="" id="zoom" placeholder="缩放">
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-primary" data-toggle='addresspicker' data-input-id="address" data-lng-id="lng" data-lat-id="lat" data-zoom-id="zoom">点击选择</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="page-header">
|
||||
<h2 id="code">调用代码</h2>
|
||||
</div>
|
||||
<div class="bs-component">
|
||||
<textarea class="form-control" rows="17">
|
||||
<form action="" method="post" role="form">
|
||||
<div class="form-group">
|
||||
<label for=""></label>
|
||||
<input type="text" class="form-control" name="" id="address" placeholder="地址">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for=""></label>
|
||||
<input type="text" class="form-control" name="" id="lng" placeholder="经度">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for=""></label>
|
||||
<input type="text" class="form-control" name="" id="lat" placeholder="纬度">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for=""></label>
|
||||
<input type="text" class="form-control" name="" id="zoom" placeholder="缩放">
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-primary" data-toggle='addresspicker' data-input-id="address" data-lng-id="lng" data-lat-id="lat" data-zoom-id="zoom">点击选择</button>
|
||||
</form>
|
||||
</textarea>
|
||||
</div>
|
||||
<div class="page-header">
|
||||
<h2>参数说明</h2>
|
||||
</div>
|
||||
|
||||
<div class="bs-component" style="background:#fff;">
|
||||
<table class="table table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>参数</th>
|
||||
<th>释义</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>data-input-id</td>
|
||||
<td>填充地址的文本框ID</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>data-lng-id</td>
|
||||
<td>填充经度的文本框ID</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>data-lat-id</td>
|
||||
<td>填充纬度的文本框ID</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>data-zoom-id</td>
|
||||
<td>填充缩放的文本框ID</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<!--@formatter:off-->
|
||||
<script type="text/javascript">
|
||||
var require = {
|
||||
config: {$config|json_encode}
|
||||
};
|
||||
</script>
|
||||
<!--@formatter:on-->
|
||||
|
||||
<script>
|
||||
require.callback = function () {
|
||||
define('addons/address', ['jquery', 'bootstrap', 'frontend', 'template'], function ($, undefined, Frontend, Template) {
|
||||
var Controller = {
|
||||
index: function () {
|
||||
}
|
||||
};
|
||||
return Controller;
|
||||
});
|
||||
define('lang', function () {
|
||||
return [];
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script src="__CDN__/assets/js/require.min.js" data-main="__CDN__/assets/js/require-frontend.min.js?v={$site.version}"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,291 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
|
||||
<title>地址选择器</title>
|
||||
<link rel="stylesheet" href="__CDN__/assets/css/frontend.min.css"/>
|
||||
<link rel="stylesheet" href="__CDN__/assets/libs/font-awesome/css/font-awesome.min.css"/>
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#container {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.confirm {
|
||||
position: absolute;
|
||||
bottom: 30px;
|
||||
right: 4%;
|
||||
z-index: 99;
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
line-height: 50px;
|
||||
font-size: 15px;
|
||||
text-align: center;
|
||||
background-color: white;
|
||||
background: #1ABC9C;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.search {
|
||||
position: absolute;
|
||||
width: 400px;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
padding: 5px;
|
||||
margin-left: -200px;
|
||||
}
|
||||
|
||||
.autocomplete-search {
|
||||
text-align: left;
|
||||
cursor: default;
|
||||
background: #fff;
|
||||
border-radius: 2px;
|
||||
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||
-moz-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175);
|
||||
background-clip: padding-box;
|
||||
position: absolute;
|
||||
display: none;
|
||||
z-index: 1036;
|
||||
max-height: 254px;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.autocomplete-search .autocomplete-suggestion {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.autocomplete-search .autocomplete-suggestion:hover {
|
||||
background: #f0f0f0;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="search">
|
||||
<div class="input-group">
|
||||
<input type="text" id="place" name="q" class="form-control" placeholder="输入地点"/>
|
||||
<span class="input-group-btn">
|
||||
<button type="button" name="search" id="search-btn" class="btn btn-success">
|
||||
<i class="fa fa-search"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="confirm">确定</div>
|
||||
<div id="container"></div>
|
||||
|
||||
<script charset="utf-8" src="//map.qq.com/api/js?v=2.exp&libraries=place&key={$config.tencentkey|default=''}"></script>
|
||||
<script src="__CDN__/assets/libs/jquery/dist/jquery.min.js"></script>
|
||||
<script src="__CDN__/assets/addons/address/js/gcoord.min.js"></script>
|
||||
<script src="__CDN__/assets/addons/address/js/jquery.autocomplete.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var map, marker, geocoder, infoWin, searchService, keyword, address, fromtype, totype;
|
||||
address = "{$address|htmlentities}";
|
||||
var lng = Number("{$lng}");
|
||||
var lat = Number("{$lat}");
|
||||
fromtype = "GCJ02";
|
||||
totype = "{$config.coordtype|default='DEFAULT'}"
|
||||
totype = totype === 'DEFAULT' ? "GCJ02" : totype;
|
||||
|
||||
if (lng && lat && fromtype !== totype) {
|
||||
var result = gcoord.transform([lng, lat], gcoord[totype], gcoord[fromtype]);
|
||||
lng = result[0] || lng;
|
||||
lat = result[1] || lat;
|
||||
}
|
||||
|
||||
var init = function () {
|
||||
var center = new qq.maps.LatLng(lat, lng);
|
||||
map = new qq.maps.Map(document.getElementById('container'), {
|
||||
center: center,
|
||||
zoom: parseInt("{$config.zoom}")
|
||||
});
|
||||
|
||||
//实例化信息窗口
|
||||
infoWin = new qq.maps.InfoWindow({
|
||||
map: map
|
||||
});
|
||||
|
||||
geocoder = {
|
||||
getAddress: function (latLng) {
|
||||
$.ajax({
|
||||
url: "https://apis.map.qq.com/ws/geocoder/v1/?location=" + latLng.lat + "," + latLng.lng + "&key={$config.tencentkey|default=''}&output=jsonp",
|
||||
dataType: "jsonp",
|
||||
type: 'GET',
|
||||
cache: true,
|
||||
crossDomain: true,
|
||||
success: function (ret) {
|
||||
console.log("getAddress:", ret)
|
||||
if (ret.status === 0) {
|
||||
var component = ret.result.address_component;
|
||||
if (ret.result.formatted_addresses && ret.result.formatted_addresses.recommend) {
|
||||
var recommend = ret.result.formatted_addresses.recommend;
|
||||
var standard_address = ret.result.formatted_addresses.standard_address;
|
||||
var address = component.province !== component.city ? component.province + component.city : component.province;
|
||||
|
||||
address = address + (recommend.indexOf(component.district) === 0 ? '' : component.district) + recommend;
|
||||
} else {
|
||||
address = ret.result.address;
|
||||
}
|
||||
showMarker(ret.result.location, address);
|
||||
showInfoWin(ret.result.location, address);
|
||||
}
|
||||
},
|
||||
error: function (e) {
|
||||
console.log(e, 'error')
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//初始化marker
|
||||
showMarker(center);
|
||||
if (address) {
|
||||
showInfoWin(center, address);
|
||||
} else {
|
||||
geocoder.getAddress(center);
|
||||
}
|
||||
|
||||
var place = $("#place");
|
||||
place.autoComplete({
|
||||
minChars: 1,
|
||||
cache: 0,
|
||||
menuClass: 'autocomplete-search',
|
||||
source: function (term, response) {
|
||||
try {
|
||||
xhr.abort();
|
||||
} catch (e) {
|
||||
}
|
||||
xhr = $.ajax({
|
||||
url: "https://apis.map.qq.com/ws/place/v1/suggestion?keyword=" + term + "&key={$config.tencentkey|default=''}&output=jsonp",
|
||||
dataType: "jsonp",
|
||||
type: 'GET',
|
||||
cache: true,
|
||||
success: function (ret) {
|
||||
if (ret.status === 0) {
|
||||
if(ret.data.length === 0){
|
||||
$(".autocomplete-suggestions.autocomplete-search").html('');
|
||||
}
|
||||
response(ret.data);
|
||||
} else {
|
||||
console.log(ret);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
renderItem: function (item, search) {
|
||||
search = search.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||
var regexp = new RegExp("(" + search.replace(/[\,|\u3000|\uff0c]/, ' ').split(' ').join('|') + ")", "gi");
|
||||
return "<div class='autocomplete-suggestion' data-item='" + JSON.stringify(item) + "' data-title='" + item.title + "' data-val='" + item.title + "'>" + item.title.replace(regexp, "<b>$1</b>") + "</div>";
|
||||
},
|
||||
onSelect: function (e, term, sel) {
|
||||
e.preventDefault();
|
||||
var item = $(sel).data("item");
|
||||
//调用获取位置方法
|
||||
geocoder.getAddress(item.location);
|
||||
|
||||
var position = new qq.maps.LatLng(item.location.lat, item.location.lng);
|
||||
map.setCenter(position);
|
||||
}
|
||||
});
|
||||
|
||||
//地图点击
|
||||
qq.maps.event.addListener(map, 'click', function (event) {
|
||||
try {
|
||||
//调用获取位置方法
|
||||
geocoder.getAddress(event.latLng);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
//显示info窗口
|
||||
var showInfoWin = function (latLng, title) {
|
||||
var position = new qq.maps.LatLng(latLng.lat, latLng.lng);
|
||||
infoWin.open();
|
||||
infoWin.setContent(title);
|
||||
infoWin.setPosition(position);
|
||||
};
|
||||
|
||||
//实例化marker和监听拖拽结束事件
|
||||
var showMarker = function (latLng, title) {
|
||||
console.log("showMarker", latLng, title)
|
||||
var position = new qq.maps.LatLng(latLng.lat, latLng.lng);
|
||||
marker && marker.setMap(null);
|
||||
marker = new qq.maps.Marker({
|
||||
map: map,
|
||||
position: position,
|
||||
draggable: true,
|
||||
title: title || '拖动图标选择位置'
|
||||
});
|
||||
|
||||
//监听拖拽结束
|
||||
qq.maps.event.addListener(marker, 'dragend', function (event) {
|
||||
//调用获取位置方法
|
||||
geocoder.getAddress(event.latLng);
|
||||
});
|
||||
};
|
||||
|
||||
var close = function (data) {
|
||||
var index = parent.Layer.getFrameIndex(window.name);
|
||||
var callback = parent.$("#layui-layer" + index).data("callback");
|
||||
//再执行关闭
|
||||
parent.Layer.close(index);
|
||||
//再调用回传函数
|
||||
if (typeof callback === 'function') {
|
||||
callback.call(undefined, data);
|
||||
}
|
||||
};
|
||||
|
||||
//点击确定后执行回调赋值
|
||||
$(document).on('click', '.confirm', function () {
|
||||
var zoom = map.getZoom();
|
||||
var data = {lat: infoWin.position.lat.toFixed(5), lng: infoWin.position.lng.toFixed(5), zoom: zoom, address: infoWin.content};
|
||||
if (fromtype !== totype) {
|
||||
var result = gcoord.transform([data.lng, data.lat], gcoord[fromtype], gcoord[totype]);
|
||||
data.lng = (result[0] || data.lng).toFixed(5);
|
||||
data.lat = (result[1] || data.lat).toFixed(5);
|
||||
console.log(data, result, fromtype, totype);
|
||||
}
|
||||
|
||||
close(data);
|
||||
});
|
||||
|
||||
//点击搜索按钮
|
||||
$(document).on('click', '#search-btn', function () {
|
||||
if ($("#place").val() === '')
|
||||
return;
|
||||
var first = $(".autocomplete-search > .autocomplete-suggestion:first");
|
||||
if (!first.length) {
|
||||
return;
|
||||
}
|
||||
var item = first.data("item");
|
||||
|
||||
//调用获取位置方法
|
||||
geocoder.getAddress(item.location);
|
||||
|
||||
var position = new qq.maps.LatLng(item.location.lat, item.location.lng);
|
||||
map.setCenter(position);
|
||||
});
|
||||
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1 +0,0 @@
|
||||
{"files":[],"license":"regular","licenseto":"34485","licensekey":"c0PdNFYlWJh284EB eq7jv5BnBK\/UCafzmrQRqA==","domains":["localhost"],"licensecodes":[],"validations":["757319b447175b6ca1882635b132a594"]}
|
||||
@@ -1,83 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\alisms;
|
||||
|
||||
use think\Addons;
|
||||
|
||||
/**
|
||||
* Alisms
|
||||
*/
|
||||
class Alisms extends Addons
|
||||
{
|
||||
|
||||
/**
|
||||
* 插件安装方法
|
||||
* @return bool
|
||||
*/
|
||||
public function install()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件卸载方法
|
||||
* @return bool
|
||||
*/
|
||||
public function uninstall()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信发送行为
|
||||
* @param array $params 必须包含mobile,event,code
|
||||
* @return boolean
|
||||
*/
|
||||
public function smsSend(&$params)
|
||||
{
|
||||
$config = get_addon_config('alisms');
|
||||
$alisms = new \addons\alisms\library\Alisms();
|
||||
$result = $alisms->mobile($params['mobile'])
|
||||
->template($config['template'][$params['event']])
|
||||
->param(['code' => $params['code']])
|
||||
->send();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 短信发送通知
|
||||
* @param array $params 必须包含 mobile,event,msg
|
||||
* @return boolean
|
||||
*/
|
||||
public function smsNotice(&$params)
|
||||
{
|
||||
$config = get_addon_config('alisms');
|
||||
$alisms = \addons\alisms\library\Alisms::instance();
|
||||
if (isset($params['msg'])) {
|
||||
if (is_array($params['msg'])) {
|
||||
$param = $params['msg'];
|
||||
} else {
|
||||
parse_str($params['msg'], $param);
|
||||
}
|
||||
} else {
|
||||
$param = [];
|
||||
}
|
||||
$param = $param ? $param : [];
|
||||
$params['template'] = isset($params['template']) ? $params['template'] : (isset($params['event']) && isset($config['template'][$params['event']]) ? $config['template'][$params['event']] : '');
|
||||
$result = $alisms->mobile($params['mobile'])
|
||||
->template($params['template'])
|
||||
->param($param)
|
||||
->send();
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测验证是否正确
|
||||
* @param $params
|
||||
* @return boolean
|
||||
*/
|
||||
public function smsCheck(&$params)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
[
|
||||
'name' => 'key',
|
||||
'title' => '应用key',
|
||||
'type' => 'string',
|
||||
'content' => [],
|
||||
'value' => 'LTAI5tBbLtPkAq7eV3Stma3R',
|
||||
'rule' => 'required',
|
||||
'msg' => '',
|
||||
'tip' => '',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'secret',
|
||||
'title' => '密钥secret',
|
||||
'type' => 'string',
|
||||
'content' => [],
|
||||
'value' => 'yIUy2I1K8mKTfcHZLqbN0qgRbvzz4y',
|
||||
'rule' => 'required',
|
||||
'msg' => '',
|
||||
'tip' => '',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'sign',
|
||||
'title' => '签名',
|
||||
'type' => 'string',
|
||||
'content' => [],
|
||||
'value' => '米多花',
|
||||
'rule' => 'required',
|
||||
'msg' => '',
|
||||
'tip' => '',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'template',
|
||||
'title' => '短信模板',
|
||||
'type' => 'array',
|
||||
'content' => [],
|
||||
'value' => [
|
||||
'register' => 'SMS_170440238',
|
||||
'resetpwd' => 'SMS_170440238',
|
||||
'changepwd' => 'SMS_170440238',
|
||||
'changemobile' => 'SMS_170440238',
|
||||
'profile' => 'SMS_170440238',
|
||||
'notice' => 'SMS_170440238',
|
||||
],
|
||||
'rule' => 'required',
|
||||
'msg' => '',
|
||||
'tip' => '',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
[
|
||||
'name' => '__tips__',
|
||||
'title' => '温馨提示',
|
||||
'type' => 'string',
|
||||
'content' => [],
|
||||
'value' => '应用key和密钥你可以通过 https://ak-console.aliyun.com/?spm=a2c4g.11186623.2.13.fd315777PX3tjy#/accesskey 获取',
|
||||
'rule' => 'required',
|
||||
'msg' => '',
|
||||
'tip' => '',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
];
|
||||
@@ -1,52 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\alisms\controller;
|
||||
|
||||
use think\addons\Controller;
|
||||
|
||||
/**
|
||||
* 阿里短信
|
||||
*/
|
||||
class Index extends Controller
|
||||
{
|
||||
|
||||
protected $model = null;
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
if (!\app\admin\library\Auth::instance()->id) {
|
||||
$this->error('暂无权限浏览');
|
||||
}
|
||||
parent::_initialize();
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
return $this->view->fetch();
|
||||
}
|
||||
|
||||
public function send()
|
||||
{
|
||||
$config = get_addon_config('alisms');
|
||||
$mobile = $this->request->post('mobile');
|
||||
$template = $this->request->post('template');
|
||||
$sign = $this->request->post('sign');
|
||||
if (!$mobile || !$template) {
|
||||
$this->error('手机号、模板ID不能为空');
|
||||
}
|
||||
$sign = $sign ? $sign : $config['sign'];
|
||||
$param = (array)json_decode($this->request->post('param', '', 'trim'));
|
||||
$alisms = new \addons\alisms\library\Alisms();
|
||||
$ret = $alisms->mobile($mobile)
|
||||
->template($template)
|
||||
->sign($sign)
|
||||
->param($param)
|
||||
->send();
|
||||
if ($ret) {
|
||||
$this->success("发送成功");
|
||||
} else {
|
||||
$this->error("发送失败!失败原因:" . $alisms->getError());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
name = alisms
|
||||
title = 阿里云短信发送
|
||||
intro = 阿里云短信发送插件
|
||||
author = FastAdmin
|
||||
website = https://www.fastadmin.net
|
||||
version = 1.0.9
|
||||
state = 1
|
||||
url = /addons/alisms
|
||||
license = regular
|
||||
licenseto = 34485
|
||||
@@ -1,170 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\alisms\library;
|
||||
|
||||
/**
|
||||
* 阿里大于SMS短信发送
|
||||
*/
|
||||
class Alisms
|
||||
{
|
||||
private $_params = [];
|
||||
public $error = '';
|
||||
protected $config = [];
|
||||
protected static $instance;
|
||||
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if ($config = get_addon_config('alisms')) {
|
||||
$this->config = array_merge($this->config, $config);
|
||||
}
|
||||
$this->config = array_merge($this->config, is_array($options) ? $options : []);
|
||||
}
|
||||
|
||||
/**
|
||||
* 单例
|
||||
* @param array $options 参数
|
||||
* @return Alisms
|
||||
*/
|
||||
public static function instance($options = [])
|
||||
{
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new static($options);
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置签名
|
||||
* @param string $sign
|
||||
* @return Alisms
|
||||
*/
|
||||
public function sign($sign = '')
|
||||
{
|
||||
$this->_params['SignName'] = $sign;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置参数
|
||||
* @param array $param
|
||||
* @return Alisms
|
||||
*/
|
||||
public function param(array $param = [])
|
||||
{
|
||||
foreach ($param as $k => &$v) {
|
||||
$v = (string)$v;
|
||||
}
|
||||
unset($v);
|
||||
$param = array_filter($param);
|
||||
$this->_params['TemplateParam'] = $param ? json_encode($param) : '{}';
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置模板
|
||||
* @param string $code 短信模板
|
||||
* @return Alisms
|
||||
*/
|
||||
public function template($code = '')
|
||||
{
|
||||
$this->_params['TemplateCode'] = $code;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 接收手机
|
||||
* @param string $mobile 手机号码
|
||||
* @return Alisms
|
||||
*/
|
||||
public function mobile($mobile = '')
|
||||
{
|
||||
$this->_params['PhoneNumbers'] = $mobile;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即发送
|
||||
* @return boolean
|
||||
*/
|
||||
public function send()
|
||||
{
|
||||
$this->error = '';
|
||||
$params = $this->_params();
|
||||
$params['Signature'] = $this->_signed($params);
|
||||
$response = $this->_curl($params);
|
||||
if ($response !== false) {
|
||||
$res = (array)json_decode($response, true);
|
||||
if (isset($res['Code']) && $res['Code'] == 'OK') {
|
||||
return true;
|
||||
}
|
||||
$this->error = isset($res['Message']) ? $res['Message'] : 'InvalidResult';
|
||||
} else {
|
||||
$this->error = 'InvalidResult';
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取错误信息
|
||||
* @return string
|
||||
*/
|
||||
public function getError()
|
||||
{
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
private function _params()
|
||||
{
|
||||
return array_merge([
|
||||
'AccessKeyId' => $this->config['key'],
|
||||
'SignName' => isset($this->config['sign']) ? $this->config['sign'] : '',
|
||||
'Action' => 'SendSms',
|
||||
'Format' => 'JSON',
|
||||
'Version' => '2017-05-25',
|
||||
'SignatureVersion' => '1.0',
|
||||
'SignatureMethod' => 'HMAC-SHA1',
|
||||
'SignatureNonce' => uniqid(),
|
||||
'Timestamp' => gmdate('Y-m-d\TH:i:s\Z'),
|
||||
], $this->_params);
|
||||
}
|
||||
|
||||
private function percentEncode($string)
|
||||
{
|
||||
$string = urlencode($string);
|
||||
$string = preg_replace('/\+/', '%20', $string);
|
||||
$string = preg_replace('/\*/', '%2A', $string);
|
||||
$string = preg_replace('/%7E/', '~', $string);
|
||||
return $string;
|
||||
}
|
||||
|
||||
private function _signed($params)
|
||||
{
|
||||
$sign = $this->config['secret'];
|
||||
ksort($params);
|
||||
$canonicalizedQueryString = '';
|
||||
foreach ($params as $key => $value) {
|
||||
$canonicalizedQueryString .= '&' . $this->percentEncode($key) . '=' . $this->percentEncode($value);
|
||||
}
|
||||
$stringToSign = 'GET&%2F&' . $this->percentencode(substr($canonicalizedQueryString, 1));
|
||||
$signature = base64_encode(hash_hmac('sha1', $stringToSign, $sign . '&', true));
|
||||
return $signature;
|
||||
}
|
||||
|
||||
private function _curl($params)
|
||||
{
|
||||
$uri = 'http://dysmsapi.aliyuncs.com/?' . http_build_query($params);
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
curl_setopt($ch, CURLOPT_URL, $uri);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
|
||||
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.98 Safari/537.36");
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
|
||||
$reponse = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
return $reponse;
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8"/>
|
||||
<title>阿里云通信短信发送示例 - FastAdmin</title>
|
||||
|
||||
<!-- Bootstrap Core CSS -->
|
||||
<link href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
<!-- Custom CSS -->
|
||||
<link href="__CDN__/assets/css/frontend.css" rel="stylesheet">
|
||||
|
||||
<!-- Plugin CSS -->
|
||||
<link href="https://cdn.staticfile.org/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
||||
<link href="https://cdn.staticfile.org/simple-line-icons/2.4.1/css/simple-line-icons.min.css" rel="stylesheet">
|
||||
|
||||
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||
<!--[if lt IE 9]>
|
||||
<script src="https://cdn.staticfile.org/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||
<script src="https://cdn.staticfile.org/respond.js/1.4.2/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="well" style="margin-top:30px;">
|
||||
<form class="form-horizontal" action="{:addon_url('alisms/index/send')}" method="POST">
|
||||
<fieldset>
|
||||
<legend>阿里云通信短信发送</legend>
|
||||
<div class="form-group">
|
||||
<label class="col-lg-2 control-label">手机号</label>
|
||||
<div class="col-lg-10">
|
||||
<input type="text" class="form-control" name="mobile" placeholder="手机号">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-lg-2 control-label">消息模板ID</label>
|
||||
<div class="col-lg-10">
|
||||
<input type="text" class="form-control" name="template" placeholder="消息模板ID,从阿里云通信获得,通常是:SMS_114000000这种格式">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-lg-2 control-label">签名</label>
|
||||
<div class="col-lg-10">
|
||||
<input type="text" class="form-control" name="sign" placeholder="消息模板(可以留空,留空使用后台插件管理中的配置)">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-lg-2 control-label">模板变量参数</label>
|
||||
<div class="col-lg-10">
|
||||
<textarea name="param" class="form-control" cols="30" rows="10" placeholder='必须是JSON字符串,如{"name":"李明"}'></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-lg-10 col-lg-offset-2">
|
||||
<button type="submit" class="btn btn-primary">发送</button>
|
||||
<button type="reset" class="btn btn-default">重置</button>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<!-- jQuery -->
|
||||
<script src="https://cdn.staticfile.org/jquery/2.1.4/jquery.min.js"></script>
|
||||
|
||||
<!-- Bootstrap Core JavaScript -->
|
||||
<script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1 +0,0 @@
|
||||
{"files":["application\\admin\\controller\\Command.php","application\\admin\\lang\\zh-cn\\command.php","application\\admin\\model\\Command.php","application\\admin\\validate\\Command.php","application\\admin\\view\\command\\add.html","application\\admin\\view\\command\\detail.html","application\\admin\\view\\command\\index.html","public\\assets\\js\\backend\\command.js"],"license":"regular","licenseto":"34485","licensekey":"wagt9BjP5LIzrmk3 MHw7JPCqrv+utw+1FcNEng==","domains":["localhost"],"licensecodes":[],"validations":["757319b447175b6ca1882635b132a594"],"menus":["command","command\/index","command\/add","command\/detail","command\/command","command\/execute","command\/del","command\/multi"]}
|
||||
@@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\command;
|
||||
|
||||
use app\common\library\Menu;
|
||||
use think\Addons;
|
||||
|
||||
/**
|
||||
* 在线命令插件
|
||||
*/
|
||||
class Command extends Addons
|
||||
{
|
||||
|
||||
/**
|
||||
* 插件安装方法
|
||||
* @return bool
|
||||
*/
|
||||
public function install()
|
||||
{
|
||||
$menu = [
|
||||
[
|
||||
'name' => 'command',
|
||||
'title' => '在线命令管理',
|
||||
'icon' => 'fa fa-terminal',
|
||||
'sublist' => [
|
||||
['name' => 'command/index', 'title' => '查看'],
|
||||
['name' => 'command/add', 'title' => '添加'],
|
||||
['name' => 'command/detail', 'title' => '详情'],
|
||||
['name' => 'command/command', 'title' => '生成并执行命令'],
|
||||
['name' => 'command/execute', 'title' => '再次执行命令'],
|
||||
['name' => 'command/del', 'title' => '删除'],
|
||||
['name' => 'command/multi', 'title' => '批量更新'],
|
||||
]
|
||||
]
|
||||
];
|
||||
Menu::create($menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件卸载方法
|
||||
* @return bool
|
||||
*/
|
||||
public function uninstall()
|
||||
{
|
||||
Menu::delete('command');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件启用方法
|
||||
* @return bool
|
||||
*/
|
||||
public function enable()
|
||||
{
|
||||
Menu::enable('command');
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件禁用方法
|
||||
* @return bool
|
||||
*/
|
||||
public function disable()
|
||||
{
|
||||
Menu::disable('command');
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
];
|
||||
@@ -1,15 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\command\controller;
|
||||
|
||||
use think\addons\Controller;
|
||||
|
||||
class Index extends Controller
|
||||
{
|
||||
|
||||
public function index()
|
||||
{
|
||||
$this->error("当前插件暂无前台页面");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
name = command
|
||||
title = 在线命令
|
||||
intro = 可在线执行一键生成CRUD、一键生成菜单等相关命令
|
||||
author = FastAdmin
|
||||
website = https://www.fastadmin.net
|
||||
version = 1.1.2
|
||||
state = 1
|
||||
url = /addons/command
|
||||
license = regular
|
||||
licenseto = 34485
|
||||
@@ -1,12 +0,0 @@
|
||||
CREATE TABLE IF NOT EXISTS `__PREFIX__command` (
|
||||
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||
`type` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '类型',
|
||||
`params` varchar(1500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '参数',
|
||||
`command` varchar(1500) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '' COMMENT '命令',
|
||||
`content` text COMMENT '返回结果',
|
||||
`executetime` bigint(16) UNSIGNED DEFAULT NULL COMMENT '执行时间',
|
||||
`createtime` bigint(16) UNSIGNED DEFAULT NULL COMMENT '创建时间',
|
||||
`updatetime` bigint(16) UNSIGNED DEFAULT NULL COMMENT '更新时间',
|
||||
`status` enum('successed','failured') CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'failured' COMMENT '状态',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '在线命令表';
|
||||
@@ -1,28 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\command\library;
|
||||
|
||||
/**
|
||||
* Class Output
|
||||
*/
|
||||
class Output extends \think\console\Output
|
||||
{
|
||||
|
||||
protected $message = [];
|
||||
|
||||
public function __construct($driver = 'console')
|
||||
{
|
||||
parent::__construct($driver);
|
||||
}
|
||||
|
||||
protected function block($style, $message)
|
||||
{
|
||||
$this->message[] = $message;
|
||||
}
|
||||
|
||||
public function getMessage()
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"files":["application\\admin\\controller\\Epay.php","public\\assets\\addons\\epay\\css\\common.css","public\\assets\\addons\\epay\\images\\alipay.png","public\\assets\\addons\\epay\\images\\expired.png","public\\assets\\addons\\epay\\images\\logo-alipay.png","public\\assets\\addons\\epay\\images\\logo-wechat.png","public\\assets\\addons\\epay\\images\\paid.png","public\\assets\\addons\\epay\\images\\scan.png","public\\assets\\addons\\epay\\images\\screenshot-alipay.png","public\\assets\\addons\\epay\\images\\screenshot-wechat.png","public\\assets\\addons\\epay\\images\\wechat.png","public\\assets\\addons\\epay\\js\\common.js","public\\assets\\addons\\epay\\js\\jquery.qrcode.min.js","public\\assets\\addons\\epay\\less\\common.less"],"license":"regular","licenseto":"34485","licensekey":"tkSvLrUYd59AD6Ge MGCbKNwNSKhfm+3lj0Kp9w==","domains":["localhost"],"licensecodes":[],"validations":["757319b447175b6ca1882635b132a594"]}
|
||||
@@ -1,100 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\epay;
|
||||
|
||||
use addons\epay\library\Service;
|
||||
use think\Addons;
|
||||
use think\Config;
|
||||
use think\Loader;
|
||||
|
||||
/**
|
||||
* 微信支付宝整合插件
|
||||
*/
|
||||
class Epay extends Addons
|
||||
{
|
||||
|
||||
/**
|
||||
* 插件安装方法
|
||||
* @return bool
|
||||
*/
|
||||
public function install()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件卸载方法
|
||||
* @return bool
|
||||
*/
|
||||
public function uninstall()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件启用方法
|
||||
* @return bool
|
||||
*/
|
||||
public function enable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件禁用方法
|
||||
* @return bool
|
||||
*/
|
||||
public function disable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// 支持自定义加载
|
||||
public function epayConfigInit()
|
||||
{
|
||||
$this->actionBegin();
|
||||
}
|
||||
|
||||
// 插件方法加载开始
|
||||
public function addonActionBegin()
|
||||
{
|
||||
$this->actionBegin();
|
||||
}
|
||||
|
||||
// 模块控制器方法加载开始
|
||||
public function actionBegin()
|
||||
{
|
||||
//添加命名空间
|
||||
if (!class_exists('\Yansongda\Pay\Pay')) {
|
||||
|
||||
//SDK版本
|
||||
$version = Service::getSdkVersion();
|
||||
|
||||
$libraryDir = ADDON_PATH . 'epay' . DS . 'library' . DS;
|
||||
Loader::addNamespace('Yansongda\Pay', $libraryDir . $version . DS . 'Yansongda' . DS . 'Pay' . DS);
|
||||
|
||||
$checkArr = [
|
||||
'\Hyperf\Context\Context' => 'context',
|
||||
'\Hyperf\Contract\Castable' => 'contract',
|
||||
'\Hyperf\Engine\Constant' => 'engine',
|
||||
'\Hyperf\Macroable\Macroable' => 'macroable',
|
||||
'\Hyperf\Pimple\Container' => 'pimple',
|
||||
'\Hyperf\Utils\Arr' => 'utils',
|
||||
];
|
||||
foreach ($checkArr as $index => $item) {
|
||||
if (!class_exists($index)) {
|
||||
Loader::addNamespace(substr($index, 1, strrpos($index, '\\') - 1), $libraryDir . 'hyperf' . DS . $item . DS . 'src' . DS);
|
||||
}
|
||||
}
|
||||
|
||||
if (!class_exists('\Yansongda\Supports\Logger')) {
|
||||
Loader::addNamespace('Yansongda\Supports', $libraryDir . $version . DS . 'Yansongda' . DS . 'Supports' . DS);
|
||||
}
|
||||
|
||||
// V3需载入辅助函数
|
||||
if ($version == Service::SDK_VERSION_V3) {
|
||||
require_once $libraryDir . $version . DS . 'Yansongda' . DS . 'Pay' . DS . 'Functions.php';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,450 +0,0 @@
|
||||
<form id="config-form" class="edit-form form-horizontal" role="form" data-toggle="validator" method="POST" action="">
|
||||
|
||||
<div class="panel panel-default panel-intro">
|
||||
<div class="panel-heading">
|
||||
<ul class="nav nav-tabs nav-group">
|
||||
<li class="active"><a href="#wechat" data-toggle="tab">微信支付</a></li>
|
||||
<li><a href="#alipay" data-toggle="tab">支付宝</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<div id="myTabContent" class="tab-content">
|
||||
{foreach $addon.config as $item}
|
||||
{if $item.name=='version'}
|
||||
<input type="hidden" value="{$item.value}" name="row[version]"/>
|
||||
|
||||
{elseif $item.name=='wechat'/}
|
||||
<div class="tab-pane fade active in" id="wechat">
|
||||
<table class="table table-striped table-config">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width="20%">APP的app_id</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[wechat][appid]" value="{$item.value.appid|default=''}" class="form-control" data-rule="" data-tip="APP应用中支付时使用"/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>公众号的app_id</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[wechat][app_id]" value="{$item.value.app_id|default=''}" class="form-control" data-rule="" data-tip="公众号中支付时使用"/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>公众号的app_secret</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[wechat][app_secret]" value="{$item.value.app_secret|default=''}" class="form-control" data-rule="" data-tip="公众号中支付时使用"/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>小程序的app_id</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[wechat][miniapp_id]" value="{$item.value.miniapp_id|default=''}" class="form-control" data-rule="" data-tip="仅在小程序支付时使用"/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>微信支付商户号</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[wechat][mch_id]" value="{$item.value.mch_id|default=''}" class="form-control" data-rule="" data-tip=""/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>微信支付商户API密钥V2</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[wechat][key]" value="{$item.value.key|default=''}" class="form-control" data-rule="" data-tip=""/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>微信支付商户API密钥V3</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[wechat][key_v3]" value="{$item.value.key_v3|default=''}" class="form-control" data-rule="" data-tip=""/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>支付模式</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
{:Form::radios('row[wechat][mode]',['normal'=>'正式环境','dev'=>'沙箱环境','service'=>'服务商模式'],$item.value.mode??'normal')}
|
||||
<div style="margin-top:5px;" data-type="dev" class="text-muted {if ($item.value.mode??'')!=='dev'}hidden{/if}">
|
||||
<i class="fa fa-info-circle"></i> 沙箱环境:<a href="https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=23_1&index=2" target="_blank">微信支付验收指引</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-type="service" class="{:$item.value.mode!='service'?'hidden':''}">
|
||||
<td>子商户商户号ID</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[wechat][sub_mch_id]" value="{$item.value.sub_mch_id|default=''}" class="form-control" data-rule="" data-tip="如果未用到子商户,请勿填写"/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-type="service" class="{:$item.value.mode!='service'?'hidden':''}">
|
||||
<td>子商户APP的app_id</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[wechat][sub_appid]" value="{$item.value.sub_appid|default=''}" class="form-control" data-rule="" data-tip="如果未用到子商户,请勿填写"/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-type="service" class="{:$item.value.mode!='service'?'hidden':''}">
|
||||
<td>子商户公众号的app_id</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[wechat][sub_app_id]" value="{$item.value.sub_app_id|default=''}" class="form-control" data-rule="" data-tip="如果未用到子商户,请勿填写"/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr data-type="service" class="{:$item.value.mode!='service'?'hidden':''}">
|
||||
<td>子商户小程序的app_id</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[wechat][sub_miniapp_id]" value="{$item.value.sub_miniapp_id|default=''}" class="form-control" data-rule="" data-tip="如果未用到子商户,请勿填写"/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>回调通知地址</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[wechat][notify_url]" value="{$item.value.notify_url|default=''}" class="form-control" data-rule="" data-tip="请勿随意修改,实际以逻辑代码中请求的为准"/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>微信支付API证书cert</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<div class="input-group">
|
||||
<input id="c-cert_client" class="form-control" size="50" name="row[wechat][cert_client]" type="text" value="{$item.value.cert_client|htmlentities}" data-tip="可选, 仅在退款、红包等情况时需要用到">
|
||||
<div class="input-group-addon no-border no-padding">
|
||||
<span><button type="button" id="faupload-cert_client" class="btn btn-danger faupload" data-url="epay/upload" data-multipart='{"certname":"cert_client"}' data-mimetype="pem" data-input-id="c-cert_client" data-multiple="false"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
|
||||
</div>
|
||||
<span class="msg-box n-right" for="c-cert_client"></span>
|
||||
</div>
|
||||
<div style="margin-top:5px;"><a href="https://pay.weixin.qq.com" target="_blank"><i class="fa fa-question-circle"></i> 如何获取微信支付API证书?</a></div>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>微信支付API证书key</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<div class="input-group">
|
||||
<input id="c-cert_key" class="form-control" size="50" name="row[wechat][cert_key]" type="text" value="{$item.value.cert_key|htmlentities}" data-tip="可选, 仅在退款、红包等情况时需要用到">
|
||||
<div class="input-group-addon no-border no-padding">
|
||||
<span><button type="button" id="faupload-cert_key" class="btn btn-danger faupload" data-url="epay/upload" data-multipart='{"certname":"cert_key"}' data-mimetype="pem" data-input-id="c-cert_key" data-multiple="false"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
|
||||
</div>
|
||||
<span class="msg-box n-right" for="c-cert_key"></span>
|
||||
</div>
|
||||
<div style="margin-top:5px;"><a href="https://pay.weixin.qq.com" target="_blank"><i class="fa fa-question-circle"></i> 如何获取微信支付API证书?</a></div>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>记录日志</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
{:Form::radios('row[wechat][log]',['1'=>'开启','0'=>'关闭'],$item.value.log)}
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{elseif $item.name=='alipay'}
|
||||
<div class="tab-pane fade" id="alipay">
|
||||
<table class="table table-striped table-config">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>支付模式</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-xs-12">
|
||||
{:Form::radios('row[alipay][mode]',['normal'=>'正式环境','dev'=>'沙箱环境', 'service'=>'服务商模式'],$item.value.mode??'normal')}
|
||||
|
||||
<div style="margin-top:5px;" data-mode="dev" class="text-muted {if ($item.value.mode??'')!=='dev'}hidden{/if}">
|
||||
<i class="fa fa-info-circle"></i> 如果使用沙箱环境,务必使用沙箱的app_id和沙箱配置,以及使用沙箱账号进行测试。<br>
|
||||
沙箱环境:<a href="https://openhome.alipay.com/develop/sandbox/app" target="_blank">https://openhome.alipay.com/develop/sandbox/app</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="text-muted {if ($item.value.mode??'')!=='service'}hidden{/if}" data-mode="service">
|
||||
<td width="20%">服务商ID(pid)</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[alipay][pid]" value="{$item.value.pid|default=''}" class="form-control" data-rule="" data-tip=""/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="20%">应用ID(app_id)</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[alipay][app_id]" value="{$item.value.app_id|default=''}" class="form-control" data-rule="" data-tip=""/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>回调通知地址</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[alipay][notify_url]" value="{$item.value.notify_url|default=''}" class="form-control" data-rule="" data-tip="请勿随意修改,实际以逻辑代码中请求的为准"/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>支付跳转地址</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[alipay][return_url]" value="{$item.value.return_url|default=''}" class="form-control" data-rule="" data-tip="请勿随意修改,实际以逻辑代码中请求的为准"/>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>应用私钥(private_key)</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<input type="text" name="row[alipay][private_key]" value="{$item.value.private_key|default=''}" class="form-control" data-rule=""/>
|
||||
<div style="margin-top:5px;"><a href="https://opensupport.alipay.com/support/helpcenter/207/201602469554" target="_blank"><i class="fa fa-question-circle"></i> 如何获取应用私钥?</a></div>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>签名方式</td>
|
||||
<td>
|
||||
<div>
|
||||
<div class="radio">
|
||||
<label for="row[alipay][signtype]-publickey"><input id="row[alipay][signtype]-publickey" name="row[alipay][signtype]" {if isset($item.value.signtype)&&$item.value.signtype=='publickey'}checked{/if} type="radio" value="publickey"> 普通公钥</label>
|
||||
<label for="row[alipay][signtype]-cert"><input id="row[alipay][signtype]-cert" {if isset($item.value.signtype)&&$item.value.signtype=='cert'}checked{/if} name="row[alipay][signtype]" type="radio" value="cert"> 公钥证书</label>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin:5px 0;" class="text-muted">
|
||||
<i class="fa fa-info-circle"></i> 如果要使用转账、提现功能,则必须使用公钥证书
|
||||
</div>
|
||||
<div data-signtype="publickey" class="{if ($item.value.signtype??'')==='cert'}hidden{/if}">
|
||||
<a href="https://opensupport.alipay.com/support/FAQ/65b9c843a8e10e054512d07dprod" target="_blank"><i class="fa fa-info-circle"></i> 如何生成支付宝公钥、应用私钥?</a>
|
||||
</div>
|
||||
<div data-signtype="cert" class="{if ($item.value.signtype??'')==='publickey'}hidden{/if}">
|
||||
<a href="https://opensupport.alipay.com/support/FAQ/6718ab4563fae8044fe13dc7prod" target="_blank"><i class="fa fa-info-circle"></i> 支付宝公钥证书、应用公钥证书、支付宝根证书?</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span data-signtype="publickey" class="{if ($item.value.signtype??'')==='cert'}hidden{/if}">支付宝公钥</span>
|
||||
<span data-signtype="cert" class="{if ($item.value.signtype??'')==='publickey' || ($item.value.signtype??'')==''}hidden{/if}">支付宝公钥证书路径</span>
|
||||
(alipay_public_key)
|
||||
</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<div class="input-group">
|
||||
<input id="c-ali_public_key" class="form-control" size="50" name="row[alipay][ali_public_key]" type="text" value="{$item.value.ali_public_key|default=''|htmlentities}" placeholder="普通公钥请直接粘贴,公钥证书请点击右侧的上传">
|
||||
<div class="input-group-addon no-border no-padding {if ($item.value.signtype??'')==='publickey' || ($item.value.signtype??'')==''}hidden{/if}" data-signtype="cert">
|
||||
<span><button type="button" id="faupload-ali_public_key" class="btn btn-danger faupload" data-url="epay/upload" data-multipart='{"certname":"ali_public_key"}' data-mimetype="crt" data-input-id="c-ali_public_key" data-multiple="false"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
|
||||
</div>
|
||||
<span class="msg-box n-right" for="c-ali_public_key"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="{if ($item.value.signtype??'')==='publickey' || ($item.value.signtype??'')==''}hidden{/if}" data-signtype="cert">
|
||||
<td>
|
||||
<span data-signtype="publickey" class="{if ($item.value.signtype??'')==='cert'}hidden{/if}">应用公钥</span>
|
||||
<span data-signtype="cert" class="{if ($item.value.signtype??'')==='publickey' || ($item.value.signtype??'')==''}hidden{/if}">应用公钥证书路径</span>
|
||||
(app_cert_public_key)
|
||||
</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<div class="input-group">
|
||||
<input id="c-app_cert_public_key" class="form-control" size="50" name="row[alipay][app_cert_public_key]" type="text" value="{$item.value.app_cert_public_key|default=''|htmlentities}">
|
||||
<div class="input-group-addon no-border no-padding {if ($item.value.signtype??'')==='publickey' || ($item.value.signtype??'')==''}hidden{/if}" data-signtype="cert">
|
||||
<span><button type="button" id="faupload-app_cert_public_key" class="btn btn-danger faupload" data-url="epay/upload" data-multipart='{"certname":"app_cert_public_key"}' data-mimetype="crt" data-input-id="c-app_cert_public_key" data-multiple="false"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
|
||||
</div>
|
||||
<span class="msg-box n-right" for="c-app_cert_public_key"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="{if ($item.value.signtype??'')==='publickey' || ($item.value.signtype??'')==''}hidden{/if}" data-signtype="cert">
|
||||
<td>支付宝根证书路径(alipay_root_cert)</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
<div class="input-group">
|
||||
<input id="c-alipay_root_cert" class="form-control" size="50" name="row[alipay][alipay_root_cert]" type="text" value="{$item.value.alipay_root_cert|default=''|htmlentities}">
|
||||
<div class="input-group-addon no-border no-padding">
|
||||
<span><button type="button" id="faupload-alipay_root_cert" class="btn btn-danger faupload" data-url="epay/upload" data-multipart='{"certname":"alipay_root_cert"}' data-mimetype="crt" data-input-id="c-alipay_root_cert" data-multiple="false"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
|
||||
</div>
|
||||
<span class="msg-box n-right" for="c-alipay_root_cert"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>记录日志</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
{:Form::radios('row[alipay][log]',['1'=>'开启','0'=>'关闭'],$item.value.log)}
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>PC端使用扫码支付</td>
|
||||
<td>
|
||||
<div class="row">
|
||||
<div class="col-sm-8 col-xs-12">
|
||||
{:Form::radios('row[alipay][scanpay]',['1'=>'开启','0'=>'关闭'],$item.value.scanpay??0)}
|
||||
</div>
|
||||
<div class="col-sm-4"></div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{/if}
|
||||
{/foreach}
|
||||
<div class="form-group layer-footer">
|
||||
<label class="control-label col-xs-12 col-sm-2"></label>
|
||||
<div class="col-xs-12 col-sm-8">
|
||||
<button type="submit" class="btn btn-primary btn-embossed disabled">{:__('OK')}</button>
|
||||
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<script>
|
||||
require.callback = function () {
|
||||
define('backend/addon', ['backend', 'form'], function (Backend, Form) {
|
||||
var Controller = {
|
||||
config: function () {
|
||||
$(document).on("click", ".nav-group li a[data-toggle='tab']", function () {
|
||||
if ($(this).attr("href") === "#all") {
|
||||
$(".tab-pane").addClass("active in");
|
||||
}
|
||||
return;
|
||||
});
|
||||
|
||||
$(document).on("click", "input[name='row[wechat][mode]']", function () {
|
||||
$("#wechat [data-type]").addClass("hidden");
|
||||
$("#wechat [data-type='" + $(this).val() + "']").removeClass("hidden");
|
||||
});
|
||||
$(document).on("click", "input[name='row[alipay][mode]']", function () {
|
||||
$("#alipay [data-mode]").addClass("hidden");
|
||||
$("#alipay [data-mode='" + $(this).val() + "']").removeClass("hidden");
|
||||
});
|
||||
$(document).on("click", "input[name='row[alipay][signtype]']", function () {
|
||||
let value = $(this).val();
|
||||
$("#alipay [data-signtype]").addClass("hidden");
|
||||
$("#alipay [data-signtype='" + value + "']").removeClass("hidden");
|
||||
});
|
||||
|
||||
Form.api.bindevent($("form[role=form]"), undefined, undefined, function () {
|
||||
let value = $("input[name='row[alipay][signtype]']:checked").val();
|
||||
// 如果选择了普通公钥,则需要清空未使用的应用公钥证书路径值和支付宝根证书路径值
|
||||
if (value === 'publickey') {
|
||||
$("#c-app_cert_public_key,#c-alipay_root_cert").val('');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
return Controller;
|
||||
});
|
||||
};
|
||||
</script>
|
||||
@@ -1,70 +0,0 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
[
|
||||
'name' => 'version',
|
||||
'title' => 'API版本(请勿修改该值)',
|
||||
'type' => 'radio',
|
||||
'content' => [],
|
||||
'value' => 'v2',
|
||||
'rule' => '',
|
||||
'msg' => '',
|
||||
'tip' => 'V2版本只支持微信支付V2密钥,V3版本只支持微信支付V3密钥,请勿修改该值!!!',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'wechat',
|
||||
'title' => '微信',
|
||||
'type' => 'array',
|
||||
'content' => [],
|
||||
'value' => [
|
||||
'appid' => '',
|
||||
'app_id' => '',
|
||||
'app_secret' => '',
|
||||
'miniapp_id' => '',
|
||||
'mch_id' => '',
|
||||
'key' => '',
|
||||
'key_v3' => '',
|
||||
'mode' => 'normal',
|
||||
'sub_mch_id' => '',
|
||||
'sub_appid' => '',
|
||||
'sub_app_id' => '',
|
||||
'sub_miniapp_id' => '',
|
||||
'notify_url' => '',
|
||||
'cert_client' => '/addons/epay/certs/apiclient_cert.pem',
|
||||
'cert_key' => '/addons/epay/certs/apiclient_key.pem',
|
||||
'log' => '1',
|
||||
],
|
||||
'rule' => 'required',
|
||||
'msg' => '',
|
||||
'tip' => '微信参数配置',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
],
|
||||
[
|
||||
'name' => 'alipay',
|
||||
'title' => '支付宝',
|
||||
'type' => 'array',
|
||||
'content' => [],
|
||||
'value' => [
|
||||
'app_id' => '',
|
||||
'mode' => 'normal',
|
||||
'notify_url' => '/addons/epay/api/notifyx/type/alipay',
|
||||
'return_url' => '/addons/epay/api/returnx/type/alipay',
|
||||
'private_key' => '',
|
||||
'signtype' => 'cert',
|
||||
'pid' => '',
|
||||
'ali_public_key' => '',
|
||||
'app_cert_public_key' => '',
|
||||
'alipay_root_cert' => '',
|
||||
'log' => '1',
|
||||
'scanpay' => '0',
|
||||
],
|
||||
'rule' => 'required',
|
||||
'msg' => '',
|
||||
'tip' => '支付宝参数配置',
|
||||
'ok' => '',
|
||||
'extend' => '',
|
||||
]
|
||||
];
|
||||
@@ -1,234 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\epay\controller;
|
||||
|
||||
use addons\epay\library\Service;
|
||||
use addons\epay\library\Wechat;
|
||||
use addons\third\model\Third;
|
||||
use app\common\library\Auth;
|
||||
use Exception;
|
||||
use think\addons\Controller;
|
||||
use think\Response;
|
||||
use think\Session;
|
||||
use Yansongda\Pay\Exceptions\GatewayException;
|
||||
use Yansongda\Pay\Pay;
|
||||
|
||||
/**
|
||||
* API接口控制器
|
||||
*
|
||||
* @package addons\epay\controller
|
||||
*/
|
||||
class Api extends Controller
|
||||
{
|
||||
|
||||
protected $layout = 'default';
|
||||
protected $config = [];
|
||||
|
||||
/**
|
||||
* 默认方法
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 外部提交
|
||||
*/
|
||||
public function submit()
|
||||
{
|
||||
$this->request->filter('trim');
|
||||
$out_trade_no = $this->request->request("out_trade_no");
|
||||
$title = $this->request->request("title");
|
||||
$amount = $this->request->request('amount');
|
||||
$type = $this->request->request('type', $this->request->request('paytype'));
|
||||
$method = $this->request->request('method', 'web');
|
||||
$openid = $this->request->request('openid', '');
|
||||
$auth_code = $this->request->request('auth_code', '');
|
||||
$notifyurl = $this->request->request('notifyurl', '');
|
||||
$returnurl = $this->request->request('returnurl', '');
|
||||
|
||||
if (!$amount || $amount < 0) {
|
||||
$this->error("支付金额必须大于0");
|
||||
}
|
||||
|
||||
if (!$type || !in_array($type, ['alipay', 'wechat'])) {
|
||||
$this->error("支付类型错误");
|
||||
}
|
||||
|
||||
$params = [
|
||||
'type' => $type,
|
||||
'out_trade_no' => $out_trade_no,
|
||||
'title' => $title,
|
||||
'amount' => $amount,
|
||||
'method' => $method,
|
||||
'openid' => $openid,
|
||||
'auth_code' => $auth_code,
|
||||
'notifyurl' => $notifyurl,
|
||||
'returnurl' => $returnurl,
|
||||
];
|
||||
return Service::submitOrder($params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信支付(公众号支付&PC扫码支付)
|
||||
*/
|
||||
public function wechat()
|
||||
{
|
||||
$config = Service::getConfig('wechat');
|
||||
|
||||
$isWechat = stripos($this->request->server('HTTP_USER_AGENT'), 'MicroMessenger') !== false;
|
||||
$isMobile = $this->request->isMobile();
|
||||
$this->view->assign("isWechat", $isWechat);
|
||||
$this->view->assign("isMobile", $isMobile);
|
||||
|
||||
//发起PC支付(Scan支付)(PC扫码模式)
|
||||
if ($this->request->isAjax()) {
|
||||
$pay = Pay::wechat($config);
|
||||
$orderid = $this->request->post("orderid");
|
||||
try {
|
||||
$result = Service::isVersionV3() ? $pay->find(['out_trade_no' => $orderid]) : $pay->find($orderid, 'scan');
|
||||
$this->success("", "", ['status' => $result['trade_state'] ?? 'NOTPAY']);
|
||||
} catch (GatewayException $e) {
|
||||
$this->error("查询失败(1001)");
|
||||
}
|
||||
}
|
||||
|
||||
$orderData = Session::get("wechatorderdata");
|
||||
if (!$orderData) {
|
||||
$this->error("请求参数错误");
|
||||
}
|
||||
if ($isWechat && $isMobile) {
|
||||
//发起公众号(jsapi支付),openid必须
|
||||
|
||||
//如果没有openid,则自动去获取openid
|
||||
if (!isset($orderData['openid']) || !$orderData['openid']) {
|
||||
$orderData['openid'] = Service::getOpenid();
|
||||
}
|
||||
|
||||
$orderData['method'] = 'mp';
|
||||
$type = 'jsapi';
|
||||
$payData = Service::submitOrder($orderData);
|
||||
if (!isset($payData['paySign'])) {
|
||||
$this->error("创建订单失败,请返回重试", "");
|
||||
}
|
||||
} else {
|
||||
$orderData['method'] = 'scan';
|
||||
$type = 'pc';
|
||||
$payData = Service::submitOrder($orderData);
|
||||
if (!isset($payData['code_url'])) {
|
||||
$this->error("创建订单失败,请返回重试", "");
|
||||
}
|
||||
}
|
||||
$this->view->assign("orderData", $orderData);
|
||||
$this->view->assign("payData", $payData);
|
||||
$this->view->assign("type", $type);
|
||||
|
||||
$this->view->assign("title", "微信支付");
|
||||
return $this->view->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付宝支付(PC扫码支付)
|
||||
*/
|
||||
public function alipay()
|
||||
{
|
||||
$config = Service::getConfig('alipay');
|
||||
|
||||
$isWechat = stripos($this->request->server('HTTP_USER_AGENT'), 'MicroMessenger') !== false;
|
||||
$isMobile = $this->request->isMobile();
|
||||
$this->view->assign("isWechat", $isWechat);
|
||||
$this->view->assign("isMobile", $isMobile);
|
||||
|
||||
if ($this->request->isAjax()) {
|
||||
$orderid = $this->request->post("orderid");
|
||||
$pay = Pay::alipay($config);
|
||||
try {
|
||||
$result = $pay->find(['out_trade_no' => $orderid]);
|
||||
if ($result['code'] == '10000' && $result['trade_status'] == 'TRADE_SUCCESS') {
|
||||
$this->success("", "", ['status' => $result['trade_status']]);
|
||||
} else {
|
||||
$this->error("查询失败");
|
||||
}
|
||||
} catch (GatewayException $e) {
|
||||
$this->error("查询失败(1001)");
|
||||
}
|
||||
}
|
||||
|
||||
//发起PC支付(Scan支付)(PC扫码模式)
|
||||
$orderData = Session::get("alipayorderdata");
|
||||
if (!$orderData) {
|
||||
$this->error("请求参数错误");
|
||||
}
|
||||
|
||||
$orderData['method'] = 'scan';
|
||||
$payData = Service::submitOrder($orderData);
|
||||
if (!isset($payData['qr_code'])) {
|
||||
$this->error("创建订单失败,请返回重试");
|
||||
}
|
||||
|
||||
$type = 'pc';
|
||||
$this->view->assign("orderData", $orderData);
|
||||
$this->view->assign("payData", $payData);
|
||||
$this->view->assign("type", $type);
|
||||
$this->view->assign("title", "支付宝支付");
|
||||
return $this->view->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付成功回调
|
||||
*/
|
||||
public function notifyx()
|
||||
{
|
||||
$paytype = $this->request->param('paytype');
|
||||
$pay = Service::checkNotify($paytype);
|
||||
if (!$pay) {
|
||||
return json(['code' => 'FAIL', 'message' => '失败'], 500, ['Content-Type' => 'application/json']);
|
||||
}
|
||||
|
||||
// 获取回调数据,V3和V2的回调接收不同
|
||||
$data = Service::isVersionV3() ? $pay->callback() : $pay->verify();
|
||||
|
||||
try {
|
||||
//微信支付V3返回和V2不同
|
||||
if (Service::isVersionV3() && $paytype === 'wechat') {
|
||||
$data = $data['resource']['ciphertext'];
|
||||
$data['total_fee'] = $data['amount']['total'];
|
||||
}
|
||||
|
||||
\think\Log::record($data);
|
||||
//获取支付金额、订单号
|
||||
$payamount = $paytype == 'alipay' ? $data['total_amount'] : $data['total_fee'] / 100;
|
||||
$out_trade_no = $data['out_trade_no'];
|
||||
|
||||
\think\Log::record("回调成功,订单号:{$out_trade_no},金额:{$payamount}");
|
||||
|
||||
//你可以在此编写订单逻辑
|
||||
} catch (Exception $e) {
|
||||
\think\Log::record("回调逻辑处理错误:" . $e->getMessage(), "error");
|
||||
}
|
||||
|
||||
//下面这句必须要执行,且在此之前不能有任何输出
|
||||
if (Service::isVersionV3()) {
|
||||
return $pay->success()->getBody()->getContents();
|
||||
} else {
|
||||
return $pay->success()->send();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付成功返回
|
||||
*/
|
||||
public function returnx()
|
||||
{
|
||||
$paytype = $this->request->param('paytype');
|
||||
if (Service::checkReturn($paytype)) {
|
||||
echo '签名错误';
|
||||
return;
|
||||
}
|
||||
|
||||
//你可以在这里定义你的提示信息,但切记不可在此编写逻辑
|
||||
$this->success("恭喜你!支付成功!", addon_url("epay/index/index"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\epay\controller;
|
||||
|
||||
use addons\epay\library\Service;
|
||||
use fast\Random;
|
||||
use think\addons\Controller;
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* 微信支付宝整合插件首页
|
||||
*
|
||||
* 此控制器仅用于开发展示说明和测试,请自行添加一个新的控制器进行处理返回和回调事件,同时删除此控制器文件
|
||||
*
|
||||
* Class Index
|
||||
* @package addons\epay\controller
|
||||
*/
|
||||
class Index extends Controller
|
||||
{
|
||||
protected $layout = 'default';
|
||||
|
||||
protected $config = [];
|
||||
|
||||
public function _initialize()
|
||||
{
|
||||
parent::_initialize();
|
||||
if (!config("app_debug")) {
|
||||
$this->error("仅在开发环境下查看");
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$this->view->assign("title", "微信支付宝整合");
|
||||
return $this->view->fetch();
|
||||
}
|
||||
|
||||
/**
|
||||
* 体验,仅供开发测试
|
||||
*/
|
||||
public function experience()
|
||||
{
|
||||
$amount = $this->request->post('amount');
|
||||
$type = $this->request->post('type');
|
||||
$method = $this->request->post('method');
|
||||
$openid = $this->request->post('openid', "");
|
||||
|
||||
if (!$amount || $amount < 0) {
|
||||
$this->error("支付金额必须大于0");
|
||||
}
|
||||
|
||||
if (!$type || !in_array($type, ['alipay', 'wechat'])) {
|
||||
$this->error("支付类型不能为空");
|
||||
}
|
||||
|
||||
if (in_array($method, ['miniapp', 'mp']) && !$openid) {
|
||||
$this->error("openid不能为空");
|
||||
}
|
||||
|
||||
//订单号
|
||||
$out_trade_no = date("YmdHis") . mt_rand(100000, 999999);
|
||||
|
||||
//订单标题
|
||||
$title = '测试订单';
|
||||
|
||||
//回调链接
|
||||
$notifyurl = $this->request->root(true) . '/addons/epay/index/notifyx/paytype/' . $type;
|
||||
$returnurl = $this->request->root(true) . '/addons/epay/index/returnx/paytype/' . $type . '/out_trade_no/' . $out_trade_no;
|
||||
|
||||
$response = Service::submitOrder($amount, $out_trade_no, $type, $title, $notifyurl, $returnurl, $method, $openid);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付成功,仅供开发测试
|
||||
*/
|
||||
public function notifyx()
|
||||
{
|
||||
$paytype = $this->request->param('paytype');
|
||||
$pay = Service::checkNotify($paytype);
|
||||
if (!$pay) {
|
||||
return json(['code' => 'FAIL', 'message' => '失败'], 500, ['Content-Type' => 'application/json']);
|
||||
}
|
||||
|
||||
// 获取回调数据,V3和V2的回调接收不同
|
||||
$data = Service::isVersionV3() ? $pay->callback() : $pay->verify();
|
||||
|
||||
try {
|
||||
//微信支付V3返回和V2不同
|
||||
if (Service::isVersionV3() && $paytype === 'wechat') {
|
||||
$data = $data['resource']['ciphertext'];
|
||||
$data['total_fee'] = $data['amount']['total'];
|
||||
}
|
||||
|
||||
\think\Log::record($data);
|
||||
//获取支付金额、订单号
|
||||
$payamount = $paytype == 'alipay' ? $data['total_amount'] : $data['total_fee'] / 100;
|
||||
$out_trade_no = $data['out_trade_no'];
|
||||
|
||||
\think\Log::record("回调成功,订单号:{$out_trade_no},金额:{$payamount}");
|
||||
|
||||
//你可以在此编写订单逻辑
|
||||
} catch (Exception $e) {
|
||||
\think\Log::record("回调逻辑处理错误:" . $e->getMessage(), "error");
|
||||
}
|
||||
|
||||
//下面这句必须要执行,且在此之前不能有任何输出
|
||||
if (Service::isVersionV3()) {
|
||||
return $pay->success()->getBody()->getContents();
|
||||
} else {
|
||||
return $pay->success()->send();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 支付返回,仅供开发测试
|
||||
*/
|
||||
public function returnx()
|
||||
{
|
||||
$paytype = $this->request->param('paytype');
|
||||
$out_trade_no = $this->request->param('out_trade_no');
|
||||
$pay = Service::checkReturn($paytype);
|
||||
if (!$pay) {
|
||||
$this->error('签名错误', '');
|
||||
}
|
||||
|
||||
//你可以在这里定义你的提示信息,但切记不可在此编写逻辑
|
||||
$this->success("请返回网站查看支付结果", addon_url("epay/index/index"));
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
name = epay
|
||||
title = 微信支付宝整合
|
||||
intro = 可用于快速整合企业微信、支付宝支付功能
|
||||
author = FastAdmin
|
||||
website = https://www.fastadmin.net
|
||||
version = 1.3.9
|
||||
state = 1
|
||||
url = /addons/epay
|
||||
license = regular
|
||||
licenseto = 34485
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\epay\library;
|
||||
|
||||
class Collection extends \Yansongda\Supports\Collection
|
||||
{
|
||||
|
||||
/**
|
||||
* 创建 Collection 实例
|
||||
* @access public
|
||||
* @param array $items 数据
|
||||
* @return static
|
||||
*/
|
||||
public static function make($items = [])
|
||||
{
|
||||
return new static($items);
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\epay\library;
|
||||
|
||||
use think\Exception;
|
||||
|
||||
class OrderException extends Exception
|
||||
{
|
||||
public function __construct($message = "", $code = 0, $data = [])
|
||||
{
|
||||
$this->message = $message;
|
||||
$this->code = $code;
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\epay\library;
|
||||
|
||||
class RedirectResponse extends \Symfony\Component\HttpFoundation\RedirectResponse implements \JsonSerializable, \Serializable
|
||||
{
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getContent();
|
||||
}
|
||||
|
||||
public function setTargetUrl($url)
|
||||
{
|
||||
if ('' === ($url ?? '')) {
|
||||
throw new \InvalidArgumentException('无法跳转到空页面');
|
||||
}
|
||||
|
||||
$this->targetUrl = $url;
|
||||
|
||||
$this->setContent(
|
||||
sprintf('<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="refresh" content="0;url=\'%1$s\'" />
|
||||
|
||||
<title>正在跳转支付 %1$s</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="redirect" style="display:none;">正在跳转支付 <a href="%1$s">%1$s</a></div>
|
||||
<script type="text/javascript">
|
||||
setTimeout(function(){
|
||||
document.getElementById("redirect").style.display = "block";
|
||||
}, 1000);
|
||||
</script>
|
||||
</body>
|
||||
</html>', htmlspecialchars($url, \ENT_QUOTES, 'UTF-8')));
|
||||
|
||||
$this->headers->set('Location', $url);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->getContent();
|
||||
}
|
||||
|
||||
public function serialize()
|
||||
{
|
||||
return serialize($this->content);
|
||||
}
|
||||
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
return $this->content = unserialize($serialized);
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\epay\library;
|
||||
|
||||
class Response extends \Symfony\Component\HttpFoundation\Response implements \JsonSerializable, \Serializable
|
||||
{
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getContent();
|
||||
}
|
||||
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return $this->getContent();
|
||||
}
|
||||
|
||||
public function serialize()
|
||||
{
|
||||
return serialize($this->content);
|
||||
}
|
||||
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
return $this->content = unserialize($serialized);
|
||||
}
|
||||
}
|
||||
@@ -1,489 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\epay\library;
|
||||
|
||||
use addons\third\model\Third;
|
||||
use app\common\library\Auth;
|
||||
use Exception;
|
||||
use think\Hook;
|
||||
use think\Session;
|
||||
use Yansongda\Pay\Pay;
|
||||
use Yansongda\Supports\Str;
|
||||
|
||||
/**
|
||||
* 订单服务类
|
||||
*
|
||||
* @package addons\epay\library
|
||||
*/
|
||||
class Service
|
||||
{
|
||||
|
||||
public const SDK_VERSION_V2 = 'v2';
|
||||
|
||||
public const SDK_VERSION_V3 = 'v3';
|
||||
|
||||
/**
|
||||
* 提交订单
|
||||
* @param array|float $amount 订单金额
|
||||
* @param string $orderid 订单号
|
||||
* @param string $type 支付类型,可选alipay或wechat
|
||||
* @param string $title 订单标题
|
||||
* @param string $notifyurl 通知回调URL
|
||||
* @param string $returnurl 跳转返回URL
|
||||
* @param string $method 支付方法
|
||||
* @param string $openid Openid
|
||||
* @param array $custom 自定义微信支付宝相关配置
|
||||
* @return Response|RedirectResponse|Collection
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function submitOrder($amount, $orderid = null, $type = null, $title = null, $notifyurl = null, $returnurl = null, $method = null, $openid = '', $custom = [])
|
||||
{
|
||||
$version = self::getSdkVersion();
|
||||
$request = request();
|
||||
$addonConfig = get_addon_config('epay');
|
||||
|
||||
if (!is_array($amount)) {
|
||||
$params = [
|
||||
'amount' => $amount,
|
||||
'orderid' => $orderid,
|
||||
'type' => $type,
|
||||
'title' => $title,
|
||||
'notifyurl' => $notifyurl,
|
||||
'returnurl' => $returnurl,
|
||||
'method' => $method,
|
||||
'openid' => $openid,
|
||||
'custom' => $custom,
|
||||
];
|
||||
} else {
|
||||
$params = $amount;
|
||||
}
|
||||
$type = isset($params['type']) && in_array($params['type'], ['alipay', 'wechat']) ? $params['type'] : 'wechat';
|
||||
$method = $params['method'] ?? 'web';
|
||||
$orderid = $params['orderid'] ?? date("YmdHis") . mt_rand(100000, 999999);
|
||||
$amount = $params['amount'] ?? 1;
|
||||
$title = $params['title'] ?? "支付";
|
||||
$auth_code = $params['auth_code'] ?? '';
|
||||
$openid = $params['openid'] ?? '';
|
||||
|
||||
//自定义微信支付宝相关配置
|
||||
$custom = $params['custom'] ?? [];
|
||||
|
||||
//未定义则使用默认回调和跳转
|
||||
$notifyurl = !empty($params['notifyurl']) ? $params['notifyurl'] : $request->root(true) . '/addons/epay/index/notifyx/paytype/' . $type;
|
||||
$returnurl = !empty($params['returnurl']) ? $params['returnurl'] : $request->root(true) . '/addons/epay/index/returnx/paytype/' . $type . '/out_trade_no/' . $orderid;
|
||||
|
||||
$html = '';
|
||||
$config = Service::getConfig($type, array_merge($custom, ['notify_url' => $notifyurl, 'return_url' => $returnurl]));
|
||||
|
||||
//判断是否移动端或微信内浏览器
|
||||
$isMobile = $request->isMobile();
|
||||
$isWechat = strpos($request->server('HTTP_USER_AGENT'), 'MicroMessenger') !== false;
|
||||
|
||||
$result = null;
|
||||
if ($type == 'alipay') {
|
||||
//如果是PC支付,判断当前环境,进行跳转
|
||||
if ($method == 'web') {
|
||||
//如果是微信环境或后台配置PC使用扫码支付
|
||||
if ($isWechat || $addonConfig['alipay']['scanpay']) {
|
||||
Session::set("alipayorderdata", $params);
|
||||
$url = addon_url('epay/api/alipay', [], true, true);
|
||||
return new RedirectResponse($url);
|
||||
} elseif ($isMobile) {
|
||||
$method = 'wap';
|
||||
}
|
||||
}
|
||||
|
||||
//创建支付对象
|
||||
$pay = Pay::alipay($config);
|
||||
$params = [
|
||||
'out_trade_no' => $orderid,//你的订单号
|
||||
'total_amount' => $amount,//单位元
|
||||
'subject' => $title,
|
||||
];
|
||||
|
||||
switch ($method) {
|
||||
case 'web':
|
||||
//电脑支付
|
||||
$result = $pay->web($params);
|
||||
break;
|
||||
case 'wap':
|
||||
//手机网页支付
|
||||
$result = $pay->wap($params);
|
||||
break;
|
||||
case 'app':
|
||||
//APP支付
|
||||
$result = $pay->app($params);
|
||||
break;
|
||||
case 'scan':
|
||||
//扫码支付
|
||||
$result = $pay->scan($params);
|
||||
break;
|
||||
case 'pos':
|
||||
//刷卡支付必须要有auth_code
|
||||
$params['auth_code'] = $auth_code;
|
||||
$result = $pay->pos($params);
|
||||
break;
|
||||
case 'mini':
|
||||
case 'miniapp':
|
||||
//小程序支付,直接返回字符串
|
||||
//小程序支付必须要有buyer_id或buyer_open_id
|
||||
if (is_numeric($openid) && strlen($openid) === 16) {
|
||||
$params['buyer_id'] = $openid;
|
||||
} else {
|
||||
$params['buyer_open_id'] = $openid;
|
||||
}
|
||||
$result = $pay->mini($params);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
//如果是PC支付,判断当前环境,进行跳转
|
||||
if ($method == 'web') {
|
||||
//如果是移动端,但不是微信环境
|
||||
if ($isMobile && !$isWechat) {
|
||||
$method = 'wap';
|
||||
} else {
|
||||
Session::set("wechatorderdata", $params);
|
||||
$url = addon_url('epay/api/wechat', [], true, true);
|
||||
return new RedirectResponse($url);
|
||||
}
|
||||
}
|
||||
|
||||
//单位分
|
||||
$total_fee = function_exists('bcmul') ? bcmul($amount, 100) : $amount * 100;
|
||||
$total_fee = (int)$total_fee;
|
||||
$ip = $request->ip();
|
||||
//微信服务商模式时需传递sub_openid参数
|
||||
$openidName = $addonConfig['wechat']['mode'] == 'service' ? 'sub_openid' : 'openid';
|
||||
|
||||
//创建支付对象
|
||||
$pay = Pay::wechat($config);
|
||||
|
||||
if (self::isVersionV3()) {
|
||||
//V3支付
|
||||
$params = [
|
||||
'out_trade_no' => $orderid,
|
||||
'description' => $title,
|
||||
'amount' => [
|
||||
'total' => $total_fee,
|
||||
]
|
||||
];
|
||||
switch ($method) {
|
||||
case 'mp':
|
||||
//公众号支付
|
||||
//公众号支付必须有openid
|
||||
$params['payer'] = [$openidName => $openid];
|
||||
$result = $pay->mp($params);
|
||||
break;
|
||||
case 'wap':
|
||||
//手机网页支付,跳转
|
||||
$params['scene_info'] = [
|
||||
'payer_client_ip' => $ip,
|
||||
'h5_info' => [
|
||||
'type' => 'Wap',
|
||||
]
|
||||
];
|
||||
$result = $pay->wap($params);
|
||||
break;
|
||||
case 'app':
|
||||
//APP支付,直接返回字符串
|
||||
$result = $pay->app($params);
|
||||
break;
|
||||
case 'scan':
|
||||
//扫码支付,直接返回字符串
|
||||
$result = $pay->scan($params);
|
||||
break;
|
||||
case 'pos':
|
||||
//刷卡支付,直接返回字符串
|
||||
//刷卡支付必须要有auth_code
|
||||
$params['auth_code'] = $auth_code;
|
||||
$result = $pay->pos($params);
|
||||
break;
|
||||
case 'mini':
|
||||
case 'miniapp':
|
||||
//小程序支付,直接返回字符串
|
||||
//小程序支付必须要有openid
|
||||
$params['payer'] = [$openidName => $openid];
|
||||
$result = $pay->mini($params);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
} else {
|
||||
//V2支付
|
||||
$params = [
|
||||
'out_trade_no' => $orderid,
|
||||
'body' => $title,
|
||||
'total_fee' => $total_fee,
|
||||
];
|
||||
switch ($method) {
|
||||
case 'mp':
|
||||
//公众号支付
|
||||
//公众号支付必须有openid
|
||||
$params[$openidName] = $openid;
|
||||
$result = $pay->mp($params);
|
||||
break;
|
||||
case 'wap':
|
||||
//手机网页支付,跳转
|
||||
$params['spbill_create_ip'] = $ip;
|
||||
$result = $pay->wap($params);
|
||||
break;
|
||||
case 'app':
|
||||
//APP支付,直接返回字符串
|
||||
$result = $pay->app($params);
|
||||
break;
|
||||
case 'scan':
|
||||
//扫码支付,直接返回字符串
|
||||
$result = $pay->scan($params);
|
||||
break;
|
||||
case 'pos':
|
||||
//刷卡支付,直接返回字符串
|
||||
//刷卡支付必须要有auth_code
|
||||
$params['auth_code'] = $auth_code;
|
||||
$result = $pay->pos($params);
|
||||
break;
|
||||
case 'mini':
|
||||
case 'miniapp':
|
||||
//小程序支付,直接返回字符串
|
||||
//小程序支付必须要有openid
|
||||
$params[$openidName] = $openid;
|
||||
$result = $pay->miniapp($params);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//使用重写的Response类、RedirectResponse、Collection类
|
||||
if ($result instanceof \Symfony\Component\HttpFoundation\RedirectResponse) {
|
||||
$result = new RedirectResponse($result->getTargetUrl());
|
||||
} elseif ($result instanceof \Symfony\Component\HttpFoundation\Response) {
|
||||
$result = new Response($result->getContent());
|
||||
} elseif ($result instanceof \Yansongda\Supports\Collection) {
|
||||
$result = Collection::make($result->all());
|
||||
} elseif ($result instanceof \GuzzleHttp\Psr7\Response) {
|
||||
$result = new Response($result->getBody());
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证回调是否成功
|
||||
* @param string $type 支付类型
|
||||
* @param array $custom 自定义配置信息
|
||||
* @return bool|\Yansongda\Pay\Gateways\Alipay|\Yansongda\Pay\Gateways\Wechat|\Yansongda\Pay\Provider\Wechat|\Yansongda\Pay\Provider\Alipay
|
||||
*/
|
||||
public static function checkNotify($type, $custom = [])
|
||||
{
|
||||
$type = strtolower($type);
|
||||
if (!in_array($type, ['wechat', 'alipay'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$version = self::getSdkVersion();
|
||||
|
||||
try {
|
||||
$config = self::getConfig($type, $custom);
|
||||
$pay = $type == 'wechat' ? Pay::wechat($config) : Pay::alipay($config);
|
||||
|
||||
$data = Service::isVersionV3() ? $pay->callback() : $pay->verify();
|
||||
if ($type == 'alipay') {
|
||||
if (in_array($data['trade_status'], ['TRADE_SUCCESS', 'TRADE_FINISHED'])) {
|
||||
return $pay;
|
||||
}
|
||||
} else {
|
||||
return $pay;
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
\think\Log::record("回调请求参数解析错误", "error");
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证返回是否成功,请勿用于判断是否支付成功的逻辑验证
|
||||
* 已弃用
|
||||
*
|
||||
* @param string $type 支付类型
|
||||
* @param array $custom 自定义配置信息
|
||||
* @return bool
|
||||
* @deprecated 已弃用,请勿用于逻辑验证
|
||||
*/
|
||||
public static function checkReturn($type, $custom = [])
|
||||
{
|
||||
//由于PC及移动端无法获取请求的参数信息,取消return验证,均返回true
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理证书路径
|
||||
* @param array $config 配置
|
||||
* @param string $field 字段
|
||||
* @return void
|
||||
*/
|
||||
private static function processAddonsPath(&$config, $field)
|
||||
{
|
||||
if (isset($config[$field]) && substr($config[$field], 0, 8) == '/addons/') {
|
||||
$config[$field] = ROOT_PATH . str_replace('/', DS, substr($config[$field], 1));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取配置
|
||||
* @param string $type 支付类型
|
||||
* @param array $custom 自定义配置,用于覆盖插件默认配置
|
||||
* @return array
|
||||
*/
|
||||
public static function getConfig($type = 'wechat', $custom = [])
|
||||
{
|
||||
$addonConfig = get_addon_config('epay');
|
||||
$config = $addonConfig[$type] ?? $addonConfig['wechat'];
|
||||
|
||||
// SDK版本
|
||||
$version = self::getSdkVersion();
|
||||
|
||||
// 处理微信证书路径
|
||||
if ($type === 'wechat') {
|
||||
$certFields = ['cert_client', 'cert_key'];
|
||||
foreach ($certFields as $field) {
|
||||
self::processAddonsPath($config, $field);
|
||||
}
|
||||
}
|
||||
|
||||
// 处理支付宝证书路径
|
||||
if ($type === 'alipay') {
|
||||
$config['signtype'] = $config['signtype'] ?? 'publickey';
|
||||
if ($config['signtype'] == 'cert') {
|
||||
$certFields = ['app_cert_public_key', 'alipay_root_cert', 'ali_public_key'];
|
||||
foreach ($certFields as $field) {
|
||||
self::processAddonsPath($config, $field);
|
||||
}
|
||||
} else {
|
||||
// 如果是普通公钥需要将app_cert_public_key和alipay_root_cert设置为空,不然会导致错误
|
||||
$config['app_cert_public_key'] = '';
|
||||
$config['alipay_root_cert'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
// V3支付
|
||||
if (self::isVersionV3()) {
|
||||
if ($type == 'wechat') {
|
||||
$config['mp_app_id'] = $config['app_id'] ?? '';
|
||||
$config['app_id'] = $config['appid'] ?? '';
|
||||
$config['mini_app_id'] = $config['miniapp_id'] ?? '';
|
||||
$config['combine_mch_id'] = $config['combine_mch_id'] ?? '';
|
||||
$config['mch_secret_key'] = $config['key_v3'] ?? '';
|
||||
$config['mch_secret_cert'] = $config['cert_key'];
|
||||
$config['mch_public_cert_path'] = $config['cert_client'];
|
||||
|
||||
$config['sub_mp_app_id'] = $config['sub_appid'] ?? '';
|
||||
$config['sub_app_id'] = $config['sub_app_id'] ?? '';
|
||||
$config['sub_mini_app_id'] = $config['sub_miniapp_id'] ?? '';
|
||||
$config['sub_mch_id'] = $config['sub_mch_id'] ?? '';
|
||||
} elseif ($type == 'alipay') {
|
||||
$config['app_secret_cert'] = $config['private_key'] ?? '';
|
||||
$config['app_public_cert_path'] = $config['app_cert_public_key'] ?? '';
|
||||
$config['alipay_public_cert_path'] = $config['ali_public_key'] ?? '';
|
||||
$config['alipay_root_cert_path'] = $config['alipay_root_cert'] ?? '';
|
||||
$config['service_provider_id'] = $config['pid'] ?? '';
|
||||
}
|
||||
$modeArr = ['normal' => 0, 'dev' => 1, 'service' => 2];
|
||||
$config['mode'] = $modeArr[$config['mode']] ?? 0;
|
||||
}
|
||||
|
||||
// 日志
|
||||
if ($config['log']) {
|
||||
$config['log'] = [
|
||||
'enable' => true,
|
||||
'file' => LOG_PATH . 'epaylogs' . DS . $type . '-' . date("Y-m-d") . '.log',
|
||||
'level' => 'debug'
|
||||
];
|
||||
} else {
|
||||
$config['log'] = [
|
||||
'enable' => false,
|
||||
];
|
||||
}
|
||||
|
||||
// GuzzleHttp配置,可选
|
||||
$config['http'] = [
|
||||
'timeout' => 10,
|
||||
'connect_timeout' => 10,
|
||||
// 更多配置项请参考 [Guzzle](https://guzzle-cn.readthedocs.io/zh_CN/latest/request-options.html)
|
||||
];
|
||||
|
||||
$config['notify_url'] = empty($config['notify_url']) ? addon_url('epay/api/notifyx', [], false) . '/type/' . $type : $config['notify_url'];
|
||||
$config['notify_url'] = !preg_match("/^(http:\/\/|https:\/\/)/i", $config['notify_url']) ? request()->root(true) . $config['notify_url'] : $config['notify_url'];
|
||||
$config['return_url'] = empty($config['return_url']) ? addon_url('epay/api/returnx', [], false) . '/type/' . $type : $config['return_url'];
|
||||
$config['return_url'] = !preg_match("/^(http:\/\/|https:\/\/)/i", $config['return_url']) ? request()->root(true) . $config['return_url'] : $config['return_url'];
|
||||
|
||||
//合并自定义配置
|
||||
$config = array_merge($config, $custom);
|
||||
|
||||
//v3版本时返回的结构不同
|
||||
if (self::isVersionV3()) {
|
||||
$config = [$type => ['default' => $config], 'logger' => $config['log'], 'http' => $config['http'], '_force' => true];
|
||||
|
||||
}
|
||||
return $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信Openid
|
||||
*
|
||||
* @param array $custom 自定义配置信息
|
||||
* @return mixed|string
|
||||
*/
|
||||
public static function getOpenid($custom = [])
|
||||
{
|
||||
$openid = '';
|
||||
$auth = Auth::instance();
|
||||
if ($auth->isLogin()) {
|
||||
$third = get_addon_info('third');
|
||||
if ($third && $third['state']) {
|
||||
$thirdInfo = Third::where('user_id', $auth->id)->where('platform', 'wechat')->where('apptype', 'mp')->find();
|
||||
$openid = $thirdInfo ? $thirdInfo['openid'] : '';
|
||||
}
|
||||
}
|
||||
if (!$openid) {
|
||||
$openid = Session::get("openid");
|
||||
|
||||
//如果未传openid,则去读取openid
|
||||
if (!$openid) {
|
||||
$addonConfig = get_addon_config('epay');
|
||||
$wechat = new Wechat($custom['app_id'] ?? $addonConfig['wechat']['app_id'], $custom['app_secret'] ?? $addonConfig['wechat']['app_secret']);
|
||||
$openid = $wechat->getOpenid();
|
||||
}
|
||||
}
|
||||
return $openid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取SDK版本
|
||||
* @return mixed|string
|
||||
*/
|
||||
public static function getSdkVersion()
|
||||
{
|
||||
$addonConfig = get_addon_config('epay');
|
||||
return $addonConfig['version'] ?? self::SDK_VERSION_V2;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否V2支付
|
||||
* @return bool
|
||||
*/
|
||||
public static function isVersionV2()
|
||||
{
|
||||
return self::getSdkVersion() === self::SDK_VERSION_V2;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否V3支付
|
||||
* @return bool
|
||||
*/
|
||||
public static function isVersionV3()
|
||||
{
|
||||
return self::getSdkVersion() === self::SDK_VERSION_V3;
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace addons\epay\library;
|
||||
|
||||
use fast\Http;
|
||||
use think\Cache;
|
||||
use think\Session;
|
||||
|
||||
/**
|
||||
* 微信授权
|
||||
*
|
||||
*/
|
||||
class Wechat
|
||||
{
|
||||
private $app_id = '';
|
||||
private $app_secret = '';
|
||||
private $scope = 'snsapi_userinfo';
|
||||
|
||||
public function __construct($app_id, $app_secret)
|
||||
{
|
||||
$this->app_id = $app_id;
|
||||
$this->app_secret = $app_secret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信授权链接
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getAuthorizeUrl()
|
||||
{
|
||||
$redirect_uri = addon_url('epay/api/wechat', [], true, true);
|
||||
$redirect_uri = urlencode($redirect_uri);
|
||||
$state = \fast\Random::alnum();
|
||||
Session::set('state', $state);
|
||||
return "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->app_id}&redirect_uri={$redirect_uri}&response_type=code&scope={$this->scope}&state={$state}#wechat_redirect";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取微信openid
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function getOpenid()
|
||||
{
|
||||
$openid = Session::get('openid');
|
||||
if (!$openid) {
|
||||
if (!isset($_GET['code'])) {
|
||||
$url = $this->getAuthorizeUrl();
|
||||
|
||||
Header("Location: $url");
|
||||
exit();
|
||||
} else {
|
||||
$state = Session::get('state');
|
||||
if ($state == $_GET['state']) {
|
||||
$code = $_GET['code'];
|
||||
$token = $this->getAccessToken($code);
|
||||
if (!isset($token['openid']) && isset($token['errmsg'])) {
|
||||
exception($token['errmsg']);
|
||||
}
|
||||
$openid = $token['openid'] ?? '';
|
||||
if ($openid) {
|
||||
Session::set("openid", $openid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $openid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取授权token网页授权
|
||||
*
|
||||
* @param string $code
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function getAccessToken($code = '')
|
||||
{
|
||||
$params = [
|
||||
'appid' => $this->app_id,
|
||||
'secret' => $this->app_secret,
|
||||
'code' => $code,
|
||||
'grant_type' => 'authorization_code'
|
||||
];
|
||||
$ret = Http::sendRequest('https://api.weixin.qq.com/sns/oauth2/access_token', $params, 'GET');
|
||||
if ($ret['ret']) {
|
||||
$ar = json_decode($ret['msg'], true);
|
||||
return $ar;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getJsticket($code = '')
|
||||
{
|
||||
$jsticket = Session::get('jsticket');
|
||||
if (!$jsticket) {
|
||||
$token = $this->getAccessToken($code);
|
||||
$params = [
|
||||
'access_token' => 'token',
|
||||
'type' => 'jsapi',
|
||||
];
|
||||
$ret = Http::sendRequest('https://api.weixin.qq.com/cgi-bin/ticket/getticket', $params, 'GET');
|
||||
if ($ret['ret']) {
|
||||
$ar = json_decode($ret['msg'], true);
|
||||
return $ar;
|
||||
}
|
||||
}
|
||||
return $jsticket;
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
/tests export-ignore
|
||||
/.github export-ignore
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Hyperf
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,40 +0,0 @@
|
||||
{
|
||||
"name": "hyperf/context",
|
||||
"description": "A coroutine context library.",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"php",
|
||||
"swoole",
|
||||
"hyperf",
|
||||
"context"
|
||||
],
|
||||
"homepage": "https://hyperf.io",
|
||||
"support": {
|
||||
"docs": "https://hyperf.wiki",
|
||||
"issues": "https://github.com/hyperf/hyperf/issues",
|
||||
"pull-request": "https://github.com/hyperf/hyperf/pulls",
|
||||
"source": "https://github.com/hyperf/hyperf"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2",
|
||||
"hyperf/engine": "^1.1"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Hyperf\\Context\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"HyperfTest\\Context\\": "tests/"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.2-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Context;
|
||||
|
||||
use Hyperf\Engine\Coroutine;
|
||||
|
||||
class Context
|
||||
{
|
||||
protected static $nonCoContext = [];
|
||||
|
||||
public static function set(string $id, $value)
|
||||
{
|
||||
if (Coroutine::id() > 0) {
|
||||
Coroutine::getContextFor()[$id] = $value;
|
||||
} else {
|
||||
static::$nonCoContext[$id] = $value;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
public static function get(string $id, $default = null, $coroutineId = null)
|
||||
{
|
||||
if (Coroutine::id() > 0) {
|
||||
return Coroutine::getContextFor($coroutineId)[$id] ?? $default;
|
||||
}
|
||||
|
||||
return static::$nonCoContext[$id] ?? $default;
|
||||
}
|
||||
|
||||
public static function has(string $id, $coroutineId = null)
|
||||
{
|
||||
if (Coroutine::id() > 0) {
|
||||
return isset(Coroutine::getContextFor($coroutineId)[$id]);
|
||||
}
|
||||
|
||||
return isset(static::$nonCoContext[$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the context when you are not in coroutine environment.
|
||||
*/
|
||||
public static function destroy(string $id)
|
||||
{
|
||||
unset(static::$nonCoContext[$id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the context from a coroutine to current coroutine.
|
||||
* This method will delete the origin values in current coroutine.
|
||||
*/
|
||||
public static function copy(int $fromCoroutineId, ?array $keys = []): void
|
||||
{
|
||||
$from = Coroutine::getContextFor($fromCoroutineId);
|
||||
if ($from === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$current = Coroutine::getContextFor();
|
||||
|
||||
if ($keys) {
|
||||
$map = array_intersect_key($from->getArrayCopy(), array_flip($keys));
|
||||
} else {
|
||||
$map = $from->getArrayCopy();
|
||||
}
|
||||
|
||||
$current->exchangeArray($map);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value and override it by closure.
|
||||
*/
|
||||
public static function override(string $id, \Closure $closure)
|
||||
{
|
||||
$value = null;
|
||||
if (self::has($id)) {
|
||||
$value = self::get($id);
|
||||
}
|
||||
$value = $closure($value);
|
||||
self::set($id, $value);
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value and store it if not exists.
|
||||
* @param mixed $value
|
||||
*/
|
||||
public static function getOrSet(string $id, $value)
|
||||
{
|
||||
if (! self::has($id)) {
|
||||
return self::set($id, value($value));
|
||||
}
|
||||
return self::get($id);
|
||||
}
|
||||
|
||||
public static function getContainer()
|
||||
{
|
||||
if (Coroutine::id() > 0) {
|
||||
return Coroutine::getContextFor();
|
||||
}
|
||||
|
||||
return static::$nonCoContext;
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
/tests export-ignore
|
||||
/.github export-ignore
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Hyperf
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"name": "hyperf/contract",
|
||||
"description": "The contracts of Hyperf.",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"php",
|
||||
"swoole",
|
||||
"hyperf"
|
||||
],
|
||||
"homepage": "https://hyperf.io",
|
||||
"support": {
|
||||
"docs": "https://hyperf.wiki",
|
||||
"issues": "https://github.com/hyperf/hyperf/issues",
|
||||
"pull-request": "https://github.com/hyperf/hyperf/pulls",
|
||||
"source": "https://github.com/hyperf/hyperf"
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Hyperf\\Contract\\": "src/"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.2-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface ApplicationInterface
|
||||
{
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface Castable
|
||||
{
|
||||
/**
|
||||
* Get the name of the caster class to use when casting from / to this cast target.
|
||||
*
|
||||
* @return CastsAttributes|CastsInboundAttributes|string
|
||||
*/
|
||||
public static function castUsing();
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface CastsAttributes
|
||||
{
|
||||
/**
|
||||
* Transform the attribute from the underlying model values.
|
||||
*
|
||||
* @param object $model
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($model, ?string $key, $value, ?array $attributes);
|
||||
|
||||
/**
|
||||
* Transform the attribute to its underlying model values.
|
||||
*
|
||||
* @param object $model
|
||||
* @param mixed $value
|
||||
* @return array|string
|
||||
*/
|
||||
public function set($model, ?string $key, $value, ?array $attributes);
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface CastsInboundAttributes
|
||||
{
|
||||
/**
|
||||
* Transform the attribute to its underlying model values.
|
||||
*
|
||||
* @param object $model
|
||||
* @param mixed $value
|
||||
* @return array
|
||||
*/
|
||||
public function set($model, ?string $key, $value, ?array $attributes);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface CompressInterface
|
||||
{
|
||||
public function compress(): UnCompressInterface;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface ConfigInterface
|
||||
{
|
||||
/**
|
||||
* Finds an entry of the container by its identifier and returns it.
|
||||
*
|
||||
* @param string $key identifier of the entry to look for
|
||||
* @param mixed $default default value of the entry when does not found
|
||||
* @return mixed entry
|
||||
*/
|
||||
public function get(string $key, $default = null);
|
||||
|
||||
/**
|
||||
* Returns true if the container can return an entry for the given identifier.
|
||||
* Returns false otherwise.
|
||||
*
|
||||
* @param string $keys identifier of the entry to look for
|
||||
* @return bool
|
||||
*/
|
||||
public function has(string $keys);
|
||||
|
||||
/**
|
||||
* Set a value to the container by its identifier.
|
||||
*
|
||||
* @param string $key identifier of the entry to set
|
||||
* @param mixed $value the value that save to container
|
||||
*/
|
||||
public function set(string $key, $value);
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface ConnectionInterface
|
||||
{
|
||||
/**
|
||||
* Get the real connection from pool.
|
||||
*/
|
||||
public function getConnection();
|
||||
|
||||
/**
|
||||
* Reconnect the connection.
|
||||
*/
|
||||
public function reconnect(): bool;
|
||||
|
||||
/**
|
||||
* Check the connection is valid.
|
||||
*/
|
||||
public function check(): bool;
|
||||
|
||||
/**
|
||||
* Close the connection.
|
||||
*/
|
||||
public function close(): bool;
|
||||
|
||||
/**
|
||||
* Release the connection to pool.
|
||||
*/
|
||||
public function release(): void;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
use Psr\Container\ContainerInterface as PsrContainerInterface;
|
||||
|
||||
interface ContainerInterface extends PsrContainerInterface
|
||||
{
|
||||
/**
|
||||
* Build an entry of the container by its name.
|
||||
* This method behave like get() except resolves the entry again every time.
|
||||
* For example if the entry is a class then a new instance will be created each time.
|
||||
* This method makes the container behave like a factory.
|
||||
*
|
||||
* @param string $name entry name or a class name
|
||||
* @param array $parameters Optional parameters to use to build the entry. Use this to force specific parameters
|
||||
* to specific values. Parameters not defined in this array will be resolved using
|
||||
* the container.
|
||||
* @throws InvalidArgumentException the name parameter must be of type string
|
||||
* @throws NotFoundException no entry found for the given name
|
||||
*/
|
||||
public function make(string $name, ?array $parameters = []);
|
||||
|
||||
/**
|
||||
* Bind an arbitrary resolved entry to an identifier.
|
||||
* Useful for testing 'get'.
|
||||
*
|
||||
* @param mixed $entry
|
||||
*/
|
||||
public function set(string $name, $entry);
|
||||
|
||||
/**
|
||||
* Unbind an arbitrary resolved entry.
|
||||
*/
|
||||
public function unbind(string $name);
|
||||
|
||||
/**
|
||||
* Bind an arbitrary definition to an identifier.
|
||||
* Useful for testing 'make'.
|
||||
*
|
||||
* @param array|callable|string $definition
|
||||
*/
|
||||
public function define(string $name, $definition);
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface DispatcherInterface
|
||||
{
|
||||
public function dispatch(...$params);
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface FrequencyInterface
|
||||
{
|
||||
/**
|
||||
* Number of hit per time.
|
||||
*/
|
||||
public function hit(int $number = 1): bool;
|
||||
|
||||
/**
|
||||
* Hits per second.
|
||||
*/
|
||||
public function frequency(): float;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface IdGeneratorInterface
|
||||
{
|
||||
public function generate();
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface LengthAwarePaginatorInterface extends PaginatorInterface
|
||||
{
|
||||
/**
|
||||
* Create a range of pagination URLs.
|
||||
*/
|
||||
public function getUrlRange(int $start, int $end): array;
|
||||
|
||||
/**
|
||||
* Determine the total number of items in the data store.
|
||||
*/
|
||||
public function total(): int;
|
||||
|
||||
/**
|
||||
* Get the page number of the last available page.
|
||||
*/
|
||||
public function lastPage(): int;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface MiddlewareInitializerInterface
|
||||
{
|
||||
public function initCoreMiddleware(string $serverName): void;
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface NormalizerInterface
|
||||
{
|
||||
/**
|
||||
* Normalizes an object into a set of arrays/scalars.
|
||||
*
|
||||
* @param mixed $object
|
||||
* @return null|array|\ArrayObject|bool|float|int|string
|
||||
*/
|
||||
public function normalize($object);
|
||||
|
||||
/**
|
||||
* Denormalizes data back into an object of the given class.
|
||||
*
|
||||
* @param mixed $data Data to restore
|
||||
* @param string $class The expected class to instantiate
|
||||
* @return mixed|object
|
||||
*/
|
||||
public function denormalize($data, ?string $class);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
use Swoole\Http\Response;
|
||||
use Swoole\Server;
|
||||
|
||||
interface OnCloseInterface
|
||||
{
|
||||
/**
|
||||
* @param Response|Server $server
|
||||
*/
|
||||
public function onClose($server, int $fd, int $reactorId): void;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
use Swoole\Http\Request;
|
||||
use Swoole\Http\Response;
|
||||
|
||||
interface OnHandShakeInterface
|
||||
{
|
||||
public function onHandShake(Request $request, Response $response): void;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
use Swoole\Http\Response;
|
||||
use Swoole\WebSocket\Frame;
|
||||
use Swoole\WebSocket\Server;
|
||||
|
||||
interface OnMessageInterface
|
||||
{
|
||||
/**
|
||||
* @param Response|Server $server
|
||||
*/
|
||||
public function onMessage($server, Frame $frame): void;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
use Swoole\Http\Request;
|
||||
use Swoole\Http\Response;
|
||||
use Swoole\WebSocket\Server;
|
||||
|
||||
interface OnOpenInterface
|
||||
{
|
||||
/**
|
||||
* @param Response|Server $server
|
||||
*/
|
||||
public function onOpen($server, Request $request): void;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
use Swoole\WebSocket\Server;
|
||||
|
||||
interface OnPacketInterface
|
||||
{
|
||||
/**
|
||||
* @param Server $server
|
||||
* @param mixed $data
|
||||
* @param array $clientInfo
|
||||
*/
|
||||
public function onPacket($server, $data, $clientInfo): void;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
use Swoole\Coroutine\Server\Connection;
|
||||
use Swoole\Server as SwooleServer;
|
||||
|
||||
interface OnReceiveInterface
|
||||
{
|
||||
/**
|
||||
* @param Connection|SwooleServer $server
|
||||
*/
|
||||
public function onReceive($server, int $fd, int $reactorId, ?string $data): void;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface OnRequestInterface
|
||||
{
|
||||
/**
|
||||
* @param mixed $request swoole request or psr server request
|
||||
* @param mixed $response swoole response or swow session
|
||||
*/
|
||||
public function onRequest($request, $response): void;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface PackerInterface
|
||||
{
|
||||
public function pack($data): string;
|
||||
|
||||
public function unpack(string $data);
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface PaginatorInterface
|
||||
{
|
||||
/**
|
||||
* Get the URL for a given page.
|
||||
*/
|
||||
public function url(int $page): string;
|
||||
|
||||
/**
|
||||
* Add a set of query string values to the paginator.
|
||||
*
|
||||
* @param array|string $key
|
||||
* @return $this
|
||||
*/
|
||||
public function appends($key, ?string $value = null);
|
||||
|
||||
/**
|
||||
* Get / set the URL fragment to be appended to URLs.
|
||||
*
|
||||
* @return $this|string
|
||||
*/
|
||||
public function fragment(?string $fragment = null);
|
||||
|
||||
/**
|
||||
* The URL for the next page, or null.
|
||||
*/
|
||||
public function nextPageUrl(): ?string;
|
||||
|
||||
/**
|
||||
* Get the URL for the previous page, or null.
|
||||
*/
|
||||
public function previousPageUrl(): ?string;
|
||||
|
||||
/**
|
||||
* Get all of the items being paginated.
|
||||
*/
|
||||
public function items(): array;
|
||||
|
||||
/**
|
||||
* Get the "index" of the first item being paginated.
|
||||
*/
|
||||
public function firstItem(): ?int;
|
||||
|
||||
/**
|
||||
* Get the "index" of the last item being paginated.
|
||||
*/
|
||||
public function lastItem(): ?int;
|
||||
|
||||
/**
|
||||
* Determine how many items are being shown per page.
|
||||
*/
|
||||
public function perPage(): int;
|
||||
|
||||
/**
|
||||
* Determine the current page being paginated.
|
||||
*/
|
||||
public function currentPage(): int;
|
||||
|
||||
/**
|
||||
* Determine if there are enough items to split into multiple pages.
|
||||
*/
|
||||
public function hasPages(): bool;
|
||||
|
||||
/**
|
||||
* Determine if there is more items in the data store.
|
||||
*/
|
||||
public function hasMorePages(): bool;
|
||||
|
||||
/**
|
||||
* Determine if the list of items is empty or not.
|
||||
*/
|
||||
public function isEmpty(): bool;
|
||||
|
||||
/**
|
||||
* Determine if the list of items is not empty.
|
||||
*/
|
||||
public function isNotEmpty(): bool;
|
||||
|
||||
/**
|
||||
* Render the paginator using a given view.
|
||||
*/
|
||||
public function render(?string $view = null, ?array $data = []): string;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface PoolInterface
|
||||
{
|
||||
/**
|
||||
* Get a connection from the connection pool.
|
||||
*/
|
||||
public function get(): ConnectionInterface;
|
||||
|
||||
/**
|
||||
* Release a connection back to the connection pool.
|
||||
*/
|
||||
public function release(ConnectionInterface $connection): void;
|
||||
|
||||
/**
|
||||
* Close and clear the connection pool.
|
||||
*/
|
||||
public function flush(): void;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface PoolOptionInterface
|
||||
{
|
||||
public function getMaxConnections(): int;
|
||||
|
||||
public function getMinConnections(): int;
|
||||
|
||||
public function getConnectTimeout(): float;
|
||||
|
||||
public function getWaitTimeout(): float;
|
||||
|
||||
public function getHeartbeat(): float;
|
||||
|
||||
public function getMaxIdleTime(): float;
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
use Swoole\Coroutine\Http\Server as CoHttpServer;
|
||||
use Swoole\Coroutine\Server as CoServer;
|
||||
use Swoole\Server;
|
||||
|
||||
interface ProcessInterface
|
||||
{
|
||||
/**
|
||||
* Create the process object according to process number and bind to server.
|
||||
* @param CoHttpServer|CoServer|Server $server
|
||||
*/
|
||||
public function bind($server): void;
|
||||
|
||||
/**
|
||||
* Determine if the process should start ?
|
||||
* @param CoServer|Server $server
|
||||
*/
|
||||
public function isEnable($server): bool;
|
||||
|
||||
/**
|
||||
* The logical of process will place in here.
|
||||
*/
|
||||
public function handle(): void;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
interface ResponseEmitterInterface
|
||||
{
|
||||
/**
|
||||
* @param mixed $connection swoole response or swow session
|
||||
*/
|
||||
public function emit(ResponseInterface $response, $connection, bool $withContent = true);
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface SessionInterface
|
||||
{
|
||||
/**
|
||||
* Starts the session storage.
|
||||
*
|
||||
* @throws \RuntimeException if session fails to start
|
||||
* @return bool True if session started
|
||||
*/
|
||||
public function start(): bool;
|
||||
|
||||
/**
|
||||
* Returns the session ID.
|
||||
*
|
||||
* @return string The session ID
|
||||
*/
|
||||
public function getId(): string;
|
||||
|
||||
/**
|
||||
* Sets the session ID.
|
||||
*/
|
||||
public function setId(string $id);
|
||||
|
||||
/**
|
||||
* Returns the session name.
|
||||
*/
|
||||
public function getName(): string;
|
||||
|
||||
/**
|
||||
* Sets the session name.
|
||||
*/
|
||||
public function setName(string $name);
|
||||
|
||||
/**
|
||||
* Invalidates the current session.
|
||||
*
|
||||
* Clears all session attributes and flashes and regenerates the
|
||||
* session and deletes the old session from persistence.
|
||||
*
|
||||
* @param int $lifetime Sets the cookie lifetime for the session cookie. A null value
|
||||
* will leave the system settings unchanged, 0 sets the cookie
|
||||
* to expire with browser session. Time is in seconds, and is
|
||||
* not a Unix timestamp.
|
||||
*
|
||||
* @return bool True if session invalidated, false if error
|
||||
*/
|
||||
public function invalidate(?int $lifetime = null): bool;
|
||||
|
||||
/**
|
||||
* Migrates the current session to a new session id while maintaining all
|
||||
* session attributes.
|
||||
*
|
||||
* @param bool $destroy Whether to delete the old session or leave it to garbage collection
|
||||
* @param int $lifetime Sets the cookie lifetime for the session cookie. A null value
|
||||
* will leave the system settings unchanged, 0 sets the cookie
|
||||
* to expire with browser session. Time is in seconds, and is
|
||||
* not a Unix timestamp.
|
||||
*
|
||||
* @return bool True if session migrated, false if error
|
||||
*/
|
||||
public function migrate(bool $destroy = false, ?int $lifetime = null): bool;
|
||||
|
||||
/**
|
||||
* Force the session to be saved and closed.
|
||||
*
|
||||
* This method is generally not required for real sessions as
|
||||
* the session will be automatically saved at the end of
|
||||
* code execution.
|
||||
*/
|
||||
public function save(): void;
|
||||
|
||||
/**
|
||||
* Checks if an attribute is defined.
|
||||
*
|
||||
* @param string $name The attribute name
|
||||
*
|
||||
* @return bool true if the attribute is defined, false otherwise
|
||||
*/
|
||||
public function has(string $name): bool;
|
||||
|
||||
/**
|
||||
* Returns an attribute.
|
||||
*
|
||||
* @param string $name The attribute name
|
||||
* @param mixed $default The default value if not found
|
||||
*/
|
||||
public function get(string $name, $default = null);
|
||||
|
||||
/**
|
||||
* Sets an attribute.
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function set(string $name, $value): void;
|
||||
|
||||
/**
|
||||
* Put a key / value pair or array of key / value pairs in the session.
|
||||
*
|
||||
* @param array|string $key
|
||||
* @param null|mixed $value
|
||||
*/
|
||||
public function put($key, $value = null): void;
|
||||
|
||||
/**
|
||||
* Returns attributes.
|
||||
*/
|
||||
public function all(): array;
|
||||
|
||||
/**
|
||||
* Sets attributes.
|
||||
*/
|
||||
public function replace(array $attributes): void;
|
||||
|
||||
/**
|
||||
* Removes an attribute, returning its value.
|
||||
*
|
||||
* @return mixed The removed value or null when it does not exist
|
||||
*/
|
||||
public function remove(string $name);
|
||||
|
||||
/**
|
||||
* Remove one or many items from the session.
|
||||
*
|
||||
* @param array|string $keys
|
||||
*/
|
||||
public function forget($keys): void;
|
||||
|
||||
/**
|
||||
* Clears all attributes.
|
||||
*/
|
||||
public function clear(): void;
|
||||
|
||||
/**
|
||||
* Checks if the session was started.
|
||||
*/
|
||||
public function isStarted(): bool;
|
||||
|
||||
/**
|
||||
* Get the previous URL from the session.
|
||||
*/
|
||||
public function previousUrl(): ?string;
|
||||
|
||||
/**
|
||||
* Set the "previous" URL in the session.
|
||||
*/
|
||||
public function setPreviousUrl(string $url): void;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
interface StdoutLoggerInterface extends LoggerInterface
|
||||
{
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface Synchronized
|
||||
{
|
||||
/**
|
||||
* Whether the data has been synchronized.
|
||||
*/
|
||||
public function isSynchronized(): bool;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface TranslatorInterface
|
||||
{
|
||||
/**
|
||||
* Get the translation for a given key.
|
||||
*/
|
||||
public function trans(string $key, ?array $replace = [], ?string $locale = null);
|
||||
|
||||
/**
|
||||
* Get a translation according to an integer value.
|
||||
*
|
||||
* @param array|\Countable|int $number
|
||||
*/
|
||||
public function transChoice(string $key, $number, ?array $replace = [], ?string $locale = null): string;
|
||||
|
||||
/**
|
||||
* Get the default locale being used.
|
||||
*/
|
||||
public function getLocale(): string;
|
||||
|
||||
/**
|
||||
* Set the default locale.
|
||||
*/
|
||||
public function setLocale(string $locale);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface TranslatorLoaderInterface
|
||||
{
|
||||
/**
|
||||
* Load the messages for the given locale.
|
||||
*/
|
||||
public function load(string $locale, ?string $group, ?string $namespace = null): array;
|
||||
|
||||
/**
|
||||
* Add a new namespace to the loader.
|
||||
*/
|
||||
public function addNamespace(string $namespace, ?string $hint);
|
||||
|
||||
/**
|
||||
* Add a new JSON path to the loader.
|
||||
*/
|
||||
public function addJsonPath(string $path);
|
||||
|
||||
/**
|
||||
* Get an array of all the registered namespaces.
|
||||
*/
|
||||
public function namespaces(): array;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
interface UnCompressInterface
|
||||
{
|
||||
public function uncompress();
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* This file is part of Hyperf.
|
||||
*
|
||||
* @link https://www.hyperf.io
|
||||
* @document https://hyperf.wiki
|
||||
* @contact group@hyperf.io
|
||||
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
*/
|
||||
namespace Hyperf\Contract;
|
||||
|
||||
use Hyperf\Utils\Contracts\MessageBag;
|
||||
use Hyperf\Utils\Contracts\MessageProvider;
|
||||
|
||||
interface ValidatorInterface extends MessageProvider
|
||||
{
|
||||
/**
|
||||
* Run the validator's rules against its data.
|
||||
*/
|
||||
public function validate(): array;
|
||||
|
||||
/**
|
||||
* Get the attributes and values that were validated.
|
||||
*/
|
||||
public function validated(): array;
|
||||
|
||||
/**
|
||||
* Determine if the data fails the validation rules.
|
||||
*/
|
||||
public function fails(): bool;
|
||||
|
||||
/**
|
||||
* Get the failed validation rules.
|
||||
*/
|
||||
public function failed(): array;
|
||||
|
||||
/**
|
||||
* Add conditions to a given field based on a Closure.
|
||||
*
|
||||
* @param array|string $attribute
|
||||
* @param array|string $rules
|
||||
* @return $this
|
||||
*/
|
||||
public function sometimes($attribute, $rules, callable $callback);
|
||||
|
||||
/**
|
||||
* Add an after validation callback.
|
||||
*
|
||||
* @param callable|string $callback
|
||||
* @return $this
|
||||
*/
|
||||
public function after($callback);
|
||||
|
||||
/**
|
||||
* Get all of the validation error messages.
|
||||
*/
|
||||
public function errors(): MessageBag;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
/.github export-ignore
|
||||
/examples export-ignore
|
||||
/tests export-ignore
|
||||
|
||||
4
addons/epay/library/hyperf/engine/.gitignore
vendored
4
addons/epay/library/hyperf/engine/.gitignore
vendored
@@ -1,4 +0,0 @@
|
||||
/vendor/
|
||||
composer.lock
|
||||
*.cache
|
||||
*.log
|
||||
@@ -1,89 +0,0 @@
|
||||
<?php
|
||||
|
||||
$header = <<<'EOF'
|
||||
This file is part of Hyperf.
|
||||
|
||||
@link https://www.hyperf.io
|
||||
@document https://hyperf.wiki
|
||||
@contact group@hyperf.io
|
||||
@license https://github.com/hyperf/hyperf/blob/master/LICENSE
|
||||
EOF;
|
||||
|
||||
return (new PhpCsFixer\Config())
|
||||
->setRiskyAllowed(true)
|
||||
->setRules([
|
||||
'@PSR2' => true,
|
||||
'@Symfony' => true,
|
||||
'@DoctrineAnnotation' => true,
|
||||
'@PhpCsFixer' => true,
|
||||
'header_comment' => [
|
||||
'comment_type' => 'PHPDoc',
|
||||
'header' => $header,
|
||||
'separate' => 'none',
|
||||
'location' => 'after_declare_strict',
|
||||
],
|
||||
'array_syntax' => [
|
||||
'syntax' => 'short'
|
||||
],
|
||||
'list_syntax' => [
|
||||
'syntax' => 'short'
|
||||
],
|
||||
'concat_space' => [
|
||||
'spacing' => 'one'
|
||||
],
|
||||
'blank_line_before_statement' => [
|
||||
'statements' => [
|
||||
'declare',
|
||||
],
|
||||
],
|
||||
'general_phpdoc_annotation_remove' => [
|
||||
'annotations' => [
|
||||
'author'
|
||||
],
|
||||
],
|
||||
'ordered_imports' => [
|
||||
'imports_order' => [
|
||||
'class', 'function', 'const',
|
||||
],
|
||||
'sort_algorithm' => 'alpha',
|
||||
],
|
||||
'single_line_comment_style' => [
|
||||
'comment_types' => [
|
||||
],
|
||||
],
|
||||
'yoda_style' => [
|
||||
'always_move_variable' => false,
|
||||
'equal' => false,
|
||||
'identical' => false,
|
||||
],
|
||||
'phpdoc_align' => [
|
||||
'align' => 'left',
|
||||
],
|
||||
'multiline_whitespace_before_semicolons' => [
|
||||
'strategy' => 'no_multi_line',
|
||||
],
|
||||
'constant_case' => [
|
||||
'case' => 'lower',
|
||||
],
|
||||
'class_attributes_separation' => true,
|
||||
'combine_consecutive_unsets' => true,
|
||||
'declare_strict_types' => true,
|
||||
'linebreak_after_opening_tag' => true,
|
||||
'lowercase_static_reference' => true,
|
||||
'no_useless_else' => true,
|
||||
'no_unused_imports' => true,
|
||||
'not_operator_with_successor_space' => true,
|
||||
'not_operator_with_space' => false,
|
||||
'ordered_class_elements' => true,
|
||||
'php_unit_strict' => false,
|
||||
'phpdoc_separation' => false,
|
||||
'single_quote' => true,
|
||||
'standardize_not_equals' => true,
|
||||
'multiline_comment_opening_closing' => true,
|
||||
])
|
||||
->setFinder(
|
||||
PhpCsFixer\Finder::create()
|
||||
->exclude('vendor')
|
||||
->in(__DIR__)
|
||||
)
|
||||
->setUsingCache(false);
|
||||
@@ -1,6 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace PHPSTORM_META {
|
||||
// Reflect
|
||||
override(\Psr\Container\ContainerInterface::get(0), map('@'));
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
# Default Dockerfile
|
||||
#
|
||||
# @link https://www.hyperf.io
|
||||
# @document https://hyperf.wiki
|
||||
# @contact group@hyperf.io
|
||||
# @license https://github.com/hyperf-cloud/hyperf/blob/master/LICENSE
|
||||
|
||||
ARG PHP_VERSION
|
||||
ARG ALPINE_VERSION
|
||||
|
||||
FROM hyperf/hyperf:${PHP_VERSION}-alpine-${ALPINE_VERSION}-swoole
|
||||
LABEL maintainer="Hyperf Developers <group@hyperf.io>" version="1.0" license="MIT" app.name="Hyperf"
|
||||
|
||||
ARG timezone
|
||||
ARG PHP_VERSION
|
||||
|
||||
ENV TIMEZONE=${timezone:-"Asia/Shanghai"}
|
||||
ENV COMPOSER_ROOT_VERSION="v1.2.0"
|
||||
|
||||
# update
|
||||
RUN set -ex \
|
||||
# show php version and extensions
|
||||
&& php -v \
|
||||
&& php -m \
|
||||
&& php --ri swoole \
|
||||
# ---------- some config ----------
|
||||
&& cd "/etc/php${PHP_VERSION%\.*}" \
|
||||
# - config PHP
|
||||
&& { \
|
||||
echo "upload_max_filesize=128M"; \
|
||||
echo "post_max_size=128M"; \
|
||||
echo "memory_limit=1G"; \
|
||||
echo "date.timezone=${TIMEZONE}"; \
|
||||
} | tee conf.d/99_overrides.ini \
|
||||
# - config timezone
|
||||
&& ln -sf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \
|
||||
&& echo "${TIMEZONE}" > /etc/timezone \
|
||||
# ---------- clear works ----------
|
||||
&& rm -rf /var/cache/apk/* /tmp/* /usr/share/man \
|
||||
&& echo -e "\033[42;37m Build Completed :).\033[0m\n"
|
||||
|
||||
WORKDIR /opt/www
|
||||
|
||||
COPY . /opt/www
|
||||
|
||||
RUN composer install -o
|
||||
@@ -1,7 +0,0 @@
|
||||
# Swoole Engine
|
||||
|
||||

|
||||
|
||||
```
|
||||
composer require hyperf/engine
|
||||
```
|
||||
@@ -1,49 +0,0 @@
|
||||
{
|
||||
"name": "hyperf/engine",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"keywords": [
|
||||
"php",
|
||||
"hyperf"
|
||||
],
|
||||
"description": "",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Hyperf\\Engine\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"HyperfTest\\": "tests"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^3.0",
|
||||
"hyperf/guzzle": "^2.2",
|
||||
"phpstan/phpstan": "^1.0",
|
||||
"phpunit/phpunit": "^9.4",
|
||||
"swoole/ide-helper": "dev-master"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-swoole": ">=4.5"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"config": {
|
||||
"optimize-autoloader": true,
|
||||
"sort-packages": true
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.2-dev"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "phpunit -c phpunit.xml --colors=always",
|
||||
"analyse": "phpstan analyse --memory-limit 1024M -l 0 ./src",
|
||||
"cs-fix": "php-cs-fixer fix $1"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user