Activiti工作流管理系統(tǒng)(三)

前言

當(dāng)工作流流程圖發(fā)布完成之后京闰,下一步就是啟動(dòng)工作流帆喇,也是工作流引擎的核心功能乳附,本篇重點(diǎn)將要對(duì)工作流的啟動(dòng)和流程進(jìn)行詳細(xì)說(shuō)明辛蚊。
說(shuō)明:所有項(xiàng)目配置均在系列第一篇文章中進(jìn)行介紹,配置系列通用窟扑。

系列三內(nèi)容

初始化參數(shù)棒口、啟動(dòng)工作流、執(zhí)行工作流

頁(yè)面總覽

頁(yè)面總覽.png

功能詳細(xì)說(shuō)明

初始化參數(shù)

說(shuō)明

在實(shí)際項(xiàng)目中辜膝,有可能會(huì)有如下需求:需要在啟動(dòng)工作流的時(shí)候无牵,提前向工作流中傳參(全局變量),這些參數(shù)往往在業(yè)務(wù)上具有重要意義厂抖,例如:xxId茎毁,status等。因此此工作流管理系統(tǒng)特加入此功能忱辅,在啟動(dòng)流程前對(duì)參數(shù)進(jìn)行定義七蜘,并在啟動(dòng)時(shí)將這些參數(shù)賦值到流程實(shí)例中。
此處包含兩個(gè)子功能:
打開(kāi)參數(shù)列表功能墙懂、保存參數(shù)列表功能

頁(yè)面

初始化參數(shù).png

前端關(guān)鍵代碼

TableData.vue

打開(kāi)參數(shù)列表
<Button type="info" :disabled="row.defId === null" size="small" @click="initParams(row)">初始化參數(shù)</Button>
<Modal v-model="initParamsModal" width="540" :mask-closable="false" :closable="false" :footer-hide="true">
      <input type="hidden" v-model="flowId"/>
      請(qǐng)輸入初始化參數(shù):<Input v-model="paramsName" placeholder="各參數(shù)間以','隔開(kāi)" style="width: 260px" />
      <Button type="primary" size="small" @click="confirmParams">確認(rèn)</Button>
      <Button type="primary" size="small" @click="clearParams">清空</Button>
      <Button type="primary" size="small" @click="cancelParams">取消</Button>
    </Modal>
return {
        initParamsModal:false,
        paramsName:''橡卤,
        flowId:''
      }
methods: {
      //初始化方法
      initParams(row){
        this.initParamsModal = true
        const flowId = row.id ;
        this.flowId = flowId ;
        openParams({
          flowId:flowId
        }).then(res => {
          if(res.data.responseCode === 1){
            let paramsName = res.data.responseData.paramsName ;
            this.paramsName = paramsName === null ? '':paramsName ;
          }else{}
        })
      }
}
保存參數(shù)列表
//保存參數(shù)列表
confirmParams(){
        const flowId = this.flowId
        const paramsName = this.paramsName
        this.initParamsModal = false
        saveParams({
          flowId:flowId,
          paramsName:paramsName
        }).then(res => {
          if(res.data.responseCode === 1){
            this.$Message.success('保存參數(shù)成功!');
          }else{
            this.$Message.error('保存參數(shù)失斔鸢帷碧库!');
          }
          //清空數(shù)據(jù)
          this.paramsName = ''
        })
      }

后端關(guān)鍵代碼

ParamsRecordController

打開(kāi)原參數(shù)列表

    @Autowired
    private ParamsRecordService paramsRecordService ;
/**
     * 打開(kāi)參數(shù)列表
     * @return
     */
    @RequestMapping("/open")
    @Transactional
    public JsonResult open(Long flowId){
        JsonResult jr = new JsonResult() ;
        resultMap = new HashMap<String,Object>() ;
        try {
            String paramsName = paramsRecordService.getParamsNameByFlowId(flowId);
            //獲取到原參數(shù)列表(以“坝冕,”隔開(kāi)的字符串)
            resultMap.put("paramsName",paramsName) ;
            jr.setResponseData(resultMap);
        }catch (Exception e){
            e.printStackTrace();
        }
        return jr;
    }

