Merge branch 'dev_aliyun' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_aliyun
commit
2aa630e911
@ -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);
|
||||
})
|
||||
}
|
||||
})
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
@ -0,0 +1,5 @@
|
||||
class TemplatesController < ApplicationController
|
||||
def show
|
||||
@template = EcTemplate.find_by_name!(params[:name])
|
||||
end
|
||||
end
|
@ -1,6 +1,6 @@
|
||||
module MemosHelper
|
||||
|
||||
def forum_list
|
||||
[{id: 5, name: "技术分享"}, {id: 3, name: "操作指南"}]
|
||||
[{id: 5, name: "技术分享"}, {id: 3, name: "操作指南"}, {id: 16, name: "通知公告"}]
|
||||
end
|
||||
end
|
||||
|
@ -0,0 +1,12 @@
|
||||
class CreateDiffRecordJob < ApplicationJob
|
||||
queue_as :default
|
||||
|
||||
def perform(user_id, obj_id, obj_klass, column_name, before, after)
|
||||
user = User.find_by(id: user_id)
|
||||
obj = obj_klass.constantize.find_by(id: obj_id)
|
||||
|
||||
return if user.blank? || obj.blank?
|
||||
|
||||
CreateDiffRecordService.call(user, obj, column_name, before, after)
|
||||
end
|
||||
end
|
@ -1,75 +0,0 @@
|
||||
module Util::Wechat
|
||||
BASE_SITE = 'https://api.weixin.qq.com'.freeze
|
||||
|
||||
Error = Class.new(StandardError)
|
||||
|
||||
class << self
|
||||
attr_accessor :appid, :secret
|
||||
|
||||
def js_sdk_signature(url, noncestr, timestamp)
|
||||
data = { jsapi_ticket: jsapi_ticket, noncestr: noncestr, timestamp: timestamp, url: url }
|
||||
str = data.map { |k, v| "#{k}=#{v}" }.join('&')
|
||||
Digest::SHA1.hexdigest(str)
|
||||
end
|
||||
|
||||
def access_token
|
||||
# 7200s 有效时间
|
||||
Rails.cache.fetch(access_token_cache_key, expires_in: 100.minutes) do
|
||||
result = request(:get, '/cgi-bin/token', appid: appid, secret: secret, grant_type: 'client_credential')
|
||||
result['access_token']
|
||||
end
|
||||
end
|
||||
|
||||
def refresh_access_token
|
||||
Rails.cache.delete(access_token_cache_key)
|
||||
access_token
|
||||
end
|
||||
|
||||
def jsapi_ticket
|
||||
# 7200s 有效时间
|
||||
Rails.cache.fetch(jsapi_ticket_cache_key, expires_in: 100.minutes) do
|
||||
result = request(:get, '/cgi-bin/ticket/getticket', access_token: access_token, type: 'jsapi')
|
||||
result['ticket']
|
||||
end
|
||||
end
|
||||
|
||||
def refresh_jsapi_ticket
|
||||
Rails.cache.delete(jsapi_ticket_cache_key)
|
||||
jsapi_ticket
|
||||
end
|
||||
|
||||
def access_token_cache_key
|
||||
"#{base_cache_key}/access_token"
|
||||
end
|
||||
|
||||
def jsapi_ticket_cache_key
|
||||
"#{base_cache_key}/jsapi_ticket"
|
||||
end
|
||||
|
||||
def base_cache_key
|
||||
"wechat/#{appid}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def request(method, url, **params)
|
||||
Rails.logger.error("[wechat] request: #{method} #{url} #{params.inspect}")
|
||||
|
||||
client = Faraday.new(url: BASE_SITE)
|
||||
response = client.public_send(method, url, params)
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
Rails.logger.error("[wechat] response:#{response.status} #{result.inspect}")
|
||||
|
||||
if response.status != 200
|
||||
raise Error, result.inspect
|
||||
end
|
||||
|
||||
if result['errcode'].present? && result['errcode'].to_i.nonzero?
|
||||
raise Error, result.inspect
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,2 @@
|
||||
module Wechat
|
||||
end
|
@ -0,0 +1,11 @@
|
||||
class Wechat::App
|
||||
class << self
|
||||
attr_accessor :appid, :secret
|
||||
|
||||
delegate :access_token, :jscode2session, to: :client
|
||||
|
||||
def client
|
||||
@_client ||= Wechat::Client.new(appid, secret)
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,74 @@
|
||||
class Wechat::Client
|
||||
BASE_SITE = 'https://api.weixin.qq.com'.freeze
|
||||
|
||||
attr_reader :appid, :secret
|
||||
|
||||
def initialize(appid, secret)
|
||||
@appid = appid
|
||||
@secret = secret
|
||||
end
|
||||
|
||||
def access_token
|
||||
# 7200s 有效时间
|
||||
Rails.cache.fetch(access_token_cache_key, expires_in: 100.minutes) do
|
||||
result = request(:get, '/cgi-bin/token', appid: appid, secret: secret, grant_type: 'client_credential')
|
||||
result['access_token']
|
||||
end
|
||||
end
|
||||
|
||||
def refresh_access_token
|
||||
Rails.cache.delete(access_token_cache_key)
|
||||
access_token
|
||||
end
|
||||
|
||||
def jsapi_ticket
|
||||
# 7200s 有效时间
|
||||
Rails.cache.fetch(jsapi_ticket_cache_key, expires_in: 100.minutes) do
|
||||
result = request(:get, '/cgi-bin/ticket/getticket', access_token: access_token, type: 'jsapi')
|
||||
result['ticket']
|
||||
end
|
||||
end
|
||||
|
||||
def refresh_jsapi_ticket
|
||||
Rails.cache.delete(jsapi_ticket_cache_key)
|
||||
jsapi_ticket
|
||||
end
|
||||
|
||||
def jscode2session(code)
|
||||
request(:get, '/sns/jscode2session', appid: appid, secret: secret, js_code: code, grant_type: 'authorization_code')
|
||||
end
|
||||
|
||||
def access_token_cache_key
|
||||
"#{base_cache_key}/access_token"
|
||||
end
|
||||
|
||||
def jsapi_ticket_cache_key
|
||||
"#{base_cache_key}/jsapi_ticket"
|
||||
end
|
||||
|
||||
def base_cache_key
|
||||
"wechat/#{appid}"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def request(method, url, **params)
|
||||
Rails.logger.error("[wechat] request: #{method} #{url} #{params.except(:secret).inspect}")
|
||||
|
||||
client = Faraday.new(url: BASE_SITE)
|
||||
response = client.public_send(method, url, params)
|
||||
result = JSON.parse(response.body)
|
||||
|
||||
Rails.logger.error("[wechat] response:#{response.status} #{result.inspect}")
|
||||
|
||||
if response.status != 200
|
||||
raise Wechat::Error.parse(result)
|
||||
end
|
||||
|
||||
if result['errcode'].present? && result['errcode'].to_i.nonzero?
|
||||
raise Wechat::Error.parse(result)
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
end
|
@ -0,0 +1,14 @@
|
||||
class Wechat::Error < StandardError
|
||||
attr_reader :code
|
||||
|
||||
def initialize(code, message)
|
||||
super message
|
||||
@code = code
|
||||
end
|
||||
|
||||
class << self
|
||||
def parse(result)
|
||||
new(result['errcode'], result['errmsg'])
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,17 @@
|
||||
class Wechat::OfficialAccount
|
||||
class << self
|
||||
attr_accessor :appid, :secret
|
||||
|
||||
delegate :access_token, :jsapi_ticket, to: :client
|
||||
|
||||
def js_sdk_signature(url, noncestr, timestamp)
|
||||
data = { jsapi_ticket: jsapi_ticket, noncestr: noncestr, timestamp: timestamp, url: url }
|
||||
str = data.map { |k, v| "#{k}=#{v}" }.join('&')
|
||||
Digest::SHA1.hexdigest(str)
|
||||
end
|
||||
|
||||
def client
|
||||
@_client ||= Wechat::Client.new(appid, secret)
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,8 @@
|
||||
class DiffRecord < ApplicationRecord
|
||||
belongs_to :user
|
||||
belongs_to :container, polymorphic: true
|
||||
|
||||
has_one :diff_record_content, dependent: :destroy
|
||||
|
||||
delegate :content, to: :diff_record_content
|
||||
end
|
@ -0,0 +1,3 @@
|
||||
class DiffRecordContent < ApplicationRecord
|
||||
belongs_to :diff_record
|
||||
end
|
@ -1,2 +1,3 @@
|
||||
class Forum < ApplicationRecord
|
||||
has_many :memos, dependent: :destroy
|
||||
end
|
||||
|
@ -1,2 +1,5 @@
|
||||
class PortalImage < ApplicationRecord
|
||||
def online?
|
||||
status?
|
||||
end
|
||||
end
|
||||
|
@ -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? || move.id == after.id # 移动至末尾
|
||||
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 - 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@ -0,0 +1,46 @@
|
||||
class CreateDiffRecordService < ApplicationService
|
||||
attr_reader :user, :obj, :column_name, :after, :before
|
||||
|
||||
def initialize(user, obj, column_name, before, after)
|
||||
@user = user
|
||||
@obj = obj
|
||||
@before = before
|
||||
@after = after
|
||||
@column_name = column_name
|
||||
end
|
||||
|
||||
def call
|
||||
ActiveRecord::Base.transaction do
|
||||
diff_record = DiffRecord.create!(user: user, container: obj, column_name: column_name)
|
||||
diff_record.create_diff_record_content!(content: diff_content)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def diff_content
|
||||
content = ''
|
||||
|
||||
arr = []
|
||||
index = 0
|
||||
fragment_size = 1
|
||||
Diffy::Diff.new(before, after).each do |line|
|
||||
unless line =~ /^[\+-]/
|
||||
if arr.empty? && index < fragment_size
|
||||
content += line
|
||||
index += 1
|
||||
else
|
||||
index = 0
|
||||
arr << line
|
||||
arr.shift if arr.size > fragment_size
|
||||
end
|
||||
next
|
||||
end
|
||||
|
||||
content += arr.join('') if arr.present?
|
||||
content += line
|
||||
arr.clear
|
||||
end
|
||||
content
|
||||
end
|
||||
end
|
@ -0,0 +1,43 @@
|
||||
<%
|
||||
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-carousel-modal' } %>
|
||||
</div>
|
||||
<div class="card-body row" id="carousels-container">
|
||||
<% @images.each_with_index do |image, index| %>
|
||||
<div class="col-12 custom-carousel-item custom-carousel-item-<%= image.id %>" data-id="<%= image.id %>">
|
||||
<div class="border rounded relative p-3 mb-3 drag row align-items-center <%= image.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="<%= image.id %>" data-source-type="PortalImage" data-toggle="modal" data-target=".admin-upload-file-modal">
|
||||
<img src="<%= Util::FileManage.exist?('PortalImage', image.id) ? Util::FileManage.disk_file_url('PortalImage', image.id) : '' %>" data-toggle="tooltip" data-title="重新上传"/>
|
||||
</div>
|
||||
<div class="col-10 col-md-7">
|
||||
<div class="input-group">
|
||||
<input type="text" value="<%= image.name %>" class="form-control name-input" placeholder="请输入名称" />
|
||||
<input type="text" value="<%= image.link %>" class="form-control link-input" placeholder="请输入跳转地址">
|
||||
<div class="input-group-prepend">
|
||||
<button class="input-group-text save-data-btn" data-id="<%= image.id %>">保存</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2 col-md-1 operate-box">
|
||||
<%= check_box_tag(:online, 1, image.online?, id: nil, class: 'online-check-box', data: { id: image.id, toggle: 'tooltip', title: '首页展示' }) %>
|
||||
<%= delete_link '删除', admins_carousel_path(image, element: ".custom-carousel-item-#{image.id}", not_refresh: true), class: 'delete-btn' do %>
|
||||
<i class="fa fa-trash-o" data-id="<%= image.id %>"></i>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<%= render partial: 'admins/carousels/shared/add_carousel_modal' %>
|
||||
<%= render partial: 'admins/shared/modal/upload_file_modal' %>
|
@ -0,0 +1,36 @@
|
||||
<div class="modal fade admin-add-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(PortalImage.new, url: admins_carousels_path, html: { class: 'admin-add-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="portal_image[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 :name, label: '名称', placeholder: '请输入名称' %>
|
||||
<%= 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>
|
@ -1 +1,7 @@
|
||||
json.course_evaluations @course_evaluations, partial: 'ecs/course_evaluations/shared/ec_course_evaluation_slim', as: :ec_course_evaluation
|
||||
json.course_evaluations do
|
||||
json.array! @course_evaluations do |course_evaluation|
|
||||
json.partial! 'ecs/course_evaluations/shared/ec_course_evaluation_slim', ec_course_evaluation: course_evaluation
|
||||
|
||||
json.evaluation_relates course_evaluation.evaluation_relates
|
||||
end
|
||||
end
|
@ -1 +0,0 @@
|
||||
json.partial! 'ecs/shared/user', user: @user
|
@ -1,3 +1,4 @@
|
||||
json.status 1
|
||||
json.message "发送成功"
|
||||
json.course_id @course.id
|
||||
json.first_category_url module_url(@course.none_hidden_course_modules.first, @course)
|
@ -0,0 +1,3 @@
|
||||
json.template do
|
||||
json.partial! 'attachments/attachment_simple', attachment: @template.attachments.last
|
||||
end
|
@ -0,0 +1,9 @@
|
||||
class MigrateForumName < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
forum = Forum.find_by(id: 16)
|
||||
if forum.present?
|
||||
forum.update_attributes(name: "通知公告")
|
||||
forum.memos.destroy_all
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,11 @@
|
||||
class CreateDiffRecords < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
create_table :diff_records do |t|
|
||||
t.references :user
|
||||
t.references :container, polymorphic: true
|
||||
t.string :column_name
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,9 @@
|
||||
class CreateDiffRecordContents < ActiveRecord::Migration[5.2]
|
||||
def change
|
||||
create_table :diff_record_contents do |t|
|
||||
t.references :diff_record
|
||||
|
||||
t.text :content
|
||||
end
|
||||
end
|
||||
end
|
@ -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
|
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue