周晓杰

周晓杰 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑

PHP程序员 Cocos Creator爱好者

个人动态

周晓杰 关注了用户 · 10月7日

C&LrQ0xX @c_lrq0xx

关注 1

周晓杰 赞了文章 · 9月28日

兴趣驱动职业,七年之后的我...

clipboard.png

关于我

大家好(๑╹◡╹)ノ”,我是CrazyCodes,一枚大气没成的程序员。在SegmentFault划水四年了,多多少少写了一些水文,从一名菜鸡到现在的伪菜鸡,还是需要一个过程的。

正式自我介绍下

真实姓名:张某某
网络名称:CrazyCodes
性别:男
年龄:23
婚姻状况:距离婚礼还有5天 (这可能是我单身的最后一篇文章😆)
本命语言:PHP (世界上最好的语言)

在学校我是那种垫底的学生,至少在老师眼里基本算是“湿垃圾”,初中毕业后再某某职专上了一年后跑来北京开始北漂的生活,从初中就比较喜欢研究一些游戏的外挂,写一些脚本,自认为已经非常强大了,结果发现社会套路深,我要回农村。

在北京漂了一个月,身上的钱也花的差不多了,没办法但还想当程序员(不知道那时候为什么会有那么强烈的欲望,可能对于新人来说程序员是一份神秘的职业,当时的想法已记不清楚了),还好我心爱的母亲资助了我八千块,我进入当年我感觉最牛逼的培训学校(LAMP兄弟连)。

(不是打广告),就是聊聊当年的兄弟连,那应该是2012年的时候,PC企业站开发,套站,CMS,论坛满天飞,可以说是PHP在中国最盛行的时期。当然那时的兄弟连也仅仅只有PHP的培训,我没得选(现在的LAMP兄弟连我不妄加评论),印象中当时我们上午8点上课,晚上12点下课,可能还会更晚,反正大家都在拼命。可能对我们来说,那是最后的机会了把,如果放弃了,我将一辈子无缘程序员。

在噩梦的六个月后,成功毕业的我依旧找不到工作,当时年龄小,未成年的嘛,也可能是技术确实也不咋滴,反正是无论如何也找不到工作,最后经朋友推荐进入第一家外包公司。这些年过去了,虽然感觉那第一份工作很累,但成长总是在最开始,还是非常感谢第一家公司的老板。

这七年

感觉程序员的经历都差不多,敲代码就跟搞对象一样。

  • 从相识到相知最后到相爱结婚生子

程序则是

  1. 学习语法
  2. 了解开发模式
  3. 写好代码
  4. 深究原理
  5. 最后人机合一

工作经历就更不用说了

  • 996 早上九点上班晚上九点下班,一周上六天
  • 9126 早上九点上班晚上十二点下班,一周上六天
  • 9127 早上九点上班晚上十二点下班,一周上七天
  • 9x7 早上九点上班晚上不知道几点下班,一周上七天

可以这样说,没有加班过的不是一位正在的程序员,在中国的市场环境下,加班是跑不掉了。无论你是大神还是菜鸡都跳不过加班这条不成文的规定。

在工作中也做过一些很搞笑的事情

拆东墙补西墙

刚开始工作的时候,除了自己敲代码则就是拿来主义,比如一个execl的解析类,自己写多费劲,直接拿过来一个,当时php还木有composer包管理,基本步骤就是酱紫

第一步:打开百度
第二步:搜索php execl表格解析类
第三步:拷贝
第四步:粘贴
第五步、第六步、第七步、第N步:一直在调试这个类,反正无论怎么改都不好使

这种不算可怕,怕的就是开始好使,过了一段时间,因为毕竟拷贝的别人的代码,也没有什么注释,出现问题后,打开文件内心想的一件事是 我X,这是哪个XX写的代码 😆

双管齐下

在当年WEB前端没有现在这么牛逼,当时PHP的招聘要求是

  1. 精通PHP,MYSQL
  2. 熟练使用 HTML,CSS,JS
  3. 对DEDE,帝国有二次开发经验者优先
  4. 会PS切图的优先

看,这就是2012年的中小型公司普遍的招聘要求。翻译过来就是(一个人干所有事,啥都得会立马入职)

