【制作独立jeecg-ai】删除示例代码

This commit is contained in:
JEECG
2025-12-04 14:38:45 +08:00
parent 281c3ff3c8
commit d6051addeb
286 changed files with 1 additions and 31900 deletions

View File

@ -1,196 +0,0 @@
# PWA 功能说明
## 概述
项目集成了 `vite-plugin-pwa` 插件,**适配按需加载**,实现资源缓存优化和离线支持。
**升级亮点**:通过集成 vite-plugin-pwa 实现渐进式 Web 应用,提升了首屏加载速度,同时异步加载系统资源,点击菜单响应更迅速。
**核心设计**:只预缓存关键资源,按需加载的路由组件 chunk 通过运行时缓存策略处理,避免预缓存过多资源。
## 核心文件
### 构建生成的文件
- **`sw.js`** - Service Worker 文件,由 `vite-plugin-pwa` 自动生成,包含:
- 预缓存资源列表HTML、CSS、核心 JS、静态资源
- 运行时缓存策略JS chunk、CSS、图片、API 等)
- 缓存清理和更新逻辑
- **`workbox-*.js`** - Workbox 运行时库Service Worker 的核心依赖
- **`manifest.webmanifest`** - PWA 清单文件,定义应用元数据
### 配置文件
- **`build/vite/plugin/pwa.ts`** - PWA 插件配置
- **预缓存策略**:只缓存关键资源
- 入口文件:`index.html``manifest.webmanifest`
- 核心 JS入口 JS`js/index-*.js`、vendor chunk`js/*-vendor-*.js`
- 静态资源CSS、图片、字体等
- **不预缓存**:按需加载的路由组件 chunk避免预缓存过多资源
- **运行时缓存**:按需加载的资源通过运行时缓存策略处理
- 按需加载的 JS chunkNetworkFirst优先网络失败后使用缓存
- CSS、图片、API 等:按需缓存
- **注册方式**`injectRegister: 'inline'`(内联到 HTML避免缓存问题
## 功能特性
1. **资源缓存优化** - 通过缓存策略提升加载速度
2. **离线支持** - 缓存静态资源,支持离线访问
## 缓存策略
### 预缓存Precache
| 资源类型 | 说明 |
|---------|------|
| `index.html` | 入口 HTML 文件 |
| `manifest.webmanifest` | PWA 清单文件 |
| `js/index-*.js` | 入口 JS 文件 |
| `js/*-vendor-*.js` | 核心 vendor chunkVue、Ant Design Vue 等) |
| `assets/index-*.css` | **仅入口 CSS**(主样式文件) |
| `favicon.ico``logo.png` | **仅关键静态资源**logo、图标 |
**重要优化**
-**不预缓存**:路由组件的 CSS避免登录页加载全部 CSS
-**不预缓存**:路由组件的 JS chunk按需加载
-**不预缓存**:所有图片和字体(按需加载)
-**只预缓存**:登录页和首屏必需的关键资源
**效果**:访问登录页时,只加载登录页相关资源,不会预加载系统大部分资源。
### 运行时缓存Runtime Cache
| 资源类型 | 策略 | 有效期 | 说明 |
|---------|------|--------|------|
| 按需加载 JS chunk | NetworkFirst | 7天 | 优先网络,失败后使用缓存 |
| 路由组件 CSS | CacheFirst | 30天 | **按需加载**,优先缓存 |
| 图片 | CacheFirst | 30天 | 优先缓存 |
| API 请求 | NetworkFirst | 5分钟 | 优先网络,短时缓存 |
| Google Fonts | CacheFirst | 365天 | 长期缓存 |
**优势**
-**减少预缓存体积 80%+**:只预缓存关键资源,不预缓存路由组件 CSS/JS
-**登录页加载优化**:访问登录页时只加载登录页资源,不会加载系统大部分资源
-**按需加载**:路由组件的 CSS 和 JS 只在访问对应页面时加载和缓存
-**节省存储空间**:按需加载的 chunk 只在需要时缓存
-**网络优先策略**:确保用户获取最新代码
## 性能提升分析
### 首次访问(无缓存)
- **Service Worker 注册**~50-100ms后台异步不影响页面加载
- **预缓存安装**~200-500ms后台进行关键资源已加载
- **页面加载**无影响Service Worker 在后台工作)
### 二次访问(有缓存)
| 指标 | 无 PWA | 有 PWA | 提升 |
|------|--------|--------|------|
| **首屏加载时间** | 2-5s | 0.5-1.5s | **60-70%** ⬇️ |
| **关键资源加载** | 网络请求 | 缓存读取 | **90%+** ⬇️ |
| **CSS 加载** | 100-300ms | <10ms | **95%+** |
| **图片加载** | 200-500ms | <10ms | **95%+** |
| **离线访问** | 不可用 | 可用 | - |
### 按需加载优化
- **预缓存体积** ~1-3MB关键资源而非全部资源**减少 80%+**
- **Service Worker 安装时间**减少 **60-80%**
- **登录页加载**只加载登录页资源**不加载系统大部分资源**
- **存储空间**节省 **70-85%**不预缓存路由组件 CSS/JS
### 实际场景性能提升
1. **弱网环境3G/4G**
- 首屏加载**3-5s 0.8-1.5s**提升 60-70%
- 页面切换**1-2s 0.2-0.5s**提升 75-80%
2. **离线访问**
- 已访问页面**完全可用**
- 未访问页面**部分可用**关键资源已缓存
3. **重复访问**
- 资源加载**网络 缓存**提升 90%+
- 用户体验**秒开**<100ms
## 前端体验优化建议
### 1. 资源加载优化
- **已实现**
- 只预缓存关键资源入口 JSvendor入口 CSSlogo
- 路由组件的 CSS JS **不预缓存**按需加载
- 访问登录页时只加载登录页资源不会加载系统大部分资源
- 💡 **建议**确保静态资源图片字体使用 CDN配合缓存策略
### 2. 网络策略优化
- **已实现**JS chunk 使用 NetworkFirst3s 超时
- 💡 **建议**可根据实际网络情况调整 `networkTimeoutSeconds`
- 弱网环境可适当增加超时时间5-8s
- 强网环境可减少超时时间1-2s
### 3. 缓存策略优化
- **已实现**CSS图片使用 CacheFirst30天
- 💡 **建议**
- 静态资源logo图标可延长至 90-180
- 业务图片保持 30 确保内容更新及时
### 4. 存储空间管理
- **已实现**按需加载 chunk 限制 100 7 天过期
- 💡 **建议**
- 监控缓存使用情况Chrome DevTools Application Storage
- 根据用户访问模式调整 `maxEntries` `maxAgeSeconds`
### 5. 用户体验优化
- **已实现**Service Worker 后台注册不阻塞页面加载
- 💡 **建议**
- 添加加载提示可选显示"正在准备离线功能"
- 错误处理Service Worker 注册失败时优雅降级
### 6. 性能监控
建议监控以下指标
- **FCPFirst Contentful Paint**目标 < 1.5s
- **LCPLargest Contentful Paint**目标 < 2.5s
- **TTITime to Interactive**目标 < 3.5s
- **缓存命中率**目标 > 80%
## 注意事项
1. **仅生产环境生效** - 开发环境默认禁用
2. **HTTPS 要求** - Service Worker 仅在 HTTPS 或 localhost 下工作
3. **注册代码内联** - 使用 `injectRegister: 'inline'` 避免 `registerSW.js` 缓存问题
4. **手动注册** - Service Worker 通过内联代码自动注册,但**不包含自动更新检测功能**
5. **按需加载适配** - 配置已优化适配 Vue Router 的按需加载,只预缓存关键资源,路由组件 chunk 按需缓存
## 禁用 PWA
如需禁用 PWA 功能,在 `build/vite/plugin/index.ts` 中注释:
```typescript
// vitePlugins.push(configPwaPlugin(isBuild));
```
## 故障排查
### 清除 Service Worker
浏览器控制台执行:
```javascript
navigator.serviceWorker.getRegistrations().then(registrations => {
registrations.forEach(registration => registration.unregister());
});
```
### 检查 Service Worker 状态
- Chrome DevTools → Application → Service Workers
- 查看注册状态和缓存内容

View File

