超碰91资源站-超碰97豆花-超碰97人妻-超碰97人人干-超碰97人人香蕉-超碰97天天操-超碰97在线资源站-超碰97资源站共享-超碰97资源站总站-超碰aa在线91-超碰av操-超碰爱爱

半岛外围网上直营

工作流的實現(在Ruby on Rails環境下)

轉帖|其它|編輯:郝浩|2009-02-09 11:33:47.000|閱讀 3526 次

概述:工作流是企業開發中不可或缺的一個重要組件。有了工作流,客戶需求的實現速度將大大提高,同時兼顧到開發效率,靈活性。Java領域已經有了多個穩定的工作流,成了Java占領企業級開發的有力助手。

# 界面/圖表報表/文檔/IDE等千款熱門軟控件火熱銷售中 >>

  工作流是企業開發中不可或缺的一個重要組件。有了工作流,客戶需求的實現速度將大大提高,同時兼顧到開發效率,靈活性。Java領域已經有了多個穩定的工作流,成了Java占領企業級開發的有力助手。但在ROR領域,目前還沒有出色的工作流出現。RubyForge上有一些工作流的項目,但仔細看下,都是針對Java工作流的移植,而且達不到可以實用的程度。面對這個現狀,我在2006年自己開發了一個小型Ruby工作流,雖然代碼量小,但是實用性卻不錯,對于一些真實的使用案例能夠輕松勝任,也有力的支撐著我繼續向ROR道路前行。

  下面介紹我的工作流是怎么實現的。

  用VC寫一個工作流設計器,這個小軟件功能比較簡單,包含一些簡單符號的繪圖及拖拽,比如開始、結束、狀態、流轉。對于每個狀態可以設置權限,對于每個流轉可以設置條件。我在工作流領域研究的不是很深,開發這個設計器就以實用性為原則,沒有實現的特別復雜。在能夠實現用戶需求的基礎上怎么簡單怎么做。

點擊查看大圖

文件保存為xml格式

Xml代碼
<?xml version="1.0" encoding="gb2312" ?> 
<workflow> 
    <start right="" leave="" enter="@form.a2 = @user.truename&#x0D;&#x0A;@form.c2 = @user.department.name" x1="97" y1="156" x2="247" y2="279" /> 
    <end right="行政歸檔" x1="969" y1="148" x2="1129" y2="285" enter="" /> 
    <state name="部門經理審批" right="領導" enter="" leave="" x1="343" y1="179" x2="453" y2="253" /> 
    <state name="總經理審批" right="經理審批" enter="" leave="" x1="566" y1="34" x2="668" y2="98" /> 
    <state name="行政審批" right="行政審批" enter="" leave="" x1="717" y1="191" x2="870" y2="244" /> 
    <trasit name="" condition="" from="開始" to="部門經理審批" /> 
    <trasit name="大于等于3天" condition="@form.b5!=nil &amp;&amp; @form.b5 &gt;=3" from="部門經理審批" to="總經理審批" /> 
    <trasit name="" condition="@form.b5 == nil || @form.b5 &lt;3" from="部門經理審批" to="行政審批" /> 
    <trasit name="" condition="" from="總經理審批" to="行政審批" /> 
    <trasit name="" condition="" from="行政審批" to="結束" /> 
</workflow> 

<?xml version="1.0" encoding="gb2312" ?>
<workflow>
    <start right="" leave="" enter="@form.a2 = @user.truename&#x0D;&#x0A;@form.c2 = @user.department.name" x1="97" y1="156" x2="247" y2="279" />
    <end right="行政歸檔" x1="969" y1="148" x2="1129" y2="285" enter="" />
    <state name="部門經理審批" right="領導" enter="" leave="" x1="343" y1="179" x2="453" y2="253" />
    <state name="總經理審批" right="經理審批" enter="" leave="" x1="566" y1="34" x2="668" y2="98" />
    <state name="行政審批" right="行政審批" enter="" leave="" x1="717" y1="191" x2="870" y2="244" />
    <trasit name="" condition="" from="開始" to="部門經理審批" />
    <trasit name="大于等于3天" condition="@form.b5!=nil &amp;&amp; @form.b5 &gt;=3" from="部門經理審批" to="總經理審批" />
    <trasit name="" condition="@form.b5 == nil || @form.b5 &lt;3" from="部門經理審批" to="行政審批" />
    <trasit name="" condition="" from="總經理審批" to="行政審批" />
    <trasit name="" condition="" from="行政審批" to="結束" />
</workflow>

  然后將這個文件發布到系統上,由Ruby來解析這個工作流,解析工作流的Ruby代碼(放在lib目錄下)如下:

Ruby代碼
#Flow.rb  
 
require 'rexml/document' 
require "State" 
require "Trasit" 
require "Flow" 
require "pp" 
 
include REXML  
 
class Flow   
  attr_accessor :name, :publish_time 
  attr_reader :trasits, :states 
  def initialize(name, xmlstr, publish_time)  
    @publish_time = publish_time  
    @name = name  
      
    #存放所有狀態,包括開始狀態和結束,開始狀態放在第一個,結束狀態放在最后  
    @states = Array.new 
    @trasits = Array.new 
      
    #載入XML文檔  
    doc = Document.new(xmlstr)  
      
    #開始解析doc文檔  
    root = doc.root  
      
    #解析開始狀態節點  
    root.elements.each("start") {|element|  
      start = State.start  
      start.name = "開始" 
      start.enter = element.attributes["enter"].gbk  
      start.leave = element.attributes["leave"].gbk  
      start.right = element.attributes["right"].gbk  
      start.x1 = element.attributes["x1"].to_i  
      start.x2 = element.attributes["x2"].to_i  
      start.y1 = element.attributes["y1"].to_i  
      start.y2 = element.attributes["y2"].to_i  
      @states << start  
      break 
    }  
      
    #解析所有狀態節點  
    root.elements.each("state") {|element|  
      state = State.new 
      state.name = element.attributes["name"].gbk  
      state.right = element.attributes["right"].gbk  
      state.enter = element.attributes["enter"].gbk  
      state.leave = element.attributes["leave"].gbk  
      state.x1 = element.attributes["x1"].to_i  
      state.x2 = element.attributes["x2"].to_i  
      state.y1 = element.attributes["y1"].to_i  
      state.y2 = element.attributes["y2"].to_i  
      @states << state  
    }  
      
    #解析結束狀態節點  
    root.elements.each("end") {|element|  
      end_node = State.new 
      end_node.name = "結束" 
      end_node.right = element.attributes["right"].gbk  
      end_node.enter = element.attributes["enter"].gbk  
      end_node.x1 = element.attributes["x1"].to_i  
      end_node.x2 = element.attributes["x2"].to_i  
      end_node.y1 = element.attributes["y1"].to_i  
      end_node.y2 = element.attributes["y2"].to_i  
        
      @states << end_node  
    }  
    #解析所有流轉  
    root.elements.each("trasit") {|element|  
      from_name = element.attributes["from"].gbk  
      to_name = element.attributes["to"].gbk  
          
      for state in @states 
        if state.name == from_name  
          from_node = state  
        end 
        if state.name == to_name  
          to_node = state  
        end 
      end         
          
      trasit = Trasit.new(from_node, to_node)  
      trasit.name = element.attributes["name"].gbk  
      trasit.condition = element.attributes["condition"].gbk  
          
      from_node.trasits << trasit  
      to_node.guest_trasits << trasit  
      @trasits << trasit    
    }  
  end 
    
  def start  
    @states[0]  
  end 
    
  def get_state(name)  
    for state in @states 
      return state if state.name == name  
    end 
    nil 
  end 
    
end 

#Flow.rb

require 'rexml/document'
require "State"
require "Trasit"
require "Flow"
require "pp"[SPAN]

include REXML

