ant-design-pro动态的选择输出表格字段的功能

场景:有一天,产品经理突然发了疯,要做一个可以动态的选择表格的显示字段的功能,然后字段分为商品相关的字段(40多个),库存相关的字段(30多个),采购相关的字段(30多个),订单相关的字段(数不清)... MMP的,总共好几百个字段,不同类型的字段在各个地方重用,然后又要选择性的导出。
如图:
(1)字段选择框


output.png

(2)主页面


list.png

解决过程:

1.封装框架自带的穿梭框。
class OutputWordsSelector extends BaseComponent{
  mDataList=[];
  constructor(props){
    super(props);
    if(props.datalist!==null){
      this.mDataList=props.datalist;
    }
    this.state={
      leftTitle:"未选项目",
      rightTitle:"已选项目",
      targetKeys: props.targetKeys,
      selectedKeys: props.selectedKeys,
      disabled: false,
    }
  }

  handleChange = (nextTargetKeys, direction, moveKeys) => {
    this.setState({ targetKeys: nextTargetKeys });
    LogUtil.debugTag("nextTargetKeys=",nextTargetKeys);
    if(this.props.selectChange!=null){
      this.props.selectChange(nextTargetKeys);
    }
  }

  handleSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
    this.setState({ selectedKeys: [...sourceSelectedKeys, ...targetSelectedKeys] });
  }

  render() {
    const { targetKeys, selectedKeys,leftTitle,rightTitle} = this.state;
    return(
      <div>
        <Transfer
          className={style.width}
          dataSource={this.mDataList}
          titles={[leftTitle,rightTitle]}
          targetKeys={targetKeys}
          selectedKeys={selectedKeys}
          onChange={this.handleChange}
          onSelectChange={this.handleSelectChange}
          onScroll={this.handleScroll}
          render={item => item.title}
        />
      </div>
    )
  }

}

export default OutputWordsSelector
2.构造商品模块通用的表格输出字段工具。
class GoodsInfoColumns {
  /**
   * 商品资料输出字段
   * @type {*[]}
   */
  static colums = [
    {
      code: MyConstants.OUTPUT_PDT_NAME,
      title: '商品名称',
      dataIndex: 'goodsInfo',
      render: (text, record) => (
        <div style={{ width: 280 }}>
          <GoodsInfo goodsInfo={record.goodsInfo}>
          </GoodsInfo>
        </div>
      ),
    },
    {
      code: MyConstants.OUTPUT_PDT_GOODS_CODE,
      title: '货号',
      dataIndex: 'number',
      render: (text, record) => {
        return <div style={{width:100}}>{record.number==null?"-":record.number}</div>;
      },
    },
    {
      code: MyConstants.OUTPUT_PDT_STYLE_CODE,
      title: '款号',
      dataIndex: 'styleNumber',
      render: (text, record) => {
        return <div style={{width:100}}>{record.styleNumber==null?"-":record.styleNumber}</div>;
      },
    },
    {
      code: MyConstants.OUTPUT_PDT_STOCK_UNIT,
      title: '库存单位',
      dataIndex: 'unit',
      render: (text, record) => {
        return <div style={{width:100}}>{record.unit==null?"-":record.unit}</div>;
      },
    },
    {
      code: MyConstants.OUTPUT_PDT_COOPERATE_WAY,
      title: '合作方式',
      dataIndex: 'saleMold',
      render: (text, record) => {
        return <div style={{width:100}}>{record.saleMold==null?"-":record.saleMold}</div>;
      },
    },
    {
      code: MyConstants.OUTPUT_PDT_BRAND,
      title: '品牌',
      dataIndex: 'brandName',
      render: (text, record) => {
        return <div style={{width:100}}>{record.brandName==null?"-":record.brandName}</div>;
      },
    },
    {
      code: MyConstants.OUTPUT_PDT_MF_TYPE,
      title: '品类',
      dataIndex: 'mfCategoryName',
      render: (text, record) => {
        return <div style={{width:100}}>{record.mfCategoryName==null?"-":record.mfCategoryName}</div>;
      },
    },
 ...

}

export default GoodsInfoColumns;

3.构造库存列表独有的字段表格工具
import MoneyUtil from '../../../../../utils/erp/MoneyUtil';
import PayUtil from '../../../../../utils/erp/PayUtil';
import TimeUtil from '../../../../../utils/erp/TimeUtil';
import OrderUtil from '../../../../../utils/erp/OrderUtil';
import MyConstants from '../../../../../utils/erp/MyConstants';
import ExcelUtil from '../../../../../utils/erp/ExcelUtil';
import GoodsInfo from '../../../common/goodsInfo/GoodsInfo';

class StockListUtil {
  /**
   * 所有表格数据字段
   * @type {*[]}
   */
  static colums = [
    //基础字段
    {
      code: MyConstants.OUTPUT_STOCK_TOTAL,
      title: '总库存',
      dataIndex: 'totalAmount',
      render: (text, record) => {
        return <div style={{width:100}}>{record.totalAmount==null?"-":record.totalAmount}</div>;
      },
    },
    {
      code: MyConstants.OUTPUT_STOCK_ON_THE_WAY,
      title: '在途库存',
      dataIndex: 'onWayAmount',
      render: (text, record) => {
        return <div style={{width:80}}>{record.onWayAmount==null?"-":record.onWayAmount}</div>;
      },
    },
    {
      code: MyConstants.OUTPUT_SS_STOCK_CAN_SALE,
      title: '可售库存',
      dataIndex: 'salableAmount',
      render: (text, record) => {
        return <div style={{width:80}}>{record.salableAmount==null?"-":record.salableAmount}</div>;
      },
    },
    {
      code: MyConstants.OUTPUT_SS_STOCK_AVG_COST,
      title: '平均成本(元)',
      dataIndex: 'averageCost',
      render:(text,record)=>{
        return <div style={{width:100}}>{MoneyUtil.changeMoneyNumToShow(record.averageCost)}</div>
      }
    },
    {
      code: MyConstants.OUTPUT_STOCK_TOTAL_COST,
      title: '总成本(元)',
      dataIndex: 'totalCost',
      render:(text,record)=>{
        return <div style={{width:100}}>{MoneyUtil.changeMoneyNumToShow(record.totalCost)}</div>
      }
    },
  ];

