2018-12-20 18:25:49 +08:00
|
|
|
export default {
|
|
|
|
data () {
|
|
|
|
return {
|
|
|
|
defaultHorizon: false,
|
|
|
|
defaultXAxisFS: 10,
|
|
|
|
defaultYAxisFS: 10,
|
|
|
|
defaultXOffset: 30,
|
|
|
|
defaultRotateAngel: 30,
|
|
|
|
|
|
|
|
defaultXAxisLineColor: 'rgba(255, 255, 255, 0.3)',
|
|
|
|
defaultYAxisLineColor: 'rgba(255, 255, 255, 0.3)',
|
2018-12-20 22:36:22 +08:00
|
|
|
defaultGridColor: 'rgba(255, 255, 255, 0.3)',
|
|
|
|
defaultGridType: 'line',
|
2018-12-21 14:46:55 +08:00
|
|
|
defaultAxisLabelGap: 5,
|
2018-12-20 18:25:49 +08:00
|
|
|
|
|
|
|
horizon: false,
|
|
|
|
// user data's max and min value
|
|
|
|
valueMaxMin: [],
|
|
|
|
// axis's max and min value
|
|
|
|
axisMaxMin: [],
|
|
|
|
// label's max width where x and y Axis
|
|
|
|
labelXYMaxWidth: [],
|
|
|
|
valueAxisTag: [],
|
|
|
|
labelAxisTag: [],
|
|
|
|
xyAxisFS: [],
|
|
|
|
xyAxisUnitWidth: [],
|
|
|
|
axisMargin: [],
|
|
|
|
axisOriginPos: [],
|
|
|
|
axisWH: [],
|
|
|
|
valueTagPos: [],
|
|
|
|
labelTagPos: [],
|
2018-12-21 14:46:55 +08:00
|
|
|
labelAxisPos: [],
|
2018-12-20 18:25:49 +08:00
|
|
|
valueTagGap: 0,
|
|
|
|
labelTagGap: 0,
|
|
|
|
xTagColor: '',
|
|
|
|
yTagColor: '',
|
|
|
|
xTagColorMul: false,
|
2018-12-20 22:36:22 +08:00
|
|
|
yTagColorMul: false,
|
|
|
|
xGridColor: '',
|
|
|
|
yGridColor: '',
|
|
|
|
xGridColorMul: false,
|
|
|
|
yGridColorMul: false
|
2018-12-20 18:25:49 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
initAxis () {
|
|
|
|
const { calcMaxMinValue, calcValueAxisTag, calcLabelAxisTag, calcXYAxisFS } = this
|
|
|
|
|
|
|
|
calcMaxMinValue()
|
|
|
|
|
|
|
|
calcValueAxisTag()
|
|
|
|
|
|
|
|
calcLabelAxisTag()
|
|
|
|
|
|
|
|
calcXYAxisFS()
|
|
|
|
|
|
|
|
const { calcXYLabelMaxWidth, calcAxisMargin, calcAxisOriginPos } = this
|
|
|
|
|
|
|
|
calcXYLabelMaxWidth()
|
|
|
|
|
|
|
|
calcAxisMargin()
|
|
|
|
|
|
|
|
calcAxisOriginPos()
|
|
|
|
|
2018-12-20 22:36:22 +08:00
|
|
|
const { calcAxisWH, calcValueTagPos, calcLabelTagPos, calcTagGap, calcTagColor, calcGridColor } = this
|
2018-12-20 18:25:49 +08:00
|
|
|
|
|
|
|
calcAxisWH()
|
|
|
|
|
|
|
|
calcValueTagPos()
|
|
|
|
|
|
|
|
calcLabelTagPos()
|
|
|
|
|
|
|
|
calcTagGap()
|
|
|
|
|
|
|
|
calcTagColor()
|
2018-12-20 22:36:22 +08:00
|
|
|
|
|
|
|
calcGridColor()
|
2018-12-20 18:25:49 +08:00
|
|
|
},
|
|
|
|
calcMaxMinValue () {
|
|
|
|
const { data: { data }, multipleSum, filterNull, getArrayMaxMin } = this
|
|
|
|
|
2018-12-20 22:36:22 +08:00
|
|
|
const valueData = data.map(item => item.data)
|
|
|
|
|
|
|
|
const trueValue = valueData.map(item =>
|
2018-12-20 18:25:49 +08:00
|
|
|
item.map(v =>
|
|
|
|
v ? (typeof v === 'number' ? v : multipleSum(...filterNull(v))) : false))
|
|
|
|
|
|
|
|
this.valueMaxMin = getArrayMaxMin(trueValue)
|
|
|
|
},
|
|
|
|
calcValueAxisTag () {
|
|
|
|
const { valueMaxMin: [ valueMax, valueMin ], data, defaultHorizon } = this
|
|
|
|
|
|
|
|
const { horizon } = data
|
|
|
|
|
|
|
|
this.horizon = horizon || defaultHorizon
|
|
|
|
|
|
|
|
let { max, min, num, fixed } = data[horizon ? 'x' : 'y']
|
|
|
|
|
|
|
|
let [trueMax, trueMin] = [max, min]
|
|
|
|
|
|
|
|
const thirdValueMinus = parseInt((valueMax - valueMin) / 3)
|
|
|
|
|
|
|
|
!max && (max !== 0) && (trueMax = valueMax + thirdValueMinus)
|
|
|
|
!min && (min !== 0) && (trueMin = valueMin - thirdValueMinus)
|
|
|
|
|
|
|
|
const trueMinus = trueMax - trueMin
|
|
|
|
|
|
|
|
!num && trueMinus < 9 && (num = trueMinus + 1)
|
|
|
|
!num && (num = 10)
|
|
|
|
|
|
|
|
const valueGap = trueMinus / (num - 1)
|
|
|
|
|
|
|
|
const valueAxisTag = this.valueAxisTag = Array(num).fill(0).map((t, i) =>
|
|
|
|
(trueMin + i * valueGap).toFixed(fixed))
|
|
|
|
|
|
|
|
const lastValueAxisTagIndex = valueAxisTag.length - 1
|
|
|
|
|
|
|
|
this.axisMaxMin = [parseFloat(valueAxisTag[lastValueAxisTagIndex]), parseFloat(valueAxisTag[0])]
|
|
|
|
},
|
|
|
|
calcLabelAxisTag () {
|
|
|
|
const { data, horizon } = this
|
|
|
|
|
|
|
|
this.labelAxisTag = data[horizon ? 'y' : 'x'].data
|
|
|
|
},
|
|
|
|
calcXYAxisFS () {
|
|
|
|
const { defaultXAxisFS, defaultYAxisFS } = this
|
|
|
|
|
|
|
|
const { data: { x: { fontSize: xfs }, y: { fontSize: yfs } } } = this
|
|
|
|
|
|
|
|
this.xyAxisFS = [xfs || defaultXAxisFS, yfs || defaultYAxisFS]
|
|
|
|
},
|
|
|
|
calcXYLabelMaxWidth () {
|
|
|
|
const { ctx, valueAxisTag, labelAxisTag, horizon, xyAxisFS } = this
|
|
|
|
|
|
|
|
const { canvas: { getTextsWidth } } = this
|
|
|
|
|
|
|
|
const { data: { x: { unit: xUN }, y: { unit: yUN } } } = this
|
|
|
|
|
|
|
|
ctx.font = `${xyAxisFS[0]}px Arial`
|
|
|
|
|
2018-12-21 14:46:55 +08:00
|
|
|
this.labelXYMaxWidth[0] = Math.max(...getTextsWidth(ctx, horizon ? valueAxisTag : labelAxisTag))
|
2018-12-20 18:25:49 +08:00
|
|
|
|
|
|
|
this.xyAxisUnitWidth[0] = ctx.measureText(xUN || '').width
|
|
|
|
|
|
|
|
ctx.font = `${xyAxisFS[1]}px Arial`
|
|
|
|
|
2018-12-21 14:46:55 +08:00
|
|
|
this.labelXYMaxWidth[1] = Math.max(...getTextsWidth(ctx, horizon ? labelAxisTag : valueAxisTag))
|
2018-12-20 18:25:49 +08:00
|
|
|
|
|
|
|
this.xyAxisUnitWidth[1] = ctx.measureText(yUN || '').width
|
|
|
|
},
|
|
|
|
calcAxisMargin () {
|
|
|
|
const { defaultXOffset, labelXYMaxWidth, data, xyAxisUnitWidth } = this
|
|
|
|
|
|
|
|
const { offset: xOF, unitWidth: xUW } = data.x
|
|
|
|
|
|
|
|
const { offset: yOF, unitHeight: yUH } = data.y
|
|
|
|
|
|
|
|
this.axisMargin[0] = yUH || defaultXOffset
|
|
|
|
this.axisMargin[1] = xUW || xyAxisUnitWidth[0] + 10
|
|
|
|
this.axisMargin[2] = xOF || defaultXOffset
|
|
|
|
this.axisMargin[3] = yOF || labelXYMaxWidth[1] + 10
|
|
|
|
},
|
|
|
|
calcAxisOriginPos () {
|
|
|
|
const { axisMargin, canvasWH } = this
|
|
|
|
|
|
|
|
this.axisOriginPos[0] = axisMargin[3]
|
|
|
|
this.axisOriginPos[1] = canvasWH[1] - axisMargin[2]
|
|
|
|
},
|
|
|
|
calcAxisWH () {
|
|
|
|
const { axisMargin, canvasWH } = this
|
|
|
|
|
|
|
|
this.axisWH[0] = canvasWH[0] - axisMargin[1] - axisMargin[3]
|
|
|
|
this.axisWH[1] = canvasWH[1] - axisMargin[0] - axisMargin[2]
|
|
|
|
},
|
|
|
|
calcValueTagPos () {
|
|
|
|
const { axisWH, valueAxisTag, horizon, axisOriginPos: [x, y] } = this
|
|
|
|
|
|
|
|
const valueTagNum = valueAxisTag.length
|
|
|
|
|
|
|
|
const gapWidth = (horizon ? axisWH[0] : axisWH[1]) / (valueTagNum - 1)
|
|
|
|
|
|
|
|
this.valueTagPos = new Array(valueTagNum).fill(0).map((t, i) =>
|
|
|
|
horizon ? [x + gapWidth * i, y + 5] : [x - 5, y - gapWidth * i])
|
|
|
|
},
|
|
|
|
calcLabelTagPos () {
|
2018-12-21 14:46:55 +08:00
|
|
|
const { axisWH, labelAxisTag, horizon, axisOriginPos: [x, y], data } = this
|
|
|
|
|
|
|
|
const { defaultAxisLabelGap, axisType } = this
|
2018-12-20 18:25:49 +08:00
|
|
|
|
|
|
|
const { boundaryGap } = data
|
|
|
|
|
|
|
|
const labelNum = labelAxisTag.length
|
|
|
|
|
|
|
|
const gapAllWidth = horizon ? axisWH[1] : axisWH[0]
|
|
|
|
|
|
|
|
const tempArray = new Array(labelNum).fill(0)
|
|
|
|
|
|
|
|
if (axisType === 'column' || (axisType === 'line' && boundaryGap)) {
|
|
|
|
const gapWidth = gapAllWidth / labelNum
|
|
|
|
|
|
|
|
const halfGapWidth = gapWidth / 2
|
|
|
|
|
2018-12-21 14:46:55 +08:00
|
|
|
this.labelAxisPos = tempArray.map((t, i) =>
|
|
|
|
horizon ? [x, y - gapWidth * i - halfGapWidth]
|
|
|
|
: [x + gapWidth * i + halfGapWidth, y])
|
|
|
|
|
2018-12-20 18:25:49 +08:00
|
|
|
this.labelTagPos = tempArray.map((t, i) =>
|
2018-12-21 14:46:55 +08:00
|
|
|
horizon ? [x - defaultAxisLabelGap, y - gapWidth * i - halfGapWidth]
|
|
|
|
: [x + gapWidth * i + halfGapWidth, y + defaultAxisLabelGap])
|
2018-12-20 18:25:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (axisType === 'line' && !boundaryGap) {
|
|
|
|
const gapWidth = gapAllWidth / (labelNum - 1)
|
|
|
|
|
2018-12-21 14:46:55 +08:00
|
|
|
this.labelAxisPos = tempArray.map((t, i) =>
|
|
|
|
horizon ? [x, y - gapWidth]
|
|
|
|
: [x + gapWidth * i, y])
|
|
|
|
|
2018-12-20 18:25:49 +08:00
|
|
|
this.labelTagPos = tempArray.map((t, i) =>
|
2018-12-21 14:46:55 +08:00
|
|
|
horizon ? [x - defaultAxisLabelGap, y - gapWidth]
|
|
|
|
: [x + gapWidth * i, y + defaultAxisLabelGap])
|
2018-12-20 18:25:49 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
calcTagGap () {
|
|
|
|
const { horizon, valueTagPos, labelTagPos } = this
|
|
|
|
|
|
|
|
const v = horizon ? '0' : '1'
|
|
|
|
|
|
|
|
this.valueTagGap = Math.abs(valueTagPos[0][v] - valueTagPos[1][v])
|
|
|
|
|
|
|
|
const l = horizon ? '1' : '0'
|
|
|
|
|
|
|
|
this.labelTagGap = Math.abs(labelTagPos[0][l] - labelTagPos[1][l])
|
|
|
|
},
|
|
|
|
calcTagColor () {
|
|
|
|
const { defaultXAxisLineColor, defaultYAxisLineColor, drawColors, data } = this
|
|
|
|
|
|
|
|
const { x: { color: xc }, y: { color: yc } } = data
|
|
|
|
|
|
|
|
let xTagColor = xc || defaultXAxisLineColor
|
|
|
|
|
|
|
|
xTagColor === 'colors' && (xTagColor = drawColors)
|
|
|
|
|
|
|
|
let yTagColor = yc || defaultYAxisLineColor
|
|
|
|
|
|
|
|
yTagColor === 'colors' && (yTagColor = drawColors)
|
|
|
|
|
|
|
|
this.xTagColor = xTagColor
|
|
|
|
|
|
|
|
this.xTagColorMul = xTagColor instanceof Array
|
|
|
|
|
|
|
|
this.yTagColor = yTagColor
|
|
|
|
|
|
|
|
this.yTagColorMul = yTagColor instanceof Array
|
|
|
|
},
|
2018-12-20 22:36:22 +08:00
|
|
|
calcGridColor () {
|
|
|
|
const { drawColors, data, defaultGridColor } = this
|
|
|
|
|
|
|
|
const { x: { gridColor: xgc }, y: { gridColor: ygc } } = data
|
|
|
|
|
|
|
|
let xGridColor = xgc || defaultGridColor
|
|
|
|
let yGridColor = ygc || defaultGridColor
|
|
|
|
|
|
|
|
xGridColor === 'colors' && (xGridColor = drawColors)
|
|
|
|
yGridColor === 'colors' && (yGridColor = drawColors)
|
|
|
|
|
|
|
|
this.xGridColor = xGridColor
|
|
|
|
this.yGridColor = yGridColor
|
|
|
|
|
|
|
|
this.xGridColorMul = xGridColor instanceof Array
|
|
|
|
this.yGridColorMul = yGridColor instanceof Array
|
|
|
|
},
|
2018-12-20 18:25:49 +08:00
|
|
|
drawAxis () {
|
2018-12-21 14:46:55 +08:00
|
|
|
const { drawAxisLine, drawAxisTag, drawUnit, drawGrid } = this
|
2018-12-20 18:25:49 +08:00
|
|
|
|
|
|
|
drawAxisLine()
|
|
|
|
|
|
|
|
drawAxisTag()
|
2018-12-20 22:36:22 +08:00
|
|
|
|
2018-12-21 14:46:55 +08:00
|
|
|
drawUnit()
|
|
|
|
|
2018-12-20 22:36:22 +08:00
|
|
|
drawGrid()
|
2018-12-20 18:25:49 +08:00
|
|
|
},
|
|
|
|
drawAxisLine () {
|
|
|
|
const { ctx, defaultXAxisLineColor, defaultYAxisLineColor, axisOriginPos, axisWH, data } = this
|
|
|
|
|
2018-12-21 14:46:55 +08:00
|
|
|
const { x: { lineColor: xlc, noAxisLine: xNAL }, y: { lineColor: ylc, noAxisLine: yNAL } } = data
|
2018-12-20 18:25:49 +08:00
|
|
|
|
2018-12-21 14:46:55 +08:00
|
|
|
if (xNAL && yNAL) return
|
2018-12-20 18:25:49 +08:00
|
|
|
|
2018-12-21 14:46:55 +08:00
|
|
|
ctx.lineWidth = 1
|
2018-12-20 18:25:49 +08:00
|
|
|
|
2018-12-21 14:46:55 +08:00
|
|
|
if (!xNAL) {
|
|
|
|
ctx.strokeStyle = xlc || defaultXAxisLineColor
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.moveTo(...axisOriginPos)
|
|
|
|
ctx.lineTo(axisOriginPos[0] + axisWH[0], axisOriginPos[1])
|
|
|
|
ctx.stroke()
|
|
|
|
}
|
2018-12-20 18:25:49 +08:00
|
|
|
|
2018-12-21 14:46:55 +08:00
|
|
|
if (!yNAL) {
|
|
|
|
ctx.strokeStyle = ylc || defaultYAxisLineColor
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.moveTo(...axisOriginPos)
|
|
|
|
ctx.lineTo(axisOriginPos[0], axisOriginPos[1] - axisWH[1])
|
|
|
|
ctx.stroke()
|
|
|
|
}
|
2018-12-20 18:25:49 +08:00
|
|
|
},
|
|
|
|
drawAxisTag () {
|
|
|
|
const { ctx, horizon, valueTagPos, labelTagPos, valueAxisTag, labelAxisTag } = this
|
|
|
|
|
|
|
|
const { xTagColor, xTagColorMul, yTagColor, yTagColorMul, xyAxisFS } = this
|
|
|
|
|
2018-12-21 14:46:55 +08:00
|
|
|
const { data: { x: { noAxisTag: xNAT, rotate }, y: { noAxisTag: yNAT } } } = this
|
|
|
|
|
|
|
|
if (xNAT && yNAT) return
|
|
|
|
|
2018-12-20 18:25:49 +08:00
|
|
|
const xAxisData = horizon ? valueTagPos : labelTagPos
|
|
|
|
const yAxisData = horizon ? labelTagPos : valueTagPos
|
|
|
|
|
|
|
|
const xTagData = horizon ? valueAxisTag : labelAxisTag
|
|
|
|
const yTagData = horizon ? labelAxisTag : valueAxisTag
|
|
|
|
|
|
|
|
!xTagColorMul && (ctx.fillStyle = xTagColor)
|
|
|
|
|
|
|
|
const xTagColorNum = xTagColor.length
|
|
|
|
|
|
|
|
ctx.font = `${xyAxisFS[0]}px Arial`
|
|
|
|
|
|
|
|
ctx.textAlign = 'center'
|
|
|
|
ctx.textBaseline = 'top'
|
|
|
|
|
2018-12-21 14:46:55 +08:00
|
|
|
if (rotate) ctx.textAlign = 'left'
|
|
|
|
|
|
|
|
!xNAT && xAxisData.forEach((pos, i) => {
|
|
|
|
if (!xTagData[i]) return
|
|
|
|
|
|
|
|
if (rotate) {
|
|
|
|
ctx.save()
|
|
|
|
ctx.translate(...pos)
|
|
|
|
ctx.rotate(Math.PI / 4)
|
|
|
|
}
|
|
|
|
|
2018-12-20 18:25:49 +08:00
|
|
|
xTagColorMul && (ctx.fillStyle = xTagColor[i % xTagColorNum])
|
|
|
|
|
2018-12-21 14:46:55 +08:00
|
|
|
ctx.fillText(xTagData[i], ...(rotate ? [0, 0] : pos))
|
|
|
|
|
|
|
|
if (rotate) ctx.restore()
|
2018-12-20 18:25:49 +08:00
|
|
|
})
|
|
|
|
|
|
|
|
!yTagColorMul && (ctx.fillStyle = yTagColor)
|
|
|
|
|
|
|
|
const yTagColorNum = yTagColor.length
|
|
|
|
|
|
|
|
ctx.font = `${xyAxisFS[1]}px Arial`
|
|
|
|
|
|
|
|
ctx.textAlign = 'right'
|
|
|
|
ctx.textBaseline = 'middle'
|
|
|
|
|
2018-12-21 14:46:55 +08:00
|
|
|
!yNAT && yAxisData.forEach((pos, i) => {
|
|
|
|
if (!yTagData[i]) return
|
|
|
|
|
2018-12-20 18:25:49 +08:00
|
|
|
xTagColorMul && (ctx.fillStyle = yTagColor[i % yTagColorNum])
|
|
|
|
|
|
|
|
ctx.fillText(yTagData[i], ...pos)
|
|
|
|
})
|
|
|
|
|
|
|
|
this.ctx.fill()
|
2018-12-20 22:36:22 +08:00
|
|
|
},
|
2018-12-21 14:46:55 +08:00
|
|
|
drawUnit () {
|
|
|
|
const { ctx, data, axisOriginPos, canvasWH, defaultAxisLabelGap } = this
|
|
|
|
|
|
|
|
const { x: { unit: xUN, fontSize: xFS }, y: { unit: yUN, fontSize: yFS } } = data
|
|
|
|
|
|
|
|
ctx.font = `${xFS}px Arial`
|
|
|
|
|
|
|
|
ctx.textAlign = 'right'
|
|
|
|
ctx.textBaseline = 'top'
|
|
|
|
ctx.fillText(xUN || '', canvasWH[0], axisOriginPos[1] + defaultAxisLabelGap)
|
|
|
|
|
|
|
|
ctx.font = `${yFS}px Arial`
|
|
|
|
|
|
|
|
ctx.fillText(yUN || '', axisOriginPos[0], 0)
|
|
|
|
},
|
2018-12-20 22:36:22 +08:00
|
|
|
drawGrid () {
|
|
|
|
const { horizon, labelTagPos, valueTagPos, axisOriginPos, ctx, data, axisWH } = this
|
|
|
|
|
|
|
|
const { xGridColor, xGridColorMul, yGridColor, yGridColorMul, axisType } = this
|
|
|
|
|
|
|
|
const { x: { grid: xG, gridType: xT }, y: { grid: yG, gridType: yT }, boundaryGap } = data
|
|
|
|
|
|
|
|
const xAxisData = horizon ? valueTagPos : labelTagPos
|
|
|
|
const yAxisData = horizon ? labelTagPos : valueTagPos
|
|
|
|
|
|
|
|
ctx.lineWidth = 1
|
|
|
|
|
|
|
|
!xGridColorMul && (ctx.strokeStyle = xGridColor)
|
|
|
|
|
|
|
|
const xGridColorNum = xGridColor.length
|
|
|
|
|
|
|
|
ctx.setLineDash(xT === 'dashed' ? [5, 5] : [10, 0])
|
|
|
|
|
|
|
|
xG && xAxisData.forEach(([x, y], i) => {
|
|
|
|
xGridColorMul && (ctx.strokeStyle = xGridColor[i % xGridColorNum])
|
|
|
|
|
|
|
|
if (!horizon && i === 0 && axisType === 'line' && !boundaryGap) return
|
|
|
|
if (horizon && i === 0) return
|
|
|
|
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.moveTo(x, axisOriginPos[1])
|
|
|
|
ctx.lineTo(x, axisOriginPos[1] - axisWH[1])
|
|
|
|
ctx.stroke()
|
|
|
|
})
|
|
|
|
|
|
|
|
!yGridColorMul && (ctx.strokeStyle = yGridColor)
|
|
|
|
|
|
|
|
const yGridColorNum = yGridColor.length
|
|
|
|
|
|
|
|
ctx.setLineDash(yT === 'dashed' ? [5, 5] : [10, 0])
|
|
|
|
|
|
|
|
yG && yAxisData.forEach(([x, y], i) => {
|
|
|
|
yGridColorMul && (ctx.strokeStyle = yGridColor[i % yGridColorNum])
|
|
|
|
|
|
|
|
if (!horizon && i === 0) return
|
|
|
|
if (horizon && i === 0 && axisType === 'line' && !boundaryGap) return
|
|
|
|
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.moveTo(axisOriginPos[0], y)
|
|
|
|
ctx.lineTo(axisOriginPos[0] + axisWH[0], y)
|
|
|
|
ctx.stroke()
|
|
|
|
})
|
2018-12-20 18:25:49 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|