掃碼登錄

package cc.zenking.classcard.system.controller;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import cc.zenking.classcard.common.Const;
import cc.zenking.classcard.system.model.QrCodeResponse;
import cc.zenking.classcard.system.service.ScanService;
import cc.zenking.classcard.utils.RedisUtil;
import net.sf.json.JSONObject;

/** 
* @ClassName: ScanController 
* @Description: (掃碼登錄) 
* @date 2019年7月11日 上午10:15:48 
* @version V1.0
*  
*/
@Controller
@RequestMapping("/zhbpappscan")
public class ScanController{

    @Autowired
    private RedisUtil rs;
    @Autowired
    private ScanService scanService;
    /**
     * 二維碼 掃碼登錄 存儲三分鐘
     */
    @Value("${zhbp.redis.auth.code.three}")
    private long authCodeThree;

    /**
     * @param @return 設定文件
     * @return ResponseEntity<Object>    返回類型
     * @throws
     * @Title: createQRCode
     * @Description: (生成二維碼並將uuid存儲到redis中)
     */
    @RequestMapping("/qrcode")
    @ResponseBody
    public JSONObject createQRCode() {
        Map<String, Object>map = new HashMap<>();
        map.put("status", 1);
        map.put("reason", "成功");
        map.put("data", 0);
        String uuid = UUID.randomUUID().toString();
        //組裝二維碼內容 zenking,1,uuid=xxxx
        String text = Const.QRCODE_DOMAIN + "?type=" + Const.QRCODE_TYPE + "&uuid=" + uuid;
        int width = 300;
        int height = 300;
        String format = "png";
        Map<String, Object> uuidMap = new HashMap<>();
        uuidMap.put("userId", "0");
        //是否掃碼 0未掃碼,1掃碼
        uuidMap.put("isAppScan", "0");
        try {
            Map<EncodeHintType, Object> hints = new HashMap<EncodeHintType, Object>();
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            // hints.put(EncodeHintType.MARGIN, 1);
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 容錯率
            BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
            ByteArrayOutputStream bao = new ByteArrayOutputStream();
            MatrixToImageWriter.writeToStream(bitMatrix, format, bao);
            bao.toByteArray();
            Base64 encoder = new Base64();
            String img = encoder.encodeAsString(bao.toByteArray());
            QrCodeResponse qrCodeResponse = new QrCodeResponse();
            qrCodeResponse.setUuid(uuid);
            qrCodeResponse.setImg(img);
            rs.addMap(Const.QECODE + uuid, uuidMap);
            rs.expire(Const.QECODE + uuid, authCodeThree);
            map.put("data", qrCodeResponse);
        } catch (WriterException e) {
            map.put("status", -1000);
            map.put("reason", "參數有誤");
            e.printStackTrace();
        } catch (IOException e) {
            map.put("status", -1000);
            map.put("reason", "參數有誤");
            e.printStackTrace();
        }
        return JSONObject.fromObject(map);
    }

    /**
     * @param @param  uuid
     * @param @return 設定文件
     * @return ResponseEntity<Object>    返回類型
     * @throws
     * @Title: cleanRedisQrcode
     * @Description: (掃碼後未確認返回二維碼登錄時重置)
     */
    @RequestMapping("/resetQrcode")
    @ResponseBody
    public JSONObject resetQrcode(String uuid) {
        Map<String, Object>map = new HashMap<>();
        map.put("status", 1);
        map.put("reason", "成功");
        map.put("data", 0);
        try {
            Object uuidExist = rs.getMapField(Const.QECODE + uuid, "userId", Object.class);
            if (null == uuidExist) {
                map.put("status", -6371);
                map.put("reason", "redis中uuid不存在");
            } else {
                //掃描成功標識,用該標識展示“請在手機上確認登錄”界面
                rs.addMap(Const.QECODE + uuid, "isAppScan", "0");
            }
        } catch (Exception e) {
            e.printStackTrace();
            map.put("status", -6379);
            map.put("reason", "uuid保存到redis中異常");
        }
        return JSONObject.fromObject(map);
    }