  /**
   * 对JSON数据进行相应的转化,导出excel表格(动态控制导出字段)
   * @param datalist
   * @param fileName
   */
  static outputExcelDynamic(datalist,columns, fileName) {
    let tempList = [];
    for (let i = 0; i < datalist.length; i++) {
      let temp = {};
      for(let j=0;j<columns.length;j++){
        let title=columns[j].title;
        let dataIndex=columns[j].dataIndex;
        temp[title]=datalist[i][dataIndex];
      }
      tempList.push(temp);
    }
    ExcelUtil.exportExcelTable(tempList, fileName);
  }
  // /**
  //  * 对JSON数据进行相应的转化,导出excel表格
  //  * @param datalist
  //  * @param fileName
  //  */
  // static outputExcel(datalist, fileName) {
  //   let tempList = [];
  //   for (let i = 0; i < datalist.length; i++) {
  //     let temp = {};
  //     temp.订单号 = datalist[i].orderNum;
  //     temp.金额 = MoneyUtil.changeMoneyNumToShow(datalist[i].money);
  //     temp.支付方式 = PayUtil.changeChannelPayToStr(datalist[i].payway);
  //     temp.会员 = datalist[i].member;
  //     temp.所属门店 = datalist[i].belongTo;
  //     temp.创建时间 = TimeUtil.changeTimeStampToDateTime(datalist[i].createTime);
  //     temp.状态 = OrderUtil.changeOrderStatusToStr(datalist[i].status);
  //     temp.支付时间 = TimeUtil.changeTimeStampToDateTime(datalist[i].payTime);
  //     temp.运费 = MoneyUtil.changeMoneyNumToShow(datalist[i].dlvPrice);
  //     temp.快递单号 = datalist[i].dlvNum;
  //     temp.物流公司 = datalist[i].dlvCompany;
  //     tempList.push(temp);
  //   }
  //   ExcelUtil.exportExcelTable(tempList, fileName);
  // }

}

export default StockListUtil;

4.主页面
import BaseComponent from '../../../base/BaseComponent';
import { connect } from 'dva';
import { Input, Select, Table, Modal, Button, Card } from 'antd';
import LogUtil from '../../../../../utils/erp/LogUtil';
import MyConstants from '../../../../../utils/erp/MyConstants';
import OutputWordsSelector from '../../../common/outputWordsSelector/OutputWordsSelector';
import router from 'umi/router';
import StockListUtil from './StockListUtil';
import OutputWordUtil from '../../../../../utils/erp/OutputWordUtil';
import style from '../../StockStyle.css';
import GoodsInfoColumns from '../../../common/columns/GoodsInfoColumns';
import StockDistribution from './StockDistribution';
import HttpCode from '../../../../../utils/erp/HttpCode';
import MsgUtil from '../../../../../utils/erp/MsgUtil';

const Option = Select.Option;

@connect(({ stockSearch, stockCommon,loading }) => ({
  stockSearch,
  stockCommon,
  loading: loading.models.stockSearch,
}))
class StockList extends BaseComponent {
  //可操作列
  columnOperator = {
    title: '操作',
    dataIndex: 'operate',
    key: 'operate',
    render: (text, record) => (
      <div style={{ width: 150 }}>
        <a onClick={this.showDialog2.bind(this, record)}>分配</a>
        <span> | </span>
        <a onClick={this.goToStockStream.bind(this,record)}>流水</a>
      </div>
    ),
  };
  //所有可选字段
  mWordList = [];
  //已经选择的字段
  mSelectedWordList = [];
  //已选字段暂存数组
  tempKeys = [];
  //输出字段字符串
  outputValue = '';
  //数据分页
  mPageSize = 20;
  mCurrentPage = 0;
  //查询参数
  text=MyConstants.DefaultEmptyStringValue;
  mfBrand=MyConstants.DefaultNumValue;
  brand=MyConstants.DefaultNumValue;
  supplier=MyConstants.DefaultNumValue;
  constructor(props) {
    super(props);
    this.initOutputWords();
    this.getSelectedColumns();
  }

