PHP中用MVC模式来实现数据库的增删改查

PHP中用MVC模式来实现数据库的增删改查

在这里插入图片描述

视图View

代表用户交互的页面、可以包含HTML界面、Smarty模板等和界面相关的元素。MVC设计模式对于视图的处理仅限于视图上数据的采集和处理,以及用户的点击、拖动等事件的处理,而不包括在视图上的业务流程处理。业务流程会交给模型层(Model)处理

模型Model

模型层是对业务流程、状态的处理以及业务规则的指定。业务流程的处理过程对其他层来说是黑箱操作,模型接受视图的请求处理数据,返回最终的处理结果。业务模型还有一个很重要的模型–数据模型,数据模型主要指实体对象的数据保存(持久化)。比如将一张订单保存到数据库,从数据库获取订单,所有和数据库相关的操作限定在该模型中。

控制器Controller

控制层是View层和Model层之间的一个桥梁,接收到用户的请求,将模型和视图匹配在一起,共同完成用户的请求。比如,用户点击一个链接,控制层接收到请求后,把信息传递给模型层,模型层处理完成之后返回视图给用户。

题目要求:

用MVC模式实现以下功能

  • 首页导航栏中内置功能
    在这里插入图片描述

  • 查看数据库
    在这里插入图片描述

  • 点击Edit修改数据库内容
    在这里插入图片描述

  • 点击Delete后删除数据库内此记录,返回首页输出删除成功。

  • 向数据库里增加数据
    在这里插入图片描述

  • 向搜索框输入查询的关键字
    在这里插入图片描述之后输出查询结果:
    在这里插入图片描述

目录结构:
在这里插入图片描述
代码如下:

代码源文件链接
在这里插入图片描述
app/controller/BookingsController.php

<?php

include_once 'controller/Controller.php';
include_once 'model/BookingModel.php';
include_once 'Validation.php';

//用关键字extends 继承
class BookingsController extends Controller {

    var $booking = null;
    var $fields = [
        'firstname' => 'alpha_spaces|true',
        'lastname' => 'alpha_spaces|true',
        'email' => 'email|true',
        'mobile' => 'digits|true',
        'photo' => 'photo|true',
    ];

    //创建对象
    function __construct() {
        $this->booking = new BookingModel();
    }

    function index() {
        include_once 'view/content.php';
    }

    function addBooking() {
        if (isset($_POST['submit'])) {

            $_POST['photo'] = $_FILES['photo']['name'];
            $values = [$_POST['firstname'], $_POST['lastname'], $_POST['email'], $_POST['mobile'], $_FILES['photo']['name']];
            $validation = new Validation();
            $errors = $validation->validate_form_data($_POST, $this->fields);
            if (count($errors) == 0) {

                $success = $this->booking->insertRecord($values);

                $filename = $_FILES["photo"]["name"];
                $temp_file = $_FILES["photo"]["tmp_name"];
                $destination = "assets/img/photos/$filename";
                move_uploaded_file($temp_file, $destination);

                if ($success) {
                    include_once "index.php";
                } else {
                    echo "Insert ERROR!";
                }
            } else {

                include_once 'view/registration_form.php';
            }
        } else {
            include_once 'view/registration_form.php';
        }
    }

    function deleteBooking() {
        $id = $_GET['id'];

        $success = $this->booking->deleteRecord($id);
        if (!$success) {
            echo "Delete Failed!";
        } else {

            $records = $this->booking->readRecords();
            include_once("view/viewBookings.php");
        }

        return $success;
    }

