mirror of
https://github.com/jeecgboot/JeecgBoot.git
synced 2026-01-01 09:55:28 +08:00
前端和后端源码,合并到一个git仓库中,方便用户下载,避免前后端不匹配的问题
This commit is contained in:
16
jeecgboot-vue3/src/views/dashboard/Analysis/api.ts
Normal file
16
jeecgboot-vue3/src/views/dashboard/Analysis/api.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
enum Api {
|
||||
loginfo = '/sys/loginfo',
|
||||
visitInfo = '/sys/visitInfo',
|
||||
}
|
||||
/**
|
||||
* 日志统计信息
|
||||
* @param params
|
||||
*/
|
||||
export const getLoginfo = (params) => defHttp.get({ url: Api.loginfo, params }, { isTransformResponse: false });
|
||||
/**
|
||||
* 访问量信息
|
||||
* @param params
|
||||
*/
|
||||
export const getVisitInfo = (params) => defHttp.get({ url: Api.visitInfo, params }, { isTransformResponse: false });
|
||||
@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<a-card :loading="loading" :bordered="false" :body-style="{ padding: '0' }">
|
||||
<div class="salesCard">
|
||||
<a-tabs default-active-key="1" size="large" :tab-bar-style="{ marginBottom: '24px', paddingLeft: '16px' }">
|
||||
<template #rightExtra>
|
||||
<div class="extra-wrapper">
|
||||
<div class="extra-item">
|
||||
<a>今日</a>
|
||||
<a>本周</a>
|
||||
<a>本月</a>
|
||||
<a>本年</a>
|
||||
</div>
|
||||
<a-range-picker :style="{ width: '256px' }" />
|
||||
</div>
|
||||
</template>
|
||||
<a-tab-pane loading="true" tab="受理监管" key="1">
|
||||
<a-row>
|
||||
<a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
|
||||
<Bar :chartData="barData" :option="{ title: { text: '', textStyle: { fontWeight: 'lighter' } } }" height="40vh" :seriesColor="seriesColor" />
|
||||
</a-col>
|
||||
<a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">
|
||||
<QuickNav :loading="loading" class="enter-y" :bordered="false" :body-style="{ padding: 0 }" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="交互监管" key="2">
|
||||
<a-row>
|
||||
<a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
|
||||
<BarMulti
|
||||
:seriesColor="interactiveColor"
|
||||
:chartData="barMultiData"
|
||||
:option="{ title: { text: '', textStyle: { fontWeight: 'lighter' } } }"
|
||||
height="40vh"
|
||||
/>
|
||||
</a-col>
|
||||
<a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">
|
||||
<QuickNav :loading="loading" class="enter-y" :bordered="false" :body-style="{ padding: 0 }" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="存储监管" key="3">
|
||||
<a-row>
|
||||
<a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24" style="display: flex">
|
||||
<Gauge :seriesColor="seriesColor" :chartData="{ name: 'C盘', value: 70 }" height="30vh"></Gauge>
|
||||
<Gauge :seriesColor="seriesColor" :chartData="{ name: 'D盘', value: 50 }" height="30vh"></Gauge>
|
||||
</a-col>
|
||||
<a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">
|
||||
<QuickNav :loading="loading" class="enter-y" :bordered="false" :body-style="{ padding: 0 }" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</a-card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import Bar from '/@/components/chart/Bar.vue';
|
||||
import BarMulti from '/@/components/chart/BarMulti.vue';
|
||||
import Gauge from '/@/components/chart/Gauge.vue';
|
||||
import QuickNav from './QuickNav.vue';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
|
||||
defineProps({
|
||||
loading: {
|
||||
type: Boolean,
|
||||
},
|
||||
});
|
||||
const { getThemeColor } = useRootSetting();
|
||||
const interactiveColor = ref();
|
||||
const rankList = [];
|
||||
for (let i = 0; i < 7; i++) {
|
||||
rankList.push({
|
||||
name: '白鹭岛 ' + (i + 1) + ' 号店',
|
||||
total: 1234.56 - i * 100,
|
||||
});
|
||||
}
|
||||
|
||||
const barData = [];
|
||||
for (let i = 0; i < 12; i += 1) {
|
||||
barData.push({
|
||||
name: `${i + 1}月`,
|
||||
value: Math.floor(Math.random() * 1000) + 200,
|
||||
});
|
||||
}
|
||||
const barMultiData = [];
|
||||
for (let j = 0; j < 2; j++) {
|
||||
for (let i = 0; i < 12; i += 1) {
|
||||
barMultiData.push({
|
||||
type: j == 0 ? 'jeecg' : 'jeebt',
|
||||
name: `${i + 1}月`,
|
||||
value: Math.floor(Math.random() * 1000) + 200,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const seriesColor = computed(() => {
|
||||
interactiveColor.value = [
|
||||
{ type: 'jeecg', color: getThemeColor.value },
|
||||
{ type: 'jeebt', color: getRandomColor() },
|
||||
];
|
||||
return getThemeColor.value;
|
||||
});
|
||||
function getRandomColor() {
|
||||
var letters = '0123456789ABCDEF';
|
||||
var color = '#';
|
||||
for (var i = 0; i < 6; i++) {
|
||||
color += letters[Math.floor(Math.random() * 16)];
|
||||
}
|
||||
return color;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.extra-wrapper {
|
||||
line-height: 55px;
|
||||
padding-right: 24px;
|
||||
|
||||
.extra-item {
|
||||
display: inline-block;
|
||||
margin-right: 24px;
|
||||
|
||||
a {
|
||||
margin-left: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<div class="md:flex">
|
||||
<template v-for="(item, index) in dataList" :key="item.title">
|
||||
<ChartCard
|
||||
:loading="loading"
|
||||
:title="item.title"
|
||||
:total="getTotal(item.total, index)"
|
||||
class="md:w-1/4 w-full !md:mt-0 !mt-4"
|
||||
:class="[index + 1 < 4 && '!md:mr-4']"
|
||||
>
|
||||
<template #action>
|
||||
<a-tooltip title="指标说明">
|
||||
<Icon :icon="item.icon" :size="20" />
|
||||
</a-tooltip>
|
||||
</template>
|
||||
<div v-if="type === 'chart'">
|
||||
<Trend term="周同比" :percentage="12" v-if="index === 0" />
|
||||
<Trend term="日同比" :percentage="11" v-if="index === 0" :type="false" />
|
||||
|
||||
<SingleLine v-if="index === 1" :option="option" :chartData="chartData" :seriesColor="seriesColor" height="50px"></SingleLine>
|
||||
|
||||
<Bar v-if="index === 2" :option="option" :chartData="chartData" :seriesColor="seriesColor" height="50px"></Bar>
|
||||
|
||||
<Progress v-if="index === 3" :percent="78" :show-info="false"></Progress>
|
||||
</div>
|
||||
<div v-else>
|
||||
<SingleLine :seriesColor="seriesColor" v-if="index === 0" :option="option" :chartData="chartData" height="50px"></SingleLine>
|
||||
|
||||
<SingleLine :seriesColor="seriesColor" v-if="index === 1" :option="option" :chartData="chartData" height="50px"></SingleLine>
|
||||
|
||||
<Bar :seriesColor="seriesColor" v-if="index === 2" :option="option" :chartData="chartData" height="50px"></Bar>
|
||||
|
||||
<Progress v-if="index === 3" :percent="78" :show-info="false"></Progress>
|
||||
|
||||
</div>
|
||||
<template #footer v-if="type === 'chart'">
|
||||
<span v-if="index !== 3"
|
||||
>{{ item.footer }}<span>{{ item.value }}</span></span
|
||||
>
|
||||
<Trend term="周同比" :percentage="12" v-if="index === 3" />
|
||||
<Trend term="日同比" :percentage="11" v-if="index === 3" :type="false" />
|
||||
</template>
|
||||
<template #footer v-else>
|
||||
<span
|
||||
>{{ item.footer }}<span>{{ item.value }}</span></span
|
||||
>
|
||||
</template>
|
||||
</ChartCard>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
import { Progress } from 'ant-design-vue';
|
||||
import ChartCard from '/@/components/chart/ChartCard.vue';
|
||||
import Trend from '/@/components/chart/Trend.vue';
|
||||
import Bar from '/@/components/chart/Bar.vue';
|
||||
import SingleLine from '/@/components/chart/SingleLine.vue';
|
||||
import { chartCardList, bdcCardList } from '../data';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
|
||||
const { getThemeColor } = useRootSetting();
|
||||
const props = defineProps({
|
||||
loading: {
|
||||
type: Boolean,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'chart',
|
||||
},
|
||||
});
|
||||
const option = ref({ xAxis: { show: false, boundaryGap: false }, yAxis: { show: false, boundaryGap: false, max: 220 } });
|
||||
|
||||
const chartData = ref([
|
||||
{
|
||||
name: '1月',
|
||||
value: 50,
|
||||
},
|
||||
{
|
||||
name: '2月',
|
||||
value: 100,
|
||||
},
|
||||
{
|
||||
name: '3月',
|
||||
value: 150,
|
||||
},
|
||||
{
|
||||
name: '4月',
|
||||
value: 40,
|
||||
},
|
||||
{
|
||||
name: '5月',
|
||||
value: 110,
|
||||
},
|
||||
{
|
||||
name: '6月',
|
||||
value: 120,
|
||||
},
|
||||
]);
|
||||
const seriesColor = computed(() => {
|
||||
return getThemeColor.value;
|
||||
})
|
||||
const dataList = computed(() => (props.type === 'dbc' ? bdcCardList : chartCardList));
|
||||
|
||||
function getTotal(total, index) {
|
||||
return index === 0 ? `¥${total}` : index === 3 ? `${total}%` : total;
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,40 @@
|
||||
<template>
|
||||
<div class="md:flex">
|
||||
<template v-for="(item, index) in growCardList" :key="item.title">
|
||||
<Card
|
||||
size="small"
|
||||
:loading="loading"
|
||||
:title="item.title"
|
||||
class="md:w-1/4 w-full !md:mt-0 !mt-4"
|
||||
:class="[index + 1 < 4 && '!md:mr-4']"
|
||||
:canExpan="false"
|
||||
>
|
||||
<template #extra>
|
||||
<Tag :color="item.color">{{ item.action }}</Tag>
|
||||
</template>
|
||||
|
||||
<div class="py-4 px-4 flex justify-between">
|
||||
<CountTo prefix="$" :startVal="1" :endVal="item.value" class="text-2xl" />
|
||||
<Icon :icon="item.icon" :size="40" />
|
||||
</div>
|
||||
|
||||
<div class="p-2 px-4 flex justify-between">
|
||||
<span>总{{ item.title }}</span>
|
||||
<CountTo prefix="$" :startVal="1" :endVal="item.total" />
|
||||
</div>
|
||||
</Card>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { CountTo } from '/@/components/CountTo/index';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
import { Tag, Card } from 'ant-design-vue';
|
||||
import { growCardList } from '../data';
|
||||
|
||||
defineProps({
|
||||
loading: {
|
||||
type: Boolean,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@ -0,0 +1,56 @@
|
||||
<template>
|
||||
<Card title="快捷导航" v-bind="$attrs">
|
||||
<template v-for="item in navItems" :key="item">
|
||||
<CardGrid @click="goPage">
|
||||
<span class="flex flex-col items-center">
|
||||
<Icon :icon="item.icon" :color="item.color" size="20" />
|
||||
<span class="text-md mt-2">{{ item.title }}</span>
|
||||
</span>
|
||||
</CardGrid>
|
||||
</template>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
|
||||
const CardGrid = Card.Grid;
|
||||
const $message = useMessage();
|
||||
const navItems = [
|
||||
{
|
||||
title: '业务受理',
|
||||
icon: 'ion:home-outline',
|
||||
color: '#1fdaca',
|
||||
},
|
||||
{
|
||||
title: '业务管理',
|
||||
icon: 'ion:grid-outline',
|
||||
color: '#bf0c2c',
|
||||
},
|
||||
{
|
||||
title: '文件管理',
|
||||
icon: 'ion:layers-outline',
|
||||
color: '#e18525',
|
||||
},
|
||||
{
|
||||
title: '信息查询',
|
||||
icon: 'ion:settings-outline',
|
||||
color: '#3fb27f',
|
||||
},
|
||||
{
|
||||
title: '通知公告',
|
||||
icon: 'ion:notifications',
|
||||
color: '#13b0ff',
|
||||
},
|
||||
{
|
||||
title: '我的任务',
|
||||
icon: 'ion:person-stalker',
|
||||
color: '#b27315',
|
||||
}
|
||||
];
|
||||
|
||||
function goPage() {
|
||||
$message.createMessage.success('根据业务自行处理跳转页面!');
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<a-card :loading="loading" :bordered="false" :body-style="{ padding: '0' }">
|
||||
<div class="salesCard">
|
||||
<a-tabs default-active-key="1" size="large" :tab-bar-style="{ marginBottom: '24px', paddingLeft: '16px' }">
|
||||
<template #rightExtra>
|
||||
<div class="extra-wrapper">
|
||||
<div class="extra-item">
|
||||
<a>今日</a>
|
||||
<a>本周</a>
|
||||
<a>本月</a>
|
||||
<a>本年</a>
|
||||
</div>
|
||||
<a-range-picker :style="{ width: '256px' }" />
|
||||
</div>
|
||||
</template>
|
||||
<a-tab-pane loading="true" tab="销售额" key="1">
|
||||
<a-row>
|
||||
<a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
|
||||
<Bar :chartData="barData" :option="{ title: { text: '', textStyle: { fontWeight: 'lighter' } } }" height="40vh" :seriesColor="seriesColor" />
|
||||
</a-col>
|
||||
<a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">
|
||||
<RankList title="门店销售排行榜" :list="rankList" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-tab-pane>
|
||||
<a-tab-pane tab="销售趋势" key="2">
|
||||
<a-row>
|
||||
<a-col :xl="16" :lg="12" :md="12" :sm="24" :xs="24">
|
||||
<Bar :chartData="barData.reverse()" :option="{ title: { text: '', textStyle: { fontWeight: 'lighter' } } }" height="40vh" :seriesColor="seriesColor" />
|
||||
</a-col>
|
||||
<a-col :xl="8" :lg="12" :md="12" :sm="24" :xs="24">
|
||||
<RankList title="门店销售排行榜" :list="rankList" />
|
||||
</a-col>
|
||||
</a-row>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</div>
|
||||
</a-card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, computed } from 'vue';
|
||||
import Bar from '/@/components/chart/Bar.vue';
|
||||
import RankList from '/@/components/chart/RankList.vue';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
|
||||
|
||||
defineProps({
|
||||
loading: {
|
||||
type: Boolean,
|
||||
},
|
||||
});
|
||||
const { getThemeColor } = useRootSetting();
|
||||
const rankList = [];
|
||||
for (let i = 0; i < 7; i++) {
|
||||
rankList.push({
|
||||
name: '白鹭岛 ' + (i + 1) + ' 号店',
|
||||
total: 1234.56 - i * 100,
|
||||
});
|
||||
}
|
||||
|
||||
const barData = [];
|
||||
for (let i = 0; i < 12; i += 1) {
|
||||
barData.push({
|
||||
name: `${i + 1}月`,
|
||||
value: Math.floor(Math.random() * 1000) + 200,
|
||||
});
|
||||
}
|
||||
const seriesColor = computed(() => {
|
||||
return getThemeColor.value
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.extra-wrapper {
|
||||
line-height: 55px;
|
||||
padding-right: 24px;
|
||||
|
||||
.extra-item {
|
||||
display: inline-block;
|
||||
margin-right: 24px;
|
||||
|
||||
a {
|
||||
margin-left: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<Card title="成交占比" :loading="loading">
|
||||
<div ref="chartRef" :style="{ width, height }"></div>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Ref, ref, watch } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
|
||||
const props = defineProps({
|
||||
loading: Boolean,
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: '300px',
|
||||
},
|
||||
});
|
||||
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
watch(
|
||||
() => props.loading,
|
||||
() => {
|
||||
if (props.loading) {
|
||||
return;
|
||||
}
|
||||
setOptions({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
},
|
||||
|
||||
series: [
|
||||
{
|
||||
name: '访问来源',
|
||||
type: 'pie',
|
||||
radius: '80%',
|
||||
center: ['50%', '50%'],
|
||||
color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
|
||||
data: [
|
||||
{ value: 500, name: '电子产品' },
|
||||
{ value: 310, name: '服装' },
|
||||
{ value: 274, name: '化妆品' },
|
||||
{ value: 400, name: '家居' },
|
||||
].sort(function (a, b) {
|
||||
return a.value - b.value;
|
||||
}),
|
||||
roseType: 'radius',
|
||||
animationType: 'scale',
|
||||
animationEasing: 'exponentialInOut',
|
||||
animationDelay: function () {
|
||||
return Math.random() * 400;
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<Card :tab-list="tabListTitle" v-bind="$attrs" :active-tab-key="activeKey" @tabChange="onTabChange">
|
||||
<p v-if="activeKey === 'tab1'">
|
||||
<VisitAnalysis />
|
||||
</p>
|
||||
<p v-if="activeKey === 'tab2'">
|
||||
<VisitAnalysisBar />
|
||||
</p>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import VisitAnalysis from './VisitAnalysis.vue';
|
||||
import VisitAnalysisBar from './VisitAnalysisBar.vue';
|
||||
|
||||
const activeKey = ref('tab1');
|
||||
|
||||
const tabListTitle = [
|
||||
{
|
||||
key: 'tab1',
|
||||
tab: '流量趋势',
|
||||
},
|
||||
{
|
||||
key: 'tab2',
|
||||
tab: '访问量',
|
||||
},
|
||||
];
|
||||
|
||||
function onTabChange(key) {
|
||||
activeKey.value = key;
|
||||
}
|
||||
</script>
|
||||
@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, Ref, watchEffect } from 'vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
import { basicProps } from './props';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
defineProps({
|
||||
...basicProps,
|
||||
});
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
|
||||
const { getThemeColor } = useRootSetting();
|
||||
const init = () => {
|
||||
setOptions({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: getThemeColor.value,
|
||||
},
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: [
|
||||
'6:00',
|
||||
'7:00',
|
||||
'8:00',
|
||||
'9:00',
|
||||
'10:00',
|
||||
'11:00',
|
||||
'12:00',
|
||||
'13:00',
|
||||
'14:00',
|
||||
'15:00',
|
||||
'16:00',
|
||||
'17:00',
|
||||
'18:00',
|
||||
'19:00',
|
||||
'20:00',
|
||||
'21:00',
|
||||
'22:00',
|
||||
'23:00',
|
||||
],
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
type: 'solid',
|
||||
color: 'rgba(226,226,226,0.5)',
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
max: 80000,
|
||||
splitNumber: 4,
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
splitArea: {
|
||||
show: true,
|
||||
areaStyle: {
|
||||
color: ['rgba(255,255,255,0.2)', 'rgba(226,226,226,0.2)'],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
grid: { left: '1%', right: '1%', top: '2 %', bottom: 0, containLabel: true },
|
||||
series: [
|
||||
{
|
||||
smooth: true,
|
||||
data: [111, 222, 4000, 18000, 33333, 55555, 66666, 33333, 14000, 36000, 66666, 44444, 22222, 11111, 4000, 2000, 500, 333, 222, 111],
|
||||
type: 'line',
|
||||
areaStyle: {},
|
||||
itemStyle: {
|
||||
color: '#5ab1ef',
|
||||
},
|
||||
},
|
||||
{
|
||||
smooth: true,
|
||||
data: [33, 66, 88, 333, 3333, 5000, 18000, 3000, 1200, 13000, 22000, 11000, 2221, 1201, 390, 198, 60, 30, 22, 11],
|
||||
type: 'line',
|
||||
areaStyle: {},
|
||||
itemStyle: {
|
||||
color: getThemeColor.value,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
watchEffect(() => {
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, Ref, watchEffect } from 'vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
import { basicProps } from './props';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
|
||||
defineProps({
|
||||
...basicProps,
|
||||
});
|
||||
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
const { getThemeColor } = useRootSetting();
|
||||
const init = () => {
|
||||
setOptions({
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: getThemeColor.value,
|
||||
},
|
||||
},
|
||||
},
|
||||
grid: { left: '1%', right: '1%', top: '2 %', bottom: 0, containLabel: true },
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
max: 8000,
|
||||
splitNumber: 4,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: [3000, 2000, 3333, 5000, 3200, 4200, 3200, 2100, 3000, 5100, 6000, 3200, 4800],
|
||||
type: 'bar',
|
||||
barMaxWidth: 80,
|
||||
color: getThemeColor.value,
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
watchEffect(() => {
|
||||
init();
|
||||
});
|
||||
</script>
|
||||
@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<Card title="转化率" :loading="loading">
|
||||
<div ref="chartRef" :style="{ width, height }"></div>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Ref, ref, watch } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
|
||||
const props = defineProps({
|
||||
loading: Boolean,
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: '300px',
|
||||
},
|
||||
});
|
||||
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
watch(
|
||||
() => props.loading,
|
||||
() => {
|
||||
if (props.loading) {
|
||||
return;
|
||||
}
|
||||
setOptions({
|
||||
legend: {
|
||||
bottom: 0,
|
||||
data: ['访问', '购买'],
|
||||
},
|
||||
tooltip: {},
|
||||
radar: {
|
||||
radius: '60%',
|
||||
splitNumber: 8,
|
||||
indicator: [
|
||||
{
|
||||
name: '电脑',
|
||||
},
|
||||
{
|
||||
name: '充电器',
|
||||
},
|
||||
{
|
||||
name: '耳机',
|
||||
},
|
||||
{
|
||||
name: '手机',
|
||||
},
|
||||
{
|
||||
name: 'Ipad',
|
||||
},
|
||||
{
|
||||
name: '耳机',
|
||||
},
|
||||
],
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'radar' as 'custom',
|
||||
symbolSize: 0,
|
||||
areaStyle: {
|
||||
shadowBlur: 0,
|
||||
shadowColor: 'rgba(0,0,0,.2)',
|
||||
shadowOffsetX: 0,
|
||||
shadowOffsetY: 10,
|
||||
opacity: 1,
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: [90, 50, 86, 40, 50, 20],
|
||||
name: '访问',
|
||||
itemStyle: {
|
||||
color: '#b6a2de',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: [70, 75, 70, 76, 20, 85],
|
||||
name: '购买',
|
||||
itemStyle: {
|
||||
color: '#5ab1ef',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<Card title="访问来源" :loading="loading">
|
||||
<div ref="chartRef" :style="{ width, height }"></div>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Ref, ref, watch } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
const props = defineProps({
|
||||
loading: Boolean,
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: '300px',
|
||||
},
|
||||
});
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
watch(
|
||||
() => props.loading,
|
||||
() => {
|
||||
if (props.loading) {
|
||||
return;
|
||||
}
|
||||
setOptions({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
},
|
||||
legend: {
|
||||
bottom: '1%',
|
||||
left: 'center',
|
||||
},
|
||||
series: [
|
||||
{
|
||||
color: ['#5ab1ef', '#b6a2de', '#67e0e3', '#2ec7c9'],
|
||||
name: '访问来源',
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
avoidLabelOverlap: false,
|
||||
itemStyle: {
|
||||
borderRadius: 10,
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2,
|
||||
},
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center',
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: true,
|
||||
fontSize: '12',
|
||||
fontWeight: 'bold',
|
||||
},
|
||||
},
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
data: [
|
||||
{ value: 1048, name: '搜索引擎' },
|
||||
{ value: 735, name: '直接访问' },
|
||||
{ value: 580, name: '邮件营销' },
|
||||
{ value: 484, name: '联盟广告' },
|
||||
],
|
||||
animationType: 'scale',
|
||||
animationEasing: 'exponentialInOut',
|
||||
animationDelay: function () {
|
||||
return Math.random() * 100;
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
@ -0,0 +1,16 @@
|
||||
import { PropType } from 'vue';
|
||||
|
||||
export interface BasicProps {
|
||||
width: string;
|
||||
height: string;
|
||||
}
|
||||
export const basicProps = {
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: '280px',
|
||||
},
|
||||
};
|
||||
219
jeecgboot-vue3/src/views/dashboard/Analysis/data.ts
Normal file
219
jeecgboot-vue3/src/views/dashboard/Analysis/data.ts
Normal file
@ -0,0 +1,219 @@
|
||||
export interface GrowCardItem {
|
||||
icon: string;
|
||||
title: string;
|
||||
value?: number;
|
||||
total: number;
|
||||
color?: string;
|
||||
action?: string;
|
||||
footer?: string;
|
||||
}
|
||||
|
||||
export const growCardList: GrowCardItem[] = [
|
||||
{
|
||||
title: '访问数',
|
||||
icon: 'visit-count|svg',
|
||||
value: 2000,
|
||||
total: 120000,
|
||||
color: 'green',
|
||||
action: '月',
|
||||
},
|
||||
{
|
||||
title: '成交额',
|
||||
icon: 'total-sales|svg',
|
||||
value: 20000,
|
||||
total: 500000,
|
||||
color: 'blue',
|
||||
action: '月',
|
||||
},
|
||||
{
|
||||
title: '下载数',
|
||||
icon: 'download-count|svg',
|
||||
value: 8000,
|
||||
total: 120000,
|
||||
color: 'orange',
|
||||
action: '周',
|
||||
},
|
||||
{
|
||||
title: '成交数',
|
||||
icon: 'transaction|svg',
|
||||
value: 5000,
|
||||
total: 50000,
|
||||
color: 'purple',
|
||||
action: '年',
|
||||
},
|
||||
];
|
||||
|
||||
export const chartCardList: GrowCardItem[] = [
|
||||
{
|
||||
title: '总销售额',
|
||||
icon: 'visit-count|svg',
|
||||
total: 126560,
|
||||
value: 234.56,
|
||||
footer: '日均销售额',
|
||||
},
|
||||
{
|
||||
title: '订单量',
|
||||
icon: 'total-sales|svg',
|
||||
value: 1234,
|
||||
total: 8846,
|
||||
color: 'blue',
|
||||
footer: '日订单量',
|
||||
},
|
||||
{
|
||||
title: '支付笔数',
|
||||
icon: 'download-count|svg',
|
||||
value: 60,
|
||||
total: 6560,
|
||||
color: 'orange',
|
||||
footer: '转化率',
|
||||
},
|
||||
{
|
||||
title: '运营活动效果',
|
||||
icon: 'transaction|svg',
|
||||
total: 78,
|
||||
},
|
||||
];
|
||||
export const bdcCardList: GrowCardItem[] = [
|
||||
{
|
||||
title: '受理量',
|
||||
icon: 'ant-design:info-circle-outlined',
|
||||
total: 100,
|
||||
value: 60,
|
||||
footer: '今日受理量',
|
||||
},
|
||||
{
|
||||
title: '办结量',
|
||||
icon: 'ant-design:info-circle-outlined',
|
||||
value: 54,
|
||||
total: 87,
|
||||
color: 'blue',
|
||||
footer: '今日办结量',
|
||||
},
|
||||
{
|
||||
title: '用户受理量',
|
||||
icon: 'ant-design:info-circle-outlined',
|
||||
value: 13,
|
||||
total: 15,
|
||||
color: 'orange',
|
||||
footer: '用户今日受理量',
|
||||
},
|
||||
{
|
||||
title: '用户办结量',
|
||||
icon: 'ant-design:info-circle-outlined',
|
||||
total: 9,
|
||||
value: 7,
|
||||
footer: '用户今日办结量',
|
||||
},
|
||||
];
|
||||
|
||||
export const table = {
|
||||
dataSource: [
|
||||
{ reBizCode: '1', type: '转移登记', acceptBy: '张三', acceptDate: '2019-01-22', curNode: '任务分派', flowRate: 60 },
|
||||
{ reBizCode: '2', type: '抵押登记', acceptBy: '李四', acceptDate: '2019-01-23', curNode: '领导审核', flowRate: 30 },
|
||||
{ reBizCode: '3', type: '转移登记', acceptBy: '王武', acceptDate: '2019-01-25', curNode: '任务处理', flowRate: 20 },
|
||||
{ reBizCode: '4', type: '转移登记', acceptBy: '赵楼', acceptDate: '2019-11-22', curNode: '部门审核', flowRate: 80 },
|
||||
{ reBizCode: '5', type: '转移登记', acceptBy: '钱就', acceptDate: '2019-12-12', curNode: '任务分派', flowRate: 90 },
|
||||
{ reBizCode: '6', type: '转移登记', acceptBy: '孙吧', acceptDate: '2019-03-06', curNode: '任务处理', flowRate: 10 },
|
||||
{ reBizCode: '7', type: '抵押登记', acceptBy: '周大', acceptDate: '2019-04-13', curNode: '任务分派', flowRate: 100 },
|
||||
{ reBizCode: '8', type: '抵押登记', acceptBy: '吴二', acceptDate: '2019-05-09', curNode: '任务上报', flowRate: 50 },
|
||||
{ reBizCode: '9', type: '抵押登记', acceptBy: '郑爽', acceptDate: '2019-07-12', curNode: '任务处理', flowRate: 63 },
|
||||
{ reBizCode: '20', type: '抵押登记', acceptBy: '林有', acceptDate: '2019-12-12', curNode: '任务打回', flowRate: 59 },
|
||||
{ reBizCode: '11', type: '转移登记', acceptBy: '码云', acceptDate: '2019-09-10', curNode: '任务签收', flowRate: 87 },
|
||||
],
|
||||
columns: [
|
||||
{
|
||||
title: '业务号',
|
||||
align: 'center',
|
||||
dataIndex: 'reBizCode',
|
||||
},
|
||||
{
|
||||
title: '业务类型',
|
||||
align: 'center',
|
||||
dataIndex: 'type',
|
||||
},
|
||||
{
|
||||
title: '受理人',
|
||||
align: 'center',
|
||||
dataIndex: 'acceptBy',
|
||||
},
|
||||
{
|
||||
title: '受理时间',
|
||||
align: 'center',
|
||||
dataIndex: 'acceptDate',
|
||||
},
|
||||
{
|
||||
title: '当前节点',
|
||||
align: 'center',
|
||||
dataIndex: 'curNode',
|
||||
},
|
||||
{
|
||||
title: '办理时长',
|
||||
align: 'center',
|
||||
dataIndex: 'flowRate',
|
||||
},
|
||||
],
|
||||
ipagination: {
|
||||
current: 1,
|
||||
pageSize: 5,
|
||||
pageSizeOptions: ['10', '20', '30'],
|
||||
showTotal: (total, range) => {
|
||||
return range[0] + '-' + range[1] + ' 共' + total + '条';
|
||||
},
|
||||
showQuickJumper: true,
|
||||
showSizeChanger: true,
|
||||
total: 0,
|
||||
},
|
||||
};
|
||||
export const table1 = {
|
||||
dataSource: [
|
||||
{ reBizCode: 'A001', type: '转移登记', acceptBy: '张四', acceptDate: '2019-01-22', curNode: '任务分派', flowRate: 12 },
|
||||
{ reBizCode: 'A002', type: '抵押登记', acceptBy: '李吧', acceptDate: '2019-01-23', curNode: '任务签收', flowRate: 3 },
|
||||
{ reBizCode: 'A003', type: '转移登记', acceptBy: '王三', acceptDate: '2019-01-25', curNode: '任务处理', flowRate: 24 },
|
||||
{ reBizCode: 'A004', type: '转移登记', acceptBy: '赵二', acceptDate: '2019-11-22', curNode: '部门审核', flowRate: 10 },
|
||||
{ reBizCode: 'A005', type: '转移登记', acceptBy: '钱大', acceptDate: '2019-12-12', curNode: '任务签收', flowRate: 8 },
|
||||
{ reBizCode: 'A006', type: '转移登记', acceptBy: '孙就', acceptDate: '2019-03-06', curNode: '任务处理', flowRate: 10 },
|
||||
{ reBizCode: 'A007', type: '抵押登记', acceptBy: '周晕', acceptDate: '2019-04-13', curNode: '部门审核', flowRate: 24 },
|
||||
{ reBizCode: 'A008', type: '抵押登记', acceptBy: '吴有', acceptDate: '2019-05-09', curNode: '部门审核', flowRate: 30 },
|
||||
{ reBizCode: 'A009', type: '抵押登记', acceptBy: '郑武', acceptDate: '2019-07-12', curNode: '任务分派', flowRate: 1 },
|
||||
{ reBizCode: 'A0010', type: '抵押登记', acceptBy: '林爽', acceptDate: '2019-12-12', curNode: '部门审核', flowRate: 16 },
|
||||
{ reBizCode: 'A0011', type: '转移登记', acceptBy: '码楼', acceptDate: '2019-09-10', curNode: '部门审核', flowRate: 7 },
|
||||
],
|
||||
columns: [
|
||||
{
|
||||
title: '业务号',
|
||||
align: 'center',
|
||||
dataIndex: 'reBizCode',
|
||||
},
|
||||
{
|
||||
title: '受理人',
|
||||
align: 'center',
|
||||
dataIndex: 'acceptBy',
|
||||
},
|
||||
{
|
||||
title: '发起时间',
|
||||
align: 'center',
|
||||
dataIndex: 'acceptDate',
|
||||
},
|
||||
{
|
||||
title: '当前节点',
|
||||
align: 'center',
|
||||
dataIndex: 'curNode',
|
||||
},
|
||||
{
|
||||
title: '超时时间',
|
||||
align: 'center',
|
||||
dataIndex: 'flowRate',
|
||||
},
|
||||
],
|
||||
ipagination: {
|
||||
current: 1,
|
||||
pageSize: 5,
|
||||
pageSizeOptions: ['10', '20', '30'],
|
||||
showTotal: (total, range) => {
|
||||
return range[0] + '-' + range[1] + ' 共' + total + '条';
|
||||
},
|
||||
showQuickJumper: true,
|
||||
showSizeChanger: true,
|
||||
total: 0,
|
||||
},
|
||||
};
|
||||
@ -0,0 +1,244 @@
|
||||
<template>
|
||||
<div class="p-4">
|
||||
<ChartGroupCard class="enter-y" :loading="loading" type="bdc" />
|
||||
<BdcTabCard class="!my-4 enter-y" :loading="loading" />
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-card :loading="loading" :class="{ 'anty-list-cust': true }" :bordered="false">
|
||||
<a-tabs v-model:activeKey="indexBottomTab" size="large" :tab-bar-style="{ marginBottom: '24px', paddingLeft: '16px' }">
|
||||
<template #rightExtra>
|
||||
<div class="extra-wrapper">
|
||||
<a-radio-group v-model:value="indexRegisterType" @change="changeRegisterType">
|
||||
<a-radio-button value="转移登记">转移登记</a-radio-button>
|
||||
<a-radio-button value="抵押登记">抵押登记</a-radio-button>
|
||||
<a-radio-button value="">所有</a-radio-button>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<a-tab-pane tab="业务流程限时监管" key="1">
|
||||
<a-table
|
||||
:dataSource="dataSource"
|
||||
size="default"
|
||||
rowKey="reBizCode"
|
||||
:columns="table.columns"
|
||||
:pagination="ipagination"
|
||||
@change="tableChange"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'flowRate'">
|
||||
<Progress
|
||||
:strokeColor="getPercentColor(record.flowRate)"
|
||||
:format="getPercentFormat"
|
||||
:percent="getFlowRateNumber(record.flowRate)"
|
||||
style="width: 80px"
|
||||
/>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-tab-pane>
|
||||
|
||||
<a-tab-pane loading="true" tab="业务节点限时监管" key="2">
|
||||
<a-table
|
||||
:dataSource="dataSource1"
|
||||
size="default"
|
||||
rowKey="reBizCode"
|
||||
:columns="table1.columns"
|
||||
:pagination="ipagination1"
|
||||
@change="tableChange1"
|
||||
>
|
||||
<template #bodyCell="{ column, record }">
|
||||
<template v-if="column.dataIndex === 'flowRate'">
|
||||
<span style="color: red">{{ record.flowRate }}小时</span>
|
||||
</template>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, unref } from 'vue';
|
||||
import { Progress } from 'ant-design-vue';
|
||||
import ChartGroupCard from '../components/ChartGroupCard.vue';
|
||||
import BdcTabCard from '../components/BdcTabCard.vue';
|
||||
import LineMulti from '/@/components/chart/LineMulti.vue';
|
||||
import HeadInfo from '/@/components/chart/HeadInfo.vue';
|
||||
import { table, table1 } from '../data';
|
||||
|
||||
const loading = ref(true);
|
||||
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 500);
|
||||
|
||||
const indexBottomTab = ref('1');
|
||||
const indexRegisterType = ref('转移登记');
|
||||
const dataSource = ref([]);
|
||||
const dataSource1 = ref([]);
|
||||
const ipagination = ref(table.ipagination);
|
||||
const ipagination1 = ref(table1.ipagination);
|
||||
|
||||
function changeRegisterType(e) {
|
||||
indexRegisterType.value = e.target.value;
|
||||
if (unref(indexBottomTab) == '1') {
|
||||
loadDataSource();
|
||||
} else {
|
||||
loadDataSource1();
|
||||
}
|
||||
}
|
||||
|
||||
function tableChange(pagination) {
|
||||
ipagination.value.current = pagination.current;
|
||||
ipagination.value.pageSize = pagination.pageSize;
|
||||
loadDataSource();
|
||||
}
|
||||
|
||||
function tableChange1(pagination) {
|
||||
ipagination1.value.current = pagination.current;
|
||||
ipagination1.value.pageSize = pagination.pageSize;
|
||||
loadDataSource1();
|
||||
}
|
||||
|
||||
function getFlowRateNumber(value) {
|
||||
return +value;
|
||||
}
|
||||
|
||||
function getPercentFormat(value) {
|
||||
if (value == 100) {
|
||||
return '超时';
|
||||
} else {
|
||||
return value + '%';
|
||||
}
|
||||
}
|
||||
|
||||
function getPercentColor(value) {
|
||||
let p = +value;
|
||||
if (p >= 90 && p < 100) {
|
||||
return 'rgb(244, 240, 89)';
|
||||
} else if (p >= 100) {
|
||||
return 'red';
|
||||
} else {
|
||||
return 'rgb(16, 142, 233)';
|
||||
}
|
||||
}
|
||||
|
||||
function loadDataSource() {
|
||||
dataSource.value = table.dataSource.filter((item) => {
|
||||
if (!unref(indexRegisterType)) {
|
||||
return true;
|
||||
}
|
||||
return item.type == unref(indexRegisterType);
|
||||
});
|
||||
}
|
||||
|
||||
function loadDataSource1() {
|
||||
dataSource1.value = table1.dataSource.filter((item) => {
|
||||
if (!unref(indexRegisterType)) {
|
||||
return true;
|
||||
}
|
||||
return item.type == unref(indexRegisterType);
|
||||
});
|
||||
}
|
||||
|
||||
loadDataSource();
|
||||
loadDataSource1();
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.ant-table-wrapper {
|
||||
:deep(.ant-table){
|
||||
td,th {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.extra-wrapper {
|
||||
line-height: 55px;
|
||||
padding-right: 24px;
|
||||
|
||||
.extra-item {
|
||||
display: inline-block;
|
||||
margin-right: 24px;
|
||||
|
||||
a {
|
||||
margin-left: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.item-group {
|
||||
padding: 20px 0 8px 24px;
|
||||
font-size: 0;
|
||||
|
||||
a {
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
margin-bottom: 13px;
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
.item-group {
|
||||
.more-btn {
|
||||
margin-bottom: 13px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.list-content-item {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
font-size: 14px;
|
||||
margin-left: 40px;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1600px) {
|
||||
.list-content-item {
|
||||
margin-left: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1300px) {
|
||||
.list-content-item {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.width-hidden4 {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.list-content-item {
|
||||
span {
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.list-content-item {
|
||||
p {
|
||||
margin-top: 4px;
|
||||
margin-bottom: 0;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
.anty-list-cust {
|
||||
.ant-list-item-meta {
|
||||
flex: 0.3 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.anty-list-cust {
|
||||
.ant-list-item-content {
|
||||
flex: 1 !important;
|
||||
justify-content: flex-start !important;
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<div class="p-4">
|
||||
<ChartGroupCard class="enter-y" :loading="loading" type="chart" />
|
||||
<SaleTabCard class="!my-4 enter-y" :loading="loading" />
|
||||
<a-row>
|
||||
<a-col :span="24">
|
||||
<a-card :loading="loading" :bordered="false" title="最近一周访问量统计">
|
||||
<div class="infoArea">
|
||||
<HeadInfo title="今日IP" :iconColor="ipColor" :content="loginfo.todayIp" icon="environment"></HeadInfo>
|
||||
<HeadInfo title="今日访问" :iconColor="visitColor" :content="loginfo.todayVisitCount" icon="team"></HeadInfo>
|
||||
<HeadInfo title="总访问量" :iconColor="seriesColor" :content="loginfo.totalVisitCount" icon="rise"></HeadInfo>
|
||||
</div>
|
||||
<LineMulti :chartData="lineMultiData" height="33vh" type="line" :option="{ legend: { top: 'bottom' } }"></LineMulti>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, watch } from 'vue';
|
||||
import ChartGroupCard from '../components/ChartGroupCard.vue';
|
||||
import SaleTabCard from '../components/SaleTabCard.vue';
|
||||
import LineMulti from '/@/components/chart/LineMulti.vue';
|
||||
import HeadInfo from '/@/components/chart/HeadInfo.vue';
|
||||
import { getLoginfo, getVisitInfo } from '../api.ts';
|
||||
import { useRootSetting } from '/@/hooks/setting/useRootSetting';
|
||||
|
||||
const loading = ref(true);
|
||||
const { getThemeColor } = useRootSetting();
|
||||
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 500);
|
||||
|
||||
const loginfo = ref({});
|
||||
const lineMultiData = ref([]);
|
||||
|
||||
function initLogInfo() {
|
||||
getLoginfo(null).then((res) => {
|
||||
if (res.success) {
|
||||
Object.keys(res.result).forEach((key) => {
|
||||
res.result[key] = res.result[key] + '';
|
||||
});
|
||||
loginfo.value = res.result;
|
||||
}
|
||||
});
|
||||
getVisitInfo(null).then((res) => {
|
||||
if (res.success) {
|
||||
lineMultiData.value = [];
|
||||
res.result.forEach((item) => {
|
||||
lineMultiData.value.push({ name: item.type, type: 'ip', value: item.ip, color: ipColor.value });
|
||||
lineMultiData.value.push({ name: item.type, type: 'visit', value: item.visit, color: visitColor.value });
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const ipColor = ref();
|
||||
const visitColor = ref();
|
||||
const seriesColor = ref();
|
||||
watch(
|
||||
() => getThemeColor.value,
|
||||
() => {
|
||||
seriesColor.value = getThemeColor.value;
|
||||
visitColor.value = '#67B962';
|
||||
ipColor.value = getThemeColor.value;
|
||||
initLogInfo();
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
function getRandomColor() {
|
||||
var letters = '0123456789ABCDEF';
|
||||
var color = '#';
|
||||
for (var i = 0; i < 6; i++) {
|
||||
color += letters[Math.floor(Math.random() * 16)];
|
||||
}
|
||||
return color;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.infoArea {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0 10%;
|
||||
.head-info.center {
|
||||
padding: 0;
|
||||
}
|
||||
.head-info {
|
||||
min-width: 0;
|
||||
}
|
||||
}
|
||||
.circle-cust {
|
||||
position: relative;
|
||||
top: 28px;
|
||||
left: -100%;
|
||||
}
|
||||
|
||||
.extra-wrapper {
|
||||
line-height: 55px;
|
||||
padding-right: 24px;
|
||||
|
||||
.extra-item {
|
||||
display: inline-block;
|
||||
margin-right: 24px;
|
||||
|
||||
a {
|
||||
margin-left: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 首页访问量统计 */
|
||||
.head-info {
|
||||
position: relative;
|
||||
text-align: left;
|
||||
padding: 0 32px 0 0;
|
||||
min-width: 125px;
|
||||
|
||||
&.center {
|
||||
text-align: center;
|
||||
padding: 0 32px;
|
||||
}
|
||||
|
||||
span {
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
display: inline-block;
|
||||
font-size: 0.95rem;
|
||||
line-height: 42px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 42px;
|
||||
margin: 0;
|
||||
|
||||
a {
|
||||
font-weight: 600;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ant-card {
|
||||
::v-deep(.ant-card-head-title) {
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<div class="p-4">
|
||||
<GrowCard :loading="loading" class="enter-y" />
|
||||
<SiteAnalysis class="!my-4 enter-y" :loading="loading" />
|
||||
<div class="md:flex enter-y">
|
||||
<VisitRadar class="md:w-1/3 w-full" :loading="loading" />
|
||||
<VisitSource class="md:w-1/3 !md:mx-4 !md:my-0 !my-4 w-full" :loading="loading" />
|
||||
<SalesProductPie class="md:w-1/3 w-full" :loading="loading" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import GrowCard from '../components/GrowCard.vue';
|
||||
import SiteAnalysis from '../components/SiteAnalysis.vue';
|
||||
import VisitSource from '../components/VisitSource.vue';
|
||||
import VisitRadar from '../components/VisitRadar.vue';
|
||||
import SalesProductPie from '../components/SalesProductPie.vue';
|
||||
|
||||
const loading = ref(true);
|
||||
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 500);
|
||||
</script>
|
||||
@ -0,0 +1,422 @@
|
||||
<template>
|
||||
<div class="index-container-ty">
|
||||
<a-row type="flex" justify="start" :gutter="3">
|
||||
<a-col :sm="24" :lg="12">
|
||||
<a-card>
|
||||
<template #title>
|
||||
<div class="index-md-title">
|
||||
<img src="../../../../assets/images/daiban.png" />
|
||||
我的待办【{{ dataSource1.length }}】
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="dataSource1 && dataSource1.length > 0" #extra>
|
||||
<a @click="goPage"
|
||||
>更多
|
||||
<Icon icon="ant-design:double-right-outlined" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<a-table
|
||||
:class="'my-index-table tytable1'"
|
||||
ref="table1"
|
||||
size="small"
|
||||
rowKey="id"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource1"
|
||||
:pagination="false"
|
||||
>
|
||||
<template #ellipsisText="{ text }">
|
||||
<JEllipsis :value="text" :length="textMaxLength"></JEllipsis>
|
||||
</template>
|
||||
|
||||
<template #dayWarnning="{ text, record }">
|
||||
<BellTwoTone style="font-size: 22px" :twoToneColor="getTipColor(record)" />
|
||||
</template>
|
||||
|
||||
<template #action="{ text, record }">
|
||||
<a @click="handleData">办理</a>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
</a-col>
|
||||
|
||||
<a-col :sm="24" :lg="12">
|
||||
<a-card>
|
||||
<template #title>
|
||||
<div class="index-md-title">
|
||||
<img src="../../../../assets/images/zaiban.png" />
|
||||
我的在办【{{ dataSource2.length }}】
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-if="dataSource2 && dataSource2.length > 0" #extra>
|
||||
<a @click="goPage"
|
||||
>更多
|
||||
<Icon icon="ant-design:double-right-outlined" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<a-table
|
||||
:class="'my-index-table tytable2'"
|
||||
ref="table1"
|
||||
size="small"
|
||||
rowKey="id"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource2"
|
||||
:pagination="false"
|
||||
>
|
||||
<template #ellipsisText="{ text }">
|
||||
<JEllipsis :value="text" :length="textMaxLength"></JEllipsis>
|
||||
</template>
|
||||
|
||||
<template #dayWarnning="{ text, record }">
|
||||
<BellTwoTone style="font-size: 22px" :twoToneColor="getTipColor(record)" />
|
||||
</template>
|
||||
|
||||
<template #action="{ text, record }">
|
||||
<a @click="handleData">办理</a>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
</a-col>
|
||||
|
||||
<a-col :span="24">
|
||||
<div style="height: 5px"></div>
|
||||
</a-col>
|
||||
|
||||
<a-col :sm="24" :lg="12">
|
||||
<a-card>
|
||||
<template #title>
|
||||
<div class="index-md-title">
|
||||
<img src="../../../../assets/images/guaz.png" />
|
||||
我的挂账【{{ dataSource4.length }}】
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<a-table
|
||||
:class="'my-index-table tytable4'"
|
||||
ref="table1"
|
||||
size="small"
|
||||
rowKey="id"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource4"
|
||||
:pagination="false"
|
||||
>
|
||||
<template #ellipsisText="{ text }">
|
||||
<JEllipsis :value="text" :length="textMaxLength"></JEllipsis>
|
||||
</template>
|
||||
|
||||
<template #dayWarnning="{ text, record }">
|
||||
<BellTwoTone style="font-size: 22px" :twoToneColor="getTipColor(record)" />
|
||||
</template>
|
||||
|
||||
<template #action="{ text, record }">
|
||||
<a @click="handleData">办理</a>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
</a-col>
|
||||
|
||||
<a-col :sm="24" :lg="12">
|
||||
<a-card>
|
||||
<template #title>
|
||||
<div class="index-md-title">
|
||||
<img src="../../../../assets/images/duban.png" />
|
||||
我的督办【{{ dataSource3.length }}】
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<a-table
|
||||
:class="'my-index-table tytable3'"
|
||||
ref="table1"
|
||||
size="small"
|
||||
rowKey="id"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource3"
|
||||
:pagination="false"
|
||||
>
|
||||
<template #ellipsisText="{ text }">
|
||||
<JEllipsis :value="text" :length="textMaxLength"></JEllipsis>
|
||||
</template>
|
||||
|
||||
<template #dayWarnning="{ text, record }">
|
||||
<BellTwoTone style="font-size: 22px" :twoToneColor="getTipColor(record)" />
|
||||
</template>
|
||||
|
||||
<template #action="{ text, record }">
|
||||
<a @click="handleData">办理</a>
|
||||
</template>
|
||||
</a-table>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import noDataPng from '/@/assets/images/nodata.png';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import JEllipsis from '/@/components/Form/src/jeecg/components/JEllipsis.vue';
|
||||
import { BulbTwoTone, BellTwoTone } from '@ant-design/icons-vue';
|
||||
|
||||
const tempSs1 = [
|
||||
{
|
||||
id: '001',
|
||||
orderNo: '电[1]1267102',
|
||||
orderTitle: '药品出问题了',
|
||||
restDay: 1,
|
||||
},
|
||||
{
|
||||
id: '002',
|
||||
orderNo: '电[4]5967102',
|
||||
orderTitle: '吃了xxx医院的药,病情越来越严重',
|
||||
restDay: 0,
|
||||
},
|
||||
{
|
||||
id: '003',
|
||||
orderNo: '电[3]5988987',
|
||||
orderTitle: '今天去超市买鸡蛋,鸡蛋都是坏的',
|
||||
restDay: 7,
|
||||
},
|
||||
{
|
||||
id: '004',
|
||||
orderNo: '电[2]5213491',
|
||||
orderTitle: 'xx宝实体店高价售卖xx',
|
||||
restDay: 5,
|
||||
},
|
||||
{
|
||||
id: '005',
|
||||
orderNo: '电[1]1603491',
|
||||
orderTitle: '以红利相诱,答应退保后扣一年费用',
|
||||
restDay: 0,
|
||||
},
|
||||
];
|
||||
|
||||
const tempSs2 = [
|
||||
{
|
||||
id: '001',
|
||||
orderTitle: '我要投诉这个大超市',
|
||||
orderNo: '电[1]10299456',
|
||||
restDay: 6,
|
||||
},
|
||||
{
|
||||
id: '002',
|
||||
orderTitle: 'xxx医院乱开药方,售卖假药',
|
||||
orderNo: '电[2]20235691',
|
||||
restDay: 0,
|
||||
},
|
||||
{
|
||||
id: '003',
|
||||
orderTitle: '我想问问这家店是干啥的',
|
||||
orderNo: '电[3]495867322',
|
||||
restDay: 7,
|
||||
},
|
||||
{
|
||||
id: '004',
|
||||
orderTitle: '我要举报朝阳区奥森公园酒店',
|
||||
orderNo: '电[2]1193849',
|
||||
restDay: 3,
|
||||
},
|
||||
{
|
||||
id: '005',
|
||||
orderTitle: '我今天吃饭吃到一个石头子',
|
||||
orderNo: '电[4]56782344',
|
||||
restDay: 9,
|
||||
},
|
||||
];
|
||||
|
||||
//4-7天
|
||||
const tip_green = 'rgba(0, 255, 0, 1)';
|
||||
//1-3天
|
||||
const tip_yellow = 'rgba(255, 255, 0, 1)';
|
||||
//超期
|
||||
const tip_red = 'rgba(255, 0, 0, 1)';
|
||||
|
||||
const textMaxLength = 8;
|
||||
const $message = useMessage();
|
||||
|
||||
const dataSource1 = ref([]);
|
||||
const dataSource2 = ref([]);
|
||||
const dataSource3 = ref([]);
|
||||
const dataSource4 = ref([]);
|
||||
const columns = [
|
||||
{
|
||||
title: '',
|
||||
dataIndex: '',
|
||||
key: 'rowIndex',
|
||||
width: 50,
|
||||
fixed: 'left',
|
||||
align: 'center',
|
||||
slots: { customRender: 'dayWarnning' },
|
||||
},
|
||||
{
|
||||
title: '剩余天数',
|
||||
align: 'center',
|
||||
dataIndex: 'restDay',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '工单标题',
|
||||
align: 'center',
|
||||
dataIndex: 'orderTitle',
|
||||
slots: { customRender: 'ellipsisText' },
|
||||
},
|
||||
{
|
||||
title: '工单编号',
|
||||
align: 'center',
|
||||
dataIndex: 'orderNo',
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'action',
|
||||
align: 'center',
|
||||
slots: { customRender: 'action' },
|
||||
},
|
||||
];
|
||||
|
||||
function getTipColor(rd) {
|
||||
let num = rd.restDay;
|
||||
if (num <= 0) {
|
||||
return tip_red;
|
||||
} else if (num >= 1 && num < 4) {
|
||||
return tip_yellow;
|
||||
} else if (num >= 4) {
|
||||
return tip_green;
|
||||
}
|
||||
}
|
||||
|
||||
function mock() {
|
||||
dataSource1.value = tempSs1;
|
||||
dataSource2.value = tempSs2;
|
||||
dataSource3.value = tempSs1;
|
||||
dataSource4.value = tempSs2;
|
||||
ifNullDataSource(dataSource4, '.tytable4');
|
||||
}
|
||||
|
||||
function ifNullDataSource(ds, tb) {
|
||||
if (!ds || ds.length == 0) {
|
||||
var tmp = document.createElement('img');
|
||||
tmp.src = noDataPng;
|
||||
tmp.width = 300;
|
||||
let tbclass = `${tb} .ant-table-placeholder`;
|
||||
document.querySelector(tbclass).innerHTML = '';
|
||||
document.querySelector(tbclass).appendChild(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
function handleData() {
|
||||
$message.createMessage.success('办理完成');
|
||||
}
|
||||
|
||||
function goPage() {
|
||||
$message.createMessage.success('请根据具体业务跳转页面');
|
||||
}
|
||||
|
||||
mock();
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.my-index-table {
|
||||
height: 270px;
|
||||
|
||||
table {
|
||||
font-size: 14px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.index-container-ty {
|
||||
margin: 12px 12px 0;
|
||||
|
||||
:deep(.ant-card-body) {
|
||||
padding: 10px 12px 0 12px;
|
||||
}
|
||||
|
||||
:deep(.ant-card-head) {
|
||||
line-height: 24px;
|
||||
min-height: 24px;
|
||||
background: #7196fb !important;
|
||||
|
||||
.ant-card-head-title {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
|
||||
.ant-card-extra {
|
||||
padding: 0;
|
||||
|
||||
a {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #152ede;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-table-footer) {
|
||||
text-align: right;
|
||||
padding: 6px 12px 6px 6px;
|
||||
background: #fff;
|
||||
border-top: 2px solid #f7f1f1;
|
||||
}
|
||||
|
||||
.index-md-title {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
font-size: 21px;
|
||||
font-family: cursive;
|
||||
padding-left: 25px;
|
||||
|
||||
img {
|
||||
position: absolute;
|
||||
height: 25px;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.ant-table-thead > tr > th),
|
||||
:deep(.ant-table-tbody > tr > td) {
|
||||
border-bottom: 1px solid #90aeff;
|
||||
}
|
||||
|
||||
:deep(
|
||||
.ant-table-small
|
||||
> .ant-table-content
|
||||
> .ant-table-fixed-left
|
||||
> .ant-table-body-outer
|
||||
> .ant-table-body-inner
|
||||
> table
|
||||
> .ant-table-thead
|
||||
> tr
|
||||
> th),
|
||||
:deep(
|
||||
.ant-table-small
|
||||
> .ant-table-content
|
||||
> .ant-table-fixed-right
|
||||
> .ant-table-body-outer
|
||||
> .ant-table-body-inner
|
||||
> table
|
||||
> .ant-table-thead
|
||||
> tr
|
||||
> th) {
|
||||
border-bottom: 1px solid #90aeff;
|
||||
}
|
||||
|
||||
:deep(.ant-table-small > .ant-table-content > .ant-table-scroll > .ant-table-body > table > .ant-table-thead > tr > th) {
|
||||
border-bottom: 1px solid #90aeff;
|
||||
}
|
||||
|
||||
:deep(.ant-table-small) {
|
||||
border: 1px solid #90aeff;
|
||||
}
|
||||
|
||||
:deep(.ant-table-placeholder) {
|
||||
padding: 0;
|
||||
height: 215px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
24
jeecgboot-vue3/src/views/dashboard/Analysis/index.vue
Normal file
24
jeecgboot-vue3/src/views/dashboard/Analysis/index.vue
Normal file
@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<IndexChart v-if="indexStyle === 0"></IndexChart>
|
||||
<IndexDef v-if="indexStyle === 1"></IndexDef>
|
||||
<IndexBdc v-if="indexStyle == 2"></IndexBdc>
|
||||
<IndexTask v-if="indexStyle == 3"></IndexTask>
|
||||
<div style="width: 100%; text-align: right; margin-top: 20px">
|
||||
首页主题:
|
||||
<a-radio-group v-model:value="indexStyle">
|
||||
<a-radio :value="0">默认</a-radio>
|
||||
<a-radio :value="1">销量统计</a-radio>
|
||||
<a-radio :value="2">业务统计</a-radio>
|
||||
<a-radio :value="3">我的任务</a-radio>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import IndexDef from './homePage/IndexDef.vue';
|
||||
import IndexChart from './homePage/IndexChart.vue';
|
||||
import IndexBdc from './homePage/IndexBdc.vue';
|
||||
import IndexTask from './homePage/IndexTask.vue';
|
||||
|
||||
const indexStyle = ref(0);
|
||||
</script>
|
||||
@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<div v-if="visible" ref="aideWrapRef" class="aide-wrap" @click="handleGo">
|
||||
<div class="icon">
|
||||
<svg t="1706259688149" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2056" width="17" height="17">
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M427.904 492.608a16.896 16.896 0 0 0 0 24.96l438.528 426.368a54.272 54.272 0 0 0 77.056 0 50.752 50.752 0 0 0 0-74.88L504.96 442.688a18.112 18.112 0 0 0-25.664 0l-51.392 49.92z m-12.16-137.728l-70.272-58.624a36.48 36.48 0 0 0-46.208 0l-46.144 38.464c-13.248 11.008-13.248 27.52 0 38.464l70.336 58.624a24.32 24.32 0 0 0 30.784 0l61.568-51.264c8.768-7.36 8.768-18.304 0-25.664z m-160.64 448c23.68-78.72 81.152-140.8 158.4-165.696a13.12 13.12 0 0 0 0-24.832C338.24 587.52 278.848 527.424 255.104 446.656c-3.968-12.416-19.84-12.416-23.808 0-23.68 78.72-81.152 140.8-158.4 165.696a13.12 13.12 0 0 0 0 24.832c75.264 24.896 134.656 84.928 158.4 165.76 3.968 10.304 19.84 10.304 23.808 0zM621.184 71.04a203.584 203.584 0 0 1-132.096 132.096 11.008 11.008 0 0 0 0 20.48 203.584 203.584 0 0 1 132.16 132.16 11.008 11.008 0 0 0 20.48 0 203.584 203.584 0 0 1 132.096-132.16 11.008 11.008 0 0 0 0-20.48 203.584 203.584 0 0 1-132.096-132.096c-3.776-9.28-18.624-9.28-20.48 0zM191.488 282.368c15.936-48.512 53.76-83.968 105.536-98.88 7.936-1.92 7.936-13.056 0-14.976-51.776-14.912-89.6-50.368-105.536-98.88-1.984-7.488-13.952-7.488-15.936 0-15.936 48.512-53.76 83.968-105.536 98.88-7.936 1.92-7.936 13.056 0 14.976 51.84 14.912 89.6 50.368 105.6 98.88 1.92 7.488 13.888 7.488 15.872 0z"
|
||||
p-id="2057"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<a-popconfirm
|
||||
:open="popconfirmVisible"
|
||||
title="确定AI助手退出吗?"
|
||||
ok-text="确定"
|
||||
cancel-text="取消"
|
||||
@cancel="handleCancel"
|
||||
@confirm="handleConfirm"
|
||||
>
|
||||
<span class="text">AI助手</span>
|
||||
</a-popconfirm>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { router } from '/@/router';
|
||||
import { AIDE_FLAG } from '/@/enums/cacheEnum';
|
||||
import { getToken } from '/@/utils/auth';
|
||||
import { getAuthCache, setAuthCache, removeAuthCache } from '/@/utils/auth';
|
||||
const visible = ref(1);
|
||||
const aideWrapRef = ref(null);
|
||||
const popconfirmVisible = ref(false);
|
||||
|
||||
onMounted(() => {
|
||||
const aideFlag = getAuthCache(AIDE_FLAG);
|
||||
if (aideFlag && aideFlag == getToken()) {
|
||||
visible.value = false;
|
||||
} else {
|
||||
visible.value = true;
|
||||
}
|
||||
if (visible.value) {
|
||||
aideWrapRef.value.addEventListener('contextmenu', (e) => {
|
||||
popconfirmVisible.value = true;
|
||||
e.preventDefault();
|
||||
});
|
||||
}
|
||||
});
|
||||
const handleCancel = () => {
|
||||
popconfirmVisible.value = false;
|
||||
};
|
||||
const handleConfirm = () => {
|
||||
popconfirmVisible.value = false;
|
||||
visible.value = false;
|
||||
setAuthCache(AIDE_FLAG, getToken());
|
||||
};
|
||||
const handleGo = (params) => {
|
||||
router.push({ path: '/ai' });
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.aide-wrap {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
transform: translate(0, -50%);
|
||||
background-color: @primary-color;
|
||||
height: 46px;
|
||||
width: 46px;
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
line-height: 1;
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
.text {
|
||||
font-size: 12px;
|
||||
transform: scale(0.88);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
26
jeecgboot-vue3/src/views/dashboard/ai/index.vue
Normal file
26
jeecgboot-vue3/src/views/dashboard/ai/index.vue
Normal file
@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<div class="wrap">
|
||||
<div class="content">
|
||||
<AiChat></AiChat>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import AiChat from '/@/components/jeecg/AiChat/index.vue';
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.wrap {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
.content {
|
||||
background: #fff;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<Card title="最新动态" v-bind="$attrs">
|
||||
<template #extra>
|
||||
<a-button type="link" size="small">更多</a-button>
|
||||
</template>
|
||||
<List item-layout="horizontal" :data-source="dynamicInfoItems">
|
||||
<template #renderItem="{ item }">
|
||||
<ListItem>
|
||||
<ListItemMeta>
|
||||
<template #description>
|
||||
{{ item.date }}
|
||||
</template>
|
||||
<!-- eslint-disable-next-line -->
|
||||
<template #title> {{ item.name }} <span v-html="item.desc"> </span> </template>
|
||||
<template #avatar>
|
||||
<Icon :icon="item.avatar" :size="30" />
|
||||
</template>
|
||||
</ListItemMeta>
|
||||
</ListItem>
|
||||
</template>
|
||||
</List>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Card, List } from 'ant-design-vue';
|
||||
import { dynamicInfoItems } from './data';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
|
||||
const ListItem = List.Item;
|
||||
const ListItemMeta = List.Item.Meta;
|
||||
</script>
|
||||
@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<Card title="项目" v-bind="$attrs">
|
||||
<template #extra>
|
||||
<a-button type="link" size="small">更多</a-button>
|
||||
</template>
|
||||
|
||||
<template v-for="item in items" :key="item">
|
||||
<CardGrid class="!md:w-1/3 !w-full">
|
||||
<span class="flex">
|
||||
<Icon :icon="item.icon" :color="item.color" size="30" />
|
||||
<span class="text-lg ml-4">{{ item.title }}</span>
|
||||
</span>
|
||||
<div class="flex mt-2 h-10 text-secondary"> {{ item.desc }} </div>
|
||||
<div class="flex justify-between text-secondary">
|
||||
<span>{{ item.group }}</span>
|
||||
<span>{{ item.date }}</span>
|
||||
</div>
|
||||
</CardGrid>
|
||||
</template>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
import { groupItems } from './data';
|
||||
|
||||
export default defineComponent({
|
||||
components: { Card, CardGrid: Card.Grid, Icon },
|
||||
setup() {
|
||||
return { items: groupItems };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<Card title="快捷导航" v-bind="$attrs">
|
||||
<template v-for="item in navItems" :key="item">
|
||||
<CardGrid>
|
||||
<span class="flex flex-col items-center">
|
||||
<Icon :icon="item.icon" :color="item.color" size="20" />
|
||||
<span class="text-md mt-2">{{ item.title }}</span>
|
||||
</span>
|
||||
</CardGrid>
|
||||
</template>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { navItems } from './data';
|
||||
import { Icon } from '/@/components/Icon';
|
||||
|
||||
const CardGrid = Card.Grid;
|
||||
</script>
|
||||
@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<Card title="销售统计" :loading="loading">
|
||||
<div ref="chartRef" :style="{ width, height }"></div>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { Ref, ref, watch } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
|
||||
const props = defineProps({
|
||||
loading: Boolean,
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: '400px',
|
||||
},
|
||||
});
|
||||
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
watch(
|
||||
() => props.loading,
|
||||
() => {
|
||||
if (props.loading) {
|
||||
return;
|
||||
}
|
||||
setOptions({
|
||||
legend: {
|
||||
bottom: 0,
|
||||
data: ['Visits', 'Sales'],
|
||||
},
|
||||
tooltip: {},
|
||||
radar: {
|
||||
radius: '60%',
|
||||
splitNumber: 8,
|
||||
indicator: [
|
||||
{
|
||||
name: '2017',
|
||||
},
|
||||
{
|
||||
name: '2017',
|
||||
},
|
||||
{
|
||||
name: '2018',
|
||||
},
|
||||
{
|
||||
name: '2019',
|
||||
},
|
||||
{
|
||||
name: '2020',
|
||||
},
|
||||
{
|
||||
name: '2021',
|
||||
},
|
||||
],
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'radar' as 'custom',
|
||||
symbolSize: 0,
|
||||
areaStyle: {
|
||||
shadowBlur: 0,
|
||||
shadowColor: 'rgba(0,0,0,.2)',
|
||||
shadowOffsetX: 0,
|
||||
shadowOffsetY: 10,
|
||||
opacity: 1,
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: [90, 50, 86, 40, 50, 20],
|
||||
name: 'Visits',
|
||||
itemStyle: {
|
||||
color: '#b6a2de',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: [70, 75, 70, 76, 20, 85],
|
||||
name: 'Sales',
|
||||
itemStyle: {
|
||||
color: '#67e0e3',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div class="lg:flex">
|
||||
<Avatar :src="userinfo.avatar || headerImg" :size="72" class="!mx-auto !block" />
|
||||
<div class="md:ml-6 flex flex-col justify-center md:mt-0 mt-2">
|
||||
<h1 class="md:text-lg text-md">早安, {{ userinfo.realname }}, 开始您一天的工作吧!</h1>
|
||||
<span class="text-secondary"> 今日晴,20℃ - 32℃! </span>
|
||||
</div>
|
||||
<div class="flex flex-1 justify-end md:mt-0 mt-4">
|
||||
<div class="flex flex-col justify-center text-right">
|
||||
<span class="text-secondary"> 待办 </span>
|
||||
<span class="text-2xl">2/10</span>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col justify-center text-right md:mx-16 mx-12">
|
||||
<span class="text-secondary"> 项目 </span>
|
||||
<span class="text-2xl">8</span>
|
||||
</div>
|
||||
<div class="flex flex-col justify-center text-right md:mr-10 mr-4">
|
||||
<span class="text-secondary"> 团队 </span>
|
||||
<span class="text-2xl">300</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { Avatar } from 'ant-design-vue';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
import headerImg from '/@/assets/images/header.jpg';
|
||||
|
||||
const userStore = useUserStore();
|
||||
const userinfo = computed(() => userStore.getUserInfo);
|
||||
</script>
|
||||
156
jeecgboot-vue3/src/views/dashboard/workbench/components/data.ts
Normal file
156
jeecgboot-vue3/src/views/dashboard/workbench/components/data.ts
Normal file
@ -0,0 +1,156 @@
|
||||
interface GroupItem {
|
||||
title: string;
|
||||
icon: string;
|
||||
color: string;
|
||||
desc: string;
|
||||
date: string;
|
||||
group: string;
|
||||
}
|
||||
|
||||
interface NavItem {
|
||||
title: string;
|
||||
icon: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
interface DynamicInfoItem {
|
||||
avatar: string;
|
||||
name: string;
|
||||
date: string;
|
||||
desc: string;
|
||||
}
|
||||
|
||||
export const navItems: NavItem[] = [
|
||||
{
|
||||
title: '首页',
|
||||
icon: 'ion:home-outline',
|
||||
color: '#1fdaca',
|
||||
},
|
||||
{
|
||||
title: '仪表盘',
|
||||
icon: 'ion:grid-outline',
|
||||
color: '#bf0c2c',
|
||||
},
|
||||
{
|
||||
title: '组件',
|
||||
icon: 'ion:layers-outline',
|
||||
color: '#e18525',
|
||||
},
|
||||
{
|
||||
title: '系统管理',
|
||||
icon: 'ion:settings-outline',
|
||||
color: '#3fb27f',
|
||||
},
|
||||
{
|
||||
title: '权限管理',
|
||||
icon: 'ion:key-outline',
|
||||
color: '#4daf1bc9',
|
||||
},
|
||||
{
|
||||
title: '图表',
|
||||
icon: 'ion:bar-chart-outline',
|
||||
color: '#00d8ff',
|
||||
},
|
||||
];
|
||||
|
||||
export const dynamicInfoItems: DynamicInfoItem[] = [
|
||||
{
|
||||
avatar: 'dynamic-avatar-1|svg',
|
||||
name: '威廉',
|
||||
date: '刚刚',
|
||||
desc: `在 <a>开源组</a> 创建了项目 <a>Vue</a>`,
|
||||
},
|
||||
{
|
||||
avatar: 'dynamic-avatar-2|svg',
|
||||
name: '艾文',
|
||||
date: '1个小时前',
|
||||
desc: `关注了 <a>威廉</a> `,
|
||||
},
|
||||
{
|
||||
avatar: 'dynamic-avatar-3|svg',
|
||||
name: '克里斯',
|
||||
date: '1天前',
|
||||
desc: `发布了 <a>个人动态</a> `,
|
||||
},
|
||||
{
|
||||
avatar: 'dynamic-avatar-4|svg',
|
||||
name: 'Jeecg',
|
||||
date: '2天前',
|
||||
desc: `发表文章 <a>如何编写一个Vite插件</a> `,
|
||||
},
|
||||
{
|
||||
avatar: 'dynamic-avatar-5|svg',
|
||||
name: '皮特',
|
||||
date: '3天前',
|
||||
desc: `回复了 <a>杰克</a> 的问题 <a>如何进行项目优化?</a>`,
|
||||
},
|
||||
{
|
||||
avatar: 'dynamic-avatar-6|svg',
|
||||
name: '杰克',
|
||||
date: '1周前',
|
||||
desc: `关闭了问题 <a>如何运行项目</a> `,
|
||||
},
|
||||
{
|
||||
avatar: 'dynamic-avatar-1|svg',
|
||||
name: '威廉',
|
||||
date: '1周前',
|
||||
desc: `发布了 <a>个人动态</a> `,
|
||||
},
|
||||
{
|
||||
avatar: 'dynamic-avatar-1|svg',
|
||||
name: '威廉',
|
||||
date: '2021-04-01 20:00',
|
||||
desc: `推送了代码到 <a>Github</a>`,
|
||||
},
|
||||
];
|
||||
|
||||
export const groupItems: GroupItem[] = [
|
||||
{
|
||||
title: 'Github',
|
||||
icon: 'carbon:logo-github',
|
||||
color: '',
|
||||
desc: '不要等待机会,而要创造机会。',
|
||||
group: '开源组',
|
||||
date: '2021-04-01',
|
||||
},
|
||||
{
|
||||
title: 'Vue',
|
||||
icon: 'ion:logo-vue',
|
||||
color: '#3fb27f',
|
||||
desc: '现在的你决定将来的你。',
|
||||
group: '算法组',
|
||||
date: '2021-04-01',
|
||||
},
|
||||
{
|
||||
title: 'Html5',
|
||||
icon: 'ion:logo-html5',
|
||||
color: '#e18525',
|
||||
desc: '没有什么才能比努力更重要。',
|
||||
group: '上班摸鱼',
|
||||
date: '2021-04-01',
|
||||
},
|
||||
{
|
||||
title: 'Angular',
|
||||
icon: 'ion:logo-angular',
|
||||
color: '#bf0c2c',
|
||||
desc: '热情和欲望可以突破一切难关。',
|
||||
group: 'UI',
|
||||
date: '2021-04-01',
|
||||
},
|
||||
{
|
||||
title: 'React',
|
||||
icon: 'bx:bxl-react',
|
||||
color: '#00d8ff',
|
||||
desc: '健康的身体是实目标的基石。',
|
||||
group: '技术牛',
|
||||
date: '2021-04-01',
|
||||
},
|
||||
{
|
||||
title: 'Js',
|
||||
icon: 'ion:logo-javascript',
|
||||
color: '#4daf1bc9',
|
||||
desc: '路是走出来的,而不是空想出来的。',
|
||||
group: '架构组',
|
||||
date: '2021-04-01',
|
||||
},
|
||||
];
|
||||
36
jeecgboot-vue3/src/views/dashboard/workbench/index.vue
Normal file
36
jeecgboot-vue3/src/views/dashboard/workbench/index.vue
Normal file
@ -0,0 +1,36 @@
|
||||
<template>
|
||||
<PageWrapper>
|
||||
<template #headerContent> <WorkbenchHeader /> </template>
|
||||
<div class="lg:flex">
|
||||
<div class="lg:w-7/10 w-full !mr-4 enter-y">
|
||||
<ProjectCard :loading="loading" class="enter-y" />
|
||||
<DynamicInfo :loading="loading" class="!my-4 enter-y" />
|
||||
</div>
|
||||
<div class="lg:w-3/10 w-full enter-y">
|
||||
<QuickNav :loading="loading" class="enter-y" />
|
||||
|
||||
<Card class="!my-4 enter-y" :loading="loading">
|
||||
<img class="xl:h-50 h-30 mx-auto" src="../../../assets/svg/illustration.svg" />
|
||||
</Card>
|
||||
|
||||
<SaleRadar :loading="loading" class="enter-y" />
|
||||
</div>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import WorkbenchHeader from './components/WorkbenchHeader.vue';
|
||||
import ProjectCard from './components/ProjectCard.vue';
|
||||
import QuickNav from './components/QuickNav.vue';
|
||||
import DynamicInfo from './components/DynamicInfo.vue';
|
||||
import SaleRadar from './components/SaleRadar.vue';
|
||||
|
||||
const loading = ref(true);
|
||||
|
||||
setTimeout(() => {
|
||||
loading.value = false;
|
||||
}, 500);
|
||||
</script>
|
||||
117
jeecgboot-vue3/src/views/demo/charts/Line.vue
Normal file
117
jeecgboot-vue3/src/views/demo/charts/Line.vue
Normal file
@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, Ref, onMounted } from 'vue';
|
||||
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
import { getLineData } from './data';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions, echarts } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
const { barData, lineData, category } = getLineData;
|
||||
onMounted(() => {
|
||||
setOptions({
|
||||
backgroundColor: '#0f375f',
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'shadow',
|
||||
label: {
|
||||
show: true,
|
||||
backgroundColor: '#333',
|
||||
},
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
data: ['line', 'bar'],
|
||||
textStyle: {
|
||||
color: '#ccc',
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
data: category,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#ccc',
|
||||
},
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
splitLine: { show: false },
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#ccc',
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'line',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
showAllSymbol: 'auto',
|
||||
symbol: 'emptyCircle',
|
||||
symbolSize: 15,
|
||||
data: lineData,
|
||||
},
|
||||
{
|
||||
name: 'bar',
|
||||
type: 'bar',
|
||||
barWidth: 10,
|
||||
itemStyle: {
|
||||
borderRadius: 5,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#14c8d4' },
|
||||
{ offset: 1, color: '#43eec6' },
|
||||
]),
|
||||
},
|
||||
data: barData,
|
||||
},
|
||||
{
|
||||
name: 'line',
|
||||
type: 'bar',
|
||||
barGap: '-100%',
|
||||
barWidth: 10,
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: 'rgba(20,200,212,0.5)' },
|
||||
{ offset: 0.2, color: 'rgba(20,200,212,0.2)' },
|
||||
{ offset: 1, color: 'rgba(20,200,212,0)' },
|
||||
]),
|
||||
},
|
||||
z: -12,
|
||||
data: lineData,
|
||||
},
|
||||
{
|
||||
name: 'dotted',
|
||||
type: 'pictorialBar',
|
||||
symbol: 'rect',
|
||||
itemStyle: {
|
||||
color: '#0f375f',
|
||||
},
|
||||
symbolRepeat: true,
|
||||
symbolSize: [12, 4],
|
||||
symbolMargin: 1,
|
||||
z: -10,
|
||||
data: lineData,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
75
jeecgboot-vue3/src/views/demo/charts/Map.vue
Normal file
75
jeecgboot-vue3/src/views/demo/charts/Map.vue
Normal file
@ -0,0 +1,75 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, Ref, onMounted } from 'vue';
|
||||
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
import { mapData } from './data';
|
||||
import { registerMap } from 'echarts';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
|
||||
onMounted(async () => {
|
||||
const json = (await (await import('./china.json')).default) as any;
|
||||
registerMap('china', json);
|
||||
setOptions({
|
||||
visualMap: [
|
||||
{
|
||||
min: 0,
|
||||
max: 1000,
|
||||
left: 'left',
|
||||
top: 'bottom',
|
||||
text: ['高', '低'],
|
||||
calculable: false,
|
||||
orient: 'horizontal',
|
||||
inRange: {
|
||||
color: ['#e0ffff', '#006edd'],
|
||||
symbolSize: [30, 100],
|
||||
},
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
backgroundColor: 'rgba(0, 0, 0, .6)',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'iphone4',
|
||||
type: 'map',
|
||||
map: 'china',
|
||||
label: {
|
||||
show: true,
|
||||
color: 'rgb(249, 249, 249)',
|
||||
fontSize: 10,
|
||||
},
|
||||
itemStyle: {
|
||||
areaColor: '#2f82ce',
|
||||
borderColor: '#0DAAC1',
|
||||
},
|
||||
data: mapData,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
135
jeecgboot-vue3/src/views/demo/charts/Pie.vue
Normal file
135
jeecgboot-vue3/src/views/demo/charts/Pie.vue
Normal file
@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<div ref="chartRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, ref, Ref, onMounted } from 'vue';
|
||||
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
const dataAll = [389, 259, 262, 324, 232, 176, 196, 214, 133, 370];
|
||||
const yAxisData = ['原因1', '原因2', '原因3', '原因4', '原因5', '原因6', '原因7', '原因8', '原因9', '原因10'];
|
||||
onMounted(() => {
|
||||
setOptions({
|
||||
backgroundColor: '#0f375f',
|
||||
title: [
|
||||
{
|
||||
text: '各渠道投诉占比',
|
||||
left: '2%',
|
||||
top: '1%',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
fontSize: 14,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '投诉原因TOP10',
|
||||
left: '40%',
|
||||
top: '1%',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
fontSize: 14,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '各级别投诉占比',
|
||||
left: '2%',
|
||||
top: '50%',
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
fontSize: 14,
|
||||
},
|
||||
},
|
||||
],
|
||||
grid: [{ left: '50%', top: '7%', width: '45%', height: '90%' }],
|
||||
tooltip: {
|
||||
formatter: '{b} ({c})',
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
gridIndex: 0,
|
||||
axisTick: { show: false },
|
||||
axisLabel: { show: false },
|
||||
splitLine: { show: false },
|
||||
axisLine: { show: false },
|
||||
},
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
gridIndex: 0,
|
||||
interval: 0,
|
||||
data: yAxisData.reverse(),
|
||||
axisTick: { show: false },
|
||||
axisLabel: { show: true },
|
||||
splitLine: { show: false },
|
||||
axisLine: { show: true, lineStyle: { color: '#6173a3' } },
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '各渠道投诉占比',
|
||||
type: 'pie',
|
||||
radius: '30%',
|
||||
center: ['22%', '25%'],
|
||||
data: [
|
||||
{ value: 335, name: '客服电话' },
|
||||
{ value: 310, name: '奥迪官网' },
|
||||
{ value: 234, name: '媒体曝光' },
|
||||
{ value: 135, name: '质检总局' },
|
||||
{ value: 105, name: '其他' },
|
||||
],
|
||||
labelLine: { show: false },
|
||||
label: {
|
||||
show: true,
|
||||
formatter: '{b} \n ({d}%)',
|
||||
color: '#B1B9D3',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '各级别投诉占比',
|
||||
type: 'pie',
|
||||
radius: '30%',
|
||||
center: ['22%', '75%'],
|
||||
labelLine: { show: false },
|
||||
data: [
|
||||
{ value: 335, name: 'A级' },
|
||||
{ value: 310, name: 'B级' },
|
||||
{ value: 234, name: 'C级' },
|
||||
{ value: 135, name: 'D级' },
|
||||
],
|
||||
label: {
|
||||
show: true,
|
||||
formatter: '{b} \n ({d}%)',
|
||||
color: '#B1B9D3',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '投诉原因TOP10',
|
||||
type: 'bar',
|
||||
xAxisIndex: 0,
|
||||
yAxisIndex: 0,
|
||||
barWidth: '45%',
|
||||
itemStyle: { color: '#86c9f4' },
|
||||
label: { show: true, position: 'right', color: '#9EA7C4' },
|
||||
data: dataAll.sort(),
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
100
jeecgboot-vue3/src/views/demo/charts/SaleRadar.vue
Normal file
100
jeecgboot-vue3/src/views/demo/charts/SaleRadar.vue
Normal file
@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<Card title="销售统计" :loading="loading">
|
||||
<div ref="chartRef" :style="{ width, height }"></div>
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import type { Ref } from 'vue';
|
||||
import { defineComponent, ref, watch } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { useECharts } from '/@/hooks/web/useECharts';
|
||||
|
||||
export default defineComponent({
|
||||
components: { Card },
|
||||
props: {
|
||||
loading: Boolean,
|
||||
width: {
|
||||
type: String as PropType<string>,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String as PropType<string>,
|
||||
default: '400px',
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const chartRef = ref<HTMLDivElement | null>(null);
|
||||
const { setOptions } = useECharts(chartRef as Ref<HTMLDivElement>);
|
||||
watch(
|
||||
() => props.loading,
|
||||
() => {
|
||||
if (props.loading) {
|
||||
return;
|
||||
}
|
||||
setOptions({
|
||||
legend: {
|
||||
bottom: 0,
|
||||
data: ['Visits', 'Sales'],
|
||||
},
|
||||
tooltip: {},
|
||||
radar: {
|
||||
radius: '60%',
|
||||
splitNumber: 8,
|
||||
indicator: [
|
||||
{
|
||||
name: '2017',
|
||||
},
|
||||
{
|
||||
name: '2017',
|
||||
},
|
||||
{
|
||||
name: '2018',
|
||||
},
|
||||
{
|
||||
name: '2019',
|
||||
},
|
||||
{
|
||||
name: '2020',
|
||||
},
|
||||
{
|
||||
name: '2021',
|
||||
},
|
||||
],
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'radar' as 'custom',
|
||||
symbolSize: 0,
|
||||
areaStyle: {
|
||||
shadowBlur: 0,
|
||||
shadowColor: 'rgba(0,0,0,.2)',
|
||||
shadowOffsetX: 0,
|
||||
shadowOffsetY: 10,
|
||||
opacity: 1,
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value: [90, 50, 86, 40, 50, 20],
|
||||
name: 'Visits',
|
||||
itemStyle: {
|
||||
color: '#9f8ed7',
|
||||
},
|
||||
},
|
||||
{
|
||||
value: [70, 75, 70, 76, 20, 85],
|
||||
name: 'Sales',
|
||||
itemStyle: {
|
||||
color: '#1edec5',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
return { chartRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
839
jeecgboot-vue3/src/views/demo/charts/china.json
Normal file
839
jeecgboot-vue3/src/views/demo/charts/china.json
Normal file
@ -0,0 +1,839 @@
|
||||
{
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "710000",
|
||||
"properties": {
|
||||
"id": "710000",
|
||||
"cp": [121.509062, 24.044332],
|
||||
"name": "台湾",
|
||||
"childNum": 6
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@°Ü¯Û"],
|
||||
["@@ƛĴÕƊÉɼģºðʀ\\ƎsÆNŌÔĚänÜƤɊĂǀĆĴĤNJŨxĚĮǂƺòƌâÔ®ĮXŦţƸZûÐƕƑGđ¨ĭMó·ęcëƝɉlÝƯֹÅŃ^Ó·śŃNjƏďíåɛGɉ¿@ăƑ¥ĘWǬÏĶŁâ"],
|
||||
["@@\\p|WoYG¿¥Ij@¢"],
|
||||
["@@
¡@V^RqBbAnTXeRz¤L«³I"],
|
||||
["@@ÆEEkWqë @"],
|
||||
["@@fced"],
|
||||
["@@¯ɜÄèaì¯ØǓIġĽ"],
|
||||
["@@çûĖëĄhòř "]
|
||||
],
|
||||
"encodeOffsets": [
|
||||
[[122886, 24033]],
|
||||
[[123335, 22980]],
|
||||
[[122375, 24193]],
|
||||
[[122518, 24117]],
|
||||
[[124427, 22618]],
|
||||
[[124862, 26043]],
|
||||
[[126259, 26318]],
|
||||
[[127671, 26683]]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "130000",
|
||||
"properties": {
|
||||
"id": "130000",
|
||||
"cp": [114.502461, 38.045474],
|
||||
"name": "河北",
|
||||
"childNum": 3
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@o~Z]ªrºc_ħ²G¼s`jΟnüsÂłNX_M`ǽÓnUK
Ĝēs¤©yrý§uģcJe"],
|
||||
["@@U`Ts¿mÂ"],
|
||||
[
|
||||
"@@oºƋÄdeVDJj£J|ÅdzÂFt~KŨ¸IÆv|¢r}èonb}`RÎÄn°ÒdÞ²^®lnÐèĄlðÓ×]ªÆ}LiñÖ`^°Ç¶p®đDcŋ`ZÔ¶êqvFÆN®ĆTH®¦O¾IbÐã´BĐɢŴÆíȦpĐÞXR·nndO¤OÀĈƒQgµFo|gȒęSWb©osx|hYhgŃfmÖĩnºTÌSp¢dYĤ¶UĈjlǐpäìë|³kÛfw²Xjz~ÂqbTÑěŨ@|oMzv¢ZrÃVw¬ŧˏf°ÐTªqs{S¯r æÝlNd®²Ğ džiGĘJ¼lr}~K¨ŸƐÌWöÆzR¤lêmĞLÎ@¡|q]SvKÑcwpÏÏĿćènĪWlĄkT}J¤~ÈTdpddʾĬBVtEÀ¢ôPĎƗè@~kü\\rÊĔÖæW_§¼F´©òDòjYÈrbĞāøŀG{ƀ|¦ðrb|ÀH`pʞkvGpuARhÞÆǶgĘTǼƹS£¨¡ù³ŘÍ]¿ÂyôEP xX¶¹ÜO¡gÚ¡IwÃé¦ÅBÏ|ǰ
N«úmH¯âDùyŜŲIÄuШD¸dɂFOhđ©OiÃ`ww^ÌkÑH«ƇǤŗĺtFu
{Z}Ö@U´
ʚLg®¯Oı°Ãw ^VbÉsmA
ê]]w§RRl£ȭµu¯b{ÍDěïÿȧuT£ġěŗƃĝQ¨fVƋƅna@³@ďyýIĹÊKŭfċŰóxV@tƯJ]eR¾fe|rHA|h~Ėƍl§ÏlTíb ØoÅbbx³^zÃͶSj®AyÂhðk`«P˵EFÛ¬Y¨Ļrõqi¼Wi°§Ð±´°^[À|ĠO@ÆxO\\ta\\tĕtû{ġȧXýĪÓjùÎRb^ÎfK[ÝděYfíÙTyuUSyŌŏů@Oi½éŅaVcř§ax¹XŻácWU£ôãºQ¨÷Ñws¥qEHÙ|šYQoŕÇyáĂ£MðoťÊP¡mWO¡v{ôvîēÜISpÌhp¨ jdeŔQÖjX³àĈ[n`Yp@UcM`RKhEbpŞlNut®EtqnsÁgAiúoHqCXhfgu~ÏWP½¢G^}¯ÅīGCÑ^ãziMáļMTÃƘrMc|O_¯Ŏ´|morDkO\\mĆJfl@c̬¢aĦtRıÒ¾ùƀ^juųœKUFyƝ
īÛ÷ąV×qƥV¿aȉd³BqPBmaËđŻģmÅ®V¹d^KKonYg¯XhqaLdu¥ÍpDž¡KąÅkĝęěhq}HyÃ]¹ǧ£
Í÷¿qáµ§g¤o^á¾ZE¤i`ij{nOl»WÝĔįhgF[¿¡ßkOüš_ūiDZàUtėGyl}ÓM}jpEC~¡FtoQiHkk{Ãmï"
|
||||
]
|
||||
],
|
||||
"encodeOffsets": [[[119712, 40641]], [[121616, 39981]], [[116462, 37237]]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "140000",
|
||||
"properties": {
|
||||
"id": "140000",
|
||||
"cp": [111.849248, 36.857014],
|
||||
"name": "山西",
|
||||
"childNum": 1
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
"@@ÞĩÒSra}ÁyWix±Üe´lèßÓǏokćiµVZģ¡coTS˹ĪmnÕńehZg{gtwªpXaĚThȑp{¶Eh®RćƑP¿£Pmc¸mQÝWďȥoÅîɡųAďä³aÏJ½¥PGąSM
EÅruµéYÓŌ_dĒCoȵ]¯_²ÕjāK~©ÅØ^ÔkïçămÏk]±cݯÑÃmQÍ~_apm
~ç¡qu{JÅŧ·Ls}EyÁÆcI{¤IiCfUcƌÃp§]ě«vD@¡SÀµMÅwuYY¡DbÑc¡h×]nkoQdaMç~eDÛtT©±@¥ù@É¡ZcW|WqOJmĩl«ħşvOÓ«IqăV¥D[mI~Ó¢cehiÍ]Ɠ~ĥqX·eƷn±}v[ěďŕ]_œ`¹§ÕōIo©bs^}Ét±ū«³p£ÿ·Wµ|¡¥ăFÏs×¥ŅxÊdÒ{ºvĴÎêÌɊ²¶ü¨|ÞƸµȲLLúÉƎ¤ϊęĔV`_bªS^|dzY|dz¥pZbÆ£¶ÒK}tĦÔņƠPYznÍvX¶Ěn ĠÔzý¦ª÷ÑĸÙUȌ¸dòÜJð´ìúNM¬XZ´¤ŊǸ_tldI{¦ƀðĠȤ¥NehXnYGR° ƬDj¬¸|CĞKqºfƐiĺ©ª~ĆOQª ¤@ìǦɌ²æBÊTŸʂōĖĴŞȀÆÿȄlŤĒötνî¼ĨXh|ªM¤Ðz"
|
||||
],
|
||||
"encodeOffsets": [[116874, 41716]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "150000",
|
||||
"properties": {
|
||||
"id": "150000",
|
||||
"cp": [111.670801, 41.818311],
|
||||
"name": "内蒙古",
|
||||
"childNum": 2
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
[
|
||||
"@@¯PqFB
|S³C|kñHdiÄ¥sʼnÅ
PóÑÑE^ÅPpy_YtShQ·aHwsOnʼnÃs©iqjUSiº]ïW«gW¡ARë¥_sgÁnUI«m
]jvV¼euhwqAaW_µj
»çjioQR¹ēÃßt@r³[ÛlćË^ÍÉáGOUÛOB±XkŹ£k|e]olkVͼÕqtaÏõjgÁ£§U^RLËnX°ÇBz^~wfvypV ¯ƫĉ˭ȫƗŷɿÿĿƑ˃ĝÿÃǃßËőó©ǐȍŒĖM×ÍEyxþp]ÉvïèvƀnÂĴÖ@V~Ĉv¦wĖtējyÄDXÄxGQuv_i¦aBçw˛wD©{tāmQ{EJ§KPśƘƿ¥@sCTÉ}ɃwƇy±gÑ}T[÷kÐ禫
SÒ¥¸ëBX½HáŵÀğtSÝÂa[ƣ°¯¦Pï¡]£ġÒk®G²èQ°óMq}EóƐÇ\\@áügQÍu¥FTÕ¿Jû]|mvāÎYua^WoÀa·ząÒot×¶CLƗi¯¤mƎHNJ¤îìɾŊìTdåwsRÖgĒųúÍġäÕ}Q¶¿A[¡{d×uQAMxVvMOmăl«ct[wº_ÇÊjb£ĦS_éQZ_lwgOiýe`YYLq§IÁdz£ÙË[ÕªuƏ³ÍTs·bÁĽäė[b[ŗfãcn¥îC¿÷µ[ŏÀQōĉm¿Á^£mJVmL[{Ï_£F¥Ö{ŹA}
×Wu©ÅaųijƳhB{·TQqÙIķËZđ©Yc|M¡
LeVUóK_QWk_ĥ¿ãZ»X\\ĴuUèlG®ěłTĠğDŃOrÍdÆÍz]±
ŭ©Å]ÅÐ}UË¥©TċïxgckfWgi\\ÏĒ¥HkµEë{»ÏetcG±ahUiñiWsɁ·cCÕk]wȑ|ća}w
VaĚá G°ùnM¬¯{ÈÐÆA¥ÄêJxÙ¢hP¢ÛºµwWOóFÁz^ÀŗÎú´§¢T¤ǻƺSėǵhÝÅQgvBHouʝl_o¿Ga{ïq{¥|ſĿHĂ÷aĝÇqZñiñC³ª
»E`¨åXēÕqÉû[l}ç@čƘóO¿¡FUsAʽīccocÇS}£IS~ălkĩXçmĈ
ŀÐoÐdxÒuL^T{r@¢ÍĝKén£kQyÅõËXŷƏL§~}kq»IHėDžjĝ»ÑÞoå°qTt|r©ÏS¯·eŨĕx«È[eM¿yupN~¹ÏyN£{©għWí»Í¾səšDž_ÃĀɗ±ąijĉʍŌŷSÉA±åǥɋ@ë£R©ąP©}ĹªƏj¹erLDĝ·{i«ƫC£µsKC
GS|úþXgp{ÁX¿ć{ƱȏñZáĔyoÁhA}ŅĆfdʼn_¹Y°ėǩÑ¡H¯¶oMQqð¡Ë|Ñ`ƭŁX½·óÛxğįÅcQs«tȋDžFù^it«Č¯[hAi©á¥ÇĚ×l|¹y¯YȵƓñǙµïċĻ|Düȭ¶¡oŽäÕG\\ÄT¿Òõr¯LguÏYęRƩɷŌO\\İТæ^Ŋ IJȶȆbÜGĝ¬¿ĚVĎgª^íu½jÿĕęjık@Ľ]ėl¥ËĭûÁėéV©±ćn©ȇÍq¯½YÃÔʼnÉNÑÅÝy¹NqáʅDǡËñƁYÅy̱os§ȋµʽǘǏƬɱàưN¢ƔÊuľýľώȪƺɂļxZĈ}ÌʼnŪĺœĭFЛĽ̅ȣͽÒŵìƩÇϋÿȮǡŏçƑůĕ~ǼȳÐUfdIxÿ\\G zâɏÙOº·pqy£@qþ@Ǟ˽IBäƣzsÂZÁàĻdñ°ŕzéØűzșCìDȐĴĺf®Àľưø@ɜÖÞKĊŇƄ§͑těï͡VAġÑÑ»d³öǍÝXĉĕÖ{þĉu¸ËʅğU̎éhɹƆ̗̮ȘNJ֥ड़ࡰţાíϲäʮW¬®ҌeרūȠkɬɻ̼ãüfƠSצɩςåȈHϚÎKdzͲOðÏȆƘ¼CϚǚ࢚˼ФÔ¤ƌĞ̪Qʤ´¼mȠJˀƲÀɠmǐnǔĎȆÞǠN~ʢĜ¶ƌĆĘźʆȬ˪ĚǏĞGȖƴƀj`ĢçĶāàŃºēĢĖćYÀŎüôQÐÂŎŞdžŞêƖoˆDĤÕºÑǘÛˤ³̀gńƘĔÀ^ªƂ`ªt¾äƚêĦ¼ÐĔǎ¨Ȕ»͠^ˮÊȦƤøxRrŜH¤¸ÂxDÄ|ø˂˜ƮЬɚwɲFjĔ²Äw°dždÀÉ_ĸdîàŎjÊêTЪŌŜWÈ|tqĢUB~´°ÎFCU¼pĀēƄN¦¾O¶łKĊOjĚj´ĜYp{¦SĚÍ\\TתV÷Ší¨ÅDK°ßtŇĔK¨ǵÂcḷ̌ĚǣȄĽFlġUĵŇȣFʉɁMğįʏƶɷØŭOǽ«ƽū¹Ʊő̝Ȩ§ȞʘĖiɜɶʦ}¨֪ࠜ̀ƇǬ¹ǨE˦ĥªÔêFxúQEr´Wrh¤Ɛ \\talĈDJÜ|[Pll̚¸ƎGú´P¬W¦^¦H]prRn|or¾wLVnÇIujkmon£cX^Bh`¥V¦U¤¸}xRj[^xN[~ªxQ[`ªHÆÂExx^wN¶Ê|¨ìMrdYpoRzNyÀDs~bcfÌ`L¾n|¾T°c¨È¢ar¤`[|òDŞĔöxElÖdHÀI`Ď\\Àì~ÆR¼tf¦^¢ķ¶eÐÚMptgjɡČÅyġLûŇV®ÄÈƀϰP|ªVVªj¬ĚÒêp¬E|ŬÂc|ÀtƐK f{ĘFĒƌXƲąo½Ę\\¥o}Ûu£çkX{uĩ«āíÓUŅßŢqŤ¥lyň[oi{¦LńðFȪȖĒL¿Ìf£K£ʺoqNwğc`uetOj×°KJ±qÆġmĚŗos¬
qehqsuH{¸kH¡
ÊRǪÇƌbȆ¢´äÜ¢NìÉʖ¦â©Ġu¦öČ^â£ĂhĖMÈÄw\\fŦ°W ¢¾luŸDw\\̀ʉÌÛM
Ā[bÓEn}¶Vc
ês"
|
||||
]
|
||||
],
|
||||
"encodeOffsets": [[[129102, 52189]]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "210000",
|
||||
"properties": {
|
||||
"id": "210000",
|
||||
"cp": [123.429096, 41.796767],
|
||||
"name": "辽宁",
|
||||
"childNum": 16
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@L@@sa"],
|
||||
["@@MnNm"],
|
||||
["@@dc"],
|
||||
["@@eÀC@b"],
|
||||
["@@f
XwkbrÄ`qg"],
|
||||
["@@^jtWQ"],
|
||||
["@@~ Y]c"],
|
||||
["@@G`ĔN^_¿ZÃM"],
|
||||
["@@iX¶BY"],
|
||||
["@@YZ"],
|
||||
["@@L_{Epf"],
|
||||
["@@^WqCT\\"],
|
||||
["@@\\[§t|¤_"],
|
||||
["@@m`n_"],
|
||||
["@@Ïxnj{q_×^Giip"],
|
||||
[
|
||||
"@@@é^BntaÊU]x ¯ÄPIJ°hʙK³VÕ@Y~|EvĹsǦL^pòŸÒG Ël]xxÄ_fT¤Ď¤cPC¨¸TVjbgH²sdÎdHt`B²¬GJję¶[ÐhjeXdlwhðSȦªVÊÏÆZÆŶ®²^ÎyÅÎcPqńĚDMħĜŁHkçvV[ij¼WYÀäĦ`XlR`ôLUVfK¢{NZdĒªYĸÌÚJRr¸SA|ƴgŴĴÆbvªØX~źB|¦ÕE¤Ð`\\|KUnnI]¤ÀÂĊnŎR®Ő¿¶\\ÀøíDm¦ÎbŨabaĘ\\ľã¸atÎSƐ´©v\\ÖÚÌǴ¤Â¨JKrZ_ZfjþhPkx`YRIjJcVf~sCN¤ EhæmsHy¨SðÑÌ\\\\ĐRZk°IS§fqŒßýáĞÙÉÖ[^¯ǤŲê´\\¦¬ĆPM¯£»uïpùzExanµyoluqe¦W^£ÊL}ñrkqWňûPUP¡ôJoo·U}£[·¨@XĸDXmÛݺGUCÁª½{íĂ^cjk¶Ã[q¤LÉö³cux«zZf²BWÇ®Yß½ve±ÃCý£W{Ú^q^sÑ·¨ÍOt¹·C¥GDrí@wÕKţëV·i}xËÍ÷i©ĝɝǡ]{c±OW³Ya±_ç©HĕoƫŇqr³Lys[ñ³¯OSďOMisZ±ÅFC¥Pq{Ã[Pg}\\¿ghćO
k^ģÁFıĉĥMoEqqZûěʼn³F¦oĵhÕP{¯~TÍlªNßYÐ{Ps{ÃVUeĎwk±ʼnVÓ½ŽJãÇÇ»Jm°dhcÀffdF~ĀeĖd`sx² ®EżĀdQÂd^~ăÔH¦\\LKpĄVez¤NP ǹÓRÆąJSha[¦´ÂghwmBШźhI|VV|p] ¼èNä¶ÜBÖ¼L`¼bØæKVpoúNZÞÒKxpw|ÊEMnzEQIZZNBčÚFÜçmĩWĪñtÞĵÇñZ«uD±|Əlij¥ãn·±PmÍada CLǑkùó¡³Ï«QaċÏOÃ¥ÕđQȥċƭy³ÃA"
|
||||
]
|
||||
],
|
||||
"encodeOffsets": [
|
||||
[[123686, 41445]],
|
||||
[[126019, 40435]],
|
||||
[[124393, 40128]],
|
||||
[[126117, 39963]],
|
||||
[[125322, 40140]],
|
||||
[[126686, 40700]],
|
||||
[[126041, 40374]],
|
||||
[[125584, 40168]],
|
||||
[[125453, 40165]],
|
||||
[[125362, 40214]],
|
||||
[[125280, 40291]],
|
||||
[[125774, 39997]],
|
||||
[[125976, 40496]],
|
||||
[[125822, 39993]],
|
||||
[[125509, 40217]],
|
||||
[[122731, 40949]]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "220000",
|
||||
"properties": { "id": "220000", "cp": [125.3245, 43.886841], "name": "吉林", "childNum": 1 },
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
"@@pä³PClFbbÍzwBGĭZÅi»lYċ²SgkÇ£^Sqd¯R
©é£¯S\\cZ¹iűƏCuƍÓXoR}M^o£
R}oªUF
uuXHlEÅÏ©¤ÛmTþ¤D²ÄufàÀXXȱAeyYw¬dvõ´KÊ£\\rµÄlidā]|DÂVH¹Þ®ÜWnCķ W§@\\¸~¤Vp¸póIO¢VOŇürXql~òÉK]¤¥Xrfkvzpm¶bwyFoúv𼤠N°ąO¥«³[éǡű_°Õ\\ÚÊĝþâőàerR¨JYlďQ[ ÏYëЧTGztnß¡gFkMāGÁ¤ia Éȹ`\\xs¬dĆkNnuNUuP@vRY¾\\¢
GªóĄ~RãÖÎĢùđŴÕhQxtcæëSɽʼníëlj£ƍG£nj°KƘµDsØÑpyƸ®¿bXp]vbÍZuĂ{n^IüÀSÖ¦EvRÎûh@â[ƏÈô~FNr¯ôçR±HÑlĢ^¤¢OðævxsŒ]ÞÁTĠs¶¿âÆGW¾ìA¦·TѬè¥ÏÐJ¨¼ÒÖ¼ƦɄxÊ~StD@Ă¼Ŵ¡jlºWvÐzƦZвCH AxiukdGgetqmcÛ£Ozy¥cE}|
¾cZ
k¿uŐã[oxGikfeäT@
SUwpiÚFM©£è^Ú`@v¶eňf heP¶täOlÃUgÞzŸU`l}ÔÆUvØ_Ō¬Öi^ĉi§²ÃB~¡ĈÚEgc|DC_Ȧm²rBx¼MÔ¦ŮdĨÃâYxƘDVÇĺĿg¿cwÅ\\¹¥Yĭl¤OvLjM_a W`zļMž·\\swqÝSAqŚij¯°kRē°wx^ĐkǂÒ\\]nrĂ}²ĊŲÒøãh·M{yMzysěnĒġV·°G³¼XÀ¤¹i´o¤ŃÈ`ÌDzÄUĞd\\iÖmÈBĤÜɲDEh LG¾ƀľ{WaYÍÈĢĘÔRîĐj}ÇccjoUb½{h§Ǿ{KƖµÎ÷GĀÖŠåưÎslyiē«`å§H¥Ae^§GK}iã\\c]v©ģZmÃ|[M}ģTɟĵÂÂ`ÀçmFK¥ÚíÁbX³ÌQÒHof{]ept·GŋĜYünĎųVY^ydõkÅZW«WUa~U·SbwGçǑiW^qFuNĝ·EwUtW·Ýďæ©PuqEzwAVXRãQ`©GMehccďÏd©ÑW_ÏYƅ»
é\\ɹ~ǙG³mØ©BšuT§Ĥ½¢Ã_ýL¡ýqT^rme\\PpZZbyuybQefµ]UhĿDCmûvaÙNSkCwncćfv~
YÇG"
|
||||
],
|
||||
"encodeOffsets": [[130196, 42528]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "230000",
|
||||
"properties": {
|
||||
"id": "230000",
|
||||
"cp": [128.642464, 46.756967],
|
||||
"name": "黑龙江",
|
||||
"childNum": 2
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
[
|
||||
"@@UµNÿ¥īèçHÍøƕ¶Lǽ|g¨|a¾pVidd~ÈiíďÓQġėÇZÎXb½|ſÃH½KFgɱCģÛÇAnjÕc[VĝDZÃËÇ_ £ń³pj£º¿»WH´¯U¸đĢmtĜyzzNN|g¸÷äűѱĉā~mq^[ǁÑďlw]¯xQĔ¯l°řĴrBÞTxr[tޏĻN_yX`biNKu
P£kZĮ¦[ºxÆÀdhĹŀUÈƗCwáZħÄŭcÓ¥»NAw±qȥnD`{ChdÙFć}¢A±Äj¨]ĊÕjŋ«×`VuÓÅ~_kŷVÝyhVkÄãPsOµfgeŇ
µf@u_Ù ÙcªNªÙEojVxT@ãSefjlwH\\pŏäÀvlY½d{F~¦dyz¤PÜndsrhfHcvlwjF£G±DÏƥYyÏu¹XikĿ¦ÏqƗǀOŜ¨LI|FRĂn sª|C˜zxAè¥bfudTrFWÁ¹Am|ĔĕsķÆF´N}ć
UÕ@Áijſmuçuð^ÊýowFzØÎĕNőǏȎôªÌŒDŽàĀÄ˄ĞŀƒʀĀƘŸˮȬƬĊ°Uzouxe]}
AyÈW¯ÌmKQ]Īºif¸ÄX|sZt|½ÚUÎ lk^p{f¤lºlÆW A²PVÜPHÊâ]ÎĈÌÜk´\\@qàsĔÄQºpRij¼èi`¶bXrBgxfv»uUi^v~J¬mVp´£´VWrnP½ì¢BX¬hðX¹^TjVriªjtŊÄmtPGx¸bgRsT`ZozÆO]ÒFôÒOÆŊvÅpcGêsx´DR{AEOr°x|íb³Wm~DVjºéNNËܲɶGxŷCSt}]ûōSmtuÇÃĕNāg»íT«u}ç½BĵÞʣ¥ëÊ¡MÛ³ãȅ¡ƋaǩÈÉQG¢·lG|tvgrrf«ptęŘnÅĢrI²¯LiØsPf_vĠdxM prʹL¤¤eËÀđKïÙVY§]Ióáĥ]ķK¥j|pŇ\\kzţ¦šnņäÔVĂîά|vW®l¤èØrxm¶ă~lÄƯĄ̈́öȄEÔ¤ØQĄĄ»ƢjȦOǺ¨ìSŖÆƬyQv`cwZSÌ®ü±DŽ]ŀç¬B¬©ńzƺŷɄeeOĨSfm ĊƀP̎ēz©ĊÄÕÊmgÇsJ¥ƔŊśæÎÑqv¿íUOµªÂnĦÁ_½ä@êí
£P}Ġ[@gġ}gɊ×ûÏWXá¢užƻÌsNͽƎÁ§čŐAēeL³àydl¦ĘVçŁpśdžĽĺſÊQíÜçÛġÔsĕ¬Ǹ¯YßċġHµ ¡eå`ļrĉŘóƢFìĎWøxÊkƈdƬv|I|·©NqńRŀ¤éeŊŀàŀU²ŕƀBQ£Ď}L¹Îk@©ĈuǰųǨÚ§ƈnTËÇéƟÊcfčŤ^XmHĊĕË«W·ċëx³ǔķÐċJāwİ_ĸȀ^ôWr°oú¬Ħ
ŨK~ȰCĐ´Ƕ£fNÎèâw¢XnŮeÂÆĶ¾¾xäLĴĘlļO¤ÒĨA¢Êɚ¨®ØCÔ ŬGƠƦYĜĘÜƬDJg_ͥœ@čŅĻA¶¯@wÎqC½Ĉ»NăëKďÍQÙƫ[«ÃígßÔÇOÝáWñuZ¯ĥŕā¡ÑķJu¤E 寰WKɱ_d_}}vyõu¬ï¹ÓU±½@gÏ¿rýDg
Cdµ°MFYxw¿CG£Rƛ½Õ{]L§{qqą¿BÇƻğëܭNJË|c²}Fµ}ÙRsÓpg±QNqǫŋRwŕnéÑÉK«SeYR
ŋ@{¤SJ}D Ûǖ֍]gr¡µŷjqWÛham³~S«Þ]"
|
||||
]
|
||||
],
|
||||
"encodeOffsets": [[[134456, 44547]]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "320000",
|
||||
"properties": {
|
||||
"id": "320000",
|
||||
"cp": [119.767413, 33.041544],
|
||||
"name": "江苏",
|
||||
"childNum": 1
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
"@@cþÅPi`ZRu¥É\\]~°Y`µÓ^phÁbnÀşúòaĬºTÖŒbe¦¦{¸ZâćNp©Hr|^mjhSEb\\afv`sz^lkljÄtg¤D¾X¿À|ĐiZȀåB·î}GL¢õcßjayBFµÏC^ĭcÙt¿sğH]j{s©HM¢QnDÀ©DaÜÞ·jgàiDbPufjDk`dPOîhw¡ĥ¥GP²ĐobºrYî¶aHŢ´ ]´rılw³r_{£DB_Ûdåuk|Ũ¯F Cºyr{XFye³Þċ¿ÂkĭB¿MvÛpm`rÚã@ƹhågËÖƿxnlč¶Åì½Ot¾dJlVJĂǀŞqvnO^JZż·Q}êÍÅmµÒ]ƍ¦Dq}¬R^èĂ´ŀĻĊIÔtIJyQŐĠMNtR®òLhĚs©»}OÓGZz¶A\\jĨFäOĤHYJvÞHNiÜaĎÉnFQlNM¤B´ĄNöɂtpŬdfå
qm¿QûùŞÚb¤uŃJŴu»¹ĄlȖħŴw̌ŵ²ǹǠ͛hĭłƕrçü±Yxcitğ®jű¢KOķCoy`å®VTa_Ā]ŐÝɞï²ʯÊ^]afYǸÃĆēĪȣJđ͍ôƋÄÄÍīçÛɈǥ£ÛmY`ó£Z«§°Ó³QafusNıDž_k}¢m[ÝóDµ¡RLčiXyÅNïă¡¸iĔÏNÌŕoēdōîåŤûHcs}~Ûwbù¹£¦ÓCtOPrE^ÒogĉIµÛÅʹK
¤½phMü`oæŀ"
|
||||
],
|
||||
"encodeOffsets": [[121740, 32276]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "330000",
|
||||
"properties": {
|
||||
"id": "330000",
|
||||
"cp": [120.153576, 29.287459],
|
||||
"name": "浙江",
|
||||
"childNum": 45
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@E^dQ]K"],
|
||||
["@@jX^j"],
|
||||
["@@sfbU"],
|
||||
["@@qP\\xz[ck"],
|
||||
["@@R¢FX}°[s_"],
|
||||
["@@Cb\\}"],
|
||||
["@@e|v\\la{u"],
|
||||
["@@v~u}"],
|
||||
["@@QxÂF¯}"],
|
||||
["@@¹nvÞs¯o"],
|
||||
["@@rSkUEj"],
|
||||
["@@biZP"],
|
||||
["@@p[}INf"],
|
||||
["@@À¿"],
|
||||
["@@¹dnb
"],
|
||||
["@@rSBnR"],
|
||||
["@@g~h}"],
|
||||
["@@FlEk"],
|
||||
["@@OdPc"],
|
||||
["@@v[u\\"],
|
||||
["@@FjâL~wyoo~sµL\\"],
|
||||
["@@¬e¹aN"],
|
||||
["@@\\nÔ¡q]L³ë\\ÿ®QÖ"],
|
||||
["@@ÊA©[¬"],
|
||||
["@@Kxv"],
|
||||
["@@@hlIk]"],
|
||||
["@@pW{o||j"],
|
||||
["@@Md|_mC"],
|
||||
["@@¢
X£ÏylD¼XtH"],
|
||||
["@@hlÜ[LykAvyfw^E¤"],
|
||||
["@@fp¤MusR"],
|
||||
["@@®_ma~LÁ¬Z"],
|
||||
["@@iMxZ"],
|
||||
["@@ZcYd"],
|
||||
["@@Z~dOSo|A¿qZv"],
|
||||
["@@@`EN¡v"],
|
||||
["@@|TY{"],
|
||||
["@@@n@m"],
|
||||
["@@XWkCT\\"],
|
||||
["@@ºwZRkĕWO¢"],
|
||||
["@@X®±Grƪ\\ÔáXq{"],
|
||||
["@@ůTG°ĄLHm°UC"],
|
||||
[
|
||||
"@@¤aÜx~}dtüGæţŎíĔcŖpMËÐj碷ðĄÆMzjWKĎ¢Q¶À_ê_Bıi«pZgf¤Nrq]§ĂN®«H±yƳí¾×ŸīàLłčŴǝĂíÀBŖÕªÁŖHŗʼnåqûõi¨hÜ·ñt»¹ýv_[«¸mYL¯Qª
mĉÅdMgÇjcº«ę¬K´B«Âącoċ\\xKd¡gěŧ«®á[~ıxu·ÅKsËÉc¢Ù\\ĭƛëbf¹ģSĜkáƉÔĈZB{aMµfzʼnfåÂŧįƋǝÊĕġć£g³neą»@¦S®\\ßðChiqªĭiAuAµ_W¥ƣO\\lċĢttC¨£t`PZäuXßBsĻyekOđġĵHuXBµ]×\\°®¬F¢¾pµ¼kŘó¬Wät¸|@L¨¸µrºù³Ù~§WIZW®±Ð¨ÒÉx`²pĜrOògtÁZ}þÙ]¡FKwsPlU[}¦Rvn`hq¬\\nQ´ĘRWb_ rtČFIÖkĦPJ¶ÖÀÖJĈĄTĚòC ²@Pú
Øz©PCÈÚDZhŖl¬â~nm¨f©iļ«mntuÖZÜÄjL®EÌFª²iÊxبIÈhhst"
|
||||
],
|
||||
["@@o\\VzRZ}y"],
|
||||
["@@@°¡mÛGĕ¨§Ianá[ýƤjfæØLäGr"]
|
||||
],
|
||||
"encodeOffsets": [
|
||||
[[125592, 31553]],
|
||||
[[125785, 31436]],
|
||||
[[125729, 31431]],
|
||||
[[125513, 31380]],
|
||||
[[125223, 30438]],
|
||||
[[125115, 30114]],
|
||||
[[124815, 29155]],
|
||||
[[124419, 28746]],
|
||||
[[124095, 28635]],
|
||||
[[124005, 28609]],
|
||||
[[125000, 30713]],
|
||||
[[125111, 30698]],
|
||||
[[125078, 30682]],
|
||||
[[125150, 30684]],
|
||||
[[124014, 28103]],
|
||||
[[125008, 31331]],
|
||||
[[125411, 31468]],
|
||||
[[125329, 31479]],
|
||||
[[125626, 30916]],
|
||||
[[125417, 30956]],
|
||||
[[125254, 30976]],
|
||||
[[125199, 30997]],
|
||||
[[125095, 31058]],
|
||||
[[125083, 30915]],
|
||||
[[124885, 31015]],
|
||||
[[125218, 30798]],
|
||||
[[124867, 30838]],
|
||||
[[124755, 30788]],
|
||||
[[124802, 30809]],
|
||||
[[125267, 30657]],
|
||||
[[125218, 30578]],
|
||||
[[125200, 30562]],
|
||||
[[124968, 30474]],
|
||||
[[125167, 30396]],
|
||||
[[124955, 29879]],
|
||||
[[124714, 29781]],
|
||||
[[124762, 29462]],
|
||||
[[124325, 28754]],
|
||||
[[123990, 28459]],
|
||||
[[125366, 31477]],
|
||||
[[125115, 30363]],
|
||||
[[125369, 31139]],
|
||||
[[122495, 31878]],
|
||||
[[125329, 30690]],
|
||||
[[125192, 30787]]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "340000",
|
||||
"properties": { "id": "340000", "cp": [117.283042, 31.26119], "name": "安徽", "childNum": 3 },
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@^iuLX^"],
|
||||
["@@e©Ehl"],
|
||||
[
|
||||
"@@°ZÆëϵmkǀwÌÕæhºgBĝâqÙĊzÖgņtÀÁĂÆáhEz|WzqD¹°Eŧl{ævÜcA`¤C`|´qxIJkq^³³GšµbíZ
¹qpa±ď OH¦Ħx¢gPícOl_iCveaOjCh߸iÝbÛªCC¿mRV§¢A|t^iĠGÀtÚsd]ĮÐDE¶zAb àiödK¡~H¸íæAǿYj{ď¿À½W®£ChÃsikkly]_teu[bFaTign{]GqªoĈMYá|·¥f¥őaSÕėNµñĞ«Im_m¿Âa]uĜp
Z_§{Cäg¤°r[_YjÆOdý[I[á·¥Q_nùgL¾mvˊBÜÆ¶ĊJhpc¹O]iŠ]¥ jtsggJǧw×jÉ©±EFËKiÛÃÕYv
sm¬njĻª§emná}k«ŕgđ²ÙDÇ¤í¡ªOy×Où±@DñSęćăÕIÕ¿IµĥOjNÕËT¡¿tNæŇàåyķrĕq§ÄĩsWÆßF¶X®¿mw
RIÞfßoG³¾©uyHį{Ɓħ¯AFnuP
ÍÔzVdàôº^Ðæd´oG¤{S¬ćxã}ŧ×Kǥĩ«ÕOEзÖdÖsƘѨ[Û^Xr¢¼§xvÄÆµ`K§ tÒ´Cvlo¸fzŨð¾NY´ı~ÉĔē
ßúLÃÃ_ÈÏ|]ÂÏFlg`ben¾¢pUh~ƴ˶_r sĄ~cƈ]|r c~`¼{À{ȒiJjz`îÀT¥Û³
]u}f
ïQl{skloNdjäËzDvčoQďHI¦rbtHĔ~BmlRV_ħTLnñH±DL¼Lªl§Ťa¸ĚlK²\\RòvDcÎJbt[¤D@®hh~kt°ǾzÖ@¾ªdbYhüóZ ň¶vHrľ\\ÊJuxAT|dmÀO[ÃÔG·ĚąĐlŪÚpSJ¨ĸLvÞcPæķŨ®mÐálwKhïgA¢ųƩޤOÈm°K´"
|
||||
]
|
||||
],
|
||||
"encodeOffsets": [[[121722, 32278]], [[119475, 30423]], [[119168, 35472]]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "350000",
|
||||
"properties": {
|
||||
"id": "350000",
|
||||
"cp": [118.306239, 26.075302],
|
||||
"name": "福建",
|
||||
"childNum": 18
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@zht´]"],
|
||||
["@@aj^~ĆG©O"],
|
||||
["@@ed¨C}}i"],
|
||||
["@@@vPGsQ"],
|
||||
["@@sBzddW]Q"],
|
||||
["@@S¨Q{"],
|
||||
["@@NVucW"],
|
||||
["@@qptBAq"],
|
||||
["@@¸[mu"],
|
||||
["@@Q\\pD]_"],
|
||||
["@@jSwUadpF"],
|
||||
["@@eXª~"],
|
||||
["@@AjvFso"],
|
||||
["@@fT_Çí\\v|ba¦jZÆy°"],
|
||||
["@@IjJi"],
|
||||
["@@wJIx«¼AoNe{M"],
|
||||
["@@K±¡ÓČäeZ"],
|
||||
[
|
||||
"@@k¡¹Eh~c®wBkUplÀ¡I~Māe£bN¨gZý¡a±Öcp©PhI¢Qq
ÇGj|¥U g[Ky¬ŏv@OptÉEF\\@ åA¬V{XģĐBy
cpě
¼³Ăp·¤¥ohqqÚ¡ŅLs^á§qlÀhH¨MCe»åÇGD¥zPO£čÙkJA¼ßėuĕeûÒiÁŧSW¥Qûŗ½ùěcݧSùĩąSWó«íęACµeRåǃRCÒÇZÍ¢ź±^dlstjD¸ZpuÔâÃH¾oLUêÃÔjjēò´ĄWƛ
^Ñ¥Ħ@ÇòmOw¡õyJyD}¢ďÑÈġfZda©º²z£NjD°Ötj¶¬ZSÎ~¾c°¶ÐmxO¸¢Pl´SL|¥AȪĖMņIJg®áIJČĒü` QF¬h|ĂJ@zµ |ê³È ¸UÖŬŬÀEttĸr]ðM¤ĶIJHtÏ AĬkvsq^aÎbvdfÊòSD´Z^xPsĂrvƞŀjJd×ŘÉ ®AΦĤdxĆqAZRÀMźnĊ»İÐZ YXæJyĊ²·¶q§·K@·{sXãô«lŗ¶»o½E¡«¢±¨Y®Ø¶^AvWĶGĒĢPlzfļtàAvWYãO_¤sD§ssČġ[kƤPX¦`¶®BBvĪjv©jx[L¥àï[F
¼ÍË»ğV`«Ip}ccÅĥZEãoP
´B@D¸m±z«Ƴ¿å³BRضWlâþäą`]Z£Tc ĹGµ¶Hm@_©k¾xĨôȉðX«½đCIbćqK³ÁÄš¬OAwã»aLʼnËĥW[ÂGIÂNxij¤D¢îĎÎB§°_JGs¥E@
¤uć
PåcuMuw¢BI¿]zG¹guĮck\\_"
|
||||
]
|
||||
],
|
||||
"encodeOffsets": [
|
||||
[[123250, 27563]],
|
||||
[[122541, 27268]],
|
||||
[[123020, 27189]],
|
||||
[[122916, 27125]],
|
||||
[[122887, 26845]],
|
||||
[[122808, 26762]],
|
||||
[[122568, 25912]],
|
||||
[[122778, 26197]],
|
||||
[[122515, 26757]],
|
||||
[[122816, 26587]],
|
||||
[[123388, 27005]],
|
||||
[[122450, 26243]],
|
||||
[[122578, 25962]],
|
||||
[[121255, 25103]],
|
||||
[[120987, 24903]],
|
||||
[[122339, 25802]],
|
||||
[[121042, 25093]],
|
||||
[[122439, 26024]]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "360000",
|
||||
"properties": {
|
||||
"id": "360000",
|
||||
"cp": [115.592151, 27.676493],
|
||||
"name": "江西",
|
||||
"childNum": 1
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
"@@ĢĨƐgļ¼ÂMD~ņªe^\\^§ý©j×cZبzdÒa¶lÒJìõ`oz÷@¤u޸´ôęöY¼HČƶajlÞƩ¥éZ[|h}^U ¥pĄžƦO lt¸Æ Q\\aÆ|CnÂOjtĚĤdÈF`¶@Ðë ¦ōÒ¨SêvHĢûXD®
QgÄWiØPÞìºr¤džNĠ¢lĄtZoCƞÔºCxrpĠV®Ê{f_Y`_eq®Aot`@oDXfkp¨|s¬\\DÄSfè©Hn¬
^DhÆyøJhØxĢĀLÊƠPżċĄwȠ̦G®ǒĤäTŠÆ~Ħw«|TF¡nc³Ïå¹]ĉđxe{ÎÓvOEm°BƂĨİ|Gvz½ª´HàpeJÝQxnÀWEµàXÅĪt¨ÃĖrÄwÀFÎ|ňÓMå¼ibµ¯»åDT±m[r«_gmQu~¥V\\OkxtL E¢Ú^~ýêPóqoě±_Êw§ÑªåƗā¼mĉŹ¿NQ
YBąrwģcÍ¥BŗÊcØiIƝĿuqtāwO]³YCñTeÉcaubÍ]trluī
BÐGsĵıN£ï^ķqss¿FūūVÕ·´Ç{éĈýÿOER_đûIċâJhŅıNȩĕB
¦K{Tk³¡OP·wnµÏd¯}½TÍ«YiµÕsC¯iM¤¦¯P|ÿUHvhe¥oFTuõ\\OSsMòđƇiaºćXĊĵà·çhƃ÷Ç{ígu^đgm[×zkKN¶Õ»lčÓ{XSÆv©_ÈëJbVkĔVÀ¤P¾ºÈMÖxlò~ªÚàGĂ¢B±ÌKyáV¼Ã~
`gsÙfIƋlę¹e|~udjuTlXµf`¿Jd[\\L²"
|
||||
],
|
||||
"encodeOffsets": [[116689, 26234]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "370000",
|
||||
"properties": {
|
||||
"id": "370000",
|
||||
"cp": [118.000923, 36.275807],
|
||||
"name": "山东",
|
||||
"childNum": 13
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@Xjd]{K"],
|
||||
["@@itbFHy"],
|
||||
["@@HlGk"],
|
||||
["@@TGy"],
|
||||
["@@K¬U"],
|
||||
["@@WdXc"],
|
||||
["@@PtOs"],
|
||||
["@@LnXhc"],
|
||||
["@@ppVu]Or"],
|
||||
["@@cdzAUa"],
|
||||
["@@udRhnCI"],
|
||||
["@@oIpR"],
|
||||
[
|
||||
"@@Ľč{fzƤîKÎMĮ]ZF½Y]â£ph¶¨râøÀÎǨ¤^ºÄGz~grĚĜlĞÆLĆdž¢Îo¦cvKbgr°WhmZp L]LºcUÆnżĤÌĒbAnrOA´ȊcÀbƦUØrĆUÜøĬƞEzVL®öØBkŖÝĐ˹ŧ̄±ÀbÎÉnb²ĦhņBĖįĦåXćì@L¯´ywƕCéõė ƿ¸lµ¾Z|ZWyFY¨Mf~C¿`à_RÇzwƌfQnny´INoƬèôº|sTJULîVjǎ¾ĒØDz²XPn±ŴPè¸ŔLƔÜƺ_TüÃĤBBċÈöA´faM¨{«M`¶d¡ôÖ°mȰBÔjj´PM|c^d¤u¤Û´ä«ƢfPk¶Môl]Lb}su^ke{lC
MrDÇ]NÑFsmoõľHyGă{{çrnÓEƕZGª¹Fj¢ïW
uøCǷë¡ąuhÛ¡^KxC`C\\bÅxì²ĝÝ¿_NīCȽĿåB¥¢·IŖÕy\\¹kxãČ×GDyäÁçFQ¡KtŵƋ]CgÏAùSedcÚźuYfyMmhUWpSyGwMPqŀÁ¼zK¶GY§Ë@´śÇµƕBm@IogZ¯uTMx}CVKï{éƵP_K«pÛÙqċtkkù]gTğwoɁsMõ³ăAN£MRkmEÊčÛbMjÝGu
IZGPģãħE[iµBEuDPÔ~ª¼ęt]ûG§¡QMsğNPŏįzs£Ug{đJĿļā³]ç«Qr~¥CƎÑ^n¶ÆéÎR~ݏYI] PumŝrƿIā[xedzL¯v¯s¬ÁY
~}
ťuŁgƋpÝĄ_ņī¶ÏSR´ÁP~¿Cyċßdwk´SsX|t`Ä ÈðAªìÎT°¦Dda^lĎDĶÚY°`ĪŴǒàŠv\\ebZHŖR¬ŢƱùęOÑM³FÛWp["
|
||||
]
|
||||
],
|
||||
"encodeOffsets": [
|
||||
[[123806, 39303]],
|
||||
[[123821, 39266]],
|
||||
[[123742, 39256]],
|
||||
[[123702, 39203]],
|
||||
[[123649, 39066]],
|
||||
[[123847, 38933]],
|
||||
[[123580, 38839]],
|
||||
[[123894, 37288]],
|
||||
[[123043, 36624]],
|
||||
[[123344, 38676]],
|
||||
[[123522, 38857]],
|
||||
[[123628, 38858]],
|
||||
[[118260, 36742]]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "410000",
|
||||
"properties": {
|
||||
"id": "410000",
|
||||
"cp": [113.665412, 33.757975],
|
||||
"name": "河南",
|
||||
"childNum": 1
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
"@@ýLùµP³swIÓxcŢĞð´E®ÚPtĴXØx¶@«ŕŕQGYfa[şußǩđš_X³ijÕčC]kbc¥CS¯ëÍB©÷³Si_}mYTt³xlàcČzÀD}ÂOQ³ÐTĨ¯ƗòËŖ[hłŦv~}ÂZ«¤lPÇ£ªÝŴÅR§ØnhctâknÏľŹUÓÝdKuķI§oTũÙďkęĆH¸Ó\\Ä¿PcnS{wBIvÉĽ[GqµuŇôYgûZca©@½Õǽys¯}lgg@C\\£asIdÍuCQñ[L±ęk·ţb¨©kK»KC²òGKmĨS`UQnk}AGēsqaJ¥ĐGRĎpCuÌy ã iMcplk|tRkðev~^´¦ÜSí¿_iyjI|ȑ|¿_»d}q^{Ƈdă}tqµ`Ƴĕg}V¡om½faÇo³TTj¥tĠRyK{ùÓjuµ{t}uËRivGçJFjµÍyqÎàQÂFewixGw½Yŷpµú³XU½ġyłåkÚwZX·l¢Á¢KzOÎÎjc¼htoDHr
|J½}JZ_¯iPq{tę½ĕ¦Zpĵø«kQ
Ť]MÛfaQpě±ǽ¾]uFu÷nčįADp}AjmcEÇaª³o³ÆÍSƇĈÙDIzËčľ^KLiÞñ[aA²zzÌ÷D|[íijgfÕÞd®|`Ć~oĠƑô³ŊD×°¯CsøÀ«ìUMhTº¨¸ǡîSÔDruÂÇZÖEvPZW~ØÐtĄE¢¦Ðy¸bô´oŬ¬²Ês~]®tªapŎJ¨Öº_Ŕ`Ŗ^Đ\\Ĝu~m²Ƹ¸fWĦrƔ}Î^gjdfÔ¡J}\\n C¦þWxªJRÔŠu¬ĨĨmFdM{\\d\\YÊ¢ú@@¦ª²SÜsC}fNècbpRmlØ^gd¢aÒ¢CZZxvƶN¿¢T@uC¬^ĊðÄn|lGlRjsp¢ED}Fio~ÔN~zkĘHVsDzßjŬŢ`Pûàl¢\\ÀEhİgÞē X¼Pk|m"
|
||||
],
|
||||
"encodeOffsets": [[118256, 37017]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "420000",
|
||||
"properties": {
|
||||
"id": "420000",
|
||||
"cp": [113.298572, 30.684355],
|
||||
"name": "湖北",
|
||||
"childNum": 3
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@AB"],
|
||||
["@@lskt"],
|
||||
[
|
||||
"@@¾«}{ra®pîÃ\\{øCËyyB±b\\òÝjKL ]ĎĽÌJyÚCƈćÎT´Å´pb©ÈdFin~BCo°BĎÃømv®E^vǾ½Ĝ²RobÜeN^ĺ£R¬lĶ÷YoĖ¥Ě¾|sOr°jY`~I¾®I{GqpCgyl{£ÍÍyPL¡¡¸kWxYlÙæŁĢz¾V´W¶ùŸo¾ZHxjwfxGNÁ³Xéæl¶EièIH ujÌQ~v|sv¶Ôi|ú¢FhQsğ¦SiŠBgÐE^ÁÐ{čnOÂÈUÎóĔÊēIJ}Z³½Mŧïeyp·uk³DsѨL¶_Åuèw»¡WqÜ]\\Ò§tƗcÕ¸ÕFÏǝĉăxŻČƟOKÉġÿ×wg÷IÅzCg]m«ªGeçÃTC«[t§{loWeC@ps_Bprf_``Z|ei¡oċMqow¹DƝÓDYpûsYkıǃ}s¥ç³[§cY§HK«Qy]¢wwö¸ïx¼ņ¾Xv®ÇÀµRĠÐHM±cÏdƒǍũȅȷ±DSyúĝ£ŤĀàtÖÿï[îb\\}pĭÉI±Ñy
¿³x¯No|¹HÏÛmjúË~TuęjCöAwě¬Rđl¯ ÑbŇTĿ_[IčĄʿnM¦ğ\\É[T·k¹©oĕ@A¾wya¥Y\\¥Âaz¯ãÁ¡k¥ne£ÛwE©Êō¶˓uoj_U¡cF¹[WvP©whuÕyBF`RqJUw\\i¡{jEPïÿ½fć
QÑÀQ{°fLÔ~wXgītêݾĺHd³fJd]HJ²
EoU¥HhwQsƐ»Xmg±çve]DmÍPoCc¾_hhøYrŊU¶eD°Č_N~øĹĚ·`z]Äþp¼
äÌQv\\rCé¾TnkžŐÚÜa¼ÝƆ̶Ûo
d
ĔňТJqPb ¾|J¾fXƐîĨ_Z¯À}úƲN_ĒÄ^ĈaŐyp»CÇÄKñL³ġM²wrIÒŭxjb[n«øæà ^²h¯ÚŐªÞ¸Y²ĒVø}Ā^İ´LÚm¥ÀJÞ{JVųÞŃx×sxxƈē ģMřÚðòIfĊŒ\\Ʈ±ŒdʧĘDvČ_Àæ~Dċ´A®µ¨ØLV¦êHÒ¤"
|
||||
]
|
||||
],
|
||||
"encodeOffsets": [[[113712, 34000]], [[115612, 30507]], [[113649, 34054]]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "430000",
|
||||
"properties": { "id": "430000", "cp": [111.782279, 28.09409], "name": "湖南", "childNum": 3 },
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@nFTs"],
|
||||
["@@ßÅÆá½ÔXrCO
ËRïÿĩTooQyÓ[ŅBE¬ÎÓXaį§Ã¸G °ITxpúxÚij¥Ï̾edÄ©ĸG
àGhM¤Â_U}Ċ}¢pczfþg¤ÇòAVM"],
|
||||
[
|
||||
"@@©KA·³CQ±Á«³BUƑ¹AtćOwD]JiØSm¯b£ylX
HËѱH«C^õľAŧ¤É¥ïyuǙuA¢^{ÌC´¦ŷJ£^[ª¿ĕ~Ƈ
N
skóā¹¿ï]ă~÷O§@Vm¡Qđ¦¢Ĥ{ºjÔª¥nf´~Õo×ÛąMąıuZmZcÒ IJβSÊDŽŶ¨ƚCÖŎªQؼrŭ«}NÏürʬmjr@ĘrTW SsdHzƓ^ÇÂyUi¯DÅYlŹu{hT}mĉ¹¥ěDÿë©ıÓ[Oº£¥ótł¹MÕƪ`P
DiÛU¾ÅâìUñBÈ£ýhedy¡oċ`pfmjP~kZa
ZsÐd°wj§@Ĵ®w~^kÀÅKvNmX\\¨aŃqvíó¿F¤¡@ũÑVw}S@j}¾«pĂrªg àÀ²NJ¶¶Dô
K|^ª°LX¾ŴäPα£EXd^¶IJÞÜ~u¸ǔMRhsR
e`ÄofIÔ\\Ø ićymnú¨cj ¢»GČìƊÿШXeĈ¾Oð Fi ¢|[jVxrIQ_EzAN¦zLU`cªxOTu RLÄ¢dVi`p˔vŎµªÉF~Ød¢ºgİàw¸Áb[¦Zb¦z½xBĖ@ªpºlS¸Ö\\Ĕ[N¥ˀmĎăJ\\ŀ`
ňSÚĖÁĐiOĜ«BxDõĚivSÌ}iùÜnкG{p°M´wÀÒzJ²ò¨ oTçüöoÛÿñőФùTz²CȆȸǎŪƑÐc°dPÎğ˶[Ƚu¯½WM¡ÉB·rínZÒ `¨GA¾\\pēXhÃRCüWGġu
Té§ŎÑ©ò³I±³}_EÃħg®ęisÁPDmÅ{b[RÅs·kPŽƥóRoOV~]{g\\êYƪ¦kÝbiċƵGZ»Ěõ
ó·³vŝ£ø@pyö_ëIkѵbcѧy
×dYتiþ¨[]f]Ņ©C}ÁN»hĻħƏĩ"
|
||||
]
|
||||
],
|
||||
"encodeOffsets": [[[115640, 30489]], [[112543, 27312]], [[116690, 26230]]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "440000",
|
||||
"properties": {
|
||||
"id": "440000",
|
||||
"cp": [113.280637, 23.125178],
|
||||
"name": "广东",
|
||||
"childNum": 24
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@QdAua"],
|
||||
["@@lxDLo"],
|
||||
["@@sbhNLo"],
|
||||
["@@Ă ā"],
|
||||
["@@WltO[["],
|
||||
["@@Kr]S"],
|
||||
["@@eI]y"],
|
||||
["@@I|Mym"],
|
||||
["@@Û³LS¼Y"],
|
||||
["@@nvºBëui©`¾"],
|
||||
["@@zdÛJw®"],
|
||||
["@@°
¯"],
|
||||
["@@a yAª¸ËJIxØ@ĀHAmÃV¡ofuo"],
|
||||
["@@sŗÃÔėAƁZÄ ~°ČPäh"],
|
||||
["@@¶ÝÌvmĞhıQ"],
|
||||
["@@HdSjǢD}war
u«ZqadYM"],
|
||||
["@@el\\LqqU"],
|
||||
["@@~rMo\\"],
|
||||
["@@f^C"],
|
||||
["@@øPªoj÷ÍÝħXČx°Q¨ıXNv"],
|
||||
["@@gÇƳo[~tly"],
|
||||
["@@EÆC¿"],
|
||||
["@@OP"],
|
||||
[
|
||||
"@@wđógĝ[³¡VÙæÅöM̳¹pÁaËýý©D©ÜJŹƕģGą¤{Ùū
ÇO²«BƱéAÒĥ¡«BhlmtÃPµyU¯ucd·w_bŝcīímGO|KPȏŹãŝIŕŭŕ@Óoo¿ē±ß}
ŭIJWÈCőâUâǙIğʼn©IijE×
Á³AówXJþ±ÌÜÓĨ£L]ĈÙƺZǾĆĖMĸĤfÎĵlŨnÈĐtFFĤêk¶^k°f¶g}®Faf`vXŲxl¦ÔÁ²¬Ð¦pqÊ̲iXØRDÎ}Ä@ZĠsx®AR~®ETtĄZƈfŠŠHâÒÐAµ\\S¸^wĖkRzalŜ|E¨ÈNĀňZTpBh£\\ĎƀuXĖtKL¶G|»ĺEļĞ~ÜĢÛĊrOÙîvd]n¬VÊĜ°RÖpMƂªFbwEÀ©\\
¤]ŸI®¥D³|Ë]CöAŤ¦
æ´¥¸Lv¼¢ĽBaôF~®²GÌÒEYzk¤°ahlVÕI^CxĈPsBƒºV¸@¾ªR²ĨN]´_eavSivc}p}Đ¼ƌkJÚe th_¸ ºx±ò_xN˲@ă¡ßH©Ùñ}wkNÕ¹ÇO½¿£ĕ]ly_WìIǪ`uTÅxYĒÖ¼kÖµMjJÚwn\\hĒv]îh|ÈƄøèg¸Ķß ĉĈWb¹ƀdéĘNTtP[öSvrCZaGubo´ŖÒÇĐ~¡zCI
özx¢PnÈñ @ĥÒ¦]ƞV}³ăĔñiiÄÓVépKG½ÄÓávYoC·sitiaÀyŧΡÈYDÑům}ý|m[węõĉZÅxUO}÷N¹³ĉo_qtăqwµŁYÙǝŕ¹tïÛUïmRCº
ĭ|µÕÊK½Rē ó]GªęAx»HO£|ām¡diď×YïYWªʼnOeÚtĐ«zđ¹T
āúEá²\\ķÍ}jYàÙÆſ¿Çdğ·ùTßÇţʄ¡XgWÀLJğ·¿ÃOj YÇ÷Qěi"
|
||||
]
|
||||
],
|
||||
"encodeOffsets": [
|
||||
[[117381, 22988]],
|
||||
[[116552, 22934]],
|
||||
[[116790, 22617]],
|
||||
[[116973, 22545]],
|
||||
[[116444, 22536]],
|
||||
[[116931, 22515]],
|
||||
[[116496, 22490]],
|
||||
[[116453, 22449]],
|
||||
[[113301, 21439]],
|
||||
[[118726, 21604]],
|
||||
[[118709, 21486]],
|
||||
[[113210, 20816]],
|
||||
[[115482, 22082]],
|
||||
[[113171, 21585]],
|
||||
[[113199, 21590]],
|
||||
[[115232, 22102]],
|
||||
[[115739, 22373]],
|
||||
[[115134, 22184]],
|
||||
[[113056, 21175]],
|
||||
[[119573, 21271]],
|
||||
[[119957, 24020]],
|
||||
[[115859, 22356]],
|
||||
[[116561, 22649]],
|
||||
[[116285, 22746]]
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "450000",
|
||||
"properties": { "id": "450000", "cp": [108.320004, 22.82402], "name": "广西", "childNum": 2 },
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@H TQ§A"],
|
||||
[
|
||||
"@@ĨʪLƊDÎĹĐCǦė¸zÚGn£¾rªŀÜt¬@ÖÚSx~øOŒŶÐÂæȠ\\ÈÜObĖw^oÞLf¬°bI lTØBÌF£Ć¹gñĤaYt¿¤VSñK¸¤nM¼JE±½¸ñoÜCƆæĪ^ĚQÖ¦^f´QüÜÊz¯lzUĺš@ìp¶n]sxtx¶@~ÒĂJb©gk{°~c°`Ô¬rV\\la¼¤ôá`¯¹LCÆbxEræOv[H[~|aB£ÖsºdAĐzNÂðsÞÆ
Ĥªbab`ho¡³F«èVlo¤ÔRzpp®SĪº¨ÖºN
ijd`a¦¤F³ºDÎńĀìCĜº¦Ċ~nS|gźvZkCÆj°zVÈÁƔ]LÊFZg
čPkini«qÇczÍY®¬Ů»qR×ō©DÕ§ƙǃŵTÉĩ±ıdÑnYYIJvNĆĆØÜ Öp}e³¦m©iÓ|¹ħņ|ª¦QF¢Â¬ʖovg¿em^ucà÷gÕuíÙćĝ}FϼĹ{µHKsLSđƃrč¤[AgoSŇYMÿ§Ç{FśbkylQxĕ]T·¶[B
ÑÏGáşşƇe
ăYSsFQ}BwtYğÃ@~
CÍQ ×Wj˱rÉ¥oÏ ±«ÓÂ¥kwWűmcih³K~µh¯e]lµélEģEďsmÇŧē`ãògK_ÛsUʝćğ¶höO¤Ǜn³c`¡y¦CezYwa[ďĵűMę§]XÎ_íÛ]éÛUćİÕBƣ±
dy¹T^dûÅÑŦ·PĻþÙ`K¦
¢ÍeĥR¿³£[~äu¼dltW¸oRM¢ď\\z}Æzdvň{ÎXF¶°Â_ÒÂÏL©ÖTmu¼ãlīkiqéfA·Êµ\\őDc¥ÝFyÔćcűH_hLÜêĺШc}rn`½Ì@¸¶ªVLhŒ\\Ţĺk~Ġið°|gtTĭĸ^xvKVGréAébUuMJVÃO¡
qĂXËSģãlýà_juYÛÒBG^éÖ¶§EGÅzěƯ¤EkN[kdåucé¬dnYpAyČ{`]þ¯TbÜÈk¡ĠvàhÂƄ¢Jî¶²"
|
||||
]
|
||||
],
|
||||
"encodeOffsets": [[[111707, 21520]], [[107619, 25527]]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "460000",
|
||||
"properties": { "id": "460000", "cp": [109.83119, 19.031971], "name": "海南", "childNum": 1 },
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": ["@@¦Ŝil¢XƦƞòïè§ŞCêɕrŧůÇąĻõ·ĉ³œ̅kÇm@ċȧŧĥĽʉƅſȓÒ˦ŝE}ºƑ[ÍĜȋ gÎfǐÏĤ¨êƺ\\Ɔ¸ĠĎvʄȀоjNðĀÒRZdžzÐŘΰH¨Ƣb²_Ġ "],
|
||||
"encodeOffsets": [[112750, 20508]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "510000",
|
||||
"properties": {
|
||||
"id": "510000",
|
||||
"cp": [104.065735, 30.659462],
|
||||
"name": "四川",
|
||||
"childNum": 2
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@LqKr"],
|
||||
[
|
||||
"@@[ĻéV£_ţġñpG réÏ·~ąSfy×Í·ºſƽiÍıƣıĻmHH}siaX@iǰÁÃ×t«T¤JJJyJÈ`Ohߦ¡uËhIyCjmÿw
ZG
TiSsOB²fNmsPa{M{õE^Hj}gYpaeu¯oáwHjÁ½M¡pMuåmni{fk\\oÎqCwEZ¼KĝAy{m÷LwO×SimRI¯rKõBS«sFe]fµ¢óY_ÆPRcue°Cbo×bd£ŌIHgtrnyPt¦foaXďxlBowz_{ÊéWiêEGhܸºuFĈIxf®Y½ĀǙ]¤EyF²ċw¸¿@g¢§RGv»áW`ÃĵJwi]t¥wO½a[×]`ÃiüL¦LabbTÀåc}ÍhÆh®BHî|îºÉk¤Sy£ia©taį·Ɖ`ō¥UhO
ĝLk}©Fos´JmµlŁu
ønÑJWΪYÀïAetTŅÓGË«bo{ıwodƟ½OġܵxàNÖ¾P²§HKv¾]|BÆåoZ`¡Ø`ÀmºĠ~ÌЧnÇ
¿¤]wğ@srğu~Io[é±¹ ¿ſđÓ@qg¹zƱřaí°KtǤV»Ã[ĩǭƑ^ÇÓ@áťsZÏÅĭƋěpwDóÖáŻneQËq·GCœýS]x·ýq³OÕ¶Qzßti{řáÍÇWŝŭñzÇWpç¿JXĩè½cFÂLiVjx}\\NŇĖ¥GeJA¼ÄHfÈu~¸Æ«dE³ÉMA|bÒ
ćhG¬CMõƤąAvüVéŀ_V̳ĐwQj´·ZeÈÁ¨X´Æ¡Qu·»ÕZ³ġqDoy`L¬gdp°şp¦ėìÅĮZ°Iähzĵf²å ĚÑKpIN|Ñz]ń
·FU×é»R³MÉ»GM«kiér}Ã`¹ăÞmÈnÁîRǀ³ĜoİzŔwǶVÚ£À]ɜ»ĆlƂ²Ġ
þTº·àUȞÏʦ¶I«dĽĢdĬ¿»Ĕ×h\\c¬ä²GêëĤł¥ÀǿżÃÆMº}BÕĢyFVvwxBèĻĒ©ĈtCĢɽŠȣ¦āæ·HĽîôNÔ~^¤Ɗu^s¼{TA¼ø°¢İªDè¾Ň¶ÝJ®Z´ğ~Sn|ªWÚ©òzPOȸbð¢|øĞŒQìÛÐ@ĞǎRS¤Á§d
i´ezÝúØã]HqkIþËQǦÃsǤ[E¬ÉŪÍxXƒ·ÖƁİlƞ¹ª¹|XÊwnÆƄmÀêErĒtD®ċæcQE®³^ĭ¥©l}äQtoŖÜqÆkµªÔĻĴ¡@Ċ°B²Èw^^RsºT£ڿQPJvÄz^Đ¹Æ¯fLà´GC²dtĀRt¼¤ĦOðğfÔðDŨŁĞƘïPÈ®âbMüÀXZ ¸£@Å»»QÉ]dsÖ×_Í_ÌêŮPrĔĐÕGĂeZÜîĘqBhtO ¤tE[h|YÔZśÎs´xº±Uñt|OĩĠºNbgþJy^dÂY Į]Řz¦gC³R`Āz¢Aj¸CL¤RÆ»@Ŏk\\Ç´£YW}z@Z}öoû¶]´^NÒ}èNªPÍy¹`S°´ATeVamdUĐwʄvĮÕ\\uÆŗ¨Yp¹àZÂmWh{á}WØǍÉüwga§áCNęÎ[ĀÕĪgÖɪXøx¬½Ů¦¦[NÎLÜUÖ´òrÙŠxR^JkijnDX{U~ET{ļº¦PZcjF²Ė@pg¨B{u¨ŦyhoÚD®¯¢ WòàFΤ¨GDäz¦kŮPġqË¥À]eâÚ´ªKxīPÖ|æ[xäJÞĥsNÖ½I¬nĨY´®ÐƐmDŝuäđđEb
ee_v¡}ìęNJē}qÉåT¯µRs¡M@}ůaa¯wvƉåZw\\Z{åû^"
|
||||
]
|
||||
],
|
||||
"encodeOffsets": [[[108815, 30935]], [[110617, 31811]]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "520000",
|
||||
"properties": {
|
||||
"id": "520000",
|
||||
"cp": [106.713478, 26.578343],
|
||||
"name": "贵州",
|
||||
"childNum": 3
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@G\\lY£in"],
|
||||
["@@q|mc¯tÏVSÎ"],
|
||||
[
|
||||
"@@hÑ£IsNgßHHªķÃh_¹¡ĝħń¦uÙùgS¯JH|sÝÅtÁïyMDč»eÕtA¤{b\\}G®u\\åPFqwÅaD
K°ºâ_£ùbµmÁÛĹM[q|hlaªāI}ѵ@swtwm^oµD鼊yVky°ÉûÛR
³e¥]RÕěħ[ƅåÛDpJiVÂF²I
»mN·£LbÒYbWsÀbpkiTZĄă¶Hq`
ĥ_J¯ae«KpÝx]aĕÛPÇȟ[ÁåŵÏő÷Pw}TÙ@Õs«ĿÛq©½m¤ÙH·yǥĘĉBµĨÕnđ]K©œáGçş§ÕßgǗĦTèƤƺ{¶ÉHÎd¾ŚÊ·OÐjXWrãLyzÉAL¾ę¢bĶėy_qMĔąro¼hĊw¶øV¤w²Ĉ]ÊKx|`ź¦ÂÈdrcÈbe¸`I¼čTF´¼Óýȃr¹ÍJ©k_șl³´_pĐ`oÒh¶pa^ÓĔ}D»^Xy`d[Kv
JPhèhCrĂĚÂ^Êƌ wZLĠ£ÁbrzOIlMMĪŐžËr×ÎeŦtw|¢mKjSǘňĂStÎŦEtqFT¾E쬬ôxÌO¢ K³ŀºäYPVgŎ¦Ŋm޼VZwVlz¤
£Tl®ctĽÚó{GAÇge~Îd¿æaSba¥KKûj®_Ä^\\ؾbP®¦x^sxjĶI_Ä Xâ¼Hu¨Qh¡À@Ëô}±GNìĎlT¸
`V~R°tbÕĊ`¸úÛtÏFDu[MfqGH·¥yAztMFe|R_GkChZeÚ°tov`xbDnÐ{E}ZèxNEÞREn[Pv@{~rĆAB§EO¿|UZ~ìUf¨J²ĂÝÆsªB`s¶fvö¦Õ~dÔq¨¸º»uù[[§´sb¤¢zþF¢Æ
ÀhÂW\\ıËIÝo±ĭŠ£þÊs}¡R]ěDg´VG¢j±®èºÃmpU[Á뺰rÜbNu¸}º¼`niºÔXĄ¤¼ÔdaµÁ_Ã
ftQQgR·Ǔv}Ý×ĵ]µWc¤F²OĩųãW½¯K©
]{LóµCIµ±Mß¿h©āq¬o½~@i~TUxŪÒ¢@£ÀEîôruńb[§nWuMÆLl¿]x}ij½"
|
||||
]
|
||||
],
|
||||
"encodeOffsets": [[[112158, 27383]], [[112105, 27474]], [[112095, 27476]]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "530000",
|
||||
"properties": {
|
||||
"id": "530000",
|
||||
"cp": [101.512251, 24.740609],
|
||||
"name": "云南",
|
||||
"childNum": 1
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
"@@[ùx½}ÑRHYīĺûsÍniEoã½Ya²ė{c¬ĝgĂsAØÅwďõzFjw}«Dx¿}Uũlê@HÅF¨ÇoJ´Ónũuą¡Ã¢pÒÅØ TF²xa²ËXcÊlHîAßËŁkŻƑŷÉ©hWæßUËs¡¦}teèÆ¶StÇÇ}Fd£jĈZĆÆ¤Tč\\D}O÷£U§~ŃGåŃDĝ¸Tsd¶¶Bª¤u¢ŌĎo~t¾ÍŶÒtD¦ÚiôözØX²ghįh½Û±¯ÿm·zR¦Ɵ`ªŊÃh¢rOÔ´£Ym¼èêf¯ŪĽncÚbw\\zlvWªâ ¦gmĿBĹ£¢ƹřbĥkǫßeeZkÙIKueT»sVesbaĕ ¶®dNĄÄpªy¼³BE®lGŭCǶwêżĔÂepÍÀQƞpC¼ŲÈAÎô¶RäQ^Øu¬°_Èôc´¹ò¨P΢hlϦ´ĦÆ´sâÇŲPnÊD^¯°Upv}®BP̪jǬxSöwlfòªvqĸ|`HviļndĜĆhňem·FyÞqóSᝳX_ĞçêtryvL¤§z¦c¦¥jnŞklD¤øz½ĜàĂŧMÅ|áƆàÊcðÂFÜáŢ¥\\\\ºİøÒÐJĴîD¦zK²ǏÎEh~CDhMn^ÌöÄ©ČZÀaüfɭyœpį´ěFűk]Ôě¢qlÅĆÙa¶~ÄqêljN¬¼HÊNQ´ê¼VظE^ŃÒyM{JLoÒęæe±Ķygã¯JYÆĭĘëo¥Šo¯hcK«z_prC´ĢÖY¼ v¸¢RÅW³Â§fǸYi³xR´ďUË`êĿUûuĆBƣöNDH«ĈgÑaB{ÊNF´¬c·Åv}eÇÃGB»If¦HňĕM
~[iwjUÁKE¾dĪçWIèÀoÈXòyŞŮÈXâÎŚj|àsRyµÖPr´þ ¸^wþTDŔHr¸RÌmfżÕâCôoxĜƌÆĮÐYtâŦÔ@]ÈǮƒ\\μģUsȯLbîƲŚºyhr@ĒÔƀÀ²º\\êpJ}ĠvqtĠ@^xÀ£È¨mËÏğ}n¹_¿¢×Y_æpÅA^{½Lu¨GO±Õ½ßM¶wÁĢÛPƢ¼pcIJx|ap̬HÐŊSfsðBZ¿©XÏÒKk÷Eû¿S
rEFsÕūkóVǥʼniTL¡n{uxţÏhôŝ¬ğōNNJkyPaqÂğ¤K®YxÉƋÁ]āęDqçgOgILu\\_gz]W¼~CÔē]bµogpÑ_oď`´³Țkl`IªºÎȄqÔþ»E³ĎSJ»_f·adÇqÇc¥Á_Źw{L^ɱćxU£µ÷xgĉp»ĆqNē`rĘzaĵĚ¡K½ÊBzyäKXqiWPÏɸ½řÍcÊG|µƕƣGË÷k°_^ý|_zċBZocmø¯hhcæ\\lMFlư£ĜÆyHF¨µêÕ]HA
àÓ^it `þßäkĤÎT~Wlÿ¨ÔPzUCNVv [jâôDôď[}z¿msSh¯{jïğl}šĹ[őgK©U·µË@¾m_~q¡f¹
ÅË^»f³ø}Q¡Ö˳gͱ^Ç
\\ëÃA_¿bWÏ[¶ƛé£F{īZgm@|kHǭƁć¦UĔť×ë}ǝeďºȡȘÏíBÉ£āĘPªij¶ʼnÿy©nď£G¹¡I±LÉĺÑdĉÜW¥}gÁ{aqÃ¥aıęÏZï`"
|
||||
],
|
||||
"encodeOffsets": [[104636, 22969]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "540000",
|
||||
"properties": { "id": "540000", "cp": [89.132212, 30.860361], "name": "西藏", "childNum": 1 },
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
"@@ÂhľxŖxÒVºÅâAĪÝȆµę¯Ňa±r_w~uSÕňqOj]ɄQ
£Z
UDûoY»©M[L¼qãË{VÍçWVi]ë©Ä÷àyƛhÚU°adcQ~Mx¥cc¡ÙaSyFÖkuRýq¿ÔµQĽ³aG{¿FµëªéĜÿª@¬·K·àariĕĀ«V»ŶĴūgèLǴŇƶaftèBŚ£^âǐÝ®M¦ÁǞÿ¬LhJ¾óƾƺcxwf]Y
´¦|QLn°adĊ
\\¨oǀÍŎ´ĩĀd`tÊQŞŕ|¨C^©Ĉ¦¦ÎJĊ{ëĎjª²rÐl`¼Ą[t|¦Stè¾PÜK¸dƄı]s¤î_v¹ÎVòŦj£Əsc¬_Ğ´|٦Av¦w`ăaÝaa¢e¤ı²©ªSªÈMĄwÉØŔì@T¤Ę\\õª@þo´xA sÂtŎKzó´ÇĊµ¢r^nĊƬ×üG¢³ {âĊ]G~bÀgVjzlhǶfOfdªB]pjTOtĊn¤}®¦Č¥d¢¼»ddY¼t¢eȤJ¤}Ǿ¡°§¤AÐlc@ĝsªćļđAçwxUuzEÖġ~AN¹ÄÅȀݦ¿ģŁéì±H
ãd«g[ؼēÀcīľġ¬cJµ
ÐʥVȝ¸ßS¹ý±ğkƁ¼ą^ɛ¤Ûÿb[}¬ōõÃ]ËNm®g@Bg}ÍF±ǐyL¥íCIijÏ÷Ñį[¹¦[âšEÛïÁÉdƅß{âNÆāŨß¾ě÷yC£k´ÓH@¹TZ¥¢į·ÌAЧ®Zc
v½Z¹|ÅWZqgW|ieZÅYVÓqdqbc²R@c¥Rã»GeeƃīQ}J[ÒK
¬Ə|oėjġĠÑN¡ð¯EBčnwôɍėª²CλŹġǝʅįĭạ̃ūȹ]ΓͧgšsgȽóϧµǛęgſ¶ҍć`ĘąŌJÞä¤rÅň¥ÖÁUětęuůÞiĊÄÀ\\Æs¦ÓRb|Â^řÌkÄŷ¶½÷f±iMÝ@ĥ°G¬ÃM¥n£Øąğ¯ß§aëbéüÑOčk£{\\eµª×MÉfm«Ƒ{Å×Gŏǩãy³©WÑăû··Qòı}¯ãIéÕÂZ¨īès¶ZÈsæĔTŘvgÌsN@îá¾ó@ÙwU±ÉT廣TđWxq¹Zobs[ׯcĩvėŧ³BM|¹kªħ¥TzNYnÝßpęrñĠĉRS~½ěVVµõ«M££µBĉ¥áºae~³AuĐh`ܳç@BÛïĿa©|z²Ý¼D£àč²ŸIûI āóK¥}rÝ_Á´éMaň¨~ªSĈ½½KÙóĿeƃÆB·¬ën×W|Uº}LJrƳlŒµ`bÔ`QÐÓ@s¬ñIÍ@ûws¡åQÑßÁ`ŋĴ{ĪTÚÅTSijYo|Ç[ǾµMW¢ĭiÕØ¿@Mh
pÕ]jéò¿OƇĆƇpêĉâlØwěsǩĵ¸c
bU¹ř¨WavquSMzeo_^gsÏ·¥Ó@~¯¿RiīB\\qTGªÇĜçPoÿfñòą¦óQīÈáPābß{ZŗĸIæÅhnszÁCËìñÏ·ąĚÝUm®óL·ăUÈíoù´Êj°ŁŤ_uµ^°ìÇ@tĶĒ¡ÆM³Ģ«İĨÅ®ğRāðggheÆ¢zÊ©Ô\\°ÝĎz~ź¤PnMĪÖB£kné§żćĆKǰ¼L¶èâz¨u¦¥LDĘz¬ýÎmĘd¾ßFzhg²Fy¦ĝ¤ċņbÎ@yĄæm°NĮZRÖíJ²öLĸÒ¨Y®ƌÐVàtt_ÚÂyĠz]ŢhzĎ{ÂĢXc|ÐqfO¢¤ögÌHNPKŖUú´xx[xvĐCûĀìÖT¬¸^}Ìsòd´_KgžLĴ
ÀBon|H@Êx¦BpŰŌ¿fµƌA¾zLjRx¶FkĄźRzŀ~¶[´HnªVƞuĒȨƎcƽÌm¸ÁÈM¦x͊ëÀxdžBú^´W£dkɾĬpw˂ØɦļĬIŚÊnŔa¸~J°îlɌxĤÊÈðhÌ®gT´øàCÀ^ªerrƘd¢İP|Ė ŸWªĦ^¶´ÂLaT±üWƜǀRÂŶUńĖ[QhlLüAÜ\\qRĄ©"
|
||||
],
|
||||
"encodeOffsets": [[90849, 37210]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "610000",
|
||||
"properties": {
|
||||
"id": "610000",
|
||||
"cp": [108.948024, 34.263161],
|
||||
"name": "陕西",
|
||||
"childNum": 1
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
"@@p¢ȮµûGĦ}Ħðǚ¶òƄjɂz°{ºØkÈęâ¦jªBg\\ċ°s¬]jú EȌdž¬stRÆdĠİwܸôW¾ƮłÒ_{Ìû¼jº¹¢GǪÒ¯ĘZ`ºŊecņą~BÂgzpâēòYǠȰÌTΨÂW|fcă§uF@N¢XLRMº[ğȣſï|¥Jkc`sʼnǷY¹W@µ÷K
ãï³ÛIcñ·VȋÚÒķø©þ¥yÓğęmWµÎumZyOŅƟĥÓ~sÑL¤µaÅ
Y¦ocyZ{y c]{Ta©`U_Ěē£ωÊƍKùK¶ȱÝƷ§{û»ÅÁȹÍéuij|¹cÑdìUYOuFÕÈYvÁCqÓTǢí§·S¹NgV¬ë÷Át°DدC´ʼnƒópģ}ċcEË
FéGU¥×K
§¶³BČ}C¿åċ`wġB·¤őcƭ²ő[Å^axwQO
ÿEËߌĤNĔwƇÄńwĪo[_KÓª³ÙnKÇěÿ]ďă_d©·©Ýŏ°Ù®g]±ßå¬÷m\\iaǑkěX{¢|ZKlçhLtŇîŵœè[É@ƉĄEtƇϳħZ«mJ
×¾MtÝĦ£IwÄå\\Õ{OwĬ©LÙ³ÙgBƕŀrÌĢŭO¥lãyC§HÍ£ßEñX¡°ÙCgpťzb`wIvA|§hoĕ@E±iYd¥OϹS|}F@¾oAO²{tfÜ¢FǂÒW²°BĤh^Wx{@¬F¸¡ķn£P|ªĴ@^ĠĈæbÔc¶lYi
^MicϰÂ[ävï¶gv@ÀĬ·lJ¸sn|¼u~a]ÆÈtŌºJpþ£KKf~¦UbyäIĺãnÔ¿^ŵMThĠܤko¼Ŏìąǜh`[tRd²IJ_XPrɲlXiL§à¹H°Ȧqº®QCbAŌJ¸ĕÚ³ĺ§ `d¨YjiZvRĺ±öVKkjGȊÄePĞZmļKÀ[`ösìhïÎoĬdtKÞ{¬èÒÒBÔpIJÇĬJŊ¦±J«Y§@·pHµàåVKepWftsAÅqC·¬ko«pHÆuK@oHĆÛķhxenS³àǍrqƶRbzy¸ËÐl¼EºpĤ¼x¼½~Ğà@ÚüdK^mÌSj"
|
||||
],
|
||||
"encodeOffsets": [[110234, 38774]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "620000",
|
||||
"properties": {
|
||||
"id": "620000",
|
||||
"cp": [103.823557, 36.058039],
|
||||
"name": "甘肃",
|
||||
"childNum": 2
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@VuUv"],
|
||||
[
|
||||
"@@ũEĠtt~nkh`Q¦ÅÄÜdwAb×ĠąJ¤DüègĺqBqj°lI¡ĨÒ¤úSHbjÎB°aZ¢KJO[|A£Dx}NìHUnrk kp¼Y kMJn[aGáÚÏ[½rc}aQxOgsPMnUsncZ
sKúvAtÞġ£®ĀYKdnFw¢JE°Latf`¼h¬we|Æbj}GA·~W`¢MC¤tL©IJ°qdfObÞĬ¹ttu`^ZúE`[@Æsîz®¡CƳƜG²R¢RmfwĸgÜą G@pzJM½mhVy¸uÈÔO±¨{LfæU¶ßGĂq\\ª¬²I¥IʼnÈīoıÓÑAçÑ|«LÝcspīðÍg
të_õ\\ĉñLYnĝgRǡÁiHLlõUĹ²uQjYi§Z_c¨´ĹĖÙ·ŋI
aBDR¹ȥr¯GºßK¨jWkɱOqWij\\aQ\\sg_ĆǛōëp»£lğÛgSŶN®À]ÓämĹãJaz¥V}Le¤Lýo¹IsŋÅÇ^bz
³tmEÁ´a¹cčecÇNĊãÁ\\č¯dNj]jZµkÓdaćå]ğij@ ©O{¤ĸm¢E·®«|@Xwg]A챝XǁÑdzªcwQÚŝñsÕ³ÛV_ý¥\\ů¥©¾÷w©WÕÊĩhÿÖÁRo¸V¬âDb¨hûxÊ×nj~Zâg|XÁnßYoº§ZÅŘv[ĭÖʃuďxcVbnUSf
B¯³_TzºÎO©çMÑ~M³]µ^püµÄY~y@X~¤Z³[Èōl@®Å¼£QK·Di¡ByÿQ_´D¥hŗy^ĭÁZ]cIzýah¹MĪğPs{ò²Vw¹t³ŜË[Ñ}X\\gsF£sPAgěp×ëfYHāďÖqēŭOÏëdLü\\it^c®Rʺ¶¢H°mrY£B¹čIoľu¶uI]vģSQ{UŻÅ}QÂ|̰ƅ¤ĩŪU ęĄÌZÒ\\v²PĔ»ƢNHĂyAmƂwVm`]ÈbH`Ì¢²ILvĜH®¤Dlt_¢JJÄämèÔDëþgºƫaʎÌrêYi~ ÎݤNpÀA¾Ĕ¼b
ð÷®üszMzÖĖQdȨýv§Tè|ªHþa¸|Ð ƒwKĢx¦ivr^ÿ ¸l öæfƟĴ·PJv}n\\h¹¶v·À|\\ƁĚN´ĜçèÁz]ġ¤²¨QÒŨTIlªťØ}¼˗ƦvÄùØE«FïËIqōTvāÜŏíÛßÛVj³âwGăÂíNOPìyV³ʼnĖýZso§HÑiYw[ß\\X¦¥c]ÔƩÜ·«jÐqvÁ¦m^ċ±R¦ƈťĚgÀ»IïĨʗƮ°ƝĻþÍAƉſ±tÍEÕÞāNUÍ¡\\ſčåÒʻĘm ƭÌŹöʥëQ¤µÇcƕªoIýIÉ_mkl³ăƓ¦j¡YzŇi}Msßõīʋ }ÁVm_[n}eıUĥ¼ªI{ΧDÓƻėojqYhĹT©oūĶ£]ďxĩǑMĝq`B´ƃ˺Чç~²ņj@¥@đ´ί}ĥtPńǾV¬ufÓÉCtÓ̻
¹£G³]ƖƾŎĪŪĘ̖¨ʈĢƂlɘ۪üºňUðǜȢƢż̌ȦǼĤŊɲĖÂKq´ï¦ºĒDzņɾªǀÞĈĂD½ĄĎÌŗĞrôñnN¼â¾ʄľԆ|DŽ֦ज़ȗlj̘̭ɺƅêgV̍ʆĠ·ÌĊv|ýĖÕWĊǎÞ´õ¼cÒÒBĢ͢UĜð͒s¨ňƃLĉÕÝ@ɛƯ÷¿ĽĹeȏijëCȚDŲyê×Ŗyò¯ļcÂßY
tÁƤyAã˾J@ǝrý@¤
rz¸oP¹ɐÚyáHĀ[Jw
cVeȴÏ»ÈĖ}ƒŰŐèȭǢόĀƪÈŶë;Ñ̆ȤМľĮEŔĹŊũ~ËUă{ĻƹɁύȩþĽvĽƓÉ@ēĽɲßǐƫʾǗĒpäWÐxnsÀ^ƆwW©¦cÅ¡Ji§vúF¶¨c~c¼īeXǚ\\đ¾JwÀďksãAfÕ¦L}waoZD½Ml«]eÒÅaɲáo½FõÛ]ĻÒ¡wYR£¢rvÓ®y®LFLzĈôe]gx}|KK}xklL]c¦£fRtív¦PĤoH{tK"
|
||||
]
|
||||
],
|
||||
"encodeOffsets": [[[108619, 36299]], [[108589, 36341]]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "630000",
|
||||
"properties": { "id": "630000", "cp": [96.778916, 35.623178], "name": "青海", "childNum": 2 },
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@InJm"],
|
||||
[
|
||||
"@@CƽOŃĦsΰ~dz¦@@Ņi±è}ШƄ˹A³r_ĞǒNĪĐw¤^ŬĵªpĺSZgrpiƼĘÔ¨C|ÍJ©Ħ»®VIJ~f\\m `UnÂ~ʌĬàöNt~ňjy¢ZiƔ¥Ąk´nl`JÊJþ©pdƖ®È£¶ìRʦźõƮËnʼėæÑƀĎ[¢VÎĂMÖÝÎF²sƊƀÎBļýƞ¯ʘƭðħ¼Jh¿ŦęΌƇ¥²Q]Č¥nuÂÏri¸¬ƪÛ^Ó¦d¥[Wà
x\\ZjÒ¨GtpþYŊĕ´zUOëPîMĄÁxH´áiÜUàîÜŐĂÛSuŎrJð̬EFÁú×uÃÎkrĒ{V}İ«O_ÌËĬ©ÓŧSRѱ§Ģ£^ÂyèçěM³Ƃę{[¸¿u
ºµ[gt£¸OƤĿéYõ·kĀq]juw¥DĩƍõÇPéĽG©ã¤G
uȧþRcÕĕNyyûtøï»a½ē¿BMoį£Íj}éZËqbʍƬh¹ìÿÓAçãnIáI`ks£CGěUy×Cy
@¶ʡÊBnāzGơMē¼±O÷õJËĚăVĪũƆ£¯{ËL½ÌzżVR|ĠTbuvJvµhĻĖHAëáa
OÇðñęNw
œľ·LmI±íĠĩPÉ×®ÿscB³±JKßĊ«`
ađ»·QAmOVţéÿ¤¹SQt]]Çx±¯A@ĉij¢Óļ©l¶ÅÛrŕspãRk~¦ª]Į´FRådČsCqđéFn¿ÅƃmÉx{W©ºƝºįkÕƂƑ¸wWūЩÈF£\\tÈ¥ÄRÈýÌJ lGr^×äùyÞ³fjc¨£ÂZ|ǓMĝÏ@ëÜőRĝ÷¡{aïȷPu°ËXÙ{©TmĠ}Y³ÞIňµç½©C¡į÷¯B»|St»]vųs»}MÓ ÿʪƟǭA¡fs»PY¼c¡»¦cċ¥£~msĉPSi^o©AecPeǵkgyUi¿h}aHĉ^|á´¡HØûÅ«ĉ®]m¡qĉ¶³ÈyôōLÁstB®wn±ă¥HSòė£Së@לÊăxÇN©©T±ª£IJ¡fb®Þbb_Ą¥xu¥B{łĝ³«`dƐt¤ťiñÍUuºí`£^tƃIJc·ÛLO½sç¥Ts{ă\\_»kϱq©čiìĉ|ÍI¥ć¥]ª§D{ŝŖÉR_sÿc³ĪōƿΧp[ĉc¯bKmR¥{³Ze^wx¹dƽŽôIg §Mĕ ƹĴ¿ǣÜÍ]Ý]snåA{eƭ`ǻŊĿ\\ijŬűYÂÿ¬jĖqßb¸L«¸©@ěĀ©ê¶ìÀEH|´bRľÓ¶rÀQþvl®ÕETzÜdb hw¤{LRdcb¯ÙVgƜßzÃôì®^jUèXÎ|UäÌ»rK\\ªN¼pZCüVY¤ɃRi^rPŇTÖ}|br°qňb̰ªiƶGQ¾²x¦PmlŜ[Ĥ¡ΞsĦÔÏâ\\ªÚŒU\\f
¢N²§x|¤§xĔsZPòʛ²SÐqF`ªVÞŜĶƨVZÌL`¢dŐIqr\\oäõF礻Ŷ×h¹]ClÙ\\¦ďÌį¬řtTӺƙgQÇÓHţĒ´ÃbEÄlbʔC|CŮkƮ[ʼ¬ň´KŮÈΰÌζƶlðļATUvdTGº̼ÔsÊDÔveOg"
|
||||
]
|
||||
],
|
||||
"encodeOffsets": [[[105308, 37219]], [[95370, 40081]]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "640000",
|
||||
"properties": { "id": "640000", "cp": [106.278179, 37.26637], "name": "宁夏", "childNum": 2 },
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
[
|
||||
"@@KëÀęĞ«Oęȿȕı]ʼn¡åįÕÔ«ǴõƪĚQÐZhv K°öqÀÑS[ÃÖHƖčËnL]ûc
Ùß@ĝ¾}w»»oģF¹»kÌÏ·{zP§B¢íyÅt@@á]Yv_ssģ¼ißĻL¾ġsKD£¡N_
X¸}B~HaiÅf{«x»ge_bsKF¯¡IxmELcÿZ¤ĢÝsuBLùtYdmVtNmtOPhRw~bd
¾qÐ\\âÙH\\bImlNZ»loqlVmGā§~QCw¤{A\\PKNY¯bFkC¥sks_Ã\\ă«¢ħkJi¯rrAhĹûç£CUĕĊ_ÔBixÅÙĄnªÑaM~ħpOu¥sîeQ¥¤^dkKwlL~{L~hw^ófćKyEKzuÔ¡qQ¤xZÑ¢^ļöܾEp±âbÊÑÆ^fk¬
NC¾YpxbK~¥eÖäBlt¿Đx½I[ĒǙWf»Ĭ}d§dµùEuj¨IÆ¢¥dXªƅx¿]mtÏwßRĶX¢͎vÆzƂZò®ǢÌʆCrâºMÞzÆMÒÊÓŊZľr°Î®Ȉmª²ĈUªĚîøºĮ¦ÌĘk^FłĬhĚiĀ˾iİbjÕ"
|
||||
],
|
||||
["@@mfwěwMrŢªv@G"]
|
||||
],
|
||||
"encodeOffsets": [[[109366, 40242]], [[108600, 36303]]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "650000",
|
||||
"properties": { "id": "650000", "cp": [85.617733, 40.792818], "name": "新疆", "childNum": 1 },
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
"@@QØĔ²X¨~ǘBºjʐߨvKƔX¨vĊO÷¢i@~cĝe_«E}QxgɪëÏÃ@sÅyXoŖ{ô«ŸuX
êÎf`C¹ÂÿÐGĮÕĞXŪōŸMźÈƺQèĽôe|¿ƸJR¤ĘEjcUóº¯Ĩ_ŘÁMª÷Ð¥OéÈ¿ÖğǤǷÂFÒzÉx[]Ĥĝœ¦EP}ûƥé¿İƷTėƫœŕƅƱB»Đ±ēO
¦E}`cȺrĦáŖuÒª«IJπdƺÏØZƴwʄ¤ĖGĐǂZĶèH¶}ÚZצʥĪï|ÇĦMŔ»İĝLjì¥Βba¯¥ǕǚkĆŵĦɑĺƯxūД̵nơʃĽá½M»òmqóŘĝč˾ăC
ćāƿÝɽ©DZҹđ¥³ðLrÁ®ɱĕģʼnǻ̋ȥơŻǛȡVï¹Ň۩ûkɗġƁ§ʇė̕ĩũƽō^ƕUv£ƁQïƵkŏ½ΉÃŭdzLŇʻ«ƭ\\lŭD{ʓDkaFÃÄa³ŤđÔGRÈƚhSӹŚsİ«ĐË[¥ÚDkº^Øg¼ŵ¸£EÍöůʼnT¡c_ËKYƧUśĵÝU_©rETÏʜ±OñtYwē¨{£¨uM³x½şL©Ùá[ÓÐĥ Νtģ¢\\śnkOw¥±T»ƷFɯàĩÞáB¹Æ
ÑUwŕĽw[mG½Èå~Æ÷QyěCFmĭZīŵVÁƿQƛûXS²b½KϽĉS©ŷXĕ{ĕK·¥Ɨcqq©f¿]ßDõU³hgËÇïģÉɋwk¯í}I·œbmÉřīJɥĻˁ×xoɹīlc
¤³Xù]DžA¿w͉ì¥wÇN·ÂËnƾƍdǧđ®ƝvUm©³G\\}µĿQyŹlăµEwLJQ½yƋBe¶ŋÀůo¥AÉw@{Gpm¿AijŽKLh³`ñcËtW±»ÕSëüÿďDu\\wwwù³VLŕOMËGh£õP¡erÏd{ġWÁ
č|yšg^ğyÁzÙs`s|ÉåªÇ}m¢Ń¨`x¥ù^}Ì¥H«YªƅAйn~ź¯f¤áÀzgÇDIÔ´AňĀÒ¶ûEYospõD[{ù°]uJqU|Soċxţ[õÔĥkŋÞŭZ˺óYËüċrw ÞkrťË¿XGÉbřaDü·Ē÷Aê[ÄäI®BÕĐÞ_¢āĠpÛÄȉĖġDKwbmÄNôfƫVÉvidzHQµâFùœ³¦{YGd¢ĚÜO {Ö¦ÞÍÀP^bƾl[vt×ĈÍE˨¡Đ~´î¸ùÎhuè`¸HÕŔVºwĠââWò@{ÙNÝ´ə²ȕn{¿¥{l÷eé^eďXj©î\\ªÑòÜìc\\üqÕ[Č¡xoÂċªbØø|¶ȴZdÆÂońéG\\¼C°ÌÆn´nxÊOĨŪƴĸ¢¸òTxÊǪMīĞÖŲÃɎOvʦƢ~FRěò¿ġ~åŊúN¸qĘ[Ĕ¶ÂćnÒPĒÜvúĀÊbÖ{Äî¸~Ŕünp¤ÂH¾ĄYÒ©ÊfºmÔĘcDoĬMŬS¤s²ʘÚžȂVŦ èW°ªB|IJXŔþÈJĦÆæFĚêYĂªĂ]øªŖNÞüAfɨJ¯ÎrDDĤ`mz\\§~D¬{vJ«lµĂb¤pŌŰNĄ¨ĊXW|ų ¿¾ɄĦƐMTòP÷fØĶK¢ȝ˔Sô¹òEð`Ɩ½ǒÂň×äı§ĤƝ§C~¡hlåǺŦŞkâ~}FøàIJaĞfƠ¥Ŕd®U¸źXv¢aƆúŪtŠųƠjdƺƺÅìnrh\\ĺ¯äɝĦ]èpĄ¦´LƞĬ´ƤǬ˼Ēɸ¤rºǼ²¨zÌPðŀbþ¹ļD¢¹\\ĜÑŚ¶ZƄ³àjĨoâȴLÊȮĐĚăÀêZǚŐ¤qȂ\\L¢ŌİfÆs|zºeªÙæ§{Ā´ƐÚ¬¨Ĵà²łhʺKÞºÖTiƢ¾ªì°`öøu®Ê¾ãØ"
|
||||
],
|
||||
"encodeOffsets": [[88824, 50096]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "110000",
|
||||
"properties": {
|
||||
"id": "110000",
|
||||
"cp": [116.405285, 39.904989],
|
||||
"name": "北京",
|
||||
"childNum": 1
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
"@@ĽOÁûtŷmiÍt_H»Ĩ±d`¹{bw
Yr³S]§§o¹qGtm_SŧoaFLgQN_dV@Zom_ć\\ßc±x¯oœRcfe
£o§ËgToÛJíĔóu
|wP¤XnO¢ÉŦ¯rNÄā¤zâŖÈRpŢZÚ{GrFt¦Òx§ø¹RóäV¤XdżâºWbwڍUd®bêņ¾jnŎGŃŶnzÚSeîĜZczî¾i]ÍQaúÍÔiþĩȨWĢü|Ėu[qb[swP@ÅğP¿{\\¥A¨ÏѨj¯X\\¯MKpA³[H
īu}}"
|
||||
],
|
||||
"encodeOffsets": [[120023, 41045]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "120000",
|
||||
"properties": {
|
||||
"id": "120000",
|
||||
"cp": [117.190182, 39.125596],
|
||||
"name": "天津",
|
||||
"childNum": 1
|
||||
},
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
"@@ŬgX§Ü«E
¶F̬O_ïlÁgz±AXeµÄĵ{¶]gitgIj·¥îakS¨ÐƎk}ĕ{gBqGf{¿aU^fIư³õ{YıëNĿk©ïËZŏR§òoY×Ógc
ĥs¡bġ«@dekąI[nlPqCnp{ō³°`{PNdƗqSÄĻNNâyj]äÒD ĬH°Æ]~¡HO¾X}ÐxgpgWrDGpù^LrzWxZ^¨´T\\|~@IzbĤjeĊªz£®ĔvěLmV¾Ô_ÈNW~zbĬvG²ZmDM~~"
|
||||
],
|
||||
"encodeOffsets": [[120237, 41215]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "310000",
|
||||
"properties": {
|
||||
"id": "310000",
|
||||
"cp": [121.472644, 31.231706],
|
||||
"name": "上海",
|
||||
"childNum": 6
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@ɧư¬EpƸÁxc"],
|
||||
["@@©ª"],
|
||||
["@@MA"],
|
||||
["@@QpİE§ÉC¾"],
|
||||
["@@bŝÕÕEȣÚƥêImɇǦèÜĠÚÃƌÃ͎ó"],
|
||||
["@@ǜûȬɋŭ×^sYɍDŋŽąñCG²«ªč@h_p¯A{oloY¬j@IJ`gQÚhr|ǀ^MIJvtbe´R¯Ô¬¨Yô¤r]ìƬį"]
|
||||
],
|
||||
"encodeOffsets": [[[124702, 32062]], [[124547, 32200]], [[124808, 31991]], [[124726, 32110]], [[124903, 32376]], [[124438, 32149]]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "500000",
|
||||
"properties": {
|
||||
"id": "500000",
|
||||
"cp": [107.304962, 29.533155],
|
||||
"name": "重庆",
|
||||
"childNum": 2
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
[
|
||||
"@@vjG~nGŘŬĶȂƀƾ¹¸ØÎezĆT¸}êÐqHðqĖä¥^CÆIj²p
\\_ æüY|[YxƊæu°xb®
Űb@~¢NQt°¶Sæ Ê~rljĔëĚ¢~uf`faĔJåĊnÖ]jƎćÊ@£¾a®£Ű{ŶĕFègLk{Y|¡ĜWƔtƬJÑxq±ĢN´òKLÈüD|s`ŋć]Ã`đMûƱ½~Y°ħ`ƏíW½eI½{aOIrÏ¡ĕŇapµÜƅġ^ÖÛbÙŽŏml½SêqDu[RãË»ÿw`»y¸_ĺę}÷`M¯ċfCVµqʼn÷Zgg`d½pDOÎCn^uf²ènh¼WtƏxRGg¦
pVFI±G^Ic´ecGĹÞ½sëĬhxW}KÓeXsbkF¦LØgTkïƵNï¶}Gyw\\oñ¡nmĈzj@Óc£»Wă¹Ój_m»¹·~MvÛaq»ê\\ÂoVnÓØÍ²«bq¿efE Ĝ^Q~ Évýş¤²ĮpEİ}zcĺL½¿gÅ¡ýE¡ya£³t\\¨\\vú»¼§·Ñr_oÒý¥u_n»_At©Þűā§IVeëY}{VPÀFA¨ąB}q@|Ou\\FmQFÝ
Mwå}]|FmÏCawu_p¯sfÙgY
DHl`{QEfNysB¦zG¸rHeN\\CvEsÐùÜ_·ÖĉsaQ¯}_UxÃđqNH¬Äd^ÝŰR¬ã°wećJE·vÝ·HgéFXjÉê`|ypxkAwWĐpb¥eOsmzwqChóUQl¥F^lafanòsrEvfQdÁUVfÎvÜ^eftET¬ôA\\¢sJnQTjPØxøK|nBzĞ»LY
FDxÓvr[ehľvN¢o¾NiÂxGpâ¬zbfZo~hGi]öF||NbtOMn eA±tPTLjpYQ|SHYĀxinzDJÌg¢và¥Pg_ÇzIIII£®S¬Øsμ£N"
|
||||
],
|
||||
["@@ifjN@s"]
|
||||
],
|
||||
"encodeOffsets": [[[109628, 30765]], [[111725, 31320]]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "810000",
|
||||
"properties": {
|
||||
"id": "810000",
|
||||
"cp": [114.173355, 22.320048],
|
||||
"name": "香港",
|
||||
"childNum": 5
|
||||
},
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [
|
||||
["@@AlBk"],
|
||||
["@@mn"],
|
||||
["@@EpFo"],
|
||||
["@@ea¢pl¸Eõ¹hj[]ÔCÎ@lj¡uBX
´AI¹
[yDU]W`çwZkmc
MpÅv}IoJlcafŃK°ä¬XJmÐ đhI®æÔtSHnEÒrÈc"],
|
||||
["@@rMUwAS®e"]
|
||||
],
|
||||
"encodeOffsets": [[[117111, 23002]], [[117072, 22876]], [[117045, 22887]], [[116975, 23082]], [[116882, 22747]]]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Feature",
|
||||
"id": "820000",
|
||||
"properties": { "id": "820000", "cp": [113.54909, 22.198951], "name": "澳门", "childNum": 1 },
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": ["@@kÊd°å§s"],
|
||||
"encodeOffsets": [[116279, 22639]]
|
||||
}
|
||||
}
|
||||
],
|
||||
"UTF8Encoding": true
|
||||
}
|
||||
189
jeecgboot-vue3/src/views/demo/charts/data.ts
Normal file
189
jeecgboot-vue3/src/views/demo/charts/data.ts
Normal file
@ -0,0 +1,189 @@
|
||||
export const mapData: any = [
|
||||
{
|
||||
name: '北京',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '天津',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '上海',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '重庆',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '河北',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '河南',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '云南',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '辽宁',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '黑龙江',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '湖南',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '安徽',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '山东',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '新疆',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '江苏',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '浙江',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '江西',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '湖北',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '广西',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '甘肃',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '山西',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '内蒙古',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '陕西',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '吉林',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '福建',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '贵州',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '广东',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '青海',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '西藏',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '四川',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '宁夏',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '海南',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '台湾',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '香港',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
{
|
||||
name: '澳门',
|
||||
value: Math.round(Math.random() * 1000),
|
||||
tipData: [Math.round(Math.random() * 1000), Math.round(Math.random() * 1000)],
|
||||
},
|
||||
];
|
||||
|
||||
export const getLineData = (() => {
|
||||
const category: any[] = [];
|
||||
let dottedBase = +new Date();
|
||||
const lineData: any[] = [];
|
||||
const barData: any[] = [];
|
||||
|
||||
for (let i = 0; i < 20; i++) {
|
||||
const date = new Date((dottedBase += 1000 * 3600 * 24));
|
||||
category.push([date.getFullYear(), date.getMonth() + 1, date.getDate()].join('-'));
|
||||
const b = Math.random() * 200;
|
||||
const d = Math.random() * 200;
|
||||
barData.push(b);
|
||||
lineData.push(d + b);
|
||||
}
|
||||
return { barData, category, lineData };
|
||||
})();
|
||||
45
jeecgboot-vue3/src/views/demo/charts/map/Baidu.vue
Normal file
45
jeecgboot-vue3/src/views/demo/charts/map/Baidu.vue
Normal file
@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div ref="wrapRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, nextTick, unref, onMounted } from 'vue';
|
||||
|
||||
import { useScript } from '/@/hooks/web/useScript';
|
||||
|
||||
const BAI_DU_MAP_URL = 'https://api.map.baidu.com/getscript?v=3.0&ak=OaBvYmKX3pjF7YFUFeeBCeGdy9Zp7xB2&services=&t=20210201100830&s=1';
|
||||
export default defineComponent({
|
||||
name: 'BaiduMap',
|
||||
props: {
|
||||
width: {
|
||||
type: String,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const wrapRef = ref<HTMLDivElement | null>(null);
|
||||
const { toPromise } = useScript({ src: BAI_DU_MAP_URL });
|
||||
|
||||
async function initMap() {
|
||||
await toPromise();
|
||||
await nextTick();
|
||||
const wrapEl = unref(wrapRef);
|
||||
if (!wrapEl) return;
|
||||
const BMap = (window as any).BMap;
|
||||
const map = new BMap.Map(wrapEl);
|
||||
const point = new BMap.Point(116.404, 39.915);
|
||||
map.centerAndZoom(point, 15);
|
||||
map.enableScrollWheelZoom(true);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initMap();
|
||||
});
|
||||
|
||||
return { wrapRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
47
jeecgboot-vue3/src/views/demo/charts/map/Gaode.vue
Normal file
47
jeecgboot-vue3/src/views/demo/charts/map/Gaode.vue
Normal file
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div ref="wrapRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, nextTick, unref, onMounted } from 'vue';
|
||||
|
||||
import { useScript } from '/@/hooks/web/useScript';
|
||||
|
||||
const A_MAP_URL = 'https://webapi.amap.com/maps?v=2.0&key=06313eb9c6563b674a8fd789db0692c3';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'AMap',
|
||||
props: {
|
||||
width: {
|
||||
type: String,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const wrapRef = ref<HTMLDivElement | null>(null);
|
||||
const { toPromise } = useScript({ src: A_MAP_URL });
|
||||
|
||||
async function initMap() {
|
||||
await toPromise();
|
||||
await nextTick();
|
||||
const wrapEl = unref(wrapRef);
|
||||
if (!wrapEl) return;
|
||||
const AMap = (window as any).AMap;
|
||||
new AMap.Map(wrapEl, {
|
||||
zoom: 11,
|
||||
center: [116.397428, 39.90923],
|
||||
viewMode: '3D',
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initMap();
|
||||
});
|
||||
|
||||
return { wrapRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
52
jeecgboot-vue3/src/views/demo/charts/map/Google.vue
Normal file
52
jeecgboot-vue3/src/views/demo/charts/map/Google.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<div ref="wrapRef" :style="{ height, width }"></div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, nextTick, unref, onMounted } from 'vue';
|
||||
|
||||
import { useScript } from '/@/hooks/web/useScript';
|
||||
|
||||
const MAP_URL = 'https://maps.googleapis.com/maps/api/js?key=AIzaSyBQWrGwj4gAzKndcbwD5favT9K0wgty_0&signed_in=true';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'GoogleMap',
|
||||
props: {
|
||||
width: {
|
||||
type: String,
|
||||
default: '100%',
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: 'calc(100vh - 78px)',
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const wrapRef = ref<HTMLDivElement | null>(null);
|
||||
const { toPromise } = useScript({ src: MAP_URL });
|
||||
|
||||
async function initMap() {
|
||||
await toPromise();
|
||||
await nextTick();
|
||||
const wrapEl = unref(wrapRef);
|
||||
if (!wrapEl) return;
|
||||
const google = (window as any).google;
|
||||
const latLng = { lat: 116.404, lng: 39.915 };
|
||||
const map = new google.maps.Map(wrapEl, {
|
||||
zoom: 4,
|
||||
center: latLng,
|
||||
});
|
||||
new google.maps.Marker({
|
||||
position: latLng,
|
||||
map: map,
|
||||
title: 'Hello World!',
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initMap();
|
||||
});
|
||||
|
||||
return { wrapRef };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
67
jeecgboot-vue3/src/views/demo/codemirror/index.vue
Normal file
67
jeecgboot-vue3/src/views/demo/codemirror/index.vue
Normal file
@ -0,0 +1,67 @@
|
||||
<template>
|
||||
<div>
|
||||
<textarea ref="textarea">
|
||||
白日依山尽,黄河入海流。
|
||||
欲穷千里目,更上一层楼。
|
||||
</textarea
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, onMounted, ref, reactive } from 'vue';
|
||||
// 引入全局实例
|
||||
import _CodeMirror from 'codemirror';
|
||||
|
||||
// 核心样式
|
||||
import 'codemirror/lib/codemirror.css';
|
||||
// 引入主题后还需要在 options 中指定主题才会生效
|
||||
import 'codemirror/theme/cobalt.css';
|
||||
|
||||
// 需要引入具体的语法高亮库才会有对应的语法高亮效果
|
||||
// codemirror 官方其实支持通过 /addon/mode/loadmode.js 和 /mode/meta.js 来实现动态加载对应语法高亮库
|
||||
// 但 vue 貌似没有无法在实例初始化后再动态加载对应 JS ,所以此处才把对应的 JS 提前引入
|
||||
import 'codemirror/mode/javascript/javascript.js';
|
||||
import 'codemirror/mode/css/css.js';
|
||||
import 'codemirror/mode/xml/xml.js';
|
||||
import 'codemirror/mode/clike/clike.js';
|
||||
import 'codemirror/mode/markdown/markdown.js';
|
||||
import 'codemirror/mode/python/python.js';
|
||||
import 'codemirror/mode/r/r.js';
|
||||
import 'codemirror/mode/shell/shell.js';
|
||||
import 'codemirror/mode/sql/sql.js';
|
||||
import 'codemirror/mode/swift/swift.js';
|
||||
import 'codemirror/mode/vue/vue.js';
|
||||
// 尝试获取全局实例
|
||||
|
||||
export default defineComponent({
|
||||
components: {},
|
||||
setup() {
|
||||
const CodeMirror = window.CodeMirror || _CodeMirror;
|
||||
|
||||
const textarea = ref(null);
|
||||
const options = reactive({
|
||||
// 缩进格式
|
||||
tabSize: 2,
|
||||
// 主题,对应主题库 JS 需要提前引入
|
||||
theme: 'cobalt',
|
||||
// 显示行号
|
||||
lineNumbers: true,
|
||||
line: true,
|
||||
});
|
||||
onMounted(() => {
|
||||
init();
|
||||
});
|
||||
|
||||
function init() {
|
||||
CodeMirror.fromTextArea(textarea.value, options);
|
||||
}
|
||||
|
||||
return {
|
||||
textarea,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="css" scoped></style>
|
||||
110
jeecgboot-vue3/src/views/demo/comp/button/index.vue
Normal file
110
jeecgboot-vue3/src/views/demo/comp/button/index.vue
Normal file
@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<PageWrapper
|
||||
contentFullHeight
|
||||
title="基础组件"
|
||||
content=" 基础组件依赖于ant-design-vue,组件库已有的基础组件,项目中不会再次进行demo展示(二次封装组件除外)"
|
||||
>
|
||||
<a-row :gutter="[20, 20]">
|
||||
<a-col :xl="10" :lg="24">
|
||||
<a-card title="BasicButton Color">
|
||||
<div class="my-2">
|
||||
<h3>success</h3>
|
||||
<div class="py-2">
|
||||
<a-button color="success"> 成功 </a-button>
|
||||
<a-button color="success" class="ml-2" disabled> 禁用 </a-button>
|
||||
<a-button color="success" class="ml-2" loading> loading </a-button>
|
||||
<a-button color="success" type="link" class="ml-2"> link </a-button>
|
||||
<a-button color="success" type="link" class="ml-2" loading> loading link </a-button>
|
||||
<a-button color="success" type="link" class="ml-2" disabled> disabled link </a-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="my-2">
|
||||
<h3>warning</h3>
|
||||
<a-button color="warning"> 警告 </a-button>
|
||||
<a-button color="warning" class="ml-2" disabled> 禁用 </a-button>
|
||||
<a-button color="warning" class="ml-2" loading> loading </a-button>
|
||||
<a-button color="warning" type="link" class="ml-2"> link </a-button>
|
||||
<a-button color="warning" type="link" class="ml-2" loading> loading link </a-button>
|
||||
<a-button color="warning" type="link" class="ml-2" disabled> disabled link </a-button>
|
||||
</div>
|
||||
|
||||
<div class="my-2">
|
||||
<h3>error</h3>
|
||||
<a-button color="error"> 错误 </a-button>
|
||||
<a-button color="error" class="ml-2" disabled> 禁用 </a-button>
|
||||
<a-button color="error" class="ml-2" loading> loading </a-button>
|
||||
<a-button color="error" type="link" class="ml-2"> link </a-button>
|
||||
<a-button color="error" type="link" class="ml-2" loading> loading link </a-button>
|
||||
<a-button color="error" type="link" class="ml-2" disabled> disabled link </a-button>
|
||||
</div>
|
||||
|
||||
<div class="my-2">
|
||||
<h3>ghost</h3>
|
||||
<a-button ghost color="success" class="ml-2"> 幽灵成功 </a-button>
|
||||
<a-button ghost color="warning" class="ml-2"> 幽灵警告 </a-button>
|
||||
<a-button ghost color="error" class="ml-2"> 幽灵错误 </a-button>
|
||||
<a-button ghost type="dashed" color="warning" class="ml-2"> 幽灵警告dashed </a-button>
|
||||
<a-button ghost danger class="ml-2"> 幽灵危险 </a-button>
|
||||
</div>
|
||||
</a-card>
|
||||
</a-col>
|
||||
<a-col :xl="14" :lg="24">
|
||||
<a-card title="BasicButton Types">
|
||||
<div class="my-2">
|
||||
<h3>primary</h3>
|
||||
<a-button type="primary" preIcon="mdi:page-next-outline"> 主按钮 </a-button>
|
||||
<a-button type="primary" class="ml-2" disabled> 禁用 </a-button>
|
||||
<a-button type="primary" class="ml-2" danger preIcon="mdi:page-next-outline"> 危险 </a-button>
|
||||
<a-button type="primary" class="ml-2" loading> loading </a-button>
|
||||
<a-button type="link" class="ml-2"> link </a-button>
|
||||
<a-button type="link" class="ml-2" loading> loading link </a-button>
|
||||
<a-button type="link" class="ml-2" disabled> disabled link </a-button>
|
||||
</div>
|
||||
|
||||
<div class="my-2">
|
||||
<h3>default</h3>
|
||||
<a-button type="default"> 默认 </a-button>
|
||||
<a-button type="default" class="ml-2" disabled> 禁用 </a-button>
|
||||
<a-button type="default" class="ml-2" danger> 危险 </a-button>
|
||||
<a-button type="default" class="ml-2" loading> loading </a-button>
|
||||
<a-button type="link" class="ml-2"> link </a-button>
|
||||
<a-button type="link" class="ml-2" loading> loading link </a-button>
|
||||
<a-button type="link" class="ml-2" disabled> disabled link </a-button>
|
||||
</div>
|
||||
|
||||
<div class="my-2">
|
||||
<h3>dashed</h3>
|
||||
<a-button type="dashed"> dashed </a-button>
|
||||
<a-button type="dashed" class="ml-2" disabled> 禁用 </a-button>
|
||||
<a-button type="dashed" class="ml-2" danger> 危险 </a-button>
|
||||
<a-button type="dashed" class="ml-2" loading> loading </a-button>
|
||||
</div>
|
||||
|
||||
<div class="my-2">
|
||||
<h3>ghost 常规幽灵按钮通常用于有色背景下</h3>
|
||||
<div class="bg-gray-400 py-2">
|
||||
<a-button ghost type="primary" class="ml-2"> 幽灵主要 </a-button>
|
||||
<a-button ghost type="default" class="ml-2"> 幽灵默认 </a-button>
|
||||
<a-button ghost type="dashed" class="ml-2"> 幽灵dashed </a-button>
|
||||
<a-button ghost type="primary" class="ml-2" disabled> 禁用 </a-button>
|
||||
<a-button ghost type="primary" class="ml-2" loading> loading </a-button>
|
||||
</div>
|
||||
<!-- antd 按钮不能同时使用ghost和link -->
|
||||
<!-- <a-button ghost type="link" class="ml-2"> link </a-button>-->
|
||||
<!-- <a-button ghost type="link" class="ml-2" loading> loading link </a-button>-->
|
||||
<!-- <a-button ghost type="link" class="ml-2" disabled> disabled link </a-button>-->
|
||||
</div>
|
||||
</a-card>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { Card, Row, Col } from 'ant-design-vue';
|
||||
export default defineComponent({
|
||||
components: { PageWrapper, ACard: Card, ARow: Row, ACol: Col },
|
||||
});
|
||||
</script>
|
||||
32
jeecgboot-vue3/src/views/demo/comp/card-list/index.vue
Normal file
32
jeecgboot-vue3/src/views/demo/comp/card-list/index.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<PageWrapper title="卡片列表示例" content="基础封装">
|
||||
<CardList :params="params" :api="demoListApi" @getMethod="getMethod" @delete="handleDel">
|
||||
<template #header>
|
||||
<Button type="primary" color="error"> 按钮1 </Button>
|
||||
<Button type="primary" color="success"> 按钮2 </Button>
|
||||
</template>
|
||||
</CardList>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { CardList } from '/@/components/CardList';
|
||||
import { Button } from '/@/components/Button';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { demoListApi } from '/@/api/demo/table';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
const { notification } = useMessage();
|
||||
// 请求api时附带参数
|
||||
const params = {};
|
||||
|
||||
let reload = () => {};
|
||||
// 获取内部fetch方法;
|
||||
function getMethod(m: any) {
|
||||
reload = m;
|
||||
}
|
||||
//删除按钮事件
|
||||
function handleDel(id) {
|
||||
console.log(id);
|
||||
notification.success({ message: `成功删除${id}` });
|
||||
reload();
|
||||
}
|
||||
</script>
|
||||
42
jeecgboot-vue3/src/views/demo/comp/count-to/index.vue
Normal file
42
jeecgboot-vue3/src/views/demo/comp/count-to/index.vue
Normal file
@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<PageWrapper title="数字动画示例">
|
||||
<Card>
|
||||
<CardGrid class="count-to-demo-card">
|
||||
<CountTo prefix="$" :color="'#409EFF'" :startVal="1" :endVal="200000" :duration="8000" />
|
||||
</CardGrid>
|
||||
<CardGrid class="count-to-demo-card">
|
||||
<CountTo suffix="$" :color="'red'" :startVal="1" :endVal="300000" :decimals="2" :duration="6000" />
|
||||
</CardGrid>
|
||||
<CardGrid class="count-to-demo-card">
|
||||
<CountTo suffix="$" :color="'rgb(0,238,0)'" :startVal="1" :endVal="400000" :duration="7000" />
|
||||
</CardGrid>
|
||||
<CardGrid class="count-to-demo-card">
|
||||
<CountTo separator="-" :color="'rgba(138,43,226,.6)'" :startVal="10000" :endVal="500000" :duration="8000" />
|
||||
</CardGrid>
|
||||
</Card>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
import { CountTo } from '/@/components/CountTo/index';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
Card,
|
||||
CardGrid: Card.Grid,
|
||||
CountTo,
|
||||
PageWrapper,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.count-to-demo {
|
||||
&-card {
|
||||
width: 50%;
|
||||
font-size: 30px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
94
jeecgboot-vue3/src/views/demo/comp/cropper/index.vue
Normal file
94
jeecgboot-vue3/src/views/demo/comp/cropper/index.vue
Normal file
@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<PageWrapper title="图片裁剪示例" content="需要开启测试接口服务才能进行上传测试!">
|
||||
<CollapseContainer title="头像裁剪">
|
||||
<CropperAvatar :uploadApi="uploadApi" :value="avatar" />
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="矩形裁剪" class="my-4">
|
||||
<div class="container p-4">
|
||||
<div class="cropper-container mr-10">
|
||||
<CropperImage ref="refCropper" :src="img" @cropend="handleCropend" style="width: 40vw" />
|
||||
</div>
|
||||
<img :src="cropperImg" class="croppered" v-if="cropperImg" alt="" />
|
||||
</div>
|
||||
<p v-if="cropperImg">裁剪后图片信息:{{ info }}</p>
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="圆形裁剪">
|
||||
<div class="container p-4">
|
||||
<div class="cropper-container mr-10">
|
||||
<CropperImage ref="refCropper" :src="img" @cropend="handleCircleCropend" style="width: 40vw" circled />
|
||||
</div>
|
||||
<img :src="circleImg" class="croppered" v-if="circleImg" />
|
||||
</div>
|
||||
<p v-if="circleImg">裁剪后图片信息:{{ circleInfo }}</p>
|
||||
</CollapseContainer>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { CollapseContainer } from '/@/components/Container';
|
||||
import { CropperImage, CropperAvatar } from '/@/components/Cropper';
|
||||
import { uploadApi } from '/@/api/sys/upload';
|
||||
import img from '/@/assets/images/header.jpg';
|
||||
import { useUserStore } from '/@/store/modules/user';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
PageWrapper,
|
||||
CropperImage,
|
||||
CollapseContainer,
|
||||
CropperAvatar,
|
||||
},
|
||||
setup() {
|
||||
const info = ref('');
|
||||
const cropperImg = ref('');
|
||||
const circleInfo = ref('');
|
||||
const circleImg = ref('');
|
||||
const userStore = useUserStore();
|
||||
const avatar = ref(userStore.getUserInfo?.avatar || '');
|
||||
function handleCropend({ imgBase64, imgInfo }) {
|
||||
info.value = imgInfo;
|
||||
cropperImg.value = imgBase64;
|
||||
}
|
||||
|
||||
function handleCircleCropend({ imgBase64, imgInfo }) {
|
||||
circleInfo.value = imgInfo;
|
||||
circleImg.value = imgBase64;
|
||||
}
|
||||
|
||||
return {
|
||||
img,
|
||||
info,
|
||||
circleInfo,
|
||||
cropperImg,
|
||||
circleImg,
|
||||
handleCropend,
|
||||
handleCircleCropend,
|
||||
avatar,
|
||||
uploadApi: uploadApi as any,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.container {
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cropper-container {
|
||||
width: 40vw;
|
||||
}
|
||||
|
||||
.croppered {
|
||||
height: 360px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 10px;
|
||||
}
|
||||
</style>
|
||||
79
jeecgboot-vue3/src/views/demo/comp/desc/index.vue
Normal file
79
jeecgboot-vue3/src/views/demo/comp/desc/index.vue
Normal file
@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<PageWrapper title="详情组件示例">
|
||||
<Description title="基础示例" :collapseOptions="{ canExpand: true, helpMessage: 'help me' }" :column="3" :data="mockData" :schema="schema" />
|
||||
|
||||
<Description
|
||||
class="mt-4"
|
||||
title="垂直示例"
|
||||
layout="vertical"
|
||||
:collapseOptions="{ canExpand: true, helpMessage: 'help me' }"
|
||||
:column="2"
|
||||
:data="mockData"
|
||||
:schema="schema"
|
||||
/>
|
||||
|
||||
<Description @register="register" class="mt-4" />
|
||||
<Description @register="register1" class="mt-4" />
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { Description, DescItem, useDescription } from '/@/components/Description/index';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
const mockData: Recordable = {
|
||||
username: 'test',
|
||||
nickName: 'VB',
|
||||
age: '123',
|
||||
phone: '15695909xxx',
|
||||
email: '190848757@qq.com',
|
||||
addr: '厦门市思明区',
|
||||
sex: '男',
|
||||
certy: '3504256199xxxxxxxxx',
|
||||
tag: 'orange',
|
||||
};
|
||||
const schema: DescItem[] = [
|
||||
{
|
||||
field: 'username',
|
||||
label: '用户名',
|
||||
},
|
||||
{
|
||||
field: 'nickName',
|
||||
label: '昵称',
|
||||
render: (curVal, data) => {
|
||||
return `${data.username}-${curVal}`;
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'phone',
|
||||
label: '联系电话',
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
label: '邮箱',
|
||||
},
|
||||
{
|
||||
field: 'addr',
|
||||
label: '地址',
|
||||
},
|
||||
];
|
||||
export default defineComponent({
|
||||
components: { Description, PageWrapper },
|
||||
setup() {
|
||||
const [register] = useDescription({
|
||||
title: 'useDescription',
|
||||
data: mockData,
|
||||
schema: schema,
|
||||
});
|
||||
|
||||
const [register1] = useDescription({
|
||||
title: '无边框',
|
||||
bordered: false,
|
||||
data: mockData,
|
||||
schema: schema,
|
||||
});
|
||||
|
||||
return { mockData, schema, register, register1 };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
13
jeecgboot-vue3/src/views/demo/comp/drawer/Drawer1.vue
Normal file
13
jeecgboot-vue3/src/views/demo/comp/drawer/Drawer1.vue
Normal file
@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<BasicDrawer v-bind="$attrs" title="Drawer Title" width="50%"> Drawer Info. </BasicDrawer>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { BasicDrawer } from '/@/components/Drawer';
|
||||
export default defineComponent({
|
||||
components: { BasicDrawer },
|
||||
setup() {
|
||||
return {};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
17
jeecgboot-vue3/src/views/demo/comp/drawer/Drawer2.vue
Normal file
17
jeecgboot-vue3/src/views/demo/comp/drawer/Drawer2.vue
Normal file
@ -0,0 +1,17 @@
|
||||
<template>
|
||||
<BasicDrawer v-bind="$attrs" @register="register" title="Drawer Title" width="50%">
|
||||
Drawer Info.
|
||||
<a-button type="primary" @click="closeDrawer"> 内部关闭drawer </a-button>
|
||||
</BasicDrawer>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
|
||||
export default defineComponent({
|
||||
components: { BasicDrawer },
|
||||
setup() {
|
||||
const [register, { closeDrawer }] = useDrawerInner();
|
||||
return { register, closeDrawer };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
35
jeecgboot-vue3/src/views/demo/comp/drawer/Drawer3.vue
Normal file
35
jeecgboot-vue3/src/views/demo/comp/drawer/Drawer3.vue
Normal file
@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<BasicDrawer v-bind="$attrs" title="Modal Title" width="50%" showFooter @ok="handleOk">
|
||||
<p class="h-20" v-for="index in 40" :key="index"> 根据屏幕高度自适应 </p>
|
||||
<template #insertFooter>
|
||||
<a-button> btn</a-button>
|
||||
</template>
|
||||
<template #centerFooter>
|
||||
<a-button> btn2</a-button>
|
||||
</template>
|
||||
|
||||
<template #appendFooter>
|
||||
<a-button> btn3</a-button>
|
||||
</template>
|
||||
|
||||
<!-- <template #footer>
|
||||
<a-button> customerFooter</a-button>
|
||||
</template> -->
|
||||
</BasicDrawer>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { BasicDrawer } from '/@/components/Drawer';
|
||||
export default defineComponent({
|
||||
components: { BasicDrawer },
|
||||
setup() {
|
||||
return {
|
||||
handleOk: () => {
|
||||
console.log('=====================');
|
||||
console.log('ok');
|
||||
console.log('======================');
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
53
jeecgboot-vue3/src/views/demo/comp/drawer/Drawer4.vue
Normal file
53
jeecgboot-vue3/src/views/demo/comp/drawer/Drawer4.vue
Normal file
@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<BasicDrawer v-bind="$attrs" @register="register" title="Drawer Title" width="50%">
|
||||
<div>
|
||||
<BasicForm @register="registerForm" />
|
||||
</div>
|
||||
</BasicDrawer>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { BasicDrawer, useDrawerInner } from '/@/components/Drawer';
|
||||
|
||||
import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
|
||||
const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'field1',
|
||||
component: 'Input',
|
||||
label: '字段1',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
defaultValue: '111',
|
||||
},
|
||||
{
|
||||
field: 'field2',
|
||||
component: 'Input',
|
||||
label: '字段2',
|
||||
colProps: {
|
||||
span: 12,
|
||||
},
|
||||
},
|
||||
];
|
||||
export default defineComponent({
|
||||
components: { BasicDrawer, BasicForm },
|
||||
setup() {
|
||||
const [registerForm, { setFieldsValue }] = useForm({
|
||||
labelWidth: 120,
|
||||
schemas,
|
||||
showActionButtonGroup: false,
|
||||
actionColOptions: {
|
||||
span: 24,
|
||||
},
|
||||
});
|
||||
const [register] = useDrawerInner((data) => {
|
||||
// 方式1
|
||||
setFieldsValue({
|
||||
field2: data.data,
|
||||
field1: data.info,
|
||||
});
|
||||
});
|
||||
return { register, schemas, registerForm };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
13
jeecgboot-vue3/src/views/demo/comp/drawer/Drawer5.vue
Normal file
13
jeecgboot-vue3/src/views/demo/comp/drawer/Drawer5.vue
Normal file
@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<BasicDrawer v-bind="$attrs" :isDetail="true" title="Drawer Title5">
|
||||
<p class="h-20"> Content Message </p>
|
||||
<template #titleToolbar> toolbar </template>
|
||||
</BasicDrawer>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { BasicDrawer } from '/@/components/Drawer';
|
||||
export default defineComponent({
|
||||
components: { BasicDrawer },
|
||||
});
|
||||
</script>
|
||||
69
jeecgboot-vue3/src/views/demo/comp/drawer/index.vue
Normal file
69
jeecgboot-vue3/src/views/demo/comp/drawer/index.vue
Normal file
@ -0,0 +1,69 @@
|
||||
<template>
|
||||
<PageWrapper title="抽屉组件使用示例">
|
||||
<Alert message="使用 useDrawer 进行抽屉操作" show-icon />
|
||||
<a-button type="primary" class="my-4" @click="openDrawerLoading"> 打开Drawer </a-button>
|
||||
|
||||
<Alert message="内外同时控制显示隐藏" show-icon />
|
||||
<a-button type="primary" class="my-4" @click="openDrawer2(true)"> 打开Drawer </a-button>
|
||||
<Alert message="自适应高度/显示footer" show-icon />
|
||||
<a-button type="primary" class="my-4" @click="openDrawer3(true)"> 打开Drawer </a-button>
|
||||
|
||||
<Alert message="内外数据交互" show-icon />
|
||||
<a-button type="primary" class="my-4" @click="send"> 打开Drawer并传递数据 </a-button>
|
||||
<Alert message="详情页模式" show-icon />
|
||||
<a-button type="primary" class="my-4" @click="openDrawer5(true)"> 打开详情Drawer </a-button>
|
||||
<Drawer1 @register="register1" />
|
||||
<Drawer2 @register="register2" />
|
||||
<Drawer3 @register="register3" />
|
||||
<Drawer4 @register="register4" />
|
||||
<Drawer5 @register="register5" />
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { Alert } from 'ant-design-vue';
|
||||
import { useDrawer } from '/@/components/Drawer';
|
||||
import Drawer1 from './Drawer1.vue';
|
||||
import Drawer2 from './Drawer2.vue';
|
||||
import Drawer3 from './Drawer3.vue';
|
||||
import Drawer4 from './Drawer4.vue';
|
||||
import Drawer5 from './Drawer5.vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { Alert, PageWrapper, Drawer1, Drawer2, Drawer3, Drawer4, Drawer5 },
|
||||
setup() {
|
||||
const [register1, { openDrawer: openDrawer1, setDrawerProps }] = useDrawer();
|
||||
const [register2, { openDrawer: openDrawer2 }] = useDrawer();
|
||||
const [register3, { openDrawer: openDrawer3 }] = useDrawer();
|
||||
const [register4, { openDrawer: openDrawer4 }] = useDrawer();
|
||||
const [register5, { openDrawer: openDrawer5 }] = useDrawer();
|
||||
function send() {
|
||||
openDrawer4(true, {
|
||||
data: 'content',
|
||||
info: 'Info',
|
||||
});
|
||||
}
|
||||
function openDrawerLoading() {
|
||||
openDrawer1();
|
||||
setDrawerProps({ loading: true });
|
||||
setTimeout(() => {
|
||||
setDrawerProps({ loading: false });
|
||||
}, 2000);
|
||||
}
|
||||
return {
|
||||
register1,
|
||||
openDrawer1,
|
||||
register2,
|
||||
openDrawer2,
|
||||
register3,
|
||||
openDrawer3,
|
||||
register4,
|
||||
register5,
|
||||
openDrawer5,
|
||||
send,
|
||||
openDrawerLoading,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
19
jeecgboot-vue3/src/views/demo/comp/lazy/TargetContent.vue
Normal file
19
jeecgboot-vue3/src/views/demo/comp/lazy/TargetContent.vue
Normal file
@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<Card hoverable :style="{ width: '240px', background: '#fff' }">
|
||||
<template #cover>
|
||||
<img alt="example" src="https://os.alipayobjects.com/rmsportal/QBnOOoLaAfKPirc.png" />
|
||||
</template>
|
||||
<CardMeta title="懒加载组件" />
|
||||
</Card>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { Card } from 'ant-design-vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: { CardMeta: Card.Meta, Card },
|
||||
setup() {
|
||||
return {};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
77
jeecgboot-vue3/src/views/demo/comp/lazy/Transition.vue
Normal file
77
jeecgboot-vue3/src/views/demo/comp/lazy/Transition.vue
Normal file
@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<PageWrapper title="懒加载自定义动画示例" content="懒加载组件显示动画">
|
||||
<div class="lazy-base-demo-wrap">
|
||||
<h1>向下滚动</h1>
|
||||
|
||||
<div class="lazy-base-demo-box">
|
||||
<LazyContainer transitionName="custom">
|
||||
<TargetContent />
|
||||
</LazyContainer>
|
||||
</div>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import TargetContent from './TargetContent.vue';
|
||||
import { LazyContainer } from '/@/components/Container/index';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { LazyContainer, TargetContent, PageWrapper },
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
.lazy-base-demo {
|
||||
&-wrap {
|
||||
display: flex;
|
||||
width: 50%;
|
||||
height: 2000px;
|
||||
margin: 20px auto;
|
||||
text-align: center;
|
||||
background-color: @component-background;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-box {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
height: 1300px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
}
|
||||
|
||||
.custom-enter {
|
||||
opacity: 0;
|
||||
transform: scale(0.4) translate(100%);
|
||||
}
|
||||
|
||||
.custom-enter-to {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.custom-enter-active {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
transition: all 0.5s;
|
||||
}
|
||||
|
||||
.custom-leave {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.custom-leave-to {
|
||||
opacity: 0;
|
||||
transform: scale(0.4) translate(-100%);
|
||||
}
|
||||
|
||||
.custom-leave-active {
|
||||
transition: all 0.5s;
|
||||
}
|
||||
</style>
|
||||
52
jeecgboot-vue3/src/views/demo/comp/lazy/index.vue
Normal file
52
jeecgboot-vue3/src/views/demo/comp/lazy/index.vue
Normal file
@ -0,0 +1,52 @@
|
||||
<template>
|
||||
<PageWrapper title="懒加载基础示例" content="向下滚动到可见区域才会加载组件">
|
||||
<div class="lazy-base-demo-wrap">
|
||||
<h1>向下滚动</h1>
|
||||
|
||||
<div class="lazy-base-demo-box">
|
||||
<LazyContainer>
|
||||
<TargetContent />
|
||||
<template #skeleton>
|
||||
<Skeleton :rows="10" />
|
||||
</template>
|
||||
</LazyContainer>
|
||||
</div>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { Skeleton } from 'ant-design-vue';
|
||||
import TargetContent from './TargetContent.vue';
|
||||
import { LazyContainer } from '/@/components/Container/index';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { LazyContainer, PageWrapper, TargetContent, Skeleton },
|
||||
});
|
||||
</script>
|
||||
<style lang="less">
|
||||
.lazy-base-demo {
|
||||
&-wrap {
|
||||
display: flex;
|
||||
width: 50%;
|
||||
height: 2000px;
|
||||
margin: 20px auto;
|
||||
text-align: center;
|
||||
background-color: @component-background;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&-box {
|
||||
width: 300px;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
height: 1300px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
101
jeecgboot-vue3/src/views/demo/comp/loading/index.vue
Normal file
101
jeecgboot-vue3/src/views/demo/comp/loading/index.vue
Normal file
@ -0,0 +1,101 @@
|
||||
<template>
|
||||
<PageWrapper v-loading="loadingRef" loading-tip="加载中..." title="Loading组件示例">
|
||||
<div ref="wrapEl">
|
||||
<a-alert message="组件方式" />
|
||||
<a-button class="my-4 mr-4" type="primary" @click="openCompFullLoading"> 全屏 Loading </a-button>
|
||||
<a-button class="my-4" type="primary" @click="openCompAbsolute"> 容器内 Loading </a-button>
|
||||
<Loading :loading="loading" :absolute="absolute" :theme="theme" :background="background" :tip="tip" />
|
||||
|
||||
<a-alert message="函数方式" />
|
||||
|
||||
<a-button class="my-4 mr-4" type="primary" @click="openFnFullLoading"> 全屏 Loading </a-button>
|
||||
<a-button class="my-4" type="primary" @click="openFnWrapLoading"> 容器内 Loading </a-button>
|
||||
|
||||
<a-alert message="指令方式" />
|
||||
<a-button class="my-4 mr-4" type="primary" @click="openDirectiveLoading"> 打开指令Loading </a-button>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs, ref } from 'vue';
|
||||
import { Loading, useLoading } from '/@/components/Loading';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { Alert } from 'ant-design-vue';
|
||||
|
||||
export default defineComponent({
|
||||
components: { Loading, PageWrapper, [Alert.name]: Alert },
|
||||
setup() {
|
||||
const wrapEl = ref<ElRef>(null);
|
||||
|
||||
const loadingRef = ref(false);
|
||||
const compState = reactive({
|
||||
absolute: false,
|
||||
loading: false,
|
||||
theme: 'dark',
|
||||
background: 'rgba(111,111,111,.7)',
|
||||
tip: '加载中...',
|
||||
});
|
||||
const [openFullLoading, closeFullLoading] = useLoading({
|
||||
tip: '加载中...',
|
||||
});
|
||||
|
||||
const [openWrapLoading, closeWrapLoading] = useLoading({
|
||||
target: wrapEl,
|
||||
props: {
|
||||
tip: '加载中...',
|
||||
absolute: true,
|
||||
},
|
||||
});
|
||||
|
||||
function openLoading(absolute: boolean) {
|
||||
compState.absolute = absolute;
|
||||
compState.loading = true;
|
||||
setTimeout(() => {
|
||||
compState.loading = false;
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function openCompFullLoading() {
|
||||
openLoading(false);
|
||||
}
|
||||
|
||||
function openCompAbsolute() {
|
||||
openLoading(true);
|
||||
}
|
||||
|
||||
function openFnFullLoading() {
|
||||
openFullLoading();
|
||||
|
||||
setTimeout(() => {
|
||||
closeFullLoading();
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function openFnWrapLoading() {
|
||||
openWrapLoading();
|
||||
|
||||
setTimeout(() => {
|
||||
closeWrapLoading();
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
function openDirectiveLoading() {
|
||||
loadingRef.value = true;
|
||||
setTimeout(() => {
|
||||
loadingRef.value = false;
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
return {
|
||||
openCompFullLoading,
|
||||
openFnFullLoading,
|
||||
openFnWrapLoading,
|
||||
openCompAbsolute,
|
||||
wrapEl,
|
||||
loadingRef,
|
||||
openDirectiveLoading,
|
||||
...toRefs(compState),
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
58
jeecgboot-vue3/src/views/demo/comp/modal/Modal1.vue
Normal file
58
jeecgboot-vue3/src/views/demo/comp/modal/Modal1.vue
Normal file
@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" destroyOnClose @register="register" title="Modal Title" :helpMessage="['提示1', '提示2']" @visible-change="handleShow">
|
||||
<template #insertFooter>
|
||||
<a-button type="primary" danger @click="setLines" :disabled="loading">点我更新内容</a-button>
|
||||
</template>
|
||||
<template v-if="loading">
|
||||
<div class="empty-tips"> 加载中,稍等3秒…… </div>
|
||||
</template>
|
||||
<template v-if="!loading">
|
||||
<ul>
|
||||
<li v-for="index in lines" :key="index">加载完成{{ index }}!</li>
|
||||
</ul>
|
||||
</template>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, watch } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
export default defineComponent({
|
||||
components: { BasicModal },
|
||||
setup() {
|
||||
const loading = ref(true);
|
||||
const lines = ref(10);
|
||||
const [register, { setModalProps, redoModalHeight }] = useModalInner();
|
||||
|
||||
watch(
|
||||
() => lines.value,
|
||||
() => {
|
||||
redoModalHeight();
|
||||
}
|
||||
);
|
||||
|
||||
function handleShow(visible: boolean) {
|
||||
if (visible) {
|
||||
loading.value = true;
|
||||
setModalProps({ loading: true, confirmLoading: true });
|
||||
setTimeout(() => {
|
||||
lines.value = Math.round(Math.random() * 30 + 5);
|
||||
loading.value = false;
|
||||
setModalProps({ loading: false, confirmLoading: false });
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
function setLines() {
|
||||
lines.value = Math.round(Math.random() * 20 + 10);
|
||||
}
|
||||
return { register, loading, handleShow, lines, setLines };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style scoped>
|
||||
.empty-tips {
|
||||
height: 100px;
|
||||
line-height: 100px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
23
jeecgboot-vue3/src/views/demo/comp/modal/Modal2.vue
Normal file
23
jeecgboot-vue3/src/views/demo/comp/modal/Modal2.vue
Normal file
@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<BasicModal @register="register" title="Modal Title" :helpMessage="['提示1', '提示2']" :okButtonProps="{ disabled: true }">
|
||||
<a-button type="primary" @click="closeModal" class="mr-2"> 从内部关闭弹窗 </a-button>
|
||||
<a-button type="primary" @click="setModalProps"> 从内部修改title </a-button>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
export default defineComponent({
|
||||
components: { BasicModal },
|
||||
setup() {
|
||||
const [register, { closeModal, setModalProps }] = useModalInner();
|
||||
return {
|
||||
register,
|
||||
closeModal,
|
||||
setModalProps: () => {
|
||||
setModalProps({ title: 'Modal New Title' });
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
15
jeecgboot-vue3/src/views/demo/comp/modal/Modal3.vue
Normal file
15
jeecgboot-vue3/src/views/demo/comp/modal/Modal3.vue
Normal file
@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" title="Modal Title" :helpMessage="['提示1', '提示2']" width="700px">
|
||||
<p class="h-20" v-for="index in 20" :key="index"> 根据屏幕高度自适应 </p>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { BasicModal } from '/@/components/Modal';
|
||||
export default defineComponent({
|
||||
components: { BasicModal },
|
||||
setup() {
|
||||
return {};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
81
jeecgboot-vue3/src/views/demo/comp/modal/Modal4.vue
Normal file
81
jeecgboot-vue3/src/views/demo/comp/modal/Modal4.vue
Normal file
@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<BasicModal v-bind="$attrs" @register="register" title="Modal Title" @visible-change="handleVisibleChange">
|
||||
<div class="pt-3px pr-3px">
|
||||
<BasicForm @register="registerForm" :model="model" />
|
||||
</div>
|
||||
</BasicModal>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, nextTick } from 'vue';
|
||||
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||
import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
|
||||
|
||||
const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'field1',
|
||||
component: 'Input',
|
||||
label: '字段1',
|
||||
colProps: {
|
||||
span: 24,
|
||||
},
|
||||
defaultValue: '111',
|
||||
},
|
||||
{
|
||||
field: 'field2',
|
||||
component: 'Input',
|
||||
label: '字段2',
|
||||
colProps: {
|
||||
span: 24,
|
||||
},
|
||||
},
|
||||
];
|
||||
export default defineComponent({
|
||||
components: { BasicModal, BasicForm },
|
||||
props: {
|
||||
userData: { type: Object },
|
||||
},
|
||||
setup(props) {
|
||||
const modelRef = ref({});
|
||||
const [
|
||||
registerForm,
|
||||
{
|
||||
// setFieldsValue,
|
||||
// setProps
|
||||
},
|
||||
] = useForm({
|
||||
labelWidth: 120,
|
||||
schemas,
|
||||
showActionButtonGroup: false,
|
||||
actionColOptions: {
|
||||
span: 24,
|
||||
},
|
||||
});
|
||||
|
||||
const [register] = useModalInner((data) => {
|
||||
data && onDataReceive(data);
|
||||
});
|
||||
|
||||
function onDataReceive(data) {
|
||||
console.log('Data Received', data);
|
||||
// 方式1;
|
||||
// setFieldsValue({
|
||||
// field2: data.data,
|
||||
// field1: data.info,
|
||||
// });
|
||||
|
||||
// // 方式2
|
||||
modelRef.value = { field2: data.data, field1: data.info };
|
||||
|
||||
// setProps({
|
||||
// model:{ field2: data.data, field1: data.info }
|
||||
// })
|
||||
}
|
||||
|
||||
function handleVisibleChange(v) {
|
||||
v && props.userData && nextTick(() => onDataReceive(props.userData));
|
||||
}
|
||||
|
||||
return { register, schemas, registerForm, model: modelRef, handleVisibleChange };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
112
jeecgboot-vue3/src/views/demo/comp/modal/index.vue
Normal file
112
jeecgboot-vue3/src/views/demo/comp/modal/index.vue
Normal file
@ -0,0 +1,112 @@
|
||||
<template>
|
||||
<PageWrapper title="modal组件使用示例">
|
||||
<Alert
|
||||
message="使用 useModal 进行弹窗操作,默认可以拖动,可以通过 draggable
|
||||
参数进行控制是否可以拖动/全屏,并演示了在Modal内动态加载内容并自动调整高度"
|
||||
show-icon
|
||||
/>
|
||||
<a-button type="primary" class="my-4" @click="openModalLoading"> 打开弹窗,加载动态数据并自动调整高度(默认可以拖动/全屏) </a-button>
|
||||
|
||||
<Alert message="内外同时同时显示隐藏" show-icon />
|
||||
<a-button type="primary" class="my-4" @click="openModal2"> 打开弹窗</a-button>
|
||||
<Alert message="自适应高度" show-icon />
|
||||
<a-button type="primary" class="my-4" @click="openModal3"> 打开弹窗</a-button>
|
||||
|
||||
<Alert message="内外数据交互" show-icon />
|
||||
<a-button type="primary" class="my-4" @click="send"> 打开弹窗并传递数据</a-button>
|
||||
|
||||
<Alert message="使用动态组件的方式在页面内使用多个弹窗" show-icon />
|
||||
<a-space>
|
||||
<a-button type="primary" class="my-4" @click="openTargetModal(1)"> 打开弹窗1</a-button>
|
||||
<a-button type="primary" class="my-4" @click="openTargetModal(2)"> 打开弹窗2</a-button>
|
||||
<a-button type="primary" class="my-4" @click="openTargetModal(3)"> 打开弹窗3</a-button>
|
||||
<a-button type="primary" class="my-4" @click="openTargetModal(4)"> 打开弹窗4</a-button>
|
||||
</a-space>
|
||||
|
||||
<component :is="currentModal" v-model:visible="modalVisible" :userData="userData" />
|
||||
|
||||
<Modal1 @register="register1" :minHeight="100" />
|
||||
<Modal2 @register="register2" />
|
||||
<Modal3 @register="register3" />
|
||||
<Modal4 @register="register4" />
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, shallowRef, ComponentOptions, ref, nextTick } from 'vue';
|
||||
import { Alert, Space } from 'ant-design-vue';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import Modal1 from './Modal1.vue';
|
||||
import Modal2 from './Modal2.vue';
|
||||
import Modal3 from './Modal3.vue';
|
||||
import Modal4 from './Modal4.vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { Alert, Modal1, Modal2, Modal3, Modal4, PageWrapper, ASpace: Space },
|
||||
setup() {
|
||||
const currentModal = shallowRef<Nullable<ComponentOptions>>(null);
|
||||
const [register1, { openModal: openModal1 }] = useModal();
|
||||
const [register2, { openModal: openModal2 }] = useModal();
|
||||
const [register3, { openModal: openModal3 }] = useModal();
|
||||
const [register4, { openModal: openModal4 }] = useModal();
|
||||
const modalVisible = ref<Boolean>(false);
|
||||
const userData = ref<any>(null);
|
||||
|
||||
function send() {
|
||||
openModal4(true, {
|
||||
data: 'content',
|
||||
info: 'Info',
|
||||
});
|
||||
}
|
||||
|
||||
function openModalLoading() {
|
||||
openModal1(true);
|
||||
// setModalProps({ loading: true });
|
||||
// setTimeout(() => {
|
||||
// setModalProps({ loading: false });
|
||||
// }, 2000);
|
||||
}
|
||||
|
||||
function openTargetModal(index) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
currentModal.value = Modal1;
|
||||
break;
|
||||
case 2:
|
||||
currentModal.value = Modal2;
|
||||
break;
|
||||
case 3:
|
||||
currentModal.value = Modal3;
|
||||
break;
|
||||
default:
|
||||
currentModal.value = Modal4;
|
||||
break;
|
||||
}
|
||||
nextTick(() => {
|
||||
// `useModal` not working with dynamic component
|
||||
// passing data through `userData` prop
|
||||
userData.value = { data: Math.random(), info: 'Info222' };
|
||||
// open the target modal
|
||||
modalVisible.value = true;
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
register1,
|
||||
openModal1,
|
||||
register2,
|
||||
openModal2,
|
||||
register3,
|
||||
openModal3,
|
||||
register4,
|
||||
openModal4,
|
||||
modalVisible,
|
||||
userData,
|
||||
openTargetModal,
|
||||
send,
|
||||
currentModal,
|
||||
openModalLoading,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
117
jeecgboot-vue3/src/views/demo/comp/qrcode/index.vue
Normal file
117
jeecgboot-vue3/src/views/demo/comp/qrcode/index.vue
Normal file
@ -0,0 +1,117 @@
|
||||
<template>
|
||||
<PageWrapper title="二维码组件使用示例">
|
||||
<div class="flex flex-wrap">
|
||||
<CollapseContainer title="基础示例" :canExpan="true" class="text-center mb-6 qrcode-demo-item">
|
||||
<QrCode :value="qrCodeUrl" />
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="渲染成img标签示例" class="text-center mb-6 qrcode-demo-item">
|
||||
<QrCode :value="qrCodeUrl" tag="img" />
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="配置样式示例" class="text-center mb-6 qrcode-demo-item">
|
||||
<QrCode
|
||||
:value="qrCodeUrl"
|
||||
:options="{
|
||||
color: { dark: '#55D187' },
|
||||
}"
|
||||
/>
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="本地logo示例" class="text-center mb-6 qrcode-demo-item">
|
||||
<QrCode :value="qrCodeUrl" :logo="LogoImg" />
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="在线logo示例" class="text-center mb-6 qrcode-demo-item">
|
||||
<QrCode
|
||||
:value="qrCodeUrl"
|
||||
logo="http://jeecg.com/images/logo.png"
|
||||
:options="{
|
||||
color: { dark: '#55D187' },
|
||||
}"
|
||||
/>
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="logo配置示例" class="text-center mb-6 qrcode-demo-item">
|
||||
<QrCode
|
||||
:value="qrCodeUrl"
|
||||
:logo="{
|
||||
src: 'http://jeecg.com/images/logo.png',
|
||||
logoSize: 0.2,
|
||||
borderSize: 0.05,
|
||||
borderRadius: 50,
|
||||
bgColor: 'blue',
|
||||
}"
|
||||
/>
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="下载示例" class="text-center qrcode-demo-item">
|
||||
<QrCode :value="qrCodeUrl" ref="qrRef" :logo="LogoImg" />
|
||||
<a-button class="mb-2" type="primary" @click="download"> 下载 </a-button>
|
||||
<div class="msg"> (在线logo会导致图片跨域,需要下载图片需要自行解决跨域问题) </div>
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="配置大小示例" class="text-center qrcode-demo-item">
|
||||
<QrCode :value="qrCodeUrl" :width="300" />
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="扩展绘制示例" class="text-center qrcode-demo-item">
|
||||
<QrCode :value="qrCodeUrl" :width="200" :options="{ margin: 5 }" ref="qrDiyRef" :logo="LogoImg" @done="onQrcodeDone" />
|
||||
<a-button class="mb-2" type="primary" @click="downloadDiy"> 下载 </a-button>
|
||||
<div class="msg"> 要进行扩展绘制则不能将tag设为img </div>
|
||||
</CollapseContainer>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, unref } from 'vue';
|
||||
import { QrCode, QrCodeActionType } from '/@/components/Qrcode/index';
|
||||
import LogoImg from '/@/assets/images/logo.png';
|
||||
import { CollapseContainer } from '/@/components/Container/index';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
const qrCodeUrl = 'https://www.vvbin.cn';
|
||||
export default defineComponent({
|
||||
components: { CollapseContainer, QrCode, PageWrapper },
|
||||
setup() {
|
||||
const qrRef = ref<Nullable<QrCodeActionType>>(null);
|
||||
const qrDiyRef = ref<Nullable<QrCodeActionType>>(null);
|
||||
function download() {
|
||||
const qrEl = unref(qrRef);
|
||||
if (!qrEl) return;
|
||||
qrEl.download('文件名');
|
||||
}
|
||||
function downloadDiy() {
|
||||
const qrEl = unref(qrDiyRef);
|
||||
if (!qrEl) return;
|
||||
qrEl.download('Qrcode');
|
||||
}
|
||||
|
||||
function onQrcodeDone({ ctx }: any) {
|
||||
if (ctx instanceof CanvasRenderingContext2D) {
|
||||
// 额外绘制
|
||||
ctx.fillStyle = 'black';
|
||||
ctx.font = '16px "微软雅黑"';
|
||||
ctx.textBaseline = 'bottom';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.fillText('你帅你先扫', 100, 195, 200);
|
||||
}
|
||||
}
|
||||
return {
|
||||
onQrcodeDone,
|
||||
qrCodeUrl,
|
||||
LogoImg,
|
||||
download,
|
||||
downloadDiy,
|
||||
qrRef,
|
||||
qrDiyRef,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style scoped>
|
||||
.qrcode-demo-item {
|
||||
width: 30%;
|
||||
margin-right: 1%;
|
||||
}
|
||||
</style>
|
||||
59
jeecgboot-vue3/src/views/demo/comp/scroll/Action.vue
Normal file
59
jeecgboot-vue3/src/views/demo/comp/scroll/Action.vue
Normal file
@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<PageWrapper title="滚动组件函数示例" content="基于el-scrollbar">
|
||||
<div class="my-4">
|
||||
<a-button @click="scrollTo(100)" class="mr-2"> 滚动到100px位置 </a-button>
|
||||
<a-button @click="scrollTo(800)" class="mr-2"> 滚动到800px位置 </a-button>
|
||||
<a-button @click="scrollTo(0)" class="mr-2"> 滚动到顶部 </a-button>
|
||||
<a-button @click="scrollBottom()" class="mr-2"> 滚动到底部 </a-button>
|
||||
</div>
|
||||
<div class="scroll-wrap">
|
||||
<ScrollContainer class="mt-4" ref="scrollRef">
|
||||
<ul class="p-3">
|
||||
<template v-for="index in 100" :key="index">
|
||||
<li class="p-2" :style="{ border: '1px solid #eee' }">
|
||||
{{ index }}
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</ScrollContainer>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, unref } from 'vue';
|
||||
import { ScrollContainer, ScrollActionType } from '/@/components/Container/index';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { ScrollContainer, PageWrapper },
|
||||
setup() {
|
||||
const scrollRef = ref<Nullable<ScrollActionType>>(null);
|
||||
const getScroll = () => {
|
||||
const scroll = unref(scrollRef);
|
||||
if (!scroll) {
|
||||
throw new Error('scroll is Null');
|
||||
}
|
||||
return scroll;
|
||||
};
|
||||
|
||||
function scrollTo(top: number) {
|
||||
getScroll().scrollTo(top);
|
||||
}
|
||||
function scrollBottom() {
|
||||
getScroll().scrollBottom();
|
||||
}
|
||||
return {
|
||||
scrollTo,
|
||||
scrollRef,
|
||||
scrollBottom,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.scroll-wrap {
|
||||
width: 50%;
|
||||
height: 300px;
|
||||
background-color: @component-background;
|
||||
}
|
||||
</style>
|
||||
64
jeecgboot-vue3/src/views/demo/comp/scroll/VirtualScroll.vue
Normal file
64
jeecgboot-vue3/src/views/demo/comp/scroll/VirtualScroll.vue
Normal file
@ -0,0 +1,64 @@
|
||||
<template>
|
||||
<PageWrapper class="virtual-scroll-demo">
|
||||
<Divider>基础滚动示例</Divider>
|
||||
<div class="virtual-scroll-demo-wrap">
|
||||
<VScroll :itemHeight="41" :items="data" :height="300" :width="300">
|
||||
<template #default="{ item }">
|
||||
<div class="virtual-scroll-demo__item">
|
||||
{{ item.title }}
|
||||
</div>
|
||||
</template>
|
||||
</VScroll>
|
||||
</div>
|
||||
|
||||
<Divider>即使不可见,也预先加载50条数据,防止空白</Divider>
|
||||
<div class="virtual-scroll-demo-wrap">
|
||||
<VScroll :itemHeight="41" :items="data" :height="300" :width="300" :bench="50">
|
||||
<template #default="{ item }">
|
||||
<div class="virtual-scroll-demo__item">
|
||||
{{ item.title }}
|
||||
</div>
|
||||
</template>
|
||||
</VScroll>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { VScroll } from '/@/components/VirtualScroll/index';
|
||||
|
||||
import { Divider } from 'ant-design-vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
const data: Recordable[] = (() => {
|
||||
const arr: Recordable[] = [];
|
||||
for (let index = 1; index < 20000; index++) {
|
||||
arr.push({
|
||||
title: '列表项' + index,
|
||||
});
|
||||
}
|
||||
return arr;
|
||||
})();
|
||||
export default defineComponent({
|
||||
components: { VScroll: VScroll, Divider, PageWrapper },
|
||||
setup() {
|
||||
return { data: data };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.virtual-scroll-demo {
|
||||
&-wrap {
|
||||
display: flex;
|
||||
margin: 0 30%;
|
||||
background-color: @component-background;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
&__item {
|
||||
height: 40px;
|
||||
padding: 0 20px;
|
||||
line-height: 40px;
|
||||
border-bottom: 1px solid @border-color-base;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
31
jeecgboot-vue3/src/views/demo/comp/scroll/index.vue
Normal file
31
jeecgboot-vue3/src/views/demo/comp/scroll/index.vue
Normal file
@ -0,0 +1,31 @@
|
||||
<template>
|
||||
<PageWrapper title="滚动组件示例" content="基于el-scrollbar">
|
||||
<div class="scroll-wrap">
|
||||
<ScrollContainer class="mt-4">
|
||||
<ul class="p-3">
|
||||
<template v-for="index in 100" :key="index">
|
||||
<li class="p-2" :style="{ border: '1px solid #eee' }">
|
||||
{{ index }}
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</ScrollContainer>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { ScrollContainer } from '/@/components/Container/index';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { ScrollContainer, PageWrapper },
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.scroll-wrap {
|
||||
width: 50%;
|
||||
height: 300px;
|
||||
background-color: @component-background;
|
||||
}
|
||||
</style>
|
||||
32
jeecgboot-vue3/src/views/demo/comp/strength-meter/index.vue
Normal file
32
jeecgboot-vue3/src/views/demo/comp/strength-meter/index.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<PageWrapper title="密码强度校验组件">
|
||||
<div class="flex justify-center">
|
||||
<div class="demo-wrap p-10">
|
||||
<StrengthMeter placeholder="默认" />
|
||||
<StrengthMeter placeholder="禁用" disabled />
|
||||
<br />
|
||||
<StrengthMeter placeholder="隐藏input" :show-input="false" value="!@#qwe12345" />
|
||||
</div>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { StrengthMeter } from '/@/components/StrengthMeter';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
StrengthMeter,
|
||||
PageWrapper,
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.demo-wrap {
|
||||
width: 50%;
|
||||
background-color: @component-background;
|
||||
border-radius: 10px;
|
||||
}
|
||||
</style>
|
||||
44
jeecgboot-vue3/src/views/demo/comp/time/index.vue
Normal file
44
jeecgboot-vue3/src/views/demo/comp/time/index.vue
Normal file
@ -0,0 +1,44 @@
|
||||
<template>
|
||||
<PageWrapper title="时间组件示例">
|
||||
<CollapseContainer title="基础示例">
|
||||
<Time :value="time1" />
|
||||
<br />
|
||||
<Time :value="time2" />
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="定时更新" class="my-4">
|
||||
<Time :value="now" :step="1" />
|
||||
<br />
|
||||
<Time :value="now" :step="5" />
|
||||
</CollapseContainer>
|
||||
|
||||
<CollapseContainer title="定时更新">
|
||||
<Time :value="now" mode="date" />
|
||||
<br />
|
||||
<Time :value="now" mode="datetime" />
|
||||
<br />
|
||||
<Time :value="now" />
|
||||
</CollapseContainer>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, toRefs } from 'vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { Time } from '/@/components/Time';
|
||||
import { CollapseContainer } from '/@/components/Container/index';
|
||||
|
||||
export default defineComponent({
|
||||
components: { PageWrapper, Time, CollapseContainer },
|
||||
setup() {
|
||||
const now = new Date().getTime();
|
||||
const state = reactive({
|
||||
time1: now - 60 * 3 * 1000,
|
||||
time2: now - 86400 * 3 * 1000,
|
||||
});
|
||||
return {
|
||||
...toRefs(state),
|
||||
now,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
91
jeecgboot-vue3/src/views/demo/comp/transition/index.vue
Normal file
91
jeecgboot-vue3/src/views/demo/comp/transition/index.vue
Normal file
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<PageWrapper title="动画组件示例">
|
||||
<div class="flex">
|
||||
<Select :options="options" v-model:value="value" placeholder="选择动画" :style="{ width: '150px' }" />
|
||||
<a-button type="primary" class="ml-4" @click="start"> start </a-button>
|
||||
</div>
|
||||
<component :is="`${value}Transition`">
|
||||
<div class="box" v-show="show"></div>
|
||||
</component>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { Select } from 'ant-design-vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import {
|
||||
FadeTransition,
|
||||
ScaleTransition,
|
||||
SlideYTransition,
|
||||
ScrollYTransition,
|
||||
SlideYReverseTransition,
|
||||
ScrollYReverseTransition,
|
||||
SlideXTransition,
|
||||
ScrollXTransition,
|
||||
SlideXReverseTransition,
|
||||
ScrollXReverseTransition,
|
||||
ScaleRotateTransition,
|
||||
ExpandXTransition,
|
||||
ExpandTransition,
|
||||
} from '/@/components/Transition';
|
||||
|
||||
const transitionList = [
|
||||
'Fade',
|
||||
'Scale',
|
||||
'SlideY',
|
||||
'ScrollY',
|
||||
'SlideYReverse',
|
||||
'ScrollYReverse',
|
||||
'SlideX',
|
||||
'ScrollX',
|
||||
'SlideXReverse',
|
||||
'ScrollXReverse',
|
||||
'ScaleRotate',
|
||||
'ExpandX',
|
||||
'Expand',
|
||||
];
|
||||
const options = transitionList.map((item) => ({
|
||||
label: item,
|
||||
value: item,
|
||||
key: item,
|
||||
}));
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
Select,
|
||||
PageWrapper,
|
||||
FadeTransition,
|
||||
ScaleTransition,
|
||||
SlideYTransition,
|
||||
ScrollYTransition,
|
||||
SlideYReverseTransition,
|
||||
ScrollYReverseTransition,
|
||||
SlideXTransition,
|
||||
ScrollXTransition,
|
||||
SlideXReverseTransition,
|
||||
ScrollXReverseTransition,
|
||||
ScaleRotateTransition,
|
||||
ExpandXTransition,
|
||||
ExpandTransition,
|
||||
},
|
||||
setup() {
|
||||
const value = ref('Fade');
|
||||
const show = ref(true);
|
||||
function start() {
|
||||
show.value = false;
|
||||
setTimeout(() => {
|
||||
show.value = true;
|
||||
}, 300);
|
||||
}
|
||||
return { options, value, start, show };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.box {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
margin-top: 20px;
|
||||
background-color: rgb(126, 170, 236);
|
||||
}
|
||||
</style>
|
||||
54
jeecgboot-vue3/src/views/demo/comp/upload/index.vue
Normal file
54
jeecgboot-vue3/src/views/demo/comp/upload/index.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<PageWrapper title="上传组件示例">
|
||||
<a-alert message="基础示例" />
|
||||
<BasicUpload :maxSize="20" :maxNumber="10" @change="handleChange" :api="uploadApi" class="my-5" :accept="['image/*']" />
|
||||
|
||||
<a-alert message="嵌入表单,加入表单校验" />
|
||||
|
||||
<BasicForm @register="register" class="my-5" />
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { BasicUpload } from '/@/components/Upload';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { BasicForm, FormSchema, useForm } from '/@/components/Form/index';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
import { Alert } from 'ant-design-vue';
|
||||
import { uploadApi } from '/@/api/sys/upload';
|
||||
|
||||
const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'field1',
|
||||
component: 'Upload',
|
||||
label: '字段1',
|
||||
colProps: {
|
||||
span: 8,
|
||||
},
|
||||
rules: [{ required: true, message: '请选择上传文件' }],
|
||||
componentProps: {
|
||||
api: uploadApi,
|
||||
},
|
||||
},
|
||||
];
|
||||
export default defineComponent({
|
||||
components: { BasicUpload, BasicForm, PageWrapper, [Alert.name]: Alert },
|
||||
setup() {
|
||||
const { createMessage } = useMessage();
|
||||
const [register] = useForm({
|
||||
labelWidth: 120,
|
||||
schemas,
|
||||
actionColOptions: {
|
||||
span: 16,
|
||||
},
|
||||
});
|
||||
return {
|
||||
handleChange: (list: string[]) => {
|
||||
createMessage.info(`已上传文件${JSON.stringify(list)}`);
|
||||
},
|
||||
uploadApi,
|
||||
register,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
33
jeecgboot-vue3/src/views/demo/comp/verify/Rotate.vue
Normal file
33
jeecgboot-vue3/src/views/demo/comp/verify/Rotate.vue
Normal file
@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<PageWrapper title="旋转校验示例">
|
||||
<div class="flex justify-center p-4 items-center bg-gray-700">
|
||||
<RotateDragVerify :src="img" ref="el" @success="handleSuccess" />
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { RotateDragVerify } from '/@/components/Verify/index';
|
||||
|
||||
import img from '/@/assets/images/header.jpg';
|
||||
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { RotateDragVerify, PageWrapper },
|
||||
setup() {
|
||||
const handleSuccess = () => {
|
||||
console.log('success!');
|
||||
};
|
||||
return {
|
||||
handleSuccess,
|
||||
img,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.bg-gray-700 {
|
||||
background-color: #4a5568;
|
||||
}
|
||||
</style>
|
||||
97
jeecgboot-vue3/src/views/demo/comp/verify/index.vue
Normal file
97
jeecgboot-vue3/src/views/demo/comp/verify/index.vue
Normal file
@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<PageWrapper title="拖动校验示例">
|
||||
<div class="flex justify-center p-4 items-center bg-gray-700">
|
||||
<BasicDragVerify ref="el1" @success="handleSuccess" />
|
||||
<a-button type="primary" class="ml-2" @click="handleBtnClick(el1)"> 还原 </a-button>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center p-4 items-center bg-gray-700">
|
||||
<BasicDragVerify ref="el2" @success="handleSuccess" circle />
|
||||
<a-button type="primary" class="ml-2" @click="handleBtnClick(el2)"> 还原 </a-button>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center p-4 items-center bg-gray-700">
|
||||
<BasicDragVerify
|
||||
ref="el3"
|
||||
@success="handleSuccess"
|
||||
text="拖动以进行校验"
|
||||
successText="校验成功"
|
||||
:barStyle="{
|
||||
backgroundColor: '#018ffb',
|
||||
}"
|
||||
/>
|
||||
<a-button type="primary" class="ml-2" @click="handleBtnClick(el3)"> 还原 </a-button>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center p-4 items-center bg-gray-700">
|
||||
<BasicDragVerify ref="el4" @success="handleSuccess">
|
||||
<template #actionIcon="isPassing">
|
||||
<BugOutlined v-if="isPassing" />
|
||||
<RightOutlined v-else />
|
||||
</template>
|
||||
</BasicDragVerify>
|
||||
<a-button type="primary" class="ml-2" @click="handleBtnClick(el4)"> 还原 </a-button>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center p-4 items-center bg-gray-700">
|
||||
<BasicDragVerify ref="el5" @success="handleSuccess">
|
||||
<template #text="isPassing">
|
||||
<div v-if="isPassing">
|
||||
<BugOutlined />
|
||||
成功
|
||||
</div>
|
||||
<div v-else>
|
||||
拖动
|
||||
<RightOutlined />
|
||||
</div>
|
||||
</template>
|
||||
</BasicDragVerify>
|
||||
<a-button type="primary" class="ml-2" @click="handleBtnClick(el5)"> 还原 </a-button>
|
||||
</div>
|
||||
</PageWrapper>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { BasicDragVerify, DragVerifyActionType, PassingData } from '/@/components/Verify/index';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { BugOutlined, RightOutlined } from '@ant-design/icons-vue';
|
||||
import { PageWrapper } from '/@/components/Page';
|
||||
|
||||
export default defineComponent({
|
||||
components: { BasicDragVerify, BugOutlined, RightOutlined, PageWrapper },
|
||||
setup() {
|
||||
const { createMessage } = useMessage();
|
||||
const el1 = ref<Nullable<DragVerifyActionType>>(null);
|
||||
const el2 = ref<Nullable<DragVerifyActionType>>(null);
|
||||
const el3 = ref<Nullable<DragVerifyActionType>>(null);
|
||||
const el4 = ref<Nullable<DragVerifyActionType>>(null);
|
||||
const el5 = ref<Nullable<DragVerifyActionType>>(null);
|
||||
|
||||
function handleSuccess(data: PassingData) {
|
||||
const { time } = data;
|
||||
createMessage.success(`校验成功,耗时${time}秒`);
|
||||
}
|
||||
|
||||
function handleBtnClick(elRef: Nullable<DragVerifyActionType>) {
|
||||
if (!elRef) {
|
||||
return;
|
||||
}
|
||||
elRef.resume();
|
||||
}
|
||||
return {
|
||||
handleSuccess,
|
||||
el1,
|
||||
el2,
|
||||
el3,
|
||||
el4,
|
||||
el5,
|
||||
handleBtnClick,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.bg-gray-700 {
|
||||
background-color: #4a5568;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,81 @@
|
||||
<!-- 标题与字段布局 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" @submit="handleSubmit" style="margin: 20px auto"/>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
label: '姓名',
|
||||
field: 'name',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '年龄',
|
||||
field: 'password',
|
||||
component: 'InputNumber',
|
||||
},
|
||||
{
|
||||
label: '生日',
|
||||
field: 'birthday',
|
||||
component: 'DatePicker',
|
||||
},
|
||||
{
|
||||
label: '头像',
|
||||
field: 'avatar',
|
||||
component: 'JImageUpload',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm] = useForm({
|
||||
//注册表单列
|
||||
schemas: formSchemas,
|
||||
showActionButtonGroup: false,
|
||||
actionColOptions: { span: 12 },
|
||||
//控制标题宽度占比
|
||||
labelCol: {
|
||||
xs: 2,
|
||||
sm: 2,
|
||||
md: 2,
|
||||
lg: 9,
|
||||
xl: 3,
|
||||
xxl: 2,
|
||||
},
|
||||
//控制组件宽度占比
|
||||
wrapperCol: {
|
||||
xs: 15,
|
||||
sm: 14,
|
||||
md: 16,
|
||||
lg: 17,
|
||||
xl: 19,
|
||||
xxl: 20,
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* 点击提交按钮的value值
|
||||
* @param values
|
||||
*/
|
||||
function handleSubmit(values: any) {
|
||||
console.log('提交按钮数据::::', values);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/** 时间和数字输入框样式 */
|
||||
:deep(.ant-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-picker) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,70 @@
|
||||
<!-- 固定label标题的宽度 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" @submit="handleSubmit" style="margin-top: 20px" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
label: '姓名',
|
||||
field: 'name',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '年龄',
|
||||
field: 'password',
|
||||
component: 'InputNumber',
|
||||
},
|
||||
{
|
||||
label: '生日',
|
||||
field: 'birthday',
|
||||
component: 'DatePicker',
|
||||
},
|
||||
{
|
||||
label: '头像',
|
||||
field: 'avatar',
|
||||
component: 'JImageUpload',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm] = useForm({
|
||||
//注册表单列
|
||||
schemas: formSchemas,
|
||||
showResetButton: false,
|
||||
submitButtonOptions: { text: '提交', preIcon: '' },
|
||||
actionColOptions: { span: 17 },
|
||||
//使用labelWidth控制标题宽度
|
||||
labelWidth: '150px',
|
||||
//使用labelCol的样式属性来控制标题宽度
|
||||
labelCol: { style: { width: '150px' } },
|
||||
//标题对齐方式(left:左对齐,right:右对齐),默认右对齐
|
||||
labelAlign: 'right',
|
||||
});
|
||||
|
||||
/**
|
||||
* 点击提交按钮的value值
|
||||
* @param values
|
||||
*/
|
||||
function handleSubmit(values: any) {
|
||||
console.log('提交按钮数据::::', values);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/** 时间和数字输入框样式 */
|
||||
:deep(.ant-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-picker) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
143
jeecgboot-vue3/src/views/demo/document/form/BasicFormAdd.vue
Normal file
143
jeecgboot-vue3/src/views/demo/document/form/BasicFormAdd.vue
Normal file
@ -0,0 +1,143 @@
|
||||
<!-- 动态增减表单 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px;" @submit="handleSubmit">
|
||||
<!-- 添加input的插槽 -->
|
||||
<template #addForm="{ field }">
|
||||
<a-button v-if="Number(field) === 0" @click="addField" style="width: 50px">+</a-button>
|
||||
<a-button v-if="Number(field) > 0" @click="delField(field)" style="width: 50px">-</a-button>
|
||||
</template>
|
||||
</BasicForm>
|
||||
<!-- <div style="margin: 20px auto; text-align: center">
|
||||
<a-button @click="addField">添加表单项</a-button>
|
||||
</div>-->
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
import { CollapseContainer } from '/@/components/Container';
|
||||
import { ref } from 'vue';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
field: 'name1',
|
||||
label: '姓名1',
|
||||
component: 'Input',
|
||||
// ifShow:false,
|
||||
colProps: {
|
||||
span: 8,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'age1',
|
||||
label: '年龄1',
|
||||
component: 'InputNumber',
|
||||
// ifShow:false,
|
||||
colProps: {
|
||||
span: 8,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: '0',
|
||||
component: 'Input',
|
||||
// ifShow:false,
|
||||
label: ' ',
|
||||
colProps: {
|
||||
span: 8,
|
||||
},
|
||||
slot: 'addForm',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
* appendSchemaByField:增加表单项(字段)
|
||||
*
|
||||
* removeSchemaByFiled:减少表单项(字段)
|
||||
*/
|
||||
const [registerForm, { appendSchemaByField, removeSchemaByFiled }] = useForm({
|
||||
schemas: formSchemas,
|
||||
showResetButton: false,
|
||||
labelWidth: '150px',
|
||||
// showSubmitButton:false
|
||||
submitButtonOptions: { text: '提交', preIcon: '' },
|
||||
actionColOptions: { span: 17 },
|
||||
});
|
||||
|
||||
//组件个数
|
||||
let n = ref<number>(2);
|
||||
|
||||
/**
|
||||
* 添加字段
|
||||
* appendSchemaByField类型: ( schema: FormSchema, prefixField: string | undefined, first?: boolean | undefined ) => Promise<void>
|
||||
* 说明: 插入到指定 filed 后面,如果没传指定 field,则插入到最后,当 first = true 时插入到第一个位置
|
||||
*/
|
||||
async function addField() {
|
||||
//添加表单字段,里面为schemas对应的属性,可自行配置
|
||||
await appendSchemaByField(
|
||||
{
|
||||
field: `name${n.value}`,
|
||||
component: 'Input',
|
||||
label: '字段' + n.value,
|
||||
colProps: {
|
||||
span: 8,
|
||||
},
|
||||
},
|
||||
''
|
||||
);
|
||||
await appendSchemaByField(
|
||||
{
|
||||
field: `sex${n.value}`,
|
||||
component: 'InputNumber',
|
||||
label: '字段' + n.value,
|
||||
colProps: {
|
||||
span: 8,
|
||||
},
|
||||
},
|
||||
''
|
||||
);
|
||||
|
||||
await appendSchemaByField(
|
||||
{
|
||||
field: `${n.value}`,
|
||||
component: 'Input',
|
||||
label: ' ',
|
||||
colProps: {
|
||||
span: 8,
|
||||
},
|
||||
slot: 'addForm',
|
||||
},
|
||||
''
|
||||
);
|
||||
n.value++;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除字段
|
||||
* 类型: (field: string | string[]) => Promise<void>
|
||||
* 说明: 根据 field 删除 Schema
|
||||
* @param field 当前字段名称
|
||||
*/
|
||||
function delField(field) {
|
||||
//移除指定字段
|
||||
removeSchemaByFiled([`name${field}`, `sex${field}`, `${field}`]);
|
||||
n.value--;
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击提交按钮的value值
|
||||
* @param values
|
||||
*/
|
||||
function handleSubmit(values: any) {
|
||||
console.log('提交按钮数据::::', values);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/** 数字输入框样式 */
|
||||
:deep(.ant-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
66
jeecgboot-vue3/src/views/demo/document/form/BasicFormBtn.vue
Normal file
66
jeecgboot-vue3/src/views/demo/document/form/BasicFormBtn.vue
Normal file
@ -0,0 +1,66 @@
|
||||
<!-- 操作按钮 -->
|
||||
<template>
|
||||
<div style="margin: 20px auto; text-align: center">
|
||||
<!-- 通过setProps 可以设置 userForm 中的属性 -->
|
||||
<!-- showActionButtonGroup 显示或者隐藏查询、重置按钮 -->
|
||||
<a-button @click="setProps({ showActionButtonGroup: false })" class="mr-2"> 隐藏操作按钮 </a-button>
|
||||
<a-button @click="setProps({ showActionButtonGroup: true })" class="mr-2"> 显示操作按钮 </a-button>
|
||||
<!-- showActionButtonGroup 显示或者隐藏重置按钮 -->
|
||||
<a-button @click="setProps({ showResetButton: false })" class="mr-2"> 隐藏重置按钮 </a-button>
|
||||
<a-button @click="setProps({ showResetButton: true })" class="mr-2"> 显示重置按钮 </a-button>
|
||||
<!-- showActionButtonGroup 显示或者隐藏查询按钮 -->
|
||||
<a-button @click="setProps({ showSubmitButton: false })" class="mr-2"> 隐藏查询按钮 </a-button>
|
||||
<a-button @click="setProps({ showSubmitButton: true })" class="mr-2"> 显示查询按钮 </a-button>
|
||||
</div>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" @submit="handleSubmit" style="margin-top: 50px; margin-left: 50px" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
import { CollapseContainer } from '/@/components/Container';
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
* setProps方法可以动态设置useForm中的属性
|
||||
*/
|
||||
const [registerForm, { setProps }] = useForm({
|
||||
//自定义查询按钮的文本和图标
|
||||
submitButtonOptions: { text: '查询', preIcon: '' },
|
||||
//自定义重置按钮的文本和图标
|
||||
resetButtonOptions: { text: '重置', preIcon: '' },
|
||||
//操作按钮的位置
|
||||
actionColOptions: { span: 17 },
|
||||
//提交按钮的自定义事件
|
||||
submitFunc: customSubmitFunc,
|
||||
//重置按钮的自定义时间
|
||||
resetFunc: customSubmitFunc,
|
||||
//显示操作按钮
|
||||
showActionButtonGroup: true,
|
||||
});
|
||||
|
||||
/**
|
||||
* 查询按钮点击事件
|
||||
*/
|
||||
async function customSubmitFunc() {
|
||||
console.log('查询按钮点击事件,此处处理查询按钮的逻辑');
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置按钮点击事件
|
||||
*/
|
||||
async function customResetFunc() {
|
||||
console.log('重置按钮点击事件,此处处理重置按钮的逻辑');
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击提交按钮的value值
|
||||
* @param values
|
||||
*/
|
||||
function handleSubmit(values: any) {
|
||||
console.log('提交按钮数据::::', values);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,95 @@
|
||||
<!-- 操作禁用表单 -->
|
||||
<template>
|
||||
<div style="margin: 20px auto; text-align: center">
|
||||
<!-- all 触发或清空所有验证,visitor 只触发或者清空来访人员验证 -->
|
||||
<a-button @click="triggerFormRule('all')" class="mr-2"> 触发表单验证 </a-button>
|
||||
<a-button @click="cancelFormRule('all')" class="mr-2"> 清空表单验证 </a-button>
|
||||
<a-button @click="triggerFormRule('visitor')" class="mr-2"> 只验证来访人员 </a-button>
|
||||
<a-button @click="cancelFormRule('visitor')" class="mr-2"> 只清空来访人员验证 </a-button>
|
||||
</div>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px;" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
field: 'visitor',
|
||||
label: '来访人员',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'accessed',
|
||||
label: '来访日期',
|
||||
component: 'DatePicker',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'phone',
|
||||
label: '来访人手机号',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
* clearValidate 清除所有验证,支持取消验证其中几个字段 如 clearValidate(['visitor',...])
|
||||
* validate 验证所有,支持验证其中几个字段,validate(['visitor',...])
|
||||
* validateFields 只支持验证其中几个字段,如validateFields(['visitor',...])
|
||||
*/
|
||||
const [registerForm, { clearValidate, validateFields, validate }] = useForm({
|
||||
schemas: formSchemas,
|
||||
labelWidth: '150px',
|
||||
//隐藏操作按钮
|
||||
showActionButtonGroup: false,
|
||||
//默认聚焦第一个,只支持input
|
||||
autoFocusFirstItem: true,
|
||||
});
|
||||
|
||||
/**
|
||||
* 触发表单验证
|
||||
* @param type all 所有验证 visitor 只验证来访人员
|
||||
*/
|
||||
async function triggerFormRule(type) {
|
||||
if (type == 'all') {
|
||||
//触发所有验证
|
||||
await validate();
|
||||
} else {
|
||||
//触发来访人员验证
|
||||
//visitor 来访人员的对应formSchemas field字段
|
||||
await validateFields(['visitor']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 触发表单验证
|
||||
* @param type all 所有验证 visitor 只验证来访人员
|
||||
*/
|
||||
async function cancelFormRule(type) {
|
||||
if (type == 'all') {
|
||||
//取消全部验证
|
||||
await clearValidate();
|
||||
} else {
|
||||
//只取消来访人员的验证
|
||||
//visitor 来访人员的对应formSchemas field字段
|
||||
await clearValidate(['visitor']);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/** 时间和数字输入框样式 */
|
||||
:deep(.ant-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-picker) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,58 @@
|
||||
<!-- 操作禁用表单 -->
|
||||
<template>
|
||||
<div style="margin: 20px auto; text-align: center">
|
||||
<!-- 通过setProps 可以设置 userForm 中的属性 -->
|
||||
<!-- 表单大小,默认为 default -->
|
||||
<a-button @click="setProps({ size: 'large' })" class="mr-2"> 更改大小为最大 </a-button>
|
||||
<a-button @click="setProps({ size: 'default' })" class="mr-2"> 还原大小 </a-button>
|
||||
<a-button @click="setProps({ size: 'small' })" class="mr-2"> 更改大小为最小 </a-button>
|
||||
<!-- disabled表单禁用 -->
|
||||
<a-button @click="setProps({ disabled: true })" class="mr-2"> 禁用表单 </a-button>
|
||||
<a-button @click="setProps({ disabled: false })" class="mr-2"> 解除禁用 </a-button>
|
||||
<!-- compact 是否为紧凑表单 -->
|
||||
<a-button @click="setProps({ compact: true })" class="mr-2"> 紧凑表单 </a-button>
|
||||
<a-button @click="setProps({ compact: false })" class="mr-2"> 还原正常间距 </a-button>
|
||||
</div>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px;" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
import { CollapseContainer } from '/@/components/Container';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
field: 'visitor',
|
||||
label: '来访人员',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
field: 'accessed',
|
||||
label: '来访日期',
|
||||
component: 'DatePicker',
|
||||
},
|
||||
{
|
||||
field: 'phone',
|
||||
label: '来访人手机号',
|
||||
component: 'Input',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
* setProps方法可以动态设置useForm中的属性
|
||||
*/
|
||||
const [registerForm, { setProps }] = useForm({
|
||||
schemas: formSchemas,
|
||||
labelWidth: '150px',
|
||||
//隐藏操作按钮
|
||||
showActionButtonGroup: false,
|
||||
//默认聚焦第一个,只支持input
|
||||
autoFocusFirstItem: true,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,34 @@
|
||||
<!-- 操作表单值 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px;" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
import { schemas } from './example.data';
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm, { getFieldsValue, setFieldsValue, resetFields, validate }] = useForm({
|
||||
schemas: schemas,
|
||||
labelWidth: '150px',
|
||||
//隐藏操作按钮
|
||||
showActionButtonGroup: false,
|
||||
//默认聚焦第一个,只支持input
|
||||
autoFocusFirstItem: true,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/** 时间和数字输入框样式 */
|
||||
:deep(.ant-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-picker) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,63 @@
|
||||
<!-- 控件属性 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
label: '员工姓名',
|
||||
field: 'name',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
defaultValue: '张三',
|
||||
},
|
||||
{
|
||||
label: '性别',
|
||||
field: 'sex',
|
||||
component: 'Select',
|
||||
//填写组件的属性
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '男', value: 1 },
|
||||
{ label: '女', value: 2 },
|
||||
{ label: '未知', value: 3 },
|
||||
],
|
||||
},
|
||||
//默认值
|
||||
defaultValue: 3,
|
||||
},
|
||||
{
|
||||
label: '年龄',
|
||||
field: 'age',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '入职时间',
|
||||
subLabel: '( 选填 )',
|
||||
field: 'entryTime',
|
||||
component: 'TimePicker',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm] = useForm({
|
||||
//注册表单列
|
||||
schemas: formSchemas,
|
||||
labelWidth: '150px',
|
||||
showResetButton: false,
|
||||
submitButtonOptions: { text: '提交', preIcon: '' },
|
||||
actionColOptions: { span: 17 },
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,32 @@
|
||||
<!-- 自定义组件 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
field: 'custom',
|
||||
label: '自定义组件',
|
||||
//引入自定义组件
|
||||
component: 'JInput',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm] = useForm({
|
||||
//注册表单列
|
||||
schemas: formSchemas,
|
||||
labelWidth: '150px',
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,32 @@
|
||||
<!-- 操作表单值 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
import { schemas } from './exampleCustom.data';
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm, { getFieldsValue, setFieldsValue, resetFields, validate }] = useForm({
|
||||
schemas: schemas,
|
||||
labelWidth: '150px',
|
||||
//隐藏操作按钮
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/** 时间和数字输入框样式 */
|
||||
:deep(.ant-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-picker) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,64 @@
|
||||
<!-- 插槽 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px" @submit="handleSubmit">
|
||||
<!-- #name对应的是formSchemas对应slot(name)插槽 -->
|
||||
<template #name="{ model, field }">
|
||||
<JInput v-model:value="model[field]" />
|
||||
</template>
|
||||
</BasicForm>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
//引入CustomDemo自定义组件
|
||||
import JInput from "/@/components/Form/src/jeecg/components/JInput.vue";
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
field: 'name',
|
||||
label: '姓名',
|
||||
component: 'Input',
|
||||
slot:'name'
|
||||
},
|
||||
{
|
||||
field: 'phone',
|
||||
label: '联系方式',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
field: 'feedback',
|
||||
label: '问题反馈',
|
||||
component: 'InputTextArea',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm] = useForm({
|
||||
//注册表单列
|
||||
schemas: formSchemas,
|
||||
showResetButton: false,
|
||||
labelWidth: '150px',
|
||||
submitButtonOptions: { text: '提交', preIcon: '' },
|
||||
actionColOptions: { span: 17 },
|
||||
});
|
||||
|
||||
/**
|
||||
* 提交信息
|
||||
*/
|
||||
function handleSubmit(values) {
|
||||
console.log("values::",values);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.font-color {
|
||||
font-size: 13px;
|
||||
color: #a1a1a1;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,80 @@
|
||||
<!-- 动态表单验证 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px" @submit="handleSubmit" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
import { duplicateCheck } from '/@/views/system/user/user.api';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
field: 'visitor',
|
||||
label: '来访人员',
|
||||
component: 'Input',
|
||||
//自动触发检验,布尔类型
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'accessed',
|
||||
label: '来访日期',
|
||||
component: 'DatePicker',
|
||||
//支持获取当前值判断触发 values代表当前表单的值
|
||||
required: ({ values }) => {
|
||||
return !values.accessed;
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'phone',
|
||||
label: '来访人手机号',
|
||||
component: 'Input',
|
||||
//动态自定义正则,values: 当前表单的所有值
|
||||
dynamicRules: ({ values }) => {
|
||||
//需要return
|
||||
return [
|
||||
{
|
||||
//默认开启表单检验
|
||||
required: true,
|
||||
// value 当前手机号输入的值
|
||||
validator: (_, value) => {
|
||||
//需要return 一个Promise对象
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!value) {
|
||||
reject('请输入手机号!');
|
||||
}
|
||||
//验证手机号是否正确
|
||||
let reg = /^1[3456789]\d{9}$/;
|
||||
if (!reg.test(value)) {
|
||||
reject('请输入正确手机号!');
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm] = useForm({
|
||||
//注册表单列
|
||||
schemas: formSchemas,
|
||||
showResetButton: false,
|
||||
labelWidth: '150px',
|
||||
submitButtonOptions: { text: '提交', preIcon: '' },
|
||||
actionColOptions: { span: 17 },
|
||||
});
|
||||
|
||||
/**
|
||||
* 提交事件
|
||||
*/
|
||||
function handleSubmit(values: any) {}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,70 @@
|
||||
<!-- 字段显示与隐藏 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
field: 'id',
|
||||
label: '编号',
|
||||
component: 'Input',
|
||||
//隐藏id,css 控制,不会删除 dom(支持布尔类型 true和false。支持动态值判断,详情请见ifShow)
|
||||
show: false,
|
||||
},
|
||||
{
|
||||
field: 'evaluate',
|
||||
label: '对公司整体评价',
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '满意', value: '0' },
|
||||
{ label: '不满意', value: '1' },
|
||||
],
|
||||
},
|
||||
defaultValue: '0',
|
||||
},
|
||||
{
|
||||
field: 'describe',
|
||||
label: '不满意原因说明',
|
||||
component: 'InputTextArea',
|
||||
//ifShow和show属性一致,使用其中一个即可,values代表当前表单的值,js 控制,会删除 dom
|
||||
ifShow: ({ values }) => {
|
||||
return values.evaluate == '1';
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'satisfiedLevel',
|
||||
label: '满意度',
|
||||
component: 'Slider',
|
||||
componentProps: {
|
||||
tipFormatter: (value) => {
|
||||
return value + '%';
|
||||
},
|
||||
},
|
||||
//动态禁用,values代表当前表单的值,返回 true或false
|
||||
dynamicDisabled: ({ values }) => {
|
||||
return values.evaluate == '1';
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm] = useForm({
|
||||
//注册表单列
|
||||
schemas: formSchemas,
|
||||
showResetButton: false,
|
||||
labelWidth: '150px',
|
||||
submitButtonOptions: { text: '提交', preIcon: '' },
|
||||
actionColOptions: { span: 17 },
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,55 @@
|
||||
<!-- 字段标题提示及前缀 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
field: 'month',
|
||||
label: '当前月份',
|
||||
component: 'Input',
|
||||
suffix: '月',
|
||||
},
|
||||
{
|
||||
field: 'lateNumber',
|
||||
label: '迟到次数',
|
||||
component: 'InputNumber',
|
||||
//帮助信息:可以直接返回String(helpMessage:"迟到次数"),也可以获取表单值,动态填写
|
||||
helpMessage: ({ values }) => {
|
||||
return '当前迟到次数' + values.lateNumber + ', 扣款' + values.lateNumber * 50 + '元';
|
||||
},
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
field: 'lateReason',
|
||||
label: '迟到原因',
|
||||
component: 'Input',
|
||||
helpMessage: '什么原因耽误上班迟到',
|
||||
//自定义提示属性,需要结合helpMessage一起使用
|
||||
helpComponentProps: {
|
||||
maxWidth: '200px',
|
||||
color: '#66CCFF',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm] = useForm({
|
||||
//注册表单列
|
||||
schemas: formSchemas,
|
||||
showResetButton: false,
|
||||
labelWidth: '150px',
|
||||
submitButtonOptions: { text: '提交', preIcon: '' },
|
||||
actionColOptions: { span: 17 },
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
105
jeecgboot-vue3/src/views/demo/document/form/BasicFormFooter.vue
Normal file
105
jeecgboot-vue3/src/views/demo/document/form/BasicFormFooter.vue
Normal file
@ -0,0 +1,105 @@
|
||||
<!-- 自定义页脚 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px">
|
||||
<template #formHeader>
|
||||
<div style="margin: 0 auto 20px">
|
||||
<span>我是自定义按钮</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #formFooter>
|
||||
<div style="margin: 0 auto">
|
||||
<a-button type="primary" @click="save" class="mr-2"> 保存 </a-button>
|
||||
<a-button type="primary" @click="saveDraft" class="mr-2"> 保存草稿 </a-button>
|
||||
<a-button type="error" @click="reset" class="mr-2"> 重置 </a-button>
|
||||
</div>
|
||||
</template>
|
||||
</BasicForm>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
label: '员工姓名',
|
||||
field: 'name',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '性别',
|
||||
field: 'sex',
|
||||
component: 'Select',
|
||||
//填写组件的属性
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '男', value: 1 },
|
||||
{ label: '女', value: 2 },
|
||||
{ label: '未知', value: 3 },
|
||||
],
|
||||
},
|
||||
//默认值
|
||||
defaultValue: 3,
|
||||
},
|
||||
{
|
||||
label: '年龄',
|
||||
field: 'age',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '入职时间',
|
||||
subLabel: '( 选填 )',
|
||||
field: 'entryTime',
|
||||
component: 'TimePicker',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm, { validate, resetFields }] = useForm({
|
||||
schemas: formSchemas,
|
||||
labelWidth: '150px',
|
||||
//隐藏操作按钮
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
|
||||
/**
|
||||
* 保存
|
||||
*/
|
||||
async function save() {
|
||||
//使用useForm方法获取表单值
|
||||
let values = await validate();
|
||||
console.log(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存草稿
|
||||
*/
|
||||
async function saveDraft() {
|
||||
//使用useForm方法validate获取表单值
|
||||
let values = await validate();
|
||||
console.log(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置
|
||||
*/
|
||||
async function reset() {
|
||||
//使用useForm方法resetFields清空值
|
||||
await resetFields();
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/** 时间和数字输入框样式 */
|
||||
:deep(.ant-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-picker) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,63 @@
|
||||
<!-- 表单布局 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
label: '会议名称',
|
||||
field: 'name',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '参会地点',
|
||||
field: 'meetingLocation',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '参与人数',
|
||||
field: 'numberOfPart',
|
||||
component: 'InputNumber',
|
||||
},
|
||||
{
|
||||
label: '会议纪要',
|
||||
field: 'meetingMinutes',
|
||||
component: 'JUpload',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm] = useForm({
|
||||
//表单布局属性,支持(vertical,inline),默认为inline
|
||||
layout: 'inline',
|
||||
//注册表单列
|
||||
schemas: formSchemas,
|
||||
//不显示查询和重置按钮
|
||||
showActionButtonGroup: false,
|
||||
//默认row行配置,当 layout 为 inline 生效
|
||||
rowProps: { gutter: 24, justify: 'center', align: 'middle' },
|
||||
//全局col列占比(每列显示多少位),和schemas中的colProps属性一致
|
||||
baseColProps: { span: 12 },
|
||||
//row行的样式
|
||||
baseRowStyle: { width: '100%' },
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/** 时间和数字输入框样式 */
|
||||
:deep(.ant-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-picker) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,84 @@
|
||||
<!-- 弹出层表单 -->
|
||||
<template>
|
||||
<div style="margin: 20px auto">
|
||||
<a-button type="primary" @click="openPopup" class="mr-2"> 打开弹窗 </a-button>
|
||||
</div>
|
||||
<!-- 自定义弹窗组件 -->
|
||||
<BasicModal @register="registerModal" title="弹出层表单">
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" />
|
||||
</BasicModal>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
import { BasicModal } from '/@/components/Modal';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
label: '员工姓名',
|
||||
field: 'name',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '性别',
|
||||
field: 'sex',
|
||||
component: 'Select',
|
||||
//填写组件的属性
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '男', value: 1 },
|
||||
{ label: '女', value: 2 },
|
||||
{ label: '未知', value: 3 },
|
||||
],
|
||||
},
|
||||
//默认值
|
||||
defaultValue: 3,
|
||||
},
|
||||
{
|
||||
label: '年龄',
|
||||
field: 'age',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
label: '入职时间',
|
||||
subLabel: '( 选填 )',
|
||||
field: 'entryTime',
|
||||
component: 'TimePicker',
|
||||
},
|
||||
];
|
||||
|
||||
//BasicModal绑定注册;
|
||||
const [registerModal, { openModal }] = useModal();
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm, { validate, resetFields }] = useForm({
|
||||
schemas: formSchemas,
|
||||
//隐藏操作按钮
|
||||
showActionButtonGroup: false,
|
||||
});
|
||||
|
||||
/**
|
||||
* 打开弹窗
|
||||
*/
|
||||
async function openPopup() {
|
||||
//详见 BasicModal模块
|
||||
openModal(true, {});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/** 时间和数字输入框样式 */
|
||||
:deep(.ant-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-picker) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,90 @@
|
||||
<!-- 自定义渲染 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px">
|
||||
<!-- #phone对应的是formSchemas对应slot(phone)插槽 -->
|
||||
<template #phone="{ model, field }">
|
||||
<!-- 如果是组件需要进行双向绑定,model当前表单对象,field当前字段名称 -->
|
||||
<a-input v-model:value="model[field]" placeholder="请输入手机号" />
|
||||
<span class="font-color">请输入您的手机号,方便我们联系您</span>
|
||||
</template>
|
||||
<template #feedback="{ model, field }">
|
||||
<JEditor v-model:value="model[field]" placeholder="请输入问题反馈" />
|
||||
<span class="font-color">请您图文并茂,方便我们了解问题并及时反馈</span>
|
||||
</template>
|
||||
</BasicForm>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
import JEditor from '/@/components/Form/src/jeecg/components/JEditor.vue';
|
||||
import { h } from 'vue';
|
||||
import { Input } from 'ant-design-vue';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
field: 'productName',
|
||||
label: '商品名称',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
field: 'price',
|
||||
label: '价格',
|
||||
component: 'InputNumber',
|
||||
},
|
||||
{
|
||||
field: 'buyNums',
|
||||
label: '购买个数',
|
||||
component: 'InputNumber',
|
||||
//model 单签表单对象,field 当前字段
|
||||
render: ({ model, field }) => {
|
||||
//渲染自定义组件,以Input为例
|
||||
return h(Input, {
|
||||
placeholder: '请输入购买个数',
|
||||
value: model[field],
|
||||
style: { width: '100%' },
|
||||
type: 'number',
|
||||
onChange: (e: ChangeEvent) => {
|
||||
model[field] = e.target.value;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'describe',
|
||||
label: '描述',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
//渲染 values当前表单所有值
|
||||
render: ({ values }) => {
|
||||
let productName = values.productName?values.productName:'';
|
||||
let price = values.price ? values.price : 0;
|
||||
let buyNums = values.buyNums ? values.buyNums : 0;
|
||||
return '购买商品名称:' + productName + ', 总价格: ' + price * buyNums + '元';
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm] = useForm({
|
||||
//注册表单列
|
||||
schemas: formSchemas,
|
||||
showResetButton: false,
|
||||
labelWidth: '150px',
|
||||
submitButtonOptions: { text: '提交', preIcon: '' },
|
||||
actionColOptions: { span: 17 },
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/** 数字输入框样式 */
|
||||
:deep(.ant-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,58 @@
|
||||
<!-- 表单验证 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px" @submit="handleSubmit" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
field: 'visitor',
|
||||
label: '来访人员',
|
||||
component: 'Input',
|
||||
//自动触发检验,布尔类型
|
||||
required: true,
|
||||
//检验的时候不加上标题
|
||||
rulesMessageJoinLabel: false,
|
||||
},
|
||||
{
|
||||
field: 'accessed',
|
||||
label: '来访日期',
|
||||
component: 'DatePicker',
|
||||
//支持获取当前值判断触发 values代表当前表单的值
|
||||
required: ({ values }) => {
|
||||
return !values.accessed;
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'phone',
|
||||
label: '来访人手机号',
|
||||
component: 'Input',
|
||||
//支持正则表达式pattern 和 自定义提示信息 message
|
||||
rules: [{ required: false, message: '请输入正确的手机号', pattern: /^1[3456789]\d{9}$/ }],
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm] = useForm({
|
||||
//注册表单列
|
||||
schemas: formSchemas,
|
||||
showResetButton: false,
|
||||
labelWidth: '150px',
|
||||
submitButtonOptions: { text: '提交', preIcon: '' },
|
||||
actionColOptions: { span: 17 },
|
||||
});
|
||||
|
||||
/**
|
||||
* 提交事件
|
||||
*/
|
||||
function handleSubmit(values: any) {}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,99 @@
|
||||
<!-- 操作表单schemas配置 -->
|
||||
<template>
|
||||
<div style="margin: 20px auto; text-align: center">
|
||||
<a-button @click="updateFormSchemas" class="mr-2"> 更新字段属性 </a-button>
|
||||
<a-button @click="resetFormSchemas" class="mr-2"> 重置字段属性 </a-button>
|
||||
</div>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
field: 'visitor',
|
||||
label: '来访人员',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
disabled: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'accessed',
|
||||
label: '来访日期',
|
||||
component: 'DatePicker',
|
||||
ifShow: false,
|
||||
},
|
||||
{
|
||||
field: 'phone',
|
||||
label: '来访人手机号',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
* updateSchema 更新字段属性,支持schemas里面所有的配置
|
||||
* updateSchema([{ field: 'visitor', componentProps: { disabled: false },}, ... ]);
|
||||
* resetSchema 重置字段属性,支持schemas里面所有的配置
|
||||
* resetSchema([{ field: 'visitor',label: '来访人员',component: 'Input',},... ]);
|
||||
*/
|
||||
const [registerForm, { updateSchema, resetSchema }] = useForm({
|
||||
schemas: formSchemas,
|
||||
//隐藏操作按钮
|
||||
showActionButtonGroup: false,
|
||||
labelWidth: '150px',
|
||||
//默认聚焦第一个,只支持input
|
||||
autoFocusFirstItem: true,
|
||||
});
|
||||
|
||||
/**
|
||||
* 清除表单配置
|
||||
*/
|
||||
async function resetFormSchemas() {
|
||||
await resetSchema([
|
||||
{
|
||||
//字段必填
|
||||
field: 'visitor',
|
||||
label: '来访人员',
|
||||
component: 'Input',
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新表单配置
|
||||
*/
|
||||
async function updateFormSchemas() {
|
||||
//支持更新schemas里面所有的配置
|
||||
await updateSchema([
|
||||
{
|
||||
//字段必填
|
||||
field: 'visitor',
|
||||
componentProps: {
|
||||
disabled: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'accessed',
|
||||
ifShow: true,
|
||||
},
|
||||
]);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/** 时间和数字输入框样式 */
|
||||
:deep(.ant-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-picker) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
116
jeecgboot-vue3/src/views/demo/document/form/BasicFormSearch.vue
Normal file
116
jeecgboot-vue3/src/views/demo/document/form/BasicFormSearch.vue
Normal file
@ -0,0 +1,116 @@
|
||||
<!-- 查询区域 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" @submit="handleSubmit" style="margin-top: 20px" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
field: 'name',
|
||||
label: '姓名',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
field: 'hobby',
|
||||
label: '爱好',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
field: 'birthday',
|
||||
label: '生日',
|
||||
component: 'DatePicker',
|
||||
},
|
||||
{
|
||||
field: 'joinTime',
|
||||
label: '入职时间',
|
||||
component: 'RangePicker',
|
||||
componentProps: {
|
||||
valueType: 'Date',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'workYears',
|
||||
label: '工作年份',
|
||||
component: 'JRangeNumber',
|
||||
},
|
||||
{
|
||||
field: 'sex',
|
||||
label: '性别',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: [
|
||||
{
|
||||
label: '男',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '女',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'marital',
|
||||
label: '婚姻状况',
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
options: [
|
||||
{
|
||||
label: '未婚',
|
||||
value: '1',
|
||||
},
|
||||
{
|
||||
label: '已婚',
|
||||
value: '2',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm] = useForm({
|
||||
//将表单内时间区域的值映射成 2个字段, 'YYYY-MM-DD'日期格式化
|
||||
fieldMapToTime: [['joinTime', ['joinTime_begin', 'joinTime_end'], 'YYYY-MM-DD']],
|
||||
//注册表单列
|
||||
schemas: formSchemas,
|
||||
//是否显示展开收起按钮,默认false
|
||||
showAdvancedButton: true,
|
||||
//超过指定行数折叠,默认3行
|
||||
autoAdvancedCol: 3,
|
||||
//折叠时默认显示行数,默认1行
|
||||
alwaysShowLines: 2,
|
||||
|
||||
//将表单内数值类型区域的值映射成 2个字段
|
||||
fieldMapToNumber: [['workYears', ['workYears_begin', 'workYears_end']]],
|
||||
//每列占比,默认一行为24
|
||||
baseColProps: { span: 12 },
|
||||
});
|
||||
|
||||
/**
|
||||
* 点击提交按钮的value值
|
||||
* @param values
|
||||
*/
|
||||
function handleSubmit(values: any) {
|
||||
console.log('提交按钮数据::::', values);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/** 时间和数字输入框样式 */
|
||||
:deep(.ant-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-picker) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,63 @@
|
||||
<!-- 插槽 -->
|
||||
<template>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px">
|
||||
<!-- #phone对应的是formSchemas对应slot(phone)插槽 -->
|
||||
<template #phone="{ model, field }">
|
||||
<!-- 如果是组件需要进行双向绑定,model当前表单对象,field当前字段名称 -->
|
||||
<a-input v-model:value="model[field]" placeholder="请输入手机号" />
|
||||
<span class="font-color">请输入您的手机号,方便我们联系您</span>
|
||||
</template>
|
||||
<template #feedback="{ model, field }">
|
||||
<JEditor v-model:value="model[field]" placeholder="请输入问题反馈" />
|
||||
<span class="font-color">请您图文并茂,方便我们了解问题并及时反馈</span>
|
||||
</template>
|
||||
</BasicForm>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
import JEditor from '/@/components/Form/src/jeecg/components/JEditor.vue';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
field: 'name',
|
||||
label: '姓名',
|
||||
component: 'Input',
|
||||
},
|
||||
{
|
||||
field: 'phone',
|
||||
label: '联系方式',
|
||||
component: 'Input',
|
||||
slot: 'phone',
|
||||
},
|
||||
{
|
||||
field: 'feedback',
|
||||
label: '问题反馈',
|
||||
component: 'InputTextArea',
|
||||
slot: 'feedback',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
*/
|
||||
const [registerForm] = useForm({
|
||||
//注册表单列
|
||||
schemas: formSchemas,
|
||||
showResetButton: false,
|
||||
labelWidth: '150px',
|
||||
submitButtonOptions: { text: '提交', preIcon: '' },
|
||||
actionColOptions: { span: 17 },
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.font-color {
|
||||
font-size: 13px;
|
||||
color: #a1a1a1;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,94 @@
|
||||
<!-- 操作表单值 -->
|
||||
<template>
|
||||
<div style="margin: 20px auto; text-align: center">
|
||||
<a-button @click="getFormValue" class="mr-2"> 获取表单值 </a-button>
|
||||
<a-button @click="clearFormValue" class="mr-2"> 清空表单值 </a-button>
|
||||
<a-button @click="updateFormValue" class="mr-2"> 更新表单值 </a-button>
|
||||
</div>
|
||||
<!-- 自定义表单 -->
|
||||
<BasicForm @register="registerForm" style="margin-top: 20px" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
field: 'visitor',
|
||||
label: '来访人员',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'accessed',
|
||||
label: '来访日期',
|
||||
component: 'DatePicker',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
field: 'phone',
|
||||
label: '来访人手机号',
|
||||
component: 'Input',
|
||||
required: true,
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
* getFieldsValue 获取所有表单值
|
||||
* validate 验证通过之后的表单值,支持验证其中几个字段,validate(['visitor',...])
|
||||
* setFieldsValue 更新表单值,如 setFieldsValue({'visitor':'李四',...})
|
||||
* resetFields 清除所有表单值
|
||||
*/
|
||||
const [registerForm, { getFieldsValue, setFieldsValue, resetFields, validate }] = useForm({
|
||||
schemas: formSchemas,
|
||||
//隐藏操作按钮
|
||||
showActionButtonGroup: false,
|
||||
labelWidth: '150px',
|
||||
//默认聚焦第一个,只支持input
|
||||
autoFocusFirstItem: true,
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取表单值
|
||||
*/
|
||||
async function getFormValue() {
|
||||
//获取所有值
|
||||
let fieldsValue = await getFieldsValue();
|
||||
console.log('fieldsValue:::', fieldsValue);
|
||||
//表单验证通过后获取所有字段值
|
||||
fieldsValue = await validate();
|
||||
console.log('fieldsValue:::', fieldsValue);
|
||||
//表单验`visitor来访人员`通过后获取的值
|
||||
fieldsValue = await validate(['visitor']);
|
||||
console.log('fieldsValue:::', fieldsValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空表单值
|
||||
*/
|
||||
async function clearFormValue() {
|
||||
await resetFields();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新表单值
|
||||
*/
|
||||
async function updateFormValue() {
|
||||
console.log('我进来了');
|
||||
await setFieldsValue({ visitor: '李四' });
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/** 时间和数字输入框样式 */
|
||||
:deep(.ant-input-number) {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
:deep(.ant-picker) {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
@ -0,0 +1,63 @@
|
||||
<!-- 基本用法 -->
|
||||
<template>
|
||||
<!-- 自定表单 -->
|
||||
<BasicForm @register="registerForm" @submit="handleSubmit" style="margin-top: 20px" />
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
//引入依赖
|
||||
import { useForm, BasicForm, FormSchema } from '/@/components/Form';
|
||||
|
||||
//自定义表单字段
|
||||
const formSchemas: FormSchema[] = [
|
||||
{
|
||||
//标题名称
|
||||
label: '用户名(后面根据labelLength定义的长度隐藏)',
|
||||
//字段
|
||||
field: 'username',
|
||||
//组件
|
||||
component: 'Input',
|
||||
//标题宽度,支持数字和字符串
|
||||
labelWidth: 150,
|
||||
//标题长度,超过位数隐藏
|
||||
labelLength: 3,
|
||||
},
|
||||
{
|
||||
label: '密码',
|
||||
field: 'password',
|
||||
//子标题名称(在主标题后面)
|
||||
subLabel: '(数字和字母组成)',
|
||||
component: 'InputPassword',
|
||||
labelWidth: '150px',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* BasicForm绑定注册;
|
||||
* useForm 是整个框架的核心用于表单渲染,里边封装了很多公共方法;
|
||||
* 支持(schemas: 渲染表单列,autoSubmitOnEnter:回车提交,submitButtonOptions:自定义按钮文本和图标等方法);
|
||||
* 平台通过此封装,简化了代码,支持自定义扩展;
|
||||
*/
|
||||
const [registerForm] = useForm({
|
||||
//注册表单列
|
||||
schemas: formSchemas,
|
||||
//回车提交
|
||||
autoSubmitOnEnter: true,
|
||||
//不显示重置按钮
|
||||
showResetButton: false,
|
||||
//自定义提交按钮文本和图标
|
||||
submitButtonOptions: { text: '提交', preIcon: '' },
|
||||
//查询列占比 24代表一行 取值范围 0-24
|
||||
actionColOptions: { span: 17 },
|
||||
});
|
||||
|
||||
/**
|
||||
* 点击提交按钮的value值
|
||||
* @param values
|
||||
*/
|
||||
function handleSubmit(values: any) {
|
||||
console.log('提交按钮数据::::', values);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
393
jeecgboot-vue3/src/views/demo/document/form/example.data.ts
Normal file
393
jeecgboot-vue3/src/views/demo/document/form/example.data.ts
Normal file
@ -0,0 +1,393 @@
|
||||
import { FormSchema } from '/@/components/Form';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
export const schemas: FormSchema[] = [
|
||||
{
|
||||
label: '文本框',
|
||||
field: 'name',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
prefix: '中文',
|
||||
showCount: true,
|
||||
},
|
||||
defaultValue: '张三',
|
||||
},
|
||||
{
|
||||
label: '密码',
|
||||
field: 'password',
|
||||
component: 'InputPassword',
|
||||
componentProps: {
|
||||
//是否显示切换按钮或者控制密码显隐
|
||||
visibilityToggle: true,
|
||||
prefix: '密码',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '搜索框',
|
||||
field: 'searchBox',
|
||||
component: 'InputSearch',
|
||||
componentProps: {
|
||||
onSearch: (value) => {
|
||||
console.log(value);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '文本域',
|
||||
field: 'textArea',
|
||||
component: 'InputTextArea',
|
||||
componentProps: {
|
||||
//可以点击清除图标删除内容
|
||||
allowClear: true,
|
||||
//是否展示字数
|
||||
showCount: true,
|
||||
//自适应内容高度,可设置为 true | false 或对象:{ minRows: 2, maxRows: 6 }
|
||||
autoSize: {
|
||||
//最小显示行数
|
||||
minRows: 2,
|
||||
//最大显示行数
|
||||
maxRows: 3,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数值输入框',
|
||||
field: 'number',
|
||||
component: 'InputNumber',
|
||||
componentProps: {
|
||||
//带标签的 input,设置后置标签
|
||||
addonAfter: '保留两位小数',
|
||||
//最大值
|
||||
max: 100,
|
||||
//数值经度
|
||||
precision: 2,
|
||||
//步数
|
||||
step: 0.1,
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
label: '下拉框',
|
||||
field: 'jinputtype',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ value: 'like', label: '模糊(like)' },
|
||||
{ value: 'ne', label: '不等于(ne)' },
|
||||
{ value: 'ge', label: '大于等于(ge)' },
|
||||
{ value: 'le', label: '小于等于(le)' },
|
||||
],
|
||||
//下拉多选
|
||||
mode: 'multiple',
|
||||
//配置是否可搜索
|
||||
showSearch: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'TreeSelect',
|
||||
label: '下拉树',
|
||||
component: 'TreeSelect',
|
||||
componentProps: {
|
||||
//是否显示下拉框,默认false
|
||||
treeCheckable: true,
|
||||
//标题
|
||||
title: '下拉树',
|
||||
//下拉树
|
||||
treeData: [
|
||||
{
|
||||
label: '洗衣机',
|
||||
value: '0',
|
||||
children: [
|
||||
{
|
||||
label: '滚筒洗衣机',
|
||||
value: '0-1',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '电视机',
|
||||
value: '1',
|
||||
children: [
|
||||
{
|
||||
label: '平板电视',
|
||||
value: '1-1',
|
||||
disabled: true,
|
||||
},
|
||||
{
|
||||
label: 'CRT电视机',
|
||||
value: '1-2',
|
||||
},
|
||||
{
|
||||
label: '投影电视',
|
||||
value: '1-3',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'RadioButtonGroup组件',
|
||||
field: 'status',
|
||||
component: 'RadioButtonGroup',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '有效', value: 1 },
|
||||
{ label: '无效', value: 0 },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '单选框',
|
||||
field: 'radioSex',
|
||||
component: 'RadioGroup',
|
||||
componentProps: {
|
||||
//options里面由一个一个的radio组成,支持disabled禁用
|
||||
options: [
|
||||
{ label: '男', value: 1, disabled: false },
|
||||
{ label: '女', value: 0 },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '多选框',
|
||||
field: 'checkbox',
|
||||
component: 'Checkbox',
|
||||
componentProps: {
|
||||
//是否禁用,默认false
|
||||
disabled: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '多选框组',
|
||||
field: 'checkSex',
|
||||
component: 'CheckboxGroup',
|
||||
componentProps: {
|
||||
//RadioGroup 下所有 input[type="radio"] 的 name 属性
|
||||
name: '爱好',
|
||||
//options支持disabled禁用
|
||||
options: [
|
||||
{ label: '运动', value: 0, disabled: true },
|
||||
{ label: '听音乐', value: 1 },
|
||||
{ label: '看书', value: 2 },
|
||||
],
|
||||
},
|
||||
defaultValue: [2],
|
||||
},
|
||||
{
|
||||
label: '自动完成组件',
|
||||
field: 'AutoComplete',
|
||||
component: 'AutoComplete',
|
||||
componentProps: {
|
||||
options: [{ value: 'Burns Bay Road' }, { value: 'Downing Street' }, { value: 'Wall Street' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '级联选择',
|
||||
field: 'cascade',
|
||||
component: 'Cascader',
|
||||
componentProps: {
|
||||
//最多显示多少个tag
|
||||
maxTagCount: 2,
|
||||
//浮层预设位置
|
||||
placement: 'bottomRight',
|
||||
//在选择框中显示搜索框,默认false
|
||||
showSearch: true,
|
||||
options: [
|
||||
{
|
||||
label: '北京',
|
||||
value: 'BeiJin',
|
||||
children: [
|
||||
{
|
||||
label: '海淀区',
|
||||
value: 'HaiDian',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: '江苏省',
|
||||
value: 'JiangSu',
|
||||
children: [
|
||||
{
|
||||
label: '南京',
|
||||
value: 'Nanjing',
|
||||
children: [
|
||||
{
|
||||
label: '中华门',
|
||||
value: 'ZhongHuaMen',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '日期选择',
|
||||
field: 'dateSelect',
|
||||
component: 'DatePicker',
|
||||
componentProps: {
|
||||
//日期格式化,页面上显示的值
|
||||
format: 'YYYY-MM-DD',
|
||||
//返回值格式化(绑定值的格式)
|
||||
valueFormat: 'YYYY-MM-DD',
|
||||
//是否显示今天按钮
|
||||
showToday: true,
|
||||
//不可选择日期
|
||||
disabledDate: (currentDate) => {
|
||||
let date = dayjs(currentDate).format('YYYY-MM-DD');
|
||||
let nowDate = dayjs(new Date()).format('YYYY-MM-DD');
|
||||
//当天不可选择
|
||||
if (date == nowDate) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '月份选择',
|
||||
field: 'monthSelect',
|
||||
component: 'MonthPicker',
|
||||
componentProps: {
|
||||
//不可选择日期
|
||||
disabledDate: (currentDate) => {
|
||||
let date = dayjs(currentDate).format('YYYY-MM');
|
||||
let nowDate = dayjs(new Date()).format('YYYY-MM');
|
||||
//当天不可选择
|
||||
if (date == nowDate) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '周选择',
|
||||
field: 'weekSelect',
|
||||
component: 'WeekPicker',
|
||||
componentProps: {
|
||||
size: 'small',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '时间选择',
|
||||
field: 'timeSelect',
|
||||
component: 'TimePicker',
|
||||
componentProps: {
|
||||
size: 'default',
|
||||
//日期时间或者时间模式下是否显示此刻,不支持日期时间范围和时间范围
|
||||
showNow: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '日期时间范围',
|
||||
field: 'dateTimeRangeSelect',
|
||||
component: 'RangePicker',
|
||||
componentProps: {
|
||||
//是否显示时间
|
||||
showTime: true,
|
||||
//日期格式化
|
||||
format: 'YYYY/MM/DD HH:mm:ss',
|
||||
//范围文本描述用集合
|
||||
placeholder: ['请选择开始日期时间', '请选择结束日期时间'],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '日期范围',
|
||||
field: 'dateRangeSelect',
|
||||
component: 'RangeDate',
|
||||
componentProps: {
|
||||
//日期格式化
|
||||
format: 'YYYY/MM/DD',
|
||||
//范围文本描述用集合
|
||||
placeholder: ['请选择开始日期', '请选择结束日期'],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '时间范围',
|
||||
field: 'timeRangeSelect',
|
||||
component: 'RangeTime',
|
||||
componentProps: {
|
||||
//日期格式化
|
||||
format: 'HH/mm/ss',
|
||||
//范围文本描述用集合
|
||||
placeholder: ['请选择开始时间', '请选择结束时间'],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '开关',
|
||||
field: 'switch',
|
||||
component: 'Switch',
|
||||
componentProps: {
|
||||
//开关大小,可选值:default small
|
||||
size: 'default',
|
||||
//非选中时的内容
|
||||
unCheckedChildren: '开启',
|
||||
//非选中时的值
|
||||
unCheckedValue: '0',
|
||||
//选中时的内容
|
||||
checkedChildren: '关闭',
|
||||
//选中时的值
|
||||
checkedValue: '1',
|
||||
//是否禁用
|
||||
disabled: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '滑动输入条',
|
||||
field: 'slider',
|
||||
component: 'Slider',
|
||||
componentProps: {
|
||||
//最小值
|
||||
min: -20,
|
||||
//最大值
|
||||
max: 100,
|
||||
//是否为双滑块模式
|
||||
range: true,
|
||||
//刻度标记
|
||||
marks: {
|
||||
'-20': '-20°C',
|
||||
0: '0°C',
|
||||
26: '26°C',
|
||||
37: '37°C',
|
||||
100: {
|
||||
style: {
|
||||
color: '#f50',
|
||||
},
|
||||
label: '100°C',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '评分',
|
||||
field: 'rate',
|
||||
component: 'Rate',
|
||||
componentProps: {
|
||||
//是否允许半选
|
||||
allowHalf: true,
|
||||
//star 总数
|
||||
count: 5,
|
||||
//tooltip提示,有几颗星写几个
|
||||
tooltips: ['非常差', '较差', '正常', '很好', '非很好'],
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '分割线',
|
||||
field: 'divisionLine',
|
||||
component: 'Divider',
|
||||
componentProps: {
|
||||
//是否虚线
|
||||
dashed: false,
|
||||
//分割线标题的位置(left | right | center)
|
||||
orientation: 'center',
|
||||
//文字是否显示为普通正文样式
|
||||
plain: true,
|
||||
//水平还是垂直类型(horizontal | vertical)
|
||||
type: 'horizontal',
|
||||
},
|
||||
},
|
||||
];
|
||||
@ -0,0 +1,452 @@
|
||||
import { FormSchema } from '/@/components/Form';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
|
||||
export const schemas: FormSchema[] = [
|
||||
{
|
||||
label: '验证码',
|
||||
field: 'code',
|
||||
component: 'InputCountDown',
|
||||
componentProps: {
|
||||
//'default': 默认, 'large': 最大, 'small': 最小
|
||||
size:'default',
|
||||
//倒计时
|
||||
count: 120,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Api下拉选择',
|
||||
field: 'apiSelect',
|
||||
component: 'ApiSelect',
|
||||
componentProps: {
|
||||
//multiple: 多选;不填写为单选
|
||||
mode: 'multiple',
|
||||
//请求api,返回结果{ result: { records:[{'id':'1',name:'scott'},{'id':'2',name:'小张'}] }}
|
||||
api: () => defHttp.get({ url: '/test/jeecgDemo/list' }),
|
||||
//数值转成String
|
||||
numberToString: false,
|
||||
//标题字段
|
||||
labelField: 'name',
|
||||
//值字段
|
||||
valueField: 'id',
|
||||
//请求参数
|
||||
params: {},
|
||||
//返回结果字段
|
||||
resultField: 'records',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'Api树选择',
|
||||
field: 'apiSelect',
|
||||
component: 'ApiTreeSelect',
|
||||
componentProps: {
|
||||
/* 请求api,返回结果
|
||||
{ result: { list: [{ title:'选项0',value:'0',key:'0',
|
||||
children: [ {"title": "选项0-0","value": "0-0","key": "0-0"},...]
|
||||
}, ...]
|
||||
}} */
|
||||
api: () => defHttp.get({ url: '/mock/tree/getDemoOptions' }),
|
||||
//请求参数
|
||||
params: {},
|
||||
//返回结果字段
|
||||
resultField: 'list',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '校验密码强度',
|
||||
field: 'pwd',
|
||||
component: 'StrengthMeter',
|
||||
componentProps: {
|
||||
//是否显示密码文本框
|
||||
showInput: true,
|
||||
//是否禁用
|
||||
disabled: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '省市县联动',
|
||||
field: 'province',
|
||||
component: 'JAreaLinkage',
|
||||
componentProps: {
|
||||
//是否显示区县,默认true,否则只显示省
|
||||
showArea: true,
|
||||
//是否是全部文本,默认false
|
||||
showAll: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '岗位选择',
|
||||
field: 'post',
|
||||
component: 'JSelectPosition',
|
||||
componentProps: {
|
||||
//是否右侧显示选中列表
|
||||
showSelected: true,
|
||||
//最大选择数量
|
||||
maxSelectCount: 1,
|
||||
//岗位标题
|
||||
modalTitle: '岗位',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '角色选择',
|
||||
field: 'role',
|
||||
component: 'JSelectRole',
|
||||
componentProps: {
|
||||
//请求参数 如params:{"code":"001"}
|
||||
params: {},
|
||||
//是否单选,默认false
|
||||
isRadioSelection: true,
|
||||
//角色标题
|
||||
modalTitle: '角色',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '用户选择',
|
||||
field: 'user',
|
||||
component: 'JSelectUser',
|
||||
componentProps: {
|
||||
//取值字段配置,一般为主键字段
|
||||
rowKey: 'username',
|
||||
//显示字段配置
|
||||
labelKey: 'realname',
|
||||
//是否显示选择按钮
|
||||
showButton: false,
|
||||
//用户标题
|
||||
modalTitle: '用户',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '图片上传',
|
||||
field: 'uploadImage',
|
||||
component: 'JImageUpload',
|
||||
componentProps: {
|
||||
//按钮显示文字
|
||||
text:'图片上传',
|
||||
//支持两种基本样式picture和picture-card
|
||||
listType:'picture-card',
|
||||
//用于控制文件上传的业务路径,默认temp
|
||||
bizPath:'temp',
|
||||
//是否禁用
|
||||
disabled:false,
|
||||
//最大上传数量
|
||||
fileMax:1,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '字典标签',
|
||||
field: 'dictTags',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
//字典code配置,比如通过性别字典编码:sex,也可以使用demo,name,id 表名,名称,值的方式
|
||||
dictCode:'sex',
|
||||
//支持radio(单选按钮)、radioButton(单选按钮 btn风格)、select(下拉框)
|
||||
type:'radioButton'
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '部门选择',
|
||||
field: 'dept',
|
||||
component: 'JSelectDept',
|
||||
componentProps: {
|
||||
//是否开启异步加载
|
||||
sync: false,
|
||||
//是否显示复选框
|
||||
checkable: true,
|
||||
//是否显示选择按钮
|
||||
showButton: false,
|
||||
//父子节点选中状态不再关联
|
||||
checkStrictly: true,
|
||||
//选择框标题
|
||||
modalTitle: '部门选择',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '省市县级联动',
|
||||
field: 'provinceArea',
|
||||
component: 'JAreaSelect',
|
||||
componentProps: {
|
||||
//级别 1 只显示省 2 省市 3 省市区
|
||||
level:3
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '富文本',
|
||||
field: 'editor',
|
||||
component: 'JEditor',
|
||||
componentProps: {
|
||||
//是否禁用
|
||||
disabled: false
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'markdown',
|
||||
field: 'markdown',
|
||||
component: 'JMarkdownEditor',
|
||||
componentProps: {
|
||||
//是否禁用
|
||||
disabled: false
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '可输入下拉框',
|
||||
field: 'inputSelect',
|
||||
component: 'JSelectInput',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: 'Default', value: 'default' },
|
||||
{ label: 'IFrame', value: 'iframe' },
|
||||
],
|
||||
//是否为搜索模式
|
||||
showSearch: true,
|
||||
//是否禁用
|
||||
disabled: false
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '代码编辑器组件',
|
||||
field: 'jCode',
|
||||
component: 'JCodeEditor',
|
||||
componentProps: {
|
||||
//高度,默认auto
|
||||
height:'150px',
|
||||
//是否禁用
|
||||
disabled:false,
|
||||
//是否全屏
|
||||
fullScreen:false,
|
||||
//全屏之后的坐标
|
||||
zIndex: 999,
|
||||
//代码主题,目前只支持idea,可在组件自行扩展
|
||||
theme:'idea',
|
||||
//代码提示
|
||||
keywords:['console'],
|
||||
//语言如(javascript,vue,markdown)可在组件自行扩展
|
||||
language:'javascript'
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '分类字典树',
|
||||
field: 'dictTree',
|
||||
component: 'JCategorySelect',
|
||||
componentProps: {
|
||||
//占位内容
|
||||
placeholder:'请选择分类字典树',
|
||||
//查询条件,如“{'name':'笔记本'}”
|
||||
condition:"",
|
||||
//是否多选
|
||||
multiple: false,
|
||||
//起始选择code,见配置的分类字典的类型编码
|
||||
pcode: 'A04',
|
||||
//父级id
|
||||
pid:'',
|
||||
//返回key
|
||||
back:'id',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '下拉多选',
|
||||
field: 'selectMultiple',
|
||||
component: 'JSelectMultiple',
|
||||
componentProps: {
|
||||
//字典code配置,比如通过性别字典编码:sex,也可以使用demo,name,id 表名,名称,值的方式
|
||||
dictCode:'company_rank',
|
||||
//是否只读
|
||||
readOnly:false,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: 'popup',
|
||||
field: 'popup',
|
||||
component: 'JPopup',
|
||||
componentProps: ({ formActionType }) => {
|
||||
const {setFieldsValue} = formActionType;
|
||||
return{
|
||||
setFieldsValue:setFieldsValue,
|
||||
//online报表编码
|
||||
code:"demo",
|
||||
//是否为多选
|
||||
multi:false,
|
||||
//字段配置
|
||||
fieldConfig: [
|
||||
{ source: 'name', target: 'popup' },
|
||||
],
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '开关自定义',
|
||||
field: 'switch',
|
||||
component: 'JSwitch',
|
||||
componentProps:{
|
||||
//取值 options
|
||||
options:['Y','N'],
|
||||
//文本option
|
||||
labelOptions:['是', '否'],
|
||||
//是否启用下拉
|
||||
query: false,
|
||||
//是否禁用
|
||||
disabled: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '定时表达式选择',
|
||||
field: 'timing',
|
||||
component: 'JEasyCron',
|
||||
componentProps:{
|
||||
//是否隐藏参数秒和年设置,如果隐藏,那么参数秒和年将会全部忽略掉。
|
||||
hideSecond: false,
|
||||
//是否隐藏参数年设置,如果隐藏,那么参数年将会全部忽略掉
|
||||
hideYear: false,
|
||||
//是否禁用
|
||||
disabled: false,
|
||||
//获取预览执行时间列表的函数,格式为:remote (cron值, time时间戳, cb回调函数)
|
||||
remote:(cron,time,cb)=>{}
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '分类字典树',
|
||||
field: 'treeDict',
|
||||
component: 'JTreeDict',
|
||||
componentProps:{
|
||||
//指定当前组件需要存储的字段 可选: id(主键)和code(编码)
|
||||
field:'id',
|
||||
//是否为异步
|
||||
async: true,
|
||||
//是否禁用
|
||||
disabled: false,
|
||||
//指定一个节点的编码,加载该节点下的所有字典数据,若不指定,默认加载所有数据
|
||||
parentCode:'A04'
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '多行输入窗口',
|
||||
field: 'inputPop',
|
||||
component: 'JInputPop',
|
||||
componentProps:{
|
||||
//标题
|
||||
title:'多行输入窗口',
|
||||
//弹窗显示位置
|
||||
position:'bottom',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '多选',
|
||||
field: 'multipleChoice',
|
||||
component: 'JCheckbox',
|
||||
componentProps:{
|
||||
//字典code配置,比如通过职位字典编码:company_rank,也可以使用demo,name,id 表名,名称,值的方式
|
||||
dictCode:'company_rank',
|
||||
//是否禁用
|
||||
disabled: false,
|
||||
//没有字典code可以使用option来定义
|
||||
// options:[
|
||||
// {label:'CE0',value:'1'}
|
||||
// ]
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '下拉树选择',
|
||||
field: 'treeCusSelect',
|
||||
component: 'JTreeSelect',
|
||||
componentProps: {
|
||||
//字典code配置,比如通过性别字典编码:sex,也可以使用sys_permission,name,id 表名,名称,值的方式
|
||||
dict: 'sys_permission,name,id',
|
||||
//父级id字段
|
||||
pidField: 'parent_id',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '根据部门选择用户组件',
|
||||
field: 'userByDept',
|
||||
component: 'JSelectUserByDept',
|
||||
componentProps: {
|
||||
//是否显示选择按钮
|
||||
showButton: true,
|
||||
//选择框标题
|
||||
modalTitle: '部门用户选择'
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '文件上传',
|
||||
field: 'uploadFile',
|
||||
component: 'JUpload',
|
||||
componentProps: {
|
||||
//是否显示选择按钮
|
||||
text: '文件上传',
|
||||
//最大上传数
|
||||
maxCount: 2,
|
||||
//是否显示下载按钮
|
||||
download: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '字典表搜索',
|
||||
field: 'dictSearchSelect',
|
||||
component: 'JSearchSelect',
|
||||
componentProps: {
|
||||
//字典code配置,通过 demo,name,id 表名,名称,值的方式
|
||||
dict: 'demo,name,id',
|
||||
//是否异步加载
|
||||
async: true,
|
||||
//当async设置为true时有效,表示异步查询时,每次获取数据的数量,默认10
|
||||
pageSize:3
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '动态创建input框',
|
||||
field: 'jAddInput',
|
||||
component: 'JAddInput',
|
||||
componentProps: {
|
||||
//自定义超过多少行才会显示删除按钮,默认为1
|
||||
min:1
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '用户选择组件',
|
||||
field: 'userCusSelect',
|
||||
component: 'UserSelect',
|
||||
componentProps: {
|
||||
//是否多选
|
||||
multi: true,
|
||||
//从用户表中选择一列,其值作为该控件的存储值,默认id列
|
||||
store: 'id',
|
||||
//是否排除我自己(当前登录用户)
|
||||
izExcludeMy: false,
|
||||
//是否禁用
|
||||
disabled: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '选择角色组件',
|
||||
field: 'roleSelect',
|
||||
component: 'RoleSelect',
|
||||
componentProps: {
|
||||
//最大选择数量
|
||||
maxSelectCount: 3,
|
||||
//是否单选
|
||||
isRadioSelection: false
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '数值范围输入框',
|
||||
field: 'rangeNumber',
|
||||
component: 'JRangeNumber',
|
||||
},
|
||||
{
|
||||
label: '远程Api单选框组',
|
||||
field: 'apiRadioGroup',
|
||||
component: 'ApiRadioGroup',
|
||||
componentProps:{
|
||||
//请求接口返回结果{ result:{ list: [ name: '选项0',id: '1' ] }}
|
||||
api:()=> defHttp.get({ url: '/mock/select/getDemoOptions' }),
|
||||
//请求参数
|
||||
params:{},
|
||||
//是否为按钮风格类型,默认false
|
||||
isBtn: false,
|
||||
//返回集合名称
|
||||
resultField: 'list',
|
||||
//标题字段名称
|
||||
labelField: 'name',
|
||||
//值字段名称
|
||||
valueField: 'id',
|
||||
}
|
||||
},
|
||||
];
|
||||
24
jeecgboot-vue3/src/views/demo/document/form/index.ts
Normal file
24
jeecgboot-vue3/src/views/demo/document/form/index.ts
Normal file
@ -0,0 +1,24 @@
|
||||
export { default as BasicFiledsLayotForm } from './BasicFiledsLayotForm.vue';
|
||||
export { default as BasicFixedWidthForm } from './BasicFixedWidthForm.vue';
|
||||
export { default as BasicFormAdd } from './BasicFormAdd.vue';
|
||||
export { default as BasicFormBtn } from './BasicFormBtn.vue';
|
||||
export { default as BasicFormCleanRule } from './BasicFormCleanRule.vue';
|
||||
export { default as BasicFormCompact } from './BasicFormCompact.vue';
|
||||
export { default as BasicFormComponent } from './BasicFormComponent.vue';
|
||||
export { default as BasicFormConAttribute } from './BasicFormConAttribute.vue';
|
||||
export { default as BasicFormCustom } from './BasicFormCustom.vue';
|
||||
export { default as BasicFormCustomComponent } from './BasicFormCustomComponent.vue';
|
||||
export { default as BasicFormCustomSlots } from './BasicFormCustomSlots.vue';
|
||||
export { default as BasicFormDynamicsRules } from './BasicFormDynamicsRules.vue';
|
||||
export { default as BasicFormFieldShow } from './BasicFormFieldShow.vue';
|
||||
export { default as BasicFormFieldTip } from './BasicFormFieldTip.vue';
|
||||
export { default as BasicFormFooter } from './BasicFormFooter.vue';
|
||||
export { default as BasicFormLayout } from './BasicFormLayout.vue';
|
||||
export { default as BasicFormModal } from './BasicFormModal.vue';
|
||||
export { default as BasicFormRander } from './BasicFormRander.vue';
|
||||
export { default as BasicFormRules } from './BasicFormRules.vue';
|
||||
export { default as BasicFormSchemas } from './BasicFormSchemas.vue';
|
||||
export { default as BasicFormSearch } from './BasicFormSearch.vue';
|
||||
export { default as BasicFormSlots } from './BasicFormSlots.vue';
|
||||
export { default as BasicFormValue } from './BasicFormValue.vue';
|
||||
export { default as BasicFunctionForm } from './BasicFunctionForm.vue';
|
||||
114
jeecgboot-vue3/src/views/demo/document/form/tabIndex.vue
Normal file
114
jeecgboot-vue3/src/views/demo/document/form/tabIndex.vue
Normal file
@ -0,0 +1,114 @@
|
||||
<template>
|
||||
<div class="p-4">
|
||||
<a-card :bordered="false" style="height: 100%">
|
||||
<a-tabs v-model:activeKey="activeKey" @change="tabChange">
|
||||
<a-tab-pane :key="item.key" :tab="item.label" v-for="item in compList" />
|
||||
</a-tabs>
|
||||
<component :is="currentComponent" />
|
||||
</a-card>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, computed } from 'vue';
|
||||
import {
|
||||
BasicFunctionForm,
|
||||
BasicFormConAttribute,
|
||||
BasicFormFieldShow,
|
||||
BasicFormFieldTip,
|
||||
BasicFormRules,
|
||||
BasicFormDynamicsRules,
|
||||
BasicFormSlots,
|
||||
BasicFormCustomSlots,
|
||||
BasicFormRander,
|
||||
BasicFixedWidthForm,
|
||||
BasicFiledsLayotForm,
|
||||
BasicFormLayout,
|
||||
BasicFormBtn,
|
||||
BasicFormCompact,
|
||||
BasicFormCleanRule,
|
||||
BasicFormValue,
|
||||
BasicFormSchemas,
|
||||
BasicFormAdd,
|
||||
BasicFormFooter,
|
||||
BasicFormModal,
|
||||
BasicFormCustom,
|
||||
BasicFormSearch,
|
||||
BasicFormComponent,
|
||||
BasicFormCustomComponent,
|
||||
} from './index';
|
||||
export default defineComponent({
|
||||
name: 'document-table-demo',
|
||||
components: {
|
||||
BasicFunctionForm,
|
||||
BasicFormConAttribute,
|
||||
BasicFormFieldShow,
|
||||
BasicFormFieldTip,
|
||||
BasicFormRules,
|
||||
BasicFormDynamicsRules,
|
||||
BasicFormSlots,
|
||||
BasicFormCustomSlots,
|
||||
BasicFormRander,
|
||||
BasicFixedWidthForm,
|
||||
BasicFiledsLayotForm,
|
||||
BasicFormLayout,
|
||||
BasicFormBtn,
|
||||
BasicFormCompact,
|
||||
BasicFormCleanRule,
|
||||
BasicFormValue,
|
||||
BasicFormSchemas,
|
||||
BasicFormAdd,
|
||||
BasicFormFooter,
|
||||
BasicFormModal,
|
||||
BasicFormCustom,
|
||||
BasicFormSearch,
|
||||
BasicFormComponent,
|
||||
BasicFormCustomComponent,
|
||||
},
|
||||
setup() {
|
||||
//当前选中key
|
||||
const activeKey = ref('BasicFunctionForm');
|
||||
//组件集合
|
||||
const compList = ref([
|
||||
{ key: 'BasicFunctionForm', label: '基础表单' },
|
||||
{ key: 'BasicFormConAttribute', label: '字段控件属性' },
|
||||
{ key: 'BasicFormComponent', label: 'Ant Design Vue自带控件' },
|
||||
{ key: 'BasicFormCustomComponent', label: 'JEECG封装的控件' },
|
||||
{ key: 'BasicFormFieldShow', label: '字段显示和隐藏' },
|
||||
{ key: 'BasicFormFieldTip', label: '字段标题提示' },
|
||||
{ key: 'BasicFormRules', label: '表单检验' },
|
||||
{ key: 'BasicFormDynamicsRules', label: '自定义动态检验' },
|
||||
{ key: 'BasicFormSlots', label: '字段插槽' },
|
||||
{ key: 'BasicFormCustomSlots', label: '自定义组件(插槽)' },
|
||||
{ key: 'BasicFormCustom', label: '自定义组件(component)' },
|
||||
{ key: 'BasicFormRander', label: '自定义渲染' },
|
||||
{ key: 'BasicFixedWidthForm', label: '固定label宽度' },
|
||||
{ key: 'BasicFiledsLayotForm', label: '标题与字段布局' },
|
||||
{ key: 'BasicFormLayout', label: '表单布局' },
|
||||
{ key: 'BasicFormBtn', label: '操作按钮示例' },
|
||||
{ key: 'BasicFormCompact', label: '表单紧凑' },
|
||||
{ key: 'BasicFormCleanRule', label: '表单检验配置' },
|
||||
{ key: 'BasicFormValue', label: '获取value值' },
|
||||
{ key: 'BasicFormSchemas', label: '更新schemas表单配置' },
|
||||
{ key: 'BasicFormAdd', label: '动态增减表单' },
|
||||
{ key: 'BasicFormFooter', label: '自定义页脚' },
|
||||
{ key: 'BasicFormModal', label: '弹出层表单' },
|
||||
{ key: 'BasicFormSearch', label: '查询区域' },
|
||||
]);
|
||||
//当前选中组件
|
||||
const currentComponent = computed(() => {
|
||||
return activeKey.value;
|
||||
});
|
||||
|
||||
//使用component动态切换tab
|
||||
function tabChange(key) {
|
||||
activeKey.value = key;
|
||||
}
|
||||
return {
|
||||
activeKey,
|
||||
currentComponent,
|
||||
tabChange,
|
||||
compList,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
135
jeecgboot-vue3/src/views/demo/document/table/AuthColumnDemo.vue
Normal file
135
jeecgboot-vue3/src/views/demo/document/table/AuthColumnDemo.vue
Normal file
@ -0,0 +1,135 @@
|
||||
<template>
|
||||
<div class="p-4">
|
||||
<BasicTable @register="registerTable">
|
||||
<template #action="{ record }">
|
||||
<TableAction
|
||||
:actions="[
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
auth: 'demo:btn:show', // 根据权限控制是否显示: 无权限,不显示
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
icon: 'ic:outline-delete-outline',
|
||||
onClick: handleDelete.bind(null, record),
|
||||
auth: 'super', // 根据权限控制是否显示: 有权限,会显示
|
||||
},
|
||||
]"
|
||||
:dropDownActions="[
|
||||
{
|
||||
label: '启用',
|
||||
popConfirm: {
|
||||
title: '是否启用?',
|
||||
confirm: handleOpen.bind(null, record),
|
||||
},
|
||||
ifShow: (_action) => {
|
||||
return record.status !== 'enable'; // 根据业务控制是否显示: 非enable状态的不显示启用按钮
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '禁用',
|
||||
popConfirm: {
|
||||
title: '是否禁用?',
|
||||
confirm: handleOpen.bind(null, record),
|
||||
},
|
||||
ifShow: () => {
|
||||
return record.status === 'enable'; // 根据业务控制是否显示: enable状态的显示禁用按钮
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '同时控制',
|
||||
popConfirm: {
|
||||
title: '是否动态显示?',
|
||||
confirm: handleOpen.bind(null, record),
|
||||
},
|
||||
auth: 'super', // 同时根据权限和业务控制是否显示
|
||||
ifShow: () => {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
</BasicTable>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { BasicTable, useTable, BasicColumn, TableAction } from '/@/components/Table';
|
||||
|
||||
import { demoListApi } from '/@/api/demo/table';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
const columns: BasicColumn[] = [
|
||||
{
|
||||
title: '编号',
|
||||
dataIndex: 'no',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'name',
|
||||
auth: 'demo:field:show', // 根据权限控制是否显示: 无权限,不显示
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
},
|
||||
{
|
||||
title: '地址',
|
||||
dataIndex: 'address',
|
||||
auth: 'super', // 同时根据权限和业务控制是否显示
|
||||
ifShow: (_column) => {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '开始时间',
|
||||
dataIndex: 'beginTime',
|
||||
},
|
||||
{
|
||||
title: '结束时间',
|
||||
dataIndex: 'endTime',
|
||||
width: 200,
|
||||
},
|
||||
];
|
||||
export default defineComponent({
|
||||
components: { BasicTable, TableAction },
|
||||
setup() {
|
||||
const { tableContext } = useListPage({
|
||||
tableProps: {
|
||||
title: '权限列',
|
||||
api: demoListApi,
|
||||
columns: columns,
|
||||
bordered: true,
|
||||
useSearchForm: false,
|
||||
actionColumn: {
|
||||
width: 250,
|
||||
title: 'Action',
|
||||
dataIndex: 'action',
|
||||
slots: { customRender: 'action' },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
//注册table数据
|
||||
const [registerTable] = tableContext;
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
}
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
}
|
||||
function handleOpen(record: Recordable) {
|
||||
console.log('点击了启用', record);
|
||||
}
|
||||
return {
|
||||
registerTable,
|
||||
handleEdit,
|
||||
handleDelete,
|
||||
handleOpen,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<!--引用表格-->
|
||||
<div class="p-4">
|
||||
<BasicTable @register="registerTable">
|
||||
<template #bodyCell="{ column, text }">
|
||||
<template v-if="column.dataIndex === 'name'">
|
||||
<a>{{ text }}</a>
|
||||
</template>
|
||||
</template>
|
||||
<template #footer>页脚</template>
|
||||
</BasicTable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="basic-table-demo" setup>
|
||||
import { ActionItem, BasicColumn, BasicTable, TableAction } from '/@/components/Table';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
//定义表格列
|
||||
const columns: BasicColumn[] = [
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
title: '年龄',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
width: 300,
|
||||
},
|
||||
{
|
||||
title: '住址',
|
||||
dataIndex: 'address',
|
||||
key: 'address',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '长内容列',
|
||||
dataIndex: 'address',
|
||||
key: 'address 2',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '长内容列',
|
||||
dataIndex: 'address',
|
||||
key: 'address 3',
|
||||
ellipsis: true,
|
||||
},
|
||||
];
|
||||
// 列表页面公共参数、方法
|
||||
const { tableContext } = useListPage({
|
||||
designScope: 'basic-table-demo',
|
||||
tableProps: {
|
||||
title: '边框表格',
|
||||
dataSource: [
|
||||
{
|
||||
key: '1',
|
||||
name: '张三',
|
||||
age: 32,
|
||||
address: '中国北京北京市朝阳区大屯路科学院南里1号楼3单元401',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
name: '刘思',
|
||||
age: 32,
|
||||
address: '中国北京北京市昌平区顺沙路尚湖世家2号楼7单元503',
|
||||
},
|
||||
],
|
||||
columns: columns,
|
||||
showActionColumn: false,
|
||||
useSearchForm: false,
|
||||
},
|
||||
});
|
||||
//注册table数据
|
||||
const [registerTable] = tableContext;
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record): ActionItem[] {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function handleEdit(record) {
|
||||
console.log(record);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<div class="p-4">
|
||||
<!--引用表格-->
|
||||
<BasicTable @register="registerTable">
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="basic-table-demo" setup>
|
||||
import { ActionItem, BasicColumn, BasicTable, TableAction } from '/@/components/Table';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
//定义表格列
|
||||
const columns: BasicColumn[] = [
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
resizable: false,
|
||||
},
|
||||
{
|
||||
title: '年龄',
|
||||
dataIndex: 'age',
|
||||
key: 'age',
|
||||
},
|
||||
{
|
||||
title: '住址',
|
||||
dataIndex: 'address',
|
||||
key: 'address',
|
||||
},
|
||||
];
|
||||
// 列表页面公共参数、方法
|
||||
const { tableContext } = useListPage({
|
||||
designScope: 'basic-table-demo',
|
||||
tableProps: {
|
||||
title: '用户列表',
|
||||
dataSource: [
|
||||
{
|
||||
key: '1',
|
||||
name: '胡歌',
|
||||
age: 32,
|
||||
address: '朝阳区林萃路1号',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
name: '刘诗诗',
|
||||
age: 32,
|
||||
address: '昌平区白沙路1号',
|
||||
},
|
||||
],
|
||||
columns: columns,
|
||||
size: 'large', //紧凑型表格 large
|
||||
striped: false, //斑马纹设置 false
|
||||
showActionColumn: true,
|
||||
useSearchForm: false,
|
||||
},
|
||||
});
|
||||
//注册table数据
|
||||
const [registerTable, methods] = tableContext;
|
||||
console.log('methods', methods);
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record): ActionItem[] {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function handleEdit(record) {
|
||||
console.log(record);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@ -0,0 +1,157 @@
|
||||
<template>
|
||||
<div class="p-4">
|
||||
<!--定义表格-->
|
||||
<BasicTable @register="registerTable">
|
||||
<!-- 搜索区域插槽自定义查询 -->
|
||||
<template #form-email="{ model, field }">
|
||||
<a-input placeholder="请输入邮箱" v-model:value="model[field]" addon-before="邮箱:" addon-after=".com"></a-input>
|
||||
</template>
|
||||
<!--操作栏-->
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getTableAction(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" name="basic-table-demo" setup>
|
||||
import { ActionItem, BasicColumn, BasicTable, FormSchema, TableAction } from '/@/components/Table';
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
//定义表格列
|
||||
const columns: BasicColumn[] = [
|
||||
{
|
||||
title: '姓名',
|
||||
dataIndex: 'name',
|
||||
width: 170,
|
||||
align: 'left',
|
||||
resizable: true,
|
||||
sorter: {
|
||||
multiple: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '关键词',
|
||||
dataIndex: 'keyWord',
|
||||
width: 130,
|
||||
resizable: true,
|
||||
},
|
||||
{
|
||||
title: '打卡时间',
|
||||
dataIndex: 'punchTime',
|
||||
width: 140,
|
||||
resizable: true,
|
||||
},
|
||||
{
|
||||
title: '工资',
|
||||
dataIndex: 'salaryMoney',
|
||||
width: 140,
|
||||
resizable: true,
|
||||
sorter: {
|
||||
multiple: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '奖金',
|
||||
dataIndex: 'bonusMoney',
|
||||
width: 140,
|
||||
resizable: true,
|
||||
},
|
||||
{
|
||||
title: '性别',
|
||||
dataIndex: 'sex',
|
||||
sorter: {
|
||||
multiple: 3,
|
||||
},
|
||||
filters: [
|
||||
{ text: '男', value: '1' },
|
||||
{ text: '女', value: '2' },
|
||||
],
|
||||
customRender: ({ record }) => {
|
||||
return record.sex ? (record.sex == '1' ? '男' : '女') : '';
|
||||
},
|
||||
width: 120,
|
||||
resizable: true,
|
||||
},
|
||||
{
|
||||
title: '生日',
|
||||
dataIndex: 'birthday',
|
||||
width: 120,
|
||||
resizable: true,
|
||||
},
|
||||
{
|
||||
title: '邮箱',
|
||||
dataIndex: 'email',
|
||||
width: 120,
|
||||
resizable: true,
|
||||
},
|
||||
];
|
||||
//表单搜索字段
|
||||
const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
label: '姓名', //显示label
|
||||
field: 'name', //查询字段
|
||||
component: 'JInput', //渲染的组件
|
||||
defaultValue: '苏榕润', //设置默认值
|
||||
},
|
||||
{
|
||||
label: '性别',
|
||||
field: 'sex',
|
||||
component: 'JDictSelectTag',
|
||||
componentProps: {
|
||||
//渲染的组件的props
|
||||
dictCode: 'sex',
|
||||
placeholder: '请选择性别',
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '邮箱',
|
||||
field: 'email',
|
||||
component: 'JInput',
|
||||
slot: 'email',
|
||||
},
|
||||
{
|
||||
label: '生日',
|
||||
field: 'birthday',
|
||||
component: 'DatePicker',
|
||||
},
|
||||
];
|
||||
//ajax请求api接口
|
||||
const demoListApi = (params) => {
|
||||
return defHttp.get({ url: '/test/jeecgDemo/list', params });
|
||||
};
|
||||
// 列表页面公共参数、方法
|
||||
const { tableContext } = useListPage({
|
||||
designScope: 'basic-table-demo-filter',
|
||||
tableProps: {
|
||||
title: '用户列表',
|
||||
api: demoListApi,
|
||||
columns: columns,
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
},
|
||||
useSearchForm: true,
|
||||
},
|
||||
});
|
||||
//BasicTable绑定注册
|
||||
const [registerTable, { getForm }] = tableContext;
|
||||
/**
|
||||
* 操作栏
|
||||
*/
|
||||
function getTableAction(record): ActionItem[] {
|
||||
return [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function handleEdit(record) {
|
||||
let { getFieldsValue } = getForm();
|
||||
console.log('查询form的数据', getFieldsValue());
|
||||
console.log(record);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user