    /**
     * @param @param  uuid
     * @param @param  status  無值 或者 0的時候 返回掃過的狀態  1的時候 不返回
     * @param @return 設定文件
     * @return ResponseEntity<Object>    返回類型
     * @throws
     * @Title: pool
     * @Description: (檢查二維碼是否被掃描)
     */
    @RequestMapping("/pool")
    @ResponseBody
    public JSONObject pool(String uuid, Integer status) {
        Map<String, Object>map = new HashMap<>();
        Map<String, Object>userInfoMap = new HashMap<>();
        map.put("status", 1);
        map.put("reason", "成功");
        map.put("data", 0);
        userInfoMap.put("userId", "");
        userInfoMap.put("userName", "");
        userInfoMap.put("portrait", "");
        map.put("userInfo",userInfoMap);
        //計時
        int time = 0;
        while (true) {
            time++;
            Map<String, Object> ad = rs.mget(Const.QECODE + uuid, Object.class);
            if (ad == null || ad.size() == 0) {
                //點擊刷新  3代表超時,頁面點擊刷新
                map.put("data", 3);
                return JSONObject.fromObject(map);
            }
            if (ad != null && !("0".equals(ad.get("userId")))) {
                //app掃過 並且登錄  使用userId 生成token
                int n = scanService.getUserInfo(Integer.parseInt(ad.get("userId").toString()));
                if (n == 1) {
                    //登錄後信息
                    map.put("userInfo", scanService.getLoginInfo(Integer.parseInt(ad.get("userId").toString())));
                    //2 代表成功登錄狀態
                    map.put("data", 2);
                    return JSONObject.fromObject(map);
                } else {
                    //3代表 刷新
                    map.put("data", 3);
                    return JSONObject.fromObject(map);
                }
            }
            if (ad != null && "1".equals(ad.get("isAppScan"))) {
                //app掃過
                if (status == null || status.intValue() == 0) {
                    //1 是 app掃過,彈出選擇登錄 還是 取消
                    map.put("data", 1);
                    return JSONObject.fromObject(map);
                }
            }
            if (time >= 10) {
                //保持10秒
                map.put("data", 0);
                return JSONObject.fromObject(map);
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
     * @param @param  uuid
     * @param @param  userId
     * @param @return 設定文件
     * @return ResponseEntity<Object>    返回類型
     * @throws
     * @Title: login
     * @Description: (app按鈕 : 允許登錄)
     */
    @RequestMapping("/appScanLogin")
    @ResponseBody
    public JSONObject appScanLogin(String uuid, String userId) {
        Map<String, Object>map = new HashMap<>();
        map.put("status", 1);
        map.put("reason", "成功");
        map.put("data", 0);
        Map<String, Object> ad = rs.mget(Const.QECODE + uuid, Object.class);
        if (null == ad||ad.isEmpty()) {
            map.put("status", -1021);
            map.put("reason", "請重新掃碼");
        } else {
            //如果isAppScan狀態是1纔可以登錄
            if (ad.get("isAppScan") != null && "1".equals(ad.get("isAppScan"))) {
                rs.addMap(Const.QECODE + uuid, "userId", userId);
            }
        }
        return JSONObject.fromObject(map);
    }
    
    /**
     * 功能描述:退出
     *
     * @param uuid
     * @param userId
     * @return: org.springframework.http.ResponseEntity<java.lang.Object>
     */
    @RequestMapping(value = "/appScanCancel")
    @ResponseBody
    public JSONObject appScanCancel(String uuid, String userId) {
        Map<String, Object>map = new HashMap<>();
        map.put("status", 1);
        map.put("reason", "成功");
        try {
            Map<String, Object> ad = rs.mget(Const.QECODE + uuid, Object.class);
            if (null == ad || ad.isEmpty()) {
                map.put("status", -1021);
                map.put("reason", "請重新掃碼");
            }
            //如果 isAppScan=1 則移除
            if (ad.get("isAppScan") != null && "1".equals(ad.get("isAppScan"))) {
                rs.del(Const.QECODE + uuid);
            }
        } catch (Exception e) {
            e.printStackTrace();
            map.put("status", -1021);
            map.put("reason", "請重新掃碼");
        }
        return JSONObject.fromObject(map);
    }
    
    /**
     * @param uuid
     * @param userId
     * @return ResponseEntity<Object>    返回類型
     * @Title: appScanEnd
     * @Description: (app掃描二維碼後)
     */
    @RequestMapping("/appScanPrevious")
    @ResponseBody
    public JSONObject appScanPrevious(@RequestParam(value = "uuid", required = true) String uuid,
                                                  @RequestParam(value = "userId", required = true) String userId) {
        Map<String, Object>map = new HashMap<>();
        map.put("status", 1);
        map.put("reason", "成功");
        map.put("data", 0);
        try {
            Object uuidExist = rs.getMapField(Const.QECODE + uuid, "userId", Object.class);
            if (null == uuidExist) {
                map.put("status", -6371);
                map.put("reason", "redis中uuid不存在");
            } else {
                //掃描成功標識,用該標識展示“請在手機上確認登錄”界面
                rs.addMap(Const.QECODE + uuid, "isAppScan", "1");
            }
        } catch (Exception e) {
            e.printStackTrace();
            map.put("status", -6379);
            map.put("reason", "uuid保存到redis中異常");
        }
        return JSONObject.fromObject(map);
    }
}
layui.extend({
    common: '../lib/common'
}).define(['common', 'form', 'layer', 'element'], function (exports) {
    var form = layui.form
        , layer = layui.layer
        , element = layui.element
        , common = layui.common
        , layerIndex = -1
        , getQrCode = function (n) {//n=1是初始化
            $.ajax({
                type: "get",
                url: common.prefix + "appscan/qrcode",
                data: [],
                cache: false,
                dataType: 'json',
                success: function (response) {
                    if (response) {
                        if (response.status == 1) {
                            $("#qrcode").attr("src", "data:image/png;base64," + response.data.img);
                            if (n == 1) {
                                keepPool(response.data.uuid, 0);
                                $("#redisUUID").val(response.data.uuid);
                            }
                        }
                    }
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    if (textStatus == null || textStatus == "") {
                    } else {
                    }
                }
            });
        }
        , keepPool = function (uuid, status) {//status=1 已經掃描 等待登錄
            if (!status) {
                status = 0;
            }
            $.ajax(
                {
                    type: "get",
                    url: common.prefix + "appscan/pool",
                    data: {uuid: uuid, status: status},
                    cache: false,
                    dataType: 'json',
                    success: function (data) {
                        if (data && data.status == '1') {
                            if (data.data == '1') {
                                //掃碼成功
                                $('.scan-box').addClass('layui-hide');
                                $('.scanned-box').removeClass('layui-hide');
                                $('.lapse-box').addClass('layui-hide');
                                keepPool(uuid, 1);
                            } else if (data.data == '2') {
                                //如果有返回地址 則重定向回
                                var redirectUri = "";
                                redirectUri = common.getRequest().redirectUri;
                                if (redirectUri) {
                                    var token = "?token=" + common.getCookie("token");
                                    if (!token) {
                                        token = "";
                                    }
                                    top.location.replace(redirectUri + token);
                                }
                                else {
                                    window.location.replace(common.prefix + "view/index.html");
                                }
                            } else if (data.data == '3') {
                                //點擊刷新
                                $('.scan-box').addClass('layui-hide');
                                $('.scanned-box').addClass('layui-hide');
                                $('.lapse-box').removeClass('layui-hide');
                            } else {
                                keepPool(uuid, 0);
                            }
                        }
                        else {
                            keepPool(uuid, 0);
                        }
                    },
                    error: function (XMLHttpRequest, textStatus, errorThrown) {
                        if (textStatus == "timeout") {
                            keepPool(uuid, 0);
                        } else {
                            keepPool(uuid, 0);
                        }
                    }
                }
            );
        }
        // 檢測是否需要強制修改密碼
        , checkUpdatePwd = function () {
            $.ajax({
                type: "post",
                url: common.prefix + "user/constraintUpdatePwd",
                async: false,
                dataType: 'json',
                success: function (result) {
                    if (result.status != 1) {
                        form.val("formPwd",{
                            'pwd':'',
                            'pwdSure':''
                        });
                        layer.open({
                            type: 1,
                            title: false,
                            closeBtn: 0,
                            content: $('#updatePwd'),
                            area: ['680px','440px'],
                            resize: false,
                            scrollbar: false,
                            success: function(layero, index){
                                layerIndex = index;
                                $('#updatePwd').removeClass('layui-hide');
                            },
                            end: function(){
                                $('#updatePwd').addClass('layui-hide');
                                form.val("formPwd",{
                                    'pwd':'',
                                    'pwdSure':''
                                });
                            }
                        });
                    } else {                    
                        logIn();
                    }
                }
            });
        }
        // 登入系統
        , logIn = function () {
            //如果有返回地址 則重定向回
            var redirectUri = "";
            redirectUri = common.getRequest().redirectUri;
            if (redirectUri) {
                //帶上token
                var token = "?token=" + common.getCookie("token");
                if (!token) {
                    token = "";
                }
                top.location.replace(redirectUri + token);
            }
            else {
                window.location.replace(common.prefix + "view/index.html");
            }
        }
        , initListeners = function () {
            //二維碼
            getQrCode(1);
            // 掃碼
            $("body").on("click", "[data-scan]", function () {
                var type = $(this).attr("data-scan");
                var $parent = $(this).parents(".scan");
                $parent.addClass("layui-hide");
                $(".scan-box").removeClass("layui-hide");
                if (type == 'back') {
                    // '返回'
                    //調用接口 重置 redis中的uuid  ajax成功後 調用 getQrCode(1);
                    var redisUUID = $("#redisUUID").val();
                    $.ajax({
                        type: "get",
                        url: common.prefix + "appscan/resetQrcode",
                        data: {uuid: redisUUID},
                        cache: false,
                        dataType: 'json',
                        success: function (response) {
                            if (response) {
                                if (response.status == 1) {
                                    //window.location.reload();
                                    //getQrCode(0);
                                } else {
                                    lay.msg(response.reason);
                                }
                            }
                        },
                        error: function (XMLHttpRequest, textStatus, errorThrown) {
                            if (textStatus == null || textStatus == "") {
                            } else {
                            }
                        }
                    });
                } else if (type == 'refresh') {
                    // '刷新'
                    getQrCode(1);
                }
            });

            // 帳號登錄
            $("body").on("click", "[data-logintype]", function () {
                var type = $(this).attr("data-logintype");
                var $tabTitle = $("[data-account]");
                var newTab = '', newPlaceholder = '', newType = '', newBtntxt = '';
                if (type == 'student') {
                    // 切換爲學生
                    newTab = "學生登錄";
                    newPlaceholder = '帳號';
                    newType = 'zksc';
                    newBtntxt = '<i class="layui-icon layui-icon-return"></i>返回';
                    $("[data-zksc]").addClass("layui-hide");
                    $("[data-student]").removeClass("layui-hide");
                } else if (type == 'zksc') {
                    // 帳號
                    newTab = "帳號登錄";
                    newPlaceholder = '手機號';
                    newType = 'student';
                    newBtntxt = '學生登錄';
                    $("[data-student]").addClass("layui-hide");
                    $("[data-zksc]").removeClass("layui-hide");
                }
                $tabTitle.text(newTab);
                $(this).attr("data-logintype", newType).html(newBtntxt);
                $("[name='username']").attr("placeholder", newPlaceholder);
				$('[name="username"]').val("");
				$('[name="password"]').val("");
				$('[name="authcode"]').val("");
            });

            //監聽提交
            form.on('submit(loginform)', function (data) {
                type = gettype();
                $.ajax({
                    type: "post",
                    url: common.prefix + "user/login",
                    data: {
                        type: type,
                        username: $.trim($("[name='username']").val()),
                        password: $.trim($("[name='password']").val()),
                        code: $.trim($("[name='authcode']").val()),
                        loginType: 1
                    },
                    async: false,
                    dataType: 'json',
                    success: function (result) {
                        if (result.status != 1) {
                            if(result.data){
                                // 被鎖定
                                if(result.data.loginErrorStatus==4){
                                    layer.open({'title':'您的帳號已被禁用,暫時無法登錄', 'content':'<div><i class="icon-danger"></i></div>'+result.reason, closeBtn:0, skin: 'login-layer'});
                                } else {
                                    layer.open({'title':'溫馨提示', 'content':result.reason, closeBtn:0, skin: 'login-layer',
                                        yes: function(index, layero){                                        
                                            if(result.data.loginErrorStatus==2){
                                                // 賬號或密碼錯誤時,刷新驗證碼
                                                $('#imgCode').attr('src', 'user/validateCode?'+Math.random());
                                            }
                                            layer.close(index);
                                        }
                                    });
                                }
                            } else {
                                layer.open({'title':'溫馨提示', 'content':result.reason, closeBtn:0, skin: 'login-layer'});
                            }                          
                            return;
                        }
                        
                        //檢測是否需要強制修改密碼
                        checkUpdatePwd();
                    },
                    error: function (XMLHttpRequest, textStatus, errorThrown) {
                        if (textStatus == null || textStatus == "") {
                            layer.msg(errorThrown);
                        } else {
                            layer.msg(textStatus);
                        }
                    }
                });
                return false;
            });

            // 提交,強制修改密碼
            form.on('submit(updatePwd)', function (data) {
                var phone=$(".account input[name='username']").val();
                var field=data.field;
                $.ajax({
                    type:'POST',
                    url:common.prefix+'forgetPwd/setNewPwd',
                    data:{phoneNo:phone, pwd:field.pwd, pwdSure:field.pwdSure},
                    cache:false,
                    dataType:'json',
                    success:function(result) {
                        layer.close(layerIndex);
                        layerIndex = -1; // 重置
                        if(result.status==1){
                            layer.open({'title':'溫馨提示', 'content':'修改成功,請重新登錄!'});
                            $(".account input[name='password']").val("");
                        } else {
                            layer.msg(result.reason,{title:false,icon:5,closeBtn:0,shade:0,time:3000});
                        }
                    }
                });
                return false;
            });

            form.verify({
                password: function(value){
                    if(value.trim().length<8){
                        return '密碼不能少於8位';
                    } else if(value.trim().length>24){
                        return '密碼不能超過24位';
                    } else if( !(/^(?=.*[A-Z])(?=.*\d)[A-Za-z\d]{8,24}$/.test(value)) && !(/^(?=.*[a-z])(?=.*\d)[A-Za-z\d]{8,24}$/.test(value)) ){
                        return '密碼要字母加數字進行組合';
                    }
                }
                ,equalPwd: function(value){
                    var pwd1=$("[name='pwd']").val().trim(),
                        pwd2=$("[name='pwdSure']").val().trim();
                    if(pwd1!=pwd2){
                        return '兩次密碼不一致';
                    }
                }
            });

            // 禁止輸入空格
            $("form").on("keypress", "input[name='username'],input[name='password']", function (event) {
                var evt = arguments.callee.caller.arguments[0];
                var key = evt.charCode;
                if (key == 32) {
                    event.preventDefault();
                }
            });

            // 回車登錄
            $("body").bind("keyup",function(event){
                var showFlag = $(".account").hasClass("layui-show");
                if(!showFlag){
                    return;
                }
                var evt=arguments.callee.caller.arguments[0];
                var key = evt.keyCode;
                if(key == 13){
                    var $layer = $("body>.layui-layer");
                    if($layer.length==0){
                        // 登錄
                        $("[lay-filter='loginform']").click();
                    }
                }
            });

            // 發送驗證碼
            $("[name='btnCode']").bind("click", function () {
                if ($("body").find(".error").length > 0) {
                    return false;
                }
                var flag = validRequired('username');
                if (!flag) {
                    layer.msg("請填寫手機號!");
                    return false;
                }
                flag = validRequired('password');
                if (!flag) {
                    layer.msg("請填寫密碼!");
                    return false;
                }
                sendcode(common.prefix, $(this));
            });

            // 用戶協議
            form.on('checkbox(agreement)', function(data){
                var $parent = $(data.elem).parents(".form-btn");
                    $btn = $parent.find('[lay-filter="loginform"]');
                if(data.elem.checked){
                    // 勾選
                    $btn.removeClass("layui-btn-disabled").removeAttr("disabled");
                } else {
                    $btn.addClass("layui-btn-disabled").attr("disabled",true);
                }
            });

            // 強制重置密碼,監聽密碼輸入框,改變‘確定’按鈕狀態
            $("#updatePwd").on("input porpertychange","input[required]",function(){
                var pwd1 = $("#updatePwd [name='pwd']").val().trim();
                var pwd2 = $("#updatePwd [name='pwdSure']").val().trim();
                if(pwd1!=""&&pwd2!=""){
                    $("#updatePwd .layui-btn").removeClass("layui-btn-disabled").removeAttr("disabled");
                } else {
                    $("#updatePwd .layui-btn").addClass("layui-btn-disabled").attr("disabled","disabled");
                }
            });
        };

    var type = 0;
    var sTime; //發送間隔時間    

    initListeners();
    exports('login', {});
});

/**
 * 獲取登錄名稱類型
 */
function gettype() {
    if ($("body").find(".error").length > 0) {
        return false;
    }
    var flag = validRequired('username');
    if (!flag) {
        return false;
    }
    flag = validRequired('password');
    if (!flag) {
        return false;
    }

    if (/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test($.trim($("[name='username']").val()))) {
        type = 2;

    } else if (/^1[0-9]{10}$/.test($.trim($("[name='username']").val()))) {
        type = 1;
    } else {
        type = 0;
    }
    return type;
}

/**
 * 發送驗證碼
 * @param wrap
 */
function sendcode(commonUrl, wrap) {
    gettype();
    wrap.attr("disabled","disabled").addClass("layui-btn-disabled");
    $.ajax({
        type: "post",
        url: commonUrl + "user/sendLoginRandomNo",
        data: {
            type: type,
            phoneNo: $.trim($("[name='username']").val()),
            password: $.trim($("[name='password']").val()),
            loginType: 0
        },
        async: false,
        dataType: 'json',
        success: function (data) {
            if (data.status != 1) {
                layer.msg(data.reason);
                wrap.removeAttr("disabled").removeClass("layui-btn-disabled");
            } else {
                layer.msg("驗證碼發送成功,請注意查收");                
                if (wrap) {
                    sTime = 60;
                    resendtime(wrap);
                }                
            }
        },
        error: function (XMLHttpRequest, textStatus, errorThrown) {
            if (textStatus == null || textStatus == "") {
                layer.msg(errorThrown);
            } else {
                layer.msg(textStatus);
            }
        }
    });
}

//設置定時,1分鐘後才能重新發送
function resendtime(wrap) {
    if (sTime != 0) {
        wrap.val("獲取驗證碼("+sTime+")");
        sTime--;
        setTimeout(function () {
            resendtime(wrap)
        }, 1000)
    } else {
        wrap.removeAttr("disabled").val("獲取驗證碼").removeClass("layui-btn-disabled");
    }
}

function validRequired(name) {
    var flag = true;
    var that = $("[name='" + name + "']");
    var value = that.val();
    if (value == "") {
        flag = false;
    }
    return flag;
}

function replaceNull(obj) {
    var exp = obj;
    if (typeof(exp) == "undefined" || exp == null) {
        return "";
    }
    return obj;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章