day07项目【课程发布-添加课程信息】

课程相关表关系

01-课程发布表单-步骤导航

一、需求

二、配置路由

1、添加路由

 {

    path: '/course',

    component: Layout,

    redirect: '/course/list',

    name: '课程管理',

    meta: { title: '课程管理', icon: 'example' },

    children: [

      {

        path: 'list',

        name: '课程列表',

        component: () => import('@/views/edu/course/list'),

        meta: { title: '课程列表', icon: 'table' }

      },

      {

        path: 'info',

        name: 'EduCourseInfo',

        component: () => import('@/views/edu/course/info'),

        meta: { title: '发布课程' ,icon: 'tree'}

      },

      {

        path: 'info/:id',

        name: 'EduCourseInfoEdit',

        component: () => import('@/views/edu/course/info'),

        meta: { title: '编辑课程基本信息', noCache: true },

        hidden: true

      },

      {

        path: 'chapter/:id',

        name: '编辑课程大纲',

        component: () => import('@/views/edu/course/chapter'),

        meta: { title: '编辑课程大纲', icon: 'tree' },

        hidden: true

      },

      {

        path: 'publish/:id',

        name: 'EduTeacherEdit',

        component: () => import('@/views/edu/course/publish'),

        meta: { title: '发布课程', noCache:true },

        hidden:true

      }

    ]

  },

2、添加vue组件

三、整合步骤条组件

参考 http://element-cn.eleme.io/#/zh-CN/component/steps

1、课程信息页面

info.vue

<template>

  <div class="app-container">

    <h2 style="text-align: center;">发布新课程</h2>


    <el-steps :active="1" process-status="wait" align-center style="margin-bottom: 40px;">

      <el-step title="填写课程基本信息"/>

      <el-step title="创建课程大纲"/>

      <el-step title="最终发布"/>

    </el-steps>


    <el-form label-width="120px">

      <el-form-item>

        <el-button :disabled="saveBtnDisabled" type="primary" @click="next">保存并下一步</el-button>

      </el-form-item>

    </el-form>

  </div>

</template>

<script>

export default {

    data(){

        return {

            saveBtnDisabled: false // 保存按钮是否禁用

        }

    },

    created(){

    },

    methods:{

        next(){

            //跳转到第二步

            this.$router.push({path:'/course/chapter/1'})

        }

    }

}

</script>

2、课程大纲页面

chapter.vue

<template>

  <div class="app-container">

    <h2 style="text-align: center;">发布新课程</h2>


    <el-steps :active="2" process-status="wait" align-center style="margin-bottom: 40px;">

      <el-step title="填写课程基本信息"/>

      <el-step title="创建课程大纲"/>

      <el-step title="最终发布"/>

    </el-steps>


    <el-form label-width="120px">

      <el-form-item>

        <el-button @click="previous">上一步</el-button>

        <el-button :disabled="saveBtnDisabled" type="primary" @click="next">下一步</el-button>

      </el-form-item>

    </el-form>

  </div>

</template>

<script>

export default {

    data(){

        return {

            saveBtnDisabled: false // 保存按钮是否禁用

        }

    },

    created(){

    },

    methods:{

        //上一步

        previous(){

            this.$router.push({path:'/course/info/1'})

        },

        next(){

            //跳转到第二步

            this.$router.push({path:'/course/publish/1'})

        }

    }

}

</script>

3、课程发布页面

publish.vue

<template>

  <div class="app-container">

    <h2 style="text-align: center;">发布新课程</h2>


    <el-steps :active="3" process-status="wait" align-center style="margin-bottom: 40px;">

      <el-step title="填写课程基本信息"/>

      <el-step title="创建课程大纲"/>

      <el-step title="最终发布"/>

    </el-steps>


    <el-form label-width="120px">

      <el-form-item>

        <el-button @click="previous">返回修改</el-button>

        <el-button :disabled="saveBtnDisabled" type="primary" @click="publish">发布课程</el-button>

      </el-form-item>

    </el-form>

  </div>

</template>

<script>

export default {

    data(){

        return {

            saveBtnDisabled: false // 保存按钮是否禁用

        }

    },

    created(){

    },

    methods:{

        previous(){

            this.$router.push({path:'/course/chapter/1'})

        },

        publish(){

            //跳转到第二步

            this.$router.push({path:'/course/list'})

        }

    }

}

</script>


02-编辑课程基本信息

一、后台api

1、定义form表单对象

CourseInfoVo.java