那时都是开好多个编辑器边写前端边写后端,经常会出现改了一段代码发现为什么页面上不显示,折腾一天,才发现,我X,改错项目了。

公众号时代

随后就到了公众号的时代,铺天盖地的公众号开发,咔咔咔,就发现当时学的兼容IE5.5,6,7以没用处,那时的公众号开发别提多亏了。微信官方文档内埋着比你代码都多的坑等着你跳。因为公众号开发我还砸坏了一个键盘(腾讯得赔我一个)

移动互联网时代

随着互联网行业人才需求的不断洗牌,和不断出现的新技术,前端与后端的界限已经被划分的非常清楚了。不过这是一个三国争霸的时代,什么?你问我是哪三国?

  • 后端开发者
  • 安卓开发者
  • 苹果开发者

经历了近四年的Api开发,不断的出现了一个不成文的规定,那就是

if(安卓API == ERROR){
   可能 后端的问题
   可能 安卓的问题
}

if(苹果API == ERROR){
   可能 后端的问题
   可能 苹果的问题
}

if(安卓API == ERROR && 苹果API == ERROR){
   一定 后端的问题
}

看,后端多惨,这事我就不多说了,蓝瘦香菇。

学习

既然选择了这个职业,就注定一生都在学习的道路上。语言版本更替速度极快,不进则退,学习分很多方式,在这里分享给各位自己总结的一些学习方法。

专一

学就学一个,例如感觉数据库不够好,那就专心看数据库。不要吃着碗里看着锅里的。在计算机的领域里一辈子都学不完,不能着急,一个一个来,网络上出现的各种大佬讲的课,买一个就可以了。买多了也不看,浪费~

专注

开始一个新课程的学习,跟学校里一样,在学习这门课程的过程中,请放弃游戏,娱乐和无意义的社交。专心去学习,才会有可能达到想要的效果

专心

准备去学习一门课程的时候,要有学不会就不睡觉,学不死就往死里学的决心。

其他

向他人请教也是一种学习的方法,不过要先学会提问的艺术,否则你会获得一份鸟哥语录

clipboard.png

其次则是各大技术论坛,但那并不是学习的主要途径,只能说是了解,学习是需要先定好计划,并不是一个随心所欲的动作。

送给新人的一句话

多看书多读书,多提问多看报,多敲代码少吃零食,少睡觉。

致谢

感谢看完我这一篇的唠叨,如果还有一次选择职业的机会,我依旧会选择程序员,人的一生要做自己喜欢做的事情,收入多少并没有那么重要,感谢这个世界可以让我成为一名程序员,虽然不够优秀,但兴趣驱动着我,向渺茫的计算机世界慢慢靠近,可能我会停在某个点上不再前行,但希望后者可以跨阔鸿沟,创造一片属于自己的小世界,谢谢。

记得关注么么哒

SF小姐姐,来个五仁月饼

查看原文

赞 22 收藏 4 评论 6

周晓杰 发布了文章 · 9月28日

mpvue不维护了,已经成型的mpvue项目怎么办

mpvue作为美团技术团队的一个KPI产品,莫名其妙突然就不维护了,随着node版本和项目依赖不断更新,你会发现你原先的项目可能突然跑不起来了,此时你需要mpvue的替代品,没错,我要说的就是uni-app。

只需几步,你可以很轻松的把mpvue项目迁移到uni-app。

先去官网按步骤建好项目

https://uniapp.dcloud.io/quickstart

1、 把mpvue项目里src目录的文件复制到uni-app项目里

image.png

2、把main.js搬到uniapp的page.json里

mpvue的main.js

image.png

搬过来之后是这样的

image.png

3、运行,看看css是否跟原版有偏差,重新调整。此外要把api改成uni-app的,例如发请求api的要换成这个

https://uniapp.dcloud.io/api/request/request

大功告成

查看原文

赞 0 收藏 0 评论 0

周晓杰 关注了用户 · 7月10日

CrazyCodes @crazycodes