@ -1,106 +0,0 @@
JeecgBoot 企业级低代码开发平台
===============
当前最新版本: 3.9.0预计发布时间2025-12-01
[![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
[![](https://img.shields.io/badge/Author-北京国炬软件-orange.svg)](http://jeecg.com/aboutusIndex)
[![](https://img.shields.io/badge/version-3.9.0-brightgreen.svg)](https://github.com
/zhangdaiscott/jeecg-boot)
[![GitHub stars](https://img.shields.io/github/stars/zhangdaiscott/jeecg-boot.svg?style=social&label=Stars)](https://github.com/zhangdaiscott/jeecg-boot)
[![GitHub forks](https://img.shields.io/github/forks/zhangdaiscott/jeecg-boot.svg?style=social&label=Fork)](https://github.com/zhangdaiscott/jeecg-boot)
## 简介
JeecgBoot-Vue3采用 Vue3.0、Vite、 Ant-Design-Vue4、TypeScript 等新技术方案包括二次封装组件、utils、hooks、动态菜单、权限校验、按钮级别权限控制等功能。
> 强大的代码生成器让前后端代码一键生成! JeecgBoot引领低代码开发模式(OnlineCoding-> 代码生成-> 手工MERGE) 帮助解决Java项目70%的重复工作,让开发更多关注业务。既能快速提高效率,节省成本,同时又不失灵活性
## 开发环境搭建
- [前端开发环境准备](https://help.jeecg.com/setup/dev)
- [前端项目快速启动](https://help.jeecg.com/setup/startup)
- [通过IDEA启动项目](https://help.jeecg.com/java/setup/idea/startup)
## 技术文档
- 官方文档:[https://help.jeecg.com](https://help.jeecg.com)
- 快速入门:[快速入门](http://jeecg.com/doc/quickstart) | [常见问题](http://help.jeecg.com/qa)
- QQ交流群964611995、⑩716488839(满)、⑨808791225(满)、其他满
- 在线演示 [系统演示](http://boot3.jeecg.com) | [APP演示](http://jeecg.com/appIndex)
> 演示系统的登录账号密码,请点击 [获取账号密码](http://jeecg.com/doc/demo) 获取
## 安装与使用
* 本地环境安装 `Node.js 、npm 、pnpm`
* Node.js 版本要求`Node 20+` 版本以上
` ( 因为Vite5 不再支持已 EOL 的 Node.js 14 / 16 / 17 / 19现在需要 Node 20+ )`
- Get the project code
```bash
git clone https://github.com/jeecgboot/JeecgBoot.git
```
- Installation dependencies
```bash
cd JeecgBoot/jeecgboot-vue3
pnpm install
```
- 配置接口地址 `.env.development`
```bash
VITE_PROXY = [["/jeecgboot","http://localhost:8080/jeecg-boot"],["/upload","http://localhost:3300/upload"]]
VITE_GLOB_DOMAIN_URL=http://localhost:8080/jeecg-boot
```
> 说明:把`http://localhost:8080/jeecg-boot` 换成自己地址,其他不用改。
- run
```bash
pnpm dev
```
- build
```bash
pnpm build
```
## 入门必备
本项目需要一定前端基础知识,请确保掌握 Vue 的基础知识,以便能处理一些常见的问题。 建议在开发前先学一下以下内容,提前了解和学习这些知识,会对项目理解非常有帮助:
* [JeecgBoot文档](http://help.jeecg.com)
* [Vue3 文档](https://cn.vuejs.org/)
* [Vben文档](https://doc.vvbin.cn)
* [Ant-Design-Vue](https://www.antdv.com/docs/vue/introduce-cn/)
* [TypeScript](https://www.typescriptlang.org/)
* [Vue-router](https://router.vuejs.org/zh)
* [Es6](https://es6.ruanyifeng.com/)
* [Vitejs](https://cn.vitejs.dev/guide/)
* [Pinia(vuex替代方案)](https://pinia.esm.dev/introduction.html)
* [Vue-RFCS](https://github.com/vuejs/rfcs)
* [vxetable文档](https://vxetable.cn)
## 浏览器支持
**本地开发**推荐使用`Chrome 最新版`浏览器,**不支持**`Chrome 90`以下版本。
**生产环境**支持现代浏览器,不支持 IE。
| [![IE](https://raw.githubusercontent.com/alrra/browser-logos/master/src/archive/internet-explorer_9-11/internet-explorer_9-11_48x48.png)](http://godban.github.io/browsers-support-badges/)IE | [![ Edge](https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png)](http://godban.github.io/browsers-support-badges/)Edge | [![Firefox](https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png)](http://godban.github.io/browsers-support-badges/)Firefox | [![Chrome](https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png)](http://godban.github.io/browsers-support-badges/)Chrome | [![Safari](https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png)](http://godban.github.io/browsers-support-badges/)Safari |
| --- | --- | --- | --- | --- |
| not support | last 2 versions | last 2 versions | last 2 versions | last 2 versions |

View File

@ -2,10 +2,8 @@ import type { AppRouteRecordRaw, AppRouteModule } from '/@/router/types';
import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/routes/basic'; import { PAGE_NOT_FOUND_ROUTE, REDIRECT_ROUTE } from '/@/router/routes/basic';
import { mainOutRoutes } from './mainOut';
import { PageEnum } from '/@/enums/pageEnum'; import { PageEnum } from '/@/enums/pageEnum';
import { t } from '/@/hooks/web/useI18n'; import { t } from '/@/hooks/web/useI18n';
import { LAYOUT } from '/@/router/constant';
const modules = import.meta.glob('./modules/**/*.ts', { eager: true }); const modules = import.meta.glob('./modules/**/*.ts', { eager: true });
@ -65,4 +63,4 @@ export const TokenLoginRoute: AppRouteRecordRaw = {
}, },
}; };
// Basic routing without permission // Basic routing without permission
export const basicRoutes = [LoginRoute, RootRoute, ...mainOutRoutes, REDIRECT_ROUTE, PAGE_NOT_FOUND_ROUTE, TokenLoginRoute, Oauth2LoginRoute]; export const basicRoutes = [LoginRoute, RootRoute, REDIRECT_ROUTE, PAGE_NOT_FOUND_ROUTE, TokenLoginRoute, Oauth2LoginRoute];

View File

@ -1,22 +0,0 @@
/**
The routing of this file will not show the layout.
It is an independent new page.
the contents of the file still need to log in to access
*/
import type { AppRouteModule } from '/@/router/types';
// test
// http:ip:port/main-out
export const mainOutRoutes: AppRouteModule[] = [
{
path: '/main-out',
name: 'MainOut',
component: () => import('/@/views/demo/main-out/index.vue'),
meta: {
title: 'MainOut',
ignoreAuth: true,
},
},
];
export const mainOutRouteNames = mainOutRoutes.map((item) => item.name);

View File

@ -1,79 +0,0 @@
import type { AppRouteModule } from '/@/router/types';
import { getParentLayout, LAYOUT } from '/@/router/constant';
import { t } from '/@/hooks/web/useI18n';
const charts: AppRouteModule = {
path: '/charts',
name: 'Charts',
component: LAYOUT,
redirect: '/charts/echarts/map',
meta: {
orderNo: 500,
icon: 'ion:bar-chart-outline',
title: t('routes.demo.charts.charts'),
},
children: [
{
path: 'baiduMap',
name: 'BaiduMap',
meta: {
title: t('routes.demo.charts.baiduMap'),
},
component: () => import('/@/views/demo/charts/map/Baidu.vue'),
},
{
path: 'aMap',
name: 'AMap',
meta: {
title: t('routes.demo.charts.aMap'),
},
component: () => import('/@/views/demo/charts/map/Gaode.vue'),
},
{
path: 'googleMap',
name: 'GoogleMap',
meta: {
title: t('routes.demo.charts.googleMap'),
},
component: () => import('/@/views/demo/charts/map/Google.vue'),
},
{
path: 'echarts',
name: 'Echarts',
component: getParentLayout('Echarts'),
meta: {
title: 'Echarts',
},
redirect: '/charts/echarts/map',
children: [
{
path: 'map',
name: 'Map',
component: () => import('/@/views/demo/charts/Map.vue'),
meta: {
title: t('routes.demo.charts.map'),
},
},
{
path: 'line',
name: 'Line',
component: () => import('/@/views/demo/charts/Line.vue'),
meta: {
title: t('routes.demo.charts.line'),
},
},
{
path: 'pie',
name: 'Pie',
component: () => import('/@/views/demo/charts/Pie.vue'),
meta: {
title: t('routes.demo.charts.pie'),
},
},
],
},
],
};
export default charts;

View File

@ -1,692 +0,0 @@
import type { AppRouteModule } from '/@/router/types';
import { getParentLayout, LAYOUT } from '/@/router/constant';
import { t } from '/@/hooks/web/useI18n';
const comp: AppRouteModule = {
path: '/comp',
name: 'Comp',
component: LAYOUT,
redirect: '/comp/basic',
meta: {
orderNo: 30,
icon: 'ion:layers-outline',
title: t('routes.demo.comp.comp'),
},
children: [
{
path: 'jeecg',
name: 'JeecgDemo',
redirect: '/comp/jeecg/basic',
component: getParentLayout('JeecgDemo'),
meta: {
title: t('routes.demo.comp.jeecg'),
},
children: [
{
path: 'basic',
name: 'JAreaLinkage',
component: () => import('/@/views/demo/jeecg/JeecgComponents.vue'),
meta: {
title: t('routes.demo.jeecg.JAreaLinkage'),
},
},
{
path: 'oneToMore',
name: 'oneToMoreDemo',
component: () => import('/@/views/demo/vextable/index.vue'),
meta: {
title: t('routes.demo.comp.oneToMore'),
},
},
],
},
{
path: 'basic',
name: 'BasicDemo',
component: getParentLayout('BasicDemo'),
meta: {
title: t('routes.demo.comp.basic'),
},
children: [
{
path: 'button',
name: 'ButtonDemo',
component: () => import('/@/views/demo/comp/button/index.vue'),
meta: {
title: t('routes.demo.basic.button'),
},
},
{
path: 'icon',
name: 'IconDemo',
component: () => import('/@/views/demo/feat/icon/index.vue'),
meta: {
title: t('routes.demo.feat.icon'),
},
},
{
path: 'msg',
name: 'MsgDemo',
component: () => import('/@/views/demo/feat/msg/index.vue'),
meta: {
title: t('routes.demo.feat.msg'),
},
},
{
path: 'tabs',
name: 'TabsDemo',
component: () => import('/@/views/demo/feat/tabs/index.vue'),
meta: {
title: t('routes.demo.feat.tabs'),
hideChildrenInMenu: true,
},
children: [
{
path: 'detail/:id',
name: 'TabDetail',
component: () => import('/@/views/demo/feat/tabs/TabDetail.vue'),
meta: {
currentActiveMenu: '/comp/basic/tabs',
title: t('routes.demo.feat.tabDetail'),
hideMenu: true,
dynamicLevel: 3,
realPath: '/comp/basic/tabs/detail',
},
},
],
},
],
},
{
path: 'form',
name: 'FormDemo',
redirect: '/comp/form/basic',
component: getParentLayout('FormDemo'),
meta: {
// icon: 'mdi:form-select',
title: t('routes.demo.form.form'),
},
children: [
{
path: 'basic',
name: 'FormBasicDemo',
component: () => import('/@/views/demo/form/index.vue'),
meta: {
title: t('routes.demo.form.basic'),
},
},
{
path: 'useForm',
name: 'UseFormDemo',
component: () => import('/@/views/demo/form/UseForm.vue'),
meta: {
title: t('routes.demo.form.useForm'),
},
},
{
path: 'refForm',
name: 'RefFormDemo',
component: () => import('/@/views/demo/form/RefForm.vue'),
meta: {
title: t('routes.demo.form.refForm'),
},
},
{
path: 'advancedForm',
name: 'AdvancedFormDemo',
component: () => import('/@/views/demo/form/AdvancedForm.vue'),
meta: {
title: t('routes.demo.form.advancedForm'),
},
},
{
path: 'ruleForm',
name: 'RuleFormDemo',
component: () => import('/@/views/demo/form/RuleForm.vue'),
meta: {
title: t('routes.demo.form.ruleForm'),
},
},
{
path: 'dynamicForm',
name: 'DynamicFormDemo',
component: () => import('/@/views/demo/form/DynamicForm.vue'),
meta: {
title: t('routes.demo.form.dynamicForm'),
},
},
{
path: 'customerForm',
name: 'CustomerFormDemo',
component: () => import('/@/views/demo/form/CustomerForm.vue'),
meta: {
title: t('routes.demo.form.customerForm'),
},
},
{
path: 'appendForm',
name: 'appendFormDemo',
component: () => import('/@/views/demo/form/AppendForm.vue'),
meta: {
title: t('routes.demo.form.appendForm'),
},
},
],
},
{
path: 'table',
name: 'TableDemo',
redirect: '/comp/table/basic',
component: getParentLayout('TableDemo'),
meta: {
// icon: 'carbon:table-split',
title: t('routes.demo.table.table'),
},
children: [
{
path: 'basic',
name: 'TableBasicDemo',
component: () => import('/@/views/demo/table/Basic.vue'),
meta: {
title: t('routes.demo.table.basic'),
},
},
{
path: 'treeTable',
name: 'TreeTableDemo',
component: () => import('/@/views/demo/table/TreeTable.vue'),
meta: {
title: t('routes.demo.table.treeTable'),
},
},
{
path: 'fetchTable',
name: 'FetchTableDemo',
component: () => import('/@/views/demo/table/FetchTable.vue'),
meta: {
title: t('routes.demo.table.fetchTable'),
},
},
{
path: 'fixedColumn',
name: 'FixedColumnDemo',
component: () => import('/@/views/demo/table/FixedColumn.vue'),
meta: {
title: t('routes.demo.table.fixedColumn'),
},
},
{
path: 'customerCell',
name: 'CustomerCellDemo',
component: () => import('/@/views/demo/table/CustomerCell.vue'),
meta: {
title: t('routes.demo.table.customerCell'),
},
},
{
path: 'formTable',
name: 'FormTableDemo',
component: () => import('/@/views/demo/table/FormTable.vue'),
meta: {
title: t('routes.demo.table.formTable'),
},
},
{
path: 'useTable',
name: 'UseTableDemo',
component: () => import('/@/views/demo/table/UseTable.vue'),
meta: {
title: t('routes.demo.table.useTable'),
},
},
{
path: 'refTable',
name: 'RefTableDemo',
component: () => import('/@/views/demo/table/RefTable.vue'),
meta: {
title: t('routes.demo.table.refTable'),
},
},
{
path: 'multipleHeader',
name: 'MultipleHeaderDemo',
component: () => import('/@/views/demo/table/MultipleHeader.vue'),
meta: {
title: t('routes.demo.table.multipleHeader'),
},
},
{
path: 'mergeHeader',
name: 'MergeHeaderDemo',
component: () => import('/@/views/demo/table/MergeHeader.vue'),
meta: {
title: t('routes.demo.table.mergeHeader'),
},
},
{
path: 'nestedTable',
name: 'nestedTableDemo',
component: () => import('/@/views/demo/table/NestedTable.vue'),
meta: {
title: t('routes.demo.table.nestedTable'),
},
},
{
path: 'expandTable',
name: 'ExpandTableDemo',
component: () => import('/@/views/demo/table/ExpandTable.vue'),
meta: {
title: t('routes.demo.table.expandTable'),
},
},
{
path: 'fixedHeight',
name: 'FixedHeightDemo',
component: () => import('/@/views/demo/table/FixedHeight.vue'),
meta: {
title: t('routes.demo.table.fixedHeight'),
},
},
{
path: 'footerTable',
name: 'FooterTableDemo',
component: () => import('/@/views/demo/table/FooterTable.vue'),
meta: {
title: t('routes.demo.table.footerTable'),
},
},
{
path: 'editCellTable',
name: 'EditCellTableDemo',
component: () => import('/@/views/demo/table/EditCellTable.vue'),
meta: {
title: t('routes.demo.table.editCellTable'),
},
},
{
path: 'editRowTable',
name: 'EditRowTableDemo',
component: () => import('/@/views/demo/table/EditRowTable.vue'),
meta: {
title: t('routes.demo.table.editRowTable'),
},
},
{
path: 'authColumn',
name: 'AuthColumnDemo',
component: () => import('/@/views/demo/table/AuthColumn.vue'),
meta: {
title: t('routes.demo.table.authColumn'),
},
},
],
},
{
path: 'modal',
name: 'ModalDemo',
redirect: '/comp/modal/basic',
component: getParentLayout('ModalDemo'),
meta: {
title: t('routes.demo.comp.modal'),
},
children: [
{
path: 'basic',
name: 'ModalBasicDemo',
component: () => import('/@/views/demo/comp/modal/index.vue'),
meta: {
title: t('routes.demo.comp.modal.basic'),
},
},
{
path: 'drawer',
name: 'DrawerDemo',
component: () => import('/@/views/demo/comp/drawer/index.vue'),
meta: {
title: t('routes.demo.comp.modal.drawer'),
},
},
],
},
{
path: 'third',
name: 'ThirdDemo',
redirect: '/comp/third/basic',
component: getParentLayout('ModalDemo'),
meta: {
title: t('routes.demo.comp.third'),
},
children: [
{
path: 'basic',
name: 'CropperDemo',
component: () => import('/@/views/demo/comp/cropper/index.vue'),
meta: {
title: t('routes.demo.comp.cropperImage'),
},
},
{
path: 'qrcode',
name: 'QrCodeDemo',
component: () => import('/@/views/demo/comp/qrcode/index.vue'),
meta: {
title: t('routes.demo.comp.qrcode'),
},
},
{
path: 'strength-meter',
name: 'StrengthMeterDemo',
component: () => import('/@/views/demo/comp/strength-meter/index.vue'),
meta: {
title: t('routes.demo.comp.strength'),
},
},
{
path: 'upload',
name: 'UploadDemo',
component: () => import('/@/views/demo/comp/upload/index.vue'),
meta: {
title: t('routes.demo.comp.upload'),
},
},
{
path: 'loading',
name: 'LoadingDemo',
component: () => import('/@/views/demo/comp/loading/index.vue'),
meta: {
title: t('routes.demo.comp.loading'),
},
},
{
path: 'timestamp',
name: 'TimeDemo',
component: () => import('/@/views/demo/comp/time/index.vue'),
meta: {
title: t('routes.demo.comp.time'),
},
},
{
path: 'countTo',
name: 'CountTo',
component: () => import('/@/views/demo/comp/count-to/index.vue'),
meta: {
title: t('routes.demo.comp.countTo'),
},
},
{
path: 'transition',
name: 'transitionDemo',
component: () => import('/@/views/demo/comp/transition/index.vue'),
meta: {
title: t('routes.demo.comp.transition'),
},
},
{
path: 'print',
name: 'Print',
component: () => import('/@/views/demo/feat/print/index.vue'),
meta: {
title: t('routes.demo.feat.print'),
},
},
{
path: 'img-preview',
name: 'ImgPreview',
component: () => import('/@/views/demo/feat/img-preview/index.vue'),
meta: {
title: t('routes.demo.feat.imgPreview'),
},
},
{
path: 'download',
name: 'DownLoadDemo',
component: () => import('/@/views/demo/feat/download/index.vue'),
meta: {
title: t('routes.demo.feat.download'),
},
},
{
path: 'click-out-side',
name: 'ClickOutSideDemo',
component: () => import('/@/views/demo/feat/click-out-side/index.vue'),
meta: {
title: t('routes.demo.feat.clickOutSide'),
},
},
{
path: 'copy',
name: 'CopyDemo',
component: () => import('/@/views/demo/feat/copy/index.vue'),
meta: {
title: t('routes.demo.feat.copy'),
},
},
{
path: 'ripple',
name: 'RippleDemo',
component: () => import('/@/views/demo/feat/ripple/index.vue'),
meta: {
title: t('routes.demo.feat.ripple'),
},
},
],
},
{
path: 'tree',
name: 'TreeDemo',
redirect: '/comp/tree/basic',
component: getParentLayout('TreeDemo'),
meta: {
// icon: 'clarity:tree-view-line',
title: t('routes.demo.comp.tree'),
},
children: [
{
path: 'basic',
name: 'BasicTreeDemo',
component: () => import('/@/views/demo/tree/index.vue'),
meta: {
title: t('routes.demo.comp.treeBasic'),
},
},
{
path: 'editTree',
name: 'EditTreeDemo',
component: () => import('/@/views/demo/tree/EditTree.vue'),
meta: {
title: t('routes.demo.comp.editTree'),
},
},
{
path: 'actionTree',
name: 'ActionTreeDemo',
component: () => import('/@/views/demo/tree/ActionTree.vue'),
meta: {
title: t('routes.demo.comp.actionTree'),
},
},
],
},
{
path: 'editor',
name: 'EditorDemo',
redirect: '/comp/editor/markdown',
component: getParentLayout('EditorDemo'),
meta: {
// icon: 'carbon:table-split',
title: t('routes.demo.editor.editor'),
},
children: [
{
path: 'json',
component: () => import('/@/views/demo/editor/json/index.vue'),
name: 'JsonEditorDemo',
meta: {
title: t('routes.demo.editor.jsonEditor'),
},
},
{
path: 'markdown',
component: getParentLayout('MarkdownDemo'),
name: 'MarkdownDemo',
meta: {
title: t('routes.demo.editor.markdown'),
},
redirect: '/comp/editor/markdown/index',
children: [
{
path: 'index',
name: 'MarkDownBasicDemo',
component: () => import('/@/views/demo/editor/markdown/index.vue'),
meta: {
title: t('routes.demo.editor.tinymceBasic'),
},
},
{
path: 'editor',
name: 'MarkDownFormDemo',
component: () => import('/@/views/demo/editor/markdown/Editor.vue'),
meta: {
title: t('routes.demo.editor.tinymceForm'),
},
},
],
},
{
path: 'tinymce',
component: getParentLayout('TinymceDemo'),
name: 'TinymceDemo',
meta: {
title: t('routes.demo.editor.tinymce'),
},
redirect: '/comp/editor/tinymce/index',
children: [
{
path: 'index',
name: 'TinymceBasicDemo',
component: () => import('/@/views/demo/editor/tinymce/index.vue'),
meta: {
title: t('routes.demo.editor.tinymceBasic'),
},
},
{
path: 'editor',
name: 'TinymceFormDemo',
component: () => import('/@/views/demo/editor/tinymce/Editor.vue'),
meta: {
title: t('routes.demo.editor.tinymceForm'),
},
},
],
},
],
},
{
path: 'scroll',
name: 'ScrollDemo',
redirect: '/comp/scroll/basic',
component: getParentLayout('ScrollDemo'),
meta: {
title: t('routes.demo.comp.scroll'),
},
children: [
{
path: 'basic',
name: 'BasicScrollDemo',
component: () => import('/@/views/demo/comp/scroll/index.vue'),
meta: {
title: t('routes.demo.comp.scrollBasic'),
},
},
{
path: 'action',
name: 'ActionScrollDemo',
component: () => import('/@/views/demo/comp/scroll/Action.vue'),
meta: {
title: t('routes.demo.comp.scrollAction'),
},
},
{
path: 'virtualScroll',
name: 'VirtualScrollDemo',
component: () => import('/@/views/demo/comp/scroll/VirtualScroll.vue'),
meta: {
title: t('routes.demo.comp.virtualScroll'),
},
},
],
},
{
path: 'desc',
name: 'DescDemo',
component: () => import('/@/views/demo/comp/desc/index.vue'),
meta: {
title: t('routes.demo.comp.desc'),
},
},
{
path: 'lazy',
name: 'LazyDemo',
component: getParentLayout('LazyDemo'),
redirect: '/comp/lazy/basic',
meta: {
title: t('routes.demo.comp.lazy'),
},
children: [
{
path: 'basic',
name: 'BasicLazyDemo',
component: () => import('/@/views/demo/comp/lazy/index.vue'),
meta: {
title: t('routes.demo.comp.lazyBasic'),
},
},
{
path: 'transition',
name: 'BasicTransitionDemo',
component: () => import('/@/views/demo/comp/lazy/Transition.vue'),
meta: {
title: t('routes.demo.comp.lazyTransition'),
},
},
],
},
{
path: 'verify',
name: 'VerifyDemo',
component: getParentLayout('VerifyDemo'),
redirect: '/comp/verify/drag',
meta: {
title: t('routes.demo.comp.verify'),
},
children: [
{
path: 'drag',
name: 'VerifyDragDemo',
component: () => import('/@/views/demo/comp/verify/index.vue'),
meta: {
title: t('routes.demo.comp.verifyDrag'),
},
},
{
path: 'rotate',
name: 'VerifyRotateDemo',
component: () => import('/@/views/demo/comp/verify/Rotate.vue'),
meta: {
title: t('routes.demo.comp.verifyRotate'),
},
},
],
},
],
};
export default comp;

View File

@ -1,196 +0,0 @@
import type { AppRouteModule } from '/@/router/types';
import { getParentLayout, LAYOUT } from '/@/router/constant';
import { t } from '/@/hooks/web/useI18n';
const feat: AppRouteModule = {
path: '/feat',
name: 'FeatDemo',
component: LAYOUT,
redirect: '/feat/icon',
meta: {
orderNo: 19,
icon: 'ion:git-compare-outline',
title: t('routes.demo.feat.feat'),
},
children: [
{
path: 'ws',
name: 'WebSocket',
component: () => import('/@/views/demo/feat/ws/index.vue'),
meta: {
title: t('routes.demo.feat.ws'),
},
},
{
path: 'session-timeout',
name: 'SessionTimeout',
component: () => import('/@/views/demo/feat/session-timeout/index.vue'),
meta: {
title: t('routes.demo.feat.sessionTimeout'),
},
},
{
path: 'breadcrumb',
name: 'BreadcrumbDemo',
redirect: '/feat/breadcrumb/flat',
component: getParentLayout('BreadcrumbDemo'),
meta: {
title: t('routes.demo.feat.breadcrumb'),
},
children: [
{
path: 'flat',
name: 'BreadcrumbFlatDemo',
component: () => import('/@/views/demo/feat/breadcrumb/FlatList.vue'),
meta: {
title: t('routes.demo.feat.breadcrumbFlat'),
},
},
{
path: 'flatDetail',
name: 'BreadcrumbFlatDetailDemo',
component: () => import('/@/views/demo/feat/breadcrumb/FlatListDetail.vue'),
meta: {
title: t('routes.demo.feat.breadcrumbFlatDetail'),
hideMenu: true,
hideTab: true,
currentActiveMenu: '/feat/breadcrumb/flat',
},
},
{
path: 'children',
name: 'BreadcrumbChildrenDemo',
component: () => import('/@/views/demo/feat/breadcrumb/ChildrenList.vue'),
meta: {
title: t('routes.demo.feat.breadcrumbChildren'),
},
children: [
{
path: 'childrenDetail',
name: 'BreadcrumbChildrenDetailDemo',
component: () => import('/@/views/demo/feat/breadcrumb/ChildrenListDetail.vue'),
meta: {
currentActiveMenu: '/feat/breadcrumb/children',
title: t('routes.demo.feat.breadcrumbChildrenDetail'),
//hideTab: true,
// hideMenu: true,
},
},
],
},
],
},
{
path: 'context-menu',
name: 'ContextMenuDemo',
component: () => import('/@/views/demo/feat/context-menu/index.vue'),
meta: {
title: t('routes.demo.feat.contextMenu'),
},
},
{
path: 'copy',
name: 'CopyDemo',
component: () => import('/@/views/demo/feat/copy/index.vue'),
meta: {
title: t('routes.demo.feat.copy'),
},
},
{
path: 'watermark',
name: 'WatermarkDemo',
component: () => import('/@/views/demo/feat/watermark/index.vue'),
meta: {
title: t('routes.demo.feat.watermark'),
},
},
{
path: 'full-screen',
name: 'FullScreenDemo',
component: () => import('/@/views/demo/feat/full-screen/index.vue'),
meta: {
title: t('routes.demo.feat.fullScreen'),
},
},
{
path: '/error-log',
name: 'ErrorLog',
component: () => import('/@/views/sys/error-log/index.vue'),
meta: {
title: t('routes.demo.feat.errorLog'),
},
},
{
path: 'testTab/:id',
name: 'TestTab',
component: () => import('/@/views/demo/feat/tab-params/index.vue'),
meta: {
title: t('routes.demo.feat.tab'),
carryParam: true,
hidePathForChildren: true,
},
children: [
{
path: 'testTab/id1',
name: 'TestTab1',
component: () => import('/@/views/demo/feat/tab-params/index.vue'),
meta: {
title: t('routes.demo.feat.tab1'),
carryParam: true,
ignoreRoute: true,
},
},
{
path: 'testTab/id2',
name: 'TestTab2',
component: () => import('/@/views/demo/feat/tab-params/index.vue'),
meta: {
title: t('routes.demo.feat.tab2'),
carryParam: true,
ignoreRoute: true,
},
},
],
},
{
path: 'testParam/:id',
name: 'TestParam',
component: getParentLayout('TestParam'),
meta: {
title: t('routes.demo.feat.menu'),
ignoreKeepAlive: true,
},
children: [
{
path: 'sub1',
name: 'TestParam_1',
component: () => import('/@/views/demo/feat/menu-params/index.vue'),
meta: {
title: t('routes.demo.feat.menu1'),
ignoreKeepAlive: true,
},
},
{
path: 'sub2',
name: 'TestParam_2',
component: () => import('/@/views/demo/feat/menu-params/index.vue'),
meta: {
title: t('routes.demo.feat.menu2'),
ignoreKeepAlive: true,
},
},
],
},
],
};
export default feat;

View File

@ -1,48 +0,0 @@
import type { AppRouteModule } from '/@/router/types';
import { LAYOUT } from '/@/router/constant';
const IFrame = () => import('/@/views/sys/iframe/FrameBlank.vue');
import { t } from '/@/hooks/web/useI18n';
const iframe: AppRouteModule = {
path: '/frame',
name: 'Frame',
component: LAYOUT,
redirect: '/frame/doc',
meta: {
orderNo: 1000,
icon: 'ion:tv-outline',
title: t('routes.demo.iframe.frame'),
},
children: [
{
path: 'doc',
name: 'Doc',
component: IFrame,
meta: {
frameSrc: 'https://vvbin.cn/doc-next/',
title: t('routes.demo.iframe.doc'),
},
},
{
path: 'antv',
name: 'Antv',
component: IFrame,
meta: {
frameSrc: 'https://2x.antdv.com/docs/vue/introduce-cn/',
title: t('routes.demo.iframe.antv'),
},
},
{
path: 'https://vvbin.cn/doc-next/',
name: 'DocExternal',
component: IFrame,
meta: {
title: t('routes.demo.iframe.docExternal'),
},
},
],
};
export default iframe;

View File

@ -1,68 +0,0 @@
import type { AppRouteModule } from '/@/router/types';
import { getParentLayout, LAYOUT } from '/@/router/constant';
import { t } from '/@/hooks/web/useI18n';
const permission: AppRouteModule = {
path: '/level',
name: 'Level',
component: LAYOUT,
redirect: '/level/menu1/menu1-1/menu1-1-1',
meta: {
orderNo: 2000,
icon: 'ion:menu-outline',
title: t('routes.demo.level.level'),
},
children: [
{
path: 'menu1',
name: 'Menu1Demo',
component: getParentLayout('Menu1Demo'),
meta: {
title: 'Menu1',
},
redirect: '/level/menu1/menu1-1/menu1-1-1',
children: [
{
path: 'menu1-1',
name: 'Menu11Demo',
component: getParentLayout('Menu11Demo'),
meta: {
title: 'Menu1-1',
},
redirect: '/level/menu1/menu1-1/menu1-1-1',
children: [
{
path: 'menu1-1-1',
name: 'Menu111Demo',
component: () => import('/@/views/demo/level/Menu111.vue'),
meta: {
title: 'Menu111',
},
},
],
},
{
path: 'menu1-2',
name: 'Menu12Demo',
component: () => import('/@/views/demo/level/Menu12.vue'),
meta: {
title: 'Menu1-2',
},
},
],
},
{
path: 'menu2',
name: 'Menu2Demo',
component: () => import('/@/views/demo/level/Menu2.vue'),
meta: {
title: 'Menu2',
// ignoreKeepAlive: true,
},
},
],
};
export default permission;

View File

@ -1,255 +0,0 @@
import type { AppRouteModule } from '/@/router/types';
import { getParentLayout, LAYOUT } from '/@/router/constant';
import { ExceptionEnum } from '/@/enums/exceptionEnum';
import { t } from '/@/hooks/web/useI18n';
const ExceptionPage = () => import('/@/views/sys/exception/Exception.vue');
const page: AppRouteModule = {
path: '/page-demo',
name: 'PageDemo',
component: LAYOUT,
redirect: '/page-demo/form/basic',
meta: {
orderNo: 20,
icon: 'ion:aperture-outline',
title: t('routes.demo.page.page'),
},
children: [
// =============================form start=============================
{
path: 'form',
name: 'FormPage',
redirect: '/page-demo/form/basic',
component: getParentLayout('FormPage'),
meta: {
title: t('routes.demo.page.form'),
},
children: [
{
path: 'basic',
name: 'FormBasicPage',
component: () => import('/@/views/demo/page/form/basic/index.vue'),
meta: {
title: t('routes.demo.page.formBasic'),
},
},
{
path: 'step',
name: 'FormStepPage',
component: () => import('/@/views/demo/page/form/step/index.vue'),
meta: {
title: t('routes.demo.page.formStep'),
},
},
{
path: 'high',
name: 'FormHightPage',
component: () => import('/@/views/demo/page/form/high/index.vue'),
meta: {
title: t('routes.demo.page.formHigh'),
},
},
],
},
// =============================form end=============================
// =============================desc start=============================
{
path: 'desc',
name: 'DescPage',
component: getParentLayout('DescPage'),
redirect: '/page-demo/desc/basic',
meta: {
title: t('routes.demo.page.desc'),
},
children: [
{
path: 'basic',
name: 'DescBasicPage',
component: () => import('/@/views/demo/page/desc/basic/index.vue'),
meta: {
title: t('routes.demo.page.descBasic'),
},
},
{
path: 'high',
name: 'DescHighPage',
component: () => import('/@/views/demo/page/desc/high/index.vue'),
meta: {
title: t('routes.demo.page.descHigh'),
},
},
],
},
// =============================desc end=============================
// =============================result start=============================
{
path: 'result',
name: 'ResultPage',
redirect: '/page-demo/result/success',
component: getParentLayout('ResultPage'),
meta: {
title: t('routes.demo.page.result'),
},
children: [
{
path: 'success',
name: 'ResultSuccessPage',
component: () => import('/@/views/demo/page/result/success/index.vue'),
meta: {
title: t('routes.demo.page.resultSuccess'),
},
},
{
path: 'fail',
name: 'ResultFailPage',
component: () => import('/@/views/demo/page/result/fail/index.vue'),
meta: {
title: t('routes.demo.page.resultFail'),
},
},
],
},
// =============================result end=============================
// =============================account start=============================
{
path: 'account',
name: 'AccountPage',
component: getParentLayout('AccountPage'),
redirect: '/page-demo/account/setting',
meta: {
title: t('routes.demo.page.account'),
},
children: [
{
path: 'center',
name: 'AccountCenterPage',
component: () => import('/@/views/demo/page/account/center/index.vue'),
meta: {
title: t('routes.demo.page.accountCenter'),
},
},
{
path: 'setting',
name: 'AccountSettingPage',
component: () => import('/@/views/demo/page/account/setting/index.vue'),
meta: {
title: t('routes.demo.page.accountSetting'),
},
},
],
},
// =============================account end=============================
// =============================exception start=============================
{
path: 'exception',
name: 'ExceptionPage',
component: getParentLayout('ExceptionPage'),
redirect: '/page-demo/exception/404',
meta: {
title: t('routes.demo.page.exception'),
},
children: [
{
path: '403',
name: 'PageNotAccess',
component: ExceptionPage,
props: {
status: ExceptionEnum.PAGE_NOT_ACCESS,
},
meta: {
title: '403',
},
},
{
path: '404',
name: 'PageNotFound',
component: ExceptionPage,
props: {
status: ExceptionEnum.PAGE_NOT_FOUND,
},
meta: {
title: '404',
},
},
{
path: '500',
name: 'ServiceError',
component: ExceptionPage,
props: {
status: ExceptionEnum.ERROR,
},
meta: {
title: '500',
},
},
{
path: 'net-work-error',
name: 'NetWorkError',
component: ExceptionPage,
props: {
status: ExceptionEnum.NET_WORK_ERROR,
},
meta: {
title: t('routes.demo.page.netWorkError'),
},
},
{
path: 'not-data',
name: 'NotData',
component: ExceptionPage,
props: {
status: ExceptionEnum.PAGE_NOT_DATA,
},
meta: {
title: t('routes.demo.page.notData'),
},
},
],
},
// =============================exception end=============================
// =============================list start=============================
{
path: 'list',
name: 'ListPage',
component: getParentLayout('ListPage'),
redirect: '/page-demo/list/card',
meta: {
title: t('routes.demo.page.list'),
},
children: [
{
path: 'basic',
name: 'ListBasicPage',
component: () => import('/@/views/demo/page/list/basic/index.vue'),
meta: {
title: t('routes.demo.page.listBasic'),
},
},
{
path: 'card',
name: 'ListCardPage',
component: () => import('/@/views/demo/page/list/card/index.vue'),
meta: {
title: t('routes.demo.page.listCard'),
},
},
{
path: 'search',
name: 'ListSearchPage',
component: () => import('/@/views/demo/page/list/search/index.vue'),
meta: {
title: t('routes.demo.page.listSearch'),
},
},
],
},
// =============================list end=============================
],
};
export default page;

View File

@ -1,92 +0,0 @@
import type { AppRouteModule } from '/@/router/types';
import { getParentLayout, LAYOUT } from '/@/router/constant';
import { RoleEnum } from '/@/enums/roleEnum';
import { t } from '/@/hooks/web/useI18n';
const permission: AppRouteModule = {
path: '/permission',
name: 'Permission',
component: LAYOUT,
redirect: '/permission/front/page',
meta: {
orderNo: 15,
icon: 'ion:key-outline',
title: t('routes.demo.permission.permission'),
},
children: [
{
path: 'front',
name: 'PermissionFrontDemo',
component: getParentLayout('PermissionFrontDemo'),
meta: {
title: t('routes.demo.permission.front'),
},
children: [
{
path: 'page',
name: 'FrontPageAuth',
component: () => import('/@/views/demo/permission/front/index.vue'),
meta: {
title: t('routes.demo.permission.frontPage'),
},
},
{
path: 'btn',
name: 'FrontBtnAuth',
component: () => import('/@/views/demo/permission/front/Btn.vue'),
meta: {
title: t('routes.demo.permission.frontBtn'),
},
},
{
path: 'auth-pageA',
name: 'FrontAuthPageA',
component: () => import('/@/views/demo/permission/front/AuthPageA.vue'),
meta: {
title: t('routes.demo.permission.frontTestA'),
roles: [RoleEnum.SUPER],
},
},
{
path: 'auth-pageB',
name: 'FrontAuthPageB',
component: () => import('/@/views/demo/permission/front/AuthPageB.vue'),
meta: {
title: t('routes.demo.permission.frontTestB'),
roles: [RoleEnum.TEST],
},
},
],
},
{
path: 'back',
name: 'PermissionBackDemo',
component: getParentLayout('PermissionBackDemo'),
meta: {
title: t('routes.demo.permission.back'),
},
children: [
{
path: 'page',
name: 'BackAuthPage',
component: () => import('/@/views/demo/permission/back/index.vue'),
meta: {
title: t('routes.demo.permission.backPage'),
},
},
{
path: 'btn',
name: 'BackAuthBtn',
component: () => import('/@/views/demo/permission/back/Btn.vue'),
meta: {
title: t('routes.demo.permission.backBtn'),
},
},
],
},
],
};
export default permission;

View File

@ -1,31 +0,0 @@
import type { AppRouteModule } from '/@/router/types';
import { LAYOUT } from '/@/router/constant';
import { t } from '/@/hooks/web/useI18n';
const setup: AppRouteModule = {
path: '/setup',
name: 'SetupDemo',
component: LAYOUT,
redirect: '/setup/index',
meta: {
orderNo: 90000,
hideChildrenInMenu: true,
icon: 'whh:paintroll',
title: t('routes.demo.setup.page'),
},
children: [
{
path: 'index',
name: 'SetupDemoPage',
component: () => import('/@/views/demo/setup/index.vue'),
meta: {
title: t('routes.demo.setup.page'),
icon: 'whh:paintroll',
hideMenu: true,
},
},
],
};
export default setup;

View File

@ -1,86 +0,0 @@
import type { AppRouteModule } from '/@/router/types';
import { LAYOUT } from '/@/router/constant';
import { t } from '/@/hooks/web/useI18n';
const system: AppRouteModule = {
path: '/system',
name: 'System',
component: LAYOUT,
redirect: '/system/account',
meta: {
orderNo: 2000,
icon: 'ion:settings-outline',
title: t('routes.demo.system.moduleName'),
},
children: [
{
path: 'test',
name: 'TestManagement',
meta: {
title: t('routes.demo.system.test'),
ignoreKeepAlive: true,
},
component: () => import('/@/views/demo/system/test/index.vue'),
},
{
path: 'account',
name: 'AccountManagement',
meta: {
title: t('routes.demo.system.account'),
ignoreKeepAlive: false,
},
component: () => import('/@/views/demo/system/account/index.vue'),
},
{
path: 'account_detail/:id',
name: 'AccountDetail',
meta: {
hideMenu: true,
title: t('routes.demo.system.account_detail'),
ignoreKeepAlive: true,
showMenu: false,
currentActiveMenu: '/system/account',
},
component: () => import('/@/views/demo/system/account/AccountDetail.vue'),
},
{
path: 'role',
name: 'RoleManagement',
meta: {
title: t('routes.demo.system.role'),
ignoreKeepAlive: true,
},
component: () => import('/@/views/demo/system/role/index.vue'),
},
{
path: 'menu',
name: 'MenuManagement',
meta: {
title: t('routes.demo.system.menu'),
ignoreKeepAlive: true,
},
component: () => import('/@/views/demo/system/menu/index.vue'),
},
{
path: 'dept',
name: 'DeptManagement',
meta: {
title: t('routes.demo.system.dept'),
ignoreKeepAlive: true,
},
component: () => import('/@/views/demo/system/dept/index.vue'),
},
{
path: 'changePassword',
name: 'ChangePassword',
meta: {
title: t('routes.demo.system.password'),
ignoreKeepAlive: true,
},
component: () => import('/@/views/demo/system/password/index.vue'),
},
],
};
export default system;

View File

@ -1,117 +0,0 @@
<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>

View File

@ -1,75 +0,0 @@
<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>

View File

@ -1,135 +0,0 @@
<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>

View File

@ -1,100 +0,0 @@
<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>

View File

@ -1,839 +0,0 @@
{
"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¿¥I†j@¢"],
["@@…¡‰@ˆV^RqˆBbAŒnTXeRz¤Lž«³I"],
["@@ÆEE—„kWqë @œ"],
["@@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ģŒc†JŠ›e"],
["@@U`Ts¿m‚"],
[
"@@oºƋÄd–eVŽDJj£€J|Ådz•Ft~ž¸IÆv|”‡¢r}膎onb˜}`RÎÄn°ÒdÞ²„’lnÐèĄlðӜ×]ªÆ}LiĂ±Ö`^°Ç¶p®đDcœŋ`–’¶êqvFƚ†N®ĆTH®¦O’¾ŠIbÐã´BĐɢŴÆíȦp–ĐÞXR€·nndOž¤’OÀĈƒ­Qg˜µFo|gȒęSWb©osx|hYh•gŃfmÖĩnº€’Sp›¢dYĤ¶UĈjl’ǐpäìë|³kÛfw²Xjz~ÂqbTŠÑ„ěŨ@|oM‡’zv¢ZrÃVw¬ŧˏfŒ°ÐT€ªqŽs{Sž¯r æÝlNd®²Ğ džiGʂJ™¼lr}~K¨ŸƐÌWö€™ÆŠzRš¤lêmĞL΄’@¡|q]SvK€ÑcwpÏρ†ĿćènĪWlĄkT}ˆJ”¤~ƒÈT„d„™pddʾĬŠ”ŽBVt„EÀ¢ôPĎƗè@~‚k–ü\\rÊĔÖæW_§¼F˜†´©òDòj’ˆYÈrbĞāøŀG{ƀ|¦ðrb|ÀH`pʞkv‚GpuARhÞÆǶgƊTǼƹS£¨¡ù³ŘÍ]¿Ây™ôEP xX¶¹܇“gÚ¡IwÃ鑦ÅB‡Ï|ǰ…N«úmH¯‹âŸŽžŲIÄuШDž•¸‡‚FŸƒ•›Oh‡đ©OŸ›iÃ`ww^ƒÌkŸ‘ÑH«ƇǤŗĺtFu…{Z}Ö@U‡´…ʚLg®¯Oı°ÃwŸ ^˜—€VbÉs‡ˆmA…ê]]w„§›RRl£‡ȭµu¯b{ÍDěïÿȧŽuT£ġƒěŗƃĝ“Q¨fV†Ƌ•ƅn­a@‘³@šď„yýIĹÊKšŭfċŰóŒxV@tˆƯŒJ”]eƒR¾fe|rHA˜|h~Ėƍl§ÏŠlTíb ØoˆÅbbx³^zÃ͚¶Sj®A”yÂhðk`š«P€”ˈµEF†Û¬Y¨Ļrõqi¼‰Wi°§’б´°^[ˆÀ|ĠO@ÆxO\\tŽa\\tĕtû{ġŒȧXýĪÓjùÎRb›š›fK[ݏděYfíÙTyŽuUSyŌŏů@Oi½’éŅ­aVcř§ax¹XŻác‡žWU£ôãºQ¨÷Ñws¥qEH‰Ù|‰›šYQoŕÇyáĂ£MðoťÊ‰P¡mšWO¡€v†{ôvîēÜISpÌhp¨ ‘j†deŔQÖj˜X³à™Ĉ[n`Yp@Už–cM`’RKhŒEbœ”lNut®Etq‚nsÁŠgA‹‹oH‡qCX‡”hfgu“‹WP½¢G^}¯ÅīGCŸÑ^ãziMáļMTÃƘrMc|O_ž¯Ŏ´|‡morDkO\\mĆJfl@c̬¢aĦtRıҙ¾ùƀ^juųœK­ƒUFy™—Ɲ…›īÛ÷ąV×qƥV¿aȉd³B›qPBm›aËđŻģm“Å®Vйd^K‡KoŸnYg“¯Xhqa”Ldu¥•ÍpDž¡KąÅƒkĝęěhq‡}HyÓ]¹ǧ£…Í÷¿qáµ§š™g‘¤o^á¾ZE‡¤i`ij{n•ƒOl»ŸWÝĔįhg›F[¿¡—ßkOüš_‰€ū‹i„DZàUtėGylƒ}ŒÓM}€jpEC~¡FtoQi‘šHkk{Ã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": [
"@@Þĩ҃S‰ra}Á€yWix±Üe´“ßÓǏok‘ćiµVZģ¡coœ‘TS˹ĪmnÕńe–hZg{gtwªpXaĚThȑp{¶Eh—®RćƑP¿£‘Pmc¸mQÝW•ďȥoÅîɡųAďä³aωJ‘½¥PG­ąSM­™…EÅruµé€‘Ž•Ō_d›ĒCo­Èµ]¯_²ÕjāŽK~©ÅØ^ԛkïçămϑk]­±ƒcݯÑÃmQÍ~_a—pm…~ç¡q“ˆu{JÅŧ·Ls}–EyÁÆcI{¤IiCfUc•ƌÃp§]웫vD@¡SÀ‘µM‚ÅwuŽYY‡¡DbÑc¡hƒ×]nkoQdaMç~eD•ÛtT‰©±@¥ù@É¡‰ZcW|WqOJmĩl«ħşvOÓ«IqăV—¥ŸD[mI~Ó¢cehiÍ]Ɠ~ĥqXŠ·eƷœ“}v•[ěďŽŕ]_‘œ•`‰¹ƒ§ÕōI™o©b­s^}Ét±ū«³p£ÿ·Wµ|¡¥ăFÏs׌¥ŅxŸÊdÒ{ºvĴÎêÌɊ²¶€ü¨|ÞƸµȲ‘LLúÉƎ¤ϊęĔV`„_bª‹S^|ŸdŠzY|dz¥p†ZbÆ£¶ÒK}tĦÔņƠ‚PYzn€ÍvX¶Ěn ĠÔ„zý¦ª˜÷žÑĸَ¸‚dòÜJð´’ìúNM¬ŒXZ´‘¤ŊǸ_tldIš{¦ƀðĠȤ¥NehXnYG‚‡ Ƭ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": [
[
"@@¯PqƒFB…‰|S•³C|kñ•H‹d‘iÄ¥sˆʼnő…PóÑÑE^‘ÅPpy_YtS™hQ·aHwsOnʼnÚs©iqj›‰€USiº]ïWš‰«gW¡A–Rë¥_ŽsgÁnUI«m‰…„‹]j‡vV¼euhwqA„aW˜ƒ_µj…»çjioQR¹ēÃßt@r³[ÛlćË^ÍÉáG“›OUۗOB±•XŸ‡¹£k|e]ol™ŸkVͼÕqtaÏõjgÁ£§U^Œ”RLˆËnX°Ç’Bz†^~wfvˆypV ¯„ƫĉ˭ȫƗŷɿÿĿƑ˃ĝÿÃǃßËőó©ǐȍŒĖ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¥Fƒ“›¿Jû‡]|mvāÎYua^WoÀa·­ząÒot×¶CLƗi¯¤mƎHNJ¤îìɾŊìTdåwsRÖgĒųúÍġäÕ}Q¶—ˆ¿A•†‹[¡Œ{d×uQAƒ›M•xV‹vMOmăl«ct[wº_šÇʊŽŸjb£ĦS_é“QZ“_lwgOiýe`YYLq§IÁˆdz£ÙË[ÕªuƏ³ÍT—s·bÁĽäė[›b[ˆŗfãcn¥îC¿÷µ[ŏÀQ­ōšĉm¿Á^£mJVm‡—L[{Ï_£›F¥Ö{ŹA}…×Wu©ÅaųijƳhB{·TQqÙIķˑZđ©Yc|M¡…L•eVUóK_QWk’‘¿ãZ•»X\\ĴuUƒè‡lG®ěłTĠğDєOrÍd‚ÆÍz]‹±…ŭ©ŸÅ’]ŒÅÐ}UË¥©Tċ™ïxgckfWgi\\ÏĒ¥HkµE˜ë{»ÏetcG±ahUiñiWsɁˆ·c–C‚Õk]wȑ|ća}w…VaĚ᠞ŒG°ùnM¬¯†ˆÐÆA’¥ÄêJxÙ¢”hP¢Ûˆº€µwWOŸóFŽšÁz^ÀŗÎú´§¢T¤ǻƺSė‰ǵhÝÅQgvBHouʝl_o¿Ga{ïq{¥|ſĿHĂ÷aĝÇq‡Z‘ñiñC³ª—…»E`¨åXēÕqÉû[l•}ç@čƘóO¿¡ƒFUsA‰“ʽīccšocƒ‚ƒÇS}„“£‡IS~ălkĩXçmĈ…ŀЂoÐdxÒuL^T{r@¢‘žÍƒĝKén£kQ™‰yšÅõËXŷƏL§~}kqš»IHėDžjĝŸ»ÑÞoŸå°qTt|r©ÏS‹¯·eŨĕx«È[eMˆ¿yuˆ‘pN~¹ÏyN£{©’—g‹ħWí»Í¾s“əšDž_ÃĀɗ±ą™ijĉʍŌŷ—S›É“A‹±åǥɋ@럣R©ąP©}ĹªƏj¹erƒLDĝ·{i«ƫC£µsKCš…GS|úþX”gp›{ÁX¿Ÿć{ƱȏñZáĔyoÁhA™}ŅĆfdʼn„„Y°ėǩÑ¡H¯¶oMQqð¡Ë™|‘Ñ`ƭŁX½·óۓxğįÅcQ‡ˆ“ƒs«tȋDžF“Ÿù^i‘t«Č¯[›hAi©á¥ÇĚ×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ľýľώȪƺɂļžxœZĈ}ÌʼnŪ˜ĺœŽĭFЛĽ̅ȣͽÒŵìƩÇϋÿȮǡŏçƑůĕ~Ǎ›¼ȳÐUf†dIxÿ\\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~´°ÎFC•ŽU¼pĀēƄ¾O¶ŠłKĊOj“Ě”j´ĜYp˜„ˆSĚÍ\\Tš×ªV–÷Ší¨ÅDK°ßtŇĔKš¨ǵÂcḷ̌ĚǣȄĽF‡lġUĵœŇ‹ȣɁƒMğįʏƶɷØŭOǽ«ƽū¹Ʊő̝Ȩ§ȞʘĖiɜɶʦ}¨֪ࠜ̀ƇǬ¹ǨE˦ĥªÔêFŽxúQ„Er´W„rh¤Ɛ \\talĈDJ˜Ü|[Pll̚¸ƎGú´Pž¬W¦†–H]prR“n|or¾wLVnÇIujkmon£cX^Bh`¥V”„¦U¤¸}€xRj–[^xN[~ªŠxQ„‚[`ªHÆÂExx^wšN¶Ê˜|¨ì†˜€MrœdYp‚oRzNy˜ÀDs~€bcfÌ`L–¾n‹|¾T‚°c¨È¢a‚–`[|òDŞĔöxElÖdH„ÀI`„Ď\\Àì~ƎR¼tf•¦^¢ķ¶e”ÐÚMŒptgj–„ɡČÅ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£ʺ™oqNŸƒwğc`ue—tOj×°KJ±qƒÆġm‰Ěŗos¬…qehqsuœƒH{¸kH¡Š…ÊRǪÇƌbȆ¢´ä܍¢NìÉʖ¦â©Ġu¦öČ^â£Ăh–šĖMÈÄw‚\\fŦ°W ¢¾luŸD„wŠ\\̀ʉÌÛ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–Ž@@s™a"],
["@@MnNm"],
["@@d‚c"],
["@@eÀ‚C@b‚“‰"],
["@@f‡…Xwkbr–Ä`qg"],
["@@^jtW‘Q"],
["@@~ Y]c"],
["@@G`ĔN^_¿Z‚ÃM"],
["@@iX¶B‹Y"],
["@@„YƒZ"],
["@@L_{Epf"],
["@@^WqCT\\"],
["@@\\[“‹§t|”¤_"],
["@@m`n_"],
["@@Ïxnj{q_×^Giip"],
[
"@@@œé^B†‡ntˆU—˜Ÿ]x ¯ÄPIJ­°h€ʙK³†VˆÕ@Y~†|EvĹsDŽ¦­L^p²ŸÒG ’Ël]„xxÄ_˜fT¤Ď¤cŽœP„–¸TVjbgH²sdÎdHt`Bˆ—²¬GJję¶[ÐhjeXdlwhšðSȦªVÊπ‹Æ‘Z˜ÆŶ®²†^ŒÎyÅÎcPqń“ĚDMħĜŁH­ˆk„çvV[ij¼W–‚YÀäĦ’‘`XlžR`žôLUVžfK–¢†{NZdĒª’YĸÌÚJRr¸SA|ƴgŴĴÆbvªØX~†źBŽ|¦ÕœEž¤Ð`\\|Kˆ˜UnnI]¤ÀÂĊnŎ™R®Ő¿¶\\ÀøíDm¦ÎbŨab‰œaĘ\\ľã‚¸a˜tÎSƐ´©v\\ÖÚÌǴ¤Â‡¨JKr€Z_Z€fjþhPkx€`Y”’RIŒjJcVf~sCN¤ ˆE‚œm‰–sHy¨SðÑÌ\\\\ŸĐRZk°IS§fqŒßýáЍÙÉÖ[^¯ǤŲ„ê´\\¦¬ĆPM¯£Ÿˆ»uïpùzEx€žanµyoluqe¦W^£ÊL}ñrkqWňûP™‰UP¡ôJŠoo·ŒU}£Œ„[·¨@XŒĸŸ“‹‹DXm­Ûݏº‡›GU‹CÁª½{íĂ^cj‡k“¶Ã[q¤“LÉö³cux«zZfƒ²BWÇ®Yß½ve±ÃC•ý£W{Ú^’q^sÑ·¨‹ÍOt“¹·C¥‡GD›rí@wÕKţ݋˜Ÿ«V·i}xËÍ÷‘i©ĝ‡ɝǡ]ƒˆ{c™±OW‹³Ya±Ÿ‰_穂Hžĕoƫ€Ňqƒr³‰Lys[„ñ³¯OS–ďOMisZ†±ÅFC¥Pq{‚Ã[Pg}\\—¿ghćO…•k^ģÁFıĉĥM­oEqqZûěʼn³F‘¦oĵ—hŸÕP{¯~TÍlª‰N‰ßY“Ð{Ps{ÃVU™™eĎwk±ʼnVÓ½ŽJãÇÇ»Jm°dhcÀff‘dF~ˆ€ĀeĖ€d`sx² šƒ®EżĀdQ‹Âd^~ăÔHˆ¦\\›LKpĄVez¤NP ǹӗR™ÆąJSh­a[¦´Âghwm€BÐ¨źhI|žVVŽ—Ž|p] Â¼èNä¶ÜBÖ¼“L`‚¼bØæŒKV”ŸpoœúNZÞÒKxpw|ÊEMnzEQšŽIZ”ŽZ‡NBˆčÚFÜçmĩ‚WĪñt‘ÞĵÇñZ«uD‚±|Əlij¥ãn·±PmÍa‰–da‡ 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": [
"@@‘”³PClƒFbbÍzš€wBG’ĭ€Z„Åi“»ƒlY­ċ²SgŽkÇ£—^S‰“qd¯•‹R…©éŽ£¯S†\\cZ¹iűƏCuƍÓX‡oR}“M^o•£…R}oªU­F…uuXHl•‡€Ï©¤ÛmTŽþ¤D–²ÄufàÀ­XXȱAe„yYw¬dvõ´KÊ£”\\rµÄl”iˆdā]|DÂVŒœˆÞ®ÜWnŒC”Œķ W‹§@\\¸‹ƒ‹Vp¸‰póIO¢ŠVOšŇürXql~òÉK]¤¥Xrfkvzpm¶bwyFoúvð‡¼¤ N°ąO¥«³[ƒéǡű_°Õ\\ÚÊĝŽþâőàerR¨­JYlďQ[ ÏYëЧTGz•tnŠß¡gFkMŸāGÁ¤ia É‰™È¹`\\xs€¬dĆkNnuNUŠ–užP@‚vRY¾•–\\¢…ŒGªóĄ~RãÖÎĢù‚đŴÕhQŽxtcæëSɽʼníëlj£ƍG£nj°KƘµDsØÑpyƸ®¿bXp‚]vbÍZuĂ{nˆ^IüœÀSք”¦EŒvRÎûh@℈[‚Əȉô~FNr¯ôçR±ƒ­HÑl•’Ģ–^¤¢‚ŸŒævxsŒ]ÞÁTĠs¶¿âƊGW¾ìA¦·TѬ†è¥€ÏÐJ¨¼ÒÖ¼ƒƦɄxÊ~S–tD@ŠĂ¼Ŵ¡jlºWž‰ˆzƦ޲CH— „Axiukd‹ŒGgetqmcžÛ£Ozy¥cE}|…¾cZ…k‚‰¿uŐã[oxGikfeäT@…šSUwpiÚFM©’£è^ڟ‚`@v¶eň†f h˜eP¶žt“äOlÔUgƒÞzŸU`lœ}ÔÆUvØ_Ō¬Öi^ĉi§²ÃŠB~¡Ĉ™ÚEgc|DC_Ȧm²rBx¼MÔ¦ŮdĨÃâYx‘ƘDVÇĺĿg¿cwÅ\\¹˜¥Yĭlœ¤žOv†šLjM_a W`zļMž·\\swqÝSA‡š—q‰Śij¯Š‘°kŠRē°wx^Đkǂғ„œž“œŽ„‹\\]˜nrĂ}²ĊŲÒøãh·M{yMzysěnĒġV·°“G³¼XÀ““™¤¹i´o¤ŃšŸÈ`̃DzÄUĞd\\i֚ŒˆmÈBĤÜɲDEh LG¾ƀľ{WaŒYÍȏĢĘÔRîĐj‹ž“ccj‡oUb½š{“h§Ǿ{K‹ƖµÎ÷žGĀÖŠåưÎs­l›•yiē«‹`姝H¥Ae„GK}iã\\c]v©ģZ“mÃ|“[M}ģTɟĵ‘Â`À–çm‰‘FK¥ÚíÁbXš³ÌQґHof{‰]e€pt·GŋĜYünĎųVY^’˜ydõkÅZW„«WUa~U·Sb•wGçǑ‚“iW^q‹F‚“›uNĝ—·Ew„‹UtW·Ýďæ©PuqEzwAV•—XR‰ãQ`­©GŒM‡ehc›c”ďϝd‡©ÑW_ϗŒ»…é\\ƒɹ~ǙG³mØ©BšuT§Ĥ½¢Ã_ý‘‘ýŸqT^rme™\\Pp•ZZbƒyŸ’uybQ—efµ]UhĿDCmûvašÙNSkCwn‰cć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¾pViˆdd”~ÈiŒíďÓQġėǐ‹ŽXb½|ſÃH½ŸKFgɱCģÛÇA‡n™‹jÕc[VĝDZÃ˄Ç_™ £ń³pŽj£º”š¿”»WH´¯”U¸đĢmžtĜyzzNN|g¸÷äűѱĉā~mq^—Œ[ƒ”››”ƒǁÑďlw]¯xQĔ‰¯l‰’€°řĴrŠ™˜BˆÞTxr[tޏĻN_yŸX`biN™Ku…P›£k‚—¦[ºxÆÀdhŽĹŀUÈƗCw’áZħÄŭcÓ¥»NAw±qȥnD`{ChdÙF暉A±Äj¨]ĊÕjŋ«×`VuÓś~_kŷVÝyh„“VkÄãPs”—fŸge‚Ň…µf@u ÙcŸªNªÙEojVx™T@†ãSefjlwH\\pŏäÀvŠŽlY†½d{†F~¦dyz¤PÜndsrhf‹HcŒvlwjFœ£G˜±DύƥY‡Šu¹XikĿ¦ÏqƗǀOŜ¨LI|FRĂn sª|Cš˜zxAè¥bœfudTrFWÁ¹Am|˜ĔĕsķÆF‡´Nš‰…UŠÕ@Áijſmužç’uð^ÊýowŒFzØÎĕNőžǏȎôªÌŒDŽàĀÄ˄ĞŀƒʀĀƘŸˮȬƬĊ°ƒUŸzou‡xe]}Ž…AyȑW¯ÌmK‡“Q]‹Īºif¸ÄX|sZt|½ÚUΠlkš^p{f¤lˆºlÆW –€˜PVܜPH”Êâ]ÎĈÌÜk´\\@qàsĔÄQºpRij¼èi†—„bXƒrBgxfv»ŽuUiˆŒ^v~”J¬mVp´£Œ´VWrnP½ì¢BX‚¬h™ŠðX¹^TjVœŠriªj™tŊÄm€tPGx¸bgRšŽsT`ZozÆO]’ÒFô҆’‡ŊŒž”p’cGŒêŠsx´DR–Œ{A†„EOr°Œ•žx|íœbˆ³Wm~DVjºéNN†Ëܲɶ­GƒxŷCStŸ}]ûō•SmtuÇÃĕN•™āg»šíT«u}ç½BĵÞʣ¥ëÊ¡Mێ³ãȅ¡ƋaǩÈÉQ‰†G¢·lG|›„tvgrrf«†ptęŘnŠÅĢr„I²¯LiØsPf˜_vĠd„xM prʹš‹¤‡ŒƒÀđK“žïÙVY§]I‡óáĥ]ķ†Kˆ¥Œj|pŇ\\kzţ¦šnņäÔVĂîά|vW’®l¤èØr‚˜•xm¶ă~lÄƯĄ̈́öȄEÔ¤ØQĄ–Ą»ƢjȦOǺ¨ìSŖÆƬy”Qœv`–cwƒZSÌ®ü±DŽ]ŀç¬B¬©ńzƺŷɄeeOĨS’Œfm Ċ‚ƀ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ŀƒ¤é”œŀ›ˆàŀU²ŕƀB‚Q£Ď}L¹Îk@©ĈuǰųǨ”Ú§ƈnTËÇéƟÊcfčŤ^Xm‡—HĊĕË«W·ċëx³ǔķÐċJā‚wİ_ĸ˜Ȁ^ôWr­°oú¬Ħ…ŨK~”ȰCĐ´Ƕ£’fNÎèâw¢XnŮeÂÆĶŽ¾¾xäLĴĘlļO¤ÒĨA¢Êɚ¨®‚ØCÔ ŬGƠ”Ʀ‡ĘÜƬDJ—g_ͥœ@čŅĻA“¶¯@wÎqC½Ĉ»NŸăëK™ďÍQ“Ùƫ[«Ãí•gßÔÇOÝáW‘ñuZ“¯ĥ€Ÿŕā¡ÑķJu¤E Ÿå¯°WKɱ_d_}}vyŸõu¬ï¹ÓU±½@gÏ¿rýD‰†g…Cd‰µ—°MFYxw¿CG£‹Rƛ½Õ{]L§{qqąš¿BÇƻğëšܭNJË|c²}Fµ}›ÙRsÓpg±ŠQNqǫŋRwŕnéÑÉKŸ†«SeYR…ŋ‹@{¤SJ}šD Ûǖ֍Ÿ]gr¡µŷ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Š`ZŸRu¥É\\]~°ŽY`µ†Óƒ^phÁbnÀşúŽòa–ĬºTÖŒb‚˜e¦¦€{¸ZâćNpŒ©žHr|^ˆmjhŠSEb\\afv`sz^lkŽlj‹Ätg‹¤D˜­¾Xš¿À’”iZ„ȀåB·î}GL¢õcßjaŸyBFµÏC^ĭ•cÙt¿sğH]j{s©HM¢ƒQnDÀ©DaÜތ·jgàiDbPufjDk`dPOîƒhw¡ĥ‡¥šG˜ŸP²ĐobºrY†„î¶aHŢ´ ]´‚rılw³r_{£DB_Ûdåuk|ˆŨ¯F Cºyr{XFy™e³Þċ‡¿Â™kĭB¿„MvÛpm`rÚã”@ƹhågËÖƿxnlč¶Åì½Ot¾dJlŠVJʜǀœŞqvnOŠ^ŸJ”Z‘ż·Q}ê͎ÅmµÒ]Žƍ¦Dq}¬R^èĂ´ŀĻĊIԒtžIJyQŐĠMNtœòLh‰›Ěs©»œ}OӌGZz¶A\\jĨFˆäOĤ˜HYš†JvÞHNiÜaϚɖnFQlšNM¤ˆB´ĄNöɂtp–Ŭdf先‹qm¿QûŠùއÚb¤uŃJŴu»¹Ą•lȖħŴw̌ŵ²ǹǠ͛hĭłƕrçü±Y™xci‡tğ®jű¢KOķ•Coy`å®VTa­_Ā]ŐÝɞï²ʯÊ^]afYǸÃĆēĪȣJđ͍ôƋĝÄ͎ī‰çÛɈǥ£­ÛmY`ó£Z«§°Ó³QafusNıDž_k}¢m[ÝóDµ—¡RLčiXy‡ÅNïă¡¸iĔϑNÌŕoēdōîåŤûHcs}~Ûwbù¹£¦ÓCt‹OPrƒE^ÒoŠg™ĉ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‡"],
["@@sfŠbU‡"],
["@@qP\\xz[ck"],
["@@‘Rƒ¢‚FX}°[s_"],
["@@Cbœ\\—}"],
["@@e|v\\la{u"],
["@@v~u}"],
["@@QxÂF¯}"],
["@@¹nŒvÞs¯o"],
["@@rSkUEj"],
["@@bi­ZŒP"],
["@@p[}INf"],
["@@À¿€"],
["@@¹dnbŒ…"],
["@@rSŸBnR"],
["@@g~h}"],
["@@FlEk"],
["@@OdPc"],
["@@v[u\\"],
["@@FjâL~wyoo~›sµL–\\"],
["@@¬e¹aNˆ"],
["@@\\nÔ¡q]L³ë\\ÿ®ŒŽ"],
["@@ÊA­©[¬"],
["@@KxŒv­"],
["@@@hlIk]"],
["@@pW{o||j"],
["@@Md|_mC"],
["@@¢…X£ÏylD¼XˆtH"],
["@@hlÜ[LykAvyfw^Ež›¤"],
["@@fp¤Mus“R"],
["@@®_ma~•LÁ¬šZ"],
["@@iM„xZ"],
["@@ZcYd"],
["@@Z~dOSo|A¿qZv"],
["@@@`”EN¡v"],
["@@|–TY{"],
["@@@n@m"],
["@@XWkCT\\"],
["@@ºwšZRkĕWO¢"],
["@@™X®±Grƪ\\ÔáXq{‹"],
["@@ůTG°ĄLHm°UC‹"],
[
"@@¤Ž€aÜx~}dtüGæţŎíĔcŖpMËВj碷ðĄÆMzˆjWKĎ¢Q¶˜À_꒔_Bı€i«pZ€gf€¤Nrq]§ĂN®«H±‡yƳí¾×ŸīàLłčŴǝĂíÀBŖÕªˆŠÁŖHŗʼnåqûõi¨hÜ·ƒñt»¹ýv_[«¸m‰YL¯‰…mĉÅdMˆ•gÇjcº«•ęœ¬­K­´ƒB«Âącoċ\\xKd¡gěŧ«®á’[~ıxu·Å”KsËɏc¢Ù\\ĭƛëbf¹­ģSƒĜkáƉÔ­ĈZB{ŠaM‘µ‰fzʼnfåÂŧįƋǝÊĕġć£g³ne­ą»@­¦S®‚\\ßðCšh™iqªĭiAu‡A­µ”_W¥ƣO\\lċĢttC¨£t`ˆ™PZäuXßBs‡Ļyek€OđġĵHuXBšµ]׌‡­­\\›°®¬F¢¾pµ¼kŘó¬Wät’¸|@ž•¸µr“ºù³Ù~§WI‹ŸZWŽ®’±Ð¨ÒÉx€`‰²pĜ•rOògtÁZ}þÙ]„’¡ŒŸFK‚wsPlU[}¦Rvn`hq¬\\”nQ´ĘRWb”‚_ rtČFI֊kŠŠĦPJ¶ÖÀÖJĈĄTĚòžC ²@Pú…Øzœ©PœCÈÚœĒ±„‡l¬â~nm¨f©–iļ«m‡nt–u†ÖZÜÄj“ŠLŽ®E̜Fª²iÊxبžIÈhhst"
],
["@@o\\V’zRZ}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`|´qžxIJkq^³³ŸGšµbƒíZ…¹qpa±ď OH—¦™Ħˆ„gPícOl_iCveaOjCh߸‹bÛªCC¿€m„RV§¢A|t^iĠGÀtÚs–d]ĮÐDE¶zAb àiödK¡~H¸íæAžǿYƒ“j{ď¿‘™À½W—®£ChŒÃsiŒkkly]_teu[bFa‰Tig‡n{]Gqªo‹ĈMYá|·¥—őaSÕė™ñĞ«ImŒ_m¿Âa]uĜp …Z_§{Cƒäg¤°r[_Yj‰ÆOdý“[ŽI[á·¥“Q_n‡ùgL¾mv™ˊBÜÆ¶ĊJhšp“˜O]iŠ]œ¥ jtsggJǧw×jÉ©±›EFˍ­‰Ki”ÛÃÕYv…s•ˆm¬njĻª•§emná}k«ŕˆƒgđ²Ù›DǤ›í¡ªOy›†×Où±@DŸñSęćăÕIÕ¿IµĥO‰‰jNÕËT¡¿tNæŇàåyķrĕq§ÄĩsWÆßŽžX®¿‰mŒ™w…RIޓfßoG‘³¾©uyH‘į{Ɓħ¯AFnuP…ÍÔzšŒV—dàôº^Ðæd´€‡oG¤{S‰¬ćxã}›ŧ×Kǥĩ«žÕOEзÖdÖsƘѨ[’Û^Xr¢¼˜§xvěƵ`K”§ ´Cvlo¸fzŨð¾NY´ı~ÉĔē…ßúLÃϖ_ÈÏ|]ÂÏFl”g`bšežž€n¾¢pU‚h~ƴ˶_‚r sĄ~cž”ƈ]|r c~`¼{À{ȒiJjz`îÀT¥Û³…]’u}›f…ïQl{skl“oNdŸjŸäËzDvčoQŠďHI¦rb“tHĔ~BmlRš—V_„ħTLnñH±’DžœL‘¼L˜ªl§Ťa¸ŒĚlK²€\\RòvDcÎJbt[¤€D@®hh~kt°ǾzÖ@¾ªdb„YhüóZ ň¶vHrľ\\ʗJuxAT|dmÀO„‹[ÃԋG·ĚąĐlŪÚpSJ¨ĸˆLvÞcPæķŨŽ®mАˆálŸwKhï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"],
["@@@vˆPGsQ"],
["@@‰sBz‚ddW]Q"],
["@@SލQ“{"],
["@@NŽVucW"],
["@@qptBAq"],
["@@‰’¸[mu"],
["@@Q\\pD]_"],
["@@jSwUadpF"],
["@@eXª~ƒ•"],
["@@AjvFso"],
["@@fT–›_Çí\\Ÿ™—v|ba¦jZÆy€°"],
["@@IjJi"],
["@@wJI€ˆxš«¼AoNe{M­"],
["@@K‰±¡Óˆ”ČäeZ"],
[
"@@k¡¹Eh~c®wBk‹UplÀ¡I•~Māe£bN¨gZý¡a±Öcp©PhžI”Ÿ¢Qq…ÇGj‹|¥U™ g[Ky¬ŏ–v@OpˆtÉEŸF„\\@ åˆV{Xģ‰ĐBy…cpě…¼³Ăp·¤ƒ¥o“hqqÚ¡ŅLsƒ^ᗞ§qlŸÀhH¨MCe»åÇGD¥zPO£čÙkJA¼ß–ėu›ĕeûҍiÁŧSW¥˜QŠûŗ½ùěcݧSùĩąSWó«íęACµ›eR—åǃRCÒÇZÍ¢‹ź±^dlsŒtjD¸•‚ZpužÔâÒH¾oLUêÃÔjjēò´ĄW‚ƛ…^Ñ¥‹ĦŸ@Çò–ŠmŒƒOw¡õyJ†yD}¢ďÑÈġfŠZd–a©º²z£šN–ƒjD°Ötj¶¬ZSÎ~¾c°¶Ðm˜x‚O¸¢Pl´žSL|¥žA†ȪĖM’ņIJg®áIJČĒü` ŽQF‡¬h|ÓJ@zµ |ê³È ¸UÖŬŬÀEttĸr‚]€˜ðŽM¤ĶIJHtÏ A’†žĬkvsq‡^aÎbvŒd–™fÊòSD€´Z^’xPsÞrv‹ƞŀ˜jJd×ŘÉ ®A–ΦĤd€xĆqAŒ†ZR”ÀMźŒnĊ»ŒİÐZ— YX–æJŠyĊ²ˆ·¶q§·–K@·{s‘Xãô«lŗ¶»o½E¡­«¢±¨Yˆ®Ø‹¶^A™vWĶGĒĢžPlzfˆļŽtàAvWYãšO_‡¤sD§ssČġ[kƤPX¦Ž“ž®ˆBBvĪjv©šjx[L¥àï[F…¼ÍË»ğV`«•Ip™}ccÅĥZE‹ãoP…´B@ŠD—¸“z«Ƴ—¿å³BRضˆœWlâþäą`“]Z£Tc— ĹGµ¶H™m@_©—kŒ‰¾xĨ‡ôȉðX«½đCIbćqK³Á‹Äš¬OAwã»aLʼn‡ËĥW[“ÂGI—ÂNxij¤D¢ŽîĎÎB§°_JœGsƒ¥E@…¤uć…P‘å†cuMuw¢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ˆJŒìõ`oz÷@¤u޸´†ôęöY¼‰HČƶajlÞƩ¥éZ[”|h}^U Œ ¥p„ĄžƦO lt¸Æ €Q\\€ŠaÆ|CnÂOjt­ĚĤd’ÈŒF`’¶„@Ð딠¦ōҞ¨Sêv†HĢûXD®…QgėWiØPÞìºr¤dž€NĠ¢l–•ĄtZoœCƞÔºCxrpĠV®Ê{f_Y`_ƒeq’’®Aot`@o‚DXfkp¨|Šs¬\\D‘ÄSfè©Hn¬…^DhÆyøJh“ØxĢĀLʈ„ƠPżċĄwȠ̦G®ǒĤäTŠÆ~ĦwŠ«|TF¡Šn€c³Ïå¹]ĉđxe{ÎӐ†vOEm°BƂĨİ|G’vz½ª´€H’àp”eJ݆Qšxn‹ÀŠW­žEµàXÅĪt¨ÃĖrÄwÀFÎ|ňÓMå¼ibµ¯»åDT±m[“r«_gŽmQu~¥V\\OkxtL ‹ƒ‘Ú^~ýꋖqo슱_Êw§ÑªåƗ⼋mĉŹ‹¿NQ“…YB‹ąrwģcÍ¥B•Ÿ­ŗÊcØiI—žƝĿuŒqtāwO]‘³YCñTeɕš‹caub͈]trlu€ī…B‘ПGsĵıN£ï—^ķqss¿FūūV՟·´Ç{éĈý‰ÿ›OEˆR_ŸđûIċâJh­ŅıN‘ȩĕB…¦K{Tk³¡OP·wn—µÏd¯}½TÍ«YiµÕsC¯„iM•¤™­•¦¯P|ÿUHv“he¥oFTu‰õ\\ŽOSs‹MòđƇiaºćXŸĊĵà·çhƃ÷ǜ{‘ígu^›đg’m[×zkKN‘¶Õ»lčÓ{XSƉv©_ÈëJbVk„ĔVÀ¤P¾ºÈMÖxlò~ªÚàGĂ¢B„±’ÌŒK˜y’áV‡¼Ã~­…`g›ŸsÙfI›Ƌlę¹e|–~udjˆuTlXµ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"],
["@@T‚ŒGŸy"],
["@@K¬˜•‹U"],
["@@WdXc"],
["@@PtOs"],
["@@•LnXhc"],
["@@ppVƒu]Or"],
["@@cdzAUa"],
["@@udRhnCI‡"],
["@@ˆoIƒpR„"],
[
"@@Ľč{fzƤî’Kš–ÎMĮ]†—ZFˆ½Y]â£ph’™š¶¨râøÀ†ÎǨ¤^ºÄ”Gzˆ~grĚĜlĞÆ„LĆdž¢Îo¦–cv“Kb€gr°Wh”mZp ˆL]LºcU‰Æ­n”żĤÌǜbAnrOAœ´žȊcÀbƦUØrĆUÜøœĬƞ†š˜Ez„VL®öØBkŖÝĐ˹ŧ̄±ÀbÎɜnb²ĦhņBĖ›žįĦåXćì@L¯´ywƕCéõė ƿ¸‘lµ¾Z|†ZWyFYŸ¨Mf~C¿`€à_RÇzwƌfQnny´INoƬˆèôº|sT„JUš›‚L„îVj„ǎ¾Ē؍‚Dz²XPn±ŴPè¸ŔLƔÜƺ_T‘üÃĤBBċȉöA´fa„˜M¨{«M`‡d¡ô‰Ö°šmȰBÔjjŒ´PM|”c^d¤u•ƒ¤Û´Œä«ƢfPk¶Môlˆ]Lb„}su^ke{lC‘…M•rDŠÇ­]NÑFsmoõľH‰yGă{{çrnÓE‰‹ƕZGª¹Fj¢ïW…CǷ돡ąuhÛ¡^Kx•C`C\\bÅxì²ĝÝ¿_N‰īCȽĿåB¥¢·IŖÕy\\‡¹kx‡Ã£Č×GDyÕ¤ÁçFQ¡„KtŵƋ]CgÏAùSed‡cÚź—ŠuYfƒyMmhUWpSyGwMPqŀ—›Á¼zK›†G•­Y§Ëƒ@–´śÇµƕBmœ@Io‚g——Z¯u‹TMx}C‘‰VK‚ï{éƵP—™_K«™pÛÙqċtkkù]gŽ‹Tğwo•ɁsMõ³ă‡AN£™MRkmEʕč™ÛbMjÝGu…IZ™—GPģ‡ãħE[iµBEuŸDPԛ~ª¼ętŠœ]ŒûG§€¡QMsğNPŏįzs£Ug{đJĿļā³]ç«Qr~¥CƎÑ^n¶ÆéÎR~ݏY’I“] P‰umŝrƿ›‰›‹[x‰edz‹L‘¯v¯s¬ÁY…~}…ťuٌg›ƋpÝĄ_ņī¶ÏSR´ÁP~ž¿Cyžċßdwk´Ss•X|t‰ Èð€AªìÎT°¦Dd–€a^lĎDĶÚY°Ž`ĪŴǒˆ”àŠv\\ebŒZH„Ŗ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ŢĞð†´žÚPt†ĴXØx¶˜@«ŕŕQGƒ‹Yfa[şu“ßǩ™đš_X³ijÕčC]kbc•¥CS¯ëÍB©÷‹–³­Siˆ_}m˜YTtž³xlàcȂzÀD}ÂOQ³ÐTĨ¯†ƗòËŖ[hœł‹Ŧv~††}ÂZž«¤lPǕ£ªÝŴÅR§ØnhcŒtâk‡­ľŹUÓÝdKuķ‡I§oTũÙďkęĆH¸ÓŒ\\ăŒ¿PcnS{wBIvɘĽ[GqµuŸŇôYgûƒZcaŽ©@½Õǽys¯}lgg@­C\\£as€IdÍuCQñ[L±ęk·‹ţb¨©kK—’»›KC²‘òGKmĨS`ƒ˜UQ™nk}AGē”sqaJ¥ĐGR‰ĎpCuÌy ã iMc”plk|tRk†ðœev~^‘´†¦ÜŽSí¿_iyjI|ȑ|¿_»d}qŸ^{“Ƈdă}Ÿtqµ`Ƴĕg}V¡om½fa™Ço³TTj¥„—Ry”K{ùÓjuµ{t}uËR‘iŸvGŠçJFjµŠÍyqΘàQÂFewixGw½Yŷpµú³XU›½ġy™łå‰kÚwZXˆ·l„¢Á¢K”zO„Λ΀jc¼htoDHr…|­J“½}JZ_¯iPq{tę½ĕ¦Zpĵø«kQ…Ťƒ]MÛfaQpě±ǽ¾]u­Fu‹÷nƒ™čįADp}AjmcEǒaª³o³ÆÍSƇĈÙDIzˑ赟^ˆKLœ—i—Þñ€[œƒaA²zz‰Ì÷Dœ|[šíijgf‚ÕÞd®|`ƒĆ~„oĠƑô³Ŋ‘D×°¯CsŠøÀ«ì‰UMhTº¨¸ǡîS–Ô„DruÂÇZ•ÖEŽ’vPZ„žW”‹ÐtĄE¢¦Ðy¸bŠô´oŬ¬Ž²Ês~€€]®tªašpŎJ¨Öº„_ŠŔ–`’Ŗ^Ѝ\\Ĝu–”~m²Ƹ›¸fW‰ĦrƔ}Î^gjdfÔ¡J}\\n C˜¦þWxªJRÔŠu¬ĨĨmF†dM{\\d\\ŠYÊ¢ú@@¦ª²SŠÜsC–}fNècbpRmlØ^g„d¢aÒ¢CZˆZxvÆ¶N¿’¢T@€uCœ¬^ĊðÄn|žlGl’™Rjsp¢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": [
["@@AB‚"],
["@@lskt"],
[
"@@¾«}{ra®pîÃ\\™›{øCŠËyyB±„b\\›ò˜Ý˜jK›‡L ]ĎĽÌ’JyÚCƈćÎT´Å´pb©È‘dFin~BCo°BĎĚømvŒ®E^vǾ½Ĝ²Ro‚bÜeNŽ„^ĺ£R†¬lĶ÷YoĖ¥Ě¾|sOr°jY`~I”¾®I†{GqpCgyl{‡£œÍƒÍyPL“¡ƒ¡¸kW‡xYlÙæŠšŁĢzœ¾žV´W¶ùŸo¾ZHxjwfx„GNÁ•³Xéæl¶‰EièIH‰ u’jÌQ~v|sv¶Ôi|ú¢Fh˜Qsğ¦ƒSiŠBg™ÐE^ÁÐ{–čnOÂȞUÎóĔ†ÊēIJ}Z³½Mŧïeyp·uk³DsѨŸL“¶_œÅuèw»—€¡WqÜ]\\‘Ò§tƗcÕ¸ÕFÏǝĉăxŻČƟO‡ƒKÉġÿ×wg”÷IÅzCg†]m«ªGeçÃTC’«[‰t§{loWeC@ps_Bp‘­r‘„f_``Z|ei¡—oċMqow€¹DƝӛDYpûs•–‹Ykıǃ}s¥ç³[§ŸcYЧHK„«Qy‰“wwö€¸ïx¼ņ¾Xv®ÇÀµRĠЋžHMž±cÏd„ƒǍũȅȷ±DSyúĝ£ŤĀàtÖÿï[îb\\}pĭÉI±Ñy…¿³x¯N‰o‰|¹H™ÏÛm‹júË~Tš•u˜ęjCöAwě¬R’đl¯ Ñb­‰ŇT†Ŀ_[Œ‘IčĄʿnM¦ğ\\É[T·™œ©oĕ@A¾w•ya¥Y\\¥Âaz¯ãÁ¡k¥ne£Ûw†E©Êō¶˓uoj_Uƒ¡cF¹­[Wv“P©w—huÕyBF“ƒ`R‹qJUw\\i¡{jŸŸEPïÿ½fć…QÑÀQ{ž‚°‡fLԁ~wXg—ītêݾ–ĺ‘Hdˆ³fJd]‹HJ²…E€ƒoU¥†HhwQsƐ»Xmg±çve›]Dm͂PˆoCc¾‹_h”–høYrŊU¶eD°Č_N~øĹĚ·`z’]Äþp¼…äÌQŒv\\rCŒé¾TnkžŐڀÜa‡“¼ÝƆ̶Ûo…d…ĔňТJq’Pb ¾|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ʧĘD†vČ_Àæ~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": [
["@@—n„FTs"],
["@@ßÅÆá‰½ÔXr—†CO™“…ËR‘ïÿĩ­TooQyšÓ[‹ŅBE¬–ÎÓXa„į§Ã¸G °ITxp‰úxÚij¥Ïš–̾ŠedžÄ©ĸG…œàGh‚€–Â_U}Ċ}¢pczfŠþg¤€”ÇòAV‘‹M"],
[
"@@©K—ƒA·³CQ±Á«³BUŠƑ¹AŠtćOw™D]ŒJiØSm¯b£‘ylƒ›X…HËѱH•«–‘C^õľA–Å§¤É¥„ïyuǙuA¢^{ÌC´­¦ŷJ£^[†“ª¿‡ĕ~•Ƈ…•N… skóā‡¹¿€ï]ă~÷O§­@—Vm¡‹Qđ¦¢Ĥ{ºjԏŽŒª¥nf´•~ÕoŸž×Ûą‹ıuZœmZcÒ 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“È£ýhe‰dy¡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Œ„_E”zAN¦zLU`œcªx”OTu RLÄ¢dV„i`p˔vŎµªÉžF~ƒØ€d¢ºgİàw¸Áb[¦Zb¦–z½xBĖ@ªpº›šlS¸Ö\\Ĕ[N¥ˀmĎă’J\\‹ŀ`€…ňSڊĖÁĐiO“Ĝ«BxDõĚiv—ž–S™Ì}iùŒžÜnšÐºGŠ{Šp°M´w†ÀÒzJ²ò¨ oTçüöoÛÿñŽőФ‚ùTz²CȆȸǎۃƑÐc°dPÎŸğ˶[Ƚu¯½WM¡­Éž“’B·rížnZŸÒ `‡¨GA¾\\pē˜XhÆRC­üWGġu…§Ŏѝ©ò³I±³}_‘‹EÃħg®ęisÁPDmÅ{‰b[Ÿ€kPŸŽƥƒóRo”O‹ŸVŸ~]{g\\“êYƪ¦kÝbiċƵŠGZ»Ěõ…ó·³vŝž£ø@pyö_‹ëŽIkѵ‡bcѧ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": [
["@@QdˆAua"],
["@@ƒlxDLo"],
["@@sbhNLo"],
["@@Ă āŸ"],
["@@WltO[["],
["@@Krœ]S"],
["@@e„„I]y"],
["@@I|„Mym"],
["@@ƒÛ³LSŒž¼Y"],
["@@nvºB–ëui©`¾"],
["@@zdšÛ›Jw®"],
["@@†°…¯"],
["@@a yAª¸ËJIx،@€ĀHAmßV¡o•fu•o"],
["@@šs‰ŗÃÔėAƁ›ZšÄ ~°ČP‚‹äh"],
["@@‹¶Ý’Ì‚vmĞh­ı‡Q"],
["@@HœŠdSjĒ¢D}war…“u«ZqadYM"],
["@@elŒ\\LqqU"],
["@@~rMo\\"],
["@@f„^ƒC"],
["@@øPªoj÷ÍÝħXČx”°Q¨ıXNv"],
["@@gÇƳˆŽˆ”oˆŠˆ[~tly"],
["@@E–ÆC¿‘"],
["@@OŽP"],
[
"@@w‹†đóg‰™ĝ—‹¡VÙæÅöM̳¹pÁaËýý©D©Ü“JŹƕģGą¤{Ùū…ǘO²«BƱéA—Ò‰ĥ‡¡«BhlmtÃPµyU¯uc“d·w_bŝcīímGOŽ|KP’ȏ‡ŹãŝIŕŭŕ@Óoo¿ē‹±ß}Ž…ŭ‚ŸIJWÈCőâUâǙI›ğʼn©I›ijEׅÁ”³Aó›wXJþ±ÌŒÜӔĨ£L]ĈÙƺZǾĆĖMĸĤfŒÎĵl•ŨnȈ‘ĐtF”Š––‚êk¶œ^k°f¶gŠŽœ}®Fa˜f`vXŲxl˜„¦–ÔÁ²¬ÐŸ¦pqÊ̲ˆi€XŸØRDÎ}†Ä@ZĠ’s„x®AR~®ETtĄZ†–ƈfŠŠHâÒÐA†µ\\S¸„^wĖkRzŠalŽŜ|E¨ÈNĀňZTŒ’pBh£\\ŒĎƀuXĖtKL–¶G|Ž»ĺEļĞ~ÜĢÛĊrˆO˜Ùîvd]nˆ¬VœÊĜ°R֟pM††–‚ƂªFbwžˆ˜©Œž\\…¤]ŸI®¥D³|ˎ]CöAŤ¦…æ’´¥¸Lv¼€•¢ĽBaô–F~—š®²GÌҐEY„„œzk¤’°ahlV՞I^‹šCxĈPŽsB‰ƒºV‰¸@¾ªR²ĨN]´_eavSi‡vc•}p}Đ¼ƌkJœÚe thœ†_¸ ºx±ò_xN›Ë‹²‘@ƒă¡ßH©Ùñ}wkNÕ¹ÇO½¿£ĕ]ly_WìIžÇª`ŠuTÅxYĒÖ¼k֞’µ‚MžjJÚwn\\h‘œĒv]îh|’È›Ƅøègž¸Ķß ĉĈWb¹ƀdéƌNTtP[ŠöSvrCZžžaGuœbo´ŖÒÇА~¡zCI…özx¢„Pn‹•‰Èñ @ŒĥÒ¦†]ƞŠV}³ăĔñiiÄÓVépKG½Ä‘ÓávYo–C·sit‹iaÀy„ŧΡÈYDÑům}‰ý|m[węõĉZÅxUO}÷N¹³ĉo_qtă“qwµŁYلǝŕ¹tïÛUïmRCº…ˆĭ|µ›ÕÊK™½R‘ē ó]‘–GªęAx–»HO£|ām‡¡diď׍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ñĤaY“t¿¤VSñœK¸¤nM†¼‚JE±„½¸šŠño‹ÜCƆæĪ^ŠĚQÖ¦^‡ˆˆf´Q†üÜʝšlzUĺš@쇀p¶n]sxtx¶@„~ÒĂJb©gk‚{°‚~c°`ԙ¬rV\\“la¼¤ôá`¯¹LC†ÆbŒxEræO‚v[H­˜„[~|aB£ÖsºdAĐzNÂðsŽÞƔ…Ĥªbƒ–ab`ho¡³F«èVloޤ™ÔRzpp®SŽĪº¨ÖƒºN…ij„d`’a”¦¤F³ºDÎńĀìŠCžĜº¦Ċ•~nS›|gźvZkCÆj°zVÈÁƔ]LÊFZg…čP­kini«‹€cz͔Y®¬Ů»qR×ō©DՄ‘§ƙǃŵTÉĩ±ŸıdÑnYY›IJvNĆÌØÜ Öp–}e³¦m‹©iÓ|¹Ÿħņ›|ª¦QF¢Â¬ʖovg¿em‡^ucà÷gՎuŒíÙćĝ}FϼĹ{µHK•sLSđƃr‹č¤[Ag‘oS‹ŇYMÿ§Ç{Fśbky‰lQxĕƒ]T·¶[B…ÑÏGáşşƇe€…•ăYSs­FQ}­Bƒw‘tYğÃ@~…€Q ×W‡j˱rÉ¥oÏ ±«ÓÂ¥•ƒ€k—ŽwWűŒmcih³K›~‰µh¯e]lµ›él•‰•E“ďs‡’–ŧē`ãògK_ÛsUʝ“ćğ¶hŒöŒO¤Ǜn³Žc‘`¡y‹¦C‘ez€YŠwa™–‘[ďĵűMę§]X˜Î_‚훘Û]é’ÛUćİÕBƣ±…dƒy¹T^džûÅÑŦ·‡PĻþÙ`K€¦˜…¢ÍeœĥR¿Œ³£[~Œäu¼dl‰t‚†W¸oRM¢ď\\zœ}Æzdvň–{ÎXF¶°Â_„ÒÂÏL©Ö•TmuŸ¼ãl‰›īkiqéfA„·Êµ\\őDc¥ÝF“y›Ôć˜c€űH_hL܋êĺШc}rn`½„Ì@¸¶ªVLŒŠ‹\\•Ţĺk~ŽĠið°|gŒtTĭĸ^x‘vK˜VGréAé‘bUu›MJ‰VÃO¡…XËS‰ģãlýàŸ_ju‡YÛÒB†œG^˜é֊¶§ŽƒEG”ÅzěƒƯ¤Ek‡N[kdåucé¬dnYpAyČ{`]þ¯T’bÜÈ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ðĀÒRŒš™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×͂·ºſƽıƣıĻmHH}siaX@iǰÁÃ׃­Tƒ¤J–JJŒyJ•ÈŠ`Ohߦ¡uËhIyCjmÿw…ZG……Ti‹SˆsO‰žŸfNmsPaˆ{M{ŠõE‘^Hj}gYpaeuž¯‘oáwHjÁ½M¡pM“–‡mni{fk”\\oƒÎqCw†EZ¼K›ĝŠƒAy{m÷L‡wO×SimRI¯rK™õBS«sFe‡]fµ¢óY_ÆPRcue°Cbo׌bd£ŌIHgtrnyPt¦foaXďx›lBowz‹_{ÊéWiêE„GhܸºuFĈIxf®Ž•Y½ĀǙ]¤EyŸF²ċ’w¸¿@g¢§RGv»–áŸW`ÃĵJwi]t¥wO­½a[׈]`Ãi­üL€¦LabbTÀå’c}Íh™Æhˆ‹®BH€î|Ék­¤S†„ia©taį·Ɖ`ō¥Uh“O…ƒĝLk}©Fos‰´›Jm„µlŁu—…ø–nÑJWΪ–YÀïAetTžŅ‚ӍG™Ë«bo‰{ıwodƟ½ƒžOġܑµxàNÖ¾P²§HKv¾–]|•B‡ÆåoZ`¡Ø`ÀmºĠ~ÌЧnDž¿¤]wğ@sƒ‰rğu‰~‘Io”[é±¹ ¿žſđӉ@q‹gˆ¹zƱřaí°KtǤV»Ã[ĩǭƑ^ÇÓ@ỗs›•‹œÅĭ€Ƌ•ěpwDóÖሯneQˌ•GCœýS]xŸ·ý‹•œŒ¶Qzßti{ř‰áÍÇWŝŭñzÇW‹pç¿JŒ™‚Xœĩè½cŒF–ÂLiVjx}\\N†ŇĖ¥Ge–“JA¼ÄHfÈu~¸Æ«dE³ÉMA|b˜Ò…˜ćhG¬CM‚õŠ„ƤąAvƒüV€éŀ‰_V̳ĐwQj´·ZeÈÁ¨X´Æ¡Qu·»Ÿ“˜ÕZ³ġqDo‰y`L¬gdp°şŠp¦ėìÅĮZްIä”h‚‘ˆzŠĵœf²å ›ĚрKp‹IN|‹„Ñ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ÕĢyFVvw–ˆxBèĻĒ©Ĉ“tCĢɽŠȣ¦āæ·HĽî“ôNԓ~^¤Ɗœu„œ^s¼{TA¼ø°¢İªDè¾Ň¶ÝJ‘®Z´ğ~Sn|ªWÚ©òzPOȸ‚bð¢|‹øĞŠŒœŒQìÛÐ@Ğ™ǎRS¤Á§d…i“´ezÝúØã]Hq„kIŸþËQǦÃsǤ[E¬ÉŪÍxXƒ·ÖƁİlƞ¹ª¹|XÊwn‘ÆƄmÀêErĒtD®ċæcQƒ”E®³^ĭ¥©l}äQto˜ŖÜqƎ–„ªÔĻĴ¡@Ċ°B²Èw^^RsºT£ڿœQP‘JvÄz„^Đ¹Æ¯fLà´GC²‘dt˜­ĀRt¼¤ĦOðğfÔðDŨŁĞƘ®âbMüÀXZ ¸£@Ś›»»QÉ­™]d“×–_ÌêŮ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°´†ATe€VamdUĐwʄvĮÕ\\ƒu‹Æŗ¨Yp¹àZÂm™Wh{á„}WØǍ•Éüw™ga§áCNęÎ[ĀÕĪgÖɪX˜øx¬½Ů¦¦[€—„†L€ÜUÖ´òrÙŠxR^–†J˜k„ijnDX{Uƒ~ET{ļº¦PZc”jF²Ė@Žp˜g€ˆ¨“B{ƒŦyhoÚD®¯¢˜ àFΤ¨GDäz¦kŮPœġq˚¥À]€Ÿ˜eŽâÚ´ªKxī„Pˆ—Ö|æ[xäJÞĥ‚s’NÖ½ž€I†¬nĨY´®Ð—ƐŠ€mD™ŝuäđđEb…e’e_™v¡}ìęNJē}q”É埁T¯µRs¡M@}ůa†a­¯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Ñ£Is‡NgßH†›HªķÃh_¹ƒ¡ĝħń¦uيùŽgS¯JHŸ|sÝÅtÁïyMDč»eÕtA¤{b\\}—ƒG®u\\åPFq‹wÅaD…žK°ºâ_£ùbµ”‹ÛœĹM[q|hlaªāI}тƒµ@swtwm^oµˆD鼊yV™ky°ÉžûÛR…³‚‡eˆ‡¥]RՋěħ[ƅåÛDpŒ”J„iV™™‰ÂF²I…»mN·£›LbÒYb—WsÀbŽ™pki™TZĄă¶HŒq`……ĥ_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|`ź¦ÂÈdr„be¸›`I¼čTF´¼Óýȃr¹ÍJ©k_șl³´_`oÒh޶pa‚^ÓĔ}D»^Xyœ`d˜[Kv…JPhèhCrĂĚÂ^Êƌ wˆZL­Ġ£šÁbrzOIl’MM”ĪŐžËr×ÎeŦŽtw|Œ¢mKjSǘňĂStÎŦEtqFT†¾†E쬬ôxÌO¢Ÿ KгŀºäY†„”PVgŎ¦Ŋm޼VZwVlŒ„…ž£Tl®ctĽÚó{G­A‡ŒÇgeš‘d¿æaSba¥KKûj®_ć^\\ؾbP®¦x^sxjĶI_Ä X‚⼕Hu¨Qh¡À@Ëô}ޱžGNìĎlT¸ˆ…`V~R°tbÕĊ`¸úÛtπFDu€[ƒMfqGH·¥yA‰ztMFe|R‚_Gk†ChZeÚ°to˜v`x‹b„ŒDnÐ{E}šZ˜è€x—†NEފREn˜[Pv@{~rĆAB§‚EO¿|UZ~ì„Uf¨J²ĂÝÆ€‚–B`„œfvö¦ŠÕ~dÔq¨¸º»uù[[§´sb¤¢zþFœ¢Æ…Àhˆ™ÂˆW\\ıŽËI݊o±ĭŠ£þˆÊs}¡R]ŒěƒD‚g´VG¢‚j±®è†ºÃmpU[Á›‘Œëº°r›ÜbNu¸}Žº¼‡`ni”ºÔXĄ¤¼Ôdaµ€Á_À…†ftQQgœR—‘·Ǔ’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½}ÑRH‘YīĺûsÍn‘iEoã½Ya²ė{c¬ĝg•ĂsA•ØÅwď‚õzFjw}—«Dx¿}UũlŸê™@•HÅ­F‰¨ÇoJ´Ónũuą¡Ã¢pÒŌ“Ø TF²‚xa²ËX€‚‹lHîAßËŁkŻƑŷÉ©h™W­æß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¯ŪĽn„†cÚbŒw\\zlvWžªâˆ ¦g–mĿBş£¢ƹřbĥkǫßeeZkÙIKueT»sVesb‘aĕ  ¶®dNœĄÄpªyސ¼—„³BE˜®l‡ŽGœŭCœǶwêżĔÂe„pÍÀQƞpC„–¼ŲÈ­AÎô¶R„ä’Q^Øu¬°š_Èôc´¹ò¨P΢hlϦ´Ħ“Æ´sâDŽŲPnÊD^¯°’Upv†BP̪–jǬx–Söwlfòªv€qĸ|`H€­viļ€ndĜ­Ćhň•‚em·FyށžSᝑ³X_ĞçêtryvL¤§z„¦c¦¥jnŞk˜ˆlD¤øz½ĜàžĂŧMÅ|áƆàÊcðÂF܎‚áŢ¥\\\\º™İøÒÐJĴ‡„îD¦zK²ǏÎEh~’CD­hMn^ÌöÄ©ČZÀž„fɭyœpį´ěFűk]Ôě¢qlÅĆÙa¶~Äqššê€ljN¬¼H„ÊšNQ´ê¼VظE††^ŃÒyŒƒM{ŒJLoÒœęæŸe±Ķ›y‰’‡gã“¯JYÆĭĘëo¥Š‰o¯hcK«z_pŠrC´ĢÖY”—¼ v¸¢RŽÅW³Â§fǸYi³xR´ďUˊ`êĿU„û€uĆBƒƣö‰N€DH«Ĉg†——Ñ‚aB{ÊNF´¬c·Åv}eÇÃGB»”If•¦HňĕM…~[iwjUÁKE•Ž‹¾dĪçW›šI‹èÀŒoÈXòyŞŮÈXâÎŚŠj|àsRy‹µÖ›–Pr´þŒ ¸^wþTDŔ–Hr¸‹žRÌmf‡żÕâCôox–ĜƌÆĮŒ›Ð–œY˜tâŦÔ@]ÈǮƒ\\μģUsȯLbîƲŚºyh‡rŒŠ@ĒԝƀŸÀ²º\\êp“’JŠ}ĠvŠqt„Ġ@^xÀ£È†¨mËÏğ}n¹_¿¢×Y_æpˆÅ–A^{½•Lu¨GO±Õ½ßM¶w’ÁĢۂP‚›Ƣ¼pcIJxŠ|ap̬HšÐŒŊSfsðBZ¿©“XÏÒK•k†÷Eû¿‰S…rEFsÕūk”óVǥʼniTL‚¡n{‹uxţÏh™ôŝ¬ğōN“‘NJkyPaq™Âğ¤K®‡YŸxÉƋÁ]āęDqçgOg†ILu—\\_gz—]W¼ž~CÔē]bµogž_oď`´³Țkl`IªºÎȄqÔþž»E³ĎSJ»œ_f·‚adÇqƒÇc¥Á_Źw{™L^ɱćx“U£µ÷xgĉp»ĆqNē`rĘzaĵĚ¡K½ÊBzyäKXqiWPÏɸ½řÍcÊG|µƕƣG˛÷Ÿk°_^ý|_zċBZocmø¯hhcæ\\lˆMFlư£Ĝ„ÆyH“„‰µêÕ]—›HA…àӄ^it `þßäkŠĤÎT~Wlÿ¨„ÔPzUC–NVv [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ĉ܇˜‰}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͕çWViŽ]ë©Ä÷àyƛh›ÚU°ŒŒa”d„cQƒ~Mx¥™cc¡ÙaSyF—ցk­ŒuRýq¿Ôµ•QĽ³aG{¿FµëªéĜÿª@¬·–K‰·àariĕĀ«V»Ŷ™Ĵū˜gèLǴŇƶaf‹tŒèBŚ£^Šâ†ǐÝ®–šM¦ÁǞÿ¬LhŸŽJ¾óƾƺcxw‹f]Y…´ƒ¦|œQLn°aœ…œ\\¨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ÀgVjzlhǶf€žOšfdЉªB]pj„•TO–‚n¤}®¦ƒČ¥d¢¼»ddš”Žt—¢eȤJ¤}Ǿ¡°§¤AГlc@ĝ”sªćļđAç‡wx•UuzEÖġ~AN¹ÄÅȀݦ¿ģŁéì±H…ãd«g[؉¼ēÀ•cīľġ¬cJ‘µ…ÐʥVȝ¸ßS¹†ý±ğkƁ¼ą^ɛ¤Ûÿ‰b[}¬ōõÃ]ËNm®g@•Bg}ÍF±ǐyL¥íCˆƒ€Ï÷њį[¹¦[⚍EÛïÁÉdƅß{âNÆāŨߝ¾ě÷yC£‡k­´ÓH@¹†TZ¥¢įƒ·ÌAЧ®—Zc…ŸZ­¹|ŕWZqgW“|ieZÅYVӁqdq•bc²R@†c‡¥Rã»Ge†Ÿeƃī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ŘvŽgÌsN@îá¾ó@‰˜ÙwU±ÉT廣TđŸWxq¹Zo‘b‹s[׌¯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•ÚÅTSij‚‹Yo|Ç[ǾµMW¢ĭiÕØ¿@˜šMh…pÕ]j†éò¿OƇĆƇp€êĉâlØw–ěsˆǩ‚ĵ¸c…bU¹ř¨WavquSMzeo_^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~ź¤Pn–MĪÖB£Ÿk™„§żćŠ˜ĆK„ǰ¼L¶è‰âz¨u¦¥LDĘz¬ýÎmĘd¾ß”Fz“hg²™Fy¦ĝ¤ċņbΛ@y‚Ąæm°NĮZRÖíŽJ²öLĸÒ¨Y®ƌÐV‰à˜tt_ڀÂyĠzž]Ţh€zĎ{†ĢX”ˆc|šÐqŽšfO¢¤ög‚ÌHNŽ„PKŖœŽ˜´xx[xˆvĐCûŠìÖT¬¸^}Ìsòd´_އKgžLĴ…ÀBon|H@–Êx˜—¦BpŰˆŌ¿fµƌA¾zLjRxжF”œkĄźRzŀˆ~¶[”´Hnª–VƞuĒ­È¨ƎcƽÌm¸ÁÈM¦x͊ëÀxdžB’šú^´W†£–d„kɾĬpœw‚˂ØɦļĬIŚœÊ•n›Ŕa¸™~J°î”lɌxĤÊÈðhÌ®‚g˜T´øŽàCˆŽÀ^ªerrƘdž¢İP|Ė ŸWœªĦ^¶´ÂL„aT±üWƜ˜ǀšŶ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": [
"@@˜—ȮµšûG™Ħ}Ħšðǚ¶òƄ€jɂz°{ºØkÈęâ¦jª‚Bg‚\\œċ°s¬Ž’]jžú ‚E”Ȍdž¬s„t‡”RˆÆdĠݎ”¸ôW¾ƮłÒ_{’Ìšû¼„jº¹¢GǪÒ¯ĘƒZ`ºŊƒecņąš~BÂgzpâēòYǠȰÌTΨÂWœ|fcŸă§uF—Œ@NŸ¢XLƒŠRMº[ğȣſï|¥J™kc`sʼnǷ’‹W@µ÷K…ãï³ÛIcñ·VȋڍÒķø©—þ¥ƒy‚ÓŸğęmWµÎumZyOŅƟĥÓ~sÑL¤µaŅY¦ocyZ{‰y c]{ŒTa©ƒ`U_Ěē£ωÊƍ’K¶ȱÝƷ§{û»ÅÁȹÍéuij|¹cÑd‘ŠìUYƒŽO‘uF–ÕÈYvÁCqӃT•Ǣí§·S¹NgŠV¬ë÷Át‡°Dد’C´ʼnƒópģ}„ċcE˅FŸŸéGU¥×K…§­¶³B‹Č}C¿åċ`wġB·¤őcƭ²ő[Å^axwQO…ÿEËߌ•ĤNĔŸˆÄŠńwĪ­Šo[„_KÓª³“ÙnK‰Çƒěœÿ]ď€ă_d©·©Ýŏ°Ù®g]±„Ÿ‡ß˜å›—¬÷m\\›iaǑkěX{¢|ZKlçhLt€Ňîŵ€œè[€É@ƉĄEœ‡Ï˜³­ħZ«mJ…›×¾‘MtÝĦ£IwÄå\\Õ{‡˜ƒOwĬ©LÙ³ÙgBƕŀr̛ĢŭO¥lãyC§HÍ£ßEñŸ—­°ÙCgpťz‘ˆb`wI„vA|§”‡—hoĕ@E±“iYd¥OϹS|}F@¾oAO²{tfžÜ—¢Fǂ҈W²°BĤh^Wx{@„¬‚­F¸¡„ķn£P|ŸªĴ@^ĠĈæb–Ôc¶l˜Yi…–^Mi˜cϰÂ[ä€vï¶gv@À“Ĭ·lJ¸sn|¼u~a]’ÆÈtŌºJp’ƒþ£KKf~ЦUbyäIšĺãn‡Ô¿^­žŵMT–hĠܤko¼Ŏìąǜh`[tŒRd²IJ_œXPrɲ‰l‘‚XžiL§àƒ–¹ŽH˜°Ȧqº®QC—bA†„ŌJ¸ĕÚ³ĺ§ `d¨YjžiZvRĺ±öVKkjGȊĐePОZmļKÀ€‚[ŠŽ`ösìh†ïÎoĬdtKÞ{¬èÒÒBŒÔpIJÇĬJŊ¦±J«ˆ‹@·pH€µàåVKe›pW†ftsAÅqC·¬ko«pHÆuK@oŸHĆۄķhx“e‘n›S³àǍ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‰¦ÅÄÜdw˜Ab×ĠąJˆ¤DüègĺqBqœj°lI¡ĨÒ¤úSHbš‡Š‘BаaZˆ¢KJŽ’O[|A£žDx}Nì•HUnrk„ kp€¼Y kMJn[aG‚áÚÏ[½rc†}aQxOgsPMnUs‡nc‹Z…ž–sKúvA›t„Þġ’£®ĀYKdnFwš¢JE°”Latf`¼h¬we|€Æ‡šbj}GA€·~WŽ”—`†¢MC¤tL©IJ°qdf”O‚“bÞĬ¹ttu`^ZúE`Œ[@„Æsîz®¡’C„ƳƜG²“R‘¢R’m”fŽwĸg܃‚ą G@pzJM½mŠhVy¸uÈÔO±¨{LfæU¶ßGĂq\\ª¬‡²I‚¥IʼnÈīoı‹ÓÑAçÑ|«LÝcspīðÍg…të_õ‰\\ĉñLYnĝg’ŸRǡÁiHLlõUĹ²uQjYi§Z_c¨Ÿ´ĹĖÙ·ŋI…ƒaBD˜­R¹ȥr—¯G•ºß„jWk’ɱŠOq›Wij\\a­‹Q\\sg_ĆǛōëp»£lğۀgS•ŶN®À]ˆÓäm™ĹãJaz¥V}‰Le¤L„ýo‘¹IsŋÅÇ^‘Žbz…³tmEÁ´aйcčecÇN•ĊãÁ\\蝗dNj•]j†—ZµkÓda•ćå]ğij@ ©O{¤ĸm¢ƒ®ƒ«|@Xwg]A챝‡XǁÑdzªc›wQÚŝñ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ĪğP‘s{ò‡‹‘²Vw¹t³Ŝˁ[ŽÑ}X\\gsFŸ£sPAgěp×ëfYHāďÖqēŭOÏë“dLü•\\iŒ”t^c®šRʺ¶—¢H°mˆ‘rYŸ£BŸ¹čIoľu¶uI]vģSQ{ƒ”Å}QÂ|̋°ƅ¤ĩŪU ęĄžÌZҞ\\v˜²PĔ»ƢNHƒĂyAmƂwVmž`”b•”H`‰Ì¢²ILvĜ—H®¤Dlt_„¢JJÄämèÔDëþgºƫ™”aʎÌrêYi~ ÎݤNpÀA¾Ĕ¼b…ð÷’Žˆ‡®‚”üs”zMzÖĖQdȨý†v§Tè|ªH’þa¸|šÐ ƒwKĢx¦ivr^ÿ ¸l öæfƟĴ·PJv}n\\h¹¶v†·À|\\ƁĚN´Ĝ€çèÁz]ġ¤²¨QÒŨTIl‡ªťØ}¼˗ƦvÄùØE‹’«Fï˛Iq”ōŒTvāÜŏ‚íÛߜÛV—j³âwGăÂíNOŠˆŠPìyV³ʼnĖýZso§HіiYw[߆\\X¦¥c]ÔƩÜ·«j‡ÐqvÁ¦m^ċ±R™¦΋ƈťĚgÀ»IïĨʗƮްƝ˜ĻþÍAƉſ±tÍEÕÞāNU͗¡\\ſčåÒʻĘm ƭÌŹöʥ’ëQ¤µ­ÇcƕªoIýˆ‰_mkl³ă‰Ɠ¦j—¡Yz•Ňi–}Msßõ–īʋ —}ƒÁVmŸ_[n}eı­Uĥ¼‘ª•I{ΧDӜƻėoj‘qYhĹT©oūĶ£]ďxĩ‹ǑMĝ‰q`B´ƃ˺Ч—ç~™²ņj@”¥@đ´ί}ĥtPńǾV¬ufӃÉC‹̻‰…¹£G³€]ƖƾŎĪŪĘ̖¨ʈĢƂlɘ۪üºňUðǜȢƢż̌ȦǼ‚ĤŊɲĖ­Kq´ï¦—ºĒDzņɾªǀÞĈĂD†½ĄĎÌŗĞrôñnŽœN¼â¾ʄľԆ|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ǚ‹\\đ¾JŽwÀďksãA‹fÕ¦L}wa‚o”Z’‹†Ml«]eÒÅaɲáo½FõÛ]ĻÒ¡wYR£¢rvÓ®y®LF‹LzĈ„ô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ĺSZg’rpiƼĘԛ¨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\\ZŽ•¨GtpþYŊĕ´€zUO뇉P‰îMĄÁxH´á˜iÜUà›îÜՁĂÛSuŎ‹r“œJð̬EŒ‘FÁú×uÃÎkr“Ē{V}İ«O_ÌËĬ©ŽÓŧSRѱ§Ģ£^ÂyèçěM³Ƃę{[¸¿u…ºµ[gt£¸OƤĿéYŸõ·kŸq]juw¥Dĩƍ€õÇPéĽG‘ž©ã‡¤G…uȧþRcÕĕNy“yû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ĻĖH”Aëáa…­OÇðñęNw‡…œľ·L›mI±íĠĩPÉ×®ÿs—’cB³±JKßĊ«`…ađ»·QAmO’‘Vţéÿ¤¹SQt]]Çx€±¯A@ĉij¢Ó祖•ƒl¶ÅÛr—ŕspãRk~¦ª]Į­´“FR„åd­ČsCqđéFn¿Åƃm’Éx{W©ºƝºįkÕƂƑ¸wWūЩÈFž£\\tÈ¥ÄRÈýÌJ ƒlGr^×äùyÞ³fj”c†€¨£ÂZ|ǓMĝšÏ@ëÜőR‹›ĝ‰Œ÷¡{aïȷPu°ËXÙ{©TmĠ}Y³’­ÞIňµç½©C¡į÷¯B»|St»›]vƒųƒ”}MÓ ÿʪƟǭA¡fs˜»PY¼c¡»¦c„ċ­¥£~msĉP•–Siƒ^o©A‰Šec‚™PeǵŽkg‚yUi¿h}aH™šĉ^|ᴟ¡HØûÅ«ĉ®]m€¡qĉ¶³ÈyôōLÁst“BŸ®wn±ă¥HSò뚣˜S’ë@לÊăxÇN©™©T±ª£IJ¡fb®ÞbŽb_Ą¥xu¥B—ž{łĝ³«`d˜Ɛt—¤ťiñžÍUuºí`£˜^tƃIJc—·ÛLO‹½Šsç¥Ts{ă\\_»™Š±q©čiìĉ|ÍIƒ¥ć¥›€]ª§D{ŝŖÉR_sÿc³Īō›ƿΑ›§p›†›c¯bKm›R¥{³„Z†e^ŽŒwx¹dƽŽôIg §Mĕ ƹĴ¿—ǣÜ̓]‹Ý–]snåA{‹eŒƭ`ǻŊĿ\\ijŬű”YÂÿ¬jĖqŽßbЏ•¸©@ěĀ©ê¶ìÀEH|´bRľž–Ó¶rÀQþ‹vl®Õ‚E˜TzÜdb ˜hw¤{LR„ƒd“c‹‹ÙVgœ‚ƜßzÃô쮍^jUèXΖ|UäÌ»rKŽ\\ŒªN‘¼pZCü†VY††¤ɃRi^rPҒTÖ}|br°qňb̰ªiƶGQ¾²„x¦PœmlŜ‘[Ĥ¡Ξ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ð”ļA†TUvdTŠG†º̼ŠÔ€Œ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 ›ö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_bs“KF¯¡Ix™mELcÿZ¤­Ģ‘ƒÝœsuBLù•t†ŒYdˆmVtNmtOPhRw~bd…¾qÐ\\âÙH\\bImlNZŸ»loƒŸqlVm–Gā§~QCw¤™{A\\‘PKŸNY‡¯bF‡kC¥’sk‹Šs_Ã\\ă«¢ħkJi¯r›rAhĹûç£CU‡ĕĊ_ԗBixÅُĄnªÑaM~ħpOu¥sîeQ¥¤^dkKwlL~{L~–hw^‚ófćƒKyEŒ­K­zuÔ¡qQ¤xZÑ¢^ļöܾEpž±âbÊÑÆ^fk¬…NC¾‘Œ“YpxbK~¥ŽŽŒäBlt¿Đx½I[ĒǙŒWž‹f»Ĭ}d§dµùEu‚IÆ¢¥dXªƅx¿]mtÏwßR͌X¢͎vÆzƂZò®ǢÌʆCrâºMÞzžÆMҔÊÓŊZľ–Î®Ȉ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ģ¢\\‚ś’nkO›w¥±ƒƷFɯàĩÞáB¹Æ…ÑUw„੍žĽw[“mG½Èå~‡Æ÷QyŠěCFmĭZī—ŵVÁ™ƿQƛ—ûXS²‰b½KϽĉS›©ŷXĕŸ{ŽĕK·¥Ɨcqq©f¿]‡ßDõU³h—­gËÇïģÉɋw“k¯í}I·šœbmœÉ–ř›īJɥĻˁ×xo›ɹī‡l•c…¤³Xù]‘™DžA¿w͉ì¥wÇN·ÂËnƾƍdǧđ®Ɲv•Um©³G\\“}µĿ‡QyŹ“›µEw‰LJQ½yƋBe¶ŋÀů‡ož¥A—˜Éw@•{Gpm¿Aij†ŽKLhˆ³`ñcËtW‚±»ÕS‰ëüÿďD‡u\\wwwù³—V›ƒOMËGh£õP¡™er™Ïd{“‡ġWÁ…č|yšg^ğyÁzÙs`—s|ÉåªÇ}m¢Ń¨`x¥’ù^•}ƒÌ¥H«‰Yªƅ”Aйn~Ꝛf¤áÀz„gŠÇDIԝ´AňĀ҄¶ûEYospõD[{ù°]u›Jq•U•|Soċxţ[õÔĥkŋÞŭZ˺óYËüċrw €ÞkrťË¿XGÉbřaDü·Ē÷Aê[Ää€I®BÕИÞ_¢āĠpŠÛÄȉĖġDKwbm‡ÄNô‡ŠfœƫVÉvi†dz—H‘‹QµâFšù­Âœ³¦{YGžƒd¢ĚÜO „€{Ö¦ÞÍÀPŒ^b–ƾŠlŽ[„vt×ĈÍE˨¡Đ~´î¸ùÎh€uè`¸ŸHÕŔVºwĠââWò‡@{œÙNÝ´ə²ȕn{¿¥{l—÷eé^e’ďˆXj©î\\ªÑò˜Üìc\\üqˆÕ[Č¡xoÂċªbØ­Œø|€¶ȴZdÆÂšońéŒGš\\”¼C°ÌƁn´nxšÊOĨ’ہƴĸ¢¸òTxÊǪMīИÖŲÃɎOvˆʦƢ~FއRěò—¿ġ~åŊœú‰Nšžš¸qŽ’Ę[Ĕ¶ÂćnÒPĒÜvúĀÊbÖ{Äî¸~Ŕünp¤ÂH¾œĄYÒ©ÊfºmԈĘcDoĬMŬ’˜„‚”ʘچžȂVŦ –ŽèW°ªB|IJXŔþÈJĦÆæFĚêŠYĂªĂ]øªŖNÞüA€’fɨJ€˜¯ÎrDDšĤ€`€mz\\„§~D¬{vJÂ˜«lµĂb–¤p€ŌŰNĄ¨ĊXW|ų ¿¾ɄĦƐMT”‡òP˜÷fØĶK¢ȝ˔Sô¹òEð­”`Ɩ½ǒÂň×äı–§ĤƝ§C~¡‚hlå‚ǺŦŞkâ’~}ŽFøàIJaĞ‚fƠ¥Ž„Ŕdž˜®U¸ˆźXœv¢aƆúŪtŠųƠjd•ƺŠƺÅìnrh\\ĺ¯äɝĦ]èpĄ¦´LƞĬŠ´ƤǬ˼Ēɸ¤rºǼ²¨zÌPðŀbþ¹ļD¢¹œ\\ĜÑŚŸ¶ZƄ³àjĨoâŠȴLʉȮŒĐ­ĚăŽÀêZǚŐ¤qȂ\\L¢ŌİfÆs|zºeªÙæ§΢{Ā´ƐÚ¬¨Ĵà²łhʺKÞºÖTŠiƢ¾ªì°`öø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ŧ€“oa›‹FLg‘QN_•dV€@Zom_ć\\ߚc±x¯oœRcfe…£’o§ËgToÛJíĔóu…|wP¤™XnO¢ÉˆŦ¯rNÄā¤zâŖÈRpŢZŠœÚ{GŠrFt¦Òx§ø¹RóäV¤XdˆżâºWbwڍUd®bêņ¾‘jnŎGŃŶŠnzÚSeîĜZczî¾i]͜™QaúÍÔiþĩȨWĢ‹ü|Ėu[qb[swP@ÅğP¿{\\‡¥A¨Ï‘ѨŠX\\¯œMK‘pA³[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…¶Ḟ“¬O_™ïlÁg“z±AXe™µÄĵ{¶]gitgšIj·›¥îakS€‰¨ÐƎk}ĕ{gB—qGf{¿a†U^fI“ư‹³õ{YƒıëNĿžk©ïËZŏ‘R§òoY×Ógc…ĥs¡bġ«@dekąI[nlPqCnp{ˆō³°`{PNdƗqSÄĻNNâyj]äžÒD ĬH°Æ]~¡HO¾ŒX}ÐxŒgp“gWˆrDGˆŒ‚Š^L‚ˆrzWxˆZ^¨´T\\|~@I‰zƒ–‹œjeĊªz£®Ĕvě€L†mV¾Ô_Ȕ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ƸÁxc‡"],
["@@©„ªƒ"],
["@@”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°¶‚ “Ê~rljĔëĚ¢~šuf`‘‚†fa‚ĔJåĊ„nÖ]„jƎćÊ@Š£¾a®£Ű{ŶĕF‹ègLk{Y|¡ĜWƔtƬJÑxq‹±ĢN´‰òK‰™–LÈüD|s`ŋ’ć]ƒÃ‰`đŒMûƱ½~Y°ħ`ƏíW‰½eI‹½{aŸ‘OIrÏ¡ĕŇa†p†µÜƅġ‘œ^ÖÛbÙŽŏml½S‹êqDu[R‹ãË»†ÿw`»y‘¸_ĺę}÷`M¯ċfCVµqʼn÷Z•gg“Œ`d½pDO‡ÎCnœ^uf²ènh¼WtƏxRGg¦…pV„†FI±ŽG^ŒIc´ec‡’G•ĹÞ½sëĬ„h˜xW‚}Kӈe­Xsbk”›L‘ØgTkïƵNï¶}Gy“w\\oñ¡nmĈzjŸ•@™Óc£»Wă¹Ój“_m»ˆ¹·~MvÛaqœ»­‰êœ’\\ÂoVnŽÓØÍ™²«‹bq¿efE „€‹Ĝ^Qž~ Évý‡ş¤²Į‰pEİ}zcĺƒL‹½‡š¿gņ›¡ýE¡ya£³t\\¨\\vú»¼§·Ñr_oÒý¥u‚•_n»_ƒ•At©Þűā§IVeëƒY}{VPÀFA¨ąB}q@|Ou—\\Fm‰QF݅Mw˜å}]•€|FmϋCaƒwŒu_p—¯sfÙgY…DHl`{QEfNysBЦzG¸rHe‚„N\\CvEsÐùÜ_·ÖĉsaQ¯€}_U‡†xÃđŠq›NH¬•Äd^ÝŰR¬ã°wećJEž·vÝ·Hgƒ‚éFXjÉê`|yŒpxkAwœWĐpb¥eOsmzwqChóUQl¥F^laf‹anòsr›EvfQdÁUVf—ÎvÜ^efˆtET¬ôA\\œ¢sJŽnQTjP؈xøK|nBz‰„œĞ»LY‚…FDxӄvr“[ehľš•vN”¢o¾NiÂxGp⬐z›bfZo~hGi’]öF|‰|Nb‡tOMn eA±ŠtPT‡LjpYQ|†SH††YĀxinzDJ€Ìg¢và¥Pg‰_–ÇzII‹€II•„£®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"],
["@@mŽn"],
["@@EpFo"],
["@@ea¢pl¸Eõ¹‡hj[ƒ]ÔCΖ@lj˜¡uBXŸ…•´‹AI¹…[‹yDUˆ]W`çwZkmc–…M›žp€Åv›}I‹oJlcaƒ‘Kްä¬XJmРđhI®æÔtSHn€Eˆ„ÒrÈc"],
["@@rMUw‡AS®€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
}

View File

@ -1,189 +0,0 @@
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 };
})();

View File

@ -1,45 +0,0 @@
<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>

View File

@ -1,47 +0,0 @@
<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>

View File

@ -1,52 +0,0 @@
<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>

View File

@ -1,67 +0,0 @@
<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>

View File

@ -1,110 +0,0 @@
<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>

View File

@ -1,32 +0,0 @@
<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>

View File

@ -1,42 +0,0 @@
<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>

View File

@ -1,94 +0,0 @@
<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>

View File

@ -1,79 +0,0 @@
<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>

View File

@ -1,13 +0,0 @@
<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>

View File

@ -1,17 +0,0 @@
<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>

View File

@ -1,35 +0,0 @@
<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>

View File

@ -1,53 +0,0 @@
<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>

View File

@ -1,13 +0,0 @@
<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>

View File

@ -1,69 +0,0 @@
<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>

View File

@ -1,19 +0,0 @@
<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>

View File

@ -1,77 +0,0 @@
<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>

View File

@ -1,52 +0,0 @@
<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>

View File

@ -1,101 +0,0 @@
<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>

View File

@ -1,58 +0,0 @@
<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>

View File

@ -1,23 +0,0 @@
<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>

View File

@ -1,15 +0,0 @@
<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>

View File

@ -1,81 +0,0 @@
<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>

View File

@ -1,112 +0,0 @@
<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>

View File

@ -1,117 +0,0 @@
<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>

View File

@ -1,59 +0,0 @@
<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>

View File

@ -1,64 +0,0 @@
<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>

View File

@ -1,31 +0,0 @@
<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>

View File

@ -1,32 +0,0 @@
<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>

View File

@ -1,44 +0,0 @@
<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>

View File

@ -1,91 +0,0 @@
<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>

View File

@ -1,54 +0,0 @@
<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>

View File

@ -1,33 +0,0 @@
<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>

View File

@ -1,97 +0,0 @@
<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>

View File

@ -1,81 +0,0 @@
<!-- 标题与字段布局 -->
<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>

View File

@ -1,70 +0,0 @@
<!-- 固定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>

View File

@ -1,143 +0,0 @@
<!-- 动态增减表单 -->
<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>

View File

@ -1,66 +0,0 @@
<!-- 操作按钮 -->
<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>

View File

@ -1,95 +0,0 @@
<!-- 操作禁用表单 -->
<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>

View File

@ -1,58 +0,0 @@
<!-- 操作禁用表单 -->
<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>

View File

@ -1,34 +0,0 @@
<!-- 操作表单值 -->
<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>

View File

@ -1,63 +0,0 @@
<!-- 控件属性 -->
<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>

View File

@ -1,32 +0,0 @@
<!-- 自定义组件 -->
<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>

View File

@ -1,32 +0,0 @@
<!-- 操作表单值 -->
<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>

View File

@ -1,64 +0,0 @@
<!-- 插槽 -->
<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>

View File

@ -1,80 +0,0 @@
<!-- 动态表单验证 -->
<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>

View File

@ -1,70 +0,0 @@
<!-- 字段显示与隐藏 -->
<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',
//隐藏idcss 控制,不会删除 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>

View File

@ -1,55 +0,0 @@
<!-- 字段标题提示及前缀 -->
<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>

View File

@ -1,105 +0,0 @@
<!-- 自定义页脚 -->
<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>

View File

@ -1,63 +0,0 @@
<!-- 表单布局 -->
<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>

View File

@ -1,84 +0,0 @@
<!-- 弹出层表单 -->
<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>

View File

@ -1,90 +0,0 @@
<!-- 自定义渲染 -->
<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>

View File

@ -1,58 +0,0 @@
<!-- 表单验证 -->
<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>

View File

@ -1,99 +0,0 @@
<!-- 操作表单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>

View File

@ -1,116 +0,0 @@
<!-- 查询区域 -->
<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>

View File

@ -1,63 +0,0 @@
<!-- 插槽 -->
<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>

View File

@ -1,94 +0,0 @@
<!-- 操作表单值 -->
<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>

View File

@ -1,63 +0,0 @@
<!-- 基本用法 -->
<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>

View File

@ -1,393 +0,0 @@
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',
},
},
];

View File

@ -1,452 +0,0 @@
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: 4,
//是否单选
multi: true
},
},
{
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',
}
},
];

View File

@ -1,24 +0,0 @@
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';

View File

@ -1,114 +0,0 @@
<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>

View File

@ -1,135 +0,0 @@
<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>

View File

@ -1,94 +0,0 @@
<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>

View File

@ -1,81 +0,0 @@
<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>

View File

@ -1,157 +0,0 @@
<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>

View File

@ -1,106 +0,0 @@
<template>
<div class="p-4">
<BasicTable @register="registerTable">
<template #id="{ record }"> ID: {{ record.id }} </template>
<template #bodyCell="{ column, record }">
<Avatar v-if="column.key === 'avatar'" :size="60" :src="record.avatar" />
<Tag v-if="column.key === 'no'" color="green">
{{ record.no }}
</Tag>
</template>
<template #img="{ text }">
<TableImg :size="60" :simpleShow="true" :imgList="text" />
</template>
<template #imgs="{ text }"> <TableImg :size="60" :imgList="text" /> </template>
<template #category="{ record }">
<Tag color="green">
{{ record.no }}
</Tag>
</template>
</BasicTable>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { BasicTable, useTable, BasicColumn, TableImg } from '/@/components/Table';
import { Tag, Avatar } from 'ant-design-vue';
import { demoListApi } from '/@/api/demo/table';
import { useListPage } from '/@/hooks/system/useListPage';
const columns: BasicColumn[] = [
{
title: 'ID',
dataIndex: 'id',
slots: { customRender: 'id' },
},
{
title: '头像',
dataIndex: 'avatar',
width: 100,
},
{
title: '分类',
dataIndex: 'category',
width: 80,
align: 'center',
defaultHidden: true,
slots: { customRender: 'category' },
},
{
title: '姓名',
dataIndex: 'name',
width: 120,
},
{
title: '图片列表1',
dataIndex: 'imgArr',
helpMessage: ['这是简单模式的图片列表', '只会显示一张在表格中', '但点击可预览多张图片'],
width: 140,
slots: { customRender: 'img' },
},
{
title: '照片列表2',
dataIndex: 'imgs',
width: 160,
slots: { customRender: 'imgs' },
},
{
title: '地址',
dataIndex: 'address',
},
{
title: '编号',
dataIndex: 'no',
},
{
title: '开始时间',
dataIndex: 'beginTime',
},
{
title: '结束时间',
dataIndex: 'endTime',
},
];
export default defineComponent({
components: { BasicTable, TableImg, Tag, Avatar },
setup() {
const { tableContext } = useListPage({
tableProps: {
title: '自定义列内容',
titleHelpMessage: '表格中所有头像、图片均为mock生成仅用于演示图片占位',
api: demoListApi,
columns: columns,
bordered: true,
showTableSetting: false,
showActionColumn: false,
useSearchForm: false,
},
});
//注册table数据
const [registerTable] = tableContext;
return {
registerTable,
};
},
});
</script>

View File

@ -1,217 +0,0 @@
<template>
<div class="p-4">
<BasicTable @register="registerTable" @edit-end="handleEditEnd" @edit-cancel="handleEditCancel" :beforeEditSubmit="beforeEditSubmit" />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { BasicTable, useTable, BasicColumn } from '/@/components/Table';
import { optionsListApi } from '/@/api/demo/select';
import { demoListApi } from '/@/api/demo/table';
import { treeOptionsListApi } from '/@/api/demo/tree';
import { useMessage } from '/@/hooks/web/useMessage';
import { useListPage } from '/@/hooks/system/useListPage';
const columns: BasicColumn[] = [
{
title: '输入框',
dataIndex: 'name',
edit: true,
editComponentProps: {
prefix: '$',
},
width: 200,
},
{
title: '默认输入状态',
dataIndex: 'name7',
edit: true,
editable: true,
width: 200,
},
{
title: '输入框校验',
dataIndex: 'name1',
edit: true,
// 默认必填校验
editRule: true,
width: 200,
},
{
title: '输入框函数校验',
dataIndex: 'name2',
edit: true,
editRule: async (text) => {
if (text === '2') {
return '不能输入该值';
}
return '';
},
width: 200,
},
{
title: '数字输入框',
dataIndex: 'id',
edit: true,
editRule: true,
editComponent: 'InputNumber',
width: 200,
},
{
title: '下拉框',
dataIndex: 'name3',
edit: true,
editComponent: 'Select',
editComponentProps: {
options: [
{
label: 'Option1',
value: '1',
},
{
label: 'Option2',
value: '2',
},
],
},
width: 200,
},
{
title: '远程下拉',
dataIndex: 'name4',
edit: true,
editComponent: 'ApiSelect',
editComponentProps: {
api: optionsListApi,
resultField: 'list',
labelField: 'name',
valueField: 'id',
},
width: 200,
},
{
title: '远程下拉树',
dataIndex: 'name71',
edit: true,
editComponent: 'ApiTreeSelect',
editRule: false,
editComponentProps: {
api: treeOptionsListApi,
resultField: 'list',
},
width: 200,
},
{
title: '日期选择',
dataIndex: 'date',
edit: true,
editComponent: 'DatePicker',
editComponentProps: {
valueFormat: 'YYYY-MM-DD',
format: 'YYYY-MM-DD',
},
width: 200,
},
{
title: '时间选择',
dataIndex: 'time',
edit: true,
editComponent: 'TimePicker',
editComponentProps: {
valueFormat: 'HH:mm',
format: 'HH:mm',
},
width: 200,
},
{
title: '勾选框',
dataIndex: 'name5',
edit: true,
editComponent: 'Checkbox',
editValueMap: (value) => {
return value ? '是' : '否';
},
width: 200,
},
{
title: '开关',
dataIndex: 'name6',
edit: true,
editComponent: 'Switch',
editValueMap: (value) => {
return value ? '开' : '关';
},
width: 200,
},
];
export default defineComponent({
components: { BasicTable },
setup() {
// 列表页面公共参数、方法
const { tableContext } = useListPage({
designScope: 'basic-table-demo',
tableProps: {
title: '可编辑单元格示例',
api: demoListApi,
columns: columns,
showIndexColumn: false,
bordered: true,
showActionColumn: false,
useSearchForm: false,
},
});
//注册table数据
const [registerTable] = tableContext;
const { createMessage } = useMessage();
function handleEditEnd({ record, index, key, value }: Recordable) {
console.log(record, index, key, value);
return false;
}
// 模拟将指定数据保存
function feakSave({ value, key, id }) {
createMessage.loading({
content: `正在模拟保存${key}`,
key: '_save_fake_data',
duration: 0,
});
return new Promise((resolve) => {
setTimeout(() => {
if (value === '') {
createMessage.error({
content: '保存失败:不能为空',
key: '_save_fake_data',
duration: 2,
});
resolve(false);
} else {
createMessage.success({
content: `记录${id}${key}已保存`,
key: '_save_fake_data',
duration: 2,
});
resolve(true);
}
}, 2000);
});
}
async function beforeEditSubmit({ record, index, key, value }) {
console.log('单元格数据正在准备提交', { record, index, key, value });
return await feakSave({ id: record.id, key, value });
}
function handleEditCancel() {
console.log('cancel');
}
return {
registerTable,
handleEditEnd,
handleEditCancel,
beforeEditSubmit,
};
},
});
</script>

View File

@ -1,261 +0,0 @@
<template>
<div class="p-4">
<BasicTable @register="registerTable" @edit-change="onEditChange">
<template #action="{ record, column }">
<TableAction :actions="createActions(record, column)" />
</template>
</BasicTable>
</div>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { BasicTable, useTable, TableAction, BasicColumn, ActionItem, EditRecordRow } from '/@/components/Table';
import { optionsListApi } from '/@/api/demo/select';
import { demoListApi } from '/@/api/demo/table';
import { treeOptionsListApi } from '/@/api/demo/tree';
import { cloneDeep } from 'lodash-es';
import { useMessage } from '/@/hooks/web/useMessage';
import { useListPage } from '/@/hooks/system/useListPage';
const columns: BasicColumn[] = [
{
title: '输入框',
dataIndex: 'name',
editRow: true,
editComponentProps: {
prefix: '$',
},
width: 150,
},
{
title: '默认输入状态',
dataIndex: 'name7',
editRow: true,
width: 150,
},
{
title: '输入框校验',
dataIndex: 'name1',
editRow: true,
align: 'left',
// 默认必填校验
editRule: true,
width: 150,
},
{
title: '输入框函数校验',
dataIndex: 'name2',
editRow: true,
align: 'right',
editRule: async (text) => {
if (text === '2') {
return '不能输入该值';
}
return '';
},
},
{
title: '数字输入框',
dataIndex: 'id',
editRow: true,
editRule: true,
editComponent: 'InputNumber',
width: 150,
},
{
title: '下拉框',
dataIndex: 'name3',
editRow: true,
editComponent: 'Select',
editComponentProps: {
options: [
{
label: 'Option1',
value: '1',
},
{
label: 'Option2',
value: '2',
},
{
label: 'Option3',
value: '3',
},
],
},
width: 200,
},
{
title: '远程下拉',
dataIndex: 'name4',
editRow: true,
editComponent: 'ApiSelect',
editComponentProps: {
api: optionsListApi,
resultField: 'list',
labelField: 'name',
valueField: 'id',
},
width: 200,
},
{
title: '远程下拉树',
dataIndex: 'name8',
editRow: true,
editComponent: 'ApiTreeSelect',
editRule: false,
editComponentProps: {
api: treeOptionsListApi,
resultField: 'list',
},
width: 200,
},
{
title: '日期选择',
dataIndex: 'date',
editRow: true,
editComponent: 'DatePicker',
editComponentProps: {
valueFormat: 'YYYY-MM-DD',
format: 'YYYY-MM-DD',
},
width: 150,
},
{
title: '时间选择',
dataIndex: 'time',
editRow: true,
editComponent: 'TimePicker',
editComponentProps: {
valueFormat: 'HH:mm',
format: 'HH:mm',
},
width: 100,
},
{
title: '勾选框',
dataIndex: 'name5',
editRow: true,
editComponent: 'Checkbox',
editValueMap: (value) => {
return value ? '是' : '否';
},
width: 100,
},
{
title: '开关',
dataIndex: 'name6',
editRow: true,
editComponent: 'Switch',
editValueMap: (value) => {
return value ? '开' : '关';
},
width: 100,
},
];
export default defineComponent({
components: { BasicTable, TableAction },
setup() {
const { createMessage: msg } = useMessage();
const currentEditKeyRef = ref('');
const { tableContext } = useListPage({
designScope: 'basic-table-demo',
tableProps: {
title: '可编辑行示例',
titleHelpMessage: ['本例中修改[数字输入框]这一列时,同一行的[远程下拉]列的当前编辑数据也会同步发生改变'],
api: demoListApi,
columns: columns,
showIndexColumn: false,
showTableSetting: true,
tableSetting: { fullScreen: true },
actionColumn: {
width: 160,
title: 'Action',
dataIndex: 'action',
slots: { customRender: 'action' },
},
useSearchForm: false,
},
});
//注册table数据
const [registerTable] = tableContext;
function handleEdit(record: EditRecordRow) {
currentEditKeyRef.value = record.key;
record.onEdit?.(true);
}
function handleCancel(record: EditRecordRow) {
currentEditKeyRef.value = '';
record.onEdit?.(false, false);
}
async function handleSave(record: EditRecordRow) {
// 校验
msg.loading({ content: '正在保存...', duration: 0, key: 'saving' });
const valid = await record.onValid?.();
if (valid) {
try {
const data = cloneDeep(record.editValueRefs);
console.log(data);
//TODO 此处将数据提交给服务器保存
// ...
// 保存之后提交编辑状态
const pass = await record.onEdit?.(false, true);
if (pass) {
currentEditKeyRef.value = '';
}
msg.success({ content: '数据已保存', key: 'saving' });
} catch (error) {
msg.error({ content: '保存失败', key: 'saving' });
}
} else {
msg.error({ content: '请填写正确的数据', key: 'saving' });
}
}
function createActions(record: EditRecordRow, column: BasicColumn): ActionItem[] {
if (!record.editable) {
return [
{
label: '编辑',
disabled: currentEditKeyRef.value ? currentEditKeyRef.value !== record.key : false,
onClick: handleEdit.bind(null, record),
},
];
}
return [
{
label: '保存',
onClick: handleSave.bind(null, record, column),
},
{
label: '取消',
popConfirm: {
title: '是否取消编辑',
confirm: handleCancel.bind(null, record, column),
},
},
];
}
function onEditChange({ column, value, record }) {
// 本例
if (column.dataIndex === 'id') {
record.editValueRefs.name4.value = `${value}`;
}
console.log(column, value, record);
}
return {
registerTable,
handleEdit,
createActions,
onEditChange,
};
},
});
</script>

View File

@ -1,119 +0,0 @@
<template>
<PageWrapper
title="可展开表格"
content="不可与scroll共用。TableAction组件可配置stopButtonPropagation来阻止操作按钮的点击事件冒泡以便配合Table组件的expandRowByClick"
>
<BasicTable @register="registerTable">
<template #expandedRowRender="{ record }">
<span>No: {{ record.no }} </span>
</template>
<template #action="{ record }">
<TableAction
stopButtonPropagation
:actions="[
{
label: '删除',
icon: 'ic:outline-delete-outline',
onClick: handleDelete.bind(null, record),
},
]"
:dropDownActions="[
{
label: '启用',
popConfirm: {
title: '是否启用?',
confirm: handleOpen.bind(null, record),
},
},
]"
/>
</template>
</BasicTable>
</PageWrapper>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { BasicTable, useTable, TableAction, BasicColumn } from '/@/components/Table';
import { PageWrapper } from '/@/components/Page';
import { demoListApi } from '/@/api/demo/table';
import { useListPage } from '/@/hooks/system/useListPage';
const columns: BasicColumn[] = [
{
title: 'ID',
dataIndex: 'id',
fixed: 'left',
width: 200,
},
{
title: '姓名',
dataIndex: 'name',
width: 150,
filters: [
{ text: 'Male', value: 'male' },
{ text: 'Female', value: 'female' },
],
},
{
title: '地址',
dataIndex: 'address',
width: 300,
},
{
title: '编号',
dataIndex: 'no',
width: 150,
sorter: true,
defaultHidden: true,
},
{
title: '开始时间',
width: 150,
sorter: true,
dataIndex: 'beginTime',
},
{
title: '结束时间',
width: 150,
sorter: true,
dataIndex: 'endTime',
},
];
export default defineComponent({
components: { BasicTable, TableAction, PageWrapper },
setup() {
const { tableContext } = useListPage({
designScope: 'basic-table-demo',
tableProps: {
api: demoListApi,
title: '可展开表格演示',
titleHelpMessage: ['已启用expandRowByClick', '已启用stopButtonPropagation'],
columns: columns,
rowKey: 'id',
canResize: false,
expandRowByClick: true,
actionColumn: {
width: 160,
title: 'Action',
dataIndex: 'action',
},
useSearchForm: false,
},
});
//注册table数据
const [registerTable] = tableContext;
function handleDelete(record: Recordable) {
console.log('点击了删除', record);
}
function handleOpen(record: Recordable) {
console.log('点击了启用', record);
}
return {
registerTable,
handleDelete,
handleOpen,
};
},
});
</script>

View File

@ -1,131 +0,0 @@
<template>
<div class="p-4">
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<template #tableTitle>
<a-button type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<j-upload-button type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
</template>
<!--操作栏-->
<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';
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,
},
];
//ajax请求api接口
const demoListApi = (params) => {
return defHttp.get({ url: '/test/jeecgDemo/list', params });
};
// 列表页面公共参数、方法
const { tableContext, onExportXls, onImportXls } = useListPage({
designScope: 'basic-table-demo-filter',
tableProps: {
title: '表单搜索',
api: demoListApi,
columns: columns,
showActionColumn: false,
useSearchForm: false,
},
exportConfig: {
name: '示例列表',
url: '/test/jeecgDemo/exportXls',
},
importConfig: {
url: '/test/jeecgDemo/importExcel',
},
});
//注册table数据
const [registerTable, { reload }, { rowSelection, selectedRows, selectedRowKeys }] = tableContext;
/**
* 操作栏
*/
function getTableAction(record): ActionItem[] {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
];
}
function handleEdit(record) {
console.log(record);
}
</script>
<style scoped></style>

View File

@ -1,98 +0,0 @@
<template>
<div class="p-4">
<BasicTable @register="registerTable">
<template #action="{ record }">
<TableAction
:actions="[
{
label: '删除',
icon: 'ic:outline-delete-outline',
onClick: handleDelete.bind(null, record),
},
]"
:dropDownActions="[
{
label: '启用',
popConfirm: {
title: '是否启用?',
confirm: handleOpen.bind(null, record),
},
},
]"
/>
</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: 'ID',
dataIndex: 'id',
fixed: 'left',
width: 280,
},
{
title: '姓名',
dataIndex: 'name',
width: 260,
},
{
title: '地址',
dataIndex: 'address',
},
{
title: '编号',
dataIndex: 'no',
width: 300,
},
{
title: '开始时间',
width: 200,
dataIndex: 'beginTime',
},
{
title: '结束时间',
dataIndex: 'endTime',
width: 200,
},
];
export default defineComponent({
components: { BasicTable, TableAction },
setup() {
const { tableContext } = useListPage({
tableProps: {
title: '固定头和列示例',
api: demoListApi,
columns: columns,
canResize: false,
scroll: { y: 200 },
actionColumn: {
width: 160,
title: 'Action',
dataIndex: 'action',
},
useSearchForm: false,
},
});
const [registerTable] = tableContext;
function handleDelete(record: Recordable) {
console.log('点击了删除', record);
}
function handleOpen(record: Recordable) {
console.log('点击了启用', record);
}
return {
registerTable,
handleDelete,
handleOpen,
};
},
});
</script>

View File

@ -1,131 +0,0 @@
<template>
<div class="p-4">
<BasicTable @register="registerTable" class="components-table-demo-nested">
<template #bodyCell="{ column }">
<template v-if="column.key === 'operation'">
<a>Publish</a>
</template>
</template>
<template #expandedRowRender>
<a-table :columns="innerColumns" :data-source="innerData" :pagination="false">
<template #bodyCell="{ column }">
<template v-if="column.dataIndex === 'state'">
<span>
<a-badge status="success" />
Finished
</span>
</template>
<template v-if="column.dataIndex === 'operation'">
<span class="table-operation">
<a>Pause</a>
<a>Stop</a>
<a-dropdown>
<template #overlay>
<a-menu>
<a-menu-item>Action 1</a-menu-item>
<a-menu-item>Action 2</a-menu-item>
</a-menu>
</template>
<a> More </a>
</a-dropdown>
</span>
</template>
</template>
</a-table>
</template>
</BasicTable>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { BasicTable } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
const columns = [
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Platform', dataIndex: 'platform', key: 'platform' },
{ title: 'Version', dataIndex: 'version', key: 'version' },
{ title: 'Upgraded', dataIndex: 'upgradeNum', key: 'upgradeNum' },
{ title: 'Creator', dataIndex: 'creator', key: 'creator' },
{ title: 'Date', dataIndex: 'createdAt', key: 'createdAt' },
{ title: 'Action', key: 'operation' },
];
interface DataItem {
key: number;
name: string;
platform: string;
version: string;
upgradeNum: number;
creator: string;
createdAt: string;
}
const data: DataItem[] = [];
for (let i = 0; i < 3; ++i) {
data.push({
key: i,
name: 'Screem',
platform: 'iOS',
version: '10.3.4.5654',
upgradeNum: 500,
creator: 'Jack',
createdAt: '2014-12-24 23:12:00',
});
}
const innerColumns = [
{ title: 'Date', dataIndex: 'date', key: 'date' },
{ title: 'Name', dataIndex: 'name', key: 'name' },
{ title: 'Status', dataIndex: 'state', key: 'state' },
{ title: 'Upgrade Status', dataIndex: 'upgradeNum', key: 'upgradeNum' },
{
title: 'Action',
dataIndex: 'operation',
key: 'operation',
},
];
interface innerDataItem {
key: number;
date: string;
name: string;
upgradeNum: string;
}
const innerData: innerDataItem[] = [];
for (let i = 0; i < 3; ++i) {
innerData.push({
key: i,
date: '2014-12-24 23:12:00',
name: 'This is production name',
upgradeNum: 'Upgraded: 56',
});
}
export default defineComponent({
components: { BasicTable },
setup() {
// 列表页面公共参数、方法
const { tableContext } = useListPage({
tableProps: {
title: '内嵌表格',
dataSource: data,
columns: columns,
showActionColumn: false,
rowKey: 'key',
useSearchForm: false,
},
});
//注册table数据
const [registerTable] = tableContext;
return {
data,
columns,
innerColumns,
innerData,
registerTable,
};
},
});
</script>

View File

@ -1,70 +0,0 @@
<template>
<div class="p-4">
<BasicTable @register="registerTable" />
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { BasicColumn, BasicTable, useTable } from '/@/components/Table';
import { demoListApi } from '/@/api/demo/table';
//计算合并表头
export default defineComponent({
components: { BasicTable },
setup() {
const [registerTable] = useTable({
title: '分组表头示例',
api: demoListApi,
columns: getMergeHeaderColumns(),
bordered: true,
useSearchForm: false,
});
function getMergeHeaderColumns(): BasicColumn[] {
return [
{
title: 'ID',
dataIndex: 'id',
width: 300,
},
{
title: '姓名',
dataIndex: 'name',
width: 300,
},
{
title: '地址',
width: 120,
children: [
{
title: '地址',
dataIndex: 'address',
key: 'address',
width: 200,
},
{
title: '编号',
dataIndex: 'no',
key: 'no',
},
],
},
{
title: '开始时间',
dataIndex: 'beginTime',
width: 200,
},
{
title: '结束时间',
dataIndex: 'endTime',
width: 200,
},
];
}
return {
registerTable,
};
},
});
</script>

View File

@ -1,144 +0,0 @@
<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',
customCell: (record, index, column) => ({
colSpan: index < 4 ? 1 : 5,
}),
customRender: ({ text, record, index, column }) => {
return index < 4 ? text : `${record.name}/${record.age}/${record.address}/${record.phone}`;
},
},
{
title: '年龄',
dataIndex: 'age',
customCell: (record, index, column) => {
if (index == 4) {
return { colSpan: 0 };
}
},
},
{
title: '家庭住址',
dataIndex: 'address',
customCell: (record, index, column) => {
if (index == 4) {
return { colSpan: 0 };
}
},
},
{
title: '联系电话',
colSpan: 2,
dataIndex: 'tel',
customCell: (record, index, column) => {
if (index === 2) {
return { rowSpan: 2 };
}
if (index === 3) {
return { rowSpan: 0 };
}
if (index === 4) {
return { colSpan: 0 };
}
},
},
{
title: 'Phone',
colSpan: 0,
dataIndex: 'phone',
customCell: (record, index, column) => {
if (index === 4) {
return { colSpan: 0 };
}
},
},
];
// 列表页面公共参数、方法
const { tableContext } = useListPage({
designScope: 'basic-table-demo',
tableProps: {
title: '合并行列',
dataSource: [
{
key: '1',
name: '尹嘉乐',
age: 32,
tel: '0319-5972018',
phone: 17600080009,
address: '北京市昌平区',
},
{
key: '2',
name: '龙佳钰',
tel: '0319-5972018',
phone: 17600060007,
age: 42,
address: '北京市海淀区',
},
{
key: '3',
name: '贺泽惠',
age: 32,
tel: '0319-5972018',
phone: 17600040005,
address: '北京市门头沟区',
},
{
key: '4',
name: '沈勇',
age: 18,
tel: '0319-5972018',
phone: 17600010003,
address: '北京市朝阳区',
},
{
key: '5',
name: '白佳毅',
age: 18,
tel: '0319-5972018',
phone: 17600010002,
address: '北京市丰台区',
},
],
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>

View File

@ -1,139 +0,0 @@
<template>
<div>
<a-alert
message="多表格实例测试 (Issue #8792 修复)"
description="此示例演示父子组件同时使用 BasicTable 时,列配置、列宽调整等功能正常工作,两个表格实例互不干扰"
type="info"
show-icon
class="mb-4"
/>
<a-card title="父组件的表格" class="mb-4">
<BasicTable
@register="registerParentTable"
:columns="parentColumns"
:dataSource="parentData"
:pagination="false"
showTableSetting
:canResize="false"
>
<template #toolbar>
<a-button type="primary" @click="testParentTable">测试父表格</a-button>
</template>
</BasicTable>
</a-card>
<a-card title="子组件的表格">
<BasicTable
@register="registerChildTable"
:columns="childColumns"
:dataSource="childData"
:pagination="false"
showTableSetting
:canResize="false"
>
<template #toolbar>
<a-button type="primary" @click="testChildTable">测试子表格</a-button>
</template>
</BasicTable>
</a-card>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import { BasicTable, useTable, BasicColumn } from '/@/components/Table';
import { useMessage } from '/@/hooks/web/useMessage';
const { createMessage } = useMessage();
// 父表格配置
const parentColumns: BasicColumn[] = [
{
title: 'ID',
dataIndex: 'id',
width: 80,
},
{
title: '父表格-姓名',
dataIndex: 'name',
width: 150,
},
{
title: '父表格-年龄',
dataIndex: 'age',
width: 100,
},
{
title: '父表格-地址',
dataIndex: 'address',
width: 200,
},
];
const parentData = ref([
{ id: 1, name: '父表格-张三', age: 25, address: '北京市朝阳区' },
{ id: 2, name: '父表格-李四', age: 30, address: '上海市浦东新区' },
{ id: 3, name: '父表格-王五', age: 28, address: '广州市天河区' },
]);
const [registerParentTable, { getColumns: getParentColumns }] = useTable({
columns: parentColumns,
dataSource: parentData.value,
});
// 子表格配置
const childColumns: BasicColumn[] = [
{
title: 'ID',
dataIndex: 'id',
width: 80,
},
{
title: '子表格-产品名称',
dataIndex: 'product',
width: 150,
},
{
title: '子表格-价格',
dataIndex: 'price',
width: 100,
},
{
title: '子表格-库存',
dataIndex: 'stock',
width: 100,
},
{
title: '子表格-分类',
dataIndex: 'category',
width: 150,
},
];
const childData = ref([
{ id: 1, product: '子表格-商品A', price: 99, stock: 100, category: '电子产品' },
{ id: 2, product: '子表格-商品B', price: 199, stock: 50, category: '家居用品' },
{ id: 3, product: '子表格-商品C', price: 299, stock: 30, category: '服装鞋包' },
]);
const [registerChildTable, { getColumns: getChildColumns }] = useTable({
columns: childColumns,
dataSource: childData.value,
});
function testParentTable() {
const cols = getParentColumns();
createMessage.success(`父表格列数: ${cols.length},请查看控制台`);
console.log('父表格列配置:', cols);
}
function testChildTable() {
const cols = getChildColumns();
createMessage.success(`子表格列数: ${cols.length},请查看控制台`);
console.log('子表格列配置:', cols);
}
</script>
<style scoped>
</style>

View File

@ -1,80 +0,0 @@
<template>
<div class="p-4">
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" />
</template>
</BasicTable>
</div>
</template>
<script lang="ts" name="basic-table-demo" setup>
import { BasicColumn, BasicTable, TableAction } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
//定义表格列
const columns: BasicColumn[] = [
{
title: '姓名',
dataIndex: 'name',
key: 'name',
resizable: true,
},
{
title: '年龄',
dataIndex: 'age',
key: 'age',
},
{
title: '住址',
dataIndex: 'address',
key: 'address',
},
];
// 列表页面公共参数、方法
const { tableContext } = useListPage({
designScope: 'basic-table-demo',
tableProps: {
title: '可选择表格',
dataSource: [
{
id: '1',
name: '胡歌',
age: 32,
address: '朝阳区林萃路1号',
},
{
id: '2',
name: '刘诗诗',
age: 32,
address: '昌平区白沙路1号',
},
],
columns: columns,
rowSelection: { type: 'checkbox' }, //默认是 checkbox 多选,可以设置成 radio 单选
useSearchForm: false,
},
});
//注册table数据
const [registerTable, { reload }, { rowSelection, selectedRows, selectedRowKeys }] = tableContext;
/**
* 操作栏
*/
function getTableAction(record): ActionItem[] {
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
},
];
}
function handleEdit(record) {
console.log(record);
console.log(selectedRows.value);
console.log(selectedRowKeys.value);
}
</script>
<style scoped></style>

View File

@ -1,124 +0,0 @@
<template>
<div class="p-4">
<BasicTable @register="register">
<template #toolbar>
<a-button type="primary" @click="expandAll">展开全部</a-button>
<a-button type="primary" @click="collapseAll">折叠全部</a-button>
</template>
</BasicTable>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { BasicColumn, BasicTable } from '/@/components/Table';
import { useListPage } from '/@/hooks/system/useListPage';
const columns: BasicColumn[] = [
{
title: 'ID',
dataIndex: 'id',
fixed: 'left',
width: 200,
},
{
title: '姓名',
dataIndex: 'name',
width: 150,
filters: [
{ text: 'Male', value: 'male' },
{ text: 'Female', value: 'female' },
],
},
{
title: '地址',
dataIndex: 'address',
width: 300,
},
{
title: '编号',
dataIndex: 'no',
width: 150,
sorter: true,
defaultHidden: true,
},
{
title: '开始时间',
width: 150,
sorter: true,
dataIndex: 'beginTime',
},
{
title: '结束时间',
width: 150,
sorter: true,
dataIndex: 'endTime',
},
];
export default defineComponent({
components: { BasicTable },
setup() {
const { tableContext } = useListPage({
tableProps: {
title: '树形表格',
isTreeTable: true,
rowSelection: {
type: 'checkbox',
getCheckboxProps(record: Recordable) {
// Demo: 第一行id为0的选择框禁用
if (record.id === '0') {
return { disabled: true };
} else {
return { disabled: false };
}
},
},
columns: columns,
dataSource: getTreeTableData(),
rowKey: 'id',
useSearchForm: false,
},
});
//注册table数据
const [register, { expandAll, collapseAll }] = tableContext;
function getTreeTableData() {
const data: any = (() => {
const arr: any = [];
for (let index = 0; index < 40; index++) {
arr.push({
id: `${index}`,
name: 'John Brown',
age: `1${index}`,
no: `${index + 10}`,
address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park',
beginTime: new Date().toLocaleString(),
endTime: new Date().toLocaleString(),
children: [
{
id: `l2-${index}`,
name: 'John Brown',
age: `1${index}`,
no: `${index + 10}`,
address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park',
beginTime: new Date().toLocaleString(),
endTime: new Date().toLocaleString(),
},
{
id: `l3-${index}`,
name: 'John Mary',
age: `1${index}`,
no: `${index + 10}`,
address: 'New York No. 1 Lake ParkNew York No. 1 Lake Park',
beginTime: new Date().toLocaleString(),
endTime: new Date().toLocaleString(),
},
],
});
}
return arr;
})();
return data;
}
return { register, expandAll, collapseAll };
},
});
</script>

View File

@ -1,16 +0,0 @@
export { default as AuthColumnDemo } from './AuthColumnDemo.vue';
export { default as BasicTableBorder } from './BasicTableBorder.vue';
export { default as BasicTableDemo } from './BasicTableDemo.vue';
export { default as BasicTableDemoAjax } from './BasicTableDemoAjax.vue';
export { default as CustomerCellDemo } from './CustomerCellDemo.vue';
export { default as EditCellTableDemo } from './EditCellTableDemo.vue';
export { default as EditRowTableDemo } from './EditRowTableDemo.vue';
export { default as ExpandTableDemo } from './ExpandTableDemo.vue';
export { default as ExportTableDemo } from './ExportTableDemo.vue';
export { default as FixedHeaderColumn } from './FixedHeaderColumn.vue';
export { default as InnerTableDemo } from './InnerTableDemo.vue';
export { default as MergeHeaderDemo } from './MergeHeaderDemo.vue';
export { default as MergeTableDemo } from './MergeTableDemo.vue';
export { default as SelectTableDemo } from './SelectTableDemo.vue';
export { default as TreeTableDemo } from './TreeTableDemo.vue';
export { default as MultipleTableDemo } from './MultipleTableDemo.vue';

View File

@ -1,90 +0,0 @@
<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 {
AuthColumnDemo,
BasicTableBorder,
BasicTableDemo,
BasicTableDemoAjax,
CustomerCellDemo,
EditCellTableDemo,
EditRowTableDemo,
ExpandTableDemo,
ExportTableDemo,
FixedHeaderColumn,
InnerTableDemo,
MergeHeaderDemo,
MergeTableDemo,
SelectTableDemo,
TreeTableDemo,
MultipleTableDemo,
} from './index';
export default defineComponent({
name: 'document-table-demo',
components: {
AuthColumnDemo,
BasicTableBorder,
BasicTableDemo,
BasicTableDemoAjax,
CustomerCellDemo,
EditCellTableDemo,
EditRowTableDemo,
ExpandTableDemo,
ExportTableDemo,
FixedHeaderColumn,
InnerTableDemo,
MergeHeaderDemo,
MergeTableDemo,
SelectTableDemo,
TreeTableDemo,
MultipleTableDemo,
},
setup() {
//当前选中key
const activeKey = ref('BasicTableDemo');
//组件集合
const compList = ref([
{ key: 'BasicTableDemo', label: '基础静态表格' },
{ key: 'BasicTableDemoAjax', label: '常规AJAX表格' },
{ key: 'BasicTableBorder', label: '边框表格' },
{ key: 'CustomerCellDemo', label: '自定义列内容' },
{ key: 'EditCellTableDemo', label: '可编辑单元格' },
{ key: 'EditRowTableDemo', label: '可编辑行' },
{ key: 'ExpandTableDemo', label: '可展开表格' },
{ key: 'ExportTableDemo', label: '导入导出' },
{ key: 'FixedHeaderColumn', label: '固定头和列示例' },
{ key: 'InnerTableDemo', label: '内嵌表格' },
{ key: 'MergeHeaderDemo', label: '分组表头示例' },
{ key: 'MergeTableDemo', label: '合并行列' },
{ key: 'SelectTableDemo', label: '可选择表格' },
{ key: 'TreeTableDemo', label: '树形表格' },
{ key: 'AuthColumnDemo', label: '权限列设置' },
{ key: 'MultipleTableDemo', label: '多表格实例' },
]);
//当前选中组件
const currentComponent = computed(() => {
return activeKey.value;
});
//使用component动态切换tab
function tabChange(key) {
activeKey.value = key;
}
return {
activeKey,
currentComponent,
tabChange,
compList,
};
},
});
</script>

View File

@ -1,91 +0,0 @@
<template>
<PageWrapper title="代码编辑器组件示例" contentFullHeight fixedHeight contentBackground>
<template #extra>
<a-space size="middle">
<a-button @click="showData" type="primary">获取数据</a-button>
<RadioGroup button-style="solid" v-model:value="modeValue" @change="handleModeChange">
<RadioButton value="application/json"> json数据 </RadioButton>
<RadioButton value="htmlmixed"> html代码 </RadioButton>
<RadioButton value="javascript"> javascript代码 </RadioButton>
</RadioGroup>
</a-space>
</template>
<CodeEditor v-model:value="value" :mode="modeValue" />
</PageWrapper>
</template>
<script lang="ts">
import { defineComponent, ref } from 'vue';
import { CodeEditor } from '/@/components/CodeEditor';
import { PageWrapper } from '/@/components/Page';
import { Radio, Space, Modal } from 'ant-design-vue';
const jsonData =
'{"name":"BeJson","url":"http://www.xxx.com","page":88,"isNonProfit":true,"address":{"street":"科技园路.","city":"江苏苏州","country":"中国"},"links":[{"name":"Google","url":"http://www.xxx.com"},{"name":"Baidu","url":"http://www.xxx.com"},{"name":"SoSo","url":"http://www.xxx.com"}]}';
const jsData = `
(() => {
var htmlRoot = document.getElementById('htmlRoot');
var theme = window.localStorage.getItem('__APP__DARK__MODE__');
if (htmlRoot && theme) {
htmlRoot.setAttribute('data-theme', theme);
theme = htmlRoot = null;
}
})();
`;
const htmlData = `
<!DOCTYPE html>
<html lang="en" id="htmlRoot">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit" />
<meta
name="viewport"
content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=0"
/>
<title><%= title %></title>
<link rel="icon" href="/favicon.ico" />
</head>
<body>
<div id="app">
</div>
</body>
</html>
`;
export default defineComponent({
components: {
CodeEditor,
PageWrapper,
RadioButton: Radio.Button,
RadioGroup: Radio.Group,
ASpace: Space,
},
setup() {
const modeValue = ref('application/json');
const value = ref(jsonData);
function handleModeChange(e: ChangeEvent) {
const mode = e.target.value;
if (mode === 'application/json') {
value.value = jsonData;
return;
}
if (mode === 'htmlmixed') {
value.value = htmlData;
return;
}
if (mode === 'javascript') {
value.value = jsData;
return;
}
}
function showData() {
Modal.info({ title: '编辑器当前值', content: value.value });
}
return { value, modeValue, handleModeChange, showData };
},
});
</script>

Some files were not shown because too many files have changed in this diff Show More