File.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. <?php
  2. namespace Dcat\Admin\Form\Field;
  3. use Dcat\Admin\Contracts\UploadField as UploadFieldInterface;
  4. use Dcat\Admin\Form\Field;
  5. use Dcat\Admin\Support\Helper;
  6. use Dcat\Admin\Support\JavaScript;
  7. use Illuminate\Support\Arr;
  8. use Illuminate\Support\Facades\Validator;
  9. use Illuminate\Support\Str;
  10. class File extends Field implements UploadFieldInterface
  11. {
  12. use WebUploader, UploadField;
  13. protected static $css = [
  14. '@webuploader',
  15. ];
  16. protected static $js = [
  17. '@webuploader',
  18. ];
  19. protected $containerId;
  20. protected $relationName;
  21. /**
  22. * @param string $column
  23. * @param array $arguments
  24. */
  25. public function __construct($column, $arguments = [])
  26. {
  27. parent::__construct($column, $arguments);
  28. $this->setupDefaultOptions();
  29. $this->containerId = $this->generateId();
  30. }
  31. /**
  32. * @return mixed
  33. */
  34. public function defaultDirectory()
  35. {
  36. return config('admin.upload.directory.file');
  37. }
  38. /**
  39. * {@inheritdoc}
  40. */
  41. public function getValidator(array $input)
  42. {
  43. if (request()->has(static::FILE_DELETE_FLAG)) {
  44. return false;
  45. }
  46. if ($this->validator) {
  47. return $this->validator->call($this, $input);
  48. }
  49. $value = Arr::get($input, $this->column);
  50. $value = array_filter(is_array($value) ? $value : explode(',', $value));
  51. $fileLimit = $this->options['fileNumLimit'] ?? 1;
  52. if ($fileLimit < count($value)) {
  53. $this->form->responseValidationMessages(
  54. $this->column,
  55. trans('admin.uploader.max_file_limit', ['attribute' => $this->label, 'max' => $fileLimit])
  56. );
  57. return false;
  58. }
  59. $rules = $attributes = [];
  60. if (! $this->hasRule('required')) {
  61. return false;
  62. }
  63. $rules[$this->column] = 'required';
  64. $attributes[$this->column] = $this->label;
  65. return Validator::make($input, $rules, $this->getValidationMessages(), $attributes);
  66. }
  67. /**
  68. * @param string $file
  69. *
  70. * @return mixed|string
  71. */
  72. protected function prepareInputValue($file)
  73. {
  74. if (request()->has(static::FILE_DELETE_FLAG)) {
  75. return $this->destroy();
  76. }
  77. $this->destroyIfChanged($file);
  78. return $file;
  79. }
  80. /**
  81. * 设置字段的关联关系(在一/多对多表单中使用).
  82. *
  83. * @param string|null $name
  84. *
  85. * @return $this
  86. */
  87. public function setRelation(?string $name)
  88. {
  89. $this->relationName = $name;
  90. $this->options['formData']['upload_column'] = $name.'.'.$this->column();
  91. return $this;
  92. }
  93. /**
  94. * @return mixed
  95. */
  96. public function getRelation()
  97. {
  98. return $this->relationName;
  99. }
  100. /**
  101. * Set field as disabled.
  102. *
  103. * @return $this
  104. */
  105. public function disable()
  106. {
  107. $this->options['disabled'] = true;
  108. return $this;
  109. }
  110. protected function formatFieldData($data)
  111. {
  112. return Helper::array(Arr::get($data, $this->column));
  113. }
  114. /**
  115. * @return array
  116. */
  117. protected function initialPreviewConfig()
  118. {
  119. $previews = [];
  120. foreach ($this->value() as $value) {
  121. $previews[] = [
  122. 'id' => $value,
  123. 'path' => basename($value),
  124. 'url' => $this->objectUrl($value),
  125. ];
  126. }
  127. return $previews;
  128. }
  129. protected function forceOptions()
  130. {
  131. $this->options['fileNumLimit'] = 1;
  132. }
  133. /**
  134. * @return string
  135. */
  136. public function render()
  137. {
  138. $this->setDefaultServer();
  139. if (! empty($this->value())) {
  140. $this->setupPreviewOptions();
  141. }
  142. $this->forceOptions();
  143. $this->formatValue();
  144. $this->setupScript();
  145. $this->addVariables([
  146. 'fileType' => $this->options['isImage'] ? '' : 'file',
  147. 'containerId' => $this->containerId,
  148. ]);
  149. return parent::render();
  150. }
  151. protected function setupScript()
  152. {
  153. $newButton = trans('admin.uploader.add_new_media');
  154. $options = JavaScript::format($this->options);
  155. $this->script = <<<JS
  156. (function () {
  157. var upload, options = {$options}, listenComplete;
  158. build();
  159. function build() {
  160. var opts = $.extend({
  161. selector: '#{$this->containerId}',
  162. addFileButton: '#{$this->containerId} .add-file-button',
  163. }, options);
  164. opts.upload = $.extend({
  165. pick: {
  166. id: '#{$this->containerId} .file-picker',
  167. label: '<i class="feather icon-folder"></i>&nbsp; {$newButton}'
  168. },
  169. dnd: '#{$this->containerId} .dnd-area',
  170. paste: '#{$this->containerId} .web-uploader'
  171. }, opts);
  172. upload = Dcat.Uploader(opts);
  173. upload.build();
  174. upload.preview();
  175. function resize() {
  176. setTimeout(function () {
  177. if (! upload) return;
  178. upload.refreshButton();
  179. resize();
  180. if (! listenComplete) {
  181. listenComplete = 1;
  182. $(document).one('pjax:complete', function () {
  183. upload = null;
  184. });
  185. }
  186. }, 250);
  187. }
  188. resize();
  189. }
  190. })();
  191. JS;
  192. }
  193. /**
  194. * @return void
  195. */
  196. protected function formatValue()
  197. {
  198. if ($this->value !== null) {
  199. $this->value = implode(',', $this->value);
  200. } elseif (is_array($this->default)) {
  201. $this->default = implode(',', $this->default);
  202. }
  203. }
  204. /**
  205. * @return string
  206. */
  207. protected function generateId()
  208. {
  209. return 'file-'.Str::random(8);
  210. }
  211. }