https://github.com/CrazyCodes... 我的博客
_
| |__ __ _
| '_ | | | |/ _` |
| |_) | |_| | (_| |
|_.__/ \__,_|\__, |

         |___/   感谢生命可以让我成为一名程序员

                         CrazyCodes To Author

关注 4671

周晓杰 关注了专栏 · 7月4日

Cocos Creator 教程

Cocos Creator 2.0+实战教程,使用TypeScript编写。

关注 10

周晓杰 发布了文章 · 6月9日

mpvue使用component组件

前言

我们都知道mpvue的好处是可以用到很多vue的东西,那么如何在mpvue中创建这样的标签栏组件

image.png

子组件

先创建子组件
image.png

内容如下
titletab.vue

<template>
  <div class="tabs">
        <ul>
          <li
            v-for="(item, index) in tabs" :key="index"
            :class="activeIndex == index ?'active':''"
            @click="reloadQuestion(index)"
          >{{ item }}</li>
        </ul>
      </div>
</template>

<script>
    export default {
        props: ['tabs','activeIndex'],
        created() {
          console.log(this.tabs)
        },
        methods: {
            //触发父组件的刷新问题
            reloadQuestion(index) {
               this.$emit("reloadQuestion",index);
            },
        }
    }
</script>

<style>
  .tabs {
    width: 100%;
    background: #f54353;
    font-size: 24rpx;
    height: 80rpx;
  }
  .tabs ul li {
    width: 33%;
    display: inline-block;
    text-align: center;
    line-height: 80rpx;
    color: #fff;
    border-bottom: 4rpx solid #f54353;
  }
  .tabs ul li.active {
    border-bottom: 4rpx solid #f9e98a;
  }
</style>

引用

在我引用的的地方,引入

index.vue

//@reloadQuestion接受子组件传来的刷新消息
<template>
  <div class="container">
    <titletab :tabs="tabs" :activeIndex="activeIndex" @reloadQuestion="getQuestionList"></titletab>
</template>

<script>
import titletab from "../../components/titletab";
export default {
  data() {
    return {
      tabs: ["关注", "全部", "榜单"],
      activeIndex: 0,
      questionlist: []
    };
  },

  components: {
    titletab
  },

  methods: {
    //刷新问题列表
    async getQuestionList(type = 0) {
      var that = this;
      that.activeIndex = type;
      let res = await this.$post("question", { type: that.activeIndex });
      that.questionlist = res.data;
    }, 
  },
  
};
</script>

搞定

GIF.gif

查看原文

赞 1 收藏 0 评论 1

周晓杰 发布了文章 · 6月5日

微信答题PK类游戏尝试实现

前言

前阵子头脑王者类的微信答题PK游戏很火,自己也是很痴迷,玩了一阵子之后,想自己尝试来模仿下答题这一部分的实现。服务端打算在下swoole和socket.io之间选择,因为socket.io可以不借助redis直接缓存一些变量,所以选择了socket.io。简单实现了对战这一部分,实现的并不完善,只是一种思路

客户端实现

index.html

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0,user-scalable=0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>答题</title>

    <script type="text/javascript" data-original="vue.js"></script>
    
    <style>
    .player {
        display: flex;
        color: #fff;
        text-align: center;
    }

    .player .item {
        height: 80px;
    }

    .player .item.select {
        border: 4px solid #ff9933;
        box-sizing: border-box;
    }

    .player .item:first-child {
        background-color: #6dcffb;
        flex: 3;
    }

    .player .item:nth-child(2) {
        background-color: #5247a4;
        flex: 1;
        line-height: 80px;
    }

    .player .item:last-child {
        background-color: #d64e8c;
        flex: 3;
    }

    #app {
        background-color: #5a8ced
    }

    .question {
        color: #fff;
        text-align: center;
    }

    .options {
        padding-bottom: 40px
    }

    .options li {
        width: 280px;
        height: 60px;
        background-color: #fff;
        margin-top: 40px;
        display: block;
        border-radius: 50px;
        text-align: center;
        line-height: 60px;
    }

    .options li.correct {
        background-color: #00e2bc;
        color: #fff;
    }

    .options li.wrong {
        background-color: #fe6f5f;
        color: #fff;
    }

    .tips {
        text-align: center;
        color: #fff
    }
</style>
</head>