@ApiModel(value = "课程基本信息", description = "编辑课程基本信息的表单对象")

@Data

public class CourseInfoVo implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "课程ID")

    private String id;

    @ApiModelProperty(value = "课程讲师ID")

    private String teacherId;

    @ApiModelProperty(value = "课程专业ID")

    private String subjectId;

    @ApiModelProperty(value = "课程标题")

    private String title;

    @ApiModelProperty(value = "课程销售价格,设置为0则可免费观看")

    //0.01

    private BigDecimal price;

    @ApiModelProperty(value = "总课时")

    private Integer lessonNum;

    @ApiModelProperty(value = "课程封面图片路径")

    private String cover;

    @ApiModelProperty(value = "课程简介")

    private String description;

}

2、修改CourseDescription主键生成策略

由于课程表和课程简介表是一对一的关系,所以简介表的id应该与课程表的id一致。

3、定义控制层接口

@RestController

@RequestMapping("/eduservice/course")

@CrossOrigin

public class EduCourseController {

    @Autowired

    private EduCourseService courseService;

    //添加课程基本信息的方法

    @ApiOperation(value = "新增课程")

    @PostMapping("addCourseInfo")

    public R addCourseInfo( @ApiParam(name = "CourseInfoForm", value = "课程基本信息", required = true)

            @RequestBody CourseInfoVo courseInfoVo){

        courseService.saveCourseInfo(courseInfoVo);

        return R.ok();

    }

}

4、定义业务层方法

接口:EduCourseService.java

public interface EduCourseService extends IService<EduCourse> {

    //添加课程基本信息的方法

    void saveCourseInfo(CourseInfoVo courseInfoVo);

}

实现:EduCourseServiceImpl.java

@Service

public class EduCourseServiceImpl extends ServiceImpl<EduCourseMapper, EduCourse> implements EduCourseService {

    @Autowired

    private EduCourseDescriptionService courseDescriptionService;

    @Override

    public void saveCourseInfo(CourseInfoVo courseInfoVo) {

        //1 向课程表添加课程基本信息

        //将CourseInfoVo对象转换为eduCourse对象

        EduCourse eduCourse = new EduCourse();

        BeanUtils.copyProperties(courseInfoVo,eduCourse);

        int insert = baseMapper.insert(eduCourse);

        if (insert == 0){

            //添加失败

            throw new GuliException(20001,"添加课程信息失败");

        }

        //获取添加之后的课程id

        String cid = eduCourse.getId();


        //2 向课程简介表添加课程简介

        //EduCourseDescription

        EduCourseDescription courseDescription = new EduCourseDescription();

        courseDescription.setDescription(courseInfoVo.getDescription());


        //设置描述id就是课程id

        courseDescription.setId(cid);

        courseDescriptionService.save(courseDescription);

    }

}

6、Swagger测试

二、前端实现

1、定义api

import request from '@/utils/request'

export default{

    //1 添加课程信息

    addCourseInfo(courseInfo){

        return request({

            url:`/eduservice/course/addCourseInfo`,

            method:'post',

            data:courseInfo

        })

    }

}

2、组件模板

<el-form label-width="120px">


        <el-form-item label="课程标题">

            <el-input v-model="courseInfo.title" placeholder=" 示例:机器学习项目课:从基础到搭建项目视频课程。专业名称注意大小写"/>

        </el-form-item>


        <!-- 所属分类 TODO -->


        <!-- 课程讲师 TODO -->


        <el-form-item label="总课时">

            <el-input-number :min="0" v-model="courseInfo.lessonNum" controls-position="right" placeholder="请填写课程的总课时数"/>

        </el-form-item>


        <!-- 课程简介 TODO -->

        <el-form-item label="课程标题">

            <el-input v-model="courseInfo.description" placeholder="  "/>

        </el-form-item>

        <!-- 课程封面 TODO -->

        <el-form-item label="课程价格">

            <el-input-number :min="0" v-model="courseInfo.price" controls-position="right" placeholder="免费课程请设置为0元"/> 元

        </el-form-item>

        <el-form-item>

            <el-button :disabled="saveBtnDisabled" type="primary" @click="saveOrUpdate">保存并下一步</el-button>

        </el-form-item>

    </el-form>

3、组件js

<script>

import course from '@/api/edu/course'