    function editBooking() {
        $id = $_GET['id'];

        $records = $this->booking->readRecords();
        for ($i = 0; $i < count($records); $i++) {
            if ($records[$i]['id'] == $id) {
                $firstname_temp = $records[$i]['first_name'];
                $lastname_temp = $records[$i]['last_name'];
                $email_temp = $records[$i]['email'];
                $mobile_temp = $records[$i]['mobile'];
            }
        }

        if (isset($_POST['submit'])) {
            $_POST['photo'] = $_FILES['photo']['name'];
            $validation = new Validation();
            $errors = $validation->validate_form_data($_POST, $this->fields);
            if (count($errors) == 0) {

                $values = [$_POST['firstname'], $_POST['lastname'], $_POST['email'], $_POST['mobile'], $_FILES['photo']['name']];

                $filename = $_FILES["photo"]["name"];
                $temp_file = $_FILES["photo"]["tmp_name"];
                $destination = "assets/img/photos/$filename";
                move_uploaded_file($temp_file, $destination);

                $success = $this->booking->updateRecord($id, $values);

                if ($success) {
                    $firstname_temp = "";
                    $lastname_temp = "";
                    $email_temp = "";
                    $mobile_temp = "";
                    $photo_temp = "";

                    $records = $this->booking->readRecords();
                    include_once("view/viewBookings.php");
                } else {
                    echo "Update Failed!";
                }
            } else {
                include_once 'view/registration_form.php';
            }
        } else {
            include_once 'view/registration_form.php';
        }
    }

    function searchBookings() {


        if (isset($_POST['Search'])) {
            $keyword = $_POST['search'];

            $search_record = $this->booking->searchRecord($keyword);
            if (isset($search_record)) {
                $records = $search_record;
                include_once 'view/viewBookings.php';
            } else {
                echo "None";
            }
        } else {
            include_once 'view/search_form.php';
        }
    }

    function viewBookings() {
        $records = $this->booking->readRecords();
        include_once 'view/viewBookings.php';
    }

}

app/controller/Controller.php

<?php

//定义一个抽象类
abstract class Controller {

    abstract function index(); //抽象方法不用写函数体
}

?>

app/controller/HomeController.php

<?php

include_once 'controller/Controller.php';

class HomeController extends Controller {

    public function index() {
        include_once 'view/content.php';
    }

}

app/database/dbconfig.json

{"DSN":"mysql:host=localhost:3306;dbname=contactsdb","USERNAME":"root","PASSWORD":""}

app/factory/PDOFactory.php

<?php

class PDOFactory {

    const DB_CONFIG_FILE_PATH = __DIR__ . '/../database/dbconfig.json';

    //static是不需要实例化就能使用的
    static function getConnection() {

        $f = fopen(PDOFactory::DB_CONFIG_FILE_PATH, "r");
        $content = fread($f, filesize(PDOFactory::DB_CONFIG_FILE_PATH));
        $json_data = json_decode($content);

        $dsn = $json_data->DSN;
        $username = $json_data->USERNAME;
        $password = $json_data->PASSWORD;

        $conn = new PDO($dsn, $username, $password);
        return $conn;
    }

}

在这里插入图片描述
app/model/BookingModel.php

<?php

include_once 'DataModel.php';

class BookingModel extends DataModel {

    function __construct() {
        parent::__construct('contacts');
    }

    function readRecords() {
        $records = [];
        $sql = 'select * from contacts';
        $this->statement = $this->conn->query($sql);
        $this->statement->setFetchMode(PDO::FETCH_ASSOC);
        $records = $this->statement->fetchAll();

        return $records;
    }

    function deleteRecord($id) {
        $sql = "delete from contacts where id=$id";
        $this->statement = $this->conn->query($sql);

        $success = $this->statement->execute();
        return $success;
    }

    function insertRecord($values) {
        $sql = 'insert into contacts (
        first_name,
        last_name,
        email,
        mobile,
        photo_filename)
        values(?,?,?,?,?)';

        $this->statement = $this->conn->prepare($sql);
        $success = $this->statement->execute($values);
        return $success;
    }

    function updateRecord($id, $values) {
        $sql = "update contacts set first_name=?,
            last_name=?,
            email=?,
            mobile=?,
            photo_filename=?
            where id=$id";

        $this->statement = $this->conn->prepare($sql);
        $success = $this->statement->execute($values);
        return $success;
    }

    function searchRecord($keyword) {
        $sql = "select * from contacts where first_name like '%$keyword%' or last_name like '%$keyword%' or email like '%$keyword%' or mobile like '%$keyword%' or photo_filename like '%$keyword%'";

        $this->statement = $this->conn->query($sql);
        $this->statement->setFetchMode(PDO::FETCH_ASSOC);
        $booking_records = $this->statement->fetchAll();
        return $booking_records;
    }

}

app/model/Crudable.php

<?php