保存參數(shù)列表

/**
     * 保存實(shí)體
     * @return
     */
    @RequestMapping("/save")
    @Transactional
    public JsonResult save(Long flowId,String paramsName){
        JsonResult jr = new JsonResult() ;
        try {
            //先清空所有的參數(shù)
            paramsRecordService.deleteBatchByFlowId(flowId);
            if(StringUtils.isNotEmpty(paramsName)){
                //進(jìn)行保存廷支,如果參數(shù)列表不為空,則執(zhí)行保存操作础浮,否則只清空颅悉,為了應(yīng)對(duì)前端清除按鈕的功能
                List<ParamsRecord> list = strToObj(flowId,paramsName) ;
                paramsRecordService.insertBatch(list) ;
            }
            jr.setResponseMessage(ResultEnum.SUCCESS);
            jr.setResponseCode(1);
        }catch (Exception e){
            e.printStackTrace();
            jr.setResponseMessage(ResultEnum.EXCEPTION);
            jr.setResponseCode(0);
        }
        return jr;
    }

    /**
     * 將前臺(tái)獲取到的str轉(zhuǎn)化為ParamsRecord實(shí)體類
     * str -> paramsRecord obj
     * @param str
     */
    private static List<ParamsRecord> strToObj(Long flowId,String str){
        String[] paramsName = str.trim().split(",");
        List<ParamsRecord> list = new ArrayList<ParamsRecord>() ;
        for(String pname:paramsName){
            ParamsRecord pr = new ParamsRecord() ;
            pr.setFlowId(flowId);
            pr.setIsInit(true);
            pr.setParamName(pname);

            list.add(pr) ;
        }

        return list ;
    }

ParamsRecordServiceImpl

@Override
    public List<ParamsRecord> getParamsListByFlowId(Long flowId) {
                //根據(jù)flowId獲取該流程定義下的原參數(shù)列表
        List<ParamsRecord> list = mapper.getParamsListByFlowId(flowId) ;
        if(list == null) return null ;
        return list ;
    }

啟動(dòng)工作流

說(shuō)明

在本系統(tǒng)中沽瞭,根據(jù)上文內(nèi)容,啟動(dòng)工作流分為含參啟動(dòng)和無(wú)參啟動(dòng)剩瓶,二者的區(qū)別即:含參啟動(dòng)是將上文中的參數(shù)列表進(jìn)行羅列驹溃,并分別傳初始參數(shù)值后啟動(dòng);無(wú)參啟動(dòng)則不包含此過(guò)程延曙。

頁(yè)面展示

無(wú)參啟動(dòng).png

含參啟動(dòng).png

前端代碼

TableData.vue

<Button type="success" :disabled="row.defId === null" size="small" @click="startProcess(row)">啟動(dòng)</Button>
 <Modal :closable="false" :footer-hide="true" :mask-closable="false" v-model="startModal"
           width="350">
      <FormItemActiveAdd @change-modal="changeModal" ref="formItemActiveAdd"></FormItemActiveAdd>
</Modal>
components: {
      FormItemActiveAdd
    }
startProcess(row){
        //流程定義ID
        const processDefinitionId = row.defId ;
        //流程定義業(yè)務(wù)主鍵ID
        const flowId = row.id ;
        let o = {}
        getParamsListByFlowId({
          flowId:flowId
        }).then(res => {
          this.startModal = true
          let obj = {};
          let arr = res.data.responseData.list ;
          if(arr.length === 0){
            //如果數(shù)組的長(zhǎng)度為0豌鹤,則不需要打開(kāi)
            this.$Message.warning('未獲取到初始化參數(shù)列表,直接啟動(dòng)即可搂鲫!');
          }else{
            for(let key in arr){
              obj[key] = arr[key]
            }
            this.$refs.formItemActiveAdd.paramsRecord = obj ;
          }
          this.$refs.formItemActiveAdd.processDefinitionId = processDefinitionId ;
        })
      },

FormItemActiveAdd.vue

