diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php index 18159056b95479836c2ce98503b85fb6e14a6aa4..8489955c3836f23711a330d583876d0f1a4af01e 100644 --- a/app/Http/Middleware/VerifyCsrfToken.php +++ b/app/Http/Middleware/VerifyCsrfToken.php @@ -12,6 +12,6 @@ class VerifyCsrfToken extends Middleware * @var array */ protected $except = [ - 'admin/*' + '*' ]; } diff --git a/app/Library/cpu_usage.vbs b/app/Library/cpu_usage.vbs new file mode 100644 index 0000000000000000000000000000000000000000..60a7bddb9421ae21e1131e4482d83637a4897853 --- /dev/null +++ b/app/Library/cpu_usage.vbs @@ -0,0 +1,3 @@ +On Error Resume Next + Set objProc = GetObject("winmgmts:\\.\root\cimv2:win32_processor='cpu0'") + WScript.Echo(objProc.LoadPercentage) \ No newline at end of file diff --git a/app/Library/memory_usage.vbs b/app/Library/memory_usage.vbs new file mode 100644 index 0000000000000000000000000000000000000000..4c4218f308656747c35bb246896630c714f99d69 --- /dev/null +++ b/app/Library/memory_usage.vbs @@ -0,0 +1,6 @@ +On Error Resume Next + Set objWMI = GetObject("winmgmts:\\.\root\cimv2") + Set colOS = objWMI.InstancesOf("Win32_OperatingSystem") + For Each objOS in colOS + Wscript.Echo("{""TotalVisibleMemorySize"":" & objOS.TotalVisibleMemorySize & ",""FreePhysicalMemory"":" & objOS.FreePhysicalMemory & "}") + Next \ No newline at end of file diff --git a/app/Models/UploadFile.php b/app/Models/UploadFile.php new file mode 100644 index 0000000000000000000000000000000000000000..6d20137ede0dd76e311ce192334d25955ce7a78f --- /dev/null +++ b/app/Models/UploadFile.php @@ -0,0 +1,22 @@ +attributes['storage'] == 'local'){ + return Storage::url($this->attributes['file_name']); + // return env('APP_URL') . '/' . trim($this->attributes['file_name'],'/'); + } + return $this->attributes['host_url'] . '/' . trim($this->attributes['file_name'],'/'); + } +} diff --git a/app/Models/UploadGroup.php b/app/Models/UploadGroup.php new file mode 100644 index 0000000000000000000000000000000000000000..5a77d424b4f901cc8c4bb9b086c7762412821caa --- /dev/null +++ b/app/Models/UploadGroup.php @@ -0,0 +1,9 @@ +attributes['article_images'] = implode(',', $article_images); + } + } + public function category() { return $this->hasOne(ArticleCategory::class, 'category_id', 'category_id'); diff --git a/app/Modules/Admin/Http/Controllers/FileController.php b/app/Modules/Admin/Http/Controllers/FileController.php new file mode 100644 index 0000000000000000000000000000000000000000..740952397c10362076e80bb86d85c6886b312d61 --- /dev/null +++ b/app/Modules/Admin/Http/Controllers/FileController.php @@ -0,0 +1,30 @@ +service = $fileService; + } + + /** + * 移动文件至指定分组 + * + * @param \Illuminate\Http\Request $request + * + * @return \Illuminate\Http\JsonResponse + */ + public function removeFileGroup(Request $request) + { + if ($this->service->removeFileGroup($request->all())){ + return $this->successJson([], $this->service->getError()); + }else{ + return $this->errorJson($this->service->getError()); + } + } +} diff --git a/app/Modules/Admin/Http/Controllers/FileGroupController.php b/app/Modules/Admin/Http/Controllers/FileGroupController.php new file mode 100644 index 0000000000000000000000000000000000000000..d6267e6fb1bbd6fc56d40af8596d601e74df8fbe --- /dev/null +++ b/app/Modules/Admin/Http/Controllers/FileGroupController.php @@ -0,0 +1,24 @@ +service = $fileGroupService; + } + + public function create(FileGroupRequest $request) + { + return $this->createService($request); + } + + public function update(FileGroupRequest $request) + { + return $this->updateService($request); + } +} diff --git a/app/Modules/Admin/Http/Controllers/UploadController.php b/app/Modules/Admin/Http/Controllers/UploadController.php index 5277dc1110d46c53bb99f80ce692b5aa81b8ebc9..ac287ffdf8c74951d30b03d0402b906ac37c28e7 100644 --- a/app/Modules/Admin/Http/Controllers/UploadController.php +++ b/app/Modules/Admin/Http/Controllers/UploadController.php @@ -2,8 +2,8 @@ namespace App\Modules\Admin\Http\Controllers; +use App\Models\UploadFile; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Storage; class UploadController extends BaseController { @@ -21,11 +21,44 @@ class UploadController extends BaseController return $this->errorJson('请上传文件!'); } + // var_dump($request->file($file)->getClientOriginalExtension()); + // var_dump($request->file($file)->getMimeType()); + // var_dump($request->file($file)->getType()); + // var_dump($request->file($file)->getClientMimeType()); + // exit; + $path = $request->file($file)->storePublicly( date('Ym'), config('filesystems') ); - return $this->successJson($path, '上传成功', ['path_url' => Storage::url($path)]); + // 添加文件库记录 + $uploadFile = $this->addUploadFile($path, $request->file($file)); + + return $this->successJson($path, '上传成功', ['file_url' => $uploadFile->file_url]); + } + + /** + * 添加文件库上传记录 + * @param $fileName + * @param $fileInfo + * @param $fileType + * @return UploadFile + */ + private function addUploadFile($file_name, $file) + { + // 存储引擎 + $storage = 'local'; + // 存储域名 + $host_url = ''; + // 添加文件库记录 + return UploadFile::create([ + 'storage' => $storage, + 'host_url' => $host_url, + 'file_name' => $file_name, + 'file_size' => $file->getSize(), + 'file_type' => $file->getMimeType(), + 'extension' => $file->getClientOriginalExtension(), + ]); } } diff --git a/app/Modules/Admin/Http/Middleware/CheckAuth.php b/app/Modules/Admin/Http/Middleware/CheckAuth.php index eaf612d3de013aff8d33edcb46e4d13316e8ccdc..70e822d97356663c1cf795d3beed6c198e8082de 100644 --- a/app/Modules/Admin/Http/Middleware/CheckAuth.php +++ b/app/Modules/Admin/Http/Middleware/CheckAuth.php @@ -29,7 +29,7 @@ class CheckAuth $auth = Auth()->guard($this->guard); try { if ( !$auth->check() ) { //未登录踢回,给予错误返回提示 - return $this->errorJson('认证失败,请重新登录!'); + return $this->errorJson('认证失败,请重新登录!', -1); } } catch (TokenExpiredException $e) { return $this->errorJson($e->getMessage()); diff --git a/app/Modules/Admin/Http/Requests/Article/ArticleRequest.php b/app/Modules/Admin/Http/Requests/Article/ArticleRequest.php index 8336bf2cb7fd6966c0c69789bc98a6c6f5d0ef8e..88fc05eada52d6abf0ef9ecdf91a0a8993a05196 100644 --- a/app/Modules/Admin/Http/Requests/Article/ArticleRequest.php +++ b/app/Modules/Admin/Http/Requests/Article/ArticleRequest.php @@ -28,9 +28,9 @@ class ArticleRequest extends BaseRequest 'category_id' => [ 'required', ], - 'article_cover' => [ - 'required', - ], + // 'article_image' => [ + // 'required', + // ], ]; } diff --git a/app/Modules/Admin/Http/Requests/FileGroupRequest.php b/app/Modules/Admin/Http/Requests/FileGroupRequest.php new file mode 100644 index 0000000000000000000000000000000000000000..4ed9ed1f4abf4a8cc13becae9924efbee49d0f14 --- /dev/null +++ b/app/Modules/Admin/Http/Requests/FileGroupRequest.php @@ -0,0 +1,38 @@ +instance = UploadGroup::getInstance(); + } + + /** + * Get the validation rules that apply to the request. + * + * @return array + */ + public function rules() + { + return [ + 'group_name' => [ + 'required', + 'max:256', + 'unique:' . $this->instance->getTable() . ',group_name' . $this->validate_id + ], + ]; + } + + public function messages() + { + return [ + 'group_name.required' => '请输入分组名称!', + 'group_name.max' => '分组名称字数不可超过 256!', + 'group_name.unique' => '分组名称已存在,请更换!', + ]; + } +} diff --git a/app/Modules/Admin/Resources/vue-element-admin/App.vue b/app/Modules/Admin/Resources/vue-element-admin/App.vue index ec9032c1c638e918ec97e413aa081993a95048f4..6aeab527a3339f30e0d4767e93292de47ee8aeec 100644 --- a/app/Modules/Admin/Resources/vue-element-admin/App.vue +++ b/app/Modules/Admin/Resources/vue-element-admin/App.vue @@ -9,3 +9,13 @@ export default { name: 'App' } + diff --git a/app/Modules/Admin/Resources/vue-element-admin/api/file_groups.js b/app/Modules/Admin/Resources/vue-element-admin/api/file_groups.js new file mode 100644 index 0000000000000000000000000000000000000000..55026c60c485f0cf80f553d03216266ac3f96aa5 --- /dev/null +++ b/app/Modules/Admin/Resources/vue-element-admin/api/file_groups.js @@ -0,0 +1,36 @@ +import request from '@/utils/request' + +// 文件列表 +export function getFileGroup(params) { + return request({ + url: '/getGroupList', + method: 'get', + params + }) +} + +export function create(data) { + return request({ + url: '/fileGroup/create', + method: 'post', + data + }); +} + +export function update(data) { + return request({ + url: '/fileGroup/update', + method: 'put', + data + }); +} + +export function delFileGroup(data) { + return request({ + url: `/fileGroup/delete`, + method: 'delete', + data + }) +} + + diff --git a/app/Modules/Admin/Resources/vue-element-admin/api/files.js b/app/Modules/Admin/Resources/vue-element-admin/api/files.js new file mode 100644 index 0000000000000000000000000000000000000000..73264db23acd57b8762df22bd7559a91c0ea233e --- /dev/null +++ b/app/Modules/Admin/Resources/vue-element-admin/api/files.js @@ -0,0 +1,26 @@ +import request from '@/utils/request' + +// 文件列表 +export function getFileList(params) { + return request({ + url: '/getFileList', + method: 'get', + params + }) +} + +export function delFile(data) { + return request({ + url: `/files/delete`, + method: 'delete', + data + }) +} + +export function removeFileGroup(data) { + return request({ + url: '/files/removeFileGroup', + method: 'put', + data + }); +} diff --git a/app/Modules/Admin/Resources/vue-element-admin/components/FilesSelect/index.vue b/app/Modules/Admin/Resources/vue-element-admin/components/FilesSelect/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..bf63e943b89d93088d17443d05ff01c20c147d1b --- /dev/null +++ b/app/Modules/Admin/Resources/vue-element-admin/components/FilesSelect/index.vue @@ -0,0 +1,550 @@ + + + + 新建分组 + 编辑分组 + 删除分组 + + + + + + + + + + + + + + 搜索 + + + + 上传 + + + + + + + + + + {{ item.file_name }} + + + + + + + 已选择{{ selectedIndexs.length }}项 + + 删除 + 移动至: + + + + + + + + + + + + + + 取消 + 确定 + + + + + + diff --git a/app/Modules/Admin/Resources/vue-element-admin/layout/components/Sidebar/Item.vue b/app/Modules/Admin/Resources/vue-element-admin/layout/components/Sidebar/Item.vue index aa1f5da4de23482ad3fdb4a0d8d07772117ecd36..4edf6b4c41c08ed1fabcca158a2dccf8de80f994 100644 --- a/app/Modules/Admin/Resources/vue-element-admin/layout/components/Sidebar/Item.vue +++ b/app/Modules/Admin/Resources/vue-element-admin/layout/components/Sidebar/Item.vue @@ -17,11 +17,13 @@ export default { const vnodes = [] if (icon) { - if (icon.includes('el-icon')) { - vnodes.push() - } else { - vnodes.push() - } + if (icon.includes('el-icon')) { + vnodes.push() + } else if (icon.includes('fa fa-')) { // 支持fontAwesome图标左侧栏目展示 + vnodes.push() + } else { + vnodes.push() + } } if (title) { diff --git a/app/Modules/Admin/Resources/vue-element-admin/main.js b/app/Modules/Admin/Resources/vue-element-admin/main.js index 5ba947f4fa8ae74d32f1c55838f41d6f1acfaa28..6329e1d08cdafcdf94d4467d5d7c311b8ff91036 100644 --- a/app/Modules/Admin/Resources/vue-element-admin/main.js +++ b/app/Modules/Admin/Resources/vue-element-admin/main.js @@ -47,6 +47,25 @@ Object.keys(filters).forEach(key => { Vue.config.productionTip = false + +// 图标选择器 +import eIconPicker, {iconList} from 'e-icon-picker'; +import "e-icon-picker/lib/symbol.js"; //基本彩色图标库 +import 'e-icon-picker/lib/index.css'; // 基本样式,包含基本图标 +import 'font-awesome/css/font-awesome.min.css'; //font-awesome 图标库 +import 'element-ui/lib/theme-chalk/icon.css'; //element-ui 图标库 +//全局删除增加图标 +Vue.use(eIconPicker, { + FontAwesome: true, + ElementUI: true, + eIcon: true,//自带的图标,来自阿里 + eIconSymbol: true,//是否开启彩色图标 + addIconList: [], + removeIconList: [] +}); + + + new Vue({ el: '#app', router, diff --git a/app/Modules/Admin/Resources/vue-element-admin/router/index.js b/app/Modules/Admin/Resources/vue-element-admin/router/index.js index 3ffbeb32346f807ff8c6d2615eb8662cabf39cb7..0143bc473641d0773b0d18c452b07ec9fa0eaf97 100644 --- a/app/Modules/Admin/Resources/vue-element-admin/router/index.js +++ b/app/Modules/Admin/Resources/vue-element-admin/router/index.js @@ -7,8 +7,8 @@ Vue.use(Router) import Layout from '@/layout' /* Router Modules */ -import componentsRouter from './modules/components' -import chartsRouter from './modules/charts' +// import componentsRouter from './modules/components' +// import chartsRouter from './modules/charts' /** * Note: sub-menu only appear when route children.length >= 1 @@ -108,8 +108,8 @@ export const constantRoutes = [ ] }, - componentsRouter, - chartsRouter + // componentsRouter, + // chartsRouter ]; diff --git a/app/Modules/Admin/Resources/vue-element-admin/views/admin_menus/components/detail.vue b/app/Modules/Admin/Resources/vue-element-admin/views/admin_menus/components/detail.vue index 328f7ad402957e57589851c821f5cff0b1e67754..d03a3e07a8adb518a013b4d0fd16069e0a7fb303 100644 --- a/app/Modules/Admin/Resources/vue-element-admin/views/admin_menus/components/detail.vue +++ b/app/Modules/Admin/Resources/vue-element-admin/views/admin_menus/components/detail.vue @@ -32,7 +32,7 @@ - + diff --git a/app/Modules/Admin/Resources/vue-element-admin/views/articles/components/ArticleDetail.vue b/app/Modules/Admin/Resources/vue-element-admin/views/articles/components/ArticleDetail.vue index 75242b801fe594592358f237207080929a814c71..f477f7b893f23ac4bcb77257fb56ec95fb04c559 100644 --- a/app/Modules/Admin/Resources/vue-element-admin/views/articles/components/ArticleDetail.vue +++ b/app/Modules/Admin/Resources/vue-element-admin/views/articles/components/ArticleDetail.vue @@ -23,7 +23,8 @@ @clear="handleClear" ref="selectUpCategoryId" > - + - - + + + - 文章封面 + 选择图标 - - @@ -90,7 +84,7 @@ 文章内容: - + @@ -128,6 +122,7 @@ + @@ -144,6 +139,7 @@ import {detail, create, update} from '@/api/articles' import {getCategorySelect} from "@/api/article_categories"; import {getArticleLabelSelect} from "@/api/article_labels"; + import FileSelect from '@/components/FilesSelect/index' const defaultForm = { article_id: 0, @@ -152,23 +148,27 @@ article_content: '', // 文章内容 article_keywords: '', // 关键字 article_description: '', // 文章摘要 - article_cover: '', // 封面图 + // article_cover: '', // 封面图 + article_images: [], // 多图 article_link: '', // 文章外链 article_sort: 99, // 排序 - set_top:0, // 是否置顶 - is_recommend:0, // 是否推荐 - is_public:0, // 是否公开 - article_origin:'', // 文章来源 - article_author:'', // 文章作者 + set_top: 0, // 是否置顶 + is_recommend: 0, // 是否推荐 + is_public: 0, // 是否公开 + article_origin: '', // 文章来源 + article_author: '', // 文章作者 label_ids: [], // 文章标签 }; export default { name: 'ArticleDetail', - components: {MDinput, Sticky, SourceUrlDropdown, - 'my-upload': myUpload, + components: { + MDinput, + Sticky, + SourceUrlDropdown, PanThumb, - MarkdownEditor + MarkdownEditor, + FileSelect }, props: { isEdit: { @@ -211,30 +211,40 @@ rules: { article_title: [{validator: validateRequire}], category_id: [{validator: validateRequire}], - article_cover: [{validator: validateRequire}], + // article_cover: [{validator: validateRequire}], article_content: [{validator: validateRequire}], article_link: [{validator: validateSourceUri, trigger: 'blur'}] }, tempRoute: {}, - // 图片上传 - show: false, - size: 2.1, // 图片上传 upload_url: '', - image_url: '', - borderRadius:'initial', + show_files: false, + + borderRadius: 'initial', labels: [], // 标签 - checkCategories:[], // 默认选中的分类 - default_select_category_name : '请选择文章分类', + checkCategories: [], // 默认选中的分类 + default_select_category_name: '请选择文章分类', select_category_name: '请选择文章分类', - category:[], // 分类 + category: [], // 分类 defaultProps: { children: '_child', label: 'category_name' }, + + + // 多图的数量 + image_limit:3, + // 测试 + filesList: [], + + dialogImageUrl: '', + dialogVisible: false, + dialogImageUrl: '', + dialogVisible: false, + disabled: false } }, computed: { @@ -250,27 +260,27 @@ // 因为下拉tree是需要先获取数据,进行数据对比,拿到当前选中的值,所以需要:获取文章详情之后,再去获取文章分类。 if (this.isEdit) { const article_id = this.$route.query && this.$route.query.article_id; - if (article_id > 0){ + if (article_id > 0) { this.getDetail(article_id, function () { // 文章分类列表 _this.getCategorySelect(function () { - try{ + try { _this.category.forEach(item => { - if(item.category_id == _this.postForm.category_id){ + if (item.category_id == _this.postForm.category_id) { _this.select_category_name = item.category_name; throw new Error("end……对比成功");//报错,就跳出循环 } }); - }catch (e) { + } catch (e) { // console.log(e); } }); }); - }else{ + } else { // 文章分类列表 this.getCategorySelect(); } - }else{ + } else { // 文章分类列表 this.getCategorySelect(); } @@ -286,8 +296,55 @@ this.getArticleLabelSelect(); }, methods: { + handleRemove(file) { + console.log(file); + }, + handlePictureCardPreview(file) { + this.dialogImageUrl = file.url; + this.dialogVisible = true; + }, + handleDownload(file) { + console.log(file); + }, + + + + + + + + + + + + + // 打开文件选择器 + openSelectFiles() { + this.show_files = true; + this.$nextTick(() => { + this.$refs.file.init(); + }); + }, + // 选择指定文件之后,点击’确认‘,获取到的文件信息 + selectImageSubmit(e) { + let val; + for (var i = 0; i < e.length; i++) { + val = e[i]; + this.postForm.article_images.push(val.file_url); + this.filesList.push({ + 'name': val.file_name, + 'url': val.file_url, + }); + } + + // 验证文件数量 + if (this.postForm.article_images.length > this.image_limit){ + this.postForm.article_images = this.postForm.article_images.slice(this.postForm.article_images.length - this.image_limit); + this.filesList = this.filesList.slice(this.filesList.length - this.image_limit); + } + }, // 获取文章标签列表 - async getArticleLabelSelect(){ + async getArticleLabelSelect() { const res = await getArticleLabelSelect(); this.labels = res.data; }, @@ -298,16 +355,22 @@ if (callback) callback(); - // 默认展示的封面图 - this.image_url = this.postForm.article_cover; - - if (this.postForm.labels){ + if (this.postForm.labels) { this.postForm.label_ids = []; for (const key in this.postForm.labels) { this.postForm.label_ids.push(this.postForm.labels[key].label_id); } } + // 多图 + for (var i = 0; i < this.postForm.article_images.length; i++) { + this.filesList.push({ + 'name': this.postForm.article_images[i], + 'url': this.postForm.article_images[i], + }); + } + console.log(this.filesList); + // 选中的分类 this.checkCategories.push(this.postForm.category_id); @@ -353,7 +416,7 @@ this.loading = true; const {msg, status} = this.postForm.article_id > 0 ? await update(this.postForm) : await create(this.postForm); - if (status == 1){ + if (status == 1) { this.$notify({ title: '成功', message: this.postForm.article_id > 0 ? '编辑文章成功' : '发布文章成功', @@ -363,7 +426,7 @@ // 返回文章列表 this.$router.push(`/articles`); - }else{ + } else { this.$message({ message: msg, type: 'error', @@ -377,19 +440,6 @@ } }) }, - cropSuccess(imgDataUrl, field) { - // console.log('-------- crop success --------', imgDataUrl, field); - }, - // 上传成功回调 - cropUploadSuccess(result, field) { - this.image_url = result.path_url; - this.postForm.article_cover = result.data; - }, - // 上传失败回调 - cropUploadFail(status, field) { - // console.log('上传失败状态' + status); - // console.log('field: ' + field); - }, } } @@ -401,7 +451,7 @@ position: relative; .el-form { - .el-form-item{ + .el-form-item { margin-bottom: 40px; } } diff --git a/app/Modules/Admin/Resources/vue-element-admin/views/articles/index.vue b/app/Modules/Admin/Resources/vue-element-admin/views/articles/index.vue index 75e2545a406d08ce443489cf0f71c1ca0e5ce129..d6ac117b65bcf44ba3bb73a7ee8c662424da0136 100644 --- a/app/Modules/Admin/Resources/vue-element-admin/views/articles/index.vue +++ b/app/Modules/Admin/Resources/vue-element-admin/views/articles/index.vue @@ -87,7 +87,7 @@ - + @@ -454,6 +454,9 @@
{{ item.file_name }}