diff --git a/app/assets/javascripts/cooperative/carousels/index.js b/app/assets/javascripts/cooperative/carousels/index.js new file mode 100644 index 000000000..4d8fe1b2c --- /dev/null +++ b/app/assets/javascripts/cooperative/carousels/index.js @@ -0,0 +1,125 @@ +$(document).on('turbolinks:load', function() { + if ($('body.cooperative-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: '/cooperative/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: '/cooperative/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: '/cooperative/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.cooperative-add-carousel-modal'); + var $createForm = $createModal.find('form.cooperative-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.cooperative-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/javascripts/cooperative/laboratory_users/index.js b/app/assets/javascripts/cooperative/laboratory_users/index.js new file mode 100644 index 000000000..cd705d8d0 --- /dev/null +++ b/app/assets/javascripts/cooperative/laboratory_users/index.js @@ -0,0 +1,62 @@ +$(document).on('turbolinks:load', function() { + if ($('body.cooperative-laboratory-users-index-page').length > 0) { + // ============= 添加管理员 ============== + var $addMemberModal = $('.cooperative-add-laboratory-user-modal'); + var $addMemberForm = $addMemberModal.find('.cooperative-add-laboratory-user-form'); + var $memberSelect = $addMemberModal.find('.laboratory-user-select'); + + $addMemberModal.on('show.bs.modal', function(event){ + $memberSelect.select2('val', ' '); + }); + + $memberSelect.select2({ + theme: 'bootstrap4', + placeholder: '请输入要添加的管理员姓名', + multiple: true, + minimumInputLength: 1, + ajax: { + delay: 500, + url: '/cooperative/users', + dataType: 'json', + data: function(params){ + return { name: params.term }; + }, + processResults: function(data){ + return { results: data.users } + } + }, + templateResult: function (item) { + if(!item.id || item.id === '') return item.text; + return item.real_name + "--" + item.identity; + }, + templateSelection: function(item){ + if (item.id) { + } + return item.real_name || item.text; + } + }); + + $addMemberModal.on('click', '.submit-btn', function(){ + $addMemberForm.find('.error').html(''); + + var memberIds = $memberSelect.val(); + if (memberIds && memberIds.length > 0) { + $.ajax({ + method: 'POST', + dataType: 'json', + url: '/cooperative/laboratory_users', + data: { user_ids: memberIds }, + success: function(data){ + if(data && data.status == 0){ + show_success_flash(); + $addMemberModal.modal('hide'); + window.location.reload(); + } + } + }); + } else { + $addMemberModal.modal('hide'); + } + }); + } +}); diff --git a/app/assets/javascripts/cooperative/modals/upload-file-modal.js b/app/assets/javascripts/cooperative/modals/upload-file-modal.js new file mode 100644 index 000000000..835ccd383 --- /dev/null +++ b/app/assets/javascripts/cooperative/modals/upload-file-modal.js @@ -0,0 +1,62 @@ +$(document).on('turbolinks:load', function() { + var $modal = $('.modal.cooperative-upload-file-modal'); + if ($modal.length > 0) { + var $form = $modal.find('form.cooperative-upload-file-form') + var $sourceIdInput = $modal.find('input[name="source_id"]'); + var $sourceTypeInput = $modal.find('input[name="source_type"]'); + + $modal.on('show.bs.modal', function(event){ + var $link = $(event.relatedTarget); + var sourceId = $link.data('sourceId'); + var sourceType = $link.data('sourceType'); + + $sourceIdInput.val(sourceId); + $sourceTypeInput.val(sourceType); + + $modal.find('.upload-file-input').trigger('click'); + }); + + $modal.find('.upload-file-input').on('change', function(e){ + var file = $(this)[0].files[0]; + + if(file){ + $modal.find('.file-names').html(file.name); + $modal.find('.submit-btn').trigger('click'); + } + }) + + var formValid = function(){ + if($form.find('input[name="file"]').val() == undefined || $form.find('input[name="file"]').val().length == 0){ + $form.find('.error').html('请选择文件'); + return false; + } + + return true; + }; + + $modal.on('click', '.submit-btn', function(){ + $form.find('.error').html(''); + + if (formValid()) { + var formDataString = $form.serialize(); + $.ajax({ + method: 'POST', + dataType: 'json', + url: '/cooperatives/files?' + formDataString, + data: new FormData($form[0]), + processData: false, + contentType: false, + success: function(data){ + $.notify({ message: '上传成功' }); + $modal.trigger('upload:success', data); + $modal.modal('hide'); + }, + error: function(res){ + var data = res.responseJSON; + $form.find('.error').html(data.message); + } + }); + } + }); + } +}); \ No newline at end of file diff --git a/app/assets/stylesheets/cooperative/carousels.scss b/app/assets/stylesheets/cooperative/carousels.scss new file mode 100644 index 000000000..092e02fe8 --- /dev/null +++ b/app/assets/stylesheets/cooperative/carousels.scss @@ -0,0 +1,60 @@ +.cooperative-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/cooperative/carousels_controller.rb b/app/controllers/cooperative/carousels_controller.rb new file mode 100644 index 000000000..c958f9859 --- /dev/null +++ b/app/controllers/cooperative/carousels_controller.rb @@ -0,0 +1,80 @@ +class Cooperative::CarouselsController < Cooperative::BaseController + before_action :convert_file!, only: [:create] + + def index + @images = current_laboratory.portal_images.order(position: :asc) + end + + def create + position = current_laboratory.portal_images.count + 1 + + ActiveRecord::Base.transaction do + image = current_laboratory.portal_images.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 cooperative_carousels_path(current_laboratory) + end + + def update + current_image.update!(update_params) + render_ok + end + + def destroy + ActiveRecord::Base.transaction do + current_image.destroy! + # 前移 + current_laboratory.portal_images.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 = current_laboratory.portal_images.find_by(id: params[:move_id]) + after = current_laboratory.portal_images.find_by(id: params[:after_id]) + + Admins::DragPortalImageService.call(current_laboratory, move, after) + render_ok + rescue Admins::DragPortalImageService::Error => e + render_error(e.message) + end + + private + + def current_image + @_current_image ||= current_laboratory.portal_images.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/controllers/cooperative/files_controller.rb b/app/controllers/cooperative/files_controller.rb new file mode 100644 index 000000000..56710a968 --- /dev/null +++ b/app/controllers/cooperative/files_controller.rb @@ -0,0 +1,46 @@ +class Cooperative::FilesController < Cooperative::BaseController + before_action :convert_file!, only: [:create] + + def create + File.delete(file_path) if File.exist?(file_path) # 删除之前的文件 + + Util.write_file(@file, file_path) + + render_ok(source_id: params[:source_id], source_type: params[:source_type].to_s, url: file_url + "?t=#{Random.rand}") + rescue StandardError => ex + logger_error(ex) + render_error('上传失败') + end + + private + + def convert_file! + max_size = 10 * 1024 * 1024 # 10M + if params[:file].class == ActionDispatch::Http::UploadedFile + @file = params[:file] + render_error('请上传文件') if @file.size.zero? + render_error('文件大小超过限制') if @file.size > max_size + else + file = params[: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 + + def file_path + @_file_path ||= begin + case params[:source_type].to_s + when 'Shixun' then + Util::FileManage.disk_filename('Shixun', params[:source_id]) + else + Util::FileManage.disk_filename(params[:source_type].to_s, params[:source_id].to_s) + end + end + end + + def file_url + Util::FileManage.disk_file_url(params[:source_type].to_s, params[:source_id].to_s) + end +end \ No newline at end of file diff --git a/app/controllers/cooperative/laboratory_users_controller.rb b/app/controllers/cooperative/laboratory_users_controller.rb new file mode 100644 index 000000000..390d1f2b1 --- /dev/null +++ b/app/controllers/cooperative/laboratory_users_controller.rb @@ -0,0 +1,23 @@ +class Cooperative::LaboratoryUsersController < Cooperative::BaseController + def index + laboratory_users = current_laboratory.laboratory_users + @laboratory_users = paginate laboratory_users.includes(user: { user_extension: [:school, :department] }) + end + + def create + Admins::AddLaboratoryUserService.call(current_laboratory, params.permit(user_ids: [])) + render_ok + end + + def destroy + current_laboratory_user.destroy! + + render_delete_success + end + + private + + def current_laboratory_user + @_current_laboratory_user ||= current_laboratory.laboratory_users.find(params[:id]) + end +end \ No newline at end of file diff --git a/app/controllers/cooperative/users_controller.rb b/app/controllers/cooperative/users_controller.rb new file mode 100644 index 000000000..8d6e5f52a --- /dev/null +++ b/app/controllers/cooperative/users_controller.rb @@ -0,0 +1,10 @@ +class Cooperative::UsersController < Cooperative::BaseController + def index + params[:sort_by] = params[:sort_by].presence || 'created_on' + params[:sort_direction] = params[:sort_direction].presence || 'desc' + params[:school_id] = current_laboratory.school_id + + users = Admins::UserQuery.call(params) + @users = paginate users.includes(user_extension: :school) + end +end \ No newline at end of file diff --git a/app/queries/admins/user_query.rb b/app/queries/admins/user_query.rb index 75e50fc1b..749ba2110 100644 --- a/app/queries/admins/user_query.rb +++ b/app/queries/admins/user_query.rb @@ -37,6 +37,9 @@ class Admins::UserQuery < ApplicationQuery users = users.where('CONCAT(lastname, firstname) LIKE :name', name: "%#{name}%") end + # 单位ID + users = users.joins(:user_extension).where(user_extensions: { school_id: params[:school_id] }) if params[:school_id].present? + # 学校名称 school_name = params[:school_name].to_s.strip.presence users = users.joins(user_extension: :school).where('schools.name LIKE ?', "%#{school_name}%") if school_name diff --git a/app/views/cooperative/carousels/index.html.erb b/app/views/cooperative/carousels/index.html.erb new file mode 100644 index 000000000..4b7c0bcc5 --- /dev/null +++ b/app/views/cooperative/carousels/index.html.erb @@ -0,0 +1,41 @@ +<% define_breadcrumbs do %> + <% add_breadcrumb('轮播图设置') %> +<% end %> + +
头像 | +真实姓名 | +邮件地址 | +手机号码 | +单位部门 | +操作 | +
---|---|---|---|---|---|
+ <%= link_to "/users/#{user.login}", target: '_blank' do %>
+ |
+ + <%= link_to "/users/#{user.login}", target: '_blank' do %> + <%= overflow_hidden_span user.real_name, width: 100 %> + <% end %> + | +<%= overflow_hidden_span display_text(user.mail), width: 150 %> | +<%= overflow_hidden_span display_text(user.phone), width: 100 %> | +<%= [user.school_name.presence, user.department_name.presence].compact.join('-') %> | ++ <%= delete_link '删除', cooperative_laboratory_user_path(laboratory_user, element: ".laboratory-user-item-#{laboratory_user.id}"), class: 'delete-laboratory-user-action' %> + | +