  componentDidMount() {
    this.getDataList();
    this.getMFBrandList();
    this.getBrandList();
    this.getSupplierList();
  }

  //默认的表格显示字段
  defaultOutputKeys = [
    MyConstants.OUTPUT_PDT_NAME,
    MyConstants.OUTPUT_PDT_DESCRIPTION,
    MyConstants.OUTPUT_PDT_COOPERATE_WAY,
    MyConstants.OUTPUT_PDT_BRAND,
    MyConstants.OUTPUT_PDT_MF_TYPE,
    MyConstants.OUTPUT_PDT_STOCK_UNIT,
    MyConstants.OUTPUT_SS_STOCK_TOTAL,
    MyConstants.OUTPUT_SS_STOCK_ON_THE_WAY,
    MyConstants.OUTPUT_SS_STOCK_CAN_SALE,
    MyConstants.OUTPUT_SS_STOCK_AVG_COST,
    MyConstants.OUTPUT_SS_STOCK_TOTAL_COST,
  ];

  /**
   * 初始化输出字段
   */
  initOutputWords() {
    StockListUtil.colums.map((item) => {
      let temp = {};
      temp.key = item.code;
      temp.title = item.title;
      this.mWordList.push(temp);
    });
    GoodsInfoColumns.colums.map(item => {
      let temp = {};
      temp.key = item.code;
      temp.title = item.title;
      this.mWordList.push(temp);
    });
    this.mSelectedWordList = JSON.parse(JSON.stringify(this.defaultOutputKeys));
  }

  /**
   * 获取输出表格列
   */
  getSelectedColumns() {
    this.colums = OutputWordUtil.getColums(this.mSelectedWordList, GoodsInfoColumns.colums);
    // //按code排序,需要的时候使用
    // this.colums = this.colums.sort(function(a, b) {
    //   return a.code - b.code;
    // });
    let tempList = OutputWordUtil.getColums(this.mSelectedWordList, StockListUtil.colums);
    for (let i = 0; i < tempList.length; i++) {
      this.colums.push(tempList[i]);
    }
    this.colums.push(this.columnOperator);
    //获取表格头字符
    this.outputValue = '';
    for (let i = 0; i < this.colums.length; i++) {
      this.outputValue = this.outputValue + this.colums[i].title + ',';
    }
  }