<template>
  <Form :model="paramsRecord" style="width: 100%;text-align: left">
    <FormItem
      v-for="(item, index) in paramsRecord"
      v-if="item.id"
      :key="index"
      :label="'參數(shù)'+(++index)+':'+item.paramName"
      :prop="item.paramName" class="FormItem-class">
      <Row>
        <Col span="28">
          <br><Input type="text" v-model="item.paramVal" placeholder="Enter something..."></Input>
        </Col>
      </Row>
    </FormItem>
    <FormItem>
      <Button type="success" @click="handleSubmit" style="margin-left: 95px">啟動(dòng)</Button>
      <Button type="primary" @click="handleReturn" style="margin-left: 8px">返回</Button>
    </FormItem>
  </Form>
</template>

<script>
  import {
    start
  } from '../api/activityManagement'

  export default {
    name: 'FormItemActiveAdd',
    data () {
      return {
        index: 1,
        processDefinitionId:'',
        paramsRecord:{
        },
      }
    },
    methods: {
      handleSubmit () {
        const processDefinitionId = this.processDefinitionId ;
        const obj = Object.values(this.paramsRecord) ;
        let o = {} ;
        for(let i = 0,len=obj.length; i < len; i++) {
          o[obj[i].paramName] = obj[i].paramVal ;
        }
        start({
          processDefinitionId:processDefinitionId,
          paramMap:o
        }).then(res =>{
          if(res.data.responseCode === 1){
            this.$Message.success('啟動(dòng)成功傍药!流程實(shí)例ID:'+res.data.responseData.pid);
          }else {
            this.$Message.error('啟動(dòng)失敾瞧健魂仍!');
          }
          this.$emit('change-modal',false)
        })
      },
      handleReturn () {
        this.paramsRecord = {}
        this.$emit('change-modal',false)
      }
    },
    mounted () {
    }
  }
</script>

<style scoped>
</style>

注:參數(shù)列表的展示使用的是FormItem組件拐辽,具體可查看iview官方文檔的4.x版本說(shuō)明

activityManagement.js

/**啟動(dòng)工作流**/
export const start = (processDefinitionId,paramMap) => {
  return axios.request({
    url: 'workflow/start',
    params: processDefinitionId,
    data:paramMap,
    method: 'post'
  })
}

后端代碼

WorkflowController

/**
     * 啟動(dòng)工作流
     * @param processDefinitionId,paramVal
     * @return
     */
    @RequestMapping("/start")
    public JsonResult start(String processDefinitionId, String paramMap){
        JsonResult jr = new JsonResult() ;
        resultMap = new HashMap<String,Object>() ;
        try {
            Map<String, Object> map = JsonUtils.stringToMap(paramMap);
            ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId,map);
            //啟動(dòng)成功后獲取流程實(shí)例ID
            String processInstanceId = processInstance.getId() ;
            jr.setResponseCode(1);
            jr.setResponseMessage(ResultEnum.SUCCESS);
            resultMap.put("pid",processInstanceId) ;
            jr.setResponseData(resultMap) ;
        }catch (Exception e){
            e.printStackTrace();
            jr.setResponseCode(0);
            jr.setResponseMessage(ResultEnum.EXCEPTION);
        }
        return jr ;
    }

JsonUtils