//接口使用关键字 interface 来定义,并使用关键字 implements 来实现接口中的方法,且必须完全实现。
//继承是父子关系,一个孩子只能有一个父亲。所以抽象类只能单继承,当一个子类需要实现的功能需要继承多个父类时,就必须使用接口
interface Crudable {

    //在里面定义的方法,却不去实例化,而需要别的类去implements它
    function readRecords();

    function updateRecord($id, $values);

    function deleteRecord($id);

    function insertRecord($values);

    function searchRecord($keyword);
}

app/model/DataModel.php

<?php

include_once 'Crudable.php';
include_once 'factory/PDOFactory.php';

abstract class DataModel implements Crudable {

    var $conn = null;

    function __construct() {
        $this->conn = PDOFactory::getConnection();
    }

    function close() {
        $this->conn = null;
    }

}

app/view/content.php

<div class="slogan">
    <h2><span class="text_color">CONTACTS DATABASE</span> </h2>
    <h4>I AM A STUDENT IN THE WEB APPLICATION & SERVER MANAGEMENT UNIT</h4>
</div>

app/view/footer.php

</section>
<!-- /Section: intro -->
<footer>
    <div class="container">
        <div class="row">
            <div class="col-md-12 col-lg-12">
                <div class="wow shake" data-wow-delay="0.4s">
                    <div class="page-scroll marginbot-30">

                    </div>
                    <p>&copy;SquadFREE. All rights reserved.</p>
                    <div class="credits">
                        Designed by <a href="https://bootstrapmade.com/">BootstrapMade</a>
                    </div>
                </div>
            </div>
        </div>
</footer>

<!-- Core JavaScript Files -->
<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/bootstrap.min.js"></script>
<script src="assets/js/jquery.easing.min.js"></script>
<script src="assets/js/jquery.scrollTo.js"></script>
<script src="assets/js/wow.min.js"></script>
<!-- Custom Theme JavaScript -->
<script src="assets/js/custom.js"></script>


</body>

</html>

app/view/header.php

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta name="description" content="">
        <meta name="author" content="">

        <title>CONTACTS DATABASE</title>

        <!-- Bootstrap Core CSS -->
        <link href="assets/css/bootstrap.min.css" rel="stylesheet" type="text/css">

        <!-- Fonts -->
        <link href="assets/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css">
        <link href="assets/css/animate.css" rel="stylesheet" />
        <!-- Squad theme CSS -->
        <link href="assets/css/style.css" rel="stylesheet">
        <link href="assets/color/default.css" rel="stylesheet">


    </head>

    <body id="page-top" data-spy="scroll" data-target=".navbar-custom">


        <nav class="navbar navbar-custom navbar-fixed-top" role="navigation">
            <div class="container">
                <div class="navbar-header page-scroll">
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-main-collapse">
                        <i class="fa fa-bars"></i>
                    </button>
                    <a class="navbar-brand" href="index.html">
                        <h1>CONTACTS DATABASE</h1>
                    </a>
                </div>

                <!-- Collect the nav links, forms, and other content for toggling -->
                <div class="collapse navbar-collapse navbar-right navbar-main-collapse">
                    <ul class="nav navbar-nav">
                        <li class="active"><a href="#intro">HOME</a></li>
                        <!--          <li><a href="#about">About</a></li>
                                  <li><a href="#service">Service</a></li>
                                  <li><a href="#contact">Contact</a></li>-->
                        <li class="dropdown">
                            <a href="#" class="dropdown-toggle" data-toggle="dropdown">E-CONTACTS<b class="caret"></b></a>
                            <ul class="dropdown-menu">
                                <li><a href="?action=viewBookings">VIEW CONTACTS</a></li>
                                <li><a href="?action=addBooking">ADD CONTACT</a></li>
                                <li><a href="?action=research">SEARCH CONTACTS</a></li>
                            </ul>
                        </li>
                    </ul>
                </div>
                <!-- /.navbar-collapse -->
            </div>
            <!-- /.container -->
        </nav>
        <!-- Section: intro -->
        <section id="intro" class="intro">

app/view/registration_form.php

