at功能实现
This commit is contained in:
parent
38215dad77
commit
d351827ba2
14
Gemfile
14
Gemfile
|
@ -49,9 +49,6 @@ gem 'kaminari'
|
|||
gem 'elasticsearch-model'
|
||||
gem 'elasticsearch-rails'
|
||||
|
||||
### profile
|
||||
# gem 'oneapm_rpm'
|
||||
|
||||
group :development do
|
||||
gem 'grape-swagger'
|
||||
gem 'better_errors', '~> 1.1.0'
|
||||
|
@ -60,11 +57,18 @@ group :development do
|
|||
if RUBY_PLATFORM =~ /w32/
|
||||
gem 'win32console'
|
||||
end
|
||||
|
||||
if RUBY_PLATFORM =~ /darwin/
|
||||
gem 'puma'
|
||||
end
|
||||
end
|
||||
|
||||
group :development, :test do
|
||||
gem 'rspec-rails', '~> 3.5'
|
||||
gem "test-unit", "~>3.0"
|
||||
if RUBY_VERSION >= '2.0.0'
|
||||
gem 'pry-byebug'
|
||||
gem "test-unit", "~>3.0"
|
||||
end
|
||||
gem 'rspec-rails', '~> 3.0'
|
||||
end
|
||||
|
||||
# Gems used only for assets and not required
|
||||
|
|
|
@ -17,17 +17,18 @@ module Mobile
|
|||
end
|
||||
else
|
||||
case field
|
||||
when :download_url
|
||||
"attachments/download/#{f.try(:id)}"
|
||||
when :file_dir
|
||||
"attachments/download/" << f.send(:id).to_s << '/'
|
||||
when :attafile_size
|
||||
(number_to_human_size(f.filesize)).gsub("ytes", "").to_s
|
||||
when :coursename
|
||||
f.course.nil? ? "" : f.course.name
|
||||
f.try(:course).try(:name) || ''
|
||||
when :syllabus_title
|
||||
f.course.nil? ? "" : f.course.syllabus.nil? ? "" : f.course.syllabus.title
|
||||
f.try(:course).try(:syllabus).try(:title) || ''
|
||||
when :course_id
|
||||
f.course.nil? ? 0 : f.course.id
|
||||
|
||||
f.try(:course).try(:id) || 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -50,6 +51,8 @@ module Mobile
|
|||
current_user_is_teacher = is_course_teacher(current_user,instance.course)
|
||||
current_user_is_teacher
|
||||
end
|
||||
|
||||
attachment_expose :download_url
|
||||
end
|
||||
end
|
||||
end
|
|
@ -180,6 +180,8 @@ module Mobile
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
expose :attachments, using: Mobile::Entities::Attachment
|
||||
end
|
||||
end
|
||||
end
|
|
@ -117,6 +117,9 @@ class ApplicationController < ActionController::Base
|
|||
elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth?
|
||||
# RSS key authentication does not start a session
|
||||
user = User.find_by_rss_key(params[:key])
|
||||
elsif session[:wechat_openid]
|
||||
uw = UserWechat.find_by_openid(session[:wechat_openid])
|
||||
user = uw.user if uw
|
||||
end
|
||||
end
|
||||
if user.nil? && Setting.rest_api_enabled? && accept_api_auth?
|
||||
|
@ -509,8 +512,7 @@ class ApplicationController < ActionController::Base
|
|||
# render_404
|
||||
# end
|
||||
|
||||
def self.
|
||||
model_object(model)
|
||||
def self.model_object(model)
|
||||
self.model_object = model
|
||||
end
|
||||
|
||||
|
|
|
@ -72,8 +72,10 @@ class AttachmentsController < ApplicationController
|
|||
|
||||
def direct_download
|
||||
@attachment.increment_download
|
||||
file_type = detect_content_type(@attachment)
|
||||
|
||||
send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename),
|
||||
:type => detect_content_type(@attachment),
|
||||
:type => file_type,
|
||||
:disposition => 'attachment' #inline can open in browser
|
||||
end
|
||||
|
||||
|
@ -130,11 +132,7 @@ class AttachmentsController < ApplicationController
|
|||
def download
|
||||
# modify by nwb
|
||||
# 下载添加权限设置
|
||||
if (params[:type] && params[:type] == "wechat" )
|
||||
candown = true
|
||||
else
|
||||
candown = attachment_candown @attachment
|
||||
end
|
||||
candown = attachment_candown @attachment
|
||||
|
||||
if candown || User.current.admin? || User.current.id == @attachment.author_id
|
||||
if stale?(:etag => @attachment.digest)
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#coding=utf-8
|
||||
|
||||
require 'base64'
|
||||
class WechatsController < ActionController::Base
|
||||
wechat_responder
|
||||
|
||||
|
@ -485,9 +487,33 @@ class WechatsController < ActionController::Base
|
|||
end
|
||||
|
||||
|
||||
# 用于权限跳转
|
||||
def auth
|
||||
state = params[:state]
|
||||
url = "#{ROOT_URL}/wechat/auth_callback"
|
||||
authorize_url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=#{Wechat.config.appid}&redirect_uri=#{url}&response_type=code&scope=snsapi_base&state=#{state}&connect_redirect=1#wechat_redirect"
|
||||
redirect_to authorize_url
|
||||
end
|
||||
|
||||
def auth_callback
|
||||
path = Base64.urlsafe_decode64(params[:state])
|
||||
open_id = get_openid_from_code(params[:code])
|
||||
unless open_id
|
||||
render 'wechats/open_wechat', layout: nil and return
|
||||
end
|
||||
|
||||
redirect_to "/wechat/user_activities##{path}"
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def get_openid_from_code(code)
|
||||
return 'oCnvgvz8R7QheXE-R9Kkr39j8Ndg' if code =='only-for-test'
|
||||
if code =='only-for-test'
|
||||
openid = 'o3ss_wHOOnHkz1khBJxH8RF4SfPY'
|
||||
session[:wechat_openid] = openid
|
||||
return openid
|
||||
end
|
||||
|
||||
openid = session[:wechat_openid]
|
||||
unless openid
|
||||
if code
|
||||
|
|
|
@ -397,7 +397,7 @@ class Attachment < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def course
|
||||
container
|
||||
Course === container ? container : nil
|
||||
end
|
||||
|
||||
def visible?(user=User.current)
|
||||
|
|
|
@ -1412,6 +1412,8 @@ RedmineApp::Application.routes.draw do
|
|||
post :bind
|
||||
post :get_bind
|
||||
post :is_bind
|
||||
get :auth
|
||||
get :auth_callback
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
<script src="/javascripts/wechat/others/routes.js"></script>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -27,6 +27,18 @@
|
|||
<div class="c-grey4 f13 mt5"><span class="mr10">{{issue.project_name}} - 项目问题</span><span>{{issue.created_on}}</span></div>
|
||||
|
||||
<div class="f13 c-black mt5 text-control post-all-content" ng-bind-html="issue.description|safeHtml" img-preview></div>
|
||||
|
||||
|
||||
<ul class="weixin-files clear f14 mb10">
|
||||
<ol ng-repeat="attachment in issue.attachments"><img src="images/wechat/w-icons-file.png" width="18" style="vertical-align:top; margin-top:2px;" class="mr5" /><a class="c-blue " ng-href="{{attachment.download_url}}">{{attachment.filename}}</a><span class="c-grey ml5 ">({{attachment.attafile_size}})</span></ol>
|
||||
</ul>
|
||||
|
||||
<div class=" clear f14 mb10">
|
||||
<div ng-repeat="attachment in previewImgUrls track by $index">
|
||||
<img ng-click="previewImg($index)" ng-src="{{attachment}}" width="50" class="mr5 weixin-files-img fl" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="c-grey f12 mr15">状 态:{{issue.issue_status}}</span>
|
||||
<span class="c-grey f12">优先级:{{issue.issue_priority}}</span><br/>
|
||||
<span class="c-grey f12 mr15">指派给:{{issue.issue_assigned_to}}</span>
|
||||
|
@ -114,7 +126,7 @@
|
|||
<div class="post-reply-row border-bottom-none">
|
||||
<div class="post-input-container">
|
||||
<div class="copy-input-container"><textarea class="copy-input"></textarea></div>
|
||||
<textarea input-auto type="text" class="post-reply-input" id="postInput1" ng-model="issue.comment" placeholder="输入回复内容~" /></textarea>
|
||||
<textarea input-auto type="text" class="post-reply-input" id="postInput1" ng-change="onPostChange(issue.comment, '{{issue.comment}}')" ng-model="issue.comment" placeholder="输入回复内容~" /></textarea>
|
||||
<button ng-click="addReply(issue,0)" ng-disabled="issue.disabled" ng-hide="issue.disabled" class="post-reply-submit fr border-radius">提交</button>
|
||||
<button ng-disabled="issue.disabled" ng-hide="!issue.disabled" class="post-reply-submit bg-grey fr border-radius">提交</button>
|
||||
<div class="cl"></div>
|
||||
|
@ -124,4 +136,15 @@
|
|||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="post-container wechat-at" ng-show="showAtDialog">
|
||||
<div loading-spinner></div>
|
||||
<div class="class-detail-name"><span class="course-name-width hidden inline-block">选择您要@的人</span>
|
||||
<button>取消</button>
|
||||
</div>
|
||||
<ul class="weixin-users-all">
|
||||
<li ng-repeat="person in at_persons track by $index" ng-click="selectAtPerson($index)"><p class="fl ">{{person.name}}</p><p class="fl ">({{person.login}})</p></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
|
@ -10,6 +10,7 @@ app.constant('config', {
|
|||
app.run(['$rootScope', 'auth', '$location', '$routeParams', function($rootScope, auth, $location, $routeParams){
|
||||
|
||||
if(g_redirect_path && g_redirect_path.length>1){
|
||||
console.log(g_redirect_path);
|
||||
$location.path(g_redirect_path);
|
||||
g_redirect_path = null;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,54 @@
|
|||
app.controller('IssueController', ['$scope', '$http', '$routeParams', 'auth', 'common', function($scope, $http, $routeParams, auth, common){
|
||||
app.controller('IssueController', ['$scope', '$http', '$routeParams', 'auth', 'common',
|
||||
function($scope, $http, $routeParams, auth, common){
|
||||
|
||||
var vm = $scope;
|
||||
vm.previewImgUrls = [];
|
||||
vm.showAtDialog = false;
|
||||
|
||||
var parseAtPersons = function (comment) {
|
||||
var selectedPersons = [];
|
||||
var ss = comment.match(/@(.+?)\s+/g);
|
||||
|
||||
for(var i in ss){
|
||||
var personName = ss[i].substr(1, ss[i].length-2);
|
||||
console.log(personName);
|
||||
|
||||
for(var j in vm.at_persons){
|
||||
var person = vm.at_persons[j];
|
||||
if(person.name == personName){
|
||||
selectedPersons.push(person);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(var i in selectedPersons){
|
||||
var person = selectedPersons[i];
|
||||
comment = comment.replace('@'+person.name+' ',
|
||||
'<span class="atwho-inserted"><span class="at" data-user-id="'+person.id
|
||||
+'"><a href="/users/'+person.id+'">@'+person.name+'('+person.login+')'+' </a></span></span>'
|
||||
);
|
||||
}
|
||||
return comment;
|
||||
};
|
||||
|
||||
vm.onPostChange = function (newValue, oldValue) {
|
||||
if(newValue.length > oldValue.length && newValue.match(/@$/)=='@'){
|
||||
console.log('@ fire');
|
||||
vm.showAtDialog = true;
|
||||
if(!vm.at_persons){
|
||||
$http.get('/at/'+$routeParams.id+'.json?type=Issue').then(function (response) {
|
||||
vm.at_persons = response.data;
|
||||
});
|
||||
}
|
||||
}
|
||||
console.log(vm.issue.comment);
|
||||
};
|
||||
|
||||
vm.selectAtPerson = function (index) {
|
||||
var person = vm.at_persons[index];
|
||||
vm.showAtDialog = false;
|
||||
vm.issue.comment += person.name + ' ';
|
||||
};
|
||||
|
||||
common.init({
|
||||
id: $routeParams.id,
|
||||
|
@ -18,11 +68,29 @@ app.controller('IssueController', ['$scope', '$http', '$routeParams', 'auth', 'c
|
|||
replytype = data.type;
|
||||
page = data.page;
|
||||
|
||||
|
||||
var parseImgAttachment = function(attachments){
|
||||
var urls = [];
|
||||
if(!attachments){
|
||||
return urls;
|
||||
}
|
||||
|
||||
for(var i = attachments.length-1; i>=0; i--){
|
||||
if(attachments[i].filename.match('.jpg$')=='.jpg' || attachments[i].filename.match('.png$')=='.png'){
|
||||
urls.push(attachments[i].download_url);
|
||||
attachments.splice(i, 1);
|
||||
}
|
||||
}
|
||||
urls.push('http://imgsrc.baidu.com/baike/pic/item/f9198618367adab43246bfa18ed4b31c8601e4ba.jpg');
|
||||
return urls;
|
||||
};
|
||||
|
||||
if (replytype == 0){
|
||||
if (page == 0){
|
||||
$scope.issue = data.data;
|
||||
$scope.page = 0;
|
||||
$scope.is_public = data.is_public;
|
||||
$scope.previewImgUrls = parseImgAttachment($scope.issue.attachments);
|
||||
}
|
||||
else{
|
||||
$scope.issue.all_children = $scope.issue.all_children.concat(data.data.all_children);
|
||||
|
@ -42,6 +110,17 @@ app.controller('IssueController', ['$scope', '$http', '$routeParams', 'auth', 'c
|
|||
}
|
||||
},
|
||||
replyCallback: function(){
|
||||
},
|
||||
beforeReplay: function(data){
|
||||
return parseAtPersons(data);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.previewImg = function(index){
|
||||
console.log(index);
|
||||
wx.previewImage({
|
||||
current: $scope.previewImgUrls[index], // 当前显示图片的http链接
|
||||
urls: $scope.previewImgUrls // 需要预览的图片http链接列表
|
||||
});
|
||||
}
|
||||
}]);
|
|
@ -94,24 +94,17 @@ app.factory('rms', function(){
|
|||
});
|
||||
|
||||
app.factory('common', ['$http', 'auth', '$routeParams','rms','config','wx','$location', function($http, auth, $routeParams,rms,config,wx,$location){
|
||||
var addCommonReply = function(id, type, data,args,reply_type, cb){
|
||||
//先判断有没有绑定
|
||||
// $http.post(
|
||||
// '/wechat/is_bind',
|
||||
// {} ///不用传code了,都由服务器来处理
|
||||
// ).then(function(response){
|
||||
// console.log(response.data);
|
||||
// if(response.data.status != 0){
|
||||
// $location.path("/login_tip");
|
||||
// }
|
||||
// });
|
||||
|
||||
var addCommonReply = function(id, type, data,args,reply_type, beforeReply, cb){
|
||||
if(!data.comment || data.comment.length<=0){
|
||||
return;
|
||||
}
|
||||
|
||||
var temp = data.comment.replace(/\n/g,'<br/>');
|
||||
|
||||
if(typeof beforeReply==='function'){
|
||||
temp = beforeReply(temp);
|
||||
}
|
||||
|
||||
var userInfo = {
|
||||
type: type,
|
||||
content: temp,
|
||||
|
@ -121,6 +114,8 @@ app.factory('common', ['$http', 'auth', '$routeParams','rms','config','wx','$loc
|
|||
//回复按钮禁用
|
||||
data.disabled = true;
|
||||
|
||||
console.log(userInfo);
|
||||
|
||||
$http({
|
||||
method: 'POST',
|
||||
url: apiUrl+ "new_comment/"+id,
|
||||
|
@ -308,7 +303,8 @@ app.factory('common', ['$http', 'auth', '$routeParams','rms','config','wx','$loc
|
|||
loadData(args.id,0,0);
|
||||
args.scope.addReply = function(data,reply_type){
|
||||
console.log(data.comment);
|
||||
addCommonReply(data.act_id, args.replyType, data,args,reply_type, function(subscribe){
|
||||
|
||||
addCommonReply(data.act_id, args.replyType, data,args, reply_type, args.beforeReplay, function(subscribe){
|
||||
// args.scope.formData = {comment: ''};
|
||||
if(subscribe == 0){
|
||||
$location.path("/login_tip");
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
@charset "utf-8";
|
||||
/* CSS Document */
|
||||
|
||||
html, body{ margin:0; height:100%; }
|
||||
|
||||
/*基本样式*/
|
||||
body,table,input,textarea,select,button { font-family: "微软雅黑","宋体","Helvetica Neue", Helvetica, Arial, sans-serif;}
|
||||
body, ul, h1,h2,h3,h4,h5,p,pre,input {padding:0px; margin:0px;}
|
||||
|
@ -263,4 +265,22 @@ a.underline {text-decoration:underline;}
|
|||
/*资料修改*/
|
||||
.blank-row {width:100%; height:38px; line-height:38px; vertical-align:middle;}
|
||||
.upload-input-container {width:30px; height:30px; border:1px solid #ddd; position:relative;}
|
||||
.upload-input {width:30px; height:30px; position:absolute; z-index:1; opacity:0;}
|
||||
.upload-input {width:30px; height:30px; position:absolute; z-index:1; opacity:0;}
|
||||
.select-container {position:relative; padding-left:62px;}
|
||||
.select-text {position:absolute; left:15px;}
|
||||
.select-model {width:100%; border:none; color:#999; margin-top:8px;}
|
||||
|
||||
|
||||
/*附件显示 20161202byLB*/
|
||||
.clear:after{clear:both;content:".";display:block;font-size:0;height:0;line-height:0;visibility:hidden}
|
||||
.clear{clear:both;zoom:1}
|
||||
.weixin-files{ width:100%; word-break:break-all; word-wrap: break-word;}
|
||||
.weixin-files ol{-webkit-padding-start: 0px;}
|
||||
.weixin-files-img{ border:1px solid #eee; padding:2px; width:50px; margin-bottom:5px;}
|
||||
/*所有人 20161202byLB*/
|
||||
.weixin-users-all{ width:100%; background:#fff;}
|
||||
.weixin-users-all li{ height:40px; line-height:40px; font-size:14px; color:#888; padding:0 15px; border-bottom:1px solid #ccc;}
|
||||
.weixin-users-all li:hover{ background:#f4f4f4;}
|
||||
|
||||
/*弹出@选择对话框 guange*/
|
||||
.wechat-at {position: fixed; top: 0; left:0; width: 100%; height: 100%; background-color: #ffffff;}
|
Loading…
Reference in New Issue