export default {

    data(){

        return {

            courseInfo:{

                title: '',

                subjectId: '',

                teacherId: '',

                lessonNum: 0,

                description: '',

                cover: '',

                price: 0,

            },

            saveBtnDisabled: false // 保存按钮是否禁用

        }

    },

    created(){

    },

    methods:{

        saveOrUpdate(){

            course.addCourseInfo(this.courseInfo)

                .then(response=>{

                    //提示

                    this.$message({

                         type: 'success',

                         message: '添加课程信息成功!'

                    });

                    //跳转到第二步

                    this.$router.push({path:'/course/chapter/'+response.data.courseId})

                })

        },

    }

}

</script>



03-课程分类多级联动的实现

一、需求

二、获取一级分类

1、组件数据定义

定义在data中

            subjectOneList:[],//一级分类

            subjectTwoList:[],//二级分类

2、组件模板

<!-- 所属分类 TODO -->

        <el-form-item label="课程分类">

            <el-select

                v-model="courseInfo.subjectParentId"

                placeholder="一级分类">

                <el-option

                    v-for="subject in subjectOneList"

                    :key="subject.id"

                    :label="subject.title"

                    :value="subject.id"/>

            </el-select>

    </el-form-item>

3、组件脚本

表单初始化时获取一级分类嵌套列表,引入subject api

import subject from '@/api/edu/subject'

定义方法

        //获取一级分类

        getOneSubjectList(){

            subject.getSubjectList()

                .then(response=>{

                    this.subjectOneList = response.data.list

                })

        },

三、级联显示二级分类

1、组件模板

            <!-- 二级分类 -->

            <el-select v-model="courseInfo.subjectId" placeholder="二级分类">

                <el-option

                    v-for="subject in subjectTwoList"

                    :key="subject.id"

                    :label="subject.title"

                    :value="subject.id"/>

            </el-select>

2、注册change事件

在一级分类的<el-select>组件中注册change事件

        <!-- 所属分类 TODO -->

        <el-form-item label="课程分类">

            <el-select

                v-model="courseInfo.subjectParentId"

                placeholder="一级分类" @change="subjectLevelOneChanged">

               .......

            </el-select>

3、定义change事件方法

        //点击某一个一级分类,触发change事件,显示对应二级分类

        subjectLevelOneChanged(value){

            //value就是一级分类id值

            //遍历所有的分类,包含一级和二级

            for(var i =0; i<this.subjectOneList.length;i++){

                //每一个一级分类

                var oneSubject = this.subjectOneList[i]

                //判断:所有一级分类id和点击一级分类id是否一样

                if(oneSubject.id === value){

                    //从一级分类获取里面所有的二级分类

                    this.subjectTwoList = oneSubject.children

                    //把二级分类id值清空

                    this.courseInfo.subjectId = ''

                }

            }

        },


04-讲师下拉列表

一、前端实现

1、组件模板

        <!-- 课程讲师 TODO -->

        <!-- 课程讲师 -->

        <el-form-item label="课程讲师">

            <el-select

                v-model="courseInfo.teacherId"

                placeholder="请选择">

                <el-option

                    v-for="teacher in teacherList"

                    :key="teacher.id"

                    :label="teacher.name"

                    :value="teacher.id"/>

            </el-select>

        </el-form-item>

2、定义api

api/edu/course.js

//2 查询所有讲师

    getListTeacher(){

        return request({

            url:`/eduservice/teacher/findAll`,

            method:'get'

        })

    }

组件中引入course api

import course from '@/api/edu/course'

3、组件脚本

定义data

teacherList:[],//讲师列表

获取讲师列表:

        //查询所有讲师

        getListTeacher(){

            course.getListTeacher()

                .then(response => {

                    this.teacherList = response.data.items

                })

        }

  created(){

        //初始化所有讲师

        this.getListTeacher()

    },


05-富文本编辑器Tinymce

一、Tinymce可视化编辑器

参考

https://panjiachen.gitee.io/vue-element-admin/#/components/tinymce

https://panjiachen.gitee.io/vue-element-admin/#/example/create

二、组件初始化

Tinymce是一个传统javascript插件,默认不能用于Vue.js因此需要做一些特殊的整合步骤

1、复制脚本库

将脚本库复制到项目的static目录下(在vue-element-admin-master的static路径下)

2、配置html变量

在 guli-admin/build/webpack.dev.conf.js 中添加配置

使在html页面中可是使用这里定义的BASE_URL变量

3、引入js脚本

在guli-admin/index.html 中引入js脚本

    <script src=<%= BASE_URL %>/tinymce4.7.5/tinymce.min.js></script>

    <script src=<%= BASE_URL %>/tinymce4.7.5/langs/zh_CN.js></script>

