Activiti動態(tài)表單開發(fā)技術(shù)分享

1. 動態(tài)表單特點

一般而言菊霜,工作流引擎常用表單有三種:普通表單奠衔、外置表單和動態(tài)表單。各自都有其優(yōu)缺點戚绕,可根據(jù)具體場景靈活選用纹坐。需要說明的是,三種表單方式只是在任務(wù)節(jié)點上用戶的表單定義方式上面有差別舞丛,而流程的運轉(zhuǎn)機制則完全相同恰画。


image.png

如圖所示,區(qū)別于普通表單和外置表單瓷马,動態(tài)表單是直接將工作流節(jié)點處的表單嵌入流程定義文件BPMN中,系統(tǒng)利用JS或者模板引擎根據(jù)流程定義中表單定義的各個子控件及其屬性動態(tài)渲染出表單加載出來跨晴。

2. 動態(tài)表單流程設(shè)計

在模板管理界面欧聘,點擊新增模板按鈕,進(jìn)入流程模板設(shè)計頁面端盆。

image.png

編輯流程信息:流程key怀骤、流程name等:


image.png

拖拽添加啟動節(jié)點,點擊啟動節(jié)點焕妙,在下面的屬性中點擊動態(tài)表單屬性:


image.png

編輯啟動節(jié)點的動態(tài)表單屬性蒋伦,編輯活動編號、名稱焚鹊、類型痕届、必輸、可讀末患、可寫等屬性后研叫,點擊保存:
image.png

添加下一個活動事件,并編輯該節(jié)點屬性信息璧针,重點是代理嚷炉、和動態(tài)表單屬性信息:


image.png

點擊代理,編輯該事件的代理人探橱、候選人(組)申屹,點擊保存:
image.png

中間流程設(shè)計不詳細(xì)講述绘证,最后添加一個結(jié)束節(jié)點并連接:
image.png

動態(tài)表單節(jié)點的常用屬性介紹:

TIM截圖20180705173841.png

TIM截圖20180705174046.png

流程全部設(shè)計完成后,點擊保存按鈕進(jìn)行保存:

image.png

在流程玩法-流程列表界面點擊部署流程按鈕:

image.png

3. 流程列表

流程部署成功后哗讥,在待啟動流程列表界面可以看到已部署的流程:

image.png

點擊啟動按鈕嚷那,彈出啟動節(jié)點的動態(tài)表單,輸入信息后點擊啟動流程按鈕:

image.png

4. 任務(wù)列表

啟動成功后忌栅,登錄流程設(shè)計的該節(jié)點候選人(組)用戶登錄车酣,在任務(wù)列表界面可以看到該流程,并可以點擊簽收按鈕進(jìn)行簽收:

image.png

簽收成功后索绪,該項操作會變成“辦理”狀態(tài)湖员,可以點擊進(jìn)行辦理:

image.png

點擊辦理按鈕,彈出該節(jié)點定義的動態(tài)表單瑞驱,并進(jìn)行提交操作:

image.png

5. 運行中流程

點擊運行中流程菜單可以查看已啟動但未結(jié)束的流程列表娘摔,并且可以查看每個流程正在運行的節(jié)點:

image.png

點擊當(dāng)前節(jié)點,可以查看每個流程圖及當(dāng)前運行節(jié)點位置:

image.png

6. 已結(jié)束流程

在已結(jié)束流程頁面可以看到已經(jīng)結(jié)束的流程列表:

image.png

7. 動態(tài)表單開發(fā)關(guān)鍵點

標(biāo)準(zhǔn)流程的啟動和運轉(zhuǎn)直接調(diào)用Activiti的通用API即可實現(xiàn)唤反,下面主要從以下幾個方面講解凳寺。

1) 動態(tài)表單渲染

動態(tài)表單將表單定義在了流程定義的文件中,因此在啟動節(jié)點和任務(wù)節(jié)點處能分別通過流程定義ID和任務(wù)ID去獲取節(jié)點處的表單屬性JSON彤侍,如下所示:

獲取啟動節(jié)點處表單數(shù)據(jù)鏈接:

<u>http://localhost:8083/form/dynamic/get-form/start/leave-dynamic-from:2:47515</u>

