用Swift3和SQLite3实现课程表

xiaoxiao2021-02-28  68

功能描述:从数据库读取所有课程信息并显示在表格里,点击显示课程的格子会跳转页面显示该课程的详细信息,点击清空课表会清空表格里所有课程信息并清空数据库,点击加载课程会模拟一节课添加进数据库,然后会读取出来显示出来。清空课表和加载课程可以日后用于更新课表这个功能。

上代码吧。


目录结构如图所示 - Controller两个:ViewController是主控制器,DetailsViewController是课程详细信息控制器 - view有两个:都是UICollectionViewCell,DateCell是用来显示星期和节数的,CourseCell是用来盛放课程格子的,两个都是有xib伴随的 - Model层有一个Course,就是课程对象啦 - 最后还有个工具类dbOperations,是用原生的SQLite3写的,用于数据持久化,要有桥接文件bridging-header.h


Course.swift:

import UIKit // 课程model class Course: NSObject, NSCoding { // MARK: - 课程名称 var courseName: String! // MARK: - 任课教师 var teacher: String! // MARK: - 上课教室 var classroom: String! // MARK: - 起始周 var start: Int! // MARK: - 结束周 var end: Int! // MARK: - 上课日期 var day: Int! // MARK: - 课程总周数 var weeks: Int! override init() { } // MARK: - 编码 func encode(with aCoder: NSCoder) { aCoder.encode(self.courseName, forKey: "courseName") aCoder.encode(self.teacher, forKey: "teacher") aCoder.encode(self.classroom, forKey: "classroom") aCoder.encode(self.start, forKey: "start") aCoder.encode(self.end, forKey: "end") aCoder.encode(self.day, forKey: "day") aCoder.encode(self.weeks, forKey: "weeks") } // MARK: - 初始化时解码 required init?(coder aDecoder: NSCoder) { super.init() self.courseName = aDecoder.decodeObject(forKey: "courseName") as! String self.teacher = aDecoder.decodeObject(forKey: "teacher") as! String self.classroom = aDecoder.decodeObject(forKey: "classroom") as! String self.start = aDecoder.decodeObject(forKey: "start") as! Int self.end = aDecoder.decodeObject(forKey: "end") as! Int self.day = aDecoder.decodeObject(forKey: "day") as! Int self.weeks = aDecoder.decodeObject(forKey: "weeks") as! Int } }

DateCell: DateCell.swift

import UIKit // 左边和上边的日期cell class DateCell: UICollectionViewCell { // MARK: - 右边框 @IBOutlet weak var rightBorder: UIView! // MARK: - 下边框 @IBOutlet weak var buttonBorder: UIView! // MARK: - 日期label @IBOutlet weak var dateLabel: UILabel! override func awakeFromNib() { super.awakeFromNib() // Initialization code } }

DateCell.xib: CourseCell.swift:

import UIKit // 课程cell class CourseCell: UICollectionViewCell { // MARK: - 课程label @IBOutlet weak var courseLabel: UILabel! override func awakeFromNib() { super.awakeFromNib() // Initialization code } }

Course.xib:


Course.swift:

import UIKit // 课程model class Course: NSObject, NSCoding { // MARK: - 课程名称 var courseName: String! // MARK: - 任课教师 var teacher: String! // MARK: - 上课教室 var classroom: String! // MARK: - 起始周 var start: Int! // MARK: - 结束周 var end: Int! // MARK: - 上课日期 var day: Int! // MARK: - 课程总周数 var weeks: Int! override init() { } // MARK: - 编码 func encode(with aCoder: NSCoder) { aCoder.encode(self.courseName, forKey: "courseName") aCoder.encode(self.teacher, forKey: "teacher") aCoder.encode(self.classroom, forKey: "classroom") aCoder.encode(self.start, forKey: "start") aCoder.encode(self.end, forKey: "end") aCoder.encode(self.day, forKey: "day") aCoder.encode(self.weeks, forKey: "weeks") } // MARK: - 初始化时解码 required init?(coder aDecoder: NSCoder) { super.init() self.courseName = aDecoder.decodeObject(forKey: "courseName") as! String self.teacher = aDecoder.decodeObject(forKey: "teacher") as! String self.classroom = aDecoder.decodeObject(forKey: "classroom") as! String self.start = aDecoder.decodeObject(forKey: "start") as! Int self.end = aDecoder.decodeObject(forKey: "end") as! Int self.day = aDecoder.decodeObject(forKey: "day") as! Int self.weeks = aDecoder.decodeObject(forKey: "weeks") as! Int } }