  render() {
    const { stockSearch: { stockListData, loading },stockCommon:{mfList,brandList,supplierList} } = this.props;
    return (
      <Card bordered={false}>
        <div className={style.select_div}>
          <div className={style.select_line}>
            <span>商品筛选:</span>
            <Input placeholder="商品名称/货号/条码" className={style.input} onChange={this.onTextInputChange} value={this.text}/>
            <span className={style.space_left}>MF品牌:</span>
            <Select defaultValue={MyConstants.DefaultNumValue} value={this.mfBrand} className={style.select_width} onSelect={this.onMFbrandSelect}>
              <Option value={MyConstants.DefaultNumValue}>全部</Option>
              {mfList.map(item=>{
                return <Option value={item.id}>{item.name}</Option>
              })}
            </Select>
            <span className={style.space_left}>商品品牌:</span>
            <Select defaultValue={MyConstants.DefaultNumValue} value={this.brand} className={style.select_width} onSelect={this.onBrandSelect}>
              <Option value={MyConstants.DefaultNumValue}>全部</Option>
              {brandList.map(item=>{
                return <Option value={item.id}>{item.name}</Option>
              })}
            </Select>
          </div>
          <div className={style.select_line} style={{ marginTop: 10 }}>
            <span>供应商:</span>
            <Select defaultValue={MyConstants.DefaultNumValue} value={this.supplier} className={style.select_width} onSelect={this.onSupplierSelect}>
              <Option value={MyConstants.DefaultNumValue}>全部</Option>
              {supplierList.map(item=>{
                return <Option value={item.id}>{item.name}</Option>
              })}
            </Select>
          </div>
          <div className={style.select_line} style={{ marginTop: 10 }}>
            <span>输出:</span>
            <Input value={this.outputValue} style={{ width: 300, marginLeft: 30 }} disabled={true}/>
            <Button type="primary" onClick={this.showDialog} ghost>...</Button>
          </div>
          <div className={style.select_line} style={{ marginTop: 10 }}>
            <Button type="primary" onClick={this.searchInfo}>筛选</Button>
            <Button type="primary" onClick={this.outputData} ghost style={{ marginLeft: 10 }}>导出</Button>
            <a onClick={this.initSearchCondition} style={{ marginLeft: 10 }}>清除筛选条件</a>
          </div>
        </div>
        <div style={{ marginTop: 20 }}>
          <Table
            rowKey={this.getRowKey}
            columns={this.colums}
            dataSource={stockListData.pageData}
            loading={loading}
            // scroll={{ x: 100 }}
            style={{overflowX:"scroll",tableLayout:"fixed"}}
            pagination={{
              onChange: page => {
                console.log(page);
                /**
                 * 数据库数据页是从0开始的,antD是从1开始的
                 * */
                this.mCurrentPage = page - 1;
                this.getData();
              },
              pageSize: this.mPageSize,
              total: stockListData.totalSize,
            }}
          />
        </div>

        <Modal
          title="输出栏目"
          visible={this.state.dialogVisible}
          onOk={this.dialogOk}
          onCancel={this.dialogCancel}
        >
          <OutputWordsSelector datalist={this.mWordList} selectedKeys={[]} targetKeys={this.mSelectedWordList}
                               selectChange={this.outputWordsChange}/>
        </Modal>
        <Modal
          width="800px"
          title="分布"
          visible={this.state.dialogVisible2}
          onOk={this.dialogOk2}
          onCancel={this.dialogCancel2}
          footer={null}
          destroyOnClose={true}
        >
          <StockDistribution info={this.goodsInfo}></StockDistribution>
        </Modal>

      </Card>);
  }

  getRowKey = (record) => {
    return record.skuId;
  };