獲取表單定義數(shù)據(jù)結(jié)果:

*{*

*"form":{*

*"deploymentId":"47512",*

*"formKey":"",*

*"formProperties":[*

*{*

*"id":"startDate",*

*"name":"請假開始日期",*

*"readable":true,*

*"required":true,*

*"type":{*

*"name":"date"*

*},*

*"value":"",*

*"writable":true*

*},*

*{*

*"id":"endDate",*

*"name":"請假結(jié)束日期",*

*"readable":true,*

*"required":true,*

*"type":{*

*"name":"date"*

*},*

*"value":"",*

*"writable":true*

*},*

*{*

*"id":"reason",*

*"name":"請假原因",*

*"readable":true,*

*"required":true,*

*"type":{*

*"mimeType":"text/plain",*

*"name":"string"*

*},*

*"value":"",*

*"writable":true*

*}*

*],*

*"processDefinition":""*

*}*

*}*

獲取到了表單定義屬性文件后肠缨,就可以利用JS或者模板引擎渲染出表單了。比如利用layui的模板引擎來渲染盏阶,就可以定義如下模板:

***var****getTpl =* *`*

*<form class="layui-form" lay-filter="form-tpl" style="padding: 10px;">*

*{{# $.each(d.taskFormData.formProperties, function(i,v1) { }} {{# console.log(i,v1)}}*

*<div>*

*{{# if(v1.type.name=="string" ){ }}*

*<div class="layui-form-item">*

*<label class="layui-form-label">{{v1.name}}</label>*

*<div class="layui-input-block">*

*<input class="layui-input" type="text" name="{{v1.writable ? 'fp_'+v1.id : v1.id}}" autocomplete="off" {{v1.required? 'lay-verify="required"': ''}} placeholder="{{v1.name}}" lay-blur lay-verType="tips" value="{{v1.value}}" {{v1.writable ? '':'disabled'}}/>*

*</div>*

*</div>*

*{{# } }}*

*<div></div>*

*{{# if(v1.type.name=="date" ){ }}*

*<div class="layui-form-item">*

*<label class="layui-form-label">{{v1.name}}</label>*

*<div class="layui-input-block">*

*<input class="layui-input date" type="text" name="{{v1.writable ? 'fp_'+v1.id : v1.id}}" autocomplete="off" {{v1.required? 'lay-verify="required|date"': ''}} placeholder="yyyy-MM-dd" lay-verType="tips" value="{{v1.value}}" {{v1.writable ? '':'disabled'}}/>*

*</div>*

*</div>*

*{{# } }}*

*<div></div>*

*{{# if(v1.type.name=="enum" ){ }}*

*<div class="layui-form-item">*

*<label class="layui-form-label">{{v1.name}}</label>*

*<div class="layui-input-block">*

*<select name="{{v1.writable ? 'fp_'+v1.id : v1.id}}" {{v1.writable ? '':'disabled'}}>*

*<option value=""></option>*

*{{# $.each(d[v1.id+''],function(i2,v2){ }}*

*<option value="{{i2}}" {{i2==v1.value ? 'selected':''}}>{{v2}}</option>*

*{{# }) }}*

*</select>*

*</div>*

*</div>*

*{{# } }}*

*</div>*

*{{# }) }}*

*<div style="display:none;">*

*<!--此處隱藏但不能省略,為觸發(fā)事件準(zhǔn)備-->*

*<button lay-submit>提交</button><button type="reset">重置</button>*

*</div>*

*</form>*

*<style type="text/css">*

*.layui-layer-page .layui-layer-content {*

*overflow: visible;*

*}*

*</style>*

*`**;*

上述模板對常見的string晒奕、date、enum類型進(jìn)行了解析和渲染名斟,有更多類型可以自己根據(jù)需要添加脑慧。

此外,需要注意的是砰盐,要區(qū)別開表單中可編輯參數(shù)與不可編輯參數(shù)的屬性配置闷袒,如下所示(紅色標(biāo)注的部分),可編輯參數(shù)的name屬性值前面加上“fp_”(約定)岩梳。這樣配置的好處是后臺在接收到參數(shù)后可以區(qū)分開哪些參數(shù)是當(dāng)前節(jié)點需要保存的參數(shù)信息囊骤,以便進(jìn)行保存(見下面第二點表單的參數(shù)解析部分)。

