Commit 4b9f3775 authored by 郭铭瑶's avatar 郭铭瑶 🤘

同步翻新组件库

parent 762c3106
---
title: MyAnimate
wrapperClass: my-animate
---
# MyAnimate
基于[animate.css](https://animate.style/)封装的动画组件,对包裹其中的元素实现进入、离开时的动画。
Tag: `m-animate`
```vue demo
<template>
<m-animate enter="fadeInLeft" leave="fadeOutLeft">
<h1 v-show="show">Animate 1</h1>
</m-animate>
<m-animate enter="zoomInDown" leave="zoomOutUp">
<h1 v-show="show">Animate 2</h1>
</m-animate>
<m-animate enter="slideInRight" leave="slideOutRight">
<h1 v-show="show">Animate 3</h1>
</m-animate>
<button @click="show = !show">Click Me!</button>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const show = ref(true)
return {
show,
}
},
}
</script>
```
## Props
| props | description | type | default |
| -------- | ------------------ | ------ | ------- |
| enter | 进入动画名 | string | - |
| leave | 离开动画名 | string | - |
| duration | 动画执行时间(毫秒) | number | 500 |
......@@ -17,10 +17,12 @@ export default defineComponent({
name: 'MyAnimate',
displayName: 'm-animate',
props: {
/** 进入动画 */
enter: {
type: String as PropType<string>,
required: true,
},
/** 离开动画 */
leave: {
type: String as PropType<string>,
required: true,
......
---
title: MyCard
wrapperClass: my-card
---
# MyCard
模块包裹组件
Tag: `m-card`
```vue demo
<template>
<m-card title="这是标题"><h1>内容或组件</h1></m-card>
<m-card title="这是标题" mode="2"><h1>内容或组件</h1></m-card>
</template>
```
## Props
| props | description | type | default |
| ----- | ----------- | --------------- | ----------- |
| title | 标题名 | string | - |
| mode | 模式选择 | string / number | 1 |
| enter | 进入动画名 | string | fadeInLeft |
| leave | 离开动画名 | string | fadeOutLeft |
......@@ -4,48 +4,11 @@
<script lang="ts">
import { defineComponent, onMounted, PropType, watchEffect } from 'vue'
import * as echarts from 'echarts/core'
import {
DatasetComponent,
DatasetComponentOption,
TitleComponent,
TitleComponentOption,
TooltipComponent,
TooltipComponentOption,
GridComponent,
GridComponentOption,
LegendComponent,
LegendComponentOption,
} from 'echarts/components'
import {
LineChart,
LineSeriesOption,
BarChart,
BarSeriesOption,
} from 'echarts/charts'
import { SVGRenderer } from 'echarts/renderers'
echarts.use([
DatasetComponent,
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
LineChart,
BarChart,
SVGRenderer,
])
import useChartGenerate from '@/hooks/useChartGenerate.ts'
type ECOption = echarts.ComposeOption<
| DatasetComponentOption
| TitleComponentOption
| TooltipComponentOption
| GridComponentOption
| LegendComponentOption
| LineSeriesOption
| BarSeriesOption
>
import { use } from 'echarts/core'
import { LineChart, BarChart } from 'echarts/charts'
use([LineChart, BarChart])
import useChartGenerate from './useChartGenerate'
import { BarOption, DatasetComponentOption } from './types'
export default defineComponent({
name: 'MyBar',
......@@ -56,18 +19,12 @@ export default defineComponent({
default: null,
},
option: {
type: Object as PropType<ECOption>,
default: null,
},
format: {
type: Function as PropType<
(dataset: DatasetComponentOption, option: ECOption) => ECOption
>,
type: Object as PropType<BarOption>,
default: null,
},
},
setup(props) {
const defaultOption: ECOption = {
const defaultOption: BarOption = {
backgroundColor: 'transparent',
tooltip: {
confine: true,
......@@ -108,7 +65,7 @@ export default defineComponent({
},
],
}
const defaultSeriesItem: BarSeriesOption = {
const defaultSeriesItem = {
type: 'bar',
barGap: 0,
emphasis: {
......@@ -117,15 +74,10 @@ export default defineComponent({
}
const { chartRef, initChart } = useChartGenerate(
defaultOption,
defaultSeriesItem,
props.format
defaultSeriesItem
)
onMounted(() => {
initChart(props.dataset, props.option)
})
watchEffect(() => {
initChart(props.dataset, props.option)
})
onMounted(() => initChart(props.dataset, props.option))
watchEffect(() => initChart(props.dataset, props.option))
return {
chartRef,
}
......
This diff is collapsed.
......@@ -3,50 +3,12 @@
</template>
<script lang="ts">
import { defineComponent, onMounted, PropType, watchEffect } from 'vue'
import * as echarts from 'echarts/core'
import {
DatasetComponent,
DatasetComponentOption,
TitleComponent,
TitleComponentOption,
TooltipComponent,
TooltipComponentOption,
GridComponent,
GridComponentOption,
LegendComponent,
LegendComponentOption,
DataZoomComponent,
} from 'echarts/components'
import {
LineChart,
LineSeriesOption,
BarChart,
BarSeriesOption,
} from 'echarts/charts'
import { SVGRenderer } from 'echarts/renderers'
echarts.use([
DatasetComponent,
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
DataZoomComponent,
LineChart,
BarChart,
SVGRenderer,
])
import useChartGenerate from '@/hooks/useChartGenerate'
export type ECOption = echarts.ComposeOption<
| DatasetComponentOption
| TitleComponentOption
| TooltipComponentOption
| GridComponentOption
| LegendComponentOption
| LineSeriesOption
| BarSeriesOption
>
import { defineComponent, PropType, onMounted, watchEffect } from 'vue'
import { use } from 'echarts/core'
import { LineChart, BarChart } from 'echarts/charts'
use([LineChart, BarChart])
import useChartGenerate from './useChartGenerate'
import { LineOption, DatasetComponentOption } from './types'
export default defineComponent({
name: 'MyLine',
......@@ -57,18 +19,12 @@ export default defineComponent({
default: null,
},
option: {
type: Object as PropType<ECOption>,
default: null,
},
format: {
type: Function as PropType<
(dataset: DatasetComponentOption, option: ECOption) => ECOption
>,
type: Object as PropType<LineOption>,
default: null,
},
},
setup(props) {
const defaultOption: ECOption = {
const defaultOption: LineOption = {
backgroundColor: 'transparent',
tooltip: {
confine: true,
......@@ -104,7 +60,7 @@ export default defineComponent({
},
],
}
const defaultSeriesItem: LineSeriesOption = {
const defaultSeriesItem = {
type: 'line',
smooth: true,
lineStyle: {
......@@ -116,15 +72,10 @@ export default defineComponent({
}
const { chartRef, initChart } = useChartGenerate(
defaultOption,
defaultSeriesItem,
props.format
defaultSeriesItem
)
onMounted(async () => {
initChart(props.dataset, props.option)
})
watchEffect(() => {
initChart(props.dataset, props.option)
})
onMounted(() => initChart(props.dataset, props.option))
watchEffect(() => initChart(props.dataset, props.option))
return {
chartRef,
}
......
......@@ -3,41 +3,12 @@
</template>
<script lang="ts">
import { defineComponent, onMounted, PropType, watchEffect } from 'vue'
import * as echarts from 'echarts/core'
import {
DatasetComponent,
DatasetComponentOption,
TitleComponent,
TitleComponentOption,
TooltipComponent,
TooltipComponentOption,
GridComponent,
GridComponentOption,
LegendComponent,
LegendComponentOption,
} from 'echarts/components'
import { PieChart, PieSeriesOption } from 'echarts/charts'
import { SVGRenderer } from 'echarts/renderers'
echarts.use([
DatasetComponent,
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
PieChart,
SVGRenderer,
])
import useChartGenerate from '@/hooks/useChartGenerate'
type ECOption = echarts.ComposeOption<
| DatasetComponentOption
| TitleComponentOption
| TooltipComponentOption
| GridComponentOption
| LegendComponentOption
| PieSeriesOption
>
import { defineComponent, PropType, onMounted, watchEffect } from 'vue'
import { use } from 'echarts/core'
import { PieChart } from 'echarts/charts'
use([PieChart])
import useChartGenerate from './useChartGenerate'
import { PieOption, DatasetComponentOption } from './types'
export default defineComponent({
name: 'MyPie',
......@@ -48,18 +19,12 @@ export default defineComponent({
default: null,
},
option: {
type: Object as PropType<ECOption>,
default: null,
},
format: {
type: Function as PropType<
(dataset: DatasetComponentOption, option: ECOption) => ECOption
>,
type: Object as PropType<PieOption>,
default: null,
},
},
setup(props) {
const defaultOption: ECOption = {
const defaultOption: PieOption = {
backgroundColor: 'transparent',
tooltip: {
confine: true,
......@@ -73,7 +38,7 @@ export default defineComponent({
containLabel: true,
},
}
const defaultSeriesItem: PieSeriesOption = {
const defaultSeriesItem = {
type: 'pie',
radius: ['30%', '50%'],
center: ['50%', '55%'],
......@@ -87,15 +52,10 @@ export default defineComponent({
}
const { chartRef, initChart } = useChartGenerate(
defaultOption,
defaultSeriesItem,
props.format
defaultSeriesItem
)
onMounted(async () => {
initChart(props.dataset, props.option)
})
watchEffect(() => {
initChart(props.dataset, props.option)
})
onMounted(() => initChart(props.dataset, props.option))
watchEffect(() => initChart(props.dataset, props.option))
return {
chartRef,
}
......
......@@ -3,41 +3,12 @@
</template>
<script lang="ts">
import { defineComponent, onMounted, PropType, watchEffect } from 'vue'
import * as echarts from 'echarts/core'
import {
DatasetComponent,
DatasetComponentOption,
TitleComponent,
TitleComponentOption,
TooltipComponent,
TooltipComponentOption,
GridComponent,
GridComponentOption,
LegendComponent,
LegendComponentOption,
} from 'echarts/components'
import { RadarChart, RadarSeriesOption } from 'echarts/charts'
import { SVGRenderer } from 'echarts/renderers'
echarts.use([
DatasetComponent,
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
RadarChart,
SVGRenderer,
])
import useChartGenerate from '@/hooks/useChartGenerate'
type ECOption = echarts.ComposeOption<
| DatasetComponentOption
| TitleComponentOption
| TooltipComponentOption
| GridComponentOption
| LegendComponentOption
| RadarSeriesOption
>
import { defineComponent, PropType, onMounted, watchEffect } from 'vue'
import { use } from 'echarts/core'
import { RadarChart } from 'echarts/charts'
use([RadarChart])
import useChartGenerate from './useChartGenerate'
import { RadarOption, DatasetComponentOption } from './types'
export default defineComponent({
name: 'MyRadar',
......@@ -48,18 +19,12 @@ export default defineComponent({
default: null,
},
option: {
type: Object as PropType<ECOption>,
default: null,
},
format: {
type: Function as PropType<
(dataset: DatasetComponentOption, option: ECOption) => ECOption
>,
type: Object as PropType<RadarOption>,
default: null,
},
},
setup(props) {
const defaultOption: ECOption = {
const defaultOption: RadarOption = {
backgroundColor: 'transparent',
tooltip: {
confine: true,
......@@ -74,7 +39,8 @@ export default defineComponent({
},
radar: {
axisName: {
show: false,
// show: false,
color: 'transparent',
textStyle: {
color: '#fff',
backgroundColor: 'rgba(255,255,255,.3)',
......@@ -108,7 +74,7 @@ export default defineComponent({
radius: '55%',
},
}
const defaultSeriesItem: RadarSeriesOption = {
const defaultSeriesItem = {
type: 'radar',
symbol: 'none',
areaStyle: {
......@@ -119,11 +85,18 @@ export default defineComponent({
},
}
const { chartRef, initChart } = useChartGenerate(
props.option ? Object.assign(defaultOption, props.option) : defaultOption,
defaultSeriesItem,
props.format
defaultOption,
defaultSeriesItem
)
onMounted(async () => {
onMounted(() => {
// eslint-disable-next-line
;(defaultOption as any).radar.indicator =
props.dataset &&
props.dataset.dimensions &&
props.dataset.dimensions.map((d) => ({
name: (d as any).displayName,
max: (d as any).max,
}))
initChart(props.dataset, props.option)
})
watchEffect(() => {
......
......@@ -3,41 +3,12 @@
</template>
<script lang="ts">
import { defineComponent, onMounted, PropType, watchEffect } from 'vue'
import * as echarts from 'echarts/core'
import {
DatasetComponent,
DatasetComponentOption,
TitleComponent,
TitleComponentOption,
TooltipComponent,
TooltipComponentOption,
GridComponent,
GridComponentOption,
LegendComponent,
LegendComponentOption,
} from 'echarts/components'
import { ScatterChart, ScatterSeriesOption } from 'echarts/charts'
import { SVGRenderer } from 'echarts/renderers'
echarts.use([
DatasetComponent,
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
ScatterChart,
SVGRenderer,
])
import useChartGenerate from '@/hooks/useChartGenerate'
type ECOption = echarts.ComposeOption<
| DatasetComponentOption
| TitleComponentOption
| TooltipComponentOption
| GridComponentOption
| LegendComponentOption
| ScatterSeriesOption
>
import { defineComponent, PropType, onMounted, watchEffect } from 'vue'
import { use } from 'echarts/core'
import { ScatterChart, EffectScatterChart } from 'echarts/charts'
use([ScatterChart, EffectScatterChart])
import useChartGenerate from './useChartGenerate'
import { ScatterOption, DatasetComponentOption } from './types'
export default defineComponent({
name: 'MyScatter',
......@@ -48,18 +19,12 @@ export default defineComponent({
default: null,
},
option: {
type: Object as PropType<ECOption>,
default: null,
},
format: {
type: Function as PropType<
(dataset: DatasetComponentOption, option: ECOption) => ECOption
>,
type: Object as PropType<ScatterOption>,
default: null,
},
},
setup(props) {
const defaultOption: ECOption = {
const defaultOption: ScatterOption = {
backgroundColor: 'transparent',
tooltip: {
confine: true,
......@@ -75,20 +40,15 @@ export default defineComponent({
xAxis: {},
yAxis: {},
}
const defaultSeriesItem: ScatterSeriesOption = {
const defaultSeriesItem = {
type: 'scatter',
}
const { chartRef, initChart } = useChartGenerate(
defaultOption,
defaultSeriesItem,
props.format
defaultSeriesItem
)
onMounted(async () => {
initChart(props.dataset, props.option)
})
watchEffect(() => {
initChart(props.dataset, props.option)
})
onMounted(() => initChart(props.dataset, props.option))
watchEffect(() => initChart(props.dataset, props.option))
return {
chartRef,
}
......
import { ComposeOption } from 'echarts/core'
import {
DatasetComponentOption as DatasetOption,
TitleComponentOption,
TooltipComponentOption,
GridComponentOption,
LegendComponentOption,
DataZoomComponentOption,
} from 'echarts/components'
import {
LineSeriesOption,
BarSeriesOption,
PieSeriesOption,
RadarSeriesOption,
ScatterSeriesOption,
} from 'echarts/charts'
/** Dataset选项参数 */
export type DatasetComponentOption = DatasetOption
/** 附加组件的选项参数(如title、tooltip、legend等) */
export type ComponentsOption = ComposeOption<
| DatasetComponentOption
| TitleComponentOption
| TooltipComponentOption
| GridComponentOption
| LegendComponentOption
| DataZoomComponentOption
>
/** 所有选项参数 */
export type ECOption = ComposeOption<
| LineSeriesOption
| BarSeriesOption
| PieSeriesOption
| RadarSeriesOption
| ScatterSeriesOption
> &
ComponentsOption
/** 柱状图选项参数 */
export type BarOption = ComponentsOption &
ComposeOption<LineSeriesOption | BarSeriesOption>
/** 折线图选项参数 */
export type LineOption = ComponentsOption &
ComposeOption<LineSeriesOption | BarSeriesOption>
/** 饼图选项参数 */
export type PieOption = ComponentsOption & ComposeOption<PieSeriesOption>
/** 雷达图选项参数 */
export type RadarOption = ComponentsOption & ComposeOption<RadarSeriesOption>
/** 散点图选项参数 */
export type ScatterOption = ComponentsOption &
ComposeOption<ScatterSeriesOption>
import { onMounted, onBeforeUnmount, nextTick, shallowRef, Ref } from 'vue'
import { use, init, graphic, ECharts } from 'echarts/core'
import { SVGRenderer } from 'echarts/renderers'
import {
DatasetComponent,
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
DataZoomComponent,
} from 'echarts/components'
use([
SVGRenderer,
DatasetComponent,
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
DataZoomComponent,
])
import { RadarSeriesOption } from 'echarts/charts'
import { ECOption, RadarOption, DatasetComponentOption } from './types'
interface ReturnProp {
chartRef: Ref<null | HTMLElement>
initChart: (dataset: DatasetComponentOption, option?: ECOption) => void
}
/**
* 根据屏幕调整尺寸
* @param myChart Echarts实例引用
* @param chartRef Echarts容器引用
*/
const setResizeAble = (myChart: Ref, chartRef: Ref) => {
const handleResize = () => {
if (!myChart.value) return
myChart.value.resize()
}
onMounted(async () => {
window.addEventListener('resize', handleResize)
await nextTick()
myChart.value = init(chartRef.value as HTMLElement, 'dark')
})
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize)
if (!myChart.value) return
myChart.value.dispose()
myChart.value = null
})
}
/**
* 由于radar图的dataset支持不好
* 故此根据数据集里source数组里的seriesName来重置tooltip显示的名字
* @param defaultOption 图表默认配置
* @param defaultSeriesItem 默认series项
* @param dataset 数据集
* @returns 转换后的图表配置
*/
const transRadarOption = (
defaultOption: RadarOption,
defaultSeriesItem: RadarSeriesOption,
dataset: DatasetComponentOption
): RadarOption => {
const source = dataset && (dataset.source as any[])
const length = (source && source.length) || 0
const result = Object.assign({}, defaultOption)
const seriesData = []
for (let index = 0; index < length; index++) {
const data: number[] = []
Object.keys(source[index]).forEach((key) => {
if (key !== 'seriesName') {
data.push(source[index][key])
}
})
seriesData.push(
Object.assign({}, defaultSeriesItem, {
value: data,
name: source[index].seriesName,
})
)
}
result.series = [
{
type: 'radar',
data: seriesData as any[],
},
]
if (dataset) result.dataset = dataset
return result
}
/**
* 设置color选项中
* 如果有数组项则封装为渐变
* @param options 图表配置
*/
const transLinearColorOption = (options: ECOption): ECOption => {
if (!options.color || (options.color as string[]).length === 0) {
return options
}
const result = Object.assign({}, options)
result.color = (result.color as string[]).map((color) => {
if (Array.isArray(color)) {
if (color.length < 2) {
return color[0]
}
return new graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: color[0],
},
{
offset: 1,
color: color[1],
},
])
}
return color
})
return result
}
/**
* 将defaultSeriesItem和dataset填充进defaultOption形成初始配置项
* @param defaultOption 默认图表配置
* @param defaultSeriesItem 默认series项
* @param dataset 数据集
* @returns 初始配置项
*/
const defaultConfig = <T>(
defaultOption: ECOption,
defaultSeriesItem: T,
dataset: DatasetComponentOption
): ECOption => {
const result = Object.assign({}, defaultOption)
let length = 0
result.series = []
if (dataset) {
result.dataset = dataset
if (dataset.dimensions) {
length = dataset.dimensions.length - 1
} else if (dataset.source && Array.isArray(dataset.source)) {
length = Object.keys(dataset.source[0] || []).length - 1
}
}
for (let index = 0; index < length; index++) {
result.series.push(defaultSeriesItem)
}
return result
}
/**
* 合并默认配置项和自定义配置项
* @param defaultOption 默认图表配置
* @param customOption 自定义图表配置
*/
const mergeOptions = <T>(defaultOption: T, customOption: T) => {
if (!customOption) return
for (const key in customOption) {
if (Array.isArray(customOption[key])) {
defaultOption[key] = customOption[key]
continue
}
if (customOption[key] !== null && typeof customOption[key] === 'object') {
if (!defaultOption[key]) {
defaultOption[key] = customOption[key]
} else {
mergeOptions(defaultOption[key], customOption[key])
}
} else {
defaultOption[key] = customOption[key]
}
}
}
/**
* 构建图表组件公共方法
* @param defaultOption 默认配置
* @param defaultSeriesItem 默认的series项
* @returns chartRef:Echarts容器引用, initChart:初始化方法
*/
const useChartGenerate = <T>(
defaultOption: ECOption,
defaultSeriesItem: T
): ReturnProp => {
const chartRef = shallowRef<null | HTMLElement>(null)
const myChart = shallowRef<null | ECharts>(null)
setResizeAble(myChart, chartRef)
/**
* 根据数据集和配置初始化图表
* @param dataset 数据集
* @param option 自定义图表配置
*/
const initChart = (dataset: DatasetComponentOption, option?: ECOption) => {
if (!myChart.value) return
const config =
(defaultSeriesItem as any).type === 'radar'
? transRadarOption(
defaultOption as RadarOption,
defaultSeriesItem as RadarSeriesOption,
dataset
)
: defaultConfig(defaultOption, defaultSeriesItem, dataset)
mergeOptions(config, option)
myChart.value.setOption(transLinearColorOption(config), true)
}
return { chartRef, initChart }
}
export default useChartGenerate
---
title: MyCount
wrapperClass: my-count
---
# MyCount
数字跳动展示组件
Tag: `m-count`
```vue demo
<template>
<div><m-count :value="99999" /></div>
<div><m-count :value="99999" :speed="1" /></div>
<div><m-count :value="99999" :decimal="2" /></div>
<div><m-count :value="99999" auto-play :duration="5" /></div>
</template>
```
## Props
| props | description | type | default |
| --------- | ---------------------------------------- | --------------- | ------- |
| value | 展示数字 | number / string | 0 |
| decimal | 保留几位小数 | number / string | 0 |
| speed | 数字跳动速度(秒) | number / string | 2 |
| auto-play | 是否定时自动跳动 | boolean | false |
| duration | auto-play 开启后,每次跳动间隔时间(秒) | number / string | 10 |
......@@ -17,6 +17,7 @@ export default defineComponent({
name: 'MyCount',
displayName: 'm-count',
props: {
/** 展示值 */
value: {
type: [Number, String] as PropType<number | string>,
default: 0,
......@@ -61,6 +62,7 @@ export default defineComponent({
countUp.start()
} else {
console.error(`m-count error: ${countUp.error}`)
return
}
countUpInstance.value = countUp
if (props.autoPlay) {
......
---
title: MyDrawer
wrapperClass: my-drawer
---
# MyDrawer
侧边抽屉组件
Tag: `m-drawer`
```vue demo
<template>
<m-drawer v-model="show" @close="handleClose">
<h1>内容……</h1>
</m-drawer>
<button @click="show = true">Click Me!</button>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const show = ref(false)
const handleClose = () => {
console.log(
'可以使用close回调,或者直接watch v-model的值进行关闭后的操作'
)
}
return {
show,
handleClose,
}
},
}
</script>
```
## Props
| props | description | type | default |
| -------------------- | ----------- | ------- | ------- |
| v-model / modelValue | 值 | boolean | false |
| width | 抽屉宽度 | string | 49vw |
## Events
| events | description | arguments |
| ------ | ---------------- | --------- |
| close | 关闭抽屉触发事件 | - |
......@@ -23,18 +23,21 @@ export default defineComponent({
displayName: 'm-drawer',
components: { MyAnimate },
props: {
/** 值 */
modelValue: {
type: Boolean as PropType<boolean>,
default: false,
},
/** 宽度 */
width: {
type: String as PropType<string>,
default: '49vw',
},
maskClosable: {
type: Boolean as PropType<boolean>,
default: true,
},
// /** 点击蒙层是否允许关闭 */
// maskClosable: {
// type: Boolean as PropType<boolean>,
// default: true,
// },
},
emits: ['update:modelValue', 'close'],
setup(_, ctx) {
......
---
title: MyEmpty
wrapperClass: my-empty
---
# MyEmpty
无数据时展示
Tag: `m-empty`
```vue demo
<template>
<m-empty text="建设中" />
</template>
```
## Props
| props | description | type | default |
| ----- | ----------- | ------ | -------- |
| text | 展示信息 | string | 暂无数据 |
......@@ -12,6 +12,7 @@ export default defineComponent({
name: 'MyEmpty',
displayName: 'm-empty',
props: {
/** 展示信息 */
text: {
type: String as PropType<string>,
default: '暂无数据',
......
---
title: MyForm
wrapperClass: my-form
---
# MyForm
Form 表单组件
Tag: `m-form`
### Basic Use
```vue demo
<template>
<m-form
:template="[
'key1:标题1|key2:标题2|key3:标题3',
'key4:标题4|key5:标题5|key6:标题6',
]"
:data="formData"
/>
</template>
<script>
export default {
setup() {
return {
formData: {
key1: '测试1',
key2: '测试2',
key3: '测试3',
key4: '测试4',
key5: '测试5',
key6: '测试6',
},
}
},
}
</script>
```
### Advanced Use
```vue demo
<template>
<m-form
:template="[
'name:小区名称|address:小区地址*3',
'belong:所属居委会|buildingNum:总门牌幢数|roomNum:总户数>formatRoomNum|',
'||buildingArea:总建筑面积>formatArea|area:占地面积>formatArea',
'rang:小区四至范围|excludeRang:四至范围不包括',
'photo:照片#image',
]"
:data="formData"
:formatter="formatter"
/>
</template>
<script>
export default {
setup() {
return {
formData: {
name: '测试文字',
photo: 'https://avatars2.githubusercontent.com/u/43328103?v=4',
address: '测试文字',
belong: '测试文字',
buildingNum: '测试文字',
roomNum: '测试文字',
buildingArea: '测试文字',
area: '测试文字',
rang: '测试文字',
excludeRang: '测试文字',
},
formatter: {
formatArea: (area) => area + '㎡',
formatRoomNum: (val) => val + '万户',
},
}
},
}
</script>
```
## Props
| props | description | type | default |
| --------------------- | ---------------------- | -------- | ------- |
| [template](#template) | 布局模板 | string[] | - |
| data | 表单数据 | object | - |
| formatter | 数据格式化方法对象集合 | object | - |
| label-width | label 宽度 | string | 1rem |
### <i id="template">template introduction</i>
| tag | description |
| --- | ------------------------------------------------------------------------ |
| \| | 将每行划分为 col 块 |
| : | 冒号前为数据 key,冒号后为 label 名称 |
| \* | 后跟该 col 块所占行的比例 |
| > | 后跟该 col 块所需使用的 format 数据方法(方法需在 formatter 参数中定义) |
| # | 后跟该 col 块所属的特殊类型(目前仅实现 image) |
| = | 放在 col 块头则 label 左对齐,尾则右对齐(默认为右对齐) |
<template>
<div class="my-form" :style="{ fontSize: `${size}rem` }">
<a-row v-for="(row, rowIndex) in layout" :key="rowIndex" class="row">
<a-col
v-for="(col, key) in row"
:key="key"
class="col"
:span="col.width"
:offset="col.offset || 0"
>
<div class="my-form">
<div v-for="(row, rowIndex) in template" :key="rowIndex" class="row">
<div
:style="`text-align: ${
col.align || 'right'
}; width:${labelWidth}rem;`"
v-for="(col, colIndex) in row.split('|')"
:key="colIndex"
class="col"
:style="{ flex: calcWidth(col) }"
>
{{ col.label }}
</div>
<template v-if="col.type == 'img'">
<p :style="{ width: labelWidth, textAlign: calcAlign(col) }">
{{ getLabel(col) }}
</p>
<img
v-for="img in model[key] && model[key].split(',')"
:key="img"
:src="img"
@click="handleView(img)"
v-if="isImage(col)"
:src="data[isImage(col)]"
:draggable="false"
@click.stop="handleViewImage(data[isImage(col)])"
/>
</template>
<div v-else class="content">
{{ col.format ? col.format(model[key]) : model[key] || ' ' }}
<p v-else class="content">
{{ formatData(col) }}
</p>
</div>
</a-col>
</a-row>
</div>
<MyModal v-model="showImg" title="图片">
<img v-if="showImg" style="max-height: 45vh; width: 100%" :src="curImg" />
<MyModal v-model="showImgModal" title="照片预览">
<img
v-if="showImgModal && imgSrc"
style="max-height: 45vh; width: 100%"
:src="imgSrc"
/>
</MyModal>
</div>
</template>
<script lang="ts">
import { defineComponent, PropType, ref } from 'vue'
import MyModal from '../MyModal/my-modal.vue'
interface ModelProp {
[key: string]: any
interface FormatterType {
[propName: string]: <T>(val: T) => T
}
interface LayoutItemProp {
label: string | number
width: number
offset?: number
align?: 'left' | 'center' | 'right'
type?: 'img'
format?: (arg: any) => any
}
export interface LayoutProp {
[key: string]: LayoutItemProp
interface DataType {
[propName: string]: string | number | string[] | number[]
}
export default defineComponent({
name: 'MyForm',
displayName: 'm-form',
components: {
MyModal,
},
components: { MyModal },
props: {
size: {
type: Number as PropType<number>,
default: 0.1,
},
labelWidth: {
type: Number as PropType<number>,
default: 1,
},
layout: {
type: Array as PropType<LayoutProp[]>,
/** 布局模板 */
template: {
type: Array as PropType<string[]>,
required: true,
},
model: {
type: Object as PropType<ModelProp>,
default() {
return {}
/** 数据 */
data: {
type: Object as PropType<DataType>,
default: null,
},
/** 数据的格式化方法对象集合 */
formatter: {
type: Object as PropType<FormatterType>,
default: null,
},
/** label宽度 */
labelWidth: {
type: String as PropType<string>,
default: '1rem',
},
},
setup() {
const showImg = ref(false)
const curImg = ref(null)
const handleView = (img: any) => {
curImg.value = img
showImg.value = true
setup(props) {
const calcWidth = (key: string): number => {
if (!key) return 1
if (key.match(/\*(\d*)[#>:]?/)) {
return +RegExp.$1
}
return 1
}
const getLabel = (key: string): string => {
if (!key) return ''
if (key.match(/:([\u4e00-\u9fa5]*[^#=>\*]*)[#>\*]?/)) {
return RegExp.$1 + ':'
}
return ''
}
const imgSrc = ref<string | null>(null)
const showImgModal = ref(false)
const handleViewImage = (src: string): void => {
imgSrc.value = src
showImgModal.value = true
}
/** 是图片则返回图片的key,否则返回false */
const isImage = (key: string): string | false => {
if (!key) return false
if (key.match(/#(\w*)[>:=]?/)) {
if (RegExp.$1 === 'image') {
key.match(/=?(\w*)[#>:]?/)
return RegExp.$1
}
return false
}
return false
}
const formatData = (key: string): unknown => {
if (!key) return ''
const { formatter, data } = props
key.match(/=?(\w*)[#>\*:]?/)
const dataKey = RegExp.$1
if (formatter && key.match(/>(\w*)[#\*:]?/)) {
return formatter[RegExp.$1](data[dataKey])
}
return data[dataKey] || ''
}
const calcAlign = (key: string): string => {
if (!key) return 'right'
const index = key.indexOf('=')
if (index === 0) return 'left'
if (index === key.length - 1) return 'right'
return 'right'
}
return {
showImg,
curImg,
handleView,
calcWidth,
getLabel,
handleViewImage,
isImage,
imgSrc,
showImgModal,
formatData,
calcAlign,
}
},
})
</script>
<style lang="stylus" scoped>
@import '../main.styl'
.my-form
$full()
.row
line-height 2
display flex
background $table-content-bg
padding .04rem 0
&:nth-child(odd)
background rgba(51,145,255,.2)
background transparent
.col
display flex
align-items center
p
padding 0 .05rem
.content
box-sizing border-box
>.content
flex 1
img
width 19%
height .5rem
margin .05rem .03rem .05rem 0
padding-left 0
>img
max-height .6rem
cursor pointer
</style>
---
title: MyGrid
wrapperClass: my-grid
---
# MyGrid
大屏布局组件
Tag: `m-grid`
```vue demo
<template>
<!-- 真实使用中不需要这个min-height, m-grid默认高度为父容器的100% -->
<m-grid
style="min-height: 50vh;"
:template="[
'title title title',
'box1 . box3',
'box2 . box3',
'box2 box4 box4',
]"
columns="1fr 1.5fr 1fr"
rows="0.4rem 1fr 1fr 1fr"
>
<m-title area="title">大标题</m-title>
<div area="box1" style="background:skyblue;padding:.1rem">
<h3>有area名的元素会被摆放至template中的同名位置</h3>
</div>
<m-card title="box2" area="box2">
<m-grid
:template="['inner1 inner2 inner3', 'inner4 inner4 inner3']"
columns="1rem 20% auto"
rows="30% 1fr"
>
<div area="inner1" style="background:gold"></div>
<div area="inner2" style="background:gold"></div>
<div area="inner3" style="background:gold"></div>
<div area="inner4" style="background:gold"></div>
</m-grid>
</m-card>
<m-card title="box3" area="box3"></m-card>
<div area="box4" style="background:brown;padding:.1rem"></div>
</m-grid>
</template>
```
## Props
| props | description | type | default |
| -------- | ------------ | -------- | ------- |
| template | 区块摆放模板 | string[] | - |
| columns | 列宽比例 | string | - |
| rows | 行高比例 | string | - |
| gap | 区块间隔 | string | 0.05rem |
......@@ -11,18 +11,22 @@ export default defineComponent({
name: 'MyGrid',
displayName: 'm-grid',
props: {
/** 区块摆放模板 */
template: {
type: Array as PropType<string[]>,
required: true,
},
/** 列宽比例 */
columns: {
type: String as PropType<string>,
required: true,
},
/** 行高比例 */
rows: {
type: String as PropType<string>,
required: true,
},
/** 区块间隔 */
gap: {
type: String as PropType<string>,
default: '.05rem',
......@@ -31,6 +35,7 @@ export default defineComponent({
setup(props) {
const gridRef = ref<HTMLElement | null>(null)
onMounted(() => {
if (!gridRef.value) return
const { children } = gridRef.value as HTMLElement
for (let i = 0; i < children.length; i++) {
const child = children[i] as HTMLElement
......@@ -68,8 +73,6 @@ export default defineComponent({
@import '../main.styl'
.my-grid
$full()
background-size cover
background-position center
position relative
display grid
overflow hidden
......
---
title: MyLoader
wrapperClass: my-loader
---
# MyLoader
Loading 组件
Tag: `m-loader`
```vue demo
<template>
<m-loader v-if="show" />
<button @click="handleClick">Click Me !</button>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const show = ref(false)
const handleClick = () => {
show.value = true
setTimeout(() => {
show.value = false
}, 3000)
}
return {
show,
handleClick,
}
},
}
</script>
```
## Props
| props | description | type | default |
| ----- | ----------- | ---- | ------- |
| - | - | - | - |
---
title: MyModal
wrapperClass: my-modal
---
# MyModal
弹窗组件
Tag: `m-modal`
```vue demo
<template>
<m-modal v-model="show" title="这是个弹窗" @close="handleClose">
<h1>内容……</h1>
</m-modal>
<button @click="show = true">Click Me!</button>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const show = ref(false)
const handleClose = () => {
console.log('可以使用close回调,或者直接watch v-model的值进行操作')
}
return {
show,
handleClose,
}
},
}
</script>
```
## Props
| props | description | type | default |
| -------------------- | -------------------- | ------- | ---------- |
| v-model / modelValue | 值 | boolean | false |
| enter | 进入动画 | string | fadeInDown |
| leave | 离开动画 | string | fadeOutUp |
| title | 标题 | string | - |
| width | 弹窗宽度 | string | 32% |
| offset | 弹窗水平偏移 | string | 0 |
| mask-closable | 点击蒙层是否允许关闭 | boolean | true |
## Events
| events | description | arguments |
| ------ | ---------------- | --------- |
| close | 关闭弹窗触发事件 | - |
......@@ -78,7 +78,7 @@ export default defineComponent({
},
},
emits: ['update:modelValue', 'close'],
setup(props, context) {
setup(_, context) {
const closeModal = () => {
context.emit('update:modelValue', false)
context.emit('close')
......
---
title: MyProgress
wrapperClass: my-progress
---
# MyProgress
进度条组件
Tag: `m-progress`
```vue demo
<template>
<m-progress :value="80" />
<m-progress
:value="67"
:msg="{ name: '测试', value: 67, unit: '%' }"
:color="['red', 'gold']"
/>
</template>
```
## Props
| props | description | type | default |
| ----------- | ------------------------- | ----------------- | ---------------------- |
| color | 进度条颜色 如为数组则渐变 | string / string[] | ['#0094FF', '#1EFBFF'] |
| value | 进度百分值 | number | 0 |
| [msg](#msg) | 附加信息 | object | - |
| height | 进度条高度(rem) | number | 0.07 |
### <i id="msg">msg props</i>
| props | description | type | default |
| ----- | ----------- | ------ | ------- |
| name | 名字 | string | - |
| value | 展示值 | number | - |
| unit | 值后边单位 | string | - |
......@@ -28,18 +28,22 @@ export default defineComponent({
displayName: 'm-progress',
components: { MonitorCount },
props: {
/** 进度条颜色 如为数组则渐变 */
color: {
type: [String, Array] as PropType<string | string[]>,
default: () => ['#0094FF', '#1EFBFF'],
},
/** 进度百分值 */
value: {
type: Number as PropType<number>,
default: 0,
},
/** 附加信息 */
msg: {
type: Object as PropType<ProgressProps>,
default: null,
},
/** 进度条高度 */
height: {
type: Number as PropType<number>,
default: 0.07,
......
---
title: MyScroll
wrapperClass: my-scroll
---
# MyScroll
轮播组件
Tag: `m-scroll`
```vue demo
<template>
<div style="display:inline-block;width:50%;height:2rem;overflow:hidden;">
<m-scroll :length="10" :limit="3">
<div
v-for="i in 10"
:key="i"
style="height: 0.8rem;text-align:center;background:skyblue;margin-bottom:.05rem;line-height:0.8rem;"
>
{{ i }}
</div>
</m-scroll>
</div>
<div style="display:inline-block;width:50%;height:2rem;overflow:hidden;">
<m-scroll :length="colors.length" :limit="2" mode="2" :step="2">
<div
v-for="color in colors"
:key="color"
:style="`height: 2rem;text-align:center;background:${color};line-height:2rem;`"
>
{{ color }}
</div>
</m-scroll>
</div>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const colors = ref(['red', 'blue', 'green', 'brown', 'pink'])
return {
colors,
}
},
}
</script>
```
## Props
| props | description | type | default |
| -------- | --------------------------------------------------------------- | --------------- | ------- |
| mode | 模式 | number / string | 1 |
| length | 数据长度 | number | - |
| limit | 数据长度小于次值则不轮播 | number | - |
| speed | mode1 的轮播速度(毫秒) | number | 50 |
| step | mode2 的每个元素高度, 有 margin 记得也要把 margin 算进去(rem) | number | 0 |
| duration | mode2 的轮播间隔(毫秒) | number | 4000 |
......@@ -64,6 +64,14 @@ export default defineComponent({
() => props.length <= 100 && props.length >= props.limit
)
const start = () => {
if (!props.length) {
console.error('MyScroll 需要length参数!')
return
}
if (!props.limit) {
console.error('MyScroll 需要limit参数!')
return
}
if (props.length < props.limit) return
if (+props.mode === 2) {
startMode2()
......
---
title: MyStep
wrapperClass: my-step
---
# MyStep
步骤条组件
Tag: `m-step`
```vue demo
<template>
<m-step :steps="['第一步', '第二步', '第三步', '第四步']" current="3" />
<m-step
:msg="['哈哈哈', `<b style='color:red;'>哈哈哈哈哈</b>`]"
:steps="['第一步', '第二步', '第三步', '第四步']"
current="2"
/>
<m-step
:msg="['msg1', 'msg2', 'msg3', 'msg4']"
:steps="['第一步', '第二步', '第三步', '第四步']"
current="1"
/>
</template>
```
## Props
| props | description | type | default |
| ------- | ------------------ | --------------- | ------- |
| steps | 节点名称 | string[] | - |
| current | 当前节点索引 | number / string | 0 |
| msg | 每个节点的附加信息 | string[] | - |
......@@ -4,7 +4,7 @@
<span />
<p><slot /></p>
<div v-if="addition" class="addition">
<m-count v-if="addition.value" class="count" :value="addition.value" />
<MyCount v-if="addition.value" class="count" :value="addition.value" />
<span v-if="addition.unit">{{ addition.unit }}</span>
</div>
<input
......@@ -29,6 +29,7 @@
<script lang="ts">
import { defineComponent, PropType, ref } from 'vue'
import MyCount from '../MyCount/my-count.vue'
export interface AdditionProp {
name?: string
......@@ -38,6 +39,7 @@ export interface AdditionProp {
export default defineComponent({
name: 'MySub',
displayName: 'm-sub',
components: { MyCount },
props: {
addition: {
type: Object as PropType<AdditionProp>,
......
---
title: MyTable
wrapperClass: my-table
---
# MyTable
Table 组件
Tag: `m-table`
```vue demo
<template>
<m-table
:template="[
'标题1|标题2*2|标题3*2',
'key1|key2>customFormatter|key3#image',
]"
:data="tableData"
:formatter="{ customFormatter }"
/>
</template>
<script>
export default {
setup() {
return {
tableData: [
{
key1: '文字1',
key2: '文字2',
key3: 'https://avatars2.githubusercontent.com/u/43328103?v=4',
},
{
key1: '文字1',
key2: '文字2',
key3: 'https://avatars2.githubusercontent.com/u/43328103?v=4',
},
{
key1: '文字1',
key2: '文字2',
key3: 'https://avatars2.githubusercontent.com/u/43328103?v=4',
},
{
key1: '文字1',
key2: '文字2',
key3: 'https://avatars2.githubusercontent.com/u/43328103?v=4',
},
],
customFormatter: (val) => {
return val + '哈哈哈'
},
}
},
}
</script>
```
## Props
| props | description | type | default |
| --------------------- | ---------------------- | -------- | ------- |
| [template](#template) | 布局模板 | string[] | - |
| data | 表单数据 | [] | - |
| formatter | 数据格式化方法对象集合 | object | - |
| selectable | 是否可触发点击事件 | boolean | false |
### <i id="template">template introduction</i>
| tag | description |
| --- | ----------------------------------------------------------------------- |
| \| | 将每行划分为 col 块 |
| \* | 后跟该列所占行的比例 |
| > | 后跟该项所需使用的 format 数据方法(方法需在 formatter 参数中定义) |
| # | 后跟该项所属的特殊类型(目前仅实现 image) |
| = | 放在 template 第一项 col 块头则标题左对齐,尾则右对齐(默认为居中对齐) |
## Events
| events | description | arguments |
| ------ | -------------------------------- | --------- |
| select | 开启 selectable 后点击行触发事件 | rowData |
......@@ -7,13 +7,13 @@
:style="`flex:${calcWidth[index]}`"
>
<p :style="`text-align:${calcAlign[index]}`">
{{ title.split('*')[0].replace('::', '') }}
{{ title.split('*')[0].replace('=', '') }}
</p>
</div>
</div>
<div class="table-content">
<div
v-for="(item, index) in dataSource"
v-for="(item, index) in data"
:key="index"
:class="{ selectable: selectable }"
@click.prevent="handleClick(item)"
......@@ -21,19 +21,16 @@
<div
v-for="(key, i) in layout.keys"
:key="key"
:style="`flex:${calcWidth[i]}`"
:style="`flex:${calcWidth[i]};text-align:${calcAlign[i]}`"
>
<p v-if="key.indexOf('>') >= 0" :style="`text-align:${calcAlign[i]}`">
{{ transValue(item, key) }}
</p>
<img
v-else-if="key.indexOf('#') >= 0 && key.split('#')[1] === 'image'"
:src="item[key.split('#')[0]]"
v-if="isImage(key)"
:src="item[isImage(key)]"
:draggable="false"
@click.stop="handleViewImage(item[key.split('#')[0]])"
@click.stop="handleViewImage(item[isImage(key)])"
/>
<p v-else :style="`text-align:${calcAlign[i]}`">
{{ item[key] }}
{{ formatData(key, item) }}
</p>
</div>
</div>
......@@ -51,8 +48,8 @@ import MyModal from '../MyModal/my-modal.vue'
interface FormatterType {
[propName: string]: <T>(val: T) => T
}
interface dataType {
[propName: string]: string | number | string[]
interface DataType {
[propName: string]: string | number | string[] | number[]
}
export default defineComponent({
......@@ -60,18 +57,22 @@ export default defineComponent({
displayName: 'm-table',
components: { MyModal },
props: {
/** 布局模板 */
template: {
type: Array as PropType<string[]>,
required: true,
},
/** 数据 */
data: {
type: Array as PropType<dataType[]>,
type: Array as PropType<DataType[]>,
default: () => [],
},
/** 数据的格式化方法对象集合 */
formatter: {
type: Object as PropType<FormatterType>,
default: null,
},
/** 是否可选择 */
selectable: {
type: Boolean as PropType<boolean>,
default: false,
......@@ -86,14 +87,7 @@ export default defineComponent({
const keys = template[1].split('|')
return { header, keys }
})
const dataSource = computed(() => props.data)
const transValue = (item: dataType, key: string) => {
return (
props.formatter &&
props.formatter[key.split('>')[1]](item[key.split('>')[0]])
)
}
const handleClick = (data: dataType) => {
const handleClick = (data: DataType): void => {
if (props.selectable) ctx.emit('select', data)
}
const calcWidth = computed(() => {
......@@ -106,10 +100,10 @@ export default defineComponent({
})
})
const calcAlign = computed(() => {
if (!layout.value) return 'center'
if (!layout.value) return ['center', 'center', 'center']
const { length } = layout.value.header
return layout.value.header.map((item) => {
const index = item.indexOf('::')
const index = item.indexOf('=')
if (index === 0) return 'left'
if (index === length) return 'right'
return 'center'
......@@ -118,20 +112,40 @@ export default defineComponent({
const imgSrc = ref<string | null>(null)
const showImgModal = ref(false)
const handleViewImage = (src: string) => {
const handleViewImage = (src: string): void => {
imgSrc.value = src
showImgModal.value = true
}
/** 是图片则返回图片的key,否则返回false */
const isImage = (key: string): string | false => {
if (key.match(/#(\w*)[>:]?/)) {
if (RegExp.$1 === 'image') {
key.match(/(\w*)[#>:]?/)
return RegExp.$1
}
return false
}
return false
}
const formatData = (key: string, data: DataType): unknown => {
const { formatter } = props
key.match(/(\w*)[#>:]?/)
const dataKey = RegExp.$1
if (formatter && key.match(/>(\w*)[#:]?/)) {
return formatter[RegExp.$1](data[dataKey])
}
return data[dataKey] || ''
}
return {
layout,
dataSource,
transValue,
handleClick,
calcWidth,
calcAlign,
imgSrc,
handleViewImage,
showImgModal,
isImage,
formatData,
}
},
})
......@@ -151,15 +165,15 @@ export default defineComponent({
background $table-title-bg
color $blue
font-weight bold
box-sizing border-box
box-sizing inherit
>div
box-sizing border-box
box-sizing inherit
.table-content
box-sizing border-box
>div
box-sizing border-box
display flex
align-items center
background $table-content-bg
box-sizing inherit
&:nth-child(odd)
background transparent
&.selectable
......@@ -168,6 +182,8 @@ export default defineComponent({
color $table-content-hover-color
background $table-content-hover-bg
img
width 100%
max-height 1rem
max-width 100%
cursor pointer
margin-top .05rem
</style>
---
title: MyTitle
wrapperClass: my-title
---
# MyTitle
大屏标题组件
Tag: `m-title`
```vue demo
<template>
<m-title>XXXXXXX数据平台1</m-title>
<m-title :bg-img="bgImg">XXXXXXX数据平台2</m-title>
</template>
<script>
import bgImg from '@/assets/images/title-bg2.png'
export default {
setup() {
return {
bgImg,
}
},
}
</script>
```
## Props
| props | description | type | default |
| ------ | ----------- | ----- | ------------ |
| bg-img | 背景图片 | Image | title-bg.png |
---
title: MyWave
wrapperClass: my-wave
---
# MyWave
百分比波浪球组件
Tag: `m-wave`
```vue demo
<template>
<m-wave :value="67" size=".5rem">67</m-wave>
<m-wave :value="80" size=".5rem" color="gold">
<m-count :value="80" />
</m-wave>
</template>
```
## Props
| props | description | type | default |
| ----- | ----------- | --------------- | ------- |
| value | 值 | number / string | 0 |
| size | 球体宽高 | string | 0.4rem |
| color | 球体颜色 | string | #4F953B |
<template>
<div class="my-wave-ball" :style="{ width: size, height: size }">
<div class="before" :style="{ top: `${percent}%` }" />
<div class="after" :style="{ top: `${percent}%` }" />
<div
class="my-wave-ball"
:style="{
width: size,
height: size,
borderColor: color,
boxShadow: `0 0 .08rem 0 ${color} inset`,
}"
>
<div class="before" :style="{ top: `${percent}%`, background: color }" />
<div class="after" :style="{ top: `${percent}%`, background: color }" />
<p><m-count :value="value" /> %</p>
</div>
</template>
......@@ -10,20 +18,27 @@
import { computed, defineComponent, PropType } from 'vue'
export default defineComponent({
name: 'MyWaveBall',
displayName: 'm-wave-ball',
name: 'MyWave',
displayName: 'm-wave',
props: {
/** 值 */
value: {
type: Number as PropType<number>,
type: [Number, String] as PropType<number | string>,
default: 0,
},
/** 球体宽高 默认0.4rem */
size: {
type: String as PropType<string>,
default: '.4rem',
},
/** 球体颜色 默认#4F953B */
color: {
type: String as PropType<string>,
default: '#4F953B',
},
},
setup(props) {
const percent = computed(() => 250 - props.value)
const percent = computed(() => 250 - +props.value)
return {
percent,
}
......@@ -38,15 +53,12 @@ export default defineComponent({
background transparent
border-radius 50%
overflow hidden
border .02rem solid $green
border .02rem solid
box-sizing content-box
box-shadow 0 0 .08rem 0 #6EB629 inset
transform translateZ(0)
$center()
p
font-size .12rem
font-weight bold
z-index: 30;
z-index 30
.before
.after
content ''
......@@ -54,7 +66,6 @@ export default defineComponent({
width 200%
height @width
left 50%
background $green
opacity .5
border-radius 40%
animation rotate 10s ease infinite alternate
......
......@@ -19,9 +19,10 @@ import MyPie from './MyChart/my-pie.vue'
import MyRadar from './MyChart/my-radar.vue'
import MyScatter from './MyChart/my-scatter.vue'
import MySub from './MySub/my-sub.vue'
import MyWaveBall from './MyWaveBall/my-wave-ball.vue'
import MyWave from './MyWave/my-wave.vue'
import MyProgress from './MyProgress/my-progress.vue'
import MyDrawer from './MyDrawer/my-drawer.vue'
import * as ChartTypes from './MyChart/types'
// import { withInstall } from './util'
import 'normalize.css'
......@@ -45,7 +46,7 @@ const components = [
MyRadar,
MyScatter,
MySub,
MyWaveBall,
MyWave,
MyProgress,
MyDrawer,
]
......@@ -80,10 +81,13 @@ export {
MyRadar,
MyScatter,
MySub,
MyWaveBall,
MyWave,
MyProgress,
MyDrawer,
}
// 图表组件的类型参数
export { ChartTypes }
// 默认导出 —— 使用import MyComponent from './components/MyComponent'来引入所有组件
export default { install }
......@@ -22,11 +22,35 @@
<m-card title="人口详情">
<Tabs class="tabs" :list="tabs" horizontal />
<SubTitle>基本信息</SubTitle>
<m-form :layout="layout1" :model="data1" :label-width="1.1" />
<m-form
:template="[
'community:所属小区|building:门牌幢',
'communityType:小区类型|roomNo:室号',
'company:物业公司|manager:物业经理',
'manageOffice:管理处|hasElev:有无电梯',
'yewei:业委会|juwei:居委会',
]"
:data="data1"
label-width="1.2rem"
/>
<SubTitle>房主信息</SubTitle>
<m-form :layout="layout2" :model="data2" :label-width="1.1" />
<m-form
:template="['name:姓名|phone:手机号码', 'household:户籍|']"
:data="data2"
label-width="1.2rem"
/>
<Tabs class="tabs" :list="tabs2" horizontal />
<m-form :layout="layout3" :model="data3" :label-width="1.1" />
<m-form
:template="[
'name:小区名称',
'address:小区地址|belong:所属居委会',
'buildingNum:总门牌幢数|roomNum:总户数',
'buildingArea:总建筑面积|aera:占地面积',
'range:小区四至范围|excludeRange:四至范围不包括',
]"
:data="data3"
label-width="1.2rem"
/>
</m-card>
</div>
</template>
......@@ -102,58 +126,6 @@ export default defineComponent({
name: '公共设施',
},
])
const layout1 = ref([
{
community: {
label: '所属小区',
width: 12,
},
building: {
label: '门牌幢',
width: 12,
},
},
{
communityType: {
label: '小区类型',
width: 12,
},
roomNo: {
label: '室号',
width: 12,
},
},
{
company: {
label: '物业公司',
width: 12,
},
manager: {
label: '物业经理',
width: 12,
},
},
{
manageOffice: {
label: '管理处',
width: 12,
},
hasElev: {
label: '有无电梯',
width: 12,
},
},
{
yewei: {
label: '业委会',
width: 12,
},
juwei: {
label: '居委会',
width: 12,
},
},
])
const data1 = ref({
community: '测试文字',
building: '测试文字',
......@@ -166,97 +138,28 @@ export default defineComponent({
yewei: '测试文字',
juwei: '测试文字',
})
const layout2 = ref([
{
name: {
label: '姓名',
width: 12,
},
phone: {
label: '手机号码',
width: 12,
},
},
{
household: {
label: '户籍',
width: 12,
},
},
])
const data2 = ref({
name: '暂无',
phone: '暂无',
household: '暂无',
})
const layout3 = ref([
{
name: {
label: '小区名称',
width: 24,
},
},
{
address: {
label: '小区地址',
width: 12,
},
belong: {
label: '所属居委会',
width: 12,
},
},
{
buildingNum: {
label: '总门牌幢数',
width: 12,
},
roomNum: {
label: '总户数',
width: 12,
},
},
{
buidlingArea: {
label: '总建筑面积',
width: 12,
},
area: {
label: '占地面积',
width: 12,
},
},
{
rang: {
label: '小区四至范围',
width: 12,
},
excludeRang: {
label: '小区四至范围不包括',
width: 12,
},
},
])
const data3 = ref({
name: '测试文字',
address: '测试文字',
belong: '测试文字',
buildingNum: '测试文字',
roomNum: '测试文字',
buidlingArea: '测试文字',
buildingArea: '测试文字',
area: '测试文字',
rang: '测试文字',
excludeRang: '测试文字',
range: '测试文字',
excludeRange: '测试文字',
})
return {
caseList,
tabs,
tabs2,
layout1,
data1,
layout2,
data2,
layout3,
data3,
}
},
......
......@@ -57,10 +57,6 @@ export default defineComponent({
grid: {
width: '105%',
left: '-5%',
right: '2%',
bottom: '1%',
top: '20%',
containLabel: true,
},
xAxis: [
{
......
......@@ -2,7 +2,7 @@
<m-card title="有诉必答">
<div class="summary">
<div v-for="item in summary" :key="item.name">
<m-wave-ball :value="item.percent" size=".34rem" />
<m-wave :value="item.percent" size=".34rem" />
<div>
<m-count class="count" :value="item.value" />
<p>{{ item.name }}</p>
......@@ -124,7 +124,7 @@ export default defineComponent({
source: [
{
seriesName: '分类排行',
class1: 150,
class1: 250,
class2: 200,
class3: 200,
class4: 300,
......@@ -136,31 +136,6 @@ export default defineComponent({
color: ['#FF9D27'],
legend: { show: false },
radar: {
axisName: {
// show: false,
color: 'transparent',
},
indicator: {},
splitArea: {
areaStyle: {
color: [
'rgba(1,124,143,.9)',
'rgba(1,124,143,.7)',
'rgba(1,124,143,.5)',
'rgba(1,124,143,.3)',
'rgba(1,124,143,.1)',
],
},
},
splitLine: {
show: true,
lineStyle: {
color: 'rgba(255,255,255,.3)',
},
},
axisLine: {
show: false,
},
radius: '80%',
},
})
......
......@@ -226,7 +226,8 @@ export default defineComponent({
const pieOption = ref({
color: ['#00BFFF', '#FFCE34', '#826AFA', '#589C20', '#F47C1F'],
legend: { show: false },
series: {
series: [
{
type: 'pie',
radius: [0, '90%'],
center: ['40%', '50%'],
......@@ -234,6 +235,7 @@ export default defineComponent({
show: false,
},
},
],
})
return {
showChart,
......
......@@ -14,7 +14,7 @@
<m-progress :value="80" :height="0.1" />
<div class="house-types">
<div v-for="item in houseTypes" :key="item.name">
<m-wave-ball :value="item.percent" size=".34rem" />
<m-wave :value="item.percent" size=".34rem" />
<div>
<m-count class="count" :value="item.value" />
<p>{{ item.name }}</p>
......
......@@ -107,7 +107,8 @@ export default defineComponent({
const pieOption = ref({
color: ['#8D51C7', '#BEBEBE', '#CA3A40', '#F9B84C', '#34ACFF', '#429321'],
legend: { show: false },
series: {
series: [
{
type: 'pie',
roseType: 'radius',
radius: ['10%', '90%'],
......@@ -116,6 +117,7 @@ export default defineComponent({
show: false,
},
},
],
})
const oldType = ref([
{ name: '孤老', value: 103, percent: 0.9 },
......
......@@ -87,11 +87,7 @@ export default defineComponent({
itemHeight: fontSize.value * 0.8,
},
grid: {
left: '2%',
right: '5%',
bottom: '15%',
top: '20%',
containLabel: true,
},
dataZoom: [
{
......
......@@ -89,8 +89,8 @@ module.exports = {
path: './src/components/MyComponent/MyProgress/my-progress.vue',
},
{
name: 'm-wave-ball',
path: './src/components/MyComponent/MyWaveBall/my-wave-ball.vue',
name: 'm-wave',
path: './src/components/MyComponent/MyWave/my-wave.vue',
},
{
name: 'm-sub',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment