提交 c50973c7 编写于 作者: fxy060608's avatar fxy060608

wip(mp): export onLoad

上级 eda4ef45
...@@ -4892,7 +4892,7 @@ var serviceContext = (function (vue) { ...@@ -4892,7 +4892,7 @@ var serviceContext = (function (vue) {
return 'param extension should not be empty.'; return 'param extension should not be empty.';
} }
if (!extension) if (!extension)
params.extension = ['']; params.extension = ['*'];
}, },
}, },
}; };
......
...@@ -18,6 +18,8 @@ const ON_ERROR = 'onError'; ...@@ -18,6 +18,8 @@ const ON_ERROR = 'onError';
const ON_THEME_CHANGE = 'onThemeChange'; const ON_THEME_CHANGE = 'onThemeChange';
const ON_PAGE_NOT_FOUND = 'onPageNotFound'; const ON_PAGE_NOT_FOUND = 'onPageNotFound';
const ON_UNHANDLE_REJECTION = 'onUnhandledRejection'; const ON_UNHANDLE_REJECTION = 'onUnhandledRejection';
//Page
const ON_LOAD = 'onLoad';
const ON_READY = 'onReady'; const ON_READY = 'onReady';
const ON_UNLOAD = 'onUnload'; const ON_UNLOAD = 'onUnload';
const ON_RESIZE = 'onResize'; const ON_RESIZE = 'onResize';
...@@ -118,7 +120,8 @@ const onError = /*#__PURE__*/ createHook(ON_ERROR); ...@@ -118,7 +120,8 @@ const onError = /*#__PURE__*/ createHook(ON_ERROR);
const onThemeChange = /*#__PURE__*/ createHook(ON_THEME_CHANGE); const onThemeChange = /*#__PURE__*/ createHook(ON_THEME_CHANGE);
const onPageNotFound = /*#__PURE__*/ createHook(ON_PAGE_NOT_FOUND); const onPageNotFound = /*#__PURE__*/ createHook(ON_PAGE_NOT_FOUND);
const onUnhandledRejection = /*#__PURE__*/ createHook(ON_UNHANDLE_REJECTION); const onUnhandledRejection = /*#__PURE__*/ createHook(ON_UNHANDLE_REJECTION);
// 小程序如果想在 setup 的 props 传递页面参数,需要定义 props,故同时暴露 onLoad 吧
const onLoad = /*#__PURE__*/ createHook(ON_LOAD);
const onReady = /*#__PURE__*/ createHook(ON_READY); const onReady = /*#__PURE__*/ createHook(ON_READY);
const onUnload = /*#__PURE__*/ createHook(ON_UNLOAD); const onUnload = /*#__PURE__*/ createHook(ON_UNLOAD);
const onResize = /*#__PURE__*/ createHook(ON_RESIZE); const onResize = /*#__PURE__*/ createHook(ON_RESIZE);
...@@ -142,6 +145,7 @@ exports.onBackPress = onBackPress; ...@@ -142,6 +145,7 @@ exports.onBackPress = onBackPress;
exports.onError = onError; exports.onError = onError;
exports.onHide = onHide; exports.onHide = onHide;
exports.onLaunch = onLaunch; exports.onLaunch = onLaunch;
exports.onLoad = onLoad;
exports.onNavigationBarButtonTap = onNavigationBarButtonTap; exports.onNavigationBarButtonTap = onNavigationBarButtonTap;
exports.onNavigationBarSearchInputChanged = onNavigationBarSearchInputChanged; exports.onNavigationBarSearchInputChanged = onNavigationBarSearchInputChanged;
exports.onNavigationBarSearchInputClicked = onNavigationBarSearchInputClicked; exports.onNavigationBarSearchInputClicked = onNavigationBarSearchInputClicked;
......
...@@ -14,6 +14,8 @@ export declare const onHide: (hook: () => any, target?: ComponentInternalInstanc ...@@ -14,6 +14,8 @@ export declare const onHide: (hook: () => any, target?: ComponentInternalInstanc
export declare const onLaunch: (hook: () => any, target?: ComponentInternalInstance | null) => any; export declare const onLaunch: (hook: () => any, target?: ComponentInternalInstance | null) => any;
export declare const onLoad: (hook: () => any, target?: ComponentInternalInstance | null) => any;
export declare const onNavigationBarButtonTap: (hook: () => any, target?: ComponentInternalInstance | null) => any; export declare const onNavigationBarButtonTap: (hook: () => any, target?: ComponentInternalInstance | null) => any;
export declare const onNavigationBarSearchInputChanged: (hook: () => any, target?: ComponentInternalInstance | null) => any; export declare const onNavigationBarSearchInputChanged: (hook: () => any, target?: ComponentInternalInstance | null) => any;
......
...@@ -15,6 +15,8 @@ const ON_ERROR = 'onError'; ...@@ -15,6 +15,8 @@ const ON_ERROR = 'onError';
const ON_THEME_CHANGE = 'onThemeChange'; const ON_THEME_CHANGE = 'onThemeChange';
const ON_PAGE_NOT_FOUND = 'onPageNotFound'; const ON_PAGE_NOT_FOUND = 'onPageNotFound';
const ON_UNHANDLE_REJECTION = 'onUnhandledRejection'; const ON_UNHANDLE_REJECTION = 'onUnhandledRejection';
//Page
const ON_LOAD = 'onLoad';
const ON_READY = 'onReady'; const ON_READY = 'onReady';
const ON_UNLOAD = 'onUnload'; const ON_UNLOAD = 'onUnload';
const ON_RESIZE = 'onResize'; const ON_RESIZE = 'onResize';
...@@ -87,7 +89,8 @@ const onError = /*#__PURE__*/ createHook(ON_ERROR); ...@@ -87,7 +89,8 @@ const onError = /*#__PURE__*/ createHook(ON_ERROR);
const onThemeChange = /*#__PURE__*/ createHook(ON_THEME_CHANGE); const onThemeChange = /*#__PURE__*/ createHook(ON_THEME_CHANGE);
const onPageNotFound = /*#__PURE__*/ createHook(ON_PAGE_NOT_FOUND); const onPageNotFound = /*#__PURE__*/ createHook(ON_PAGE_NOT_FOUND);
const onUnhandledRejection = /*#__PURE__*/ createHook(ON_UNHANDLE_REJECTION); const onUnhandledRejection = /*#__PURE__*/ createHook(ON_UNHANDLE_REJECTION);
// 小程序如果想在 setup 的 props 传递页面参数,需要定义 props,故同时暴露 onLoad 吧
const onLoad = /*#__PURE__*/ createHook(ON_LOAD);
const onReady = /*#__PURE__*/ createHook(ON_READY); const onReady = /*#__PURE__*/ createHook(ON_READY);
const onUnload = /*#__PURE__*/ createHook(ON_UNLOAD); const onUnload = /*#__PURE__*/ createHook(ON_UNLOAD);
const onResize = /*#__PURE__*/ createHook(ON_RESIZE); const onResize = /*#__PURE__*/ createHook(ON_RESIZE);
...@@ -105,4 +108,4 @@ const onNavigationBarSearchInputClicked = /*#__PURE__*/ createHook(ON_NAVIGATION ...@@ -105,4 +108,4 @@ const onNavigationBarSearchInputClicked = /*#__PURE__*/ createHook(ON_NAVIGATION
const onNavigationBarSearchInputConfirmed = /*#__PURE__*/ createHook(ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED); const onNavigationBarSearchInputConfirmed = /*#__PURE__*/ createHook(ON_NAVIGATION_BAR_SEARCH_INPUT_CONFIRMED);
const onNavigationBarSearchInputFocusChanged = /*#__PURE__*/ createHook(ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED); const onNavigationBarSearchInputFocusChanged = /*#__PURE__*/ createHook(ON_NAVIGATION_BAR_SEARCH_INPUT_FOCUS_CHANGED);
export { getSsrGlobalData, onAddToFavorites, onBackPress, onError, onHide, onLaunch, onNavigationBarButtonTap, onNavigationBarSearchInputChanged, onNavigationBarSearchInputClicked, onNavigationBarSearchInputConfirmed, onNavigationBarSearchInputFocusChanged, onPageNotFound, onPageScroll, onPullDownRefresh, onReachBottom, onReady, onResize, onShareAppMessage, onShareTimeline, onShow, onTabItemTap, onThemeChange, onUnhandledRejection, onUnload, resolveEasycom, shallowSsrRef, ssrRef }; export { getSsrGlobalData, onAddToFavorites, onBackPress, onError, onHide, onLaunch, onLoad, onNavigationBarButtonTap, onNavigationBarSearchInputChanged, onNavigationBarSearchInputClicked, onNavigationBarSearchInputConfirmed, onNavigationBarSearchInputFocusChanged, onPageNotFound, onPageScroll, onPullDownRefresh, onReachBottom, onReady, onResize, onShareAppMessage, onShareTimeline, onShow, onTabItemTap, onThemeChange, onUnhandledRejection, onUnload, resolveEasycom, shallowSsrRef, ssrRef };
...@@ -8,6 +8,7 @@ import { ...@@ -8,6 +8,7 @@ import {
ON_ERROR, ON_ERROR,
ON_HIDE, ON_HIDE,
ON_LAUNCH, ON_LAUNCH,
ON_LOAD,
ON_NAVIGATION_BAR_BUTTON_TAP, ON_NAVIGATION_BAR_BUTTON_TAP,
ON_NAVIGATION_BAR_SEARCH_INPUT_CHANGED, ON_NAVIGATION_BAR_SEARCH_INPUT_CHANGED,
ON_NAVIGATION_BAR_SEARCH_INPUT_CLICKED, ON_NAVIGATION_BAR_SEARCH_INPUT_CLICKED,
...@@ -47,8 +48,8 @@ export const onPageNotFound = /*#__PURE__*/ createHook(ON_PAGE_NOT_FOUND) ...@@ -47,8 +48,8 @@ export const onPageNotFound = /*#__PURE__*/ createHook(ON_PAGE_NOT_FOUND)
export const onUnhandledRejection = /*#__PURE__*/ createHook( export const onUnhandledRejection = /*#__PURE__*/ createHook(
ON_UNHANDLE_REJECTION ON_UNHANDLE_REJECTION
) )
// 小程序如果想在 setup 的 props 传递页面参数,需要定义 props,故同时暴露 onLoad 吧
// export const onLoad = /*#__PURE__*/ createHook(ON_LOAD) export const onLoad = /*#__PURE__*/ createHook(ON_LOAD)
export const onReady = /*#__PURE__*/ createHook(ON_READY) export const onReady = /*#__PURE__*/ createHook(ON_READY)
export const onUnload = /*#__PURE__*/ createHook(ON_UNLOAD) export const onUnload = /*#__PURE__*/ createHook(ON_UNLOAD)
......
...@@ -4,8 +4,12 @@ import { parseManifestJsonOnce } from '../json' ...@@ -4,8 +4,12 @@ import { parseManifestJsonOnce } from '../json'
export function initDefine(stringifyBoolean: boolean = false) { export function initDefine(stringifyBoolean: boolean = false) {
const manifestJson = parseManifestJsonOnce(process.env.UNI_INPUT_DIR) const manifestJson = parseManifestJsonOnce(process.env.UNI_INPUT_DIR)
const isRunByHBuilderX = runByHBuilderX() const isRunByHBuilderX = runByHBuilderX()
const isDebug = !!manifestJson.debug
return { return {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV), 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.UNI_DEBUG': stringifyBoolean
? JSON.stringify(isDebug)
: isDebug,
'process.env.UNI_APP_ID': JSON.stringify(manifestJson.appid || ''), 'process.env.UNI_APP_ID': JSON.stringify(manifestJson.appid || ''),
'process.env.UNI_APP_NAME': JSON.stringify(manifestJson.name || ''), 'process.env.UNI_APP_NAME': JSON.stringify(manifestJson.name || ''),
'process.env.UNI_PLATFORM': JSON.stringify(process.env.UNI_PLATFORM), 'process.env.UNI_PLATFORM': JSON.stringify(process.env.UNI_PLATFORM),
......
...@@ -4627,7 +4627,7 @@ const ChooseImageOptions = { ...@@ -4627,7 +4627,7 @@ const ChooseImageOptions = {
return "param extension should not be empty."; return "param extension should not be empty.";
} }
if (!extension) if (!extension)
params.extension = [""]; params.extension = ["*"];
} }
} }
}; };
......
...@@ -764,11 +764,12 @@ function initLifetimes({ mocks, isPage, initRelation, vueOptions, }) { ...@@ -764,11 +764,12 @@ function initLifetimes({ mocks, isPage, initRelation, vueOptions, }) {
initRelation(this, relationOptions); initRelation(this, relationOptions);
// 初始化 vue 实例 // 初始化 vue 实例
const mpInstance = this; const mpInstance = this;
const isMiniProgramPage = isPage(mpInstance);
this.$vm = $createComponent({ this.$vm = $createComponent({
type: vueOptions, type: vueOptions,
props: properties, props: properties,
}, { }, {
mpType: isPage(mpInstance) ? 'page' : 'component', mpType: isMiniProgramPage ? 'page' : 'component',
mpInstance, mpInstance,
slots: properties.vS, slots: properties.vS,
parentComponent: relationOptions.parent && relationOptions.parent.$, parentComponent: relationOptions.parent && relationOptions.parent.$,
......
...@@ -710,11 +710,12 @@ function initLifetimes({ mocks, isPage, initRelation, vueOptions, }) { ...@@ -710,11 +710,12 @@ function initLifetimes({ mocks, isPage, initRelation, vueOptions, }) {
initRelation(this, relationOptions); initRelation(this, relationOptions);
// 初始化 vue 实例 // 初始化 vue 实例
const mpInstance = this; const mpInstance = this;
const isMiniProgramPage = isPage(mpInstance);
this.$vm = $createComponent({ this.$vm = $createComponent({
type: vueOptions, type: vueOptions,
props: properties, props: properties,
}, { }, {
mpType: isPage(mpInstance) ? 'page' : 'component', mpType: isMiniProgramPage ? 'page' : 'component',
mpInstance, mpInstance,
slots: properties.vS, slots: properties.vS,
parentComponent: relationOptions.parent && relationOptions.parent.$, parentComponent: relationOptions.parent && relationOptions.parent.$,
......
{ [
"input": { {
"src/runtime/index.ts": "dist/uni.mp.esm.js", "input": {
"src/api/index.ts": "dist/uni.api.esm.js" "src/plugin/index.ts": "dist/uni.compiler.js"
},
"output": {
"format": "cjs"
},
"external": ["@dcloudio/uni-cli-shared", "@dcloudio/uni-mp-vite"]
}, },
"alias": { {
"entries": [ "input": {
{ "src/runtime/index.ts": "dist/uni.mp.esm.js",
"find": "@dcloudio/uni-platform", "src/api/index.ts": "dist/uni.api.esm.js"
"replacement": "packages/uni-mp-qq/src/platform/index.ts" },
}, "alias": {
{ "entries": [
"find": "@dcloudio/uni-mp-platform", {
"replacement": "packages/uni-mp-core/src/platform/index.ts" "find": "@dcloudio/uni-platform",
} "replacement": "packages/uni-mp-qq/src/platform/index.ts"
] },
}, {
"replacements": { "find": "@dcloudio/uni-mp-platform",
"__GLOBAL__": "qq", "replacement": "packages/uni-mp-core/src/platform/index.ts"
"__PLATFORM__": "\"mp-qq\"", }
"__PLATFORM_TITLE__": "QQ小程序" ]
}, },
"external": ["@dcloudio/uni-i18n", "@vue/shared", "vue"] "replacements": {
} "__GLOBAL__": "qq",
"__PLATFORM__": "\"mp-qq\"",
"__PLATFORM_TITLE__": "QQ小程序"
},
"external": ["@dcloudio/uni-i18n", "@vue/shared", "vue"]
}
]
...@@ -710,11 +710,12 @@ function initLifetimes({ mocks, isPage, initRelation, vueOptions, }) { ...@@ -710,11 +710,12 @@ function initLifetimes({ mocks, isPage, initRelation, vueOptions, }) {
initRelation(this, relationOptions); initRelation(this, relationOptions);
// 初始化 vue 实例 // 初始化 vue 实例
const mpInstance = this; const mpInstance = this;
const isMiniProgramPage = isPage(mpInstance);
this.$vm = $createComponent({ this.$vm = $createComponent({
type: vueOptions, type: vueOptions,
props: properties, props: properties,
}, { }, {
mpType: isPage(mpInstance) ? 'page' : 'component', mpType: isMiniProgramPage ? 'page' : 'component',
mpInstance, mpInstance,
slots: properties.vS, slots: properties.vS,
parentComponent: relationOptions.parent && relationOptions.parent.$, parentComponent: relationOptions.parent && relationOptions.parent.$,
......
...@@ -4291,7 +4291,7 @@ const version = "3.2.20"; ...@@ -4291,7 +4291,7 @@ const version = "3.2.20";
const resolveFilter = null; const resolveFilter = null;
function unwrapper(target) { function unwrapper(target) {
return toRaw(unref(target)); return unref(target);
} }
// import deepCopy from './deepCopy' // import deepCopy from './deepCopy'
/** /**
...@@ -4486,10 +4486,11 @@ function patch(instance, data, oldData) { ...@@ -4486,10 +4486,11 @@ function patch(instance, data, oldData) {
if (!data) { if (!data) {
return; return;
} }
// 通常不用序列化,但是好像部分边界情况需要,目前还未排查到 // TODO 微信小程序会对 props 序列化,目前通过序列化再次触发数据响应式收集,因为 render 中收集的数据可能不全面(也不能仅仅这里收集,render 中也要收集),导致子组件无法局部响应式更新
// pauseTracking() // 举例:
// data = JSON.parse(JSON.stringify(data)) // uni-indexed-list 组件传递 item 给 uni-indexed-list-item 组件,uni-indexed-list-item 发送点击到 uni-indexed-list 组件中修改 item.checked
// resetTracking() // uni-indexed-list 组件 render 中并未访问 item.checked(在 uni-indexed-list-item 中访问了,但被小程序序列化了,无法响应式),故无法收集依赖
data = JSON.parse(JSON.stringify(data));
const ctx = instance.ctx; const ctx = instance.ctx;
const mpType = ctx.mpType; const mpType = ctx.mpType;
if (mpType === 'page' || mpType === 'component') { if (mpType === 'page' || mpType === 'component') {
...@@ -4498,19 +4499,19 @@ function patch(instance, data, oldData) { ...@@ -4498,19 +4499,19 @@ function patch(instance, data, oldData) {
const mpInstance = ctx.$scope; const mpInstance = ctx.$scope;
const keys = Object.keys(data); const keys = Object.keys(data);
// data.__webviewId__ = mpInstance.data.__webviewId__ // data.__webviewId__ = mpInstance.data.__webviewId__
pauseTracking();
const diffData = diff(data, oldData || getMPInstanceData(mpInstance, keys)); const diffData = diff(data, oldData || getMPInstanceData(mpInstance, keys));
resetTracking();
if (Object.keys(diffData).length) { if (Object.keys(diffData).length) {
console.log('[' + if (process.env.UNI_DEBUG) {
+new Date() + console.log('[' +
'][' + +new Date() +
(mpInstance.is || mpInstance.route) + '][' +
'][' + (mpInstance.is || mpInstance.route) +
instance.uid + '][' +
'][耗时' + instance.uid +
(Date.now() - start) + '][耗时' +
']差量更新', JSON.stringify(diffData)); (Date.now() - start) +
']差量更新', JSON.stringify(diffData));
}
ctx.__next_tick_pending = true; ctx.__next_tick_pending = true;
mpInstance.setData(diffData, () => { mpInstance.setData(diffData, () => {
ctx.__next_tick_pending = false; ctx.__next_tick_pending = false;
......
...@@ -4291,7 +4291,7 @@ const version = "3.2.20"; ...@@ -4291,7 +4291,7 @@ const version = "3.2.20";
const resolveFilter = null; const resolveFilter = null;
function unwrapper(target) { function unwrapper(target) {
return toRaw(unref(target)); return unref(target);
} }
// import deepCopy from './deepCopy' // import deepCopy from './deepCopy'
/** /**
...@@ -4486,10 +4486,11 @@ function patch(instance, data, oldData) { ...@@ -4486,10 +4486,11 @@ function patch(instance, data, oldData) {
if (!data) { if (!data) {
return; return;
} }
// 通常不用序列化,但是好像部分边界情况需要,目前还未排查到 // TODO 微信小程序会对 props 序列化,目前通过序列化再次触发数据响应式收集,因为 render 中收集的数据可能不全面(也不能仅仅这里收集,render 中也要收集),导致子组件无法局部响应式更新
// pauseTracking() // 举例:
// data = JSON.parse(JSON.stringify(data)) // uni-indexed-list 组件传递 item 给 uni-indexed-list-item 组件,uni-indexed-list-item 发送点击到 uni-indexed-list 组件中修改 item.checked
// resetTracking() // uni-indexed-list 组件 render 中并未访问 item.checked(在 uni-indexed-list-item 中访问了,但被小程序序列化了,无法响应式),故无法收集依赖
data = JSON.parse(JSON.stringify(data));
const ctx = instance.ctx; const ctx = instance.ctx;
const mpType = ctx.mpType; const mpType = ctx.mpType;
if (mpType === 'page' || mpType === 'component') { if (mpType === 'page' || mpType === 'component') {
...@@ -4498,19 +4499,19 @@ function patch(instance, data, oldData) { ...@@ -4498,19 +4499,19 @@ function patch(instance, data, oldData) {
const mpInstance = ctx.$scope; const mpInstance = ctx.$scope;
const keys = Object.keys(data); const keys = Object.keys(data);
// data.__webviewId__ = mpInstance.data.__webviewId__ // data.__webviewId__ = mpInstance.data.__webviewId__
pauseTracking();
const diffData = diff(data, oldData || getMPInstanceData(mpInstance, keys)); const diffData = diff(data, oldData || getMPInstanceData(mpInstance, keys));
resetTracking();
if (Object.keys(diffData).length) { if (Object.keys(diffData).length) {
console.log('[' + if (process.env.UNI_DEBUG) {
+new Date() + console.log('[' +
'][' + +new Date() +
(mpInstance.is || mpInstance.route) + '][' +
'][' + (mpInstance.is || mpInstance.route) +
instance.uid + '][' +
'][耗时' + instance.uid +
(Date.now() - start) + '][耗时' +
']差量更新', JSON.stringify(diffData)); (Date.now() - start) +
']差量更新', JSON.stringify(diffData));
}
ctx.__next_tick_pending = true; ctx.__next_tick_pending = true;
mpInstance.setData(diffData, () => { mpInstance.setData(diffData, () => {
ctx.__next_tick_pending = false; ctx.__next_tick_pending = false;
......
...@@ -656,11 +656,12 @@ function initLifetimes({ mocks, isPage, initRelation, vueOptions, }) { ...@@ -656,11 +656,12 @@ function initLifetimes({ mocks, isPage, initRelation, vueOptions, }) {
initRelation(this, relationOptions); initRelation(this, relationOptions);
// 初始化 vue 实例 // 初始化 vue 实例
const mpInstance = this; const mpInstance = this;
const isMiniProgramPage = isPage(mpInstance);
this.$vm = $createComponent({ this.$vm = $createComponent({
type: vueOptions, type: vueOptions,
props: properties, props: properties,
}, { }, {
mpType: isPage(mpInstance) ? 'page' : 'component', mpType: isMiniProgramPage ? 'page' : 'component',
mpInstance, mpInstance,
slots: properties.vS, slots: properties.vS,
parentComponent: relationOptions.parent && relationOptions.parent.$, parentComponent: relationOptions.parent && relationOptions.parent.$,
......
...@@ -34,13 +34,15 @@ export function initLifetimes({ ...@@ -34,13 +34,15 @@ export function initLifetimes({
initRelation(this, relationOptions) initRelation(this, relationOptions)
// 初始化 vue 实例 // 初始化 vue 实例
const mpInstance = this const mpInstance = this
const isMiniProgramPage = isPage(mpInstance)
this.$vm = $createComponent( this.$vm = $createComponent(
{ {
type: vueOptions, type: vueOptions,
props: properties, props: properties,
}, },
{ {
mpType: isPage(mpInstance) ? 'page' : 'component', mpType: isMiniProgramPage ? 'page' : 'component',
mpInstance, mpInstance,
slots: properties.vS, // vueSlots slots: properties.vS, // vueSlots
parentComponent: relationOptions.parent && relationOptions.parent.$, parentComponent: relationOptions.parent && relationOptions.parent.$,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册