增加文件夹分类功能,待完善.
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* User: Wisp X
|
||||
* Date: 2018-12-27
|
||||
* Time: 11:08
|
||||
* Link: https://github.com/wisp-x
|
||||
*/
|
||||
|
||||
namespace app\common\model;
|
||||
|
||||
use think\Model;
|
||||
use think\model\concern\SoftDelete;
|
||||
|
||||
class Folders extends Model
|
||||
{
|
||||
use SoftDelete;
|
||||
}
|
||||
@@ -75,4 +75,9 @@ class Users extends Model
|
||||
{
|
||||
return $this->hasMany('Images', 'user_id', 'id');
|
||||
}
|
||||
|
||||
public function folders()
|
||||
{
|
||||
return $this->hasMany('Folders', 'user_id', 'id');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* User: Wisp X
|
||||
* Date: 2018-12-27
|
||||
* Time: 14:30
|
||||
* Link: https://github.com/wisp-x
|
||||
*/
|
||||
|
||||
namespace app\common\validate;
|
||||
|
||||
use think\Validate;
|
||||
|
||||
class Folders extends Validate
|
||||
{
|
||||
protected $rule = [
|
||||
'parent_id' => 'require|number|integer',
|
||||
'name' => 'require|max:30|chsAlphaNum'
|
||||
];
|
||||
|
||||
protected $message = [
|
||||
'parent_id.require' => '没有找到上级文件夹',
|
||||
'parent_id.number' => '上级文件夹异常',
|
||||
'parent_id.integer' => '上级文件夹异常',
|
||||
'name.require' => '文件夹名称不能为空',
|
||||
'name.max' => '文件夹名称长度最大30个字符',
|
||||
'name.chsAlphaNum' => '文件夹名称只能是汉字、字母和数字'
|
||||
];
|
||||
}
|
||||
@@ -190,6 +190,14 @@ EOT;
|
||||
if ($start == 1) {
|
||||
if ($file) {
|
||||
$config = Config::pull('db');
|
||||
|
||||
// 替换sql关键字
|
||||
$file = str_replace([
|
||||
'{database}'
|
||||
], [
|
||||
$config['database']
|
||||
], $file);
|
||||
|
||||
$mysqli = new \mysqli(
|
||||
$config['hostname'],
|
||||
$config['username'],
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
namespace app\index\controller;
|
||||
|
||||
use app\common\model\Folders;
|
||||
use app\common\model\Images;
|
||||
use think\Db;
|
||||
use think\facade\Config;
|
||||
@@ -16,14 +17,18 @@ use think\Exception;
|
||||
|
||||
class User extends Base
|
||||
{
|
||||
public function images($keyword = '', $limit = 60)
|
||||
public function images($keyword = '', $folderId = 0, $limit = 60)
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
try {
|
||||
$model = $this->user->images()->order('create_time', 'desc');
|
||||
$folders = $this->user->folders()->where('parent_id', $folderId)->select();
|
||||
if (!empty($keyword)) {
|
||||
$model = $model->where('pathname', 'like', "%{$keyword}%");
|
||||
}
|
||||
if (is_numeric($folderId)) {
|
||||
$model = $model->where('folder_id', $folderId);
|
||||
}
|
||||
$images = $model->paginate($limit)->each(function ($item) {
|
||||
$item->url = $item->url;
|
||||
// TODO 生成缩略图
|
||||
@@ -32,7 +37,10 @@ class User extends Base
|
||||
} catch (Exception $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
return $this->success('success', null, $images);
|
||||
return $this->success('success', null, [
|
||||
'images' => $images,
|
||||
'folders'=> $folders
|
||||
]);
|
||||
}
|
||||
return $this->fetch();
|
||||
}
|
||||
@@ -90,6 +98,90 @@ class User extends Base
|
||||
}
|
||||
}
|
||||
|
||||
public function createFolder()
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
try {
|
||||
$parentId = $this->request->post('parent_id');
|
||||
$name = $this->request->post('name');
|
||||
$data = [
|
||||
'user_id' => $this->user->id,
|
||||
'parent_id' => $parentId,
|
||||
'name' => $name
|
||||
];
|
||||
$validate = $this->validate($data, 'Folders');
|
||||
if (true !== $validate) {
|
||||
throw new Exception($validate);
|
||||
}
|
||||
Folders::create($data);
|
||||
} catch (Exception $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
return $this->success('创建成功');
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteFolder()
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
Db::startTrans();
|
||||
try {
|
||||
$id = $this->request->post('id');
|
||||
$folders = $images = [];
|
||||
$this->getDeleteFoldersAndImages($id, $folders, $images);
|
||||
$folders[] = (int) $id;
|
||||
Folders::destroy($folders, true);
|
||||
Images::destroy($images, true);
|
||||
Db::commit();
|
||||
} catch (Exception $e) {
|
||||
Db::rollback();
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
return $this->success('删除成功');
|
||||
}
|
||||
}
|
||||
|
||||
public function renameFolder()
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
Db::startTrans();
|
||||
try {
|
||||
$id = $this->request->post('id');
|
||||
$parentId = $this->request->post('parent_id');
|
||||
$name = $this->request->post('name');
|
||||
$data = [
|
||||
'id' => $id,
|
||||
'parent_id' => $parentId,
|
||||
'user_id' => $this->user->id,
|
||||
'name' => $name
|
||||
];
|
||||
$validate = $this->validate($data, 'Folders');
|
||||
if (true !== $validate) {
|
||||
throw new Exception($validate);
|
||||
}
|
||||
Folders::update($data);
|
||||
Db::commit();
|
||||
} catch (Exception $e) {
|
||||
Db::rollback();
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
return $this->success('重命名成功');
|
||||
}
|
||||
}
|
||||
|
||||
private function getDeleteFoldersAndImages($folderId, &$folders, &$images)
|
||||
{
|
||||
$folderList = Folders::where('parent_id', $folderId)->column('id');
|
||||
$imagesList = Images::where('folder_id', $folderId)->column('id');
|
||||
if ($imagesList) {
|
||||
$images = array_merge($images, $imagesList);
|
||||
}
|
||||
foreach ($folderList as &$value) {
|
||||
$folders[] = $value;
|
||||
$this->getDeleteFoldersAndImages($value, $folders, $images);
|
||||
}
|
||||
}
|
||||
|
||||
public function settings()
|
||||
{
|
||||
if ($this->request->isPost()) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<link rel="shortcut icon" href="/favicon.ico">
|
||||
<link rel="stylesheet" href="/static/app/iconfont/iconfont.css">
|
||||
<link rel="stylesheet" href="/static/mdui/0.4.1/css/mdui.min.css">
|
||||
<link rel="stylesheet" href="/static/app/css/app.css">
|
||||
<link rel="stylesheet" href="/static/app/css/app.css?v=1.0">
|
||||
<!--[if IE]>
|
||||
<script>window.location.href = '/compatibility.html';</script>
|
||||
<![endif]-->
|
||||
@@ -139,7 +139,7 @@
|
||||
<script src="/static/jquery/3.3.1/jquery.min.js"></script>
|
||||
<script src="/static/mdui/0.4.1/js/mdui.min.js"></script>
|
||||
<script src="/static/marked/0.5.1/marked.js"></script>
|
||||
<script src="/static/app/js/app.js"></script>
|
||||
<script src="/static/app/js/app.js?v=1.0"></script>
|
||||
{block name="js"}{/block}
|
||||
<script>
|
||||
var thatVer = '{$config.system_version}';
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
{block name="title"}图片管理 - {$config.site_name}{/block}
|
||||
|
||||
{block name="css"}
|
||||
<link rel="stylesheet" href="/static/contextjs/css/context.standalone.css">
|
||||
<link rel="stylesheet" href="/static/jquery-viewer/1.2.0/css/viewer.css">
|
||||
<link rel="stylesheet" href="/static/contextjs/css/context.standalone.css">
|
||||
<link rel="stylesheet" href="/static/jquery-viewer/1.2.0/css/viewer.css">
|
||||
{/block}
|
||||
|
||||
{block name="main"}
|
||||
@@ -30,9 +30,15 @@
|
||||
</form>
|
||||
<div class="mdui-clearfix"></div>
|
||||
</div>
|
||||
<ul class="breadcrumb">
|
||||
<li class="active"><a data-id="0">Home</a></li>
|
||||
</ul>
|
||||
<div class="mdui-divider mdui-m-b-1"></div>
|
||||
<div class="mdui-row">
|
||||
<div id="images-box" class="images-box mdui-row-xs-3 mdui-row-sm-9 mdui-row-md-9 mdui-row-lg-10 mdui-col-xl-12"></div>
|
||||
<div class="box mdui-row-xs-3 mdui-row-sm-9 mdui-row-md-9 mdui-row-lg-10 mdui-col-xl-12">
|
||||
<div class="folders-box"></div>
|
||||
<div class="images-box"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="mdui-btn mdui-ripple mdui-center mdui-color-grey-300 mdui-text-color-black-secondary mdui-m-t-2 more"></button>
|
||||
<!-- Info Dialog -->
|
||||
@@ -97,31 +103,47 @@
|
||||
<script>
|
||||
$(function () {
|
||||
|
||||
var params = {}, viewer, imagesBox = $('.images-box'), totalBox = $('small.num'), infoDialog = $(".mdui-dialog#info"), qrcodeApi = 'https://www.kuaizhan.com/common/encode-png?large=true&data=';
|
||||
var params = {}, viewer, foldersBox = $('.folders-box'), imagesBox = $('.images-box'), totalBox = $('small.num'), infoDialog = $(".mdui-dialog#info"), qrcodeApi = 'https://www.kuaizhan.com/common/encode-png?large=true&data=';
|
||||
params.page = 1;
|
||||
|
||||
// 函数库
|
||||
var methods = {
|
||||
getImages: function () {
|
||||
getData: function (options) {
|
||||
params = options || params;
|
||||
var more = $(".more");
|
||||
more.attr('disabled', true).text('加载中...');
|
||||
app.ajax("{:url('user/images')}", params, function (response) {
|
||||
if (response.code) {
|
||||
var list = response.data.data;
|
||||
totalBox.text(response.data.total);
|
||||
if (list.length) {
|
||||
for (var i = 0; i < list.length; i++) {
|
||||
var images = response.data.images.data;
|
||||
var folders = response.data.folders;
|
||||
totalBox.text(response.data.images.total);
|
||||
if (folders.length) {
|
||||
for (var f = 0; f < folders.length; f++) {
|
||||
foldersBox.append(
|
||||
' <div class="mdui-col">' +
|
||||
' <div class="item" data-id="' + folders[f].id + '" data-parent-id="' + folders[f].parent_id + '" data-name="' + folders[f].name + '">' +
|
||||
' <div class="info">' +
|
||||
' <img src="/static/app/images/folder.svg">' +
|
||||
' </div>' +
|
||||
' <p class="name">' + folders[f].name + '</p>' +
|
||||
' </div>' +
|
||||
'</div>'
|
||||
);
|
||||
}
|
||||
}
|
||||
if (images.length) {
|
||||
for (var i = 0; i < images.length; i++) {
|
||||
imagesBox.append(
|
||||
'<div class="mdui-col">' +
|
||||
' <div data-id="' + list[i].id + '" data-json=\'' + JSON.stringify(list[i]) + '\' class="item" title=' + list[i].name + '>' +
|
||||
' <i class="choice iconfont icon-choice"></i>' +
|
||||
' <i class="info iconfont icon-info"></i>' +
|
||||
' <div class="info image">' +
|
||||
' <img data-original="' + list[i].url + '" src="' + list[i].url + '">' +
|
||||
' </div>' +
|
||||
' <p class="name">' + list[i].name + '</p>' +
|
||||
' </div>' +
|
||||
' </div>');
|
||||
' <div class="item" data-id="' + images[i].id + '" data-json=\'' + JSON.stringify(images[i]) + '\' title=' + images[i].name + '>' +
|
||||
' <i class="choice iconfont icon-choice"></i>' +
|
||||
' <i class="info iconfont icon-info"></i>' +
|
||||
' <div class="info image">' +
|
||||
' <img data-original="' + images[i].url + '" src="' + images[i].url + '">' +
|
||||
' </div>' +
|
||||
' <p class="name">' + images[i].name + '</p>' +
|
||||
' </div>' +
|
||||
'</div>');
|
||||
}
|
||||
|
||||
// 图片预览插件
|
||||
@@ -134,17 +156,22 @@
|
||||
viewer.data('viewer').update();
|
||||
}
|
||||
|
||||
if (response.data.current_page == response.data.last_page) {
|
||||
if (response.data.images.current_page == response.data.images.last_page) {
|
||||
return more.attr('disabled', true).text('我也是有底线的~');
|
||||
}
|
||||
params.page++;
|
||||
return more.attr('disabled', false).text('加载更多');
|
||||
} else {
|
||||
more.attr('disabled', true).text('暂无数据');
|
||||
more.attr('disabled', true).text('暂无图片');
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
resetData: function (options) {
|
||||
foldersBox.html('');
|
||||
imagesBox.html('');
|
||||
methods.getData(options);
|
||||
},
|
||||
// 删除
|
||||
delete: function (id, batch, callback) {
|
||||
var msg = '确认删除该图片吗?';
|
||||
@@ -161,7 +188,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
methods.getImages();
|
||||
methods.getData();
|
||||
|
||||
// 监听复制操作
|
||||
var clipboard = new ClipboardJS('.copy-url');
|
||||
@@ -179,50 +206,149 @@
|
||||
// Context Start
|
||||
context.init({
|
||||
fadeSpeed: 100,
|
||||
filter: function ($obj){},
|
||||
filter: function ($obj) {},
|
||||
above: 'auto',
|
||||
preventDoubleContext: true,
|
||||
compress: false
|
||||
});
|
||||
|
||||
$('body').on('contextmenu', '.images-box .item', function(e) {
|
||||
var item = $(e.target).closest('.item'), data = item.data('json');
|
||||
context.attach('.images-box .item', [
|
||||
{header: 'Compressed Menu'},
|
||||
{text: '查看图片', action: function (e) {
|
||||
// 右键操作
|
||||
$('.images-container').on('contextmenu', '.box', function(e) {
|
||||
var $that = $(e.target), $item = $that.closest('.item');
|
||||
if ($that.parents().hasClass('folders-box')) {
|
||||
context.attach('.folders-box .item', [
|
||||
{header: 'Compressed Menu'},
|
||||
{text: '打开', action: function (e) {
|
||||
$item.click();
|
||||
}
|
||||
},
|
||||
{text: '重新命名', action: function (e) {
|
||||
e.preventDefault();
|
||||
item.find('img').click();
|
||||
mdui.prompt('请输入文件夹名称',
|
||||
function (value) {
|
||||
app.ajax("{:url('user/renameFolder')}", {
|
||||
id: $item.data('id'),
|
||||
parent_id: $item.data('parent-id'),
|
||||
name: value
|
||||
}, function (response) {
|
||||
if (response.code) {
|
||||
$item.attr('data-name', value).find('p.name').text(value);
|
||||
return app.msg(true, response.msg);
|
||||
}
|
||||
mdui.alert(response.msg);
|
||||
})
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
{divider: true},
|
||||
{text: '删除', action: function (e) {
|
||||
e.preventDefault();
|
||||
mdui.confirm('确认删除该文件夹吗?', function() {
|
||||
app.ajax("{:url('user/deleteFolder')}", {id: $item.data('id')}, function (response) {
|
||||
if (response.code) {
|
||||
$item.parent().remove();
|
||||
return app.msg(true, response.msg);
|
||||
}
|
||||
mdui.alert(response.msg);
|
||||
})
|
||||
});
|
||||
}
|
||||
},
|
||||
]);
|
||||
} else if ($that.parents().hasClass('images-box')) {
|
||||
var $item = $that.closest('.item'), data = $item.data('json');
|
||||
context.attach('.images-box .item', [
|
||||
{header: 'Compressed Menu'},
|
||||
{text: '查看图片', action: function (e) {
|
||||
e.preventDefault();
|
||||
$item.find('img').click();
|
||||
}
|
||||
},
|
||||
{text: '新窗口打开图片', href: data.url, target: '_blank'},
|
||||
{divider: true},
|
||||
{text: '复制链接', action: function (e) {
|
||||
e.preventDefault();
|
||||
$('#copy-url').attr('data-clipboard-text', data.url).click();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '删除', action: function (e) {
|
||||
e.preventDefault();
|
||||
methods.delete(data.id, false, function () {
|
||||
$item.parent().remove();
|
||||
totalBox.text(parseInt(totalBox.text()) - 1);
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '属性', action: function (e) {
|
||||
e.preventDefault();
|
||||
$item.find('i.info').click();
|
||||
}
|
||||
}
|
||||
},
|
||||
{text: '新窗口打开图片', href: data.url, target: '_blank'},
|
||||
{divider: true},
|
||||
{text: '复制链接', action: function (e) {
|
||||
]);
|
||||
} else {
|
||||
context.attach('.box', [
|
||||
{header: 'Compressed Menu'},
|
||||
{text: '新建文件夹', action: function (e) {
|
||||
e.preventDefault();
|
||||
$('#copy-url').attr('data-clipboard-text', data.url).click();
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '删除', action: function (e) {
|
||||
e.preventDefault();
|
||||
methods.delete(data.id, false, function () {
|
||||
item.parent().remove();
|
||||
totalBox.text(parseInt(totalBox.text()) - 1);
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
text: '属性', action: function (e) {
|
||||
e.preventDefault();
|
||||
item.find('i.info').click();
|
||||
}
|
||||
}
|
||||
]);
|
||||
mdui.prompt('请输入文件夹名称',
|
||||
function (value) {
|
||||
app.ajax("{:url('user/createFolder')}", {
|
||||
parent_id: $('ul.breadcrumb li.active:last-child a').data('id'),
|
||||
name: value
|
||||
}, function (response) {
|
||||
if (response.code) {
|
||||
methods.resetData();
|
||||
return app.msg(true, response.msg);
|
||||
}
|
||||
mdui.alert(response.msg);
|
||||
})
|
||||
}
|
||||
);
|
||||
}
|
||||
},
|
||||
{divider: true},
|
||||
{text: '刷新', action: function (e) {
|
||||
// e.preventDefault();
|
||||
methods.resetData();
|
||||
}
|
||||
},
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
// 文件夹点击操作
|
||||
$('.folders-box').on('click', '', function (e) {
|
||||
var $that = $(e.target), $item = $that.closest('.item');
|
||||
$('ul.breadcrumb li:last-child').removeClass('active');
|
||||
$('ul.breadcrumb').append(
|
||||
'<li class="active">' +
|
||||
' <a data-id="' + $item.data('id') + '">' + $item.data('name') + '</a>' +
|
||||
'</li>'
|
||||
);
|
||||
methods.resetData({
|
||||
page: 1,
|
||||
folderId: $item.data('id')
|
||||
});
|
||||
});
|
||||
|
||||
// 面包屑导航点击
|
||||
$('ul.breadcrumb').on('click', 'li:not(.active) a', function (e) {
|
||||
e.preventDefault();
|
||||
methods.resetData({
|
||||
page: 1,
|
||||
folderId: $(this).data('id')
|
||||
});
|
||||
$(this).parent('li').addClass('active').nextAll().remove();
|
||||
});
|
||||
|
||||
// Context End
|
||||
|
||||
// 加载更多
|
||||
$('.more').click(function () {
|
||||
methods.getImages();
|
||||
methods.getData();
|
||||
});
|
||||
|
||||
// 筛选
|
||||
@@ -231,7 +357,7 @@
|
||||
// 清空内容
|
||||
imagesBox.html('');
|
||||
params.keyword = $(this).find("input[name='keyword']").val();
|
||||
methods.getImages();
|
||||
methods.getData();
|
||||
});
|
||||
|
||||
// 选中项操作
|
||||
@@ -247,7 +373,7 @@
|
||||
methods.delete(array, true, function () {
|
||||
selected.remove();
|
||||
totalBox.text(parseInt(totalBox.text()) - selected.length);
|
||||
// methods.getImages();
|
||||
// methods.getData();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
@@ -332,11 +458,7 @@
|
||||
|
||||
// 重置数据
|
||||
$('#reset').click(function () {
|
||||
params = {
|
||||
page: 1
|
||||
};
|
||||
imagesBox.html('');
|
||||
methods.getImages();
|
||||
methods.resetData();
|
||||
});
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user