Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fb579a5771 | ||
![]() |
4e1e040936 | ||
![]() |
38e10896d4 | ||
![]() |
ba1595f75f | ||
![]() |
566514f729 | ||
![]() |
48c41f7948 | ||
![]() |
f67a4f33d5 |
47
catch/cms/tables/Category.php
Normal file
47
catch/cms/tables/Category.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
namespace catchAdmin\cms\table;
|
||||
|
||||
use catcher\CatchTable;
|
||||
use catcher\library\table\Actions;
|
||||
use catcher\library\table\HeaderItem;
|
||||
use catcher\library\table\Search;
|
||||
|
||||
class Category extends CatchTable
|
||||
{
|
||||
public function table()
|
||||
{
|
||||
// TODO: Implement table() method.
|
||||
return $this->getTable('category')
|
||||
->header([
|
||||
HeaderItem::label('分类名称')->prop('name'),
|
||||
HeaderItem::label('自定义链接')->prop('url'),
|
||||
HeaderItem::label('栏目类型')->prop('type')->component('type'),
|
||||
HeaderItem::label('投稿')->prop('is_can_contribute')->withSwitchComponent(),
|
||||
HeaderItem::label('评论')->prop('is_can_comment')->withSwitchComponent(),
|
||||
HeaderItem::label('状态')->prop('status')->withSwitchComponent(),
|
||||
HeaderItem::label('权重')->prop('weight')->withEditNumberComponent(),
|
||||
HeaderItem::label('创建时间')->prop('created_at'),
|
||||
HeaderItem::label('操作')->actions([
|
||||
Actions::update(),
|
||||
Actions::delete()
|
||||
])
|
||||
])
|
||||
->withActions([
|
||||
Actions::create()
|
||||
])
|
||||
->withSearch([
|
||||
Search::label('分类名称')->name('请输入分类名称'),
|
||||
Search::label('状态')->name('请选择状态'),
|
||||
])
|
||||
->toTreeTable()
|
||||
->render();
|
||||
}
|
||||
|
||||
public function form()
|
||||
{
|
||||
// TODO: Implement form() method.
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@@ -41,7 +41,8 @@ class Role extends Form
|
||||
self::select('data_range', '数据权限')
|
||||
->placeholder('请选择数据权限')
|
||||
->options(
|
||||
self::options()->add('全部数据权限', Roles::ALL_DATA)
|
||||
self::options()->add('请选择数据权限', 0)
|
||||
->add('全部数据权限', Roles::ALL_DATA)
|
||||
->add('自定义数据权限', Roles::SELF_CHOOSE)
|
||||
->add('仅本人数据权限', Roles::SELF_DATA)
|
||||
->add('本部门数据权限', Roles::DEPARTMENT_DATA)
|
||||
|
105
catch/system/controller/Excel.php
Normal file
105
catch/system/controller/Excel.php
Normal file
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
namespace catchAdmin\system\controller;
|
||||
|
||||
use catcher\base\CatchController;
|
||||
use catcher\CatchResponse;
|
||||
use think\Request;
|
||||
|
||||
class Excel extends CatchController
|
||||
{
|
||||
/**
|
||||
* 导出
|
||||
*
|
||||
* @time 2021年04月22日
|
||||
* @param Request $request
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function export(Request $request): \think\response\Json
|
||||
{
|
||||
$fields = $this->resetFields(\json_decode($request->post('fields'), true));
|
||||
|
||||
$excel = app()->make($request->post('model'))
|
||||
->field(array_column($fields, 'field'))
|
||||
->select()
|
||||
->each(function (&$item, $key) use ($fields) {
|
||||
foreach ($fields as $field) {
|
||||
if (isset($field['options']) && count($field['options'])) {
|
||||
$options = $this->valueToLabel($field['options']);
|
||||
|
||||
$item[$field['field']] = $options[$item[$field['field']]] ?? '';
|
||||
}
|
||||
}
|
||||
})->export(array_column($fields, 'name'));
|
||||
|
||||
return CatchResponse::success($excel);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入
|
||||
*
|
||||
* @time 2021年04月23日
|
||||
* @param Request $request
|
||||
* @return \think\response\Json
|
||||
*/
|
||||
public function import(Request $request): \think\response\Json
|
||||
{
|
||||
return CatchResponse::success(app()->make($request->post('model'))
|
||||
->import(
|
||||
\json_decode($request->post('fields'), 'field'),
|
||||
$request->file('file')
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* value => label
|
||||
*
|
||||
* @time 2021年04月22日
|
||||
* @param array $options
|
||||
* @return array
|
||||
*/
|
||||
protected function valueToLabel(array $options): array
|
||||
{
|
||||
$p = [];
|
||||
foreach ($options as $option) {
|
||||
$p[$option['value']] = $option['label'];
|
||||
}
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
/**
|
||||
*label => value
|
||||
*
|
||||
* @time 2021年04月22日
|
||||
* @param array $options
|
||||
* @return array
|
||||
*/
|
||||
protected function labelToValue(array $options): array
|
||||
{
|
||||
$p = [];
|
||||
foreach ($options as $option) {
|
||||
$p[$option['label']] = $option['value'];
|
||||
}
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重组 fields
|
||||
*
|
||||
* @time 2021年04月22日
|
||||
* @param array $fields
|
||||
* @return array
|
||||
*/
|
||||
protected function resetFields(array $fields): array
|
||||
{
|
||||
$f = [];
|
||||
|
||||
foreach ($fields as $field) {
|
||||
$f[$field['field']] = $field;
|
||||
}
|
||||
|
||||
return $f;
|
||||
}
|
||||
}
|
@@ -48,6 +48,11 @@ $router->group(function () use ($router) {
|
||||
$router->put('modules/<module>', '\catchAdmin\system\controller\Module@disOrEnable');
|
||||
$router->put('cache/modules', '\catchAdmin\system\controller\Module@cache');
|
||||
$router->delete('clear/modules', '\catchAdmin\system\controller\Module@clear');
|
||||
|
||||
// excel 导入&导出通用
|
||||
$router->post('excel/export', '\catchAdmin\system\controller\Excel@export');
|
||||
$router->post('excel/import', '\catchAdmin\system\controller\Excel@import');
|
||||
|
||||
})->middleware('auth');
|
||||
|
||||
// 获取 table
|
||||
|
@@ -84,6 +84,21 @@ class CatchUpload
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传到 Local
|
||||
*
|
||||
* @time 2021年04月21日
|
||||
* @param $file
|
||||
* @return string
|
||||
*/
|
||||
public function toLocal($file): string
|
||||
{
|
||||
$path = Filesystem::disk(self::LOCAL)->putFile($this->getPath(), $file);
|
||||
|
||||
return public_path() . $this->getLocalPath($path);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 本地路径
|
||||
*
|
||||
@@ -91,7 +106,7 @@ class CatchUpload
|
||||
* @param $path
|
||||
* @return string
|
||||
*/
|
||||
protected function getLocalPath($path)
|
||||
protected function getLocalPath($path): string
|
||||
{
|
||||
if ($this->getDriver() === self::LOCAL) {
|
||||
|
||||
|
@@ -18,7 +18,7 @@ use catcher\traits\db\ScopeTrait;
|
||||
*/
|
||||
abstract class CatchModel extends \think\Model
|
||||
{
|
||||
use SoftDelete, TransTrait, BaseOptionsTrait, ScopeTrait, RewriteTrait;
|
||||
use SoftDelete, BaseOptionsTrait, ScopeTrait, RewriteTrait;
|
||||
|
||||
protected $createTime = 'created_at';
|
||||
|
||||
|
50
extend/catcher/library/excel/reader/Factory.php
Normal file
50
extend/catcher/library/excel/reader/Factory.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace catcher\library\excel\reader;
|
||||
|
||||
use catcher\exceptions\FailedException;
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Csv;
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Ods;
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Slk;
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
|
||||
use PhpOffice\PhpSpreadsheet\Reader\Xml;
|
||||
|
||||
class Factory
|
||||
{
|
||||
/**
|
||||
* make reader
|
||||
*
|
||||
* @time 2021年04月01日
|
||||
* @param $filename
|
||||
* @return mixed
|
||||
*/
|
||||
public static function make($filename)
|
||||
{
|
||||
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
|
||||
|
||||
if (isset(self::readers()[$ext])) {
|
||||
return app()->make(self::readers()[$ext]);
|
||||
}
|
||||
|
||||
throw new FailedException('Dont Support The File Extension');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* readers
|
||||
*
|
||||
* @time 2021年04月01日
|
||||
* @return string[]
|
||||
*/
|
||||
protected static function readers(): array
|
||||
{
|
||||
return [
|
||||
'xlsx' => Xlsx::class,
|
||||
'xml' => Xml::class,
|
||||
'ods' => Ods::class,
|
||||
'slk' => Slk::class,
|
||||
'csv' => Csv::class,
|
||||
];
|
||||
}
|
||||
}
|
64
extend/catcher/library/excel/reader/Macro.php
Normal file
64
extend/catcher/library/excel/reader/Macro.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace catcher\library\excel\reader;
|
||||
|
||||
trait Macro
|
||||
{
|
||||
/**
|
||||
* 移除不需要的列
|
||||
*
|
||||
* @time 2021年04月21日
|
||||
* @param ...$indexes
|
||||
* @return mixed
|
||||
*/
|
||||
public function remove(...$indexes)
|
||||
{
|
||||
foreach ($indexes as $index) {
|
||||
unset($this->sheets[$index]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置 memory
|
||||
*
|
||||
* @time 2021年04月21日
|
||||
* @param int $memory
|
||||
* @return mixed
|
||||
*/
|
||||
public function memory(int $memory)
|
||||
{
|
||||
ini_set('memory_limit', $memory . 'M');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理
|
||||
*
|
||||
* @time 2021年04月23日
|
||||
* @return array
|
||||
*/
|
||||
protected function dealWith(): array
|
||||
{
|
||||
$headers = $this->headers();
|
||||
|
||||
$data = [];
|
||||
|
||||
foreach ($this->sheets as &$sheet) {
|
||||
$d = [];
|
||||
foreach ($headers as $k => $header) {
|
||||
$d[$header] = method_exists($this, 'deal' . ucfirst($header)) ?
|
||||
|
||||
$this->{'deal' . ucfirst($header)}($sheet) : $sheet[$k];
|
||||
}
|
||||
|
||||
$data[] = $d;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
74
extend/catcher/library/excel/reader/Reader.php
Normal file
74
extend/catcher/library/excel/reader/Reader.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace catcher\library\excel\reader;
|
||||
|
||||
use catcher\CatchUpload;
|
||||
use PhpOffice\PhpSpreadsheet\Spreadsheet;
|
||||
|
||||
abstract class Reader
|
||||
{
|
||||
use Macro;
|
||||
|
||||
/**
|
||||
* 当前的 sheet
|
||||
*
|
||||
* false 代表获取全部 sheets
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $active = true;
|
||||
|
||||
|
||||
protected $sheets;
|
||||
|
||||
/**
|
||||
* 导入
|
||||
*
|
||||
* @time 2021年04月21日
|
||||
* @param $file
|
||||
* @return Reader
|
||||
*/
|
||||
public function import($file): Reader
|
||||
{
|
||||
$file = (new CatchUpload)->setPath('excel')->toLocal($file);
|
||||
|
||||
$reader = Factory::make($file);
|
||||
// 设置只读
|
||||
$reader->setReadDataOnly(true);
|
||||
|
||||
/* @var $spreadsheet Spreadsheet */
|
||||
$spreadsheet = $reader->load($file);
|
||||
|
||||
if ($this->active) {
|
||||
$this->sheets = $spreadsheet->getActiveSheet()->toArray();
|
||||
} else {
|
||||
foreach ($spreadsheet->getAllSheets() as $sheet) {
|
||||
$this->sheets[] = $sheet->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 必须实现的方法
|
||||
*
|
||||
* @time 2021年04月21日
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function headers();
|
||||
|
||||
|
||||
/**
|
||||
* 数据处理
|
||||
*
|
||||
* @time 2021年04月23日
|
||||
* @param callable $callback
|
||||
* @return mixed
|
||||
*/
|
||||
public function then(callable $callback)
|
||||
{
|
||||
return $callback($this->dealWith());
|
||||
}
|
||||
}
|
@@ -30,9 +30,9 @@ trait ComponentsTrait
|
||||
* @param null $updateFields
|
||||
* @return HeaderItem
|
||||
*/
|
||||
public function withSwitchComponent($updateFields = null): HeaderItem
|
||||
public function withSwitchComponent(array $options = [], $updateFields = null): HeaderItem
|
||||
{
|
||||
return $this->component('switch_', $updateFields ? : $this->attributes['prop']);
|
||||
return $this->component('switch_', $updateFields ? : $this->attributes['prop'], $options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
109
extend/catcher/library/table/Excel.php
Normal file
109
extend/catcher/library/table/Excel.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
namespace catcher\library\table;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2021年04月21日
|
||||
*/
|
||||
class Excel
|
||||
{
|
||||
protected static $label;
|
||||
|
||||
protected $sheets = [];
|
||||
|
||||
/**
|
||||
* name
|
||||
*
|
||||
* @time 2021年04月21日
|
||||
* @param string $name
|
||||
* @return $this
|
||||
*/
|
||||
public function prop(string $name): Excel
|
||||
{
|
||||
$this->sheets['prop'] = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* label
|
||||
*
|
||||
* @time 2021年04月21日
|
||||
* @param string $label
|
||||
* @return $this
|
||||
*/
|
||||
protected function label(string $label): Excel
|
||||
{
|
||||
$this->sheets['label'] = $label;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* options
|
||||
*
|
||||
* @time 2021年04月21日
|
||||
* @param array $options
|
||||
* @return $this
|
||||
*/
|
||||
public function options(array $options): Excel
|
||||
{
|
||||
$this->sheets['options'] = $options;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入
|
||||
*
|
||||
* @time 2021年04月22日
|
||||
* @param bool $import
|
||||
* @return $this
|
||||
*/
|
||||
public function import(bool $import = true): Excel
|
||||
{
|
||||
$this->sheets['import'] = $import;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出
|
||||
*
|
||||
* @time 2021年04月22日
|
||||
* @param bool $export
|
||||
* @return $this
|
||||
*/
|
||||
public function export(bool $export = true): Excel
|
||||
{
|
||||
$this->sheets['export'] = $export;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 渲染
|
||||
*
|
||||
* @time 2021年04月21日
|
||||
* @return array
|
||||
*/
|
||||
public function render(): array
|
||||
{
|
||||
return $this->sheets;
|
||||
}
|
||||
|
||||
/**
|
||||
* 静态访问
|
||||
*
|
||||
* @time 2021年04月21日
|
||||
* @param $method
|
||||
* @param $params
|
||||
* @return false|mixed
|
||||
*/
|
||||
public static function __callStatic($method, $params)
|
||||
{
|
||||
return call_user_func_array([new self(), $method], $params);
|
||||
}
|
||||
}
|
@@ -73,6 +73,31 @@ class HeaderItem
|
||||
return $this->width(50)->type('selection');
|
||||
}
|
||||
|
||||
/**
|
||||
* dont export
|
||||
*
|
||||
* @time 2021年04月22日
|
||||
* @return $this
|
||||
*/
|
||||
public function dontExport(): HeaderItem
|
||||
{
|
||||
$this->attributes['export'] = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* dont import
|
||||
*
|
||||
* @time 2021年04月22日
|
||||
* @return $this
|
||||
*/
|
||||
public function dontImport(): HeaderItem
|
||||
{
|
||||
$this->attributes['import'] = false;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态访问
|
||||
|
@@ -98,6 +98,21 @@ class Table
|
||||
*/
|
||||
protected $forceUpdate = false;
|
||||
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $excel = [];
|
||||
|
||||
|
||||
/**
|
||||
* 导出 excel 所使用 model
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $usedModel;
|
||||
|
||||
|
||||
/**
|
||||
* Table constructor.
|
||||
* @param string $ref
|
||||
@@ -167,6 +182,25 @@ class Table
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* excel 信息
|
||||
*
|
||||
* @time 2021年04月21日
|
||||
* @param array $excel
|
||||
* @param string $usedModel
|
||||
* @return $this
|
||||
*/
|
||||
public function withUsedModelAndExcel(string $usedModel, array $excel): Table
|
||||
{
|
||||
foreach ($excel as $e) {
|
||||
$this->excel[] = $e->render();
|
||||
}
|
||||
|
||||
$this->usedModel = $usedModel;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* set
|
||||
*
|
||||
|
@@ -3,6 +3,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace catcher\traits\db;
|
||||
|
||||
use catcher\library\excel\reader\Reader;
|
||||
use catcher\Utils;
|
||||
|
||||
trait BaseOptionsTrait
|
||||
@@ -221,4 +222,55 @@ trait BaseOptionsTrait
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
public function import($fields, $file)
|
||||
{
|
||||
$excel = new class(array_column($fields, 'field')) extends Reader {
|
||||
|
||||
protected $fields;
|
||||
|
||||
public function __construct($fields)
|
||||
{
|
||||
$this->fields = $fields;
|
||||
}
|
||||
|
||||
public function headers()
|
||||
{
|
||||
// TODO: Implement headers() method.
|
||||
return $this->fields;
|
||||
}
|
||||
};
|
||||
|
||||
$options = [];
|
||||
foreach ($fields as $field) {
|
||||
$p = [];
|
||||
if (isset($field['options']) && count($field['options'])) {
|
||||
foreach ($field['options'] as $op) {
|
||||
$p[$op['label']] = $op['value'];
|
||||
}
|
||||
$options[$field['field']] = $p;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
$creatorId = request()->user()->id;
|
||||
|
||||
$excel->import($file)->remove(0)->then(function ($data) use ($options, $creatorId){
|
||||
foreach ($data as &$d) {
|
||||
foreach ($d as $field => &$v) {
|
||||
if (isset($options[$field])) {
|
||||
$v = $options[$field][$v];
|
||||
}
|
||||
}
|
||||
|
||||
$d['creator_id'] = $creatorId;
|
||||
|
||||
$this->createBy($d);
|
||||
}
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -1,50 +0,0 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace catcher\traits\db;
|
||||
|
||||
use think\facade\Db;
|
||||
|
||||
trait TransTrait
|
||||
{
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @return void
|
||||
*/
|
||||
public function startTrans()
|
||||
{
|
||||
Db::startTrans();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @return void
|
||||
*/
|
||||
public function commit()
|
||||
{
|
||||
Db::commit();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @return void
|
||||
*/
|
||||
public function rollback()
|
||||
{
|
||||
Db::rollback();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @time 2019年12月03日
|
||||
* @param \Closure $function
|
||||
* @return void
|
||||
*/
|
||||
public function transaction(\Closure $function)
|
||||
{
|
||||
Db::transaction($function());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user