<body>
    <div id="app">
        <div class="player">
            <div :class="[playerIndex===0?'item select':'item']">
                <p class="name">选手1</p>
                <p class="score">{{score[0]}}</p>
            </div>
            <div class="item">{{remain_time}}</div>
            <div :class="[playerIndex===1?'item select':'item']">
                <p class="name">选手2</p>
                <p class="score">{{score[1]}}</p>
            </div>
        </div>
        <p class="question">{{question}}</p>
        <ul class="options">
            <li v-for="(item, key, index) in options" :class='item.class' @click="sendAnswer(key)">{{item.index}}</li>
        </ul>
        <p class="tips">{{msg}}</p>
    </div>
</body>
</html>
<script>

</script>
<script data-original="./socket.io.js"></script>
<script>
    var header = new Vue({
        el: "#app",
        data: {
            socket: null, //socket.io对象
            playerIndex: null, //当前选手索引
            question: '', //问题内容
            msg: '', //下方提示语
            options: [], //选项
            canAnswer: true, //是否可以回答
            remainTime: 10, //倒计时剩余时间
            score: [0, 0] //两名选手的分数
        },

        created: function () {
            let that = this;
            this.socket = io.connect('http://localhost:1024');

            //获取选手索引
            this.socket.emit('getPlayerIndex', '')
            this.socket.on('getPlayerIndex', (data) => {
                that.playerIndex = data;
                if (that.playerIndex == 1) {
                    that.socket.emit('getQuestion', that.playerIndex)
                }
            });
            
            //服务端发送问题,更新问题、选项和提示信息
            this.socket.on('sendQueston', (data) => {
                that.canAnswer = true; //拿到问题后,允许回答
                let res = JSON.parse(data);
                that.question = res.content;
                that.options = res.options;
                that.msg = res.msg;
            });

            //服务端发送更新倒计时时间,更新倒计时
            this.socket.on('updateTime', (time) => {
                that.remain_time = time;
            });

            //游戏结束,直接alert
            this.socket.on('gameOver', (text) => {
                alert('游戏结束,' + text);
            });

            //服务端发出获取问题
            this.socket.on('getQuestion', (time) => {
                if (this.playerIndex == 0) {
                    let that = this;
                    //3秒后获取下一题
                    setTimeout(function () {
                        that.socket.emit('getQuestion', this.playerIndex)
                    }, 3000)
                }
            });

            //服务端发送答题结果
            this.socket.on('sendResult', (data) => {
                that.canAnswer = false; //回答后,禁止回答,防止另一名选手点击
                let res = JSON.parse(data);
                that.msg = res.msg;
                that.options = res.options; 
                that.score = res.score;
            });
        },

        methods: {
            //点击选项后的事件
            sendAnswer(index) {
                if (!this.canAnswer) {
                    return false;
                }
                this.socket.emit('sendAnswer', index, this.playerIndex)
            },
        }
    })
</script>

大概长这样,后端的审美,比较不好看
image.png

问题数据的存储方式

我用了redis来保存问题,内容格式如下

{
    "id": 9,
    "content": "9.一年几天",//问题内容
    "options": [  //选项
        "1",
        "2",
        "3",
        "365"
    ],
    "answer_index": 3 //答案的索引
}

选用redis的list格式,顺手自己编几个问题,用php写进去,多编几条,多写几次

$redis = new \Redis();
$redis->connect('127.0.0.1');
$content = ['id' => 1, 'content' => '1.一天有几小时', 'options' => ['1', '2', '3', '48'], 'answer_index' => 3];
$redis->lPush('questions', json_encode($content));

image.png

服务端实现

answerserver.js

const app = require('express')();
const server = require('http').Server(app);
const io = require('socket.io')(server);
const redisModule = require('redis');
const redis = redisModule.createClient(6379, '127.0.0.1');

let playerIndex = 0; //选手索引
let options = []; //选项
let answerIndex = 0; //答案索引
let timer = null; //定时器
let remainTime = 10; //剩余时间
let score = [0, 0]; //得分 ['选手1分数','选手2分数']
let questionCount = 0; //问题数
let startGame = false; //是否已经开始游戏
const maxRemainTime = 10; //最大倒计时秒数

server.listen(1024);