bridging-header.h:

#ifndef bridging_header_h #define bridging_header_h #import "SQLite3.h" #endif /* bridging_header_h */

要记得在Build Settings里设置桥接文件! dbOperations.swift:

import Foundation // 数据库操作 class dbOperations: NSObject { // 不透明指针,对应C语言里面的void *,这里指sqlite3指针 private var db: OpaquePointer? = nil // 初始化方法打开数据库 required init(dbPath: String) { print("dbPath:\(dbPath)") // String类的路径,转换成cString let cpath = dbPath.cString(using: String.Encoding.utf8) // 打开数据库 let error = sqlite3_open(cpath!, &db) // 数据库打开失败处理 if error != SQLITE_OK { print("失败打开数据库") sqlite3_close(db) }else { print("成功打开数据库") } } deinit { self.colseDB() } // MARK: - 将Bundle.main路径下的数据库文件复制到Documents下 class func loadDBPath() -> String { // 声明一个Documents下的路径 let dbPath = NSHomeDirectory() + "/Documents/Timetable.sqlite" // 判断数据库文件是否存在 if !FileManager.default.fileExists(atPath: dbPath) { // 获取安装包内数据库路径 let bundleDBPath = Bundle.main.path(forResource: "Timetable", ofType: "sqlite")! // 将安装包内数据库拷贝到Documents目录下 do { try FileManager.default.copyItem(atPath: bundleDBPath, toPath: dbPath) } catch let error as NSError{ print(error) } } return dbPath } // 关闭数据库 func colseDB() { sqlite3_close(db) } // MARK: - 判断表是否存在 func checkTable() -> Bool { // sql语句 let sql = "SELECT COUNT(*) FROM sqlite_master where type='table' and name='CourseTable';" // 执行sql语句 let executeResult = sqlite3_exec(db, sql.cString(using: String.Encoding.utf8), nil, nil, nil) // 判断是否执行成功 if executeResult != SQLITE_OK { print("判断失败") } if executeResult == 1 { return true }else { return false } } // 代码创建表 func createTable() -> Bool { print("建表ing") // sql语句 let sql = "CREATE TABLE CourseTable(id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, courseName TEXT NOT NULL, teacher TEXT NOT NULL, classroom TEXT NOT NULL, start INTEGER NOT NULL, end INTEGER NOT NULL, day INTEGER NOT NULL)" // 执行sql语句 let executeResult = sqlite3_exec(db, sql.cString(using: String.Encoding.utf8), nil, nil, nil) // 判断是否执行成功 if executeResult != SQLITE_OK { print("建表失败\(executeResult)") return false } print("建表成功") return true } // 插入一条信息 func addCourse(course: Course) -> Bool { print("插入信息ing") // sql语句 let sql = "INSERT INTO CourseTable (courseName, teacher, classroom, start, end, day) VALUES (?,?,?,?,?,?);" // sql语句转换成cString类型 let csql = sql.cString(using: String.Encoding.utf8) // sqlite3_stmt 指针 var stmt: OpaquePointer? = nil // 编译sql let prepareResult = sqlite3_prepare_v2(db, csql, -1, &stmt, nil) // 判断如果失败,获取失败信息 if prepareResult != SQLITE_OK { sqlite3_finalize(stmt) if let error = sqlite3_errmsg(db) { let msg = "SQLiteDB - failed to prepare SQL: \(sql), Error: \(error)" print(msg) } return false } // 准备参数 let cCourseName = course.courseName!.cString(using: String.Encoding.utf8) let cTeacher = course.teacher!.cString(using: String.Encoding.utf8) let cClassroom = course.classroom!.cString(using: String.Encoding.utf8) let cStart = Int32(Int(course.start!)) let cEnd = Int32(Int(course.end!)) let cDay = Int32(Int(course.day!)) // 绑定參数 sqlite3_bind_text(stmt, 1, cCourseName, -1, nil) sqlite3_bind_text(stmt, 2, cTeacher, -1, nil) sqlite3_bind_text(stmt, 3, cClassroom, -1, nil) sqlite3_bind_int(stmt, 4, cStart) sqlite3_bind_int(stmt, 5, cEnd) sqlite3_bind_int(stmt, 6, cDay) // 执行插入 if sqlite3_step(stmt) != SQLITE_DONE { sqlite3_finalize(stmt) print("插入数据失败。") return false } // 释放语句对象 sqlite3_finalize(stmt) // 关闭数据库 sqlite3_close(db) print("插入数据成功") return true } // 查询所有课程 func getAllCourse() -> [Course] { // 声明一个Course对象数组(查询的信息会添加到该数组) var courseArray = [Course]() // sql let sql = "SELECT * FROM CourseTable;" // sqlite3_stmt 指针 var stmt: OpaquePointer? = nil // sql语句转换成cString类型 let csql = sql.cString(using: String.Encoding.utf8) // 编译sql let prepareResult = sqlite3_prepare_v2(db, csql!, -1, &stmt, nil) if prepareResult != SQLITE_OK { sqlite3_finalize(stmt) if let error = sqlite3_errmsg(db) { let msg = "SQLiteDB - failed to prepare SQL: \(sql), Error: \(error)" print(msg) } return courseArray } // 查询 while sqlite3_step(stmt) == SQLITE_ROW { let course = Course() // 循环从数据库获取数据并添加到数组中 let cCourseName = UnsafePointer(sqlite3_column_text(stmt, 1)) let cTeacher = UnsafePointer(sqlite3_column_text(stmt, 2)) let cClassroom = UnsafePointer(sqlite3_column_text(stmt, 3)) let cStart = sqlite3_column_int(stmt, 4) let cEnd = sqlite3_column_int(stmt, 5) let cDay = sqlite3_column_int(stmt, 6) course.courseName = String.init(cString: cCourseName!) course.teacher = String.init(cString: cTeacher!) course.classroom = String.init(cString: cClassroom!) course.start = Int(cStart) course.end = Int(cEnd) course.day = Int(cDay) courseArray.append(course) } sqlite3_finalize(stmt) return courseArray } // MARK: - 清空课表 func cleanTable() -> Bool { print("清空课表ing") // sql let sql = "DELETE FROM CourseTable;" // sqlite3_stmt 指针 var stmt: OpaquePointer? = nil // sql语句转换成cString类型 let csql = sql.cString(using: String.Encoding.utf8) // 编译sql let prepareResult = sqlite3_prepare_v2(db, csql!, -1, &stmt, nil) if prepareResult != SQLITE_OK { sqlite3_finalize(stmt) if let error = sqlite3_errmsg(db) { let msg = "SQLiteDB - failed to prepare SQL: \(sql), Error: \(error)" print(msg) } print("清空失败") return false } // step执行 let stepResult = sqlite3_step(stmt) // 判断执行结果,如果失败,获取失败信息 if stepResult != SQLITE_OK && stepResult != SQLITE_DONE { sqlite3_finalize(stmt) if sqlite3_errmsg(stmt) != nil { let msg = "SQLiteDB - failed to execute SQL:\(sql)" print(msg) } return false } // sqlite3_finalize(stmt) print("清空成功") return true } }