*<input class="layui-input" type="text"* *name="{{v1.writable ? 'fp_'+v1.id : v1.id}}"** autocomplete="off" {{v1.required? 'lay-verify="required"': ''}} placeholder="{{v1.name}}" lay-blur lay-verType="tips" value="{{v1.value}}" {{v1.writable ? '':'disabled'}}/>*

使用方法是在需要進(jìn)行動態(tài)表單渲染的頁面JS中引入該模板:

//引入動態(tài)表單渲染模板

$.use(ctx+'/static/js/dynamic-form-common.js', **function****(){});

然后在獲得表單屬性數(shù)據(jù)后蒋腮,調(diào)用renderForm方法淘捡,傳入data數(shù)據(jù)和需要渲染的頁面dom節(jié)點元素即可:

renderForm(JSON.parse(form), $form.get(0));

2) 表單參數(shù)解析

前文已經(jīng)提到,在表單渲染時就已經(jīng)通過設(shè)置不同的name屬性值來區(qū)分開了可編輯參數(shù)和不可編輯參數(shù)池摧,因此在后臺進(jìn)行參數(shù)解析時就能很方便地對可編輯參數(shù)進(jìn)行提冉钩:

// 從request中讀取參數(shù)然后轉(zhuǎn)換

Map<String, String[]> parameterMap= request.getParameterMap();

Set<Entry<String, String[]>> entrySet= parameterMap.entrySet();

for****(Entry<String, String[]> entry: entrySet) {

String key= entry.getKey();

// fp_的意思是form <u>paremeter</u>

if**** (StringUtils.defaultString(key).startsWith("fp_")) { formProperties.put(key.replaceFirst("fp_", ""), entry.getValue()[0]);
*}
}

上述代碼就能將可編輯參數(shù)封裝在formProperties這個HashMap中。

3) 動態(tài)表單自定義類型

下面以上傳附件為例作彤,講述自定義表單類型的步驟和流程:

a. 定義表單擴展類型


***public******class****FileFormType* ***extends**** AbstractFormType {*

*/***

* **

* */*

***private******static******final******long******serialVersionUID**** = 1L;*

*@Override*

***public**** String getName() {*

*//* ***TODO**** Auto-generated method stub*

***return****"file"**;*

*}*

*@Override*

***public****Object convertFormValueToModelValue(String* *propertyValue**) {*

*//* ***TODO**** Auto-generated method stub*

***return****propertyValue**;*

*}*

*@Override*

***public****String convertModelValueToFormValue(Object* *modelValue**) {*

*//* ***TODO**** Auto-generated method stub*

***return**** (String)**modelValue**;*

*}*

*}*

b. 在activiti配置類中注冊表單擴展類型

*//注冊自定義表單類型*

*List<AbstractFormType>* *formTypes**=* ***new**** ArrayList<>();*

*formTypes**.add(****new**** FileFormType());    **processEngineConfiguration**.setCustomFormTypes(**formTypes**);*

c. 針對表單自定義類型新增動態(tài)渲染解析器