/**
     * String -> Map
     * @param str
     * @return
     */
    public static Map<String ,Object> stringToMap(String str) {
        if (StringUtils.isEmpty(str)) {
            return null;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        map = gson.fromJson(str, Map.class);
        return map;
    }

執(zhí)行工作流

說(shuō)明

執(zhí)行工作流即當(dāng)前實(shí)例繼續(xù)向下執(zhí)行,直至實(shí)例完成擦酌。

特殊說(shuō)明:該篇內(nèi)容中只介紹執(zhí)行下一步的相關(guān)功能實(shí)現(xiàn)俱诸,但實(shí)際在此功能模塊中涉及到其他內(nèi)容,此模塊莫心急赊舶,會(huì)在之后的系列篇中進(jìn)行介紹

頁(yè)面展示

下一步列表.png

執(zhí)行下一步+路由提醒.png

帶參執(zhí)行下一步.png

亮點(diǎn)介紹

如上圖所示睁搭,此功能包含下一步路由提醒功能。目的在于由于下一步可能存在互斥網(wǎng)關(guān)等情況笼平,會(huì)在連接線上填寫條件园骆,但是在實(shí)際運(yùn)轉(zhuǎn)過(guò)程中往往會(huì)忘記這個(gè)條件,所以在此添加該功能寓调,使得系統(tǒng)更加人性化~

前端代碼

ActiveProcess.vue

<template>
  <div class="div-class">
    <Card style="height: 750px">
      <p slot="title">
        <Icon type="ios-film-outline"></Icon>
        活動(dòng)實(shí)例列表({{this.$route.params.flowKey}})
      </p>
      <Button type="primary" class="btn-class" @click="returnPage">返回</Button>
      <ul>
          <Table height="550" border ref="selection" :columns="columns12" :data="data6" style="margin-top: 50px">
            <template slot-scope="{ row, index }" slot="action">
              <div class="slot_class">
                <Button type="info" size="small" @click="execute(row)">執(zhí)行下一步</Button>
              </div>
            </template>
          </Table>
      </ul>
    </Card>
</template>
<script>
  import {
    execute,
    openExecute
  } from '../../api/activityManagement'
  import FormItemExecuteAdd from '../FormItemExecuteAdd'

  export default {
    name: 'ActiveProcess',
    components: {
      FormItemExecuteAdd
    },
    data () {
      return {
        flowId:'',
        processInstanceId:'',
        executeModal:false
      }
    },
    methods: {
      execute(row){
        const processInstanceId = row.processInstanceId ;
        const flowId = this.$route.params.flowId ;
        if(processInstanceId === '' || flowId === ''){
          this.$Message.warning('數(shù)據(jù)異常锌唾,無(wú)法加載!');
          return ;
        }
        openExecute({
          flowId:this.$route.params.flowId,
          processInstanceId:processInstanceId
        }).then(res => {
          if(res.data.responseCode === 1){
            const resArr = res.data.responseData.list ;
            let message = ''
            resArr.forEach(function(e){
              message += '<p>' + e.toString() + '</p>'
            });
            console.log(message)
            this.$Notice.open({
              name:'executeNotice',
              title: '下一步路由提醒',
              duration:0,
              desc: message
            });
            this.executeModal = true ;
            this.$refs.paramList.processInstanceId = processInstanceId ;
          }else{
            this.$Message.warning('數(shù)據(jù)異常夺英,無(wú)法加載晌涕!');
          }
        })
      }
    }
  }
</script>

activityManagement.js

/**打開(kāi)下一步Modal**/
export const openExecute = params => {
  return axios.request({
    url: 'workflow/openExecute',
    params: params,
    method: 'post'
  })
}

FormItemExecuteAdd.vue

<template>
  <Form ref="paramList" :model="paramList" :label-width="80" style="width: 300px">
    <FormItem
      v-for="(item, index) in paramList.items"
      :key="index"
      :label="'參數(shù):'"
      :prop="'items.' + index + '.value'">
      <Row>
        <Col span="18">
          <Input style="width: 70px" type="text" v-model="item.key" placeholder="key"></Input> =
          <Input  style="width: 80px" type="text" v-model="item.value" placeholder="value"></Input>
        </Col>
        <Col span="4" offset="1">
          <Button @click="handleRemove(index)">刪除</Button>
        </Col>
      </Row>
    </FormItem>
    <FormItem>
      <Row>
        <Col span="12">
          <Button type="dashed" long @click="handleAdd" icon="md-add">添加</Button>
        </Col>
      </Row>
    </FormItem>
    <FormItem>
      <Button type="success" @click="handleSubmit('paramList')">執(zhí)行</Button>
      <Button type="primary" @click="handleReturn('paramList')" style="margin-left: 8px">返回</Button>
    </FormItem>
  </Form>
</template>
<script>
  import {execute} from '../api/activityManagement'

  export default {
    data () {
      return {
        index: 1,
        processInstanceId:'',
        paramList: {
          items: [
          ]
        }
      }
    },
    methods: {
      handleSubmit (name) {
        const obj = Object.values(this.paramList.items) ;
        let o = {} ;
        for(let i = 0,len=obj.length; i < len; i++) {
          if((obj[i].key !== '' && obj[i].key !== undefined && obj[i].key !== null) &&
            (obj[i].value !== '' && obj[i].value !== undefined && obj[i].value !== null)){
            o[obj[i].key] = obj[i].value ;
          }
        }
        execute({
          processInstanceId:this.processInstanceId,
          paramMap:o
        }).then(res =>{
          if(res.data.responseCode === 1){
            this.$Message.success('執(zhí)行成功!');
          }else {
            this.$Message.error('執(zhí)行失斖疵酢余黎!');
          }
          this.$emit('change-modal',false)
        })

      },
      handleReturn (name) {
        // this.paramList = {items: [{}]}
        this.paramList = {items:[]}
        this.$emit('change-modal',false)
      },
      handleReset (name) {
        this.$refs[name].resetFields();
      },
      handleAdd () {
        this.index++;
        this.paramList.items.push({
          key:'',
          value: '',
          index: this.index
        });
      },
      handleRemove (index) {
        this.index-- ;
        this.paramList.items.splice(index,1)
      }
    }
  }
</script>

后端代碼

WorkflowController

獲取下一步路由的方法,前提是已經(jīng)將任務(wù)環(huán)節(jié)信息以及各環(huán)節(jié)間邏輯關(guān)系保存到自己定義的業(yè)務(wù)表中载萌,此系列該表為task_def惧财,具體實(shí)現(xiàn)方案請(qǐng)參照系列第二篇~

/**
     * 打開(kāi)執(zhí)行下一步操作時(shí),查看下一步路由
     * @param flowId
     * @param processInstanceId
     * @return
     */
    @RequestMapping("/openExecute")
    public JsonResult openExecute(Long flowId,String processInstanceId){
        JsonResult jr = new JsonResult() ;
        resultMap = new HashMap<String,Object>() ;
        try {
            //這里需要可以獲取下一步路由
            Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
            List<TaskDef> nextTasks = taskDefService.getTaskNexts(flowId, task.getTaskDefinitionKey());
            List<String> list = new ArrayList<String>() ;
            String str = "" ;
            for(TaskDef td:nextTasks){
                String type = td.getType() ;
                //只要不是任務(wù)類或者事件扭仁,那么應(yīng)該繼續(xù)向下查詢
                if(!type.contains("Task") && !type.contains("Event")){
                    getNextTasks(flowId,td.getTaskKey(),task.getName()+"->",list);
                }else{
                    String expressionStr = td.getExpression() ;
                    str = task.getName() + "("+(StringUtils.isEmpty(expressionStr) ? "-" : expressionStr)+")"+ "->" + td.getName() ;
                    list.add(str) ;
                }
            }
            resultMap.put("list",list) ;
            jr.setResponseData(resultMap);
            jr.setResponseCode(1);
            jr.setResponseMessage(ResultEnum.SUCCESS);
        }catch (Exception e){
            e.printStackTrace();
            jr.setResponseCode(0);
            jr.setResponseMessage(ResultEnum.EXCEPTION);
        }
        return jr ;
    }

/**
     * private methods 01
     * 獲取下一步路由
     * @param flowId
     * @param taskKey
     * @return
     */
    private List<String> getNextTasks(Long flowId,String taskKey,String str,List<String> l){
        //根據(jù)流程定義業(yè)務(wù)主鍵ID和該環(huán)節(jié)的key查找其下一步路由
        List<TaskDef> taskNexts = taskDefService.getTaskNexts(flowId, taskKey);
        StringBuffer tStr = new StringBuffer(str) ;
        for(TaskDef td : taskNexts){
            String type = td.getType() ;
            String taskName = td.getName() ;
            //只要不是任務(wù)類或者事件可缚,那么應(yīng)該繼續(xù)向下查詢
            if(!tStr.toString().contains(taskName) && (!type.contains("Task") && !type.contains("Event"))){
                if(!StringUtils.isEmpty(td.getExpression())){
                    //如果涉及多個(gè)網(wǎng)關(guān)條件,則需要一一列出
                    tStr.append("("+td.getExpression()+")") ;
                }
                getNextTasks(flowId,td.getTaskKey(),tStr.toString(),l) ;
            }else{
                String expressionStr = td.getExpression() ;
                tStr.append("("+(StringUtils.isEmpty(expressionStr) ? "-" : expressionStr)+")"+td.getName()) ;
                l.add(tStr.toString()) ;
                //初始化tStr斋枢,讓其=str
                tStr = new StringBuffer(str) ;
            }
        }
        return l ;
    }
/**
     * 執(zhí)行下一步(dubbo)
     * @param processInstanceId
     * @param paramMap
     * @return
     */
    @RequestMapping("/execute")
    public JsonResult execute(String processInstanceId, String paramMap){
        JsonResult jr = new JsonResult() ;
        resultMap = new HashMap<String,Object>() ;
        try {
            Map<String, Object> map = JsonUtils.stringToMap(paramMap);
            Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
            taskService.complete(task.getId(),map);
            jr.setResponseCode(1);
            jr.setResponseMessage(ResultEnum.SUCCESS);
        }catch (Exception e){
            e.printStackTrace();
            jr.setResponseCode(0);
            jr.setResponseMessage(ResultEnum.EXCEPTION);
        }
        return jr ;
    }

總結(jié)

至此帘靡,有關(guān)于初始化參數(shù)、啟動(dòng)工作流瓤帚、執(zhí)行工作流的開(kāi)發(fā)全部完成描姚,此處涉及大量的業(yè)務(wù)端代碼,由于本人對(duì)于前端掌握的并不是很好戈次,所以可能途中會(huì)存在一些細(xì)節(jié)問(wèn)題待完善轩勘,因此各位若對(duì)代碼有任何不同的意見(jiàn)或建議歡迎下方留言,大家共同進(jìn)步怯邪!

下篇預(yù)告

1.正在運(yùn)行中實(shí)例和歷史流程查看
2.工作流的掛起與激活

敬請(qǐng)期待~~~
第三篇完結(jié)~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绊寻,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌澄步,老刑警劉巖冰蘑,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異村缸,居然都是意外死亡祠肥,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門梯皿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)仇箱,“玉大人,你說(shuō)我怎么就攤上這事东羹〖燎牛” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵属提,是天一觀的道長(zhǎng)渊额。 經(jīng)常有香客問(wèn)我,道長(zhǎng)垒拢,這世上最難降的妖魔是什么旬迹? 我笑而不...
    開(kāi)封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮求类,結(jié)果婚禮上奔垦,老公的妹妹穿的比我還像新娘。我一直安慰自己尸疆,他們只是感情好椿猎,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著寿弱,像睡著了一般犯眠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上症革,一...
    開(kāi)封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天筐咧,我揣著相機(jī)與錄音,去河邊找鬼噪矛。 笑死量蕊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的艇挨。 我是一名探鬼主播残炮,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼缩滨!你這毒婦竟也來(lái)了势就?” 一聲冷哼從身側(cè)響起泉瞻,我...
    開(kāi)封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎苞冯,沒(méi)想到半個(gè)月后袖牙,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡抱完,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年贼陶,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了刃泡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片巧娱。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖烘贴,靈堂內(nèi)的尸體忽然破棺而出禁添,到底是詐尸還是另有隱情,我是刑警寧澤桨踪,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布老翘,位于F島的核電站,受9級(jí)特大地震影響锻离,放射性物質(zhì)發(fā)生泄漏铺峭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一汽纠、第九天 我趴在偏房一處隱蔽的房頂上張望卫键。 院中可真熱鬧,春花似錦虱朵、人聲如沸莉炉。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)絮宁。三九已至,卻和暖如春服协,著一層夾襖步出監(jiān)牢的瞬間绍昂,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工偿荷, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留治专,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓遭顶,卻偏偏與公主長(zhǎng)得像张峰,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子棒旗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

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