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

wip(app): nvue styler

上级 69369a8f
......@@ -2,12 +2,22 @@
{
"input": {
"src/esm.ts": ["dist/uni-nvue-styler.es.js"]
}
},
"external": ["@vue/shared"]
},
{
"input": {
"src/index.ts": ["dist/uni-nvue-styler.cjs.js"]
},
"external": ["postcss", "parse-css-font"],
"alias": {
"entries": [
{
"find": "shared",
"replacement": "@vue/shared"
}
]
},
"compilerOptions": {
"declaration": true
}
......
......@@ -3,7 +3,6 @@
"version": "0.0.1-nvue3.3030820220125001",
"description": "uni-nvue-styler",
"main": "./dist/uni-nvue-styler.cjs.js",
"module": "./dist/uni-nvue-styler.es.js",
"types": "./dist/uni-nvue-styler.d.ts",
"files": [
"dist"
......
export { expand } from './expand'
export { normalize } from './normalize'
import { createDecl, TransformDecl } from '../utils'
const backgroundColor = __NODE_JS__ ? 'background-color' : 'backgroundColor'
const backgroundImage = __NODE_JS__ ? 'background-image' : 'backgroundImage'
export const transformBackground: TransformDecl = (decl) => {
const { value, important, raws, source } = decl
if (/^#?\S+$/.test(value) || /^rgba?(.+)$/.test(value)) {
return [createDecl('background-color', value, important, raws, source)]
return [createDecl(backgroundColor, value, important, raws, source)]
} else if (/^linear-gradient(.+)$/.test(value)) {
return [createDecl('background-image', value, important, raws, source)]
return [createDecl(backgroundImage, value, important, raws, source)]
}
return [decl]
}
import { createDecl, TransformDecl } from '../utils'
const borderWidth = __NODE_JS__ ? '-width' : 'Width'
const borderStyle = __NODE_JS__ ? '-style' : 'Style'
const borderColor = __NODE_JS__ ? '-color' : 'Color'
export const transformBorder: TransformDecl = (decl) => {
const { prop, value, important, raws, source } = decl
const splitResult = value.replace(/\s*,\s*/g, ',').split(/\s+/)
......@@ -14,21 +18,21 @@ export const transformBorder: TransformDecl = (decl) => {
}
return [
createDecl(
prop + '-width',
prop + borderWidth,
(result[0] || '0').trim(),
important,
raws,
source
),
createDecl(
prop + '-style',
prop + borderStyle,
(result[1] || 'solid').trim(),
important,
raws,
source
),
createDecl(
prop + '-color',
prop + borderColor,
(result[2] || '#000000').trim(),
important,
raws,
......
import { capitalize } from '@vue/shared'
import { createDecl, TransformDecl } from '../utils'
const borderTop = __NODE_JS__ ? 'border-top-' : 'borderTop'
const borderRight = __NODE_JS__ ? 'border-right-' : 'borderRight'
const borderBottom = __NODE_JS__ ? 'border-bottom-' : 'borderBottom'
const borderLeft = __NODE_JS__ ? 'border-left-' : 'borderLeft'
export const transformBorderColor: TransformDecl = (decl) => {
const { prop, value, important, raws, source } = decl
const property = prop.split('-')[1]
let property = prop.split('-')[1]
if (!__NODE_JS__) {
property = capitalize(property)
}
const splitResult = value.replace(/\s*,\s*/g, ',').split(/\s+/)
switch (splitResult.length) {
case 1:
......@@ -16,33 +25,15 @@ export const transformBorderColor: TransformDecl = (decl) => {
}
return [
createDecl(borderTop + property, splitResult[0], important, raws, source),
createDecl(borderRight + property, splitResult[1], important, raws, source),
createDecl(
'border-top-' + property,
splitResult[0],
important,
raws,
source
),
createDecl(
'border-right-' + property,
splitResult[1],
important,
raws,
source
),
createDecl(
'border-bottom-' + property,
borderBottom + property,
splitResult[2],
important,
raws,
source
),
createDecl(
'border-left-' + property,
splitResult[3],
important,
raws,
source
),
createDecl(borderLeft + property, splitResult[3], important, raws, source),
]
}
import { createDecl, TransformDecl } from '../utils'
const borderTopLeftRadius = __NODE_JS__
? 'border-top-left-radius'
: 'borderTopLeftRadius'
const borderTopRightRadius = __NODE_JS__
? 'border-top-right-radius'
: 'borderTopRightRadius'
const borderBottomRightRadius = __NODE_JS__
? 'border-bottom-right-radius'
: 'borderBottomRightRadius'
const borderBottomLeftRadius = __NODE_JS__
? 'border-bottom-left-radius'
: 'borderBottomLeftRadius'
export const transformBorderRadius: TransformDecl = (decl) => {
const { value, important, raws, source } = decl
const splitResult = value.split(/\s+/)
......@@ -17,33 +29,15 @@ export const transformBorderRadius: TransformDecl = (decl) => {
break
}
return [
createDecl(borderTopLeftRadius, splitResult[0], important, raws, source),
createDecl(borderTopRightRadius, splitResult[1], important, raws, source),
createDecl(
'border-top-left-radius',
splitResult[0],
important,
raws,
source
),
createDecl(
'border-top-right-radius',
splitResult[1],
important,
raws,
source
),
createDecl(
'border-bottom-right-radius',
borderBottomRightRadius,
splitResult[2],
important,
raws,
source
),
createDecl(
'border-bottom-left-radius',
splitResult[3],
important,
raws,
source
),
createDecl(borderBottomLeftRadius, splitResult[3], important, raws, source),
]
}
import { createDecl, TransformDecl } from '../utils'
const flexDirection = __NODE_JS__ ? 'flex-direction' : 'flexDirection'
const flexWrap = __NODE_JS__ ? 'flex-wrap' : 'flexWrap'
export const transformFlexFlow: TransformDecl = (decl) => {
const { value, important, raws, source } = decl
const splitResult = value.split(/\s+/)
......@@ -14,13 +16,7 @@ export const transformFlexFlow: TransformDecl = (decl) => {
return [decl]
}
return [
createDecl(
'flex-direction',
result[0] || 'column',
important,
raws,
source
),
createDecl('flex-wrap', result[1] || 'nowrap', important, raws, source),
createDecl(flexDirection, result[0] || 'column', important, raws, source),
createDecl(flexWrap, result[1] || 'nowrap', important, raws, source),
]
}
import { extend } from '@vue/shared'
import type { Plugin } from 'postcss'
import { TransformDecl } from '../utils'
import { transformBackground } from './background'
......@@ -17,20 +18,35 @@ const DeclTransforms: Record<string, TransformDecl> = {
margin: transformMargin,
padding: transformPadding,
border: transformBorder,
'border-top': transformBorder,
'border-right': transformBorder,
'border-bottom': transformBorder,
'border-left': transformBorder,
'border-style': transformBorderStyle,
'border-width': transformBorderWidth,
'border-color': transformBorderColor,
'border-radius': transformBorderRadius,
'flex-flow': transformFlexFlow,
background: transformBackground,
}
if (__NODE_JS__) {
DeclTransforms.font = transformFont
extend(DeclTransforms, {
'border-top': transformBorder,
'border-right': transformBorder,
'border-bottom': transformBorder,
'border-left': transformBorder,
'border-style': transformBorderStyle,
'border-width': transformBorderWidth,
'border-color': transformBorderColor,
'border-radius': transformBorderRadius,
'flex-flow': transformFlexFlow,
font: transformFont,
})
} else {
extend(DeclTransforms, {
borderTop: transformBorder,
borderRight: transformBorder,
borderBottom: transformBorder,
borderLeft: transformBorder,
borderStyle: transformBorderStyle,
borderWidth: transformBorderWidth,
borderColor: transformBorderColor,
borderRadius: transformBorderRadius,
flexFlow: transformFlexFlow,
})
}
const expanded = Symbol('expanded')
......
import { createDecl, TransformDecl } from '../utils'
const top = __NODE_JS__ ? '-top' : 'Top'
const right = __NODE_JS__ ? '-right' : 'Right'
const bottom = __NODE_JS__ ? '-bottom' : 'Bottom'
const left = __NODE_JS__ ? '-left' : 'Left'
export const createTransformBox = (
type: 'margin' | 'padding'
): TransformDecl => {
......@@ -20,10 +24,10 @@ export const createTransformBox = (
}
return [
createDecl(`${type}-top`, splitResult[0], important, raws, source),
createDecl(`${type}-right`, splitResult[1], important, raws, source),
createDecl(`${type}-bottom`, splitResult[2], important, raws, source),
createDecl(`${type}-left`, splitResult[3], important, raws, source),
createDecl(type + top, splitResult[0], important, raws, source),
createDecl(type + right, splitResult[1], important, raws, source),
createDecl(type + bottom, splitResult[2], important, raws, source),
createDecl(type + left, splitResult[3], important, raws, source),
]
}
}
......
import type { Declaration } from 'postcss'
import { createDecl, TransformDecl } from '../utils'
const transitionProperty = __NODE_JS__
? 'transition-property'
: 'transitionProperty'
const transitionDuration = __NODE_JS__
? 'transition-duration'
: 'transitionDuration'
const transitionTimingFunction = __NODE_JS__
? 'transition-timing-function'
: 'transitionTimingFunction'
const transitionDelay = __NODE_JS__ ? 'transition-delay' : 'transitionDelay'
export const transformTransition: TransformDecl = (decl) => {
const CHUNK_REGEXP =
/^(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?\s*(\S*)?\s*(\d*\.?\d+(?:ms|s)?)?$/
......@@ -12,25 +22,17 @@ export const transformTransition: TransformDecl = (decl) => {
}
match[1] &&
result.push(
createDecl('transition-property', match[1], important, raws, source)
createDecl(transitionProperty, match[1], important, raws, source)
)
match[2] &&
result.push(
createDecl('transition-duration', match[2], important, raws, source)
createDecl(transitionDuration, match[2], important, raws, source)
)
match[3] &&
result.push(
createDecl(
'transition-timing-function',
match[3],
important,
raws,
source
)
createDecl(transitionTimingFunction, match[3], important, raws, source)
)
match[4] &&
result.push(
createDecl('transition-delay', match[4], important, raws, source)
)
result.push(createDecl(transitionDelay, match[4], important, raws, source))
return result
}
import { Normalize, hyphenate } from '../utils'
import { Normalize, autofixedReason, validReason } from '../utils'
export const normalizeColor: Normalize = (v) => {
v = (v || '').toString()
......@@ -9,9 +9,7 @@ export const normalizeColor: Normalize = (v) => {
return {
value: '#' + v[1] + v[1] + v[2] + v[2] + v[3] + v[3],
reason: function reason(k, v, result) {
return (
'NOTE: property value `' + v + '` is autofixed to `' + result + '`'
)
return autofixedReason(v, result)
},
}
}
......@@ -19,9 +17,7 @@ export const normalizeColor: Normalize = (v) => {
return {
value: EXTENDED_COLOR_KEYWORDS[v],
reason: function reason(k, v, result) {
return (
'NOTE: property value `' + v + '` is autofixed to `' + result + '`'
)
return autofixedReason(v, result)
},
}
}
......@@ -63,13 +59,7 @@ export const normalizeColor: Normalize = (v) => {
return {
value: null,
reason(k, v, result) {
return (
'ERROR: property value `' +
v +
'` is not valid for `' +
hyphenate(k) +
'`'
)
return validReason(k, v)
},
}
}
......
import { hyphenate, Normalize } from '../utils'
import { defaultValueReason, Normalize, supportedEnumReason } from '../utils'
export function createEnumNormalize(items: Array<string | number>): Normalize {
return (v) => {
......@@ -10,28 +10,14 @@ export function createEnumNormalize(items: Array<string | number>): Normalize {
return {
value: v,
reason: function reason(k, v, result) {
return (
'NOTE: property value `' +
v +
'` is the DEFAULT value for `' +
hyphenate(k) +
'` (could be removed)'
)
return defaultValueReason(k, v)
},
}
}
return {
value: null,
reason: function reason(k, v, result) {
return (
'ERROR: property value `' +
v +
'` is not supported for `' +
hyphenate(k) +
'` (supported values are: `' +
items.join('`|`') +
'`)'
)
return supportedEnumReason(k, v, items)
},
}
}
......
import { hyphenate, Normalize } from '../utils'
import {
Normalize,
supportedEnumReason,
defaultValueReason,
compatibilityReason,
} from '../utils'
export const normalizeFlexWrap: Normalize = (v) => {
const values = ['nowrap', 'wrap', 'wrap-reverse']
......@@ -7,11 +12,7 @@ export const normalizeFlexWrap: Normalize = (v) => {
return {
value: v,
reason(k, v, result) {
return (
'NOTE: the ' +
hyphenate(k) +
' property may have compatibility problem on native'
)
return compatibilityReason(k)
},
}
}
......@@ -19,28 +20,14 @@ export const normalizeFlexWrap: Normalize = (v) => {
return {
value: v,
reason: function reason(k, v, result) {
return (
'NOTE: property value `' +
v +
'` is the DEFAULT value for `' +
hyphenate(k) +
'` (could be removed)'
)
return defaultValueReason(k, v)
},
}
}
return {
value: null,
reason(k, v, result) {
return (
'ERROR: property value `' +
v +
'` is not supported for `' +
hyphenate(k) +
'` (supported values are: `' +
values.join('`|`') +
'`)'
)
return supportedEnumReason(k, v, values)
},
}
}
import type { Plugin, Declaration, Helpers, Rule } from 'postcss'
import { camelize, hasOwn, isFunction, isString } from '@vue/shared'
import {
camelize,
hasOwn,
hyphenate,
isFunction,
isNumber,
isString,
LENGTH_REGEXP,
SUPPORT_CSS_UNIT,
hyphenateStyleProperty,
isNumber,
} from '../utils'
import { normalizeMap } from './map'
......@@ -25,11 +22,14 @@ export function normalize(opts: NormalizeOptions = {}): Plugin {
if (!hasOwn(opts, 'logLevel')) {
opts.logLevel = 'WARNING'
}
return {
const plugin: Plugin = {
postcssPlugin: 'nvue:normalize',
Rule: createRuleProcessor(opts),
Declaration: createDeclarationProcessor(opts),
}
if (__NODE_JS__) {
plugin.Rule = createRuleProcessor(opts)
}
return plugin
}
function createRuleProcessor({ descendant }: NormalizeOptions) {
......@@ -72,7 +72,7 @@ function createDeclarationProcessor({ logLevel }: NormalizeOptions) {
if (isString(value) || isNumber(value)) {
decl.value = value
}
if (log && log.reason) {
if (log && log.reason && helper) {
const { reason } = log
let needLog = false
if (logLevel === 'NOTE') {
......@@ -120,7 +120,7 @@ export function normalizeDecl(name: string, value: string) {
log = {
reason:
'WARNING: `' +
hyphenate(name) +
hyphenateStyleProperty(name) +
'` is not a standard property name (may not be supported)',
}
}
......
import { hyphenate, Normalize } from '../utils'
import { Normalize, supportedValueWithTipsReason } from '../utils'
export const normalizeInteger: Normalize = (v) => {
v = (v || '').toString()
......@@ -8,13 +8,7 @@ export const normalizeInteger: Normalize = (v) => {
return {
value: null,
reason: function reason(k, v, result) {
return (
'ERROR: property value `' +
v +
'` is not supported for `' +
hyphenate(k) +
'` (only integer is supported)'
)
return supportedValueWithTipsReason(k, v, `(only integer is supported)`)
},
}
}
import { Normalize, hyphenate, LENGTH_REGEXP, SUPPORT_CSS_UNIT } from '../utils'
import {
Normalize,
LENGTH_REGEXP,
SUPPORT_CSS_UNIT,
supportedValueWithTipsReason,
supportedUnitWithAutofixedReason,
} from '../utils'
export const normalizeLength: Normalize = (v: string | number) => {
v = (v || '').toString()
......@@ -14,15 +20,7 @@ export const normalizeLength: Normalize = (v: string | number) => {
return {
value: parseFloat(v),
reason(k, v, result) {
return (
'NOTE: unit `' +
unit +
'` is not supported and property value `' +
v +
'` is autofixed to `' +
result +
'`'
)
return supportedUnitWithAutofixedReason(unit, v, result)
},
}
}
......@@ -31,12 +29,10 @@ export const normalizeLength: Normalize = (v: string | number) => {
return {
value: null,
reason(k, v, result) {
return (
'ERROR: property value `' +
v +
'` is not supported for `' +
hyphenate(k) +
'` (only number and pixel values are supported)'
return supportedValueWithTipsReason(
k,
v,
`(only number and pixel values are supported)`
)
},
}
......
import { Normalize, hyphenate, LENGTH_REGEXP } from '../utils'
import {
Normalize,
LENGTH_REGEXP,
supportedValueWithTipsReason,
} from '../utils'
export const normalizeNumber: Normalize = (v) => {
v = (v || '').toString()
......@@ -11,13 +15,7 @@ export const normalizeNumber: Normalize = (v) => {
return {
value: null,
reason: function reason(k, v, result) {
return (
'ERROR: property value `' +
v +
'` is not supported for `' +
hyphenate(k) +
'` (only number is supported)'
)
return supportedValueWithTipsReason(k, v, '(only number is supported)')
},
}
}
import { Normalize, isFunction } from '../utils'
import { isFunction } from '@vue/shared'
import { Normalize } from '../utils'
import { normalizeLength } from './length'
export const normalizeShorthandLength: Normalize = (v) => {
......
import { hyphenate, Normalize } from '../utils'
import {
autofixedReason,
Normalize,
supportedValueWithTipsReason,
} from '../utils'
export const normalizeTransitionInterval: Normalize = (v) => {
v = (v || 0).toString()
......@@ -15,9 +19,7 @@ export const normalizeTransitionInterval: Normalize = (v) => {
return {
value: parseInt(num + ''),
reason(k, v, result) {
return (
'NOTE: property value `' + v + '` is autofixed to `' + result + '`'
)
return autofixedReason(v, result)
},
}
}
......@@ -25,12 +27,10 @@ export const normalizeTransitionInterval: Normalize = (v) => {
return {
value: null,
reason(k, v, result) {
return (
'ERROR: property value `' +
v +
'` is not supported for `' +
hyphenate(k) +
'` (only number of seconds and milliseconds is valid)'
return supportedValueWithTipsReason(
k,
v,
'(only number of seconds and milliseconds is valid)'
)
},
}
......
import { camelize, hyphenate, Normalize } from '../utils'
import { camelize } from '@vue/shared'
import { Normalize, supportedValueWithTipsReason } from '../utils'
import { normalizeMap } from './map'
export const normalizeTransitionProperty: Normalize = (v) => {
......@@ -15,13 +16,7 @@ export const normalizeTransitionProperty: Normalize = (v) => {
return {
value: null,
reason: function reason(k, v, result) {
return (
'ERROR: property value `' +
v +
'` is not supported for `' +
hyphenate(k) +
'` (only css property is valid)'
)
return supportedValueWithTipsReason(k, v, '(only css property is valid)')
},
}
}
import { hyphenate, NUM_REGEXP, Normalize } from '../utils'
import { NUM_REGEXP, Normalize, supportedEnumReason } from '../utils'
export const normalizeTransitionTimingFunction: Normalize = (v) => {
v = (v || '').toString()
......@@ -33,13 +33,14 @@ export const normalizeTransitionTimingFunction: Normalize = (v) => {
return {
value: null,
reason(k, v, result) {
return (
'ERROR: property value `' +
v +
'` is not supported for `' +
hyphenate(k) +
'` (supported values are: `linear`|`ease`|`ease-in`|`ease-out`|`ease-in-out`|`cubic-bezier(n,n,n,n)`)'
)
return supportedEnumReason(k, v, [
'linear',
'ease',
'ease-in',
'ease-out',
'ease-in-out',
'cubic-bezier(n,n,n,n)',
])
},
}
}
import { Container, Root, Document } from 'postcss'
import { extend } from './utils'
import { extend } from '@vue/shared'
interface ObjectifierContext {
'FONT-FACE': Record<string, unknown>[]
......
import postcss, { Message } from 'postcss'
import { objectifier } from '.'
import { objectifier } from './objectifier'
import { expand } from './expand'
import { NormalizeOptions, normalize } from './normalize'
......
export const extend = Object.assign
export const isArray = Array.isArray
export const isString = (val: unknown): val is string => typeof val === 'string'
export const isFunction = (val: unknown): val is Function =>
typeof val === 'function'
const hasOwnProperty = Object.prototype.hasOwnProperty
export const hasOwn = (
val: object,
key: string | symbol
): key is keyof typeof val => hasOwnProperty.call(val, key)
const cacheStringFunction = <T extends (str: string) => string>(
fn: T
): T => {
const cache: Record<string, string> = Object.create(null)
return ((str: string) => {
const hit = cache[str]
return hit || (cache[str] = fn(str))
}) as any
}
const camelizeRE = /-(\w)/g
export const camelize = cacheStringFunction((str: string): string => {
return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''))
})
export const capitalize = cacheStringFunction(
(str: string) => str.charAt(0).toUpperCase() + str.slice(1)
)
import type { Declaration, Source } from 'postcss'
export type TransformDecl = (decl: Declaration) => Declaration[]
export type Normalize = (v: string | number) => {
......@@ -31,21 +30,10 @@ export const NUM_REGEXP = /^[-]?\d*\.?\d+$/
export const LENGTH_REGEXP = /^[-+]?\d*\.?\d+(\S*)$/
export const SUPPORT_CSS_UNIT = ['px', 'pt', 'wx', 'upx', 'rpx']
export const extend = Object.assign
export const isArray = Array.isArray
export const isString = (val: unknown): val is string => typeof val === 'string'
export const isNumber = (val: unknown): val is string => typeof val === 'number'
export const isFunction = (val: unknown): val is Function =>
typeof val === 'function'
export const serialize = (val: unknown) => JSON.parse(JSON.stringify(val))
const hasOwnProperty = Object.prototype.hasOwnProperty
export const hasOwn = (
val: object,
key: string | symbol
): key is keyof typeof val => hasOwnProperty.call(val, key)
const cacheStringFunction = <T extends (str: string) => string>(fn: T): T => {
const cache: Record<string, string> = Object.create(null)
return ((str: string) => {
......@@ -54,13 +42,9 @@ const cacheStringFunction = <T extends (str: string) => string>(fn: T): T => {
}) as any
}
const camelizeRE = /-(\w)/g
export const camelize = cacheStringFunction((str: string): string => {
return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''))
})
const hyphenateRE = /([A-Z])/g
export const hyphenate = cacheStringFunction((str: string) =>
export const hyphenateStyleProperty = cacheStringFunction((str: string) =>
str
.replace(hyphenateRE, (_, m) => {
if (typeof m === 'string') {
......@@ -70,3 +54,85 @@ export const hyphenate = cacheStringFunction((str: string) =>
})
.toLowerCase()
)
export function autofixedReason(
v: string | number,
result: string | number | null
) {
return 'NOTE: property value `' + v + '` is autofixed to `' + result + '`'
}
export function validReason(k: string, v: string | number) {
return (
'ERROR: property value `' +
v +
'` is not valid for `' +
hyphenateStyleProperty(k) +
'`'
)
}
export function defaultValueReason(k: string, v: string | number) {
return (
'NOTE: property value `' +
v +
'` is the DEFAULT value for `' +
hyphenateStyleProperty(k) +
'` (could be removed)'
)
}
export function supportedEnumReason(
k: string,
v: string | number,
items: unknown[]
) {
return (
'ERROR: property value `' +
v +
'` is not supported for `' +
hyphenateStyleProperty(k) +
'` (supported values are: `' +
items.join('`|`') +
'`)'
)
}
export function supportedValueWithTipsReason(
k: string,
v: string | number,
tips?: string
) {
return (
'ERROR: property value `' +
v +
'` is not supported for `' +
hyphenateStyleProperty(k) +
'` ' +
tips
)
}
export function supportedUnitWithAutofixedReason(
unit: string,
v: string | number,
result: string | number | null
) {
return (
'NOTE: unit `' +
unit +
'` is not supported and property value `' +
v +
'` is autofixed to `' +
result +
'`'
)
}
export function compatibilityReason(k: string) {
return (
'NOTE: the ' +
hyphenateStyleProperty(k) +
' property may have compatibility problem on native'
)
}
......@@ -14,7 +14,10 @@
"resolveJsonModule": true,
"esModuleInterop": true,
"removeComments": false,
"lib": ["ESNext", "DOM"]
"lib": ["ESNext", "DOM"],
"paths": {
"shared": ["./src/shared.ts"]
}
},
"include": [
"src",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册