15课程信息功能的开发

Views: 0

课程信息不看视频的情况下基本上自己已经能写出来了,就是关联查询后端逻辑遇到一点问题,写了两天这个功能(毕竟不能全天写)

逻辑

查询课程:

前端有个搜索框可以输入课程名称查询 点击查询按钮会向后端发送请求,后端根据课程名称模糊匹配返回结果

表格会显示所有课程信息,包括课程名称、学分、教师、上课时间地点等

新增课程:

点击”新增”按钮弹出表单 填写课程信息(名称、介绍、学分、人数限制等)

需要选择授课教师和所属学院(从下拉框选择) 点击保存后,后端会创建新课程

编辑课程:

点击表格行的”编辑”按钮 会弹出表单并自动填充该课程现有信息 修改后点击保存,后端会更新这条课程信息

删除课程:

点击”删除”按钮会弹出确认框 确认后后端会删除这条课程记录

分页功能:

表格底部有分页控件 可以切换页码查看不同页的课程数据

数据关联:

课程关联了教师和学院信息 新增/编辑时可以选择已有教师和学院

表格中会显示教师姓名和学院名称(而不是ID)

创建数据库

CREATE TABLE `course` (
 `id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
 `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '课程名称',
 `content` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '课程介绍',
 `score` int DEFAULT NULL COMMENT '课程学分',
 `teacher_id` int DEFAULT NULL COMMENT '授课教师',
 `num` int DEFAULT NULL COMMENT '开班人数',
 `time` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '上课时间',
 `location` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '上课地点',
 `college_id` int DEFAULT NULL COMMENT '所属学院',
 `already_num` int DEFAULT NULL COMMENT '已选人数',
 PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='课程信息';

前端

Manager.vue

<el-menu-item index="/course" v-if ="data.user.role === 'ADMIN'">
 <el-icon><Reading /></el-icon>
 <span>课程信息</span>
</el-menu-item>

index.js

{ path: 'course', component: () => import('@/views/manager/Course.vue')},

Course.vue

<template>
 <div>

   <div class="card" style="margin-bottom: 5px;">
     <el-input v-model="data.name" style="width: 300px; margin-right: 10px" placeholder="请输入课程名称查询"></el-input>
     <el-button type="primary" @click="load">查询</el-button>
     <el-button type="info" style="margin: 0 10px" @click="reset">重置</el-button>
   </div>

   <div class="card" style="margin-bottom: 5px">
     <div style="margin-bottom: 10px">
       <el-button type="primary" @click="handleAdd">新增</el-button>
     </div>
     <el-table :data="data.tableData" stripe>
       <el-table-column label="课程名称" prop="name"></el-table-column>
       <el-table-column label="课程介绍" prop="content" show-overflow-tooltip></el-table-column>
       <el-table-column label="课程学分" prop="score"></el-table-column>
       <el-table-column label="授课教师" prop="teacherName"></el-table-column>
       <el-table-column label="开班人数" prop="num"></el-table-column>
       <el-table-column label="上课时间" prop="time"></el-table-column>
       <el-table-column label="上课地点" prop="location"></el-table-column>
       <el-table-column label="所属学院" prop="collegeName"></el-table-column>
       <el-table-column label="已选人数" prop="alreadyNum"></el-table-column>
       <el-table-column label="操作" align="center" width="160">
         <template #default="scope">
           <el-button type="primary" @click="handleEdit(scope.row)">编辑</el-button>
           <el-button type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
         </template>
       </el-table-column>
     </el-table>
   </div>

   <div class="card">
     <el-pagination background layout="prev, pager, next" v-model:page-size="data.pageSize" v-model:current-page="data.pageNum" :total="data.total"/>
   </div>

   <el-dialog title="课程信息" width="40%" v-model="data.formVisible" :close-on-click-modal="false" destroy-on-close>
     <el-form :model="data.form" label-width="100px" style="padding-right: 50px">
       <el-form-item label="课程名称" prop="name">
         <el-input v-model="data.form.name" autocomplete="off" />
       </el-form-item>
       <el-form-item label="课程介绍" prop="content">
         <el-input type="textarea" :rows="4" v-model="data.form.content" autocomplete="off" />
       </el-form-item>
       <el-form-item label="课程学分" prop="score">
         <el-input v-model="data.form.score" autocomplete="off" />
       </el-form-item>
       <el-form-item label="开班人数" prop="num">
         <el-input v-model="data.form.num" autocomplete="off" />
       </el-form-item>
       <el-form-item label="上课时间" prop="time">
         <el-input v-model="data.form.time" autocomplete="off" />
       </el-form-item>
       <el-form-item label="上课地点" prop="location">
         <el-input v-model="data.form.location" autocomplete="off" />
       </el-form-item>
<!--       授课教师 绑定的是教师的id   显示的是教师的name   下拉框的宽度为100% 遍历教师信息
设置每个教师的key为id   设置每个教师的label为name   设置每个教师的value为id-->
       <el-form-item label="授课教师" prop="teacherId">
         <el-select v-model="data.form.teacherId" placeholder="请选择教师" style="width: 100%">
           <el-option v-for="item in data.teacherDate"
                      :key="item.id"
                      :label="item.name"
                      :value="item.id">
           </el-option>
         </el-select>
       </el-form-item>
       <el-form-item label="所属学院" prop="collegeId">
         <!-- 专业信息是关联学院的,所以在新增(编辑)专业信息的时候,需要选择对应的学院,绑定起来。-->
       <el-select v-model="data.form.collegeId" placeholder="请选择学院" style="width: 100%">
         <el-option v-for="item in data.collegeDate"
                    :key="item.id"
                    :label="item.name"
                    :value="item.id">
         </el-option>
         <!-- v-model="data.form.collegeId" 绑定专业信息的学院id-->
         <!-- placeholder="请选择学院" 提示用户选择学院-->
         <!-- style="width: 100%" 设置下拉框的宽度为100%-->
         <!-- v-for="item in data.collegeDate" 遍历学院信息-->
         <!-- :key="item.id" 设置每个学院的key为id-->
         <!-- :label="item.name" 设置每个学院的label为name-->
         <!-- :value="item.id" 设置每个学院的value为id-->
       </el-select>
       </el-form-item>
     </el-form>
     <template #footer>
     <span class="dialog-footer">
       <el-button @click="data.formVisible = false">取 消</el-button>
       <el-button type="primary" @click="save">保 存</el-button>
     </span>
     </template>
   </el-dialog>

 </div>
</template>

<script setup>
import request from "@/utils/request";
import {reactive} from "vue";
import {ElMessageBox, ElMessage} from "element-plus";


const data = reactive({
 pageNum: 1,
 pageSize: 10,
 total: 0,
 formVisible: false,
 form: {},
 tableData: [],
 name: null,
 collegeDate: [],// 用于存储学院信息
 teacherDate: []// 用于存储教师信息
})

// 分页查询
const load = () => {
 request.get('/course/selectPage', {
   params: {
     pageNum: data.pageNum,
     pageSize: data.pageSize,
     name: data.name
  }
}).then(res => {
   data.tableData = res.data?.list
   data.total = res.data?.total
})
}

// 新增
const handleAdd = () => {
 data.form = {}
 data.formVisible = true
}

// 编辑
const handleEdit = (row) => {
 data.form = JSON.parse(JSON.stringify(row))
 data.formVisible = true
}

// 新增保存
const add = () => {
 request.post('/course/add', data.form).then(res => {
   if (res.code === '200') {
     load()
     ElMessage.success('操作成功')
     data.formVisible = false
  } else {
     ElMessage.error(res.msg)
  }
})
}

// 编辑保存
const update = () => {
 request.put('/course/update', data.form).then(res => {
   if (res.code === '200') {
     load()
     ElMessage.success('操作成功')
     data.formVisible = false
  } else {
     ElMessage.error(res.msg)
  }
})
}

// 弹窗保存
const save = () => {
 // data.form有id就是更新,没有就是新增
 data.form.id ? update() : add()
}

// 删除
const handleDelete = (id) => {
 ElMessageBox.confirm('删除后数据无法恢复,您确定删除吗?', '删除确认', { type: 'warning' }).then(res => {
   request.delete('/course/deleteById/' + id).then(res => {
     if (res.code === '200') {
       load()
       ElMessage.success('操作成功')
    } else {
       ElMessage.error(res.msg)
    }
  })
}).catch(err => {})
}

// 重置
const reset = () => {
 data.name = null
 load()
}

const loadTeacher = () => {//查询所有教师信息
 request.get('/teacher/selectAll').then(res => {//调用后端接口查询所有教师信息
   if (res.code === '200') {//如果查询成功,将查询到的教师信息赋值给data.teacherDate
     data.teacherDate = res.data
  }else {//如果查询失败,提示用户
     ElMessage.error(res.msg)
  }
})
}

const loadCollege= () => {//查询所有学院信息
 request.get('/college/selectAll').then(res => {//调用后端接口查询所有学院信息
   if (res.code === '200') {//如果查询成功,将查询到的学院信息赋值给data.collegeDate
     data.collegeDate = res.data
  }else {//如果查询失败,提示用户
     ElMessage.error(res.msg)
  }
})
}

load()
loadCollege()
loadTeacher()
</script>

entity—Course.java

public class Course {
   private Integer id;
   private String name;
   private String content;
   private Integer score;
   private Integer teacherId;
   private String teacherName;
   private Integer num;
   private String time;
   private String location;
   private Integer collegeId;
   private String collegeName;
   private Integer alreadyNum;

   public Integer getId() {
       return id;
  }

   public void setId(Integer id) {
       this.id = id;
  }

   public String getName() {
       return name;
  }

   public void setName(String name) {
       this.name = name;
  }

   public String getContent() {
       return content;
  }

   public void setContent(String content) {
       this.content = content;
  }

   public Integer getScore() {
       return score;
  }

   public void setScore(Integer score) {
       this.score = score;
  }

   public Integer getTeacherId() {
       return teacherId;
  }

   public void setTeacherId(Integer teacherId) {
       this.teacherId = teacherId;
  }

   public String getTeacherName() {
       return teacherName;
  }

   public void setTeacherName(String teacherName) {
       this.teacherName = teacherName;
  }

   public Integer getNum() {
       return num;
  }

   public void setNum(Integer num) {
       this.num = num;
  }

   public String getTime() {
       return time;
  }

   public void setTime(String time) {
       this.time = time;
  }

   public String getLocation() {
       return location;
  }

   public void setLocation(String location) {
       this.location = location;
  }

   public Integer getCollegeId() {
       return collegeId;
  }

   public void setCollegeId(Integer collegeId) {
       this.collegeId = collegeId;
  }

   public String getCollegeName() {
       return collegeName;
  }

   public void setCollegeName(String collegeName) {
       this.collegeName = collegeName;
  }

   public Integer getAlreadyNum() {
       return alreadyNum;
  }

   public void setAlreadyNum(Integer alreadyNum) {
       this.alreadyNum = alreadyNum;
  }
}

Controller—CourseController.java

/**
* 课程信息模块前端操作接口入口
* 拿到数据后,调用service层的方法,返回结果
* 前端调用接口时,需要传入参数,调用service层的方法,返回结果
**/
@RestController

@RequestMapping("/course")
public class CourseController {
   @Resource
//   注入CourseService
   private CourseService courseService;

   /**
    * 新增课程信息
    * */
   @PostMapping("/add")
   public Result add(@RequestBody Course course){
       courseService.add(course);
       return Result.success();
  }

   /**
    * 更新课程信息
    */
   @PutMapping("/update")//更新课程信息信息,前端调用接口时,需要传入参数,调用service层的方法,返回结果
   public Result update(@RequestBody Course course){//接收前端传来的参数
       courseService.updateById(course);//调用service层的方法,返回结果
       return Result.success();
  }

   /**
    * 删除课程信息
    */
   @DeleteMapping("/deleteById/{id}")
   public Result deleteById(@PathVariable Integer id) {
       courseService.deleteById(id);
       return Result.success();
  }

   /**
    * 分页查询
    * */
   @GetMapping("selectPage")
   public Result selectPage(Course course,
                            @RequestParam(defaultValue = "1") Integer pageNum,
                            @RequestParam(defaultValue = "5") Integer pageSize){
//       调用service层的方法,返回结果
       PageInfo<Course> pageInfo = courseService.selectPage(course,pageNum,pageSize);
//       总数
       return Result.success(pageInfo);
  }
   /**
    * 查询所有课程信息
    */
   @GetMapping("/selectAll")
   public Result selectAll(){
       List<Course> list = courseService.selectAll();
       return Result.success(list);
  }
}

Service—CourseService.java

/**
 * 课程模块业务逻辑接口
 * 要把数据往数据库里存,调用mapper层的方法,返回结果
 * 业务逻辑接口调用mapper层的方法,返回结果
 */
@Service
public class CourseService {
    //    注入CourseMapper
    @Resource
    private CourseMapper courseMapper;
    /**
     * 新增课程
     */
    public void add(Course course) {
        course.setAlreadyNum(0);//设置已选人数为0
        courseMapper.insert(course);//调用mapper层的方法,返回结果
    }
    /**
     * 分页查询
     */
    public PageInfo<Course> selectPage(Course course,Integer pageNum, Integer pageSize) {
        // ToDo 分页查询逻辑处理
        // 1. 分页查询课程信息
        // 2. 返回课程信息
        // 3. 如果没有课程信息,返回空列表
        // 4. 如果有课程信息,返回课程信息列表
        List<Course> list;//定义一个list集合
        PageHelper.startPage(pageNum,pageSize);//分页查询
        if(ObjectUtil.isNotEmpty(course.getName())){//如果name不为空,就查询name对应的课程信息
            list = courseMapper.selectByName(course.getName());
        }else{//如果name为空,就查询所有课程信息
           list = courseMapper.selectAll();
        }
        return PageInfo.of(list);//返回课程信息列表
    }
​
    //根据id查询课程信息,返回一个course对象
    public void updateById(Course course) {//传入一个course对象
        courseMapper.updateById(course);//调用mapper层的方法,返回结果
    }
​
​
    //根据id删除课程信息
    public void deleteById(Integer id) {
        courseMapper.deleteById(id);
    }
    //查询所有课程信息
    public List<Course> selectAll() {
        return courseMapper.selectAll();
    }
}

Mapper

CourseMapper.java

@Mapper
public interface CourseMapper {
   //新增
   void insert(Course course);

   //查询所有
   @Select("select course.*, college.name as collegeName,teacher.name as teacherName from course " +
           "left join college on course.college_id = college.id " +
           "left join teacher on course.teacher_id = teacher.id")
   //查询所有专业信息,并且把专业信息对应的学院名称也查询出来,并且把专业信息对应的教师名称也查询出来
   List<Course> selectAll();

   //根据name查询
   @Select("select course.*, college.name as collegeName, teacher.name as teacherName from course " +
           "left join college on course.college_id = college.id " +
           "left join teacher on course.teacher_id = teacher.id " +
           "where course.name like concat('%',#{name},'%')")
   //查询所有专业信息,并且把专业信息对应的学院名称也查询出来,并且把专业信息对应的教师名称也查询出来,并且模糊查询
   List<Course> selectByName(String name);

   //修改
   void updateById(Course course);

   //删除
   @Delete("delete from course where id = #{id}")
   void deleteById(Integer id);
}

CourseMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
       PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
       "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.mapper.CourseMapper">
   <insert id="insert" parameterType="com.example.entity.Course" useGeneratedKeys="true">
      insert into course (name, content, score, teacher_id, num, time, location, college_id, already_num)
      values (#{name}, #{content}, #{score}, #{teacherId}, #{num}, #{time}, #{location}, #{collegeId}, #{alreadyNum})
   </insert>

   <update id="updateById" parameterType="com.example.entity.Course">
      update course
      set name = #{name},
          content = #{content},
          score = #{score},
          teacher_id = #{teacherId},
          num = #{num},
          time = #{time},
          location = #{location},
          college_id = #{collegeId},
          already_num = #{alreadyNum}
      where id = #{id}
--             这里的id是实体类中的属性名,不是数据库中的字段名
   </update>
</mapper>

id="insert":对应Mapper接口中的方法名

parameterType:指定参数类型为Course实体类

useGeneratedKeys="true":启用自增主键

SQL语句将实体类属性映射到数据库字段:

#{name}对应实体类的name属性

teacher_id字段对应实体类的teacherId属性(MyBatis自动转换驼峰命名)

涉及的主要知识点可以总结如下:

MyBatis持久层框架:

XML映射文件配置(如CourseMapper.xml

SQL语句编写(INSERT/UPDATE语句)

参数绑定(#{fieldName}语法)

结果集映射(自动映射到实体类)

Spring Boot核心:

RESTful API设计(@RestController

请求映射(@RequestMapping, @PostMapping等)

依赖注入(@Resource, @Autowired

分层架构(Controller-Service-Mapper

数据库操作:

CRUD操作(增删改查) 事

务管理(默认自动提交)

主键自增(useGeneratedKeys="true"

实体类设计:

与数据库表字段映射

关联关系(如teacher_id关联教师表)

驼峰命名与下划线命名转换(如teacherId -> teacher_id

业务逻辑:

新增课程时初始化已选人数(setAlreadyNum(0)

分页查询实现(PageHelper

条件查询(按课程名称模糊查询)

前后端交互:

JSON数据格式(@RequestBody

统一响应格式(Result对象)

参数传递(路径参数@PathVariable,查询参数@RequestParam

关联查询:

多表联查(left join教师和学院表) 结果集扩展(返回教师姓名而非ID)

角色权限控制

逻辑

角色划分:

系统有三种角色:管理员(ADMIN)、教师(TEACHER)和学生(STUDENT) 每个用户登录后,系统会根据其角色显示不同的菜单和操作权限

前端控制:

通过v-if="data.user.role === 'ADMIN'"这类判断语句控制按钮/菜单的显示 例如:只有管理员能看到”新增课程”按钮,教师只能看到自己教授的课程

后端验证:

后端接口会根据用户角色返回不同数据 例如教师查询课程时,会自动过滤只返回该教师自己的课程 权限示例:

管理员:可以管理所有用户、课程、学院等信息

教师:只能管理自己教授的课程,查看自己的课表

学生:只能选课、查看自己的课程和成绩

数据存储:

用户登录后,角色信息会保存在localStorage中(system-user) 每次请求都会携带这个角色信息,后端会进行验证

简单来说就是:不同身份的人进系统后,看到的东西和能做的事情不一样。

管理员什么都能管,老师只能管自己的课,学生只能选课看课。

系统会根据你是谁,自动显示你能用的功能。

user.role,那么如果这个user是个undefined(未被定义)的时候,再去访问这个user里面的某个属性变量的时候,就会报这种错误。

课程信息,多角色权限

Course.vue

<div class="card" style="margin-bottom: 5px">
 <div style="margin-bottom: 10px" v-if ="data.user.role === 'ADMIN'">
   <el-button type="primary" @click="handleAdd">新增</el-button>
 </div>
 <el-table :data="data.tableData" stripe>
   <el-table-column label="课程名称" prop="name"></el-table-column>
   <el-table-column label="课程介绍" prop="content" show-overflow-tooltip></el-table-column>
   <el-table-column label="课程学分" prop="score"></el-table-column>
   <el-table-column label="授课教师" prop="teacherName"></el-table-column>
   <el-table-column label="开班人数" prop="num"></el-table-column>
   <el-table-column label="上课时间" prop="time"></el-table-column>
   <el-table-column label="上课地点" prop="location"></el-table-column>
   <el-table-column label="所属学院" prop="collegeName"></el-table-column>
   <el-table-column label="已选人数" prop="alreadyNum"></el-table-column>
   <el-table-column label="操作" align="center" width="160" v-if ="data.user.role !== 'TEACHER'">
     <template #default="scope" v-if ="data.user.role === 'ADMIN'">
       <el-button type="primary" @click="handleEdit(scope.row)">编辑</el-button>
       <el-button type="danger" @click="handleDelete(scope.row.id)">删除</el-button>
     </template>
     <template #default="scope" v-else>
       <el-button type="primary" @click="">选课</el-button>

     </template>
   </el-table-column>
 </el-table>
</div>
const data = reactive({
 user: JSON.parse(localStorage.getItem('system-user') || '{}'),// 获取当前登录的用户信息
 pageNum: 1,
 pageSize: 10,
 total: 0,
 formVisible: false,
 form: {},
 tableData: [],
 name: null,
 collegeDate: [],// 用于存储学院信息
 teacherDate: []// 用于存储教师信息
})

// 分页查询
const load = () => {
 let teacherId = null// 用于存储教师id
 if (data.user.role === 'TEACHER') {
   teacherId = data.user.id// 如果是教师,就查询自己的课程信息
}
 request.get('/course/selectPage', {
   params: {
     pageNum: data.pageNum,
     pageSize: data.pageSize,
     name: data.name,
     teacherId: teacherId,// 如果是教师,就查询自己的课程信息
  }
}).then(res => {
   data.tableData = res.data?.list
   data.total = res.data?.total
})
}

CourseService.java

/**
 * 分页查询
 */
public PageInfo<Course> selectPage(Course course,Integer pageNum, Integer pageSize) {
    // ToDo 分页查询逻辑处理
    // 1. 分页查询课程信息
    // 2. 返回课程信息
    // 3. 如果没有课程信息,返回空列表
    // 4. 如果有课程信息,返回课程信息列表
    List<Course> list;//定义一个list集合
    PageHelper.startPage(pageNum,pageSize);//分页查询
    //表示当前登录是教师
    if(ObjectUtil.isNotEmpty(course.getTeacherId())){//如果teacherId不为空,就查询teacherId对应的课程信息
        Integer teacherId = course.getTeacherId();
        //如果name不为空,就查询name对应的课程信息,否则就查询所有课程信息
        if (ObjectUtil.isNotEmpty(course.getName())) {//如果name不为空,就查询name对应的课程信息
            list = courseMapper.selectByNameAndTeacherId(course.getName(),teacherId);
        } else {//如果name为空,就查询所有课程信息
            list = courseMapper.selectAllByTeacherId(teacherId);
        }
    }
    else {
        //如果name不为空,就查询name对应的课程信息,否则就查询所有课程信息
        if (ObjectUtil.isNotEmpty(course.getName())) {//如果name不为空,就查询name对应的课程信息
            list = courseMapper.selectByName(course.getName());
        } else {//如果name为空,就查询所有课程信息
            list = courseMapper.selectAll();
        }
    }
    return PageInfo.of(list);//返回课程信息列表
}

CourseMapper.java

//根据name查询,并且根据teacherId查询    模糊查询
@Select("select course.*, college.name as collegeName, teacher.name as teacherName from course " +
       "left join college on course.college_id = college.id " +
       "left join teacher on course.teacher_id = teacher.id " +
       "where course.name like concat('%',#{name},'%') and teacher_id = #{teacherId}")
List<Course> selectByNameAndTeacherId(@Param("name") String name, @Param("teacherId") Integer teacherId);

//根据teacherId查询,并且把专业信息对应的学院名称也查询出来,把专业信息对应的教师名称也查询出来
@Select("select course.*, college.name as collegeName,teacher.name as teacherName from course " +
       "left join college on course.college_id = college.id " +
       "left join teacher on course.teacher_id = teacher.id " +
       "where teacher_id = #{teacherId}")
List<Course> selectAllByTeacherId(Integer teacherId);

同一个功能模块里面(同一个页面里面),不同的角色有不同的权限(权限的控制),达到不同的角色有不同的功能的效果。

版权声明

本网站名称:学海拾茜
本文链接:https://www.61lyf.top/15%e8%af%be%e7%a8%8b%e4%bf%a1%e6%81%af%e5%8a%9f%e8%83%bd%e7%9a%84%e5%bc%80%e5%8f%91/
本网站的文章部分内容可能来源于网络,仅供学习与参考,如有侵权,请联系站长进行核实删除。
转载本站文章需要遵守:商业转载请联系站长,非商业转载请注明出处并附带原文链接!!!
站长邮箱:cyg1900@outlook.com 或studygod825@qq.com ,如不方便留言可邮件联系。
暂无评论

发送评论 编辑评论


				
上一篇
下一篇