三、组件引入

为了让Tinymce能用于Vue.js项目,vue-element-admin-master对Tinymce进行了封装,下面我们将它引入到我们的课程信息页面

1、复制组件

src/components/Tinymce

2、引入组件

课程信息组件中引入 Tinymce

import Tinymce from '@/components/Tinymce' //引用

export default {

    components: { Tinymce }, //声明

    .......

}

3、组件模板

       <!-- 课程简介-->

        <el-form-item label="课程简介">

            <tinymce :height="300" v-model="courseInfo.description"/>

        </el-form-item>

4、组件样式

在info.vue文件的最后添加如下代码,调整上传图片按钮的高度

<style scoped>/* scoped表示只在当前页面有效 */    

    .tinymce-container {

        line-height: 29px;

    }

</style>

5、图片的base64编码

Tinymce中的图片上传功能直接存储的是图片的base64编码,因此无需图片服务器

测试:

添加一级分类id:



06-课程封面

一、整合上传组件

参考 http://element-cn.eleme.io/#/zh-CN/component/upload用户头像上传

1、定义data数据

BASE_API: process.env.BASE_API, // 接口API地址

2、组件模板

在info.vue中添加上传组件模板

        <!-- 课程封面-->

        <el-form-item label="课程封面">         


            <el-upload

                :show-file-list="false"

                :on-success="handleAvatarSuccess"

                :before-upload="beforeAvatarUpload"

                :action="BASE_API+'/eduoss/fileoss'"

                class="avatar-uploader">

            <img :src="courseInfo.cover">

        </el-upload>

5、结果回调

        //上传封面成功

        handleAvatarSuccess(res, file){

            this.courseInfo.cover = res.data.url

        },

        //上传封面之前

        beforeAvatarUpload(file){

            const isJPG = file.type === 'image/jpeg'

            const isLt2M = file.size / 1024 / 1024 < 2


            if (!isJPG) {

                this.$message.error('上传头像图片只能是 JPG 格式!')

            }

            if (!isLt2M) {

                this.$message.error('上传头像图片大小不能超过 2MB!')

            }

            return isJPG && isLt2M

        },




07-课程信息回显

一、后端实现

1、业务层

接口:CourseService.java

//根据ID查询课程

CourseInfoVo getCourseInfoFormById(String courseId);

实现:CourseServiceImpl.java

@Override

    public CourseInfoVo getCourseInfoFormById(String courseId) {

        //1 查询课程表

        EduCourse eduCourse = baseMapper.selectById(courseId);

//        EduCourse eduCourse = this.getById(courseId);

        if (eduCourse == null){

            throw new GuliException(20001, "数据不存在");

        }

        //把eduCourse对象中的值复制到courseInfoVo中

        CourseInfoVo courseInfoVo = new CourseInfoVo();

        BeanUtils.copyProperties(eduCourse,courseInfoVo);


        //2 查询描述表

        EduCourseDescription courseDescription = courseDescriptionService.getById(courseId);

        if (eduCourse !=null){

            //讲描述信息放入courseInfoVo

            courseInfoVo.setDescription(courseDescription.getDescription());

        }

        return courseInfoVo;

    }

2、web层

    @ApiOperation(value = "根据ID查询课程")

    @GetMapping("getCourseInfo/{courseId}")

    public R getCourseInfo(@ApiParam(name = "id", value = "课程ID", required = true)

                        @PathVariable String courseId){

      CourseInfoVo courseInfoVo  = courseService.getCourseInfoFormById(courseId);

        return R.ok().data("courseInfoVo",courseInfoVo);

    }

3、Swagger中测试

二、前端实现

1、定义api

api/edu/course.js

 //3 根据id获取课程基本信息

    getCourseInfoById(id){

        return request({

            url:`/eduservice/course/getCourseInfo/${id}`,

            method:'get'            

        })

    },

2、组件js

data中声明:

  courseId:'',

created()

    //获取路由中的路由id值

        if(this.$route.params && this.$route.params.id){

            this.courseId = this.$route.params.id

            //调用

            this.getInfo()

        }

方法:

    //根据id获取课程信息

        getInfo(){

            course.getCourseInfoById(this.courseId)

                .then(response => {

                    this.courseInfo = response.data.courseInfoVo

                })

        },

三、解决级联下拉菜单回显问题

1、数据库中增加冗余列

subject_parent_id课程专业父级ID

2、pojo中增加属性

entity.Course.java

form.CourseInfo.java

