サイボウズみたいな表を作りたい

ここ数日のイメージ

「縦に時間があって、横に人名があって、開始と終了の時間を元に予定を表示させたいな・・・」

こんな感じのプラグインとかヘルパーとかあるんじゃないかと探したが見つからない。
Redmineの1週間の表は1日の予定を出すけど、時間で区切ってくれない。
ガントチャートも人名というグループで表示はしてくれない。
 
 
そこで作りはじめる。
 
コントローラー

/app/controllers/hoge.rb
  def dayview
    @day_gantt = find_response_search
    if request.get?
      if params[:page].nil?
        @day_gantt.empty_daygantt!
        @day_gantt.select_day = Date.parse(params[:select_day]) unless params[:select_day].nil?
        @day_gantt.time_from =  Date.parse(params[:time_from]) unless params[:time_from].nil?
        @day_gantt.time_to = Date.parse(params[:time_to]) unless params[:time_to].nil? 
      end
    else
      @day_gantt.set_daygantt_params(params)
    end    
    params[:page] = 1 if params[:page].nil?
    
    @select_day = @day_gantt.select_day.to_date
    @page_title = "個人表"
    @time_from = @select_day.to_date + @day_gantt.time_from.to_i.hours
    @time_to =@select_day.to_date + @day_gantt.time_to.to_i.hours
    
    @events = []
    @events += Hoge.find(:all,
      :conditions =>["started >= ? AND responded <= ?", @time_from, @time_to])
    @events_staffs = @events.group_by{|event| event.staff_name }
  end

日付と範囲時間で検索、人名でグループ化しています。
 
モデル 

/app/model/hoge_cond.rb
  def empty_daygantt!
    @select_day = Date.today
    @time_from=8
    @time_to=22
  end

  def set_daygantt_params(params)
    @select_day = params[:day_gantt][:select_day]
    @time_from = params[:day_gantt][:time_from]
    @time_to = params[:day_gantt][:time_to]
  end

初期値は「本日の8時から22時まで」とします。
 

ビュー
これを作るときに気がついた。HTMLの都合で横方向を作るのは簡単だけど、縦は難しい。
というこで、横から挑戦。

/app/views/hoge/dayview.html.erb

<%- content_for :html_header do -%>
  <%= stylesheet_link_tag 'calendar' %>
  <%= calendar_date_select_includes %>
<script type="text/javascript">
  _translations = {
    "OK": "OK",
    "Now": "現在",
    "Today": "今日" 
  }
  Date.weekdays = $w("日 月 火 水 木 金 土");
  Date.months = $w("1 2 3 4 5 6 7 8 9 10 11 12" );
</script>
<style type	="text/css"><!--
div.hour_view{
	float:left;
	width:56px;
	text-align:center;
	padding:1px;
	margin:1px;
	border:1px;
	border-style:solid;
	border-color:silver;
}
div.hour_back{
	float:left;
	width:56px;
	height:50px;
	text-align:center;
	color:silver;
	padding:1px;
	margin:1px;
	border:1px;
	border-left-style:solid;
	border-right-style:solid;
	border-left-color:silver;
	border-right-color:silver;
	z-index:1;
}
div.hour_content{
	z-index:10;
	height:30px;
	position:absolute;
	text-align:center;
	margin-top:20px;
	border:1px;
	border-style:solid;
	border-color:green;
}
-->
</style>
<%- end -%>

<h2><%= @page_title %></h2>

<%- form_tag do %>
<table width="100%">
<tr>
<td align="left">
	<%= calendar_date_select(:day_gantt, :select_day) %>
	<%- hours_arr=[[8,8],[9,9],[10,10],[11,11],[12,12],[13,13],[14,14],[15,15],[16,16],[17,17],[18,18],[19,19],[20,20],[21,21],[22,22]] -%>
	<%= select :day_gantt, :time_from, hours_arr, :selected=>@day_gantt.time_from.to_i %>から
	<%= select :day_gantt, :time_to, hours_arr, :selected=>@day_gantt.time_to.to_i %>まで
	<%= submit_tag "変更", :class => "button-small" %>    
</td>
<td><%= @select_day %></td>
</tr>
</table>
<%- end -%>

<table width="100%" style="border:1; border-collapse: collapse;">
<tr>
	<th width="60px">staff<br /></th>
	<th >対応<br />
	<!-- 時間を作る -->
	<%- if @day_gantt.time_to.to_i > @day_gantt.time_from.to_i
		hours_count = @day_gantt.time_to.to_i - @day_gantt.time_from.to_i 
		else
		hours_count = 1
		end 
		start_hours = @day_gantt.time_from.to_i
	-%>
	
	<!-- ヘッダ時間を表示する -->
	<%- hours_count.times{|i| %>
		<div class="hour_view"><%= start_hours %></div>
	<%- start_hours=start_hours+1 } %>
	</th>
</tr>

<%- @events_staffs.each do |staffs, res| %>
<tr>
<td>
<%= staffs %>
</td>
<td>
	<!-- 背景を作る -->
	<%- start_hours = @day_gantt.time_from.to_i
		hours_count.times{|i| %>
		<div class="hour_back"><%= start_hours %></div>
	<%- start_hours=start_hours+1	} %>
	
<%- time_taiou = 0 %>
<%- res.each do |i|
#開始位置を作る
	if i.started.hour >= @day_gantt.time_from.to_i
		s_point = (i.started.hour - @day_gantt.time_from.to_i + 1)*60 + i.started.min
	else
		s_point = 0
	end
#終了位置を作る
	e_point_h = (i.responded - i.started)/3600
	e_point_m = ((i.responded - i.started) % 3600) / 60
	if e_point_h < 1
		e_point = e_point_m
	else
		e_point = e_point_h*60 + e_point_m
	end
#累計時間
	time_taiou += (i.responded - i.started)
%>
<%- s="left:"+s_point.to_s+"px;"+"width:"+e_point.to_s+"px;" -%>

<div style="<%= s %>" class="hour_content">
<%= modal_link_to truncate("■", :length=>4), {:action=>:modal_open},{:id=>i.req_id} %>
<%= modal_script :id=> i.req_id %>
</div>

<%- end %>

<div>
<%- 
hours_t = time_taiou.divmod(3600)
mins_t = hours_t[1].divmod(60)
%>
<%= hours_t[0].to_s%>時間<%= mins_t[0].to_s%>分
</div>

</td>
<</tr>
<%- end %>

</table>

プラグインとか使っているので、適当に取り込んでもらえれば動くはず。
1時間を60pxで計算しているので、文章を表示するスペースが足りない・・・■に苦笑
 
適当なCSSがわるいと思うけど、Firefox3でモーダルが消えない・・・
 
次は縦を考えぞ!