*{{# if(v1.type.name=="file" ){ }}*

*<div class="layui-form-item">*

*<label class="layui-form-label">{{v1.name}}</label>*

*<div>*

*<button type="button" class="layui-btn layui-btn-normal" id="test8">選擇文件</button>*

*</div>*

*</div>*

*{{# } }}*

d. 任務(wù)辦理時判斷是否包含附件類型膘魄,如果包含則應(yīng)將表單類型設(shè)置為“multipart/form-data”:

***if****($(**"#test8"**)){*

*     $form.attr(**'enctype'**,**'multipart/form-data'**);*

*}*

e. 在任務(wù)辦理時新增附件的保存邏輯:

首先接收參數(shù)應(yīng)新增:

@RequestParam(value="file", required=false) MultipartFile file

在參數(shù)解析后乌逐,保存file:

**if**(**null**!= file) {

attachmentService.createAttachment(file, taskId, processInstanceId, formProperties.get("attachmentDescription"), request);        

}

4) 常用API總結(jié)

引擎API是與Activiti打交道的最常用方式。 從ProcessEngine中创葡,你可以獲得很多囊括工作流/BPM方法的服務(wù)浙踢。 ProcessEngine和服務(wù)類都是線程安全的。 你可以在整個服務(wù)器中僅保持它們的一個引用就可以了灿渴。

ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();    
RuntimeService runtimeService = processEngine.getRuntimeService();  
RepositoryService repositoryService = processEngine.getRepositoryService();  
TaskService taskService = processEngine.getTaskService();  
ManagementService managementService = processEngine.getManagementService();  
IdentityService identityService = processEngine.getIdentityService();  
HistoryService historyService = processEngine.getHistoryService();  
FormService formService = processEngine.getFormService();

① ProcessEngines:

ProcessEngines.getDefaultProcessEngine()會在第一次調(diào)用時 初始化并創(chuàng)建一個流程引擎洛波,以后再調(diào)用就會返回相同的流程引擎。 使用對應(yīng)的方法可以創(chuàng)建和關(guān)閉所有流程引擎:ProcessEngines.init()和 ProcessEngines.destroy()骚露。

ProcessEngines會掃描所有activiti.cfg.xml和 activiti-context.xml 文件蹬挤。 對于activiti.cfg.xml文件,流程引擎會使用Activiti的經(jīng)典方式構(gòu)建: ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream).buildProcessEngine(). 對于activiti-context.xml文件棘幸,流程引擎會使用Spring方法構(gòu)建:先創(chuàng)建一個Spring的環(huán)境焰扳, 然后通過環(huán)境獲得流程引擎。

所有服務(wù)都是無狀態(tài)的误续。這意味著可以在多節(jié)點集群環(huán)境下運行Activiti吨悍,每個節(jié)點都指向同一個數(shù)據(jù)庫, 不用擔(dān)心哪個機器實際執(zhí)行前端的調(diào)用蹋嵌。 無論在哪里執(zhí)行服務(wù)都沒有問題育瓜。

② RepositoryService******:

RepositoryService可能是使用Activiti引擎時最先接觸的服務(wù)。 它提供了管理和控制發(fā)布包和流程定義的操作栽烂。 這里不涉及太多細(xì)節(jié)爆雹,流程定義是BPMN 2.0流程的java實現(xiàn)。 它包含了一個流程每個環(huán)節(jié)的結(jié)構(gòu)和行為愕鼓。 發(fā)布包是Activiti引擎的打包單位。一個發(fā)布包可以包含多個BPMN 2.0 xml文件和其他資源慧起。 開發(fā)者可以自由選擇把任意資源包含到發(fā)布包中菇晃。 既可以把一個單獨的BPMN 2.0 xml文件放到發(fā)布包里,也可以把整個流程和相關(guān)資源都放在一起蚓挤。 (比如磺送,'hr-processes'實例可以包含hr流程相關(guān)的任何資源)。 可以通過RepositoryService來部署這種發(fā)布包灿意。 發(fā)布一個發(fā)布包估灿,意味著把它上傳到引擎中,所有流程都會在保存進(jìn)數(shù)據(jù)庫之前分析解析好缤剧。 從這點來說馅袁,系統(tǒng)知道這個發(fā)布包的存在,發(fā)布包中包含的流程就已經(jīng)可以啟動了荒辕。

除此之外汗销,服務(wù)可以

ü 查詢引擎中的發(fā)布包和流程定義犹褒。

ü 暫停或激活發(fā)布包弛针,對應(yīng)全部和特定流程定義叠骑。 暫停意味著它們不能再執(zhí)行任何操作了,激活是對應(yīng)的反向操作削茁。

ü 獲得多種資源宙枷,像是包含在發(fā)布包里的文件, 或引擎自動生成的流程圖茧跋。

ü 獲得流程定義的pojo版本慰丛, 可以用來通過java解析流程,而不必通過xml厌衔。

③ RuntimeService******:

正如RepositoryService負(fù)責(zé)靜態(tài)信息(比如璧帝,不會改變的數(shù)據(jù),至少是不怎么改變的)富寿, RuntimeService正好是完全相反的睬隶。它負(fù)責(zé)啟動一個流程定義的新實例。 如上所述页徐,流程定義定義了流程各個節(jié)點的結(jié)構(gòu)和行為苏潜。 流程實例就是這樣一個流程定義的實例。對每個流程定義來說变勇,同一時間會有很多實例在執(zhí)行恤左。 RuntimeService也可以用來獲取和保存流程變量。 這些數(shù)據(jù)是特定于某個流程實例的搀绣,并會被很多流程中的節(jié)點使用 (比如飞袋,一個排他網(wǎng)關(guān)常常使用流程變量來決定選擇哪條路徑繼續(xù)流程)。 Runtimeservice也能查詢流程實例和執(zhí)行链患。 執(zhí)行對應(yīng)BPMN 2.0中的'token'巧鸭。基本上執(zhí)行指向流程實例當(dāng)前在哪里麻捻。 最后纲仍,RuntimeService可以在流程實例等待外部觸發(fā)時使用,這時可以用來繼續(xù)流程實例贸毕。 流程實例可以有很多暫停狀態(tài)郑叠,而服務(wù)提供了多種方法來'觸發(fā)'實例, 接受外部觸發(fā)后明棍,流程實例就會繼續(xù)向下執(zhí)行乡革。

④ TaskService******:

任務(wù)是由系統(tǒng)中真實人員執(zhí)行的,它是Activiti這類BPMN引擎的核心功能之一。 所有與任務(wù)有關(guān)的功能都包含在TaskService中:

ü 查詢分配給用戶或組的任務(wù)

ü 創(chuàng)建獨立運行任務(wù)署拟。這些任務(wù)與流程實例無關(guān)婉宰。

ü 手工設(shè)置任務(wù)的執(zhí)行者,或者這些用戶通過何種方式與任務(wù)關(guān)聯(lián)推穷。

ü 認(rèn)領(lǐng)并完成一個任務(wù)心包。認(rèn)領(lǐng)意味著一個人期望成為任務(wù)的執(zhí)行者, 即這個用戶會完成這個任務(wù)馒铃。完成意味著“做這個任務(wù)要求的事情”蟹腾。 通常來說會有很多種處理形式。

⑤ IdentityService******:

IdentityService非常簡單区宇。它可以管理(創(chuàng)建娃殖,更新,刪除,查詢...)群組和用戶。 請注意铝耻, Activiti執(zhí)行時并沒有對用戶進(jìn)行檢查。 例如芬首,任務(wù)可以分配給任何人,但是引擎不會校驗系統(tǒng)中是否存在這個用戶逼裆。 這是Activiti引擎也可以使用外部服務(wù)郁稍,比如ldap,活動目錄胜宇,等等耀怜。

⑥ FormService******:

FormService是一個可選服務(wù)。即使不使用它桐愉,Activiti也可以完美運行财破, 不會損失任何功能。這個服務(wù)提供了啟動表單任務(wù)表單兩個概念从诲。 啟動表單會在流程實例啟動之前展示給用戶狈究, 任務(wù)表單會在用戶完成任務(wù)時展示。Activiti支持在BPMN 2.0流程定義中設(shè)置這些表單盏求。 這個服務(wù)以一種簡單的方式將數(shù)據(jù)暴露出來。再次重申亿眠,它時可選的碎罚, 表單也不一定要嵌入到流程定義中。

⑦ HistoryService******:

HistoryService提供了Activiti引擎手機的所有歷史數(shù)據(jù)纳像。 在執(zhí)行流程時荆烈,引擎會保存很多數(shù)據(jù)(根據(jù)配置),比如流程實例啟動時間,任務(wù)的參與者憔购, 完成任務(wù)的時間宫峦,每個流程實例的執(zhí)行路徑,等等玫鸟。 這個服務(wù)主要通過查詢功能來獲得這些數(shù)據(jù)导绷。

⑧ ManagementService******:

ManagementService在使用Activiti的定制環(huán)境中基本上不會用到。 它可以查詢數(shù)據(jù)庫的表和表的元數(shù)據(jù)屎飘。另外妥曲,它提供了查詢和管理異步操作的功能。 Activiti的異步操作用途很多钦购,比如定時器檐盟,異步操作, 延遲暫停押桃、激活葵萎,等等。后續(xù)唱凯,會討論這些功能的更多細(xì)節(jié)羡忘。

以下總結(jié)下在開發(fā)工作流引擎動態(tài)表單相關(guān)功能時用到的一些API:

查詢流程列表:

ProcessDefinitionQuery dynamicQuery= repositoryService.createProcessDefinitionQuery()

.orderByDeploymentId().desc();

啟動流程:

identityService.setAuthenticatedUserId(user.getId());

processInstance= formService.submitStartFormData(processDefinitionId, formProperties);

讀取啟動節(jié)點表單數(shù)據(jù):

StartFormDataImpl<u>startFormData</u>* = (StartFormDataImpl)* formService.getStartFormData(processDefinitionId);

任務(wù)列表查詢:

TaskQuery taskQuery= taskService.createTaskQuery()

.taskCandidateOrAssigned(user== null****? "kafeitu":user.getId())

.active().orderByTaskCreateTime().desc();

簽收任務(wù):

taskService.claim(taskId, userId);

辦理任務(wù):

identityService.setAuthenticatedUserId(user.getId());

formService.submitTaskFormData(taskId, formProperties);

讀取Task表單數(shù)據(jù):

TaskFormDataImpltaskFormData* = (TaskFormDataImpl)formService.getTaskFormData(taskId*);

運行中流程列表查詢:

ProcessInstanceQuery dynamicQuery= runtimeService.createProcessInstanceQuery()

.orderByProcessInstanceId().desc();

已結(jié)束流程列表查詢:

HistoricProcessInstanceQuery dynamicQuery= historyService.createHistoricProcessInstanceQuery().finished().orderByProcessInstanceEndTime().desc();

掛起流程:

repositoryService.suspendProcessDefinitionById(processDefinitionId, isCascade, **new**** Date());

激活流程:

repositoryService.activateProcessDefinitionById(processDefinitionId, isCascade, **new**** Date());

刪除流程:

repositoryService.deleteDeployment(deploymentId, isCascade);

掛起流程實例:

runtimeService.suspendProcessInstanceById(processInstanceId);

激活流程實例:

runtimeService.activateProcessInstanceById(processInstanceId);

刪除流程實例:

runtimeService.deleteProcessInstance(processInstanceId, deleteReason);

關(guān)于Activiti的更多詳細(xì)介紹,請參考以下資料:

網(wǎng)址:http://www.mossle.com/docs/activiti/index.html#apiEngine

書籍:Activiti實戰(zhàn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末波丰,一起剝皮案震驚了整個濱河市壳坪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌掰烟,老刑警劉巖爽蝴,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異纫骑,居然都是意外死亡蝎亚,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門先馆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來发框,“玉大人,你說我怎么就攤上這事煤墙∶饭撸” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵仿野,是天一觀的道長铣减。 經(jīng)常有香客問我,道長脚作,這世上最難降的妖魔是什么葫哗? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任缔刹,我火速辦了婚禮,結(jié)果婚禮上劣针,老公的妹妹穿的比我還像新娘校镐。我一直安慰自己,他們只是感情好捺典,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布鸟廓。 她就那樣靜靜地躺著,像睡著了一般辣苏。 火紅的嫁衣襯著肌膚如雪肝箱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天稀蟋,我揣著相機與錄音煌张,去河邊找鬼。 笑死退客,一個胖子當(dāng)著我的面吹牛骏融,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播萌狂,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼档玻,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了茫藏?” 一聲冷哼從身側(cè)響起误趴,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎务傲,沒想到半個月后凉当,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡售葡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年看杭,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挟伙。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡楼雹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出尖阔,到底是詐尸還是另有隱情贮缅,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布介却,位于F島的核電站谴供,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏筷笨。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望胃夏。 院中可真熱鬧轴或,春花似錦、人聲如沸仰禀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽答恶。三九已至饺蚊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間悬嗓,已是汗流浹背污呼。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留包竹,地道東北人燕酷。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像周瞎,于是被迫代替她去往敵國和親苗缩。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容