  //================= 弹出框相关 ===============
  state = { dialogVisible: false, dialogVisible2: false };
  showDialog = () => {
    this.setState({
      dialogVisible: true,
    });
  };
  goodsInfo=null;
  showDialog2 = (record) => {
    this.goodsInfo=JSON.parse(JSON.stringify(record.goodsInfo));
    this.goodsInfo.skuId=record.skuId;
    this.goodsInfo.brand=record.brand;
    this.goodsInfo.mfCategoryName=record.mfCategoryName;
    this.goodsInfo.unit=record.unit;
    this.setState({
      dialogVisible2: true,
    });
  };

  dialogOk = (e) => {
    this.mSelectedWordList = this.tempKeys;
    this.getSelectedColumns();
    this.setState({
      dialogVisible: false,
    });
  };
  dialogOk2 = (e) => {
    this.setState({
      dialogVisible2: false,
    });
  };

  dialogCancel = (e) => {
    this.setState({
      dialogVisible: false,
    });
  };
  dialogCancel2 = (e) => {
    this.setState({
      dialogVisible2: false,
    });
  };

  //======================= 状态回调函数 =====================
  outputWordsChange = (keys) => {
    this.tempKeys = [];
    keys.map(item => {
      this.tempKeys.push(item);
    });
    this.tempKeys.sort();
  };

  onMFbrandSelect=(key)=>{
    this.mfBrand=key;
    this.setState({});
  };

  onBrandSelect=(key)=>{
    this.brand=key;
    this.setState({});
  };

  onSupplierSelect=(key)=>{
    this.supplier=key;
    this.setState({});
  };

  onTextInputChange=(e)=>{
    this.text=e.target.value;
    this.setState({});
  };

  //=================== 功能点击按钮 ====================
  /**
   * 搜索
   */
  searchInfo = () => {
      this.getDataList();
  };
  /**
   * 导出数据
   */
  outputData = () => {
    const { stockSearch: { stockListData } } = this.props;
    StockListUtil.outputExcel(stockListData.pageData, this.colums,'线上销售单数据表.xlsx');
  };
  /**
   * 初始化搜索条件
   */
  initSearchCondition = () => {
    this.text=MyConstants.DefaultEmptyStringValue;
    this.mfBrand=MyConstants.DefaultNumValue;
    this.brand=MyConstants.DefaultNumValue;
    this.supplier=MyConstants.DefaultNumValue;
    this.setState({});
  };

  goToStockStream=(record)=>{
    let path = {
      pathname: '/stock/stream/singleList',
      state: {
        skuId: record.skuId,
      },
    };
    router.push(path);
  }

  //================= 网络接口调用 ====================
  getDataList = () => {
    const { dispatch } = this.props;
    let params={};
    params.pageNumber=this.mCurrentPage;
    params.pageSize=this.mPageSize;
    if(this.text!==MyConstants.DefaultEmptyStringValue){
      params.text=this.text;
    }
    if(this.mfBrand!==MyConstants.DefaultNumValue){
      params.categoryId=this.mfBrand;
    }
    if(this.brand!==MyConstants.DefaultNumValue){
      params.brandId=this.brand;
    }
    if(this.supplier!==MyConstants.DefaultNumValue){
      params.supplierId=this.supplier;
    }
    dispatch({
      type: 'stockSearch/getStockList',
      payload: params,
    });
  };

  getMFBrandList=()=>{
    const{dispatch}=this.props;
    dispatch({
      type:"stockCommon/getMFList",
      payload:{}
    });
  }
  getBrandList=()=>{
    const{dispatch}=this.props;
    dispatch({
      type:"stockCommon/getBrandList",
      payload:{}
    });
  }
  getSupplierList=()=>{
    const{dispatch}=this.props;
    dispatch({
      type:"stockCommon/getSupplierList",
      payload:{}
    });
  }
}

export default StockList;

5.导出工具类
import XLSX from 'xlsx';
import LogUtil from './LogUtil';
import MoneyUtil from './MoneyUtil';
import TimeUtil from './TimeUtil';

function createCeil(type,text) {
  var el =  document.createElement(type);
  el.innerHTML = text;
  return el;
}
function jsonToTable(data,serialNum,dataTime) {
  let table = document.createElement("table");
  let thead = document.createElement("thead");
  let title = document.createElement("tr");
  title.appendChild(createCeil('th','单号:'));
  title.appendChild(createCeil('th',serialNum));
  title.appendChild(createCeil('th','单据日期:'));
  title.appendChild(createCeil('th',dataTime));
  thead.appendChild(title);
  let clomunsH = document.createElement("tr");
  let keys = Object.keys(data[0]);
  keys.map(key => {
    clomunsH.appendChild(createCeil('th',key));
  })
  thead.appendChild(clomunsH);
  table.appendChild(thead);
  let tbody = document.createElement("tbody");
  data.map(item => {
    let tr = document.createElement("tr");
    keys.map(key => {
      tr.appendChild(createCeil('td',item[key]))
    })
    tbody.appendChild(tr);
  })
  table.appendChild(tbody);
  return table;
}

class ExcelUtil {