<div class="container">

    <div class="row">
        <div class="col-sm-3"></div>
        <div class="col-sm-6 box text-center">
            Add Contact
        </div>
        <div class="col-sm-3"></div>

    </div>

    <div class="row">
        <div class="col-sm-3"></div>
        <div class="col-sm-6 jumbotron">
            <form action="" method="post" novalidate="true" enctype="multipart/form-data">
                <div class="form-group">
                    <label class="control-label">
                        First Name
                        <span class="alert-danger">
                            <?= isset($errors["firstname"]) ? $errors["firstname"] : "" ?>
                        </span>
                    </label>
                    <input class="form-control" type="text" name="firstname" value="<?= isset($_POST['firstname']) ? $_POST['firstname'] : (isset($firstname_temp) ? $firstname_temp : "") ?>"/>

                </div>

                <div class="form-group">
                    <label class="control-label">
                        Last Name
                        <span class="alert-danger">
                            <?= isset($errors["lastname"]) ? $errors["lastname"] : "" ?>
                        </span>
                    </label>
                    <input class="form-control" type="text" name="lastname" value="<?= isset($_POST['lastname']) ? $_POST['lastname'] : (isset($lastname_temp) ? $lastname_temp : "") ?>"/>

                </div>    
                <div class="form-group">
                    <label class="control-label">
                        Email
                        <span class="alert-danger">
                            <?= isset($errors["email"]) ? $errors["email"] : "" ?>
                        </span>
                    </label>
                    <input class="form-control" type="email" name="email" value="<?= isset($_POST['email']) ? $_POST['email'] : (isset($email_temp) ? $email_temp : "") ?>"/>

                </div>  

                <div class="form-group">
                    <label class="control-label">
                        Mobile
                        <span class="alert-danger">
                            <?= isset($errors["mobile"]) ? $errors["mobile"] : "" ?>
                        </span>
                    </label>
                    <input class="form-control" type="text" name="mobile" value="<?= isset($_POST['mobile']) ? $_POST['mobile'] : (isset($mobile_temp) ? $mobile_temp : "") ?>"/>

                </div>

                <div class="form-group">
                    <label class="control-label" for="photo">
                        Photo
                        <span class="alert-danger">
                            <?= isset($errors["photo"]) ? $errors["photo"] : "" ?>
                        </span>
                    </label>
                    <input class="form-control" type="file" name="photo" /> 

                </div>


                <br/>
                <div class="form-group">

                    <input class="btn btn-primary btn-block" type="submit" name="submit" />

                </div>  

            </form>

        </div>
        <div class="col-sm-3"></div>
    </div>

</div>

app/view/search_form.php

<div class="container">

    <div class="row">
        <div class="col-sm-1"></div>
        <div class="col-sm-10 box text-center">
            Search Contacts
        </div>
        <div class="col-sm-1"></div>

    </div>

    <div class="row">
        <div class="col-sm-1"></div>
        <div class="col-sm-10 jumbotron">
            <form action="" method="post" novalidate="true">
                <div class="form-group">
                    <label class="control-label">
                        Keyword:
                    </label>
                    <input class="form-control" type="text" name="search"/>

                </div>


                <br/>
                <div class="form-group">

                    <input class="btn btn-primary btn-block" type="submit" name="Search" />

                </div>  

            </form>

        </div>
        <div class="col-sm-1"></div>
    </div>

</div>

app/view/viewBookings.php

<br>
<br>
<div class="container">
    <div class="row">
        <div class="col-md-1 text-center"></div>
        <div class="col-md-10 box text-center">View Contacts: <?= count($records) ?> results</div>
        <div class="col-md-1 text-center"></div>
    </div>
    <div class="row">
        <div class="col-md-1 text-center"></div>
        <div class="col-md-10 jumbotron text-center">
            <table class="table table-striped table-hover" >
                <tr>
                    <th>Contact ID</th>
                    <th>First Name</th>
                    <th>Last Name</th>
                    <th>Email</th>
                    <th>Mobile</th>
                    <th>Photo</th>
                    <th>Operation</th>
                </tr>
                <?php foreach ($records as $row): ?>
                    <tr>
                        <td align="left"><?= $row['id'] ?></td>
                        <td align="left"><?= $row['first_name'] ?></td>
                        <td align="left"><?= $row['last_name'] ?></td>
                        <td align="left"><?= $row['email'] ?></td>
                        <td align="left"><?= $row['mobile'] ?></td>
                        <td align="left">
                            <img src="assets/img/photos/<?= $row['photo_filename'] ?>" width="40%">
                        </td>
                        <td align="left">
                            <a href="?action=editBooking&id=<?= $row['id'] ?>" >Edit</a>
                            &nbsp;
                            <a href="?action=deleteBooking&id=<?= $row['id'] ?>" >Delete</a>
                        </td>
                    </tr> 
                <?php endforeach; ?>

            </table>
        </div>
        <div class="col-md-1 text-center"></div>
    </div>