class Flow
  attr_accessor :name, :publish_time
  attr_reader :trasits, :states
  def initialize(name, xmlstr, publish_time)
    @publish_time = publish_time
    @name = name
   
    #存放所有狀態,包括開始狀態和結束,開始狀態放在第一個,結束狀態放在最后
    @states = Array.new
    @trasits = Array.new
   
    #載入XML文檔
    doc = Document.new(xmlstr)
   
    #開始解析doc文檔
    root = doc.root
   
    #解析開始狀態節點
    root.elements.each("start") {|element|
      start = State.start
      start.name = "開始"
      start.enter = element.attributes["enter"].gbk
      start.leave = element.attributes["leave"].gbk
      start.right = element.attributes["right"].gbk
      start.x1 = element.attributes["x1"].to_i
      start.x2 = element.attributes["x2"].to_i
      start.y1 = element.attributes["y1"].to_i
      start.y2 = element.attributes["y2"].to_i
      @states << start
      break
    }
   
    #解析所有狀態節點
    root.elements.each("state") {|element|
      state = State.new
      state.name = element.attributes["name"].gbk
      state.right = element.attributes["right"].gbk
      state.enter = element.attributes["enter"].gbk
      state.leave = element.attributes["leave"].gbk
      state.x1 = element.attributes["x1"].to_i
      state.x2 = element.attributes["x2"].to_i
      state.y1 = element.attributes["y1"].to_i
      state.y2 = element.attributes["y2"].to_i
      @states << state
    }
   
    #解析結束狀態節點
    root.elements.each("end") {|element|
      end_node = State.new
      end_node.name = "結束"
      end_node.right = element.attributes["right"].gbk
      end_node.enter = element.attributes["enter"].gbk
      end_node.x1 = element.attributes["x1"].to_i
      end_node.x2 = element.attributes["x2"].to_i
      end_node.y1 = element.attributes["y1"].to_i
      end_node.y2 = element.attributes["y2"].to_i
     
      @states << end_node
    }
    #解析所有流轉
    root.elements.each("trasit") {|element|
      from_name = element.attributes["from"].gbk
      to_name = element.attributes["to"].gbk
    
      for state in @states
        if state.name == from_name
          from_node = state
        end
        if state.name == to_name
          to_node = state
        end
      end    
    
      trasit = Trasit.new(from_node, to_node)
      trasit.name = element.attributes["name"].gbk
      trasit.condition = element.attributes["condition"].gbk
    
      from_node.trasits << trasit
      to_node.guest_trasits << trasit
      @trasits << trasit 
    }
  end
 
  def start
    @states[0]
  end
 
  def get_state(name)
    for state in @states
      return state if state.name == name
    end
    nil
  end
 
end[SPAN]

Ruby代碼
#FlowMeta.rb  
 
$LOAD_PATH.unshift(File.dirname(__FILE__))  
 
require "Flow" 
require "EncodeUtil" 
 
class FlowMeta  
  class << self 
    def LoadAllFlows()  
      YtLog.info "loading all workflow..." 
      $Workflows.clear  
      flows = YtwgWorkflow.find(:all)  
      for flow in flows  
        #LoadWorkFlow(flow.name, flow.content.sub!('<?xml version="1.0" encoding="gb2312" ?>', ''))  
        LoadWorkFlow(flow.name, flow.content, flow.publish_time)  
      end 
    end 
          
    def LoadWorkFlow(name, str, publish_time=Time.new)  
      YtLog.info name  
      $Workflows[name] = Flow.new(name, str, publish_time)  
    end 
          
    def Remove(name)  
      $Workflows.delete(name)  
    end 
  end 
end 

#FlowMeta.rb

$LOAD_PATH.unshift(File.dirname(__FILE__))

require "Flow"
require "EncodeUtil"

class FlowMeta
  class << self
    def LoadAllFlows()
      YtLog.info "loading all workflow..."
      $Workflows.clear
      flows = YtwgWorkflow.find(:all)
      for flow in flows
        #LoadWorkFlow(flow.name, flow.content.sub!('<?xml version="1.0" encoding="gb2312" ?>', ''))
        LoadWorkFlow(flow.name, flow.content, flow.publish_time)
      end
    end
  
    def LoadWorkFlow(name, str, publish_time=Time.new)
      YtLog.info name
      $Workflows[name] = Flow.new(name, str, publish_time)
    end
  
    def Remove(name)
      $Workflows.delete(name)
    end
  end
end

Ruby代碼
#State.rb  
 
##工作流中的狀態  
 
require "Trasit" 
class State  
  attr_accessor :name, :leave, :enter, :right, :trasits, :guest_trasits 
  attr_accessor :x1, :x2, :y1, :y2 
  def initialize  
    #從此狀態出發的流轉  
    @trasits = Array.new 
      
    #從其他狀態到此狀態的流轉  
    @guest_trasits = Array.new 
  end 
      
  def trasits  
    @trasits 
  end 
      
  def add_trasit(trasit)  
    @trasits << trasit  
  end 
    
  def add_guest_trasit(trasit)  
    @guest_trasits << trasit  
  end 
      
  class << self 
    def start  
      start = State.new 
      start.name = "開始" 
      start  
    end 
  end 
end 

#State.rb

##工作流中的狀態

require "Trasit"
class State
  attr_accessor :name, :leave, :enter, :right, :trasits, :guest_trasits
  attr_accessor :x1, :x2, :y1, :y2
  def initialize
    #從此狀態出發的流轉
    @trasits = Array.new
   
    #從其他狀態到此狀態的流轉
    @guest_trasits = Array.new
  end
 
  def trasits
    @trasits
  end
 
  def add_trasit(trasit)
    @trasits << trasit
  end
 
  def add_guest_trasit(trasit)
    @guest_trasits << trasit
  end
 
  class << self
    def start
      start = State.new
      start.name = "開始"
      start
    end
  end
end

Ruby代碼
#Trasit.rb  
 
class Trasit  
    attr_accessor :condition, :name, :from, :to 
      
    #新建流轉類,from,to均為State類對象  
    def initialize(from, to)  
        @from = from  
        @to = to  
    end 
end 

#Trasit.rb

class Trasit
 attr_accessor :condition, :name, :from, :to
 
 #新建流轉類,from,to均為State類對象
 def initialize(from, to)
  @from = from
  @to = to
 end
end

  OK,解析工作流的任務就算完成了,250行Ruby代碼,一個小型的,可定制化程度高的工作流引擎就算是完成了。下面我們就看怎么使用這個工作流了。

  工作流引擎完成以后下面自然而然就會想到用戶在每個流程點上看到的表單界面從何而來?對于這個功能,我專門寫了表單設計器和表單解析引擎,表單解析引擎可將xml格式的表單翻譯為html格式的表單。這個表單組件更為復雜,超出了本討論的范圍,暫且先不說了。[SPAN]

  下面說一下數據庫表,為了使用這個工作流引擎需要建立3張表:

Sql代碼
//工作流表  
CREATE TABLE `ytwg_workflow` (  
  `id` int(11) NOT NULL auto_increment,  
  `name` varchar(100) default NULL,          //工作流名稱  
  `content` longtext,                                   //工作流內容,設計器保存的xml文件  
  `publish_time` datetime default NULL,     //發布時間  
  `formtable` varchar(30) default NULL,      //表單數據存放的表格,每個工作流建立后會單獨建立數據庫表,存放表單數據  
  `position` int(11) default NULL,                 //排序位置  
  `reserved1` varchar(100) default NULL,      
  `reserved2` varchar(100) default NULL,  
  `reserved3` varchar(100) default NULL,  
  `reserved4` varchar(100) default NULL,  
  `reserved5` varchar(100) default NULL,  
  `reserved6` varchar(100) default NULL,  
  PRIMARY KEY  (`id`)  
)   
 
//工作流狀態表單界面表  
CREATE TABLE `ytwg_stateinterface` (  
  `id` int(11) NOT NULL auto_increment,  
  `flowid` int(11) default NULL,                     //工作流id  
  `name` varchar(100) default NULL,            //狀態名稱  
  `content` longtext,                                     //表單,表單設計器保存的xml文件  
  `publish_time` datetime default NULL,       //發布時間  
  `reserved1` varchar(100) default NULL,       
  `reserved2` varchar(100) default NULL,  
  `reserved3` varchar(100) default NULL,  
  `reserved4` varchar(100) default NULL,  
  `reserved5` varchar(100) default NULL,  
  `reserved6` varchar(100) default NULL,  
  PRIMARY KEY  (`id`)  
)   
 
//表單處理記錄表  
CREATE TABLE `ytwg_formhistory` (  
  `id` int(11) NOT NULL auto_increment,  
  `userid` int(11) default NULL,                    //用戶id  
  `flowid` int(11) default NULL,                     //工作流id  
  `formid` int(11) default NULL,                     //表單id  
  `process_time` datetime default NULL,      //處理時間  
  PRIMARY KEY  (`id`)  
)  

//工作流表
CREATE TABLE `ytwg_workflow` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(100) default NULL,          //工作流名稱
  `content` longtext,                                   //工作流內容,設計器保存的xml文件
  `publish_time` datetime default NULL,     //發布時間
  `formtable` varchar(30) default NULL,      //表單數據存放的表格,每個工作流建立后會單獨建立數據庫表,存放表單數據
  `position` int(11) default NULL,                 //排序位置
  `reserved1` varchar(100) default NULL,   
  `reserved2` varchar(100) default NULL,
  `reserved3` varchar(100) default NULL,
  `reserved4` varchar(100) default NULL,
  `reserved5` varchar(100) default NULL,
  `reserved6` varchar(100) default NULL,
  PRIMARY KEY  (`id`)
)