io.on('connection', (socket) => {
    //客户端发送 获取问题
    socket.on('getQuestion', (playerIndex) => {
        if (startGame == false) {
            //首次发送 倒计时开始
            timer = setInterval(() => {
                remainTime--;
                if (remainTime <= 0) {
                    socket.emit('getQuestion', remainTime);
                    remainTime = maxRemainTime;
                }
                socket.emit('updateTime', remainTime);
                socket.broadcast.emit('updateTime', remainTime);

            }, 1000);
            startGame = true;
        }
        //初始化倒计时
        remainTime = maxRemainTime;
        questionCount++;
        redis.lpop('questions', function (err, data) {
            let res = JSON.parse(data);
            let new_options = [];
            answerIndex = res.answer_index;
            res.options.forEach(function (v, k) {
                let o = new Object();
                o.index = v;
                o.class = '' //这里的class供前端使用,为空时,选项是白色背景
                new_options.push(o)
            })
            res.options = new_options;
            options = new_options;
            socket.emit('sendQueston', JSON.stringify(res))
            socket.broadcast.emit('sendQueston', JSON.stringify(res))
        })
    });

    //发送答案结果
    socket.on('sendAnswer', (userSelectIndex, playerIndex) => {
        let result = { msg: '' };
        options.forEach(function (v, k) {
            if (answerIndex == k) {
                //正确的选项 背景改成绿色
                options[k].class = 'correct'
            } else if (k == userSelectIndex && userSelectIndex != answerIndex) {
                //正确的选项 背景改成红色
                result.msg = '选手' + (playerIndex + 1) + '答错了';
                options[k].class = 'wrong'
            }
        })
        //答对的选手+10分
        if (userSelectIndex == answerIndex) {
            score[playerIndex] += 10;
            result.msg = '选手' + (playerIndex + 1) + '答对了';
        }
        result.score = score;
        result.options = options;

        socket.emit('sendResult', JSON.stringify(result));
        socket.emit('getQuestion');
        socket.broadcast.emit('getQuestion');
        socket.broadcast.emit('sendResult', JSON.stringify(result));
        if (questionCount >= 5) {
            let winText = '平局'; //结束时的提示信息
            if (score[0] > score[1]) {
                winText = '选手1获胜'
            } else if (score[0] < score[1]) {
                winText = '选手2获胜'
            }
            socket.emit('gameOver', winText);
            socket.broadcast.emit('gameOver', winText);
            clearInterval(timer);
        }
    });

    //获取选手号数
    socket.on('getPlayerIndex', (data) => {
        socket.emit('getPlayerIndex', playerIndex);
        playerIndex++;
        if (playerIndex >= 2) {
            playerIndex = 0;
        }
    });
});

最终效果

GIF.gif

查看原文

赞 0 收藏 0 评论 0

周晓杰 发布了文章 · 6月1日

用python模拟美团外卖骑手推送请求

项目中接入了美团外卖配送接口,当骑手进行接单、取货等操作时,会将这些操作推送到第三方系统中,在测试环境下,并没有真正的骑手会接单,我们需要模拟正式环境推送的信息,此时就可以用python模拟请求来进行这步操作

所用到的参数
image.png

上代码

#coding=utf-8
#美团配送推送
import requests,hashlib

url = "你自己项目的推送地址"

param = {}
param['app_id'] = 1234 #美团提供的门店app_id
param['dispatcher_mobile'] = '134666666' #骑手手机
param['logistics_status'] = 15 #配送状态码
param['dispatcher_name'] = '小周' #骑手名字
param['order_id'] = '48946XXXXXXXx' #美团外卖订单编号

#排序字段
sort_key = sorted(param.keys(), key=lambda x:x.lower())
screct = '你自己的secret'

str1 = ''
for key in sort_key:
    str1 = str1+key+'='+str(param[key])+'&'

#按照美团接口拼接签名字符串
str1 = url+'?'+str1.rstrip('&') +screct

md5=hashlib.md5() 
md5.update(str1.encode('utf-8'))
#md5加密
res=md5.hexdigest() 
param['sig'] = res

content = requests.post(url,param,headers={"X-Requested-With":"XMLHttpRequest"})
print(content.text)

若推送的是其他URL,将脚本修改url和参数即可
运行代码,OK

查看原文

赞 0 收藏 0 评论 1