  /**
   * 通过转化好的json数据,输出excel表格(当前使用这种方式)
   * @param datalist
   * @param fileName
   */
  static exportExcelTable(datalist,fileName){
    var sheet=XLSX.utils.json_to_sheet(datalist);
    LogUtil.debugTag("sheet",sheet);
    var workbook = {
      SheetNames: ["mySheet"],
      Sheets: {
        mySheet:sheet
      }
    };
    XLSX.writeFile(workbook,fileName);
  }

  /**
   * 通过转化好的json数据,输出excel表格
   * @param datalist
   * @param serialNum EXCEL头部的单号
   * @param dataTime EXCEL头部的时间
   * @param fileName
   */
  static exportExcelHasHeader(datalist,serialNum,dataTime,fileName){
    let table = jsonToTable(datalist,serialNum,dataTime);
    let sheet = XLSX.utils.table_to_sheet(table);
    LogUtil.debugTag("sheet",sheet);
    var workbook = {
      SheetNames: ["mySheet"],
      Sheets: {
        mySheet:sheet
      }
    };
    XLSX.writeFile(workbook,fileName);
  }

  /**
   * 通过表格和数据输出excel表格
   * 使用方式:ExcelUtil.exportExcel(this.colums,onlineSaleList,"线上销售单数据表.xlsx");
   * @param headers
   * @param data
   * @param fileName
   */
  static exportExcel(headers, data, fileName = '数据表格.xlsx') {
    const _headers = headers
      .map((item, i) => Object.assign({}, { key: item.key, title: item.title, position: String.fromCharCode(65 + i) + 1 }))
      .reduce((prev, next) => Object.assign({}, prev, { [next.position]: { key: next.key, v: next.title } }), {});

    const _data = data
      .map((item, i) => headers.map((key, j) => Object.assign({}, { content: item[key.key], position: String.fromCharCode(65 + j) + (i + 2) })))
      // 对刚才的结果进行降维处理(二维数组变成一维数组)
      .reduce((prev, next) => prev.concat(next))
      // 转换成 worksheet 需要的结构
      .reduce((prev, next) => Object.assign({}, prev, { [next.position]: { v: next.content } }), {});

    // 合并 headers 和 data
    const output = Object.assign({}, _headers, _data);
    // 获取所有单元格的位置
    const outputPos = Object.keys(output);
    // 计算出范围 ,["A1",..., "H2"]
    const ref = `${outputPos[0]}:${outputPos[outputPos.length - 1]}`;

    // 构建 workbook 对象
    const wb = {
      SheetNames: ['mySheet'],
      Sheets: {
        mySheet: Object.assign(
          {},
          output,
          {
            '!ref': ref,
            '!cols': [{ wpx: 45 }, { wpx: 100 }, { wpx: 200 }, { wpx: 80 }, { wpx: 150 }, { wpx: 100 }, { wpx: 300 }, { wpx: 300 }],
          },
        ),
      },
    };
    // 导出 Excel
    XLSX.writeFile(wb, fileName);
  }
}
export default ExcelUtil;

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,056评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,842评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,938评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,296评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,292评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,413评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,824评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,493评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,686评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,502评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,553评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,281评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,820评论 3 305
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,873评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,109评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,699评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,257评论 2 341