提交 d9496339 编写于 作者: D DCloud_LXH

wip: seach page

上级 53bf8e26
......@@ -64,6 +64,29 @@ const config = {
.plugin('normallize-link')
.use(require('./markdown/normallizeLink'))
}
},
chainWebpack: (config, isServer) => {
console.log('config :>> ', config);
config.devServer.proxy({
'/ext': {
target: 'http://localhost:3000', // 后台api
changeOrigin: true, //是否跨域
secure: false,
// secure: true,
pathRewrite: {
'^/ext': '' //需要rewrite的,
}
},
'/ask': {
target: 'https://ask.dcloud.net.cn', // 后台api
changeOrigin: true, //是否跨域
secure: false,
// secure: true,
pathRewrite: {
'^/ask': '' //需要rewrite的,
}
}
})
}
}
......
......@@ -2,6 +2,7 @@ $svg-color = #b1b2b3
$svg-hover-color = #9b9b9b
#search-container
position relative
overflow auto
position fixed
width 100vw
......@@ -75,6 +76,8 @@ $svg-hover-color = #9b9b9b
line-height 24px
padding 10px 16px
white-space nowrap
/* position absolute
right -65px */
.search-category
.navbar
......@@ -87,8 +90,18 @@ $svg-hover-color = #9b9b9b
width 100%
padding 0
@media (max-width 630px)
&
white-space normal !important
.main-navbar-item
padding 0 6%
@media (max-width 1070px)
&
padding 0 2%
@media (max-width 900px)
&
padding 0 1%
.result-number
display flex
......@@ -132,4 +145,84 @@ $svg-hover-color = #9b9b9b
height 32px !important
.search-result
padding 0 10px
\ No newline at end of file
padding 0 10px
.search-result-aside
display none
#search-container
.search-result-aside
height 100px
position absolute
top 80px
right 100px
.search-result-aside-link
display flex
flex-direction column
justify-content center
align-items flex-start
.markdown-section
margin-top 20px
background-color #fff
padding 10px
.matching-post
$padding-n = 25px
padding $padding-n $padding-n 10px $padding-n
&:not(:last-child)
border-bottom 1px solid #eee
&:first-child
margin-top 0 !important
a
text-decoration none
color inherit
font-weight 400
&:hover
color $accentColor
.post-wrapper
display flex
p.aw-text
margin 0
display inline-flex
p
font-size 14px
overflow hidden
text-overflow ellipsis
display -webkit-box
-webkit-line-clamp 2
-webkit-box-orient vertical
.post-tag
background-color #f0f0f0
font-size 13px
padding 2px 4px
color #999
border-radius 3px
margin-right 5px
.matching-post h2
margin-top 0
padding-top 0
h2
color #2c3e50
font-size 17px
margin 0
padding 0
display inline-block
font-weight 600
border none
.search-keyword
font-style normal
font-weight 700
color $accentColor
\ No newline at end of file
......@@ -42,7 +42,15 @@
<div class="main-navbar-links">
<template v-for="(item, index) in category">
<div :class="mainNavLinkClass(index)" :key="item.text">
<a href="javascript:;" @click="categoryIndex = index">
<MainNavbarLink
:key="item.text"
v-if="item.link"
:item="{
...item,
link: searchLink(item.link),
}"
/>
<a v-else href="javascript:;" @click="switchCategory(index)">
{{ item.text }}
</a>
</div>
......@@ -62,11 +70,19 @@
<div class="search-result">
<div class="result-wrap">
<template v-if="resultList.length">
<template v-if="isAlgolia && resultList.length">
<template v-for="item in resultList">
<Results :key="item.id" :title="item.title" :results="item.items" />
</template>
</template>
<template v-else>
<div
class="markdown-section search-result-list"
v-if="serverHtml"
v-html="serverHtml"
></div>
</template>
</div>
<div v-if="isAlgolia" style="display: flex; justify-content: center; margin: 10px 0 20px">
......@@ -105,8 +121,16 @@
import NavbarLogo from '../NavbarLogo.vue';
import Results from './components/Results.vue';
import pagination from './components/pagination.vue';
import MainNavbarLink from '../MainNavbarLink.vue';
import { search as searchClient } from './searchClient';
import { forbidScroll, removeHighlightTags, debounce, isEditingContent } from '../../util';
import { postExt, postAsk } from './postDcloudServer';
import {
forbidScroll,
removeHighlightTags,
debounce,
isEditingContent,
Base64Encode,
} from '../../util';
const resolveRoutePathFromUrl = (url, base = '/') =>
url
......@@ -120,7 +144,7 @@
props: ['options'],
components: { NavbarLogo, Results, pagination },
components: { NavbarLogo, Results, pagination, MainNavbarLink },
provide() {
return {
......@@ -141,12 +165,29 @@
},
{
text: '问答社区',
tag: 'ask',
type: 'server',
},
{
text: '插件市场',
tag: 'ext',
type: 'server',
},
{
text: 'DCloud 社区',
type: 'link',
link: 'https://ask.dcloud.net.cn/search/q-',
},
{
text: '原生开发文档',
type: 'link',
link: 'https://nativesupport.dcloud.net.cn/?s=',
},
{
text: 'HBuilderX 文档',
type: 'link',
link: 'https://hx.dcloud.net.cn/?s=',
},
]),
categoryIndex: 0,
resultList: [],
......@@ -156,6 +197,8 @@
totalPage: 0, // 搜索结果总共页数
curPage: 1, // 当前页
pageSize: 0, // 每页条数
serverHtml: '',
};
},
......@@ -202,6 +245,10 @@
},
methods: {
searchLink(link) {
return link + (link.includes('ask') ? Base64Encode(this.searchValue) : this.searchValue);
},
resetSearchPage() {
this.searchPage = 0;
},
......@@ -234,7 +281,7 @@
);
break;
case 'server':
console.log('从服务端搜索');
this.searchByServer(this.searchValue);
break;
}
},
......@@ -263,7 +310,29 @@
);
},
searchByServer(query = '') {},
searchByServer(query = '') {
const { tag } = this.currentCategory;
switch (tag) {
case 'ext':
postExt(query).then(({ html, hits }) => {
this.serverHtml = '';
this.serverHtml += html;
this.curHits = hits;
});
break;
case 'ask':
postAsk(query).then(({ html, hits }) => {
this.serverHtml = '';
this.serverHtml += html;
this.curHits = hits;
});
break;
default:
break;
}
},
mainNavLinkClass(index) {
return ['main-navbar-item', this.categoryIndex === index ? 'active' : ''];
......@@ -279,6 +348,11 @@
}
},
switchCategory(index) {
this.categoryIndex = index;
this.research(1);
},
cancel() {
this.resultList.length = 0;
this.searchValue = '';
......@@ -316,6 +390,6 @@
};
</script>
<style lang="stylus" scoped>
<style lang="stylus">
@import './index'
</style>
export default {
ext: {
"ret": 0,
"desc": "ok",
"data": [
{
"id": 7637,
"name": "map高德地图组件升级、离线设置个性化地图、样式文件 (ios、android)",
"version": "1.0.1",
"description": "nvue map 高德地图组件升级、离线个性化地图、离线设置样式文件、可使用nvue map 所有功能、免VIP使用个性化地图 QQ群:656731785",
"tags": "nvue map 高德地图组件升级、离线个性化地图、离线设置样式文件、可使用nvuemap所有功能、免VIP使用个性化地图",
"platforms": [
"Android",
"iOS"
],
"category_level1": "App原生插件",
"category_level2": "App原生插件",
"total_download": 2,
"average_rating": 0,
"support_count": 0,
"tagsArray": [
"nvue",
"map",
"高德地图组件升级、离线个性化地图、离线设置样式文件、可使用nvuemap所有功能、免VIP使用个性化地图"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=7637"
},
{
"id": 7457,
"name": "【猫优壁纸】创作者收益系统、支持抖音、快手、微信、QQ四版本(尊享版)",
"version": "3.6.8.1",
"description": "版本升级来袭带PC后台管理,内置壁纸下载、头像下载、视频下载等超多丰富内容,更有完善的积分系统和订单系统,并且包括QQ小程序、微信小程序、抖音小程序三版本",
"tags": "maoeus-wall-pro 好看的前端UI设计 PC后台管理系统 云开发 完善的积分系统",
"platforms": [
"aliyun",
"tcb"
],
"category_level1": "uniCloud",
"category_level2": "云端一体项目模板",
"total_download": 103,
"average_rating": 0,
"support_count": 0,
"tagsArray": [
"maoeus-wall-pro",
"好看的前端UI设计",
"PC后台管理系统",
"云开发",
"完善的积分系统"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=7457"
},
{
"id": 6998,
"name": "原生sqlite数据库",
"version": "1.0.1",
"description": "原生稳定sqlite数据库增删查改,分页查询,版本升级,事务控制,批量执行",
"tags": "sqlite数据库 增删查改 分页查询版本升级事务控制批量执行",
"platforms": [
"Android",
"iOS"
],
"category_level1": "App原生插件",
"category_level2": "App原生插件",
"total_download": 13,
"average_rating": 5,
"support_count": 0,
"tagsArray": [
"sqlite数据库",
"增删查改",
"分页查询版本升级事务控制批量执行"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=6998"
},
{
"id": 6139,
"name": "【猫优壁纸】创作者收益系统、支持抖音、微信、QQ三版本(运营版)",
"version": "3.6.8",
"description": "版本升级来袭带PC后台管理,内置壁纸下载、头像下载、视频下载等超多丰富内容,更有完善的积分系统和订单系统,并且包括QQ小程序、微信小程序、抖音小程序三版本",
"tags": "maoeus-wallpaper 好看的前端UI设计 PC后台管理系统 云开发 完善的积分系统",
"platforms": [
"aliyun",
"tcb"
],
"category_level1": "uniCloud",
"category_level2": "云端一体项目模板",
"total_download": 482,
"average_rating": 4.5,
"support_count": 0,
"tagsArray": [
"maoeus-wallpaper",
"好看的前端UI设计",
"PC后台管理系统",
"云开发",
"完善的积分系统"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=6139"
},
{
"id": 7453,
"name": "【猫优壁纸】单系统、积分系统、壁纸、头像、视频、表情包下载(基础版)",
"version": "3.6.6.3",
"description": "版本升级来袭带PC后台管理,内置壁纸下载、头像下载、视频下载等超多丰富内容,更有完善的积分系统和订单系统,并且包括QQ小程序、微信小程序、抖音小程序三版本",
"tags": "maoeus-wall-base 好看的前端UI设计 PC后台管理系统 云开发 完善的积分系统",
"platforms": [
"aliyun",
"tcb"
],
"category_level1": "uniCloud",
"category_level2": "云端一体项目模板",
"total_download": 35,
"average_rating": 0,
"support_count": 0,
"tagsArray": [
"maoeus-wall-base",
"好看的前端UI设计",
"PC后台管理系统",
"云开发",
"完善的积分系统"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=7453"
},
{
"id": 3243,
"name": "app更新升级-wgt包热更新-整包更新-遮盖原生导航及tabbar ",
"version": "1.2.0",
"description": "请求接口返回ios及Android线上版本信息,再与本机app版本对比,如需更新则弹出更新提示框-支持外部链接、整包、热更新,",
"tags": "更新 热更新 app 不支持NVUE APP升级",
"platforms": [],
"category_level1": "前端组件",
"category_level2": "通用组件",
"total_download": 2997,
"average_rating": 4.7,
"support_count": 3,
"tagsArray": [
"更新",
"热更新",
"app",
"不支持NVUE",
"APP升级"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=3243"
},
{
"id": 5579,
"name": "腾讯Bugly插件",
"version": "1.0.4",
"description": "腾讯Bugly插件,APP检查应用版本升级、运营统计、主动上报异常,bug奔溃闪退日志、设置用户ID、用户标签",
"tags": "腾讯Bugly bugly 版本升级 运营统计 bug奔溃闪退日志收集",
"platforms": [
"Android",
"iOS"
],
"category_level1": "App原生插件",
"category_level2": "App原生插件",
"total_download": 49,
"average_rating": 2.3,
"support_count": 0,
"tagsArray": [
"腾讯Bugly",
"bugly",
"版本升级",
"运营统计",
"bug奔溃闪退日志收集"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=5579"
},
{
"id": 7238,
"name": "腾讯bugly服务插件",
"version": "1.0.1",
"description": "一键接入接入bugly服务",
"tags": "bugly 升级",
"platforms": [
"Android"
],
"category_level1": "App原生插件",
"category_level2": "App原生插件",
"total_download": 4,
"average_rating": 0,
"support_count": 0,
"tagsArray": [
"bugly",
"升级"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=7238"
},
{
"id": 1371,
"name": "app版本升级原生弹框和进度提示(包含wgt升级)",
"version": "1.48",
"description": "app版本升级(包含热更新)弹框提示和进度显示,apk自动安装",
"tags": "版本升级 进度提示 app自动安装 弹框提示 wgt升级",
"platforms": [
"Android",
"iOS"
],
"category_level1": "App原生插件",
"category_level2": "App原生插件",
"total_download": 4967,
"average_rating": 4.9,
"support_count": 1,
"tagsArray": [
"版本升级",
"进度提示",
"app自动安装",
"弹框提示",
"wgt升级"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=1371"
},
{
"id": 4542,
"name": "升级中心 uni-upgrade-center - App",
"version": "0.3.2",
"description": "uni升级中心 - 客户端检查更新",
"tags": "uniCloud update 升级 wgt",
"platforms": [
"aliyun",
"tcb"
],
"category_level1": "uniCloud",
"category_level2": "云端一体页面模板",
"total_download": 11374,
"average_rating": 4.8,
"support_count": 3,
"tagsArray": [
"uniCloud",
"update",
"升级",
"wgt"
],
"android_abis": [],
"url": "https://ext.dcloud.net.cn/plugin?id=4542"
}
]
},
ask: {
"code": 0,
"data": [
{
"url": "//ask.dcloud.net.cn/article/182",
"title": "App资源在线升级更新",
"content": " ... &amp;amp;&amp;amp;(wgtVer!=newVer)){\n\t\t\t\t\tdownWgt();\t// 下载&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;包\n\t\t\t\t}else{\n\t\t\t\t\tplus.nativeUI.alert(&amp;quot;无 ... ",
"type": "articles",
"comment_count": "212",
"view_count": "260871"
},
{
"url": "//ask.dcloud.net.cn/article/199",
"title": "App资源在线差量升级更新",
"content": " ... wgtu | 根节点 | | | |\t\n| appid | wgtu | 属性 | &lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;应用的appid | 是 |\n| basis | wgtu ... ",
"type": "articles",
"comment_count": "83",
"view_count": "76496"
},
{
"url": "//ask.dcloud.net.cn/article/17",
"title": "HBuilder升级失败或长时间无响应?",
"content": "如果装过其他eclipse插件,其&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;服务器可能连不上而导致报错。\n此时在工具-插件安装-手动安装eclipse插件-可用软件站点,取消其他插件的&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;地址。\n重新点击帮助-检查新版本即可。",
"type": "articles",
"comment_count": 0,
"view_count": "2500"
},
{
"url": "//ask.dcloud.net.cn/article/266",
"title": "增量升级",
"content": " ... ask.dcloud.net.cn/question/3388)\n\n**增量&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;的问题**\n增量、差量&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt; ... 。但是在使用H5 的增量&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;的时候遇到一个问题。 ... 是:\n当APP启动是出现&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;页面,用户点击增量 ... ",
"type": "articles",
"comment_count": "5",
"view_count": "3090"
},
{
"url": "//ask.dcloud.net.cn/article/273",
"title": "请Mac版用户近期不要升级MacOS 10.11beta3及10.11公测版",
"content": " ... 近期发布的公测版上,HBuilder也无法启动。\n**请大家近期不要&lt;span style='font-weight:bold;color:red'&gt;升级&lt;/span&gt;Mac 10.11beta3及10.11公测版,并等待苹果修复bug**\n详情 ... ",
"type": "articles",
"comment_count": "9",
"view_count": "3054"
}
],
"searchKeyword": "5Y2H57qn"
}
}
\ No newline at end of file
const xhr = new XMLHttpRequest();
const isProduction = process.env.NODE_ENV === "production"
const isMock = false
import mock from './mock'
function ajax(url = '', method = 'get',) {
return new Promise((resolve, reject) => {
if (!url) reject('url 不可为空')
xhr.open(method, url);
xhr.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
console.log('this :>> ', this);
}
}
xhr.send()
})
}
export async function postExt(query) {
const base = isProduction ? '//ext.dcloud.net.cn' : '/ext'
let extRet
if (!isMock) {
const extRes = await ajax(base + '/search/json?query=' + encodeURIComponent(query))
extRet = JSON.parse(extRes);
} else {
extRet = mock.ext;
}
let extHtml = '';
let data = extRet.data;
if (extRet.ret === 0) {
for (let i = 0, len = data.length; i < len; i++) {
extHtml += _renderExt(data[i], query);
}
}
return {
html: extHtml,
hits: data.length
}
}
export async function postAsk(query) {
const base = isProduction ? '//ask.dcloud.net.cn' : '/ask'
let ret
if (!isMock) {
const res = await ajax(base + '/search/ajax/search_result/search_type-doc__q-' + query + '__page-1')
if (!res) {
return;
}
ret = JSON.parse(res);
} else {
ret = mock.ask
}
if (ret.code !== 0) {
checkEmpty()
return;
}
var data = ret.data;
var askHtml = '';
data.forEach(function (item) {
askHtml += _renderPost(item, query);
});
return {
html: askHtml,
hits: data.length
}
}
function _renderExt(ext, keyword) {
return `<div class="matching-post">
<a href="${ext.url}" target="_blank">
<div class="post-wrapper">
<p class="aw-text">
<span class="post-tag">插件</span>
</p>
<h2>${_handleHTMLString(ext.name, keyword)}</h2>
</div>
<p>${ext.total_download}次下载</p>
<p>${_handleHTMLString(ext.description, keyword)}</p>
</a>
</div>`
}
function _renderPost(post, value) {
var html = '';
var commentText = '';
var tagName = '规范';
// 1,问题;2,文章;默认是规范。
switch (post.type) {
case 'questions':
tagName = '问题';
break;
case 'articles':
tagName = '文章';
break;
}
if (!!value) {
post.title = _handleHTMLString(post.title, value);
post.content = _handleHTMLString(post.content, value);
}
html += `<div class="matching-post">
<a href="${post.url}" target="_blank"><div class="post-wrapper">
<p class="aw-text"><span class="post-tag">${tagName}</span></p>
<h2>${post.title}</h2></div>`
/* html += '<div class="matching-post">\n';
html += `<a href="${post.url}" target="_blank"><div class="post-wrapper">`;
html += `<p class="aw-text"><span class="post-tag">${tagName}</span></p>`
html += `\n<h2>${post.title}</h2></div>`; */
if (!!value) {
commentText = post.type === 'questions' ? '回复' : '评论';
html += `<p>${post.comment_count}${commentText}<span class="aw-text-space">-</span>${post.view_count}次浏览</p>`;
}
html += `\n<p>${post.content}</p>\n</a>\n</div>`;
return html;
}
function _handleHTMLString(dataString, keyword) {
var keywordReg = new RegExp(
keyword.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&'),
'gi'
);
var tagStartReg = new RegExp(
'&lt;span style=\'font-weight:bold;color:red\'&gt;',
'g'
);
var tagEndReg = new RegExp(
'&lt;/span&gt;',
'g'
);
return dataString
.replace(tagStartReg, '')
.replace(tagEndReg, '')
.replace(keywordReg, ("<em class=\"search-keyword\">" + keyword + "</em>"));
};
\ No newline at end of file
var validBitList = [
[7],
[5, 6],
[4, 6, 6],
[3, 6, 6, 6],
[2, 6, 6, 6, 6],
[1, 6, 6, 6, 6, 6]
]
var otherByteBase = 1 << 7
var b64Info = new Array(6)
for (var i = 0; i < validBitList.length; i++) {
var validBit = validBitList[i]
var firstByteBase
if (i === 0) {
firstByteBase = 0
}
var fillLength = validBit[0] + 1
firstByteBase = 255 >> fillLength << fillLength
b64Info[i] = {
validBit,
firstByteBase,
otherByteBase,
maxValue: Math.pow(2, sum(validBit)) - 1 // 移位会溢出,使用Math.pow计算
}
}
function sum(arr) {
return arr.reduce(function (total, value) {
return total + value
}, 0)
}
function Encoder() {
this.remainder = 0
this.remainderBit = 0
this.utf8ArrLength = 0
this.result = ''
}
Encoder.prototype.push = function (utf8Code) {
this.utf8ArrLength++
var remainderMoveBit = (6 - this.remainderBit)
this.remainderBit = 8 - remainderMoveBit
var b64Value1 = this.remainder << remainderMoveBit
var b64Value2 = utf8Code >> this.remainderBit
var b64Value = b64Value1 + b64Value2
this.remainder = utf8Code - (b64Value2 << this.remainderBit)
this.result += b64CodeToString(b64Value)
if (this.remainderBit === 6) {
this.result += b64CodeToString(this.remainder)
this.remainder = 0
this.remainderBit = 0
}
}
Encoder.prototype.flush = function () {
if (this.remainderBit) {
var b64Value = this.remainder << (6 - this.remainderBit)
this.result += b64CodeToString(b64Value)
}
var eqLength = (3 - (this.utf8ArrLength % 3)) % 3
this.result += '='.repeat(eqLength)
}
function charCodeToUtf8(code) {
var lengthIndex
for (var i = 0; i < b64Info.length; i++) {
var maxValue = b64Info[i].maxValue;
if (code <= maxValue) {
lengthIndex = i
break;
}
}
if (lengthIndex === undefined) {
throw new Error('invalid char code')
}
var {
validBit,
firstByteBase,
otherByteBase,
} = b64Info[lengthIndex]
var result = []
for (var i = validBit.length - 1; i >= 0; i--) {
var base = i === 0 ? firstByteBase : otherByteBase
var tempCode = code >>> validBit[i]
result.unshift(base + code - (tempCode << validBit[i]))
code = tempCode
}
return result
}
export function Base64Encode(str) {
// 一次循环计算出结果,减少内存占用
var encoder = new Encoder()
for (var i = 0; i < str.length; i++) {
var charCode = str.charCodeAt(i);
var utf8Arr = charCodeToUtf8(charCode)
utf8Arr.forEach(function (item) {
encoder.push(item)
});
}
encoder.flush()
return encoder.result
}
function b64CodeToString(code) {
return String.fromCharCode(uint6ToB64(code))
}
/**
* 将base64 code转换为字符对应的char code
*/
function uint6ToB64(nUint6) {
return nUint6 < 26 ?
nUint6 + 65 :
nUint6 < 52 ?
nUint6 + 71 :
nUint6 < 62 ?
nUint6 - 4 :
nUint6 === 62 ?
43 :
nUint6 === 63 ?
47 :
65;
}
\ No newline at end of file
import Vue from 'vue';
export * from './searchUtils';
export * from './base64Encode';
export const isServer = Vue.prototype.$isServer
export const hashRE = /#.*$/
......@@ -291,7 +292,7 @@ export const BaiduStat = () => {
s.parentNode.insertBefore(hm, s);
}
export function debounce (fn, delay) {
export function debounce(fn, delay) {
let timeout
const newFn = function () {
clearTimeout(timeout)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册