</div>

app/Validation.php

<?php

include "myfunctions.php";

class Validation {

    function validate($value, $valid_type, $request) {
        if (!$request)
            return;
        $msg = strlen($value) == 0 ? "Miss input" : "";
        if (strlen($value) == 0)
            return $msg;
        $msg = $this->{$valid_type}($value);
        if (strlen($value))
            return $msg;
    }

    function time($value) {
        return "";
    }

    function date($value) {
        return validateDate($value) ? "" : "Invalid input";
    }

    function alpha_spaces($value) {//只允许空格与字母
        $value = str_replace(" ", "", $value);
        return ctype_alpha($value) ? '' : 'Alpha characters only';
    }

    function digits($value) {//只允许数字
        return ctype_digit($value) ? "" : "Digit only";
    }

    function photo($value) {
        return "";
    }

    function decimal($value) {//验证是否是浮点数
        return is_float($value) ? "" : "Float only";
    }

    function email($value) {//验证邮件格式
        return filter_var($value, FILTER_VALIDATE_EMAIL) ? "" : "Invaild email";
    }

    function validate_form_data($request, $field) {
        $errors = [];
        $validation = new Validation();

        foreach ($field as $fieldname => $field_data) {

            //验证其他:
            $value = trim($request[$fieldname]); //photo在这里并没有被检测到

            $tokens = explode("|", $field_data);
            $valid_type = $tokens[0];
            $require = $tokens[1];

            $errorMessage = $this->validate($value, $valid_type, $request);
            if (strlen($errorMessage) > 0) {
                $errors[$fieldname] = $errorMessage;
            }
        }
        return $errors;
    }

}

app/myfunctions.php

<?php

/*
 * To use these functions include this page in your PHP
 * 
 * How to use these functions:
 * 
 * $valid = validateDate($date);
 * 
 * $valid = validateMonthYearDate($date);
 * 
 * $valid = validateStreetAddress($street_address);
 * 
 * @author Stefan Batsas
 * @date 2017
 */

/**
 * function validates date formats: dd/mm/yyyy, yyyy-mm-dd
 * @param type $date
 * @return boolean
 */
function validateDate($date) {

    $valid = false;
    // no support for HTML5 date picker user enters input for date 
    // any other date format will not pass 
    if (preg_match("/\d{4}\-\d{2}\-\d{2}/", $date)) {
        // if we are here user has entered format of yyyy-mm-dd
        $day = $month = $year = "";
        // split up the pieces 
        list($year, $month, $day) = explode("-", $date);

        $day = intval($day);
        $month = intval($month);
        $year = intval($year);

        // now use PHP checkdate to verify it is a valid date 
        if (checkdate($month, $day, $year)) {
            $valid = true;
        }

        // no support for HTML5 date picker user enters input for date 
        // any other date format will not pass 
    } else if (preg_match("/\d{2}\/\d{2}\/\d{4}/", $date)) {
        // if we are here user has entered format of dd/mm/yyyy
        $day = $month = $year = "";
        // split up the pieces 
        list($day, $month, $year) = explode("/", $date);

        $day = intval($day);
        $month = intval($month);
        $year = intval($year);

        // now use PHP checkdate to verify it is a valid date 
        if (checkdate($month, $day, $year)) {
            $valid = true;
        }
    }
    return $valid;
}

// end function

/**
 * function validates date formats: dd/yyyy, yyyy-mm
 * eg. card expiry date
 * @param type $date
 * @return boolean
 */
