diff --git a/.eslintrc.js b/.eslintrc.js index f2977df6..70c91784 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -21,7 +21,7 @@ module.exports = defineConfig({ 'plugin:vue/vue3-recommended', 'plugin:@typescript-eslint/recommended', 'prettier', - 'plugin:prettier/recommended', + 'plugin:prettier/recommended', '@unocss' ], rules: { @@ -67,6 +67,7 @@ module.exports = defineConfig({ } ], 'vue/multi-word-component-names': 'off', - 'vue/no-v-html': 'off' + 'vue/no-v-html': 'off', + 'prettier/prettier': 'off' // 芋艿:默认关闭 prettier 的 ESLint 校验,因为我们使用的是 IDE 的 Prettier 插件 } }) diff --git a/README.md b/README.md index aa498ce2..6c0cc78d 100644 --- a/README.md +++ b/README.md @@ -38,15 +38,15 @@ | 框架 | 说明 | 版本 | |----------------------------------------------------------------------|------------------|--------| -| [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.3.4 | -| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 4.4.11 | -| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.4.0 | +| [Vue](https://staging-cn.vuejs.org/) | Vue 框架 | 3.3.8 | +| [Vite](https://cn.vitejs.dev//) | 开发与构建工具 | 4.5.0 | +| [Element Plus](https://element-plus.org/zh-CN/) | Element Plus | 2.4.2 | | [TypeScript](https://www.typescriptlang.org/docs/) | JavaScript 的超集 | 5.2.2 | | [pinia](https://pinia.vuejs.org/) | Vue 存储库 替代 vuex5 | 2.1.7 | -| [vueuse](https://vueuse.org/) | 常用工具集 | 10.5.0 | -| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.5.0 | +| [vueuse](https://vueuse.org/) | 常用工具集 | 10.6.1 | +| [vue-i18n](https://kazupon.github.io/vue-i18n/zh/introduction.html/) | 国际化 | 9.6.5 | | [vue-router](https://router.vuejs.org/) | Vue 路由 | 4.2.5 | -| [unocss](https://uno.antfu.me/) | 原子 css | 0.56.5 | +| [unocss](https://uno.antfu.me/) | 原子 css | 0.57.4 | | [iconify](https://icon-sets.iconify.design/) | 在线图标库 | 3.1.1 | | [wangeditor](https://www.wangeditor.com/) | 富文本编辑器 | 5.1.23 | diff --git a/package.json b/package.json index fb0f23ad..bc01d35f 100644 --- a/package.json +++ b/package.json @@ -31,23 +31,23 @@ "@form-create/element-ui": "^3.1.24", "@iconify/iconify": "^3.1.1", "@videojs-player/vue": "^1.0.0", - "@vueuse/core": "^10.5.0", + "@vueuse/core": "^10.6.1", "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-vue": "^5.1.10", "@zxcvbn-ts/core": "^3.0.4", "animate.css": "^4.1.1", - "axios": "^1.6.0", + "axios": "^1.6.1", "benz-amr-recorder": "^1.1.5", "bpmn-js-token-simulation": "^0.10.0", "camunda-bpmn-moddle": "^7.0.1", "cropperjs": "^1.6.1", "crypto-js": "^4.2.0", "dayjs": "^1.11.10", - "diagram-js": "^12.6.0", - "driver.js": "^1.3.0", + "diagram-js": "^12.8.0", + "driver.js": "^1.3.1", "echarts": "^5.4.3", "echarts-wordcloud": "^2.1.0", - "element-plus": "2.4.1", + "element-plus": "2.4.2", "fast-xml-parser": "^4.3.2", "highlight.js": "^11.9.0", "jsencrypt": "^3.3.2", @@ -62,9 +62,9 @@ "steady-xml": "^0.1.0", "url": "^0.11.3", "video.js": "^7.21.5", - "vue": "^3.3.7", + "vue": "^3.3.8", "vue-dompurify-html": "^4.1.4", - "vue-i18n": "^9.6.2", + "vue-i18n": "^9.6.5", "vue-router": "^4.2.5", "vue-types": "^5.1.1", "vuedraggable": "^4.1.0", @@ -72,49 +72,49 @@ "xml-js": "^1.6.11" }, "devDependencies": { - "@commitlint/cli": "^18.2.0", - "@commitlint/config-conventional": "^18.1.0", - "@iconify/json": "^2.2.135", - "@intlify/unplugin-vue-i18n": "^1.4.0", + "@commitlint/cli": "^18.4.1", + "@commitlint/config-conventional": "^18.4.0", + "@iconify/json": "^2.2.142", + "@intlify/unplugin-vue-i18n": "^1.5.0", "@purge-icons/generated": "^0.9.0", - "@types/lodash-es": "^4.17.10", - "@types/node": "^20.8.9", - "@types/nprogress": "^0.2.2", - "@types/qrcode": "^1.5.4", - "@types/qs": "^6.9.9", - "@types/sortablejs": "^1.15.4", - "@typescript-eslint/eslint-plugin": "^6.9.1", - "@typescript-eslint/parser": "^6.9.1", - "@unocss/transformer-variant-group": "^0.57.1", - "@unocss/eslint-config": "^0.57.1", + "@types/lodash-es": "^4.17.11", + "@types/node": "^20.9.0", + "@types/nprogress": "^0.2.3", + "@types/qrcode": "^1.5.5", + "@types/qs": "^6.9.10", + "@types/sortablejs": "^1.15.5", + "@typescript-eslint/eslint-plugin": "^6.11.0", + "@typescript-eslint/parser": "^6.11.0", + "@unocss/transformer-variant-group": "^0.57.4", + "@unocss/eslint-config": "^0.57.4", "@vitejs/plugin-legacy": "^4.1.1", - "@vitejs/plugin-vue": "^4.4.0", + "@vitejs/plugin-vue": "^4.4.1", "@vitejs/plugin-vue-jsx": "^3.0.2", "autoprefixer": "^10.4.16", "bpmn-js": "8.9.0", "bpmn-js-properties-panel": "0.46.0", "consola": "^3.2.3", - "eslint": "^8.52.0", + "eslint": "^8.53.0", "eslint-config-prettier": "^9.0.0", "eslint-define-config": "^1.24.1", "eslint-plugin-prettier": "^5.0.1", "eslint-plugin-vue": "^9.18.1", - "lint-staged": "^15.0.2", + "lint-staged": "^15.1.0", "postcss": "^8.4.31", "postcss-html": "^1.5.0", "postcss-scss": "^4.0.9", - "prettier": "^3.0.3", + "prettier": "^3.1.0", "rimraf": "^5.0.5", - "rollup": "^4.1.5", + "rollup": "^4.4.1", "sass": "^1.69.5", "stylelint": "^15.11.0", "stylelint-config-html": "^1.1.0", "stylelint-config-recommended": "^13.0.0", "stylelint-config-standard": "^34.0.0", "stylelint-order": "^6.0.3", - "terser": "^5.23.0", + "terser": "^5.24.0", "typescript": "5.2.2", - "unocss": "^0.57.1", + "unocss": "^0.57.4", "unplugin-auto-import": "^0.16.7", "unplugin-element-plus": "^0.8.0", "unplugin-vue-components": "^0.25.2", diff --git a/src/api/crm/contact/index.ts b/src/api/crm/contact/index.ts new file mode 100644 index 00000000..6ac5a01d --- /dev/null +++ b/src/api/crm/contact/index.ts @@ -0,0 +1,65 @@ +/* + * @Author: zyna + * @Date: 2023-11-05 13:34:41 + * @LastEditTime: 2023-11-11 16:20:19 + * @FilePath: \yudao-ui-admin-vue3\src\api\crm\contact\index.ts + * @Description: + */ +import request from '@/config/axios' + +export interface ContactVO { + name: string + nextTime: Date + mobile: string + telephone: string + email: string + post: string + customerId: number + address: string + remark: string + ownerUserId: string + lastTime: Date + id: number + parentId: number + qq: number + webchat: string + sex: number + policyMakers: boolean + creatorName: string + updateTime?: Date + createTime?: Date + customerName: string +} + +// 查询crm联系人列表 +export const getContactPage = async (params) => { + return await request.get({ url: `/crm/contact/page`, params }) +} + +// 查询crm联系人详情 +export const getContact = async (id: number) => { + return await request.get({ url: `/crm/contact/get?id=` + id }) +} + +// 新增crm联系人 +export const createContact = async (data: ContactVO) => { + return await request.post({ url: `/crm/contact/create`, data }) +} + +// 修改crm联系人 +export const updateContact = async (data: ContactVO) => { + return await request.put({ url: `/crm/contact/update`, data }) +} + +// 删除crm联系人 +export const deleteContact = async (id: number) => { + return await request.delete({ url: `/crm/contact/delete?id=` + id }) +} + +// 导出crm联系人 Excel +export const exportContact = async (params) => { + return await request.download({ url: `/crm/contact/export-excel`, params }) +} +export const simpleAlllist = async () => { + return await request.get({ url: `/crm/contact/simpleAlllist` }) +} diff --git a/src/api/infra/codegen/index.ts b/src/api/infra/codegen/index.ts index 64701efe..1b91e917 100644 --- a/src/api/infra/codegen/index.ts +++ b/src/api/infra/codegen/index.ts @@ -67,6 +67,11 @@ export type CodegenCreateListReqVO = { tableNames: string[] } +// 查询列表代码生成表定义 +export const getCodegenTableList = (dataSourceConfigId: number) => { + return request.get({ url: '/infra/codegen/table/list?dataSourceConfigId=' + dataSourceConfigId }) +} + // 查询列表代码生成表定义 export const getCodegenTablePage = (params: PageParam) => { return request.get({ url: '/infra/codegen/table/page', params }) @@ -92,11 +97,6 @@ export const syncCodegenFromDB = (id: number) => { return request.put({ url: '/infra/codegen/sync-from-db?tableId=' + id }) } -// 基于 SQL 建表语句,同步数据库的表和字段定义 -export const syncCodegenFromSQL = (id: number, sql: string) => { - return request.put({ url: '/infra/codegen/sync-from-sql?tableId=' + id + '&sql=' + sql }) -} - // 预览生成代码 export const previewCodegen = (id: number) => { return request.get({ url: '/infra/codegen/preview?tableId=' + id }) diff --git a/src/api/infra/demo/demo01/index.ts b/src/api/infra/demo/demo01/index.ts new file mode 100644 index 00000000..1a4b01ca --- /dev/null +++ b/src/api/infra/demo/demo01/index.ts @@ -0,0 +1,40 @@ +import request from '@/config/axios' + +export interface Demo01ContactVO { + id: number + name: string + sex: number + birthday: Date + description: string + avatar: string +} + +// 查询示例联系人分页 +export const getDemo01ContactPage = async (params) => { + return await request.get({ url: `/infra/demo01-contact/page`, params }) +} + +// 查询示例联系人详情 +export const getDemo01Contact = async (id: number) => { + return await request.get({ url: `/infra/demo01-contact/get?id=` + id }) +} + +// 新增示例联系人 +export const createDemo01Contact = async (data: Demo01ContactVO) => { + return await request.post({ url: `/infra/demo01-contact/create`, data }) +} + +// 修改示例联系人 +export const updateDemo01Contact = async (data: Demo01ContactVO) => { + return await request.put({ url: `/infra/demo01-contact/update`, data }) +} + +// 删除示例联系人 +export const deleteDemo01Contact = async (id: number) => { + return await request.delete({ url: `/infra/demo01-contact/delete?id=` + id }) +} + +// 导出示例联系人 Excel +export const exportDemo01Contact = async (params) => { + return await request.download({ url: `/infra/demo01-contact/export-excel`, params }) +} \ No newline at end of file diff --git a/src/api/infra/demo/demo02/index.ts b/src/api/infra/demo/demo02/index.ts new file mode 100644 index 00000000..21e45c90 --- /dev/null +++ b/src/api/infra/demo/demo02/index.ts @@ -0,0 +1,37 @@ +import request from '@/config/axios' + +export interface Demo02CategoryVO { + id: number + name: string + parentId: number +} + +// 查询示例分类列表 +export const getDemo02CategoryList = async (params) => { + return await request.get({ url: `/infra/demo02-category/list`, params }) +} + +// 查询示例分类详情 +export const getDemo02Category = async (id: number) => { + return await request.get({ url: `/infra/demo02-category/get?id=` + id }) +} + +// 新增示例分类 +export const createDemo02Category = async (data: Demo02CategoryVO) => { + return await request.post({ url: `/infra/demo02-category/create`, data }) +} + +// 修改示例分类 +export const updateDemo02Category = async (data: Demo02CategoryVO) => { + return await request.put({ url: `/infra/demo02-category/update`, data }) +} + +// 删除示例分类 +export const deleteDemo02Category = async (id: number) => { + return await request.delete({ url: `/infra/demo02-category/delete?id=` + id }) +} + +// 导出示例分类 Excel +export const exportDemo02Category = async (params) => { + return await request.download({ url: `/infra/demo02-category/export-excel`, params }) +} \ No newline at end of file diff --git a/src/api/infra/demo/demo03/erp/index.ts b/src/api/infra/demo/demo03/erp/index.ts new file mode 100644 index 00000000..d408b630 --- /dev/null +++ b/src/api/infra/demo/demo03/erp/index.ts @@ -0,0 +1,91 @@ +import request from '@/config/axios' + +export interface Demo03StudentVO { + id: number + name: string + sex: number + birthday: Date + description: string +} + +// 查询学生分页 +export const getDemo03StudentPage = async (params) => { + return await request.get({ url: `/infra/demo03-student/page`, params }) +} + +// 查询学生详情 +export const getDemo03Student = async (id: number) => { + return await request.get({ url: `/infra/demo03-student/get?id=` + id }) +} + +// 新增学生 +export const createDemo03Student = async (data: Demo03StudentVO) => { + return await request.post({ url: `/infra/demo03-student/create`, data }) +} + +// 修改学生 +export const updateDemo03Student = async (data: Demo03StudentVO) => { + return await request.put({ url: `/infra/demo03-student/update`, data }) +} + +// 删除学生 +export const deleteDemo03Student = async (id: number) => { + return await request.delete({ url: `/infra/demo03-student/delete?id=` + id }) +} + +// 导出学生 Excel +export const exportDemo03Student = async (params) => { + return await request.download({ url: `/infra/demo03-student/export-excel`, params }) +} + +// ==================== 子表(学生课程) ==================== + +// 获得学生课程分页 +export const getDemo03CoursePage = async (params) => { + return await request.get({ url: `/infra/demo03-student/demo03-course/page`, params }) +} +// 新增学生课程 +export const createDemo03Course = async (data) => { + return await request.post({ url: `/infra/demo03-student/demo03-course/create`, data }) +} + +// 修改学生课程 +export const updateDemo03Course = async (data) => { + return await request.put({ url: `/infra/demo03-student/demo03-course/update`, data }) +} + +// 删除学生课程 +export const deleteDemo03Course = async (id: number) => { + return await request.delete({ url: `/infra/demo03-student/demo03-course/delete?id=` + id }) +} + +// 获得学生课程 +export const getDemo03Course = async (id: number) => { + return await request.get({ url: `/infra/demo03-student/demo03-course/get?id=` + id }) +} + +// ==================== 子表(学生班级) ==================== + +// 获得学生班级分页 +export const getDemo03GradePage = async (params) => { + return await request.get({ url: `/infra/demo03-student/demo03-grade/page`, params }) +} +// 新增学生班级 +export const createDemo03Grade = async (data) => { + return await request.post({ url: `/infra/demo03-student/demo03-grade/create`, data }) +} + +// 修改学生班级 +export const updateDemo03Grade = async (data) => { + return await request.put({ url: `/infra/demo03-student/demo03-grade/update`, data }) +} + +// 删除学生班级 +export const deleteDemo03Grade = async (id: number) => { + return await request.delete({ url: `/infra/demo03-student/demo03-grade/delete?id=` + id }) +} + +// 获得学生班级 +export const getDemo03Grade = async (id: number) => { + return await request.get({ url: `/infra/demo03-student/demo03-grade/get?id=` + id }) +} \ No newline at end of file diff --git a/src/api/infra/demo/demo03/inner/index.ts b/src/api/infra/demo/demo03/inner/index.ts new file mode 100644 index 00000000..f15ee1dc --- /dev/null +++ b/src/api/infra/demo/demo03/inner/index.ts @@ -0,0 +1,53 @@ +import request from '@/config/axios' + +export interface Demo03StudentVO { + id: number + name: string + sex: number + birthday: Date + description: string +} + +// 查询学生分页 +export const getDemo03StudentPage = async (params) => { + return await request.get({ url: `/infra/demo03-student/page`, params }) +} + +// 查询学生详情 +export const getDemo03Student = async (id: number) => { + return await request.get({ url: `/infra/demo03-student/get?id=` + id }) +} + +// 新增学生 +export const createDemo03Student = async (data: Demo03StudentVO) => { + return await request.post({ url: `/infra/demo03-student/create`, data }) +} + +// 修改学生 +export const updateDemo03Student = async (data: Demo03StudentVO) => { + return await request.put({ url: `/infra/demo03-student/update`, data }) +} + +// 删除学生 +export const deleteDemo03Student = async (id: number) => { + return await request.delete({ url: `/infra/demo03-student/delete?id=` + id }) +} + +// 导出学生 Excel +export const exportDemo03Student = async (params) => { + return await request.download({ url: `/infra/demo03-student/export-excel`, params }) +} + +// ==================== 子表(学生课程) ==================== + +// 获得学生课程列表 +export const getDemo03CourseListByStudentId = async (studentId) => { + return await request.get({ url: `/infra/demo03-student/demo03-course/list-by-student-id?studentId=` + studentId }) +} + +// ==================== 子表(学生班级) ==================== + +// 获得学生班级 +export const getDemo03GradeByStudentId = async (studentId) => { + return await request.get({ url: `/infra/demo03-student/demo03-grade/get-by-student-id?studentId=` + studentId }) +} \ No newline at end of file diff --git a/src/api/infra/demo/demo03/normal/index.ts b/src/api/infra/demo/demo03/normal/index.ts new file mode 100644 index 00000000..f15ee1dc --- /dev/null +++ b/src/api/infra/demo/demo03/normal/index.ts @@ -0,0 +1,53 @@ +import request from '@/config/axios' + +export interface Demo03StudentVO { + id: number + name: string + sex: number + birthday: Date + description: string +} + +// 查询学生分页 +export const getDemo03StudentPage = async (params) => { + return await request.get({ url: `/infra/demo03-student/page`, params }) +} + +// 查询学生详情 +export const getDemo03Student = async (id: number) => { + return await request.get({ url: `/infra/demo03-student/get?id=` + id }) +} + +// 新增学生 +export const createDemo03Student = async (data: Demo03StudentVO) => { + return await request.post({ url: `/infra/demo03-student/create`, data }) +} + +// 修改学生 +export const updateDemo03Student = async (data: Demo03StudentVO) => { + return await request.put({ url: `/infra/demo03-student/update`, data }) +} + +// 删除学生 +export const deleteDemo03Student = async (id: number) => { + return await request.delete({ url: `/infra/demo03-student/delete?id=` + id }) +} + +// 导出学生 Excel +export const exportDemo03Student = async (params) => { + return await request.download({ url: `/infra/demo03-student/export-excel`, params }) +} + +// ==================== 子表(学生课程) ==================== + +// 获得学生课程列表 +export const getDemo03CourseListByStudentId = async (studentId) => { + return await request.get({ url: `/infra/demo03-student/demo03-course/list-by-student-id?studentId=` + studentId }) +} + +// ==================== 子表(学生班级) ==================== + +// 获得学生班级 +export const getDemo03GradeByStudentId = async (studentId) => { + return await request.get({ url: `/infra/demo03-student/demo03-grade/get-by-student-id?studentId=` + studentId }) +} \ No newline at end of file diff --git a/src/api/mall/promotion/combination/combinationActivity.ts b/src/api/mall/promotion/combination/combinationActivity.ts index 15b7eef3..062db5c2 100644 --- a/src/api/mall/promotion/combination/combinationActivity.ts +++ b/src/api/mall/promotion/combination/combinationActivity.ts @@ -57,7 +57,7 @@ export const updateCombinationActivity = async (data: CombinationActivityVO) => // 关闭拼团活动 export const closeCombinationActivity = async (id: number) => { - return await request.put({ url: '/promotion/bargain-combination/close?id=' + id }) + return await request.put({ url: '/promotion/combination-activity/close?id=' + id }) } // 删除拼团活动 diff --git a/src/assets/map/json/china.json b/src/assets/map/json/china.json index 0c92e71c..bbc0a832 100644 --- a/src/assets/map/json/china.json +++ b/src/assets/map/json/china.json @@ -1 +1,856 @@ -{"type":"FeatureCollection","features":[{"type":"Feature","id":"710000","properties":{"id":"710000","cp":[121.509062,24.044332],"name":"台湾","childNum":6},"geometry":{"type":"MultiPolygon","coordinates":[["@@°Ü¯Û"],["@@ƛĴÕƊÉɼģºðʀ\\ƎsÆNŌÔĚänÜƤɊĂǀĆĴĤNJŨxĚĮǂƺòƌâÔ®ĮXŦţƸZûÐƕƑGđ¨ĭMó·ęcëƝɉlÝƯֹÅŃ^Ó·śŃNjƏďíåɛGɉ¿@ăƑ¥ĘWǬÏĶŁâ"],["@@\\p|WoYG¿¥Ij@¢"],["@@ ¡@V^RqBbAnTXeRz¤L«³I"],["@@ÆEEkWqë @"],["@@fced"],["@@¯ɜÄèaì¯ØǓIġĽ"],["@@çûĖëĄhòř "]],"encodeOffsets":[[[122886,24033]],[[123335,22980]],[[122375,24193]],[[122518,24117]],[[124427,22618]],[[124862,26043]],[[126259,26318]],[[127671,26683]]]}},{"type":"Feature","id":"130000","properties":{"id":"130000","cp":[114.502461,38.045474],"name":"河北","childNum":3},"geometry":{"type":"MultiPolygon","coordinates":[["@@o~Z]ªrºc_ħ²G¼s`jΟnüsÂłNX_M`ǽÓnUK Ĝēs¤©yrý§uģcJe"],["@@U`Ts¿mÂ"],["@@oºƋÄdeVDJj£J|ÅdzÂFt~KŨ¸IÆv|¢r}èonb}`RÎÄn°ÒdÞ²^®lnÐèĄlðÓ×]ªÆ}LiñÖ`^°Ç¶p®đDcŋ`ZÔ¶êqvFÆN®ĆTH®¦O¾IbÐã´BĐɢŴÆíȦpĐÞXR·nndO¤OÀĈƒQgµFo|gȒęSWb©osx|hYhgŃfmÖĩnºTÌSp¢dYĤ¶UĈjlǐpäìë|³kÛfw²Xjz~ÂqbTÑěŨ@|oMzv¢ZrÃVw¬ŧˏf°ÐTªqs{S¯r æÝlNd®²Ğ džiGĘJ¼lr}~K¨ŸƐÌWöÆzR¤lêmĞLÎ@¡|q]SvKÑcwpÏÏĿćènĪWlĄkT}J¤~ÈTdpddʾĬBVtEÀ¢ôPĎƗè@~kü\\rÊĔÖæW_§¼F´©òDòjYÈrbĞāøŀG{ƀ|¦ðrb|ÀH`pʞkvGpuARhÞÆǶgĘTǼƹS£¨¡ù³ŘÍ]¿ÂyôEP xX¶¹ÜO¡gÚ¡IwÃé¦ÅBÏ|ǰ N«úmH¯âDùyŜŲIÄuШD¸dɂFOhđ©OiÃ`ww^ÌkÑH«ƇǤŗĺtFu {Z}Ö@U´ ʚLg®¯Oı°Ãw ^VbÉsmA ê]]w§RRl£ȭµu¯b{ÍDěïÿȧuT£ġěŗƃĝQ¨fVƋƅna@³@ďyýIĹÊKŭfċŰóxV@tƯJ]eR¾fe|rHA|h~Ėƍl§ÏlTíb ØoÅbbx³^zÃͶSj®AyÂhðk`«P˵EFÛ¬Y¨Ļrõqi¼Wi°§Ð±´°^[À|ĠO@ÆxO\\ta\\tĕtû{ġȧXýĪÓjùÎRb^ÎfK[ÝděYfíÙTyuUSyŌŏů@Oi½éŅaVcř§ax¹XŻácWU£ôãºQ¨÷Ñws¥qEHÙ|šYQoŕÇyáĂ£MðoťÊP¡mWO¡v{ôvîēÜISpÌhp¨ jdeŔQÖjX³àĈ[n`Yp@UcM`RKhEbpŞlNut®EtqnsÁgAiúoHqCXhfgu~ÏWP½¢G^}¯ÅīGCÑ^ãziMáļMTÃƘrMc|O_¯Ŏ´|morDkO\\mĆJfl@c̬¢aĦtRıÒ¾ùƀ^juųœKUFyƝ īÛ÷ąV×qƥV¿aȉd³BqPBmaËđŻģmÅ®V¹d^KKonYg¯XhqaLdu¥ÍpDž¡KąÅkĝęěhq}HyÃ]¹ǧ£ Í÷¿qáµ§g¤o^á¾ZE¤i`ij{nOl»WÝĔįhgF[¿¡ßkOüš_ūiDZàUtėGyl}ÓM}jpEC~¡FtoQiHkk{Ãmï"]],"encodeOffsets":[[[119712,40641]],[[121616,39981]],[[116462,37237]]]}},{"type":"Feature","id":"140000","properties":{"id":"140000","cp":[111.849248,36.857014],"name":"山西","childNum":1},"geometry":{"type":"Polygon","coordinates":["@@ÞĩÒSra}ÁyWix±Üe´lèßÓǏokćiµVZģ¡coTS˹ĪmnÕńehZg{gtwªpXaĚThȑp{¶Eh®RćƑP¿£Pmc¸mQÝWďȥoÅîɡųAďä³aÏJ½¥PGąSM EÅruµéYÓŌ_dĒCoȵ]¯_²ÕjāK~©ÅØ^ÔkïçămÏk]±cݯÑÃmQÍ~_apm ~ç¡qu{JÅŧ·Ls}EyÁÆcI{¤IiCfUcƌÃp§]ě«vD@¡SÀµMÅwuYY¡DbÑc¡h×]nkoQdaMç~eDÛtT©±@¥ù@É¡ZcW|WqOJmĩl«ħşvOÓ«IqăV¥D[mI~Ó¢cehiÍ]Ɠ~ĥqX·eƷn±}v[ěďŕ]_œ`¹§ÕōIo©bs^}Ét±ū«³p£ÿ·Wµ|¡¥ăFÏs×¥ŅxÊdÒ{ºvĴÎêÌɊ²¶ü¨|ÞƸµȲLLúÉƎ¤ϊęĔV`_bªS^|dzY|dz¥pZbÆ£¶ÒK}tĦÔņƠPYznÍvX¶Ěn ĠÔzý¦ª÷ÑĸÙUȌ¸dòÜJð´ìúNM¬XZ´¤ŊǸ_tldI{¦ƀðĠȤ¥NehXnYGR° ƬDj¬¸|CĞKqºfƐiĺ©ª~ĆOQª ¤@ìǦɌ²æBÊTŸʂōĖĴŞȀÆÿȄlŤĒötνî¼ĨXh|ªM¤Ðz"],"encodeOffsets":[[116874,41716]]}},{"type":"Feature","id":"150000","properties":{"id":"150000","cp":[111.670801,41.818311],"name":"内蒙古","childNum":2},"geometry":{"type":"MultiPolygon","coordinates":[["@@¯PqFB |S³C|kñHdiÄ¥sʼnÅ PóÑÑE^ÅPpy_YtShQ·aHwsOnʼnÃs©iqjUSiº]ïW«gW¡ARë¥_sgÁnUI«m ]jvV¼euhwqAaW_µj »çjioQR¹ēÃßt@r³[ÛlćË^ÍÉáGOUÛOB±XkŹ£k|e]olkVͼÕqtaÏõjgÁ£§U^RLËnX°ÇBz^~wfvypV ¯ƫĉ˭ȫƗŷɿÿĿƑ˃ĝÿÃǃßËőó©ǐȍŒĖM×ÍEyxþp]ÉvïèvƀnÂĴÖ@V~Ĉv¦wĖtējyÄDXÄxGQuv_i¦aBçw˛wD©{tāmQ{EJ§KPśƘƿ¥@sCTÉ}ɃwƇy±gÑ}T[÷kÐ禫 SÒ¥¸ëBX½HáŵÀğtSÝÂa[ƣ°¯¦Pï¡]£ġÒk®G²èQ°óMq}EóƐÇ\\@áügQÍu¥FTÕ¿Jû]|mvāÎYua^WoÀa·ząÒot×¶CLƗi¯¤mƎHNJ¤îìɾŊìTdåwsRÖgĒųúÍġäÕ}Q¶¿A[¡{d×uQAMxVvMOmăl«ct[wº_ÇÊjb£ĦS_éQZ_lwgOiýe`YYLq§IÁdz£ÙË[ÕªuƏ³ÍTs·bÁĽäė[b[ŗfãcn¥îC¿÷µ[ŏÀQōĉm¿Á^£mJVmL[{Ï_£F¥Ö{ŹA} ×Wu©ÅaųijƳhB{·TQqÙIķËZđ©Yc|M¡ LeVUóK_QWk_ĥ¿ãZ»X\\ĴuUèlG®ěłTĠğDŃOrÍdÆÍz]± ŭ©Å]ÅÐ}UË¥©TċïxgckfWgi\\ÏĒ¥HkµEë{»ÏetcG±ahUiñiWsɁ·cCÕk]wȑ|ća}w VaĚá G°ùnM¬¯{ÈÐÆA¥ÄêJxÙ¢hP¢ÛºµwWOóFÁz^ÀŗÎú´§¢T¤ǻƺSėǵhÝÅQgvBHouʝl_o¿Ga{ïq{¥|ſĿHĂ÷aĝÇqZñiñC³ª »E`¨åXēÕqÉû[l}ç@čƘóO¿¡FUsAʽīccocÇS}£IS~ălkĩXçmĈ ŀÐoÐdxÒuL^T{r@¢ÍĝKén£kQyÅõËXŷƏL§~}kq»IHėDžjĝ»ÑÞoå°qTt|r©ÏS¯·eŨĕx«È[eM¿yupN~¹ÏyN£{©għWí»Í¾səšDž_ÃĀɗ±ąijĉʍŌŷSÉA±åǥɋ@ë£R©ąP©}ĹªƏj¹erLDĝ·{i«ƫC£µsKC GS|úþXgp{ÁX¿ć{ƱȏñZáĔyoÁhA}ŅĆfdʼn_¹Y°ėǩÑ¡H¯¶oMQqð¡Ë|Ñ`ƭŁX½·óÛxğįÅcQs«tȋDžFù^it«Č¯[hAi©á¥ÇĚ×l|¹y¯YȵƓñǙµïċĻ|Düȭ¶¡oŽäÕG\\ÄT¿Òõr¯LguÏYęRƩɷŌO\\İТæ^Ŋ IJȶȆbÜGĝ¬¿ĚVĎgª^íu½jÿĕęjık@Ľ]ėl¥ËĭûÁėéV©±ćn©ȇÍq¯½YÃÔʼnÉNÑÅÝy¹NqáʅDǡËñƁYÅy̱os§ȋµʽǘǏƬɱàưN¢ƔÊuľýľώȪƺɂļxZĈ}ÌʼnŪĺœĭFЛĽ̅ȣͽÒŵìƩÇϋÿȮǡŏçƑůĕ~ǼȳÐUfdIxÿ\\G zâɏÙOº·pqy£@qþ@Ǟ˽IBäƣzsÂZÁàĻdñ°ŕzéØűzșCìDȐĴĺf®Àľưø@ɜÖÞKĊŇƄ§͑těï͡VAġÑÑ»d³öǍÝXĉĕÖ{þĉu¸ËʅğU̎éhɹƆ̗̮ȘNJ֥ड़ࡰţાíϲäʮW¬®ҌeרūȠkɬɻ̼ãüfƠSצɩςåȈHϚÎKdzͲOðÏȆƘ¼CϚǚ࢚˼ФÔ¤ƌĞ̪Qʤ´¼mȠJˀƲÀɠmǐnǔĎȆÞǠN~ʢĜ¶ƌĆĘźʆȬ˪ĚǏĞGȖƴƀj`ĢçĶāàŃºēĢĖćYÀŎüôQÐÂŎŞdžŞêƖoˆDĤÕºÑǘÛˤ³̀gńƘĔÀ^ªƂ`ªt¾äƚêĦ¼ÐĔǎ¨Ȕ»͠^ˮÊȦƤøxRrŜH¤¸ÂxDÄ|ø˂˜ƮЬɚwɲFjĔ²Äw°dždÀÉ_ĸdîàŎjÊêTЪŌŜWÈ|tqĢUB~´°ÎFCU¼pĀēƄN¦¾O¶łKĊOjĚj´ĜYp{¦SĚÍ\\TתV÷Ší¨ÅDK°ßtŇĔK¨ǵÂcḷ̌ĚǣȄĽFlġUĵŇȣFʉɁMğįʏƶɷØŭOǽ«ƽū¹Ʊő̝Ȩ§ȞʘĖiɜɶʦ}¨֪ࠜ̀ƇǬ¹ǨE˦ĥªÔêFxúQEr´Wrh¤Ɛ \\talĈDJÜ|[Pll̚¸ƎGú´P¬W¦^¦H]prRn|or¾wLVnÇIujkmon£cX^Bh`¥V¦U¤¸}xRj[^xN[~ªxQ[`ªHÆÂExx^wN¶Ê|¨ìMrdYpoRzNyÀDs~bcfÌ`L¾n|¾T°c¨È¢ar¤`[|òDŞĔöxElÖdHÀI`Ď\\Àì~ÆR¼tf¦^¢ķ¶eÐÚMptgjɡČÅyġLûŇV®ÄÈƀϰP|ªVVªj¬ĚÒêp¬E|ŬÂc|ÀtƐK f{ĘFĒƌXƲąo½Ę\\¥o}Ûu£çkX{uĩ«āíÓUŅßŢqŤ¥lyň[oi{¦LńðFȪȖĒL¿Ìf£K£ʺoqNwğc`uetOj×°KJ±qÆġmĚŗos¬ qehqsuH{¸kH¡ ÊRǪÇƌbȆ¢´äÜ¢NìÉʖ¦â©Ġu¦öČ^â£ĂhĖMÈÄw\\fŦ°W ¢¾luŸDw\\̀ʉÌÛM Ā[bÓEn}¶Vc ês"]],"encodeOffsets":[[[129102,52189]]]}},{"type":"Feature","id":"210000","properties":{"id":"210000","cp":[123.429096,41.796767],"name":"辽宁","childNum":16},"geometry":{"type":"MultiPolygon","coordinates":[["@@L@@sa"],["@@MnNm"],["@@dc"],["@@eÀC@b"],["@@f XwkbrÄ`qg"],["@@^jtWQ"],["@@~ Y]c"],["@@G`ĔN^_¿ZÃM"],["@@iX¶BY"],["@@YZ"],["@@L_{Epf"],["@@^WqCT\\"],["@@\\[§t|¤_"],["@@m`n_"],["@@Ïxnj{q_×^Giip"],["@@@é^BntaÊU]x ¯ÄPIJ°hʙK³VÕ@Y~|EvĹsǦL^pòŸÒG Ël]xxÄ_fT¤Ď¤cPC¨¸TVjbgH²sdÎdHt`B²¬GJję¶[ÐhjeXdlwhðSȦªVÊÏÆZÆŶ®²^ÎyÅÎcPqńĚDMħĜŁHkçvV[ij¼WYÀäĦ`XlR`ôLUVfK¢{NZdĒªYĸÌÚJRr¸SA|ƴgŴĴÆbvªØX~źB|¦ÕE¤Ð`\\|KUnnI]¤ÀÂĊnŎR®Ő¿¶\\ÀøíDm¦ÎbŨabaĘ\\ľã¸atÎSƐ´©v\\ÖÚÌǴ¤Â¨JKrZ_ZfjþhPkx`YRIjJcVf~sCN¤ EhæmsHy¨SðÑÌ\\\\ĐRZk°IS§fqŒßýáĞÙÉÖ[^¯ǤŲê´\\¦¬ĆPM¯£»uïpùzExanµyoluqe¦W^£ÊL}ñrkqWňûPUP¡ôJoo·U}£[·¨@XĸDXmÛݺGUCÁª½{íĂ^cjk¶Ã[q¤LÉö³cux«zZf²BWÇ®Yß½ve±ÃCý£W{Ú^q^sÑ·¨ÍOt¹·C¥GDrí@wÕKţëV·i}xËÍ÷i©ĝɝǡ]{c±OW³Ya±_ç©HĕoƫŇqr³Lys[ñ³¯OSďOMisZ±ÅFC¥Pq{Ã[Pg}\\¿ghćO k^ģÁFıĉĥMoEqqZûěʼn³F¦oĵhÕP{¯~TÍlªNßYÐ{Ps{ÃVUeĎwk±ʼnVÓ½ŽJãÇÇ»Jm°dhcÀffdF~ĀeĖd`sx² ®EżĀdQÂd^~ăÔH¦\\LKpĄVez¤NP ǹÓRÆąJSha[¦´ÂghwmBШźhI|VV|p] ¼èNä¶ÜBÖ¼L`¼bØæKVpoúNZÞÒKxpw|ÊEMnzEQIZZNBčÚFÜçmĩWĪñtÞĵÇñZ«uD±|Əlij¥ãn·±PmÍada CLǑkùó¡³Ï«QaċÏOÃ¥ÕđQȥċƭy³ÃA"]],"encodeOffsets":[[[123686,41445]],[[126019,40435]],[[124393,40128]],[[126117,39963]],[[125322,40140]],[[126686,40700]],[[126041,40374]],[[125584,40168]],[[125453,40165]],[[125362,40214]],[[125280,40291]],[[125774,39997]],[[125976,40496]],[[125822,39993]],[[125509,40217]],[[122731,40949]]]}},{"type":"Feature","id":"220000","properties":{"id":"220000","cp":[125.3245,43.886841],"name":"吉林","childNum":1},"geometry":{"type":"Polygon","coordinates":["@@pä³PClFbbÍzwBGĭZÅi»lYċ²SgkÇ£^Sqd¯R ©é£¯S\\cZ¹iűƏCuƍÓXoR}M^o£ R}oªUF uuXHlEÅÏ©¤ÛmTþ¤D²ÄufàÀXXȱAeyYw¬dvõ´KÊ£\\rµÄlidā]|DÂVH¹Þ®ÜWnCķ W§@\\¸~¤Vp¸póIO¢VOŇürXql~òÉK]¤¥Xrfkvzpm¶bwyFoúv𼤠N°ąO¥«³[éǡű_°Õ\\ÚÊĝþâőàerR¨JYlďQ[ ÏYëЧTGztnß¡gFkMāGÁ¤ia Éȹ`\\xs¬dĆkNnuNUuP@vRY¾\\¢ GªóĄ~RãÖÎĢùđŴÕhQxtcæëSɽʼníëlj£ƍG£nj°KƘµDsØÑpyƸ®¿bXp]vbÍZuĂ{n^IüÀSÖ¦EvRÎûh@â[ƏÈô~FNr¯ôçR±HÑlĢ^¤¢OðævxsŒ]ÞÁTĠs¶¿âÆGW¾ìA¦·TѬè¥ÏÐJ¨¼ÒÖ¼ƦɄxÊ~StD@Ă¼Ŵ¡jlºWvÐzƦZвCH AxiukdGgetqmcÛ£Ozy¥cE}| ¾cZ k¿uŐã[oxGikfeäT@ SUwpiÚFM©£è^Ú`@v¶eňf heP¶täOlÃUgÞzŸU`l}ÔÆUvØ_Ō¬Öi^ĉi§²ÃB~¡ĈÚEgc|DC_Ȧm²rBx¼MÔ¦ŮdĨÃâYxƘDVÇĺĿg¿cwÅ\\¹¥Yĭl¤OvLjM_a W`zļMž·\\swqÝSAqŚij¯°kRē°wx^ĐkǂÒ\\]nrĂ}²ĊŲÒøãh·M{yMzysěnĒġV·°G³¼XÀ¤¹i´o¤ŃÈ`ÌDzÄUĞd\\iÖmÈBĤÜɲDEh LG¾ƀľ{WaYÍÈĢĘÔRîĐj}ÇccjoUb½{h§Ǿ{KƖµÎ÷GĀÖŠåưÎslyiē«`å§H¥Ae^§GK}iã\\c]v©ģZmÃ|[M}ģTɟĵÂÂ`ÀçmFK¥ÚíÁbX³ÌQÒHof{]ept·GŋĜYünĎųVY^ydõkÅZW«WUa~U·SbwGçǑiW^qFuNĝ·EwUtW·Ýďæ©PuqEzwAVXRãQ`©GMehccďÏd©ÑW_ÏYƅ» é\\ɹ~ǙG³mØ©BšuT§Ĥ½¢Ã_ýL¡ýqT^rme\\PpZZbyuybQefµ]UhĿDCmûvaÙNSkCwncćfv~ YÇG"],"encodeOffsets":[[130196,42528]]}},{"type":"Feature","id":"230000","properties":{"id":"230000","cp":[128.642464,46.756967],"name":"黑龙江","childNum":2},"geometry":{"type":"MultiPolygon","coordinates":[["@@UµNÿ¥īèçHÍøƕ¶Lǽ|g¨|a¾pVidd~ÈiíďÓQġėÇZÎXb½|ſÃH½KFgɱCģÛÇAnjÕc[VĝDZÃËÇ_ £ń³pj£º¿»WH´¯U¸đĢmtĜyzzNN|g¸÷äűѱĉā~mq^[ǁÑďlw]¯xQĔ¯l°řĴrBÞTxr[tޏĻN_yX`biNKu P£kZĮ¦[ºxÆÀdhĹŀUÈƗCwáZħÄŭcÓ¥»NAw±qȥnD`{ChdÙFć}¢A±Äj¨]ĊÕjŋ«×`VuÓÅ~_kŷVÝyhVkÄãPsOµfgeŇ µf@u_Ù ÙcªNªÙEojVxT@ãSefjlwH\\pŏäÀvlY½d{F~¦dyz¤PÜndsrhfHcvlwjF£G±DÏƥYyÏu¹XikĿ¦ÏqƗǀOŜ¨LI|FRĂn sª|C˜zxAè¥bfudTrFWÁ¹Am|ĔĕsķÆF´N}ć UÕ@Áijſmuçuð^ÊýowFzØÎĕNőǏȎôªÌŒDŽàĀÄ˄ĞŀƒʀĀƘŸˮȬƬĊ°Uzouxe]} AyÈW¯ÌmKQ]Īºif¸ÄX|sZt|½ÚUÎ lk^p{f¤lºlÆW A²PVÜPHÊâ]ÎĈÌÜk´\\@qàsĔÄQºpRij¼èi`¶bXrBgxfv»uUi^v~J¬mVp´£´VWrnP½ì¢BX¬hðX¹^TjVriªjtŊÄmtPGx¸bgRsT`ZozÆO]ÒFôÒOÆŊvÅpcGêsx´DR{AEOr°x|íb³Wm~DVjºéNNËܲɶGxŷCSt}]ûōSmtuÇÃĕNāg»íT«u}ç½BĵÞʣ¥ëÊ¡MÛ³ãȅ¡ƋaǩÈÉQG¢·lG|tvgrrf«ptęŘnÅĢrI²¯LiØsPf_vĠdxM prʹL¤¤eËÀđKïÙVY§]Ióáĥ]ķK¥j|pŇ\\kzţ¦šnņäÔVĂîά|vW®l¤èØrxm¶ă~lÄƯĄ̈́öȄEÔ¤ØQĄĄ»ƢjȦOǺ¨ìSŖÆƬyQv`cwZSÌ®ü±DŽ]ŀç¬B¬©ńzƺŷɄeeOĨSfm ĊƀP̎ēz©ĊÄÕÊmgÇsJ¥ƔŊśæÎÑqv¿íUOµªÂnĦÁ_½ä@êí £P}Ġ[@gġ}gɊ×ûÏWXá¢užƻÌsNͽƎÁ§čŐAēeL³àydl¦ĘVçŁpśdžĽĺſÊQíÜçÛġÔsĕ¬Ǹ¯YßċġHµ ¡eå`ļrĉŘóƢFìĎWøxÊkƈdƬv|I|·©NqńRŀ¤éeŊŀàŀU²ŕƀBQ£Ď}L¹Îk@©ĈuǰųǨÚ§ƈnTËÇéƟÊcfčŤ^XmHĊĕË«W·ċëx³ǔķÐċJāwİ_ĸȀ^ôWr°oú¬Ħ ŨK~ȰCĐ´Ƕ£fNÎèâw¢XnŮeÂÆĶ¾¾xäLĴĘlļO¤ÒĨA¢Êɚ¨®ØCÔ ŬGƠƦYĜĘÜƬDJg_ͥœ@čŅĻA¶¯@wÎqC½Ĉ»NăëKďÍQÙƫ[«ÃígßÔÇOÝáWñuZ¯ĥŕā¡ÑķJu¤E 寰WKɱ_d_}}vyõu¬ï¹ÓU±½@gÏ¿rýDg Cdµ°MFYxw¿CG£Rƛ½Õ{]L§{qqą¿BÇƻğëܭNJË|c²}Fµ}ÙRsÓpg±QNqǫŋRwŕnéÑÉK«SeYR ŋ@{¤SJ}D Ûǖ֍]gr¡µŷjqWÛham³~S«Þ]"]],"encodeOffsets":[[[134456,44547]]]}},{"type":"Feature","id":"320000","properties":{"id":"320000","cp":[119.767413,33.041544],"name":"江苏","childNum":1},"geometry":{"type":"Polygon","coordinates":["@@cþÅPi`ZRu¥É\\]~°Y`µÓ^phÁbnÀşúòaĬºTÖŒbe¦¦{¸ZâćNp©Hr|^mjhSEb\\afv`sz^lkljÄtg¤D¾X¿À|ĐiZȀåB·î}GL¢õcßjayBFµÏC^ĭcÙt¿sğH]j{s©HM¢QnDÀ©DaÜÞ·jgàiDbPufjDk`dPOîhw¡ĥ¥GP²ĐobºrYî¶aHŢ´ ]´rılw³r_{£DB_Ûdåuk|Ũ¯F Cºyr{XFye³Þċ¿ÂkĭB¿MvÛpm`rÚã@ƹhågËÖƿxnlč¶Åì½Ot¾dJlVJĂǀŞqvnO^JZż·Q}êÍÅmµÒ]ƍ¦Dq}¬R^èĂ´ŀĻĊIÔtIJyQŐĠMNtR®òLhĚs©»}OÓGZz¶A\\jĨFäOĤHYJvÞHNiÜaĎÉnFQlNM¤B´ĄNöɂtpŬdfå qm¿QûùŞÚb¤uŃJŴu»¹ĄlȖħŴw̌ŵ²ǹǠ͛hĭłƕrçü±Yxcitğ®jű¢KOķCoy`å®VTa_Ā]ŐÝɞï²ʯÊ^]afYǸÃĆēĪȣJđ͍ôƋÄÄÍīçÛɈǥ£ÛmY`ó£Z«§°Ó³QafusNıDž_k}¢m[ÝóDµ¡RLčiXyÅNïă¡¸iĔÏNÌŕoēdōîåŤûHcs}~Ûwbù¹£¦ÓCtOPrE^ÒogĉIµÛÅʹK ¤½phMü`oæŀ"],"encodeOffsets":[[121740,32276]]}},{"type":"Feature","id":"330000","properties":{"id":"330000","cp":[120.153576,29.287459],"name":"浙江","childNum":45},"geometry":{"type":"MultiPolygon","coordinates":[["@@E^dQ]K"],["@@jX^j"],["@@sfbU"],["@@qP\\xz[ck"],["@@R¢FX}°[s_"],["@@Cb\\}"],["@@e|v\\la{u"],["@@v~u}"],["@@QxÂF¯}"],["@@¹nvÞs¯o"],["@@rSkUEj"],["@@biZP"],["@@p[}INf"],["@@À¿"],["@@¹dnb "],["@@rSBnR"],["@@g~h}"],["@@FlEk"],["@@OdPc"],["@@v[u\\"],["@@FjâL~wyoo~sµL\\"],["@@¬e¹aN"],["@@\\nÔ¡q]L³ë\\ÿ®QÖ"],["@@ÊA©[¬"],["@@Kxv"],["@@@hlIk]"],["@@pW{o||j"],["@@Md|_mC"],["@@¢ X£ÏylD¼XtH"],["@@hlÜ[LykAvyfw^E¤"],["@@fp¤MusR"],["@@®_ma~LÁ¬Z"],["@@iMxZ"],["@@ZcYd"],["@@Z~dOSo|A¿qZv"],["@@@`EN¡v"],["@@|TY{"],["@@@n@m"],["@@XWkCT\\"],["@@ºwZRkĕWO¢"],["@@X®±Grƪ\\ÔáXq{"],["@@ůTG°ĄLHm°UC"],["@@¤aÜx~}dtüGæţŎíĔcŖpMËÐj碷ðĄÆMzjWKĎ¢Q¶À_ê_Bıi«pZgf¤Nrq]§ĂN®«H±yƳí¾×ŸīàLłčŴǝĂíÀBŖÕªÁŖHŗʼnåqûõi¨hÜ·ñt»¹ýv_[«¸mYL¯Qª mĉÅdMgÇjcº«ę¬K´B«Âącoċ\\xKd¡gěŧ«®á[~ıxu·ÅKsËÉc¢Ù\\ĭƛëbf¹ģSĜkáƉÔĈZB{aMµfzʼnfåÂŧįƋǝÊĕġć£g³neą»@¦S®\\ßðChiqªĭiAuAµ_W¥ƣO\\lċĢttC¨£t`PZäuXßBsĻyekOđġĵHuXBµ]×\\°®¬F¢¾pµ¼kŘó¬Wät¸|@L¨¸µrºù³Ù~§WIZW®±Ð¨ÒÉx`²pĜrOògtÁZ}þÙ]¡FKwsPlU[}¦Rvn`hq¬\\nQ´ĘRWb_ rtČFIÖkĦPJ¶ÖÀÖJĈĄTĚòC ²@Pú Øz©PCÈÚDZhŖl¬â~nm¨f©iļ«mntuÖZÜÄjL®EÌFª²iÊxبIÈhhst"],["@@o\\VzRZ}y"],["@@@°¡mÛGĕ¨§Ianá[ýƤjfæØLäGr"]],"encodeOffsets":[[[125592,31553]],[[125785,31436]],[[125729,31431]],[[125513,31380]],[[125223,30438]],[[125115,30114]],[[124815,29155]],[[124419,28746]],[[124095,28635]],[[124005,28609]],[[125000,30713]],[[125111,30698]],[[125078,30682]],[[125150,30684]],[[124014,28103]],[[125008,31331]],[[125411,31468]],[[125329,31479]],[[125626,30916]],[[125417,30956]],[[125254,30976]],[[125199,30997]],[[125095,31058]],[[125083,30915]],[[124885,31015]],[[125218,30798]],[[124867,30838]],[[124755,30788]],[[124802,30809]],[[125267,30657]],[[125218,30578]],[[125200,30562]],[[124968,30474]],[[125167,30396]],[[124955,29879]],[[124714,29781]],[[124762,29462]],[[124325,28754]],[[123990,28459]],[[125366,31477]],[[125115,30363]],[[125369,31139]],[[122495,31878]],[[125329,30690]],[[125192,30787]]]}},{"type":"Feature","id":"340000","properties":{"id":"340000","cp":[117.283042,31.26119],"name":"安徽","childNum":3},"geometry":{"type":"MultiPolygon","coordinates":[["@@^iuLX^"],["@@e©Ehl"],["@@°ZÆëϵmkǀwÌÕæhºgBĝâqÙĊzÖgņtÀÁĂÆáhEz|WzqD¹°Eŧl{ævÜcA`¤C`|´qxIJkq^³³GšµbíZ ¹qpa±ď OH¦Ħx¢gPícOl_iCveaOjCh߸iÝbÛªCC¿mRV§¢A|t^iĠGÀtÚsd]ĮÐDE¶zAb àiödK¡~H¸íæAǿYj{ď¿À½W®£ChÃsikkly]_teu[bFaTign{]GqªoĈMYá|·¥f¥őaSÕėNµñĞ«Im_m¿Âa]uĜp Z_§{Cäg¤°r[_YjÆOdý[I[á·¥Q_nùgL¾mvˊBÜÆ¶ĊJhpc¹O]iŠ]¥ jtsggJǧw×jÉ©±EFËKiÛÃÕYv sm¬njĻª§emná}k«ŕgđ²ÙDÇ¤í¡ªOy×Où±@DñSęćăÕIÕ¿IµĥOjNÕËT¡¿tNæŇàåyķrĕq§ÄĩsWÆßF¶X®¿mw RIÞfßoG³¾©uyHį{Ɓħ¯AFnuP ÍÔzVdàôº^Ðæd´oG¤{S¬ćxã}ŧ×Kǥĩ«ÕOEзÖdÖsƘѨ[Û^Xr¢¼§xvÄÆµ`K§ tÒ´Cvlo¸fzŨð¾NY´ı~ÉĔē ßúLÃÃ_ÈÏ|]ÂÏFlg`ben¾¢pUh~ƴ˶_r sĄ~cƈ]|r c~`¼{À{ȒiJjz`îÀT¥Û³ ]u}f ïQl{skloNdjäËzDvčoQďHI¦rbtHĔ~BmlRV_ħTLnñH±DL¼Lªl§Ťa¸ĚlK²\\RòvDcÎJbt[¤D@®hh~kt°ǾzÖ@¾ªdbYhüóZ ň¶vHrľ\\ÊJuxAT|dmÀO[ÃÔG·ĚąĐlŪÚpSJ¨ĸLvÞcPæķŨ®mÐálwKhïgA¢ųƩޤOÈm°K´"]],"encodeOffsets":[[[121722,32278]],[[119475,30423]],[[119168,35472]]]}},{"type":"Feature","id":"350000","properties":{"id":"350000","cp":[118.306239,26.075302],"name":"福建","childNum":18},"geometry":{"type":"MultiPolygon","coordinates":[["@@zht´]"],["@@aj^~ĆG©O"],["@@ed¨C}}i"],["@@@vPGsQ"],["@@sBzddW]Q"],["@@S¨Q{"],["@@NVucW"],["@@qptBAq"],["@@¸[mu"],["@@Q\\pD]_"],["@@jSwUadpF"],["@@eXª~"],["@@AjvFso"],["@@fT_Çí\\v|ba¦jZÆy°"],["@@IjJi"],["@@wJIx«¼AoNe{M"],["@@K±¡ÓČäeZ"],["@@k¡¹Eh~c®wBkUplÀ¡I~Māe£bN¨gZý¡a±Öcp©PhI¢Qq ÇGj|¥U g[Ky¬ŏv@OptÉEF\\@ åA¬V{XģĐBy cpě ¼³Ăp·¤¥ohqqÚ¡ŅLs^á§qlÀhH¨MCe»åÇGD¥zPO£čÙkJA¼ßėuĕeûÒiÁŧSW¥Qûŗ½ùěcݧSùĩąSWó«íęACµeRåǃRCÒÇZÍ¢ź±^dlstjD¸ZpuÔâÃH¾oLUêÃÔjjēò´ĄWƛ ^Ñ¥Ħ@ÇòmOw¡õyJyD}¢ďÑÈġfZda©º²z£NjD°Ötj¶¬ZSÎ~¾c°¶ÐmxO¸¢Pl´SL|¥AȪĖMņIJg®áIJČĒü` QF¬h|ĂJ@zµ |ê³È ¸UÖŬŬÀEttĸr]ðM¤ĶIJHtÏ AĬkvsq^aÎbvdfÊòSD´Z^xPsĂrvƞŀjJd×ŘÉ ®AΦĤdxĆqAZRÀMźnĊ»İÐZ YXæJyĊ²·¶q§·K@·{sXãô«lŗ¶»o½E¡«¢±¨Y®Ø¶^AvWĶGĒĢPlzfļtàAvWYãO_¤sD§ssČġ[kƤPX¦`¶®BBvĪjv©jx[L¥àï[F ¼ÍË»ğV`«Ip}ccÅĥZEãoP ´B@D¸m±z«Ƴ¿å³BRضWlâþäą`]Z£Tc ĹGµ¶Hm@_©k¾xĨôȉðX«½đCIbćqK³ÁÄš¬OAwã»aLʼnËĥW[ÂGIÂNxij¤D¢îĎÎB§°_JGs¥E@ ¤uć PåcuMuw¢BI¿]zG¹guĮck\\_"]],"encodeOffsets":[[[123250,27563]],[[122541,27268]],[[123020,27189]],[[122916,27125]],[[122887,26845]],[[122808,26762]],[[122568,25912]],[[122778,26197]],[[122515,26757]],[[122816,26587]],[[123388,27005]],[[122450,26243]],[[122578,25962]],[[121255,25103]],[[120987,24903]],[[122339,25802]],[[121042,25093]],[[122439,26024]]]}},{"type":"Feature","id":"360000","properties":{"id":"360000","cp":[115.592151,27.676493],"name":"江西","childNum":1},"geometry":{"type":"Polygon","coordinates":["@@ĢĨƐgļ¼ÂMD~ņªe^\\^§ý©j×cZبzdÒa¶lÒJìõ`oz÷@¤u޸´ôęöY¼HČƶajlÞƩ¥éZ[|h}^U ¥pĄžƦO lt¸Æ Q\\aÆ|CnÂOjtĚĤdÈF`¶@Ðë ¦ōÒ¨SêvHĢûXD® QgÄWiØPÞìºr¤džNĠ¢lĄtZoCƞÔºCxrpĠV®Ê{f_Y`_eq®Aot`@oDXfkp¨|s¬\\DÄSfè©Hn¬ ^DhÆyøJhØxĢĀLÊƠPżċĄwȠ̦G®ǒĤäTŠÆ~Ħw«|TF¡nc³Ïå¹]ĉđxe{ÎÓvOEm°BƂĨİ|Gvz½ª´HàpeJÝQxnÀWEµàXÅĪt¨ÃĖrÄwÀFÎ|ňÓMå¼ibµ¯»åDT±m[r«_gmQu~¥V\\OkxtL E¢Ú^~ýêPóqoě±_Êw§ÑªåƗā¼mĉŹ¿NQ YBąrwģcÍ¥BŗÊcØiIƝĿuqtāwO]³YCñTeÉcaubÍ]trluī BÐGsĵıN£ï^ķqss¿FūūVÕ·´Ç{éĈýÿOER_đûIċâJhŅıNȩĕB ¦K{Tk³¡OP·wnµÏd¯}½TÍ«YiµÕsC¯iM¤¦¯P|ÿUHvhe¥oFTuõ\\OSsMòđƇiaºćXĊĵà·çhƃ÷Ç{ígu^đgm[×zkKN¶Õ»lčÓ{XSÆv©_ÈëJbVkĔVÀ¤P¾ºÈMÖxlò~ªÚàGĂ¢B±ÌKyáV¼Ã~ `gsÙfIƋlę¹e|~udjuTlXµf`¿Jd[\\L²"],"encodeOffsets":[[116689,26234]]}},{"type":"Feature","id":"370000","properties":{"id":"370000","cp":[118.000923,36.275807],"name":"山东","childNum":13},"geometry":{"type":"MultiPolygon","coordinates":[["@@Xjd]{K"],["@@itbFHy"],["@@HlGk"],["@@TGy"],["@@K¬U"],["@@WdXc"],["@@PtOs"],["@@LnXhc"],["@@ppVu]Or"],["@@cdzAUa"],["@@udRhnCI"],["@@oIpR"],["@@Ľč{fzƤîKÎMĮ]ZF½Y]â£ph¶¨râøÀÎǨ¤^ºÄGz~grĚĜlĞÆLĆdž¢Îo¦cvKbgr°WhmZp L]LºcUÆnżĤÌĒbAnrOA´ȊcÀbƦUØrĆUÜøĬƞEzVL®öØBkŖÝĐ˹ŧ̄±ÀbÎÉnb²ĦhņBĖįĦåXćì@L¯´ywƕCéõė ƿ¸lµ¾Z|ZWyFY¨Mf~C¿`à_RÇzwƌfQnny´INoƬèôº|sTJULîVjǎ¾ĒØDz²XPn±ŴPè¸ŔLƔÜƺ_TüÃĤBBċÈöA´faM¨{«M`¶d¡ôÖ°mȰBÔjj´PM|c^d¤u¤Û´ä«ƢfPk¶Môl]Lb}su^ke{lC MrDÇ]NÑFsmoõľHyGă{{çrnÓEƕZGª¹Fj¢ïW uøCǷë¡ąuhÛ¡^KxC`C\\bÅxì²ĝÝ¿_NīCȽĿåB¥¢·IŖÕy\\¹kxãČ×GDyäÁçFQ¡KtŵƋ]CgÏAùSedcÚźuYfyMmhUWpSyGwMPqŀÁ¼zK¶GY§Ë@´śÇµƕBm@IogZ¯uTMx}CVKï{éƵP_K«pÛÙqċtkkù]gTğwoɁsMõ³ăAN£MRkmEÊčÛbMjÝGu IZGPģãħE[iµBEuDPÔ~ª¼ęt]ûG§¡QMsğNPŏįzs£Ug{đJĿļā³]ç«Qr~¥CƎÑ^n¶ÆéÎR~ݏYI] PumŝrƿIā[xedzL¯v¯s¬ÁY ~} ťuŁgƋpÝĄ_ņī¶ÏSR´ÁP~¿Cyċßdwk´SsX|t`Ä ÈðAªìÎT°¦Dda^lĎDĶÚY°`ĪŴǒàŠv\\ebZHŖR¬ŢƱùęOÑM³FÛWp["]],"encodeOffsets":[[[123806,39303]],[[123821,39266]],[[123742,39256]],[[123702,39203]],[[123649,39066]],[[123847,38933]],[[123580,38839]],[[123894,37288]],[[123043,36624]],[[123344,38676]],[[123522,38857]],[[123628,38858]],[[118260,36742]]]}},{"type":"Feature","id":"410000","properties":{"id":"410000","cp":[113.665412,33.757975],"name":"河南","childNum":1},"geometry":{"type":"Polygon","coordinates":["@@ýLùµP³swIÓxcŢĞð´E®ÚPtĴXØx¶@«ŕŕQGYfa[şußǩđš_X³ijÕčC]kbc¥CS¯ëÍB©÷³Si_}mYTt³xlàcČzÀD}ÂOQ³ÐTĨ¯ƗòËŖ[hłŦv~}ÂZ«¤lPÇ£ªÝŴÅR§ØnhctâknÏľŹUÓÝdKuķI§oTũÙďkęĆH¸Ó\\Ä¿PcnS{wBIvÉĽ[GqµuŇôYgûZca©@½Õǽys¯}lgg@C\\£asIdÍuCQñ[L±ęk·ţb¨©kK»KC²òGKmĨS`UQnk}AGēsqaJ¥ĐGRĎpCuÌy ã iMcplk|tRkðev~^´¦ÜSí¿_iyjI|ȑ|¿_»d}q^{Ƈdă}tqµ`Ƴĕg}V¡om½faÇo³TTj¥tĠRyK{ùÓjuµ{t}uËRivGçJFjµÍyqÎàQÂFewixGw½Yŷpµú³XU½ġyłåkÚwZX·l¢Á¢KzOÎÎjc¼htoDHr |J½}JZ_¯iPq{tę½ĕ¦Zpĵø«kQ Ť]MÛfaQpě±ǽ¾]uFu÷nčįADp}AjmcEÇaª³o³ÆÍSƇĈÙDIzËčľ^KLiÞñ[aA²zzÌ÷D|[íijgfÕÞd®|`Ć~oĠƑô³ŊD×°¯CsøÀ«ìUMhTº¨¸ǡîSÔDruÂÇZÖEvPZW~ØÐtĄE¢¦Ðy¸bô´oŬ¬²Ês~]®tªapŎJ¨Öº_Ŕ`Ŗ^Đ\\Ĝu~m²Ƹ¸fWĦrƔ}Î^gjdfÔ¡J}\\n C¦þWxªJRÔŠu¬ĨĨmFdM{\\d\\YÊ¢ú@@¦ª²SÜsC}fNècbpRmlØ^gd¢aÒ¢CZZxvƶN¿¢T@uC¬^ĊðÄn|lGlRjsp¢ED}Fio~ÔN~zkĘHVsDzßjŬŢ`Pûàl¢\\ÀEhİgÞē X¼Pk|m"],"encodeOffsets":[[118256,37017]]}},{"type":"Feature","id":"420000","properties":{"id":"420000","cp":[113.298572,30.684355],"name":"湖北","childNum":3},"geometry":{"type":"MultiPolygon","coordinates":[["@@AB"],["@@lskt"],["@@¾«}{ra®pîÃ\\{øCËyyB±b\\òÝjKL ]ĎĽÌJyÚCƈćÎT´Å´pb©ÈdFin~BCo°BĎÃømv®E^vǾ½Ĝ²RobÜeN^ĺ£R¬lĶ÷YoĖ¥Ě¾|sOr°jY`~I¾®I{GqpCgyl{£ÍÍyPL¡¡¸kWxYlÙæŁĢz¾V´W¶ùŸo¾ZHxjwfxGNÁ³Xéæl¶EièIH ujÌQ~v|sv¶Ôi|ú¢FhQsğ¦SiŠBgÐE^ÁÐ{čnOÂÈUÎóĔÊēIJ}Z³½Mŧïeyp·uk³DsѨL¶_Åuèw»¡WqÜ]\\Ò§tƗcÕ¸ÕFÏǝĉăxŻČƟOKÉġÿ×wg÷IÅzCg]m«ªGeçÃTC«[t§{loWeC@ps_Bprf_``Z|ei¡oċMqow¹DƝÓDYpûsYkıǃ}s¥ç³[§cY§HK«Qy]¢wwö¸ïx¼ņ¾Xv®ÇÀµRĠÐHM±cÏdƒǍũȅȷ±DSyúĝ£ŤĀàtÖÿï[îb\\}pĭÉI±Ñy ¿³x¯No|¹HÏÛmjúË~TuęjCöAwě¬Rđl¯ ÑbŇTĿ_[IčĄʿnM¦ğ\\É[T·k¹©oĕ@A¾wya¥Y\\¥Âaz¯ãÁ¡k¥ne£ÛwE©Êō¶˓uoj_U¡cF¹[WvP©whuÕyBF`RqJUw\\i¡{jEPïÿ½fć QÑÀQ{°fLÔ~wXgītêݾĺHd³fJd]HJ² EoU¥HhwQsƐ»Xmg±çve]DmÍPoCc¾_hhøYrŊU¶eD°Č_N~øĹĚ·`z]Äþp¼ äÌQv\\rCé¾TnkžŐÚÜa¼ÝƆ̶Ûo d ĔňТJqPb ¾|J¾fXƐîĨ_Z¯À}úƲN_ĒÄ^ĈaŐyp»CÇÄKñL³ġM²wrIÒŭxjb[n«øæà ^²h¯ÚŐªÞ¸Y²ĒVø}Ā^İ´LÚm¥ÀJÞ{JVųÞŃx×sxxƈē ģMřÚðòIfĊŒ\\Ʈ±ŒdʧĘDvČ_Àæ~Dċ´A®µ¨ØLV¦êHÒ¤"]],"encodeOffsets":[[[113712,34000]],[[115612,30507]],[[113649,34054]]]}},{"type":"Feature","id":"430000","properties":{"id":"430000","cp":[111.782279,28.09409],"name":"湖南","childNum":3},"geometry":{"type":"MultiPolygon","coordinates":[["@@nFTs"],["@@ßÅÆá½ÔXrCO ËRïÿĩTooQyÓ[ŅBE¬ÎÓXaį§Ã¸G °ITxpúxÚij¥Ï̾edÄ©ĸG àGhM¤Â_U}Ċ}¢pczfþg¤ÇòAVM"],["@@©KA·³CQ±Á«³BUƑ¹AtćOwD]JiØSm¯b£ylX HËѱH«C^õľAŧ¤É¥ïyuǙuA¢^{ÌC´¦ŷJ£^[ª¿ĕ~Ƈ N skóā¹¿ï]ă~÷O§@Vm¡Qđ¦¢Ĥ{ºjÔª¥nf´~Õo×ÛąMąıuZmZcÒ IJβSÊDŽŶ¨ƚCÖŎªQؼrŭ«}NÏürʬmjr@ĘrTW SsdHzƓ^ÇÂyUi¯DÅYlŹu{hT}mĉ¹¥ěDÿë©ıÓ[Oº£¥ótł¹MÕƪ`P DiÛU¾ÅâìUñBÈ£ýhedy¡oċ`pfmjP~kZa ZsÐd°wj§@Ĵ®w~^kÀÅKvNmX\\¨aŃqvíó¿F¤¡@ũÑVw}S@j}¾«pĂrªg àÀ²NJ¶¶Dô K|^ª°LX¾ŴäPα£EXd^¶IJÞÜ~u¸ǔMRhsR e`ÄofIÔ\\Ø ićymnú¨cj ¢»GČìƊÿШXeĈ¾Oð Fi ¢|[jVxrIQ_EzAN¦zLU`cªxOTu RLÄ¢dVi`p˔vŎµªÉF~Ød¢ºgİàw¸Áb[¦Zb¦z½xBĖ@ªpºlS¸Ö\\Ĕ[N¥ˀmĎăJ\\ŀ` ňSÚĖÁĐiOĜ«BxDõĚivSÌ}iùÜnкG{p°M´wÀÒzJ²ò¨ oTçüöoÛÿñőФùTz²CȆȸǎŪƑÐc°dPÎğ˶[Ƚu¯½WM¡ÉB·rínZÒ `¨GA¾\\pēXhÃRCüWGġu Té§ŎÑ©ò³I±³}_EÃħg®ęisÁPDmÅ{b[RÅs·kPŽƥóRoOV~]{g\\êYƪ¦kÝbiċƵGZ»Ěõ ó·³vŝ£ø@pyö_ëIkѵbcѧy ×dYتiþ¨[]f]Ņ©C}ÁN»hĻħƏĩ"]],"encodeOffsets":[[[115640,30489]],[[112543,27312]],[[116690,26230]]]}},{"type":"Feature","id":"440000","properties":{"id":"440000","cp":[113.280637,23.125178],"name":"广东","childNum":24},"geometry":{"type":"MultiPolygon","coordinates":[["@@QdAua"],["@@lxDLo"],["@@sbhNLo"],["@@Ă ā"],["@@WltO[["],["@@Kr]S"],["@@eI]y"],["@@I|Mym"],["@@Û³LS¼Y"],["@@nvºBëui©`¾"],["@@zdÛJw®"],["@@° ¯"],["@@a yAª¸ËJIxØ@ĀHAmÃV¡ofuo"],["@@sŗÃÔėAƁZÄ ~°ČPäh"],["@@¶ÝÌvmĞhıQ"],["@@HdSjĒ¢D}war u«ZqadYM"],["@@el\\LqqU"],["@@~rMo\\"],["@@f^C"],["@@øPªoj÷ÍÝħXČx°Q¨ıXNv"],["@@gÇƳo[~tly"],["@@EÆC¿"],["@@OP"],["@@wđógĝ[³¡VÙæÅöM̳¹pÁaËýý©D©ÜJŹƕģGą¤{Ùū ÇO²«BƱéAÒĥ¡«BhlmtÃPµyU¯ucd·w_bŝcīímGO|KPȏŹãŝIŕŭŕ@Óoo¿ē±ß} ŭIJWÈCőâUâǙIğʼn©IijE× Á³AówXJþ±ÌÜÓĨ£L]ĈÙƺZǾĆĖMĸĤfÎĵlŨnÈĐtFFĤêk¶^k°f¶g}®Faf`vXŲxl¦ÔÁ²¬Ð¦pqÊ̲iXØRDÎ}Ä@ZĠsx®AR~®ETtĄZƈfŠŠHâÒÐAµ\\S¸^wĖkRzalŜ|E¨ÈNĀňZTpBh£\\ĎƀuXĖtKL¶G|»ĺEļĞ~ÜĢÛĊrOÙîvd]n¬VÊĜ°RÖpMƂªFbwEÀ©\\ ¤]ŸI®¥D³|Ë]CöAŤ¦ æ´¥¸Lv¼¢ĽBaôF~®²GÌÒEYzk¤°ahlVÕI^CxĈPsBƒºV¸@¾ªR²ĨN]´_eavSivc}p}Đ¼ƌkJÚe th_¸ ºx±ò_xN˲@ă¡ßH©Ùñ}wkNÕ¹ÇO½¿£ĕ]ly_WìIǪ`uTÅxYĒÖ¼kÖµMjJÚwn\\hĒv]îh|ÈƄøèg¸Ķß ĉĈWb¹ƀdéĘNTtP[öSvrCZaGubo´ŖÒÇĐ~¡zCI özx¢PnÈñ @ĥÒ¦]ƞV}³ăĔñiiÄÓVépKG½ÄÓávYoC·sitiaÀyŧΡÈYDÑům}ý|m[węõĉZÅxUO}÷N¹³ĉo_qtăqwµŁYÙǝŕ¹tïÛUïmRCº ĭ|µÕÊK½Rē ó]GªęAx»HO£|ām¡diď×YïYWªʼnOeÚtĐ«zđ¹T āúEá²\\ķÍ}jYàÙÆſ¿Çdğ·ùTßÇţʄ¡XgWÀLJğ·¿ÃOj YÇ÷Qěi"]],"encodeOffsets":[[[117381,22988]],[[116552,22934]],[[116790,22617]],[[116973,22545]],[[116444,22536]],[[116931,22515]],[[116496,22490]],[[116453,22449]],[[113301,21439]],[[118726,21604]],[[118709,21486]],[[113210,20816]],[[115482,22082]],[[113171,21585]],[[113199,21590]],[[115232,22102]],[[115739,22373]],[[115134,22184]],[[113056,21175]],[[119573,21271]],[[119957,24020]],[[115859,22356]],[[116561,22649]],[[116285,22746]]]}},{"type":"Feature","id":"450000","properties":{"id":"450000","cp":[108.320004,22.82402],"name":"广西","childNum":2},"geometry":{"type":"MultiPolygon","coordinates":[["@@H TQ§A"],["@@ĨʪLƊDÎĹĐCǦė¸zÚGn£¾rªŀÜt¬@ÖÚSx~øOŒŶÐÂæȠ\\ÈÜObĖw^oÞLf¬°bI lTØBÌF£Ć¹gñĤaYt¿¤VSñK¸¤nM¼JE±½¸ñoÜCƆæĪ^ĚQÖ¦^f´QüÜÊz¯lzUĺš@ìp¶n]sxtx¶@~ÒĂJb©gk{°~c°`Ô¬rV\\la¼¤ôá`¯¹LCÆbxEræOv[H[~|aB£ÖsºdAĐzNÂðsÞÆ Ĥªbab`ho¡³F«èVlo¤ÔRzpp®SĪº¨ÖºN ijd`a¦¤F³ºDÎńĀìCĜº¦Ċ~nS|gźvZkCÆj°zVÈÁƔ]LÊFZg čPkini«qÇczÍY®¬Ů»qR×ō©DÕ§ƙǃŵTÉĩ±ıdÑnYYIJvNĆĆØÜ Öp}e³¦m©iÓ|¹ħņ|ª¦QF¢Â¬ʖovg¿em^ucà÷gÕuíÙćĝ}FϼĹ{µHKsLSđƃrč¤[AgoSŇYMÿ§Ç{FśbkylQxĕ]T·¶[B ÑÏGáşşƇe ăYSsFQ}BwtYğÃ@~ CÍQ ×Wj˱rÉ¥oÏ ±«ÓÂ¥kwWűmcih³K~µh¯e]lµélEģEďsmÇŧē`ãògK_ÛsUʝćğ¶höO¤Ǜn³c`¡y¦CezYwa[ďĵűMę§]XÎ_íÛ]éÛUćİÕBƣ± dy¹T^dûÅÑŦ·PĻþÙ`K¦ ¢ÍeĥR¿³£[~äu¼dltW¸oRM¢ď\\z}Æzdvň{ÎXF¶°Â_ÒÂÏL©ÖTmu¼ãlīkiqéfA·Êµ\\őDc¥ÝFyÔćcűH_hLÜêĺШc}rn`½Ì@¸¶ªVLhŒ\\Ţĺk~Ġið°|gtTĭĸ^xvKVGréAébUuMJVÃO¡ qĂXËSģãlýà_juYÛÒBG^éÖ¶§EGÅzěƯ¤EkN[kdåucé¬dnYpAyČ{`]þ¯TbÜÈk¡ĠvàhÂƄ¢Jî¶²"]],"encodeOffsets":[[[111707,21520]],[[107619,25527]]]}},{"type":"Feature","id":"460000","properties":{"id":"460000","cp":[109.83119,19.031971],"name":"海南","childNum":1},"geometry":{"type":"Polygon","coordinates":["@@¦Ŝil¢XƦƞòïè§ŞCêɕrŧůÇąĻõ·ĉ³œ̅kÇm@ċȧŧĥĽʉƅſȓÒ˦ŝE}ºƑ[ÍĜȋ gÎfǐÏĤ¨êƺ\\Ɔ¸ĠĎvʄȀоjNðĀÒRZdžzÐŘΰH¨Ƣb²_Ġ "],"encodeOffsets":[[112750,20508]]}},{"type":"Feature","id":"510000","properties":{"id":"510000","cp":[104.065735,30.659462],"name":"四川","childNum":2},"geometry":{"type":"MultiPolygon","coordinates":[["@@LqKr"],["@@[ĻéV£_ţġñpG réÏ·~ąSfy×Í·ºſƽiÍıƣıĻmHH}siaX@iǰÁÃ×t«T¤JJJyJÈ`Ohߦ¡uËhIyCjmÿw ZG TiSsOB²fNmsPa{M{õE^Hj}gYpaeu¯oáwHjÁ½M¡pMuåmni{fk\\oÎqCwEZ¼KĝAy{m÷LwO×SimRI¯rKõBS«sFe]fµ¢óY_ÆPRcue°Cbo×bd£ŌIHgtrnyPt¦foaXďxlBowz_{ÊéWiêEGhܸºuFĈIxf®Y½ĀǙ]¤EyF²ċw¸¿@g¢§RGv»áW`ÃĵJwi]t¥wO½a[×]`ÃiüL¦LabbTÀåc}ÍhÆh®BHî|îºÉk¤Sy£ia©taį·Ɖ`ō¥UhO ĝLk}©Fos´JmµlŁu ønÑJWΪYÀïAetTŅÓGË«bo{ıwodƟ½OġܵxàNÖ¾P²§HKv¾]|BÆåoZ`¡Ø`ÀmºĠ~ÌЧnÇ ¿¤]wğ@srğu~Io[é±¹ ¿ſđÓ@qg¹zƱřaí°KtǤV»Ã[ĩǭƑ^ÇÓ@áťsZÏÅĭƋěpwDóÖáŻneQËq·GCœýS]x·ýq³OÕ¶Qzßti{řáÍÇWŝŭñzÇWpç¿JXĩè½cFÂLiVjx}\\NŇĖ¥GeJA¼ÄHfÈu~¸Æ«dE³ÉMA|bÒ ćhG¬CMõƤąAvüVéŀ_V̳ĐwQj´·ZeÈÁ¨X´Æ¡Qu·»ÕZ³ġqDoy`L¬gdp°şp¦ėìÅĮZ°Iähzĵf²å ĚÑKpIN|Ñz]ń ·FU×é»R³MÉ»GM«kiér}Ã`¹ăÞmÈnÁîRǀ³ĜoİzŔwǶVÚ£À]ɜ»ĆlƂ²Ġ þTº·àUȞÏʦ¶I«dĽĢdĬ¿»Ĕ×h\\c¬ä²GêëĤł¥ÀǿżÃÆMº}BÕĢyFVvwxBèĻĒ©ĈtCĢɽŠȣ¦āæ·HĽîôNÔ~^¤Ɗu^s¼{TA¼ø°¢İªDè¾Ň¶ÝJ®Z´ğ~Sn|ªWÚ©òzPOȸbð¢|øĞŒQìÛÐ@ĞǎRS¤Á§d i´ezÝúØã]HqkIþËQǦÃsǤ[E¬ÉŪÍxXƒ·ÖƁİlƞ¹ª¹|XÊwnÆƄmÀêErĒtD®ċæcQE®³^ĭ¥©l}äQtoŖÜqÆkµªÔĻĴ¡@Ċ°B²Èw^^RsºT£ڿQPJvÄz^Đ¹Æ¯fLà´GC²dtĀRt¼¤ĦOðğfÔðDŨŁĞƘïPÈ®âbMüÀXZ ¸£@Å»»QÉ]dsÖ×_Í_ÌêŮPrĔĐÕGĂeZÜîĘqBhtO ¤tE[h|YÔZśÎs´xº±Uñt|OĩĠºNbgþJy^dÂY Į]Řz¦gC³R`Āz¢Aj¸CL¤RÆ»@Ŏk\\Ç´£YW}z@Z}öoû¶]´^NÒ}èNªPÍy¹`S°´ATeVamdUĐwʄvĮÕ\\uÆŗ¨Yp¹àZÂmWh{á}WØǍÉüwga§áCNęÎ[ĀÕĪgÖɪXøx¬½Ů¦¦[NÎLÜUÖ´òrÙŠxR^JkijnDX{U~ET{ļº¦PZcjF²Ė@pg¨B{u¨ŦyhoÚD®¯¢ WòàFΤ¨GDäz¦kŮPġqË¥À]eâÚ´ªKxīPÖ|æ[xäJÞĥsNÖ½I¬nĨY´®ÐƐmDŝuäđđEb ee_v¡}ìęNJē}qÉåT¯µRs¡M@}ůaa¯wvƉåZw\\Z{åû^"]],"encodeOffsets":[[[108815,30935]],[[110617,31811]]]}},{"type":"Feature","id":"520000","properties":{"id":"520000","cp":[106.713478,26.578343],"name":"贵州","childNum":3},"geometry":{"type":"MultiPolygon","coordinates":[["@@G\\lY£in"],["@@q|mc¯tÏVSÎ"],["@@hÑ£IsNgßHHªķÃh_¹¡ĝħń¦uÙùgS¯JH|sÝÅtÁïyMDč»eÕtA¤{b\\}G®u\\åPFqwÅaD K°ºâ_£ùbµmÁÛĹM[q|hlaªāI}ѵ@swtwm^oµD鼊yVky°ÉûÛR ³e¥]RÕěħ[ƅåÛDpJiVÂF²I »mN·£LbÒYbWsÀbpkiTZĄă¶Hq` ĥ_J¯ae«KpÝx]aĕÛPÇȟ[ÁåŵÏő÷Pw}TÙ@Õs«ĿÛq©½m¤ÙH·yǥĘĉBµĨÕnđ]K©œáGçş§ÕßgǗĦTèƤƺ{¶ÉHÎd¾ŚÊ·OÐjXWrãLyzÉAL¾ę¢bĶėy_qMĔąro¼hĊw¶øV¤w²Ĉ]ÊKx|`ź¦ÂÈdrcÈbe¸`I¼čTF´¼Óýȃr¹ÍJ©k_șl³´_pĐ`oÒh¶pa^ÓĔ}D»^Xy`d[Kv JPhèhCrĂĚÂ^Êƌ wZLĠ£ÁbrzOIlMMĪŐžËr×ÎeŦtw|¢mKjSǘňĂStÎŦEtqFT¾E쬬ôxÌO¢ K³ŀºäYPVgŎ¦Ŋm޼VZwVlz¤ £Tl®ctĽÚó{GAÇge~Îd¿æaSba¥KKûj®_Ä^\\ؾbP®¦x^sxjĶI_Ä Xâ¼Hu¨Qh¡À@Ëô}±GNìĎlT¸ `V~R°tbÕĊ`¸úÛtÏFDu[MfqGH·¥yAztMFe|R_GkChZeÚ°tov`xbDnÐ{E}ZèxNEÞREn[Pv@{~rĆAB§EO¿|UZ~ìUf¨J²ĂÝÆsªB`s¶fvö¦Õ~dÔq¨¸º»uù[[§´sb¤¢zþF¢Æ ÀhÂW\\ıËIÝo±ĭŠ£þÊs}¡R]ěDg´VG¢j±®èºÃmpU[Á뺰rÜbNu¸}º¼`niºÔXĄ¤¼ÔdaµÁ_à ftQQgR·Ǔv}Ý×ĵ]µWc¤F²OĩųãW½¯K© ]{LóµCIµ±Mß¿h©āq¬o½~@i~TUxŪÒ¢@£ÀEîôruńb[§nWuMÆLl¿]x}ij½"]],"encodeOffsets":[[[112158,27383]],[[112105,27474]],[[112095,27476]]]}},{"type":"Feature","id":"530000","properties":{"id":"530000","cp":[101.512251,24.740609],"name":"云南","childNum":1},"geometry":{"type":"Polygon","coordinates":["@@[ùx½}ÑRHYīĺûsÍniEoã½Ya²ė{c¬ĝgĂsAØÅwďõzFjw}«Dx¿}Uũlê@HÅF¨ÇoJ´Ónũuą¡Ã¢pÒÅØ TF²xa²ËXcÊlHîAßËŁkŻƑŷÉ©hWæßUËs¡¦}teèÆ¶StÇÇ}Fd£jĈZĆÆ¤Tč\\D}O÷£U§~ŃGåŃDĝ¸Tsd¶¶Bª¤u¢ŌĎo~t¾ÍŶÒtD¦ÚiôözØX²ghįh½Û±¯ÿm·zR¦Ɵ`ªŊÃh¢rOÔ´£Ym¼èêf¯ŪĽncÚbw\\zlvWªâ ¦gmĿBĹ£¢ƹřbĥkǫßeeZkÙIKueT»sVesbaĕ ¶®dNĄÄpªy¼³BE®lGŭCǶwêżĔÂepÍÀQƞpC¼ŲÈAÎô¶RäQ^Øu¬°_Èôc´¹ò¨P΢hlϦ´ĦÆ´sâÇŲPnÊD^¯°Upv}®BP̪jǬxSöwlfòªvqĸ|`HviļndĜĆhňem·FyÞqóSᝳX_ĞçêtryvL¤§z¦c¦¥jnŞklD¤øz½ĜàĂŧMÅ|áƆàÊcðÂFÜáŢ¥\\\\ºİøÒÐJĴîD¦zK²ǏÎEh~CDhMn^ÌöÄ©ČZÀaüfɭyœpį´ěFűk]Ôě¢qlÅĆÙa¶~ÄqêljN¬¼HÊNQ´ê¼VظE^ŃÒyM{JLoÒęæe±Ķygã¯JYÆĭĘëo¥Šo¯hcK«z_prC´ĢÖY¼ v¸¢RÅW³Â§fǸYi³xR´ďUË`êĿUûuĆBƣöNDH«ĈgÑaB{ÊNF´¬c·Åv}eÇÃGB»If¦HňĕM ~[iwjUÁKE¾dĪçWIèÀoÈXòyŞŮÈXâÎŚj|àsRyµÖPr´þ ¸^wþTDŔHr¸RÌmfżÕâCôoxĜƌÆĮÐYtâŦÔ@]ÈǮƒ\\μģUsȯLbîƲŚºyhr@ĒÔƀÀ²º\\êpJ}ĠvqtĠ@^xÀ£È¨mËÏğ}n¹_¿¢×Y_æpÅA^{½Lu¨GO±Õ½ßM¶wÁĢÛPƢ¼pcIJx|ap̬HÐŊSfsðBZ¿©XÏÒKk÷Eû¿S rEFsÕūkóVǥʼniTL¡n{uxţÏhôŝ¬ğōNNJkyPaqÂğ¤K®YxÉƋÁ]āęDqçgOgILu\\_gz]W¼~CÔē]bµogpÑ_oď`´³Țkl`IªºÎȄqÔþ»E³ĎSJ»_f·adÇqÇc¥Á_Źw{L^ɱćxU£µ÷xgĉp»ĆqNē`rĘzaĵĚ¡K½ÊBzyäKXqiWPÏɸ½řÍcÊG|µƕƣGË÷k°_^ý|_zċBZocmø¯hhcæ\\lMFlư£ĜÆyHF¨µêÕ]HA àÓ^it `þßäkĤÎT~Wlÿ¨ÔPzUCNVv [jâôDôď[}z¿msSh¯{jïğl}šĹ[őgK©U·µË@¾m_~q¡f¹ ÅË^»f³ø}Q¡Ö˳gͱ^Ç \\ëÃA_¿bWÏ[¶ƛé£F{īZgm@|kHǭƁć¦UĔť×ë}ǝeďºȡȘÏíBÉ£āĘPªij¶ʼnÿy©nď£G¹¡I±LÉĺÑdĉÜW¥}gÁ{aqÃ¥aıęÏZï`"],"encodeOffsets":[[104636,22969]]}},{"type":"Feature","id":"540000","properties":{"id":"540000","cp":[89.132212,30.860361],"name":"西藏","childNum":1},"geometry":{"type":"Polygon","coordinates":["@@ÂhľxŖxÒVºÅâAĪÝȆµę¯Ňa±r_w~uSÕňqOj]ɄQ £Z UDûoY»©M[L¼qãË{VÍçWVi]ë©Ä÷àyƛhÚU°adcQ~Mx¥cc¡ÙaSyFÖkuRýq¿ÔµQĽ³aG{¿FµëªéĜÿª@¬·K·àariĕĀ«V»ŶĴūgèLǴŇƶaftèBŚ£^âǐÝ®M¦ÁǞÿ¬LhJ¾óƾƺcxwf]Y ´¦|QLn°adĊ \\¨oǀÍŎ´ĩĀd`tÊQŞŕ|¨C^©Ĉ¦¦ÎJĊ{ëĎjª²rÐl`¼Ą[t|¦Stè¾PÜK¸dƄı]s¤î_v¹ÎVòŦj£Əsc¬_Ğ´|٦Av¦w`ăaÝaa¢e¤ı²©ªSªÈMĄwÉØŔì@T¤Ę\\õª@þo´xA sÂtŎKzó´ÇĊµ¢r^nĊƬ×üG¢³ {âĊ]G~bÀgVjzlhǶfOfdªB]pjTOtĊn¤}®¦Č¥d¢¼»ddY¼t¢eȤJ¤}Ǿ¡°§¤AÐlc@ĝsªćļđAçwxUuzEÖġ~AN¹ÄÅȀݦ¿ģŁéì±H ãd«g[ؼēÀcīľġ¬cJµ ÐʥVȝ¸ßS¹ý±ğkƁ¼ą^ɛ¤Ûÿb[}¬ōõÃ]ËNm®g@Bg}ÍF±ǐyL¥íCIijÏ÷Ñį[¹¦[âšEÛïÁÉdƅß{âNÆāŨß¾ě÷yC£k´ÓH@¹TZ¥¢į·ÌAЧ®Zc v½Z¹|ÅWZqgW|ieZÅYVÓqdqbc²R@c¥Rã»GeeƃīQ}J[ÒK ¬Ə|oėjġĠÑN¡ð¯EBčnwôɍėª²CλŹġǝʅįĭạ̃ūȹ]ΓͧgšsgȽóϧµǛęgſ¶ҍć`ĘąŌJÞä¤rÅň¥ÖÁUětęuůÞiĊÄÀ\\Æs¦ÓRb|Â^řÌkÄŷ¶½÷f±iMÝ@ĥ°G¬ÃM¥n£Øąğ¯ß§aëbéüÑOčk£{\\eµª×MÉfm«Ƒ{Å×Gŏǩãy³©WÑăû··Qòı}¯ãIéÕÂZ¨īès¶ZÈsæĔTŘvgÌsN@îá¾ó@ÙwU±ÉT廣TđWxq¹Zobs[ׯcĩvėŧ³BM|¹kªħ¥TzNYnÝßpęrñĠĉRS~½ěVVµõ«M££µBĉ¥áºae~³AuĐh`ܳç@BÛïĿa©|z²Ý¼D£àč²ŸIûI āóK¥}rÝ_Á´éMaň¨~ªSĈ½½KÙóĿeƃÆB·¬ën×W|Uº}LJrƳlŒµ`bÔ`QÐÓ@s¬ñIÍ@ûws¡åQÑßÁ`ŋĴ{ĪTÚÅTSijYo|Ç[ǾµMW¢ĭiÕØ¿@Mh pÕ]jéò¿OƇĆƇpêĉâlØwěsǩĵ¸c bU¹ř¨WavquSMzeo_^gsÏ·¥Ó@~¯¿RiīB\\qTGªÇĜçPoÿfñòą¦óQīÈáPābß{ZŗĸIæÅhnszÁCËìñÏ·ąĚÝUm®óL·ăUÈíoù´Êj°ŁŤ_uµ^°ìÇ@tĶĒ¡ÆM³Ģ«İĨÅ®ğRāðggheÆ¢zÊ©Ô\\°ÝĎz~ź¤PnMĪÖB£kné§żćĆKǰ¼L¶èâz¨u¦¥LDĘz¬ýÎmĘd¾ßFzhg²Fy¦ĝ¤ċņbÎ@yĄæm°NĮZRÖíJ²öLĸÒ¨Y®ƌÐVàtt_ÚÂyĠz]ŢhzĎ{ÂĢXc|ÐqfO¢¤ögÌHNPKŖUú´xx[xvĐCûĀìÖT¬¸^}Ìsòd´_KgžLĴ ÀBon|H@Êx¦BpŰŌ¿fµƌA¾zLjRx¶FkĄźRzŀ~¶[´HnªVƞuĒȨƎcƽÌm¸ÁÈM¦x͊ëÀxdžBú^´W£dkɾĬpw˂ØɦļĬIŚÊnŔa¸~J°îlɌxĤÊÈðhÌ®gT´øàCÀ^ªerrƘd¢İP|Ė ŸWªĦ^¶´ÂLaT±üWƜǀRÂŶUńĖ[QhlLüAÜ\\qRĄ©"],"encodeOffsets":[[90849,37210]]}},{"type":"Feature","id":"610000","properties":{"id":"610000","cp":[108.948024,34.263161],"name":"陕西","childNum":1},"geometry":{"type":"Polygon","coordinates":["@@p¢ȮµûGĦ}Ħðǚ¶òƄjɂz°{ºØkÈęâ¦jªBg\\ċ°s¬]jú EȌdž¬stRÆdĠİwܸôW¾ƮłÒ_{Ìû¼jº¹¢GǪÒ¯ĘZ`ºŊecņą~BÂgzpâēòYǠȰÌTΨÂW|fcă§uF@N¢XLRMº[ğȣſï|¥Jkc`sʼnǷY¹W@µ÷K ãï³ÛIcñ·VȋÚÒķø©þ¥yÓğęmWµÎumZyOŅƟĥÓ~sÑL¤µaÅ Y¦ocyZ{y c]{Ta©`U_Ěē£ωÊƍKùK¶ȱÝƷ§{û»ÅÁȹÍéuij|¹cÑdìUYOuFÕÈYvÁCqÓTǢí§·S¹NgV¬ë÷Át°DدC´ʼnƒópģ}ċcEË FéGU¥×K §¶³BČ}C¿åċ`wġB·¤őcƭ²ő[Å^axwQO ÿEËߌĤNĔwƇÄńwĪo[_KÓª³ÙnKÇěÿ]ďă_d©·©Ýŏ°Ù®g]±ßå¬÷m\\iaǑkěX{¢|ZKlçhLtŇîŵœè[É@ƉĄEtƇϳħZ«mJ ×¾MtÝĦ£IwÄå\\Õ{OwĬ©LÙ³ÙgBƕŀrÌĢŭO¥lãyC§HÍ£ßEñX¡°ÙCgpťzb`wIvA|§hoĕ@E±iYd¥OϹS|}F@¾oAO²{tfÜ¢FǂÒW²°BĤh^Wx{@¬F¸¡ķn£P|ªĴ@^ĠĈæbÔc¶lYi ^MicϰÂ[ävï¶gv@ÀĬ·lJ¸sn|¼u~a]ÆÈtŌºJpþ£KKf~¦UbyäIĺãnÔ¿^ŵMThĠܤko¼Ŏìąǜh`[tRd²IJ_XPrɲlXiL§à¹H°Ȧqº®QCbAŌJ¸ĕÚ³ĺ§ `d¨YjiZvRĺ±öVKkjGȊÄePĞZmļKÀ[`ösìhïÎoĬdtKÞ{¬èÒÒBÔpIJÇĬJŊ¦±J«Y§@·pHµàåVKepWftsAÅqC·¬ko«pHÆuK@oHĆÛķhxenS³àǍrqƶRbzy¸ËÐl¼EºpĤ¼x¼½~Ğà@ÚüdK^mÌSj"],"encodeOffsets":[[110234,38774]]}},{"type":"Feature","id":"620000","properties":{"id":"620000","cp":[103.823557,36.058039],"name":"甘肃","childNum":2},"geometry":{"type":"MultiPolygon","coordinates":[["@@VuUv"],["@@ũEĠtt~nkh`Q¦ÅÄÜdwAb×ĠąJ¤DüègĺqBqj°lI¡ĨÒ¤úSHbjÎB°aZ¢KJO[|A£Dx}NìHUnrk kp¼Y kMJn[aGáÚÏ[½rc}aQxOgsPMnUsncZ sKúvAtÞġ£®ĀYKdnFw¢JE°Latf`¼h¬we|Æbj}GA·~W`¢MC¤tL©IJ°qdfObÞĬ¹ttu`^ZúE`[@Æsîz®¡CƳƜG²R¢RmfwĸgÜą G@pzJM½mhVy¸uÈÔO±¨{LfæU¶ßGĂq\\ª¬²I¥IʼnÈīoıÓÑAçÑ|«LÝcspīðÍg të_õ\\ĉñLYnĝgRǡÁiHLlõUĹ²uQjYi§Z_c¨´ĹĖÙ·ŋI aBDR¹ȥr¯GºßK¨jWkɱOqWij\\aQ\\sg_ĆǛōëp»£lğÛgSŶN®À]ÓämĹãJaz¥V}Le¤Lýo¹IsŋÅÇ^bz ³tmEÁ´a¹cčecÇNĊãÁ\\č¯dNj]jZµkÓdaćå]ğij@ ©O{¤ĸm¢E·®«|@Xwg]A챝XǁÑdzªcwQÚŝñsÕ³ÛV_ý¥\\ů¥©¾÷w©WÕÊĩhÿÖÁRo¸V¬âDb¨hûxÊ×nj~Zâg|XÁnßYoº§ZÅŘv[ĭÖʃuďxcVbnUSf B¯³_TzºÎO©çMÑ~M³]µ^püµÄY~y@X~¤Z³[Èōl@®Å¼£QK·Di¡ByÿQ_´D¥hŗy^ĭÁZ]cIzýah¹MĪğPs{ò²Vw¹t³ŜË[Ñ}X\\gsF£sPAgěp×ëfYHāďÖqēŭOÏëdLü\\it^c®Rʺ¶¢H°mrY£B¹čIoľu¶uI]vģSQ{UŻÅ}QÂ|̰ƅ¤ĩŪU ęĄÌZÒ\\v²PĔ»ƢNHĂyAmƂwVm`]ÈbH`Ì¢²ILvĜH®¤Dlt_¢JJÄämèÔDëþgºƫaʎÌrêYi~ ÎݤNpÀA¾Ĕ¼b ð÷®üszMzÖĖQdȨýv§Tè|ªHþa¸|Ð ƒwKĢx¦ivr^ÿ ¸l öæfƟĴ·PJv}n\\h¹¶v·À|\\ƁĚN´ĜçèÁz]ġ¤²¨QÒŨTIlªťØ}¼˗ƦvÄùØE«FïËIqōTvāÜŏíÛßÛVj³âwGăÂíNOPìyV³ʼnĖýZso§HÑiYw[ß\\X¦¥c]ÔƩÜ·«jÐqvÁ¦m^ċ±R¦ƈťĚgÀ»IïĨʗƮ°ƝĻþÍAƉſ±tÍEÕÞāNUÍ¡\\ſčåÒʻĘm ƭÌŹöʥëQ¤µÇcƕªoIýIÉ_mkl³ăƓ¦j¡YzŇi}Msßõīʋ }ÁVm_[n}eıUĥ¼ªI{ΧDÓƻėojqYhĹT©oūĶ£]ďxĩǑMĝq`B´ƃ˺Чç~²ņj@¥@đ´ί}ĥtPńǾV¬ufÓÉCtÓ̻ ¹£G³]ƖƾŎĪŪĘ̖¨ʈĢƂlɘ۪üºňUðǜȢƢż̌ȦǼĤŊɲĖÂKq´ï¦ºĒDzņɾªǀÞĈĂD½ĄĎÌŗĞrôñnN¼â¾ʄľԆ|DŽ֦ज़ȗlj̘̭ɺƅêgV̍ʆĠ·ÌĊv|ýĖÕWĊǎÞ´õ¼cÒÒBĢ͢UĜð͒s¨ňƃLĉÕÝ@ɛƯ÷¿ĽĹeȏijëCȚDŲyê×Ŗyò¯ļcÂßY tÁƤyAã˾J@ǝrý@¤ rz¸oP¹ɐÚyáHĀ[Jw cVeȴÏ»ÈĖ}ƒŰŐèȭǢόĀƪÈŶë;Ñ̆ȤМľĮEŔĹŊũ~ËUă{ĻƹɁύȩþĽvĽƓÉ@ēĽɲßǐƫʾǗĒpäWÐxnsÀ^ƆwW©¦cÅ¡Ji§vúF¶¨c~c¼īeXǚ\\đ¾JwÀďksãAfÕ¦L}waoZD½Ml«]eÒÅaɲáo½FõÛ]ĻÒ¡wYR£¢rvÓ®y®LFLzĈôe]gx}|KK}xklL]c¦£fRtív¦PĤoH{tK"]],"encodeOffsets":[[[108619,36299]],[[108589,36341]]]}},{"type":"Feature","id":"630000","properties":{"id":"630000","cp":[96.778916,35.623178],"name":"青海","childNum":2},"geometry":{"type":"MultiPolygon","coordinates":[["@@InJm"],["@@CƽOŃĦsΰ~dz¦@@Ņi±è}ШƄ˹A³r_ĞǒNĪĐw¤^ŬĵªpĺSZgrpiƼĘÔ¨C|ÍJ©Ħ»®VIJ~f\\m `UnÂ~ʌĬàöNt~ňjy¢ZiƔ¥Ąk´nl`JÊJþ©pdƖ®È£¶ìRʦźõƮËnʼėæÑƀĎ[¢VÎĂMÖÝÎF²sƊƀÎBļýƞ¯ʘƭðħ¼Jh¿ŦęΌƇ¥²Q]Č¥nuÂÏri¸¬ƪÛ^Ó¦d¥[Wà x\\ZjÒ¨GtpþYŊĕ´zUOëPîMĄÁxH´áiÜUàîÜŐĂÛSuŎrJð̬EFÁú×uÃÎkrĒ{V}İ«O_ÌËĬ©ÓŧSRѱ§Ģ£^ÂyèçěM³Ƃę{[¸¿u ºµ[gt£¸OƤĿéYõ·kĀq]juw¥DĩƍõÇPéĽG©ã¤G uȧþRcÕĕNyyûtøï»a½ē¿BMoį£Íj}éZËqbʍƬh¹ìÿÓAçãnIáI`ks£CGěUy×Cy @¶ʡÊBnāzGơMē¼±O÷õJËĚăVĪũƆ£¯{ËL½ÌzżVR|ĠTbuvJvµhĻĖHAëáa OÇðñęNw œľ·LmI±íĠĩPÉ×®ÿscB³±JKßĊ«` ađ»·QAmOVţéÿ¤¹SQt]]Çx±¯A@ĉij¢Óļ©l¶ÅÛrŕspãRk~¦ª]Į´FRådČsCqđéFn¿ÅƃmÉx{W©ºƝºįkÕƂƑ¸wWūЩÈF£\\tÈ¥ÄRÈýÌJ lGr^×äùyÞ³fjc¨£ÂZ|ǓMĝÏ@ëÜőRĝ÷¡{aïȷPu°ËXÙ{©TmĠ}Y³ÞIňµç½©C¡į÷¯B»|St»]vųs»}MÓ ÿʪƟǭA¡fs»PY¼c¡»¦cċ¥£~msĉPSi^o©AecPeǵkgyUi¿h}aHĉ^|á´¡HØûÅ«ĉ®]m¡qĉ¶³ÈyôōLÁstB®wn±ă¥HSòė£Së@לÊăxÇN©©T±ª£IJ¡fb®Þbb_Ą¥xu¥B{łĝ³«`dƐt¤ťiñÍUuºí`£^tƃIJc·ÛLO½sç¥Ts{ă\\_»kϱq©čiìĉ|ÍI¥ć¥]ª§D{ŝŖÉR_sÿc³ĪōƿΧp[ĉc¯bKmR¥{³Ze^wx¹dƽŽôIg §Mĕ ƹĴ¿ǣÜÍ]Ý]snåA{eƭ`ǻŊĿ\\ijŬűYÂÿ¬jĖqßb¸L«¸©@ěĀ©ê¶ìÀEH|´bRľÓ¶rÀQþvl®ÕETzÜdb hw¤{LRdcb¯ÙVgƜßzÃôì®^jUèXÎ|UäÌ»rK\\ªN¼pZCüVY¤ɃRi^rPŇTÖ}|br°qňb̰ªiƶGQ¾²x¦PmlŜ[Ĥ¡ΞsĦÔÏâ\\ªÚŒU\\f ¢N²§x|¤§xĔsZPòʛ²SÐqF`ªVÞŜĶƨVZÌL`¢dŐIqr\\oäõF礻Ŷ×h¹]ClÙ\\¦ďÌį¬řtTӺƙgQÇÓHţĒ´ÃbEÄlbʔC|CŮkƮ[ʼ¬ň´KŮÈΰÌζƶlðļATUvdTGº̼ÔsÊDÔveOg"]],"encodeOffsets":[[[105308,37219]],[[95370,40081]]]}},{"type":"Feature","id":"640000","properties":{"id":"640000","cp":[106.278179,37.26637],"name":"宁夏","childNum":2},"geometry":{"type":"MultiPolygon","coordinates":[["@@KëÀęĞ«Oęȿȕı]ʼn¡åįÕÔ«ǴõƪĚQÐZhv K°öqÀÑS[ÃÖHƖčËnL]ûc Ùß@ĝ¾}w»»oģF¹»kÌÏ·{zP§B¢íyÅt@@á]Yv_ssģ¼ißĻL¾ġsKD£¡N_ X¸}B~HaiÅf{«x»ge_bsKF¯¡IxmELcÿZ¤ĢÝsuBLùtYdmVtNmtOPhRw~bd ¾qÐ\\âÙH\\bImlNZ»loqlVmGā§~QCw¤{A\\PKNY¯bFkC¥sks_Ã\\ă«¢ħkJi¯rrAhĹûç£CUĕĊ_ÔBixÅÙĄnªÑaM~ħpOu¥sîeQ¥¤^dkKwlL~{L~hw^ófćKyEKzuÔ¡qQ¤xZÑ¢^ļöܾEp±âbÊÑÆ^fk¬ NC¾YpxbK~¥eÖäBlt¿Đx½I[ĒǙWf»Ĭ}d§dµùEuj¨IÆ¢¥dXªƅx¿]mtÏwßRĶX¢͎vÆzƂZò®ǢÌʆCrâºMÞzÆMÒÊÓŊZľr°Î®Ȉmª²ĈUªĚîøºĮ¦ÌĘk^FłĬhĚiĀ˾iİbjÕ"],["@@mfwěwMrŢªv@G"]],"encodeOffsets":[[[109366,40242]],[[108600,36303]]]}},{"type":"Feature","id":"650000","properties":{"id":"650000","cp":[85.617733,40.792818],"name":"新疆","childNum":1},"geometry":{"type":"Polygon","coordinates":["@@QØĔ²X¨~ǘBºjʐߨvKƔX¨vĊO÷¢i@~cĝe_«E}QxgɪëÏÃ@sÅyXoŖ{ô«ŸuX êÎf`C¹ÂÿÐGĮÕĞXŪōŸMźÈƺQèĽôe|¿ƸJR¤ĘEjcUóº¯Ĩ_ŘÁMª÷Ð¥OéÈ¿ÖğǤǷÂFÒzÉx[]Ĥĝœ¦EP}ûƥé¿İƷTėƫœŕƅƱB»Đ±ēO ¦E}`cȺrĦáŖuÒª«IJπdƺÏØZƴwʄ¤ĖGĐǂZĶèH¶}ÚZצʥĪï|ÇĦMŔ»İĝLjì¥Βba¯¥ǕǚkĆŵĦɑĺƯxūД̵nơʃĽá½M»òmqóŘĝč˾ăC ćāƿÝɽ©DZҹđ¥³ðLrÁ®ɱĕģʼnǻ̋ȥơŻǛȡVï¹Ň۩ûkɗġƁ§ʇė̕ĩũƽō^ƕUv£ƁQïƵkŏ½ΉÃŭdzLŇʻ«ƭ\\lŭD{ʓDkaFÃÄa³ŤđÔGRÈƚhSӹŚsİ«ĐË[¥ÚDkº^Øg¼ŵ¸£EÍöůʼnT¡c_ËKYƧUśĵÝU_©rETÏʜ±OñtYwē¨{£¨uM³x½şL©Ùá[ÓÐĥ Νtģ¢\\śnkOw¥±T»ƷFɯàĩÞáB¹Æ ÑUwŕĽw[mG½Èå~Æ÷QyěCFmĭZīŵVÁƿQƛûXS²b½KϽĉS©ŷXĕ{ĕK·¥Ɨcqq©f¿]ßDõU³hgËÇïģÉɋwk¯í}I·œbmÉřīJɥĻˁ×xoɹīlc ¤³Xù]DžA¿w͉ì¥wÇN·ÂËnƾƍdǧđ®ƝvUm©³G\\}µĿQyŹlăµEwLJQ½yƋBe¶ŋÀůo¥AÉw@{Gpm¿AijŽKLh³`ñcËtW±»ÕSëüÿďDu\\wwwù³VLŕOMËGh£õP¡erÏd{ġWÁ č|yšg^ğyÁzÙs`s|ÉåªÇ}m¢Ń¨`x¥ù^}Ì¥H«YªƅAйn~ź¯f¤áÀzgÇDIÔ´AňĀÒ¶ûEYospõD[{ù°]uJqU|Soċxţ[õÔĥkŋÞŭZ˺óYËüċrw ÞkrťË¿XGÉbřaDü·Ē÷Aê[ÄäI®BÕĐÞ_¢āĠpÛÄȉĖġDKwbmÄNôfƫVÉvidzHQµâFùœ³¦{YGd¢ĚÜO {Ö¦ÞÍÀP^bƾl[vt×ĈÍE˨¡Đ~´î¸ùÎhuè`¸HÕŔVºwĠââWò@{ÙNÝ´ə²ȕn{¿¥{l÷eé^eďXj©î\\ªÑòÜìc\\üqÕ[Č¡xoÂċªbØø|¶ȴZdÆÂońéG\\¼C°ÌÆn´nxÊOĨŪƴĸ¢¸òTxÊǪMīĞÖŲÃɎOvʦƢ~FRěò¿ġ~åŊúN¸qĘ[Ĕ¶ÂćnÒPĒÜvúĀÊbÖ{Äî¸~Ŕünp¤ÂH¾ĄYÒ©ÊfºmÔĘcDoĬMŬS¤s²ʘÚžȂVŦ èW°ªB|IJXŔþÈJĦÆæFĚêYĂªĂ]øªŖNÞüAfɨJ¯ÎrDDĤ`mz\\§~D¬{vJ«lµĂb¤pŌŰNĄ¨ĊXW|ų ¿¾ɄĦƐMTòP÷fØĶK¢ȝ˔Sô¹òEð`Ɩ½ǒÂň×äı§ĤƝ§C~¡hlåǺŦŞkâ~}FøàIJaĞfƠ¥Ŕd®U¸źXv¢aƆúŪtŠųƠjdƺƺÅìnrh\\ĺ¯äɝĦ]èpĄ¦´LƞĬ´ƤǬ˼Ēɸ¤rºǼ²¨zÌPðŀbþ¹ļD¢¹\\ĜÑŚ¶ZƄ³àjĨoâȴLÊȮĐĚăÀêZǚŐ¤qȂ\\L¢ŌİfÆs|zºeªÙæ§{Ā´ƐÚ¬¨Ĵà²łhʺKÞºÖTiƢ¾ªì°`öøu®Ê¾ãØ"],"encodeOffsets":[[88824,50096]]}},{"type":"Feature","id":"110000","properties":{"id":"110000","cp":[116.405285,39.904989],"name":"北京","childNum":1},"geometry":{"type":"Polygon","coordinates":["@@ĽOÁûtŷmiÍt_H»Ĩ±d`¹{bw Yr³S]§§o¹qGtm_SŧoaFLgQN_dV@Zom_ć\\ßc±x¯oœRcfe £o§ËgToÛJíĔóu |wP¤XnO¢ÉŦ¯rNÄā¤zâŖÈRpŢZÚ{GrFt¦Òx§ø¹RóäV¤XdżâºWbwڍUd®bêņ¾jnŎGŃŶnzÚSeîĜZczî¾i]ÍQaúÍÔiþĩȨWĢü|Ėu[qb[swP@ÅğP¿{\\¥A¨ÏѨj¯X\\¯MKpA³[H īu}}"],"encodeOffsets":[[120023,41045]]}},{"type":"Feature","id":"120000","properties":{"id":"120000","cp":[117.190182,39.125596],"name":"天津","childNum":1},"geometry":{"type":"Polygon","coordinates":["@@ŬgX§Ü«E ¶F̬O_ïlÁgz±AXeµÄĵ{¶]gitgIj·¥îakS¨ÐƎk}ĕ{gBqGf{¿aU^fIư³õ{YıëNĿk©ïËZŏR§òoY×Ógc ĥs¡bġ«@dekąI[nlPqCnp{ō³°`{PNdƗqSÄĻNNâyj]äÒD ĬH°Æ]~¡HO¾X}ÐxgpgWrDGpù^LrzWxZ^¨´T\\|~@IzbĤjeĊªz£®ĔvěLmV¾Ô_ÈNW~zbĬvG²ZmDM~~"],"encodeOffsets":[[120237,41215]]}},{"type":"Feature","id":"310000","properties":{"id":"310000","cp":[121.472644,31.231706],"name":"上海","childNum":6},"geometry":{"type":"MultiPolygon","coordinates":[["@@ɧư¬EpƸÁxc"],["@@©ª"],["@@MA"],["@@QpİE§ÉC¾"],["@@bŝÕÕEȣÚƥêImɇǦèÜĠÚÃƌÃ͎ó"],["@@ǜûȬɋŭ×^sYɍDŋŽąñCG²«ªč@h_p¯A{oloY¬j@IJ`gQÚhr|ǀ^MIJvtbe´R¯Ô¬¨Yô¤r]ìƬį"]],"encodeOffsets":[[[124702,32062]],[[124547,32200]],[[124808,31991]],[[124726,32110]],[[124903,32376]],[[124438,32149]]]}},{"type":"Feature","id":"500000","properties":{"id":"500000","cp":[107.304962,29.533155],"name":"重庆","childNum":2},"geometry":{"type":"MultiPolygon","coordinates":[["@@vjG~nGŘŬĶȂƀƾ¹¸ØÎezĆT¸}êÐqHðqĖä¥^CÆIj²p \\_ æüY|[YxƊæu°xb® Űb@~¢NQt°¶Sæ Ê~rljĔëĚ¢~uf`faĔJåĊnÖ]jƎćÊ@£¾a®£Ű{ŶĕFègLk{Y|¡ĜWƔtƬJÑxq±ĢN´òKLÈüD|s`ŋć]Ã`đMûƱ½~Y°ħ`ƏíW½eI½{aOIrÏ¡ĕŇapµÜƅġ^ÖÛbÙŽŏml½SêqDu[RãË»ÿw`»y¸_ĺę}÷`M¯ċfCVµqʼn÷Zgg`d½pDOÎCn^uf²ènh¼WtƏxRGg¦ pVFI±G^Ic´ecGĹÞ½sëĬhxW}KÓeXsbkF¦LØgTkïƵNï¶}Gyw\\oñ¡nmĈzj@Óc£»Wă¹Ój_m»¹·~MvÛaq»ê\\ÂoVnÓØÍ²«bq¿efE Ĝ^Q~ Évýş¤²ĮpEİ}zcĺL½¿gÅ¡ýE¡ya£³t\\¨\\vú»¼§·Ñr_oÒý¥u_n»_At©Þűā§IVeëY}{VPÀFA¨ąB}q@|Ou\\FmQFÝ Mwå}]|FmÏCawu_p¯sfÙgY DHl`{QEfNysB¦zG¸rHeN\\CvEsÐùÜ_·ÖĉsaQ¯}_UxÃđqNH¬Äd^ÝŰR¬ã°wećJE·vÝ·HgéFXjÉê`|ypxkAwWĐpb¥eOsmzwqChóUQl¥F^lafanòsrEvfQdÁUVfÎvÜ^eftET¬ôA\\¢sJnQTjPØxøK|nBzĞ»LY FDxÓvr[ehľvN¢o¾NiÂxGpâ¬zbfZo~hGi]öF||NbtOMn eA±tPTLjpYQ|SHYĀxinzDJÌg¢và¥Pg_ÇzIIII£®S¬Øsμ£N"],["@@ifjN@s"]],"encodeOffsets":[[[109628,30765]],[[111725,31320]]]}},{"type":"Feature","id":"810000","properties":{"id":"810000","cp":[114.173355,22.320048],"name":"香港","childNum":5},"geometry":{"type":"MultiPolygon","coordinates":[["@@AlBk"],["@@mn"],["@@EpFo"],["@@ea¢pl¸Eõ¹hj[]ÔCÎ@lj¡uBX ´AI¹ [yDU]W`çwZkmc MpÅv}IoJlcafŃK°ä¬XJmÐ đhI®æÔtSHnEÒrÈc"],["@@rMUwAS®e"]],"encodeOffsets":[[[117111,23002]],[[117072,22876]],[[117045,22887]],[[116975,23082]],[[116882,22747]]]}},{"type":"Feature","id":"820000","properties":{"id":"820000","cp":[113.54909,22.198951],"name":"澳门","childNum":1},"geometry":{"type":"Polygon","coordinates":["@@kÊd°å§s"],"encodeOffsets":[[116279,22639]]}}],"UTF8Encoding":true} \ No newline at end of file +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "id": "710000", + "properties": { + "id": "710000", + "cp": [121.509062, 24.044332], + "name": "台湾", + "childNum": 6 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@°Ü¯Û"], + [ + "@@ƛĴÕƊÉɼģºðʀ\\ƎsÆNŌÔĚänÜƤɊĂǀĆĴĤNJŨxĚĮǂƺòƌâÔ®ĮXŦţƸZûÐƕƑGđ¨ĭMó·ęcëƝɉlÝƯֹÅŃ^Ó·śŃNjƏďíåɛGɉ¿@ăƑ¥ĘWǬÏĶŁâ" + ], + ["@@\\p|WoYG¿¥Ij@¢"], + ["@@ ¡@V^RqBbAnTXeRz¤L«³I"], + ["@@ÆEEkWqë @"], + ["@@fced"], + ["@@¯ɜÄèaì¯ØǓIġĽ"], + ["@@çûĖëĄhòř "] + ], + "encodeOffsets": [ + [[122886, 24033]], + [[123335, 22980]], + [[122375, 24193]], + [[122518, 24117]], + [[124427, 22618]], + [[124862, 26043]], + [[126259, 26318]], + [[127671, 26683]] + ] + } + }, + { + "type": "Feature", + "id": "130000", + "properties": { + "id": "130000", + "cp": [114.502461, 38.045474], + "name": "河北", + "childNum": 3 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@o~Z]ªrºc_ħ²G¼s`jΟnüsÂłNX_M`ǽÓnUK Ĝēs¤©yrý§uģcJe"], + ["@@U`Ts¿mÂ"], + [ + "@@oºƋÄdeVDJj£J|ÅdzÂFt~KŨ¸IÆv|¢r}èonb}`RÎÄn°ÒdÞ²^®lnÐèĄlðÓ×]ªÆ}LiñÖ`^°Ç¶p®đDcŋ`ZÔ¶êqvFÆN®ĆTH®¦O¾IbÐã´BĐɢŴÆíȦpĐÞXR·nndO¤OÀĈƒQgµFo|gȒęSWb©osx|hYhgŃfmÖĩnºTÌSp¢dYĤ¶UĈjlǐpäìë|³kÛfw²Xjz~ÂqbTÑěŨ@|oMzv¢ZrÃVw¬ŧˏf°ÐTªqs{S¯r æÝlNd®²Ğ džiGĘJ¼lr}~K¨ŸƐÌWöÆzR¤lêmĞLÎ@¡|q]SvKÑcwpÏÏĿćènĪWlĄkT}J¤~ÈTdpddʾĬBVtEÀ¢ôPĎƗè@~kü\\rÊĔÖæW_§¼F´©òDòjYÈrbĞāøŀG{ƀ|¦ðrb|ÀH`pʞkvGpuARhÞÆǶgĘTǼƹS£¨¡ù³ŘÍ]¿ÂyôEP xX¶¹ÜO¡gÚ¡IwÃé¦ÅBÏ|ǰ N«úmH¯âDùyŜŲIÄuШD¸dɂFOhđ©OiÃ`ww^ÌkÑH«ƇǤŗĺtFu {Z}Ö@U´ ʚLg®¯Oı°Ãw ^VbÉsmA ê]]w§RRl£ȭµu¯b{ÍDěïÿȧuT£ġěŗƃĝQ¨fVƋƅna@³@ďyýIĹÊKŭfċŰóxV@tƯJ]eR¾fe|rHA|h~Ėƍl§ÏlTíb ØoÅbbx³^zÃͶSj®AyÂhðk`«P˵EFÛ¬Y¨Ļrõqi¼Wi°§Ð±´°^[À|ĠO@ÆxO\\ta\\tĕtû{ġȧXýĪÓjùÎRb^ÎfK[ÝděYfíÙTyuUSyŌŏů@Oi½éŅaVcř§ax¹XŻácWU£ôãºQ¨÷Ñws¥qEHÙ|šYQoŕÇyáĂ£MðoťÊP¡mWO¡v{ôvîēÜISpÌhp¨ jdeŔQÖjX³àĈ[n`Yp@UcM`RKhEbpŞlNut®EtqnsÁgAiúoHqCXhfgu~ÏWP½¢G^}¯ÅīGCÑ^ãziMáļMTÃƘrMc|O_¯Ŏ´|morDkO\\mĆJfl@c̬¢aĦtRıÒ¾ùƀ^juųœKUFyƝ īÛ÷ąV×qƥV¿aȉd³BqPBmaËđŻģmÅ®V¹d^KKonYg¯XhqaLdu¥ÍpDž¡KąÅkĝęěhq}HyÃ]¹ǧ£ Í÷¿qáµ§g¤o^á¾ZE¤i`ij{nOl»WÝĔįhgF[¿¡ßkOüš_ūiDZàUtėGyl}ÓM}jpEC~¡FtoQiHkk{Ãmï" + ] + ], + "encodeOffsets": [[[119712, 40641]], [[121616, 39981]], [[116462, 37237]]] + } + }, + { + "type": "Feature", + "id": "140000", + "properties": { + "id": "140000", + "cp": [111.849248, 36.857014], + "name": "山西", + "childNum": 1 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + "@@ÞĩÒSra}ÁyWix±Üe´lèßÓǏokćiµVZģ¡coTS˹ĪmnÕńehZg{gtwªpXaĚThȑp{¶Eh®RćƑP¿£Pmc¸mQÝWďȥoÅîɡųAďä³aÏJ½¥PGąSM EÅruµéYÓŌ_dĒCoȵ]¯_²ÕjāK~©ÅØ^ÔkïçămÏk]±cݯÑÃmQÍ~_apm ~ç¡qu{JÅŧ·Ls}EyÁÆcI{¤IiCfUcƌÃp§]ě«vD@¡SÀµMÅwuYY¡DbÑc¡h×]nkoQdaMç~eDÛtT©±@¥ù@É¡ZcW|WqOJmĩl«ħşvOÓ«IqăV¥D[mI~Ó¢cehiÍ]Ɠ~ĥqX·eƷn±}v[ěďŕ]_œ`¹§ÕōIo©bs^}Ét±ū«³p£ÿ·Wµ|¡¥ăFÏs×¥ŅxÊdÒ{ºvĴÎêÌɊ²¶ü¨|ÞƸµȲLLúÉƎ¤ϊęĔV`_bªS^|dzY|dz¥pZbÆ£¶ÒK}tĦÔņƠPYznÍvX¶Ěn ĠÔzý¦ª÷ÑĸÙUȌ¸dòÜJð´ìúNM¬XZ´¤ŊǸ_tldI{¦ƀðĠȤ¥NehXnYGR° ƬDj¬¸|CĞKqºfƐiĺ©ª~ĆOQª ¤@ìǦɌ²æBÊTŸʂōĖĴŞȀÆÿȄlŤĒötνî¼ĨXh|ªM¤Ðz" + ], + "encodeOffsets": [[116874, 41716]] + } + }, + { + "type": "Feature", + "id": "150000", + "properties": { + "id": "150000", + "cp": [111.670801, 41.818311], + "name": "内蒙古", + "childNum": 2 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + "@@¯PqFB |S³C|kñHdiÄ¥sʼnÅ PóÑÑE^ÅPpy_YtShQ·aHwsOnʼnÃs©iqjUSiº]ïW«gW¡ARë¥_sgÁnUI«m ]jvV¼euhwqAaW_µj »çjioQR¹ēÃßt@r³[ÛlćË^ÍÉáGOUÛOB±XkŹ£k|e]olkVͼÕqtaÏõjgÁ£§U^RLËnX°ÇBz^~wfvypV ¯ƫĉ˭ȫƗŷɿÿĿƑ˃ĝÿÃǃßËőó©ǐȍŒĖM×ÍEyxþp]ÉvïèvƀnÂĴÖ@V~Ĉv¦wĖtējyÄDXÄxGQuv_i¦aBçw˛wD©{tāmQ{EJ§KPśƘƿ¥@sCTÉ}ɃwƇy±gÑ}T[÷kÐ禫 SÒ¥¸ëBX½HáŵÀğtSÝÂa[ƣ°¯¦Pï¡]£ġÒk®G²èQ°óMq}EóƐÇ\\@áügQÍu¥FTÕ¿Jû]|mvāÎYua^WoÀa·ząÒot×¶CLƗi¯¤mƎHNJ¤îìɾŊìTdåwsRÖgĒųúÍġäÕ}Q¶¿A[¡{d×uQAMxVvMOmăl«ct[wº_ÇÊjb£ĦS_éQZ_lwgOiýe`YYLq§IÁdz£ÙË[ÕªuƏ³ÍTs·bÁĽäė[b[ŗfãcn¥îC¿÷µ[ŏÀQōĉm¿Á^£mJVmL[{Ï_£F¥Ö{ŹA} ×Wu©ÅaųijƳhB{·TQqÙIķËZđ©Yc|M¡ LeVUóK_QWk_ĥ¿ãZ»X\\ĴuUèlG®ěłTĠğDŃOrÍdÆÍz]± ŭ©Å]ÅÐ}UË¥©TċïxgckfWgi\\ÏĒ¥HkµEë{»ÏetcG±ahUiñiWsɁ·cCÕk]wȑ|ća}w VaĚá G°ùnM¬¯{ÈÐÆA¥ÄêJxÙ¢hP¢ÛºµwWOóFÁz^ÀŗÎú´§¢T¤ǻƺSėǵhÝÅQgvBHouʝl_o¿Ga{ïq{¥|ſĿHĂ÷aĝÇqZñiñC³ª »E`¨åXēÕqÉû[l}ç@čƘóO¿¡FUsAʽīccocÇS}£IS~ălkĩXçmĈ ŀÐoÐdxÒuL^T{r@¢ÍĝKén£kQyÅõËXŷƏL§~}kq»IHėDžjĝ»ÑÞoå°qTt|r©ÏS¯·eŨĕx«È[eM¿yupN~¹ÏyN£{©għWí»Í¾səšDž_ÃĀɗ±ąijĉʍŌŷSÉA±åǥɋ@ë£R©ąP©}ĹªƏj¹erLDĝ·{i«ƫC£µsKC GS|úþXgp{ÁX¿ć{ƱȏñZáĔyoÁhA}ŅĆfdʼn_¹Y°ėǩÑ¡H¯¶oMQqð¡Ë|Ñ`ƭŁX½·óÛxğįÅcQs«tȋDžFù^it«Č¯[hAi©á¥ÇĚ×l|¹y¯YȵƓñǙµïċĻ|Düȭ¶¡oŽäÕG\\ÄT¿Òõr¯LguÏYęRƩɷŌO\\İТæ^Ŋ IJȶȆbÜGĝ¬¿ĚVĎgª^íu½jÿĕęjık@Ľ]ėl¥ËĭûÁėéV©±ćn©ȇÍq¯½YÃÔʼnÉNÑÅÝy¹NqáʅDǡËñƁYÅy̱os§ȋµʽǘǏƬɱàưN¢ƔÊuľýľώȪƺɂļxZĈ}ÌʼnŪĺœĭFЛĽ̅ȣͽÒŵìƩÇϋÿȮǡŏçƑůĕ~ǼȳÐUfdIxÿ\\G zâɏÙOº·pqy£@qþ@Ǟ˽IBäƣzsÂZÁàĻdñ°ŕzéØűzșCìDȐĴĺf®Àľưø@ɜÖÞKĊŇƄ§͑těï͡VAġÑÑ»d³öǍÝXĉĕÖ{þĉu¸ËʅğU̎éhɹƆ̗̮ȘNJ֥ड़ࡰţાíϲäʮW¬®ҌeרūȠkɬɻ̼ãüfƠSצɩςåȈHϚÎKdzͲOðÏȆƘ¼CϚǚ࢚˼ФÔ¤ƌĞ̪Qʤ´¼mȠJˀƲÀɠmǐnǔĎȆÞǠN~ʢĜ¶ƌĆĘźʆȬ˪ĚǏĞGȖƴƀj`ĢçĶāàŃºēĢĖćYÀŎüôQÐÂŎŞdžŞêƖoˆDĤÕºÑǘÛˤ³̀gńƘĔÀ^ªƂ`ªt¾äƚêĦ¼ÐĔǎ¨Ȕ»͠^ˮÊȦƤøxRrŜH¤¸ÂxDÄ|ø˂˜ƮЬɚwɲFjĔ²Äw°dždÀÉ_ĸdîàŎjÊêTЪŌŜWÈ|tqĢUB~´°ÎFCU¼pĀēƄN¦¾O¶łKĊOjĚj´ĜYp{¦SĚÍ\\TתV÷Ší¨ÅDK°ßtŇĔK¨ǵÂcḷ̌ĚǣȄĽFlġUĵŇȣFʉɁMğįʏƶɷØŭOǽ«ƽū¹Ʊő̝Ȩ§ȞʘĖiɜɶʦ}¨֪ࠜ̀ƇǬ¹ǨE˦ĥªÔêFxúQEr´Wrh¤Ɛ \\talĈDJÜ|[Pll̚¸ƎGú´P¬W¦^¦H]prRn|or¾wLVnÇIujkmon£cX^Bh`¥V¦U¤¸}xRj[^xN[~ªxQ[`ªHÆÂExx^wN¶Ê|¨ìMrdYpoRzNyÀDs~bcfÌ`L¾n|¾T°c¨È¢ar¤`[|òDŞĔöxElÖdHÀI`Ď\\Àì~ÆR¼tf¦^¢ķ¶eÐÚMptgjɡČÅyġLûŇV®ÄÈƀϰP|ªVVªj¬ĚÒêp¬E|ŬÂc|ÀtƐK f{ĘFĒƌXƲąo½Ę\\¥o}Ûu£çkX{uĩ«āíÓUŅßŢqŤ¥lyň[oi{¦LńðFȪȖĒL¿Ìf£K£ʺoqNwğc`uetOj×°KJ±qÆġmĚŗos¬ qehqsuH{¸kH¡ ÊRǪÇƌbȆ¢´äÜ¢NìÉʖ¦â©Ġu¦öČ^â£ĂhĖMÈÄw\\fŦ°W ¢¾luŸDw\\̀ʉÌÛM Ā[bÓEn}¶Vc ês" + ] + ], + "encodeOffsets": [[[129102, 52189]]] + } + }, + { + "type": "Feature", + "id": "210000", + "properties": { + "id": "210000", + "cp": [123.429096, 41.796767], + "name": "辽宁", + "childNum": 16 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@L@@sa"], + ["@@MnNm"], + ["@@dc"], + ["@@eÀC@b"], + ["@@f XwkbrÄ`qg"], + ["@@^jtWQ"], + ["@@~ Y]c"], + ["@@G`ĔN^_¿ZÃM"], + ["@@iX¶BY"], + ["@@YZ"], + ["@@L_{Epf"], + ["@@^WqCT\\"], + ["@@\\[§t|¤_"], + ["@@m`n_"], + ["@@Ïxnj{q_×^Giip"], + [ + "@@@é^BntaÊU]x ¯ÄPIJ°hʙK³VÕ@Y~|EvĹsǦL^pòŸÒG Ël]xxÄ_fT¤Ď¤cPC¨¸TVjbgH²sdÎdHt`B²¬GJję¶[ÐhjeXdlwhðSȦªVÊÏÆZÆŶ®²^ÎyÅÎcPqńĚDMħĜŁHkçvV[ij¼WYÀäĦ`XlR`ôLUVfK¢{NZdĒªYĸÌÚJRr¸SA|ƴgŴĴÆbvªØX~źB|¦ÕE¤Ð`\\|KUnnI]¤ÀÂĊnŎR®Ő¿¶\\ÀøíDm¦ÎbŨabaĘ\\ľã¸atÎSƐ´©v\\ÖÚÌǴ¤Â¨JKrZ_ZfjþhPkx`YRIjJcVf~sCN¤ EhæmsHy¨SðÑÌ\\\\ĐRZk°IS§fqŒßýáĞÙÉÖ[^¯ǤŲê´\\¦¬ĆPM¯£»uïpùzExanµyoluqe¦W^£ÊL}ñrkqWňûPUP¡ôJoo·U}£[·¨@XĸDXmÛݺGUCÁª½{íĂ^cjk¶Ã[q¤LÉö³cux«zZf²BWÇ®Yß½ve±ÃCý£W{Ú^q^sÑ·¨ÍOt¹·C¥GDrí@wÕKţëV·i}xËÍ÷i©ĝɝǡ]{c±OW³Ya±_ç©HĕoƫŇqr³Lys[ñ³¯OSďOMisZ±ÅFC¥Pq{Ã[Pg}\\¿ghćO k^ģÁFıĉĥMoEqqZûěʼn³F¦oĵhÕP{¯~TÍlªNßYÐ{Ps{ÃVUeĎwk±ʼnVÓ½ŽJãÇÇ»Jm°dhcÀffdF~ĀeĖd`sx² ®EżĀdQÂd^~ăÔH¦\\LKpĄVez¤NP ǹÓRÆąJSha[¦´ÂghwmBШźhI|VV|p] ¼èNä¶ÜBÖ¼L`¼bØæKVpoúNZÞÒKxpw|ÊEMnzEQIZZNBčÚFÜçmĩWĪñtÞĵÇñZ«uD±|Əlij¥ãn·±PmÍada CLǑkùó¡³Ï«QaċÏOÃ¥ÕđQȥċƭy³ÃA" + ] + ], + "encodeOffsets": [ + [[123686, 41445]], + [[126019, 40435]], + [[124393, 40128]], + [[126117, 39963]], + [[125322, 40140]], + [[126686, 40700]], + [[126041, 40374]], + [[125584, 40168]], + [[125453, 40165]], + [[125362, 40214]], + [[125280, 40291]], + [[125774, 39997]], + [[125976, 40496]], + [[125822, 39993]], + [[125509, 40217]], + [[122731, 40949]] + ] + } + }, + { + "type": "Feature", + "id": "220000", + "properties": { "id": "220000", "cp": [125.3245, 43.886841], "name": "吉林", "childNum": 1 }, + "geometry": { + "type": "Polygon", + "coordinates": [ + "@@pä³PClFbbÍzwBGĭZÅi»lYċ²SgkÇ£^Sqd¯R ©é£¯S\\cZ¹iűƏCuƍÓXoR}M^o£ R}oªUF uuXHlEÅÏ©¤ÛmTþ¤D²ÄufàÀXXȱAeyYw¬dvõ´KÊ£\\rµÄlidā]|DÂVH¹Þ®ÜWnCķ W§@\\¸~¤Vp¸póIO¢VOŇürXql~òÉK]¤¥Xrfkvzpm¶bwyFoúv𼤠N°ąO¥«³[éǡű_°Õ\\ÚÊĝþâőàerR¨JYlďQ[ ÏYëЧTGztnß¡gFkMāGÁ¤ia Éȹ`\\xs¬dĆkNnuNUuP@vRY¾\\¢ GªóĄ~RãÖÎĢùđŴÕhQxtcæëSɽʼníëlj£ƍG£nj°KƘµDsØÑpyƸ®¿bXp]vbÍZuĂ{n^IüÀSÖ¦EvRÎûh@â[ƏÈô~FNr¯ôçR±HÑlĢ^¤¢OðævxsŒ]ÞÁTĠs¶¿âÆGW¾ìA¦·TѬè¥ÏÐJ¨¼ÒÖ¼ƦɄxÊ~StD@Ă¼Ŵ¡jlºWvÐzƦZвCH AxiukdGgetqmcÛ£Ozy¥cE}| ¾cZ k¿uŐã[oxGikfeäT@ SUwpiÚFM©£è^Ú`@v¶eňf heP¶täOlÃUgÞzŸU`l}ÔÆUvØ_Ō¬Öi^ĉi§²ÃB~¡ĈÚEgc|DC_Ȧm²rBx¼MÔ¦ŮdĨÃâYxƘDVÇĺĿg¿cwÅ\\¹¥Yĭl¤OvLjM_a W`zļMž·\\swqÝSAqŚij¯°kRē°wx^ĐkǂÒ\\]nrĂ}²ĊŲÒøãh·M{yMzysěnĒġV·°G³¼XÀ¤¹i´o¤ŃÈ`ÌDzÄUĞd\\iÖmÈBĤÜɲDEh LG¾ƀľ{WaYÍÈĢĘÔRîĐj}ÇccjoUb½{h§Ǿ{KƖµÎ÷GĀÖŠåưÎslyiē«`å§H¥Ae^§GK}iã\\c]v©ģZmÃ|[M}ģTɟĵÂÂ`ÀçmFK¥ÚíÁbX³ÌQÒHof{]ept·GŋĜYünĎųVY^ydõkÅZW«WUa~U·SbwGçǑiW^qFuNĝ·EwUtW·Ýďæ©PuqEzwAVXRãQ`©GMehccďÏd©ÑW_ÏYƅ» é\\ɹ~ǙG³mØ©BšuT§Ĥ½¢Ã_ýL¡ýqT^rme\\PpZZbyuybQefµ]UhĿDCmûvaÙNSkCwncćfv~ YÇG" + ], + "encodeOffsets": [[130196, 42528]] + } + }, + { + "type": "Feature", + "id": "230000", + "properties": { + "id": "230000", + "cp": [128.642464, 46.756967], + "name": "黑龙江", + "childNum": 2 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + "@@UµNÿ¥īèçHÍøƕ¶Lǽ|g¨|a¾pVidd~ÈiíďÓQġėÇZÎXb½|ſÃH½KFgɱCģÛÇAnjÕc[VĝDZÃËÇ_ £ń³pj£º¿»WH´¯U¸đĢmtĜyzzNN|g¸÷äűѱĉā~mq^[ǁÑďlw]¯xQĔ¯l°řĴrBÞTxr[tޏĻN_yX`biNKu P£kZĮ¦[ºxÆÀdhĹŀUÈƗCwáZħÄŭcÓ¥»NAw±qȥnD`{ChdÙFć}¢A±Äj¨]ĊÕjŋ«×`VuÓÅ~_kŷVÝyhVkÄãPsOµfgeŇ µf@u_Ù ÙcªNªÙEojVxT@ãSefjlwH\\pŏäÀvlY½d{F~¦dyz¤PÜndsrhfHcvlwjF£G±DÏƥYyÏu¹XikĿ¦ÏqƗǀOŜ¨LI|FRĂn sª|C˜zxAè¥bfudTrFWÁ¹Am|ĔĕsķÆF´N}ć UÕ@Áijſmuçuð^ÊýowFzØÎĕNőǏȎôªÌŒDŽàĀÄ˄ĞŀƒʀĀƘŸˮȬƬĊ°Uzouxe]} AyÈW¯ÌmKQ]Īºif¸ÄX|sZt|½ÚUÎ lk^p{f¤lºlÆW A²PVÜPHÊâ]ÎĈÌÜk´\\@qàsĔÄQºpRij¼èi`¶bXrBgxfv»uUi^v~J¬mVp´£´VWrnP½ì¢BX¬hðX¹^TjVriªjtŊÄmtPGx¸bgRsT`ZozÆO]ÒFôÒOÆŊvÅpcGêsx´DR{AEOr°x|íb³Wm~DVjºéNNËܲɶGxŷCSt}]ûōSmtuÇÃĕNāg»íT«u}ç½BĵÞʣ¥ëÊ¡MÛ³ãȅ¡ƋaǩÈÉQG¢·lG|tvgrrf«ptęŘnÅĢrI²¯LiØsPf_vĠdxM prʹL¤¤eËÀđKïÙVY§]Ióáĥ]ķK¥j|pŇ\\kzţ¦šnņäÔVĂîά|vW®l¤èØrxm¶ă~lÄƯĄ̈́öȄEÔ¤ØQĄĄ»ƢjȦOǺ¨ìSŖÆƬyQv`cwZSÌ®ü±DŽ]ŀç¬B¬©ńzƺŷɄeeOĨSfm ĊƀP̎ēz©ĊÄÕÊmgÇsJ¥ƔŊśæÎÑqv¿íUOµªÂnĦÁ_½ä@êí £P}Ġ[@gġ}gɊ×ûÏWXá¢užƻÌsNͽƎÁ§čŐAēeL³àydl¦ĘVçŁpśdžĽĺſÊQíÜçÛġÔsĕ¬Ǹ¯YßċġHµ ¡eå`ļrĉŘóƢFìĎWøxÊkƈdƬv|I|·©NqńRŀ¤éeŊŀàŀU²ŕƀBQ£Ď}L¹Îk@©ĈuǰųǨÚ§ƈnTËÇéƟÊcfčŤ^XmHĊĕË«W·ċëx³ǔķÐċJāwİ_ĸȀ^ôWr°oú¬Ħ ŨK~ȰCĐ´Ƕ£fNÎèâw¢XnŮeÂÆĶ¾¾xäLĴĘlļO¤ÒĨA¢Êɚ¨®ØCÔ ŬGƠƦYĜĘÜƬDJg_ͥœ@čŅĻA¶¯@wÎqC½Ĉ»NăëKďÍQÙƫ[«ÃígßÔÇOÝáWñuZ¯ĥŕā¡ÑķJu¤E 寰WKɱ_d_}}vyõu¬ï¹ÓU±½@gÏ¿rýDg Cdµ°MFYxw¿CG£Rƛ½Õ{]L§{qqą¿BÇƻğëܭNJË|c²}Fµ}ÙRsÓpg±QNqǫŋRwŕnéÑÉK«SeYR ŋ@{¤SJ}D Ûǖ֍]gr¡µŷjqWÛham³~S«Þ]" + ] + ], + "encodeOffsets": [[[134456, 44547]]] + } + }, + { + "type": "Feature", + "id": "320000", + "properties": { + "id": "320000", + "cp": [119.767413, 33.041544], + "name": "江苏", + "childNum": 1 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + "@@cþÅPi`ZRu¥É\\]~°Y`µÓ^phÁbnÀşúòaĬºTÖŒbe¦¦{¸ZâćNp©Hr|^mjhSEb\\afv`sz^lkljÄtg¤D¾X¿À|ĐiZȀåB·î}GL¢õcßjayBFµÏC^ĭcÙt¿sğH]j{s©HM¢QnDÀ©DaÜÞ·jgàiDbPufjDk`dPOîhw¡ĥ¥GP²ĐobºrYî¶aHŢ´ ]´rılw³r_{£DB_Ûdåuk|Ũ¯F Cºyr{XFye³Þċ¿ÂkĭB¿MvÛpm`rÚã@ƹhågËÖƿxnlč¶Åì½Ot¾dJlVJĂǀŞqvnO^JZż·Q}êÍÅmµÒ]ƍ¦Dq}¬R^èĂ´ŀĻĊIÔtIJyQŐĠMNtR®òLhĚs©»}OÓGZz¶A\\jĨFäOĤHYJvÞHNiÜaĎÉnFQlNM¤B´ĄNöɂtpŬdfå qm¿QûùŞÚb¤uŃJŴu»¹ĄlȖħŴw̌ŵ²ǹǠ͛hĭłƕrçü±Yxcitğ®jű¢KOķCoy`å®VTa_Ā]ŐÝɞï²ʯÊ^]afYǸÃĆēĪȣJđ͍ôƋÄÄÍīçÛɈǥ£ÛmY`ó£Z«§°Ó³QafusNıDž_k}¢m[ÝóDµ¡RLčiXyÅNïă¡¸iĔÏNÌŕoēdōîåŤûHcs}~Ûwbù¹£¦ÓCtOPrE^ÒogĉIµÛÅʹK ¤½phMü`oæŀ" + ], + "encodeOffsets": [[121740, 32276]] + } + }, + { + "type": "Feature", + "id": "330000", + "properties": { + "id": "330000", + "cp": [120.153576, 29.287459], + "name": "浙江", + "childNum": 45 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@E^dQ]K"], + ["@@jX^j"], + ["@@sfbU"], + ["@@qP\\xz[ck"], + ["@@R¢FX}°[s_"], + ["@@Cb\\}"], + ["@@e|v\\la{u"], + ["@@v~u}"], + ["@@QxÂF¯}"], + ["@@¹nvÞs¯o"], + ["@@rSkUEj"], + ["@@biZP"], + ["@@p[}INf"], + ["@@À¿"], + ["@@¹dnb "], + ["@@rSBnR"], + ["@@g~h}"], + ["@@FlEk"], + ["@@OdPc"], + ["@@v[u\\"], + ["@@FjâL~wyoo~sµL\\"], + ["@@¬e¹aN"], + ["@@\\nÔ¡q]L³ë\\ÿ®QÖ"], + ["@@ÊA©[¬"], + ["@@Kxv"], + ["@@@hlIk]"], + ["@@pW{o||j"], + ["@@Md|_mC"], + ["@@¢ X£ÏylD¼XtH"], + ["@@hlÜ[LykAvyfw^E¤"], + ["@@fp¤MusR"], + ["@@®_ma~LÁ¬Z"], + ["@@iMxZ"], + ["@@ZcYd"], + ["@@Z~dOSo|A¿qZv"], + ["@@@`EN¡v"], + ["@@|TY{"], + ["@@@n@m"], + ["@@XWkCT\\"], + ["@@ºwZRkĕWO¢"], + ["@@X®±Grƪ\\ÔáXq{"], + ["@@ůTG°ĄLHm°UC"], + [ + "@@¤aÜx~}dtüGæţŎíĔcŖpMËÐj碷ðĄÆMzjWKĎ¢Q¶À_ê_Bıi«pZgf¤Nrq]§ĂN®«H±yƳí¾×ŸīàLłčŴǝĂíÀBŖÕªÁŖHŗʼnåqûõi¨hÜ·ñt»¹ýv_[«¸mYL¯Qª mĉÅdMgÇjcº«ę¬K´B«Âącoċ\\xKd¡gěŧ«®á[~ıxu·ÅKsËÉc¢Ù\\ĭƛëbf¹ģSĜkáƉÔĈZB{aMµfzʼnfåÂŧįƋǝÊĕġć£g³neą»@¦S®\\ßðChiqªĭiAuAµ_W¥ƣO\\lċĢttC¨£t`PZäuXßBsĻyekOđġĵHuXBµ]×\\°®¬F¢¾pµ¼kŘó¬Wät¸|@L¨¸µrºù³Ù~§WIZW®±Ð¨ÒÉx`²pĜrOògtÁZ}þÙ]¡FKwsPlU[}¦Rvn`hq¬\\nQ´ĘRWb_ rtČFIÖkĦPJ¶ÖÀÖJĈĄTĚòC ²@Pú Øz©PCÈÚDZhŖl¬â~nm¨f©iļ«mntuÖZÜÄjL®EÌFª²iÊxبIÈhhst" + ], + ["@@o\\VzRZ}y"], + ["@@@°¡mÛGĕ¨§Ianá[ýƤjfæØLäGr"] + ], + "encodeOffsets": [ + [[125592, 31553]], + [[125785, 31436]], + [[125729, 31431]], + [[125513, 31380]], + [[125223, 30438]], + [[125115, 30114]], + [[124815, 29155]], + [[124419, 28746]], + [[124095, 28635]], + [[124005, 28609]], + [[125000, 30713]], + [[125111, 30698]], + [[125078, 30682]], + [[125150, 30684]], + [[124014, 28103]], + [[125008, 31331]], + [[125411, 31468]], + [[125329, 31479]], + [[125626, 30916]], + [[125417, 30956]], + [[125254, 30976]], + [[125199, 30997]], + [[125095, 31058]], + [[125083, 30915]], + [[124885, 31015]], + [[125218, 30798]], + [[124867, 30838]], + [[124755, 30788]], + [[124802, 30809]], + [[125267, 30657]], + [[125218, 30578]], + [[125200, 30562]], + [[124968, 30474]], + [[125167, 30396]], + [[124955, 29879]], + [[124714, 29781]], + [[124762, 29462]], + [[124325, 28754]], + [[123990, 28459]], + [[125366, 31477]], + [[125115, 30363]], + [[125369, 31139]], + [[122495, 31878]], + [[125329, 30690]], + [[125192, 30787]] + ] + } + }, + { + "type": "Feature", + "id": "340000", + "properties": { "id": "340000", "cp": [117.283042, 31.26119], "name": "安徽", "childNum": 3 }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@^iuLX^"], + ["@@e©Ehl"], + [ + "@@°ZÆëϵmkǀwÌÕæhºgBĝâqÙĊzÖgņtÀÁĂÆáhEz|WzqD¹°Eŧl{ævÜcA`¤C`|´qxIJkq^³³GšµbíZ ¹qpa±ď OH¦Ħx¢gPícOl_iCveaOjCh߸iÝbÛªCC¿mRV§¢A|t^iĠGÀtÚsd]ĮÐDE¶zAb àiödK¡~H¸íæAǿYj{ď¿À½W®£ChÃsikkly]_teu[bFaTign{]GqªoĈMYá|·¥f¥őaSÕėNµñĞ«Im_m¿Âa]uĜp Z_§{Cäg¤°r[_YjÆOdý[I[á·¥Q_nùgL¾mvˊBÜÆ¶ĊJhpc¹O]iŠ]¥ jtsggJǧw×jÉ©±EFËKiÛÃÕYv sm¬njĻª§emná}k«ŕgđ²ÙDÇ¤í¡ªOy×Où±@DñSęćăÕIÕ¿IµĥOjNÕËT¡¿tNæŇàåyķrĕq§ÄĩsWÆßF¶X®¿mw RIÞfßoG³¾©uyHį{Ɓħ¯AFnuP ÍÔzVdàôº^Ðæd´oG¤{S¬ćxã}ŧ×Kǥĩ«ÕOEзÖdÖsƘѨ[Û^Xr¢¼§xvÄÆµ`K§ tÒ´Cvlo¸fzŨð¾NY´ı~ÉĔē ßúLÃÃ_ÈÏ|]ÂÏFlg`ben¾¢pUh~ƴ˶_r sĄ~cƈ]|r c~`¼{À{ȒiJjz`îÀT¥Û³ ]u}f ïQl{skloNdjäËzDvčoQďHI¦rbtHĔ~BmlRV_ħTLnñH±DL¼Lªl§Ťa¸ĚlK²\\RòvDcÎJbt[¤D@®hh~kt°ǾzÖ@¾ªdbYhüóZ ň¶vHrľ\\ÊJuxAT|dmÀO[ÃÔG·ĚąĐlŪÚpSJ¨ĸLvÞcPæķŨ®mÐálwKhïgA¢ųƩޤOÈm°K´" + ] + ], + "encodeOffsets": [[[121722, 32278]], [[119475, 30423]], [[119168, 35472]]] + } + }, + { + "type": "Feature", + "id": "350000", + "properties": { + "id": "350000", + "cp": [118.306239, 26.075302], + "name": "福建", + "childNum": 18 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@zht´]"], + ["@@aj^~ĆG©O"], + ["@@ed¨C}}i"], + ["@@@vPGsQ"], + ["@@sBzddW]Q"], + ["@@S¨Q{"], + ["@@NVucW"], + ["@@qptBAq"], + ["@@¸[mu"], + ["@@Q\\pD]_"], + ["@@jSwUadpF"], + ["@@eXª~"], + ["@@AjvFso"], + ["@@fT_Çí\\v|ba¦jZÆy°"], + ["@@IjJi"], + ["@@wJIx«¼AoNe{M"], + ["@@K±¡ÓČäeZ"], + [ + "@@k¡¹Eh~c®wBkUplÀ¡I~Māe£bN¨gZý¡a±Öcp©PhI¢Qq ÇGj|¥U g[Ky¬ŏv@OptÉEF\\@ åA¬V{XģĐBy cpě ¼³Ăp·¤¥ohqqÚ¡ŅLs^á§qlÀhH¨MCe»åÇGD¥zPO£čÙkJA¼ßėuĕeûÒiÁŧSW¥Qûŗ½ùěcݧSùĩąSWó«íęACµeRåǃRCÒÇZÍ¢ź±^dlstjD¸ZpuÔâÃH¾oLUêÃÔjjēò´ĄWƛ ^Ñ¥Ħ@ÇòmOw¡õyJyD}¢ďÑÈġfZda©º²z£NjD°Ötj¶¬ZSÎ~¾c°¶ÐmxO¸¢Pl´SL|¥AȪĖMņIJg®áIJČĒü` QF¬h|ĂJ@zµ |ê³È ¸UÖŬŬÀEttĸr]ðM¤ĶIJHtÏ AĬkvsq^aÎbvdfÊòSD´Z^xPsĂrvƞŀjJd×ŘÉ ®AΦĤdxĆqAZRÀMźnĊ»İÐZ YXæJyĊ²·¶q§·K@·{sXãô«lŗ¶»o½E¡«¢±¨Y®Ø¶^AvWĶGĒĢPlzfļtàAvWYãO_¤sD§ssČġ[kƤPX¦`¶®BBvĪjv©jx[L¥àï[F ¼ÍË»ğV`«Ip}ccÅĥZEãoP ´B@D¸m±z«Ƴ¿å³BRضWlâþäą`]Z£Tc ĹGµ¶Hm@_©k¾xĨôȉðX«½đCIbćqK³ÁÄš¬OAwã»aLʼnËĥW[ÂGIÂNxij¤D¢îĎÎB§°_JGs¥E@ ¤uć PåcuMuw¢BI¿]zG¹guĮck\\_" + ] + ], + "encodeOffsets": [ + [[123250, 27563]], + [[122541, 27268]], + [[123020, 27189]], + [[122916, 27125]], + [[122887, 26845]], + [[122808, 26762]], + [[122568, 25912]], + [[122778, 26197]], + [[122515, 26757]], + [[122816, 26587]], + [[123388, 27005]], + [[122450, 26243]], + [[122578, 25962]], + [[121255, 25103]], + [[120987, 24903]], + [[122339, 25802]], + [[121042, 25093]], + [[122439, 26024]] + ] + } + }, + { + "type": "Feature", + "id": "360000", + "properties": { + "id": "360000", + "cp": [115.592151, 27.676493], + "name": "江西", + "childNum": 1 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + "@@ĢĨƐgļ¼ÂMD~ņªe^\\^§ý©j×cZبzdÒa¶lÒJìõ`oz÷@¤u޸´ôęöY¼HČƶajlÞƩ¥éZ[|h}^U ¥pĄžƦO lt¸Æ Q\\aÆ|CnÂOjtĚĤdÈF`¶@Ðë ¦ōÒ¨SêvHĢûXD® QgÄWiØPÞìºr¤džNĠ¢lĄtZoCƞÔºCxrpĠV®Ê{f_Y`_eq®Aot`@oDXfkp¨|s¬\\DÄSfè©Hn¬ ^DhÆyøJhØxĢĀLÊƠPżċĄwȠ̦G®ǒĤäTŠÆ~Ħw«|TF¡nc³Ïå¹]ĉđxe{ÎÓvOEm°BƂĨİ|Gvz½ª´HàpeJÝQxnÀWEµàXÅĪt¨ÃĖrÄwÀFÎ|ňÓMå¼ibµ¯»åDT±m[r«_gmQu~¥V\\OkxtL E¢Ú^~ýêPóqoě±_Êw§ÑªåƗā¼mĉŹ¿NQ YBąrwģcÍ¥BŗÊcØiIƝĿuqtāwO]³YCñTeÉcaubÍ]trluī BÐGsĵıN£ï^ķqss¿FūūVÕ·´Ç{éĈýÿOER_đûIċâJhŅıNȩĕB ¦K{Tk³¡OP·wnµÏd¯}½TÍ«YiµÕsC¯iM¤¦¯P|ÿUHvhe¥oFTuõ\\OSsMòđƇiaºćXĊĵà·çhƃ÷Ç{ígu^đgm[×zkKN¶Õ»lčÓ{XSÆv©_ÈëJbVkĔVÀ¤P¾ºÈMÖxlò~ªÚàGĂ¢B±ÌKyáV¼Ã~ `gsÙfIƋlę¹e|~udjuTlXµf`¿Jd[\\L²" + ], + "encodeOffsets": [[116689, 26234]] + } + }, + { + "type": "Feature", + "id": "370000", + "properties": { + "id": "370000", + "cp": [118.000923, 36.275807], + "name": "山东", + "childNum": 13 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@Xjd]{K"], + ["@@itbFHy"], + ["@@HlGk"], + ["@@TGy"], + ["@@K¬U"], + ["@@WdXc"], + ["@@PtOs"], + ["@@LnXhc"], + ["@@ppVu]Or"], + ["@@cdzAUa"], + ["@@udRhnCI"], + ["@@oIpR"], + [ + "@@Ľč{fzƤîKÎMĮ]ZF½Y]â£ph¶¨râøÀÎǨ¤^ºÄGz~grĚĜlĞÆLĆdž¢Îo¦cvKbgr°WhmZp L]LºcUÆnżĤÌĒbAnrOA´ȊcÀbƦUØrĆUÜøĬƞEzVL®öØBkŖÝĐ˹ŧ̄±ÀbÎÉnb²ĦhņBĖįĦåXćì@L¯´ywƕCéõė ƿ¸lµ¾Z|ZWyFY¨Mf~C¿`à_RÇzwƌfQnny´INoƬèôº|sTJULîVjǎ¾ĒØDz²XPn±ŴPè¸ŔLƔÜƺ_TüÃĤBBċÈöA´faM¨{«M`¶d¡ôÖ°mȰBÔjj´PM|c^d¤u¤Û´ä«ƢfPk¶Môl]Lb}su^ke{lC MrDÇ]NÑFsmoõľHyGă{{çrnÓEƕZGª¹Fj¢ïW uøCǷë¡ąuhÛ¡^KxC`C\\bÅxì²ĝÝ¿_NīCȽĿåB¥¢·IŖÕy\\¹kxãČ×GDyäÁçFQ¡KtŵƋ]CgÏAùSedcÚźuYfyMmhUWpSyGwMPqŀÁ¼zK¶GY§Ë@´śÇµƕBm@IogZ¯uTMx}CVKï{éƵP_K«pÛÙqċtkkù]gTğwoɁsMõ³ăAN£MRkmEÊčÛbMjÝGu IZGPģãħE[iµBEuDPÔ~ª¼ęt]ûG§¡QMsğNPŏįzs£Ug{đJĿļā³]ç«Qr~¥CƎÑ^n¶ÆéÎR~ݏYI] PumŝrƿIā[xedzL¯v¯s¬ÁY ~} ťuŁgƋpÝĄ_ņī¶ÏSR´ÁP~¿Cyċßdwk´SsX|t`Ä ÈðAªìÎT°¦Dda^lĎDĶÚY°`ĪŴǒàŠv\\ebZHŖR¬ŢƱùęOÑM³FÛWp[" + ] + ], + "encodeOffsets": [ + [[123806, 39303]], + [[123821, 39266]], + [[123742, 39256]], + [[123702, 39203]], + [[123649, 39066]], + [[123847, 38933]], + [[123580, 38839]], + [[123894, 37288]], + [[123043, 36624]], + [[123344, 38676]], + [[123522, 38857]], + [[123628, 38858]], + [[118260, 36742]] + ] + } + }, + { + "type": "Feature", + "id": "410000", + "properties": { + "id": "410000", + "cp": [113.665412, 33.757975], + "name": "河南", + "childNum": 1 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + "@@ýLùµP³swIÓxcŢĞð´E®ÚPtĴXØx¶@«ŕŕQGYfa[şußǩđš_X³ijÕčC]kbc¥CS¯ëÍB©÷³Si_}mYTt³xlàcČzÀD}ÂOQ³ÐTĨ¯ƗòËŖ[hłŦv~}ÂZ«¤lPÇ£ªÝŴÅR§ØnhctâknÏľŹUÓÝdKuķI§oTũÙďkęĆH¸Ó\\Ä¿PcnS{wBIvÉĽ[GqµuŇôYgûZca©@½Õǽys¯}lgg@C\\£asIdÍuCQñ[L±ęk·ţb¨©kK»KC²òGKmĨS`UQnk}AGēsqaJ¥ĐGRĎpCuÌy ã iMcplk|tRkðev~^´¦ÜSí¿_iyjI|ȑ|¿_»d}q^{Ƈdă}tqµ`Ƴĕg}V¡om½faÇo³TTj¥tĠRyK{ùÓjuµ{t}uËRivGçJFjµÍyqÎàQÂFewixGw½Yŷpµú³XU½ġyłåkÚwZX·l¢Á¢KzOÎÎjc¼htoDHr |J½}JZ_¯iPq{tę½ĕ¦Zpĵø«kQ Ť]MÛfaQpě±ǽ¾]uFu÷nčįADp}AjmcEÇaª³o³ÆÍSƇĈÙDIzËčľ^KLiÞñ[aA²zzÌ÷D|[íijgfÕÞd®|`Ć~oĠƑô³ŊD×°¯CsøÀ«ìUMhTº¨¸ǡîSÔDruÂÇZÖEvPZW~ØÐtĄE¢¦Ðy¸bô´oŬ¬²Ês~]®tªapŎJ¨Öº_Ŕ`Ŗ^Đ\\Ĝu~m²Ƹ¸fWĦrƔ}Î^gjdfÔ¡J}\\n C¦þWxªJRÔŠu¬ĨĨmFdM{\\d\\YÊ¢ú@@¦ª²SÜsC}fNècbpRmlØ^gd¢aÒ¢CZZxvƶN¿¢T@uC¬^ĊðÄn|lGlRjsp¢ED}Fio~ÔN~zkĘHVsDzßjŬŢ`Pûàl¢\\ÀEhİgÞē X¼Pk|m" + ], + "encodeOffsets": [[118256, 37017]] + } + }, + { + "type": "Feature", + "id": "420000", + "properties": { + "id": "420000", + "cp": [113.298572, 30.684355], + "name": "湖北", + "childNum": 3 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@AB"], + ["@@lskt"], + [ + "@@¾«}{ra®pîÃ\\{øCËyyB±b\\òÝjKL ]ĎĽÌJyÚCƈćÎT´Å´pb©ÈdFin~BCo°BĎÃømv®E^vǾ½Ĝ²RobÜeN^ĺ£R¬lĶ÷YoĖ¥Ě¾|sOr°jY`~I¾®I{GqpCgyl{£ÍÍyPL¡¡¸kWxYlÙæŁĢz¾V´W¶ùŸo¾ZHxjwfxGNÁ³Xéæl¶EièIH ujÌQ~v|sv¶Ôi|ú¢FhQsğ¦SiŠBgÐE^ÁÐ{čnOÂÈUÎóĔÊēIJ}Z³½Mŧïeyp·uk³DsѨL¶_Åuèw»¡WqÜ]\\Ò§tƗcÕ¸ÕFÏǝĉăxŻČƟOKÉġÿ×wg÷IÅzCg]m«ªGeçÃTC«[t§{loWeC@ps_Bprf_``Z|ei¡oċMqow¹DƝÓDYpûsYkıǃ}s¥ç³[§cY§HK«Qy]¢wwö¸ïx¼ņ¾Xv®ÇÀµRĠÐHM±cÏdƒǍũȅȷ±DSyúĝ£ŤĀàtÖÿï[îb\\}pĭÉI±Ñy ¿³x¯No|¹HÏÛmjúË~TuęjCöAwě¬Rđl¯ ÑbŇTĿ_[IčĄʿnM¦ğ\\É[T·k¹©oĕ@A¾wya¥Y\\¥Âaz¯ãÁ¡k¥ne£ÛwE©Êō¶˓uoj_U¡cF¹[WvP©whuÕyBF`RqJUw\\i¡{jEPïÿ½fć QÑÀQ{°fLÔ~wXgītêݾĺHd³fJd]HJ² EoU¥HhwQsƐ»Xmg±çve]DmÍPoCc¾_hhøYrŊU¶eD°Č_N~øĹĚ·`z]Äþp¼ äÌQv\\rCé¾TnkžŐÚÜa¼ÝƆ̶Ûo d ĔňТJqPb ¾|J¾fXƐîĨ_Z¯À}úƲN_ĒÄ^ĈaŐyp»CÇÄKñL³ġM²wrIÒŭxjb[n«øæà ^²h¯ÚŐªÞ¸Y²ĒVø}Ā^İ´LÚm¥ÀJÞ{JVųÞŃx×sxxƈē ģMřÚðòIfĊŒ\\Ʈ±ŒdʧĘDvČ_Àæ~Dċ´A®µ¨ØLV¦êHÒ¤" + ] + ], + "encodeOffsets": [[[113712, 34000]], [[115612, 30507]], [[113649, 34054]]] + } + }, + { + "type": "Feature", + "id": "430000", + "properties": { "id": "430000", "cp": [111.782279, 28.09409], "name": "湖南", "childNum": 3 }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@nFTs"], + ["@@ßÅÆá½ÔXrCO ËRïÿĩTooQyÓ[ŅBE¬ÎÓXaį§Ã¸G °ITxpúxÚij¥Ï̾edÄ©ĸG àGhM¤Â_U}Ċ}¢pczfþg¤ÇòAVM"], + [ + "@@©KA·³CQ±Á«³BUƑ¹AtćOwD]JiØSm¯b£ylX HËѱH«C^õľAŧ¤É¥ïyuǙuA¢^{ÌC´¦ŷJ£^[ª¿ĕ~Ƈ N skóā¹¿ï]ă~÷O§@Vm¡Qđ¦¢Ĥ{ºjÔª¥nf´~Õo×ÛąMąıuZmZcÒ IJβSÊDŽŶ¨ƚCÖŎªQؼrŭ«}NÏürʬmjr@ĘrTW SsdHzƓ^ÇÂyUi¯DÅYlŹu{hT}mĉ¹¥ěDÿë©ıÓ[Oº£¥ótł¹MÕƪ`P DiÛU¾ÅâìUñBÈ£ýhedy¡oċ`pfmjP~kZa ZsÐd°wj§@Ĵ®w~^kÀÅKvNmX\\¨aŃqvíó¿F¤¡@ũÑVw}S@j}¾«pĂrªg àÀ²NJ¶¶Dô K|^ª°LX¾ŴäPα£EXd^¶IJÞÜ~u¸ǔMRhsR e`ÄofIÔ\\Ø ićymnú¨cj ¢»GČìƊÿШXeĈ¾Oð Fi ¢|[jVxrIQ_EzAN¦zLU`cªxOTu RLÄ¢dVi`p˔vŎµªÉF~Ød¢ºgİàw¸Áb[¦Zb¦z½xBĖ@ªpºlS¸Ö\\Ĕ[N¥ˀmĎăJ\\ŀ` ňSÚĖÁĐiOĜ«BxDõĚivSÌ}iùÜnкG{p°M´wÀÒzJ²ò¨ oTçüöoÛÿñőФùTz²CȆȸǎŪƑÐc°dPÎğ˶[Ƚu¯½WM¡ÉB·rínZÒ `¨GA¾\\pēXhÃRCüWGġu Té§ŎÑ©ò³I±³}_EÃħg®ęisÁPDmÅ{b[RÅs·kPŽƥóRoOV~]{g\\êYƪ¦kÝbiċƵGZ»Ěõ ó·³vŝ£ø@pyö_ëIkѵbcѧy ×dYتiþ¨[]f]Ņ©C}ÁN»hĻħƏĩ" + ] + ], + "encodeOffsets": [[[115640, 30489]], [[112543, 27312]], [[116690, 26230]]] + } + }, + { + "type": "Feature", + "id": "440000", + "properties": { + "id": "440000", + "cp": [113.280637, 23.125178], + "name": "广东", + "childNum": 24 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@QdAua"], + ["@@lxDLo"], + ["@@sbhNLo"], + ["@@Ă ā"], + ["@@WltO[["], + ["@@Kr]S"], + ["@@eI]y"], + ["@@I|Mym"], + ["@@Û³LS¼Y"], + ["@@nvºBëui©`¾"], + ["@@zdÛJw®"], + ["@@° ¯"], + ["@@a yAª¸ËJIxØ@ĀHAmÃV¡ofuo"], + ["@@sŗÃÔėAƁZÄ ~°ČPäh"], + ["@@¶ÝÌvmĞhıQ"], + ["@@HdSjĒ¢D}war u«ZqadYM"], + ["@@el\\LqqU"], + ["@@~rMo\\"], + ["@@f^C"], + ["@@øPªoj÷ÍÝħXČx°Q¨ıXNv"], + ["@@gÇƳo[~tly"], + ["@@EÆC¿"], + ["@@OP"], + [ + "@@wđógĝ[³¡VÙæÅöM̳¹pÁaËýý©D©ÜJŹƕģGą¤{Ùū ÇO²«BƱéAÒĥ¡«BhlmtÃPµyU¯ucd·w_bŝcīímGO|KPȏŹãŝIŕŭŕ@Óoo¿ē±ß} ŭIJWÈCőâUâǙIğʼn©IijE× Á³AówXJþ±ÌÜÓĨ£L]ĈÙƺZǾĆĖMĸĤfÎĵlŨnÈĐtFFĤêk¶^k°f¶g}®Faf`vXŲxl¦ÔÁ²¬Ð¦pqÊ̲iXØRDÎ}Ä@ZĠsx®AR~®ETtĄZƈfŠŠHâÒÐAµ\\S¸^wĖkRzalŜ|E¨ÈNĀňZTpBh£\\ĎƀuXĖtKL¶G|»ĺEļĞ~ÜĢÛĊrOÙîvd]n¬VÊĜ°RÖpMƂªFbwEÀ©\\ ¤]ŸI®¥D³|Ë]CöAŤ¦ æ´¥¸Lv¼¢ĽBaôF~®²GÌÒEYzk¤°ahlVÕI^CxĈPsBƒºV¸@¾ªR²ĨN]´_eavSivc}p}Đ¼ƌkJÚe th_¸ ºx±ò_xN˲@ă¡ßH©Ùñ}wkNÕ¹ÇO½¿£ĕ]ly_WìIǪ`uTÅxYĒÖ¼kÖµMjJÚwn\\hĒv]îh|ÈƄøèg¸Ķß ĉĈWb¹ƀdéĘNTtP[öSvrCZaGubo´ŖÒÇĐ~¡zCI özx¢PnÈñ @ĥÒ¦]ƞV}³ăĔñiiÄÓVépKG½ÄÓávYoC·sitiaÀyŧΡÈYDÑům}ý|m[węõĉZÅxUO}÷N¹³ĉo_qtăqwµŁYÙǝŕ¹tïÛUïmRCº ĭ|µÕÊK½Rē ó]GªęAx»HO£|ām¡diď×YïYWªʼnOeÚtĐ«zđ¹T āúEá²\\ķÍ}jYàÙÆſ¿Çdğ·ùTßÇţʄ¡XgWÀLJğ·¿ÃOj YÇ÷Qěi" + ] + ], + "encodeOffsets": [ + [[117381, 22988]], + [[116552, 22934]], + [[116790, 22617]], + [[116973, 22545]], + [[116444, 22536]], + [[116931, 22515]], + [[116496, 22490]], + [[116453, 22449]], + [[113301, 21439]], + [[118726, 21604]], + [[118709, 21486]], + [[113210, 20816]], + [[115482, 22082]], + [[113171, 21585]], + [[113199, 21590]], + [[115232, 22102]], + [[115739, 22373]], + [[115134, 22184]], + [[113056, 21175]], + [[119573, 21271]], + [[119957, 24020]], + [[115859, 22356]], + [[116561, 22649]], + [[116285, 22746]] + ] + } + }, + { + "type": "Feature", + "id": "450000", + "properties": { "id": "450000", "cp": [108.320004, 22.82402], "name": "广西", "childNum": 2 }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@H TQ§A"], + [ + "@@ĨʪLƊDÎĹĐCǦė¸zÚGn£¾rªŀÜt¬@ÖÚSx~øOŒŶÐÂæȠ\\ÈÜObĖw^oÞLf¬°bI lTØBÌF£Ć¹gñĤaYt¿¤VSñK¸¤nM¼JE±½¸ñoÜCƆæĪ^ĚQÖ¦^f´QüÜÊz¯lzUĺš@ìp¶n]sxtx¶@~ÒĂJb©gk{°~c°`Ô¬rV\\la¼¤ôá`¯¹LCÆbxEræOv[H[~|aB£ÖsºdAĐzNÂðsÞÆ Ĥªbab`ho¡³F«èVlo¤ÔRzpp®SĪº¨ÖºN ijd`a¦¤F³ºDÎńĀìCĜº¦Ċ~nS|gźvZkCÆj°zVÈÁƔ]LÊFZg čPkini«qÇczÍY®¬Ů»qR×ō©DÕ§ƙǃŵTÉĩ±ıdÑnYYIJvNĆĆØÜ Öp}e³¦m©iÓ|¹ħņ|ª¦QF¢Â¬ʖovg¿em^ucà÷gÕuíÙćĝ}FϼĹ{µHKsLSđƃrč¤[AgoSŇYMÿ§Ç{FśbkylQxĕ]T·¶[B ÑÏGáşşƇe ăYSsFQ}BwtYğÃ@~ CÍQ ×Wj˱rÉ¥oÏ ±«ÓÂ¥kwWűmcih³K~µh¯e]lµélEģEďsmÇŧē`ãògK_ÛsUʝćğ¶höO¤Ǜn³c`¡y¦CezYwa[ďĵűMę§]XÎ_íÛ]éÛUćİÕBƣ± dy¹T^dûÅÑŦ·PĻþÙ`K¦ ¢ÍeĥR¿³£[~äu¼dltW¸oRM¢ď\\z}Æzdvň{ÎXF¶°Â_ÒÂÏL©ÖTmu¼ãlīkiqéfA·Êµ\\őDc¥ÝFyÔćcűH_hLÜêĺШc}rn`½Ì@¸¶ªVLhŒ\\Ţĺk~Ġið°|gtTĭĸ^xvKVGréAébUuMJVÃO¡ qĂXËSģãlýà_juYÛÒBG^éÖ¶§EGÅzěƯ¤EkN[kdåucé¬dnYpAyČ{`]þ¯TbÜÈk¡ĠvàhÂƄ¢Jî¶²" + ] + ], + "encodeOffsets": [[[111707, 21520]], [[107619, 25527]]] + } + }, + { + "type": "Feature", + "id": "460000", + "properties": { "id": "460000", "cp": [109.83119, 19.031971], "name": "海南", "childNum": 1 }, + "geometry": { + "type": "Polygon", + "coordinates": [ + "@@¦Ŝil¢XƦƞòïè§ŞCêɕrŧůÇąĻõ·ĉ³œ̅kÇm@ċȧŧĥĽʉƅſȓÒ˦ŝE}ºƑ[ÍĜȋ gÎfǐÏĤ¨êƺ\\Ɔ¸ĠĎvʄȀоjNðĀÒRZdžzÐŘΰH¨Ƣb²_Ġ " + ], + "encodeOffsets": [[112750, 20508]] + } + }, + { + "type": "Feature", + "id": "510000", + "properties": { + "id": "510000", + "cp": [104.065735, 30.659462], + "name": "四川", + "childNum": 2 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@LqKr"], + [ + "@@[ĻéV£_ţġñpG réÏ·~ąSfy×Í·ºſƽiÍıƣıĻmHH}siaX@iǰÁÃ×t«T¤JJJyJÈ`Ohߦ¡uËhIyCjmÿw ZG TiSsOB²fNmsPa{M{õE^Hj}gYpaeu¯oáwHjÁ½M¡pMuåmni{fk\\oÎqCwEZ¼KĝAy{m÷LwO×SimRI¯rKõBS«sFe]fµ¢óY_ÆPRcue°Cbo×bd£ŌIHgtrnyPt¦foaXďxlBowz_{ÊéWiêEGhܸºuFĈIxf®Y½ĀǙ]¤EyF²ċw¸¿@g¢§RGv»áW`ÃĵJwi]t¥wO½a[×]`ÃiüL¦LabbTÀåc}ÍhÆh®BHî|îºÉk¤Sy£ia©taį·Ɖ`ō¥UhO ĝLk}©Fos´JmµlŁu ønÑJWΪYÀïAetTŅÓGË«bo{ıwodƟ½OġܵxàNÖ¾P²§HKv¾]|BÆåoZ`¡Ø`ÀmºĠ~ÌЧnÇ ¿¤]wğ@srğu~Io[é±¹ ¿ſđÓ@qg¹zƱřaí°KtǤV»Ã[ĩǭƑ^ÇÓ@áťsZÏÅĭƋěpwDóÖáŻneQËq·GCœýS]x·ýq³OÕ¶Qzßti{řáÍÇWŝŭñzÇWpç¿JXĩè½cFÂLiVjx}\\NŇĖ¥GeJA¼ÄHfÈu~¸Æ«dE³ÉMA|bÒ ćhG¬CMõƤąAvüVéŀ_V̳ĐwQj´·ZeÈÁ¨X´Æ¡Qu·»ÕZ³ġqDoy`L¬gdp°şp¦ėìÅĮZ°Iähzĵf²å ĚÑKpIN|Ñz]ń ·FU×é»R³MÉ»GM«kiér}Ã`¹ăÞmÈnÁîRǀ³ĜoİzŔwǶVÚ£À]ɜ»ĆlƂ²Ġ þTº·àUȞÏʦ¶I«dĽĢdĬ¿»Ĕ×h\\c¬ä²GêëĤł¥ÀǿżÃÆMº}BÕĢyFVvwxBèĻĒ©ĈtCĢɽŠȣ¦āæ·HĽîôNÔ~^¤Ɗu^s¼{TA¼ø°¢İªDè¾Ň¶ÝJ®Z´ğ~Sn|ªWÚ©òzPOȸbð¢|øĞŒQìÛÐ@ĞǎRS¤Á§d i´ezÝúØã]HqkIþËQǦÃsǤ[E¬ÉŪÍxXƒ·ÖƁİlƞ¹ª¹|XÊwnÆƄmÀêErĒtD®ċæcQE®³^ĭ¥©l}äQtoŖÜqÆkµªÔĻĴ¡@Ċ°B²Èw^^RsºT£ڿQPJvÄz^Đ¹Æ¯fLà´GC²dtĀRt¼¤ĦOðğfÔðDŨŁĞƘïPÈ®âbMüÀXZ ¸£@Å»»QÉ]dsÖ×_Í_ÌêŮPrĔĐÕGĂeZÜîĘqBhtO ¤tE[h|YÔZśÎs´xº±Uñt|OĩĠºNbgþJy^dÂY Į]Řz¦gC³R`Āz¢Aj¸CL¤RÆ»@Ŏk\\Ç´£YW}z@Z}öoû¶]´^NÒ}èNªPÍy¹`S°´ATeVamdUĐwʄvĮÕ\\uÆŗ¨Yp¹àZÂmWh{á}WØǍÉüwga§áCNęÎ[ĀÕĪgÖɪXøx¬½Ů¦¦[NÎLÜUÖ´òrÙŠxR^JkijnDX{U~ET{ļº¦PZcjF²Ė@pg¨B{u¨ŦyhoÚD®¯¢ WòàFΤ¨GDäz¦kŮPġqË¥À]eâÚ´ªKxīPÖ|æ[xäJÞĥsNÖ½I¬nĨY´®ÐƐmDŝuäđđEb ee_v¡}ìęNJē}qÉåT¯µRs¡M@}ůaa¯wvƉåZw\\Z{åû^" + ] + ], + "encodeOffsets": [[[108815, 30935]], [[110617, 31811]]] + } + }, + { + "type": "Feature", + "id": "520000", + "properties": { + "id": "520000", + "cp": [106.713478, 26.578343], + "name": "贵州", + "childNum": 3 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@G\\lY£in"], + ["@@q|mc¯tÏVSÎ"], + [ + "@@hÑ£IsNgßHHªķÃh_¹¡ĝħń¦uÙùgS¯JH|sÝÅtÁïyMDč»eÕtA¤{b\\}G®u\\åPFqwÅaD K°ºâ_£ùbµmÁÛĹM[q|hlaªāI}ѵ@swtwm^oµD鼊yVky°ÉûÛR ³e¥]RÕěħ[ƅåÛDpJiVÂF²I »mN·£LbÒYbWsÀbpkiTZĄă¶Hq` ĥ_J¯ae«KpÝx]aĕÛPÇȟ[ÁåŵÏő÷Pw}TÙ@Õs«ĿÛq©½m¤ÙH·yǥĘĉBµĨÕnđ]K©œáGçş§ÕßgǗĦTèƤƺ{¶ÉHÎd¾ŚÊ·OÐjXWrãLyzÉAL¾ę¢bĶėy_qMĔąro¼hĊw¶øV¤w²Ĉ]ÊKx|`ź¦ÂÈdrcÈbe¸`I¼čTF´¼Óýȃr¹ÍJ©k_șl³´_pĐ`oÒh¶pa^ÓĔ}D»^Xy`d[Kv JPhèhCrĂĚÂ^Êƌ wZLĠ£ÁbrzOIlMMĪŐžËr×ÎeŦtw|¢mKjSǘňĂStÎŦEtqFT¾E쬬ôxÌO¢ K³ŀºäYPVgŎ¦Ŋm޼VZwVlz¤ £Tl®ctĽÚó{GAÇge~Îd¿æaSba¥KKûj®_Ä^\\ؾbP®¦x^sxjĶI_Ä Xâ¼Hu¨Qh¡À@Ëô}±GNìĎlT¸ `V~R°tbÕĊ`¸úÛtÏFDu[MfqGH·¥yAztMFe|R_GkChZeÚ°tov`xbDnÐ{E}ZèxNEÞREn[Pv@{~rĆAB§EO¿|UZ~ìUf¨J²ĂÝÆsªB`s¶fvö¦Õ~dÔq¨¸º»uù[[§´sb¤¢zþF¢Æ ÀhÂW\\ıËIÝo±ĭŠ£þÊs}¡R]ěDg´VG¢j±®èºÃmpU[Á뺰rÜbNu¸}º¼`niºÔXĄ¤¼ÔdaµÁ_à ftQQgR·Ǔv}Ý×ĵ]µWc¤F²OĩųãW½¯K© ]{LóµCIµ±Mß¿h©āq¬o½~@i~TUxŪÒ¢@£ÀEîôruńb[§nWuMÆLl¿]x}ij½" + ] + ], + "encodeOffsets": [[[112158, 27383]], [[112105, 27474]], [[112095, 27476]]] + } + }, + { + "type": "Feature", + "id": "530000", + "properties": { + "id": "530000", + "cp": [101.512251, 24.740609], + "name": "云南", + "childNum": 1 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + "@@[ùx½}ÑRHYīĺûsÍniEoã½Ya²ė{c¬ĝgĂsAØÅwďõzFjw}«Dx¿}Uũlê@HÅF¨ÇoJ´Ónũuą¡Ã¢pÒÅØ TF²xa²ËXcÊlHîAßËŁkŻƑŷÉ©hWæßUËs¡¦}teèÆ¶StÇÇ}Fd£jĈZĆÆ¤Tč\\D}O÷£U§~ŃGåŃDĝ¸Tsd¶¶Bª¤u¢ŌĎo~t¾ÍŶÒtD¦ÚiôözØX²ghįh½Û±¯ÿm·zR¦Ɵ`ªŊÃh¢rOÔ´£Ym¼èêf¯ŪĽncÚbw\\zlvWªâ ¦gmĿBĹ£¢ƹřbĥkǫßeeZkÙIKueT»sVesbaĕ ¶®dNĄÄpªy¼³BE®lGŭCǶwêżĔÂepÍÀQƞpC¼ŲÈAÎô¶RäQ^Øu¬°_Èôc´¹ò¨P΢hlϦ´ĦÆ´sâÇŲPnÊD^¯°Upv}®BP̪jǬxSöwlfòªvqĸ|`HviļndĜĆhňem·FyÞqóSᝳX_ĞçêtryvL¤§z¦c¦¥jnŞklD¤øz½ĜàĂŧMÅ|áƆàÊcðÂFÜáŢ¥\\\\ºİøÒÐJĴîD¦zK²ǏÎEh~CDhMn^ÌöÄ©ČZÀaüfɭyœpį´ěFűk]Ôě¢qlÅĆÙa¶~ÄqêljN¬¼HÊNQ´ê¼VظE^ŃÒyM{JLoÒęæe±Ķygã¯JYÆĭĘëo¥Šo¯hcK«z_prC´ĢÖY¼ v¸¢RÅW³Â§fǸYi³xR´ďUË`êĿUûuĆBƣöNDH«ĈgÑaB{ÊNF´¬c·Åv}eÇÃGB»If¦HňĕM ~[iwjUÁKE¾dĪçWIèÀoÈXòyŞŮÈXâÎŚj|àsRyµÖPr´þ ¸^wþTDŔHr¸RÌmfżÕâCôoxĜƌÆĮÐYtâŦÔ@]ÈǮƒ\\μģUsȯLbîƲŚºyhr@ĒÔƀÀ²º\\êpJ}ĠvqtĠ@^xÀ£È¨mËÏğ}n¹_¿¢×Y_æpÅA^{½Lu¨GO±Õ½ßM¶wÁĢÛPƢ¼pcIJx|ap̬HÐŊSfsðBZ¿©XÏÒKk÷Eû¿S rEFsÕūkóVǥʼniTL¡n{uxţÏhôŝ¬ğōNNJkyPaqÂğ¤K®YxÉƋÁ]āęDqçgOgILu\\_gz]W¼~CÔē]bµogpÑ_oď`´³Țkl`IªºÎȄqÔþ»E³ĎSJ»_f·adÇqÇc¥Á_Źw{L^ɱćxU£µ÷xgĉp»ĆqNē`rĘzaĵĚ¡K½ÊBzyäKXqiWPÏɸ½řÍcÊG|µƕƣGË÷k°_^ý|_zċBZocmø¯hhcæ\\lMFlư£ĜÆyHF¨µêÕ]HA àÓ^it `þßäkĤÎT~Wlÿ¨ÔPzUCNVv [jâôDôď[}z¿msSh¯{jïğl}šĹ[őgK©U·µË@¾m_~q¡f¹ ÅË^»f³ø}Q¡Ö˳gͱ^Ç \\ëÃA_¿bWÏ[¶ƛé£F{īZgm@|kHǭƁć¦UĔť×ë}ǝeďºȡȘÏíBÉ£āĘPªij¶ʼnÿy©nď£G¹¡I±LÉĺÑdĉÜW¥}gÁ{aqÃ¥aıęÏZï`" + ], + "encodeOffsets": [[104636, 22969]] + } + }, + { + "type": "Feature", + "id": "540000", + "properties": { "id": "540000", "cp": [89.132212, 30.860361], "name": "西藏", "childNum": 1 }, + "geometry": { + "type": "Polygon", + "coordinates": [ + "@@ÂhľxŖxÒVºÅâAĪÝȆµę¯Ňa±r_w~uSÕňqOj]ɄQ £Z UDûoY»©M[L¼qãË{VÍçWVi]ë©Ä÷àyƛhÚU°adcQ~Mx¥cc¡ÙaSyFÖkuRýq¿ÔµQĽ³aG{¿FµëªéĜÿª@¬·K·àariĕĀ«V»ŶĴūgèLǴŇƶaftèBŚ£^âǐÝ®M¦ÁǞÿ¬LhJ¾óƾƺcxwf]Y ´¦|QLn°adĊ \\¨oǀÍŎ´ĩĀd`tÊQŞŕ|¨C^©Ĉ¦¦ÎJĊ{ëĎjª²rÐl`¼Ą[t|¦Stè¾PÜK¸dƄı]s¤î_v¹ÎVòŦj£Əsc¬_Ğ´|٦Av¦w`ăaÝaa¢e¤ı²©ªSªÈMĄwÉØŔì@T¤Ę\\õª@þo´xA sÂtŎKzó´ÇĊµ¢r^nĊƬ×üG¢³ {âĊ]G~bÀgVjzlhǶfOfdªB]pjTOtĊn¤}®¦Č¥d¢¼»ddY¼t¢eȤJ¤}Ǿ¡°§¤AÐlc@ĝsªćļđAçwxUuzEÖġ~AN¹ÄÅȀݦ¿ģŁéì±H ãd«g[ؼēÀcīľġ¬cJµ ÐʥVȝ¸ßS¹ý±ğkƁ¼ą^ɛ¤Ûÿb[}¬ōõÃ]ËNm®g@Bg}ÍF±ǐyL¥íCIijÏ÷Ñį[¹¦[âšEÛïÁÉdƅß{âNÆāŨß¾ě÷yC£k´ÓH@¹TZ¥¢į·ÌAЧ®Zc v½Z¹|ÅWZqgW|ieZÅYVÓqdqbc²R@c¥Rã»GeeƃīQ}J[ÒK ¬Ə|oėjġĠÑN¡ð¯EBčnwôɍėª²CλŹġǝʅįĭạ̃ūȹ]ΓͧgšsgȽóϧµǛęgſ¶ҍć`ĘąŌJÞä¤rÅň¥ÖÁUětęuůÞiĊÄÀ\\Æs¦ÓRb|Â^řÌkÄŷ¶½÷f±iMÝ@ĥ°G¬ÃM¥n£Øąğ¯ß§aëbéüÑOčk£{\\eµª×MÉfm«Ƒ{Å×Gŏǩãy³©WÑăû··Qòı}¯ãIéÕÂZ¨īès¶ZÈsæĔTŘvgÌsN@îá¾ó@ÙwU±ÉT廣TđWxq¹Zobs[ׯcĩvėŧ³BM|¹kªħ¥TzNYnÝßpęrñĠĉRS~½ěVVµõ«M££µBĉ¥áºae~³AuĐh`ܳç@BÛïĿa©|z²Ý¼D£àč²ŸIûI āóK¥}rÝ_Á´éMaň¨~ªSĈ½½KÙóĿeƃÆB·¬ën×W|Uº}LJrƳlŒµ`bÔ`QÐÓ@s¬ñIÍ@ûws¡åQÑßÁ`ŋĴ{ĪTÚÅTSijYo|Ç[ǾµMW¢ĭiÕØ¿@Mh pÕ]jéò¿OƇĆƇpêĉâlØwěsǩĵ¸c bU¹ř¨WavquSMzeo_^gsÏ·¥Ó@~¯¿RiīB\\qTGªÇĜçPoÿfñòą¦óQīÈáPābß{ZŗĸIæÅhnszÁCËìñÏ·ąĚÝUm®óL·ăUÈíoù´Êj°ŁŤ_uµ^°ìÇ@tĶĒ¡ÆM³Ģ«İĨÅ®ğRāðggheÆ¢zÊ©Ô\\°ÝĎz~ź¤PnMĪÖB£kné§żćĆKǰ¼L¶èâz¨u¦¥LDĘz¬ýÎmĘd¾ßFzhg²Fy¦ĝ¤ċņbÎ@yĄæm°NĮZRÖíJ²öLĸÒ¨Y®ƌÐVàtt_ÚÂyĠz]ŢhzĎ{ÂĢXc|ÐqfO¢¤ögÌHNPKŖUú´xx[xvĐCûĀìÖT¬¸^}Ìsòd´_KgžLĴ ÀBon|H@Êx¦BpŰŌ¿fµƌA¾zLjRx¶FkĄźRzŀ~¶[´HnªVƞuĒȨƎcƽÌm¸ÁÈM¦x͊ëÀxdžBú^´W£dkɾĬpw˂ØɦļĬIŚÊnŔa¸~J°îlɌxĤÊÈðhÌ®gT´øàCÀ^ªerrƘd¢İP|Ė ŸWªĦ^¶´ÂLaT±üWƜǀRÂŶUńĖ[QhlLüAÜ\\qRĄ©" + ], + "encodeOffsets": [[90849, 37210]] + } + }, + { + "type": "Feature", + "id": "610000", + "properties": { + "id": "610000", + "cp": [108.948024, 34.263161], + "name": "陕西", + "childNum": 1 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + "@@p¢ȮµûGĦ}Ħðǚ¶òƄjɂz°{ºØkÈęâ¦jªBg\\ċ°s¬]jú EȌdž¬stRÆdĠİwܸôW¾ƮłÒ_{Ìû¼jº¹¢GǪÒ¯ĘZ`ºŊecņą~BÂgzpâēòYǠȰÌTΨÂW|fcă§uF@N¢XLRMº[ğȣſï|¥Jkc`sʼnǷY¹W@µ÷K ãï³ÛIcñ·VȋÚÒķø©þ¥yÓğęmWµÎumZyOŅƟĥÓ~sÑL¤µaÅ Y¦ocyZ{y c]{Ta©`U_Ěē£ωÊƍKùK¶ȱÝƷ§{û»ÅÁȹÍéuij|¹cÑdìUYOuFÕÈYvÁCqÓTǢí§·S¹NgV¬ë÷Át°DدC´ʼnƒópģ}ċcEË FéGU¥×K §¶³BČ}C¿åċ`wġB·¤őcƭ²ő[Å^axwQO ÿEËߌĤNĔwƇÄńwĪo[_KÓª³ÙnKÇěÿ]ďă_d©·©Ýŏ°Ù®g]±ßå¬÷m\\iaǑkěX{¢|ZKlçhLtŇîŵœè[É@ƉĄEtƇϳħZ«mJ ×¾MtÝĦ£IwÄå\\Õ{OwĬ©LÙ³ÙgBƕŀrÌĢŭO¥lãyC§HÍ£ßEñX¡°ÙCgpťzb`wIvA|§hoĕ@E±iYd¥OϹS|}F@¾oAO²{tfÜ¢FǂÒW²°BĤh^Wx{@¬F¸¡ķn£P|ªĴ@^ĠĈæbÔc¶lYi ^MicϰÂ[ävï¶gv@ÀĬ·lJ¸sn|¼u~a]ÆÈtŌºJpþ£KKf~¦UbyäIĺãnÔ¿^ŵMThĠܤko¼Ŏìąǜh`[tRd²IJ_XPrɲlXiL§à¹H°Ȧqº®QCbAŌJ¸ĕÚ³ĺ§ `d¨YjiZvRĺ±öVKkjGȊÄePĞZmļKÀ[`ösìhïÎoĬdtKÞ{¬èÒÒBÔpIJÇĬJŊ¦±J«Y§@·pHµàåVKepWftsAÅqC·¬ko«pHÆuK@oHĆÛķhxenS³àǍrqƶRbzy¸ËÐl¼EºpĤ¼x¼½~Ğà@ÚüdK^mÌSj" + ], + "encodeOffsets": [[110234, 38774]] + } + }, + { + "type": "Feature", + "id": "620000", + "properties": { + "id": "620000", + "cp": [103.823557, 36.058039], + "name": "甘肃", + "childNum": 2 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@VuUv"], + [ + "@@ũEĠtt~nkh`Q¦ÅÄÜdwAb×ĠąJ¤DüègĺqBqj°lI¡ĨÒ¤úSHbjÎB°aZ¢KJO[|A£Dx}NìHUnrk kp¼Y kMJn[aGáÚÏ[½rc}aQxOgsPMnUsncZ sKúvAtÞġ£®ĀYKdnFw¢JE°Latf`¼h¬we|Æbj}GA·~W`¢MC¤tL©IJ°qdfObÞĬ¹ttu`^ZúE`[@Æsîz®¡CƳƜG²R¢RmfwĸgÜą G@pzJM½mhVy¸uÈÔO±¨{LfæU¶ßGĂq\\ª¬²I¥IʼnÈīoıÓÑAçÑ|«LÝcspīðÍg të_õ\\ĉñLYnĝgRǡÁiHLlõUĹ²uQjYi§Z_c¨´ĹĖÙ·ŋI aBDR¹ȥr¯GºßK¨jWkɱOqWij\\aQ\\sg_ĆǛōëp»£lğÛgSŶN®À]ÓämĹãJaz¥V}Le¤Lýo¹IsŋÅÇ^bz ³tmEÁ´a¹cčecÇNĊãÁ\\č¯dNj]jZµkÓdaćå]ğij@ ©O{¤ĸm¢E·®«|@Xwg]A챝XǁÑdzªcwQÚŝñsÕ³ÛV_ý¥\\ů¥©¾÷w©WÕÊĩhÿÖÁRo¸V¬âDb¨hûxÊ×nj~Zâg|XÁnßYoº§ZÅŘv[ĭÖʃuďxcVbnUSf B¯³_TzºÎO©çMÑ~M³]µ^püµÄY~y@X~¤Z³[Èōl@®Å¼£QK·Di¡ByÿQ_´D¥hŗy^ĭÁZ]cIzýah¹MĪğPs{ò²Vw¹t³ŜË[Ñ}X\\gsF£sPAgěp×ëfYHāďÖqēŭOÏëdLü\\it^c®Rʺ¶¢H°mrY£B¹čIoľu¶uI]vģSQ{UŻÅ}QÂ|̰ƅ¤ĩŪU ęĄÌZÒ\\v²PĔ»ƢNHĂyAmƂwVm`]ÈbH`Ì¢²ILvĜH®¤Dlt_¢JJÄämèÔDëþgºƫaʎÌrêYi~ ÎݤNpÀA¾Ĕ¼b ð÷®üszMzÖĖQdȨýv§Tè|ªHþa¸|Ð ƒwKĢx¦ivr^ÿ ¸l öæfƟĴ·PJv}n\\h¹¶v·À|\\ƁĚN´ĜçèÁz]ġ¤²¨QÒŨTIlªťØ}¼˗ƦvÄùØE«FïËIqōTvāÜŏíÛßÛVj³âwGăÂíNOPìyV³ʼnĖýZso§HÑiYw[ß\\X¦¥c]ÔƩÜ·«jÐqvÁ¦m^ċ±R¦ƈťĚgÀ»IïĨʗƮ°ƝĻþÍAƉſ±tÍEÕÞāNUÍ¡\\ſčåÒʻĘm ƭÌŹöʥëQ¤µÇcƕªoIýIÉ_mkl³ăƓ¦j¡YzŇi}Msßõīʋ }ÁVm_[n}eıUĥ¼ªI{ΧDÓƻėojqYhĹT©oūĶ£]ďxĩǑMĝq`B´ƃ˺Чç~²ņj@¥@đ´ί}ĥtPńǾV¬ufÓÉCtÓ̻ ¹£G³]ƖƾŎĪŪĘ̖¨ʈĢƂlɘ۪üºňUðǜȢƢż̌ȦǼĤŊɲĖÂKq´ï¦ºĒDzņɾªǀÞĈĂD½ĄĎÌŗĞrôñnN¼â¾ʄľԆ|DŽ֦ज़ȗlj̘̭ɺƅêgV̍ʆĠ·ÌĊv|ýĖÕWĊǎÞ´õ¼cÒÒBĢ͢UĜð͒s¨ňƃLĉÕÝ@ɛƯ÷¿ĽĹeȏijëCȚDŲyê×Ŗyò¯ļcÂßY tÁƤyAã˾J@ǝrý@¤ rz¸oP¹ɐÚyáHĀ[Jw cVeȴÏ»ÈĖ}ƒŰŐèȭǢόĀƪÈŶë;Ñ̆ȤМľĮEŔĹŊũ~ËUă{ĻƹɁύȩþĽvĽƓÉ@ēĽɲßǐƫʾǗĒpäWÐxnsÀ^ƆwW©¦cÅ¡Ji§vúF¶¨c~c¼īeXǚ\\đ¾JwÀďksãAfÕ¦L}waoZD½Ml«]eÒÅaɲáo½FõÛ]ĻÒ¡wYR£¢rvÓ®y®LFLzĈôe]gx}|KK}xklL]c¦£fRtív¦PĤoH{tK" + ] + ], + "encodeOffsets": [[[108619, 36299]], [[108589, 36341]]] + } + }, + { + "type": "Feature", + "id": "630000", + "properties": { "id": "630000", "cp": [96.778916, 35.623178], "name": "青海", "childNum": 2 }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@InJm"], + [ + "@@CƽOŃĦsΰ~dz¦@@Ņi±è}ШƄ˹A³r_ĞǒNĪĐw¤^ŬĵªpĺSZgrpiƼĘÔ¨C|ÍJ©Ħ»®VIJ~f\\m `UnÂ~ʌĬàöNt~ňjy¢ZiƔ¥Ąk´nl`JÊJþ©pdƖ®È£¶ìRʦźõƮËnʼėæÑƀĎ[¢VÎĂMÖÝÎF²sƊƀÎBļýƞ¯ʘƭðħ¼Jh¿ŦęΌƇ¥²Q]Č¥nuÂÏri¸¬ƪÛ^Ó¦d¥[Wà x\\ZjÒ¨GtpþYŊĕ´zUOëPîMĄÁxH´áiÜUàîÜŐĂÛSuŎrJð̬EFÁú×uÃÎkrĒ{V}İ«O_ÌËĬ©ÓŧSRѱ§Ģ£^ÂyèçěM³Ƃę{[¸¿u ºµ[gt£¸OƤĿéYõ·kĀq]juw¥DĩƍõÇPéĽG©ã¤G uȧþRcÕĕNyyûtøï»a½ē¿BMoį£Íj}éZËqbʍƬh¹ìÿÓAçãnIáI`ks£CGěUy×Cy @¶ʡÊBnāzGơMē¼±O÷õJËĚăVĪũƆ£¯{ËL½ÌzżVR|ĠTbuvJvµhĻĖHAëáa OÇðñęNw œľ·LmI±íĠĩPÉ×®ÿscB³±JKßĊ«` ađ»·QAmOVţéÿ¤¹SQt]]Çx±¯A@ĉij¢Óļ©l¶ÅÛrŕspãRk~¦ª]Į´FRådČsCqđéFn¿ÅƃmÉx{W©ºƝºįkÕƂƑ¸wWūЩÈF£\\tÈ¥ÄRÈýÌJ lGr^×äùyÞ³fjc¨£ÂZ|ǓMĝÏ@ëÜőRĝ÷¡{aïȷPu°ËXÙ{©TmĠ}Y³ÞIňµç½©C¡į÷¯B»|St»]vųs»}MÓ ÿʪƟǭA¡fs»PY¼c¡»¦cċ¥£~msĉPSi^o©AecPeǵkgyUi¿h}aHĉ^|á´¡HØûÅ«ĉ®]m¡qĉ¶³ÈyôōLÁstB®wn±ă¥HSòė£Së@לÊăxÇN©©T±ª£IJ¡fb®Þbb_Ą¥xu¥B{łĝ³«`dƐt¤ťiñÍUuºí`£^tƃIJc·ÛLO½sç¥Ts{ă\\_»kϱq©čiìĉ|ÍI¥ć¥]ª§D{ŝŖÉR_sÿc³ĪōƿΧp[ĉc¯bKmR¥{³Ze^wx¹dƽŽôIg §Mĕ ƹĴ¿ǣÜÍ]Ý]snåA{eƭ`ǻŊĿ\\ijŬűYÂÿ¬jĖqßb¸L«¸©@ěĀ©ê¶ìÀEH|´bRľÓ¶rÀQþvl®ÕETzÜdb hw¤{LRdcb¯ÙVgƜßzÃôì®^jUèXÎ|UäÌ»rK\\ªN¼pZCüVY¤ɃRi^rPŇTÖ}|br°qňb̰ªiƶGQ¾²x¦PmlŜ[Ĥ¡ΞsĦÔÏâ\\ªÚŒU\\f ¢N²§x|¤§xĔsZPòʛ²SÐqF`ªVÞŜĶƨVZÌL`¢dŐIqr\\oäõF礻Ŷ×h¹]ClÙ\\¦ďÌį¬řtTӺƙgQÇÓHţĒ´ÃbEÄlbʔC|CŮkƮ[ʼ¬ň´KŮÈΰÌζƶlðļATUvdTGº̼ÔsÊDÔveOg" + ] + ], + "encodeOffsets": [[[105308, 37219]], [[95370, 40081]]] + } + }, + { + "type": "Feature", + "id": "640000", + "properties": { "id": "640000", "cp": [106.278179, 37.26637], "name": "宁夏", "childNum": 2 }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + "@@KëÀęĞ«Oęȿȕı]ʼn¡åįÕÔ«ǴõƪĚQÐZhv K°öqÀÑS[ÃÖHƖčËnL]ûc Ùß@ĝ¾}w»»oģF¹»kÌÏ·{zP§B¢íyÅt@@á]Yv_ssģ¼ißĻL¾ġsKD£¡N_ X¸}B~HaiÅf{«x»ge_bsKF¯¡IxmELcÿZ¤ĢÝsuBLùtYdmVtNmtOPhRw~bd ¾qÐ\\âÙH\\bImlNZ»loqlVmGā§~QCw¤{A\\PKNY¯bFkC¥sks_Ã\\ă«¢ħkJi¯rrAhĹûç£CUĕĊ_ÔBixÅÙĄnªÑaM~ħpOu¥sîeQ¥¤^dkKwlL~{L~hw^ófćKyEKzuÔ¡qQ¤xZÑ¢^ļöܾEp±âbÊÑÆ^fk¬ NC¾YpxbK~¥eÖäBlt¿Đx½I[ĒǙWf»Ĭ}d§dµùEuj¨IÆ¢¥dXªƅx¿]mtÏwßRĶX¢͎vÆzƂZò®ǢÌʆCrâºMÞzÆMÒÊÓŊZľr°Î®Ȉmª²ĈUªĚîøºĮ¦ÌĘk^FłĬhĚiĀ˾iİbjÕ" + ], + ["@@mfwěwMrŢªv@G"] + ], + "encodeOffsets": [[[109366, 40242]], [[108600, 36303]]] + } + }, + { + "type": "Feature", + "id": "650000", + "properties": { "id": "650000", "cp": [85.617733, 40.792818], "name": "新疆", "childNum": 1 }, + "geometry": { + "type": "Polygon", + "coordinates": [ + "@@QØĔ²X¨~ǘBºjʐߨvKƔX¨vĊO÷¢i@~cĝe_«E}QxgɪëÏÃ@sÅyXoŖ{ô«ŸuX êÎf`C¹ÂÿÐGĮÕĞXŪōŸMźÈƺQèĽôe|¿ƸJR¤ĘEjcUóº¯Ĩ_ŘÁMª÷Ð¥OéÈ¿ÖğǤǷÂFÒzÉx[]Ĥĝœ¦EP}ûƥé¿İƷTėƫœŕƅƱB»Đ±ēO ¦E}`cȺrĦáŖuÒª«IJπdƺÏØZƴwʄ¤ĖGĐǂZĶèH¶}ÚZצʥĪï|ÇĦMŔ»İĝLjì¥Βba¯¥ǕǚkĆŵĦɑĺƯxūД̵nơʃĽá½M»òmqóŘĝč˾ăC ćāƿÝɽ©DZҹđ¥³ðLrÁ®ɱĕģʼnǻ̋ȥơŻǛȡVï¹Ň۩ûkɗġƁ§ʇė̕ĩũƽō^ƕUv£ƁQïƵkŏ½ΉÃŭdzLŇʻ«ƭ\\lŭD{ʓDkaFÃÄa³ŤđÔGRÈƚhSӹŚsİ«ĐË[¥ÚDkº^Øg¼ŵ¸£EÍöůʼnT¡c_ËKYƧUśĵÝU_©rETÏʜ±OñtYwē¨{£¨uM³x½şL©Ùá[ÓÐĥ Νtģ¢\\śnkOw¥±T»ƷFɯàĩÞáB¹Æ ÑUwŕĽw[mG½Èå~Æ÷QyěCFmĭZīŵVÁƿQƛûXS²b½KϽĉS©ŷXĕ{ĕK·¥Ɨcqq©f¿]ßDõU³hgËÇïģÉɋwk¯í}I·œbmÉřīJɥĻˁ×xoɹīlc ¤³Xù]DžA¿w͉ì¥wÇN·ÂËnƾƍdǧđ®ƝvUm©³G\\}µĿQyŹlăµEwLJQ½yƋBe¶ŋÀůo¥AÉw@{Gpm¿AijŽKLh³`ñcËtW±»ÕSëüÿďDu\\wwwù³VLŕOMËGh£õP¡erÏd{ġWÁ č|yšg^ğyÁzÙs`s|ÉåªÇ}m¢Ń¨`x¥ù^}Ì¥H«YªƅAйn~ź¯f¤áÀzgÇDIÔ´AňĀÒ¶ûEYospõD[{ù°]uJqU|Soċxţ[õÔĥkŋÞŭZ˺óYËüċrw ÞkrťË¿XGÉbřaDü·Ē÷Aê[ÄäI®BÕĐÞ_¢āĠpÛÄȉĖġDKwbmÄNôfƫVÉvidzHQµâFùœ³¦{YGd¢ĚÜO {Ö¦ÞÍÀP^bƾl[vt×ĈÍE˨¡Đ~´î¸ùÎhuè`¸HÕŔVºwĠââWò@{ÙNÝ´ə²ȕn{¿¥{l÷eé^eďXj©î\\ªÑòÜìc\\üqÕ[Č¡xoÂċªbØø|¶ȴZdÆÂońéG\\¼C°ÌÆn´nxÊOĨŪƴĸ¢¸òTxÊǪMīĞÖŲÃɎOvʦƢ~FRěò¿ġ~åŊúN¸qĘ[Ĕ¶ÂćnÒPĒÜvúĀÊbÖ{Äî¸~Ŕünp¤ÂH¾ĄYÒ©ÊfºmÔĘcDoĬMŬS¤s²ʘÚžȂVŦ èW°ªB|IJXŔþÈJĦÆæFĚêYĂªĂ]øªŖNÞüAfɨJ¯ÎrDDĤ`mz\\§~D¬{vJ«lµĂb¤pŌŰNĄ¨ĊXW|ų ¿¾ɄĦƐMTòP÷fØĶK¢ȝ˔Sô¹òEð`Ɩ½ǒÂň×äı§ĤƝ§C~¡hlåǺŦŞkâ~}FøàIJaĞfƠ¥Ŕd®U¸źXv¢aƆúŪtŠųƠjdƺƺÅìnrh\\ĺ¯äɝĦ]èpĄ¦´LƞĬ´ƤǬ˼Ēɸ¤rºǼ²¨zÌPðŀbþ¹ļD¢¹\\ĜÑŚ¶ZƄ³àjĨoâȴLÊȮĐĚăÀêZǚŐ¤qȂ\\L¢ŌİfÆs|zºeªÙæ§{Ā´ƐÚ¬¨Ĵà²łhʺKÞºÖTiƢ¾ªì°`öøu®Ê¾ãØ" + ], + "encodeOffsets": [[88824, 50096]] + } + }, + { + "type": "Feature", + "id": "110000", + "properties": { + "id": "110000", + "cp": [116.405285, 39.904989], + "name": "北京", + "childNum": 1 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + "@@ĽOÁûtŷmiÍt_H»Ĩ±d`¹{bw Yr³S]§§o¹qGtm_SŧoaFLgQN_dV@Zom_ć\\ßc±x¯oœRcfe £o§ËgToÛJíĔóu |wP¤XnO¢ÉŦ¯rNÄā¤zâŖÈRpŢZÚ{GrFt¦Òx§ø¹RóäV¤XdżâºWbwڍUd®bêņ¾jnŎGŃŶnzÚSeîĜZczî¾i]ÍQaúÍÔiþĩȨWĢü|Ėu[qb[swP@ÅğP¿{\\¥A¨ÏѨj¯X\\¯MKpA³[H īu}}" + ], + "encodeOffsets": [[120023, 41045]] + } + }, + { + "type": "Feature", + "id": "120000", + "properties": { + "id": "120000", + "cp": [117.190182, 39.125596], + "name": "天津", + "childNum": 1 + }, + "geometry": { + "type": "Polygon", + "coordinates": [ + "@@ŬgX§Ü«E ¶F̬O_ïlÁgz±AXeµÄĵ{¶]gitgIj·¥îakS¨ÐƎk}ĕ{gBqGf{¿aU^fIư³õ{YıëNĿk©ïËZŏR§òoY×Ógc ĥs¡bġ«@dekąI[nlPqCnp{ō³°`{PNdƗqSÄĻNNâyj]äÒD ĬH°Æ]~¡HO¾X}ÐxgpgWrDGpù^LrzWxZ^¨´T\\|~@IzbĤjeĊªz£®ĔvěLmV¾Ô_ÈNW~zbĬvG²ZmDM~~" + ], + "encodeOffsets": [[120237, 41215]] + } + }, + { + "type": "Feature", + "id": "310000", + "properties": { + "id": "310000", + "cp": [121.472644, 31.231706], + "name": "上海", + "childNum": 6 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@ɧư¬EpƸÁxc"], + ["@@©ª"], + ["@@MA"], + ["@@QpİE§ÉC¾"], + ["@@bŝÕÕEȣÚƥêImɇǦèÜĠÚÃƌÃ͎ó"], + ["@@ǜûȬɋŭ×^sYɍDŋŽąñCG²«ªč@h_p¯A{oloY¬j@IJ`gQÚhr|ǀ^MIJvtbe´R¯Ô¬¨Yô¤r]ìƬį"] + ], + "encodeOffsets": [ + [[124702, 32062]], + [[124547, 32200]], + [[124808, 31991]], + [[124726, 32110]], + [[124903, 32376]], + [[124438, 32149]] + ] + } + }, + { + "type": "Feature", + "id": "500000", + "properties": { + "id": "500000", + "cp": [107.304962, 29.533155], + "name": "重庆", + "childNum": 2 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + [ + "@@vjG~nGŘŬĶȂƀƾ¹¸ØÎezĆT¸}êÐqHðqĖä¥^CÆIj²p \\_ æüY|[YxƊæu°xb® Űb@~¢NQt°¶Sæ Ê~rljĔëĚ¢~uf`faĔJåĊnÖ]jƎćÊ@£¾a®£Ű{ŶĕFègLk{Y|¡ĜWƔtƬJÑxq±ĢN´òKLÈüD|s`ŋć]Ã`đMûƱ½~Y°ħ`ƏíW½eI½{aOIrÏ¡ĕŇapµÜƅġ^ÖÛbÙŽŏml½SêqDu[RãË»ÿw`»y¸_ĺę}÷`M¯ċfCVµqʼn÷Zgg`d½pDOÎCn^uf²ènh¼WtƏxRGg¦ pVFI±G^Ic´ecGĹÞ½sëĬhxW}KÓeXsbkF¦LØgTkïƵNï¶}Gyw\\oñ¡nmĈzj@Óc£»Wă¹Ój_m»¹·~MvÛaq»ê\\ÂoVnÓØÍ²«bq¿efE Ĝ^Q~ Évýş¤²ĮpEİ}zcĺL½¿gÅ¡ýE¡ya£³t\\¨\\vú»¼§·Ñr_oÒý¥u_n»_At©Þűā§IVeëY}{VPÀFA¨ąB}q@|Ou\\FmQFÝ Mwå}]|FmÏCawu_p¯sfÙgY DHl`{QEfNysB¦zG¸rHeN\\CvEsÐùÜ_·ÖĉsaQ¯}_UxÃđqNH¬Äd^ÝŰR¬ã°wećJE·vÝ·HgéFXjÉê`|ypxkAwWĐpb¥eOsmzwqChóUQl¥F^lafanòsrEvfQdÁUVfÎvÜ^eftET¬ôA\\¢sJnQTjPØxøK|nBzĞ»LY FDxÓvr[ehľvN¢o¾NiÂxGpâ¬zbfZo~hGi]öF||NbtOMn eA±tPTLjpYQ|SHYĀxinzDJÌg¢và¥Pg_ÇzIIII£®S¬Øsμ£N" + ], + ["@@ifjN@s"] + ], + "encodeOffsets": [[[109628, 30765]], [[111725, 31320]]] + } + }, + { + "type": "Feature", + "id": "810000", + "properties": { + "id": "810000", + "cp": [114.173355, 22.320048], + "name": "香港", + "childNum": 5 + }, + "geometry": { + "type": "MultiPolygon", + "coordinates": [ + ["@@AlBk"], + ["@@mn"], + ["@@EpFo"], + ["@@ea¢pl¸Eõ¹hj[]ÔCÎ@lj¡uBX ´AI¹ [yDU]W`çwZkmc MpÅv}IoJlcafŃK°ä¬XJmÐ đhI®æÔtSHnEÒrÈc"], + ["@@rMUwAS®e"] + ], + "encodeOffsets": [ + [[117111, 23002]], + [[117072, 22876]], + [[117045, 22887]], + [[116975, 23082]], + [[116882, 22747]] + ] + } + }, + { + "type": "Feature", + "id": "820000", + "properties": { "id": "820000", "cp": [113.54909, 22.198951], "name": "澳门", "childNum": 1 }, + "geometry": { + "type": "Polygon", + "coordinates": ["@@kÊd°å§s"], + "encodeOffsets": [[116279, 22639]] + } + } + ], + "UTF8Encoding": true +} diff --git a/src/components/DiyEditor/components/ComponentContainer.vue b/src/components/DiyEditor/components/ComponentContainer.vue index 2d8c2f13..e6f1beb3 100644 --- a/src/components/DiyEditor/components/ComponentContainer.vue +++ b/src/components/DiyEditor/components/ComponentContainer.vue @@ -1,7 +1,6 @@ <template> <div :class="['component', { active: active }]"> <div - class="component-inner" :style="{ ...style }" @@ -127,114 +126,110 @@ $active-border-width: 2px; $hover-border-width: 1px; $name-position: -85px; $toolbar-position: -55px; + /* 组件 */ .component { position: relative; cursor: move; - .component-inner { - position: relative; - z-index: 1; - } - /* 用于包裹组件,为组件提供 组件名称、工具栏、边框等样式 */ + .component-wrap { - z-index: 0; - // 不可以被点击 - // component-wrap会遮挡组件,导致组件不能触发鼠标事件,所以这里要先禁用,然后在组件名称、工具栏上开启。 - pointer-events: none; - display: block; position: absolute; - left: -$active-border-width; top: 0; + left: -$active-border-width; + display: block; width: 100%; height: 100%; + + /* 鼠标放到组件上时 */ + &:hover { + border: $hover-border-width dashed var(--el-color-primary); + box-shadow: 0 0 5px 0 rgb(24 144 255 / 30%); + + .component-name { + top: $hover-border-width; + + /* 防止加了边框之后,位置移动 */ + left: $name-position - $hover-border-width; + } + } + /* 左侧:组件名称 */ .component-name { - // 可以被点击 - pointer-events: auto; - display: block; position: absolute; - width: 80px; - text-align: center; - line-height: 25px; - height: 25px; - background: #fff; - font-size: 12px; - left: $name-position; top: $active-border-width; + left: $name-position; + display: block; + width: 80px; + height: 25px; + font-size: 12px; + line-height: 25px; + text-align: center; + background: #fff; box-shadow: 0 0 4px #00000014, 0 2px 6px #0000000f, 0 4px 8px 2px #0000000a; + /* 右侧小三角 */ - &:after { + &::after { position: absolute; top: 7.5px; right: -10px; - content: ' '; - height: 0; width: 0; + height: 0; border: 5px solid transparent; border-left-color: #fff; + content: ' '; } } + /* 右侧:组件操作工具栏 */ .component-toolbar { - // 可以被点击 - pointer-events: auto; - display: none; position: absolute; top: 0; right: $toolbar-position; + display: none; + /* 左侧小三角 */ - &:before { + &::before { position: absolute; top: 10px; left: -10px; - content: ' '; - height: 0; width: 0; + height: 0; border: 5px solid transparent; border-right-color: #2d8cf0; + content: ' '; } } } + /* 组件选中时 */ &.active { margin-bottom: 4px; .component-wrap { - z-index: 2; - border: $active-border-width solid var(--el-color-primary) !important; - box-shadow: 0 0 10px 0 rgba(24, 144, 255, 0.3); margin-bottom: $active-border-width + $active-border-width; + border: $active-border-width solid var(--el-color-primary) !important; + box-shadow: 0 0 10px 0 rgb(24 144 255 / 30%); .component-name { - background: var(--el-color-primary); - color: #fff; + top: 0 !important; + /* 防止加了边框之后,位置移动 */ left: $name-position - $active-border-width !important; - top: 0 !important; - &:after { + color: #fff; + background: var(--el-color-primary); + + &::after { border-left-color: var(--el-color-primary); } } + .component-toolbar { display: block; } } } - /* 鼠标放到组件上时 */ - &:hover { - .component-wrap { - z-index: 2; - border: $hover-border-width dashed var(--el-color-primary); - box-shadow: 0 0 5px 0 rgba(24, 144, 255, 0.3); - .component-name { - /* 防止加了边框之后,位置移动 */ - left: $name-position - $hover-border-width; - top: $hover-border-width; - } - } - } } </style> diff --git a/src/components/DiyEditor/components/ComponentContainerProperty.vue b/src/components/DiyEditor/components/ComponentContainerProperty.vue index 5c5ed9a0..d6540354 100644 --- a/src/components/DiyEditor/components/ComponentContainerProperty.vue +++ b/src/components/DiyEditor/components/ComponentContainerProperty.vue @@ -157,6 +157,7 @@ const handleSliderChange = (prop: string) => { :deep(.el-slider__runway) { margin-right: 16px; } + :deep(.el-input-number) { width: 50px; } diff --git a/src/components/DiyEditor/components/ComponentLibrary.vue b/src/components/DiyEditor/components/ComponentLibrary.vue index 2bcd81fd..e319a5c2 100644 --- a/src/components/DiyEditor/components/ComponentLibrary.vue +++ b/src/components/DiyEditor/components/ComponentLibrary.vue @@ -90,23 +90,26 @@ const handleCloneComponent = (component: DiyComponent<any>) => { .editor-left { z-index: 1; flex-shrink: 0; - box-shadow: 8px 0 8px -8px rgba(0, 0, 0, 0.12); + box-shadow: 8px 0 8px -8px rgb(0 0 0 / 12%); :deep(.el-collapse) { border-top: none; } + :deep(.el-collapse-item__wrap) { border-bottom: none; } + :deep(.el-collapse-item__content) { padding-bottom: 0; } + :deep(.el-collapse-item__header) { - border-bottom: none; - background-color: var(--el-bg-color-page); - padding: 0 24px; height: 32px; + padding: 0 24px; line-height: 32px; + background-color: var(--el-bg-color-page); + border-bottom: none; } .component-container { @@ -116,25 +119,26 @@ const handleCloneComponent = (component: DiyComponent<any>) => { } .component { + display: flex; width: 86px; height: 86px; - display: flex; + cursor: move; + border-right: 1px solid var(--el-border-color-lighter); + border-bottom: 1px solid var(--el-border-color-lighter); flex-direction: column; align-items: center; justify-content: center; - border-right: 1px solid var(--el-border-color-lighter); - border-bottom: 1px solid var(--el-border-color-lighter); - cursor: move; .el-icon { margin-bottom: 4px; color: gray; } } + .component.active, .component:hover { - background: var(--el-color-primary); color: var(--el-color-white); + background: var(--el-color-primary); .el-icon { color: var(--el-color-white); @@ -155,11 +159,10 @@ const handleCloneComponent = (component: DiyComponent<any>) => { .drag-area { /* 拖拽到手机区域时的样式 */ .draggable-ghost { + display: flex; width: 100%; height: 40px; - display: flex; - justify-content: center; - align-items: center; + /* 条纹背景 */ background: linear-gradient( 45deg, @@ -174,20 +177,25 @@ const handleCloneComponent = (component: DiyComponent<any>) => { ); background-size: 1rem 1rem; transition: all 0.5s; + justify-content: center; + align-items: center; + span { - color: #fff; display: inline-block; width: 140px; height: 25px; font-size: 12px; - text-align: center; line-height: 25px; + color: #fff; + text-align: center; background: #5487df; } + /* 拖拽时隐藏组件 */ .component { display: none; } + /* 拖拽时显示占位提示 */ .drag-placement { display: block; diff --git a/src/components/DiyEditor/components/mobile/ImageBar/index.vue b/src/components/DiyEditor/components/mobile/ImageBar/index.vue index 6f70c52d..d9685b50 100644 --- a/src/components/DiyEditor/components/mobile/ImageBar/index.vue +++ b/src/components/DiyEditor/components/mobile/ImageBar/index.vue @@ -17,8 +17,8 @@ defineProps<{ property: ImageBarProperty }>() <style scoped lang="scss"> /* 图片 */ img { + display: block; width: 100%; height: 100%; - display: block; } </style> diff --git a/src/components/DiyEditor/components/mobile/NavigationBar/index.vue b/src/components/DiyEditor/components/mobile/NavigationBar/index.vue index 345b6681..f5cfff8c 100644 --- a/src/components/DiyEditor/components/mobile/NavigationBar/index.vue +++ b/src/components/DiyEditor/components/mobile/NavigationBar/index.vue @@ -35,22 +35,25 @@ defineProps<{ property: NavigationBarProperty }>() </script> <style lang="scss" scoped> .navigation-bar { + display: flex; height: 35px; background: #fff; - display: flex; justify-content: space-between; align-items: center; + /* 左边 */ .left { margin-left: 8px; } + .center { - flex: 1; - text-align: center; font-size: 14px; line-height: 35px; - color: #333333; + color: #333; + text-align: center; + flex: 1; } + /* 右边 */ .right { margin-right: 8px; diff --git a/src/components/DiyEditor/components/mobile/SearchBar/index.vue b/src/components/DiyEditor/components/mobile/SearchBar/index.vue index 618c918b..9de261ad 100644 --- a/src/components/DiyEditor/components/mobile/SearchBar/index.vue +++ b/src/components/DiyEditor/components/mobile/SearchBar/index.vue @@ -45,21 +45,21 @@ defineProps<{ property: SearchProperty }>() /* 搜索框 */ .inner { position: relative; - min-height: 28px; display: flex; - align-items: center; + min-height: 28px; font-size: 14px; + align-items: center; .placeholder { display: flex; - align-items: center; width: 100%; padding: 0 8px; - gap: 2px; - text-overflow: ellipsis; overflow: hidden; + text-overflow: ellipsis; word-break: break-all; white-space: nowrap; + align-items: center; + gap: 2px; } .right { diff --git a/src/components/DiyEditor/components/mobile/TabBar/index.vue b/src/components/DiyEditor/components/mobile/TabBar/index.vue index 647e3369..4325d1e3 100644 --- a/src/components/DiyEditor/components/mobile/TabBar/index.vue +++ b/src/components/DiyEditor/components/mobile/TabBar/index.vue @@ -30,8 +30,9 @@ defineProps<{ property: TabBarProperty }>() </script> <style lang="scss" scoped> .tab-bar { - width: 100%; z-index: 2; + width: 100%; + .tab-bar-bg { display: flex; flex-direction: row; @@ -41,11 +42,11 @@ defineProps<{ property: TabBarProperty }>() .tab-bar-item { display: flex; + width: 100%; + font-size: 12px; flex-direction: column; align-items: center; justify-content: center; - font-size: 12px; - width: 100%; img { width: 26px; diff --git a/src/components/DiyEditor/components/mobile/TitleBar/index.vue b/src/components/DiyEditor/components/mobile/TitleBar/index.vue index aab65779..047a6c06 100644 --- a/src/components/DiyEditor/components/mobile/TitleBar/index.vue +++ b/src/components/DiyEditor/components/mobile/TitleBar/index.vue @@ -56,23 +56,23 @@ defineProps<{ property: TitleBarProperty }>() </script> <style scoped lang="scss"> .title-bar { + position: relative; + width: 100%; + min-height: 20px; + padding: 8px 16px; border: 2px solid #fff; box-sizing: border-box; - width: 100%; - padding: 8px 16px; - min-height: 20px; - position: relative; /* 更多 */ .more { position: absolute; - right: 8px; top: 0; + right: 8px; bottom: 0; + display: flex; margin: auto; font-size: 10px; color: #969799; - display: flex; align-items: center; justify-content: center; } diff --git a/src/components/DiyEditor/components/mobile/VideoPlayer/index.vue b/src/components/DiyEditor/components/mobile/VideoPlayer/index.vue index a62dea08..fa9a914f 100644 --- a/src/components/DiyEditor/components/mobile/VideoPlayer/index.vue +++ b/src/components/DiyEditor/components/mobile/VideoPlayer/index.vue @@ -23,8 +23,8 @@ defineProps<{ property: VideoPlayerProperty }>() <style scoped lang="scss"> /* 图片 */ img { + display: block; width: 100%; height: 100%; - display: block; } </style> diff --git a/src/components/DiyEditor/index.vue b/src/components/DiyEditor/index.vue index fbb7e103..44cb10a7 100644 --- a/src/components/DiyEditor/index.vue +++ b/src/components/DiyEditor/index.vue @@ -337,28 +337,33 @@ onMounted(() => setDefaultSelectedComponent()) /* 手机宽度 */ $phone-width: 375px; $toolbar-height: 42px; + /* 根节点样式 */ .editor { + display: flex; height: 100%; margin: calc(0px - var(--app-content-padding)); - display: flex; flex-direction: column; + /* 顶部:工具栏 */ .editor-header { display: flex; - align-items: center; - justify-content: space-between; height: $toolbar-height; padding: 0; - border-bottom: solid 1px var(--el-border-color); background-color: var(--el-bg-color); + border-bottom: solid 1px var(--el-border-color); + align-items: center; + justify-content: space-between; + /* 工具栏:右侧按钮 */ .header-right { height: 100%; + .el-button { height: 100%; } } + /* 隐藏工具栏按钮的边框 */ :deep(.el-radio-button__inner), :deep(.el-button) { @@ -367,33 +372,40 @@ $toolbar-height: 42px; border-radius: 0 !important; } } + /* 中心操作区 */ .editor-container { height: calc( 100vh - var(--top-tool-height) - var(--tags-view-height) - var(--app-footer-height) - $toolbar-height ); + /* 右侧属性面板 */ .editor-right { - flex-shrink: 0; - box-shadow: -8px 0 8px -8px rgba(0, 0, 0, 0.12); overflow: hidden; + box-shadow: -8px 0 8px -8px rgb(0 0 0 / 12%); + flex-shrink: 0; + /* 属性面板顶部:减少内边距 */ :deep(.el-card__header) { padding: 8px 16px; } + /* 属性面板分组 */ :deep(.property-group) { margin: 0 -20px; + &.el-card { border: none; } + /* 属性分组名称 */ .el-card__header { - border: none; - background: var(--el-bg-color-page); padding: 8px 32px; + background: var(--el-bg-color-page); + border: none; } + .el-card__body { border: none; } @@ -403,33 +415,36 @@ $toolbar-height: 42px; /* 中心区域 */ .editor-center { position: relative; - flex: 1 1 0; - background-color: var(--app-content-bg-color); display: flex; + width: 100%; + margin: 16px 0 0; + overflow: hidden; + background-color: var(--app-content-bg-color); + flex: 1 1 0; flex-direction: column; justify-content: center; - margin: 16px 0 0 0; - overflow: hidden; - width: 100%; /* 手机顶部 */ .editor-design-top { + display: flex; width: $phone-width; margin: 0 auto; - display: flex; flex-direction: column; + /* 手机顶部状态栏 */ .status-bar { - height: 20px; width: $phone-width; + height: 20px; background-color: #fff; } } + /* 手机底部导航 */ .editor-design-bottom { width: $phone-width; margin: 0 auto; } + /* 手机页面编辑区域 */ :deep(.editor-design-center) { width: 100%; @@ -437,14 +452,15 @@ $toolbar-height: 42px; /* 主体内容 */ .phone-container { position: relative; + width: $phone-width; + height: 100%; + margin: 0 auto; background-repeat: no-repeat; background-size: 100% 100%; - height: 100%; - width: $phone-width; - margin: 0 auto; + .drag-area { - height: 100%; width: 100%; + height: 100%; } } } diff --git a/src/components/UploadFile/src/UploadFile.vue b/src/components/UploadFile/src/UploadFile.vue index 6895440b..c1f3e4e2 100644 --- a/src/components/UploadFile/src/UploadFile.vue +++ b/src/components/UploadFile/src/UploadFile.vue @@ -144,6 +144,8 @@ watch( } else if (isArray(props.modelValue)) { // 情况2:字符串 files.concat(props.modelValue) + } else if (props.modelValue == null) { + // 情况3:undefined 不处理 } else { throw new Error('不支持的 modelValue 类型') } diff --git a/src/components/VerticalButtonGroup/index.vue b/src/components/VerticalButtonGroup/index.vue index 479ed559..9c78ea27 100644 --- a/src/components/VerticalButtonGroup/index.vue +++ b/src/components/VerticalButtonGroup/index.vue @@ -17,24 +17,28 @@ defineOptions({ name: 'VerticalButtonGroup' }) display: inline-flex; flex-direction: column; } + .el-button-group > :deep(.el-button:first-child) { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; - border-top-right-radius: var(--el-border-radius-base); border-bottom-color: var(--el-button-divide-border-color); + border-top-right-radius: var(--el-border-radius-base); + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; } + .el-button-group > :deep(.el-button:last-child) { - border-top-left-radius: 0; + border-top-color: var(--el-button-divide-border-color); border-top-right-radius: 0; border-bottom-left-radius: var(--el-border-radius-base); - border-top-color: var(--el-button-divide-border-color); + border-top-left-radius: 0; } -.el-button-group :deep(.el-button--primary:not(:first-child):not(:last-child)) { + +.el-button-group :deep(.el-button--primary:not(:first-child, :last-child)) { border-top-color: var(--el-button-divide-border-color); border-bottom-color: var(--el-button-divide-border-color); } + .el-button-group > :deep(.el-button:not(:last-child)) { - margin-bottom: -1px; margin-right: 0; + margin-bottom: -1px; } </style> diff --git a/src/layout/components/Message/src/Message.vue b/src/layout/components/Message/src/Message.vue index 3019df29..6bd7724a 100644 --- a/src/layout/components/Message/src/Message.vue +++ b/src/layout/components/Message/src/Message.vue @@ -88,8 +88,8 @@ onMounted(() => { } .message-list { - height: 400px; display: flex; + height: 400px; flex-direction: column; .message-item { diff --git a/src/router/modules/remaining.ts b/src/router/modules/remaining.ts index 58eb1733..ae564fe6 100644 --- a/src/router/modules/remaining.ts +++ b/src/router/modules/remaining.ts @@ -503,6 +503,16 @@ const remainingRouter: AppRouteRecordRaw[] = [ hidden: true }, component: () => import('@/views/crm/customer/detail/index.vue') + }, + { + path: 'contact/detail/:id', + name: 'CrmContactDetail', + meta: { + title: '联系人详情', + noCache: true, + hidden: true + }, + component: () => import('@/views/crm/contact/detail/index.vue') } ] } diff --git a/src/views/crm/contact/ContactForm.vue b/src/views/crm/contact/ContactForm.vue new file mode 100644 index 00000000..94d50299 --- /dev/null +++ b/src/views/crm/contact/ContactForm.vue @@ -0,0 +1,348 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible" :width="800"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="130px" + v-loading="formLoading" + :inline="true" + > + <el-form-item label="姓名" prop="name"> + <el-input v-model="formData.name" placeholder="请输入姓名" /> + </el-form-item> + <el-form-item label="负责人" prop="ownerUserId"> + <el-select + v-model="ownerUserList" + placeholder="请选择负责人" + multiple + value-key="id" + lable-key="nickname" + @click="openOwerForm('open')" + > + <el-option + v-for="item in ownerUserList" + :key="item.id" + :label="item.nickname" + :value="item" + /> + </el-select> + </el-form-item> + <el-form-item label="客户名称" prop="customerName"> + <el-popover + placement="bottom" + :width="600" + trigger="click" + :teleported="false" + :visible="showCustomer" + :offset="10" + > + <template #reference> + <el-input + placeholder="请选择" + @click="openCustomerSelect" + v-model="formData.customerName" + /> + </template> + <el-table :data="list" ref="multipleTableRef" @select="handleSelectionChange"> + <el-table-column label="选择" type="selection" width="55" /> + <el-table-column width="100" property="id" label="编号" /> + <el-table-column width="150" property="name" label="客户名称" /> + <el-table-column label="客户来源" align="center" prop="source" width="100"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_SOURCE" :value="scope.row.source" /> + </template> + </el-table-column> + <el-table-column label="客户等级" align="center" prop="level" width="120"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.CRM_CUSTOMER_LEVEL" :value="scope.row.level" /> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <el-row :gutter="20"> + <el-col> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + layout="sizes, prev, pager, next" + /> + </el-col> + </el-row> + <el-row :gutter="20"> + <el-col :span="10" :offset="13"> + <el-button @click="selectCustomer">确认</el-button> + <el-button @click="showCustomer = false">取消</el-button> + </el-col> + </el-row> + </el-popover> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select v-model="formData.sex" placeholder="请选择"> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + + <el-form-item label="手机号" prop="mobile"> + <el-input v-model="formData.mobile" placeholder="请输入手机号" /> + </el-form-item> + <el-form-item label="座机" prop="telephone"> + <el-input v-model="formData.telephone" placeholder="请输入座机" style="width: 215px" /> + </el-form-item> + <el-form-item label="邮箱" prop="email"> + <el-input v-model="formData.email" placeholder="请输入邮箱" /> + </el-form-item> + <el-form-item label="QQ" prop="qq"> + <el-input v-model="formData.qq" placeholder="请输入QQ" style="width: 215px" /> + </el-form-item> + <el-form-item label="微信" prop="webchat"> + <el-input v-model="formData.webchat" placeholder="请输入微信" /> + </el-form-item> + <el-form-item label="下次联系时间" prop="nextTime"> + <el-date-picker + v-model="formData.nextTime" + type="date" + value-format="x" + placeholder="选择下次联系时间" + /> + </el-form-item> + <el-form-item label="地址" prop="address"> + <el-input v-model="formData.address" placeholder="请输入地址" /> + </el-form-item> + <el-form-item label="直属上级" prop="parentId"> + <el-select v-model="formData.parentId" placeholder="请选择"> + <el-option + v-for="item in allContactList" + :key="item.id" + :label="item.name" + :value="item.id" + :disabled="item.id == formData.id" + /> + </el-select> + </el-form-item> + + <el-form-item label="职位" prop="post"> + <el-input v-model="formData.post" placeholder="请输入职位" /> + </el-form-item> + + <el-form-item label="是否关键决策人" prop="policyMakers" style="width: 400px"> + <el-radio-group v-model="formData.policyMakers"> + <el-radio + v-for="dict in getBoolDictOptions(DICT_TYPE.INFRA_BOOLEAN_STRING)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="备注" prop="remark"> + <el-input v-model="formData.remark" placeholder="请输入备注" /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> + <OwerSelect + ref="owerRef" + @confirmOwerSelect="owerSelectValue" + :initOwerUser="formData.ownerUserId" + /> +</template> +<script setup lang="ts"> +import * as ContactApi from '@/api/crm/contact' +import { DICT_TYPE, getIntDictOptions, getBoolDictOptions } from '@/utils/dict' +import OwerSelect from './OwerSelect.vue' +import * as UserApi from '@/api/system/user' +import * as CustomerApi from '@/api/crm/customer' +import { ElTable } from 'element-plus' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + nextTime: undefined, + mobile: undefined, + telephone: undefined, + email: undefined, + customerId: undefined, + customerName: undefined, + address: undefined, + remark: undefined, + ownerUserId: undefined, + lastTime: undefined, + id: undefined, + parentId: undefined, + name: undefined, + post: undefined, + qq: undefined, + webchat: undefined, + sex: undefined, + policyMakers: undefined +}) +const loading = ref(true) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref([]) // 列表的数据 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + name: null, + mobile: null, + industryId: null, + level: null, + source: null +}) +const formRules = reactive({ + name: [{ required: true, message: '姓名不能为空', trigger: 'blur' }], + customerId: [{ required: true, message: '客户不能为空', trigger: 'blur' }], + ownerUserId: [{ required: true, message: '负责人不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref +const ownerUserList = ref<any[]>([]) +const userList = ref<UserApi.UserVO[]>([]) // 用户列表 +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + allContactList.value = await ContactApi.simpleAlllist() + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await ContactApi.getContact(id) + userList.value = await UserApi.getSimpleUserList() + await gotOwnerUser(formData.value.ownerUserId) + } finally { + formLoading.value = false + } + } +} +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await CustomerApi.getCustomerPage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 +const gotOwnerUser = (owerUserId: any) => { + if (owerUserId !== null) { + owerUserId.split(',').forEach((item: string) => { + userList.value.find((user: { id: any }) => { + if (user.id == item) { + ownerUserList.value.push(user) + } + }) + }) + } +} +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + owerSelectValue(ownerUserList) + // 校验表单 + if (!formRef) return + const valid = await formRef.value.validate() + if (!valid) return + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as ContactApi.ContactVO + if (formType.value === 'create') { + await ContactApi.createContact(data) + message.success(t('common.createSuccess')) + } else { + await ContactApi.updateContact(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + nextTime: undefined, + mobile: undefined, + telephone: undefined, + email: undefined, + customerId: undefined, + address: undefined, + remark: undefined, + ownerUserId: undefined, + lastTime: undefined, + id: undefined, + parentId: undefined, + name: undefined, + post: undefined, + qq: undefined, + webchat: undefined, + sex: undefined, + policyMakers: undefined + } + formRef.value?.resetFields() + ownerUserList.value = [] +} +/** 添加/修改操作 */ +const owerRef = ref() +const openOwerForm = (type: string) => { + owerRef.value.open(type, ownerUserList.value) +} + +const owerSelectValue = (value) => { + ownerUserList.value = value.value + formData.value.ownerUserId = undefined + value.value.forEach((item, index) => { + if (index != 0) { + formData.value.ownerUserId = formData.value.ownerUserId + ',' + item.id + } else { + formData.value.ownerUserId = item.id + } + }) +} +//选择客户 +const showCustomer = ref(false) +const openCustomerSelect = () => { + showCustomer.value = !showCustomer.value + queryParams.pageNo = 1 + getList() +} +const multipleTableRef = ref<InstanceType<typeof ElTable>>() +const multipleSelection = ref() +const handleSelectionChange = ({}, row) => { + multipleSelection.value = row + multipleTableRef.value!.clearSelection() + multipleTableRef.value!.toggleRowSelection(row, undefined) +} +const selectCustomer = () => { + formData.value.customerId = multipleSelection.value.id + formData.value.customerName = multipleSelection.value.name + showCustomer.value = !showCustomer.value +} +const allContactList = ref([]) //所有联系人列表 +onMounted(async () => { + allContactList.value = await ContactApi.simpleAlllist() +}) +</script> diff --git a/src/views/crm/contact/OwerSelect.vue b/src/views/crm/contact/OwerSelect.vue new file mode 100644 index 00000000..83dd143b --- /dev/null +++ b/src/views/crm/contact/OwerSelect.vue @@ -0,0 +1,71 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible" width="600px"> + <el-transfer + v-model="value" + :data="data" + :titles="transferTitles" + :props="transferDataProp" + :right-default-checked="[1]" + /> + <el-row justify="end"> + <el-col :span="4"> + <el-button type="primary" @click="confirmOwerSelect">确认</el-button> + </el-col> + <el-col :span="4"> + <el-button type="primary" @click="confirmOwerSelect">取消</el-button> + </el-col> + </el-row> + </Dialog> +</template> +<script setup lang="ts"> +import * as UserApi from '@/api/system/user' +import { parseBigInt } from 'jsencrypt/lib/lib/jsbn/jsbn' +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('选择') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') +const transferTitles = ref(['待选择', '已选择']) +const transferDataProp = ref({ + key: 'id', + label: 'nickname' +}) +const emit = defineEmits(['confirmOwerSelect']) +const data = ref<UserApi.UserVO[]>([]) +const value = ref<any[]>([]) +const rightDefaultChecked = ref<any[]>([]) +/** 打开弹窗 */ +const open = async (type: string, ownerUserList: any[]) => { + dialogVisible.value = true + formType.value = type + // 修改时,设置数据 + if (ownerUserList) { + formLoading.value = true + try { + ownerUserList.forEach((item) => { + value.value.push(item.id) + }) + } finally { + formLoading.value = false + } + } + rightDefaultChecked.value = [] + data.value = await UserApi.getSimpleUserList() +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 +const confirmOwerSelect = () => { + const returnData = ref<any[]>([]) + data.value.forEach((item) => { + if (value.value.indexOf(item.id) > -1) { + returnData.value.push(item) + } + }) + emit('confirmOwerSelect', returnData) + dialogVisible.value = false + value.value = [] +} +</script> +<style> +.el-row { + margin-top: 20px; +} +</style> diff --git a/src/views/crm/contact/detail/ContactBasicInfo.vue b/src/views/crm/contact/detail/ContactBasicInfo.vue new file mode 100644 index 00000000..68e37d28 --- /dev/null +++ b/src/views/crm/contact/detail/ContactBasicInfo.vue @@ -0,0 +1,23 @@ +<!-- + * @Author: zyna + * @Date: 2023-11-11 14:50:11 + * @LastEditTime: 2023-11-11 14:52:47 + * @FilePath: \yudao-ui-admin-vue3\src\views\crm\contact\detail\ContactBasicInfo.vue + * @Description: +--> +<template> + <el-col> + <el-row> + <span class="text-xl font-bold">{{ contact.name }}</span> + </el-row> + </el-col> + <el-col class="mt-10px"> + <!-- TODO 标签 --> + <!-- <Icon icon="ant-design:tag-filled" />--> + </el-col> +</template> +<script setup lang="ts"> +import * as ContactApi from '@/api/crm/contact' + +const { contact } = defineProps<{ contact: ContactApi.ContactVO }>() +</script> diff --git a/src/views/crm/contact/detail/ContactDetails.vue b/src/views/crm/contact/detail/ContactDetails.vue new file mode 100644 index 00000000..5091b691 --- /dev/null +++ b/src/views/crm/contact/detail/ContactDetails.vue @@ -0,0 +1,93 @@ +<template> + <el-collapse v-model="activeNames"> + <el-collapse-item name="basicInfo"> + <template #title> + <span class="text-base font-bold">基本信息</span> + </template> + <el-descriptions :column="4"> + <el-descriptions-item label="姓名"> + {{ contact.name }} + </el-descriptions-item> + <el-descriptions-item label="客户名称"> + {{ contact.customerName }} + </el-descriptions-item> + <el-descriptions-item label="手机"> + {{ contact.mobile }} + </el-descriptions-item> + <el-descriptions-item label="座机"> + {{ contact.telephone }} + </el-descriptions-item> + <el-descriptions-item label="邮箱"> + {{ contact.email }} + </el-descriptions-item> + <el-descriptions-item label="QQ"> + {{ contact.qq }} + </el-descriptions-item> + <el-descriptions-item label="微信"> + {{ contact.webchat }} + </el-descriptions-item> + <el-descriptions-item label="详细地址"> + {{ contact.address }} + </el-descriptions-item> + <el-descriptions-item label="下次联系时间"> + {{ contact.nextTime ? formatDate(contact.nextTime) : '空' }} + </el-descriptions-item> + <el-descriptions-item label="性别"> + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="contact.sex" /> + </el-descriptions-item> + <el-descriptions-item label="备注"> + {{ contact.remark }} + </el-descriptions-item> + </el-descriptions> + </el-collapse-item> + <el-collapse-item name="systemInfo"> + <template #title> + <span class="text-base font-bold">系统信息</span> + </template> + <el-descriptions :column="2"> + <el-descriptions-item label="负责人"> + {{ gotOwnerUser(contact.ownerUserId) }} + </el-descriptions-item> + <el-descriptions-item label="创建人"> + {{ contact.creatorName }} + </el-descriptions-item> + <el-descriptions-item label="创建时间"> + {{ contact.createTime ? formatDate(contact.createTime) : '空' }} + </el-descriptions-item> + <el-descriptions-item label="更新时间"> + {{ contact.updateTime ? formatDate(contact.updateTime) : '空' }} + </el-descriptions-item> + </el-descriptions> + </el-collapse-item> + </el-collapse> +</template> +<script setup lang="ts"> +import * as ContactApi from '@/api/crm/contact' +import { DICT_TYPE } from '@/utils/dict' +import { formatDate } from '@/utils/formatTime' +import * as UserApi from '@/api/system/user' +const { contact } = defineProps<{ contact: ContactApi.ContactVO }>() + +// 展示的折叠面板 +const activeNames = ref(['basicInfo', 'systemInfo']) +const gotOwnerUser = (owerUserId: string) => { + let ownerName = '' + if (owerUserId !== null && owerUserId != undefined) { + owerUserId.split(',').forEach((item: string, index: number) => { + if (index != 0) { + ownerName = + ownerName + ',' + userList.value.find((user: { id: any }) => user.id == item)?.nickname + } else { + ownerName = userList.value.find((user: { id: any }) => user.id == item)?.nickname || '' + } + }) + } + return ownerName +} +const userList = ref<UserApi.UserVO[]>([]) // 用户列表 +/** 初始化 **/ +onMounted(async () => { + userList.value = await UserApi.getSimpleUserList() +}) +</script> +<style scoped lang="scss"></style> diff --git a/src/views/crm/contact/detail/index.vue b/src/views/crm/contact/detail/index.vue new file mode 100644 index 00000000..3ab5778b --- /dev/null +++ b/src/views/crm/contact/detail/index.vue @@ -0,0 +1,147 @@ +<template> + <div v-loading="loading"> + <div class="flex items-start justify-between"> + <div> + <!-- 左上:客户基本信息 --> + <ContactBasicInfo :contact="contact" /> + </div> + <div> + <!-- 右上:按钮 --> + <el-button @click="openForm('update', contact.id)" v-hasPermi="['crm:contact:update']"> + 编辑 + </el-button> + </div> + </div> + <el-row class="mt-10px"> + <el-button> + <Icon icon="ph:calendar-fill" class="mr-5px" /> + 创建任务 + </el-button> + <el-button> + <Icon icon="carbon:email" class="mr-5px" /> + 发送邮件 + </el-button> + <el-button> + <Icon icon="system-uicons:contacts" class="mr-5px" /> + 创建联系人 + </el-button> + <el-button> + <Icon icon="ep:opportunity" class="mr-5px" /> + 创建商机 + </el-button> + <el-button> + <Icon icon="clarity:contract-line" class="mr-5px" /> + 创建合同 + </el-button> + <el-button> + <Icon icon="icon-park:income-one" class="mr-5px" /> + 创建回款 + </el-button> + <el-button> + <Icon icon="fluent:people-team-add-20-filled" class="mr-5px" /> + 添加团队成员 + </el-button> + </el-row> + </div> + <ContentWrap class="mt-10px"> + <el-descriptions :column="5" direction="vertical"> + <el-descriptions-item label="客户名称"> + {{ contact.customerName }} + </el-descriptions-item> + <el-descriptions-item label="职务"> + {{ contact.post }} + </el-descriptions-item> + <el-descriptions-item label="手机"> + {{ contact.mobile }} + </el-descriptions-item> + <el-descriptions-item label="创建时间"> + {{ contact.createTime ? formatDate(contact.createTime) : '空' }} + </el-descriptions-item> + </el-descriptions> + </ContentWrap> + <!-- TODO wanwan:这个 tab 拉满哈,可以更好看; --> + <el-col :span="18"> + <el-tabs> + <el-tab-pane label="详细资料"> + <!-- TODO wanwan:这个 ml-2 是不是可以优化下,不要整个左移,而是里面的内容有个几 px 的偏移,不顶在框里 --> + <ContactDetails class="ml-2" :contact="contact" /> + </el-tab-pane> + <el-tab-pane label="活动" lazy> 活动</el-tab-pane> + <el-tab-pane label="邮件" lazy> 邮件</el-tab-pane> + <el-tab-pane label="工商信息" lazy> 工商信息</el-tab-pane> + <!-- TODO wanwan 以下标签上的数量需要接口统计返回 --> + <el-tab-pane label="客户" lazy> + <template #label> 客户<el-badge :value="12" class="item" type="primary" /> </template> + 客户 + </el-tab-pane> + <el-tab-pane label="团队成员" lazy> + <template #label> 团队成员<el-badge :value="2" class="item" type="primary" /> </template> + 团队成员 + </el-tab-pane> + <el-tab-pane label="商机" lazy> 商机</el-tab-pane> + <el-tab-pane label="合同" lazy> + <template #label> 合同<el-badge :value="3" class="item" type="primary" /> </template> + 合同 + </el-tab-pane> + <el-tab-pane label="回款" lazy> + <template #label> 回款<el-badge :value="4" class="item" type="primary" /> </template> + 回款 + </el-tab-pane> + <el-tab-pane label="回访" lazy> 回访</el-tab-pane> + <el-tab-pane label="发票" lazy> 发票</el-tab-pane> + </el-tabs> + </el-col> + + <!-- 表单弹窗:添加/修改 --> + <ContactForm ref="formRef" @success="getContactData(id)" /> +</template> + +<script setup lang="ts"> +import { ElMessage } from 'element-plus' +import { useTagsViewStore } from '@/store/modules/tagsView' +import * as ContactApi from '@/api/crm/contact' +import ContactBasicInfo from '@/views/crm/contact/detail/ContactBasicInfo.vue' +import ContactDetails from '@/views/crm/contact/detail/ContactDetails.vue' +import ContactForm from '@/views/crm/contact/ContactForm.vue' +import { formatDate } from '@/utils/formatTime' +import * as CustomerApi from '@/api/crm/customer' + +defineOptions({ name: 'ContactDetail' }) +const { delView } = useTagsViewStore() // 视图操作 +const route = useRoute() +const { currentRoute } = useRouter() // 路由 +const id = Number(route.params.id) +const loading = ref(true) // 加载中 +// 联系人详情 +const contact = ref<ContactApi.ContactVO>({} as ContactApi.ContactVO) +/** + * 获取详情 + * + * @param id + */ +const getContactData = async (id: number) => { + loading.value = true + try { + contact.value = await ContactApi.getContact(id) + } finally { + loading.value = false + } +} + +const formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) +} + +/** + * 初始化 + */ +onMounted(async () => { + if (!id) { + ElMessage.warning('参数错误,联系人不能为空!') + delView(unref(currentRoute)) + return + } + await getContactData(id) +}) +</script> diff --git a/src/views/crm/contact/index.vue b/src/views/crm/contact/index.vue new file mode 100644 index 00000000..3e0b3526 --- /dev/null +++ b/src/views/crm/contact/index.vue @@ -0,0 +1,333 @@ +<template> + <ContentWrap> + <!-- 搜索工作栏 --> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="客户编号" prop="customerId"> + <el-input + v-model="queryParams.customerId" + placeholder="请输入客户编号" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="姓名" prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入姓名" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="手机号" prop="mobile"> + <el-input + v-model="queryParams.mobile" + placeholder="请输入手机号" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="座机" prop="telephone"> + <el-input + v-model="queryParams.telephone" + placeholder="请输入电话" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + + <el-form-item label="QQ" prop="qq"> + <el-input + v-model="queryParams.qq" + placeholder="请输入QQ" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="微信" prop="webchat"> + <el-input + v-model="queryParams.webchat" + placeholder="请输入微信" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="电子邮箱" prop="email"> + <el-input + v-model="queryParams.email" + placeholder="请输入电子邮箱" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> + <el-button type="primary" @click="openForm('create')" v-hasPermi="['crm:contact:create']"> + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-button + type="success" + plain + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['crm:contact:export']" + > + <Icon icon="ep:download" class="mr-5px" /> 导出 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="姓名" fixed="left" align="center" prop="name"> + <template #default="scope"> + <el-link type="primary" :underline="false" @click="openDetail(scope.row.id)">{{ + scope.row.name + }}</el-link> + </template> + </el-table-column> + <el-table-column label="客户名称" fixed="left" align="center" prop="customerName" /> + <el-table-column label="性别" align="center" prop="sex"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> + </template> + </el-table-column> + <el-table-column label="职位" align="center" prop="post" /> + <el-table-column label="是否关键决策人" align="center" prop="policyMakers"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.policyMakers" /> + </template> + </el-table-column> + <el-table-column label="直属上级" align="center" prop="parentId"> + <template #default="scope"> + {{ allContactList.find((contact) => contact.id === scope.row.parentId)?.name }} + </template> + </el-table-column> + <el-table-column label="手机号" align="center" prop="mobile" /> + <el-table-column label="座机" align="center" prop="telephone" /> + <el-table-column label="QQ" align="center" prop="qq" /> + <el-table-column label="微信" align="center" prop="webchat" /> + <el-table-column label="邮箱" align="center" prop="email" /> + <el-table-column label="地址" align="center" prop="address" /> + <el-table-column + label="下次联系时间" + align="center" + prop="nextTime" + width="180px" + :formatter="dateFormatter" + /> + <el-table-column label="备注" align="center" prop="remark" /> + <el-table-column + label="最后跟进时间" + align="center" + prop="lastTime" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="负责人" align="center" prop="ownerUserId"> + <template #default="scope"> + {{ gotOwnerUser(scope.row.ownerUserId) }} + </template> + </el-table-column> + <!-- <el-table-column label="所属部门" align="center" prop="ownerUserId" /> --> + <el-table-column + label="更新时间" + align="center" + prop="updateTime" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + <!-- <el-table-column + label="创建人" + align="center" + prop="creator" + :formatter="dateFormatter" + width="180px" + > + <template #default="scope"> + {{ userList.find((user) => user.id === scope.row.creator)?.nickname }} + </template> + </el-table-column> --> + <el-table-column label="操作" align="center" fixed="right" width="200"> + <template #default="scope"> + <el-button + plain + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['crm:contact:update']" + > + 编辑 + </el-button> + <el-button + plain + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['crm:contact:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <ContactForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import { dateFormatter } from '@/utils/formatTime' +import download from '@/utils/download' +import * as ContactApi from '@/api/crm/contact' +import ContactForm from './ContactForm.vue' +import { DICT_TYPE } from '@/utils/dict' +import * as UserApi from '@/api/system/user' +import * as CustomerApi from '@/api/crm/customer' + +defineOptions({ name: 'CrmContact' }) +const message = useMessage() // 消息弹窗 +const { t } = useI18n() // 国际化 + +const loading = ref(true) // 列表的加载中 +const total = ref(0) // 列表的总页数 +const list = ref([]) // 列表的数据 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + nextTime: [], + mobile: null, + telephone: null, + email: null, + customerId: null, + address: null, + remark: null, + ownerUserId: null, + createTime: [], + lastTime: [], + parentId: null, + name: null, + post: null, + qq: null, + webchat: null, + sex: null, + policyMakers: null +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 +const userList = ref<UserApi.UserVO[]>([]) // 用户列表 +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await ContactApi.getContactPage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() +} + +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await ContactApi.deleteContact(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await ContactApi.exportContact(queryParams) + download.excel(data, '联系人.xls') + } catch { + } finally { + exportLoading.value = false + } +} +const gotOwnerUser = (owerUserId: string) => { + let ownerName = '' + if (owerUserId !== null) { + owerUserId.split(',').forEach((item: string, index: number) => { + if (index != 0) { + ownerName = + ownerName + ',' + userList.value.find((user: { id: any }) => user.id == item)?.nickname + } else { + ownerName = userList.value.find((user: { id: any }) => user.id == item)?.nickname || '' + } + }) + } + return ownerName +} +/** 详情页面 */ +/** 打开客户详情 */ +const { push } = useRouter() +const openDetail = (id: number) => { + push({ name: 'CrmContactDetail', params: { id } }) +} + +const allContactList = ref([]) //所有联系人列表 +const allCustomerList = ref([]) //客户列表 +/** 初始化 **/ +onMounted(async () => { + await getList() + userList.value = await UserApi.getSimpleUserList() + allContactList.value = await ContactApi.simpleAlllist() +}) +</script> diff --git a/src/views/infra/codegen/EditTable.vue b/src/views/infra/codegen/EditTable.vue index 9c4e7657..c94e0da6 100644 --- a/src/views/infra/codegen/EditTable.vue +++ b/src/views/infra/codegen/EditTable.vue @@ -8,7 +8,7 @@ <colum-info-form ref="columInfoRef" :columns="formData.columns" /> </el-tab-pane> <el-tab-pane label="生成信息" name="generateInfo"> - <generate-info-form ref="generateInfoRef" :table="formData.table" /> + <generate-info-form ref="generateInfoRef" :table="formData.table" :columns="formData.columns" /> </el-tab-pane> </el-tabs> <el-form> diff --git a/src/views/infra/codegen/PreviewCode.vue b/src/views/infra/codegen/PreviewCode.vue index b04775ec..b6a307d2 100644 --- a/src/views/infra/codegen/PreviewCode.vue +++ b/src/views/infra/codegen/PreviewCode.vue @@ -20,8 +20,8 @@ ref="treeRef" :data="preview.fileTree" :expand-on-click-node="false" - highlight-current default-expand-all + highlight-current node-key="id" @node-click="handleNodeClick" /> diff --git a/src/views/infra/codegen/components/GenerateInfoForm.vue b/src/views/infra/codegen/components/GenerateInfoForm.vue index 744edfe6..d2a01cc0 100644 --- a/src/views/infra/codegen/components/GenerateInfoForm.vue +++ b/src/views/infra/codegen/components/GenerateInfoForm.vue @@ -3,7 +3,7 @@ <el-row> <el-col :span="12"> <el-form-item label="生成模板" prop="templateType"> - <el-select v-model="formData.templateType" @change="tplSelectChange"> + <el-select v-model="formData.templateType"> <el-option v-for="dict in getIntDictOptions(DICT_TYPE.INFRA_CODEGEN_TEMPLATE_TYPE)" :key="dict.value" @@ -182,50 +182,33 @@ </el-col> </el-row> - <el-row v-show="formData.tplCategory === 'tree'"> - <h4 class="form-header">其他信息</h4> - <el-col :span="12"> - <el-form-item> - <template #label> - <span> - 树编码字段 - <el-tooltip content="树显示的编码字段名, 如:dept_id" placement="top"> - <Icon icon="ep:question-filled" /> - </el-tooltip> - </span> - </template> - <el-select v-model="formData.treeCode" placeholder="请选择"> - <el-option - v-for="(column, index) in formData.columns" - :key="index" - :label="column.columnName + ':' + column.columnComment" - :value="column.columnName" - /> - </el-select> - </el-form-item> + <!-- 树表信息 --> + <el-row v-if="formData.templateType == 2"> + <el-col :span="24"> + <h4 class="form-header">树表信息</h4> </el-col> <el-col :span="12"> - <el-form-item> + <el-form-item prop="treeParentColumnId"> <template #label> <span> - 树父编码字段 + 父编号字段 <el-tooltip content="树显示的父编码字段名, 如:parent_Id" placement="top"> <Icon icon="ep:question-filled" /> </el-tooltip> </span> </template> - <el-select v-model="formData.treeParentCode" placeholder="请选择"> + <el-select v-model="formData.treeParentColumnId" placeholder="请选择"> <el-option - v-for="(column, index) in formData.columns" + v-for="(column, index) in props.columns" :key="index" :label="column.columnName + ':' + column.columnComment" - :value="column.columnName" + :value="column.id" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> - <el-form-item> + <el-form-item prop="treeNameColumnId"> <template #label> <span> 树名称字段 @@ -234,60 +217,79 @@ </el-tooltip> </span> </template> - - <el-select v-model="formData.treeName" placeholder="请选择"> + <el-select v-model="formData.treeNameColumnId" placeholder="请选择"> <el-option - v-for="(column, index) in formData.columns" + v-for="(column, index) in props.columns" :key="index" :label="column.columnName + ':' + column.columnComment" - :value="column.columnName" + :value="column.id" /> </el-select> </el-form-item> </el-col> </el-row> - <el-row v-show="formData.tplCategory === 'sub'"> - <h4 class="form-header">关联信息</h4> + + <!-- 主表信息 --> + <el-row v-if="formData.templateType == 15"> + <el-col :span="24"> + <h4 class="form-header">主表信息</h4> + </el-col> <el-col :span="12"> - <el-form-item> + <el-form-item prop="masterTableId"> <template #label> <span> - 关联子表的表名 - <el-tooltip content="关联子表的表名, 如:sys_user" placement="top"> + 关联的主表 + <el-tooltip content="关联主表(父表)的表名, 如:system_user" placement="top"> <Icon icon="ep:question-filled" /> </el-tooltip> </span> </template> - <el-select v-model="formData.subTableName" placeholder="请选择" @change="subSelectChange"> + <el-select v-model="formData.masterTableId" placeholder="请选择"> <el-option v-for="(table0, index) in tables" :key="index" :label="table0.tableName + ':' + table0.tableComment" - :value="table0.tableName" + :value="table0.id" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> - <el-form-item> + <el-form-item prop="subJoinColumnId"> <template #label> <span> - 子表关联的外键名 - <el-tooltip content="子表关联的外键名, 如:user_id" placement="top"> + 子表关联的字段 + <el-tooltip content="子表关联的字段, 如:user_id" placement="top"> <Icon icon="ep:question-filled" /> </el-tooltip> </span> </template> - <el-select v-model="formData.subTableFkName" placeholder="请选择"> + <el-select v-model="formData.subJoinColumnId" placeholder="请选择"> <el-option - v-for="(column, index) in subColumns" + v-for="(column, index) in props.columns" :key="index" :label="column.columnName + ':' + column.columnComment" - :value="column.columnName" + :value="column.id" /> </el-select> </el-form-item> </el-col> + <el-col :span="12"> + <el-form-item prop="subJoinMany"> + <template #label> + <span> + 关联关系 + <el-tooltip content="主表与子表的关联关系" placement="top"> + <Icon icon="ep:question-filled" /> + </el-tooltip> + </span> + </template> + <el-radio-group v-model="formData.subJoinMany" placeholder="请选择"> + <el-radio :label="true">一对多</el-radio> + <el-radio :label="false">一对一</el-radio> + </el-radio-group> + </el-form-item> + </el-col> </el-row> </el-form> </template> @@ -305,6 +307,10 @@ const props = defineProps({ table: { type: Object as PropType<Nullable<CodegenApi.CodegenTableVO>>, default: () => null + }, + columns: { + type: Array as unknown as PropType<CodegenApi.CodegenColumnVO[]>, + default: () => null } }) @@ -319,13 +325,12 @@ const formData = ref({ classComment: '', parentMenuId: null, genPath: '', - treeCode: '', - treeParentCode: '', - treeName: '', - tplCategory: '', - subTableName: '', - subTableFkName: '', - genType: '' + genType: '', + masterTableId: undefined, + subJoinColumnId: undefined, + subJoinMany: undefined, + treeParentColumnId: undefined, + treeNameColumnId: undefined }) const rules = reactive({ @@ -336,41 +341,29 @@ const rules = reactive({ businessName: [required], businessPackage: [required], className: [required], - classComment: [required] + classComment: [required], + masterTableId: [required], + subJoinColumnId: [required], + subJoinMany: [required], + treeParentColumnId: [required], + treeNameColumnId: [required] }) -const tables = ref([]) -const subColumns = ref([]) +const tables = ref([]) // 表定义列表 const menus = ref<any[]>([]) const menuTreeProps = { label: 'name' } -/** 选择子表名触发 */ -const subSelectChange = () => { - formData.value.subTableFkName = '' -} - -/** 选择生成模板触发 */ -const tplSelectChange = (value) => { - if (value !== 1) { - // TODO 芋艿:暂时不考虑支持树形结构 - message.error( - '暂时不考虑支持【树形】和【主子表】的代码生成。原因是:导致 vm 模板过于复杂,不利于胖友二次开发' - ) - return false - } - if (value !== 'sub') { - formData.value.subTableName = '' - formData.value.subTableFkName = '' - } -} - watch( () => props.table, - (table) => { + async (table) => { if (!table) return formData.value = table as any + // 加载表列表 + if (table.dataSourceConfigId >= 0) { + tables.value = await CodegenApi.getCodegenTableList(formData.value.dataSourceConfigId) + } }, { deep: true, @@ -380,6 +373,7 @@ watch( onMounted(async () => { try { + // 加载菜单 const resp = await MenuApi.getSimpleMenusList() menus.value = handleTree(resp) } catch {} diff --git a/src/views/infra/codegen/index.vue b/src/views/infra/codegen/index.vue index e06281c7..69c3d125 100644 --- a/src/views/infra/codegen/index.vue +++ b/src/views/infra/codegen/index.vue @@ -1,5 +1,7 @@ <template> - <doc-alert title="代码生成" url="https://doc.iocoder.cn/new-feature/" /> + <doc-alert title="代码生成(单表)" url="https://doc.iocoder.cn/new-feature/" /> + <doc-alert title="代码生成(树表)" url="https://doc.iocoder.cn/new-feature/tree/" /> + <doc-alert title="代码生成(主子表)" url="https://doc.iocoder.cn/new-feature/master-sub/" /> <doc-alert title="单元测试" url="https://doc.iocoder.cn/unit-test/" /> <!-- 搜索 --> diff --git a/src/views/infra/demo/demo01/Demo01ContactForm.vue b/src/views/infra/demo/demo01/Demo01ContactForm.vue new file mode 100644 index 00000000..0452a3c0 --- /dev/null +++ b/src/views/infra/demo/demo01/Demo01ContactForm.vue @@ -0,0 +1,126 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-radio-group v-model="formData.sex"> + <el-radio + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="出生年" prop="birthday"> + <el-date-picker + v-model="formData.birthday" + type="date" + value-format="x" + placeholder="选择出生年" + /> + </el-form-item> + <el-form-item label="简介" prop="description"> + <Editor v-model="formData.description" height="150px" /> + </el-form-item> + <el-form-item label="头像" prop="avatar"> + <UploadImg v-model="formData.avatar" /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' +import * as Demo01ContactApi from '@/api/infra/demo/demo01' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + name: undefined, + sex: undefined, + birthday: undefined, + description: undefined, + avatar: undefined +}) +const formRules = reactive({ + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + sex: [{ required: true, message: '性别不能为空', trigger: 'blur' }], + birthday: [{ required: true, message: '出生年不能为空', trigger: 'blur' }], + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo01ContactApi.getDemo01Contact(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as Demo01ContactApi.Demo01ContactVO + if (formType.value === 'create') { + await Demo01ContactApi.createDemo01Contact(data) + message.success(t('common.createSuccess')) + } else { + await Demo01ContactApi.updateDemo01Contact(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + name: undefined, + sex: undefined, + birthday: undefined, + description: undefined, + avatar: undefined + } + formRef.value?.resetFields() +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo01/index.vue b/src/views/infra/demo/demo01/index.vue new file mode 100644 index 00000000..e111ab63 --- /dev/null +++ b/src/views/infra/demo/demo01/index.vue @@ -0,0 +1,214 @@ +<template> + <doc-alert title="代码生成(单表)" url="https://doc.iocoder.cn/new-feature/" /> + + <ContentWrap> + <!-- 搜索工作栏 --> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="名字" prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入名字" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select v-model="queryParams.sex" placeholder="请选择性别" clearable class="!w-240px"> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="创建时间" prop="createTime"> + <el-date-picker + v-model="queryParams.createTime" + value-format="YYYY-MM-DD HH:mm:ss" + type="daterange" + start-placeholder="开始日期" + end-placeholder="结束日期" + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo01-contact:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-button + type="success" + plain + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['infra:demo01-contact:export']" + > + <Icon icon="ep:download" class="mr-5px" /> 导出 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="性别" align="center" prop="sex"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> + </template> + </el-table-column> + <el-table-column + label="出生年" + align="center" + prop="birthday" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="简介" align="center" prop="description" /> + <el-table-column label="头像" align="center" prop="avatar" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo01-contact:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo01-contact:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <Demo01ContactForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' +import { dateFormatter } from '@/utils/formatTime' +import download from '@/utils/download' +import * as Demo01ContactApi from '@/api/infra/demo/demo01' +import Demo01ContactForm from './Demo01ContactForm.vue' + +defineOptions({ name: 'Demo01Contact' }) + +const message = useMessage() // 消息弹窗 +const { t } = useI18n() // 国际化 + +const loading = ref(true) // 列表的加载中 +const list = ref([]) // 列表的数据 +const total = ref(0) // 列表的总页数 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + name: null, + sex: null, + createTime: [] +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo01ContactApi.getDemo01ContactPage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() +} + +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await Demo01ContactApi.deleteDemo01Contact(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await Demo01ContactApi.exportDemo01Contact(queryParams) + download.excel(data, '示例联系人.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> diff --git a/src/views/infra/demo/demo02/Demo02CategoryForm.vue b/src/views/infra/demo/demo02/Demo02CategoryForm.vue new file mode 100644 index 00000000..9002d5ee --- /dev/null +++ b/src/views/infra/demo/demo02/Demo02CategoryForm.vue @@ -0,0 +1,114 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="父级编号" prop="parentId"> + <el-tree-select + v-model="formData.parentId" + :data="demo02CategoryTree" + :props="defaultProps" + check-strictly + default-expand-all + placeholder="请选择父级编号" + /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import * as Demo02CategoryApi from '@/api/infra/demo/demo02' +import { defaultProps, handleTree } from '@/utils/tree' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + name: undefined, + parentId: undefined +}) +const formRules = reactive({ + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + parentId: [{ required: true, message: '父级编号不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref +const demo02CategoryTree = ref() // 树形结构 + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo02CategoryApi.getDemo02Category(id) + } finally { + formLoading.value = false + } + } + await getDemo02CategoryTree() +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as Demo02CategoryApi.Demo02CategoryVO + if (formType.value === 'create') { + await Demo02CategoryApi.createDemo02Category(data) + message.success(t('common.createSuccess')) + } else { + await Demo02CategoryApi.updateDemo02Category(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + name: undefined, + parentId: undefined + } + formRef.value?.resetFields() +} + +/** 获得示例分类树 */ +const getDemo02CategoryTree = async () => { + demo02CategoryTree.value = [] + const data = await Demo02CategoryApi.getDemo02CategoryList() + const root: Tree = { id: 0, name: '顶级示例分类', children: [] } + root.children = handleTree(data, 'id', 'parentId') + demo02CategoryTree.value.push(root) +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo02/index.vue b/src/views/infra/demo/demo02/index.vue new file mode 100644 index 00000000..9faa8c96 --- /dev/null +++ b/src/views/infra/demo/demo02/index.vue @@ -0,0 +1,207 @@ +<template> + <doc-alert title="代码生成(树表)" url="https://doc.iocoder.cn/new-feature/tree/" /> + + <ContentWrap> + <!-- 搜索工作栏 --> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="名字" prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入名字" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="创建时间" prop="createTime"> + <el-date-picker + v-model="queryParams.createTime" + value-format="YYYY-MM-DD HH:mm:ss" + type="daterange" + start-placeholder="开始日期" + end-placeholder="结束日期" + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo02-category:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-button + type="success" + plain + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['infra:demo02-category:export']" + > + <Icon icon="ep:download" class="mr-5px" /> 导出 + </el-button> + <el-button type="danger" plain @click="toggleExpandAll"> + <Icon icon="ep:sort" class="mr-5px" /> 展开/折叠 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table + v-loading="loading" + :data="list" + :stripe="true" + :show-overflow-tooltip="true" + row-key="id" + :default-expand-all="isExpandAll" + v-if="refreshTable" + > + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo02-category:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo02-category:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <Demo02CategoryForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import { dateFormatter } from '@/utils/formatTime' +import { handleTree } from '@/utils/tree' +import download from '@/utils/download' +import * as Demo02CategoryApi from '@/api/infra/demo/demo02' +import Demo02CategoryForm from './Demo02CategoryForm.vue' + +defineOptions({ name: 'Demo02Category' }) + +const message = useMessage() // 消息弹窗 +const { t } = useI18n() // 国际化 + +const loading = ref(true) // 列表的加载中 +const list = ref([]) // 列表的数据 +const queryParams = reactive({ + name: null, + parentId: null, + createTime: [] +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo02CategoryApi.getDemo02CategoryList(queryParams) + list.value = handleTree(data, 'id', 'parentId') + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() +} + +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await Demo02CategoryApi.deleteDemo02Category(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await Demo02CategoryApi.exportDemo02Category(queryParams) + download.excel(data, '示例分类.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 展开/折叠操作 */ +const isExpandAll = ref(true) // 是否展开,默认全部展开 +const refreshTable = ref(true) // 重新渲染表格状态 +const toggleExpandAll = async () => { + refreshTable.value = false + isExpandAll.value = !isExpandAll.value + await nextTick() + refreshTable.value = true +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> diff --git a/src/views/infra/demo/demo03/erp/Demo03StudentForm.vue b/src/views/infra/demo/demo03/erp/Demo03StudentForm.vue new file mode 100644 index 00000000..29f1370d --- /dev/null +++ b/src/views/infra/demo/demo03/erp/Demo03StudentForm.vue @@ -0,0 +1,121 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-radio-group v-model="formData.sex"> + <el-radio + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="出生日期" prop="birthday"> + <el-date-picker + v-model="formData.birthday" + type="date" + value-format="x" + placeholder="选择出生日期" + /> + </el-form-item> + <el-form-item label="简介" prop="description"> + <Editor v-model="formData.description" height="150px" /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/erp' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + name: undefined, + sex: undefined, + birthday: undefined, + description: undefined +}) +const formRules = reactive({ + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + sex: [{ required: true, message: '性别不能为空', trigger: 'blur' }], + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo03StudentApi.getDemo03Student(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as Demo03StudentApi.Demo03StudentVO + if (formType.value === 'create') { + await Demo03StudentApi.createDemo03Student(data) + message.success(t('common.createSuccess')) + } else { + await Demo03StudentApi.updateDemo03Student(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + name: undefined, + sex: undefined, + birthday: undefined, + description: undefined + } + formRef.value?.resetFields() +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/erp/components/Demo03CourseForm.vue b/src/views/infra/demo/demo03/erp/components/Demo03CourseForm.vue new file mode 100644 index 00000000..de1c06de --- /dev/null +++ b/src/views/infra/demo/demo03/erp/components/Demo03CourseForm.vue @@ -0,0 +1,99 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="分数" prop="score"> + <el-input v-model="formData.score" placeholder="请输入分数" /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import * as Demo03StudentApi from '@/api/infra/demo/demo03/erp' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + studentId: undefined, + name: undefined, + score: undefined +}) +const formRules = reactive({ + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + score: [{ required: true, message: '分数不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number, studentId: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + formData.value.studentId = studentId + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo03StudentApi.getDemo03Course(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 提交请求 + formLoading.value = true + try { + const data = formData.value + if (formType.value === 'create') { + await Demo03StudentApi.createDemo03Course(data) + message.success(t('common.createSuccess')) + } else { + await Demo03StudentApi.updateDemo03Course(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + studentId: undefined, + name: undefined, + score: undefined + } + formRef.value?.resetFields() +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/erp/components/Demo03CourseList.vue b/src/views/infra/demo/demo03/erp/components/Demo03CourseList.vue new file mode 100644 index 00000000..7e06ee64 --- /dev/null +++ b/src/views/infra/demo/demo03/erp/components/Demo03CourseList.vue @@ -0,0 +1,126 @@ +<template> + <!-- 列表 --> + <ContentWrap> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo03-student:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="分数" align="center" prop="score" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo03-student:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo03-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + <!-- 表单弹窗:添加/修改 --> + <Demo03CourseForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import { dateFormatter } from '@/utils/formatTime' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/erp' +import Demo03CourseForm from './Demo03CourseForm.vue' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const loading = ref(false) // 列表的加载中 +const list = ref([]) // 列表的数据 +const total = ref(0) // 列表的总页数 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + studentId: undefined +}) + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + (val) => { + queryParams.studentId = val + handleQuery() + }, + { immediate: false } +) + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo03StudentApi.getDemo03CoursePage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + if (!props.studentId) { + message.error('请选择一个学生') + return + } + formRef.value.open(type, id, props.studentId) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await Demo03StudentApi.deleteDemo03Course(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/erp/components/Demo03GradeForm.vue b/src/views/infra/demo/demo03/erp/components/Demo03GradeForm.vue new file mode 100644 index 00000000..abba0032 --- /dev/null +++ b/src/views/infra/demo/demo03/erp/components/Demo03GradeForm.vue @@ -0,0 +1,99 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="班主任" prop="teacher"> + <el-input v-model="formData.teacher" placeholder="请输入班主任" /> + </el-form-item> + </el-form> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import * as Demo03StudentApi from '@/api/infra/demo/demo03/erp' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + studentId: undefined, + name: undefined, + teacher: undefined +}) +const formRules = reactive({ + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + teacher: [{ required: true, message: '班主任不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 打开弹窗 */ +const open = async (type: string, id?: number, studentId: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + formData.value.studentId = studentId + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo03StudentApi.getDemo03Grade(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 提交请求 + formLoading.value = true + try { + const data = formData.value + if (formType.value === 'create') { + await Demo03StudentApi.createDemo03Grade(data) + message.success(t('common.createSuccess')) + } else { + await Demo03StudentApi.updateDemo03Grade(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + studentId: undefined, + name: undefined, + teacher: undefined + } + formRef.value?.resetFields() +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/erp/components/Demo03GradeList.vue b/src/views/infra/demo/demo03/erp/components/Demo03GradeList.vue new file mode 100644 index 00000000..b12f1889 --- /dev/null +++ b/src/views/infra/demo/demo03/erp/components/Demo03GradeList.vue @@ -0,0 +1,126 @@ +<template> + <!-- 列表 --> + <ContentWrap> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo03-student:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="班主任" align="center" prop="teacher" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo03-student:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo03-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + <!-- 表单弹窗:添加/修改 --> + <Demo03GradeForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import { dateFormatter } from '@/utils/formatTime' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/erp' +import Demo03GradeForm from './Demo03GradeForm.vue' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const loading = ref(false) // 列表的加载中 +const list = ref([]) // 列表的数据 +const total = ref(0) // 列表的总页数 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + studentId: undefined +}) + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + (val) => { + queryParams.studentId = val + handleQuery() + }, + { immediate: false } +) + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo03StudentApi.getDemo03GradePage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + if (!props.studentId) { + message.error('请选择一个学生') + return + } + formRef.value.open(type, id, props.studentId) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await Demo03StudentApi.deleteDemo03Grade(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/erp/index.vue b/src/views/infra/demo/demo03/erp/index.vue new file mode 100644 index 00000000..a4a4e621 --- /dev/null +++ b/src/views/infra/demo/demo03/erp/index.vue @@ -0,0 +1,240 @@ +<template> + <doc-alert title="代码生成(主子表)" url="https://doc.iocoder.cn/new-feature/master-sub/" /> + + <ContentWrap> + <!-- 搜索工作栏 --> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="名字" prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入名字" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select v-model="queryParams.sex" placeholder="请选择性别" clearable class="!w-240px"> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="创建时间" prop="createTime"> + <el-date-picker + v-model="queryParams.createTime" + value-format="YYYY-MM-DD HH:mm:ss" + type="daterange" + start-placeholder="开始日期" + end-placeholder="结束日期" + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo03-student:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-button + type="success" + plain + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['infra:demo03-student:export']" + > + <Icon icon="ep:download" class="mr-5px" /> 导出 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table + v-loading="loading" + :data="list" + :stripe="true" + :show-overflow-tooltip="true" + highlight-current-row + @current-change="handleCurrentChange" + > + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="性别" align="center" prop="sex"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> + </template> + </el-table-column> + <el-table-column + label="出生日期" + align="center" + prop="birthday" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="简介" align="center" prop="description" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo03-student:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo03-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <Demo03StudentForm ref="formRef" @success="getList" /> + <!-- 子表的列表 --> + <ContentWrap> + <el-tabs model-value="demo03Course"> + <el-tab-pane label="学生课程" name="demo03Course"> + <Demo03CourseList :student-id="currentRow.id" /> + </el-tab-pane> + <el-tab-pane label="学生班级" name="demo03Grade"> + <Demo03GradeList :student-id="currentRow.id" /> + </el-tab-pane> + </el-tabs> + </ContentWrap> +</template> + +<script setup lang="ts"> +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' +import { dateFormatter } from '@/utils/formatTime' +import download from '@/utils/download' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/erp' +import Demo03StudentForm from './Demo03StudentForm.vue' +import Demo03CourseList from './components/Demo03CourseList.vue' +import Demo03GradeList from './components/Demo03GradeList.vue' + +defineOptions({ name: 'Demo03Student' }) + +const message = useMessage() // 消息弹窗 +const { t } = useI18n() // 国际化 + +const loading = ref(true) // 列表的加载中 +const list = ref([]) // 列表的数据 +const total = ref(0) // 列表的总页数 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + name: null, + sex: null, + description: null, + createTime: [] +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo03StudentApi.getDemo03StudentPage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() +} + +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await Demo03StudentApi.deleteDemo03Student(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await Demo03StudentApi.exportDemo03Student(queryParams) + download.excel(data, '学生.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 选中行操作 */ +const currentRow = ref({}) // 选中行 +const handleCurrentChange = (row) => { + currentRow.value = row +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> diff --git a/src/views/infra/demo/demo03/inner/Demo03StudentForm.vue b/src/views/infra/demo/demo03/inner/Demo03StudentForm.vue new file mode 100644 index 00000000..fe9327b9 --- /dev/null +++ b/src/views/infra/demo/demo03/inner/Demo03StudentForm.vue @@ -0,0 +1,153 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-radio-group v-model="formData.sex"> + <el-radio + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="出生日期" prop="birthday"> + <el-date-picker + v-model="formData.birthday" + type="date" + value-format="x" + placeholder="选择出生日期" + /> + </el-form-item> + <el-form-item label="简介" prop="description"> + <Editor v-model="formData.description" height="150px" /> + </el-form-item> + </el-form> + <!-- 子表的表单 --> + <el-tabs v-model="subTabsName"> + <el-tab-pane label="学生课程" name="demo03Course"> + <Demo03CourseForm ref="demo03CourseFormRef" :student-id="formData.id" /> + </el-tab-pane> + <el-tab-pane label="学生班级" name="demo03Grade"> + <Demo03GradeForm ref="demo03GradeFormRef" :student-id="formData.id" /> + </el-tab-pane> + </el-tabs> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/inner' +import Demo03CourseForm from './components/Demo03CourseForm.vue' +import Demo03GradeForm from './components/Demo03GradeForm.vue' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + name: undefined, + sex: undefined, + birthday: undefined, + description: undefined +}) +const formRules = reactive({ + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + sex: [{ required: true, message: '性别不能为空', trigger: 'blur' }], + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 子表的表单 */ +const subTabsName = ref('demo03Course') +const demo03CourseFormRef = ref() +const demo03GradeFormRef = ref() + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo03StudentApi.getDemo03Student(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 校验子表单 + try { + await demo03CourseFormRef.value.validate() + } catch (e) { + subTabsName.value = 'demo03Course' + return + } + try { + await demo03GradeFormRef.value.validate() + } catch (e) { + subTabsName.value = 'demo03Grade' + return + } + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as Demo03StudentApi.Demo03StudentVO + // 拼接子表的数据 + data.demo03Courses = demo03CourseFormRef.value.getData() + data.demo03Grade = demo03GradeFormRef.value.getData() + if (formType.value === 'create') { + await Demo03StudentApi.createDemo03Student(data) + message.success(t('common.createSuccess')) + } else { + await Demo03StudentApi.updateDemo03Student(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + name: undefined, + sex: undefined, + birthday: undefined, + description: undefined + } + formRef.value?.resetFields() +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/inner/components/Demo03CourseForm.vue b/src/views/infra/demo/demo03/inner/components/Demo03CourseForm.vue new file mode 100644 index 00000000..87057513 --- /dev/null +++ b/src/views/infra/demo/demo03/inner/components/Demo03CourseForm.vue @@ -0,0 +1,100 @@ +<template> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + v-loading="formLoading" + label-width="0px" + :inline-message="true" + > + <el-table :data="formData" class="-mt-10px"> + <el-table-column label="序号" type="index" width="100" /> + <el-table-column label="名字" min-width="150"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.name`" :rules="formRules.name" class="mb-0px!"> + <el-input v-model="row.name" placeholder="请输入名字" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="分数" min-width="150"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.score`" :rules="formRules.score" class="mb-0px!"> + <el-input v-model="row.score" placeholder="请输入分数" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column align="center" fixed="right" label="操作" width="60"> + <template #default="{ $index }"> + <el-button @click="handleDelete($index)" link>—</el-button> + </template> + </el-table-column> + </el-table> + </el-form> + <el-row justify="center" class="mt-3"> + <el-button @click="handleAdd" round>+ 添加学生课程</el-button> + </el-row> +</template> +<script setup lang="ts"> +import * as Demo03StudentApi from '@/api/infra/demo/demo03/inner' + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const formLoading = ref(false) // 表单的加载中 +const formData = ref([]) +const formRules = reactive({ + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + score: [{ required: true, message: '分数不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + async (val) => { + // 1. 重置表单 + formData.value = [] + // 2. val 非空,则加载数据 + if (!val) { + return; + } + try { + formLoading.value = true + formData.value = await Demo03StudentApi.getDemo03CourseListByStudentId(val) + } finally { + formLoading.value = false + } + }, + { immediate: true } +) + +/** 新增按钮操作 */ +const handleAdd = () => { + const row = { + id: undefined, + studentId: undefined, + name: undefined, + score: undefined + } + row.studentId = props.studentId + formData.value.push(row) +} + +/** 删除按钮操作 */ +const handleDelete = (index) => { + formData.value.splice(index, 1) +} + +/** 表单校验 */ +const validate = () => { + return formRef.value.validate() +} + +/** 表单值 */ +const getData = () => { + return formData.value +} + +defineExpose({ validate, getData }) +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/inner/components/Demo03CourseList.vue b/src/views/infra/demo/demo03/inner/components/Demo03CourseList.vue new file mode 100644 index 00000000..d912fc5d --- /dev/null +++ b/src/views/infra/demo/demo03/inner/components/Demo03CourseList.vue @@ -0,0 +1,51 @@ +<template> + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="分数" align="center" prop="score" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + </el-table> + </ContentWrap> +</template> +<script setup lang="ts"> +import { dateFormatter } from '@/utils/formatTime' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/inner' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const loading = ref(false) // 列表的加载中 +const list = ref([]) // 列表的数据 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + list.value = await Demo03StudentApi.getDemo03CourseListByStudentId(props.studentId) + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/inner/components/Demo03GradeForm.vue b/src/views/infra/demo/demo03/inner/components/Demo03GradeForm.vue new file mode 100644 index 00000000..e0eeb192 --- /dev/null +++ b/src/views/infra/demo/demo03/inner/components/Demo03GradeForm.vue @@ -0,0 +1,72 @@ +<template> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="班主任" prop="teacher"> + <el-input v-model="formData.teacher" placeholder="请输入班主任" /> + </el-form-item> + </el-form> +</template> +<script setup lang="ts"> +import * as Demo03StudentApi from '@/api/infra/demo/demo03/inner' + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const formLoading = ref(false) // 表单的加载中 +const formData = ref([]) +const formRules = reactive({ + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + teacher: [{ required: true, message: '班主任不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + async (val) => { + // 1. 重置表单 + formData.value = { + id: undefined, + studentId: undefined, + name: undefined, + teacher: undefined, + } + // 2. val 非空,则加载数据 + if (!val) { + return; + } + try { + formLoading.value = true + const data = await Demo03StudentApi.getDemo03GradeByStudentId(val) + if (!data) { + return + } + formData.value = data + } finally { + formLoading.value = false + } + }, + { immediate: true } +) + +/** 表单校验 */ +const validate = () => { + return formRef.value.validate() +} + +/** 表单值 */ +const getData = () => { + return formData.value +} + +defineExpose({ validate, getData }) +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/inner/components/Demo03GradeList.vue b/src/views/infra/demo/demo03/inner/components/Demo03GradeList.vue new file mode 100644 index 00000000..96905414 --- /dev/null +++ b/src/views/infra/demo/demo03/inner/components/Demo03GradeList.vue @@ -0,0 +1,55 @@ +<template> + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="班主任" align="center" prop="teacher" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + </el-table> + </ContentWrap> +</template> +<script setup lang="ts"> +import { dateFormatter } from '@/utils/formatTime' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/inner' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const loading = ref(false) // 列表的加载中 +const list = ref([]) // 列表的数据 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo03StudentApi.getDemo03GradeByStudentId(props.studentId) + if (!data) { + return + } + list.value.push(data) + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/inner/index.vue b/src/views/infra/demo/demo03/inner/index.vue new file mode 100644 index 00000000..9b32460a --- /dev/null +++ b/src/views/infra/demo/demo03/inner/index.vue @@ -0,0 +1,229 @@ +<template> + <doc-alert title="代码生成(主子表)" url="https://doc.iocoder.cn/new-feature/master-sub/" /> + + <ContentWrap> + <!-- 搜索工作栏 --> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="名字" prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入名字" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select v-model="queryParams.sex" placeholder="请选择性别" clearable class="!w-240px"> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="创建时间" prop="createTime"> + <el-date-picker + v-model="queryParams.createTime" + value-format="YYYY-MM-DD HH:mm:ss" + type="daterange" + start-placeholder="开始日期" + end-placeholder="结束日期" + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo03-student:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-button + type="success" + plain + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['infra:demo03-student:export']" + > + <Icon icon="ep:download" class="mr-5px" /> 导出 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <!-- 子表的列表 --> + <el-table-column type="expand"> + <template #default="scope"> + <el-tabs model-value="demo03Course"> + <el-tab-pane label="学生课程" name="demo03Course"> + <Demo03CourseList :student-id="scope.row.id" /> + </el-tab-pane> + <el-tab-pane label="学生班级" name="demo03Grade"> + <Demo03GradeList :student-id="scope.row.id" /> + </el-tab-pane> + </el-tabs> + </template> + </el-table-column> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="性别" align="center" prop="sex"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> + </template> + </el-table-column> + <el-table-column + label="出生日期" + align="center" + prop="birthday" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="简介" align="center" prop="description" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo03-student:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo03-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <Demo03StudentForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' +import { dateFormatter } from '@/utils/formatTime' +import download from '@/utils/download' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/inner' +import Demo03StudentForm from './Demo03StudentForm.vue' +import Demo03CourseList from './components/Demo03CourseList.vue' +import Demo03GradeList from './components/Demo03GradeList.vue' + +defineOptions({ name: 'Demo03Student' }) + +const message = useMessage() // 消息弹窗 +const { t } = useI18n() // 国际化 + +const loading = ref(true) // 列表的加载中 +const list = ref([]) // 列表的数据 +const total = ref(0) // 列表的总页数 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + name: null, + sex: null, + description: null, + createTime: [] +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo03StudentApi.getDemo03StudentPage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() +} + +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await Demo03StudentApi.deleteDemo03Student(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await Demo03StudentApi.exportDemo03Student(queryParams) + download.excel(data, '学生.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> diff --git a/src/views/infra/demo/demo03/normal/Demo03StudentForm.vue b/src/views/infra/demo/demo03/normal/Demo03StudentForm.vue new file mode 100644 index 00000000..00508228 --- /dev/null +++ b/src/views/infra/demo/demo03/normal/Demo03StudentForm.vue @@ -0,0 +1,153 @@ +<template> + <Dialog :title="dialogTitle" v-model="dialogVisible"> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-radio-group v-model="formData.sex"> + <el-radio + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.value" + > + {{ dict.label }} + </el-radio> + </el-radio-group> + </el-form-item> + <el-form-item label="出生日期" prop="birthday"> + <el-date-picker + v-model="formData.birthday" + type="date" + value-format="x" + placeholder="选择出生日期" + /> + </el-form-item> + <el-form-item label="简介" prop="description"> + <Editor v-model="formData.description" height="150px" /> + </el-form-item> + </el-form> + <!-- 子表的表单 --> + <el-tabs v-model="subTabsName"> + <el-tab-pane label="学生课程" name="demo03Course"> + <Demo03CourseForm ref="demo03CourseFormRef" :student-id="formData.id" /> + </el-tab-pane> + <el-tab-pane label="学生班级" name="demo03Grade"> + <Demo03GradeForm ref="demo03GradeFormRef" :student-id="formData.id" /> + </el-tab-pane> + </el-tabs> + <template #footer> + <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button> + <el-button @click="dialogVisible = false">取 消</el-button> + </template> + </Dialog> +</template> +<script setup lang="ts"> +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/normal' +import Demo03CourseForm from './components/Demo03CourseForm.vue' +import Demo03GradeForm from './components/Demo03GradeForm.vue' + +const { t } = useI18n() // 国际化 +const message = useMessage() // 消息弹窗 + +const dialogVisible = ref(false) // 弹窗的是否展示 +const dialogTitle = ref('') // 弹窗的标题 +const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用 +const formType = ref('') // 表单的类型:create - 新增;update - 修改 +const formData = ref({ + id: undefined, + name: undefined, + sex: undefined, + birthday: undefined, + description: undefined +}) +const formRules = reactive({ + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + sex: [{ required: true, message: '性别不能为空', trigger: 'blur' }], + birthday: [{ required: true, message: '出生日期不能为空', trigger: 'blur' }], + description: [{ required: true, message: '简介不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 子表的表单 */ +const subTabsName = ref('demo03Course') +const demo03CourseFormRef = ref() +const demo03GradeFormRef = ref() + +/** 打开弹窗 */ +const open = async (type: string, id?: number) => { + dialogVisible.value = true + dialogTitle.value = t('action.' + type) + formType.value = type + resetForm() + // 修改时,设置数据 + if (id) { + formLoading.value = true + try { + formData.value = await Demo03StudentApi.getDemo03Student(id) + } finally { + formLoading.value = false + } + } +} +defineExpose({ open }) // 提供 open 方法,用于打开弹窗 + +/** 提交表单 */ +const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调 +const submitForm = async () => { + // 校验表单 + await formRef.value.validate() + // 校验子表单 + try { + await demo03CourseFormRef.value.validate() + } catch (e) { + subTabsName.value = 'demo03Course' + return + } + try { + await demo03GradeFormRef.value.validate() + } catch (e) { + subTabsName.value = 'demo03Grade' + return + } + // 提交请求 + formLoading.value = true + try { + const data = formData.value as unknown as Demo03StudentApi.Demo03StudentVO + // 拼接子表的数据 + data.demo03Courses = demo03CourseFormRef.value.getData() + data.demo03Grade = demo03GradeFormRef.value.getData() + if (formType.value === 'create') { + await Demo03StudentApi.createDemo03Student(data) + message.success(t('common.createSuccess')) + } else { + await Demo03StudentApi.updateDemo03Student(data) + message.success(t('common.updateSuccess')) + } + dialogVisible.value = false + // 发送操作成功的事件 + emit('success') + } finally { + formLoading.value = false + } +} + +/** 重置表单 */ +const resetForm = () => { + formData.value = { + id: undefined, + name: undefined, + sex: undefined, + birthday: undefined, + description: undefined + } + formRef.value?.resetFields() +} +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/normal/components/Demo03CourseForm.vue b/src/views/infra/demo/demo03/normal/components/Demo03CourseForm.vue new file mode 100644 index 00000000..b6f58572 --- /dev/null +++ b/src/views/infra/demo/demo03/normal/components/Demo03CourseForm.vue @@ -0,0 +1,100 @@ +<template> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + v-loading="formLoading" + label-width="0px" + :inline-message="true" + > + <el-table :data="formData" class="-mt-10px"> + <el-table-column label="序号" type="index" width="100" /> + <el-table-column label="名字" min-width="150"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.name`" :rules="formRules.name" class="mb-0px!"> + <el-input v-model="row.name" placeholder="请输入名字" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column label="分数" min-width="150"> + <template #default="{ row, $index }"> + <el-form-item :prop="`${$index}.score`" :rules="formRules.score" class="mb-0px!"> + <el-input v-model="row.score" placeholder="请输入分数" /> + </el-form-item> + </template> + </el-table-column> + <el-table-column align="center" fixed="right" label="操作" width="60"> + <template #default="{ $index }"> + <el-button @click="handleDelete($index)" link>—</el-button> + </template> + </el-table-column> + </el-table> + </el-form> + <el-row justify="center" class="mt-3"> + <el-button @click="handleAdd" round>+ 添加学生课程</el-button> + </el-row> +</template> +<script setup lang="ts"> +import * as Demo03StudentApi from '@/api/infra/demo/demo03/normal' + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const formLoading = ref(false) // 表单的加载中 +const formData = ref([]) +const formRules = reactive({ + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + score: [{ required: true, message: '分数不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + async (val) => { + // 1. 重置表单 + formData.value = [] + // 2. val 非空,则加载数据 + if (!val) { + return; + } + try { + formLoading.value = true + formData.value = await Demo03StudentApi.getDemo03CourseListByStudentId(val) + } finally { + formLoading.value = false + } + }, + { immediate: true } +) + +/** 新增按钮操作 */ +const handleAdd = () => { + const row = { + id: undefined, + studentId: undefined, + name: undefined, + score: undefined + } + row.studentId = props.studentId + formData.value.push(row) +} + +/** 删除按钮操作 */ +const handleDelete = (index) => { + formData.value.splice(index, 1) +} + +/** 表单校验 */ +const validate = () => { + return formRef.value.validate() +} + +/** 表单值 */ +const getData = () => { + return formData.value +} + +defineExpose({ validate, getData }) +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/normal/components/Demo03GradeForm.vue b/src/views/infra/demo/demo03/normal/components/Demo03GradeForm.vue new file mode 100644 index 00000000..12653b6c --- /dev/null +++ b/src/views/infra/demo/demo03/normal/components/Demo03GradeForm.vue @@ -0,0 +1,72 @@ +<template> + <el-form + ref="formRef" + :model="formData" + :rules="formRules" + label-width="100px" + v-loading="formLoading" + > + <el-form-item label="名字" prop="name"> + <el-input v-model="formData.name" placeholder="请输入名字" /> + </el-form-item> + <el-form-item label="班主任" prop="teacher"> + <el-input v-model="formData.teacher" placeholder="请输入班主任" /> + </el-form-item> + </el-form> +</template> +<script setup lang="ts"> +import * as Demo03StudentApi from '@/api/infra/demo/demo03/normal' + +const props = defineProps<{ + studentId: undefined // 学生编号(主表的关联字段) +}>() +const formLoading = ref(false) // 表单的加载中 +const formData = ref([]) +const formRules = reactive({ + studentId: [{ required: true, message: '学生编号不能为空', trigger: 'blur' }], + name: [{ required: true, message: '名字不能为空', trigger: 'blur' }], + teacher: [{ required: true, message: '班主任不能为空', trigger: 'blur' }] +}) +const formRef = ref() // 表单 Ref + +/** 监听主表的关联字段的变化,加载对应的子表数据 */ +watch( + () => props.studentId, + async (val) => { + // 1. 重置表单 + formData.value = { + id: undefined, + studentId: undefined, + name: undefined, + teacher: undefined, + } + // 2. val 非空,则加载数据 + if (!val) { + return; + } + try { + formLoading.value = true + const data = await Demo03StudentApi.getDemo03GradeByStudentId(val) + if (!data) { + return + } + formData.value = data + } finally { + formLoading.value = false + } + }, + { immediate: true } +) + +/** 表单校验 */ +const validate = () => { + return formRef.value.validate() +} + +/** 表单值 */ +const getData = () => { + return formData.value +} + +defineExpose({ validate, getData }) +</script> \ No newline at end of file diff --git a/src/views/infra/demo/demo03/normal/index.vue b/src/views/infra/demo/demo03/normal/index.vue new file mode 100644 index 00000000..8a5dc1a9 --- /dev/null +++ b/src/views/infra/demo/demo03/normal/index.vue @@ -0,0 +1,214 @@ +<template> + <doc-alert title="代码生成(主子表)" url="https://doc.iocoder.cn/new-feature/master-sub/" /> + + <ContentWrap> + <!-- 搜索工作栏 --> + <el-form + class="-mb-15px" + :model="queryParams" + ref="queryFormRef" + :inline="true" + label-width="68px" + > + <el-form-item label="名字" prop="name"> + <el-input + v-model="queryParams.name" + placeholder="请输入名字" + clearable + @keyup.enter="handleQuery" + class="!w-240px" + /> + </el-form-item> + <el-form-item label="性别" prop="sex"> + <el-select v-model="queryParams.sex" placeholder="请选择性别" clearable class="!w-240px"> + <el-option + v-for="dict in getIntDictOptions(DICT_TYPE.SYSTEM_USER_SEX)" + :key="dict.value" + :label="dict.label" + :value="dict.value" + /> + </el-select> + </el-form-item> + <el-form-item label="创建时间" prop="createTime"> + <el-date-picker + v-model="queryParams.createTime" + value-format="YYYY-MM-DD HH:mm:ss" + type="daterange" + start-placeholder="开始日期" + end-placeholder="结束日期" + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]" + class="!w-240px" + /> + </el-form-item> + <el-form-item> + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button> + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button> + <el-button + type="primary" + plain + @click="openForm('create')" + v-hasPermi="['infra:demo03-student:create']" + > + <Icon icon="ep:plus" class="mr-5px" /> 新增 + </el-button> + <el-button + type="success" + plain + @click="handleExport" + :loading="exportLoading" + v-hasPermi="['infra:demo03-student:export']" + > + <Icon icon="ep:download" class="mr-5px" /> 导出 + </el-button> + </el-form-item> + </el-form> + </ContentWrap> + + <!-- 列表 --> + <ContentWrap> + <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true"> + <el-table-column label="编号" align="center" prop="id" /> + <el-table-column label="名字" align="center" prop="name" /> + <el-table-column label="性别" align="center" prop="sex"> + <template #default="scope"> + <dict-tag :type="DICT_TYPE.SYSTEM_USER_SEX" :value="scope.row.sex" /> + </template> + </el-table-column> + <el-table-column + label="出生日期" + align="center" + prop="birthday" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="简介" align="center" prop="description" /> + <el-table-column + label="创建时间" + align="center" + prop="createTime" + :formatter="dateFormatter" + width="180px" + /> + <el-table-column label="操作" align="center"> + <template #default="scope"> + <el-button + link + type="primary" + @click="openForm('update', scope.row.id)" + v-hasPermi="['infra:demo03-student:update']" + > + 编辑 + </el-button> + <el-button + link + type="danger" + @click="handleDelete(scope.row.id)" + v-hasPermi="['infra:demo03-student:delete']" + > + 删除 + </el-button> + </template> + </el-table-column> + </el-table> + <!-- 分页 --> + <Pagination + :total="total" + v-model:page="queryParams.pageNo" + v-model:limit="queryParams.pageSize" + @pagination="getList" + /> + </ContentWrap> + + <!-- 表单弹窗:添加/修改 --> + <Demo03StudentForm ref="formRef" @success="getList" /> +</template> + +<script setup lang="ts"> +import { getIntDictOptions, DICT_TYPE } from '@/utils/dict' +import { dateFormatter } from '@/utils/formatTime' +import download from '@/utils/download' +import * as Demo03StudentApi from '@/api/infra/demo/demo03/normal' +import Demo03StudentForm from './Demo03StudentForm.vue' + +defineOptions({ name: 'Demo03Student' }) + +const message = useMessage() // 消息弹窗 +const { t } = useI18n() // 国际化 + +const loading = ref(true) // 列表的加载中 +const list = ref([]) // 列表的数据 +const total = ref(0) // 列表的总页数 +const queryParams = reactive({ + pageNo: 1, + pageSize: 10, + name: null, + sex: null, + description: null, + createTime: [] +}) +const queryFormRef = ref() // 搜索的表单 +const exportLoading = ref(false) // 导出的加载中 + +/** 查询列表 */ +const getList = async () => { + loading.value = true + try { + const data = await Demo03StudentApi.getDemo03StudentPage(queryParams) + list.value = data.list + total.value = data.total + } finally { + loading.value = false + } +} + +/** 搜索按钮操作 */ +const handleQuery = () => { + queryParams.pageNo = 1 + getList() +} + +/** 重置按钮操作 */ +const resetQuery = () => { + queryFormRef.value.resetFields() + handleQuery() +} + +/** 添加/修改操作 */ +const formRef = ref() +const openForm = (type: string, id?: number) => { + formRef.value.open(type, id) +} + +/** 删除按钮操作 */ +const handleDelete = async (id: number) => { + try { + // 删除的二次确认 + await message.delConfirm() + // 发起删除 + await Demo03StudentApi.deleteDemo03Student(id) + message.success(t('common.delSuccess')) + // 刷新列表 + await getList() + } catch {} +} + +/** 导出按钮操作 */ +const handleExport = async () => { + try { + // 导出的二次确认 + await message.exportConfirm() + // 发起导出 + exportLoading.value = true + const data = await Demo03StudentApi.exportDemo03Student(queryParams) + download.excel(data, '学生.xls') + } catch { + } finally { + exportLoading.value = false + } +} + +/** 初始化 **/ +onMounted(() => { + getList() +}) +</script> diff --git a/src/views/infra/testDemo/index.vue b/src/views/infra/testDemo/index.vue deleted file mode 100644 index ca6a5b07..00000000 --- a/src/views/infra/testDemo/index.vue +++ /dev/null @@ -1,4 +0,0 @@ -<template> - <div>index</div> -</template> -<script lang="ts" setup></script> diff --git a/src/views/mall/statistics/member/components/MemberFunnelCard.vue b/src/views/mall/statistics/member/components/MemberFunnelCard.vue index fc847ef3..609c679f 100644 --- a/src/views/mall/statistics/member/components/MemberFunnelCard.vue +++ b/src/views/mall/statistics/member/components/MemberFunnelCard.vue @@ -110,9 +110,11 @@ const handleTimeRangeChange = async (times: [dayjs.ConfigType, dayjs.ConfigType] .trapezoid1 { transform: perspective(5em) rotateX(-11deg); } + .trapezoid2 { transform: perspective(7em) rotateX(-20deg); } + .trapezoid3 { transform: perspective(3em) rotateX(-13deg); } diff --git a/src/views/mall/trade/delivery/pickUpOrder/index.vue b/src/views/mall/trade/delivery/pickUpOrder/index.vue index 8eb80072..fdcb7c81 100644 --- a/src/views/mall/trade/delivery/pickUpOrder/index.vue +++ b/src/views/mall/trade/delivery/pickUpOrder/index.vue @@ -316,6 +316,7 @@ onMounted(() => { :deep(.order-table-col > .cell) { padding: 0; } + .summary { .el-col { margin-bottom: 1rem;