caipan_shop_admin/app/controller/manager/Attachment.php

501 lines
17 KiB
PHP
Executable File
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace app\controller\manager;
use app\model\Log;
use app\service\AliOss;
use think\facade\Config;
use Exception;
use app\model\Attachment as AttachmentModel;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\exception\ValidateException;
use think\response\Json;
use think\response\View;
/**
* 附件管理 - 素材管理
* Class Attachment
* @package app\controller\manager
*/
class Attachment extends Base
{
protected $noNeedLogin = ['file', 'getSize', 'md5List', 'pathDirHandle', 'toOss', 'delLostFile', 'test'];
protected $DIRECTORY_SEPARATOR = "/";
protected function initialize()
{
parent::initialize(); // TODO: Change the autogenerated stub
$this->DIRECTORY_SEPARATOR = DIRECTORY_SEPARATOR == "\\" ? "/" : DIRECTORY_SEPARATOR;
}
/**
* 删除
*
* @return Json
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function del(): Json
{
if ($this->request->isPost()) {
$ids = input('post.ids/a', []);
if (empty($ids)) {
$ids[] = input('post.id/d');
}
$items = AttachmentModel::whereIn('id', $ids)->where('is_dir', AttachmentModel::COMMON_ON)->select();
if ($items->where('is_dir', AttachmentModel::COMMON_ON)->count()) {
$dirPaths = [];
foreach ($items->toArray() as $item) {
$dirPaths[] = $item['path'].$item['name'].$this->DIRECTORY_SEPARATOR;
}
if (AttachmentModel::where('path', 'in', $dirPaths)->count()) {
return $this->json(4001, '待删除目录下存在内容!');
}
}
AttachmentModel::deleteByIds($ids);
// Log::write(get_class().'Del', 'del', '涉及到的ID为'.implode(',', $ids));
return $this->json();
}
return $this->json(4001, '非法请求!');
}
/**
* 单个字段编辑
*
* @return Json
* @throws Exception
*/
public function modify(): Json
{
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'field' => 'require',
'value' => 'require',
]);
if ($validate !== true) {
return $validate;
}
if (!$info = AttachmentModel::findById($item['id'])) {
return $this->json(4001, '记录不存在');
}
if ($item['field'] == 'name' && $info['is_dir'] == AttachmentModel::COMMON_ON) {
return $this->json(4002, '目录名称不能修改');
}
$update = [$item['field'] => $item['value']];
try {
$info->save($update);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
return $this->json(4000, '非法请求');
}
/**
* 添加
*
* @return Json|View
* @throws Exception
*/
public function add()
{
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'title|合集标题' => 'require',
'user|虚拟用户' => 'require',
'headimg|虚拟用户头像' => 'require',
]);
if ($validate !== true) {
return $validate;
}
try {
$now = date('Y-m-d H:i:s');
$item['created_at'] = $now;
$item['created_by'] = $this->auth['user_id'];
AttachmentModel::create($item);
return $this->json();
} catch (ValidateException $e) {
return $this->json(4001, $e->getError());
}
}
return $this->view();
}
/**
* 添加文件夹
*
* @return Json|View
* @throws Exception
*/
public function addFolder()
{
if ($this->request->isPost()) {
$item = input('post.');
$validate = $this->validateByApi($item, [
'name|文件夹名称' => 'require|alphaDash|max:20',
'path|文件路径' => 'require',
]);
// 例 name=dir4 path=/storage/dir1/dir2/dir3
// 去首尾/
$path = trim($item['path'], $this->DIRECTORY_SEPARATOR);
// 全路径 如 /storage/dir1/dir2/dir3/dir4/ 注意前后都有/
$fullPath = $this->DIRECTORY_SEPARATOR.$path.$this->DIRECTORY_SEPARATOR.$item['name'].$this->DIRECTORY_SEPARATOR;
if ($validate !== true) {
return $validate;
}
AttachmentModel::pathDirHandle($fullPath);
return $this->json();
}
$path = input('path/s', AttachmentModel::ROOT_PATH);
$this->data['path'] = $path;
return $this->view();
}
/**
* 图片列表
*
* @return View|Json
* @throws Exception
*/
public function image()
{
$path = input('post.path', AttachmentModel::ROOT_PATH);
$path = $this->DIRECTORY_SEPARATOR.trim($path, $this->DIRECTORY_SEPARATOR).$this->DIRECTORY_SEPARATOR;
$path = str_replace("\\", "/", $path);
$type = input('type/s', 'image');
$selected = input('selected', false);
$multiple = input('multiple', false);
Config::load('extra/alioss', 'alioss');
Config::load('extra/base', 'base');
$config = config('alioss');
$baseConfig = config('base');
$oss = $baseConfig['oss'] == 'true' ? $config['customDomain'] : '';
if ($this->request->isPost()) {
$items = $this->list($path, ['image']);
return $this->json(0, '操作成功', $items);
}
$this->data['path'] = $path;
$this->data['oss'] = $oss;
$this->data['type'] = $type;
$this->data['multiple'] = $multiple;
$this->data['selected'] = $selected;
return $this->view();
}
/**
* 视频列表
*
* @return View|Json
* @throws Exception
*/
public function video()
{
$path = input('post.path', AttachmentModel::ROOT_PATH);
$path = $this->DIRECTORY_SEPARATOR.trim($path, $this->DIRECTORY_SEPARATOR).$this->DIRECTORY_SEPARATOR;
$path = str_replace("\\", "/", $path);
$type = input('type/s', 'video');
$selected = input('selected', false);
$multiple = input('multiple', false);
Config::load('extra/alioss', 'alioss');
Config::load('extra/base', 'base');
$config = config('alioss');
$baseConfig = config('base');
$oss = $baseConfig['oss'] == 'true' ? $config['customDomain'] : '';
if ($this->request->isPost()) {
$items = $this->list($path, ['video']);
return $this->json(0, '操作成功', $items);
}
$this->data['path'] = $path;
$this->data['oss'] = $oss;
$this->data['type'] = $type;
$this->data['multiple'] = $multiple;
$this->data['selected'] = $selected;
return $this->view();
}
/**
* 文件列表
*
* @return View|Json
* @throws Exception
*/
public function file()
{
Config::load('extra/alioss', 'alioss');
$config = config('alioss');
$baseConfig = config('base');
$oss = $baseConfig['oss'] == 'true' ? $config['customDomain'] : '';
$type = input('type/s', 'all');
$selected = input('selected', false);
$multiple = input('multiple', false);
if ($this->request->isPost()) {
$page = input('post.page', 1);
$size = input('post.size', 20);
$searchParams = input('searchParams');
$where = [];
if ($searchParams) {
foreach ($searchParams as $key => $param) {
if (!empty($param)) {
if (is_string($param)) {
if ($key == 'is_oss') {
if ($param >= 0) {
$where[] = ['is_oss', '=', $param];
}
} else {
$where[] = [$key, 'like', '%'.$param.'%'];
}
} elseif (is_array($param)) {
//数组空元素去除
foreach ($param as $k => $val) {
if (empty($val)) {
unset($param[$k]);
}
}
if (!empty($param)) {
$where[] = [$key, 'in', $param];
}
}
}
}
}
if ($type !== 'all') {
$where[] = ['type', '=', $type];
}
$items = AttachmentModel::findList($where, [], $page, $size, function ($q) {
return $q->where('type', '<>', 'dir')->order('updated_at', 'desc');
});
$items['list']->each(function ($item) {
$item->size_text = getFilesize($item['size'] ?? 0);
});
return $this->json(0, '操作成功', $items);
}
$this->data['oss'] = $oss;
$this->data['type'] = $type;
$this->data['multiple'] = $multiple;
$this->data['selected'] = $selected;
return $this->view();
}
/**
* 一键删除失效记录 即oss不存在&&本地不存在
*
* @return Json
*/
public function delLostFile(): Json
{
if ($this->request->isPost()) {
$total = AttachmentModel::where('type', '<>', AttachmentModel::TYPE_DIR)
->where('is_dir', AttachmentModel::COMMON_OFF)
->where('is_oss', AttachmentModel::COMMON_OFF)
->where('has_local', AttachmentModel::COMMON_OFF)
->count();
if ($total === 0) {
return $this->json(0, 'success', ['total' => $total]);
}
if (AttachmentModel::where('type', '<>', AttachmentModel::TYPE_DIR)
->where('is_dir', AttachmentModel::COMMON_OFF)
->where('is_oss', AttachmentModel::COMMON_OFF)
->where('has_local', AttachmentModel::COMMON_OFF)
->delete()) {
return $this->json(0, 'success', ['total' => $total]);
}
return $this->json(4004, '删除失败');
}
return $this->json(4000, '请求错误');
}
/**
* 一键上传本地文件到OSS
*
* @return Json
*/
public function toOss(): Json
{
if ($this->request->isPost()) {
Config::load('extra/alioss', 'alioss');
Config::load('extra/base', 'base');
$config = config('alioss');
$baseConfig = config('base');
if ($baseConfig['oss'] != 'true') {
return $this->json('4000', '配置未开启OSS上传');
}
$ossObject = AliOss::instance();
$bucket = $config['bucket'];
$total = AttachmentModel::where('type', '<>', AttachmentModel::TYPE_DIR)
->where('is_dir', AttachmentModel::COMMON_OFF)
->where('is_oss', AttachmentModel::COMMON_OFF)
->field('id')
->count();
$done = 0;
$none = 0;
if ($total === 0) {
return $this->json(0, 'success', ['total' => $total, 'done' => $done, 'none' => $none]);
}
try {
AttachmentModel::where('type', '<>', AttachmentModel::TYPE_DIR)
->where('is_dir', AttachmentModel::COMMON_OFF)
->where('is_oss', AttachmentModel::COMMON_OFF)
->field('id,src')
->chunk(3, function ($items) use ($ossObject, $bucket, &$done, &$none) {
$doneIds = [];
$noneIds = [];
foreach ($items as $item) {
if ($item['src']) {
$realPath = public_path().ltrim($item['src'], $this->DIRECTORY_SEPARATOR);
if (!file_exists($realPath)) {
$none++;
$noneIds[] = $item['id'];
continue;
}
$pathInfo = pathinfo($item['src']);
$object = ltrim($item['src'], $this->DIRECTORY_SEPARATOR);
//是否存在
if (!$ossObject->doesObjectExist($bucket, $object)) {
//创建目录
$ossObject->createObjectDir($bucket, ltrim($pathInfo['dirname'], $this->DIRECTORY_SEPARATOR));
$ossObject->uploadFile($bucket, $object, $realPath);
}
$doneIds[] = $item['id'];
$done++;
}
}
// 失效标记
if ($noneIds) {
$update = ['is_oss' => AttachmentModel::COMMON_OFF, 'has_local' => AttachmentModel::COMMON_OFF];
(new AttachmentModel())->where('id', 'in', $noneIds)->update($update);
}
// 完成标记
if ($doneIds) {
$update = ['is_oss' => AttachmentModel::COMMON_ON];
(new AttachmentModel())->where('id', 'in', $doneIds)->update($update);
}
});
return $this->json(0, 'success', ['total' => $total, 'done' => $done, 'none' => $none]);
} catch (Exception $e) {
\think\facade\Log::error('本地文件一键上传OSS失败 '.$e->getMessage());
return $this->json(0, 'success', ['total' => $total, 'done' => $done, 'none' => $none]);
}
}
}
/**
* 指定类型附件列表
*
* @param array $type
* @param string $path
* @return array
* @throws Exception
*/
protected function list(string $path, array $type): array
{
$type[] = 'dir';
$where[] = ['path', '=', $path];
$where[] = ['type', 'in', $type];
$items = AttachmentModel::findList($where, [], 1, 0, function ($q) {
return $q->order('is_dir', 'desc')->order('updated_at', 'desc');
});
$items['list']->each(function ($item) {
$item->size_text = getFilesize($item['size'] ?? 0);
});
$items['path'] = $path;
return $items;
}
/**
* 获取文件大小
*
* @return Json
*/
public function getSize(): Json
{
$path = input('post.path', '');
$types = input('post.type/a', []);
$size = '';
if (empty($path)) {
return $this->json(0, '操作成功', $size);
}
$path = str_replace("\\", "/", $path);
$total = AttachmentModel::where('path', 'like', $path.'%')
->when(!empty($types), function ($q) use ($types) {
$q->where('type', 'in', $types);
})
->sum('size');
return $this->json(0, '操作成功', getFilesize($total));
}
// 将没有md5的文件 更新md5 仅针对本地文件
public function md5List()
{
$noMd5List = AttachmentModel::whereNull('md5')->select();
$update = [];
foreach ($noMd5List as $item) {
try {
if (!empty($item['src'])) {
$arr = [];
$path = public_path().ltrim($item['src'], $this->DIRECTORY_SEPARATOR);
$file = new \think\File($path);
$arr['md5'] = $file->md5();
$arr['id'] = $item['id'];
$update[] = $arr;
}
} catch (Exception $e) {
continue;
}
}
(new AttachmentModel())->saveAll($update);
}
}