@ApiModelProperty(value = "一级分类ID")

    private String subjectParentId;

3、vue组件中绑定数据

edu/course/info.vue

4、修改init方法

将 this.initSubjectList() 和 this.initTeacherList()移至else

        //init方法

        init(){

             //获取路由中的路由id值

            if(this.$route.params && this.$route.params.id){

                this.courseId = this.$route.params.id

                //调用

                this.getInfo()

            }else{

                //清空表单

                this.courseInfo = {...defaultForm}

                //初始化所有讲师

                this.getListTeacher()

                //初始化一级分类

                this.getOneSubjectList()

            }

        },

5、修改fetchCourseInfoById方法

解决在返回上一步的二级表单的问题。

    //根据id获取课程信息

        getInfo(){

            course.getCourseInfoById(this.courseId)

                .then(response => {

                    this.courseInfo = response.data.courseInfoVo

                    //1 查询所有的分类,包含一级和二级

                    subject.getSubjectList()

                        .then(response=>{

                            //2 获取所有一级分类

                            this.subjectOneList = response.data.list

                            //3 把所有的一级分类数组进行遍历

                            for(var i=0;i<this.subjectOneList.length; i++){

                                //获取每一个一级分类

                                var subjectOne = this.subjectOneList[i]

                                //比较当前courseInfo里面的一级分类id和所有的一级分类id

                                if(this.courseInfo.subjectParentId == subjectOne.id){

                                    //获取一级分类里面的所有二级分类

                                    this.subjectTwoList = subjectOne.children

                                }

                            }

                        })

                        //初始化所有讲师

                        this.getListTeacher()

                })

        },

刷新发布课程页面:

const defaultForm = {

    title: '',

    subjectId: '',//二级分类id

    subjectParentId:'',//一级分类id

    teacherId: '',

    lessonNum: 0,

    description: '',

    cover: '/static/11.jpg',

    price: 0

}

 created(){

       this.init()

    },

        //init方法

        init(){

             //获取路由中的路由id值

            if(this.$route.params && this.$route.params.id){

                this.courseId = this.$route.params.id

                //调用

                this.getInfo()

            }else{

                //清空表单

                this.courseInfo = {...defaultForm}

                //初始化所有讲师

                this.getListTeacher()

                //初始化一级分类

                this.getOneSubjectList()

            }

        },


    //监听

    watch:{

        $route(to,from){ //路由变化方式,路由发生变化,方法就会执行

            this.init()

        }

    },



08-更新课程信息

一、后端实现

1、业务层

接口:EduCourseService.java

    //更新课程信息

    void updateCourseInfoById(CourseInfoVo courseInfoVo);

实现:EduCourseServiceImpl.java

    //更新课程信息

    @Override

    public void updateCourseInfoById(CourseInfoVo courseInfoVo) {

        //1 修改课程表

        EduCourse eduCourse = new EduCourse();

        BeanUtils.copyProperties(courseInfoVo,eduCourse);

        int update = baseMapper.updateById(eduCourse);

        if (update == 0){

            throw new GuliException(20001,"修改课程信息失败");

        }

        //2 修改描述表

        EduCourseDescription courseDescription = new EduCourseDescription();

        courseDescription.setId(courseInfoVo.getId());

        courseDescription.setDescription(courseInfoVo.getDescription());

        courseDescriptionService.updateById(courseDescription);

    }

2、web层

    //更新课程信息

    @ApiOperation(value = "更新课程")

    @PostMapping("updateCourseInfo")

    public R updateCourseInfo( @ApiParam(name = "CourseInfoForm", value = "课程基本信息", required = true)

                                  @RequestBody CourseInfoVo courseInfoVo){

        courseService.updateCourseInfoById(courseInfoVo);

        return R.ok();

    }

二、前端实现

1、定义api

course.js

 //4 修改课程基本信息

    updateCourseInfoById(courseInfo){

        return request({

            url:`/eduservice/course/updateCourseInfo`,

            method:'post',

            data:courseInfo

        })

    }

2、组件js

info.vue

 updateCourse(){

            course.updateCourseInfoById(this.courseInfo)

                .then(response=>{

                    //提示

                    this.$message({

                         type: 'success',

                         message: '修改课程信息成功!'

                    });

                    //跳转到第二步

                    this.$router.push({path:'/course/chapter/'+this.courseId})

                })

        },

 saveOrUpdate(){

           if(!this.courseInfo.id){

               //添加

               this.addCourse()

           }else{

               //修改

               this.updateCourse()

           }

        },

403错误

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