作者 郭盛
1 个管道 的构建 失败 耗费 2 秒

图片

... ... @@ -3,7 +3,6 @@
<component name="ChangeListManager">
<list default="true" id="e93f11c2-a7d9-4d35-8b1c-8dd18e7f5fef" name="Default" comment="">
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/.idea/workspace.xml" afterPath="$PROJECT_DIR$/.idea/workspace.xml" />
<change type="MODIFICATION" beforePath="$PROJECT_DIR$/public/assets/js/backend/video.js" afterPath="$PROJECT_DIR$/public/assets/js/backend/video.js" />
</list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="TRACKING_ENABLED" value="true" />
... ... @@ -17,8 +16,8 @@
<file leaf-file-name="Order.php" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/application/admin/controller/Order.php">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="710">
<caret line="32" column="4" lean-forward="true" selection-start-line="32" selection-start-column="4" selection-end-line="32" selection-end-column="4" />
<state relative-caret-position="800">
<caret line="32" column="4" lean-forward="false" selection-start-line="32" selection-start-column="4" selection-end-line="32" selection-end-column="4" />
<folding />
</state>
</provider>
... ... @@ -27,8 +26,8 @@
<file leaf-file-name="index.html" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/application/admin/view/order/index.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="175">
<caret line="13" column="0" lean-forward="true" selection-start-line="13" selection-start-column="0" selection-end-line="13" selection-end-column="0" />
<state relative-caret-position="325">
<caret line="13" column="0" lean-forward="false" selection-start-line="13" selection-start-column="0" selection-end-line="13" selection-end-column="0" />
<folding />
</state>
</provider>
... ... @@ -37,7 +36,7 @@
<file leaf-file-name="order.js" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/public/assets/js/backend/order.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="475">
<state relative-caret-position="775">
<caret line="31" column="98" lean-forward="false" selection-start-line="31" selection-start-column="98" selection-end-line="31" selection-end-column="98" />
<folding />
</state>
... ... @@ -47,7 +46,7 @@
<file leaf-file-name="pic.js" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/public/assets/js/backend/pic.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="459">
<state relative-caret-position="900">
<caret line="36" column="83" lean-forward="false" selection-start-line="36" selection-start-column="83" selection-end-line="36" selection-end-column="83" />
<folding />
</state>
... ... @@ -57,8 +56,8 @@
<file leaf-file-name="video.js" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/public/assets/js/backend/video.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="150">
<caret line="24" column="21" lean-forward="true" selection-start-line="24" selection-start-column="21" selection-end-line="24" selection-end-column="21" />
<state relative-caret-position="275">
<caret line="23" column="26" lean-forward="true" selection-start-line="23" selection-start-column="26" selection-end-line="23" selection-end-column="26" />
<folding />
</state>
</provider>
... ... @@ -141,8 +140,8 @@
</component>
<component name="PhpWorkspaceProjectConfiguration" backward_compatibility_performed="true" />
<component name="ProjectFrameBounds" extendedState="1">
<option name="x" value="43" />
<option name="y" value="29" />
<option name="x" value="93" />
<option name="y" value="66" />
<option name="width" value="1776" />
<option name="height" value="972" />
</component>
... ... @@ -161,6 +160,7 @@
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="Scratches" />
<pane id="ProjectPane">
<subPane>
<expand>
... ... @@ -216,7 +216,6 @@
<select />
</subPane>
</pane>
<pane id="Scratches" />
<pane id="Scope" />
</panes>
</component>
... ... @@ -272,6 +271,7 @@
<workItem from="1574410294356" duration="15863000" />
<workItem from="1574469667436" duration="25235000" />
<workItem from="1574641631900" duration="15479000" />
<workItem from="1574669596135" duration="8000" />
</task>
<task id="LOCAL-00001" summary="调试">
<created>1574145133364</created>
... ... @@ -284,7 +284,7 @@
<servers />
</component>
<component name="TimeTrackingManager">
<option name="totallyTimeSpent" value="218524000" />
<option name="totallyTimeSpent" value="218532000" />
</component>
<component name="TodoView">
<todo-panel id="selected-file">
... ... @@ -296,10 +296,10 @@
</todo-panel>
</component>
<component name="ToolWindowManager">
<frame x="43" y="29" width="1776" height="972" extended-state="1" />
<frame x="93" y="66" width="1776" height="972" extended-state="1" />
<editor active="true" />
<layout>
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.1544289" sideWeight="0.5" order="1" side_tool="false" content_ui="combo" />
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.15617716" sideWeight="0.5" order="1" side_tool="false" content_ui="combo" />
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32912987" sideWeight="0.5" order="9" side_tool="false" content_ui="tabs" />
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="true" content_ui="tabs" />
<window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
... ... @@ -366,7 +366,6 @@
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="450">
<caret line="26" column="60" lean-forward="false" selection-start-line="26" selection-start-column="60" selection-end-line="26" selection-end-column="60" />
<folding />
</state>
</provider>
</entry>
... ... @@ -374,7 +373,6 @@
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="3">
<caret line="99" column="38" lean-forward="true" selection-start-line="99" selection-start-column="38" selection-end-line="99" selection-end-column="38" />
<folding />
</state>
</provider>
</entry>
... ... @@ -410,7 +408,6 @@
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="453">
<caret line="112" column="20" lean-forward="false" selection-start-line="112" selection-start-column="20" selection-end-line="112" selection-end-column="20" />
<folding />
</state>
</provider>
</entry>
... ... @@ -423,7 +420,6 @@
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="585">
<caret line="105" column="38" lean-forward="true" selection-start-line="105" selection-start-column="38" selection-end-line="105" selection-end-column="38" />
<folding />
</state>
</provider>
</entry>
... ... @@ -458,7 +454,6 @@
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="297">
<caret line="25" column="6" lean-forward="false" selection-start-line="25" selection-start-column="6" selection-end-line="25" selection-end-column="6" />
<folding />
</state>
</provider>
</entry>
... ... @@ -466,7 +461,6 @@
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="411">
<caret line="28" column="9" lean-forward="false" selection-start-line="28" selection-start-column="9" selection-end-line="28" selection-end-column="9" />
<folding />
</state>
</provider>
</entry>
... ... @@ -474,7 +468,6 @@
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="261">
<caret line="25" column="58" lean-forward="false" selection-start-line="25" selection-start-column="58" selection-end-line="25" selection-end-column="58" />
<folding />
</state>
</provider>
</entry>
... ... @@ -594,7 +587,6 @@
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="0">
<caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
... ... @@ -626,7 +618,6 @@
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="294">
<caret line="172" column="35" lean-forward="true" selection-start-line="172" selection-start-column="35" selection-end-line="172" selection-end-column="35" />
<folding />
</state>
</provider>
</entry>
... ... @@ -634,23 +625,6 @@
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="1100">
<caret line="69" column="26" lean-forward="true" selection-start-line="69" selection-start-column="26" selection-end-line="69" selection-end-column="26" />
<folding>
<element signature="e#450#569#0#PHP" expanded="false" />
<element signature="e#575#888#0#PHP" expanded="false" />
<element signature="e#2944#3264#0#PHP" expanded="false" />
<element signature="e#3269#5320#0#PHP" expanded="false" />
<element signature="e#5326#5744#0#PHP" expanded="false" />
<element signature="e#5749#10343#0#PHP" expanded="false" />
<element signature="e#8532#10276#0#PHP" expanded="false" />
<element signature="e#10349#10769#0#PHP" expanded="false" />
<element signature="e#10774#15443#0#PHP" expanded="false" />
<element signature="e#13629#15375#0#PHP" expanded="false" />
<element signature="e#15470#19172#0#PHP" expanded="false" />
<element signature="e#19202#22146#0#PHP" expanded="false" />
<element signature="e#22175#23432#0#PHP" expanded="false" />
<element signature="e#23461#24747#0#PHP" expanded="false" />
<element signature="e#24770#24987#0#PHP" expanded="false" />
</folding>
</state>
</provider>
</entry>
... ... @@ -658,7 +632,6 @@
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="125">
<caret line="5" column="6" lean-forward="true" selection-start-line="5" selection-start-column="6" selection-end-line="5" selection-end-column="6" />
<folding />
</state>
</provider>
</entry>
... ... @@ -666,61 +639,6 @@
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="456">
<caret line="990" column="5" lean-forward="true" selection-start-line="990" selection-start-column="5" selection-end-line="990" selection-end-column="5" />
<folding>
<element signature="e#365#484#0#PHP" expanded="false" />
<element signature="e#490#1228#0#PHP" expanded="false" />
<element signature="e#1233#2896#0#PHP" expanded="false" />
<element signature="e#2902#3430#0#PHP" expanded="false" />
<element signature="e#3435#4206#0#PHP" expanded="false" />
<element signature="e#4212#4619#0#PHP" expanded="false" />
<element signature="e#4624#4967#0#PHP" expanded="false" />
<element signature="e#4973#5810#0#PHP" expanded="false" />
<element signature="e#5815#8010#0#PHP" expanded="false" />
<element signature="e#8016#8661#0#PHP" expanded="false" />
<element signature="e#8666#9762#0#PHP" expanded="false" />
<element signature="e#9768#10470#0#PHP" expanded="false" />
<element signature="e#10475#11675#0#PHP" expanded="false" />
<element signature="e#11681#12257#0#PHP" expanded="false" />
<element signature="e#12262#12809#0#PHP" expanded="false" />
<element signature="e#12815#13499#0#PHP" expanded="false" />
<element signature="e#13504#15600#0#PHP" expanded="false" />
<element signature="e#15606#16476#0#PHP" expanded="false" />
<element signature="e#18983#19360#0#PHP" expanded="false" />
<element signature="e#19365#19629#0#PHP" expanded="false" />
<element signature="e#19635#20140#0#PHP" expanded="false" />
<element signature="e#20145#20396#0#PHP" expanded="false" />
<element signature="e#20402#20881#0#PHP" expanded="false" />
<element signature="e#20886#21643#0#PHP" expanded="false" />
<element signature="e#21649#22130#0#PHP" expanded="false" />
<element signature="e#22135#22905#0#PHP" expanded="false" />
<element signature="e#22911#23274#0#PHP" expanded="false" />
<element signature="e#23279#23470#0#PHP" expanded="false" />
<element signature="e#23476#23834#0#PHP" expanded="false" />
<element signature="e#23839#24029#0#PHP" expanded="false" />
<element signature="e#24035#25178#0#PHP" expanded="false" />
<element signature="e#25183#27848#0#PHP" expanded="false" />
<element signature="e#27854#28352#0#PHP" expanded="false" />
<element signature="e#28357#30103#0#PHP" expanded="false" />
<element signature="e#30109#30522#0#PHP" expanded="false" />
<element signature="e#30527#31006#0#PHP" expanded="false" />
<element signature="e#31012#31546#0#PHP" expanded="false" />
<element signature="e#31551#32936#0#PHP" expanded="false" />
<element signature="e#32942#33596#0#PHP" expanded="false" />
<element signature="e#33601#35554#0#PHP" expanded="false" />
<element signature="e#33755#33841#0#PHP" expanded="false" />
<element signature="e#33930#34018#0#PHP" expanded="false" />
<element signature="e#35560#36320#0#PHP" expanded="false" />
<element signature="e#36325#39034#0#PHP" expanded="false" />
<element signature="e#39060#39891#0#PHP" expanded="false" />
<element signature="e#39897#40317#0#PHP" expanded="false" />
<element signature="e#40322#40805#0#PHP" expanded="false" />
<element signature="e#40811#41617#0#PHP" expanded="false" />
<element signature="e#41622#44776#0#PHP" expanded="false" />
<element signature="e#44791#46119#0#PHP" expanded="false" />
<element signature="e#46135#47162#0#PHP" expanded="false" />
<element signature="e#47168#47926#0#PHP" expanded="false" />
<element signature="e#47931#50318#0#PHP" expanded="false" />
</folding>
</state>
</provider>
</entry>
... ... @@ -728,29 +646,28 @@
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="175">
<caret line="7" column="25" lean-forward="true" selection-start-line="7" selection-start-column="25" selection-end-line="7" selection-end-column="25" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/application/admin/controller/Order.php">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="710">
<caret line="32" column="4" lean-forward="true" selection-start-line="32" selection-start-column="4" selection-end-line="32" selection-end-column="4" />
<state relative-caret-position="800">
<caret line="32" column="4" lean-forward="false" selection-start-line="32" selection-start-column="4" selection-end-line="32" selection-end-column="4" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/application/admin/view/order/index.html">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="175">
<caret line="13" column="0" lean-forward="true" selection-start-line="13" selection-start-column="0" selection-end-line="13" selection-end-column="0" />
<state relative-caret-position="325">
<caret line="13" column="0" lean-forward="false" selection-start-line="13" selection-start-column="0" selection-end-line="13" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/public/assets/js/backend/order.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="475">
<state relative-caret-position="775">
<caret line="31" column="98" lean-forward="false" selection-start-line="31" selection-start-column="98" selection-end-line="31" selection-end-column="98" />
<folding />
</state>
... ... @@ -760,13 +677,12 @@
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="225">
<caret line="24" column="21" lean-forward="true" selection-start-line="24" selection-start-column="21" selection-end-line="24" selection-end-column="21" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/public/assets/js/backend/pic.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="459">
<state relative-caret-position="900">
<caret line="36" column="83" lean-forward="false" selection-start-line="36" selection-start-column="83" selection-end-line="36" selection-end-column="83" />
<folding />
</state>
... ... @@ -774,8 +690,8 @@
</entry>
<entry file="file://$PROJECT_DIR$/public/assets/js/backend/video.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="150">
<caret line="24" column="21" lean-forward="true" selection-start-line="24" selection-start-column="21" selection-end-line="24" selection-end-column="21" />
<state relative-caret-position="275">
<caret line="23" column="26" lean-forward="true" selection-start-line="23" selection-start-column="26" selection-end-line="23" selection-end-column="26" />
<folding />
</state>
</provider>
... ...
<?php
namespace addons\qiniu;
use addons\qiniu\library\Auth;
use fast\Http;
use think\Addons;
/**
* 七牛上传插件
*/
class Qiniu extends Addons
{
/**
* 插件安装方法
* @return bool
*/
public function install()
{
return true;
}
/**
* 插件卸载方法
* @return bool
*/
public function uninstall()
{
return true;
}
/**
* 上传初始化时
*/
public function uploadConfigInit(&$upload)
{
$config = $this->getConfig();
$policy = array(
'saveKey' => ltrim($config['savekey'], '/'),
);
//如果启用服务端回调
if ($config['notifyenabled']) {
$policy = array_merge($policy, [
'callbackUrl' => $config['notifyurl'],
'callbackBody' => 'filename=$(fname)&key=$(key)&imageInfo=$(imageInfo)&filesize=$(fsize)&admin=$(x:admin)&user=$(x:user)'
]);
}
if ($config['uploadmode'] == 'client') {
$auth = new Auth($config['app_key'], $config['secret_key']);
$multipart['token'] = $auth->uploadToken($config['bucket'], null, $config['expire'], $policy);
$multipart['x:admin'] = (int)session('admin.id');
$multipart['x:user'] = (int)cookie('uid');
$upload = [
'cdnurl' => $config['cdnurl'],
'uploadurl' => $config['uploadurl'],
'bucket' => $config['bucket'],
'maxsize' => $config['maxsize'],
'mimetype' => $config['mimetype'],
'multipart' => $multipart,
'multiple' => $config['multiple'] ? true : false,
];
} else {
$upload = array_merge($upload, [
'cdnurl' => $config['cdnurl'],
'uploadurl' => addon_url('qiniu/index/upload'),
'maxsize' => $config['maxsize'],
'mimetype' => $config['mimetype'],
'multiple' => $config['multiple'] ? true : false,
]);
}
}
/**
* 附件删除后
*/
public function uploadDelete($attachment)
{
$config = $this->getConfig();
if ($attachment['storage'] == 'qiniu' && isset($config['syncdelete']) && $config['syncdelete']) {
$auth = new Auth($config['app_key'], $config['secret_key']);
$entry = $config['bucket'] . ':' . ltrim($attachment->url, '/');
$encodedEntryURI = $auth->base64_urlSafeEncode($entry);
$url = 'http://rs.qiniu.com/delete/' . $encodedEntryURI;
$headers = $auth->authorization($url);
//删除云储存文件
$ret = Http::sendRequest($url, [], 'POST', [CURLOPT_HTTPHEADER => ['Authorization: ' . $headers['Authorization']]]);
//如果是服务端中转,还需要删除本地文件
if ($config['uploadmode'] == 'server') {
$filePath = ROOT_PATH . 'public' . str_replace('/', DS, $attachment->url);
if ($filePath) {
@unlink($filePath);
}
}
}
return true;
}
}
... ...
//修改上传的接口调用
require(['upload'], function (Upload) {
var _onUploadResponse = Upload.events.onUploadResponse;
Upload.events.onUploadResponse = function (response) {
try {
var ret = typeof response === 'object' ? response : JSON.parse(response);
if (ret.hasOwnProperty("code") && ret.hasOwnProperty("data")) {
return _onUploadResponse.call(this, response);
} else if (ret.hasOwnProperty("key") && !ret.hasOwnProperty("err_code")) {
ret.code = 1;
ret.data = {
url: '/' + ret.key
};
return _onUploadResponse.call(this, JSON.stringify(ret));
}
} catch (e) {
}
return _onUploadResponse.call(this, response);
};
});
\ No newline at end of file
... ...
<?php
return array (
0 =>
array (
'name' => 'app_key',
'title' => 'app_key',
'type' => 'string',
'content' =>
array (
),
'value' => 'Ds_VHtkUOmbaC5FiQ-pZXrmk77kjgC9Aiwnf9E9u',
'rule' => 'required',
'msg' => '',
'tip' => '请在个人中心 > 密钥管理中获取 > AK',
'ok' => '',
'extend' => '',
),
1 =>
array (
'name' => 'secret_key',
'title' => 'secret_key',
'type' => 'string',
'content' =>
array (
),
'value' => 'rpyOuQBf88EhxehLfXbWQWdmm4pmeoxRyFvhaaS9',
'rule' => 'required',
'msg' => '',
'tip' => '请在个人中心 > 密钥管理中获取 > SK',
'ok' => '',
'extend' => '',
),
2 =>
array (
'name' => 'bucket',
'title' => 'bucket',
'type' => 'string',
'content' =>
array (
),
'value' => 'hang-areial',
'rule' => 'required',
'msg' => '',
'tip' => '存储空间名称',
'ok' => '',
'extend' => '',
),
3 =>
array (
'name' => 'uploadurl',
'title' => '上传接口地址',
'type' => 'select',
'content' =>
array (
'https://upload-z0.qiniup.com' => '华东 https://upload-z0.qiniup.com',
'https://upload-z1.qiniup.com' => '华北 https://upload-z1.qiniup.com',
'https://upload-z2.qiniup.com' => '华南 https://upload-z2.qiniup.com',
'https://upload-na0.qiniup.com' => '北美 https://upload-na0.qiniup.com',
'https://upload-as0.qiniup.com' => '东南亚 https://upload-as0.qiniup.com',
),
'value' => 'https://upload-z0.qiniup.com',
'rule' => 'required',
'msg' => '',
'tip' => '推荐选择最近的地址',
'ok' => '',
'extend' => '',
),
4 =>
array (
'name' => 'cdnurl',
'title' => 'CDN地址',
'type' => 'string',
'content' =>
array (
),
'value' => 'http://q1i4mcfwv.bkt.clouddn.com',
'rule' => 'required',
'msg' => '',
'tip' => '未绑定CDN的话可使用七牛分配的测试域名',
'ok' => '',
'extend' => '',
),
5 =>
array (
'name' => 'notifyenabled',
'title' => '启用服务端回调',
'type' => 'bool',
'content' =>
array (
),
'value' => '0',
'rule' => '',
'msg' => '',
'tip' => '本地开发请禁用服务端回调',
'ok' => '',
'extend' => '',
),
6 =>
array (
'name' => 'notifyurl',
'title' => '回调通知地址',
'type' => 'string',
'content' =>
array (
),
'value' => 'http://www.yoursite.com/addons/qiniu/index/notify',
'rule' => '',
'msg' => '',
'tip' => '',
'ok' => '',
'extend' => '',
),
7 =>
array (
'name' => 'uploadmode',
'title' => '上传模式',
'type' => 'select',
'content' =>
array (
'client' => '客户端直传(速度快,无备份)',
'server' => '服务器中转(占用服务器带宽,有备份)',
),
'value' => 'client',
'rule' => '',
'msg' => '',
'tip' => '启用服务器中转时务必配置操作员和密码',
'ok' => '',
'extend' => '',
),
8 =>
array (
'name' => 'savekey',
'title' => '保存文件名',
'type' => 'string',
'content' =>
array (
),
'value' => '/uploads/$(year)$(mon)$(day)/$(etag)$(ext)',
'rule' => 'required',
'msg' => '',
'tip' => '',
'ok' => '',
'extend' => '',
),
9 =>
array (
'name' => 'expire',
'title' => '上传有效时长',
'type' => 'string',
'content' =>
array (
),
'value' => '600',
'rule' => 'required',
'msg' => '',
'tip' => '',
'ok' => '',
'extend' => '',
),
10 =>
array (
'name' => 'maxsize',
'title' => '最大可上传',
'type' => 'string',
'content' =>
array (
),
'value' => '1000M',
'rule' => 'required',
'msg' => '',
'tip' => '',
'ok' => '',
'extend' => '',
),
11 =>
array (
'name' => 'mimetype',
'title' => '可上传后缀格式',
'type' => 'string',
'content' =>
array (
),
'value' => 'jpg,png,bmp,jpeg,gif,zip,rar,xls,xlsx,mp4',
'rule' => 'required',
'msg' => '',
'tip' => '',
'ok' => '',
'extend' => '',
),
12 =>
array (
'name' => 'multiple',
'title' => '多文件上传',
'type' => 'bool',
'content' =>
array (
),
'value' => '1',
'rule' => 'required',
'msg' => '',
'tip' => '',
'ok' => '',
'extend' => '',
),
13 =>
array (
'name' => 'syncdelete',
'title' => '附件删除时是否同步删除文件',
'type' => 'bool',
'content' =>
array (
),
'value' => '1',
'rule' => 'required',
'msg' => '',
'tip' => '',
'ok' => '',
'extend' => '',
),
14 =>
array (
'name' => '__tips__',
'title' => '温馨提示',
'type' => '',
'content' =>
array (
),
'value' => '在使用之前请注册七牛账号并进行认证,注册链接:<a href="https://portal.qiniu.com/signup?code=3l79xtos9w9qq" target="_blank">https://portal.qiniu.com/signup?code=3l79xtos9w9qq</a>',
'rule' => '',
'msg' => '',
'tip' => '',
'ok' => '',
'extend' => '',
),
);
... ...
<?php
namespace addons\qiniu\controller;
use addons\qiniu\library\Auth;
use app\common\model\Attachment;
use think\addons\Controller;
use think\Config;
/**
* 七牛管理
*
*/
class Index extends Controller
{
public function index()
{
$this->error("当前插件暂无前台页面");
}
/**
* 上传接口
*/
public function upload()
{
Config::set('default_return_type', 'json');
if (!session('admin') && !$this->auth->id) {
$this->error("请登录后再进行操作");
}
$config = get_addon_config('qiniu');
$file = $this->request->file('file');
if (!$file || !$file->isValid()) {
$this->error("请上传有效的文件");
}
$fileInfo = $file->getInfo();
$filePath = $file->getRealPath() ?: $file->getPathname();
preg_match('/(\d+)(\w+)/', $config['maxsize'], $matches);
$type = strtolower($matches[2]);
$typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];
$size = (int)$config['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0);
$suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
$suffix = $suffix ? $suffix : 'file';
$md5 = md5_file($filePath);
$search = ['$(year)', '$(mon)', '$(day)', '$(etag)', '$(ext)'];
$replace = [date("Y"), date("m"), date("d"), $md5, '.' . $suffix];
$object = ltrim(str_replace($search, $replace, $config['savekey']), '/');
$mimetypeArr = explode(',', strtolower($config['mimetype']));
$typeArr = explode('/', $fileInfo['type']);
//检查文件大小
if (!$file->checkSize($size)) {
$this->error("起过最大可上传文件限制");
}
//验证文件后缀
if ($config['mimetype'] !== '*' &&
(
!in_array($suffix, $mimetypeArr)
|| (stripos($typeArr[0] . '/', $config['mimetype']) !== false && (!in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr)))
)
) {
$this->error(__('上传格式限制'));
}
$savekey = '/' . $object;
$uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1);
$fileName = substr($savekey, strripos($savekey, '/') + 1);
//先上传到本地
$splInfo = $file->move(ROOT_PATH . '/public' . $uploadDir, $fileName);
if ($splInfo) {
$extparam = $this->request->post();
$filePath = $splInfo->getRealPath() ?: $splInfo->getPathname();
$sha1 = sha1_file($filePath);
$imagewidth = $imageheight = 0;
if (in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf'])) {
$imgInfo = getimagesize($splInfo->getPathname());
$imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth;
$imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
}
$params = array(
'admin_id' => session('admin.id'),
'user_id' => $this->auth->id,
'filesize' => $fileInfo['size'],
'imagewidth' => $imagewidth,
'imageheight' => $imageheight,
'imagetype' => $suffix,
'imageframes' => 0,
'mimetype' => $fileInfo['type'],
'url' => $uploadDir . $splInfo->getSaveName(),
'uploadtime' => time(),
'storage' => 'local',
'sha1' => $sha1,
'extparam' => json_encode($extparam),
);
$attachment = Attachment::create(array_filter($params), true);
$policy = array(
'saveKey' => ltrim($savekey, '/'),
);
$auth = new Auth($config['app_key'], $config['secret_key']);
$token = $auth->uploadToken($config['bucket'], null, $config['expire'], $policy);
$multipart = [
['name' => 'token', 'contents' => $token],
[
'name' => 'file',
'contents' => fopen($filePath, 'r'),
'filename' => $fileName,
]
];
try {
$client = new \GuzzleHttp\Client();
$res = $client->request('POST', $config['uploadurl'], [
'multipart' => $multipart
]);
$code = $res->getStatusCode();
//成功不做任何操作
} catch (\GuzzleHttp\Exception\ClientException $e) {
$attachment->delete();
unlink($filePath);
$this->error("上传失败");
}
$url = '/' . $object;
//上传成功后将存储变更为qiniu
$attachment->storage = 'qiniu';
$attachment->save();
$this->success("上传成功", null, ['url' => $url]);
} else {
$this->error('上传失败');
}
return;
}
/**
* 通知回调
*/
public function notify()
{
$config = get_addon_config('qiniu');
$auth = new Auth($config['app_key'], $config['secret_key']);
$contentType = 'application/x-www-form-urlencoded';
$authorization = isset($_SERVER['HTTP_AUTHORIZATION']) ? $_SERVER['HTTP_AUTHORIZATION'] : '';
if (!$authorization && function_exists('apache_request_headers')) {
$headers = apache_request_headers();
$authorization = isset($headers['Authorization']) ? $headers['Authorization'] : '';
}
$url = $config['notifyurl'];
$body = file_get_contents('php://input');
$ret = $auth->verifyCallback($contentType, $authorization, $url, $body);
if ($ret) {
parse_str($body, $arr);
$admin_id = isset($arr['admin']) ? $arr['admin'] : 0;
$user_id = isset($arr['user']) ? $arr['user'] : 0;
$imageInfo = json_decode($arr['imageInfo'], true);
$params = array(
'admin_id' => (int)$admin_id,
'user_id' => (int)$user_id,
'filesize' => $arr['filesize'],
'imagewidth' => isset($imageInfo['width']) ? $imageInfo['width'] : 0,
'imageheight' => isset($imageInfo['height']) ? $imageInfo['height'] : 0,
'imagetype' => isset($imageInfo['format']) ? $imageInfo['format'] : '',
'imageframes' => 1,
'mimetype' => "image/" . (isset($imageInfo['format']) ? $imageInfo['format'] : ''),
'extparam' => '',
'url' => '/' . $arr['key'],
'uploadtime' => time(),
'storage' => 'qiniu'
);
Attachment::create($params);
return json(['ret' => 'success', 'code' => 1, 'data' => ['url' => $params['url']]]);
}
return json(['ret' => 'failed']);
}
}
... ...
name = qiniu
title = 七牛上传
intro = 使用七牛云存储,上传时直传七牛
author = Karson
website = https://www.fastadmin.net
version = 1.0.5
state = 1
url = /addons/qiniu.html
... ...
<?php
namespace addons\qiniu\library;
final class Auth
{
private $accessKey;
private $secretKey;
public function __construct($accessKey, $secretKey)
{
$this->accessKey = $accessKey;
$this->secretKey = $secretKey;
}
public function getAccessKey()
{
return $this->accessKey;
}
public function sign($data)
{
$hmac = hash_hmac('sha1', $data, $this->secretKey, true);
return $this->accessKey . ':' . $this->base64_urlSafeEncode($hmac);
}
public function signWithData($data)
{
$encodedData = $this->base64_urlSafeEncode($data);
return $this->sign($encodedData) . ':' . $encodedData;
}
public function signRequest($urlString, $body, $contentType = null)
{
$url = parse_url($urlString);
$data = '';
if (array_key_exists('path', $url)) {
$data = $url['path'];
}
if (array_key_exists('query', $url)) {
$data .= '?' . $url['query'];
}
$data .= "\n";
if ($body !== null && $contentType === 'application/x-www-form-urlencoded') {
$data .= $body;
}
return $this->sign($data);
}
public function verifyCallback($contentType, $originAuthorization, $url, $body)
{
$authorization = 'QBox ' . $this->signRequest($url, $body, $contentType);
return $originAuthorization === $authorization;
}
public function privateDownloadUrl($baseUrl, $expires = 3600)
{
$deadline = time() + $expires;
$pos = strpos($baseUrl, '?');
if ($pos !== false) {
$baseUrl .= '&e=';
} else {
$baseUrl .= '?e=';
}
$baseUrl .= $deadline;
$token = $this->sign($baseUrl);
return "$baseUrl&token=$token";
}
public function uploadToken($bucket, $key = null, $expires = 3600, $policy = null, $strictPolicy = true)
{
$deadline = time() + $expires;
$scope = $bucket;
if ($key !== null) {
$scope .= ':' . $key;
}
$args = self::copyPolicy($args, $policy, $strictPolicy);
$args['scope'] = $scope;
$args['deadline'] = $deadline;
$b = json_encode($args);
return $this->signWithData($b);
}
/**
* 上传策略,参数规格详见
* http://developer.qiniu.com/docs/v6/api/reference/security/put-policy.html
*/
private static $policyFields = array(
'callbackUrl',
'callbackBody',
'callbackHost',
'callbackBodyType',
'callbackFetchKey',
'returnUrl',
'returnBody',
'endUser',
'saveKey',
'insertOnly',
'detectMime',
'mimeLimit',
'fsizeMin',
'fsizeLimit',
'persistentOps',
'persistentNotifyUrl',
'persistentPipeline',
'deleteAfterDays',
'fileType',
'upHosts',
);
private static function copyPolicy(&$policy, $originPolicy, $strictPolicy)
{
if ($originPolicy === null) {
return array();
}
foreach ($originPolicy as $key => $value) {
if (!$strictPolicy || in_array((string)$key, self::$policyFields, true)) {
$policy[$key] = $value;
}
}
return $policy;
}
public function authorization($url, $body = null, $contentType = null)
{
$authorization = 'QBox ' . $this->signRequest($url, $body, $contentType);
return array('Authorization' => $authorization);
}
/**
* 对提供的数据进行urlsafe的base64编码。
*
* @param string $data 待编码的数据,一般为字符串
*
* @return string 编码后的字符串
* @link http://developer.qiniu.com/docs/v6/api/overview/appendix.html#urlsafe-base64
*/
function base64_urlSafeEncode($data)
{
$find = array('+', '/');
$replace = array('-', '_');
return str_replace($find, $replace, base64_encode($data));
}
/**
* 对提供的urlsafe的base64编码的数据进行解码
*
* @param string $str 待解码的数据,一般为字符串
*
* @return string 解码后的字符串
*/
function base64_urlSafeDecode($str)
{
$find = array('-', '_');
$replace = array('+', '/');
return base64_decode(str_replace($find, $replace, $str));
}
}
... ...
<?php
namespace app\admin\controller;
use app\common\controller\Backend;
/**
* 图片订单管理
*
* @icon fa fa-circle-o
*/
class Order extends Backend
{
/**
* Order模型对象
* @var \app\admin\model\Order
*/
protected $model = null;
public function _initialize()
{
parent::_initialize();
$this->model = new \app\admin\model\Order;
}
/**
* 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
* 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
* 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
*/
}
... ...
<?php
return [
'User_id' => '用户ID',
'Pic_id' => '图片ID',
'Video_id' => '视频ID',
'Total' => '价格',
'Status' => '状态',
'Num' => '订单号',
'Createtime' => '创建时间',
'Paytime' => '支付时间'
];
... ...
<?php
namespace app\admin\model;
use think\Model;
class Order extends Model
{
// 表名
protected $name = 'order';
// 自动写入时间戳字段
protected $autoWriteTimestamp = 'int';
// 定义时间戳字段名
protected $createTime = 'createtime';
protected $updateTime = false;
protected $deleteTime = false;
// 追加属性
protected $append = [
'paytime_text'
];
public function getPaytimeTextAttr($value, $data)
{
$value = $value ? $value : (isset($data['paytime']) ? $data['paytime'] : '');
return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
}
protected function setPaytimeAttr($value)
{
return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
}
}
... ...
<?php
namespace app\admin\validate;
use think\Validate;
class Order extends Validate
{
/**
* 验证规则
*/
protected $rule = [
];
/**
* 提示消息
*/
protected $message = [
];
/**
* 验证场景
*/
protected $scene = [
'add' => [],
'edit' => [],
];
}
... ...
<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('User_id')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-user_id" data-rule="required" data-source="user/user/index" data-field="nickname" class="form-control selectpage" name="row[user_id]" type="text" value="">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Pic_id')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-pic_id" data-rule="required" data-source="pic/index" class="form-control selectpage" name="row[pic_id]" type="text" value="">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Video_id')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-video_id" data-rule="required" data-source="video/index" class="form-control selectpage" name="row[video_id]" type="text" value="">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Total')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-total" class="form-control" step="0.01" name="row[total]" type="number">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-status" class="form-control" name="row[status]" type="number" value="1">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Num')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-num" class="form-control" name="row[num]" type="text">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Paytime')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-paytime" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[paytime]" type="text" value="{:date('Y-m-d H:i:s')}">
</div>
</div>
<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-success btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('User_id')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-user_id" data-rule="required" data-source="user/user/index" data-field="nickname" class="form-control selectpage" name="row[user_id]" type="text" value="{$row.user_id|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Pic_id')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-pic_id" data-rule="required" data-source="pic/index" class="form-control selectpage" name="row[pic_id]" type="text" value="{$row.pic_id|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Video_id')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-video_id" data-rule="required" data-source="video/index" class="form-control selectpage" name="row[video_id]" type="text" value="{$row.video_id|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Total')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-total" class="form-control" step="0.01" name="row[total]" type="number" value="{$row.total|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-status" class="form-control" name="row[status]" type="number" value="{$row.status|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Num')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-num" class="form-control" name="row[num]" type="text" value="{$row.num|htmlentities}">
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-12 col-sm-2">{:__('Paytime')}:</label>
<div class="col-xs-12 col-sm-8">
<input id="c-paytime" class="form-control datetimepicker" data-date-format="YYYY-MM-DD HH:mm:ss" data-use-current="true" name="row[paytime]" type="text" value="{:$row.paytime?datetime($row.paytime):''}">
</div>
</div>
<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-success btn-embossed disabled">{:__('OK')}</button>
<button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
</div>
</div>
</form>
... ...
<div class="panel panel-default panel-intro">
{:build_heading()}
<div class="panel-body">
<div id="myTabContent" class="tab-content">
<div class="tab-pane fade active in" id="one">
<div class="widget-body no-padding">
<div id="toolbar" class="toolbar">
<a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a>
<!--<a href="javascript:;" class="btn btn-success btn-add {:$auth->check('order/add')?'':'hide'}" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>-->
<!--<a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled {:$auth->check('order/edit')?'':'hide'}" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a>-->
<!--<a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled {:$auth->check('order/del')?'':'hide'}" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>-->
<!--<a href="javascript:;" class="btn btn-danger btn-import {:$auth->check('order/import')?'':'hide'}" title="{:__('Import')}" id="btn-import-file" data-url="ajax/upload" data-mimetype="csv,xls,xlsx" data-multiple="false"><i class="fa fa-upload"></i> {:__('Import')}</a>-->
<div class="dropdown btn-group {:$auth->check('order/multi')?'':'hide'}">
<a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>
<ul class="dropdown-menu text-left" role="menu">
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=normal"><i class="fa fa-eye"></i> {:__('Set to normal')}</a></li>
<li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=hidden"><i class="fa fa-eye-slash"></i> {:__('Set to hidden')}</a></li>
</ul>
</div>
</div>
<table id="table" class="table table-striped table-bordered table-hover table-nowrap"
data-operate-edit="{:$auth->check('order/edit')}"
data-operate-del="{:$auth->check('order/del')}"
width="100%">
</table>
</div>
</div>
</div>
</div>
</div>
... ...
define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
var Controller = {
index: function () {
// 初始化表格参数配置
Table.api.init({
extend: {
index_url: 'order/index' + location.search,
add_url: 'order/add',
edit_url: 'order/edit',
del_url: 'order/del',
multi_url: 'order/multi',
table: 'order',
}
});
var table = $("#table");
// 初始化表格
table.bootstrapTable({
url: $.fn.bootstrapTable.defaults.extend.index_url,
pk: 'id',
sortName: 'id',
columns: [
[
{checkbox: true},
{field: 'id', title: __('Id'), operate:false},
{field: 'user_id', title: __('User_id'), operate:false},
{field: 'pic_id', title: __('Pic_id'), operate:false},
{field: 'video_id', title: __('Video_id'), operate:false},
{field: 'total', title: __('Total'), operate:false},
{field: 'status', title: __('Status'),searchList:$.getJSON('order/type')},
{field: 'num', title: __('Num'), operate:false},
{field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', formatter: Table.api.formatter.datetime},
{field: 'paytime', title: __('Paytime'), operate:'RANGE', addclass:'datetimerange', formatter: Table.api.formatter.datetime},
]
]
});
// 为表格绑定事件
Table.api.bindevent(table);
},
add: function () {
Controller.api.bindevent();
},
edit: function () {
Controller.api.bindevent();
},
api: {
bindevent: function () {
Form.api.bindevent($("form[role=form]"));
}
}
};
return Controller;
});
\ No newline at end of file
... ...