diff --git a/app/assets/javascripts/admins/carousels/index.js b/app/assets/javascripts/admins/carousels/index.js new file mode 100644 index 000000000..0f279f17e --- /dev/null +++ b/app/assets/javascripts/admins/carousels/index.js @@ -0,0 +1,125 @@ +$(document).on('turbolinks:load', function() { + if ($('body.admins-carousels-index-page').length > 0) { + // ------------ 保存链接 ----------- + $('.carousels-card').on('click', '.save-data-btn', function(){ + var $link = $(this); + var id = $link.data('id'); + var link = $('.custom-carousel-item-' + id).find('.link-input').val(); + var name = $('.custom-carousel-item-' + id).find('.name-input').val(); + if(!name || name.length == 0){ + $.notify({ message: '名称不能为空' },{ type: 'danger' }); + return; + } + $link.attr('disabled', true); + + $.ajax({ + url: '/admins/carousels/' + id, + method: 'PATCH', + dataType: 'json', + data: { link: link, name: name }, + success: function(data){ + $.notify({ message: '操作成功' }); + }, + error: ajaxErrorNotifyHandler, + complete: function(){ + $link.removeAttr('disabled'); + } + }) + }); + // -------------- 是否在首页展示 -------------- + $('.carousels-card').on('change', '.online-check-box', function(){ + var $checkbox = $(this); + var id = $checkbox.data('id'); + var checked = $checkbox.is(':checked'); + $checkbox.attr('disabled', true); + + $.ajax({ + url: '/admins/carousels/' + id, + method: 'PATCH', + dataType: 'json', + data: { status: checked }, + success: function(data){ + $.notify({ message: '保存成功' }); + var box = $('.custom-carousel-item-' + id).find('.drag'); + if(checked){ + box.removeClass('not_active'); + }else{ + box.addClass('not_active'); + } + }, + error: ajaxErrorNotifyHandler, + complete: function(){ + $checkbox.removeAttr('disabled'); + } + }) + }); + + // ------------ 拖拽 ------------- + var onDropFunc = function(el, _target, _source, sibling){ + var moveId = $(el).data('id'); + var insertId = $(sibling).data('id') || ''; + + $.ajax({ + url: '/admins/carousels/drag', + method: 'POST', + dataType: 'json', + data: { move_id: moveId, after_id: insertId }, + success: function(data){ + $('#carousels-container .custom-carousel-item-no').each(function(index, ele){ + $(ele).html(index + 1); + }) + }, + error: function(res){ + var data = res.responseJSON; + $.notify({message: '移动失败,原因:' + data.message}, {type: 'danger'}); + } + }) + }; + var ele1 = document.getElementById('carousels-container'); + dragula([ele1], { mirrorContainer: ele1 }).on('drop', onDropFunc); + + + // ----------- 新增 -------------- + var $createModal = $('.modal.admin-add-carousel-modal'); + var $createForm = $createModal.find('form.admin-add-carousel-form'); + + $createForm.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + rules: { + "portal_image[image]": { + required: true + }, + "portal_image[name]": { + required: true + }, + } + }); + + $createModal.on('show.bs.modal', function(event){ + resetFileInputFunc($createModal.find('.img-file-input')); + $createModal.find('.file-names').html('选择文件'); + }); + + $createModal.on('click', '.submit-btn', function() { + $createForm.find('.error').html(''); + + if ($createForm.valid()) { + $createForm.submit(); + } else { + $createForm.find('.error').html('请选择图片'); + } + }); + $createModal.on('change', '.img-file-input', function(){ + var file = $(this)[0].files[0]; + $createModal.find('.file-names').html(file ? file.name : '请选择文件'); + }) + + // -------------- 重新上传图片 -------------- + //replace_image_url + $('.modal.admin-upload-file-modal').on('upload:success', function(e, data){ + var $carouselItem = $('.custom-carousel-item-' + data.source_id); + $carouselItem.find('.custom-carousel-item-img img').attr('src', data.url); + }) + } +}) \ No newline at end of file diff --git a/app/assets/stylesheets/admins/carousels.scss b/app/assets/stylesheets/admins/carousels.scss new file mode 100644 index 000000000..8e8728aaf --- /dev/null +++ b/app/assets/stylesheets/admins/carousels.scss @@ -0,0 +1,60 @@ +.admins-carousels-index-page { + .carousels-card { + .custom-carousel-item { + & > .drag { + cursor: move; + background: #fff; + box-shadow: 1px 2px 5px 3px #f0f0f0; + } + + &-no { + font-size: 28px; + text-align: center; + } + + &-img { + cursor: pointer; + width: 100%; + height: 60px; + + & > img { + display: block; + width: 100%; + height: 60px; + background: #F5F5F5; + } + } + + .not_active { + background: #F0F0F0; + } + + .delete-btn { + font-size: 20px; + color: red; + cursor: pointer; + } + + .save-url-btn { + cursor: pointer; + } + + .operate-box { + display: flex; + justify-content: space-between; + align-items: center; + } + + .online-check-box { + font-size: 20px; + } + + .name-input { + flex: 1; + } + .link-input { + flex: 3; + } + } + } +} \ No newline at end of file diff --git a/app/controllers/admins/carousels_controller.rb b/app/controllers/admins/carousels_controller.rb new file mode 100644 index 000000000..67518174c --- /dev/null +++ b/app/controllers/admins/carousels_controller.rb @@ -0,0 +1,80 @@ +class Admins::CarouselsController < Admins::BaseController + before_action :convert_file!, only: [:create] + + def index + @images = PortalImage.order(position: :asc) + end + + def create + position = PortalImage.count + 1 + + ActiveRecord::Base.transaction do + image = PortalImage.create!(create_params.merge(position: position)) + + file_path = Util::FileManage.disk_filename('PortalImage', image.id) + File.delete(file_path) if File.exist?(file_path) # 删除之前的文件 + Util.write_file(@file, file_path) + end + + flash[:success] = '保存成功' + redirect_to admins_carousels_path + end + + def update + current_image.update!(update_params) + render_ok + end + + def destroy + ActiveRecord::Base.transaction do + current_image.destroy! + # 前移 + PortalImage.where('position > ?', current_image.position) + .update_all('position = position - 1') + + file_path = Util::FileManage.disk_filename('PortalImage', current_image.id) + File.delete(file_path) if File.exist?(file_path) + end + render_delete_success + end + + def drag + move = PortalImage.find_by(id: params[:move_id]) + after = PortalImage.find_by(id: params[:after_id]) + + Admins::DragPortalImageService.call(move, after) + render_ok + rescue Admins::DragPortalImageService::Error => e + render_error(e.message) + end + + private + + def current_image + @_current_image ||= PortalImage.find(params[:id]) + end + + def create_params + params.require(:portal_image).permit(:name, :link) + end + + def update_params + params.permit(:name, :link, :status) + end + + def convert_file! + max_size = 10 * 1024 * 1024 # 10M + file = params.dig('portal_image', 'image') + if file.class == ActionDispatch::Http::UploadedFile + @file = file + render_error('请上传文件') if @file.size.zero? + render_error('文件大小超过限制') if @file.size > max_size + else + file = file.to_s.strip + return render_error('请上传正确的图片') if file.blank? + @file = Util.convert_base64_image(file, max_size: max_size) + end + rescue Base64ImageConverter::Error => ex + render_error(ex.message) + end +end \ No newline at end of file diff --git a/app/models/portal_image.rb b/app/models/portal_image.rb index 24b9af39d..a3fd71bb5 100644 --- a/app/models/portal_image.rb +++ b/app/models/portal_image.rb @@ -1,2 +1,5 @@ class PortalImage < ApplicationRecord + def online? + status? + end end diff --git a/app/services/admins/drag_portal_image_service.rb b/app/services/admins/drag_portal_image_service.rb new file mode 100644 index 000000000..6fe1ea86d --- /dev/null +++ b/app/services/admins/drag_portal_image_service.rb @@ -0,0 +1,35 @@ +class Admins::DragPortalImageService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :move, :after + + def initialize(move, after) + @move = move + @after = after # 移动后下一个位置的元素 + end + + def call + return if move.position + 1 == after&.position # 未移动 + + images = PortalImage.all + + ActiveRecord::Base.transaction do + if after.blank? # 移动至末尾 + total = images.count + + images.where('position > ?', move.position).update_all('position = position - 1') + move.update!(position: total) + return + end + + if move.position > after.position # 前移 + images.where('position >= ? AND position < ?', after.position, move.position).update_all('position = position + 1') + move.update!(position: after.position) + else # 后移 + images.where('position > ? AND position <= ?', move.position, after.position).update_all('position = position - 1') + move.update!(position: after.position) + end + end + end + +end \ No newline at end of file diff --git a/app/views/admins/carousels/index.html.erb b/app/views/admins/carousels/index.html.erb new file mode 100644 index 000000000..89c224784 --- /dev/null +++ b/app/views/admins/carousels/index.html.erb @@ -0,0 +1,43 @@ +<% + define_admin_breadcrumbs do + add_admin_breadcrumb('轮播图') + end +%> + +
+
+ 首页轮播图(拖动排序) + <%= javascript_void_link '添加', class: 'btn btn-primary btn-sm add-btn', data: { toggle: 'modal', target: '.admin-add-carousel-modal' } %> +
+
+ <% @images.each_with_index do |image, index| %> + + <% end %> +
+
+ + +<%= render partial: 'admins/carousels/shared/add_carousel_modal' %> +<%= render partial: 'admins/shared/modal/upload_file_modal' %> \ No newline at end of file diff --git a/app/views/admins/carousels/shared/_add_carousel_modal.html.erb b/app/views/admins/carousels/shared/_add_carousel_modal.html.erb new file mode 100644 index 000000000..d1e75e29e --- /dev/null +++ b/app/views/admins/carousels/shared/_add_carousel_modal.html.erb @@ -0,0 +1,36 @@ + \ No newline at end of file diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb index 2d9461f45..553820e69 100644 --- a/app/views/admins/shared/_sidebar.html.erb +++ b/app/views/admins/shared/_sidebar.html.erb @@ -77,7 +77,8 @@
  • - <%= sidebar_item_group('#helps-submenu', '帮助中心', icon: 'info-circle') do %> + <%= sidebar_item_group('#setting-submenu', '网站建设', icon: 'cogs') do %> +
  • <%= sidebar_item(admins_carousels_path, '轮播图', icon: 'image', controller: 'admins-carousels') %>
  • <%= sidebar_item(edit_admins_about_path, '关于我们', icon: 'smile-o', controller: 'admins-abouts') %>
  • <%= sidebar_item(edit_admins_contact_us_path, '联系我们', icon: 'commenting-o', controller: 'admins-contact_us') %>
  • <%= sidebar_item(admins_cooperatives_path, '合作伙伴', icon: 'handshake-o', controller: 'admins-cooperatives') %>
  • diff --git a/config/routes.rb b/config/routes.rb index 706583619..2c02c6a79 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -962,6 +962,9 @@ Rails.application.routes.draw do post :drag, on: :collection post :replace_image_url, on: :member end + resources :carousels, only: [:index, :create, :update, :destroy] do + post :drag, on: :collection + end end resources :colleges, only: [] do diff --git a/db/migrate/20190930010405_resort_portal_image_data.rb b/db/migrate/20190930010405_resort_portal_image_data.rb new file mode 100644 index 000000000..665b48466 --- /dev/null +++ b/db/migrate/20190930010405_resort_portal_image_data.rb @@ -0,0 +1,7 @@ +class ResortPortalImageData < ActiveRecord::Migration[5.2] + def change + PortalImage.order(position: :asc).each_with_index do |image, index| + image.update!(position: index + 1) + end + end +end