周晓杰 发布了文章 · 6月1日

TP5整合阿里云短信

1.安装composer

https://getcomposer.org/downl...
到这里下载composer安装包,安装

2.安装阿里SDK

在TP5项目根目录,打开CMD,运行
composer require alibabacloud/client
image.png

这一步如果安装太慢,打开这个,跟着设置
https://pkg.phpcomposer.com/

等候安装完成

3.生成代码

打开阿里的OpenAPI Explorer

填上你申请到的参数

image.png

把右边代码复制到TP5里

image.png

这里key和secret阿里云短信后台直接获取,
SignName是你在阿里云短信后台申请到的签名的名字
TemplateCode 是你创建短信模板的code,需要在阿里云短信后台获取,申请后需要等待审核

点击这里,按alt+Enter补全命名空间

image.png

大功告成

查看原文

赞 1 收藏 1 评论 0

周晓杰 发布了文章 · 5月28日

用CocosCreator来做一个黄金矿工吧(二)

绳子的拉长与缩短

从Atlas文件夹找到这2个钩子的图片,
按照图片摆放
image.png
左边钩子的锚点anchor设置为1,1,左右钩子的锚点设置为0,1,这里目前没有做动画,后期如果加上了钩子旋转动画,锚点设置好了,旋转中心才正确
因为接下来要用代码延长绳子的长度,我们直接在属性面板调整绳子的高度(Size.H)
image.png
发现钩子没有跟着绳子动,怎么办呢
这时万能的Wiget组件又来了,为钩子添加Widget组件,并设置,数值可以自己调
image.png
再次修改Hook的高度,发现,已经达到我们想要的效果了
image.png

是时候上代码了

在class外面定义好常量

Hook.ts

const { ccclass, property } = cc._decorator;

let ROPE_STATE = cc.Enum({
    ADD: 1, //增加
    REDUCE: 2, //减少
    WAIT: 3 //等待
});


@ccclass
export class Hook extends ...

class内新建属性

ropeSpeed :number = 100; //绳子长度变化速度
ropeOriginalHeight: number; //绳子初始长度

编写绳子长度改变代码

start里获取绳子初始长度,赋值初始状态

start() {
    this.ropeState = ROPE_STATE.WAIT;
    this.ropeOriginalHeight = this.node.height;
}
/**
 * 绳子长度改变 
 */
hookLengthen(deltaTime) {
    //变长时
    if (this.ropeState == ROPE_STATE.ADD) {
        this.node.height += 100 * deltaTime;
    } else if (this.ropeState == ROPE_STATE.REDUCE) {
        //缩短时
        this.node.height -= this.ropeSpeed * deltaTime;
        //当长度小于等于于初始长度
        if (this.node.height <= this.ropeOriginalHeight) {
            //绳子重新开始旋转
            this.isRotating = true;
            //重置各种属性
            this.ropeState = ROPE_STATE.WAIT;
            this.node.height = this.ropeOriginalHeight;
            this.node.angle = 0;
            this.rotateSpeed = 100;
        }
    }
}

同样放进update里

update(deltaTime) {
    this.rotateHook(deltaTime)
    this.hookLengthen(deltaTime);
}

添加屏幕触碰事件控制绳子状态

首先class里定义一个属性

@property(cc.Node)
canvas: cc.Node;

点开Hook的属性面板,将左侧canvas拖进去,这样点击整个屏幕,都可以接受到触摸事件
image.png
start里添加代码

this.canvas.on(cc.Node.EventType.TOUCH_END,this.sendHook.bind(this));
/**
 * 发射钩子
 */
sendHook() {
    this.isRotating = false;
    // 绳子变长中点击,绳子切换到变短状态
    if (this.ropeState == ROPE_STATE.ADD) {
        this.ropeState = ROPE_STATE.REDUCE;
    }
    // 绳子等待中点击,绳子切换到变长状态
    if (this.ropeState == ROPE_STATE.WAIT) {
        this.ropeState = ROPE_STATE.ADD;
    }
}

运行游戏,试试看吧
GIF3.gif

查看原文

赞 0 收藏 0 评论 0

认证与成就

  • 获得 2 次点赞
  • 获得 0 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 0 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 4月10日
个人主页被 424 人浏览