function validateMonthYearDate($date) {

    $valid = false;

    if (preg_match("/\d{4}\-\d{2}/", $date)) {
        // if we are here user has ebtered format of mm/yyyy
        $month = $year = "";
        // split up the pieces 
        list($year, $month) = explode("-", $date);


        $month = intval($month);
        $year = intval($year);
        // now use PHP checkdate to verify it is a valid date - 1 is supplied for day
        if (checkdate($month, 1, $year)) {
            $valid = true;
        }

        // no support for HTML5 date picker user enters input for date
        // any other date format will not pass 
    } else if (preg_match("/\d{2}\/\d{4}/", $date)) {
        // if we are here user has ebtered format of mm/yyyy
        $month = $year = "";
        // split up the pieces 
        list($month, $year) = explode("/", $date);


        $month = intval($month);
        $year = intval($year);
        // now use PHP checkdate to verify it is a valid date - 1 is supplied for day
        if (checkdate($month, 1, $year)) {
            $valid = true;
        }
    }
    return $valid;
}

// end function

/**
 * Street address example Unit 5/23-24 Page street
 * Can contain one forward slash and one dash
 * @param type $value
 * @return boolean
 */
function validateStreetAddress($value) {

    $valid = true;

    // check for forward slashes  - 1 is permitted
    $numSlashes = $numDashes = 0;

    // number of slashes replaced stored in $numSlashes
    $temp = str_replace("/", "", $value, $numSlashes);
    // number of dashes replaced stored in $numSlashes
    $temp = str_replace("-", "", $value, $numDashes);

    if ($numSlashes > 1 || $numDashes > 1) {

        $valid = false;
    } else {

        // remove spaces
        $temp = str_replace(" ", "", $value);
        // remove slash
        $temp = str_replace("/", "", $temp);
        // remove dashes
        $temp = str_replace("-", "", $temp);

        // check for alpha numeric
        if (!ctype_alnum($temp)) {
            $valid = false;
        } // end if
    } // end if

    return $valid;
}

// end validation of street address

/**
 * Complex names eg Jon-Palo Jnr. the 3rd
 * Allow alpha numeric, spaces, 1 hyphen, 1 period, 1 digit
 * @param type $value
 * @return boolean
 */
function validate_complex_name($value) {

    $valid = true;
    // remove the spaces
    $temp = str_replace(' ', '', $value);
    // remove dashes and count them
    $temp = str_replace('-', '', $temp, $hyphen_count);
    // remove periods and count them
    $temp = str_replace('.', '', $temp, $fullstop_count);
    // count the number of digits
    $digit_count = preg_match_all("/[0-9]/", $temp);

    // rules are 1 dash, 1 period, 1 digit and alpha permitted
    if (!ctype_alnum($temp) || $hyphen_count > 1 ||
            $fullstop_count > 1 || $digit_count > 1) {
        $valid = false;
    }

    return $valid;
}

function validateDOB($value) {
    $valid = false;

    if (validateDate($value)) {

        $today = date('Y-m-d');
        $dob = date($value);
        $time1 = strtotime($today);
        $time2 = strtotime($dob);

        if ($time2 < $time1) {
            $valid = true;
        }
    }
    return $valid;
}
?>

app/assets/config.php

<?php

set_include_path(__DIR__ . '/app');
//把app文件设置为include path

app/assets/index.php

<?php

include_once 'config.php'; //设置include path
include_once 'Validation.php';
include_once 'view/header.php';
include_once 'model/BookingModel.php';
include_once 'controller/BookingsController.php';
include_once 'controller/HomeController.php';

$homeController = new HomeController();
$bookings = new BookingModel();
$bookingsController = new BookingsController();
if (isset($_GET['action'])) {
    $action = $_GET['action'];
    if ($action == 'viewBookings') {
        $bookingsController->viewBookings();
    } else if ($action == 'addBooking') {
        $bookingsController->addBooking();
    } else if ($action == 'deleteBooking') {
        $bookingsController->deleteBooking();
    } else if ($action == 'editBooking') {
        $bookingsController->editBooking();
    } else if ($action == 'research') {
        $bookingsController->searchBookings();
    } else {
        include_once "index.php";
    }
} else {
    $homeController->index();
}

include_once 'view/footer.php';
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值