//工作流狀態表單界面表
CREATE TABLE `ytwg_stateinterface` (
  `id` int(11) NOT NULL auto_increment,
  `flowid` int(11) default NULL,                     //工作流id
  `name` varchar(100) default NULL,            //狀態名稱
  `content` longtext,                                     //表單,表單設計器保存的xml文件
  `publish_time` datetime default NULL,       //發布時間
  `reserved1` varchar(100) default NULL,    
  `reserved2` varchar(100) default NULL,
  `reserved3` varchar(100) default NULL,
  `reserved4` varchar(100) default NULL,
  `reserved5` varchar(100) default NULL,
  `reserved6` varchar(100) default NULL,
  PRIMARY KEY  (`id`)
)

//表單處理記錄表
CREATE TABLE `ytwg_formhistory` (
  `id` int(11) NOT NULL auto_increment,
  `userid` int(11) default NULL,                    //用戶id
  `flowid` int(11) default NULL,                     //工作流id
  `formid` int(11) default NULL,                     //表單id
  `process_time` datetime default NULL,      //處理時間
  PRIMARY KEY  (`id`)
)

  每發布一個工作流后,跟著要為這個工作流動態創建數據庫表,存放表單數據。我是通過向這個工作流發布一個表單模板來動態創建表的。

  下面看如何使用工作流:

Ruby代碼
#發布工作流    
def create  
    stream = params[:ytwg_workflow][:content]  
    content = stream.read  
    name = stream.original_filename[0, stream.original_filename.index(".")]  
    if YtwgWorkflow.find(:all, :conditions=>"name='#{name}'").size > 0  
      flash[:error] = "存在同名工作流,上傳失敗" 
      render :action => 'new' 
      return 
    end 
      
    @ytwg_workflow = YtwgWorkflow.new()  
    @ytwg_workflow.name = name  
    begin 
      @ytwg_workflow.content = content  
    rescue 
      flash[:error] = "上傳文件非法" 
      render :action => 'new' 
    end 
    @ytwg_workflow.publish_time = Time.new 
    if @ytwg_workflow.save  
      FlowMeta.LoadWorkFlow(@ytwg_workflow.name, @ytwg_workflow.content.sub!('<?xml version="1.0" encoding="gb2312" ?>', ''))  
      flash[:notice] = '添加工作流成功' 
      redirect_to :action => 'list' 
    else 
      flash[:error] = "添加工作流失敗" 
      render :action => 'new' 
    end 
  end 
 
  #上傳表定義模板,根據這個表單動態生成數據庫表  
  def upload_formtable  
    stream = params[:content]  
    content = stream.read  
    helper = XMLHelper.new 
    helper.ReadFromString(content)  
    formtable = helper.tables[0]  
    if !formtable  
      flash[:notice] = "上傳文件格式錯誤" 
      redirect_to :action=>"listinterface" 
      return 
    end 
    conn = ActiveRecord::Base.connection  
    conn.create_table "ytwg_#{formtable.GetTableID}", :primary_key=>:id do |t|  
      t.column "userid", :integer         #流程發起人的id  
      t.column "flowid", :integer         #工作流的id  
      Integer(0).upto(formtable.GetRowCount()-1) do |row|  
        next if formtable.IsEmptyRow(row)  
        Integer(0).upto(formtable.GetColumnCount()-1) do |col|  
          next if formtable.IsEmptyCol(col)  
          cell = formtable.GetCell(row, col)  
          next if !cell.IsStore || !cell.IsEffective  
          next if formtable.GetCellDBFieldName(row, col).downcase == "id" 
               
          t.column "_state", :string, :limit=>30  
          t.column "_madetime", :datetime 
          t.column "_lastprocesstime", :datetime 
          if cell.GetDataType == 1    #CCell.CtNumeric  
            t.column formtable.GetCellDBFieldName(row, col).downcase, :float 
          elsif cell.GetDataType == 0    #CCell.CtText                 
            if cell.IsCheckWidth()  
              t.column formtable.GetCellDBFieldName(row, col).downcase, :string, {:limit=>cell.GetTextWidth}  
            else 
              t.column formtable.GetCellDBFieldName(row, col).downcase, :string, {:limit=>100}  
            end       
          elsif cell.GetDataType == 3 #CCell.CtDate  
            t.column formtable.GetCellDBFieldName(row, col).downcase, :datetime 
          end              
        end 
      end 
    end 
      
    flow = YtwgWorkflow.find(params[:id])  
    flow.formtable = formtable.GetTableID  
    flow.save  
      
    flash[:notice] = "建表成功" 
    redirect_to :action=>"listinterface" 
  end 
 
  #上傳狀態節點的表單界面  
  def uploadinterface  
    stream = params[:content]  
    content = stream.read  
      
    interfaces = YtwgStateinterface.find(:all, :conditions=>"flowid = #{params[:id]} and name = '#{params[:name]}'")  
    if interfaces.size > 0  
      interface = interfaces[0]  
      interface.publish_time = Time.new 
    else 
      interface = YtwgStateinterface.new 
      interface.flowid = params[:id]  
      interface.name = params[:name]  
      interface.publish_time = Time.new 
    end 
    interface.content = content  #EncodeUtil.change("UTF-8", "GB2312", content)  
    interface.save  
    flash[:notice] = "上傳狀態界面成功" 
    redirect_to :action=>"listinterface" 
  end 
 
  #用戶點擊某一工作流連接后,查看自己已經發起的工作流。  
  def show_form  
    @flow = YtwgWorkflow.find(params[:flowid])  
    YtwgForm.set_table_name("ytwg_" + @flow.formtable)  
    YtwgForm.reset_column_information()   
    form = YtwgForm.find(params[:formid])  
       
    interfaces = YtwgStateinterface.find(:all, :conditions=>"flowid=#{params[:flowid]} and name='#{form._state.split(',')[0]}'")  
    if interfaces.size > 0  
      helper = XMLHelper.new 
      helper.ReadFromString(interfaces[0].content)  
      @style = helper.StyleToHTML(helper.tables[0])  
      @html = helper.TableToEditHTML(helper.tables[0], helper.dictionFactory,   
        {:record=>form, :encoding=>"gb2312"})  
      @historys = YtwgFormhistory.find(:all, :conditions=>"flowid=#{params[:flowid]} and formid = #{params[:formid]}")  
    else 
      render :text=>"沒有上傳工作流界面" 
    end 
  end 
 
  #用戶發起或者審批一個表單  
  def write_form  
    @flow = YtwgWorkflow.find(params[:flowid])  
    YtwgForm.set_table_name("ytwg_" + @flow.formtable)  
    YtwgForm.reset_column_information()   
 
    if params[:formid]  
      form_record = YtwgForm.find(params[:formid])  
      state_name = form_record._state  
    else 
      form_record = YtwgForm.new 
      form_record._state = '開始' 
      state_name = form_record._state  
    end 
      
    states = []  
    for state in form_record._state.split(',')  
      states << state if checkright(state)  
    end 
    if states.size > 0  
      state_name = states[0]  
    else 
      state_name = '開始' 
    end 
 
    process = FlowProcess.new($Workflows[@flow.name], form_record, state_name)  
    process.user = session[:user]  
    process.signal_enter  
      
    interfaces = YtwgStateinterface.find(:all, :conditions=>"flowid=#{@flow.id} and name = '#{state_name}'")  
    if interfaces.size ==0  
      render :text=>"沒有上傳開始界面" 
      return 
    end 
    @start_interface = interfaces[0]  
    helper = XMLHelper.new 
    helper.ReadFromString(@start_interface.content)  
    @style = helper.StyleToHTML(helper.tables[0])  
    @html = helper.TableToEditHTML(helper.tables[0], helper.dictionFactory,   
      {:record=>form_record,:encoding=>"gb2312", :script=>helper.script})  
    @historys = YtwgFormhistory.find(:all, :conditions=>"flowid=#{params[:flowid]} and formid = #{params[:formid]}") if params[:formid]  
  end 
 
  #用戶寫完一個表單后點擊提交  
  def update_form  
    @flow = YtwgWorkflow.find(params[:id])  
    YtwgForm.set_table_name("ytwg_" + @flow.formtable)  
    YtwgForm.reset_column_information()   
    if params[:formid]  
      form = YtwgForm.find(params[:formid])  
      form.update_attributes(params[@flow.formtable])  
        
      states = []  
      for state in form._state.split(',')  
        states << state if check_state_right(@flow.name, state)  
      end 
      state_name = states[0]  
    else 
      form = YtwgForm.new(params[@flow.formtable])  
      form._madetime = Time.new 
      form._state = '開始' 
      state_name = form._state  
      form.userid = session[:user].id  
      form.flowid = @flow.id  
    end 
 
    form._lastprocesstime = Time.new      
    process = FlowProcess.new($Workflows[@flow.name], form, state_name)  
    process.user = session[:user]  
    process.signal_leave  
      
    history = YtwgFormhistory.new 
    history.userid = session[:user].id  
    history.flowid = @flow.id  
    history.formid = form.id  
    history.process_time = Time.new 
    history.save  
    redirect_to :action=>'myform', :id=>params[:id]  
  end 
 
 #等待我處理的流程  
  def show_waiting_form  
    @forms = get_wait_form(params[:id])  
    render :layout=>false 
  end 
 
 #獲得某一種單據中等待當前登陸者審批的  
  def get_wait_form(flowid)  
    forms = []  
    flow = YtwgWorkflow.find(flowid)  
    if !flow.formtable || flow.formtable.size==0  
      return forms  
    end 
    YtwgForm.set_table_name("ytwg_" + flow.formtable)  
    YtwgForm.reset_column_information()   
    for state in $Workflows[flow.name].states  
      next if state.name == "結束" 
        
      conditions = []  
      conditions << "_state='#{state.name}'" 
        
      #如果可以從多個狀態轉移到這個狀態,則等待所有狀態都執行完此狀態才可以執行  
      if state.guest_trasits.size == 1      #只可以從一個狀態轉到這里  
        conditions << " _state like '%,#{state.name}'" 
        conditions << "_state like '#{state.name},%'" 
      end 
 
      if state.right == "領導" 
        all_forms = YtwgForm.find(:all, :conditions=>conditions.join(' or '), :order=>"id desc")  
        for form in all_forms  
          forms << form if YtwgUser.find(form.userid).department.leader_id == session[:user].id rescue nil 
        end 
      else 
        for right in state.right.split(',')  
          if checkright(right)  
            forms += YtwgForm.find(:all, :conditions=>conditions.join(' or '), :order=>"id desc")  
          end 
        end 
      end 
    end 
    forms.uniq!  
    return forms  
  end 

