Merge branch 'dev_aliyun' of http://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun
	
		
	
				
					
				
			
						commit
						e6dec1d215
					
				@ -0,0 +1,124 @@
 | 
				
			||||
$(document).on('turbolinks:load', function() {
 | 
				
			||||
  if ($('body.admins-weapp-adverts-index-page').length > 0) {
 | 
				
			||||
    var resetNo = function(){
 | 
				
			||||
      $('#adverts-container .advert-item-no').each(function(index, ele){
 | 
				
			||||
        $(ele).html(index + 1);
 | 
				
			||||
      })
 | 
				
			||||
    }
 | 
				
			||||
 | 
				
			||||
    // ------------ 保存链接 -----------
 | 
				
			||||
    $('.adverts-card').on('click', '.save-data-btn', function(){
 | 
				
			||||
      var $link = $(this);
 | 
				
			||||
      var id = $link.data('id');
 | 
				
			||||
      var link = $('.advert-item-' + id).find('.link-input').val();
 | 
				
			||||
      $link.attr('disabled', true);
 | 
				
			||||
 | 
				
			||||
      $.ajax({
 | 
				
			||||
        url: '/admins/weapp_adverts/' + id,
 | 
				
			||||
        method: 'PATCH',
 | 
				
			||||
        dataType: 'json',
 | 
				
			||||
        data: { link: link },
 | 
				
			||||
        success: function(data){
 | 
				
			||||
          $.notify({ message: '操作成功' });
 | 
				
			||||
        },
 | 
				
			||||
        error: ajaxErrorNotifyHandler,
 | 
				
			||||
        complete: function(){
 | 
				
			||||
          $link.removeAttr('disabled');
 | 
				
			||||
        }
 | 
				
			||||
      })
 | 
				
			||||
    });
 | 
				
			||||
    // -------------- 是否在首页展示 --------------
 | 
				
			||||
    $('.adverts-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/weapp_adverts/' + id,
 | 
				
			||||
        method: 'PATCH',
 | 
				
			||||
        dataType: 'json',
 | 
				
			||||
        data: { online: checked },
 | 
				
			||||
        success: function(data){
 | 
				
			||||
          $.notify({ message: '保存成功' });
 | 
				
			||||
          var box = $('.advert-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/weapp_adverts/drag',
 | 
				
			||||
        method: 'POST',
 | 
				
			||||
        dataType: 'json',
 | 
				
			||||
        data: { move_id: moveId, after_id: insertId },
 | 
				
			||||
        success: function(data){
 | 
				
			||||
          resetNo();
 | 
				
			||||
        },
 | 
				
			||||
        error: function(res){
 | 
				
			||||
          var data = res.responseJSON;
 | 
				
			||||
          $.notify({message: '移动失败,原因:' + data.message}, {type: 'danger'});
 | 
				
			||||
        }
 | 
				
			||||
      })
 | 
				
			||||
    };
 | 
				
			||||
    var ele1 = document.getElementById('adverts-container');
 | 
				
			||||
    dragula([ele1], { mirrorContainer: ele1 }).on('drop', onDropFunc);
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
    // ----------- 新增 --------------
 | 
				
			||||
    var $createModal = $('.modal.admin-add-weapp-advert-modal');
 | 
				
			||||
    var $createForm = $createModal.find('form.admin-add-weapp-advert-form');
 | 
				
			||||
 | 
				
			||||
    $createForm.validate({
 | 
				
			||||
      errorElement: 'span',
 | 
				
			||||
      errorClass: 'danger text-danger',
 | 
				
			||||
      rules: {
 | 
				
			||||
        "weapp_settings_advert[image]": {
 | 
				
			||||
          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 $advertItem = $('.advert-item-' + data.source_id);
 | 
				
			||||
      $advertItem.find('.advert-item-img img').attr('src', data.url);
 | 
				
			||||
    })
 | 
				
			||||
 | 
				
			||||
    // 删除后
 | 
				
			||||
    $(document).on('delete_success', resetNo)
 | 
				
			||||
  }
 | 
				
			||||
})
 | 
				
			||||
@ -0,0 +1,123 @@
 | 
				
			||||
$(document).on('turbolinks:load', function() {
 | 
				
			||||
  if ($('body.admins-weapp-carousels-index-page').length > 0) {
 | 
				
			||||
    var resetNo = function(){
 | 
				
			||||
      $('#carousels-container .custom-carousel-item-no').each(function(index, ele){
 | 
				
			||||
        $(ele).html(index + 1);
 | 
				
			||||
      })
 | 
				
			||||
    }
 | 
				
			||||
    // ------------ 保存链接 -----------
 | 
				
			||||
    $('.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();
 | 
				
			||||
      $link.attr('disabled', true);
 | 
				
			||||
 | 
				
			||||
      $.ajax({
 | 
				
			||||
        url: '/admins/weapp_carousels/' + id,
 | 
				
			||||
        method: 'PATCH',
 | 
				
			||||
        dataType: 'json',
 | 
				
			||||
        data: { link: link },
 | 
				
			||||
        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/weapp_carousels/' + id,
 | 
				
			||||
        method: 'PATCH',
 | 
				
			||||
        dataType: 'json',
 | 
				
			||||
        data: { online: 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/weapp_carousels/drag',
 | 
				
			||||
        method: 'POST',
 | 
				
			||||
        dataType: 'json',
 | 
				
			||||
        data: { move_id: moveId, after_id: insertId },
 | 
				
			||||
        success: function(data){
 | 
				
			||||
          resetNo();
 | 
				
			||||
        },
 | 
				
			||||
        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-weapp-carousel-modal');
 | 
				
			||||
    var $createForm = $createModal.find('form.admin-add-weapp-carousel-form');
 | 
				
			||||
 | 
				
			||||
    $createForm.validate({
 | 
				
			||||
      errorElement: 'span',
 | 
				
			||||
      errorClass: 'danger text-danger',
 | 
				
			||||
      rules: {
 | 
				
			||||
        "weapp_settings_carousel[image]": {
 | 
				
			||||
          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);
 | 
				
			||||
    })
 | 
				
			||||
 | 
				
			||||
    // 删除后
 | 
				
			||||
    $(document).on('delete_success', resetNo)
 | 
				
			||||
  }
 | 
				
			||||
})
 | 
				
			||||
@ -0,0 +1,60 @@
 | 
				
			||||
.admins-weapp-adverts-index-page {
 | 
				
			||||
  .adverts-card {
 | 
				
			||||
    .advert-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;
 | 
				
			||||
      }
 | 
				
			||||
    }
 | 
				
			||||
  }
 | 
				
			||||
}
 | 
				
			||||
@ -0,0 +1,60 @@
 | 
				
			||||
.admins-weapp-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;
 | 
				
			||||
      }
 | 
				
			||||
    }
 | 
				
			||||
  }
 | 
				
			||||
}
 | 
				
			||||
@ -0,0 +1,79 @@
 | 
				
			||||
class Admins::WeappAdvertsController < Admins::BaseController
 | 
				
			||||
  before_action :convert_file!, only: [:create]
 | 
				
			||||
  def index
 | 
				
			||||
    @adverts = WeappSettings::Advert.all
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def create
 | 
				
			||||
    position = WeappSettings::Advert.count + 1
 | 
				
			||||
 | 
				
			||||
    ActiveRecord::Base.transaction do
 | 
				
			||||
      advert = WeappSettings::Advert.create!(create_params.merge(position: position))
 | 
				
			||||
 | 
				
			||||
      file_path = Util::FileManage.source_disk_filename(advert)
 | 
				
			||||
      File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
 | 
				
			||||
      Util.write_file(@file, file_path)
 | 
				
			||||
    end
 | 
				
			||||
 | 
				
			||||
    flash[:success] = '保存成功'
 | 
				
			||||
    redirect_to admins_weapp_adverts_path
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def update
 | 
				
			||||
    current_advert.update!(update_params)
 | 
				
			||||
    render_ok
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def destroy
 | 
				
			||||
    ActiveRecord::Base.transaction do
 | 
				
			||||
      current_advert.destroy!
 | 
				
			||||
      # 前移
 | 
				
			||||
      WeappSettings::Advert.where('position > ?', current_advert.position)
 | 
				
			||||
        .update_all('position = position - 1')
 | 
				
			||||
 | 
				
			||||
      file_path = Util::FileManage.source_disk_filename(current_advert)
 | 
				
			||||
      File.delete(file_path) if File.exist?(file_path)
 | 
				
			||||
    end
 | 
				
			||||
    render_delete_success
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def drag
 | 
				
			||||
    move  = WeappSettings::Advert.find_by(id: params[:move_id])
 | 
				
			||||
    after = WeappSettings::Advert.find_by(id: params[:after_id])
 | 
				
			||||
 | 
				
			||||
    Admins::DragWeappAdvertService.call(move, after)
 | 
				
			||||
    render_ok
 | 
				
			||||
  rescue ApplicationService::Error => e
 | 
				
			||||
    render_error(e.message)
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  private
 | 
				
			||||
 | 
				
			||||
  def current_advert
 | 
				
			||||
    @_current_advert ||= WeappSettings::Advert.find(params[:id])
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def create_params
 | 
				
			||||
    params.require(:weapp_settings_advert).permit(:link)
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def update_params
 | 
				
			||||
    params.permit(:link, :online)
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def convert_file!
 | 
				
			||||
    max_size = 10 * 1024 * 1024 # 10M
 | 
				
			||||
    file = params.dig('weapp_settings_advert', '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
 | 
				
			||||
@ -0,0 +1,80 @@
 | 
				
			||||
class Admins::WeappCarouselsController < Admins::BaseController
 | 
				
			||||
  before_action :convert_file!, only: [:create]
 | 
				
			||||
 | 
				
			||||
  def index
 | 
				
			||||
    @carousels = WeappSettings::Carousel.all
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def create
 | 
				
			||||
    position = WeappSettings::Carousel.count + 1
 | 
				
			||||
 | 
				
			||||
    ActiveRecord::Base.transaction do
 | 
				
			||||
      carousel = WeappSettings::Carousel.create!(create_params.merge(position: position))
 | 
				
			||||
 | 
				
			||||
      file_path = Util::FileManage.source_disk_filename(carousel)
 | 
				
			||||
      File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
 | 
				
			||||
      Util.write_file(@file, file_path)
 | 
				
			||||
    end
 | 
				
			||||
 | 
				
			||||
    flash[:success] = '保存成功'
 | 
				
			||||
    redirect_to admins_weapp_carousels_path
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def update
 | 
				
			||||
    current_carousel.update!(update_params)
 | 
				
			||||
    render_ok
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def destroy
 | 
				
			||||
    ActiveRecord::Base.transaction do
 | 
				
			||||
      current_carousel.destroy!
 | 
				
			||||
      # 前移
 | 
				
			||||
      WeappSettings::Carousel.where('position > ?', current_carousel.position)
 | 
				
			||||
        .update_all('position = position - 1')
 | 
				
			||||
 | 
				
			||||
      file_path = Util::FileManage.source_disk_filename(current_carousel)
 | 
				
			||||
      File.delete(file_path) if File.exist?(file_path)
 | 
				
			||||
    end
 | 
				
			||||
    render_delete_success
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def drag
 | 
				
			||||
    move  = WeappSettings::Carousel.find_by(id: params[:move_id])
 | 
				
			||||
    after = WeappSettings::Carousel.find_by(id: params[:after_id])
 | 
				
			||||
 | 
				
			||||
    Admins::DragWeappCarouselService.call(move, after)
 | 
				
			||||
    render_ok
 | 
				
			||||
  rescue ApplicationService::Error => e
 | 
				
			||||
    render_error(e.message)
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  private
 | 
				
			||||
 | 
				
			||||
  def current_carousel
 | 
				
			||||
    @_current_carousel ||= WeappSettings::Carousel.find(params[:id])
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def create_params
 | 
				
			||||
    params.require(:weapp_settings_carousel).permit(:link)
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def update_params
 | 
				
			||||
    params.permit(:link, :online)
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def convert_file!
 | 
				
			||||
    max_size = 10 * 1024 * 1024 # 10M
 | 
				
			||||
    file = params.dig('weapp_settings_carousel', '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
 | 
				
			||||
@ -1,12 +1,15 @@
 | 
				
			||||
class Weapps::HomesController < Weapps::BaseController
 | 
				
			||||
  def show
 | 
				
			||||
    # banner图
 | 
				
			||||
    @images = PortalImage.where(status: true).order(position: :asc)
 | 
				
			||||
    # banner
 | 
				
			||||
    @carousels = WeappSettings::Carousel.only_online
 | 
				
			||||
    # 广告
 | 
				
			||||
    @advert = WeappSettings::Advert.only_online.first
 | 
				
			||||
 | 
				
			||||
    # 热门实训
 | 
				
			||||
    @shixuns = Shixun.where(homepage_show: true).includes(:tag_repertoires, :challenges).limit(4)
 | 
				
			||||
 | 
				
			||||
    # 热门实践课程
 | 
				
			||||
    @subjects = Subject.where(homepage_show: true).includes(:shixuns, :repertoire).limit(4)
 | 
				
			||||
 | 
				
			||||
  end
 | 
				
			||||
end
 | 
				
			||||
@ -0,0 +1,3 @@
 | 
				
			||||
class WeappSetting < ApplicationRecord
 | 
				
			||||
  scope :only_online, -> { where(online: true) }
 | 
				
			||||
end
 | 
				
			||||
@ -0,0 +1,2 @@
 | 
				
			||||
class WeappSettings::Advert < WeappSetting
 | 
				
			||||
end
 | 
				
			||||
@ -0,0 +1,3 @@
 | 
				
			||||
class WeappSettings::Carousel < WeappSetting
 | 
				
			||||
  default_scope { order(position: :asc) }
 | 
				
			||||
end
 | 
				
			||||
@ -0,0 +1,32 @@
 | 
				
			||||
class Admins::DragWeappAdvertService < ApplicationService
 | 
				
			||||
  attr_reader :move, :after
 | 
				
			||||
 | 
				
			||||
  def initialize(move, after)
 | 
				
			||||
    @move  = move
 | 
				
			||||
    @after = after # 移动后下一个位置的元素
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def call
 | 
				
			||||
    return if move.position + 1 == after&.position # 未移动
 | 
				
			||||
 | 
				
			||||
    carousels = WeappSettings::Advert.all
 | 
				
			||||
 | 
				
			||||
    ActiveRecord::Base.transaction do
 | 
				
			||||
      if after.blank? || move.id == after.id # 移动至末尾
 | 
				
			||||
        total = carousels.count
 | 
				
			||||
 | 
				
			||||
        carousels.where('position > ?', move.position).update_all('position = position - 1')
 | 
				
			||||
        move.update!(position: total)
 | 
				
			||||
        return
 | 
				
			||||
      end
 | 
				
			||||
 | 
				
			||||
      if move.position > after.position # 前移
 | 
				
			||||
        carousels.where('position >= ? AND position < ?', after.position, move.position).update_all('position = position + 1')
 | 
				
			||||
        move.update!(position: after.position)
 | 
				
			||||
      else # 后移
 | 
				
			||||
        carousels.where('position > ? AND position < ?', move.position, after.position).update_all('position = position - 1')
 | 
				
			||||
        move.update!(position: after.position - 1)
 | 
				
			||||
      end
 | 
				
			||||
    end
 | 
				
			||||
  end
 | 
				
			||||
end
 | 
				
			||||
@ -0,0 +1,32 @@
 | 
				
			||||
class Admins::DragWeappCarouselService < ApplicationService
 | 
				
			||||
  attr_reader :move, :after
 | 
				
			||||
 | 
				
			||||
  def initialize(move, after)
 | 
				
			||||
    @move  = move
 | 
				
			||||
    @after = after # 移动后下一个位置的元素
 | 
				
			||||
  end
 | 
				
			||||
 | 
				
			||||
  def call
 | 
				
			||||
    return if move.position + 1 == after&.position # 未移动
 | 
				
			||||
 | 
				
			||||
    carousels = WeappSettings::Carousel.all
 | 
				
			||||
 | 
				
			||||
    ActiveRecord::Base.transaction do
 | 
				
			||||
      if after.blank? || move.id == after.id # 移动至末尾
 | 
				
			||||
        total = carousels.count
 | 
				
			||||
 | 
				
			||||
        carousels.where('position > ?', move.position).update_all('position = position - 1')
 | 
				
			||||
        move.update!(position: total)
 | 
				
			||||
        return
 | 
				
			||||
      end
 | 
				
			||||
 | 
				
			||||
      if move.position > after.position # 前移
 | 
				
			||||
        carousels.where('position >= ? AND position < ?', after.position, move.position).update_all('position = position + 1')
 | 
				
			||||
        move.update!(position: after.position)
 | 
				
			||||
      else # 后移
 | 
				
			||||
        carousels.where('position > ? AND position < ?', move.position, after.position).update_all('position = position - 1')
 | 
				
			||||
        move.update!(position: after.position - 1)
 | 
				
			||||
      end
 | 
				
			||||
    end
 | 
				
			||||
  end
 | 
				
			||||
end
 | 
				
			||||
@ -0,0 +1,42 @@
 | 
				
			||||
<%
 | 
				
			||||
  define_admin_breadcrumbs do
 | 
				
			||||
    add_admin_breadcrumb('广告栏')
 | 
				
			||||
  end
 | 
				
			||||
%>
 | 
				
			||||
 | 
				
			||||
<div class="card mb-5 adverts-card">
 | 
				
			||||
  <div class="card-header d-flex justify-content-between align-items-center">
 | 
				
			||||
    <span class="flex-1">广告栏</span>
 | 
				
			||||
    <%= javascript_void_link '添加', class: 'btn btn-primary btn-sm add-btn', data: { toggle: 'modal', target: '.admin-add-weapp-advert-modal' } %>
 | 
				
			||||
  </div>
 | 
				
			||||
  <div class="card-body row" id="adverts-container">
 | 
				
			||||
    <% @adverts.each_with_index do |advert, index| %>
 | 
				
			||||
      <div class="col-12 advert-item advert-item-<%= advert.id %>" data-id="<%= advert.id %>">
 | 
				
			||||
        <div class="border rounded relative p-3 mb-3 drag row align-items-center <%= advert.online? ? '' : 'not_active' %>">
 | 
				
			||||
          <div class="col-2 col-md-1 advert-item-no"><%= index + 1 %></div>
 | 
				
			||||
          <div class="col-10 col-md-3 advert-item-img" data-source-id="<%= advert.id %>" data-source-type="WeappSettings::Advert" data-toggle="modal" data-target=".admin-upload-file-modal">
 | 
				
			||||
            <img src="<%= Util::FileManage.exists?(advert) ? Util::FileManage.source_disk_file_url(advert) : '' %>" data-toggle="tooltip" data-title="重新上传"/>
 | 
				
			||||
          </div>
 | 
				
			||||
          <div class="col-10 col-md-7">
 | 
				
			||||
            <div class="input-group">
 | 
				
			||||
              <input type="text" value="<%= advert.link %>" class="form-control link-input" placeholder="请输入跳转地址">
 | 
				
			||||
              <div class="input-group-prepend">
 | 
				
			||||
                <button class="input-group-text save-data-btn" data-id="<%= advert.id %>">保存</button>
 | 
				
			||||
              </div>
 | 
				
			||||
            </div>
 | 
				
			||||
          </div>
 | 
				
			||||
          <div class="col-2 col-md-1 operate-box">
 | 
				
			||||
            <%= check_box_tag(:online, 1, advert.online?, id: nil, class: 'online-check-box', data: { id: advert.id, toggle: 'tooltip', title: '首页展示' }) %>
 | 
				
			||||
            <%= delete_link '删除', admins_weapp_advert_path(advert, element: ".advert-item-#{advert.id}", not_refresh: true), class: 'delete-btn' do %>
 | 
				
			||||
              <i class="fa fa-trash-o" data-id="<%= advert.id %>"></i>
 | 
				
			||||
            <% end %>
 | 
				
			||||
          </div>
 | 
				
			||||
        </div>
 | 
				
			||||
      </div>
 | 
				
			||||
    <% end %>
 | 
				
			||||
  </div>
 | 
				
			||||
</div>
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
<%= render partial: 'admins/weapp_adverts/shared/add_weapp_advert_modal' %>
 | 
				
			||||
<%= render partial: 'admins/shared/modal/upload_file_modal' %>
 | 
				
			||||
@ -0,0 +1,35 @@
 | 
				
			||||
<div class="modal fade admin-add-weapp-advert-modal" tabindex="-1" role="dialog" aria-hidden="true">
 | 
				
			||||
  <div class="modal-dialog modal-dialog-centered" role="document">
 | 
				
			||||
    <div class="modal-content">
 | 
				
			||||
      <div class="modal-header">
 | 
				
			||||
        <h5 class="modal-title">添加轮播图</h5>
 | 
				
			||||
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
 | 
				
			||||
          <span aria-hidden="true">×</span>
 | 
				
			||||
        </button>
 | 
				
			||||
      </div>
 | 
				
			||||
      <div class="modal-body">
 | 
				
			||||
        <%= simple_form_for(WeappSettings::Advert.new, url: admins_weapp_adverts_path, html: { class: 'admin-add-weapp-advert-form', enctype: 'multipart/form-data' }) do |f| %>
 | 
				
			||||
          <div class="form-group">
 | 
				
			||||
            <div class="input-group">
 | 
				
			||||
              <div class="input-group-prepend">
 | 
				
			||||
                <span class="input-group-text">图片</span>
 | 
				
			||||
              </div>
 | 
				
			||||
              <div class="custom-file flex-row-reverse">
 | 
				
			||||
                <input type="file" name="weapp_settings_advert[image]" class="img-file-input" id="img-file-input" accept="image/*">
 | 
				
			||||
                <label class="custom-file-label file-names" for="img-file-input">选择文件</label>
 | 
				
			||||
              </div>
 | 
				
			||||
            </div>
 | 
				
			||||
          </div>
 | 
				
			||||
 | 
				
			||||
          <%= f.input :link, as: :url, label: '跳转地址', placeholder: '请输入跳转地址' %>
 | 
				
			||||
 | 
				
			||||
          <div class="error text-danger"></div>
 | 
				
			||||
        <% end %>
 | 
				
			||||
      </div>
 | 
				
			||||
      <div class="modal-footer">
 | 
				
			||||
        <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
 | 
				
			||||
        <button type="button" class="btn btn-primary submit-btn">确认</button>
 | 
				
			||||
      </div>
 | 
				
			||||
    </div>
 | 
				
			||||
  </div>
 | 
				
			||||
</div>
 | 
				
			||||
@ -0,0 +1,42 @@
 | 
				
			||||
<%
 | 
				
			||||
  define_admin_breadcrumbs do
 | 
				
			||||
    add_admin_breadcrumb('轮播图')
 | 
				
			||||
  end
 | 
				
			||||
%>
 | 
				
			||||
 | 
				
			||||
<div class="card mb-5 carousels-card">
 | 
				
			||||
  <div class="card-header d-flex justify-content-between align-items-center">
 | 
				
			||||
    <span class="flex-1">顶部轮播图<span class="text-secondary font-12">(拖动排序)</span></span>
 | 
				
			||||
    <%= javascript_void_link '添加', class: 'btn btn-primary btn-sm add-btn', data: { toggle: 'modal', target: '.admin-add-weapp-carousel-modal' } %>
 | 
				
			||||
  </div>
 | 
				
			||||
  <div class="card-body row" id="carousels-container" data-laboratory-id="<%= current_laboratory.id %>">
 | 
				
			||||
    <% @carousels.each_with_index do |carousel, index| %>
 | 
				
			||||
      <div class="col-12 custom-carousel-item custom-carousel-item-<%= carousel.id %>" data-id="<%= carousel.id %>">
 | 
				
			||||
        <div class="border rounded relative p-3 mb-3 drag row align-items-center <%= carousel.online? ? '' : 'not_active' %>">
 | 
				
			||||
          <div class="col-2 col-md-1 custom-carousel-item-no"><%= index + 1 %></div>
 | 
				
			||||
          <div class="col-10 col-md-3 custom-carousel-item-img" data-source-id="<%= carousel.id %>" data-source-type="WeappSettings::Carousel" data-toggle="modal" data-target=".admin-upload-file-modal">
 | 
				
			||||
            <img src="<%= Util::FileManage.exists?(carousel) ? Util::FileManage.source_disk_file_url(carousel) : '' %>" data-toggle="tooltip" data-title="重新上传"/>
 | 
				
			||||
          </div>
 | 
				
			||||
          <div class="col-10 col-md-7">
 | 
				
			||||
            <div class="input-group">
 | 
				
			||||
              <input type="text" value="<%= carousel.link %>" class="form-control link-input" placeholder="请输入跳转地址">
 | 
				
			||||
              <div class="input-group-prepend">
 | 
				
			||||
                <button class="input-group-text save-data-btn" data-id="<%= carousel.id %>">保存</button>
 | 
				
			||||
              </div>
 | 
				
			||||
            </div>
 | 
				
			||||
          </div>
 | 
				
			||||
          <div class="col-2 col-md-1 operate-box">
 | 
				
			||||
            <%= check_box_tag(:online, 1, carousel.online?, id: nil, class: 'online-check-box', data: { id: carousel.id, toggle: 'tooltip', title: '首页展示' }) %>
 | 
				
			||||
            <%= delete_link '删除', admins_weapp_carousel_path(carousel, element: ".custom-carousel-item-#{carousel.id}", not_refresh: true), class: 'delete-btn' do %>
 | 
				
			||||
              <i class="fa fa-trash-o" data-id="<%= carousel.id %>"></i>
 | 
				
			||||
            <% end %>
 | 
				
			||||
          </div>
 | 
				
			||||
        </div>
 | 
				
			||||
      </div>
 | 
				
			||||
    <% end %>
 | 
				
			||||
  </div>
 | 
				
			||||
</div>
 | 
				
			||||
 | 
				
			||||
 | 
				
			||||
<%= render partial: 'admins/weapp_carousels/shared/add_weapp_carousel_modal' %>
 | 
				
			||||
<%= render partial: 'admins/shared/modal/upload_file_modal' %>
 | 
				
			||||
@ -0,0 +1,35 @@
 | 
				
			||||
<div class="modal fade admin-add-weapp-carousel-modal" tabindex="-1" role="dialog" aria-hidden="true">
 | 
				
			||||
  <div class="modal-dialog modal-dialog-centered" role="document">
 | 
				
			||||
    <div class="modal-content">
 | 
				
			||||
      <div class="modal-header">
 | 
				
			||||
        <h5 class="modal-title">添加轮播图</h5>
 | 
				
			||||
        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
 | 
				
			||||
          <span aria-hidden="true">×</span>
 | 
				
			||||
        </button>
 | 
				
			||||
      </div>
 | 
				
			||||
      <div class="modal-body">
 | 
				
			||||
        <%= simple_form_for(WeappSettings::Carousel.new, url: admins_weapp_carousels_path, html: { class: 'admin-add-weapp-carousel-form', enctype: 'multipart/form-data' }) do |f| %>
 | 
				
			||||
          <div class="form-group">
 | 
				
			||||
            <div class="input-group">
 | 
				
			||||
              <div class="input-group-prepend">
 | 
				
			||||
                <span class="input-group-text">图片</span>
 | 
				
			||||
              </div>
 | 
				
			||||
              <div class="custom-file flex-row-reverse">
 | 
				
			||||
                <input type="file" name="weapp_settings_carousel[image]" class="img-file-input" id="img-file-input" accept="image/*">
 | 
				
			||||
                <label class="custom-file-label file-names" for="img-file-input">选择文件</label>
 | 
				
			||||
              </div>
 | 
				
			||||
            </div>
 | 
				
			||||
          </div>
 | 
				
			||||
 | 
				
			||||
          <%= f.input :link, as: :url, label: '跳转地址', placeholder: '请输入跳转地址' %>
 | 
				
			||||
 | 
				
			||||
          <div class="error text-danger"></div>
 | 
				
			||||
        <% end %>
 | 
				
			||||
      </div>
 | 
				
			||||
      <div class="modal-footer">
 | 
				
			||||
        <button type="button" class="btn btn-secondary" data-dismiss="modal">取消</button>
 | 
				
			||||
        <button type="button" class="btn btn-primary submit-btn">确认</button>
 | 
				
			||||
      </div>
 | 
				
			||||
    </div>
 | 
				
			||||
  </div>
 | 
				
			||||
</div>
 | 
				
			||||
@ -0,0 +1,12 @@
 | 
				
			||||
class CreateWeappSettings < ActiveRecord::Migration[5.2]
 | 
				
			||||
  def change
 | 
				
			||||
    create_table :weapp_settings do |t|
 | 
				
			||||
      t.string :type
 | 
				
			||||
      t.string :link
 | 
				
			||||
      t.boolean :online, default: false
 | 
				
			||||
      t.integer :position, default: 0
 | 
				
			||||
 | 
				
			||||
      t.timestamps
 | 
				
			||||
    end
 | 
				
			||||
  end
 | 
				
			||||
end
 | 
				
			||||
											
												
													File diff suppressed because one or more lines are too long
												
											
										
									
								
											
												Binary file not shown.
											
										
									
								
											
												Binary file not shown.
											
										
									
								
					Loading…
					
					
				
		Reference in new issue