storyboard: ViewController.swift:

import UIKit class ViewController: UIViewController { // MARK: - 时间collectionview(表头) @IBOutlet weak var dateCollectionView: UICollectionView! // MARK: - 课程collectionview(课程内容) @IBOutlet weak var courseCollectionView: UICollectionView! // MARK: - 表头tag let DATE_COLLECTION_VIEW_TAG = 0 // MARK: - 课程内容 let COURSE_COLLECTION_VIEW_TAG = 1 // MARK: - 表头 var weekItems = ["周一", "周二", "周三", "周四", "周五","周六","周日"] // MARK: - 图片view var imageView: UIImageView! // MARK: - 课程单元格大小 var courseCellSize: CGSize! // MARK: - 课程单元格背景色 var courseColor: UIColor! // MARK: - 课程数组 var courseArray = [Course]() // MARK: - 课程label数组 var courseLabelArray = [UILabel]() // MARK: - 背景图 var bgImageView: UIImageView! // MARK: - 清空课表按钮 var cleanButtonItem: UIBarButtonItem! // MARK: - 清空课表按钮tag let CLEAN_BUTTON_ITEM = 2 // MARK: - 加载课程按钮 var loadButtonItem: UIBarButtonItem! // MARK: - 加载课程按钮tag let LOAD_BUTTON_ITEM = 3 // MARK: - 主storyboard var storyBoard = UIStoryboard(name: "Main", bundle: nil) override func viewDidLoad() { super.viewDidLoad() // 背景图设置 bgImageView = UIImageView(frame: self.view.frame) bgImageView.image = UIImage.init(named: "bg") self.view.insertSubview(bgImageView, belowSubview: dateCollectionView) // 设置课程单元格背景色 courseColor = UIColor(red: 74/255, green: 187/255, blue: 230/255, alpha: 1) // 注册cell dateCollectionView.register(UINib(nibName: "DateCell", bundle: nil), forCellWithReuseIdentifier: "DateCell") courseCollectionView.register(UINib(nibName: "DateCell", bundle: nil), forCellWithReuseIdentifier: "DateCell") courseCollectionView.register(UINib(nibName: "CourseCell", bundle: nil), forCellWithReuseIdentifier: "CourseCell") // 设置tag dateCollectionView.tag = DATE_COLLECTION_VIEW_TAG courseCollectionView.tag = COURSE_COLLECTION_VIEW_TAG // 设置代理 dateCollectionView.delegate = self dateCollectionView.dataSource = self courseCollectionView.delegate = self courseCollectionView.dataSource = self // 设置课程表透明度 dateCollectionView.alpha = 0.5 courseCollectionView.alpha = 0.5 // 禁止滚动 self.automaticallyAdjustsScrollViewInsets = false // 清空按钮 cleanButtonItem = UIBarButtonItem(title: "清空课表", style: UIBarButtonItemStyle.plain, target: self, action: #selector(clearTable)) // 加载按钮 loadButtonItem = UIBarButtonItem(title: "加载课程", style: UIBarButtonItemStyle.plain, target: self, action: #selector(load)) // 将按钮添加到导航栏 self.navigationItem.leftBarButtonItem = loadButtonItem self.navigationItem.rightBarButtonItem = cleanButtonItem // 刷新数据 courseCollectionView.reloadData() // 加载课程 loadCourse() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 将课程label添加进view for courseItem in self.courseArray { drawCourse(courseItem) } } override func viewDidLayoutSubviews() { } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // MARK: - 绘画课程单元格 func drawCourse(_ course: Course) { // 计算要画的地方 let rowNum = course.end - course.start + 1 let width = courseCellSize.width let height = courseCellSize.height * CGFloat(rowNum) let x = CGFloat(30) + CGFloat(course.day - 1) * courseCellSize.width let y = CGFloat(30 + 64) + CGFloat(course.start - 1) * courseCellSize.height let courseView = UIView(frame: CGRect(x: x, y: y, width: width, height: height)) courseView.alpha = 0.8 // 显示课程信息的label let courseInfoLabel = UILabel(frame: CGRect(x: 0, y: 2, width: courseView.frame.size.width - 2, height: courseView.frame.size.height)) courseInfoLabel.numberOfLines = 5 courseInfoLabel.font = UIFont.systemFont(ofSize: 12) courseInfoLabel.textAlignment = .left courseInfoLabel.textColor = UIColor.white courseInfoLabel.text = "\(course.courseName!)@\(course.classroom!)" courseInfoLabel.tag = self.courseArray.index(of: course)! courseInfoLabel.layer.cornerRadius = 5 courseInfoLabel.layer.masksToBounds = true courseInfoLabel.backgroundColor = courseColor courseView.addSubview(courseInfoLabel) self.courseLabelArray.append(courseInfoLabel) // 点击显示课程详细信息手势 let tap = UITapGestureRecognizer(target: self, action: #selector(showCourseDetail(_:))) courseInfoLabel.addGestureRecognizer(tap) courseInfoLabel.isUserInteractionEnabled = true // 将要画的地方画上去 self.view.insertSubview(courseView, aboveSubview: courseCollectionView) } // MARK: - 显示课程详细信息 func showCourseDetail(_ recognizer: UIGestureRecognizer) { // 获取手势所在的label let label = recognizer.view as! UILabel let vc = storyBoard.instantiateViewController(withIdentifier: "details") as! DetailsViewController // 根据label的tag获取label上的Course对象 vc.course = courseArray[label.tag] // 页面跳转 self.navigationController?.pushViewController(vc, animated: true) } // MARK: - 删除课程信息 func deleteCourse(_ course: Course, tag: Int) { // 获取课程所在view let courseView = self.courseLabelArray[tag].superview // 去除这个view courseView?.removeFromSuperview() self.courseArray.remove(at: tag) self.courseLabelArray.remove(at: tag) } // MARK: - 清空课表 func clearTable() { // 获取数据库路径 let path = dbOperations.loadDBPath() // 打开数据库 let DBOperations = dbOperations(dbPath: path) // 判断是否存在Timetable表 if DBOperations.checkTable() { // 如果不存在则返回 print("不存在表") return } // 清空表 _ = DBOperations.cleanTable() // 清除label for courseLabel in courseLabelArray { let courseView = courseLabel.superview courseView?.removeFromSuperview() } // 清空课程数组 courseArray = [] courseLabelArray = [] // 刷新表格 view.reloadInputViews() } // MARK: - 加载一节课 func load() { // 模拟一节课 let course = Course() course.courseName = "高等数学" course.teacher = "高数学" course.classroom = "数学楼A206" course.day = 1 course.start = 7 course.end = 8 course.weeks = 17 self.addCourse(course) // 重新加载课程 loadCourse() for courseItem in self.courseArray { drawCourse(courseItem) } // 刷新表格 view.reloadInputViews() } // MARK: - 添加课程信息 func addCourse(_ course: Course) { // 将课程追加到数组 courseArray.append(course) // 获取数据库路径 let path = dbOperations.loadDBPath() // 打开数据库 let DBOperations = dbOperations(dbPath: path) // 判断是否存在Timetable表 if DBOperations.checkTable() { // 如果不存在则新建表 _ = DBOperations.createTable() } // 插入课程 _ = DBOperations.addCourse(course: course) } // MARK: - 加载课程信息 func loadCourse() { // 获取数据库路径 let path = dbOperations.loadDBPath() // 打开数据库 let DBOperations = dbOperations(dbPath: path) // 判断是否存在Timetable表 if DBOperations.checkTable() { // 如果不存在则新建表 _ = DBOperations.createTable() } courseArray = DBOperations.getAllCourse() } } extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate { func numberOfSections(in collectionView: UICollectionView) -> Int { switch collectionView.tag { case DATE_COLLECTION_VIEW_TAG: return 1 case COURSE_COLLECTION_VIEW_TAG: return 1 default: return 0 } } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { switch collectionView.tag { case DATE_COLLECTION_VIEW_TAG: return weekItems.count + 1 case COURSE_COLLECTION_VIEW_TAG: return (weekItems.count + 1) * 12 default: return 0 } } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { switch collectionView.tag { case DATE_COLLECTION_VIEW_TAG: let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DateCell", for: indexPath) as! DateCell if indexPath.row == 0 { cell.dateLabel.text = "" }else { cell.dateLabel.text = weekItems[indexPath.row - 1] } return cell case COURSE_COLLECTION_VIEW_TAG: if indexPath.row % 8 == 0 { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "DateCell", for: indexPath) as! DateCell cell.dateLabel.text = "\(indexPath.row / (weekItems.count + 1) + 1)" return cell }else { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CourseCell", for: indexPath) as! CourseCell cell.courseLabel.text = "" return cell } default: return UICollectionViewCell() } } } extension ViewController: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { switch collectionView.tag { case DATE_COLLECTION_VIEW_TAG: if indexPath.row == 0 { return CGSize(width: 30, height: 30) }else { return CGSize(width: (SCREEN_WIDTH - 30) / 7, height: 30) } case COURSE_COLLECTION_VIEW_TAG: let rowHeight = CGFloat((SCREEN_HEIGHT - 64 - 30) / 12) if indexPath.row % 8 == 0 { return CGSize(width: 30, height: rowHeight) }else { courseCellSize = CGSize(width: (SCREEN_WIDTH - 30) / 7, height: rowHeight) return courseCellSize } default: return CGSize(width: 0, height: 0) } } }

DetailsViewController.swift:

import UIKit // 课程细节 class DetailsViewController: UIViewController { // MARK: - 课程 var course: Course! override func viewDidLoad() { super.viewDidLoad() // 初始化界面 initView() } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } // MARK: - 初始化界面 func initView() { // label的size let labelHeight = 30 let labelWidth = Int(SCREEN_WIDTH / 2) let courseTitleLabel = UILabel(frame: CGRect(x: 0, y: 60, width: labelWidth, height: labelHeight)) initTitleLabel(title: "课程", label: courseTitleLabel) let courseLabel = UILabel(frame: CGRect(x: labelWidth, y: 60, width: labelWidth, height: labelHeight)) initLabel(title: course!.courseName!, label: courseLabel) let classroomTitleLabel = UILabel(frame: CGRect(x: 0, y: 60 + labelHeight, width: labelWidth, height: labelHeight)) initTitleLabel(title: "教室", label: classroomTitleLabel) let classroomLabel = UILabel(frame: CGRect(x: labelWidth, y: 60 + labelHeight, width: labelWidth, height: labelHeight)) initLabel(title: course!.classroom!, label: classroomLabel) let teacherTitleLabel = UILabel(frame: CGRect(x: 0, y: 60 + 2 * labelHeight, width: labelWidth, height: labelHeight)) initTitleLabel(title: "老师", label: teacherTitleLabel) let teacherLabel = UILabel(frame: CGRect(x: labelWidth, y: 60 + 2 * labelHeight, width: labelWidth, height: labelHeight)) initLabel(title: course!.teacher!, label: teacherLabel) let countTitleLabel = UILabel(frame: CGRect(x: 0, y: 60 + 3 * labelHeight, width: labelWidth, height: labelHeight)) initTitleLabel(title: "节数", label: countTitleLabel) let countLabel = UILabel(frame: CGRect(x: labelWidth, y: 60 + 3 * labelHeight, width: labelWidth, height: labelHeight)) initLabel(title: "\(course!.start!)-\(course!.end!)", label: countLabel) let weekTitleLabel = UILabel(frame: CGRect(x: 0, y: 60 + 4 * labelHeight, width: labelWidth, height: labelHeight)) initTitleLabel(title: "星期", label: weekTitleLabel) let weekLabel = UILabel(frame: CGRect(x: labelWidth, y: 60 + 4 * labelHeight, width: labelWidth, height: labelHeight)) initLabel(title: "\(course!.day!)", label: weekLabel) self.view.addSubview(courseTitleLabel) self.view.addSubview(courseLabel) self.view.addSubview(classroomTitleLabel) self.view.addSubview(classroomLabel) self.view.addSubview(teacherTitleLabel) self.view.addSubview(teacherLabel) self.view.addSubview(countTitleLabel) self.view.addSubview(countLabel) self.view.addSubview(weekTitleLabel) self.view.addSubview(weekLabel) } // MARK: - 初始化标题label func initTitleLabel(title: String, label: UILabel) { label.text = title label.textAlignment = .left label.font = UIFont.systemFont(ofSize: 14) label.textColor = UIColor.darkText } // MARK: - 初始化label func initLabel(title: String, label: UILabel) { label.text = title label.textAlignment = .right label.font = UIFont.systemFont(ofSize: 14) label.textColor = UIColor.darkGray } }

项目源码在这里,欢迎点击

转载请注明原文地址: https://www.6miu.com/read-46240.html

最新回复(0)