#發布工作流 
def create
    stream = params[:ytwg_workflow][:content]
    content = stream.read
    name = stream.original_filename[0, stream.original_filename.index(".")]
    if YtwgWorkflow.find(:all, :conditions=>"name='#{name}'").size > 0
      flash[:error] = "存在同名工作流,上傳失敗"
      render :action => 'new'
      return
    end
   
    @ytwg_workflow = YtwgWorkflow.new()
    @ytwg_workflow.name = name
    begin
      @ytwg_workflow.content = content
    rescue
      flash[:error] = "上傳文件非法"
      render :action => 'new'
    end
    @ytwg_workflow.publish_time = Time.new
    if @ytwg_workflow.save
      FlowMeta.LoadWorkFlow(@ytwg_workflow.name, @ytwg_workflow.content.sub!('<?xml version="1.0" encoding="gb2312" ?>', ''))
      flash[:notice] = '添加工作流成功'
      redirect_to :action => 'list'
    else
      flash[:error] = "添加工作流失敗"
      render :action => 'new'
    end
  end

  #上傳表定義模板,根據這個表單動態生成數據庫表
  def upload_formtable
    stream = params[:content]
    content = stream.read
    helper = XMLHelper.new
    helper.ReadFromString(content)
    formtable = helper.tables[0]
    if !formtable
      flash[:notice] = "上傳文件格式錯誤"
      redirect_to :action=>"listinterface"
      return
    end
    conn = ActiveRecord::Base.connection
    conn.create_table "ytwg_#{formtable.GetTableID}", :primary_key=>:id do |t|
      t.column "userid", :integer         #流程發起人的id
      t.column "flowid", :integer         #工作流的id
      Integer(0).upto(formtable.GetRowCount()-1) do |row|
        next if formtable.IsEmptyRow(row)
        Integer(0).upto(formtable.GetColumnCount()-1) do |col|
          next if formtable.IsEmptyCol(col)
          cell = formtable.GetCell(row, col)
          next if !cell.IsStore || !cell.IsEffective
          next if formtable.GetCellDBFieldName(row, col).downcase == "id"
         
          t.column "_state", :string, :limit=>30
          t.column "_madetime", :datetime
          t.column "_lastprocesstime", :datetime
          if cell.GetDataType == 1    #CCell.CtNumeric
            t.column formtable.GetCellDBFieldName(row, col).downcase, :float
          elsif cell.GetDataType == 0    #CCell.CtText              
            if cell.IsCheckWidth()
              t.column formtable.GetCellDBFieldName(row, col).downcase, :string, {:limit=>cell.GetTextWidth}
            else
              t.column formtable.GetCellDBFieldName(row, col).downcase, :string, {:limit=>100}
            end    
          elsif cell.GetDataType == 3 #CCell.CtDate
            t.column formtable.GetCellDBFieldName(row, col).downcase, :datetime
          end          
        end
      end
    end
   
    flow = YtwgWorkflow.find(params[:id])
    flow.formtable = formtable.GetTableID
    flow.save
   
    flash[:notice] = "建表成功"
    redirect_to :action=>"listinterface"
  end[SPAN]

  #上傳狀態節點的表單界面
  def uploadinterface
    stream = params[:content]
    content = stream.read
   
    interfaces = YtwgStateinterface.find(:all, :conditions=>"flowid = #{params[:id]} and name = '#{params[:name]}'")
    if interfaces.size > 0
      interface = interfaces[0]
      interface.publish_time = Time.new
    else
      interface = YtwgStateinterface.new
      interface.flowid = params[:id]
      interface.name = params[:name]
      interface.publish_time = Time.new
    end
    interface.content = content  #EncodeUtil.change("UTF-8", "GB2312", content)
    interface.save
    flash[:notice] = "上傳狀態界面成功"
    redirect_to :action=>"listinterface"
  end

  #用戶點擊某一工作流連接后,查看自己已經發起的工作流。
  def show_form
    @flow = YtwgWorkflow.find(params[:flowid])
    YtwgForm.set_table_name("ytwg_" + @flow.formtable)
    YtwgForm.reset_column_information()
    form = YtwgForm.find(params[:formid])
    
    interfaces = YtwgStateinterface.find(:all, :conditions=>"flowid=#{params[:flowid]} and name='#{form._state.split(',')[0]}'")
    if interfaces.size > 0
      helper = XMLHelper.new
      helper.ReadFromString(interfaces[0].content)
      @style = helper.StyleToHTML(helper.tables[0])
      @html = helper.TableToEditHTML(helper.tables[0], helper.dictionFactory,
        {:record=>form, :encoding=>"gb2312"})
      @historys = YtwgFormhistory.find(:all, :conditions=>"flowid=#{params[:flowid]} and formid = #{params[:formid]}")
    else
      render :text=>"沒有上傳工作流界面"
    end
  end

  #用戶發起或者審批一個表單
  def write_form
    @flow = YtwgWorkflow.find(params[:flowid])
    YtwgForm.set_table_name("ytwg_" + @flow.formtable)
    YtwgForm.reset_column_information()

    if params[:formid]
      form_record = YtwgForm.find(params[:formid])
      state_name = form_record._state
    else
      form_record = YtwgForm.new
      form_record._state = '開始'
      state_name = form_record._state
    end
   
    states = []
    for state in form_record._state.split(',')
      states << state if checkright(state)
    end
    if states.size > 0
      state_name = states[0]
    else
      state_name = '開始'
    end

    process = FlowProcess.new($Workflows[@flow.name], form_record, state_name)
    process.user = session[:user]
    process.signal_enter
   
    interfaces = YtwgStateinterface.find(:all, :conditions=>"flowid=#{@flow.id} and name = '#{state_name}'")
    if interfaces.size ==0
      render :text=>"沒有上傳開始界面"
      return
    end
    @start_interface = interfaces[0]
    helper = XMLHelper.new
    helper.ReadFromString(@start_interface.content)
    @style = helper.StyleToHTML(helper.tables[0])
    @html = helper.TableToEditHTML(helper.tables[0], helper.dictionFactory,
      {:record=>form_record,:encoding=>"gb2312", :script=>helper.script})
    @historys = YtwgFormhistory.find(:all, :conditions=>"flowid=#{params[:flowid]} and formid = #{params[:formid]}") if params[:formid]
  end

  #用戶寫完一個表單后點擊提交
  def update_form
    @flow = YtwgWorkflow.find(params[:id])
    YtwgForm.set_table_name("ytwg_" + @flow.formtable)
    YtwgForm.reset_column_information()
    if params[:formid]
      form = YtwgForm.find(params[:formid])
      form.update_attributes(params[@flow.formtable])
     
      states = []
      for state in form._state.split(',')
        states << state if check_state_right(@flow.name, state)
      end
      state_name = states[0]
    else
      form = YtwgForm.new(params[@flow.formtable])
      form._madetime = Time.new
      form._state = '開始'
      state_name = form._state
      form.userid = session[:user].id
      form.flowid = @flow.id
    end

    form._lastprocesstime = Time.new   
    process = FlowProcess.new($Workflows[@flow.name], form, state_name)
    process.user = session[:user]
    process.signal_leave
   
    history = YtwgFormhistory.new
    history.userid = session[:user].id
    history.flowid = @flow.id
    history.formid = form.id
    history.process_time = Time.new
    history.save
    redirect_to :action=>'myform', :id=>params[:id]
  end

 #等待我處理的流程
  def show_waiting_form
    @forms = get_wait_form(params[:id])
    render :layout=>false
  end

 #獲得某一種單據中等待當前登陸者審批的
  def get_wait_form(flowid)
    forms = []
    flow = YtwgWorkflow.find(flowid)
    if !flow.formtable || flow.formtable.size==0
      return forms
    end
    YtwgForm.set_table_name("ytwg_" + flow.formtable)
    YtwgForm.reset_column_information()
    for state in $Workflows[flow.name].states
      next if state.name == "結束"
     
      conditions = []
      conditions << "_state='#{state.name}'"
     
      #如果可以從多個狀態轉移到這個狀態,則等待所有狀態都執行完此狀態才可以執行
      if state.guest_trasits.size == 1      #只可以從一個狀態轉到這里
        conditions << " _state like '%,#{state.name}'"
        conditions << "_state like '#{state.name},%'"
      end

      if state.right == "領導"
        all_forms = YtwgForm.find(:all, :conditions=>conditions.join(' or '), :order=>"id desc")
        for form in all_forms
          forms << form if YtwgUser.find(form.userid).department.leader_id == session[:user].id rescue nil
        end
      else
        for right in state.right.split(',')
          if checkright(right)
            forms += YtwgForm.find(:all, :conditions=>conditions.join(' or '), :order=>"id desc")
          end
        end
      end
    end
    forms.uniq!
    return forms
  end

有了上面這些最核心的函數后,如何使用這個工作流基本就算明白了。除此之外還有許多附加的小功能需要去實現,比如導出Excel,導出PDF,在網頁上展示工作流的流程圖(我用VML實現)。以下是請假登記表的表單顯示界面:

點擊查看大圖

  這個工作流的應用現狀:

  目前這個工作流還沒有商用,只有一個應用場景。前幾個月我們公司買了一套金和OA,在銷售員滿嘴跑火車的吹噓下我們經理花9800買了,后來實施的時候發現金和的工作流根本無法使用。一個簡單的請假申請單都無法實現自定義表單和流程,無奈之下我基于我的工作流組件,快速開發了一套OA,幾天之后就上線,然后邊用邊完善,一個月以后就很少再動了。目前公司對這套OA還是比較滿意的。雖然我的OA比國內的優秀OA產品還有很大差距,但是這套工作流組件至少還是能夠勝任大多數場合,對于尚不能滿足的場合還可以靈活擴展。


標簽:

本站文章除注明轉載外,均為本站原創或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@ke049m.cn

文章轉載自:JavaEye

為你推薦

  • 推薦視頻
  • 推薦活動
  • 推薦產品
  • 推薦文章
  • 慧都慧問
相關產品
控件
  • 產品功能:工作流
  • 源 碼:非開源
  • 產品編號:10581
  • 當前版本:v3.1 [銷售以商家最新版為準,如需其他版本,請來電咨詢]
  • 開 發 商: ASPOSE 正式授權
  • ">Aspose.Workflow

    提供了一個功能強大的工作流引擎以及一整套符合業界標準的工作流對象

    控件
  • 產品功能:工作流
  • 源 碼:非開源
  • 產品編號:10721
  • 當前版本:v2004 r2 [銷售以商家最新版為準,如需其他版本,請來電咨詢]
  • 開 發 商: Schneider Electric Software, LLC 正式授權
  • ">Skelta Workflow.NET

    建立在.NET、XML以及Web services技術之上的業務流程管理工作流軟件,同時也是世界上第一個可嵌入的工作流引擎

    控件
  • 產品功能:UI界面
  • 源 碼:非開源
  • 產品編號:11483
  • 當前版本:v2.15 [銷售以商家最新版為準,如需其他版本,請來電咨詢]
  • 開 發 商: tmssoftware 正式授權
  • ">TMS Workflow Studio

    一個Delphi/ C ++ Builder VCL框架的業務流程管理(BPM)控件,為你的應用程序添加工作流和BPM功能

    控件
  • 產品功能:工作流
  • 源 碼:非開源
  • 產品編號:11878
  • 當前版本:2014 R2 SP2 [銷售以商家最新版為準,如需其他版本,請來電咨詢]
  • 開 發 商: Schneider Electric Software, LLC 正式授權
  • ">Wonderware Skelta BPM

    全球第一且功能強大的.NET企業級業務流程管理和高級工作流解決方案

    掃碼咨詢


    添加微信 立即咨詢

    電話咨詢

    客服熱線
    023-68661681

    TOP
    利記足球官網(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) 真人boyu·博魚滾球網(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) 最大網上PM娛樂城盤口(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) 正規雷火競技官方買球(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) 雷火競技權威十大網(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) boyu·博魚信譽足球官網(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) 權威188BET足球網(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) 正規188BET足球大全(官方)網站/網頁版登錄入口/手機版登錄入口-最新版(已更新) 2025自拍偷在线 | 国产超碰91人人 | av在线亚洲欧洲日产一区二区 | 国产成人一区二区在线不卡 | 国产大学生无码理论永久免费 | 91九色| 99精品偷拍视频一区二区三区 | 东京热人妻中文无码av | 国产一区二区三区免费在线视频 | 成人精品女人久久久 | 91无码欧精品亚洲日韩一区 | 国产精品毛片无码一区二区蜜 | 国产视频永久a级毛 | 国产精品亚洲码精品 | 国模精品成人片在线播放 | 精品亚州毛片在线免费观看 | 国产99精品久久 | 911亚洲精品国产自产 | 国产三级| 韩国三级日本三级在线观看 | 国产精品欧美亚洲日本综合 | 国产成人av在线影院 | 国产肥熟女视频一区二区视频 | 国产成人调教在线视频 | 精品无码自拍视频在线观看 | 国产精品高潮呻吟久久 | 国产精品视频一区二区噜噜 | 99精品国产综合久久久久五月 | 国产品无码一区二区三区在线 | 成人夜色视频网站在线观看 | 国产尤物在线观看无码不卡 | 精品国产一区二区三区性色a∨ | 福利国产微拍广场一区视频在 | 国产亚洲中文日本不卡2区 国产亚洲中文日本不卡二区 | 精品无人码麻豆乱码1区2区 | 国产美女福利视频一区二区 | 国产精品露出91 | 精品人妻无码专区在中文字 | 成人午夜有码一区二区 | 国产制服丝袜欧美在线观看 | 国产69精品久久熟女 | 国产毛片一区二区精品 | 精品无码一区二区三区亚洲桃色 | 911国产精品无码久久 | 国产欧美日产高清欧美一区二区 | 国精品午夜福利视频不卡麻豆 | 国产精品玖玖玖在 | 国产成a人亚洲精ⅴ品无码性色 | 国产精品一区二区日韩av在线 | 2025国内精品免费福利视频 | 丰满人妻av无码一区二区 | 国产高清一区二区在线免费观看 | 精品69视频一区二区三区 | 国产黄色网站在线免费观看 | 18禁无遮拦无码国产在线 | 91久久:助你畅享无忧体验 | 91麻豆精品福利在线观看 | 国产午夜亚洲精品国产午夜 | 国产午夜电影久久 | 国产尤物在线视精品在亚洲 | 国产精品入口麻豆免费看 | 国产在线麻豆自在拍91精品 | 国产精品麻豆一区二区三区v视界 | 精品人妻中文字幕有码在线 | 91精品国产三级在线观看 | 国产成人精品一区二区三区视频 | 国产精品成人va在线观看 | 国产无码丝袜 | av无码一区二区三区 | 精品无码专区久久久水蜜桃 | 国产欧美日韩v另类在线播放 | 国产在线观看免费视频软件 | 国产免费伦精品一区二区三区 | 成人免费无码大片a毛片抽搐 | 国产成人调教视频在线观看 | 精品线一区二区三区免费看 | 国产午夜亚洲精品国产午夜 | 国产肥熟女视频一区二区三区 | 国产精品国产三级国产av中文 | www.脏片 | 99国产欧美另 | 国产成人在线网址 | 国产精品高清一区二区不卡乱 | 国产精品成人观看视 | 国产一区二区三区日韩欧美 | 韩国三级大乳女2免费日韩 韩国三级大乳在线观看 | 精品国产福利一区二区在线 | 国产交换精品一区二区三区 | 国产黄页网站视频在线观看 | 成人午夜亚洲精品无码网站 | 成本人妻片无码中文字幕免费 | 国产精品三级av及在线观看 | 国产av熟女一区二区三区 | 国产午夜激无码av毛片护士 | 国产成人无码综合亚洲日韩色欲 | 加勒比色综合久久久久久久久 | 精品一区二区剧情熟女 | 动漫精品中文无码卡通动漫 | 国模αv人体视频 | 高潮湖久久久久久久久 | 国产99er66在线视频 | 2025国产剧情a在线 | 国产在线欧美一区二区 | 国产无码精品在线观看 | 国产福利片无码 | 东京热亚洲精品无码 | 国产日韩成人在线 | 国产中文字幕乱码免在线观看 | 二区欧美人 | 国产拍偷自偷在线视频 | 国产91欧美情侣在线 | 国产成人性生交大片免费看 | 国产精品tv在线观看 | 国产女主播一区 | 69精品视频 | 高潮流白浆潮喷 | 97人洗澡人人澡人人爽人人模 | 国女精品爽爽一区二区 | 精品国产av一二三四区 | 国产一区二区三区在线影院 | 国产精品亚洲欧美大片在线看 | 精品无人国产偷自产在线日本 | 国产日韩亚洲三级片在线观 | 另类欧美亚洲曰本 | 国产成人涩涩涩视频在线观 | 精品无码欧美一区二区三区不卡 | 2025天天做夜夜爽视频综合 | 国产精品午夜在线观看 | 国产人妖专区 | 国产成人免费片在线视频观看 | 91久久久久国产一区二区 | 国产精品区一区二区三在线 | 国产极品粉嫩美女在线播放 | 国产女性无遮挡免费裸体视频 | 成人国产在线播放9696 | 国产精品亚洲综合第一区 | 精品国产免费观看久久 | 国产亚洲欧美日韩在线看片 | 国产一区二区免 | 成人国产亚洲精品ā区天堂 | 国产精品特级毛片一区二区 | 91女神娇喘 | 精品人妻潮喷久久久又裸又黄 | 国产一区二区在线日韩 | 国产精品一区二区电影 | 国产黄在线观看免费软件下载 | 国产做野战视频在线观看 | 2025国自产拍国偷 | 按摩调教在线观看 | 国产午夜亚洲精品一级在线 | 国产一区视频 | 91a国产精品视频 | 国产在线精品一区二区三区在线 | 成人免费一区二区三区视 | 国产白白视频在 | 国产av天堂无码一 | 高潮一区二区三区在线 | 国产成人av大片大片在线 | 国产成人av一区二区三区 | 国产国产精品人在线视 | 国产高清在线免费无码 | av永久无码精品桃花岛知道 | 国产日韩欧美一区二区东京热a | 国产一区二区二区无码网站 | 国产三级精品影院 | 99久久亚洲综合精 | 成年女人毛片免费视频播放器 | 国产美女内谢视频 | 97午夜国产亚洲精品 | 成人欧美日韩视频一区 | 国产麻豆精品福利在线观看 | 国产一区二区三区精品网站 | 成人无码一区二区三区网站 | 国产裸拍裸体视频在线观看 | 国产一级毛片特级毛国产 | 国产在线视频福利 | 国产高清国内精品福利99久久 | 二区不卡 | 国产精品你懂的在线资源观看 | 国产91在线播放中文 | 国产肥熟老胖女在线看 | 国产女人高潮抽搐叫床视频 | 国产午夜亚洲精品理论片久久 | 国产精品成人无码免费 | 成人国产亚洲精品a区天堂 成人国产亚洲精品ā区天堂 | 国产麻豆激情无码视频 | 国产中文字幕永久在线观看 | 国产蜜桃扣扣传媒av性色 | 国产无码一区二区三区动态 | 丰满少妇激情进入高清播放 | 国产精品亚洲精品日韩己满 | 国产中文另类二区 | a极毛片一区二区三区免费看 | 国产无套内精一级毛片色戒 | 白洁一区二区三区中文 | 成人在线a一区二区三 | 国产精品部在线观看 | 69国产精品成人在线播放 | 91在线无码精品秘在线观看 | 国产专区视频在线12 | 国产偷抇久久精品a片69 | 高清av熟女一区 | 国产精品自拍视频合集 | 国产免费日本高清 | 国产精品无码一本 | 精品福利一区二区三区免费视频 | 调教女孩自慰网站免费观看 | 国产精品v片在线观 | 高潮呻吟久久av无码 | 福利一区二区久久 | 国产一区免费观看 | 国产精品孕妇video视频 | 精品婷婷色一区二区三区 | 国产精品国产国产aⅴ | 国产激情久久久久影院小草 | 国产精品一区二区不卡 | 爆乳无码系列肉感 | 国产成人猛男69精品视频 | 99精品久久久中文 | 国产精品国产三级国产 | 国产精品亚洲综合久久小说 | 国产熟女一区二区三区四区五区 | 91在线精品一区二区体验升级 | 精品国产乱子伦一区二区三区58 | 国精品午夜福利视频蜜臀 | 动漫精品偷拍日韩 | 91福利视频合集 | 国产毛片久久久久久国产毛片 | 国产一区二区不卡老阿姨 | 69国产精品成人无码免费视 | 国产无套高潮在线观看 | 成年人手机版三级片电影免费观看正 | 国产三级不卡在线播放 | 国产精品美女久久久网av | 国产精品日产欧美一区二区三区 | 国产免费又大又黄又粗在线 | 国产制服日本一区二区 | 精品亚洲欧美v国产一区二区 | 国产精品成人嫩草影院 | 国产91精品黄网在线观看 | 国产成人无码a区在线观看视 | 国产午夜毛片v | 国产精品久在线观看观看视频 | 国产在线污污福利网站 | 国产精品一区二区免费在线观 | 国产无码在线观看免费直播 | 国产高清无码在线一区二区 | 国产高清无套内谢 | 国产制服丝袜一区二区三区 | 高清中文字幕在线a片 | 国产成人无码一二三区视频 | 国产一区二区三区四区五区vm | 国产成人精品综合久久久久 | 精品动漫无码一区二区三区 | 国产一区二区丝袜美腿在线 | 精品日本一区二区三区在线观 | 国产一级毛片在线不卡作 | 国产午夜成人无码免费 | 成人在线影院 | 国产无套gv在线观看 | 国产精品白浆无码流出视频 | 91麻豆精品国产自产在线观 | 99国产精品 | av潮喷大喷水系列无码番号 | 91看片网站免费看 | 99久久亚洲综合精品网站 | 国产三级久久精品三级 | 国产a级毛片免费视频一区二区 | 91免费国产在线观看蜜桃 | 精品亚洲人成人网 | 精品人妻系列五月天 | 精品国产一区二区三区精品日韩 | 激情丝袜欧美专区在线观看 | 成人动漫综合网 | 国产1024精品视频专区 | 国产精品成人一区 | 国产一区亚洲二区日韩三区 | 国产一线精品在线观看 | 国产亚洲精品看片在线观看 | 国产主播福利片在线观看 | 国产午夜精品久久久久婷看片 | 国产午夜一区二区三区影院 | 国产v亚洲v天堂a无码久久蜜桃 | 国产无套粉嫩白浆免费观看 | 成人在线一区二区三区 | 99国产高清视频在线观看 | 国产v综合v亚洲欧美大另类 | 91大片淫黄大片在线天堂 | 国产成在线观看免费视频密 | 国产盗摄aⅴ一区二区 | av中文字幕精品一区二区久久久 | aⅴ天堂 | 国产天堂亚洲国产碰碰 | 国产精品国产三级国产a无密码 | 国产无码免费视频 | 国产精品高清免费网站 | 国产a级综合区毛片久久国产精品 | 国产成人精品一区二区视频 | 国产一区国产二区国产三区 | 精品久久久久久中文字幕 | 国产成自拍亚洲精品 | 国产精品午夜 | 国产国语毛片在线看国产 | 精品少妇av无码免费久久 | 国产av无码一区 | 成人三级av免费 | 国产爆乳无码一区二 | 国产日韩欧美另类重口在线 | 91午夜精品亚洲一区二区三 | 国产成人午夜 | 国产a级毛片久久久久久精品 | 国产裸拍裸体视频 | 国内综合精品午夜久久资源 | 国产成人在线观看网站 | 高清无码在线观看 | 国产自美女在线精品尤物 | 国产高清在线观看av | 国产色系视频在线观看 | 精品国产sm最大网站 | 动漫精品无码视频一区二区三区 | 精品国产一区二区 | 国产一区二区在线日韩 | 国产精品无圣光一区二区 | 国产精品爆乳奶水无码视频 | 高清中文无码久久 | 国产精品一区二区高清在线 | 国产三级片午夜大陆 | 国精品无码一区二区三区 | 国产在线观看91精品 | 国产av无码专区影视 | 操日日操 | 成人国产一区 | 精品人妻一区二区三区声综 | 国产亚洲精久久久久久无码苍井空 | 91视频国产精品免费观看 | 国产自在自线午夜精品视频 | 国产一级性爱免费片 | 爆乳无码系列肉感 | 国产福利午夜波多野结衣 | 国产种子在线看网站在线观看 | 国产成人精品久久综合 | 18禁高潮出水呻吟娇喘mp3 | 91精品国产99 | 国产三级自拍 | 不卡人成视频 | 国产精品无码免费播放 | 国产自在线亚洲精品 | 国产91精品一区二区麻豆观看 | av手机在线观看 | 国产精品三级a在线观看 | 国产精品一区二区av片 | 国产成人综合野草 | 国产成人一区二区三区影院免费 | 精品日韩丝袜在线 | 91久久精品一区二区三区 | 2025国产91精品久久久久久 | 国产不卡视频在线播放 | 国产精品视频一区二区三区四 | 国产精品嫩草影院一二三区入口 | 国产色婷婷精品综合在线播放 | 激情另类乱人伦人妻 | 国产高潮流白浆喷水在线观看 | 91大神精品无码在线观看 | 国产真实老熟女 | 国产成人18黄网站在线观看 | 91高清国产经典在线观看 | 91在线国产一区二区 | 国产成人美女福利在线观看 | 国产一区免费av | 国产超级va在线观看视频 | 国产欧美va欧美va香蕉在 | 成人夜色视频 | 国产激情久久久久影院老熟女 | av电影在线免费观看 | 18禁激情床震无遮挡污污污 | 国产精品视频色尤物yw | 国产精品无码专区在线观看不卡 | 国产欧美日韩在线在线播放 | 精品一区二区高清在线观看 | 国产精品高清在线观看 | 国产成人精品成人a在线观看 | 国产一区免费看久久无码精品 | av片在线观看免费 | 国产精品亚洲乱伦 | 91精品久久久久一区二区三区 | 国产高潮流白浆喷水动 | 国产麻豆放荡av剧情演绎 | 国产精品无码免费专区 | 国产成人久视频免费 | 国产午夜福利精品一区二区 | 国产成人无码v在线播放不卡 | 福利一区二区微拍视频 | av无码免费永久在线观看 | a级一级片| 国产白袜脚足j棉袜在线观看 | 国产精品入口 | 国产不收费b站软件 | 国产最新自拍视频 | 国产按摩推油一区二区三区在线 | 国产欧美久久久久久精品一区 | 国产成人av三级 | 国产成人自在自线视频 | 国产精品一国产精品最新章节 | va一区二区三区 | 99久久婷婷国产综合精品免费 | 国产精品美女www爽爽爽 | 国产午夜精品理论片免费观看 | 国产精品国产三级麻豆 | 国产欧美精品综合区 | 风韵丰满熟妇啪啪区老老熟女百度 | 国产精品日韩精品在线播放 | 91九色在线观看 | 国产成年女人在线观看 | 国产精品精华液 | 国产精品无码久久久久成人网站 | 成人精品日韩一区二区 | 国产在线观看福利片 | 妇女精品一二区 | 国产精品国产欧美综合一区 | 东京热av加勒比一区二区 | 国产精品成人免费视频 | 国产在线综合网站 | 91精品欧美综合在线 | 国产一区二区三区精品porn | 国产一区二区在线日韩 | 国产尤物精彩视频在线 | 2025一本久道免费在线观看 | 精品美女网站在线观看av污 | 国产成人精品免费视频网页大全 | 91黄视频在线 | 风韵丰满熟妇啪啪区老老熟妇 | 国产av无码精 | 国产熟睡乱子伦午夜视频麻豆 | av午夜福利无码精品一区 | 国产精品人成在线播放 | 精品国产一区二区三区久 | 成人无码精品 | 国产av剧情免费观看 | 国产亚洲综合网曝门系列 | 国产三a级日本三级日产三级 | 91高清在线| 国产精品沙 | 国产成人av三级在线观看 | 国产精品欧美日韩在线一区 | 国产成人精品午夜 | 国产成人av网站 | 国产精品激情欧美可乐视频 | 国产一区二区三区在线免费 | 国产午夜成人无码免费看不卡 | 国产在线拍揄自揄视频网 | 国产精久久一区二区三区 | 国产亚洲一区区二区在线 | 国产无码乱伦日本 | 99精品免费在线观看 | 国产熟女内 | 国内无码专区在线视频 | 国产三级无码在线观看 | 国产免费私拍一区二区三区 | 国产美女无套粉嫩白浆在线 | 国产av一区精品果冻传媒 | av无码精品专区在线观看 | 国产在线视频一区 | 国产精品va在线观看蜜臀 | 成人精品一区二区三区电影黑人 | av一本大道香蕉大在线 | 国产91精品一区在线观看 | 国产一区二区三区不卡在线看 | 国产午夜电影在线观看不卡 | 激情视频在线观看国产一区 | 精品国产专区91在线不卡 | 国产轮奸精品一区二区三区 | 国产xxxⅹ野性xxxxhd | 国产福利无码一区二区在线不 | 2025国产精品自在线拍 | 国产免费日本高清 | 2025国产精品最新在线 | av一本久道久久波多野结衣 | 国产巨臀系列在线观看 | 91精品国久久久久久无码免费 | 91成人午夜性a | 国产亚洲日韩欧美另类丝瓜app | 国产精品麻豆视频 | 国产真人一级无码毛片一区二区 | 国产无码高清在线观看 | 国产在线无码视频一区 | 91亚洲精品自产拍在线观看 | 99亚洲精品一区二区三区 | 国产av一区二区三区蜜芽 | 国产日韩亚洲三级片在线观 | 国产黄网站在线观看视频 | 国产一区二区三区不卡视频在线 | 91伊人国产 | 国产精品久在线观不 | 国产成人无码a区在线观看导航 | 97人妻碰碰视频免费上线 | 东京热无码av一区二区 | 国产精品日韩欧美一区二区视频 | 国产成人无码不卡网站 | 国产精品后入内射日本在线观看 | 国产91精品白浆无码流出久久 | 精品精品国产理论在线 | 精品久久人妻一区二区三区 | 99精品国产高清一区二区 | 99久久国产精品视频 | 91精品在线国产一区 | 精品国产一区二区三区久久久狼 | 国产精品偷伦视频免费手机播 | 国产成人免费视频精品一区二区 | 国产亚洲国语精品自产拍在线 | 国产欧美熟妇另类久久久 | 91精品亚洲影视在线观看 | 国外免费人妖网视频在线观看 | 国99精品无码一区二区三区 | 精品香蕉一区二区三区浪潮 | 精品一区二区三区蜜桃臀小说 | 国产美女视频爽爽爽 | av午夜精品一区 | 国产成人无码a区在线观9 | 国产自产一线在线视频 | 成人综合网站一区二区三区四区 | 2025精品国产自在现线看 | 成人亚洲国产欧美另类 | 国产专区视频在线12 | 91久久久无码国产精品免费 | 国产精品无码永久免费不卡 | 国产成人精品第一区二区三区 | 国产麻豆剧传媒精品国产免费 | 97色伦在色在线视频 | 国产人妻无码 | 精品一区二区三区免费 | 国产不卡一区二区免费视频 | 99久久一区二区三区免费 | 国产av一区二区三区无码野战 | 91精品久久香蕉国产线看观看 | 精品免费av在线播放 | 国产成人午夜福利高清在线观看 | 国产成人情侣激情小视频 | 国产精品国产三级国产专区50 | 91精品手机国产在线破解版 | 国产成人av免费网址 | 国产精品成人va在线观看入口 | 丰满少妇一区二区 | 国产麻豆精品久 | 粉嫩虎白女毛片人体 | 18成人免费毛片亚洲 | 动漫精品一区二 | 国产免费内射又粗又爽密桃视频 | 国产福利视频在线 | 国产欧洲一区二区在线观看 | 动漫在线观看无码h | 国产免费午夜一区二区视频 | 国产私拍福利视频 | av中文字幕无码无卡 | 精品国产美女在线一区二区三区 | 国产午夜精品视频夜夜嗨 | 国产精品国产免费无码专区蜜桃 | 精品久久久久精品三级a | 国产帅男男gay网站视频 | 国产精品黄色网站一级大片手机 | 国产成人精品高清国产三级 | 国产一区二区三区在线视頻 | 动漫成年美女黄漫网站在线观看 | 成人午夜免费无码福利软件 | 国产在线视精品在二区 | 国产一区亚洲一区在线观看 | 精品久久aⅴ人妻色欲 | 国产三级精品三级在线观看专 | 国产拍揄自揄精品短视频 | 国产成人午夜精华液 | 动漫黄网站免费永久在线观看 | 国产成人理在线观看视频 | 国产一区二区三区免费 | 国产极品网站在线播放 | 国产三级国产av | 国产盗撮 | 动漫精品视频一区二区三区 | 国产高清天干天天天 | 国产成人免费高清av | 国产高清无码久久 | 18禁超污无遮挡无码网址 | 国产精品秘入口18禁麻豆免会员 | 国产精品男男视频一区二区三区 | 国产在线超清日本一本 | 国产精品无码专区第1页 | 高清av无码在线 | 国产日韩麻豆电影一区二区 | 国产亚洲高清在线精品不卡 | 精品一级毛片一区2区3区 | 2025久久国自产拍 | 国产精品女视频一区二区 | 国产一二三区四区2025 | 国产成人久久精品二三区无码 | 国产美女精品在线 | 国产色系视频在线观看 | 国产精品国产对白熟妇 | 91麻豆产精品久久久久久下载 | 国产午夜福利短视频在线观看 | 国产三级精品三级在线专1 国产三级精品三级在线专区 | 国产99久60在线视频 | 动漫卡通亚洲欧美一区 | 2025年卡一卡二卡三精品 | 国产免费午夜福利在线播放92 | 99国产精品| 国产精品日韩无码 | 国产精品骚妇青草久久久久 | 国产成人亚洲精品无码影院bt | 国产精品白嫩美女在线观看app | 国产精品一卡二卡三卡 | 国产精品视频大陆免费播放 | 91se在线看片国产免费观看 | 国产一区二区三区色噜噜图片 | 91福利专区| 国产经典一区二区三区蜜芽 | 国产成a人亚洲精品无码久久 | 国产女主播精品视频一区 | 精品国产品国语原创 | 国产一区丝袜在线播放无弹窗 | 国产精品免费麻豆入口 | 国产精品高潮呻吟 | 国产成人亚洲精品无码青青草 | 国产激情91久久精品导航 | 精品久久久久久无码一区二区 | 国产精品一区二区剧情熟女 | 国产成a人片 | 不卡的国产高清av一区二区三 | 国产无码在线观看免费在线 | 国产精品一级毛片在线不卡 | 成人毛片在线观看观看 | 国产高清无码在线视频播放 | a级国产乱理伦片在线播放 a级国产乱理伦片在线观看 | 成人a级毛片免费观看av一区 | 国产91一区二区在线播放不卡 | 国产一区二区在线观看麻豆 | 91精品无码国产 | 精品无码无码一级毛片免费 | 极品少妇被后入内射视 | 国产无码av| 国产成人无精品久久久久国语 | 69式无码视频在线观看免费 | 成人免费在线视频观看 | 国产日韩精品一区在线观看播放 | 福利姬国产精品一区在线观看 | 国产女主播高潮在线播放 | 国产精品思思在线 | 国产精品偷伦视频 | 国产精品线在线精品国语 | 精品一区二区高清在线观看 | 国产成人a视频高清在线观看 | 国产欧美日韩在线综合网 | 91精品国产免费久久久久久 | 国产剧mv免费软件麻花豆传煤 | 国产最新三级在线播放视频 | 国产成人精品高清在线观看93 | 国产做爰片久久毛片片美国 | 国产午夜鲁丝片av无码蜜臀 | 岛国在线一区二区三区四区 | 国产日韩无码影院一区二区三区 | 高潮毛片无遮免费高清 | 国产美女浪高潮尖叫毛片 | 国产高清视频在线观看不卡 | 国产一区二区三区在线观看免费 | 国产高清在线播放刘婷91 | 91国内精品久久久久影院 | 成人免费毛片一区二区三区 | 国产一区在线观看 | 国产成在线观看免费 | 成人免费在线视频一区二区 | 国产av无码专区亚洲八aⅴ | 国产精品日韩精品在线播放 | 国产萝控精品福利视频免费观看 | 国产a久久精品 | 国产一区二区影院 | 成人国产精品秘久久久剧情紧凑 | 国产精品真实灌醉女在线播放 | 国产精品视频一区二区 | 国产精品美女久久久久久吹潮 | 国产成人免费无码高清 | 国产精品午夜福利不卡120 | 国产精品无需播放器在线观看 | 国产无码免费激 | 国产孕妇故爱a级高清片免费看 | 国产精品怕怕怕免费视频大全 | 国产一区二区三区四区五区vm | 国产国产精品人在线观看 | 国产精品边做奶水狂喷 | 国产日韩欧美一区二区视频在线观看 | 国产aⅴ精品一区二区三区久 | 国产精品白丝网站 | 岛国精品一区免费视频 | 成人做爰69片免费看网站 | 韩国精品一区二区三区在线观看 | 国产韩国精品一区二区三区 | 国产成人综合一区二区三区 | 丰满饥渴老女 | a三级三级成人网站在线视频 | 91麻豆精品国产高清在线 | 精品日本一线二线三线区别在 | 国产999精品久久久 国产999精品久久久久 | 国产黑色丝袜在线观看下 | 国产欧美日韩中文久久 | 91亚洲精品麻豆 | 国产成人精品无码一区二区三区 | 99精品久久久久久久91蜜桃 | 国产紧身裤三级在线视频 | 精品国产免费第一区二区三区 | 国产成人亚洲精品无码h | 精品无人区一线二线三线区别 | 99久久精品无码专区 | 国产日韩一区二区在线观看 | 国产麻豆精品在 | 国产日韩久久久久精品院 | 国产av天堂无码一 | 国产精品日本一区二区不卡视频 | 成人午夜影院在线观看 | 国产成年人未进视频 | 国产精品偷伦视频免费手机播 | 成人精品一区二区三区不 | av无码一区二区 | 国产一区二区三四 | 国产一区二区日韩一区二区 | 国产女同精品9 | 91麻豆国产自产激情在线看 | 高清无码中文 | 国产超碰人人做人人爱电影 | 国产成人免费av一区二区 | 国产孕妇喷水视频在线播放 | 韩国欧美福利视频一区二区 | 国产成a人亚洲精品无 | 国产精品国色综合 | 国产精品毛片久久久久久久av | 国产一区二区三区精品观看 | 高清少妇三级影视 | 18黑白丝水手服自慰喷水网站 | 国产精品久久久久久久久久日本 | 国产日韩精品99久久 | 国产精品高潮久久久久久无码 | 国产精品无码无卡免费观 | 国产亚洲日韩精品激情手机免费播放 | 国产91丝袜在线播放动漫 | 国产高清在线视频伊甸园 | 国产精品视频色拍拍 | 国产91精品在线观看 | 国产精品成人无码久久久久久 | 国产精品无码一区二区在线观看 | 99亚洲精品高清一二区 | 国产经典不卡的在线视频 | 精品人妻无码一区二区色欲v | 国产美女精品久久久久久久免费 | 18禁裸乳无遮挡啪啪无码免费 | 国产成年人在线观看 | 国产91精品在线观看导航 | 国产福利91三级97伦色 | av无码人妻 | 成人亚洲理论片在线观看 | 国产综合网一区二区三区视频 | 国产精品色 | 国产精品va一级二级三级电影 | 国产在线小视频午夜三区 | 国产美女精品自在线拍免费 | a级猛片在线观看免费 | 国产一区二区三区在线免费观看 | 白洁一区二区三区中文 | 911在线日韩精品视频 | 国产精品视频一区二区噜噜 | 91高清国产 | 果冻传媒色av国产在线播放 | 国产美日韩精品一区二区在线观看 | 2025国产麻豆剧传媒电影 | 国产成年码av片在线观看 | 高清不卡一区二区三区 | 果冻传媒aⅴ毛片无码蜜桃 果冻传媒app在线播放 | 国产高清一国产av麻豆网 | 91精品午夜小视 | 精品久久久久久无码中文字幕一区 | 国产国语熟妇视频在线观看 | 国产三级精品久久 | 国产丝袜一区二 | 国产高清无码一区二区久久 | 精品国产品国语原创 | 精品亚洲国产成人a在线观看 | 动漫av纯肉无码国产av | 国产a级毛片久久久精品毛片 | 91精品中文在线观看 | 国产欧美日韩视频在 | 国产精品免费一区二区三区观看 | 国产精品无码无卡在线观看 | 国产一区二区三区无码免费 | 国产午夜精品久久久久九九 | 91偷拍一区二区三区精品 | 18禁动漫美女禁处被爆桶出水 | 国产精品毛片精彩视频 | 精品高朝久久久久9999 | aⅴ无码一级a片在线视频免费 | 国产福利小视频在线播放 | 2025国产手机在线精品 | 国产免费高清视频在线观看不卡 | 成人婷婷网色偷偷亚洲男人 | 国产三级在线播放线 | 精品国产sm最大网站蜜芽 |