Procházet zdrojové kódy

feat: 地图聚合,逛一逛,有味果园

lxf před 3 hodinami
rodič
revize
159b8a2bd5
100 změnil soubory, kde provedl 11329 přidání a 421 odebrání
  1. 3 1
      api/config.js
  2. 19 0
      api/index.js
  3. 5 1
      manifest.json
  4. 15 0
      pages.json
  5. 329 3
      pages/tabBar/discover/discover.vue
  6. 199 416
      pages/tabBar/home/home.vue
  7. 193 0
      pages/tabBar/home/hotComponent.vue
  8. 164 0
      pages/tabBar/home/mapComponent.vue
  9. 239 0
      pages/tabBar/home/subPages/allGardenMap.vue
  10. 199 0
      pages/tabBar/home/subPages/gardenItem.vue
  11. binární
      static/home/fruit-1.png
  12. binární
      static/home/fruit-2.png
  13. binární
      static/home/fruit-3.png
  14. binární
      static/home/fruit.png
  15. 30 0
      uni_modules/lime-floating-panel/changelog.md
  16. 65 0
      uni_modules/lime-floating-panel/components/l-floating-panel/index-u.scss
  17. 75 0
      uni_modules/lime-floating-panel/components/l-floating-panel/index.scss
  18. 346 0
      uni_modules/lime-floating-panel/components/l-floating-panel/l-floating-panel.uvue
  19. 193 0
      uni_modules/lime-floating-panel/components/l-floating-panel/l-floating-panel.vue
  20. 30 0
      uni_modules/lime-floating-panel/components/l-floating-panel/props.ts
  21. 18 0
      uni_modules/lime-floating-panel/components/l-floating-panel/type.ts
  22. 103 0
      uni_modules/lime-floating-panel/components/l-floating-panel/useTouch.uts
  23. 149 0
      uni_modules/lime-floating-panel/components/lime-floating-panel/lime-floating-panel.uvue
  24. 133 0
      uni_modules/lime-floating-panel/components/lime-floating-panel/lime-floating-panel.vue
  25. 89 0
      uni_modules/lime-floating-panel/package.json
  26. 173 0
      uni_modules/lime-floating-panel/readme.md
  27. 42 0
      uni_modules/lime-shared/addUnit/index.ts
  28. 82 0
      uni_modules/lime-shared/animation/bezier.ts
  29. 3 0
      uni_modules/lime-shared/animation/ease.ts
  30. 12 0
      uni_modules/lime-shared/animation/index.ts
  31. 108 0
      uni_modules/lime-shared/animation/useTransition.ts
  32. 119 0
      uni_modules/lime-shared/animation/uvue.uts
  33. 123 0
      uni_modules/lime-shared/animation/vue.ts
  34. 3888 0
      uni_modules/lime-shared/areaData/city-china.json
  35. 71 0
      uni_modules/lime-shared/areaData/index.ts
  36. 10 0
      uni_modules/lime-shared/arrayBufferToFile/index.ts
  37. 10 0
      uni_modules/lime-shared/arrayBufferToFile/uvue.uts
  38. 63 0
      uni_modules/lime-shared/arrayBufferToFile/vue.ts
  39. 13 0
      uni_modules/lime-shared/base64ToArrayBuffer/index.ts
  40. 11 0
      uni_modules/lime-shared/base64ToPath/index.ts
  41. 22 0
      uni_modules/lime-shared/base64ToPath/uvue.uts
  42. 75 0
      uni_modules/lime-shared/base64ToPath/vue.ts
  43. 21 0
      uni_modules/lime-shared/camelCase/index.ts
  44. 67 0
      uni_modules/lime-shared/canIUseCanvas2d/index.ts
  45. 111 0
      uni_modules/lime-shared/capitalizedAmount/index.ts
  46. 89 0
      uni_modules/lime-shared/changelog.md
  47. 63 0
      uni_modules/lime-shared/characterLimit/index.ts
  48. 16 0
      uni_modules/lime-shared/clamp/index.ts
  49. 12 0
      uni_modules/lime-shared/cloneDeep/index.ts
  50. 39 0
      uni_modules/lime-shared/cloneDeep/uvue.uts
  51. 103 0
      uni_modules/lime-shared/cloneDeep/vue.ts
  52. 22 0
      uni_modules/lime-shared/closest/index.ts
  53. 407 0
      uni_modules/lime-shared/components/lime-shared/lime-shared.vue
  54. 11 0
      uni_modules/lime-shared/createAnimation/index.ts
  55. 25 0
      uni_modules/lime-shared/createAnimation/type.ts
  56. 5 0
      uni_modules/lime-shared/createAnimation/uvue.uts
  57. 148 0
      uni_modules/lime-shared/createAnimation/vue.ts
  58. 73 0
      uni_modules/lime-shared/createCanvas/index.ts
  59. 71 0
      uni_modules/lime-shared/createImage/index.ts
  60. 11 0
      uni_modules/lime-shared/debounce/index.ts
  61. 36 0
      uni_modules/lime-shared/debounce/uvue.uts
  62. 40 0
      uni_modules/lime-shared/debounce/vue.ts
  63. 11 0
      uni_modules/lime-shared/exif/index.ts
  64. 7 0
      uni_modules/lime-shared/exif/uvue.uts
  65. 1057 0
      uni_modules/lime-shared/exif/vue.ts
  66. 11 0
      uni_modules/lime-shared/fillZero/index.ts
  67. 36 0
      uni_modules/lime-shared/floatAdd/index.ts
  68. 45 0
      uni_modules/lime-shared/floatDiv/index.ts
  69. 44 0
      uni_modules/lime-shared/floatMul/index.ts
  70. 32 0
      uni_modules/lime-shared/floatSub/index.ts
  71. 53 0
      uni_modules/lime-shared/getClassStr/index.ts
  72. 11 0
      uni_modules/lime-shared/getCurrentPage/index.ts
  73. 5 0
      uni_modules/lime-shared/getCurrentPage/uvue.uts
  74. 6 0
      uni_modules/lime-shared/getCurrentPage/vue.ts
  75. 62 0
      uni_modules/lime-shared/getLocalFilePath/index.ts
  76. 138 0
      uni_modules/lime-shared/getRect/index.ts
  77. 17 0
      uni_modules/lime-shared/getRect/uvue.uts
  78. 117 0
      uni_modules/lime-shared/getRect/vue.ts
  79. 54 0
      uni_modules/lime-shared/getStyleStr/index.ts
  80. 28 0
      uni_modules/lime-shared/guid/index.ts
  81. 11 0
      uni_modules/lime-shared/hasOwn/index.ts
  82. 43 0
      uni_modules/lime-shared/hasOwn/uvue.uts
  83. 30 0
      uni_modules/lime-shared/hasOwn/vue.ts
  84. 43 0
      uni_modules/lime-shared/index.ts
  85. 23 0
      uni_modules/lime-shared/isBase64/index.ts
  86. 24 0
      uni_modules/lime-shared/isBoolean/index.ts
  87. 8 0
      uni_modules/lime-shared/isBrowser/index.ts
  88. 86 0
      uni_modules/lime-shared/isByteLength/index.ts
  89. 189 0
      uni_modules/lime-shared/isDate/index.ts
  90. 23 0
      uni_modules/lime-shared/isDef/index.ts
  91. 11 0
      uni_modules/lime-shared/isEmail/index.ts
  92. 81 0
      uni_modules/lime-shared/isEmpty/index.ts
  93. 16 0
      uni_modules/lime-shared/isFunction/index.ts
  94. 64 0
      uni_modules/lime-shared/isIP/index.ts
  95. 26 0
      uni_modules/lime-shared/isNumber/index.ts
  96. 33 0
      uni_modules/lime-shared/isNumeric/index.ts
  97. 19 0
      uni_modules/lime-shared/isObject/index.ts
  98. 22 0
      uni_modules/lime-shared/isPromise/index.ts
  99. 33 0
      uni_modules/lime-shared/isRegExp/index.ts
  100. 19 0
      uni_modules/lime-shared/isString/index.ts

+ 3 - 1
api/config.js

@@ -1,5 +1,7 @@
 const config = {
-	BASIC_IMG: "https://birdseye-img.sysuimars.com/youwei-uniapp/"
+	BASIC_IMG: "https://birdseye-img.sysuimars.com/youwei-uniapp/",
+	BASE_URL: 'https://feiniaotech-dev.sysuimars.cn/',
+	BASE_URL_MINI: 'https://feiniaotech-dev.sysuimars.cn/mini/',
 }
 
 export default config

+ 19 - 0
api/index.js

@@ -0,0 +1,19 @@
+// api/index.js
+import http from '@/utils/http'
+import config from './config'
+
+export default {
+  /**
+   * 用户登录
+   * @param {Object} params - 登录参数
+   * @param {string} params.username - 用户名
+   * @param {string} params.password - 密码
+   */
+  login(params) {
+    return http.post('/auth/login', params)
+  },
+  
+  getCode() {
+	  return http.post(config.BASE_URL_MINI + "cfg/get")
+  },
+}

+ 5 - 1
manifest.json

@@ -43,7 +43,11 @@
             /* ios打包配置 */
             "ios" : {},
             /* SDK配置 */
-            "sdkConfigs" : {}
+            "sdkConfigs" : {
+				"map": {
+					"QQMapKey": "Q5GBZ-2LP6I-LOKGM-UE3UC-TXH7Z-WCFG2"  // 腾讯
+				  }
+			}
         }
     },
     /* 快应用特有相关 */

+ 15 - 0
pages.json

@@ -28,7 +28,22 @@
 			{
 				"navigationBarTitleText" : "好友排行榜"
 			}
+		},
+		{
+			"path" : "pages/tabBar/home/subPages/gardenItem",
+			"style" : 
+			{
+				"navigationBarTitleText" : ""
+			}
+		},
+		{
+			"path" : "pages/tabBar/home/subPages/allGardenMap",
+			"style" : 
+			{
+				"navigationBarTitleText" : "有味地图"
+			}
 		}
+		
 	],
 	"globalStyle": {
 		"navigationBarTextStyle": "black",

+ 329 - 3
pages/tabBar/discover/discover.vue

@@ -1,9 +1,335 @@
 <template>
-	<view>discover</view>
+	<view class="discover-page base-container">
+		<view class="discover-top">
+			<view class="home-search">
+				<view class="search-wrap">
+					<up-search placeholder="搜索品种" v-model="typeSearch"></up-search>
+				</view>
+			</view>
+			
+			<all-garden-map-vue></all-garden-map-vue>
+
+			<view class="type-wrap">
+				<up-scroll-list indicatorColor="#fae6a4" indicatorActiveColor="#F3C11D" :indicatorWidth="30"
+					:indicatorBarWidth="13">
+					<view class="item-type" :class="{'active': activeType === 0}">
+						<image class="type-img" :src="`${config.BASIC_IMG}home/type-icon.png`" alt="" />
+						<view class="type-text">
+							全部
+						</view>
+					</view>
+					<view class="item-type">
+						<image class="type-img" :src="`${config.BASIC_IMG}home/type-icon-2.png`" alt="" />
+						<view class="type-text">
+							龙眼
+						</view>
+					</view>
+					<view class="item-type">
+						<image class="type-img" :src="`${config.BASIC_IMG}home/type-icon-3.png`" alt="" />
+						<view class="type-text">
+							葡萄
+						</view>
+					</view>
+					<view class="item-type">
+						<image class="type-img" :src="`${config.BASIC_IMG}home/type-icon.png`" alt="" />
+						<view class="type-text">
+							水蜜桃
+						</view>
+					</view>
+					<view class="item-type">
+						<image class="type-img" :src="`${config.BASIC_IMG}home/type-icon-2.png`" alt="" />
+						<view class="type-text">
+							龙眼
+						</view>
+					</view>
+					<view class="item-type">
+						<image class="type-img" :src="`${config.BASIC_IMG}home/type-icon-3.png`" alt="" />
+						<view class="type-text">
+							葡萄
+						</view>
+					</view>
+					<view class="item-type">
+						<image class="type-img" :src="`${config.BASIC_IMG}home/type-icon-3.png`" alt="" />
+						<view class="type-text">
+							葡萄
+						</view>
+					</view>
+					<view class="item-type">
+						<image class="type-img" :src="`${config.BASIC_IMG}home/type-icon.png`" alt="" />
+						<view class="type-text">
+							水蜜桃
+						</view>
+					</view>
+					<view class="item-type">
+						<image class="type-img" :src="`${config.BASIC_IMG}home/type-icon-2.png`" alt="" />
+						<view class="type-text">
+							龙眼
+						</view>
+					</view>
+				</up-scroll-list>
+			</view>
+
+		</view>
+
+		<!-- 列表 -->
+		<view class="discover-content">
+			<view class="discover-filter">
+				<view class="filter-item" :class="{'active': filterIndex === 0}" @click="selectFilter(0)">
+					综合
+				</view>
+				<view class="filter-item" :class="{'active': filterIndex === 1}" @click="selectFilter(1)">
+					价格
+				</view>
+				<view class="filter-item" :class="{'active': filterIndex === 2}" @click="selectFilter(2)">
+					销量
+				</view>
+			</view>
+
+			<view class="discover-list">
+				<view class="list-line">
+					<view class="list-item" v-for="(item, index) in discoverData" :key="index">
+						<image class="item-img" :src="item.img" mode=""></image>
+						<view class="item-desc">
+							<view class="item-text">
+								{{item.name}}
+							</view>
+							<view class="item-subtext">
+								<text class="subtext-text">坏单包退</text>
+								<text class="subtext-text">包邮</text>
+							</view>
+							
+							<view class="info-price">
+								<view class="price-text">
+									<text class="price-unit">¥</text>{{item.price}}
+								</view>
+								<view class="info-sold">
+									已售{{item.sold}}
+								</view>
+							</view>
+						</view>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
 </template>
 
-<script>
+<script setup>
+	import {
+		ref
+	} from "vue";
+	import config from "@/api/config.js"
+	import allGardenMapVue from "../home/subPages/allGardenMap.vue";
+
+	const typeSearch = ref(null)
+
+	const filterIndex = ref(0)
+	const activeType = ref(0)
+	
+	const discoverData = ref([
+		{
+			name: "海南妃子笑荔枝新鲜采摘新鲜采摘",
+			img: "/static/home/fruit.png",
+			text: "",
+			price: '107',
+			sold: "1250"
+		},
+		{
+			name: "海南妃子笑荔枝新鲜采摘新鲜采摘",
+			img: "/static/home/fruit.png",
+			text: "",
+			price: '107',
+			sold: "1250"
+		},
+		{
+			name: "海南妃子笑荔枝新鲜采摘新鲜采摘",
+			img: "/static/home/fruit.png",
+			text: "",
+			price: '107',
+			sold: "1250"
+		},
+		{
+			name: "海南妃子笑荔枝新鲜采摘新鲜采摘",
+			img: "/static/home/fruit.png",
+			text: "",
+			price: '107',
+			sold: "1250"
+		}
+	])
+
+	function selectFilter(i) {
+		filterIndex.value = i
+	}
 </script>
 
-<style>
+<style lang="scss" scoped>
+	.discover-page {
+		padding: 0;
+		background: #F2F3F5;
+
+		.discover-top {
+			padding: 20rpx 24rpx;
+			background: linear-gradient(#FFFFFF, #F2F3F5);
+
+			.home-search {
+				display: flex;
+				align-items: center;
+				width: 100%;
+				border: 2rpx solid #FFD95E;
+				border-radius: 40rpx;
+				margin-bottom: 40rpx;
+
+				.search-wrap {
+					flex: 1;
+
+					// padding-left: 22rpx;
+					::v-deep {
+						.u-search {
+							.u-search__content {
+								background-color: transparent !important;
+
+								.u-search__content__input {
+									background-color: transparent !important;
+
+								}
+							}
+
+							.u-search__action {
+								text-align: center;
+								line-height: 52rpx;
+								border-radius: 40rpx;
+								font-size: 28rpx;
+								background-color: #FFD95E;
+								margin: 6rpx 8rpx;
+								width: 112rpx;
+								height: 52rpx;
+							}
+						}
+					}
+				}
+
+				.search-btn {
+					text-align: center;
+					line-height: 52rpx;
+					border-radius: 40rpx;
+					font-size: 28rpx;
+					background-color: #FFD95E;
+					margin: 6rpx 8rpx;
+					width: 112rpx;
+					height: 52rpx;
+				}
+			}
+
+			.type-wrap {
+				padding: 0 20rpx 20rpx;
+				background-color: #fff;
+				border-radius: 16rpx;
+				height: 200rpx;
+				box-sizing: border-box;
+
+				.item-type {
+					text-align: center;
+					font-size: 24rpx;
+
+					.type-img {
+						width: 92rpx;
+						height: 92rpx;
+					}
+					.type-text {
+						line-height: 36rpx;
+					}
+					&.active {
+						.type-text {
+							background-color: #FFD95E;
+							border-radius: 20rpx;
+						}
+					}
+				}
+
+				.item-type+.item-type {
+					padding-left: 22rpx;
+				}
+			}
+
+		}
+
+		.discover-content {
+			padding: 0rpx 24rpx 24rpx;
+
+			.discover-filter {
+				color: #A6A6A6;
+				font-size: 28rpx;
+				display: flex;
+				align-items: center;
+
+				.filter-item {
+					padding: 12rpx 20rpx;
+
+					&.active {
+						color: #000000;
+					}
+				}
+			}
+			.discover-list {
+				padding-top: 20rpx;
+				.list-line {
+					padding-bottom: 20rpx;
+					display: flex;
+					flex-wrap: wrap;
+					.list-item {
+						background-color: #FFFFFF;
+						border-radius: 10rpx;
+						width: calc(50% - 10rpx);
+						margin-bottom: 20rpx;
+						.item-img {
+							width: 100%;
+							height: 340rpx;
+							object-fit: cover;
+							border-radius: 10rpx 10rpx 0 0;
+						}
+						.item-desc {
+							padding: 0 10rpx 10rpx;
+							.item-text {
+								width: calc(100% - 22rpx);
+								overflow: hidden;
+								color: #000000;
+								font-size: 28rpx;
+								line-height: 42rpx;
+								font-weight: 600;
+								white-space: nowrap;
+							}
+							.item-subtext {
+								color: #AFAFAF;
+								font-size: 24rpx;
+								line-height: 36rpx;
+								.subtext-text + .subtext-text {
+									padding-left: 10rpx;
+								}
+							}
+							
+							.info-price {
+								display: flex;
+								align-items: baseline;
+								justify-content: space-between;
+								.price-text {
+									color: #FF7700;
+									font-size: 36rpx;
+									.price-unit {
+										font-size: 23rpx;
+									}
+								}
+								.info-sold {
+									font-size: 20rpx;
+									color: #C4C4C4;
+								}
+							}
+						}
+					}
+					.list-item:nth-child(2n) {
+						margin-left: 20rpx;
+					}
+				}
+			}
+		}
+	}
 </style>

+ 199 - 416
pages/tabBar/home/home.vue

@@ -3,25 +3,23 @@
 		<view class="home-top">
 			<view class="home-search">
 				<view class="search-wrap">
-					<input />
-				</view>
-				<view class="search-btn">
-					搜索
+					<up-search placeholder="搜索品种" v-model="typeSearch"></up-search>
 				</view>
 			</view>
-			<view class="map-wrap">
-				 <map
-				      id="myMap"
-					  class="map-dom"
-				      :latitude="center.latitude"
-				      :longitude="center.longitude"
-				      :markers="clusters"
-				      :polyline="[]"
-				      :include-points="includePoints"
-				      @regionchange="onRegionChange"
-					  @scale="onScaleChange"
-				      show-location
-				    ></map>
+			<map
+			    id="mapId"
+			    :latitude="latitude"
+			    :longitude="longitude"
+			    @markertap="onMarkerTap"
+			    @callouttap="onCalloutTap"
+			    @labeltap="onLabelTap"
+			    :markers="markers"
+			    :include-points="includePoints"
+			    show-location
+			    style="width: 100%; height: 280rpx;"
+			  ></map>
+			<view class="map-tips" @click="toPage('allGardenMap')">
+				飞鸟入驻管理果场详情,点击查看
 			</view>
 		</view>
 		<view class="type-wrap">
@@ -95,97 +93,7 @@
 			</up-scroll-list>
 		</view>
 		<!-- 好味热卖 -->
-		<view class="hot-wrap">
-			<view class="hot-content">
-				<view class="hot-title">
-					<view class="title-l">
-						好味<text class="title-color">热卖</text>
-					</view>
-					<view class="title-btn">
-						限时抢购中<up-icon size="10" name="arrow-right"></up-icon>
-					</view>
-				</view>
-				<view class="hot-list">
-					<up-scroll-list indicatorColor="#fae6a4" indicatorActiveColor="#F3C11D" :indicatorWidth="30" :indicatorBarWidth="13">
-						<view class="hot-panel">
-							<view class="hot-item">
-								<image class="hot-img" :src="`${config.BASIC_IMG}home/hot-1.png`" mode=""></image>
-								<view class="item-info">
-									<view class="info-text">
-										<!-- <up-text :lines="2" color="#000000" size="12" text="海南妃子笑新鲜顺丰发货海南妃子笑海南妃子笑"></up-text> -->
-										<view class="ellipsis-l2">
-											海南妃子笑新鲜顺丰发货海南妃子笑海南妃子笑
-										</view>
-									</view>
-									<view class="info-price">
-										<view class="price-text">
-											<text class="price-unit">¥</text>108
-										</view>
-										<view class="info-sold">
-											已售1251
-										</view>
-									</view>
-								</view>
-							</view>
-							<view class="hot-item">
-								<image class="hot-img"  :src="`${config.BASIC_IMG}home/hot-2.png`" mode=""></image>
-								<view class="item-info">
-									<view class="info-text">
-										<view class="ellipsis-l2">
-											海南妃子笑新鲜顺丰发货海南妃子笑海南妃子笑
-										</view>
-									</view>
-									<view class="info-price">
-										<view class="price-text">
-											<text class="price-unit">¥</text>108
-										</view>
-										<view class="info-sold">
-											已售1251
-										</view>
-									</view>
-								</view>
-							</view>
-							<view class="hot-item">
-								<image class="hot-img" :src="`${config.BASIC_IMG}home/hot-1.png`" mode=""></image>
-								<view class="item-info">
-									<view class="info-text">
-										<view class="ellipsis-l2">
-											海南妃子笑新鲜顺丰发货海南妃子笑海南妃子笑新鲜顺丰发货
-										</view>
-									</view>
-									<view class="info-price">
-										<view class="price-text">
-											<text class="price-unit">¥</text>108
-										</view>
-										<view class="info-sold">
-											已售1251
-										</view>
-									</view>
-								</view>
-							</view>
-							<view class="hot-item">
-								<image class="hot-img" :src="`${config.BASIC_IMG}home/hot-2.png`" mode=""></image>
-								<view class="item-info">
-									<view class="info-text">
-										<view class="ellipsis-l2">
-											海南妃子笑新鲜顺丰发货海南妃子笑海南妃子笑新鲜顺丰发货
-										</view>
-									</view>
-									<view class="info-price">
-										<view class="price-text">
-											<text class="price-unit">¥</text>108
-										</view>
-										<view class="info-sold">
-											已售1251
-										</view>
-									</view>
-								</view>
-							</view>
-						</view>
-					</up-scroll-list>
-				</view>
-			</view>
-		</view>
+		<hot-component-vue></hot-component-vue>
 		
 		<!-- 有味果园 -->
 		<view class="garden-wrap">
@@ -199,7 +107,7 @@
 					</view>
 				</view>
 				<view class="garden-list">
-					<view class="garden-item">
+					<view class="garden-item" @click="toPage('gardenItem')">
 						<view class="garden-l">
 							<image class="garden-img" :src="`${config.BASIC_IMG}home/garden.png`" mode=""></image>
 							<text class="img-text">无人机实拍视频</text>
@@ -258,249 +166,161 @@
 </template>
 
 <script setup>
-import { ref, onMounted, reactive } from 'vue'
-import QQMapWX from 'qqmap-wx-jssdk'
+import { ref, onMounted } from 'vue'
 import config from "@/api/config.js"
+import hotComponentVue from './hotComponent.vue'
 
 
-// 广州中心坐标
-const GUANGZHOU_CENTER = {
-  latitude: 23.12911,
-  longitude: 113.26436
-}
-
-// 模拟广州的景点数据
-const GUANGZHOU_POIS = [
-  { id: 1, name: '广州塔', latitude: 23.10641, longitude: 113.32466 },
-  { id: 2, name: '白云山', latitude: 23.19746, longitude: 113.30249 },
-  { id: 3, name: '越秀公园', latitude: 23.13927, longitude: 113.26436 },
-  { id: 4, name: '沙面岛', latitude: 23.10788, longitude: 113.24365 },
-  { id: 5, name: '陈家祠', latitude: 23.12632, longitude: 113.24849 },
-  { id: 6, name: '北京路', latitude: 23.12389, longitude: 113.26799 },
-  { id: 7, name: '上下九', latitude: 23.11696, longitude: 113.24899 },
-  { id: 8, name: '荔枝博览园', latitude: 22.99405, longitude: 113.32486 },
-  { id: 9, name: '中山纪念堂', latitude: 23.13146, longitude: 113.26336 },
-  { id: 10, name: '海心沙', latitude: 23.11446, longitude: 113.32136 }
-]
-
-// 响应式数据
-const qqmapsdk = ref(null)
-const mapContext = ref(null)
-const center = ref(GUANGZHOU_CENTER)
-const allMarkers = ref([])
-const clusters = ref([])
-const includePoints = ref([])
-const currentZoom = ref(16)
-
-
-// 初始化地图
-const initMap = () => {
-  qqmapsdk.value = new QQMapWX({
-    key: 'Q5GBZ-2LP6I-LOKGM-UE3UC-TXH7Z-WCFG2' // key
-  })
-}
-
-// 加载点位数据
-const loadPoints = () => {
-  allMarkers.value = GUANGZHOU_POIS.map(item => ({
-    ...item,
-    iconPath: '../../../static/map/point.png',
-    width: 30,
-    height: 30,
-    callout: {
-      content: item.name,
-      color: '#ffffff',
-      bgColor: '#007AFF',
-      padding: 5,
-      borderRadius: 4,
-      display: 'ALWAYS'
-    }
-  }))
-  
-  updateClusters()
-}
-
-// 更新聚合点
-const updateClusters = () => {
-  if (!allMarkers.value.length) return
-  
-  // 根据缩放级别决定聚合半径(单位:米)
-  const clusterRadius = 100000 / Math.pow(2, currentZoom.value)
-  
-  // 使用网格化聚合提高性能
-  const grid = {}
-  allMarkers.value.forEach(marker => {
-    const gridX = Math.floor(marker.longitude * 100 / clusterRadius)
-    const gridY = Math.floor(marker.latitude * 100 / clusterRadius)
-    const gridKey = `${gridX}_${gridY}`
-    
-    if (!grid[gridKey]) {
-      grid[gridKey] = {
-        markers: [marker],
-        longitude: marker.longitude,
-        latitude: marker.latitude,
-        id: marker.id
-      }
-    } else {
-      grid[gridKey].markers.push(marker)
-      // 计算聚合点中心位置
-      grid[gridKey].longitude = (grid[gridKey].longitude + marker.longitude) / 2
-      grid[gridKey].latitude = (grid[gridKey].latitude + marker.latitude) / 2
-    }
+const typeSearch = ref(null)
+ 
+ function toPage(path) {
+	 uni.navigateTo({
+	 	url: `/pages/tabBar/home/subPages/${path}`
+	 });
+ }
+ 
+ 
+ const latitude = ref(23.099994)
+ const longitude = ref(113.324520)
+ const markers = ref([])
+ const includePoints = ref([])
+ const mapCtx = ref(null)
+ const img = ref('../../../static/map/point.png')
+ 
+ onMounted(async () => {
+   // #ifdef MP-WEIXIN
+   mapCtx.value = uni.createMapContext('mapId')
+   
+   mapCtx.value.on('markerClusterClick', res => {
+     console.log('markerClusterClick', res)
+   })
+   
+   bindEvent()
+   // #endif
+ })
+ 
+ const bindEvent = () => {
+   // #ifdef MP-WEIXIN
+   mapCtx.value.initMarkerCluster({
+     enableDefaultStyle: false,
+     zoomOnClick: true,
+     gridSize: 60,
+     complete(res) {
+       console.log('initMarkerCluster', res)
+     }
+   })
+   
+   addMarkers()
+   
+   mapCtx.value.on('markerClusterCreate', res => {
+     console.log('clusterCreate', res)
+     const clusters = res.clusters
+     const newMarkers = clusters.map(cluster => {
+       const { center, clusterId, markerIds } = cluster
+       return {
+         ...center,
+         width: 0,
+         height: 0,
+         clusterId, // 必须
+         label: {
+           content: markerIds.length + '',
+           fontSize: 20,
+           width: 30,
+           height: 30,
+           bgColor: '#FFCB3C',
+           borderRadius: 30,
+           textAlign: 'center',
+           anchorX: 0,
+           anchorY: -30,
+         }
+       }
+     })
+     mapCtx.value.addMarkers({
+       markers: newMarkers,
+       clear: false,
+       complete(res) {
+         console.log('clusterCreate addMarkers', res)
+       }
+     })
+   })
+   // #endif
+ }
+ 
+ const addMarkers = () => {
+   const marker = {
+     id: 1,
+     iconPath: img.value,
+     width: 30,
+     height: 30,
+     joinCluster: true, // 指定了该参数才会参与聚合
+     label: {
+       width: 50,
+       height: 30,
+       borderWidth: 1,
+       borderRadius: 4,
+       bgColor: '#FFCB3C88',
+       anchorX: -26,
+       anchorY: -60,
+       content: ''
+     }
+   }
+ 
+   const positions = [
+     { latitude: 23.099994, longitude: 113.324520 },
+     { latitude: 23.099994, longitude: 113.322520 },
+     { latitude: 23.099994, longitude: 113.326520 },
+     { latitude: 23.096994, longitude: 113.329520 }
+   ]
+   
+   const newMarkers = []
+   positions.forEach((p, i) => {
+     const newMarker = {...marker, ...p}
+     newMarker.id = i + 1
+     newMarker.label.content = `果园 ${i + 1}`
+     newMarkers.push(newMarker)
+   })
+   
+   // #ifdef MP-WEIXIN
+   mapCtx.value.addMarkers({
+     markers: newMarkers,
+     clear: false,
+     complete(res) {
+       console.log('addMarkers', res)
+     }
+   })
+   // #else
+   // 非微信平台直接设置 markers
+   markers.value = markers.value.concat(newMarkers)
+   // 更新包含的点
+   includePoints.value = markers.value.map(marker => ({
+     latitude: marker.latitude,
+     longitude: marker.longitude
+   }))
+   // #endif
+ }
+ 
+const removeMarkers = () => {
+  // #ifdef MP-WEIXIN
+  mapCtx.value.addMarkers({
+    clear: true,
+    markers: []
   })
-  
-  // 生成最终聚合数据
-  clusters.value = Object.values(grid).map(cluster => ({
-    id: cluster.id,
-    latitude: cluster.latitude,
-    longitude: cluster.longitude,
-    iconPath: cluster.markers.length > 1 
-      ? '../../../static/map/tree.png'  // 聚合图标
-      : '../../../static/map/point.png',   // 单点图标
-    width: cluster.markers.length > 1 ? 40 : 30,
-    height: cluster.markers.length > 1 ? 40 : 30,
-    callout: {
-      content: cluster.markers.length > 1 
-        ? `${cluster.markers.length}个地点` 
-        : cluster.markers[0].name,
-      color: '#ffffff',
-      bgColor: '#007AFF',
-      padding: 5,
-      borderRadius: 4,
-      display: 'ALWAYS'
-    },
-    clusterData: cluster.markers
-  }))
-  
-  // 更新地图视野包含所有点
-  includePoints.value = clusters.value.map(m => ({
-    latitude: m.latitude,
-    longitude: m.longitude
-  }))
-  
-  // 在updateClusters()最后添加
-  // if (mapContext.value) {
-  //   mapContext.value.moveToLocation({
-  //     latitude: center.value.latitude,
-  //     longitude: center.value.longitude
-  //   })
-  // }
-  
-  console.log(`当前缩放级别: ${currentZoom.value}, 聚合点数量: ${clusters.value.length}`)
-}
-
-// 计算两点间距离
-// 更精确的距离计算函数(Haversine公式)
-const getDistance = (lat1, lng1, lat2, lng2) => {
-  // 将经纬度转换为弧度
-  const toRad = d => d * Math.PI / 180
-  const R = 6371 // 地球半径(km)
-  
-  const dLat = toRad(lat2 - lat1)
-  const dLng = toRad(lng2 - lng1)
-  const a = 
-    Math.sin(dLat / 2) * Math.sin(dLat / 2) +
-    Math.cos(toRad(lat1)) * Math.cos(toRad(lat2)) *
-    Math.sin(dLng / 2) * Math.sin(dLng / 2)
-  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a))
-  
-  return R * c * 1000 // 返回米
-}
-
-// 地图区域变化事件
-const onRegionChange = (e) => {
-	// e = {causedBy, type, detail: {rotate, skew, scale, centerLocation, region}}
-  if (e.type === 'end') {
-	console.log('scale', e.detail.scale)
-    uni.createMapContext('myMap').getScale({
-      success: (res) => {
-		  if (res.scale !== currentZoom.value) {
-			currentZoom.value = res.scale // 只有缩放变化时才更新
-			updateClusters()
-		  }
-        // currentZoom.value = res.scale
-        // updateClusters()
-      }
-    })
-  }
-}
-
-const onScaleChange = (e) => {
-	console.log('eeeee', e)
+  // #else
+  markers.value = []
+  // #endif
 }
 
-const onDragEnd = (e) => {
-  // 仅更新中心点,不触发聚合
-  center.value = {
-    latitude: e.detail.center.latitude,
-    longitude: e.detail.center.longitude
-  }
+const onMarkerTap = (e) => {
+  console.log('@@ markertap', e)
 }
 
-const onScaleChange2 = (e) => {
-  // 只有手势缩放才更新层级并触发聚合
-  currentZoom.value = e.detail.scale
-  updateClusters()
-  
-  // 可选:限制最小/最大缩放级别
-  if (currentZoom.value < 12) currentZoom.value = 12
-  if (currentZoom.value > 20) currentZoom.value = 20
+const onCalloutTap = (e) => {
+  console.log('@@ onCalloutTap', e)
 }
 
-// 搜索地点
-const onSearch = (e) => {
-  qqmapsdk.value.search({
-    keyword: e.value,
-    location: center.value,
-    success: (res) => {
-      allMarkers.value = res.data.map(item => ({
-        id: item.id,
-        name: item.title,
-        latitude: item.location.lat,
-        longitude: item.location.lng,
-        iconPath: '../../../static/map/point.png',
-        callout: {
-          content: item.title,
-          color: '#ffffff',
-          bgColor: '#007AFF',
-          padding: 5,
-          borderRadius: 4,
-          display: 'ALWAYS'
-        }
-      }))
-      
-      updateClusters()
-    }
-  })
+const onLabelTap = (e) => {
+  console.log('@@ labletap', e)
 }
-
-// 清除搜索
-const clearSearch = () => {
-  loadPoints()
-}
-
-// 生命周期钩子
-onMounted(() => {
-  // #ifdef MP-WEIXIN
-  mapContext.value = uni.createMapContext('myMap', this)
-  initMap()
-  loadPoints()
-  
-  // 获取地图区域
-  if (mapContext.value && mapContext.value.getRegion) {
-    mapContext.value.getRegion({
-      success: res => console.log('地图范围:', res),
-      fail: err => console.error('地图异常:', err) 
-    })
-  }
-  // #endif
-})
-
-const typeList = reactive([  
-    'https://cdn.uviewui.com/uview/swiper/swiper3.png',  
-    'https://cdn.uviewui.com/uview/swiper/swiper2.png',  
-    'https://cdn.uviewui.com/uview/swiper/swiper1.png',  
-]);  
 </script>
 
 <style lang="scss" scoped>
@@ -510,6 +330,22 @@ const typeList = reactive([
 		.home-top {
 			padding: 20rpx 24rpx;
 			background: linear-gradient(#FFFFFF, rgba(242, 243, 245, 0));
+			position: relative;
+		}
+		.map-tips {
+			position: absolute;
+			bottom: 0%;
+			left: 24rpx;
+			height: 70rpx;
+			width: calc(100% - 48rpx);
+			background: linear-gradient(rgba(102, 102, 102, 0), rgba(0, 0, 0, 0.55));
+			display: flex;
+			align-items: center;
+			font-size: 24rpx;
+			color: #FFFFFF;
+			padding-left: 20rpx;
+			box-sizing: border-box;
+			border-radius: 0 0 16rpx 16rpx;
 		}
 		.home-search {
 			display: flex;
@@ -520,7 +356,28 @@ const typeList = reactive([
 			margin-bottom: 40rpx;
 			.search-wrap {
 				flex: 1;
-				padding-left: 22rpx;
+				// padding-left: 22rpx;
+				::v-deep {
+					.u-search {
+						.u-search__content {
+							background-color: transparent !important;
+							.u-search__content__input {
+								background-color: transparent !important;
+								
+							}
+						}
+						.u-search__action {
+							text-align: center;
+							line-height: 52rpx;
+							border-radius: 40rpx;
+							font-size: 28rpx;
+							background-color: #FFD95E;
+							margin: 6rpx 8rpx;
+							width: 112rpx;
+							height: 52rpx;
+						}
+					}
+				}
 			}
 			.search-btn {
 				text-align: center;
@@ -533,13 +390,6 @@ const typeList = reactive([
 				height: 52rpx;
 			}
 		}
-		.map-wrap {
-			height: 280rpx;
-			.map-dom {
-				width: 100%;
-				height: 100%;
-			}
-		}
 		.type-wrap {
 			margin: 20rpx;
 			padding: 20rpx;
@@ -547,14 +397,6 @@ const typeList = reactive([
 			border-radius: 16rpx;
 			height: 200rpx;
 			box-sizing: border-box;
-			.swiper-item {
-				display: flex;
-				align-items: center;
-			}
-			
-			.swiper {
-				height: 170rpx;
-			}
 			
 			.item-type {
 				text-align: center;
@@ -569,65 +411,6 @@ const typeList = reactive([
 			}
 		}
 		
-		.hot-wrap {
-			margin: 0 20rpx 20rpx;
-			background: linear-gradient(#FFFFFF, rgba(255, 255, 255, 0));
-			padding: 2rpx;
-			border-radius: 16rpx;
-			.hot-content {
-				background: linear-gradient(#fff1c3 4%,  #FFFFFF 28%);
-				border-radius: 16rpx;
-				padding: 20rpx;
-				height: 240rpx;
-				box-sizing: border-box;
-				.hot-list {
-					.hot-panel {
-						width: 100%;
-						display: flex;
-						.hot-item {
-							width: calc(50% - 10rpx);
-							display: flex;
-							white-space: nowrap;
-							.hot-img {
-								flex: none;
-								width: 116rpx;
-								height: 116rpx;
-								object-fit: cover;
-								border-radius: 10rpx;
-							}
-							.item-info {
-								padding-left: 10rpx;
-								width: 200rpx;
-								.info-text {
-									color: #000000;
-									font-size: 24rpx;
-								}
-								.info-price {
-									display: flex;
-									align-items: baseline;
-									justify-content: space-between;
-									.price-text {
-										color: #FF7700;
-										font-size: 36rpx;
-										.price-unit {
-											font-size: 23rpx;
-										}
-									}
-									.info-sold {
-										font-size: 20rpx;
-										color: #C4C4C4;
-									}
-								}
-							}
-						}
-						.hot-item + .hot-item {
-							margin-left: 20rpx;
-						}
-					}
-				}
-			}
-		}
-		
 		.garden-wrap {
 			margin: 0 20rpx 20rpx;
 			background: linear-gradient(#FFFFFF, rgba(255, 255, 255, 0));

+ 193 - 0
pages/tabBar/home/hotComponent.vue

@@ -0,0 +1,193 @@
+<template>
+	<view class="hot-wrap">
+		<view class="hot-content">
+			<view class="hot-title">
+				<view class="title-l">
+					好味<text class="title-color">热卖</text>
+				</view>
+				<view class="title-btn">
+					限时抢购中<up-icon size="10" name="arrow-right"></up-icon>
+				</view>
+			</view>
+			<view class="hot-list">
+				<up-scroll-list indicatorColor="#fae6a4" indicatorActiveColor="#F3C11D" :indicatorWidth="30"
+					:indicatorBarWidth="13">
+					<view class="hot-panel">
+						<view class="hot-item">
+							<image class="hot-img" :src="`${config.BASIC_IMG}home/hot-1.png`" mode=""></image>
+							<view class="item-info">
+								<view class="info-text">
+									<!-- <up-text :lines="2" color="#000000" size="12" text="海南妃子笑新鲜顺丰发货海南妃子笑海南妃子笑"></up-text> -->
+									<view class="ellipsis-l2">
+										海南妃子笑新鲜顺丰发货海南妃子笑海南妃子笑
+									</view>
+								</view>
+								<view class="info-price">
+									<view class="price-text">
+										<text class="price-unit">¥</text>108
+									</view>
+									<view class="info-sold">
+										已售1251
+									</view>
+								</view>
+							</view>
+						</view>
+						<view class="hot-item">
+							<image class="hot-img" :src="`${config.BASIC_IMG}home/hot-2.png`" mode=""></image>
+							<view class="item-info">
+								<view class="info-text">
+									<view class="ellipsis-l2">
+										海南妃子笑新鲜顺丰发货海南妃子笑海南妃子笑
+									</view>
+								</view>
+								<view class="info-price">
+									<view class="price-text">
+										<text class="price-unit">¥</text>108
+									</view>
+									<view class="info-sold">
+										已售1251
+									</view>
+								</view>
+							</view>
+						</view>
+						<view class="hot-item">
+							<image class="hot-img" :src="`${config.BASIC_IMG}home/hot-1.png`" mode=""></image>
+							<view class="item-info">
+								<view class="info-text">
+									<view class="ellipsis-l2">
+										海南妃子笑新鲜顺丰发货海南妃子笑海南妃子笑新鲜顺丰发货
+									</view>
+								</view>
+								<view class="info-price">
+									<view class="price-text">
+										<text class="price-unit">¥</text>108
+									</view>
+									<view class="info-sold">
+										已售1251
+									</view>
+								</view>
+							</view>
+						</view>
+						<view class="hot-item">
+							<image class="hot-img" :src="`${config.BASIC_IMG}home/hot-2.png`" mode=""></image>
+							<view class="item-info">
+								<view class="info-text">
+									<view class="ellipsis-l2">
+										海南妃子笑新鲜顺丰发货海南妃子笑海南妃子笑新鲜顺丰发货
+									</view>
+								</view>
+								<view class="info-price">
+									<view class="price-text">
+										<text class="price-unit">¥</text>108
+									</view>
+									<view class="info-sold">
+										已售1251
+									</view>
+								</view>
+							</view>
+						</view>
+					</view>
+				</up-scroll-list>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script setup>
+	import config from "@/api/config.js"
+</script>
+
+<style lang="scss" scoped>
+	.hot-title {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		padding-bottom: 20rpx;
+
+		.title-l {
+			font-family: 'PangMenZhengDao';
+			font-size: 32rpx;
+
+			.title-color {
+				color: #F3C11D;
+			}
+		}
+
+		.title-btn {
+			color: rgba(0, 0, 0, 0.6);
+			font-size: 24rpx;
+			display: inline-flex;
+			align-items: center;
+		}
+	}
+
+	.hot-wrap {
+		margin: 0 20rpx 20rpx;
+		background: linear-gradient(#FFFFFF, rgba(255, 255, 255, 0));
+		padding: 2rpx;
+		border-radius: 16rpx;
+
+		.hot-content {
+			background: linear-gradient(#fff1c3 4%, #FFFFFF 28%);
+			border-radius: 16rpx;
+			padding: 20rpx;
+			height: 240rpx;
+			box-sizing: border-box;
+
+			.hot-list {
+				.hot-panel {
+					width: 100%;
+					display: flex;
+
+					.hot-item {
+						width: calc(50% - 10rpx);
+						display: flex;
+						white-space: nowrap;
+
+						.hot-img {
+							flex: none;
+							width: 116rpx;
+							height: 116rpx;
+							object-fit: cover;
+							border-radius: 10rpx;
+						}
+
+						.item-info {
+							padding-left: 10rpx;
+							width: 200rpx;
+
+							.info-text {
+								color: #000000;
+								font-size: 24rpx;
+							}
+
+							.info-price {
+								display: flex;
+								align-items: baseline;
+								justify-content: space-between;
+
+								.price-text {
+									color: #FF7700;
+									font-size: 36rpx;
+
+									.price-unit {
+										font-size: 23rpx;
+									}
+								}
+
+								.info-sold {
+									font-size: 20rpx;
+									color: #C4C4C4;
+								}
+							}
+						}
+					}
+
+					.hot-item+.hot-item {
+						margin-left: 20rpx;
+					}
+				}
+			}
+		}
+	}
+</style>

+ 164 - 0
pages/tabBar/home/mapComponent.vue

@@ -0,0 +1,164 @@
+<template>
+  <view>
+    <map
+      id="homeId"
+      :latitude="latitude"
+      :longitude="longitude"
+      @markertap="onMarkerTap"
+      @callouttap="onCalloutTap"
+      @labeltap="onLabelTap"
+      :markers="markers"
+      :include-points="includePoints"
+      show-location
+      style="width: 100%; height: 280rpx; display: block;"
+    ></map>
+  </view>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+
+const latitude = ref(23.099994)
+const longitude = ref(113.324520)
+const markers = ref([])
+const includePoints = ref([])
+const mapCtx = ref(null)
+const img = ref('../../../static/map/point.png')
+
+onMounted(() => {
+  // #ifdef MP-WEIXIN
+  uni.nextTick(() => {
+    mapCtx.value = uni.createMapContext('homeId', this)
+    console.log('地图上下文:', mapCtx.value) // 确认是否成功获取
+    
+    if (mapCtx.value) {
+      bindEvent() // 确保上下文存在再调用
+    } else {
+      console.error('地图上下文获取失败')
+    }
+  })
+  // #endif
+})
+
+const bindEvent = () => {
+  // #ifdef MP-WEIXIN
+  console.log('bindEvent',  mapCtx.value )
+  mapCtx.value.initMarkerCluster({
+    enableDefaultStyle: false,
+    zoomOnClick: true,
+    gridSize: 60,
+    complete(res) {
+      console.log('initMarkerCluster', res)
+    }
+  })
+  
+  addMarkers()
+  
+  mapCtx.value.on('markerClusterCreate', res => {
+    console.log('clusterCreate', res)
+    const clusters = res.clusters
+    const newMarkers = clusters.map(cluster => {
+      const { center, clusterId, markerIds } = cluster
+      return {
+        ...center,
+        width: 0,
+        height: 0,
+        clusterId, // 必须
+        label: {
+          content: markerIds.length + '',
+          fontSize: 20,
+          width: 60,
+          height: 60,
+          bgColor: '#00ff00',
+          borderRadius: 30,
+          textAlign: 'center',
+          anchorX: 0,
+          anchorY: -30,
+        }
+      }
+    })
+    mapCtx.value.addMarkers({
+      markers: newMarkers,
+      clear: false,
+      complete(res) {
+        console.log('clusterCreate addMarkers', res)
+      }
+    })
+  })
+  // #endif
+}
+
+const addMarkers = () => {
+  const marker = {
+    id: 1,
+    iconPath: img.value,
+    width: 30,
+    height: 30,
+    joinCluster: true, // 指定了该参数才会参与聚合
+    label: {
+      width: 50,
+      height: 30,
+      borderWidth: 1,
+      borderRadius: 10,
+      bgColor: '#ffffff',
+      content: ''
+    }
+  }
+
+  const positions = [
+    { latitude: 23.099994, longitude: 113.324520 },
+    { latitude: 23.099994, longitude: 113.322520 },
+    { latitude: 23.099994, longitude: 113.326520 },
+    { latitude: 23.096994, longitude: 113.329520 }
+  ]
+  
+  const newMarkers = []
+  positions.forEach((p, i) => {
+    const newMarker = {...marker, ...p}
+    newMarker.id = i + 1
+    newMarker.label.content = `label ${i + 1}`
+    newMarkers.push(newMarker)
+  })
+  
+  // #ifdef MP-WEIXIN
+  mapCtx.value.addMarkers({
+    markers: newMarkers,
+    clear: false,
+    complete(res) {
+      console.log('addMarkers', res)
+    }
+  })
+  // #else
+  // 非微信平台直接设置 markers
+  markers.value = markers.value.concat(newMarkers)
+  // 更新包含的点
+  includePoints.value = markers.value.map(marker => ({
+    latitude: marker.latitude,
+    longitude: marker.longitude
+  }))
+  // #endif
+}
+
+const removeMarkers = () => {
+  // #ifdef MP-WEIXIN
+  mapCtx.value.addMarkers({
+    clear: true,
+    markers: []
+  })
+  // #else
+  markers.value = []
+  // #endif
+}
+
+const onMarkerTap = (e) => {
+  console.log('@@ markertap', e)
+}
+
+const onCalloutTap = (e) => {
+  console.log('@@ onCalloutTap', e)
+}
+
+const onLabelTap = (e) => {
+  console.log('@@ labletap', e)
+}
+</script>

+ 239 - 0
pages/tabBar/home/subPages/allGardenMap.vue

@@ -0,0 +1,239 @@
+<template>
+  <view>
+    <map
+      id="mapId"
+      :latitude="latitude"
+      :longitude="longitude"
+	  :layers="layers"
+      @markertap="onMarkerTap"
+      @callouttap="onCalloutTap"
+      @labeltap="onLabelTap"
+      :markers="markers"
+      :include-points="includePoints"
+	  :enable-satellite="true"
+	  theme="satellite"
+      show-location
+      style="width: 100%; height: 100vh;"
+    ></map>
+  </view>
+</template>
+
+<script setup>
+import { ref, onMounted } from 'vue'
+
+const latitude = ref(26.870355)
+const longitude = ref(100.239704)
+// const latitude = ref(23.584863449735067)
+// const longitude = ref(113.61702297075017)
+
+const markers = ref([])
+const includePoints = ref([])
+const mapCtx = ref(null)
+const img = ref('../../../../static/map/point.png')
+const layers = [
+        {
+          // 添加腾讯地图默认底图(可选)
+          type: 'vector',
+          subdomains: ['0', '1', '2'],
+          url: 'https://{s}.map.qq.com/tile/{z}/{x}/{y}',
+          zIndex: 0,
+        },
+        {
+          // 叠加天地图影像(WMTS)
+          type: 'wmts',
+          layer: 'img',
+		  url: 'https://t{s}.tianditu.gov.cn/img_c/wmts?tk=e95115c454a663cd052d96019fd83840&service=wmts&request=GetTile&version=1.0.0&layer=img&style=default&tilematrixset=c&format=tiles',
+          // url: 'https://t{s}.tianditu.gov.cn/img_c/wmts?tk=e95115c454a663cd052d96019fd83840',
+          tileMatrixSet: 'c',
+          subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'],
+          zIndex: 1,
+        }
+      ]
+
+onMounted(() => {
+  // #ifdef MP-WEIXIN
+  mapCtx.value = uni.createMapContext('mapId')
+  mapCtx.value.on('markerClusterClick', res => {
+    console.log('markerClusterClick', res)
+  })
+  
+  bindEvent()
+  // #endif
+  
+  
+})
+
+const bindEvent = () => {
+  // #ifdef MP-WEIXIN
+  mapCtx.value.initMarkerCluster({
+    enableDefaultStyle: false,
+    zoomOnClick: true,
+    gridSize: 60,
+    complete(res) {
+      console.log('initMarkerCluster', res)
+    }
+  })
+  
+  addMarkers()
+  
+  mapCtx.value.on('markerClusterCreate', res => {
+    console.log('clusterCreate', res)
+    const clusters = res.clusters
+    const newMarkers = clusters.map(cluster => {
+      const { center, clusterId, markerIds } = cluster
+      return {
+        ...center,
+        width: 0,
+        height: 0,
+        clusterId, // 必须
+        label: {
+          content: markerIds.length + '',
+          fontSize: 20,
+          width: 30,
+          height: 30,
+          bgColor: '#FFCB3C',
+          borderRadius: 30,
+          textAlign: 'center',
+          anchorX: 0,
+          anchorY: -30,
+        }
+      }
+    })
+    mapCtx.value.addMarkers({
+      markers: newMarkers,
+      clear: false,
+      complete(res) {
+        console.log('clusterCreate addMarkers', res)
+      }
+    })
+  })
+  // let xyz = "https://birdseye-img.sysuimars.com/map/lby/{z}/{x}/{y}.png";
+  //    mapCtx.value.addCustomLayer({
+  //      id: 'custom-tile-layer',
+  //      type: 'raster',
+  //      source: {
+  //        type: 'raster',
+  //        tiles: [xyz],  // 替换为你的瓦片 URL
+  //        tileSize: 256,
+  //      },
+  //      paint: {},
+	 //   zIndex: 99
+  //    });
+	 
+	 // const mapCtx2 = uni.createMapContext('mapId', this);
+	     const xyz = "https://birdseye-img.sysuimars.com/map/lby/z/x/y.png";
+		 const demoLayer = 'https://3gimg.qq.com/visual/lbs_gl_demo/image_tiles_layers/z/x_y.png'
+	     
+	   //   mapCtx.value.addCustomLayer({
+			 // layerId: 'cunstom',
+	   //     id: 'custom-tile-layer',
+	   //     type: 'raster',
+	   //     source: {
+	   //       type: 'raster',
+	   //       tiles: [demoLayer],
+	   //       tileSize: 256,
+	   //     },
+	   //     paint: {},
+	   //     success: (res) => console.log("图层添加成功", res),
+	   //     fail: (err) => console.error("图层添加失败", err)
+	   //   });
+		 
+		 
+		   mapCtx.value.addGroundOverlay({
+		     id: 'gaode-tiles',
+		     type: 'raster',
+		     source: {
+		       type: 'raster',
+		       tiles: [
+		         'https://webst01.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}'
+		       ],
+		       tileSize: 256,
+		     },
+		     paint: {},
+		     success: (res) => {
+		       console.log("高德瓦片加载成功");
+		     },
+		     fail: (err) => {
+		       console.error("加载失败", err);
+		     }
+		   });
+  // #endif
+}
+
+const addMarkers = () => {
+  const marker = {
+    id: 1,
+    iconPath: img.value,
+    width: 30,
+    height: 30,
+    joinCluster: true, // 指定了该参数才会参与聚合
+    label: {
+      width: 50,
+      height: 30,
+      borderWidth: 1,
+      borderRadius: 4,
+      bgColor: '#FFCB3C88',
+	  anchorX: -26,
+	  anchorY: -60,
+      content: ''
+    }
+  }
+
+  const positions = [
+    { latitude: 23.584863449735067, longitude: 113.61702297075017},
+    { latitude: 23.099994, longitude: 113.324520 },
+    { latitude: 23.099994, longitude: 113.322520 },
+    { latitude: 23.099994, longitude: 113.326520 },
+    { latitude: 23.096994, longitude: 113.329520 }
+  ]
+  
+  const newMarkers = []
+  positions.forEach((p, i) => {
+    const newMarker = {...marker, ...p}
+    newMarker.id = i + 1
+    newMarker.label.content = `果园 ${i + 1}`
+    newMarkers.push(newMarker)
+  })
+  
+  // #ifdef MP-WEIXIN
+  mapCtx.value.addMarkers({
+    markers: newMarkers,
+    clear: false,
+    complete(res) {
+      console.log('addMarkers', res)
+    }
+  })
+  // #else
+  // 非微信平台直接设置 markers
+  markers.value = markers.value.concat(newMarkers)
+  // 更新包含的点
+  includePoints.value = markers.value.map(marker => ({
+    latitude: marker.latitude,
+    longitude: marker.longitude
+  }))
+  // #endif
+}
+
+const removeMarkers = () => {
+  // #ifdef MP-WEIXIN
+  mapCtx.value.addMarkers({
+    clear: true,
+    markers: []
+  })
+  // #else
+  markers.value = []
+  // #endif
+}
+
+const onMarkerTap = (e) => {
+  console.log('@@ markertap', e)
+}
+
+const onCalloutTap = (e) => {
+  console.log('@@ onCalloutTap', e)
+}
+
+const onLabelTap = (e) => {
+  console.log('@@ labletap', e)
+}
+</script>

+ 199 - 0
pages/tabBar/home/subPages/gardenItem.vue

@@ -0,0 +1,199 @@
+<template>
+	<view class="garden-item-page">
+		<view class="report-content">
+			<view class="home-search">
+				<view class="search-wrap">
+					<up-search placeholder="搜索品种" v-model="typeSearch"></up-search>
+				</view>
+			</view>
+			<view class="tips">
+				下拉查看溯源报告
+			</view>
+			<view class="swipe-item">
+				<video class="video-wrap" src="https://birdseye-img.sysuimars.com/temp/5-25lby.mp4" controls></video>
+			</view>
+		</view>
+		<l-floating-panel v-model:height="panelHeight" :anchors="anchors" :defaultAnchor="2">
+		  <view class="panel-content">
+			  <view class="panel-title">
+			  	<view class="title-l">
+			  		<image class="garden-img" :src="`${config.BASIC_IMG}home/garden.png`" mode=""></image>
+					<view class="title-info">
+						<view class="title-garden">
+							从化荔枝博览园
+						</view>
+						<view class="btn-second">
+							有味指数
+							<text>4.5分</text>
+						</view>
+					</view>
+			  	</view>
+				<view class="title-r">
+					+
+					<text class="add-text">关注</text>
+				</view>
+			  </view>
+			  <view class="panel-video">
+			  	<video class="video-dom" src="https://birdseye-img.sysuimars.com/temp/5-25lby.mp4" controls></video>
+			  </view>
+			  <hot-component-vue></hot-component-vue>
+		  </view>
+		</l-floating-panel>
+	</view>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+import config from "@/api/config.js"
+import hotComponentVue from '../hotComponent.vue'
+
+
+const typeSearch = ref(null)
+	
+	 const {windowHeight} = uni.getSystemInfoSync()
+	    const anchors = [
+	            50,
+	            Math.round(0.5 * windowHeight),
+	            Math.round(0.95 * windowHeight),
+	    ];
+	    const panelHeight = ref(anchors[2]);
+		
+		const myVideo = ref(null);
+		const onVideoReady = () => {
+		    myVideo.value.play();
+		};
+</script>
+
+<style lang="scss" scoped>
+	.garden-item-page {
+		width: 100%;
+		height: 100vh;
+		.report-content {
+			width: 100%;
+			height: calc(100% - 140rpx);
+			position: relative;
+			.home-search {
+				position: absolute;
+				z-index: 2;
+				top: 20rpx;
+				left: 24rpx;
+				display: flex;
+				align-items: center;
+				width: calc(100% - 48rpx);
+				border: 2rpx solid rgba(255, 255, 255, 0.39);
+				border-radius: 40rpx;
+				margin-bottom: 40rpx;
+				background-color: rgba(0, 0, 0, 0.31);
+				.search-wrap {
+					flex: 1;
+					// padding-left: 22rpx;
+					::v-deep {
+						.u-search {
+							.u-search__content {
+								background-color: transparent !important;
+								.u-search__content__input {
+									background-color: transparent !important;
+									
+								}
+							}
+							.uni-input-input {
+								color: rgba(255, 255, 255, 0.8);
+							}
+							.u-search__action {
+								text-align: center;
+								line-height: 52rpx;
+								border-radius: 40rpx;
+								font-size: 28rpx;
+								background-color: rgba(255, 255, 255, 0.3);
+								color: rgba(255, 255, 255, 0.3);
+								margin: 6rpx 8rpx;
+								width: 112rpx;
+								height: 52rpx;
+							}
+						}
+					}
+				}
+			}
+			.tips {
+				position: absolute;
+				z-index: 2;
+				top: 110rpx;
+				left: 0;
+				color: #FFFFFF;
+				font-size: 24rpx;
+				width: 100%;
+				text-align: center;
+			}
+			.swipe-item {
+				width: 100%;
+				height: 100%;
+				.video-wrap {
+					width: 100%;
+					height: 100%;
+					object-fit: contain;
+				}
+			}
+		}
+	}
+	
+	.panel-content {
+		padding: 24rpx;
+		.panel-title {
+			display: flex;
+			align-items: center;
+			justify-content: space-between;
+			.title-l {
+				flex: 1;
+				display: flex;
+				align-items: center;
+				.garden-img {
+					width: 100rpx;
+					height: 100rpx;
+					border-radius: 10rpx;
+				}
+				.title-info {
+					padding-left: 20rpx;
+					.title-garden {
+						color: #000000;
+						font-size: 28rpx;
+						font-weight: 600;
+						padding-bottom: 10rpx;
+					}
+					.btn-second {
+						padding: 0 30rpx;
+						border-radius: 40rpx;
+						font-size: 24rpx;
+						color: #C49600;
+						background: rgba(255, 217, 94, 0.2);
+						height: 56rpx;
+						line-height: 56rpx;
+					}
+				}
+			}
+			.title-r {
+				display: flex;
+				font-size: 24rpx;
+				padding: 8rpx 22rpx;
+				background: #FFD95E;
+				border-radius: 30rpx;
+				.add-text {
+					padding-left: 6rpx;
+					font-weight: 600;
+				}
+			}
+		}
+		
+		.panel-video {
+			padding: 20rpx 0;
+			height: 300rpx;
+			width: 100%;
+			.video-dom {
+				width: 100%;
+				height: 100%;
+				object-fit: cover;
+				border-radius: 10rpx;
+			}
+		}
+	}
+	       
+</style>

binární
static/home/fruit-1.png


binární
static/home/fruit-2.png


binární
static/home/fruit-3.png


binární
static/home/fruit.png


+ 30 - 0
uni_modules/lime-floating-panel/changelog.md

@@ -0,0 +1,30 @@
+## 0.1.6(2025-04-25)
+- feat: 兼容uniappx 鸿蒙next
+## 0.1.5(2025-02-09)
+- feat: 更改props类型,防止重复
+## 0.1.4(2025-02-09)
+- chore: 更新文档
+## 0.1.3(2024-12-19)
+- fix: 修复uniappx anchors为0铺满屏幕的BUG。
+- feat: 兼容uniappx 微信小程序
+## 0.1.2(2024-12-05)
+- fix: 修复vue2 anchors没有默认值时报错。
+## 0.1.1(2024-11-18)
+- fix: 修复默认锚点不生效
+## 0.1.0(2024-11-15)
+- fix: 修复缺少vue
+## 0.0.9(2024-09-15)
+- feat: 兼容uniappx
+## 0.0.8(2023-08-05)
+- feat: 增加`change`事件,返回当前高度和描点下标
+## 0.0.7(2023-07-21)
+- fix: 修复 设置`props.contentDraggable`失效问题
+## 0.0.6(2023-07-19)
+- feat: 把 `anchorIndex`改成 `defaultAnchor`
+## 0.0.5(2023-07-19)
+- feat: 增加 `anchorIndex`和`toAnchor`
+- chore: 更新文档
+## 0.0.2(2023-07-18)
+- fix: 修复 vue2 app 端init无响应问题
+## 0.0.1(2023-07-06)
+- 初版,可能存在bug

+ 65 - 0
uni_modules/lime-floating-panel/components/l-floating-panel/index-u.scss

@@ -0,0 +1,65 @@
+@import '~@/uni_modules/lime-style/index.scss';
+
+
+$floating-panel-border-radius: create-var(floating-panel-border-radius, 32rpx);
+$floating-panel-header-height: create-var(floating-panel-header-height, 60rpx);
+$floating-panel-z-index: create-var(floating-panel-z-index, 999);
+$floating-panel-background: create-var(floating-panel-background, white);
+$floating-panel-bar-width: create-var(floating-panel-bar-width, 60rpx);
+$floating-panel-bar-height: create-var(floating-panel-bar-height, 6rpx);
+$floating-panel-bar-color: create-var(floating-panel-bar-color, #ddd);
+$floating-panel-bar-radius: create-var(floating-panel-bar-radius, 6rpx);
+
+
+
+.l-floating-panel {
+	position: fixed;
+	left: 0;
+	bottom: -150rpx;
+	width: 100%;
+	z-index: $floating-panel-z-index;
+	display: flex;
+	flex-direction: column;
+	// touch-action: none;
+	border-top-left-radius: $floating-panel-border-radius;
+	border-top-right-radius: $floating-panel-border-radius;
+	background: $floating-panel-background;
+	transition-property: transform;
+	// transition-duration: 10ms;
+	transition-timing-function: cubic-bezier(0.18, 0.89, 0.32, 1.28);
+	// pointer-events: auto;
+	padding-bottom: 150rpx;
+	box-sizing: content-box;
+	&__header {
+		height: $floating-panel-header-height;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		// #ifndef APP-ANDROID || APP-IOS || APP-HARMONY
+		cursor: grab;
+		user-select: none;
+		// #endif
+		&-bar {
+			height: $floating-panel-bar-height;
+			width: $floating-panel-bar-width;
+			border-radius: $floating-panel-bar-radius;
+			background: $floating-panel-bar-color;
+		}
+	}
+	
+	&__content {
+		flex: 1;
+		background-color: $floating-panel-background;
+		// user-select: none;
+	}
+	
+	// &::after {
+	//     content: '';
+	//     display: block;
+	//     position: absolute;
+	//     bottom: -100vh;
+	//     height: 100vh;
+	//     width: 750rpx;
+	//     background-color: inherit;
+	// }
+}

+ 75 - 0
uni_modules/lime-floating-panel/components/l-floating-panel/index.scss

@@ -0,0 +1,75 @@
+@import '~@/uni_modules/lime-style/index.scss';
+
+
+$floating-panel-border-radius: create-var(floating-panel-border-radius, 16px);
+$floating-panel-header-height: create-var(floating-panel-header-height, 30px);
+$floating-panel-z-index: create-var(floating-panel-z-index, 999);
+$floating-panel-background: create-var(floating-panel-background, white);
+$floating-panel-bar-width: create-var(floating-panel-bar-width,  20px);
+$floating-panel-bar-height: create-var(floating-panel-bar-height, 3px);
+$floating-panel-bar-color: create-var(floating-panel-bar-color, #ddd);
+$floating-panel-bar-radius: create-var(floating-panel-bar-radius, 3px);
+
+
+// $floating-panel-border-radius: var(--l-floating-panel-border-radius, 16px);
+// $floating-panel-header-height: var(--l-floating-panel-header-height, 30px);
+// $floating-panel-z-index: var(--l-floating-panel-z-index, 999);
+// $floating-panel-background: var(--l-floating-panel-background, white);
+// $floating-panel-bar-width: var(--l-floating-panel-bar-width, 20px);
+// $floating-panel-bar-height: var(--l-floating-panel-bar-height, 3px);
+// $floating-panel-bar-color: var(--l-floating-panel-bar-color, #ddd);
+// $floating-panel-bar-radius: var(--l-floating-panel-bar-radius, 3px);
+
+
+.l-floating-panel {
+	display: flex;
+	flex-direction: column;
+	touch-action: none;
+	border-top-left-radius: $floating-panel-border-radius;
+	border-top-right-radius: $floating-panel-border-radius;
+	background: $floating-panel-background;
+	width: 750rpx;
+	pointer-events: auto;
+	&-area {
+		position: fixed;
+		left: 0;
+		bottom: -100vh;
+		width: 750rpx;
+		height: 200vh;
+		z-index: $floating-panel-z-index;
+		pointer-events: none;
+		opacity: 0;
+		transition: transform,opacity 0.3s;
+	}
+	
+	&__header {
+		height: $floating-panel-header-height;
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		cursor: grab;
+		user-select: none;
+		&-bar {
+			height: $floating-panel-bar-height;
+			width: $floating-panel-bar-width;
+			border-radius: $floating-panel-bar-radius;
+			background: $floating-panel-bar-color;
+		}
+	}
+	
+	&__content {
+		flex: 1;
+		overflow: hidden;
+		background-color: $floating-panel-background;
+	}
+	
+	&::after {
+	    content: '';
+	    display: block;
+	    position: absolute;
+	    bottom: -100vh;
+	    height: 100vh;
+	    width: 750rpx;
+	    background-color: inherit;
+	}
+}

+ 346 - 0
uni_modules/lime-floating-panel/components/l-floating-panel/l-floating-panel.uvue

@@ -0,0 +1,346 @@
+<template>
+	<!-- #ifdef APP-ANDROID || APP-IOS || APP-HARMONY || WEB -->
+	<view class="l-floating-panel" :style="[styles]" ref="rootRef" @touchstart="onTouchstart"
+		@touchmove.stop="onTouchmove" 
+		@touchend="onTouchend" 
+		@touchcancel="onTouchend" 
+		@transitionend="onTransitionend">
+		<view class="l-floating-panel__header">
+			<view 
+				class="l-floating-panel__header-bar" 
+				:style="[barStyle]">
+			</view>
+		</view>
+		<slot></slot>
+	</view>
+	<!-- #endif -->
+	<!-- #ifndef APP-ANDROID || APP-IOS || APP-HARMONY || WEB -->
+	<movable-area class="l-floating-panel-area" :style="[areaStyles]" :data-initialized="initialized">
+		<movable-view 
+			class="l-floating-panel" 
+			direction="vertical" 
+			inertia 
+			out-of-bounds 
+			:damping="80" 
+			:friction="100"
+			:disabled="isDraggable"
+			:y="currentY"
+			:animation="isAnimation"
+			@change="onTouchmove"
+			@touchstart="onTouchstart"
+			@touchend="onTouchend"
+			@touchcancel="onTouchend"
+			:style="[styles]">
+			<view class="l-floating-panel__header" data-handle="true">
+				<view class="l-floating-panel__header-bar" :style="[barStyle]"></view>
+			</view>
+			<view class="l-floating-panel__content">
+				<slot></slot>
+			</view>
+		</movable-view>
+	</movable-area>
+	<!-- #endif -->
+</template>
+<script lang="uts" setup>
+	import { addUnit } from '@/uni_modules/lime-shared/addUnit';
+	import { closest } from '@/uni_modules/lime-shared/closest';
+	import { unitConvert } from '@/uni_modules/lime-shared/unitConvert';
+	import { LFloatingPanelBoundary , FloatingPanelProps} from './type'
+	// #ifdef APP-ANDROID || APP-IOS || APP-HARMONY || WEB
+	import { useTouch } from './useTouch'
+	// #endif
+	const emit = defineEmits(['heightChange', 'change', 'update:height'])
+	const props = withDefaults(defineProps<FloatingPanelProps>(), {
+		height: 0,
+		anchors: [] as number[],
+		defaultAnchor: 0,
+		animation: true,
+		duration: 300,
+		contentDraggable: true,
+		safeAreaInsetBottom: true
+	})
+	// const height = defineModel('height', {type: Number, default: 0})
+	
+	let info = uni.getWindowInfo()
+	const windowHeight = ref(info.windowHeight)
+	const safeAreaInsets = ref(info.safeAreaInsets)
+	
+	let dragging = ref(false);
+	let initialized = ref(false)
+
+	const boundary = computed(() : LFloatingPanelBoundary => {
+		const _anchors = props.anchors;
+		const length = _anchors.length
+		return {
+			min: length > 0 ? _anchors[0] : 100,
+			max: length > 0 ? _anchors[length - 1] : Math.round(windowHeight.value * 0.6),
+		} as LFloatingPanelBoundary
+	})
+	
+	const anchors = computed(() : number[] => {
+		return props.anchors.length >= 2 ? props.anchors : [boundary.value.min, boundary.value.max]
+	})
+	
+	const styles = computed(() : Map<string, any> => {
+		const style = new Map<string, any>()
+		style.set('height', `${boundary.value.max}px`)
+		if(props.bgColor != null) {
+			style.set('background-color', props.bgColor!)
+		}
+		return style
+	})
+	
+	const barStyle = computed(() : Map<string, any> => {
+		const style = new Map<string, any>()
+		if(props.barColor != null) {
+			style.set('background-color', props.barColor!)
+		}
+		
+		return style
+	})
+	
+	// #ifdef APP-ANDROID || APP-IOS || APP-HARMONY || WEB
+	const touch = useTouch()
+	const rootRef = ref<UniElement | null>(null)
+	const contentRef = ref<UniElement | null>(null)
+	
+	const jumpAnchor = ref(0)
+	const DAMP = 0.2;
+	const height = ref(0);
+	
+	let startY = 0;
+	let maxScroll = -1;
+	
+	const ease = (moveY : number) : number => {
+		const absDistance = Math.abs(moveY);
+		const { min, max } = boundary.value;
+
+		if (absDistance > max) {
+			return -(max + (absDistance - max) * DAMP);
+		}
+
+		if (absDistance < min) {
+			return -(min - (min - absDistance) * DAMP);
+		}
+
+		return moveY;
+	};
+
+
+	const onTouchstart = (e : UniTouchEvent) => {
+		touch.start(e);
+		dragging.value = true;
+		startY = -height.value;
+		maxScroll = -1;
+	}
+	const onTouchmove = (e : UniTouchEvent) => {
+		touch.move(e);
+		const target = e.target!
+		const classNmae = target.classList.length > 0 ? target.classList[0] : '';
+		// 只有拖动了内容区域才进行判断是否需要阻止滚动
+		if (!['l-floating-panel__header', 'l-floating-panel__header-bar'].includes(classNmae) && contentRef.value != null) {
+			let scrollTop = 0;
+			if(contentRef.value!.tagName != 'VIEW') {
+				scrollTop = contentRef.value!.scrollTop;
+			}
+			maxScroll = Math.max(maxScroll, scrollTop);
+			if (!props.contentDraggable) return;
+			if (-startY < boundary.value.max) {
+				e.preventDefault()
+				e.stopPropagation()
+			}
+			else if (!(scrollTop <= 0 && touch.deltaY.value > 0) || maxScroll > 0) {
+				return;
+			}
+		}
+		//touch.deltaY.value 向上负 向下正
+		const moveY = touch.deltaY.value + startY;
+		height.value = -ease(moveY);
+	}
+	const onTouchend = (_ : UniTouchEvent) => {
+		maxScroll = -1;
+		dragging.value = false;
+		height.value = closest(anchors.value, height.value);
+
+		if (height.value != -startY) {
+			emit('heightChange', { height: height.value });
+		}
+	}
+	const onTransitionend = (_ : UniEvent) => {
+		const index = anchors.value.findIndex((item : number) : boolean => item == height.value)
+		if (index >= 0) {
+			jumpAnchor.value = index
+		}
+	}
+	
+	const update = (value: number) => {
+		if (rootRef.value == null) return
+		rootRef.value!.style.setProperty('transition-duration', !dragging.value && initialized.value ? `${props.duration}ms` : '0ms')
+		if(!dragging.value && initialized.value) {
+			// 安卓要延时一下
+			nextTick(() => {
+				rootRef.value!.style.setProperty('transform', `translateY(${addUnit(boundary.value.max - value)})`)
+			})
+		} else {
+			rootRef.value!.style.setProperty('transform', `translateY(${addUnit(boundary.value.max - value)})`)
+		}
+		emit('update:height', value)
+	}
+	const stopWatchHeight = watch(height, update)
+
+	// const stopWatchBoundary = watch(boundary, (_ : LFloatingPanelBoundary) => {
+	// 	height.value = closest(anchors.value, props.defaultAnchor == 0 ? height.value : anchors.value[props.defaultAnchor]);
+	// })
+
+	const stopWatchJumpAnchor = watch(jumpAnchor, (index : number) => {
+		height.value = anchors.value[index]
+	})
+
+	onMounted(() => {
+		nextTick(() => {
+			// 鸿蒙无法在setup阶段获取到信息
+			const res = uni.getWindowInfo();
+			windowHeight.value = res.windowHeight
+			safeAreaInsets.value = res.safeAreaInsets
+			if (props.safeAreaInsetBottom && rootRef.value != null) {
+				rootRef.value!.style.setProperty('padding-bottom', addUnit( unitConvert('150rpx') + safeAreaInsets.value.bottom))
+			}
+			// 查找插槽中的元素节点
+			if (rootRef.value != null) {
+				const lastChild = rootRef.value!.children[rootRef.value!.children.length - 1]
+				if (lastChild.tagName != 'COMMENT') {
+					contentRef.value = lastChild
+				} else if (lastChild.previousSibling?.tagName != 'COMMENT') {
+					contentRef.value = lastChild.previousSibling
+				}
+			}
+			height.value = closest(anchors.value, props.defaultAnchor == 0 ? height.value : anchors.value[props.defaultAnchor]);
+			update(height.value)
+			nextTick(() => {
+				// 首次不使用动画
+				initialized.value = true
+			})
+			
+			// let { windowHeight ,safeAreaInsets } = uni.getWindowInfo()
+		})
+	})
+	// #endif
+	
+	// #ifndef APP-ANDROID || APP-IOS || APP-HARMONY || WEB
+	const areaStyles = computed(() => {
+		return ({
+			height: addUnit(boundary.value.max * 2 - boundary.value.min),
+			bottom: addUnit(boundary.value.max * -1 + boundary.value.min +(props.safeAreaInsetBottom ? safeAreaInsets.value.bottom:0)),
+			opacity: initialized.value ? 1 : 0
+		}) 
+	})
+	const calcY = (y: number):number => boundary.value.max - y;
+	
+	let moveYs = []
+	let startY = 0
+	const isAnimation = ref(false)
+	const currentY = ref(calcY(props.anchors[props.defaultAnchor]) ?? calcY(boundary.value.min))
+	const isDraggable = ref(!props.contentDraggable)
+	
+	
+	
+	
+	const onTouchstart = (e:  WechatMiniprogram.TouchEvent) => {
+		startY = e.touches[0].clientY
+		dragging.value = true
+		moveYs.length = 0
+		const { handle } = e.target.dataset
+		if(!props.contentDraggable && Boolean(handle)) {
+			isDraggable.value = false
+			return
+		}
+	}
+	
+	const onTouchmove = (e: WechatMiniprogram.MovableViewChange) => {
+		const {y}  = e.detail
+		if(dragging.value) {
+			moveYs.push(y)
+		}
+		const height = calcY(y) 
+		emit('update:height',height)
+	}
+	
+	const setCurrentY = (target: number) => {
+		// currentY.value = target + 0.1;
+		currentY.value = target
+		const height = calcY(target)
+		let index = anchors.value.findIndex(item => item == height)
+		
+		emit('heightChange', { height });
+		emit('change', { height, index });
+	}
+	
+	const reDraggable = () => {
+		if(!props.contentDraggable) {
+			setTimeout(() => {
+				 isDraggable.value = true
+			}, 50);
+		}
+	}
+	const onTouchend = (e: WechatMiniprogram.TouchEvent) => {
+		let moveY = 0
+		dragging.value = false
+		const { handle } = e.target.dataset
+		const isClick = Math.abs(e.changedTouches[0].clientY - startY) < 10
+		if(isClick && !Boolean(handle)) {
+			reDraggable()
+			return
+		}
+		if(isClick) {
+			const index = anchors.value.findIndex(item => item == calcY(currentY.value)) + 1
+			// setCurrentY(calcY(anchors.value[index % anchors.value.length]))
+			toAnchor(index % anchors.value.length)
+			reDraggable()
+			return
+		} else if(moveYs.length) {
+			moveY = moveYs[moveYs.length-1]
+		}
+		moveYs.length = 0
+		reDraggable()
+		setCurrentY(calcY(closest(anchors.value, calcY(moveY))))
+	}
+	
+	const stopWatch = watch(() => props.anchors, () => {
+		const index = anchors.value.findIndex(item => item == calcY(currentY.value)) + 1
+		toAnchor(index)
+	})
+	onMounted(() => {
+		isAnimation.value = props.animation
+		setTimeout(() => {
+			initialized.value = true
+		}, 50);
+	})
+	
+	onUnmounted(() => {
+		stopWatch()
+	})
+	
+	
+	// #endif
+	defineExpose({
+		toAnchor: (index : number) => {
+			if(index >= 0 && index < anchors.value.length) {
+				// #ifndef APP-ANDROID || APP-IOS || APP-HARMONY || WEB
+				setCurrentY(calcY(anchors.value[index]))
+				// #endif
+				// #ifdef APP-ANDROID || APP-IOS || APP-HARMONY || WEB
+				jumpAnchor.value = index
+				// #endif
+			}
+			
+		}
+	})
+</script>
+<style lang="scss">
+	/* #ifdef APP-ANDROID || APP-IOS || APP-HARMONY || WEB */
+	@import './index-u.scss';
+	/* #endif */
+	/* #ifndef APP-ANDROID || APP-IOS || APP-HARMONY || WEB */
+	@import './index.scss';
+	/* #endif */
+</style>

+ 193 - 0
uni_modules/lime-floating-panel/components/l-floating-panel/l-floating-panel.vue

@@ -0,0 +1,193 @@
+<template>
+	<movable-area class="l-floating-panel-area" :style="[areaStyles]" :data-initialized="initialized">
+		<movable-view 
+			class="l-floating-panel" 
+			direction="vertical" 
+			inertia 
+			out-of-bounds 
+			:damping="80" 
+			:friction="100"
+			:disabled="isDraggable"
+			:y="currentY"
+			:animation="isAnimation"
+			@change="onTouchmove"
+			@touchstart="onTouchstart"
+			@touchend="onTouchend"
+			@touchcancel="onTouchend"
+			:style="[styles]">
+			<view class="l-floating-panel__header" data-handle="true">
+				<view class="l-floating-panel__header-bar" :style="{'background': barColor}"></view>
+			</view>
+			<view class="l-floating-panel__content">
+				<slot></slot>
+			</view>
+		</movable-view>
+	</movable-area>
+</template>
+<script lang="ts">
+	// @ts-nocheck
+	import { defineComponent, computed, ref , onMounted, onUnmounted, watch} from '@/uni_modules/lime-shared/vue';
+	import floatingPanelProps from './props'
+	import {addUnit} from '@/uni_modules/lime-shared/addUnit';
+	import {sleep} from '@/uni_modules/lime-shared/sleep';
+	import {closest} from '@/uni_modules/lime-shared/closest';
+	const name = 'l-floating-panel'
+	/**
+	 * LimeFloatingPanel 浮动面板
+	 * @description 浮动在页面底部的面板,可以上下拖动来浏览内容
+	 * @tutorial https://ext.dcloud.net.cn/plugin?id=13407
+	 * @property {Number} height 插件返回的高度
+	 * @property {Array} anchors 设置自定义锚点 默认值 [100, windowHeight * 0.6]
+	 * @property {Number} defaultAnchor 设置开始锚点的下标
+	 * @property {Boolean} animation 是否开启动画
+	 * @property {Boolean} contentDraggable = true 允许拖拽内容容器 默认 true
+	 * @property {Boolean} safeAreaInsetBottom = true 是否开启底部安全区域 默认 true 
+	 * @event {Function} heightChange 高度变化时触发  
+	 */
+	export default defineComponent({
+		name,
+		props: floatingPanelProps,
+		emits: ['heightChange', 'change', 'update:height'],
+		setup(props, {emit, expose}) {
+			const {windowHeight, safeAreaInsets } = uni.getSystemInfoSync()
+			const isDraggable = ref(!props.contentDraggable)
+			const isAnimation = ref(false)
+			const dragging = ref(false)
+			
+			const initialized = ref(false)
+			const boundary = computed(() => {
+				const anchors = props.anchors as number[]||[];
+				return {
+					min: anchors[0] ?? 100,
+					max:
+						anchors[anchors.length - 1] ??
+						Math.round(windowHeight * 0.6),
+				}
+			});
+			const calcY = (y: number) => boundary.value.max - y
+			const anchors = computed(() => {
+				const anchors = props.anchors as number[]||[];
+				return anchors.length >= 2
+			        ? anchors
+			        : [boundary.value.min, boundary.value.max]
+			})
+			const areaStyles = computed(() => {
+				return ({
+					height: addUnit(boundary.value.max * 2 - boundary.value.min),
+					bottom: addUnit(boundary.value.max * -1 + boundary.value.min +(props.safeAreaInsetBottom ? safeAreaInsets.bottom:0)),
+					opacity: initialized.value ? 1 : 0
+				}) 
+			})
+			const styles = computed(() => {
+				return ({
+					height: addUnit(boundary.value.max) ,
+					background: props.baColor
+				})
+			})
+			
+			const currentY = ref(calcY(props.anchors[props.defaultAnchor]) ?? calcY(boundary.value.min))
+			let moveYs = []
+			let startY = 0
+			const onTouchstart = (e:  WechatMiniprogram.TouchEvent) => {
+				startY = e.touches[0].clientY
+				dragging.value = true
+				moveYs.length = 0
+				const { handle } = e.target.dataset
+				if(!props.contentDraggable && Boolean(handle)) {
+					isDraggable.value = false
+					return
+				}
+				
+			}
+			const onTouchmove = (e: WechatMiniprogram.MovableViewChange) => {
+				const {y}  = e.detail
+				if(dragging.value) {
+					moveYs.push(y)
+				}
+				const height = calcY(y) 
+				emit('update:height',height)
+			}
+			
+			const setCurrentY = (target: number) => {
+				currentY.value = target + 0.1;
+				// h5要延迟才能触发
+				sleep(50).then(() => {
+					currentY.value = target
+					const height = calcY(target)
+					let index = anchors.value.findIndex(item => item == height)
+					
+					emit('heightChange', { height });
+					emit('change', { height, index });
+				})
+			}
+			const toAnchor = (index: number) => {
+				if(index >= 0 && index < anchors.value.length) {
+					setCurrentY(calcY(anchors.value[index]))
+				}
+			}
+			const reDraggable = () => {
+				if(!props.contentDraggable) {
+					sleep(50).then(() => isDraggable.value = true)
+				}
+			}
+			const onTouchend = (e: WechatMiniprogram.TouchEvent) => {
+				let moveY = 0
+				dragging.value = false
+				const { handle } = e.target.dataset
+				const isClick = Math.abs(e.changedTouches[0].clientY - startY) < 10
+				if(isClick && !Boolean(handle)) {
+					reDraggable()
+					return
+				}
+				if(isClick) {
+					const index = anchors.value.findIndex(item => item == calcY(currentY.value)) + 1
+					// setCurrentY(calcY(anchors.value[index % anchors.value.length]))
+					toAnchor(index % anchors.value.length)
+					reDraggable()
+					return
+				} else if(moveYs.length) {
+					moveY = moveYs[moveYs.length-1]
+				}
+				moveYs.length = 0
+				reDraggable()
+				setCurrentY(calcY(closest(anchors.value, calcY(moveY))))
+			}
+			
+			const stopWatch = watch(() => props.anchors, () => {
+				const index = anchors.value.findIndex(item => item == calcY(currentY.value)) + 1
+				toAnchor(index)
+			})
+			onMounted(() => {
+				isAnimation.value = props.animation
+				sleep(50).then(() => initialized.value = true)
+			})
+			
+			onUnmounted(() => {
+				stopWatch()
+			})
+			// #ifdef VUE3
+			expose({
+				toAnchor
+			})
+			// #endif
+			
+			return {
+				initialized,
+				areaStyles,
+				styles,
+				isDraggable,
+				isAnimation,
+				currentY,
+				onTouchstart,
+				onTouchmove,
+				onTouchend,
+				// #ifndef VUE3
+				toAnchor
+				// #endif
+			}
+		}
+	})
+</script>
+<style lang="scss">
+	@import './index.scss';
+</style>

+ 30 - 0
uni_modules/lime-floating-panel/components/l-floating-panel/props.ts

@@ -0,0 +1,30 @@
+// @ts-nocheck
+// import {PropType} from 'vue'
+export default {
+	height: {
+		type: Number,
+		default: 0
+	},
+	defaultAnchor: {
+	    type: Number,
+	    default: 0
+	},
+	anchors: {
+		type: Array,// as PropType<number[]>,
+		default: () => []
+	},
+	animation: {
+		type: Boolean,
+		default: true
+	},
+	contentDraggable: {
+		type: Boolean,
+		default: true
+	},
+	safeAreaInsetBottom: {
+		type: Boolean,
+		default: true
+	},
+	bgColor: String,
+	barColor: String,
+}

+ 18 - 0
uni_modules/lime-floating-panel/components/l-floating-panel/type.ts

@@ -0,0 +1,18 @@
+// @ts-nocheck
+export type LFloatingPanelBoundary ={
+	min: number
+	max: number
+}
+
+
+export interface FloatingPanelProps {
+	height: number,
+	anchors:  number[],
+	defaultAnchor: number,
+	animation: boolean,
+	duration: number,
+	contentDraggable: boolean,
+	safeAreaInsetBottom: boolean,
+	bgColor?: string
+	barColor?: string
+}

+ 103 - 0
uni_modules/lime-floating-panel/components/l-floating-panel/useTouch.uts

@@ -0,0 +1,103 @@
+// @ts-nocheck
+// #ifndef UNI-APP-X
+import {type Ref, ref} from '@/uni_modules/lime-shared/vue'
+type UniTouchEvent = TouchEvent
+// #endif
+
+type Direction = '' | 'vertical' | 'horizontal';
+
+function getDirection(x : number, y : number) : Direction {
+	if (x > y) {
+		return 'horizontal';
+	}
+	if (y > x) {
+		return 'vertical';
+	}
+	return '';
+}
+
+type TouchEventHandler = (event : UniTouchEvent) => void
+type BooleanFunction = () => boolean;
+type UseTouchReturn = {
+	start : TouchEventHandler,
+	move : TouchEventHandler,
+	startX : Ref<number>,
+	startY : Ref<number>,
+	deltaX : Ref<number>,
+	deltaY : Ref<number>,
+	offsetX : Ref<number>,
+	offsetY : Ref<number>,
+	direction : Ref<Direction>,
+	isVertical : BooleanFunction,
+	isHorizontal : BooleanFunction,
+	isTap : Ref<Boolean>,
+}
+
+export function useTouch() : UseTouchReturn {
+	const startX = ref<number>(0);
+	const startY = ref<number>(0);
+	const deltaX = ref<number>(0);
+	const deltaY = ref<number>(0);
+	const offsetX = ref<number>(0);
+	const offsetY = ref<number>(0);
+	const direction = ref<Direction>('');
+	const isTap = ref(true);
+
+	const isVertical = () : boolean => direction.value === 'vertical';
+	const isHorizontal = () : boolean => direction.value === 'horizontal';
+
+	const reset = () => {
+		deltaX.value = 0;
+		deltaY.value = 0;
+		offsetX.value = 0;
+		offsetY.value = 0;
+		direction.value = '';
+		isTap.value = true;
+	};
+
+	const start = (event : UniTouchEvent) => {
+		reset();
+		startX.value = event.touches[0].clientX;
+		startY.value = event.touches[0].clientY;
+	}
+	const move = (event : UniTouchEvent) => {
+		const touch = event.touches[0];
+		// safari back will set clientX to negative number
+		deltaX.value = (touch.clientX < 0 ? 0 : touch.clientX) - startX.value;
+		deltaY.value = touch.clientY - startY.value;
+		offsetX.value = Math.abs(deltaX.value);
+		offsetY.value = Math.abs(deltaY.value);
+
+		// lock direction when distance is greater than a certain value
+		const LOCK_DIRECTION_DISTANCE = 10;
+		const TAP_OFFSET = 5;
+		if (
+			direction.value == '' ||
+			(offsetX.value < LOCK_DIRECTION_DISTANCE &&
+				offsetY.value < LOCK_DIRECTION_DISTANCE)
+		) {
+			direction.value = getDirection(offsetX.value, offsetY.value);
+		}
+
+		if (
+			isTap.value &&
+			(offsetX.value > TAP_OFFSET || offsetY.value > TAP_OFFSET)
+		) {
+			isTap.value = false;
+		}
+	}
+	return {
+		start,
+		move,
+		startX,
+		startY,
+		deltaX,
+		deltaY,
+		offsetX,
+		offsetY,
+		direction,
+		isVertical,
+		isHorizontal,
+		isTap,
+	} as UseTouchReturn
+}

+ 149 - 0
uni_modules/lime-floating-panel/components/lime-floating-panel/lime-floating-panel.uvue

@@ -0,0 +1,149 @@
+<template>
+	<view class="demo-block">
+		<text class="demo-block__title-text ultra">浮动面板</text>
+		<text class="demo-block__desc-text">浮动在页面底部的面板,可以上下拖动来浏览内容,常用于提供额外的功能或信息。</text>	
+		<view class="demo-block__body">
+			<view class="demo-block">
+				<view class="demo-block__body">
+					<view class="tabs">
+						<text class="tab" :class="{active: active == 0}" @click="tabChange(0)">基础用法</text>
+						<text class="tab" :class="{active: active == 1}" @click="tabChange(1)">自定义锚点</text>
+						<text class="tab" :class="{active: active == 2}" @click="tabChange(2)">仅头部拖拽</text>
+					</view>
+					<button type="primary" v-if="active == 1" style="margin-top: 20rpx;" @click="to">自定义锚点: 跳到3</button>
+					<l-floating-panel v-if="active == 0">
+						<scroll-view scroll-y direction="vertical" style="flex: 1" @scrolltolower="scrolltolower">
+							<view v-for="(_, index) in list" class="cell" :key="index">内容:{{index}}</view>
+							<view class="loading" v-if="loading">
+								<text style="color: #999;">loading</text>
+							</view>
+						</scroll-view>
+					</l-floating-panel>
+					
+					<l-floating-panel v-if="active == 1" v-model:height="height" :anchors="anchors" :defaultAnchor="1" ref="floatingPanelRef">
+						<view style="align-items: center; padding: 15px">
+							<text>面板显示高度 {{ height.toFixed(0) }} px</text>
+						</view>
+					</l-floating-panel>
+					
+					
+					<l-floating-panel v-if="active == 2" :content-draggable="false" @height-change="heightChange">
+						<view style="align-items: center; padding: 15px">
+							<text>面板显示高度 {{ height.toFixed(0) }} px</text>
+						</view>
+					</l-floating-panel>
+				</view>	
+			</view>	
+		</view>	
+	</view>
+</template>
+<script setup>
+	const floatingPanelRef = ref<LFloatingPanelComponentPublicInstance|null>(null)
+	const active = ref(0)
+	const loading = ref(false)
+	const height = ref(0)
+	const anchors = ref([50,400,700])
+	const list = ref<number[]>([])
+
+	const to = () => {
+		if(floatingPanelRef.value == null) return
+		floatingPanelRef.value!.toAnchor(2)
+	}
+	const heightChange = (res: UTSJSONObject) => {
+		console.log('heightChange', res)
+		height.value = (res['height'] ?? 0) as number
+	}
+	const tabChange = (index: number) => {
+		active.value = index
+	}
+	
+	const getData = () => {
+		loading.value = true
+		setTimeout(() => {
+			for (var i = 0; i < 20; i++) {
+				 list.value.push(i)
+			}
+			loading.value = false
+		},500)
+	}
+	const scrolltolower = () => {
+		getData()
+	}
+	scrolltolower()
+</script>
+<style lang="scss">
+	.tabs {
+		display: flex;
+		flex-direction: row;
+		padding: 15px 60rpx;
+		justify-content: space-between;
+		background-color: white;
+		// background-color: #ffb400;
+	}
+	.tab{
+		margin-right:10px;
+		color: rgba(0, 0, 0, 0.6);
+		
+	}
+	.text {
+		margin: 30px 0;
+		color: rgba(0, 0, 0, 0.6);
+	}
+	.active {
+		font-weight: bold;
+		color: rgba(0, 0, 0, 1);
+	}
+	
+	.cell {
+		padding: 30rpx;
+	}
+	.loading {
+		padding: 30rpx;
+		align-items: center;
+	}
+	.panel {
+		box-shadow: 0 -10rpx 20rpx rgba(0, 0, 0, 0.03);
+		// background-color: aqua;
+	}
+	.demo-block {
+		margin: 32px 20px 0;
+		overflow: visible;
+		&__title {
+			margin: 0;
+			margin-top: 8px;
+			&-text {
+				color: rgba(0, 0, 0, 0.6);
+				font-weight: 400;
+				font-size: 14px;
+				line-height: 16px;
+				
+				&.large {
+					color: rgba(0, 0, 0, 0.9);
+					font-size: 18px;
+					font-weight: 700;
+					line-height: 26px;
+				}
+				&.ultra {
+					color: rgba(0, 0, 0, 0.9);
+					font-size: 24px;
+					font-weight: 700;
+					line-height: 32px;
+				}
+			}
+		}
+		&__desc-text {
+			color: rgba(0, 0, 0, 0.6);
+			margin: 8px 16px 0 0;
+			font-size: 14px;
+			line-height: 22px;
+		}
+		&__body {
+			margin: 16px 0;
+			overflow: visible;
+			.demo-block {
+				// margin-top: 0px;
+				margin: 0;
+			}
+		}
+	}
+</style>

+ 133 - 0
uni_modules/lime-floating-panel/components/lime-floating-panel/lime-floating-panel.vue

@@ -0,0 +1,133 @@
+<template>
+	<demo-block title="浮动面板" type="ultra">
+		<view class="tabs">
+			<text class="tab" :class="{active: active == 0}" @click="tabChange(0)">基础用法</text>
+			<text class="tab" :class="{active: active == 1}" @click="tabChange(1)">自定义锚点</text>
+			<text class="tab" :class="{active: active == 2}" @click="tabChange(2)">仅头部拖拽</text>
+		</view>
+		<view v-if="active == 1" style="padding: 20rpx" @click="to">自定义锚点: 跳到3</view>
+		<view class="content">
+			<view @click="onClick">content</view>
+			<view @click="onClick">content</view>
+			<view @click="onClick">content</view>
+			<view @click="onClick">content</view>
+			<view @click="onClick">content</view>
+			<view @click="onClick">content</view>
+			<view @click="onClick">content</view>
+			<view @click="onClick">content</view>
+			<view @click="onClick">content</view>
+			<view @click="onClick">content</view>
+			<view @click="onClick">content</view>
+			<view @click="onClick">content</view>
+			<view @click="onClick">content</view>
+			<view @click="onClick">content</view>
+		</view>
+		<view v-if="active == 0">
+			<l-floating-panel>
+				<scroll-view scroll-y style="height: 100%;" @scrolltolower="scrolltolower">
+					<view v-for="(item, index) in list" class="cell" :key="index">内容:{{index}}</view>
+					<view style="text-align: center; padding: 15px;" v-if="loading">
+						<text style="color: #999;">loading</text>
+					</view>
+				</scroll-view>
+			</l-floating-panel>
+		</view>
+		<view v-if="active == 1">
+			<!-- #ifdef VUE3 -->
+			<l-floating-panel v-model:height="height" :anchors="anchors" :defaultAnchor="1" ref="floatingPanelRef">
+				  <view style="text-align: center; padding: 15px">
+						<text>面板显示高度 {{ height.toFixed(0) }} px</text>
+				  </view>
+			</l-floating-panel>
+			<!-- #endif -->
+			<!-- #ifndef VUE3 -->
+			<l-floating-panel :height.sync="height" :anchors="anchors" :defaultAnchor="1">
+				  <view style="text-align: center; padding: 15px">
+						<text>面板显示高度 {{ height.toFixed(0) }} px</text>
+				  </view>
+			</l-floating-panel>
+			<!-- #endif -->
+		</view>
+		<view v-if="active == 2">
+			<l-floating-panel :content-draggable="false" @height-change="heightChange">
+				<view style="text-align: center; padding: 15px">
+					<text style="display: block;">内容不可拖拽</text>
+					<text style="color: #999;">当前高度 {{height3}}</text>
+				</view>
+			</l-floating-panel>
+		</view>
+	</demo-block>
+</template>
+<script>
+	export default {
+		data() {
+			const {windowHeight} = uni.getSystemInfoSync()
+			return {
+				height: 0,
+				height3: 0,
+				active: 0,
+				loading: false,
+				list: [],
+				anchors: [
+			      30,
+			      Math.round(0.4 * windowHeight),
+			      Math.round(0.7 * windowHeight),
+			],
+			}
+		},
+		methods: {
+			scrolltolower() {
+				this.getData()
+			},
+			heightChange({height}) {
+				this.height3 = height
+			},
+			onClick() {
+				uni.showToast({
+					icon: "none",
+					title: "点击了内容"
+				})
+			},
+			to() {
+				this.$refs.floatingPanelRef.toAnchor(2)
+			},
+			getData() {
+				this.loading = true
+				setTimeout(() => {
+					this.list.push(...new Array(10).fill(0))
+					this.loading = false
+				},500)
+			}
+		}
+	}
+</script>
+<style lang="scss">
+	.tabs {
+		display: flex;
+		flex-direction: row;
+		padding: 15px 60rpx;
+		justify-content: space-between;
+		background-color: white;
+	}
+	.tab{margin-right:10px}
+	.tab:last-child {
+		margin-right:0px
+	}
+	.text {
+		display: block;
+		margin: 30px 0;
+		color: rgba(0, 0, 0, 0.6);
+	}
+	.active {
+		color: blue;
+	}
+	.cell {
+		height: 120rpx;
+		padding: 30rpx;
+		box-sizing: border-box;
+		border-bottom: 1rpx solid #eee;
+		&:first-child{
+			border-top: 1rpx solid #eee;
+		}
+	}
+</style>

+ 89 - 0
uni_modules/lime-floating-panel/package.json

@@ -0,0 +1,89 @@
+{
+  "id": "lime-floating-panel",
+  "displayName": "lime-floating-panel 浮动面板",
+  "version": "0.1.6",
+  "description": "lime-floating-panel 浮动在页面底部的面板,上下拖动来浏览内容,常用于提供额外的功能或信息。兼容uniapp/uniappx",
+  "keywords": [
+    "浮动面板",
+    "浮动",
+    "面板"
+],
+  "repository": "",
+  "engines": {
+    "HBuilderX": "^4.28"
+  },
+  "dcloudext": {
+    "type": "component-vue",
+    "sale": {
+      "regular": {
+        "price": "0.00"
+      },
+      "sourcecode": {
+        "price": "0.00"
+      }
+    },
+    "contact": {
+      "qq": ""
+    },
+    "declaration": {
+      "ads": "无",
+      "data": "无",
+      "permissions": "无"
+    },
+    "npmurl": ""
+  },
+  "uni_modules": {
+    "dependencies": [
+		"lime-shared",
+		"lime-style"
+	],
+    "encrypt": [],
+    "platforms": {
+      "cloud": {
+        "tcb": "y",
+        "aliyun": "y",
+        "alipay": "n"
+      },
+      "client": {
+        "Vue": {
+          "vue2": "y",
+          "vue3": "y"
+        },
+        "App": {
+            "app-vue": "y",
+            "app-uvue": "y",
+            "app-nvue": "n",
+            "app-harmony": "u"
+        },
+        "H5-mobile": {
+          "Safari": "y",
+          "Android Browser": "y",
+          "微信浏览器(Android)": "y",
+          "QQ浏览器(Android)": "y"
+        },
+        "H5-pc": {
+          "Chrome": "u",
+          "IE": "u",
+          "Edge": "u",
+          "Firefox": "u",
+          "Safari": "u"
+        },
+        "小程序": {
+          "微信": "y",
+          "阿里": "u",
+          "百度": "u",
+          "字节跳动": "u",
+          "QQ": "u",
+          "钉钉": "u",
+          "快手": "u",
+          "飞书": "u",
+          "京东": "u"
+        },
+        "快应用": {
+          "华为": "u",
+          "联盟": "u"
+        }
+      }
+    }
+  }
+}

+ 173 - 0
uni_modules/lime-floating-panel/readme.md

@@ -0,0 +1,173 @@
+# lime-floating-panel 浮动面板
+浮动在页面底部的面板,可以上下拖动来浏览内容,常用于提供额外的功能或信息。
+
+
+## 文档
+[floating-panel](https://limex.qcoon.cn/components/floating-panel.html)
+
+## 安装
+在插件市场导入即可,首次导入可能需要重新编译
+
+## 代码演示
+
+### 基础用法
+
+FloatingPanel 的默认高度为 `100px`,用户可以拖动来展开面板,使高度达到 `60%` 的屏幕高度。
+
+```html
+<l-floating-panel>
+  <view>内容</view>
+</l-floating-panel>
+```
+
+### 自定义锚点
+
+你可以通过 `anchors` 属性来设置 FloatingPanel 的锚点位置,并通过 `v-model:height` 来控制当前面板的显示高度
+
+比如,使面板的高度在 `100px`、40% 屏幕高度和 70% 屏幕高度三个位置停靠:
+
+```html
+// vue3 v-model:height
+// vue2 :height.sync
+<l-floating-panel v-model:height="height" :anchors="anchors">
+  <view style="text-align: center; padding: 15px">
+    <p>面板显示高度 {{ height.toFixed(0) }} px</p>
+  </view>
+</l-floating-panel>
+```
+
+```js
+import { ref } from 'vue';
+
+export default {
+  setup() {
+	const {windowHeight} = uni.getSystemInfoSync()
+	const anchors = [
+	        100,
+	        Math.round(0.4 * windowHeight),
+	        Math.round(0.7 * windowHeight),
+	];
+    const height = ref(anchors[0]);
+
+    return { anchors, height };
+  },
+};
+```
+
+### 仅头部拖拽
+
+默认情况下,FloatingPanel 的头部区域和内容区域都可以被拖拽,你可以通过 `content-draggable` 属性来禁用内容区域的拖拽。  
+uniappx 鸿蒙next不支持(hbx4.63)  
+
+```html
+<l-floating-panel :content-draggable="false">
+  <view style="text-align: center; padding: 15px">
+    <text>内容不可拖拽</text>
+  </view>
+</l-floating-panel>
+```
+
+### 设置初始锚点位
+
+默认情况下,FloatingPanel 的初始锚点位为0,可以通过设置 `defaultAnchor` 改变初始锚点位。
+
+```html
+<l-floating-panel :defaultAnchor="1">
+  <view style="text-align: center; padding: 15px">
+    <text>内容</text>
+  </view>
+</l-floating-panel>
+```
+
+
+### 跳到指定锚点位
+
+FloatingPanel 暴露 `toAnchor` 方法,可以跳到指点的锚点位。
+
+```html
+<l-floating-panel ref="floatingPanelRef>
+  <view style="text-align: center; padding: 15px">
+    <text>内容</text>
+  </view>
+</l-floating-panel>
+<button @click="to">跳到1</button>
+```
+```js
+ const floatingPanelRef = ref(null)
+
+ const to = () => floatingPanelRef.value.toAnchor(1)
+```
+
+### 查看示例
+- 导入后直接使用这个标签查看演示效果
+
+```html
+<!-- // 代码位于 uni_modules/lime-floating-panel/compoents/lime-floating-panel -->
+<lime-floating-panel />
+```
+
+
+### 插件标签
+- 默认 l-floating-panel 为 component
+- 默认 lime-floating-panel 为 demo
+
+### 关于vue2的使用方式
+- 插件使用了`composition-api`, 如果你希望在vue2中使用请按官方的教程[vue-composition-api](https://uniapp.dcloud.net.cn/tutorial/vue-composition-api.html)配置
+- 关键代码是: 在main.js中 在vue2部分加上这一段即可.
+```js
+// vue2
+import Vue from 'vue'
+import VueCompositionAPI from '@vue/composition-api'
+Vue.use(VueCompositionAPI)
+```
+
+
+## API
+
+### Props
+
+| 参数 | 说明 | 类型 | 默认值 |
+| --- | --- | --- | --- |
+| v-model:height | 当前面板的显示高度 | _number \| string_ | `0` |
+| anchors | 设置自定义锚点, 单位 `px` | _number[]_ | `[100, windowHeight * 0.6]` |
+| animation | 是否开启动画 |  _boolean_ | `true` |
+| content-draggable | 允许拖拽内容容器 | _boolean_ | `true` |
+| safe-area-inset-bottom | 是否开启底部安全区域 | _boolean_ | `true` |
+| defaultAnchor | 默认的锚点下标,如果指定了就在会`anchors`里找到相应的高度 | _number_ | `0` |
+
+### Events
+
+| 事件名        | 说明                             | 回调参数             |
+| ------------- | -------------------------------- | -------------------- |
+| height-change | 面板显示高度改变且结束拖动后触发 | _{ height: number }_ |
+| change | 面板显示高度改变且结束拖动后触发 | _{ height: number, index: number }_ |
+
+### Slots
+
+| Name    | Description    |
+| ------- | -------------- |
+| default | 自定义面板内容 |
+
+
+## 主题定制
+
+### 样式变量
+- nvue 不支持
+组件提供了下列 CSS 变量,可用于自定义样式。
+
+| Name                               | Default Value             | Description |
+| ---------------------------------- | ------------------------- | ----------- |
+| --l-floating-panel-border-radius | _16px_                    | -           |
+| --l-floating-panel-header-height | _30px_                    | -           |
+| --l-floating-panel-z-index       | _999_                     | -           |
+| --l-floating-panel-background    | _white_ | -           |
+| --l-floating-panel-bar-width     | _20px_                    | -           |
+| --l-floating-panel-bar-height    | _3px_                     | -           |
+| --l-floating-panel-bar-color     | _#ddd_       | -           |
+
+
+## 打赏
+
+如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。  
+![](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/alipay.png)
+![](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/wpay.png)

+ 42 - 0
uni_modules/lime-shared/addUnit/index.ts

@@ -0,0 +1,42 @@
+// @ts-nocheck
+import {isNumeric} from '../isNumeric'
+import {isDef} from '../isDef'
+/**
+ * 给一个值添加单位(像素 px)
+ * @param value 要添加单位的值,可以是字符串或数字
+ * @returns 添加了单位的值,如果值为 null 则返回 null
+ */
+
+// #ifndef UNI-APP-X && APP
+export function addUnit(value?: string | number): string | null {
+  if (!isDef(value)) {
+    return null;
+  }
+  value = String(value); // 将值转换为字符串
+  // 如果值是数字,则在后面添加单位 "px",否则保持原始值
+  return isNumeric(value) ? `${value}px` : value;
+}
+// #endif
+
+
+// #ifdef UNI-APP-X && APP
+function addUnit(value: string): string
+function addUnit(value: number): string
+function addUnit(value: any|null): string|null  {
+  if (!isDef(value)) {
+    return null;
+  }
+  value = `${value}` //value.toString(); // 将值转换为字符串
+
+  // 如果值是数字,则在后面添加单位 "px",否则保持原始值
+  return isNumeric(value) ? `${value}px` : value;
+}
+export {addUnit}
+// #endif
+
+
+// console.log(addUnit(100)); // 输出: "100px"
+// console.log(addUnit("200")); // 输出: "200px"
+// console.log(addUnit("300px")); // 输出: "300px"(已经包含单位)
+// console.log(addUnit()); // 输出: undefined(值为 undefined)
+// console.log(addUnit(null)); // 输出: undefined(值为 null)

+ 82 - 0
uni_modules/lime-shared/animation/bezier.ts

@@ -0,0 +1,82 @@
+export function cubicBezier(p1x : number, p1y : number, p2x : number, p2y : number):(x: number)=> number {
+	const ZERO_LIMIT = 1e-6;
+	// Calculate the polynomial coefficients,
+	// implicit first and last control points are (0,0) and (1,1).
+	const ax = 3 * p1x - 3 * p2x + 1;
+	const bx = 3 * p2x - 6 * p1x;
+	const cx = 3 * p1x;
+
+	const ay = 3 * p1y - 3 * p2y + 1;
+	const by = 3 * p2y - 6 * p1y;
+	const cy = 3 * p1y;
+
+	function sampleCurveDerivativeX(t : number) : number {
+		// `ax t^3 + bx t^2 + cx t` expanded using Horner's rule
+		return (3 * ax * t + 2 * bx) * t + cx;
+	}
+
+	function sampleCurveX(t : number) : number {
+		return ((ax * t + bx) * t + cx) * t;
+	}
+
+	function sampleCurveY(t : number) : number {
+		return ((ay * t + by) * t + cy) * t;
+	}
+
+	// Given an x value, find a parametric value it came from.
+	function solveCurveX(x : number) : number {
+		let t2 = x;
+		let derivative : number;
+		let x2 : number;
+
+		// https://trac.webkit.org/browser/trunk/Source/WebCore/platform/animation
+		// first try a few iterations of Newton's method -- normally very fast.
+		// http://en.wikipedia.org/wikiNewton's_method
+		for (let i = 0; i < 8; i++) {
+			// f(t) - x = 0
+			x2 = sampleCurveX(t2) - x;
+			if (Math.abs(x2) < ZERO_LIMIT) {
+				return t2;
+			}
+			derivative = sampleCurveDerivativeX(t2);
+			// == 0, failure
+			/* istanbul ignore if */
+			if (Math.abs(derivative) < ZERO_LIMIT) {
+				break;
+			}
+			t2 -= x2 / derivative;
+		}
+
+		// Fall back to the bisection method for reliability.
+		// bisection
+		// http://en.wikipedia.org/wiki/Bisection_method
+		let t1 = 1;
+		/* istanbul ignore next */
+		let t0 = 0;
+
+		/* istanbul ignore next */
+		t2 = x;
+		/* istanbul ignore next */
+		while (t1 > t0) {
+			x2 = sampleCurveX(t2) - x;
+			if (Math.abs(x2) < ZERO_LIMIT) {
+				return t2;
+			}
+			if (x2 > 0) {
+				t1 = t2;
+			} else {
+				t0 = t2;
+			}
+			t2 = (t1 + t0) / 2;
+		}
+
+		// Failure
+		return t2;
+	}
+
+	return function (x : number) : number {
+		return sampleCurveY(solveCurveX(x));
+	}
+
+	// return solve;
+}

+ 3 - 0
uni_modules/lime-shared/animation/ease.ts

@@ -0,0 +1,3 @@
+import {cubicBezier} from './bezier';
+export let ease = cubicBezier(0.25, 0.1, 0.25, 1);
+export let linear = cubicBezier(0,0,1,1);

+ 12 - 0
uni_modules/lime-shared/animation/index.ts

@@ -0,0 +1,12 @@
+// @ts-nocheck
+// #ifdef UNI-APP-X && APP
+// export * from './uvue.uts'
+export { Timeline, Animation } from './uvue.uts'
+// #endif
+
+
+
+// #ifndef UNI-APP-X && APP
+// export * from './vue.ts'
+export { Timeline, Animation } from './vue.ts'
+// #endif

+ 108 - 0
uni_modules/lime-shared/animation/useTransition.ts

@@ -0,0 +1,108 @@
+// @ts-nocheck
+import type { ComponentPublicInstance, Ref } from 'vue'
+import { ease, linear } from './ease';
+import { Timeline, Animation } from './';
+export type UseTransitionOptions = {
+	duration ?: number
+	immediate ?: boolean
+	context ?: ComponentPublicInstance
+}
+// #ifndef UNI-APP-X && APP
+import { ref, watch } from '@/uni_modules/lime-shared/vue'
+
+export function useTransition(percent : Ref<number>|(() => number), options : UseTransitionOptions) : Ref<number> {
+	const current = ref(0)
+	const { immediate, duration = 300 } = options
+	let tl:Timeline|null = null;
+	let timer = -1
+	const isFunction = typeof percent === 'function'
+	watch(isFunction ? percent : () => percent.value, (v) => {
+		if(tl == null){
+			tl = new Timeline()
+		}
+		tl.start();
+		tl.add(
+			new Animation(
+				current.value,
+				v,
+				duration,
+				0,
+				ease,
+				nowValue => {
+					current.value = nowValue
+					clearTimeout(timer)
+					if(current.value == v){
+						timer = setTimeout(()=>{
+							tl?.pause();
+							tl = null
+						}, duration)
+					}
+				}
+			)
+		);
+	}, { immediate })
+
+	return current
+}
+
+// #endif
+
+// #ifdef UNI-APP-X && APP
+type UseTransitionReturnType = Ref<number>
+export function useTransition(source : any, options : UseTransitionOptions) : UseTransitionReturnType {
+	const outputRef : Ref<number> = ref(0)
+	const immediate = options.immediate ?? false
+	const duration = options.duration ?? 300
+	const context = options.context //as ComponentPublicInstance | null
+	let tl:Timeline|null = null;
+	let timer = -1
+	const watchFunc = (v : number) => {
+		if(tl == null){
+			tl = new Timeline()
+		}
+		tl!.start();
+		tl!.add(
+			new Animation(
+				outputRef.value,
+				v,
+				duration,
+				0,
+				ease,
+				nowValue => {
+					outputRef.value = nowValue
+					clearTimeout(timer)
+					if(outputRef.value == v){
+						timer = setTimeout(()=>{
+							tl?.pause();
+							tl = null
+						}, duration)
+					}
+				}
+			), 
+			null
+		);
+	}
+
+	if (context != null && typeof source == 'string') {
+		context.$watch(source, watchFunc, { immediate } as WatchOptions)
+	} else if(typeof source == 'function'){
+		watch(source, watchFunc, { immediate })
+	} 
+	// #ifdef APP-ANDROID
+	else if(isRef(source) && source instanceof Ref<number>) {
+		watch(source as Ref<number>, watchFunc, { immediate })
+	}
+	// #endif
+	// #ifndef APP-ANDROID
+	else if(isRef(source) && typeof source.value == 'number') {
+		watch(source, watchFunc, { immediate })
+	}
+	// #endif
+	
+	const stop = ()=>{
+		
+	}
+	return outputRef //as UseTransitionReturnType
+}
+
+// #endif

+ 119 - 0
uni_modules/lime-shared/animation/uvue.uts

@@ -0,0 +1,119 @@
+// @ts-nocheck
+import { raf,  cancelRaf} from '../raf'
+export class Timeline {
+	state : string
+	animations : Set<Animation> = new Set<Animation>()
+	delAnimations : Animation[] = []
+	startTimes : Map<Animation, number> = new Map<Animation, number>()
+	pauseTime : number = 0
+	pauseStart : number = Date.now()
+	tickHandler : number = 0
+	tickHandlers : number[] = []
+	tick : (() => void) | null = null
+	constructor() {
+		this.state = 'Initiated';
+	}
+	start() {
+		if (!(this.state == 'Initiated')) return;
+		this.state = 'Started';
+
+		let startTime = Date.now();
+		this.pauseTime = 0;
+		this.tick = () => {
+			let now = Date.now();
+			this.animations.forEach((animation : Animation) => {
+				let t:number;
+				const ani = this.startTimes.get(animation)
+				if (ani == null) return
+				if (ani < startTime) {
+					t = now - startTime - animation.delay - this.pauseTime;
+				} else {
+					t = now - ani - animation.delay - this.pauseTime;
+				}
+				if (t > animation.duration) {
+					this.delAnimations.push(animation)
+					// 不能在 foreach 里面 对 集合进行删除操作
+					// this.animations.delete(animation);
+					t = animation.duration;
+				}
+				if (t > 0) animation.run(t);
+			})
+			// 不能在 foreach 里面 对 集合进行删除操作
+			while (this.delAnimations.length > 0) {
+				const animation = this.delAnimations.pop();
+				if (animation == null) return
+				this.animations.delete(animation);
+			}
+			// cancelAnimationFrame(this.tickHandler);
+			if (this.state != 'Started') return
+		
+			 this.tickHandler = raf(()=>{
+				this.tick!()
+			})
+			
+			this.tickHandlers.push(this.tickHandler)
+		}
+		if(this.tick != null) {
+			this.tick!()
+		}
+		
+	}
+	pause() {
+		if (!(this.state === 'Started')) return;
+		this.state = 'Paused';
+		this.pauseStart = Date.now();
+		cancelRaf(this.tickHandler);
+		// cancelRaf(this.tickHandler);
+	}
+	resume() {
+		if (!(this.state === 'Paused')) return;
+		this.state = 'Started';
+		this.pauseTime += Date.now() - this.pauseStart;
+		this.tick!();
+	}
+	reset() {
+		this.pause();
+		this.state = 'Initiated';
+		this.pauseTime = 0;
+		this.pauseStart = 0;
+		this.animations.clear()
+		this.delAnimations.clear()
+		this.startTimes.clear()
+		this.tickHandler = 0;
+	}
+	add(animation : Animation, startTime ?: number | null) {
+		if (startTime == null) startTime = Date.now();
+		this.animations.add(animation);
+		this.startTimes.set(animation, startTime);
+	}
+}
+
+export class Animation {
+	startValue : number
+	endValue : number
+	duration : number
+	timingFunction : (t : number) => number
+	delay : number
+	template : (t : number) => void
+	constructor(
+		startValue : number,
+		endValue : number,
+		duration : number,
+		delay : number,
+		timingFunction : (t : number) => number,
+		template : (v : number) => void) {
+		this.startValue = startValue;
+		this.endValue = endValue;
+		this.duration = duration;
+		this.timingFunction = timingFunction;
+		this.delay = delay;
+		this.template = template;
+	}
+
+	run(time : number) {
+		let range = this.endValue - this.startValue;
+		let progress = time / this.duration
+		if(progress != 1) progress = this.timingFunction(progress)
+		this.template(this.startValue + range * progress)
+	}
+}

+ 123 - 0
uni_modules/lime-shared/animation/vue.ts

@@ -0,0 +1,123 @@
+// @ts-nocheck
+const TICK = Symbol('tick');
+const TICK_HANDLER = Symbol('tick-handler');
+const ANIMATIONS = Symbol('animations');
+const START_TIMES = Symbol('start-times');
+const PAUSE_START = Symbol('pause-start');
+const PAUSE_TIME = Symbol('pause-time');
+const _raf = typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame : function(cb: Function) {return setTimeout(cb, 1000/60)}
+const _caf = typeof cancelAnimationFrame !== 'undefined' ? cancelAnimationFrame: function(id: any) {clearTimeout(id)}
+
+// const TICK = 'tick';
+// const TICK_HANDLER = 'tick-handler';
+// const ANIMATIONS = 'animations';
+// const START_TIMES = 'start-times';
+// const PAUSE_START = 'pause-start';
+// const PAUSE_TIME = 'pause-time';
+// const _raf = function(callback):number|null {return setTimeout(callback, 1000/60)}
+// const _caf = function(id: number):void {clearTimeout(id)}
+
+export class Timeline {
+	state: string
+	constructor() {
+		this.state = 'Initiated';
+		this[ANIMATIONS] = new Set();
+		this[START_TIMES] = new Map();
+	}
+	start() {
+		if (!(this.state === 'Initiated')) return;
+		this.state = 'Started';
+
+		let startTime = Date.now();
+		this[PAUSE_TIME] = 0;
+		this[TICK] = () => {
+			let now = Date.now();
+			this[ANIMATIONS].forEach((animation) => {
+				 let t: number;
+				 if (this[START_TIMES].get(animation) < startTime) {
+				 	t = now - startTime - animation.delay - this[PAUSE_TIME];
+				 } else {
+				 	t = now - this[START_TIMES].get(animation) - animation.delay - this[PAUSE_TIME];
+				 }
+				 
+				 if (t > animation.duration) {
+				 	this[ANIMATIONS].delete(animation);
+				 	t = animation.duration;
+				 }
+				 if (t > 0) animation.run(t);
+			})
+			// for (let animation of this[ANIMATIONS]) {
+			// 	let t: number;
+			// 	console.log('animation', animation)
+			// 	if (this[START_TIMES].get(animation) < startTime) {
+			// 		t = now - startTime - animation.delay - this[PAUSE_TIME];
+			// 	} else {
+			// 		t = now - this[START_TIMES].get(animation) - animation.delay - this[PAUSE_TIME];
+			// 	}
+
+			// 	if (t > animation.duration) {
+			// 		this[ANIMATIONS].delete(animation);
+			// 		t = animation.duration;
+			// 	}
+			// 	if (t > 0) animation.run(t);
+			// }
+			this[TICK_HANDLER] = _raf(this[TICK]);
+		};
+		this[TICK]();
+	}
+	pause() {
+		if (!(this.state === 'Started')) return;
+		this.state = 'Paused';
+
+		this[PAUSE_START] = Date.now();
+		_caf(this[TICK_HANDLER]);
+	}
+	resume() {
+		if (!(this.state === 'Paused')) return;
+		this.state = 'Started';
+
+		this[PAUSE_TIME] += Date.now() - this[PAUSE_START];
+		this[TICK]();
+	}
+	reset() {
+		this.pause();
+		this.state = 'Initiated';
+		this[PAUSE_TIME] = 0;
+		this[PAUSE_START] = 0;
+		this[ANIMATIONS] = new Set();
+		this[START_TIMES] = new Map();
+		this[TICK_HANDLER] = null;
+	}
+	add(animation: any, startTime?: number) {
+		if (arguments.length < 2) startTime = Date.now();
+		this[ANIMATIONS].add(animation);
+		this[START_TIMES].set(animation, startTime);
+	}
+}
+
+export class Animation {
+	startValue: number
+	endValue: number
+	duration: number
+	timingFunction: (t: number) => number
+	delay: number
+	template: (t: number) => void
+	constructor(startValue: number, endValue: number, duration: number, delay: number, timingFunction: (t: number) => number, template: (v: number) => void) {
+		timingFunction = timingFunction || (v => v);
+		template = template || (v => v);
+		
+		this.startValue = startValue;
+		this.endValue = endValue;
+		this.duration = duration;
+		this.timingFunction = timingFunction;
+		this.delay = delay;
+		this.template = template;
+	}
+
+	run(time: number) {
+		let range = this.endValue - this.startValue;
+		let progress = time / this.duration
+		if(progress != 1) progress = this.timingFunction(progress)
+		this.template(this.startValue + range * progress)
+	}
+}

+ 3888 - 0
uni_modules/lime-shared/areaData/city-china.json

@@ -0,0 +1,3888 @@
+{
+	"province_list": {
+		"110000": "北京市",
+		"120000": "天津市",
+		"130000": "河北省",
+		"140000": "山西省",
+		"150000": "内蒙古自治区",
+		"210000": "辽宁省",
+		"220000": "吉林省",
+		"230000": "黑龙江省",
+		"310000": "上海市",
+		"320000": "江苏省",
+		"330000": "浙江省",
+		"340000": "安徽省",
+		"350000": "福建省",
+		"360000": "江西省",
+		"370000": "山东省",
+		"410000": "河南省",
+		"420000": "湖北省",
+		"430000": "湖南省",
+		"440000": "广东省",
+		"450000": "广西壮族自治区",
+		"460000": "海南省",
+		"500000": "重庆市",
+		"510000": "四川省",
+		"520000": "贵州省",
+		"530000": "云南省",
+		"540000": "西藏自治区",
+		"610000": "陕西省",
+		"620000": "甘肃省",
+		"630000": "青海省",
+		"640000": "宁夏回族自治区",
+		"650000": "新疆维吾尔自治区",
+		"710000": "台湾省",
+		"810000": "香港特别行政区",
+		"820000": "澳门特别行政区"
+	},
+	"city_list": {
+		"110100": "北京市",
+		"120100": "天津市",
+		"130100": "石家庄市",
+		"130200": "唐山市",
+		"130300": "秦皇岛市",
+		"130400": "邯郸市",
+		"130500": "邢台市",
+		"130600": "保定市",
+		"130700": "张家口市",
+		"130800": "承德市",
+		"130900": "沧州市",
+		"131000": "廊坊市",
+		"131100": "衡水市",
+		"140100": "太原市",
+		"140200": "大同市",
+		"140300": "阳泉市",
+		"140400": "长治市",
+		"140500": "晋城市",
+		"140600": "朔州市",
+		"140700": "晋中市",
+		"140800": "运城市",
+		"140900": "忻州市",
+		"141000": "临汾市",
+		"141100": "吕梁市",
+		"150100": "呼和浩特市",
+		"150200": "包头市",
+		"150300": "乌海市",
+		"150400": "赤峰市",
+		"150500": "通辽市",
+		"150600": "鄂尔多斯市",
+		"150700": "呼伦贝尔市",
+		"150800": "巴彦淖尔市",
+		"150900": "乌兰察布市",
+		"152200": "兴安盟",
+		"152500": "锡林郭勒盟",
+		"152900": "阿拉善盟",
+		"210100": "沈阳市",
+		"210200": "大连市",
+		"210300": "鞍山市",
+		"210400": "抚顺市",
+		"210500": "本溪市",
+		"210600": "丹东市",
+		"210700": "锦州市",
+		"210800": "营口市",
+		"210900": "阜新市",
+		"211000": "辽阳市",
+		"211100": "盘锦市",
+		"211200": "铁岭市",
+		"211300": "朝阳市",
+		"211400": "葫芦岛市",
+		"220100": "长春市",
+		"220200": "吉林市",
+		"220300": "四平市",
+		"220400": "辽源市",
+		"220500": "通化市",
+		"220600": "白山市",
+		"220700": "松原市",
+		"220800": "白城市",
+		"222400": "延边朝鲜族自治州",
+		"230100": "哈尔滨市",
+		"230200": "齐齐哈尔市",
+		"230300": "鸡西市",
+		"230400": "鹤岗市",
+		"230500": "双鸭山市",
+		"230600": "大庆市",
+		"230700": "伊春市",
+		"230800": "佳木斯市",
+		"230900": "七台河市",
+		"231000": "牡丹江市",
+		"231100": "黑河市",
+		"231200": "绥化市",
+		"232700": "大兴安岭地区",
+		"310100": "上海市",
+		"320100": "南京市",
+		"320200": "无锡市",
+		"320300": "徐州市",
+		"320400": "常州市",
+		"320500": "苏州市",
+		"320600": "南通市",
+		"320700": "连云港市",
+		"320800": "淮安市",
+		"320900": "盐城市",
+		"321000": "扬州市",
+		"321100": "镇江市",
+		"321200": "泰州市",
+		"321300": "宿迁市",
+		"330100": "杭州市",
+		"330200": "宁波市",
+		"330300": "温州市",
+		"330400": "嘉兴市",
+		"330500": "湖州市",
+		"330600": "绍兴市",
+		"330700": "金华市",
+		"330800": "衢州市",
+		"330900": "舟山市",
+		"331000": "台州市",
+		"331100": "丽水市",
+		"340100": "合肥市",
+		"340200": "芜湖市",
+		"340300": "蚌埠市",
+		"340400": "淮南市",
+		"340500": "马鞍山市",
+		"340600": "淮北市",
+		"340700": "铜陵市",
+		"340800": "安庆市",
+		"341000": "黄山市",
+		"341100": "滁州市",
+		"341200": "阜阳市",
+		"341300": "宿州市",
+		"341500": "六安市",
+		"341600": "亳州市",
+		"341700": "池州市",
+		"341800": "宣城市",
+		"350100": "福州市",
+		"350200": "厦门市",
+		"350300": "莆田市",
+		"350400": "三明市",
+		"350500": "泉州市",
+		"350600": "漳州市",
+		"350700": "南平市",
+		"350800": "龙岩市",
+		"350900": "宁德市",
+		"360100": "南昌市",
+		"360200": "景德镇市",
+		"360300": "萍乡市",
+		"360400": "九江市",
+		"360500": "新余市",
+		"360600": "鹰潭市",
+		"360700": "赣州市",
+		"360800": "吉安市",
+		"360900": "宜春市",
+		"361000": "抚州市",
+		"361100": "上饶市",
+		"370100": "济南市",
+		"370200": "青岛市",
+		"370300": "淄博市",
+		"370400": "枣庄市",
+		"370500": "东营市",
+		"370600": "烟台市",
+		"370700": "潍坊市",
+		"370800": "济宁市",
+		"370900": "泰安市",
+		"371000": "威海市",
+		"371100": "日照市",
+		"371300": "临沂市",
+		"371400": "德州市",
+		"371500": "聊城市",
+		"371600": "滨州市",
+		"371700": "菏泽市",
+		"410100": "郑州市",
+		"410200": "开封市",
+		"410300": "洛阳市",
+		"410400": "平顶山市",
+		"410500": "安阳市",
+		"410600": "鹤壁市",
+		"410700": "新乡市",
+		"410800": "焦作市",
+		"410900": "濮阳市",
+		"411000": "许昌市",
+		"411100": "漯河市",
+		"411200": "三门峡市",
+		"411300": "南阳市",
+		"411400": "商丘市",
+		"411500": "信阳市",
+		"411600": "周口市",
+		"411700": "驻马店市",
+		"419000": "省直辖县",
+		"420100": "武汉市",
+		"420200": "黄石市",
+		"420300": "十堰市",
+		"420500": "宜昌市",
+		"420600": "襄阳市",
+		"420700": "鄂州市",
+		"420800": "荆门市",
+		"420900": "孝感市",
+		"421000": "荆州市",
+		"421100": "黄冈市",
+		"421200": "咸宁市",
+		"421300": "随州市",
+		"422800": "恩施土家族苗族自治州",
+		"429000": "省直辖县",
+		"430100": "长沙市",
+		"430200": "株洲市",
+		"430300": "湘潭市",
+		"430400": "衡阳市",
+		"430500": "邵阳市",
+		"430600": "岳阳市",
+		"430700": "常德市",
+		"430800": "张家界市",
+		"430900": "益阳市",
+		"431000": "郴州市",
+		"431100": "永州市",
+		"431200": "怀化市",
+		"431300": "娄底市",
+		"433100": "湘西土家族苗族自治州",
+		"440100": "广州市",
+		"440200": "韶关市",
+		"440300": "深圳市",
+		"440400": "珠海市",
+		"440500": "汕头市",
+		"440600": "佛山市",
+		"440700": "江门市",
+		"440800": "湛江市",
+		"440900": "茂名市",
+		"441200": "肇庆市",
+		"441300": "惠州市",
+		"441400": "梅州市",
+		"441500": "汕尾市",
+		"441600": "河源市",
+		"441700": "阳江市",
+		"441800": "清远市",
+		"441900": "东莞市",
+		"442000": "中山市",
+		"445100": "潮州市",
+		"445200": "揭阳市",
+		"445300": "云浮市",
+		"450100": "南宁市",
+		"450200": "柳州市",
+		"450300": "桂林市",
+		"450400": "梧州市",
+		"450500": "北海市",
+		"450600": "防城港市",
+		"450700": "钦州市",
+		"450800": "贵港市",
+		"450900": "玉林市",
+		"451000": "百色市",
+		"451100": "贺州市",
+		"451200": "河池市",
+		"451300": "来宾市",
+		"451400": "崇左市",
+		"460100": "海口市",
+		"460200": "三亚市",
+		"460300": "三沙市",
+		"460400": "儋州市",
+		"469000": "省直辖县",
+		"500100": "重庆市",
+		"500200": "县",
+		"510100": "成都市",
+		"510300": "自贡市",
+		"510400": "攀枝花市",
+		"510500": "泸州市",
+		"510600": "德阳市",
+		"510700": "绵阳市",
+		"510800": "广元市",
+		"510900": "遂宁市",
+		"511000": "内江市",
+		"511100": "乐山市",
+		"511300": "南充市",
+		"511400": "眉山市",
+		"511500": "宜宾市",
+		"511600": "广安市",
+		"511700": "达州市",
+		"511800": "雅安市",
+		"511900": "巴中市",
+		"512000": "资阳市",
+		"513200": "阿坝藏族羌族自治州",
+		"513300": "甘孜藏族自治州",
+		"513400": "凉山彝族自治州",
+		"520100": "贵阳市",
+		"520200": "六盘水市",
+		"520300": "遵义市",
+		"520400": "安顺市",
+		"520500": "毕节市",
+		"520600": "铜仁市",
+		"522300": "黔西南布依族苗族自治州",
+		"522600": "黔东南苗族侗族自治州",
+		"522700": "黔南布依族苗族自治州",
+		"530100": "昆明市",
+		"530300": "曲靖市",
+		"530400": "玉溪市",
+		"530500": "保山市",
+		"530600": "昭通市",
+		"530700": "丽江市",
+		"530800": "普洱市",
+		"530900": "临沧市",
+		"532300": "楚雄彝族自治州",
+		"532500": "红河哈尼族彝族自治州",
+		"532600": "文山壮族苗族自治州",
+		"532800": "西双版纳傣族自治州",
+		"532900": "大理白族自治州",
+		"533100": "德宏傣族景颇族自治州",
+		"533300": "怒江傈僳族自治州",
+		"533400": "迪庆藏族自治州",
+		"540100": "拉萨市",
+		"540200": "日喀则市",
+		"540300": "昌都市",
+		"540400": "林芝市",
+		"540500": "山南市",
+		"540600": "那曲市",
+		"542500": "阿里地区",
+		"610100": "西安市",
+		"610200": "铜川市",
+		"610300": "宝鸡市",
+		"610400": "咸阳市",
+		"610500": "渭南市",
+		"610600": "延安市",
+		"610700": "汉中市",
+		"610800": "榆林市",
+		"610900": "安康市",
+		"611000": "商洛市",
+		"620100": "兰州市",
+		"620200": "嘉峪关市",
+		"620300": "金昌市",
+		"620400": "白银市",
+		"620500": "天水市",
+		"620600": "武威市",
+		"620700": "张掖市",
+		"620800": "平凉市",
+		"620900": "酒泉市",
+		"621000": "庆阳市",
+		"621100": "定西市",
+		"621200": "陇南市",
+		"622900": "临夏回族自治州",
+		"623000": "甘南藏族自治州",
+		"630100": "西宁市",
+		"630200": "海东市",
+		"632200": "海北藏族自治州",
+		"632300": "黄南藏族自治州",
+		"632500": "海南藏族自治州",
+		"632600": "果洛藏族自治州",
+		"632700": "玉树藏族自治州",
+		"632800": "海西蒙古族藏族自治州",
+		"640100": "银川市",
+		"640200": "石嘴山市",
+		"640300": "吴忠市",
+		"640400": "固原市",
+		"640500": "中卫市",
+		"650100": "乌鲁木齐市",
+		"650200": "克拉玛依市",
+		"650400": "吐鲁番市",
+		"650500": "哈密市",
+		"652300": "昌吉回族自治州",
+		"652700": "博尔塔拉蒙古自治州",
+		"652800": "巴音郭楞蒙古自治州",
+		"652900": "阿克苏地区",
+		"653000": "克孜勒苏柯尔克孜自治州",
+		"653100": "喀什地区",
+		"653200": "和田地区",
+		"654000": "伊犁哈萨克自治州",
+		"654200": "塔城地区",
+		"654300": "阿勒泰地区",
+		"659000": "自治区直辖县级行政区划",
+		"710100": "台北市",
+		"710200": "高雄市",
+		"710300": "台南市",
+		"710400": "台中市",
+		"710500": "金门县",
+		"710600": "南投县",
+		"710700": "基隆市",
+		"710800": "新竹市",
+		"710900": "嘉义市",
+		"711100": "新北市",
+		"711200": "宜兰县",
+		"711300": "新竹县",
+		"711400": "桃园市",
+		"711500": "苗栗县",
+		"711700": "彰化县",
+		"711900": "嘉义县",
+		"712100": "云林县",
+		"712400": "屏东县",
+		"712500": "台东县",
+		"712600": "花莲县",
+		"712700": "澎湖县",
+		"712800": "连江县",
+		"810100": "香港岛",
+		"810200": "九龙",
+		"810300": "新界",
+		"820100": "澳门半岛",
+		"820200": "离岛"
+	},
+	"county_list": {
+		"110101": "东城区",
+		"110102": "西城区",
+		"110105": "朝阳区",
+		"110106": "丰台区",
+		"110107": "石景山区",
+		"110108": "海淀区",
+		"110109": "门头沟区",
+		"110111": "房山区",
+		"110112": "通州区",
+		"110113": "顺义区",
+		"110114": "昌平区",
+		"110115": "大兴区",
+		"110116": "怀柔区",
+		"110117": "平谷区",
+		"110118": "密云区",
+		"110119": "延庆区",
+		"120101": "和平区",
+		"120102": "河东区",
+		"120103": "河西区",
+		"120104": "南开区",
+		"120105": "河北区",
+		"120106": "红桥区",
+		"120110": "东丽区",
+		"120111": "西青区",
+		"120112": "津南区",
+		"120113": "北辰区",
+		"120114": "武清区",
+		"120115": "宝坻区",
+		"120116": "滨海新区",
+		"120117": "宁河区",
+		"120118": "静海区",
+		"120119": "蓟州区",
+		"130102": "长安区",
+		"130104": "桥西区",
+		"130105": "新华区",
+		"130107": "井陉矿区",
+		"130108": "裕华区",
+		"130109": "藁城区",
+		"130110": "鹿泉区",
+		"130111": "栾城区",
+		"130121": "井陉县",
+		"130123": "正定县",
+		"130125": "行唐县",
+		"130126": "灵寿县",
+		"130127": "高邑县",
+		"130128": "深泽县",
+		"130129": "赞皇县",
+		"130130": "无极县",
+		"130131": "平山县",
+		"130132": "元氏县",
+		"130133": "赵县",
+		"130171": "石家庄高新技术产业开发区",
+		"130172": "石家庄循环化工园区",
+		"130181": "辛集市",
+		"130183": "晋州市",
+		"130184": "新乐市",
+		"130202": "路南区",
+		"130203": "路北区",
+		"130204": "古冶区",
+		"130205": "开平区",
+		"130207": "丰南区",
+		"130208": "丰润区",
+		"130209": "曹妃甸区",
+		"130224": "滦南县",
+		"130225": "乐亭县",
+		"130227": "迁西县",
+		"130229": "玉田县",
+		"130273": "唐山高新技术产业开发区",
+		"130274": "河北唐山海港经济开发区",
+		"130281": "遵化市",
+		"130283": "迁安市",
+		"130284": "滦州市",
+		"130302": "海港区",
+		"130303": "山海关区",
+		"130304": "北戴河区",
+		"130306": "抚宁区",
+		"130321": "青龙满族自治县",
+		"130322": "昌黎县",
+		"130324": "卢龙县",
+		"130371": "秦皇岛市经济技术开发区",
+		"130372": "北戴河新区",
+		"130390": "经济技术开发区",
+		"130402": "邯山区",
+		"130403": "丛台区",
+		"130404": "复兴区",
+		"130406": "峰峰矿区",
+		"130407": "肥乡区",
+		"130408": "永年区",
+		"130423": "临漳县",
+		"130424": "成安县",
+		"130425": "大名县",
+		"130426": "涉县",
+		"130427": "磁县",
+		"130430": "邱县",
+		"130431": "鸡泽县",
+		"130432": "广平县",
+		"130433": "馆陶县",
+		"130434": "魏县",
+		"130435": "曲周县",
+		"130471": "邯郸经济技术开发区",
+		"130473": "邯郸冀南新区",
+		"130481": "武安市",
+		"130502": "襄都区",
+		"130503": "信都区",
+		"130505": "任泽区",
+		"130506": "南和区",
+		"130522": "临城县",
+		"130523": "内丘县",
+		"130524": "柏乡县",
+		"130525": "隆尧县",
+		"130528": "宁晋县",
+		"130529": "巨鹿县",
+		"130530": "新河县",
+		"130531": "广宗县",
+		"130532": "平乡县",
+		"130533": "威县",
+		"130534": "清河县",
+		"130535": "临西县",
+		"130571": "河北邢台经济开发区",
+		"130581": "南宫市",
+		"130582": "沙河市",
+		"130602": "竞秀区",
+		"130606": "莲池区",
+		"130607": "满城区",
+		"130608": "清苑区",
+		"130609": "徐水区",
+		"130623": "涞水县",
+		"130624": "阜平县",
+		"130626": "定兴县",
+		"130627": "唐县",
+		"130628": "高阳县",
+		"130629": "容城县",
+		"130630": "涞源县",
+		"130631": "望都县",
+		"130632": "安新县",
+		"130633": "易县",
+		"130634": "曲阳县",
+		"130635": "蠡县",
+		"130636": "顺平县",
+		"130637": "博野县",
+		"130638": "雄县",
+		"130671": "保定高新技术产业开发区",
+		"130672": "保定白沟新城",
+		"130681": "涿州市",
+		"130682": "定州市",
+		"130683": "安国市",
+		"130684": "高碑店市",
+		"130702": "桥东区",
+		"130703": "桥西区",
+		"130705": "宣化区",
+		"130706": "下花园区",
+		"130708": "万全区",
+		"130709": "崇礼区",
+		"130722": "张北县",
+		"130723": "康保县",
+		"130724": "沽源县",
+		"130725": "尚义县",
+		"130726": "蔚县",
+		"130727": "阳原县",
+		"130728": "怀安县",
+		"130730": "怀来县",
+		"130731": "涿鹿县",
+		"130732": "赤城县",
+		"130772": "张家口市察北管理区",
+		"130802": "双桥区",
+		"130803": "双滦区",
+		"130804": "鹰手营子矿区",
+		"130821": "承德县",
+		"130822": "兴隆县",
+		"130824": "滦平县",
+		"130825": "隆化县",
+		"130826": "丰宁满族自治县",
+		"130827": "宽城满族自治县",
+		"130828": "围场满族蒙古族自治县",
+		"130871": "承德高新技术产业开发区",
+		"130881": "平泉市",
+		"130902": "新华区",
+		"130903": "运河区",
+		"130921": "沧县",
+		"130922": "青县",
+		"130923": "东光县",
+		"130924": "海兴县",
+		"130925": "盐山县",
+		"130926": "肃宁县",
+		"130927": "南皮县",
+		"130928": "吴桥县",
+		"130929": "献县",
+		"130930": "孟村回族自治县",
+		"130971": "河北沧州经济开发区",
+		"130972": "沧州高新技术产业开发区",
+		"130973": "沧州渤海新区",
+		"130981": "泊头市",
+		"130982": "任丘市",
+		"130983": "黄骅市",
+		"130984": "河间市",
+		"131002": "安次区",
+		"131003": "广阳区",
+		"131022": "固安县",
+		"131023": "永清县",
+		"131024": "香河县",
+		"131025": "大城县",
+		"131026": "文安县",
+		"131028": "大厂回族自治县",
+		"131071": "廊坊经济技术开发区",
+		"131081": "霸州市",
+		"131082": "三河市",
+		"131090": "开发区",
+		"131102": "桃城区",
+		"131103": "冀州区",
+		"131121": "枣强县",
+		"131122": "武邑县",
+		"131123": "武强县",
+		"131124": "饶阳县",
+		"131125": "安平县",
+		"131126": "故城县",
+		"131127": "景县",
+		"131128": "阜城县",
+		"131171": "河北衡水经济开发区",
+		"131172": "衡水滨湖新区",
+		"131182": "深州市",
+		"140105": "小店区",
+		"140106": "迎泽区",
+		"140107": "杏花岭区",
+		"140108": "尖草坪区",
+		"140109": "万柏林区",
+		"140110": "晋源区",
+		"140121": "清徐县",
+		"140122": "阳曲县",
+		"140123": "娄烦县",
+		"140181": "古交市",
+		"140212": "新荣区",
+		"140213": "平城区",
+		"140214": "云冈区",
+		"140215": "云州区",
+		"140221": "阳高县",
+		"140222": "天镇县",
+		"140223": "广灵县",
+		"140224": "灵丘县",
+		"140225": "浑源县",
+		"140226": "左云县",
+		"140271": "山西大同经济开发区",
+		"140302": "城区",
+		"140303": "矿区",
+		"140311": "郊区",
+		"140321": "平定县",
+		"140322": "盂县",
+		"140403": "潞州区",
+		"140404": "上党区",
+		"140405": "屯留区",
+		"140406": "潞城区",
+		"140423": "襄垣县",
+		"140425": "平顺县",
+		"140426": "黎城县",
+		"140427": "壶关县",
+		"140428": "长子县",
+		"140429": "武乡县",
+		"140430": "沁县",
+		"140431": "沁源县",
+		"140471": "山西长治高新技术产业园区",
+		"140502": "城区",
+		"140521": "沁水县",
+		"140522": "阳城县",
+		"140524": "陵川县",
+		"140525": "泽州县",
+		"140581": "高平市",
+		"140602": "朔城区",
+		"140603": "平鲁区",
+		"140621": "山阴县",
+		"140622": "应县",
+		"140623": "右玉县",
+		"140671": "山西朔州经济开发区",
+		"140681": "怀仁市",
+		"140702": "榆次区",
+		"140703": "太谷区",
+		"140721": "榆社县",
+		"140722": "左权县",
+		"140723": "和顺县",
+		"140724": "昔阳县",
+		"140725": "寿阳县",
+		"140727": "祁县",
+		"140728": "平遥县",
+		"140729": "灵石县",
+		"140781": "介休市",
+		"140802": "盐湖区",
+		"140821": "临猗县",
+		"140822": "万荣县",
+		"140823": "闻喜县",
+		"140824": "稷山县",
+		"140825": "新绛县",
+		"140826": "绛县",
+		"140827": "垣曲县",
+		"140828": "夏县",
+		"140829": "平陆县",
+		"140830": "芮城县",
+		"140881": "永济市",
+		"140882": "河津市",
+		"140902": "忻府区",
+		"140921": "定襄县",
+		"140922": "五台县",
+		"140923": "代县",
+		"140924": "繁峙县",
+		"140925": "宁武县",
+		"140926": "静乐县",
+		"140927": "神池县",
+		"140928": "五寨县",
+		"140929": "岢岚县",
+		"140930": "河曲县",
+		"140931": "保德县",
+		"140932": "偏关县",
+		"140971": "五台山风景名胜区",
+		"140981": "原平市",
+		"141002": "尧都区",
+		"141021": "曲沃县",
+		"141022": "翼城县",
+		"141023": "襄汾县",
+		"141024": "洪洞县",
+		"141025": "古县",
+		"141026": "安泽县",
+		"141027": "浮山县",
+		"141028": "吉县",
+		"141029": "乡宁县",
+		"141030": "大宁县",
+		"141031": "隰县",
+		"141032": "永和县",
+		"141033": "蒲县",
+		"141034": "汾西县",
+		"141081": "侯马市",
+		"141082": "霍州市",
+		"141102": "离石区",
+		"141121": "文水县",
+		"141122": "交城县",
+		"141123": "兴县",
+		"141124": "临县",
+		"141125": "柳林县",
+		"141126": "石楼县",
+		"141127": "岚县",
+		"141128": "方山县",
+		"141129": "中阳县",
+		"141130": "交口县",
+		"141181": "孝义市",
+		"141182": "汾阳市",
+		"150102": "新城区",
+		"150103": "回民区",
+		"150104": "玉泉区",
+		"150105": "赛罕区",
+		"150121": "土默特左旗",
+		"150122": "托克托县",
+		"150123": "和林格尔县",
+		"150124": "清水河县",
+		"150125": "武川县",
+		"150172": "呼和浩特经济技术开发区",
+		"150202": "东河区",
+		"150203": "昆都仑区",
+		"150204": "青山区",
+		"150205": "石拐区",
+		"150206": "白云鄂博矿区",
+		"150207": "九原区",
+		"150221": "土默特右旗",
+		"150222": "固阳县",
+		"150223": "达尔罕茂明安联合旗",
+		"150271": "包头稀土高新技术产业开发区",
+		"150302": "海勃湾区",
+		"150303": "海南区",
+		"150304": "乌达区",
+		"150402": "红山区",
+		"150403": "元宝山区",
+		"150404": "松山区",
+		"150421": "阿鲁科尔沁旗",
+		"150422": "巴林左旗",
+		"150423": "巴林右旗",
+		"150424": "林西县",
+		"150425": "克什克腾旗",
+		"150426": "翁牛特旗",
+		"150428": "喀喇沁旗",
+		"150429": "宁城县",
+		"150430": "敖汉旗",
+		"150502": "科尔沁区",
+		"150521": "科尔沁左翼中旗",
+		"150522": "科尔沁左翼后旗",
+		"150523": "开鲁县",
+		"150524": "库伦旗",
+		"150525": "奈曼旗",
+		"150526": "扎鲁特旗",
+		"150571": "通辽经济技术开发区",
+		"150581": "霍林郭勒市",
+		"150602": "东胜区",
+		"150603": "康巴什区",
+		"150621": "达拉特旗",
+		"150622": "准格尔旗",
+		"150623": "鄂托克前旗",
+		"150624": "鄂托克旗",
+		"150625": "杭锦旗",
+		"150626": "乌审旗",
+		"150627": "伊金霍洛旗",
+		"150702": "海拉尔区",
+		"150703": "扎赉诺尔区",
+		"150721": "阿荣旗",
+		"150722": "莫力达瓦达斡尔族自治旗",
+		"150723": "鄂伦春自治旗",
+		"150724": "鄂温克族自治旗",
+		"150725": "陈巴尔虎旗",
+		"150726": "新巴尔虎左旗",
+		"150727": "新巴尔虎右旗",
+		"150781": "满洲里市",
+		"150782": "牙克石市",
+		"150783": "扎兰屯市",
+		"150784": "额尔古纳市",
+		"150785": "根河市",
+		"150802": "临河区",
+		"150821": "五原县",
+		"150822": "磴口县",
+		"150823": "乌拉特前旗",
+		"150824": "乌拉特中旗",
+		"150825": "乌拉特后旗",
+		"150826": "杭锦后旗",
+		"150902": "集宁区",
+		"150921": "卓资县",
+		"150922": "化德县",
+		"150923": "商都县",
+		"150924": "兴和县",
+		"150925": "凉城县",
+		"150926": "察哈尔右翼前旗",
+		"150927": "察哈尔右翼中旗",
+		"150928": "察哈尔右翼后旗",
+		"150929": "四子王旗",
+		"150981": "丰镇市",
+		"152201": "乌兰浩特市",
+		"152202": "阿尔山市",
+		"152221": "科尔沁右翼前旗",
+		"152222": "科尔沁右翼中旗",
+		"152223": "扎赉特旗",
+		"152224": "突泉县",
+		"152501": "二连浩特市",
+		"152502": "锡林浩特市",
+		"152522": "阿巴嘎旗",
+		"152523": "苏尼特左旗",
+		"152524": "苏尼特右旗",
+		"152525": "东乌珠穆沁旗",
+		"152526": "西乌珠穆沁旗",
+		"152527": "太仆寺旗",
+		"152528": "镶黄旗",
+		"152529": "正镶白旗",
+		"152530": "正蓝旗",
+		"152531": "多伦县",
+		"152571": "乌拉盖管委会",
+		"152921": "阿拉善左旗",
+		"152922": "阿拉善右旗",
+		"152923": "额济纳旗",
+		"152971": "内蒙古阿拉善经济开发区",
+		"210102": "和平区",
+		"210103": "沈河区",
+		"210104": "大东区",
+		"210105": "皇姑区",
+		"210106": "铁西区",
+		"210111": "苏家屯区",
+		"210112": "浑南区",
+		"210113": "沈北新区",
+		"210114": "于洪区",
+		"210115": "辽中区",
+		"210123": "康平县",
+		"210124": "法库县",
+		"210181": "新民市",
+		"210190": "经济技术开发区",
+		"210202": "中山区",
+		"210203": "西岗区",
+		"210204": "沙河口区",
+		"210211": "甘井子区",
+		"210212": "旅顺口区",
+		"210213": "金州区",
+		"210214": "普兰店区",
+		"210224": "长海县",
+		"210281": "瓦房店市",
+		"210283": "庄河市",
+		"210302": "铁东区",
+		"210303": "铁西区",
+		"210304": "立山区",
+		"210311": "千山区",
+		"210321": "台安县",
+		"210323": "岫岩满族自治县",
+		"210381": "海城市",
+		"210390": "高新区",
+		"210402": "新抚区",
+		"210403": "东洲区",
+		"210404": "望花区",
+		"210411": "顺城区",
+		"210421": "抚顺县",
+		"210422": "新宾满族自治县",
+		"210423": "清原满族自治县",
+		"210502": "平山区",
+		"210503": "溪湖区",
+		"210504": "明山区",
+		"210505": "南芬区",
+		"210521": "本溪满族自治县",
+		"210522": "桓仁满族自治县",
+		"210602": "元宝区",
+		"210603": "振兴区",
+		"210604": "振安区",
+		"210624": "宽甸满族自治县",
+		"210681": "东港市",
+		"210682": "凤城市",
+		"210702": "古塔区",
+		"210703": "凌河区",
+		"210711": "太和区",
+		"210726": "黑山县",
+		"210727": "义县",
+		"210781": "凌海市",
+		"210782": "北镇市",
+		"210793": "经济技术开发区",
+		"210802": "站前区",
+		"210803": "西市区",
+		"210804": "鲅鱼圈区",
+		"210811": "老边区",
+		"210881": "盖州市",
+		"210882": "大石桥市",
+		"210902": "海州区",
+		"210903": "新邱区",
+		"210904": "太平区",
+		"210905": "清河门区",
+		"210911": "细河区",
+		"210921": "阜新蒙古族自治县",
+		"210922": "彰武县",
+		"211002": "白塔区",
+		"211003": "文圣区",
+		"211004": "宏伟区",
+		"211005": "弓长岭区",
+		"211011": "太子河区",
+		"211021": "辽阳县",
+		"211081": "灯塔市",
+		"211102": "双台子区",
+		"211103": "兴隆台区",
+		"211104": "大洼区",
+		"211122": "盘山县",
+		"211202": "银州区",
+		"211204": "清河区",
+		"211221": "铁岭县",
+		"211223": "西丰县",
+		"211224": "昌图县",
+		"211281": "调兵山市",
+		"211282": "开原市",
+		"211302": "双塔区",
+		"211303": "龙城区",
+		"211321": "朝阳县",
+		"211322": "建平县",
+		"211324": "喀喇沁左翼蒙古族自治县",
+		"211381": "北票市",
+		"211382": "凌源市",
+		"211402": "连山区",
+		"211403": "龙港区",
+		"211404": "南票区",
+		"211421": "绥中县",
+		"211422": "建昌县",
+		"211481": "兴城市",
+		"220102": "南关区",
+		"220103": "宽城区",
+		"220104": "朝阳区",
+		"220105": "二道区",
+		"220106": "绿园区",
+		"220112": "双阳区",
+		"220113": "九台区",
+		"220122": "农安县",
+		"220171": "长春经济技术开发区",
+		"220172": "长春净月高新技术产业开发区",
+		"220173": "长春高新技术产业开发区",
+		"220174": "长春汽车经济技术开发区",
+		"220182": "榆树市",
+		"220183": "德惠市",
+		"220184": "公主岭市",
+		"220192": "经济技术开发区",
+		"220202": "昌邑区",
+		"220203": "龙潭区",
+		"220204": "船营区",
+		"220211": "丰满区",
+		"220221": "永吉县",
+		"220271": "吉林经济开发区",
+		"220272": "吉林高新技术产业开发区",
+		"220281": "蛟河市",
+		"220282": "桦甸市",
+		"220283": "舒兰市",
+		"220284": "磐石市",
+		"220302": "铁西区",
+		"220303": "铁东区",
+		"220322": "梨树县",
+		"220323": "伊通满族自治县",
+		"220382": "双辽市",
+		"220402": "龙山区",
+		"220403": "西安区",
+		"220421": "东丰县",
+		"220422": "东辽县",
+		"220502": "东昌区",
+		"220503": "二道江区",
+		"220521": "通化县",
+		"220523": "辉南县",
+		"220524": "柳河县",
+		"220581": "梅河口市",
+		"220582": "集安市",
+		"220602": "浑江区",
+		"220605": "江源区",
+		"220621": "抚松县",
+		"220622": "靖宇县",
+		"220623": "长白朝鲜族自治县",
+		"220681": "临江市",
+		"220702": "宁江区",
+		"220721": "前郭尔罗斯蒙古族自治县",
+		"220722": "长岭县",
+		"220723": "乾安县",
+		"220771": "吉林松原经济开发区",
+		"220781": "扶余市",
+		"220802": "洮北区",
+		"220821": "镇赉县",
+		"220822": "通榆县",
+		"220871": "吉林白城经济开发区",
+		"220881": "洮南市",
+		"220882": "大安市",
+		"222401": "延吉市",
+		"222402": "图们市",
+		"222403": "敦化市",
+		"222404": "珲春市",
+		"222405": "龙井市",
+		"222406": "和龙市",
+		"222424": "汪清县",
+		"222426": "安图县",
+		"230102": "道里区",
+		"230103": "南岗区",
+		"230104": "道外区",
+		"230108": "平房区",
+		"230109": "松北区",
+		"230110": "香坊区",
+		"230111": "呼兰区",
+		"230112": "阿城区",
+		"230113": "双城区",
+		"230123": "依兰县",
+		"230124": "方正县",
+		"230125": "宾县",
+		"230126": "巴彦县",
+		"230127": "木兰县",
+		"230128": "通河县",
+		"230129": "延寿县",
+		"230183": "尚志市",
+		"230184": "五常市",
+		"230202": "龙沙区",
+		"230203": "建华区",
+		"230204": "铁锋区",
+		"230205": "昂昂溪区",
+		"230206": "富拉尔基区",
+		"230207": "碾子山区",
+		"230208": "梅里斯达斡尔族区",
+		"230221": "龙江县",
+		"230223": "依安县",
+		"230224": "泰来县",
+		"230225": "甘南县",
+		"230227": "富裕县",
+		"230229": "克山县",
+		"230230": "克东县",
+		"230231": "拜泉县",
+		"230281": "讷河市",
+		"230302": "鸡冠区",
+		"230303": "恒山区",
+		"230304": "滴道区",
+		"230305": "梨树区",
+		"230306": "城子河区",
+		"230307": "麻山区",
+		"230321": "鸡东县",
+		"230381": "虎林市",
+		"230382": "密山市",
+		"230402": "向阳区",
+		"230403": "工农区",
+		"230404": "南山区",
+		"230405": "兴安区",
+		"230406": "东山区",
+		"230407": "兴山区",
+		"230421": "萝北县",
+		"230422": "绥滨县",
+		"230502": "尖山区",
+		"230503": "岭东区",
+		"230505": "四方台区",
+		"230506": "宝山区",
+		"230521": "集贤县",
+		"230522": "友谊县",
+		"230523": "宝清县",
+		"230524": "饶河县",
+		"230602": "萨尔图区",
+		"230603": "龙凤区",
+		"230604": "让胡路区",
+		"230605": "红岗区",
+		"230606": "大同区",
+		"230621": "肇州县",
+		"230622": "肇源县",
+		"230623": "林甸县",
+		"230624": "杜尔伯特蒙古族自治县",
+		"230671": "大庆高新技术产业开发区",
+		"230717": "伊美区",
+		"230718": "乌翠区",
+		"230719": "友好区",
+		"230722": "嘉荫县",
+		"230723": "汤旺县",
+		"230724": "丰林县",
+		"230725": "大箐山县",
+		"230726": "南岔县",
+		"230751": "金林区",
+		"230781": "铁力市",
+		"230803": "向阳区",
+		"230804": "前进区",
+		"230805": "东风区",
+		"230811": "郊区",
+		"230822": "桦南县",
+		"230826": "桦川县",
+		"230828": "汤原县",
+		"230881": "同江市",
+		"230882": "富锦市",
+		"230883": "抚远市",
+		"230902": "新兴区",
+		"230903": "桃山区",
+		"230904": "茄子河区",
+		"230921": "勃利县",
+		"231002": "东安区",
+		"231003": "阳明区",
+		"231004": "爱民区",
+		"231005": "西安区",
+		"231025": "林口县",
+		"231081": "绥芬河市",
+		"231083": "海林市",
+		"231084": "宁安市",
+		"231085": "穆棱市",
+		"231086": "东宁市",
+		"231102": "爱辉区",
+		"231123": "逊克县",
+		"231124": "孙吴县",
+		"231181": "北安市",
+		"231182": "五大连池市",
+		"231183": "嫩江市",
+		"231202": "北林区",
+		"231221": "望奎县",
+		"231222": "兰西县",
+		"231223": "青冈县",
+		"231224": "庆安县",
+		"231225": "明水县",
+		"231226": "绥棱县",
+		"231281": "安达市",
+		"231282": "肇东市",
+		"231283": "海伦市",
+		"232701": "漠河市",
+		"232721": "呼玛县",
+		"232722": "塔河县",
+		"232761": "加格达奇区",
+		"232762": "松岭区",
+		"232763": "新林区",
+		"232764": "呼中区",
+		"310101": "黄浦区",
+		"310104": "徐汇区",
+		"310105": "长宁区",
+		"310106": "静安区",
+		"310107": "普陀区",
+		"310109": "虹口区",
+		"310110": "杨浦区",
+		"310112": "闵行区",
+		"310113": "宝山区",
+		"310114": "嘉定区",
+		"310115": "浦东新区",
+		"310116": "金山区",
+		"310117": "松江区",
+		"310118": "青浦区",
+		"310120": "奉贤区",
+		"310151": "崇明区",
+		"320102": "玄武区",
+		"320104": "秦淮区",
+		"320105": "建邺区",
+		"320106": "鼓楼区",
+		"320111": "浦口区",
+		"320112": "江北新区",
+		"320113": "栖霞区",
+		"320114": "雨花台区",
+		"320115": "江宁区",
+		"320116": "六合区",
+		"320117": "溧水区",
+		"320118": "高淳区",
+		"320205": "锡山区",
+		"320206": "惠山区",
+		"320211": "滨湖区",
+		"320213": "梁溪区",
+		"320214": "新吴区",
+		"320281": "江阴市",
+		"320282": "宜兴市",
+		"320302": "鼓楼区",
+		"320303": "云龙区",
+		"320305": "贾汪区",
+		"320311": "泉山区",
+		"320312": "铜山区",
+		"320321": "丰县",
+		"320322": "沛县",
+		"320324": "睢宁县",
+		"320371": "徐州经济技术开发区",
+		"320381": "新沂市",
+		"320382": "邳州市",
+		"320391": "工业园区",
+		"320402": "天宁区",
+		"320404": "钟楼区",
+		"320411": "新北区",
+		"320412": "武进区",
+		"320413": "金坛区",
+		"320481": "溧阳市",
+		"320505": "虎丘区",
+		"320506": "吴中区",
+		"320507": "相城区",
+		"320508": "姑苏区",
+		"320509": "吴江区",
+		"320571": "苏州工业园区",
+		"320581": "常熟市",
+		"320582": "张家港市",
+		"320583": "昆山市",
+		"320585": "太仓市",
+		"320590": "工业园区",
+		"320591": "高新区",
+		"320611": "港闸区",
+		"320612": "通州区",
+		"320613": "崇川区",
+		"320614": "海门区",
+		"320623": "如东县",
+		"320681": "启东市",
+		"320682": "如皋市",
+		"320685": "海安市",
+		"320691": "高新区",
+		"320703": "连云区",
+		"320706": "海州区",
+		"320707": "赣榆区",
+		"320722": "东海县",
+		"320723": "灌云县",
+		"320724": "灌南县",
+		"320771": "连云港经济技术开发区",
+		"320803": "淮安区",
+		"320804": "淮阴区",
+		"320812": "清江浦区",
+		"320813": "洪泽区",
+		"320826": "涟水县",
+		"320830": "盱眙县",
+		"320831": "金湖县",
+		"320871": "淮安经济技术开发区",
+		"320890": "经济开发区",
+		"320902": "亭湖区",
+		"320903": "盐都区",
+		"320904": "大丰区",
+		"320921": "响水县",
+		"320922": "滨海县",
+		"320923": "阜宁县",
+		"320924": "射阳县",
+		"320925": "建湖县",
+		"320971": "盐城经济技术开发区",
+		"320981": "东台市",
+		"321002": "广陵区",
+		"321003": "邗江区",
+		"321012": "江都区",
+		"321023": "宝应县",
+		"321071": "扬州经济技术开发区",
+		"321081": "仪征市",
+		"321084": "高邮市",
+		"321090": "经济开发区",
+		"321102": "京口区",
+		"321111": "润州区",
+		"321112": "丹徒区",
+		"321150": "镇江新区",
+		"321181": "丹阳市",
+		"321182": "扬中市",
+		"321183": "句容市",
+		"321202": "海陵区",
+		"321203": "高港区",
+		"321204": "姜堰区",
+		"321271": "泰州医药高新技术产业开发区",
+		"321281": "兴化市",
+		"321282": "靖江市",
+		"321283": "泰兴市",
+		"321302": "宿城区",
+		"321311": "宿豫区",
+		"321322": "沭阳县",
+		"321323": "泗阳县",
+		"321324": "泗洪县",
+		"321371": "宿迁经济技术开发区",
+		"330102": "上城区",
+		"330105": "拱墅区",
+		"330106": "西湖区",
+		"330108": "滨江区",
+		"330109": "萧山区",
+		"330110": "余杭区",
+		"330111": "富阳区",
+		"330112": "临安区",
+		"330113": "临平区",
+		"330114": "钱塘区",
+		"330122": "桐庐县",
+		"330127": "淳安县",
+		"330182": "建德市",
+		"330203": "海曙区",
+		"330205": "江北区",
+		"330206": "北仑区",
+		"330211": "镇海区",
+		"330212": "鄞州区",
+		"330213": "奉化区",
+		"330225": "象山县",
+		"330226": "宁海县",
+		"330281": "余姚市",
+		"330282": "慈溪市",
+		"330302": "鹿城区",
+		"330303": "龙湾区",
+		"330304": "瓯海区",
+		"330305": "洞头区",
+		"330324": "永嘉县",
+		"330326": "平阳县",
+		"330327": "苍南县",
+		"330328": "文成县",
+		"330329": "泰顺县",
+		"330381": "瑞安市",
+		"330382": "乐清市",
+		"330383": "龙港市",
+		"330402": "南湖区",
+		"330411": "秀洲区",
+		"330421": "嘉善县",
+		"330424": "海盐县",
+		"330481": "海宁市",
+		"330482": "平湖市",
+		"330483": "桐乡市",
+		"330502": "吴兴区",
+		"330503": "南浔区",
+		"330521": "德清县",
+		"330522": "长兴县",
+		"330523": "安吉县",
+		"330602": "越城区",
+		"330603": "柯桥区",
+		"330604": "上虞区",
+		"330624": "新昌县",
+		"330681": "诸暨市",
+		"330683": "嵊州市",
+		"330702": "婺城区",
+		"330703": "金东区",
+		"330723": "武义县",
+		"330726": "浦江县",
+		"330727": "磐安县",
+		"330781": "兰溪市",
+		"330782": "义乌市",
+		"330783": "东阳市",
+		"330784": "永康市",
+		"330802": "柯城区",
+		"330803": "衢江区",
+		"330822": "常山县",
+		"330824": "开化县",
+		"330825": "龙游县",
+		"330881": "江山市",
+		"330902": "定海区",
+		"330903": "普陀区",
+		"330921": "岱山县",
+		"330922": "嵊泗县",
+		"331002": "椒江区",
+		"331003": "黄岩区",
+		"331004": "路桥区",
+		"331022": "三门县",
+		"331023": "天台县",
+		"331024": "仙居县",
+		"331081": "温岭市",
+		"331082": "临海市",
+		"331083": "玉环市",
+		"331102": "莲都区",
+		"331121": "青田县",
+		"331122": "缙云县",
+		"331123": "遂昌县",
+		"331124": "松阳县",
+		"331125": "云和县",
+		"331126": "庆元县",
+		"331127": "景宁畲族自治县",
+		"331181": "龙泉市",
+		"340102": "瑶海区",
+		"340103": "庐阳区",
+		"340104": "蜀山区",
+		"340111": "包河区",
+		"340121": "长丰县",
+		"340122": "肥东县",
+		"340123": "肥西县",
+		"340124": "庐江县",
+		"340171": "合肥高新技术产业开发区",
+		"340172": "合肥经济技术开发区",
+		"340173": "合肥新站高新技术产业开发区",
+		"340181": "巢湖市",
+		"340190": "高新技术开发区",
+		"340191": "经济技术开发区",
+		"340202": "镜湖区",
+		"340207": "鸠江区",
+		"340209": "弋江区",
+		"340210": "湾沚区",
+		"340212": "繁昌区",
+		"340223": "南陵县",
+		"340281": "无为市",
+		"340302": "龙子湖区",
+		"340303": "蚌山区",
+		"340304": "禹会区",
+		"340311": "淮上区",
+		"340321": "怀远县",
+		"340322": "五河县",
+		"340323": "固镇县",
+		"340371": "蚌埠市高新技术开发区",
+		"340372": "蚌埠市经济开发区",
+		"340402": "大通区",
+		"340403": "田家庵区",
+		"340404": "谢家集区",
+		"340405": "八公山区",
+		"340406": "潘集区",
+		"340421": "凤台县",
+		"340422": "寿县",
+		"340503": "花山区",
+		"340504": "雨山区",
+		"340506": "博望区",
+		"340521": "当涂县",
+		"340522": "含山县",
+		"340523": "和县",
+		"340602": "杜集区",
+		"340603": "相山区",
+		"340604": "烈山区",
+		"340621": "濉溪县",
+		"340705": "铜官区",
+		"340706": "义安区",
+		"340711": "郊区",
+		"340722": "枞阳县",
+		"340802": "迎江区",
+		"340803": "大观区",
+		"340811": "宜秀区",
+		"340822": "怀宁县",
+		"340825": "太湖县",
+		"340826": "宿松县",
+		"340827": "望江县",
+		"340828": "岳西县",
+		"340881": "桐城市",
+		"340882": "潜山市",
+		"341002": "屯溪区",
+		"341003": "黄山区",
+		"341004": "徽州区",
+		"341021": "歙县",
+		"341022": "休宁县",
+		"341023": "黟县",
+		"341024": "祁门县",
+		"341102": "琅琊区",
+		"341103": "南谯区",
+		"341122": "来安县",
+		"341124": "全椒县",
+		"341125": "定远县",
+		"341126": "凤阳县",
+		"341181": "天长市",
+		"341182": "明光市",
+		"341202": "颍州区",
+		"341203": "颍东区",
+		"341204": "颍泉区",
+		"341221": "临泉县",
+		"341222": "太和县",
+		"341225": "阜南县",
+		"341226": "颍上县",
+		"341271": "阜阳合肥现代产业园区",
+		"341282": "界首市",
+		"341302": "埇桥区",
+		"341321": "砀山县",
+		"341322": "萧县",
+		"341323": "灵璧县",
+		"341324": "泗县",
+		"341371": "宿州马鞍山现代产业园区",
+		"341372": "宿州经济技术开发区",
+		"341390": "经济开发区",
+		"341502": "金安区",
+		"341503": "裕安区",
+		"341504": "叶集区",
+		"341522": "霍邱县",
+		"341523": "舒城县",
+		"341524": "金寨县",
+		"341525": "霍山县",
+		"341602": "谯城区",
+		"341621": "涡阳县",
+		"341622": "蒙城县",
+		"341623": "利辛县",
+		"341702": "贵池区",
+		"341721": "东至县",
+		"341722": "石台县",
+		"341723": "青阳县",
+		"341802": "宣州区",
+		"341821": "郎溪县",
+		"341823": "泾县",
+		"341824": "绩溪县",
+		"341825": "旌德县",
+		"341871": "宣城市经济开发区",
+		"341881": "宁国市",
+		"341882": "广德市",
+		"350102": "鼓楼区",
+		"350103": "台江区",
+		"350104": "仓山区",
+		"350105": "马尾区",
+		"350111": "晋安区",
+		"350112": "长乐区",
+		"350121": "闽侯县",
+		"350122": "连江县",
+		"350123": "罗源县",
+		"350124": "闽清县",
+		"350125": "永泰县",
+		"350128": "平潭县",
+		"350181": "福清市",
+		"350203": "思明区",
+		"350205": "海沧区",
+		"350206": "湖里区",
+		"350211": "集美区",
+		"350212": "同安区",
+		"350213": "翔安区",
+		"350302": "城厢区",
+		"350303": "涵江区",
+		"350304": "荔城区",
+		"350305": "秀屿区",
+		"350322": "仙游县",
+		"350402": "梅列区",
+		"350404": "三元区",
+		"350405": "沙县区",
+		"350421": "明溪县",
+		"350423": "清流县",
+		"350424": "宁化县",
+		"350425": "大田县",
+		"350426": "尤溪县",
+		"350428": "将乐县",
+		"350429": "泰宁县",
+		"350430": "建宁县",
+		"350481": "永安市",
+		"350502": "鲤城区",
+		"350503": "丰泽区",
+		"350504": "洛江区",
+		"350505": "泉港区",
+		"350521": "惠安县",
+		"350524": "安溪县",
+		"350525": "永春县",
+		"350526": "德化县",
+		"350527": "金门县",
+		"350581": "石狮市",
+		"350582": "晋江市",
+		"350583": "南安市",
+		"350602": "芗城区",
+		"350603": "龙文区",
+		"350604": "龙海区",
+		"350605": "长泰区",
+		"350622": "云霄县",
+		"350623": "漳浦县",
+		"350624": "诏安县",
+		"350626": "东山县",
+		"350627": "南靖县",
+		"350628": "平和县",
+		"350629": "华安县",
+		"350702": "延平区",
+		"350703": "建阳区",
+		"350721": "顺昌县",
+		"350722": "浦城县",
+		"350723": "光泽县",
+		"350724": "松溪县",
+		"350725": "政和县",
+		"350781": "邵武市",
+		"350782": "武夷山市",
+		"350783": "建瓯市",
+		"350802": "新罗区",
+		"350803": "永定区",
+		"350821": "长汀县",
+		"350823": "上杭县",
+		"350824": "武平县",
+		"350825": "连城县",
+		"350881": "漳平市",
+		"350902": "蕉城区",
+		"350921": "霞浦县",
+		"350922": "古田县",
+		"350923": "屏南县",
+		"350924": "寿宁县",
+		"350925": "周宁县",
+		"350926": "柘荣县",
+		"350981": "福安市",
+		"350982": "福鼎市",
+		"360102": "东湖区",
+		"360103": "西湖区",
+		"360104": "青云谱区",
+		"360111": "青山湖区",
+		"360112": "新建区",
+		"360113": "红谷滩区",
+		"360121": "南昌县",
+		"360123": "安义县",
+		"360124": "进贤县",
+		"360190": "经济技术开发区",
+		"360192": "高新区",
+		"360202": "昌江区",
+		"360203": "珠山区",
+		"360222": "浮梁县",
+		"360281": "乐平市",
+		"360302": "安源区",
+		"360313": "湘东区",
+		"360321": "莲花县",
+		"360322": "上栗县",
+		"360323": "芦溪县",
+		"360402": "濂溪区",
+		"360403": "浔阳区",
+		"360404": "柴桑区",
+		"360423": "武宁县",
+		"360424": "修水县",
+		"360425": "永修县",
+		"360426": "德安县",
+		"360428": "都昌县",
+		"360429": "湖口县",
+		"360430": "彭泽县",
+		"360481": "瑞昌市",
+		"360482": "共青城市",
+		"360483": "庐山市",
+		"360490": "经济技术开发区",
+		"360502": "渝水区",
+		"360521": "分宜县",
+		"360602": "月湖区",
+		"360603": "余江区",
+		"360681": "贵溪市",
+		"360702": "章贡区",
+		"360703": "南康区",
+		"360704": "赣县区",
+		"360722": "信丰县",
+		"360723": "大余县",
+		"360724": "上犹县",
+		"360725": "崇义县",
+		"360726": "安远县",
+		"360728": "定南县",
+		"360729": "全南县",
+		"360730": "宁都县",
+		"360731": "于都县",
+		"360732": "兴国县",
+		"360733": "会昌县",
+		"360734": "寻乌县",
+		"360735": "石城县",
+		"360781": "瑞金市",
+		"360783": "龙南市",
+		"360802": "吉州区",
+		"360803": "青原区",
+		"360821": "吉安县",
+		"360822": "吉水县",
+		"360823": "峡江县",
+		"360824": "新干县",
+		"360825": "永丰县",
+		"360826": "泰和县",
+		"360827": "遂川县",
+		"360828": "万安县",
+		"360829": "安福县",
+		"360830": "永新县",
+		"360881": "井冈山市",
+		"360902": "袁州区",
+		"360921": "奉新县",
+		"360922": "万载县",
+		"360923": "上高县",
+		"360924": "宜丰县",
+		"360925": "靖安县",
+		"360926": "铜鼓县",
+		"360981": "丰城市",
+		"360982": "樟树市",
+		"360983": "高安市",
+		"361002": "临川区",
+		"361003": "东乡区",
+		"361021": "南城县",
+		"361022": "黎川县",
+		"361023": "南丰县",
+		"361024": "崇仁县",
+		"361025": "乐安县",
+		"361026": "宜黄县",
+		"361027": "金溪县",
+		"361028": "资溪县",
+		"361030": "广昌县",
+		"361102": "信州区",
+		"361103": "广丰区",
+		"361104": "广信区",
+		"361123": "玉山县",
+		"361124": "铅山县",
+		"361125": "横峰县",
+		"361126": "弋阳县",
+		"361127": "余干县",
+		"361128": "鄱阳县",
+		"361129": "万年县",
+		"361130": "婺源县",
+		"361181": "德兴市",
+		"370102": "历下区",
+		"370103": "市中区",
+		"370104": "槐荫区",
+		"370105": "天桥区",
+		"370112": "历城区",
+		"370113": "长清区",
+		"370114": "章丘区",
+		"370115": "济阳区",
+		"370116": "莱芜区",
+		"370117": "钢城区",
+		"370124": "平阴县",
+		"370126": "商河县",
+		"370171": "济南高新技术产业开发区",
+		"370190": "高新区",
+		"370202": "市南区",
+		"370203": "市北区",
+		"370211": "黄岛区",
+		"370212": "崂山区",
+		"370213": "李沧区",
+		"370214": "城阳区",
+		"370215": "即墨区",
+		"370271": "青岛高新技术产业开发区",
+		"370281": "胶州市",
+		"370283": "平度市",
+		"370285": "莱西市",
+		"370290": "开发区",
+		"370302": "淄川区",
+		"370303": "张店区",
+		"370304": "博山区",
+		"370305": "临淄区",
+		"370306": "周村区",
+		"370321": "桓台县",
+		"370322": "高青县",
+		"370323": "沂源县",
+		"370402": "市中区",
+		"370403": "薛城区",
+		"370404": "峄城区",
+		"370405": "台儿庄区",
+		"370406": "山亭区",
+		"370481": "滕州市",
+		"370502": "东营区",
+		"370503": "河口区",
+		"370505": "垦利区",
+		"370522": "利津县",
+		"370523": "广饶县",
+		"370571": "东营经济技术开发区",
+		"370572": "东营港经济开发区",
+		"370602": "芝罘区",
+		"370611": "福山区",
+		"370612": "牟平区",
+		"370613": "莱山区",
+		"370614": "蓬莱区",
+		"370634": "长岛县",
+		"370671": "烟台高新技术产业开发区",
+		"370672": "烟台经济技术开发区",
+		"370681": "龙口市",
+		"370682": "莱阳市",
+		"370683": "莱州市",
+		"370685": "招远市",
+		"370686": "栖霞市",
+		"370687": "海阳市",
+		"370690": "开发区",
+		"370702": "潍城区",
+		"370703": "寒亭区",
+		"370704": "坊子区",
+		"370705": "奎文区",
+		"370724": "临朐县",
+		"370725": "昌乐县",
+		"370772": "潍坊滨海经济技术开发区",
+		"370781": "青州市",
+		"370782": "诸城市",
+		"370783": "寿光市",
+		"370784": "安丘市",
+		"370785": "高密市",
+		"370786": "昌邑市",
+		"370790": "开发区",
+		"370791": "高新区",
+		"370811": "任城区",
+		"370812": "兖州区",
+		"370826": "微山县",
+		"370827": "鱼台县",
+		"370828": "金乡县",
+		"370829": "嘉祥县",
+		"370830": "汶上县",
+		"370831": "泗水县",
+		"370832": "梁山县",
+		"370871": "济宁高新技术产业开发区",
+		"370881": "曲阜市",
+		"370883": "邹城市",
+		"370890": "高新区",
+		"370902": "泰山区",
+		"370911": "岱岳区",
+		"370921": "宁阳县",
+		"370923": "东平县",
+		"370982": "新泰市",
+		"370983": "肥城市",
+		"371002": "环翠区",
+		"371003": "文登区",
+		"371071": "威海火炬高技术产业开发区",
+		"371072": "威海经济技术开发区",
+		"371082": "荣成市",
+		"371083": "乳山市",
+		"371091": "经济技术开发区",
+		"371102": "东港区",
+		"371103": "岚山区",
+		"371121": "五莲县",
+		"371122": "莒县",
+		"371171": "日照经济技术开发区",
+		"371302": "兰山区",
+		"371311": "罗庄区",
+		"371312": "河东区",
+		"371321": "沂南县",
+		"371322": "郯城县",
+		"371323": "沂水县",
+		"371324": "兰陵县",
+		"371325": "费县",
+		"371326": "平邑县",
+		"371327": "莒南县",
+		"371328": "蒙阴县",
+		"371329": "临沭县",
+		"371371": "临沂高新技术产业开发区",
+		"371402": "德城区",
+		"371403": "陵城区",
+		"371422": "宁津县",
+		"371423": "庆云县",
+		"371424": "临邑县",
+		"371425": "齐河县",
+		"371426": "平原县",
+		"371427": "夏津县",
+		"371428": "武城县",
+		"371472": "德州运河经济开发区",
+		"371481": "乐陵市",
+		"371482": "禹城市",
+		"371502": "东昌府区",
+		"371503": "茌平区",
+		"371521": "阳谷县",
+		"371522": "莘县",
+		"371524": "东阿县",
+		"371525": "冠县",
+		"371526": "高唐县",
+		"371581": "临清市",
+		"371602": "滨城区",
+		"371603": "沾化区",
+		"371621": "惠民县",
+		"371622": "阳信县",
+		"371623": "无棣县",
+		"371625": "博兴县",
+		"371681": "邹平市",
+		"371702": "牡丹区",
+		"371703": "定陶区",
+		"371721": "曹县",
+		"371722": "单县",
+		"371723": "成武县",
+		"371724": "巨野县",
+		"371725": "郓城县",
+		"371726": "鄄城县",
+		"371728": "东明县",
+		"371771": "菏泽经济技术开发区",
+		"371772": "菏泽高新技术开发区",
+		"410102": "中原区",
+		"410103": "二七区",
+		"410104": "管城回族区",
+		"410105": "金水区",
+		"410106": "上街区",
+		"410108": "惠济区",
+		"410122": "中牟县",
+		"410171": "郑州经济技术开发区",
+		"410172": "郑州高新技术产业开发区",
+		"410173": "郑州航空港经济综合实验区",
+		"410181": "巩义市",
+		"410182": "荥阳市",
+		"410183": "新密市",
+		"410184": "新郑市",
+		"410185": "登封市",
+		"410190": "高新技术开发区",
+		"410191": "经济技术开发区",
+		"410202": "龙亭区",
+		"410203": "顺河回族区",
+		"410204": "鼓楼区",
+		"410205": "禹王台区",
+		"410212": "祥符区",
+		"410221": "杞县",
+		"410222": "通许县",
+		"410223": "尉氏县",
+		"410225": "兰考县",
+		"410302": "老城区",
+		"410303": "西工区",
+		"410304": "瀍河回族区",
+		"410305": "涧西区",
+		"410307": "偃师区",
+		"410308": "孟津区",
+		"410311": "洛龙区",
+		"410323": "新安县",
+		"410324": "栾川县",
+		"410325": "嵩县",
+		"410326": "汝阳县",
+		"410327": "宜阳县",
+		"410328": "洛宁县",
+		"410329": "伊川县",
+		"410402": "新华区",
+		"410403": "卫东区",
+		"410404": "石龙区",
+		"410411": "湛河区",
+		"410421": "宝丰县",
+		"410422": "叶县",
+		"410423": "鲁山县",
+		"410425": "郏县",
+		"410471": "平顶山高新技术产业开发区",
+		"410481": "舞钢市",
+		"410482": "汝州市",
+		"410502": "文峰区",
+		"410503": "北关区",
+		"410505": "殷都区",
+		"410506": "龙安区",
+		"410522": "安阳县",
+		"410523": "汤阴县",
+		"410526": "滑县",
+		"410527": "内黄县",
+		"410581": "林州市",
+		"410590": "开发区",
+		"410602": "鹤山区",
+		"410603": "山城区",
+		"410611": "淇滨区",
+		"410621": "浚县",
+		"410622": "淇县",
+		"410702": "红旗区",
+		"410703": "卫滨区",
+		"410704": "凤泉区",
+		"410711": "牧野区",
+		"410721": "新乡县",
+		"410724": "获嘉县",
+		"410725": "原阳县",
+		"410726": "延津县",
+		"410727": "封丘县",
+		"410771": "新乡高新技术产业开发区",
+		"410772": "新乡经济技术开发区",
+		"410781": "卫辉市",
+		"410782": "辉县市",
+		"410783": "长垣市",
+		"410802": "解放区",
+		"410803": "中站区",
+		"410804": "马村区",
+		"410811": "山阳区",
+		"410821": "修武县",
+		"410822": "博爱县",
+		"410823": "武陟县",
+		"410825": "温县",
+		"410871": "焦作城乡一体化示范区",
+		"410882": "沁阳市",
+		"410883": "孟州市",
+		"410902": "华龙区",
+		"410922": "清丰县",
+		"410923": "南乐县",
+		"410926": "范县",
+		"410927": "台前县",
+		"410928": "濮阳县",
+		"410971": "河南濮阳工业园区",
+		"411002": "魏都区",
+		"411003": "建安区",
+		"411024": "鄢陵县",
+		"411025": "襄城县",
+		"411071": "许昌经济技术开发区",
+		"411081": "禹州市",
+		"411082": "长葛市",
+		"411102": "源汇区",
+		"411103": "郾城区",
+		"411104": "召陵区",
+		"411121": "舞阳县",
+		"411122": "临颍县",
+		"411171": "漯河经济技术开发区",
+		"411202": "湖滨区",
+		"411203": "陕州区",
+		"411221": "渑池县",
+		"411224": "卢氏县",
+		"411271": "河南三门峡经济开发区",
+		"411281": "义马市",
+		"411282": "灵宝市",
+		"411302": "宛城区",
+		"411303": "卧龙区",
+		"411321": "南召县",
+		"411322": "方城县",
+		"411323": "西峡县",
+		"411324": "镇平县",
+		"411325": "内乡县",
+		"411326": "淅川县",
+		"411327": "社旗县",
+		"411328": "唐河县",
+		"411329": "新野县",
+		"411330": "桐柏县",
+		"411372": "南阳市城乡一体化示范区",
+		"411381": "邓州市",
+		"411402": "梁园区",
+		"411403": "睢阳区",
+		"411421": "民权县",
+		"411422": "睢县",
+		"411423": "宁陵县",
+		"411424": "柘城县",
+		"411425": "虞城县",
+		"411426": "夏邑县",
+		"411481": "永城市",
+		"411502": "浉河区",
+		"411503": "平桥区",
+		"411521": "罗山县",
+		"411522": "光山县",
+		"411523": "新县",
+		"411524": "商城县",
+		"411525": "固始县",
+		"411526": "潢川县",
+		"411527": "淮滨县",
+		"411528": "息县",
+		"411602": "川汇区",
+		"411603": "淮阳区",
+		"411621": "扶沟县",
+		"411622": "西华县",
+		"411623": "商水县",
+		"411624": "沈丘县",
+		"411625": "郸城县",
+		"411627": "太康县",
+		"411628": "鹿邑县",
+		"411671": "河南周口经济开发区",
+		"411681": "项城市",
+		"411690": "经济开发区",
+		"411702": "驿城区",
+		"411721": "西平县",
+		"411722": "上蔡县",
+		"411723": "平舆县",
+		"411724": "正阳县",
+		"411725": "确山县",
+		"411726": "泌阳县",
+		"411727": "汝南县",
+		"411728": "遂平县",
+		"411729": "新蔡县",
+		"419001": "济源市",
+		"420102": "江岸区",
+		"420103": "江汉区",
+		"420104": "硚口区",
+		"420105": "汉阳区",
+		"420106": "武昌区",
+		"420107": "青山区",
+		"420111": "洪山区",
+		"420112": "东西湖区",
+		"420113": "汉南区",
+		"420114": "蔡甸区",
+		"420115": "江夏区",
+		"420116": "黄陂区",
+		"420117": "新洲区",
+		"420202": "黄石港区",
+		"420203": "西塞山区",
+		"420204": "下陆区",
+		"420205": "铁山区",
+		"420222": "阳新县",
+		"420281": "大冶市",
+		"420302": "茅箭区",
+		"420303": "张湾区",
+		"420304": "郧阳区",
+		"420322": "郧西县",
+		"420323": "竹山县",
+		"420324": "竹溪县",
+		"420325": "房县",
+		"420381": "丹江口市",
+		"420502": "西陵区",
+		"420503": "伍家岗区",
+		"420504": "点军区",
+		"420505": "猇亭区",
+		"420506": "夷陵区",
+		"420525": "远安县",
+		"420526": "兴山县",
+		"420527": "秭归县",
+		"420528": "长阳土家族自治县",
+		"420529": "五峰土家族自治县",
+		"420581": "宜都市",
+		"420582": "当阳市",
+		"420583": "枝江市",
+		"420590": "经济开发区",
+		"420602": "襄城区",
+		"420606": "樊城区",
+		"420607": "襄州区",
+		"420624": "南漳县",
+		"420625": "谷城县",
+		"420626": "保康县",
+		"420682": "老河口市",
+		"420683": "枣阳市",
+		"420684": "宜城市",
+		"420702": "梁子湖区",
+		"420703": "华容区",
+		"420704": "鄂城区",
+		"420802": "东宝区",
+		"420804": "掇刀区",
+		"420822": "沙洋县",
+		"420881": "钟祥市",
+		"420882": "京山市",
+		"420902": "孝南区",
+		"420921": "孝昌县",
+		"420922": "大悟县",
+		"420923": "云梦县",
+		"420981": "应城市",
+		"420982": "安陆市",
+		"420984": "汉川市",
+		"421002": "沙市区",
+		"421003": "荆州区",
+		"421022": "公安县",
+		"421024": "江陵县",
+		"421081": "石首市",
+		"421083": "洪湖市",
+		"421087": "松滋市",
+		"421088": "监利市",
+		"421102": "黄州区",
+		"421121": "团风县",
+		"421122": "红安县",
+		"421123": "罗田县",
+		"421124": "英山县",
+		"421125": "浠水县",
+		"421126": "蕲春县",
+		"421127": "黄梅县",
+		"421171": "龙感湖管理区",
+		"421181": "麻城市",
+		"421182": "武穴市",
+		"421202": "咸安区",
+		"421221": "嘉鱼县",
+		"421222": "通城县",
+		"421223": "崇阳县",
+		"421224": "通山县",
+		"421281": "赤壁市",
+		"421303": "曾都区",
+		"421321": "随县",
+		"421381": "广水市",
+		"422801": "恩施市",
+		"422802": "利川市",
+		"422822": "建始县",
+		"422823": "巴东县",
+		"422825": "宣恩县",
+		"422826": "咸丰县",
+		"422827": "来凤县",
+		"422828": "鹤峰县",
+		"429004": "仙桃市",
+		"429005": "潜江市",
+		"429006": "天门市",
+		"429021": "神农架林区",
+		"430102": "芙蓉区",
+		"430103": "天心区",
+		"430104": "岳麓区",
+		"430105": "开福区",
+		"430111": "雨花区",
+		"430112": "望城区",
+		"430121": "长沙县",
+		"430181": "浏阳市",
+		"430182": "宁乡市",
+		"430202": "荷塘区",
+		"430203": "芦淞区",
+		"430204": "石峰区",
+		"430211": "天元区",
+		"430212": "渌口区",
+		"430223": "攸县",
+		"430224": "茶陵县",
+		"430225": "炎陵县",
+		"430271": "云龙示范区",
+		"430281": "醴陵市",
+		"430302": "雨湖区",
+		"430304": "岳塘区",
+		"430321": "湘潭县",
+		"430373": "湘潭九华示范区",
+		"430381": "湘乡市",
+		"430382": "韶山市",
+		"430405": "珠晖区",
+		"430406": "雁峰区",
+		"430407": "石鼓区",
+		"430408": "蒸湘区",
+		"430412": "南岳区",
+		"430421": "衡阳县",
+		"430422": "衡南县",
+		"430423": "衡山县",
+		"430424": "衡东县",
+		"430426": "祁东县",
+		"430481": "耒阳市",
+		"430482": "常宁市",
+		"430502": "双清区",
+		"430503": "大祥区",
+		"430511": "北塔区",
+		"430522": "新邵县",
+		"430523": "邵阳县",
+		"430524": "隆回县",
+		"430525": "洞口县",
+		"430527": "绥宁县",
+		"430528": "新宁县",
+		"430529": "城步苗族自治县",
+		"430581": "武冈市",
+		"430582": "邵东市",
+		"430602": "岳阳楼区",
+		"430603": "云溪区",
+		"430611": "君山区",
+		"430621": "岳阳县",
+		"430623": "华容县",
+		"430624": "湘阴县",
+		"430626": "平江县",
+		"430681": "汨罗市",
+		"430682": "临湘市",
+		"430702": "武陵区",
+		"430703": "鼎城区",
+		"430721": "安乡县",
+		"430722": "汉寿县",
+		"430723": "澧县",
+		"430724": "临澧县",
+		"430725": "桃源县",
+		"430726": "石门县",
+		"430781": "津市市",
+		"430802": "永定区",
+		"430811": "武陵源区",
+		"430821": "慈利县",
+		"430822": "桑植县",
+		"430902": "资阳区",
+		"430903": "赫山区",
+		"430921": "南县",
+		"430922": "桃江县",
+		"430923": "安化县",
+		"430971": "益阳市大通湖管理区",
+		"430981": "沅江市",
+		"431002": "北湖区",
+		"431003": "苏仙区",
+		"431021": "桂阳县",
+		"431022": "宜章县",
+		"431023": "永兴县",
+		"431024": "嘉禾县",
+		"431025": "临武县",
+		"431026": "汝城县",
+		"431027": "桂东县",
+		"431028": "安仁县",
+		"431081": "资兴市",
+		"431102": "零陵区",
+		"431103": "冷水滩区",
+		"431122": "东安县",
+		"431123": "双牌县",
+		"431124": "道县",
+		"431125": "江永县",
+		"431126": "宁远县",
+		"431127": "蓝山县",
+		"431128": "新田县",
+		"431129": "江华瑶族自治县",
+		"431181": "祁阳市",
+		"431202": "鹤城区",
+		"431221": "中方县",
+		"431222": "沅陵县",
+		"431223": "辰溪县",
+		"431224": "溆浦县",
+		"431225": "会同县",
+		"431226": "麻阳苗族自治县",
+		"431227": "新晃侗族自治县",
+		"431228": "芷江侗族自治县",
+		"431229": "靖州苗族侗族自治县",
+		"431230": "通道侗族自治县",
+		"431271": "怀化市洪江管理区",
+		"431281": "洪江市",
+		"431302": "娄星区",
+		"431321": "双峰县",
+		"431322": "新化县",
+		"431381": "冷水江市",
+		"431382": "涟源市",
+		"433101": "吉首市",
+		"433122": "泸溪县",
+		"433123": "凤凰县",
+		"433124": "花垣县",
+		"433125": "保靖县",
+		"433126": "古丈县",
+		"433127": "永顺县",
+		"433130": "龙山县",
+		"440103": "荔湾区",
+		"440104": "越秀区",
+		"440105": "海珠区",
+		"440106": "天河区",
+		"440111": "白云区",
+		"440112": "黄埔区",
+		"440113": "番禺区",
+		"440114": "花都区",
+		"440115": "南沙区",
+		"440117": "从化区",
+		"440118": "增城区",
+		"440203": "武江区",
+		"440204": "浈江区",
+		"440205": "曲江区",
+		"440222": "始兴县",
+		"440224": "仁化县",
+		"440229": "翁源县",
+		"440232": "乳源瑶族自治县",
+		"440233": "新丰县",
+		"440281": "乐昌市",
+		"440282": "南雄市",
+		"440303": "罗湖区",
+		"440304": "福田区",
+		"440305": "南山区",
+		"440306": "宝安区",
+		"440307": "龙岗区",
+		"440308": "盐田区",
+		"440309": "龙华区",
+		"440310": "坪山区",
+		"440311": "光明区",
+		"440402": "香洲区",
+		"440403": "斗门区",
+		"440404": "金湾区",
+		"440507": "龙湖区",
+		"440511": "金平区",
+		"440512": "濠江区",
+		"440513": "潮阳区",
+		"440514": "潮南区",
+		"440515": "澄海区",
+		"440523": "南澳县",
+		"440604": "禅城区",
+		"440605": "南海区",
+		"440606": "顺德区",
+		"440607": "三水区",
+		"440608": "高明区",
+		"440703": "蓬江区",
+		"440704": "江海区",
+		"440705": "新会区",
+		"440781": "台山市",
+		"440783": "开平市",
+		"440784": "鹤山市",
+		"440785": "恩平市",
+		"440802": "赤坎区",
+		"440803": "霞山区",
+		"440804": "坡头区",
+		"440811": "麻章区",
+		"440823": "遂溪县",
+		"440825": "徐闻县",
+		"440881": "廉江市",
+		"440882": "雷州市",
+		"440883": "吴川市",
+		"440890": "经济技术开发区",
+		"440902": "茂南区",
+		"440904": "电白区",
+		"440981": "高州市",
+		"440982": "化州市",
+		"440983": "信宜市",
+		"441202": "端州区",
+		"441203": "鼎湖区",
+		"441204": "高要区",
+		"441223": "广宁县",
+		"441224": "怀集县",
+		"441225": "封开县",
+		"441226": "德庆县",
+		"441284": "四会市",
+		"441302": "惠城区",
+		"441303": "惠阳区",
+		"441322": "博罗县",
+		"441323": "惠东县",
+		"441324": "龙门县",
+		"441402": "梅江区",
+		"441403": "梅县区",
+		"441422": "大埔县",
+		"441423": "丰顺县",
+		"441424": "五华县",
+		"441426": "平远县",
+		"441427": "蕉岭县",
+		"441481": "兴宁市",
+		"441502": "城区",
+		"441521": "海丰县",
+		"441523": "陆河县",
+		"441581": "陆丰市",
+		"441602": "源城区",
+		"441621": "紫金县",
+		"441622": "龙川县",
+		"441623": "连平县",
+		"441624": "和平县",
+		"441625": "东源县",
+		"441702": "江城区",
+		"441704": "阳东区",
+		"441721": "阳西县",
+		"441781": "阳春市",
+		"441802": "清城区",
+		"441803": "清新区",
+		"441821": "佛冈县",
+		"441823": "阳山县",
+		"441825": "连山壮族瑶族自治县",
+		"441826": "连南瑶族自治县",
+		"441881": "英德市",
+		"441882": "连州市",
+		"441901": "中堂镇",
+		"441903": "南城街道",
+		"441904": "长安镇",
+		"441905": "东坑镇",
+		"441906": "樟木头镇",
+		"441907": "莞城街道",
+		"441908": "石龙镇",
+		"441909": "桥头镇",
+		"441910": "万江街道",
+		"441911": "麻涌镇",
+		"441912": "虎门镇",
+		"441913": "谢岗镇",
+		"441914": "石碣镇",
+		"441915": "茶山镇",
+		"441916": "东城街道",
+		"441917": "洪梅镇",
+		"441918": "道滘镇",
+		"441919": "高埗镇",
+		"441920": "企石镇",
+		"441921": "凤岗镇",
+		"441922": "大岭山镇",
+		"441923": "松山湖",
+		"441924": "清溪镇",
+		"441925": "望牛墩镇",
+		"441926": "厚街镇",
+		"441927": "常平镇",
+		"441928": "寮步镇",
+		"441929": "石排镇",
+		"441930": "横沥镇",
+		"441931": "塘厦镇",
+		"441932": "黄江镇",
+		"441933": "大朗镇",
+		"441934": "东莞港",
+		"441935": "东莞生态园",
+		"441990": "沙田镇",
+		"442001": "南头镇",
+		"442002": "神湾镇",
+		"442003": "东凤镇",
+		"442004": "五桂山街道",
+		"442005": "黄圃镇",
+		"442006": "小榄镇",
+		"442007": "石岐街道",
+		"442008": "横栏镇",
+		"442009": "三角镇",
+		"442010": "三乡镇",
+		"442011": "港口镇",
+		"442012": "沙溪镇",
+		"442013": "板芙镇",
+		"442015": "东升镇",
+		"442016": "阜沙镇",
+		"442017": "民众镇",
+		"442018": "东区街道",
+		"442019": "火炬开发区街道办事处",
+		"442020": "西区街道",
+		"442021": "南区街道",
+		"442022": "古镇镇",
+		"442023": "坦洲镇",
+		"442024": "大涌镇",
+		"442025": "南朗镇",
+		"445102": "湘桥区",
+		"445103": "潮安区",
+		"445122": "饶平县",
+		"445202": "榕城区",
+		"445203": "揭东区",
+		"445222": "揭西县",
+		"445224": "惠来县",
+		"445281": "普宁市",
+		"445302": "云城区",
+		"445303": "云安区",
+		"445321": "新兴县",
+		"445322": "郁南县",
+		"445381": "罗定市",
+		"450102": "兴宁区",
+		"450103": "青秀区",
+		"450105": "江南区",
+		"450107": "西乡塘区",
+		"450108": "良庆区",
+		"450109": "邕宁区",
+		"450110": "武鸣区",
+		"450123": "隆安县",
+		"450124": "马山县",
+		"450125": "上林县",
+		"450126": "宾阳县",
+		"450181": "横州市",
+		"450202": "城中区",
+		"450203": "鱼峰区",
+		"450204": "柳南区",
+		"450205": "柳北区",
+		"450206": "柳江区",
+		"450222": "柳城县",
+		"450223": "鹿寨县",
+		"450224": "融安县",
+		"450225": "融水苗族自治县",
+		"450226": "三江侗族自治县",
+		"450302": "秀峰区",
+		"450303": "叠彩区",
+		"450304": "象山区",
+		"450305": "七星区",
+		"450311": "雁山区",
+		"450312": "临桂区",
+		"450321": "阳朔县",
+		"450323": "灵川县",
+		"450324": "全州县",
+		"450325": "兴安县",
+		"450326": "永福县",
+		"450327": "灌阳县",
+		"450328": "龙胜各族自治县",
+		"450329": "资源县",
+		"450330": "平乐县",
+		"450332": "恭城瑶族自治县",
+		"450381": "荔浦市",
+		"450403": "万秀区",
+		"450405": "长洲区",
+		"450406": "龙圩区",
+		"450421": "苍梧县",
+		"450422": "藤县",
+		"450423": "蒙山县",
+		"450481": "岑溪市",
+		"450502": "海城区",
+		"450503": "银海区",
+		"450512": "铁山港区",
+		"450521": "合浦县",
+		"450602": "港口区",
+		"450603": "防城区",
+		"450621": "上思县",
+		"450681": "东兴市",
+		"450702": "钦南区",
+		"450703": "钦北区",
+		"450721": "灵山县",
+		"450722": "浦北县",
+		"450802": "港北区",
+		"450803": "港南区",
+		"450804": "覃塘区",
+		"450821": "平南县",
+		"450881": "桂平市",
+		"450902": "玉州区",
+		"450903": "福绵区",
+		"450921": "容县",
+		"450922": "陆川县",
+		"450923": "博白县",
+		"450924": "兴业县",
+		"450981": "北流市",
+		"451002": "右江区",
+		"451003": "田阳区",
+		"451022": "田东县",
+		"451024": "德保县",
+		"451026": "那坡县",
+		"451027": "凌云县",
+		"451028": "乐业县",
+		"451029": "田林县",
+		"451030": "西林县",
+		"451031": "隆林各族自治县",
+		"451081": "靖西市",
+		"451082": "平果市",
+		"451102": "八步区",
+		"451103": "平桂区",
+		"451121": "昭平县",
+		"451122": "钟山县",
+		"451123": "富川瑶族自治县",
+		"451202": "金城江区",
+		"451203": "宜州区",
+		"451221": "南丹县",
+		"451222": "天峨县",
+		"451223": "凤山县",
+		"451224": "东兰县",
+		"451225": "罗城仫佬族自治县",
+		"451226": "环江毛南族自治县",
+		"451227": "巴马瑶族自治县",
+		"451228": "都安瑶族自治县",
+		"451229": "大化瑶族自治县",
+		"451302": "兴宾区",
+		"451321": "忻城县",
+		"451322": "象州县",
+		"451323": "武宣县",
+		"451324": "金秀瑶族自治县",
+		"451381": "合山市",
+		"451402": "江州区",
+		"451421": "扶绥县",
+		"451422": "宁明县",
+		"451423": "龙州县",
+		"451424": "大新县",
+		"451425": "天等县",
+		"451481": "凭祥市",
+		"460105": "秀英区",
+		"460106": "龙华区",
+		"460107": "琼山区",
+		"460108": "美兰区",
+		"460202": "海棠区",
+		"460203": "吉阳区",
+		"460204": "天涯区",
+		"460205": "崖州区",
+		"460321": "西沙区",
+		"460322": "南沙区",
+		"460401": "那大镇",
+		"460402": "和庆镇",
+		"460403": "南丰镇",
+		"460404": "大成镇",
+		"460405": "雅星镇",
+		"460406": "兰洋镇",
+		"460407": "光村镇",
+		"460408": "木棠镇",
+		"460409": "海头镇",
+		"460410": "峨蔓镇",
+		"460411": "王五镇",
+		"460412": "白马井镇",
+		"460413": "中和镇",
+		"460414": "排浦镇",
+		"460415": "东成镇",
+		"460416": "新州镇",
+		"460417": "洋浦经济开发区",
+		"460418": "华南热作学院",
+		"469001": "五指山市",
+		"469002": "琼海市",
+		"469005": "文昌市",
+		"469006": "万宁市",
+		"469007": "东方市",
+		"469021": "定安县",
+		"469022": "屯昌县",
+		"469023": "澄迈县",
+		"469024": "临高县",
+		"469025": "白沙黎族自治县",
+		"469026": "昌江黎族自治县",
+		"469027": "乐东黎族自治县",
+		"469028": "陵水黎族自治县",
+		"469029": "保亭黎族苗族自治县",
+		"469030": "琼中黎族苗族自治县",
+		"500101": "万州区",
+		"500102": "涪陵区",
+		"500103": "渝中区",
+		"500104": "大渡口区",
+		"500105": "江北区",
+		"500106": "沙坪坝区",
+		"500107": "九龙坡区",
+		"500108": "南岸区",
+		"500109": "北碚区",
+		"500110": "綦江区",
+		"500111": "大足区",
+		"500112": "渝北区",
+		"500113": "巴南区",
+		"500114": "黔江区",
+		"500115": "长寿区",
+		"500116": "江津区",
+		"500117": "合川区",
+		"500118": "永川区",
+		"500119": "南川区",
+		"500120": "璧山区",
+		"500151": "铜梁区",
+		"500152": "潼南区",
+		"500153": "荣昌区",
+		"500154": "开州区",
+		"500155": "梁平区",
+		"500156": "武隆区",
+		"500229": "城口县",
+		"500230": "丰都县",
+		"500231": "垫江县",
+		"500233": "忠县",
+		"500235": "云阳县",
+		"500236": "奉节县",
+		"500237": "巫山县",
+		"500238": "巫溪县",
+		"500240": "石柱土家族自治县",
+		"500241": "秀山土家族苗族自治县",
+		"500242": "酉阳土家族苗族自治县",
+		"500243": "彭水苗族土家族自治县",
+		"510104": "锦江区",
+		"510105": "青羊区",
+		"510106": "金牛区",
+		"510107": "武侯区",
+		"510108": "成华区",
+		"510112": "龙泉驿区",
+		"510113": "青白江区",
+		"510114": "新都区",
+		"510115": "温江区",
+		"510116": "双流区",
+		"510117": "郫都区",
+		"510118": "新津区",
+		"510121": "金堂县",
+		"510129": "大邑县",
+		"510131": "蒲江县",
+		"510181": "都江堰市",
+		"510182": "彭州市",
+		"510183": "邛崃市",
+		"510184": "崇州市",
+		"510185": "简阳市",
+		"510191": "高新区",
+		"510302": "自流井区",
+		"510303": "贡井区",
+		"510304": "大安区",
+		"510311": "沿滩区",
+		"510321": "荣县",
+		"510322": "富顺县",
+		"510402": "东区",
+		"510403": "西区",
+		"510411": "仁和区",
+		"510421": "米易县",
+		"510422": "盐边县",
+		"510502": "江阳区",
+		"510503": "纳溪区",
+		"510504": "龙马潭区",
+		"510521": "泸县",
+		"510522": "合江县",
+		"510524": "叙永县",
+		"510525": "古蔺县",
+		"510603": "旌阳区",
+		"510604": "罗江区",
+		"510623": "中江县",
+		"510681": "广汉市",
+		"510682": "什邡市",
+		"510683": "绵竹市",
+		"510703": "涪城区",
+		"510704": "游仙区",
+		"510705": "安州区",
+		"510722": "三台县",
+		"510723": "盐亭县",
+		"510725": "梓潼县",
+		"510726": "北川羌族自治县",
+		"510727": "平武县",
+		"510781": "江油市",
+		"510791": "高新区",
+		"510802": "利州区",
+		"510811": "昭化区",
+		"510812": "朝天区",
+		"510821": "旺苍县",
+		"510822": "青川县",
+		"510823": "剑阁县",
+		"510824": "苍溪县",
+		"510903": "船山区",
+		"510904": "安居区",
+		"510921": "蓬溪县",
+		"510923": "大英县",
+		"510981": "射洪市",
+		"511002": "市中区",
+		"511011": "东兴区",
+		"511024": "威远县",
+		"511025": "资中县",
+		"511083": "隆昌市",
+		"511102": "市中区",
+		"511111": "沙湾区",
+		"511112": "五通桥区",
+		"511113": "金口河区",
+		"511123": "犍为县",
+		"511124": "井研县",
+		"511126": "夹江县",
+		"511129": "沐川县",
+		"511132": "峨边彝族自治县",
+		"511133": "马边彝族自治县",
+		"511181": "峨眉山市",
+		"511302": "顺庆区",
+		"511303": "高坪区",
+		"511304": "嘉陵区",
+		"511321": "南部县",
+		"511322": "营山县",
+		"511323": "蓬安县",
+		"511324": "仪陇县",
+		"511325": "西充县",
+		"511381": "阆中市",
+		"511402": "东坡区",
+		"511403": "彭山区",
+		"511421": "仁寿县",
+		"511423": "洪雅县",
+		"511424": "丹棱县",
+		"511425": "青神县",
+		"511502": "翠屏区",
+		"511503": "南溪区",
+		"511504": "叙州区",
+		"511523": "江安县",
+		"511524": "长宁县",
+		"511525": "高县",
+		"511526": "珙县",
+		"511527": "筠连县",
+		"511528": "兴文县",
+		"511529": "屏山县",
+		"511602": "广安区",
+		"511603": "前锋区",
+		"511621": "岳池县",
+		"511622": "武胜县",
+		"511623": "邻水县",
+		"511681": "华蓥市",
+		"511702": "通川区",
+		"511703": "达川区",
+		"511722": "宣汉县",
+		"511723": "开江县",
+		"511724": "大竹县",
+		"511725": "渠县",
+		"511781": "万源市",
+		"511802": "雨城区",
+		"511803": "名山区",
+		"511822": "荥经县",
+		"511823": "汉源县",
+		"511824": "石棉县",
+		"511825": "天全县",
+		"511826": "芦山县",
+		"511827": "宝兴县",
+		"511902": "巴州区",
+		"511903": "恩阳区",
+		"511921": "通江县",
+		"511922": "南江县",
+		"511923": "平昌县",
+		"511971": "巴中经济开发区",
+		"512002": "雁江区",
+		"512021": "安岳县",
+		"512022": "乐至县",
+		"513201": "马尔康市",
+		"513221": "汶川县",
+		"513222": "理县",
+		"513223": "茂县",
+		"513224": "松潘县",
+		"513225": "九寨沟县",
+		"513226": "金川县",
+		"513227": "小金县",
+		"513228": "黑水县",
+		"513230": "壤塘县",
+		"513231": "阿坝县",
+		"513232": "若尔盖县",
+		"513233": "红原县",
+		"513301": "康定市",
+		"513322": "泸定县",
+		"513323": "丹巴县",
+		"513324": "九龙县",
+		"513325": "雅江县",
+		"513326": "道孚县",
+		"513327": "炉霍县",
+		"513328": "甘孜县",
+		"513329": "新龙县",
+		"513330": "德格县",
+		"513331": "白玉县",
+		"513332": "石渠县",
+		"513333": "色达县",
+		"513334": "理塘县",
+		"513335": "巴塘县",
+		"513336": "乡城县",
+		"513337": "稻城县",
+		"513338": "得荣县",
+		"513401": "西昌市",
+		"513402": "会理市",
+		"513422": "木里藏族自治县",
+		"513423": "盐源县",
+		"513424": "德昌县",
+		"513426": "会东县",
+		"513427": "宁南县",
+		"513428": "普格县",
+		"513429": "布拖县",
+		"513430": "金阳县",
+		"513431": "昭觉县",
+		"513432": "喜德县",
+		"513433": "冕宁县",
+		"513434": "越西县",
+		"513435": "甘洛县",
+		"513436": "美姑县",
+		"513437": "雷波县",
+		"520102": "南明区",
+		"520103": "云岩区",
+		"520111": "花溪区",
+		"520112": "乌当区",
+		"520113": "白云区",
+		"520115": "观山湖区",
+		"520121": "开阳县",
+		"520122": "息烽县",
+		"520123": "修文县",
+		"520181": "清镇市",
+		"520201": "钟山区",
+		"520203": "六枝特区",
+		"520204": "水城区",
+		"520281": "盘州市",
+		"520302": "红花岗区",
+		"520303": "汇川区",
+		"520304": "播州区",
+		"520322": "桐梓县",
+		"520323": "绥阳县",
+		"520324": "正安县",
+		"520325": "道真仡佬族苗族自治县",
+		"520326": "务川仡佬族苗族自治县",
+		"520327": "凤冈县",
+		"520328": "湄潭县",
+		"520329": "余庆县",
+		"520330": "习水县",
+		"520381": "赤水市",
+		"520382": "仁怀市",
+		"520402": "西秀区",
+		"520403": "平坝区",
+		"520422": "普定县",
+		"520423": "镇宁布依族苗族自治县",
+		"520424": "关岭布依族苗族自治县",
+		"520425": "紫云苗族布依族自治县",
+		"520502": "七星关区",
+		"520521": "大方县",
+		"520523": "金沙县",
+		"520524": "织金县",
+		"520525": "纳雍县",
+		"520526": "威宁彝族回族苗族自治县",
+		"520527": "赫章县",
+		"520581": "黔西市",
+		"520602": "碧江区",
+		"520603": "万山区",
+		"520621": "江口县",
+		"520622": "玉屏侗族自治县",
+		"520623": "石阡县",
+		"520624": "思南县",
+		"520625": "印江土家族苗族自治县",
+		"520626": "德江县",
+		"520627": "沿河土家族自治县",
+		"520628": "松桃苗族自治县",
+		"522301": "兴义市",
+		"522302": "兴仁市",
+		"522323": "普安县",
+		"522324": "晴隆县",
+		"522325": "贞丰县",
+		"522326": "望谟县",
+		"522327": "册亨县",
+		"522328": "安龙县",
+		"522601": "凯里市",
+		"522622": "黄平县",
+		"522623": "施秉县",
+		"522624": "三穗县",
+		"522625": "镇远县",
+		"522626": "岑巩县",
+		"522627": "天柱县",
+		"522628": "锦屏县",
+		"522629": "剑河县",
+		"522630": "台江县",
+		"522631": "黎平县",
+		"522632": "榕江县",
+		"522633": "从江县",
+		"522634": "雷山县",
+		"522635": "麻江县",
+		"522636": "丹寨县",
+		"522701": "都匀市",
+		"522702": "福泉市",
+		"522722": "荔波县",
+		"522723": "贵定县",
+		"522725": "瓮安县",
+		"522726": "独山县",
+		"522727": "平塘县",
+		"522728": "罗甸县",
+		"522729": "长顺县",
+		"522730": "龙里县",
+		"522731": "惠水县",
+		"522732": "三都水族自治县",
+		"530102": "五华区",
+		"530103": "盘龙区",
+		"530111": "官渡区",
+		"530112": "西山区",
+		"530113": "东川区",
+		"530114": "呈贡区",
+		"530115": "晋宁区",
+		"530124": "富民县",
+		"530125": "宜良县",
+		"530126": "石林彝族自治县",
+		"530127": "嵩明县",
+		"530128": "禄劝彝族苗族自治县",
+		"530129": "寻甸回族彝族自治县",
+		"530181": "安宁市",
+		"530302": "麒麟区",
+		"530303": "沾益区",
+		"530304": "马龙区",
+		"530322": "陆良县",
+		"530323": "师宗县",
+		"530324": "罗平县",
+		"530325": "富源县",
+		"530326": "会泽县",
+		"530381": "宣威市",
+		"530402": "红塔区",
+		"530403": "江川区",
+		"530423": "通海县",
+		"530424": "华宁县",
+		"530425": "易门县",
+		"530426": "峨山彝族自治县",
+		"530427": "新平彝族傣族自治县",
+		"530428": "元江哈尼族彝族傣族自治县",
+		"530481": "澄江市",
+		"530502": "隆阳区",
+		"530521": "施甸县",
+		"530523": "龙陵县",
+		"530524": "昌宁县",
+		"530581": "腾冲市",
+		"530602": "昭阳区",
+		"530621": "鲁甸县",
+		"530622": "巧家县",
+		"530623": "盐津县",
+		"530624": "大关县",
+		"530625": "永善县",
+		"530626": "绥江县",
+		"530627": "镇雄县",
+		"530628": "彝良县",
+		"530629": "威信县",
+		"530681": "水富市",
+		"530702": "古城区",
+		"530721": "玉龙纳西族自治县",
+		"530722": "永胜县",
+		"530723": "华坪县",
+		"530724": "宁蒗彝族自治县",
+		"530802": "思茅区",
+		"530821": "宁洱哈尼族彝族自治县",
+		"530822": "墨江哈尼族自治县",
+		"530823": "景东彝族自治县",
+		"530824": "景谷傣族彝族自治县",
+		"530825": "镇沅彝族哈尼族拉祜族自治县",
+		"530826": "江城哈尼族彝族自治县",
+		"530827": "孟连傣族拉祜族佤族自治县",
+		"530828": "澜沧拉祜族自治县",
+		"530829": "西盟佤族自治县",
+		"530902": "临翔区",
+		"530921": "凤庆县",
+		"530922": "云县",
+		"530923": "永德县",
+		"530924": "镇康县",
+		"530925": "双江拉祜族佤族布朗族傣族自治县",
+		"530926": "耿马傣族佤族自治县",
+		"530927": "沧源佤族自治县",
+		"532301": "楚雄市",
+		"532302": "禄丰市",
+		"532322": "双柏县",
+		"532323": "牟定县",
+		"532324": "南华县",
+		"532325": "姚安县",
+		"532326": "大姚县",
+		"532327": "永仁县",
+		"532328": "元谋县",
+		"532329": "武定县",
+		"532501": "个旧市",
+		"532502": "开远市",
+		"532503": "蒙自市",
+		"532504": "弥勒市",
+		"532523": "屏边苗族自治县",
+		"532524": "建水县",
+		"532525": "石屏县",
+		"532527": "泸西县",
+		"532528": "元阳县",
+		"532529": "红河县",
+		"532530": "金平苗族瑶族傣族自治县",
+		"532531": "绿春县",
+		"532532": "河口瑶族自治县",
+		"532601": "文山市",
+		"532622": "砚山县",
+		"532623": "西畴县",
+		"532624": "麻栗坡县",
+		"532625": "马关县",
+		"532626": "丘北县",
+		"532627": "广南县",
+		"532628": "富宁县",
+		"532801": "景洪市",
+		"532822": "勐海县",
+		"532823": "勐腊县",
+		"532901": "大理市",
+		"532922": "漾濞彝族自治县",
+		"532923": "祥云县",
+		"532924": "宾川县",
+		"532925": "弥渡县",
+		"532926": "南涧彝族自治县",
+		"532927": "巍山彝族回族自治县",
+		"532928": "永平县",
+		"532929": "云龙县",
+		"532930": "洱源县",
+		"532931": "剑川县",
+		"532932": "鹤庆县",
+		"533102": "瑞丽市",
+		"533103": "芒市",
+		"533122": "梁河县",
+		"533123": "盈江县",
+		"533124": "陇川县",
+		"533301": "泸水市",
+		"533323": "福贡县",
+		"533324": "贡山独龙族怒族自治县",
+		"533325": "兰坪白族普米族自治县",
+		"533401": "香格里拉市",
+		"533422": "德钦县",
+		"533423": "维西傈僳族自治县",
+		"540102": "城关区",
+		"540103": "堆龙德庆区",
+		"540104": "达孜区",
+		"540121": "林周县",
+		"540122": "当雄县",
+		"540123": "尼木县",
+		"540124": "曲水县",
+		"540127": "墨竹工卡县",
+		"540202": "桑珠孜区",
+		"540221": "南木林县",
+		"540222": "江孜县",
+		"540223": "定日县",
+		"540224": "萨迦县",
+		"540225": "拉孜县",
+		"540226": "昂仁县",
+		"540227": "谢通门县",
+		"540228": "白朗县",
+		"540229": "仁布县",
+		"540230": "康马县",
+		"540231": "定结县",
+		"540232": "仲巴县",
+		"540233": "亚东县",
+		"540234": "吉隆县",
+		"540235": "聂拉木县",
+		"540236": "萨嘎县",
+		"540237": "岗巴县",
+		"540302": "卡若区",
+		"540321": "江达县",
+		"540322": "贡觉县",
+		"540323": "类乌齐县",
+		"540324": "丁青县",
+		"540325": "察雅县",
+		"540326": "八宿县",
+		"540327": "左贡县",
+		"540328": "芒康县",
+		"540329": "洛隆县",
+		"540330": "边坝县",
+		"540402": "巴宜区",
+		"540421": "工布江达县",
+		"540423": "墨脱县",
+		"540424": "波密县",
+		"540425": "察隅县",
+		"540426": "朗县",
+		"540481": "米林市",
+		"540502": "乃东区",
+		"540521": "扎囊县",
+		"540522": "贡嘎县",
+		"540523": "桑日县",
+		"540524": "琼结县",
+		"540525": "曲松县",
+		"540526": "措美县",
+		"540527": "洛扎县",
+		"540528": "加查县",
+		"540529": "隆子县",
+		"540531": "浪卡子县",
+		"540581": "错那市",
+		"540602": "色尼区",
+		"540621": "嘉黎县",
+		"540622": "比如县",
+		"540623": "聂荣县",
+		"540624": "安多县",
+		"540625": "申扎县",
+		"540626": "索县",
+		"540627": "班戈县",
+		"540628": "巴青县",
+		"540629": "尼玛县",
+		"540630": "双湖县",
+		"542521": "普兰县",
+		"542522": "札达县",
+		"542523": "噶尔县",
+		"542524": "日土县",
+		"542525": "革吉县",
+		"542526": "改则县",
+		"542527": "措勤县",
+		"610102": "新城区",
+		"610103": "碑林区",
+		"610104": "莲湖区",
+		"610111": "灞桥区",
+		"610112": "未央区",
+		"610113": "雁塔区",
+		"610114": "阎良区",
+		"610115": "临潼区",
+		"610116": "长安区",
+		"610117": "高陵区",
+		"610118": "鄠邑区",
+		"610122": "蓝田县",
+		"610124": "周至县",
+		"610202": "王益区",
+		"610203": "印台区",
+		"610204": "耀州区",
+		"610222": "宜君县",
+		"610302": "渭滨区",
+		"610303": "金台区",
+		"610304": "陈仓区",
+		"610305": "凤翔区",
+		"610323": "岐山县",
+		"610324": "扶风县",
+		"610326": "眉县",
+		"610327": "陇县",
+		"610328": "千阳县",
+		"610329": "麟游县",
+		"610330": "凤县",
+		"610331": "太白县",
+		"610402": "秦都区",
+		"610403": "杨陵区",
+		"610404": "渭城区",
+		"610422": "三原县",
+		"610423": "泾阳县",
+		"610424": "乾县",
+		"610425": "礼泉县",
+		"610426": "永寿县",
+		"610428": "长武县",
+		"610429": "旬邑县",
+		"610430": "淳化县",
+		"610431": "武功县",
+		"610481": "兴平市",
+		"610482": "彬州市",
+		"610502": "临渭区",
+		"610503": "华州区",
+		"610522": "潼关县",
+		"610523": "大荔县",
+		"610524": "合阳县",
+		"610525": "澄城县",
+		"610526": "蒲城县",
+		"610527": "白水县",
+		"610528": "富平县",
+		"610581": "韩城市",
+		"610582": "华阴市",
+		"610602": "宝塔区",
+		"610603": "安塞区",
+		"610621": "延长县",
+		"610622": "延川县",
+		"610625": "志丹县",
+		"610626": "吴起县",
+		"610627": "甘泉县",
+		"610628": "富县",
+		"610629": "洛川县",
+		"610630": "宜川县",
+		"610631": "黄龙县",
+		"610632": "黄陵县",
+		"610681": "子长市",
+		"610702": "汉台区",
+		"610703": "南郑区",
+		"610722": "城固县",
+		"610723": "洋县",
+		"610724": "西乡县",
+		"610725": "勉县",
+		"610726": "宁强县",
+		"610727": "略阳县",
+		"610728": "镇巴县",
+		"610729": "留坝县",
+		"610730": "佛坪县",
+		"610802": "榆阳区",
+		"610803": "横山区",
+		"610822": "府谷县",
+		"610824": "靖边县",
+		"610825": "定边县",
+		"610826": "绥德县",
+		"610827": "米脂县",
+		"610828": "佳县",
+		"610829": "吴堡县",
+		"610830": "清涧县",
+		"610831": "子洲县",
+		"610881": "神木市",
+		"610902": "汉滨区",
+		"610921": "汉阴县",
+		"610922": "石泉县",
+		"610923": "宁陕县",
+		"610924": "紫阳县",
+		"610925": "岚皋县",
+		"610926": "平利县",
+		"610927": "镇坪县",
+		"610929": "白河县",
+		"610981": "旬阳市",
+		"611002": "商州区",
+		"611021": "洛南县",
+		"611022": "丹凤县",
+		"611023": "商南县",
+		"611024": "山阳县",
+		"611025": "镇安县",
+		"611026": "柞水县",
+		"620102": "城关区",
+		"620103": "七里河区",
+		"620104": "西固区",
+		"620105": "安宁区",
+		"620111": "红古区",
+		"620121": "永登县",
+		"620122": "皋兰县",
+		"620123": "榆中县",
+		"620171": "兰州新区",
+		"620201": "市辖区",
+		"620290": "雄关区",
+		"620291": "长城区",
+		"620292": "镜铁区",
+		"620293": "新城镇",
+		"620294": "峪泉镇",
+		"620295": "文殊镇",
+		"620302": "金川区",
+		"620321": "永昌县",
+		"620402": "白银区",
+		"620403": "平川区",
+		"620421": "靖远县",
+		"620422": "会宁县",
+		"620423": "景泰县",
+		"620502": "秦州区",
+		"620503": "麦积区",
+		"620521": "清水县",
+		"620522": "秦安县",
+		"620523": "甘谷县",
+		"620524": "武山县",
+		"620525": "张家川回族自治县",
+		"620602": "凉州区",
+		"620621": "民勤县",
+		"620622": "古浪县",
+		"620623": "天祝藏族自治县",
+		"620702": "甘州区",
+		"620721": "肃南裕固族自治县",
+		"620722": "民乐县",
+		"620723": "临泽县",
+		"620724": "高台县",
+		"620725": "山丹县",
+		"620802": "崆峒区",
+		"620821": "泾川县",
+		"620822": "灵台县",
+		"620823": "崇信县",
+		"620825": "庄浪县",
+		"620826": "静宁县",
+		"620881": "华亭市",
+		"620902": "肃州区",
+		"620921": "金塔县",
+		"620922": "瓜州县",
+		"620923": "肃北蒙古族自治县",
+		"620924": "阿克塞哈萨克族自治县",
+		"620981": "玉门市",
+		"620982": "敦煌市",
+		"621002": "西峰区",
+		"621021": "庆城县",
+		"621022": "环县",
+		"621023": "华池县",
+		"621024": "合水县",
+		"621025": "正宁县",
+		"621026": "宁县",
+		"621027": "镇原县",
+		"621102": "安定区",
+		"621121": "通渭县",
+		"621122": "陇西县",
+		"621123": "渭源县",
+		"621124": "临洮县",
+		"621125": "漳县",
+		"621126": "岷县",
+		"621202": "武都区",
+		"621221": "成县",
+		"621222": "文县",
+		"621223": "宕昌县",
+		"621224": "康县",
+		"621225": "西和县",
+		"621226": "礼县",
+		"621227": "徽县",
+		"621228": "两当县",
+		"622901": "临夏市",
+		"622921": "临夏县",
+		"622922": "康乐县",
+		"622923": "永靖县",
+		"622924": "广河县",
+		"622925": "和政县",
+		"622926": "东乡族自治县",
+		"622927": "积石山保安族东乡族撒拉族自治县",
+		"623001": "合作市",
+		"623021": "临潭县",
+		"623022": "卓尼县",
+		"623023": "舟曲县",
+		"623024": "迭部县",
+		"623025": "玛曲县",
+		"623026": "碌曲县",
+		"623027": "夏河县",
+		"630102": "城东区",
+		"630103": "城中区",
+		"630104": "城西区",
+		"630105": "城北区",
+		"630106": "湟中区",
+		"630121": "大通回族土族自治县",
+		"630123": "湟源县",
+		"630202": "乐都区",
+		"630203": "平安区",
+		"630222": "民和回族土族自治县",
+		"630223": "互助土族自治县",
+		"630224": "化隆回族自治县",
+		"630225": "循化撒拉族自治县",
+		"632221": "门源回族自治县",
+		"632222": "祁连县",
+		"632223": "海晏县",
+		"632224": "刚察县",
+		"632301": "同仁市",
+		"632322": "尖扎县",
+		"632323": "泽库县",
+		"632324": "河南蒙古族自治县",
+		"632521": "共和县",
+		"632522": "同德县",
+		"632523": "贵德县",
+		"632524": "兴海县",
+		"632525": "贵南县",
+		"632621": "玛沁县",
+		"632622": "班玛县",
+		"632623": "甘德县",
+		"632624": "达日县",
+		"632625": "久治县",
+		"632626": "玛多县",
+		"632701": "玉树市",
+		"632722": "杂多县",
+		"632723": "称多县",
+		"632724": "治多县",
+		"632725": "囊谦县",
+		"632726": "曲麻莱县",
+		"632801": "格尔木市",
+		"632802": "德令哈市",
+		"632803": "茫崖市",
+		"632821": "乌兰县",
+		"632822": "都兰县",
+		"632823": "天峻县",
+		"632857": "大柴旦行政委员会",
+		"640104": "兴庆区",
+		"640105": "西夏区",
+		"640106": "金凤区",
+		"640121": "永宁县",
+		"640122": "贺兰县",
+		"640181": "灵武市",
+		"640202": "大武口区",
+		"640205": "惠农区",
+		"640221": "平罗县",
+		"640302": "利通区",
+		"640303": "红寺堡区",
+		"640323": "盐池县",
+		"640324": "同心县",
+		"640381": "青铜峡市",
+		"640402": "原州区",
+		"640422": "西吉县",
+		"640423": "隆德县",
+		"640424": "泾源县",
+		"640425": "彭阳县",
+		"640502": "沙坡头区",
+		"640521": "中宁县",
+		"640522": "海原县",
+		"650102": "天山区",
+		"650103": "沙依巴克区",
+		"650104": "新市区",
+		"650105": "水磨沟区",
+		"650106": "头屯河区",
+		"650107": "达坂城区",
+		"650109": "米东区",
+		"650121": "乌鲁木齐县",
+		"650202": "独山子区",
+		"650203": "克拉玛依区",
+		"650204": "白碱滩区",
+		"650205": "乌尔禾区",
+		"650402": "高昌区",
+		"650421": "鄯善县",
+		"650422": "托克逊县",
+		"650502": "伊州区",
+		"650521": "巴里坤哈萨克自治县",
+		"650522": "伊吾县",
+		"652301": "昌吉市",
+		"652302": "阜康市",
+		"652323": "呼图壁县",
+		"652324": "玛纳斯县",
+		"652325": "奇台县",
+		"652327": "吉木萨尔县",
+		"652328": "木垒哈萨克自治县",
+		"652701": "博乐市",
+		"652702": "阿拉山口市",
+		"652722": "精河县",
+		"652723": "温泉县",
+		"652801": "库尔勒市",
+		"652822": "轮台县",
+		"652823": "尉犁县",
+		"652824": "若羌县",
+		"652825": "且末县",
+		"652826": "焉耆回族自治县",
+		"652827": "和静县",
+		"652828": "和硕县",
+		"652829": "博湖县",
+		"652901": "阿克苏市",
+		"652902": "库车市",
+		"652922": "温宿县",
+		"652924": "沙雅县",
+		"652925": "新和县",
+		"652926": "拜城县",
+		"652927": "乌什县",
+		"652928": "阿瓦提县",
+		"652929": "柯坪县",
+		"653001": "阿图什市",
+		"653022": "阿克陶县",
+		"653023": "阿合奇县",
+		"653024": "乌恰县",
+		"653101": "喀什市",
+		"653121": "疏附县",
+		"653122": "疏勒县",
+		"653123": "英吉沙县",
+		"653124": "泽普县",
+		"653125": "莎车县",
+		"653126": "叶城县",
+		"653127": "麦盖提县",
+		"653128": "岳普湖县",
+		"653129": "伽师县",
+		"653130": "巴楚县",
+		"653131": "塔什库尔干塔吉克自治县",
+		"653201": "和田市",
+		"653221": "和田县",
+		"653222": "墨玉县",
+		"653223": "皮山县",
+		"653224": "洛浦县",
+		"653225": "策勒县",
+		"653226": "于田县",
+		"653227": "民丰县",
+		"654002": "伊宁市",
+		"654003": "奎屯市",
+		"654004": "霍尔果斯市",
+		"654021": "伊宁县",
+		"654022": "察布查尔锡伯自治县",
+		"654023": "霍城县",
+		"654024": "巩留县",
+		"654025": "新源县",
+		"654026": "昭苏县",
+		"654027": "特克斯县",
+		"654028": "尼勒克县",
+		"654201": "塔城市",
+		"654202": "乌苏市",
+		"654203": "沙湾市",
+		"654221": "额敏县",
+		"654224": "托里县",
+		"654225": "裕民县",
+		"654226": "和布克赛尔蒙古自治县",
+		"654301": "阿勒泰市",
+		"654321": "布尔津县",
+		"654322": "富蕴县",
+		"654323": "福海县",
+		"654324": "哈巴河县",
+		"654325": "青河县",
+		"654326": "吉木乃县",
+		"659001": "石河子市",
+		"659002": "阿拉尔市",
+		"659003": "图木舒克市",
+		"659004": "五家渠市",
+		"659005": "北屯市",
+		"659006": "铁门关市",
+		"659007": "双河市",
+		"659008": "可克达拉市",
+		"659009": "昆玉市",
+		"659010": "胡杨河市",
+		"659011": "新星市",
+		"659012": "白杨市",
+		"710101": "中正区",
+		"710102": "大同区",
+		"710103": "中山区",
+		"710104": "松山区",
+		"710105": "大安区",
+		"710106": "万华区",
+		"710107": "信义区",
+		"710108": "士林区",
+		"710109": "北投区",
+		"710110": "内湖区",
+		"710111": "南港区",
+		"710112": "文山区",
+		"710199": "其它区",
+		"710201": "新兴区",
+		"710202": "前金区",
+		"710203": "芩雅区",
+		"710204": "盐埕区",
+		"710205": "鼓山区",
+		"710206": "旗津区",
+		"710207": "前镇区",
+		"710208": "三民区",
+		"710209": "左营区",
+		"710210": "楠梓区",
+		"710211": "小港区",
+		"710241": "苓雅区",
+		"710242": "仁武区",
+		"710243": "大社区",
+		"710244": "冈山区",
+		"710245": "路竹区",
+		"710246": "阿莲区",
+		"710247": "田寮区",
+		"710248": "燕巢区",
+		"710249": "桥头区",
+		"710250": "梓官区",
+		"710251": "弥陀区",
+		"710252": "永安区",
+		"710253": "湖内区",
+		"710254": "凤山区",
+		"710255": "大寮区",
+		"710256": "林园区",
+		"710257": "鸟松区",
+		"710258": "大树区",
+		"710259": "旗山区",
+		"710260": "美浓区",
+		"710261": "六龟区",
+		"710262": "内门区",
+		"710263": "杉林区",
+		"710264": "甲仙区",
+		"710265": "桃源区",
+		"710266": "那玛夏区",
+		"710267": "茂林区",
+		"710268": "茄萣区",
+		"710299": "其它区",
+		"710301": "中西区",
+		"710302": "东区",
+		"710303": "南区",
+		"710304": "北区",
+		"710305": "安平区",
+		"710306": "安南区",
+		"710339": "永康区",
+		"710340": "归仁区",
+		"710341": "新化区",
+		"710342": "左镇区",
+		"710343": "玉井区",
+		"710344": "楠西区",
+		"710345": "南化区",
+		"710346": "仁德区",
+		"710347": "关庙区",
+		"710348": "龙崎区",
+		"710349": "官田区",
+		"710350": "麻豆区",
+		"710351": "佳里区",
+		"710352": "西港区",
+		"710353": "七股区",
+		"710354": "将军区",
+		"710355": "学甲区",
+		"710356": "北门区",
+		"710357": "新营区",
+		"710358": "后壁区",
+		"710359": "白河区",
+		"710360": "东山区",
+		"710361": "六甲区",
+		"710362": "下营区",
+		"710363": "柳营区",
+		"710364": "盐水区",
+		"710365": "善化区",
+		"710366": "大内区",
+		"710367": "山上区",
+		"710368": "新市区",
+		"710369": "安定区",
+		"710399": "其它区",
+		"710401": "中区",
+		"710402": "东区",
+		"710403": "南区",
+		"710404": "西区",
+		"710405": "北区",
+		"710406": "北屯区",
+		"710407": "西屯区",
+		"710408": "南屯区",
+		"710431": "太平区",
+		"710432": "大里区",
+		"710433": "雾峰区",
+		"710434": "乌日区",
+		"710435": "丰原区",
+		"710436": "后里区",
+		"710437": "石冈区",
+		"710438": "东势区",
+		"710439": "和平区",
+		"710440": "新社区",
+		"710441": "潭子区",
+		"710442": "大雅区",
+		"710443": "神冈区",
+		"710444": "大肚区",
+		"710445": "沙鹿区",
+		"710446": "龙井区",
+		"710447": "梧栖区",
+		"710448": "清水区",
+		"710449": "大甲区",
+		"710450": "外埔区",
+		"710451": "大安区",
+		"710499": "其它区",
+		"710507": "金沙镇",
+		"710508": "金湖镇",
+		"710509": "金宁乡",
+		"710510": "金城镇",
+		"710511": "烈屿乡",
+		"710512": "乌坵乡",
+		"710614": "南投市",
+		"710615": "中寮乡",
+		"710616": "草屯镇",
+		"710617": "国姓乡",
+		"710618": "埔里镇",
+		"710619": "仁爱乡",
+		"710620": "名间乡",
+		"710621": "集集镇",
+		"710622": "水里乡",
+		"710623": "鱼池乡",
+		"710624": "信义乡",
+		"710625": "竹山镇",
+		"710626": "鹿谷乡",
+		"710701": "仁爱区",
+		"710702": "信义区",
+		"710703": "中正区",
+		"710704": "中山区",
+		"710705": "安乐区",
+		"710706": "暖暖区",
+		"710707": "七堵区",
+		"710799": "其它区",
+		"710801": "东区",
+		"710802": "北区",
+		"710803": "香山区",
+		"710899": "其它区",
+		"710901": "东区",
+		"710902": "西区",
+		"710999": "其它区",
+		"711130": "万里区",
+		"711132": "板桥区",
+		"711133": "汐止区",
+		"711134": "深坑区",
+		"711135": "石碇区",
+		"711136": "瑞芳区",
+		"711137": "平溪区",
+		"711138": "双溪区",
+		"711139": "贡寮区",
+		"711140": "新店区",
+		"711141": "坪林区",
+		"711142": "乌来区",
+		"711143": "永和区",
+		"711144": "中和区",
+		"711145": "土城区",
+		"711146": "三峡区",
+		"711147": "树林区",
+		"711148": "莺歌区",
+		"711149": "三重区",
+		"711150": "新庄区",
+		"711151": "泰山区",
+		"711152": "林口区",
+		"711153": "芦洲区",
+		"711154": "五股区",
+		"711155": "八里区",
+		"711156": "淡水区",
+		"711157": "三芝区",
+		"711158": "石门区",
+		"711287": "宜兰市",
+		"711288": "头城镇",
+		"711289": "礁溪乡",
+		"711290": "壮围乡",
+		"711291": "员山乡",
+		"711292": "罗东镇",
+		"711293": "三星乡",
+		"711294": "大同乡",
+		"711295": "五结乡",
+		"711296": "冬山乡",
+		"711297": "苏澳镇",
+		"711298": "南澳乡",
+		"711299": "钓鱼台",
+		"711387": "竹北市",
+		"711388": "湖口乡",
+		"711389": "新丰乡",
+		"711390": "新埔镇",
+		"711391": "关西镇",
+		"711392": "芎林乡",
+		"711393": "宝山乡",
+		"711394": "竹东镇",
+		"711395": "五峰乡",
+		"711396": "横山乡",
+		"711397": "尖石乡",
+		"711398": "北埔乡",
+		"711399": "峨眉乡",
+		"711414": "中坜区",
+		"711415": "平镇区",
+		"711417": "杨梅区",
+		"711418": "新屋区",
+		"711419": "观音区",
+		"711420": "桃园区",
+		"711421": "龟山区",
+		"711422": "八德区",
+		"711423": "大溪区",
+		"711425": "大园区",
+		"711426": "芦竹区",
+		"711487": "中坜市",
+		"711488": "平镇市",
+		"711489": "龙潭乡",
+		"711490": "杨梅市",
+		"711491": "新屋乡",
+		"711492": "观音乡",
+		"711493": "桃园市",
+		"711494": "龟山乡",
+		"711495": "八德市",
+		"711496": "大溪镇",
+		"711497": "复兴乡",
+		"711498": "大园乡",
+		"711499": "芦竹乡",
+		"711520": "头份市",
+		"711582": "竹南镇",
+		"711583": "头份镇",
+		"711584": "三湾乡",
+		"711585": "南庄乡",
+		"711586": "狮潭乡",
+		"711587": "后龙镇",
+		"711588": "通霄镇",
+		"711589": "苑里镇",
+		"711590": "苗栗市",
+		"711591": "造桥乡",
+		"711592": "头屋乡",
+		"711593": "公馆乡",
+		"711594": "大湖乡",
+		"711595": "泰安乡",
+		"711596": "铜锣乡",
+		"711597": "三义乡",
+		"711598": "西湖乡",
+		"711599": "卓兰镇",
+		"711736": "员林市",
+		"711774": "彰化市",
+		"711775": "芬园乡",
+		"711776": "花坛乡",
+		"711777": "秀水乡",
+		"711778": "鹿港镇",
+		"711779": "福兴乡",
+		"711780": "线西乡",
+		"711781": "和美镇",
+		"711782": "伸港乡",
+		"711783": "员林镇",
+		"711784": "社头乡",
+		"711785": "永靖乡",
+		"711786": "埔心乡",
+		"711787": "溪湖镇",
+		"711788": "大村乡",
+		"711789": "埔盐乡",
+		"711790": "田中镇",
+		"711791": "北斗镇",
+		"711792": "田尾乡",
+		"711793": "埤头乡",
+		"711794": "溪州乡",
+		"711795": "竹塘乡",
+		"711796": "二林镇",
+		"711797": "大城乡",
+		"711798": "芳苑乡",
+		"711799": "二水乡",
+		"711982": "番路乡",
+		"711983": "梅山乡",
+		"711984": "竹崎乡",
+		"711985": "阿里山乡",
+		"711986": "中埔乡",
+		"711987": "大埔乡",
+		"711988": "水上乡",
+		"711989": "鹿草乡",
+		"711990": "太保市",
+		"711991": "朴子市",
+		"711992": "东石乡",
+		"711993": "六脚乡",
+		"711994": "新港乡",
+		"711995": "民雄乡",
+		"711996": "大林镇",
+		"711997": "溪口乡",
+		"711998": "义竹乡",
+		"711999": "布袋镇",
+		"712180": "斗南镇",
+		"712181": "大埤乡",
+		"712182": "虎尾镇",
+		"712183": "土库镇",
+		"712184": "褒忠乡",
+		"712185": "东势乡",
+		"712186": "台西乡",
+		"712187": "仑背乡",
+		"712188": "麦寮乡",
+		"712189": "斗六市",
+		"712190": "林内乡",
+		"712191": "古坑乡",
+		"712192": "莿桐乡",
+		"712193": "西螺镇",
+		"712194": "二仑乡",
+		"712195": "北港镇",
+		"712196": "水林乡",
+		"712197": "口湖乡",
+		"712198": "四湖乡",
+		"712199": "元长乡",
+		"712451": "崁顶乡",
+		"712467": "屏东市",
+		"712468": "三地门乡",
+		"712469": "雾台乡",
+		"712470": "玛家乡",
+		"712471": "九如乡",
+		"712472": "里港乡",
+		"712473": "高树乡",
+		"712474": "盐埔乡",
+		"712475": "长治乡",
+		"712476": "麟洛乡",
+		"712477": "竹田乡",
+		"712478": "内埔乡",
+		"712479": "万丹乡",
+		"712480": "潮州镇",
+		"712481": "泰武乡",
+		"712482": "来义乡",
+		"712483": "万峦乡",
+		"712484": "莰顶乡",
+		"712485": "新埤乡",
+		"712486": "南州乡",
+		"712487": "林边乡",
+		"712488": "东港镇",
+		"712489": "琉球乡",
+		"712490": "佳冬乡",
+		"712491": "新园乡",
+		"712492": "枋寮乡",
+		"712493": "枋山乡",
+		"712494": "春日乡",
+		"712495": "狮子乡",
+		"712496": "车城乡",
+		"712497": "牡丹乡",
+		"712498": "恒春镇",
+		"712499": "满州乡",
+		"712584": "台东市",
+		"712585": "绿岛乡",
+		"712586": "兰屿乡",
+		"712587": "延平乡",
+		"712588": "卑南乡",
+		"712589": "鹿野乡",
+		"712590": "关山镇",
+		"712591": "海端乡",
+		"712592": "池上乡",
+		"712593": "东河乡",
+		"712594": "成功镇",
+		"712595": "长滨乡",
+		"712596": "金峰乡",
+		"712597": "大武乡",
+		"712598": "达仁乡",
+		"712599": "太麻里乡",
+		"712686": "花莲市",
+		"712687": "新城乡",
+		"712688": "太鲁阁",
+		"712689": "秀林乡",
+		"712690": "吉安乡",
+		"712691": "寿丰乡",
+		"712692": "凤林镇",
+		"712693": "光复乡",
+		"712694": "丰滨乡",
+		"712695": "瑞穗乡",
+		"712696": "万荣乡",
+		"712697": "玉里镇",
+		"712698": "卓溪乡",
+		"712699": "富里乡",
+		"712794": "马公市",
+		"712795": "西屿乡",
+		"712796": "望安乡",
+		"712797": "七美乡",
+		"712798": "白沙乡",
+		"712799": "湖西乡",
+		"712896": "南竿乡",
+		"712897": "北竿乡",
+		"712898": "东引乡",
+		"712899": "莒光乡",
+		"810101": "中西区",
+		"810102": "湾仔区",
+		"810103": "东区",
+		"810104": "南区",
+		"810201": "九龙城区",
+		"810202": "油尖旺区",
+		"810203": "深水埗区",
+		"810204": "黄大仙区",
+		"810205": "观塘区",
+		"810301": "北区",
+		"810302": "大埔区",
+		"810303": "沙田区",
+		"810304": "西贡区",
+		"810305": "元朗区",
+		"810306": "屯门区",
+		"810307": "荃湾区",
+		"810308": "葵青区",
+		"810309": "离岛区",
+		"820102": "花地玛堂区",
+		"820103": "花王堂区",
+		"820104": "望德堂区",
+		"820105": "大堂区",
+		"820106": "风顺堂区",
+		"820202": "嘉模堂区",
+		"820203": "路氹填海区",
+		"820204": "圣方济各堂区"
+	}
+}

+ 71 - 0
uni_modules/lime-shared/areaData/index.ts

@@ -0,0 +1,71 @@
+// @ts-nocheck
+import _areaList from './city-china.json';
+export const areaList = _areaList
+// #ifndef UNI-APP-X
+type UTSJSONObject = Record<string, string>
+// #endif
+// #ifdef UNI-APP-X
+type Object = UTSJSONObject
+// #endif
+type AreaList = {
+	province_list : Map<string, string>;
+	city_list : Map<string, string>;
+	county_list : Map<string, string>;
+}
+// type CascaderOption = {
+// 	text : string;
+// 	value : string;
+// 	children ?: CascaderOption[];
+// };
+
+const makeOption = (
+	label : string,
+	value : string,
+	children ?: UTSJSONObject[],
+) : UTSJSONObject => ({
+	label,
+	value,
+	children,
+});
+
+
+
+export function useCascaderAreaData() : UTSJSONObject[] {
+	const city = areaList['city_list'] as UTSJSONObject
+	const county = areaList['county_list'] as UTSJSONObject
+	const province = areaList['province_list'] as UTSJSONObject
+	const provinceMap = new Map<string, UTSJSONObject>();
+	Object.keys(province).forEach((code) => {
+		provinceMap.set(code.slice(0, 2), makeOption(`${province[code]}`, code, []));
+	});
+
+	const cityMap = new Map<string, UTSJSONObject>();
+
+	Object.keys(city).forEach((code) => {
+		const option = makeOption(`${city[code]}`, code, []);
+		cityMap.set(code.slice(0, 4), option);
+
+		const _province = provinceMap.get(code.slice(0, 2));
+		if (_province != null) {
+			(_province['children'] as UTSJSONObject[]).push(option)
+		}
+	});
+
+	Object.keys(county).forEach((code) => {
+		const _city = cityMap.get(code.slice(0, 4));
+		if (_city != null) {
+			(_city['children'] as UTSJSONObject[]).push(makeOption(`${county[code]}`, code, null));
+		}
+	});
+	
+	// #ifndef APP-ANDROID || APP-IOS
+	return Array.from(provinceMap.values());
+	// #endif
+	// #ifdef APP-ANDROID || APP-IOS
+	const obj : UTSJSONObject[] = []
+	provinceMap.forEach((value, code) => {
+		obj.push(value)
+	})
+	return obj
+	// #endif
+}

+ 10 - 0
uni_modules/lime-shared/arrayBufferToFile/index.ts

@@ -0,0 +1,10 @@
+// @ts-nocheck
+// #ifndef UNI-APP-X && APP
+// export * from './vue.ts'
+export { arrayBufferToFile } from './vue.ts'
+// #endif
+
+// #ifdef UNI-APP-X && APP
+// export * from './uvue.uts'
+export { arrayBufferToFile } from './uvue.uts'
+// #endif

+ 10 - 0
uni_modules/lime-shared/arrayBufferToFile/uvue.uts

@@ -0,0 +1,10 @@
+// @ts-nocheck
+// import {platform} from '../platform'
+/**
+ * buffer转路径
+ * @param {Object} buffer
+ */
+// @ts-nocheck
+export function arrayBufferToFile(buffer: ArrayBuffer, name?: string, format?:string):Promise<(File|string)> {
+	console.error('[arrayBufferToFile] 当前环境不支持')
+}

+ 63 - 0
uni_modules/lime-shared/arrayBufferToFile/vue.ts

@@ -0,0 +1,63 @@
+// @ts-nocheck
+import {platform} from '../platform'
+/**
+ * buffer转路径
+ * @param {Object} buffer
+ */
+// @ts-nocheck
+export function arrayBufferToFile(buffer: ArrayBuffer | Blob, name?: string, format?:string):Promise<(File|string)> {
+	return new Promise((resolve, reject) => {
+		// #ifdef MP
+		const fs = uni.getFileSystemManager()
+		//自定义文件名
+		if (!name && !format) {
+			reject(new Error('ERROR_NAME_PARSE'))
+		}
+		const fileName = `${name || new Date().getTime()}.${format.replace(/(.+)?\//,'')}`;
+		let pre = platform()
+		const filePath = `${pre.env.USER_DATA_PATH}/${fileName}`
+		fs.writeFile({
+			filePath,
+			data: buffer, 
+			success() {
+				resolve(filePath)
+			},
+			fail(err) {
+				console.error(err)
+				reject(err)
+			}
+		})
+		// #endif
+
+		// #ifdef H5
+		const file = new File([buffer], name, {
+		     type: format,
+		});
+		resolve(file)
+		// #endif
+
+		// #ifdef APP-PLUS
+		const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
+		const base64 = uni.arrayBufferToBase64(buffer)
+		bitmap.loadBase64Data(base64, () => {
+			if (!name && !format) {
+				reject(new Error('ERROR_NAME_PARSE'))
+			}
+			const fileNmae = `${name || new Date().getTime()}.${format.replace(/(.+)?\//,'')}`;
+			const filePath = `_doc/uniapp_temp/${fileNmae}`
+			bitmap.save(filePath, {},
+				() => {
+					bitmap.clear()
+					resolve(filePath)
+				},
+				(error) => {
+					bitmap.clear()
+					reject(error)
+				})
+		}, (error) => {
+			bitmap.clear()
+			reject(error)
+		})
+		// #endif
+	})
+}

+ 13 - 0
uni_modules/lime-shared/base64ToArrayBuffer/index.ts

@@ -0,0 +1,13 @@
+// @ts-nocheck
+// 未完成
+export function base64ToArrayBuffer(base64 : string) {
+	const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
+	if (!format) {
+		new Error('ERROR_BASE64SRC_PARSE')
+	}
+	if(uni.base64ToArrayBuffer) {
+		return uni.base64ToArrayBuffer(bodyData)
+	} else {
+		
+	}
+}

+ 11 - 0
uni_modules/lime-shared/base64ToPath/index.ts

@@ -0,0 +1,11 @@
+// @ts-nocheck
+// #ifndef UNI-APP-X && APP
+// export * from './vue.ts'
+export { base64ToPath } from './vue.ts'
+// #endif
+
+
+// #ifdef UNI-APP-X && APP
+// export * from './uvue.uts'
+export { base64ToPath } from './uvue.uts'
+// #endif

+ 22 - 0
uni_modules/lime-shared/base64ToPath/uvue.uts

@@ -0,0 +1,22 @@
+// @ts-nocheck
+import { processFile, type ProcessFileOptions  } from '@/uni_modules/lime-file-utils'
+
+/**
+ * base64转路径
+ * @param {Object} base64
+ */
+export function base64ToPath(base64: string, filename: string | null = null):Promise<string> {
+	return new Promise((resolve,reject) => {
+		processFile({
+		    type: 'toDataURL',
+		    path: base64,
+		    filename,
+		    success(res: string){
+		       resolve(res)
+		    },
+			fail(err){
+				reject(err)
+			}
+		} as ProcessFileOptions)
+	})
+}

+ 75 - 0
uni_modules/lime-shared/base64ToPath/vue.ts

@@ -0,0 +1,75 @@
+// @ts-nocheck
+import {platform} from '../platform'
+/**
+ * base64转路径
+ * @param {Object} base64
+ */
+export function base64ToPath(base64: string, filename?: string):Promise<string> {
+	const [, format] = /^data:image\/(\w+);base64,/.exec(base64) || [];
+	return new Promise((resolve, reject) => {
+		// #ifdef MP
+		const fs = uni.getFileSystemManager()
+		//自定义文件名
+		if (!filename && !format) {
+			reject(new Error('ERROR_BASE64SRC_PARSE'))
+		}
+		// const time = new Date().getTime();
+		const name = filename || `${new Date().getTime()}.${format}`;
+		let pre = platform()
+		const filePath = `${pre.env.USER_DATA_PATH}/${name}`
+		fs.writeFile({
+			filePath,
+			data: base64.split(',')[1], 
+			encoding: 'base64',
+			success() {
+				resolve(filePath)
+			},
+			fail(err) {
+				console.error(err)
+				reject(err)
+			}
+		})
+		// #endif
+
+		// #ifdef H5
+		// mime类型
+		let mimeString = base64.split(',')[0].split(':')[1].split(';')[0];
+		//base64 解码
+		let byteString = atob(base64.split(',')[1]);
+		//创建缓冲数组
+		let arrayBuffer = new ArrayBuffer(byteString.length);
+		//创建视图
+		let intArray = new Uint8Array(arrayBuffer);
+		for (let i = 0; i < byteString.length; i++) {
+			intArray[i] = byteString.charCodeAt(i);
+		}
+		resolve(URL.createObjectURL(new Blob([intArray], {
+			type: mimeString
+		})))
+		// #endif
+
+		// #ifdef APP-PLUS
+		const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
+		bitmap.loadBase64Data(base64, () => {
+			if (!filename && !format) {
+				reject(new Error('ERROR_BASE64SRC_PARSE'))
+			}
+			// const time = new Date().getTime();
+			const name = filename || `${new Date().getTime()}.${format}`;
+			const filePath = `_doc/uniapp_temp/${name}`
+			bitmap.save(filePath, {},
+				() => {
+					bitmap.clear()
+					resolve(filePath)
+				},
+				(error) => {
+					bitmap.clear()
+					reject(error)
+				})
+		}, (error) => {
+			bitmap.clear()
+			reject(error)
+		})
+		// #endif
+	})
+}

+ 21 - 0
uni_modules/lime-shared/camelCase/index.ts

@@ -0,0 +1,21 @@
+/**
+ * 将字符串转换为 camelCase 或 PascalCase 风格的命名约定
+ * @param str 要转换的字符串
+ * @param isPascalCase 指示是否转换为 PascalCase 的布尔值,默认为 false
+ * @returns 转换后的字符串
+ */
+export function camelCase(str: string, isPascalCase: boolean = false): string {
+    // 将字符串分割成单词数组
+    let words: string[] = str.split(/[\s_-]+/);
+  
+    // 将数组中的每个单词首字母大写(除了第一个单词)
+    let camelCased: string[] = words.map((word, index):string => {
+      if (index == 0 && !isPascalCase) {
+        return word.toLowerCase(); // 第一个单词全小写
+      }
+      return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
+    });
+  
+    // 将数组中的单词拼接成一个字符串
+    return camelCased.join('');
+};

+ 67 - 0
uni_modules/lime-shared/canIUseCanvas2d/index.ts

@@ -0,0 +1,67 @@
+// @ts-nocheck
+
+// #ifndef UNI-APP-X && APP
+
+// #ifdef MP-ALIPAY
+interface My {
+	SDKVersion: string
+}
+declare var my: My
+// #endif
+
+function compareVersion(v1:string, v2:string) {
+  let a1 = v1.split('.');
+  let a2 = v2.split('.');
+  const len = Math.max(a1.length, a2.length);
+
+  while (a1.length < len) {
+    a1.push('0');
+  }
+  while (a2.length < len) {
+    a2.push('0');
+  }
+
+  for (let i = 0; i < len; i++) {
+    const num1 = parseInt(a1[i], 10);
+    const num2 = parseInt(a2[i], 10);
+
+    if (num1 > num2) {
+      return 1;
+    }
+    if (num1 < num2) {
+      return -1;
+    }
+  }
+
+  return 0;
+}
+
+function gte(version: string) {
+	let {SDKVersion} = uni.getSystemInfoSync();
+	// #ifdef MP-ALIPAY
+	SDKVersion = my.SDKVersion
+	// #endif
+	return compareVersion(SDKVersion, version) >= 0;
+}
+// #endif
+
+
+/** 环境是否支持canvas 2d */
+export function canIUseCanvas2d(): boolean {
+	// #ifdef MP-WEIXIN
+	return gte('2.9.0');
+	// #endif
+	// #ifdef MP-ALIPAY
+	return gte('2.7.0');
+	// #endif
+	// #ifdef MP-TOUTIAO
+	return gte('1.78.0');
+	// #endif
+	// #ifdef UNI-APP-X && WEB ||  UNI-APP-X && APP
+	return true;
+	// #endif
+	// #ifndef MP-WEIXIN || MP-ALIPAY || MP-TOUTIAO
+	return false
+	// #endif
+	
+}

+ 111 - 0
uni_modules/lime-shared/capitalizedAmount/index.ts

@@ -0,0 +1,111 @@
+// @ts-nocheck
+import { isString } from "../isString";
+import { isNumber } from "../isNumber";
+/**
+ * 将金额转换为中文大写形式
+ * @param {number | string} amount - 需要转换的金额,可以是数字或字符串
+ * @returns {string} 转换后的中文大写金额
+ */
+export function capitalizedAmount(amount : number) : string
+export function capitalizedAmount(amount : string) : string
+export function capitalizedAmount(amount : any | null) : string {
+	try {
+		let _amountStr :string;
+		let _amountNum :number = 0;
+		// 如果输入是字符串,先将其转换为数字,并去除逗号
+		if (typeof amount == 'string') {
+			 _amountNum = parseFloat((amount as string).replace(/,/g, ''));
+		}
+		if(isNumber(amount)) {
+			_amountNum = amount as number
+		}
+		// 判断输入是否为有效的金额  || isNaN(amount)
+		if (amount == null) throw new Error('不是有效的金额!');
+
+		let result = '';
+
+		// 处理负数情况
+		if (_amountNum < 0) {
+			result = '欠';
+			_amountNum = Math.abs(_amountNum);
+		}
+
+		// 金额不能超过千亿以上
+		if (_amountNum >= 10e11) throw new Error('计算金额过大!');
+
+		// 保留两位小数并转换为字符串
+		_amountStr = _amountNum.toFixed(2);
+
+		// 定义数字、单位和小数单位的映射
+		const digits = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖'];
+		const units = ['', '拾', '佰', '仟'];
+		const bigUnits = ['', '万', '亿'];
+		const decimalUnits = ['角', '分'];
+
+		// 分离整数部分和小数部分
+		const amountArray = _amountStr.split('.');
+		let integerPart = amountArray[0]; // string| number[]
+		const decimalPart = amountArray[1];
+
+		// 处理整数部分
+		if (integerPart != '0') {
+			let _integerPart = integerPart.split('').map((item):number => parseInt(item));
+
+			// 将整数部分按四位一级进行分组
+			const levels = _integerPart.reverse().reduce((prev:string[][], item, index):string[][] => {
+				// const level = prev?.[0]?.length < 4 ? prev[0] : [];
+				const level = prev.length > 0 && prev[0].length < 4 ? prev[0]: []
+
+				const value = item == 0 ? digits[item] : digits[item] + units[index % 4];
+
+				level.unshift(value);
+
+				if (level.length == 1) {
+					prev.unshift(level);
+				} else {
+					prev[0] = level;
+				}
+
+				return prev;
+			}, [] as string[][]);
+			// 将分组后的整数部分转换为中文大写形式
+			result += levels.reduce((prev, item, index):string => {
+				let _level = bigUnits[levels.length - index - 1];
+				let _item = item.join('').replace(/(零)\1+/g, '$1');
+
+				if (_item == '零') {
+					_level = '';
+					_item = '';
+				} else if (_item.endsWith('零')) {
+					_item = _item.slice(0, _item.length - 1);
+				}
+
+				return prev + _item + _level;
+			}, '');
+		} else {
+			result += '零';
+		}
+
+		// 添加元
+		result += '元';
+
+		// 处理小数部分
+		if (decimalPart != '00') {
+			if (result == '零元') result = '';
+
+			for (let i = 0; i < decimalPart.length; i++) {
+				const digit = parseInt(decimalPart.charAt(i));
+
+				if (digit != 0) {
+					result += digits[digit] + decimalUnits[i];
+				}
+			}
+		} else {
+			result += '整';
+		}
+
+		return result;
+	} catch (error : Error) {
+		return error.message;
+	}
+};

+ 89 - 0
uni_modules/lime-shared/changelog.md

@@ -0,0 +1,89 @@
+## 0.4.1(2025-06-13)
+- fix:测试hbx4.71更新
+## 0.4.0(2025-06-04)
+- fix:测试hbx4.71更新
+## 0.3.9(2025-06-04)
+ - fix: 因hbx4.71更新导致mac用户下载的文件被重命名,故退回4.66
+## 0.3.8(2025-06-03)
+- fix: 修复`while`在vue2报错的问题
+## 0.3.7(2025-05-21)
+- fix: 修复`merge`在vue2报错的问题
+## 0.3.6(2025-05-17)
+- fix: 修复`raf`导错目录的问题
+## 0.3.5(2025-05-16)
+- feat: 增加`isIP`
+- feat: 增加`merge`
+- feat: 增加`isByteLength`
+- feat: 增加`isRegExp`
+## 0.3.4(2025-04-27)
+- fix: 修复exif缺少isBase64的问题
+## 0.3.3(2025-04-14)
+- fix: 修复4.61上的类型问题
+## 0.3.2(2025-04-14)
+- fix: 修复4.61上的类型问题
+## 0.3.1(2025-03-28)
+- fix: 修复getRect在nvue上的问题
+## 0.3.0(2025-02-27)
+- fix: 修复部分函数无法在uniappx上运行的问题
+## 0.2.9(2025-02-19)
+- chore: 更新文档
+## 0.2.8(2025-02-11)
+- chore: 更新文档
+## 0.2.7(2025-01-17)
+- fix: 针对canvas 平台判断优化
+## 0.2.6(2025-01-09)
+- feat: 增加`areaData`中国省市区数据
+## 0.2.5(2025-01-07)
+- fix: animation在app上类型问题
+## 0.2.4(2025-01-04)
+- feat: getRect类型问题
+## 0.2.3(2025-01-01)
+- chore: unitConvert使用uni.rpx2px
+## 0.2.2(2024-12-11)
+- chore: 动画使用`requestAnimationFrame`
+## 0.2.1(2024-11-20)
+- feat: 增加`characterLimit`
+## 0.2.0(2024-11-14)
+- fix: vue2的类型问题
+## 0.1.9(2024-11-14)
+- feat: 增加`shuffle`
+## 0.1.8(2024-10-08)
+- fix: vue2 条件编译 // #ifdef APP-IOS || APP-ANDROID 会生效
+## 0.1.7(2024-09-23)
+- fix: raf 类型跟随版本变更
+## 0.1.6(2024-07-24)
+- fix: vue2 app ts需要明确的后缀,所有补全
+- chore: 减少依赖
+## 0.1.5(2024-07-21)
+- feat: 删除 Hooks
+- feat: 兼容uniappx
+## 0.1.4(2023-09-05)
+- feat: 增加 Hooks `useIntersectionObserver`
+- feat: 增加 `floatAdd`
+- feat: 因为本人插件兼容 vue2 需要使用 `composition-api`,故增加vue文件代码插件的条件编译
+## 0.1.3(2023-08-13)
+- feat: 增加 `camelCase`
+## 0.1.2(2023-07-17)
+- feat: 增加 `getClassStr`
+## 0.1.1(2023-07-06)
+- feat: 增加 `isNumeric`, 区别于 `isNumber`
+## 0.1.0(2023-06-30)
+- fix: `clamp`忘记导出了
+## 0.0.9(2023-06-27)
+- feat: 增加`arrayBufferToFile`
+## 0.0.8(2023-06-19)
+- feat: 增加`createAnimation`、`clamp`
+## 0.0.7(2023-06-08)
+- chore: 更新注释
+## 0.0.6(2023-06-08)
+- chore: 增加`createImage`为`lime-watermark`和`lime-qrcode`提供依赖
+## 0.0.5(2023-06-03)
+- chore: 更新注释
+## 0.0.4(2023-05-22)
+- feat: 增加`range`,`exif`,`selectComponent`
+## 0.0.3(2023-05-08)
+- feat: 增加`fillZero`,`debounce`,`throttle`,`random`
+## 0.0.2(2023-05-05)
+- chore: 更新文档
+## 0.0.1(2023-05-05)
+- 无

+ 63 - 0
uni_modules/lime-shared/characterLimit/index.ts

@@ -0,0 +1,63 @@
+// @ts-nocheck
+/**
+ * 计算字符串字符的长度并可以截取字符串。
+ * @param char 传入字符串(maxcharacter条件下,一个汉字表示两个字符)
+ * @param max 规定最大字符串长度
+ * @returns 当没有传入maxCharacter/maxLength 时返回字符串字符长度,当传入maxCharacter/maxLength时返回截取之后的字符串和长度。
+ */
+export type CharacterLengthResult = {
+	length : number;
+	characters : string;
+}
+// #ifdef APP-ANDROID
+type ChartType = any
+// #endif
+// #ifndef APP-ANDROID
+type ChartType = string | number
+// #endif
+
+export function characterLimit(type : string, char : ChartType, max : number) : CharacterLengthResult {
+	const str = `${char}`;
+
+	if (str.length == 0) {
+		return {
+			length: 0,
+			characters: '',
+		} as CharacterLengthResult
+	}
+
+	if (type == 'maxcharacter') {
+		let len = 0;
+		for (let i = 0; i < str.length; i += 1) {
+			let currentStringLength : number// = 0;
+			const code = str.charCodeAt(i)!
+			if (code > 127 || code == 94) {
+				currentStringLength = 2;
+			} else {
+				currentStringLength = 1;
+			}
+			if (len + currentStringLength > max) {
+				return {
+					length: len,
+					characters: str.slice(0, i),
+				} as CharacterLengthResult
+			}
+			len += currentStringLength;
+		}
+		return {
+			length: len,
+			characters: str,
+		} as CharacterLengthResult
+	} else if (type == 'maxlength') {
+		const length = str.length > max ? max : str.length;
+		return {
+			length: length,
+			characters: str.slice(0, length),
+		} as CharacterLengthResult
+	}
+
+	return {
+		length: str.length,
+		characters: str,
+	} as CharacterLengthResult
+};

+ 16 - 0
uni_modules/lime-shared/clamp/index.ts

@@ -0,0 +1,16 @@
+// @ts-nocheck
+/**
+ * 将一个值限制在指定的范围内
+ * @param val 要限制的值
+ * @param min 最小值
+ * @param max 最大值
+ * @returns 限制后的值
+ */
+export function clamp(val: number, min: number, max: number): number {
+  return Math.max(min, Math.min(max, val));
+}
+
+
+// console.log(clamp(5 ,0, 10)); // 输出: 5(在范围内,不做更改)
+// console.log(clamp(-5 ,0, 10)); // 输出: 0(小于最小值,被限制为最小值)
+// console.log(clamp(15 ,0, 10)); // 输出: 10(大于最大值,被限制为最大值)

+ 12 - 0
uni_modules/lime-shared/cloneDeep/index.ts

@@ -0,0 +1,12 @@
+// @ts-nocheck
+
+// #ifdef APP-ANDROID
+// export * from './uvue.uts'
+export { cloneDeep } from  './uvue.uts'
+// #endif
+
+
+// #ifndef APP-ANDROID
+// export * from './vue.ts'
+export { cloneDeep } from  './vue.ts'
+// #endif

+ 39 - 0
uni_modules/lime-shared/cloneDeep/uvue.uts

@@ -0,0 +1,39 @@
+// @ts-nocheck
+/**
+ * 深度克隆一个对象或数组
+ * @param obj 要克隆的对象或数组
+ * @returns 克隆后的对象或数组
+ */
+export function cloneDeep<T>(obj : any) : T {
+	if (obj instanceof Set) {
+		const set = new Set<any>();
+		obj.forEach((item : any) => {
+			set.add(item)
+		})
+		return set as T;
+	}
+	if (obj instanceof Map) {
+		const map = new Map<any, any>();
+		obj.forEach((value : any, key : any) => {
+			map.set(key, value)
+		})
+		return map as T;
+	}
+
+	if (obj instanceof RegExp) {
+		return new RegExp(obj) as T;
+	}
+
+	if (Array.isArray(obj)) {
+		return (obj as any[]).map((item : any):any => item) as T;
+	}
+
+	if (obj instanceof Date) {
+		return new Date(obj.getTime()) as T;
+	}
+
+	if (typeof obj == 'object') {
+		return UTSJSONObject.assign<T>({}, toRaw(obj))! 
+	}
+	return obj as T
+}

+ 103 - 0
uni_modules/lime-shared/cloneDeep/vue.ts

@@ -0,0 +1,103 @@
+// @ts-nocheck
+/**
+ * 深度克隆一个对象或数组
+ * @param obj 要克隆的对象或数组
+ * @returns 克隆后的对象或数组
+ */
+export function cloneDeep<T>(obj: any): T {
+  // 如果传入的对象为空,返回空
+  if (obj === null) {
+    return null as unknown as T;
+  }
+
+  // 如果传入的对象是 Set 类型,则将其转换为数组,并通过新的 Set 构造函数创建一个新的 Set 对象
+  if (obj instanceof Set) {
+    return new Set([...obj]) as unknown as T;
+  }
+
+  // 如果传入的对象是 Map 类型,则将其转换为数组,并通过新的 Map 构造函数创建一个新的 Map 对象
+  if (obj instanceof Map) {
+    return new Map([...obj]) as unknown as T;
+  }
+
+  // 如果传入的对象是 WeakMap 类型,则直接用传入的 WeakMap 对象进行赋值
+  if (obj instanceof WeakMap) {
+    let weakMap = new WeakMap();
+    weakMap = obj;
+    return weakMap as unknown as T;
+  }
+
+  // 如果传入的对象是 WeakSet 类型,则直接用传入的 WeakSet 对象进行赋值
+  if (obj instanceof WeakSet) {
+    let weakSet = new WeakSet();
+    weakSet = obj;
+    return weakSet as unknown as T;
+  }
+
+  // 如果传入的对象是 RegExp 类型,则通过新的 RegExp 构造函数创建一个新的 RegExp 对象
+  if (obj instanceof RegExp) {
+    return new RegExp(obj) as unknown as T;
+  }
+
+  // 如果传入的对象是 undefined 类型,则返回 undefined
+  if (typeof obj === 'undefined') {
+    return undefined as unknown as T;
+  }
+
+  // 如果传入的对象是数组,则递归调用 cloneDeep 函数对数组中的每个元素进行克隆
+  if (Array.isArray(obj)) {
+    return obj.map(cloneDeep) as unknown as T;
+  }
+
+  // 如果传入的对象是 Date 类型,则通过新的 Date 构造函数创建一个新的 Date 对象
+  if (obj instanceof Date) {
+    return new Date(obj.getTime()) as unknown as T;
+  }
+
+  // 如果传入的对象是普通对象,则使用递归调用 cloneDeep 函数对对象的每个属性进行克隆
+  if (typeof obj === 'object') {
+    const newObj: any = {};
+    for (const [key, value] of Object.entries(obj)) {
+      newObj[key] = cloneDeep(value);
+    }
+    const symbolKeys = Object.getOwnPropertySymbols(obj);
+    for (const key of symbolKeys) {
+      newObj[key] = cloneDeep(obj[key]);
+    }
+    return newObj;
+  }
+
+  // 如果传入的对象是基本数据类型(如字符串、数字等),则直接返回
+  return obj;
+}
+
+// 示例使用
+
+// // 克隆一个对象
+// const obj = { name: 'John', age: 30 };
+// const clonedObj = cloneDeep(obj);
+
+// console.log(clonedObj); // 输出: { name: 'John', age: 30 }
+// console.log(clonedObj === obj); // 输出: false (副本与原对象是独立的)
+
+// // 克隆一个数组
+// const arr = [1, 2, 3];
+// const clonedArr = cloneDeep(arr);
+
+// console.log(clonedArr); // 输出: [1, 2, 3]
+// console.log(clonedArr === arr); // 输出: false (副本与原数组是独立的)
+
+// // 克隆一个包含嵌套对象的对象
+// const person = {
+//   name: 'Alice',
+//   age: 25,
+//   address: {
+//     city: 'New York',
+//     country: 'USA',
+//   },
+// };
+// const clonedPerson = cloneDeep(person);
+
+// console.log(clonedPerson); // 输出: { name: 'Alice', age: 25, address: { city: 'New York', country: 'USA' } }
+// console.log(clonedPerson === person); // 输出: false (副本与原对象是独立的)
+// console.log(clonedPerson.address === person.address); // 输出: false (嵌套对象的副本也是独立的)

+ 22 - 0
uni_modules/lime-shared/closest/index.ts

@@ -0,0 +1,22 @@
+// @ts-nocheck
+
+/**
+ * 在给定数组中找到最接近目标数字的元素。
+ * @param arr 要搜索的数字数组。
+ * @param target 目标数字。
+ * @returns 最接近目标数字的数组元素。
+ */
+export function closest(arr: number[], target: number):number {
+  return arr.reduce((pre: number, cur: number):number =>
+    Math.abs(pre - target) < Math.abs(cur - target) ? pre : cur
+  );
+}
+
+// 示例
+// // 定义一个数字数组
+// const numbers = [1, 3, 5, 7, 9];
+
+// // 在数组中找到最接近目标数字 6 的元素
+// const closestNumber = closest(numbers, 6);
+
+// console.log(closestNumber); // 输出结果: 5

+ 407 - 0
uni_modules/lime-shared/components/lime-shared/lime-shared.vue

@@ -0,0 +1,407 @@
+<template>
+	<view id="shared" style="height: 500px; width: 300px; background-color: aqua;">
+		
+	</view>
+</template>
+
+<script lang="ts">
+	// #ifdef WEB
+	import validator from 'validator'
+	// #endif
+	import { getRect, getAllRect } from '@/uni_modules/lime-shared/getRect'
+	
+	import { camelCase } from '@/uni_modules/lime-shared/camelCase'
+	import { canIUseCanvas2d } from '@/uni_modules/lime-shared/canIUseCanvas2d'
+	import { clamp } from '@/uni_modules/lime-shared/clamp'
+	import { cloneDeep } from '@/uni_modules/lime-shared/cloneDeep'
+	import { closest } from '@/uni_modules/lime-shared/closest'
+	import { debounce } from '@/uni_modules/lime-shared/debounce'
+	import { fillZero } from '@/uni_modules/lime-shared/fillZero'
+	import { floatAdd } from '@/uni_modules/lime-shared/floatAdd'
+	import { floatMul } from '@/uni_modules/lime-shared/floatMul'
+	import { floatDiv } from '@/uni_modules/lime-shared/floatDiv'
+	import { floatSub } from '@/uni_modules/lime-shared/floatSub'
+	import { getClassStr } from '@/uni_modules/lime-shared/getClassStr'
+	import { getCurrentPage } from '@/uni_modules/lime-shared/getCurrentPage'
+	import { getStyleStr } from '@/uni_modules/lime-shared/getStyleStr'
+	import { hasOwn } from '@/uni_modules/lime-shared/hasOwn'
+	import { isBase64 } from '@/uni_modules/lime-shared/isBase64'
+	import { isBrowser } from '@/uni_modules/lime-shared/isBrowser'
+	import { isDef } from '@/uni_modules/lime-shared/isDef'
+	import { isEmpty } from '@/uni_modules/lime-shared/isEmpty'
+	import { isFunction } from '@/uni_modules/lime-shared/isFunction'
+	import { isNumber } from '@/uni_modules/lime-shared/isNumber'
+	import { isNumeric } from '@/uni_modules/lime-shared/isNumeric'
+	import { isObject } from '@/uni_modules/lime-shared/isObject'
+	import { isPromise } from '@/uni_modules/lime-shared/isPromise'
+	import { isString } from '@/uni_modules/lime-shared/isString'
+	import { kebabCase } from '@/uni_modules/lime-shared/kebabCase'
+	import { raf, doubleRaf } from '@/uni_modules/lime-shared/raf'
+	import { random } from '@/uni_modules/lime-shared/random'
+	import { range } from '@/uni_modules/lime-shared/range'
+	import { sleep } from '@/uni_modules/lime-shared/sleep'
+	import { throttle } from '@/uni_modules/lime-shared/throttle'
+	import { toArray } from '@/uni_modules/lime-shared/toArray'
+	import { toBoolean } from '@/uni_modules/lime-shared/toBoolean'
+	import { toNumber } from '@/uni_modules/lime-shared/toNumber'
+	import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
+	import { getCurrentInstance } from '@/uni_modules/lime-shared/vue'
+	import { capitalizedAmount } from '@/uni_modules/lime-shared/capitalizedAmount'
+	
+	import { obj2url } from '@/uni_modules/lime-shared/obj2url'
+	import { isURL, type IsURLOptions } from '@/uni_modules/lime-shared/isURL'
+	import { isIP } from '@/uni_modules/lime-shared/isIP'
+	import { isDate, type IsDateOptions } from '@/uni_modules/lime-shared/isDate'
+	import { isEmail } from '@/uni_modules/lime-shared/isEmail'
+	import { isRegExp } from '@/uni_modules/lime-shared/isRegExp'
+	import { isValidDomain, type IsValidDomainOptions } from '@/uni_modules/lime-shared/isValidDomain'
+	import { merge } from '@/uni_modules/lime-shared/merge'
+	import { isByteLength, type IsByteLengthOptions } from '@/uni_modules/lime-shared/isByteLength'
+	
+	// #ifdef VUE2
+	type UTSJSONObject = any
+	// #endif
+	
+	const context = getCurrentInstance()
+	// getRect('#shared', context!).then(res =>{
+	// 	console.log('res', res.bottom)
+	// })
+	// getAllRect('#shared', context).then(res =>{
+	// 	console.log('res', res)
+	// })
+	
+	
+	// console.log('camelCase::', camelCase("hello world"));
+	// console.log('camelCase::', camelCase("my_name_is_john", true));
+	// console.log('canIUseCanvas2d::', canIUseCanvas2d());
+	// console.log('clamp::', clamp(5 ,0, 10));
+	// console.log('cloneDeep::', cloneDeep<UTSJSONObject>({a:5}));
+	// console.log('closest::', closest([1, 3, 5, 7, 9], 6));
+	
+	
+	
+	
+	// const saveData = (data: any) => {
+	// 	// 模拟保存数据的操作
+	// 	console.log(`Saving data: ${data}`);
+	// }
+	
+	// const debouncedSaveData = debounce(saveData, 500);
+	// debouncedSaveData('Data 1'); 
+	// debouncedSaveData('Data 2'); 
+	
+	// console.log('fillZero', fillZero(1))
+	// console.log('floatAdd', floatAdd(0.1, 0.2), floatAdd(1.05, 0.05), floatAdd(0.1, 0.7), floatAdd(0.0001, 0.0002), floatAdd(123.456 , 789.012))
+	// console.log('floatMul', floatMul(0.1, 0.02), floatMul(1.0255, 100))
+	// console.log('floatDiv', floatDiv(10.44, 100), floatDiv(1.0255, 100), floatDiv(5.419909340994699, 0.2))
+	// console.log('floatSub', floatSub(0.4, 0.1), floatSub(1.0255, 100))
+	// const now = () : number => System.nanoTime() / 1_000_000.0
+	// console.log('capitalizedAmount', capitalizedAmount(0.4))
+	// console.log('capitalizedAmount', capitalizedAmount(100))
+	// console.log('capitalizedAmount', capitalizedAmount(100000000))
+	// console.log('capitalizedAmount', capitalizedAmount('2023.04'))
+	// console.log('capitalizedAmount', capitalizedAmount(-1024))
+	// console.log('now', now(), Date.now())
+	// console.log('getClassStr', getClassStr({hover: true}))
+	// console.log('getStyleStr', getStyleStr({ color: 'red', fontSize: '16px', backgroundColor: '', border: null }))
+	// console.log('hasOwn', hasOwn({a: true}, 'key'))
+	// console.log('isBase64::', isBase64("SGVsbG8sIFdvcmxkIQ=="));
+	// console.log('isBrowser::', isBrowser);
+	// console.log('isDef::', isDef('6'));
+	// console.log('isEmpty::', isEmpty({a: true}));
+	
+	// const b = () =>{}
+	// console.log('isFunction::', isFunction(b));
+	// console.log('isNumber::', isNumber('6'));
+	// console.log('isNumeric::', isNumeric('6'));
+	// console.log('isObject::', isObject({}));
+	
+	// const promise = ():Promise<boolean> => {
+	// 	return new Promise((resolve) => {
+	// 		resolve(true)
+	// 	})
+	// }
+	// const a = promise()
+	// console.log('isPromise::', isPromise(a));
+	// console.log('isString::', isString('null'));
+	// console.log('kebabCase::', kebabCase('my love'));
+	// console.log('raf::', raf(()=>{
+	// 	console.log('raf:::1')
+	// }));
+	// console.log('doubleRaf::', doubleRaf(()=>{
+	// 	console.log('doubleRaf:::1')
+	// }));
+	// console.log('random', random(0, 10))
+	// console.log('random', random(0, 1, 2))
+	// console.log('range', range(0, 10, 2))
+	// console.log('sleep', sleep(300).then(res => {
+	// 	console.log('log')
+	// }))
+	
+	// const handleScroll = (a: string) => {
+	//   console.log("Scroll event handled!", a);
+	// }
+	
+	// // // 使用节流函数对 handleScroll 进行节流,间隔时间为 500 毫秒
+	// const throttledScroll = throttle(handleScroll, 500);
+	// throttledScroll('5');
+	// const page = getCurrentPage()
+	// console.log('getCurrentPage::', page)
+	
+	// console.log('toArray', toArray<number>(5))
+	// console.log('toBoolean', toBoolean(5))
+	// console.log('toNumber', toNumber('5'))
+	// console.log('unitConvert', unitConvert('5'))
+	
+	// uni.getImageInfo({
+	// 	src: '/static/logo.png',
+	// 	success(res) {
+	// 		console.log('res', res)
+	// 	}
+	// })
+	
+	// --------------------------
+	// IPv4 验证示例
+	// --------------------------
+	
+	// 标准IPv4格式
+	// console.log(isIP('192.168.1.1', 4));             // true
+	// console.log(isIP('255.255.255.255', { version: 4 })); // true
+	
+	// // 边界值验证
+	// console.log(isIP('0.0.0.0', 4));                 // true
+	// console.log(isIP('223.255.255.255', '4'));       // true
+	
+	// // 非法IPv4案例
+	// console.log(isIP('256.400.999.1', 4));           // false(数值超限)
+	// console.log(isIP('192.168.01', 4));              // false(段数不足)
+	
+	// // --------------------------
+	// // IPv6 验证示例
+	// // --------------------------
+	
+	// // 标准IPv6格式
+	// console.log(isIP('2001:0db8:85a3:0000:0000:8a2e:0370:7334', 6)); // true
+	// console.log(isIP('fe80::1%eth0', { version: 6 }));               // true(带区域标识)
+	
+	// // 压缩格式验证
+	// console.log(isIP('2001:db8::1', '6'));           // true(双冒号压缩)
+	// console.log(isIP('::1', 6));                     // true(本地环回简写)
+	
+	// // IPv4混合格式
+	// console.log(isIP('::ffff:192.168.1.1', 6));     // true(IPv4映射地址)
+	
+	// // 非法IPv6案例
+	// console.log(isIP('2001::gggg::1', 6));           // false(非法字符)
+	// console.log(isIP('fe80::1%', 6));                // false(空区域标识)
+	
+	// // --------------------------
+	// // 自动版本检测
+	// // --------------------------
+	
+	// // 有效地址检测
+	// console.log(isIP('172.16.254.1'));               // true(自动识别IPv4)
+	// console.log(isIP('2001:db8:3333:4444:5555:6666:7777:8888')); // true(自动识别IPv6)
+	
+	// // 无效地址检测
+	// console.log(isIP('192.168.1.256'));              // false(无效IPv4)
+	// console.log(isIP('2001::gggg::1'));              // false(无效IPv6)
+	
+	// // --------------------------
+	// // 特殊场景
+	// // --------------------------
+	
+	// // 带前后空格处理
+	// console.log(isIP(' 203.0.113.50 ', 4));          // true(自动trim)
+	// console.log(isIP(' fe80::1%1 ', 6));             // true(自动trim)
+	
+	// // 非法版本指定
+	// console.log(isIP('192.168.1.1', 5));             // false(不存在IPv5)
+	// console.log(isIP('2001:db8::1', 'ipv6'));        // false(版本参数格式错误)
+	
+	// // --------------------------
+	// // 边界案例
+	// // --------------------------
+	
+	// // 最小/最大有效值
+	// console.log(isIP('0.0.0.0', 4));                 // true
+	// console.log(isIP('255.255.255.255', 4));         // true
+	// console.log(isIP('0000:0000:0000:0000:0000:0000:0000:0000', 6)); // true
+	
+	// // 超长地址验证
+	// console.log(isIP('192.168.1.1.1', 4));           // false(IPv4段数过多)
+	// console.log(isIP('2001:db8:1:2:3:4:5:6:7', 6)); // false(IPv6段数过多)
+	
+	// const original = { color: 'red' };
+	// const merged = merge({ ...original }, { color: 'blue', size: 'M' });
+	
+	// console.log('original', original);    // 输出: { color: 'red' } (保持不变)
+	// console.log('merged', merged);      // 输出: { color: 'red', size: 'M' }
+	
+	
+	type ColorType = {
+		color?: string,
+		size?: string,
+	}
+	
+	const merged2 = merge({ color: 'red' }, { size: 'M' } as ColorType);
+	console.log('merged2:::', merged2)
+	
+	// // 使用配置对象参数
+	// console.log(isByteLength('hello', { min: 3, max: 7 } as ByteLengthOptions)); // true (5字节)
+	// console.log(isByteLength('hello', { min: 6 } as ByteLengthOptions));       // false (5 < 6)
+	// console.log(isByteLength('hello', { max: 4 } as ByteLengthOptions));       // false (5 > 4)
+	
+	// // 使用独立参数(旧式调用)
+	// console.log(isByteLength('hello', 3, 7));            // true
+	// console.log(isByteLength('hello', 6));                // false
+	// console.log(isByteLength('hello', null, 4));     // false
+	
+	// =====================
+	// 多字节字符处理示例
+	// =====================
+	
+	// 中文字符(UTF-8 每个汉字3字节)
+	// console.log(isByteLength('中国', { min: 6 }));         // true (2字 × 3字节 = 6)
+	// console.log(isByteLength('中国', { max: 5 }));         // false (6 > 5)
+	
+	// // 表情符号(多数占用4字节)
+	// console.log(isByteLength('🌟', { min: 4, max: 4 }));  // true
+	// console.log(isByteLength('👨👩👧👦', { max: 15 })); // false (家庭表情占25字节)
+	
+	// // 混合字符集
+	// console.log(isByteLength('aé🌟', { min: 7 }));        // true 
+	
+	// // URL编码字符
+	// console.log(isByteLength('%20', { min: 3 }));         // true(实际字节长度3)
+	// console.log(isByteLength('%E2%82%AC', { max: 3 }));  // false(欧元符号编码为3字节)
+	
+	// // 构造函数创建的正则表达式
+	// console.log(isRegExp(new RegExp('hello')));      // true
+	// console.log(isRegExp(new RegExp('\\d+', 'gi'))); // true
+	
+	// // 字面量正则表达式
+	// console.log(isRegExp(/abc/));                    // true
+	// console.log(isRegExp(/^[0-9]+$/gi));             // true
+	
+	// // 字符串(含正则格式字符串)
+	// console.log(isRegExp('/abc/'));                  // false
+	// console.log(isRegExp('new RegExp("abc")'));      // false
+	
+	// console.log(isEmail('"John"@example.com')) // false(实际有效)
+	// console.log(isEmail('中国@例子.中国'))       // false(实际有效)
+	
+	// // 简单键值对
+	// console.log(obj2url({ name: '张三', age: 25 }));
+	// // "name=%E5%BC%A0%E4%B8%89&age=25"
+	// // 包含布尔值
+	// console.log(obj2url({ active: true, admin: false }));
+	// // "active=true&admin=false"
+	
+	// // 数字处理
+	// console.log(obj2url({ page: 1, limit: 10 }));
+	// // "page=1&limit=10"
+
+	// 基础验证
+	// console.log("example.com =>", isValidDomain("example.com")); // true
+	// console.log("sub.example.co.uk =>", isValidDomain("sub.example.co.uk")); // true
+	
+	// // 缺少TLD的情况
+	// console.log("localhost =>", isValidDomain("localhost")); // false
+	// console.log("localhost (不要求TLD) =>", isValidDomain("localhost", { requireTld: false } as DomainOptions)); // true
+	
+	// // 带结尾点号的情况
+	// console.log("example.com. =>", isValidDomain("example.com.")); // false 
+	// console.log("example.com. (允许结尾点号) =>", isValidDomain("example.com.", { allowTrailingDot: true }  as DomainOptions)); // true
+	
+	// // 带下划线的情况
+	// console.log("my_site.com =>", isValidDomain("my_site.com")); // false
+	// console.log("my_site.com (允许下划线) =>", isValidDomain("my_site.com", { allowUnderscore: true } as DomainOptions)); // true
+	
+	// // 非法字符测试
+	// console.log("含有空格的域名 =>", isValidDomain("exa mple.com")); // false
+	// console.log("含有!的域名 =>", isValidDomain("exa!mple.com")); // false
+	
+	// // 长度测试
+	// const longPart = "a".repeat(64);
+	// console.log(`超长部分 (${longPart.length}字符) =>`, isValidDomain(`${longPart}.com`)); // false
+
+	// // 连字符测试
+	// console.log("以连字符开头 =>", isValidDomain("-example.com")); // false
+	// console.log("以连字符结尾 =>", isValidDomain("example-.com")); // false
+	
+	// // 国际化域名测试
+	// console.log("中文域名 =>", isValidDomain("中国.中国")); // true
+	// console.log("日文域名 =>", isValidDomain("ドメイン.テスト")); // true
+	
+	// // 基础格式验证
+	// console.log("1. 标准日期格式验证:");
+	// console.log("2023/12/31 =>", isDate("2023/12/31")); // true
+	// console.log("1999-01-01 =>", isDate("1999-01-01")); // true
+	// console.log("02.28.2023 =>", isDate("02.28.2023", { delimiters: ['.'], format: 'MM.DD.YYYY' } as DateOptions)); // true (自定义分隔符)
+	
+	// // 严格模式验证
+	// console.log("2. 严格模式验证:");
+	// console.log("严格匹配格式:", isDate("2023/02/28", { strictMode: true, format: "YYYY/MM/DD" }as DateOptions)); // true
+	// console.log("长度不符:", isDate("2023/2/28", { strictMode: true, format: "YYYY/MM/DD" }as DateOptions)); // false
+	// console.log("错误分隔符:", isDate("2023-02-28", { strictMode: true, format: "YYYY/MM/DD" }as DateOptions)); // false
+	
+	// // 两位年份处理
+	// console.log("3. 两位年份验证:");
+	// console.log("23 -> 2023:", isDate("23/12/31", { format: "YY/MM/DD" } as DateOptions)); // true → 2023-12-31
+	// console.log("87 -> 1987:", isDate("87-01-01", { format: "YY-MM-DD" } as DateOptions)); // true → 1987-01-01
+	// console.log("负数年份:", isDate("-100/12/31", { format: "YYYY/MM/DD" } as DateOptions)); // false
+	
+	// // 日期有效性验证
+	// console.log("4. 无效日期检测:");
+	// console.log("闰年2020-02-29:", isDate("2020/02/29")); // true
+	// console.log("非闰年2023-02-29:", isDate("2023/02/29")); // false
+	// console.log("月份溢出:", isDate("2023/13/01")); // false
+	// console.log("日期溢出:", isDate("2023/12/32")); // false
+	
+	// // Date对象验证
+	// console.log("5. Date对象验证:");
+	// console.log("有效Date对象:", isDate(new Date())); // true
+	// console.log("无效Date对象:", isDate(new Date("invalid")), new Date("invalid")); // false
+	// console.log("严格模式Date对象:", isDate(new Date(), { strictMode: true } as DateOptions)); // false
+	
+	// // 自定义格式验证
+	// console.log("6. 自定义格式测试:");
+	// console.log("MM-DD-YYYY:", isDate("12-31-2023", { format: "MM-DD-YYYY" } as DateOptions)); // true
+	// console.log("DD.MM.YY:", isDate("31.12.23", { format: "DD.MM.YY", delimiters: ['.'] } as DateOptions)); // true
+	// console.log("中文分隔符:", isDate("2023年12月31日", { 
+	//   format: "YYYY年MM月DD日",
+	//   strictMode: true,
+	//   delimiters: ['年', '月', '日']
+	// } as DateOptions )); // true
+	
+	
+	// 示例测试
+	// console.log("示例1 标准HTTP URL:", isURL("http://example.com")); // true
+	// console.log("示例2 需要端口时缺少端口:", isURL("https://example.com", { requirePort: true } as URLOptions)); // false
+	// console.log("示例3 协议相对URL:", isURL("//example.com", { allowProtocolRelativeUrls: true })); // true
+	console.log("示例4 IPv6地址:", isURL("http://[2001:db8::1]:8080", {})); // true
+	// console.log("示例5 带认证信息被禁用:", isURL("user:pass@example.com", { disallowAuth: true })); // false
+	console.log("示例6 查询参数被禁用:", isURL("http://example.com?q=test", { allowQueryComponents: true })); // false
+	console.log("示例7 非字符串输入:", isURL(null, {})); // false
+	console.log("示例8 邮件协议被排除:", isURL("mailto:test@example.com", {})); // false
+	console.log("示例9 自定义协议:", isURL("ftp://files.example.com", { protocols: ["ftp"] })); // true
+	console.log("示例10 白名单检查:", isURL("http://trusted.com", { hostWhitelist: ["trusted.com"] })); // true
+	
+	
+	// #ifdef WEB
+	// console.log('validator', validator.isURL())
+	console.log("示例4 IPv6地址:", validator.isURL("http://[2001:db8::1]:8080", {})); // true
+	console.log("示例6 查询参数被禁用:", validator.isURL("http://example.com?q=test", { allow_query_components: true })); // false
+	console.log("示例8 邮件协议被排除:", validator.isURL("mailto:test@example.com", {})); // false
+	console.log("示例9 自定义协议:", isURL("ftp://files.example.com", { protocols: ["ftp"] })); // true
+	// #endif
+	
+	export default {
+		
+	}
+</script>
+
+<style>
+
+</style>

+ 11 - 0
uni_modules/lime-shared/createAnimation/index.ts

@@ -0,0 +1,11 @@
+// @ts-nocheck
+// #ifndef UNI-APP-X
+export * from './type.ts'
+// export * from './vue.ts'
+export { createAnimation } from './vue.ts'
+// #endif
+
+// #ifdef UNI-APP-X
+// export * from './uvue.ts'
+export { createAnimation } from './uvue.uts' 
+// #endif

+ 25 - 0
uni_modules/lime-shared/createAnimation/type.ts

@@ -0,0 +1,25 @@
+export type CreateAnimationOptions = {
+	/**
+	 * 动画持续时间,单位ms
+	 */
+	duration ?: number;
+	/**
+	 * 定义动画的效果
+	 * - linear: 动画从头到尾的速度是相同的
+	 * - ease: 动画以低速开始,然后加快,在结束前变慢
+	 * - ease-in: 动画以低速开始
+	 * - ease-in-out: 动画以低速开始和结束
+	 * - ease-out: 动画以低速结束
+	 * - step-start: 动画第一帧就跳至结束状态直到结束
+	 * - step-end: 动画一直保持开始状态,最后一帧跳到结束状态
+	 */
+	timingFunction ?: string //'linear' | 'ease' | 'ease-in' | 'ease-in-out' | 'ease-out' | 'step-start' | 'step-end';
+	/**
+	 * 动画延迟时间,单位 ms
+	 */
+	delay ?: number;
+	/**
+	 * 设置transform-origin
+	 */
+	transformOrigin ?: string;
+}

+ 5 - 0
uni_modules/lime-shared/createAnimation/uvue.uts

@@ -0,0 +1,5 @@
+// @ts-nocheck
+// export * from '@/uni_modules/lime-animateIt'
+export function createAnimation() {
+	console.error('当前环境不支持,请使用:lime-animateIt')
+}

+ 148 - 0
uni_modules/lime-shared/createAnimation/vue.ts

@@ -0,0 +1,148 @@
+// @ts-nocheck
+// nvue 需要在节点上设置ref或在export里传入
+// const animation = createAnimation({
+//   ref: this.$refs['xxx'],
+// 	 duration: 0,
+// 	 timingFunction: 'linear'
+// })
+// animation.opacity(1).translate(x, y).step({duration})
+// animation.export(ref)
+
+// 抹平nvue 与 uni.createAnimation的使用差距
+// 但是nvue动画太慢
+
+
+
+import { type CreateAnimationOptions } from './type'
+// #ifdef APP-NVUE
+const nvueAnimation = uni.requireNativePlugin('animation')
+
+type AnimationTypes = 'matrix' | 'matrix3d' | 'rotate' | 'rotate3d' | 'rotateX' | 'rotateY' | 'rotateZ' | 'scale' | 'scale3d' | 'scaleX' | 'scaleY' | 'scaleZ' | 'skew' | 'skewX' | 'skewY' | 'translate' | 'translate3d' | 'translateX' | 'translateY' | 'translateZ'
+	| 'opacity' | 'backgroundColor' | 'width' | 'height' | 'left' | 'right' | 'top' | 'bottom'
+
+interface Styles {
+	[key : string] : any
+}
+	
+interface StepConfig {
+	duration?: number
+	timingFunction?: string
+	delay?: number
+	needLayout?: boolean
+	transformOrigin?: string
+}
+interface StepAnimate {
+	styles?: Styles
+	config?: StepConfig
+}
+interface StepAnimates {
+	[key: number]: StepAnimate
+}
+// export interface CreateAnimationOptions extends UniApp.CreateAnimationOptions {
+// 	ref?: string
+// }
+
+type Callback = (time: number) => void
+const animateTypes1 : AnimationTypes[] = ['matrix', 'matrix3d', 'rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scale3d',
+	'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'translate', 'translate3d', 'translateX', 'translateY',
+	'translateZ'
+]
+const animateTypes2 : AnimationTypes[] = ['opacity', 'backgroundColor']
+const animateTypes3 : AnimationTypes[] = ['width', 'height', 'left', 'right', 'top', 'bottom']
+
+class LimeAnimation {
+	ref : any
+	context : any
+	options : UniApp.CreateAnimationOptions
+	// stack : any[] = []
+	next : number = 0
+	currentStepAnimates : StepAnimates = {}
+	duration : number = 0
+	constructor(options : CreateAnimationOptions) {
+		const {ref} = options
+		this.ref = ref
+		this.options = options
+	}
+	addAnimate(type : AnimationTypes, args: (string | number)[]) {
+		let aniObj = this.currentStepAnimates[this.next]
+		let stepAnimate:StepAnimate = {}
+		if (!aniObj) {
+			stepAnimate = {styles: {}, config: {}}
+		} else {
+			stepAnimate = aniObj
+		}
+
+		if (animateTypes1.includes(type)) {
+			if (!stepAnimate.styles.transform) {
+				stepAnimate.styles.transform = ''
+			}
+			let unit = ''
+			if (type === 'rotate') {
+				unit = 'deg'
+			}
+			stepAnimate.styles.transform += `${type}(${args.map((v: number) => v + unit).join(',')}) `
+		} else {
+			stepAnimate.styles[type] = `${args.join(',')}`
+		}
+		this.currentStepAnimates[this.next] = stepAnimate
+	}
+	animateRun(styles: Styles = {}, config:StepConfig = {}, ref: any) {
+		const el = ref || this.ref
+		if (!el) return
+		return new Promise((resolve) => {
+			const time = +new Date()
+			nvueAnimation.transition(el, {
+				styles,
+				...config
+			}, () => {
+				resolve(+new Date() - time)
+			})
+		})
+	}
+	nextAnimate(animates: StepAnimates, step: number = 0, ref: any, cb: Callback) {
+		let obj = animates[step]
+		if (obj) {
+			let { styles, config } = obj
+			// this.duration += config.duration
+			this.animateRun(styles, config, ref).then((time: number) => {
+				step += 1
+				this.duration += time
+				this.nextAnimate(animates, step, ref, cb)
+			})
+		} else {
+			this.currentStepAnimates = {}
+			cb && cb(this.duration)
+		}
+	}
+	step(config:StepConfig = {}) {
+		this.currentStepAnimates[this.next].config = Object.assign({}, this.options, config)
+		this.currentStepAnimates[this.next].styles.transformOrigin = this.currentStepAnimates[this.next].config.transformOrigin
+		this.next++
+		return this
+	}
+	export(ref: any, cb?: Callback) {
+		ref = ref || this.ref
+		if(!ref) return
+		this.duration = 0
+		this.next = 0
+		this.nextAnimate(this.currentStepAnimates, 0, ref, cb)
+		return null
+	}
+}
+
+
+animateTypes1.concat(animateTypes2, animateTypes3).forEach(type => {
+	LimeAnimation.prototype[type] = function(...args: (string | number)[]) {
+		this.addAnimate(type, args)
+		return this
+	}
+})
+// #endif
+export function createAnimation(options : CreateAnimationOptions) {
+	// #ifndef APP-NVUE
+	return uni.createAnimation({ ...options })
+	// #endif
+	// #ifdef APP-NVUE
+	return new LimeAnimation(options)
+	// #endif
+}

+ 73 - 0
uni_modules/lime-shared/createCanvas/index.ts

@@ -0,0 +1,73 @@
+
+// @ts-nocheck
+// #ifndef UNI-APP-X && APP
+import type { ComponentInternalInstance } from '@/uni_modules/lime-shared/vue'
+import { getRect } from '@/uni_modules/lime-shared/getRect'
+import { canIUseCanvas2d } from '@/uni_modules/lime-shared/canIUseCanvas2d'
+export const isCanvas2d = canIUseCanvas2d()
+// #endif
+
+
+export function createCanvas(canvasId : string, component : ComponentInternalInstance) {
+	// #ifdef UNI-APP-X
+	uni.createCanvasContextAsync({
+		canvasId,
+		component,
+		success(context : CanvasContext) {
+
+		},
+		fail(error : UniError) {
+
+		}
+	})
+	// #endif
+	// #ifndef UNI-APP-X
+	const isCanvas2d = canIUseCanvas2d()
+	getRect('#' + canvasId, context, isCanvas2d).then(res => {
+		if (res.node) {
+			res.node.width = res.width
+			res.node.height = res.height
+			return res.node
+		} else {
+			const ctx = uni.createCanvasContext(canvasId, context)
+			if (!ctx._drawImage) {
+				ctx._drawImage = ctx.drawImage
+				ctx.drawImage = function (...args) {
+					const { path } = args.shift()
+					ctx._drawImage(path, ...args)
+				}
+			}
+			if (!ctx.getImageData) {
+				ctx.getImageData = function () {
+					return new Promise((resolve, reject) => {
+						uni.canvasGetImageData({
+							canvasId,
+							x: parseInt(arguments[0]),
+							y: parseInt(arguments[1]),
+							width: parseInt(arguments[2]),
+							height: parseInt(arguments[3]),
+							success(res) {
+								resolve(res)
+							},
+							fail(err) {
+								reject(err)
+							}
+						}, context)
+					})
+
+				}
+				return {
+					getContext(type: string) {
+						if(type == '2d') {
+							return ctx
+						}
+					},
+					width: res.width,
+					height: res.height,
+					createImage
+				}
+			}
+		}
+	})
+	// #endif
+}

+ 71 - 0
uni_modules/lime-shared/createImage/index.ts

@@ -0,0 +1,71 @@
+// @ts-nocheck
+// #ifndef UNI-APP-X && APP
+import {isBrowser} from '../isBrowser'
+class Image {
+	currentSrc: string | null = null
+	naturalHeight: number = 0
+	naturalWidth: number = 0
+	width: number = 0
+	height: number = 0
+	tagName: string = 'IMG'
+	path: string = ''
+	crossOrigin: string = ''
+	referrerPolicy: string = ''
+	onload: () => void = () => {}
+	onerror: () => void = () => {}
+	complete: boolean = false
+	constructor() {}
+	set src(src: string) {
+		console.log('src', src)
+		if(!src) {
+			return this.onerror()
+		}
+		src = src.replace(/^@\//,'/')
+		this.currentSrc = src
+		uni.getImageInfo({
+			src,
+			success: (res) => {
+				const localReg = /^\.|^\/(?=[^\/])/;
+				// #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO
+				res.path = localReg.test(src) ?  `/${res.path}` : res.path;
+				// #endif
+				this.complete = true
+				this.path = res.path
+				this.naturalWidth = this.width = res.width
+				this.naturalHeight = this.height = res.height
+				this.onload()
+			},
+			fail: () => {
+				this.onerror()
+			}
+		})
+	}
+	get src() {
+		return this.currentSrc
+	}
+}
+interface UniImage extends WechatMiniprogram.Image {
+	complete?: boolean
+	naturalHeight?: number
+	naturalWidth?: number
+}
+/** 创建用于 canvas 的 img */
+export function createImage(canvas?: any): HTMLImageElement | UniImage {
+	if(canvas && canvas.createImage) {
+		return (canvas as WechatMiniprogram.Canvas).createImage()
+	} else if(this && this['tagName'] == 'canvas' && !('toBlob' in this) || canvas && !('toBlob' in canvas)){
+		return new Image()
+	} else if(isBrowser) {
+		return new window.Image()
+	}
+	return new Image()
+}
+// #endif
+
+
+// #ifdef UNI-APP-X && APP
+export function createImage():Image{
+	// console.error('当前环境不支持')
+	return new Image()
+}
+// #endif

+ 11 - 0
uni_modules/lime-shared/debounce/index.ts

@@ -0,0 +1,11 @@
+// @ts-nocheck
+
+// #ifdef UNI-APP-X && APP
+// export * from './uvue.uts'
+export { debounce } from './uvue.uts'
+// #endif
+
+// #ifndef UNI-APP-X && APP
+// export * from './vue.ts'
+export { debounce } from './vue.ts'
+// #endif

+ 36 - 0
uni_modules/lime-shared/debounce/uvue.uts

@@ -0,0 +1,36 @@
+// @ts-nocheck
+/**
+ * 防抖函数,通过延迟一定时间来限制函数的执行频率。
+ * @param fn 要防抖的函数。
+ * @param wait 触发防抖的等待时间,单位为毫秒。
+ * @returns 防抖函数。
+ */
+export function debounce<A extends any>(fn : (args: A)=> void, wait = 300): (args: A)=> void {
+	let timer = -1
+	
+	return (args: A) => {
+		if (timer >-1) {clearTimeout(timer)};
+		
+		timer = setTimeout(()=>{
+			fn(args)
+		}, wait)
+	}
+};
+
+
+
+// 示例
+// 定义一个函数
+// function saveData(data: string) {
+//   // 模拟保存数据的操作
+//   console.log(`Saving data: ${data}`);
+// }
+
+// // 创建一个防抖函数,延迟 500 毫秒后调用 saveData 函数
+// const debouncedSaveData = debounce(saveData, 500);
+
+// // 连续调用防抖函数
+// debouncedSaveData('Data 1'); // 不会立即调用 saveData 函数
+// debouncedSaveData('Data 2'); // 不会立即调用 saveData 函数
+
+// 在 500 毫秒后,只会调用一次 saveData 函数,输出结果为 "Saving data: Data 2"

+ 40 - 0
uni_modules/lime-shared/debounce/vue.ts

@@ -0,0 +1,40 @@
+// @ts-nocheck
+type Timeout = ReturnType<typeof setTimeout> | null;
+/**
+ * 防抖函数,通过延迟一定时间来限制函数的执行频率。
+ * @param fn 要防抖的函数。
+ * @param wait 触发防抖的等待时间,单位为毫秒。
+ * @returns 防抖函数。
+ */
+export function debounce<A extends any, R>(
+	fn : (...args : A) => R,
+	wait : number = 300) : (...args : A) => void {
+	let timer : Timeout = null; 
+
+	return function (...args : A) {
+		if (timer) clearTimeout(timer); // 如果上一个 setTimeout 存在,则清除它
+
+		// 设置一个新的 setTimeout,在指定的等待时间后调用防抖函数
+		timer = setTimeout(() => {
+			fn.apply(this, args); // 使用提供的参数调用原始函数
+		}, wait);
+	};
+};
+
+
+
+// 示例
+// 定义一个函数
+// function saveData(data: string) {
+//   // 模拟保存数据的操作
+//   console.log(`Saving data: ${data}`);
+// }
+
+// // 创建一个防抖函数,延迟 500 毫秒后调用 saveData 函数
+// const debouncedSaveData = debounce(saveData, 500);
+
+// // 连续调用防抖函数
+// debouncedSaveData('Data 1'); // 不会立即调用 saveData 函数
+// debouncedSaveData('Data 2'); // 不会立即调用 saveData 函数
+
+// 在 500 毫秒后,只会调用一次 saveData 函数,输出结果为 "Saving data: Data 2"

+ 11 - 0
uni_modules/lime-shared/exif/index.ts

@@ -0,0 +1,11 @@
+// @ts-nocheck
+// #ifndef UNI-APP-X && APP
+// export * from './vue.ts'
+export { exif } from './vue.ts'
+// #endif
+
+
+// #ifdef UNI-APP-X && APP
+// export * from './uvue.uts'
+export { exif } from './uvue.uts'
+// #endif

+ 7 - 0
uni_modules/lime-shared/exif/uvue.uts

@@ -0,0 +1,7 @@
+class EXIF {
+	constructor(){
+		console.error('当前环境不支持')
+	}
+}
+
+export const exif = new EXIF()

+ 1057 - 0
uni_modules/lime-shared/exif/vue.ts

@@ -0,0 +1,1057 @@
+// @ts-nocheck
+import { base64ToArrayBuffer } from '../base64ToArrayBuffer';
+import { pathToBase64 } from '../pathToBase64';
+// import { isBase64 } from '../isBase64';
+import { isDataURI } from '../isBase64';
+import { isString } from '../isString';
+
+interface File {
+	exifdata : any
+	iptcdata : any
+	xmpdata : any
+	src : string
+}
+class EXIF {
+	isXmpEnabled = false
+	debug = false
+	Tags = {
+		// version tags
+		0x9000: "ExifVersion", // EXIF version
+		0xA000: "FlashpixVersion", // Flashpix format version
+
+		// colorspace tags
+		0xA001: "ColorSpace", // Color space information tag
+
+		// image configuration
+		0xA002: "PixelXDimension", // Valid width of meaningful image
+		0xA003: "PixelYDimension", // Valid height of meaningful image
+		0x9101: "ComponentsConfiguration", // Information about channels
+		0x9102: "CompressedBitsPerPixel", // Compressed bits per pixel
+
+		// user information
+		0x927C: "MakerNote", // Any desired information written by the manufacturer
+		0x9286: "UserComment", // Comments by user
+
+		// related file
+		0xA004: "RelatedSoundFile", // Name of related sound file
+
+		// date and time
+		0x9003: "DateTimeOriginal", // Date and time when the original image was generated
+		0x9004: "DateTimeDigitized", // Date and time when the image was stored digitally
+		0x9290: "SubsecTime", // Fractions of seconds for DateTime
+		0x9291: "SubsecTimeOriginal", // Fractions of seconds for DateTimeOriginal
+		0x9292: "SubsecTimeDigitized", // Fractions of seconds for DateTimeDigitized
+
+		// picture-taking conditions
+		0x829A: "ExposureTime", // Exposure time (in seconds)
+		0x829D: "FNumber", // F number
+		0x8822: "ExposureProgram", // Exposure program
+		0x8824: "SpectralSensitivity", // Spectral sensitivity
+		0x8827: "ISOSpeedRatings", // ISO speed rating
+		0x8828: "OECF", // Optoelectric conversion factor
+		0x9201: "ShutterSpeedValue", // Shutter speed
+		0x9202: "ApertureValue", // Lens aperture
+		0x9203: "BrightnessValue", // Value of brightness
+		0x9204: "ExposureBias", // Exposure bias
+		0x9205: "MaxApertureValue", // Smallest F number of lens
+		0x9206: "SubjectDistance", // Distance to subject in meters
+		0x9207: "MeteringMode", // Metering mode
+		0x9208: "LightSource", // Kind of light source
+		0x9209: "Flash", // Flash status
+		0x9214: "SubjectArea", // Location and area of main subject
+		0x920A: "FocalLength", // Focal length of the lens in mm
+		0xA20B: "FlashEnergy", // Strobe energy in BCPS
+		0xA20C: "SpatialFrequencyResponse", //
+		0xA20E: "FocalPlaneXResolution", // Number of pixels in width direction per FocalPlaneResolutionUnit
+		0xA20F: "FocalPlaneYResolution", // Number of pixels in height direction per FocalPlaneResolutionUnit
+		0xA210: "FocalPlaneResolutionUnit", // Unit for measuring FocalPlaneXResolution and FocalPlaneYResolution
+		0xA214: "SubjectLocation", // Location of subject in image
+		0xA215: "ExposureIndex", // Exposure index selected on camera
+		0xA217: "SensingMethod", // Image sensor type
+		0xA300: "FileSource", // Image source (3 == DSC)
+		0xA301: "SceneType", // Scene type (1 == directly photographed)
+		0xA302: "CFAPattern", // Color filter array geometric pattern
+		0xA401: "CustomRendered", // Special processing
+		0xA402: "ExposureMode", // Exposure mode
+		0xA403: "WhiteBalance", // 1 = auto white balance, 2 = manual
+		0xA404: "DigitalZoomRation", // Digital zoom ratio
+		0xA405: "FocalLengthIn35mmFilm", // Equivalent foacl length assuming 35mm film camera (in mm)
+		0xA406: "SceneCaptureType", // Type of scene
+		0xA407: "GainControl", // Degree of overall image gain adjustment
+		0xA408: "Contrast", // Direction of contrast processing applied by camera
+		0xA409: "Saturation", // Direction of saturation processing applied by camera
+		0xA40A: "Sharpness", // Direction of sharpness processing applied by camera
+		0xA40B: "DeviceSettingDescription", //
+		0xA40C: "SubjectDistanceRange", // Distance to subject
+
+		// other tags
+		0xA005: "InteroperabilityIFDPointer",
+		0xA420: "ImageUniqueID" // Identifier assigned uniquely to each image
+	}
+	TiffTags = {
+		0x0100: "ImageWidth",
+		0x0101: "ImageHeight",
+		0x8769: "ExifIFDPointer",
+		0x8825: "GPSInfoIFDPointer",
+		0xA005: "InteroperabilityIFDPointer",
+		0x0102: "BitsPerSample",
+		0x0103: "Compression",
+		0x0106: "PhotometricInterpretation",
+		0x0112: "Orientation",
+		0x0115: "SamplesPerPixel",
+		0x011C: "PlanarConfiguration",
+		0x0212: "YCbCrSubSampling",
+		0x0213: "YCbCrPositioning",
+		0x011A: "XResolution",
+		0x011B: "YResolution",
+		0x0128: "ResolutionUnit",
+		0x0111: "StripOffsets",
+		0x0116: "RowsPerStrip",
+		0x0117: "StripByteCounts",
+		0x0201: "JPEGInterchangeFormat",
+		0x0202: "JPEGInterchangeFormatLength",
+		0x012D: "TransferFunction",
+		0x013E: "WhitePoint",
+		0x013F: "PrimaryChromaticities",
+		0x0211: "YCbCrCoefficients",
+		0x0214: "ReferenceBlackWhite",
+		0x0132: "DateTime",
+		0x010E: "ImageDescription",
+		0x010F: "Make",
+		0x0110: "Model",
+		0x0131: "Software",
+		0x013B: "Artist",
+		0x8298: "Copyright"
+	}
+	GPSTags = {
+		0x0000: "GPSVersionID",
+		0x0001: "GPSLatitudeRef",
+		0x0002: "GPSLatitude",
+		0x0003: "GPSLongitudeRef",
+		0x0004: "GPSLongitude",
+		0x0005: "GPSAltitudeRef",
+		0x0006: "GPSAltitude",
+		0x0007: "GPSTimeStamp",
+		0x0008: "GPSSatellites",
+		0x0009: "GPSStatus",
+		0x000A: "GPSMeasureMode",
+		0x000B: "GPSDOP",
+		0x000C: "GPSSpeedRef",
+		0x000D: "GPSSpeed",
+		0x000E: "GPSTrackRef",
+		0x000F: "GPSTrack",
+		0x0010: "GPSImgDirectionRef",
+		0x0011: "GPSImgDirection",
+		0x0012: "GPSMapDatum",
+		0x0013: "GPSDestLatitudeRef",
+		0x0014: "GPSDestLatitude",
+		0x0015: "GPSDestLongitudeRef",
+		0x0016: "GPSDestLongitude",
+		0x0017: "GPSDestBearingRef",
+		0x0018: "GPSDestBearing",
+		0x0019: "GPSDestDistanceRef",
+		0x001A: "GPSDestDistance",
+		0x001B: "GPSProcessingMethod",
+		0x001C: "GPSAreaInformation",
+		0x001D: "GPSDateStamp",
+		0x001E: "GPSDifferential"
+	}
+	// EXIF 2.3 Spec
+	IFD1Tags = {
+		0x0100: "ImageWidth",
+		0x0101: "ImageHeight",
+		0x0102: "BitsPerSample",
+		0x0103: "Compression",
+		0x0106: "PhotometricInterpretation",
+		0x0111: "StripOffsets",
+		0x0112: "Orientation",
+		0x0115: "SamplesPerPixel",
+		0x0116: "RowsPerStrip",
+		0x0117: "StripByteCounts",
+		0x011A: "XResolution",
+		0x011B: "YResolution",
+		0x011C: "PlanarConfiguration",
+		0x0128: "ResolutionUnit",
+		0x0201: "JpegIFOffset", // When image format is JPEG, this value show offset to JPEG data stored.(aka "ThumbnailOffset" or "JPEGInterchangeFormat")
+		0x0202: "JpegIFByteCount", // When image format is JPEG, this value shows data size of JPEG image (aka "ThumbnailLength" or "JPEGInterchangeFormatLength")
+		0x0211: "YCbCrCoefficients",
+		0x0212: "YCbCrSubSampling",
+		0x0213: "YCbCrPositioning",
+		0x0214: "ReferenceBlackWhite"
+	}
+	StringValues = {
+		ExposureProgram: {
+			0: "Not defined",
+			1: "Manual",
+			2: "Normal program",
+			3: "Aperture priority",
+			4: "Shutter priority",
+			5: "Creative program",
+			6: "Action program",
+			7: "Portrait mode",
+			8: "Landscape mode"
+		},
+		MeteringMode: {
+			0: "Unknown",
+			1: "Average",
+			2: "CenterWeightedAverage",
+			3: "Spot",
+			4: "MultiSpot",
+			5: "Pattern",
+			6: "Partial",
+			255: "Other"
+		},
+		LightSource: {
+			0: "Unknown",
+			1: "Daylight",
+			2: "Fluorescent",
+			3: "Tungsten (incandescent light)",
+			4: "Flash",
+			9: "Fine weather",
+			10: "Cloudy weather",
+			11: "Shade",
+			12: "Daylight fluorescent (D 5700 - 7100K)",
+			13: "Day white fluorescent (N 4600 - 5400K)",
+			14: "Cool white fluorescent (W 3900 - 4500K)",
+			15: "White fluorescent (WW 3200 - 3700K)",
+			17: "Standard light A",
+			18: "Standard light B",
+			19: "Standard light C",
+			20: "D55",
+			21: "D65",
+			22: "D75",
+			23: "D50",
+			24: "ISO studio tungsten",
+			255: "Other"
+		},
+		Flash: {
+			0x0000: "Flash did not fire",
+			0x0001: "Flash fired",
+			0x0005: "Strobe return light not detected",
+			0x0007: "Strobe return light detected",
+			0x0009: "Flash fired, compulsory flash mode",
+			0x000D: "Flash fired, compulsory flash mode, return light not detected",
+			0x000F: "Flash fired, compulsory flash mode, return light detected",
+			0x0010: "Flash did not fire, compulsory flash mode",
+			0x0018: "Flash did not fire, auto mode",
+			0x0019: "Flash fired, auto mode",
+			0x001D: "Flash fired, auto mode, return light not detected",
+			0x001F: "Flash fired, auto mode, return light detected",
+			0x0020: "No flash function",
+			0x0041: "Flash fired, red-eye reduction mode",
+			0x0045: "Flash fired, red-eye reduction mode, return light not detected",
+			0x0047: "Flash fired, red-eye reduction mode, return light detected",
+			0x0049: "Flash fired, compulsory flash mode, red-eye reduction mode",
+			0x004D: "Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected",
+			0x004F: "Flash fired, compulsory flash mode, red-eye reduction mode, return light detected",
+			0x0059: "Flash fired, auto mode, red-eye reduction mode",
+			0x005D: "Flash fired, auto mode, return light not detected, red-eye reduction mode",
+			0x005F: "Flash fired, auto mode, return light detected, red-eye reduction mode"
+		},
+		SensingMethod: {
+			1: "Not defined",
+			2: "One-chip color area sensor",
+			3: "Two-chip color area sensor",
+			4: "Three-chip color area sensor",
+			5: "Color sequential area sensor",
+			7: "Trilinear sensor",
+			8: "Color sequential linear sensor"
+		},
+		SceneCaptureType: {
+			0: "Standard",
+			1: "Landscape",
+			2: "Portrait",
+			3: "Night scene"
+		},
+		SceneType: {
+			1: "Directly photographed"
+		},
+		CustomRendered: {
+			0: "Normal process",
+			1: "Custom process"
+		},
+		WhiteBalance: {
+			0: "Auto white balance",
+			1: "Manual white balance"
+		},
+		GainControl: {
+			0: "None",
+			1: "Low gain up",
+			2: "High gain up",
+			3: "Low gain down",
+			4: "High gain down"
+		},
+		Contrast: {
+			0: "Normal",
+			1: "Soft",
+			2: "Hard"
+		},
+		Saturation: {
+			0: "Normal",
+			1: "Low saturation",
+			2: "High saturation"
+		},
+		Sharpness: {
+			0: "Normal",
+			1: "Soft",
+			2: "Hard"
+		},
+		SubjectDistanceRange: {
+			0: "Unknown",
+			1: "Macro",
+			2: "Close view",
+			3: "Distant view"
+		},
+		FileSource: {
+			3: "DSC"
+		},
+
+		Components: {
+			0: "",
+			1: "Y",
+			2: "Cb",
+			3: "Cr",
+			4: "R",
+			5: "G",
+			6: "B"
+		}
+	}
+	enableXmp() {
+		this.isXmpEnabled = true
+	}
+	disableXmp() {
+		this.isXmpEnabled = false;
+	}
+	/**
+	 * 获取图片数据
+	 * @param img 图片地址
+	 * @param callback 回调 返回图片数据
+	 * */
+	getData(img : any, callback : Function) {
+		// if (((self.Image && img instanceof self.Image) || (self.HTMLImageElement && img instanceof self.HTMLImageElement)) && !img.complete)
+		// 	return false;
+		let file : File = {
+			src: '',
+			exifdata: null,
+			iptcdata: null,
+			xmpdata: null,
+		}
+		if (isDataURI(img)) {
+			file.src = img
+		} else if (img.path) {
+			file.src = img.path
+		} else if (isString(img)) {
+			file.src = img
+		} else {
+			return false;
+		}
+
+
+		if (!imageHasData(file)) {
+			getImageData(file, callback);
+		} else {
+			if (callback) {
+				callback.call(file);
+			}
+		}
+		return true;
+	}
+	/**
+	 * 获取图片tag
+	 * @param img 图片数据
+	 * @param tag tag 类型
+	 * */
+	getTag(img : File, tag : string) {
+		if (!imageHasData(img)) return;
+		return img.exifdata[tag];
+	}
+	getIptcTag(img : File, tag : string) {
+		if (!imageHasData(img)) return;
+		return img.iptcdata[tag];
+	}
+	getAllTags(img : File) {
+		if (!imageHasData(img)) return {};
+		let a,
+			data = img.exifdata,
+			tags = {};
+		for (a in data) {
+			if (data.hasOwnProperty(a)) {
+				tags[a] = data[a];
+			}
+		}
+		return tags;
+	}
+	getAllIptcTags(img : File) {
+		if (!imageHasData(img)) return {};
+		let a,
+			data = img.iptcdata,
+			tags = {};
+		for (a in data) {
+			if (data.hasOwnProperty(a)) {
+				tags[a] = data[a];
+			}
+		}
+		return tags;
+	}
+	pretty(img : File) {
+		if (!imageHasData(img)) return "";
+		let a,
+			data = img.exifdata,
+			strPretty = "";
+		for (a in data) {
+			if (data.hasOwnProperty(a)) {
+				if (typeof data[a] == "object") {
+					if (data[a] instanceof Number) {
+						strPretty += a + " : " + data[a] + " [" + data[a].numerator + "/" + data[a]
+							.denominator + "]\r\n";
+					} else {
+						strPretty += a + " : [" + data[a].length + " values]\r\n";
+					}
+				} else {
+					strPretty += a + " : " + data[a] + "\r\n";
+				}
+			}
+		}
+		return strPretty;
+	}
+	readFromBinaryFile(file: ArrayBuffer) {
+		return findEXIFinJPEG(file);
+	}
+}
+
+export const exif = new EXIF()
+// export function getData(img, callback) {
+// 	const exif = new EXIF()
+// 	exif.getData(img, callback)
+// }
+
+// export default {getData}
+const ExifTags = exif.Tags
+const TiffTags = exif.TiffTags
+const IFD1Tags = exif.IFD1Tags
+const GPSTags = exif.GPSTags
+const StringValues = exif.StringValues
+
+
+function imageHasData(img : File) : boolean {
+	return !!(img.exifdata);
+}
+
+function objectURLToBlob(url : string, callback : Function) {
+	try {
+		const http = new XMLHttpRequest();
+		http.open("GET", url, true);
+		http.responseType = "blob";
+		http.onload = function (e) {
+			if (this.status == 200 || this.status === 0) {
+				callback(this.response);
+			}
+		};
+		http.send();
+	} catch (e) {
+		console.warn(e)
+	}
+}
+
+
+function getImageData(img : File, callback : Function) {
+	function handleBinaryFile(binFile: ArrayBuffer) {
+		const data = findEXIFinJPEG(binFile);
+		img.exifdata = data ?? {};
+		const iptcdata = findIPTCinJPEG(binFile);
+		img.iptcdata = iptcdata ?? {};
+		if (exif.isXmpEnabled) {
+			const xmpdata = findXMPinJPEG(binFile);
+			img.xmpdata = xmpdata ?? {};
+		}
+		if (callback) {
+			callback.call(img);
+		}
+	}
+
+	if (img.src) {
+		if (/^data\:/i.test(img.src)) { // Data URI
+			// var arrayBuffer = base64ToArrayBuffer(img.src);
+			handleBinaryFile(base64ToArrayBuffer(img.src));
+
+		} else if (/^blob\:/i.test(img.src) && typeof FileReader !== 'undefined') { // Object URL
+			var fileReader = new FileReader();
+			fileReader.onload = function (e) {
+				handleBinaryFile(e.target.result);
+			};
+			objectURLToBlob(img.src, function (blob : Blob) {
+				fileReader.readAsArrayBuffer(blob);
+			});
+		} else if (typeof XMLHttpRequest !== 'undefined') {
+			var http = new XMLHttpRequest();
+			http.onload = function () {
+				if (this.status == 200 || this.status === 0) {
+					handleBinaryFile(http.response);
+				} else {
+					throw "Could not load image";
+				}
+				http = null;
+			};
+			http.open("GET", img.src, true);
+			http.responseType = "arraybuffer";
+			http.send(null);
+		} else {
+			pathToBase64(img.src).then(res => {
+				handleBinaryFile(base64ToArrayBuffer(res));
+			})
+		}
+	} else if (typeof FileReader !== 'undefined' && self.FileReader && (img instanceof self.Blob || img instanceof self.File)) {
+		var fileReader = new FileReader();
+		fileReader.onload = function (e : any) {
+			if (exif.debug) console.log("Got file of length " + e.target.result.byteLength);
+			handleBinaryFile(e.target.result);
+		};
+
+		fileReader.readAsArrayBuffer(img);
+	}
+}
+
+function findEXIFinJPEG(file: ArrayBuffer) {
+	const dataView = new DataView(file);
+
+	if (exif.debug) console.log("Got file of length " + file.byteLength);
+	if ((dataView.getUint8(0) != 0xFF) || (dataView.getUint8(1) != 0xD8)) {
+		if (exif.debug) console.log("Not a valid JPEG");
+		return false; // not a valid jpeg
+	}
+
+	let offset = 2,
+		length = file.byteLength,
+		marker;
+
+	while (offset < length) {
+		if (dataView.getUint8(offset) != 0xFF) {
+			if (exif.debug) console.log("Not a valid marker at offset " + offset + ", found: " + dataView.getUint8(
+				offset));
+			return false; // not a valid marker, something is wrong
+		}
+
+		marker = dataView.getUint8(offset + 1);
+		if (exif.debug) console.log(marker);
+
+		// we could implement handling for other markers here,
+		// but we're only looking for 0xFFE1 for EXIF data
+
+		if (marker == 225) {
+			if (exif.debug) console.log("Found 0xFFE1 marker");
+
+			return readEXIFData(dataView, offset + 4, dataView.getUint16(offset + 2) - 2);
+
+			// offset += 2 + file.getShortAt(offset+2, true);
+
+		} else {
+			offset += 2 + dataView.getUint16(offset + 2);
+		}
+
+	}
+
+}
+
+function findIPTCinJPEG(file: ArrayBuffer) {
+	const dataView = new DataView(file);
+
+	if (exif.debug) console.log("Got file of length " + file.byteLength);
+	if ((dataView.getUint8(0) != 0xFF) || (dataView.getUint8(1) != 0xD8)) {
+		if (exif.debug) console.log("Not a valid JPEG");
+		return false; // not a valid jpeg
+	}
+
+	let offset = 2,
+		length = file.byteLength;
+
+
+	const isFieldSegmentStart = function (dataView, offset: number) {
+		return (
+			dataView.getUint8(offset) === 0x38 &&
+			dataView.getUint8(offset + 1) === 0x42 &&
+			dataView.getUint8(offset + 2) === 0x49 &&
+			dataView.getUint8(offset + 3) === 0x4D &&
+			dataView.getUint8(offset + 4) === 0x04 &&
+			dataView.getUint8(offset + 5) === 0x04
+		);
+	};
+
+	while (offset < length) {
+
+		if (isFieldSegmentStart(dataView, offset)) {
+
+			// Get the length of the name header (which is padded to an even number of bytes)
+			var nameHeaderLength = dataView.getUint8(offset + 7);
+			if (nameHeaderLength % 2 !== 0) nameHeaderLength += 1;
+			// Check for pre photoshop 6 format
+			if (nameHeaderLength === 0) {
+				// Always 4
+				nameHeaderLength = 4;
+			}
+
+			var startOffset = offset + 8 + nameHeaderLength;
+			var sectionLength = dataView.getUint16(offset + 6 + nameHeaderLength);
+
+			return readIPTCData(file, startOffset, sectionLength);
+
+			break;
+
+		}
+
+
+		// Not the marker, continue searching
+		offset++;
+
+	}
+
+}
+
+const IptcFieldMap = {
+	0x78: 'caption',
+	0x6E: 'credit',
+	0x19: 'keywords',
+	0x37: 'dateCreated',
+	0x50: 'byline',
+	0x55: 'bylineTitle',
+	0x7A: 'captionWriter',
+	0x69: 'headline',
+	0x74: 'copyright',
+	0x0F: 'category'
+};
+
+function readIPTCData(file: ArrayBuffer, startOffset: number, sectionLength: number) {
+	const dataView = new DataView(file);
+	let data = {};
+	let fieldValue, fieldName, dataSize, segmentType, segmentSize;
+	let segmentStartPos = startOffset;
+	while (segmentStartPos < startOffset + sectionLength) {
+		if (dataView.getUint8(segmentStartPos) === 0x1C && dataView.getUint8(segmentStartPos + 1) === 0x02) {
+			segmentType = dataView.getUint8(segmentStartPos + 2);
+			if (segmentType in IptcFieldMap) {
+				dataSize = dataView.getInt16(segmentStartPos + 3);
+				segmentSize = dataSize + 5;
+				fieldName = IptcFieldMap[segmentType];
+				fieldValue = getStringFromDB(dataView, segmentStartPos + 5, dataSize);
+				// Check if we already stored a value with this name
+				if (data.hasOwnProperty(fieldName)) {
+					// Value already stored with this name, create multivalue field
+					if (data[fieldName] instanceof Array) {
+						data[fieldName].push(fieldValue);
+					} else {
+						data[fieldName] = [data[fieldName], fieldValue];
+					}
+				} else {
+					data[fieldName] = fieldValue;
+				}
+			}
+
+		}
+		segmentStartPos++;
+	}
+	return data;
+}
+
+function readTags(file: DataView, tiffStart: number, dirStart: number, strings: any[], bigEnd: number) {
+	let entries = file.getUint16(dirStart, !bigEnd),
+		tags = {},
+		entryOffset, tag;
+
+	for (let i = 0; i < entries; i++) {
+		entryOffset = dirStart + i * 12 + 2;
+		tag = strings[file.getUint16(entryOffset, !bigEnd)];
+		if (!tag && exif.debug) console.log("Unknown tag: " + file.getUint16(entryOffset, !bigEnd));
+		tags[tag] = readTagValue(file, entryOffset, tiffStart, dirStart, bigEnd);
+	}
+	return tags;
+}
+
+function readTagValue(file: DataView, entryOffset: number, tiffStart: number, dirStart: number, bigEnd: number) {
+	let type = file.getUint16(entryOffset + 2, !bigEnd),
+		numValues = file.getUint32(entryOffset + 4, !bigEnd),
+		valueOffset = file.getUint32(entryOffset + 8, !bigEnd) + tiffStart,
+		offset,
+		vals, val, n,
+		numerator, denominator;
+
+	switch (type) {
+		case 1: // byte, 8-bit unsigned int
+		case 7: // undefined, 8-bit byte, value depending on field
+			if (numValues == 1) {
+				return file.getUint8(entryOffset + 8, !bigEnd);
+			} else {
+				offset = numValues > 4 ? valueOffset : (entryOffset + 8);
+				vals = [];
+				for (n = 0; n < numValues; n++) {
+					vals[n] = file.getUint8(offset + n);
+				}
+				return vals;
+			}
+
+		case 2: // ascii, 8-bit byte
+			offset = numValues > 4 ? valueOffset : (entryOffset + 8);
+			return getStringFromDB(file, offset, numValues - 1);
+
+		case 3: // short, 16 bit int
+			if (numValues == 1) {
+				return file.getUint16(entryOffset + 8, !bigEnd);
+			} else {
+				offset = numValues > 2 ? valueOffset : (entryOffset + 8);
+				vals = [];
+				for (n = 0; n < numValues; n++) {
+					vals[n] = file.getUint16(offset + 2 * n, !bigEnd);
+				}
+				return vals;
+			}
+
+		case 4: // long, 32 bit int
+			if (numValues == 1) {
+				return file.getUint32(entryOffset + 8, !bigEnd);
+			} else {
+				vals = [];
+				for (n = 0; n < numValues; n++) {
+					vals[n] = file.getUint32(valueOffset + 4 * n, !bigEnd);
+				}
+				return vals;
+			}
+
+		case 5: // rational = two long values, first is numerator, second is denominator
+			if (numValues == 1) {
+				numerator = file.getUint32(valueOffset, !bigEnd);
+				denominator = file.getUint32(valueOffset + 4, !bigEnd);
+				val = new Number(numerator / denominator);
+				val.numerator = numerator;
+				val.denominator = denominator;
+				return val;
+			} else {
+				vals = [];
+				for (n = 0; n < numValues; n++) {
+					numerator = file.getUint32(valueOffset + 8 * n, !bigEnd);
+					denominator = file.getUint32(valueOffset + 4 + 8 * n, !bigEnd);
+					vals[n] = new Number(numerator / denominator);
+					vals[n].numerator = numerator;
+					vals[n].denominator = denominator;
+				}
+				return vals;
+			}
+
+		case 9: // slong, 32 bit signed int
+			if (numValues == 1) {
+				return file.getInt32(entryOffset + 8, !bigEnd);
+			} else {
+				vals = [];
+				for (n = 0; n < numValues; n++) {
+					vals[n] = file.getInt32(valueOffset + 4 * n, !bigEnd);
+				}
+				return vals;
+			}
+
+		case 10: // signed rational, two slongs, first is numerator, second is denominator
+			if (numValues == 1) {
+				return file.getInt32(valueOffset, !bigEnd) / file.getInt32(valueOffset + 4, !bigEnd);
+			} else {
+				vals = [];
+				for (n = 0; n < numValues; n++) {
+					vals[n] = file.getInt32(valueOffset + 8 * n, !bigEnd) / file.getInt32(valueOffset + 4 + 8 *
+						n, !bigEnd);
+				}
+				return vals;
+			}
+	}
+}
+/**
+	 * Given an IFD (Image File Directory) start offset
+	 * returns an offset to next IFD or 0 if it's the last IFD.
+	 */
+function getNextIFDOffset(dataView: DataView, dirStart: number, bigEnd: number) {
+	//the first 2bytes means the number of directory entries contains in this IFD
+	var entries = dataView.getUint16(dirStart, !bigEnd);
+
+	// After last directory entry, there is a 4bytes of data,
+	// it means an offset to next IFD.
+	// If its value is '0x00000000', it means this is the last IFD and there is no linked IFD.
+
+	return dataView.getUint32(dirStart + 2 + entries * 12, !bigEnd); // each entry is 12 bytes long
+}
+
+function readThumbnailImage(dataView: DataView, tiffStart: number, firstIFDOffset: number, bigEnd: number) {
+	// get the IFD1 offset
+	const IFD1OffsetPointer = getNextIFDOffset(dataView, tiffStart + firstIFDOffset, bigEnd);
+
+	if (!IFD1OffsetPointer) {
+		// console.log('******** IFD1Offset is empty, image thumb not found ********');
+		return {};
+	} else if (IFD1OffsetPointer > dataView.byteLength) { // this should not happen
+		// console.log('******** IFD1Offset is outside the bounds of the DataView ********');
+		return {};
+	}
+	// console.log('*******  thumbnail IFD offset (IFD1) is: %s', IFD1OffsetPointer);
+
+	let thumbTags : any = readTags(dataView, tiffStart, tiffStart + IFD1OffsetPointer, IFD1Tags, bigEnd)
+
+	// EXIF 2.3 specification for JPEG format thumbnail
+
+	// If the value of Compression(0x0103) Tag in IFD1 is '6', thumbnail image format is JPEG.
+	// Most of Exif image uses JPEG format for thumbnail. In that case, you can get offset of thumbnail
+	// by JpegIFOffset(0x0201) Tag in IFD1, size of thumbnail by JpegIFByteCount(0x0202) Tag.
+	// Data format is ordinary JPEG format, starts from 0xFFD8 and ends by 0xFFD9. It seems that
+	// JPEG format and 160x120pixels of size are recommended thumbnail format for Exif2.1 or later.
+
+	if (thumbTags['Compression'] && typeof Blob !== 'undefined') {
+		// console.log('Thumbnail image found!');
+
+		switch (thumbTags['Compression']) {
+			case 6:
+				// console.log('Thumbnail image format is JPEG');
+				if (thumbTags.JpegIFOffset && thumbTags.JpegIFByteCount) {
+					// extract the thumbnail
+					var tOffset = tiffStart + thumbTags.JpegIFOffset;
+					var tLength = thumbTags.JpegIFByteCount;
+					thumbTags['blob'] = new Blob([new Uint8Array(dataView.buffer, tOffset, tLength)], {
+						type: 'image/jpeg'
+					});
+				}
+				break;
+
+			case 1:
+				console.log("Thumbnail image format is TIFF, which is not implemented.");
+				break;
+			default:
+				console.log("Unknown thumbnail image format '%s'", thumbTags['Compression']);
+		}
+	} else if (thumbTags['PhotometricInterpretation'] == 2) {
+		console.log("Thumbnail image format is RGB, which is not implemented.");
+	}
+	return thumbTags;
+}
+
+function getStringFromDB(buffer: DataView, start: number, length: number) {
+	let outstr = "";
+	for (let n = start; n < start + length; n++) {
+		outstr += String.fromCharCode(buffer.getUint8(n));
+	}
+	return outstr;
+}
+
+function readEXIFData(file: DataView, start: number) {
+	if (getStringFromDB(file, start, 4) != "Exif") {
+		if (exif.debug) console.log("Not valid EXIF data! " + getStringFromDB(file, start, 4));
+		return false;
+	}
+
+	let bigEnd,
+		tags, tag,
+		exifData, gpsData,
+		tiffOffset = start + 6;
+
+	// test for TIFF validity and endianness
+	if (file.getUint16(tiffOffset) == 0x4949) {
+		bigEnd = false;
+	} else if (file.getUint16(tiffOffset) == 0x4D4D) {
+		bigEnd = true;
+	} else {
+		if (exif.debug) console.log("Not valid TIFF data! (no 0x4949 or 0x4D4D)");
+		return false;
+	}
+
+	if (file.getUint16(tiffOffset + 2, !bigEnd) != 0x002A) {
+		if (exif.debug) console.log("Not valid TIFF data! (no 0x002A)");
+		return false;
+	}
+
+	const firstIFDOffset = file.getUint32(tiffOffset + 4, !bigEnd);
+
+	if (firstIFDOffset < 0x00000008) {
+		if (exif.debug) console.log("Not valid TIFF data! (First offset less than 8)", file.getUint32(tiffOffset + 4,
+			!bigEnd));
+		return false;
+	}
+
+	tags = readTags(file, tiffOffset, tiffOffset + firstIFDOffset, TiffTags, bigEnd);
+
+	if (tags.ExifIFDPointer) {
+		exifData = readTags(file, tiffOffset, tiffOffset + tags.ExifIFDPointer, ExifTags, bigEnd);
+		for (tag in exifData) {
+			switch (tag) {
+				case "LightSource":
+				case "Flash":
+				case "MeteringMode":
+				case "ExposureProgram":
+				case "SensingMethod":
+				case "SceneCaptureType":
+				case "SceneType":
+				case "CustomRendered":
+				case "WhiteBalance":
+				case "GainControl":
+				case "Contrast":
+				case "Saturation":
+				case "Sharpness":
+				case "SubjectDistanceRange":
+				case "FileSource":
+					exifData[tag] = StringValues[tag][exifData[tag]];
+					break;
+
+				case "ExifVersion":
+				case "FlashpixVersion":
+					exifData[tag] = String.fromCharCode(exifData[tag][0], exifData[tag][1], exifData[tag][2],
+						exifData[tag][3]);
+					break;
+
+				case "ComponentsConfiguration":
+					exifData[tag] =
+						StringValues.Components[exifData[tag][0]] +
+						StringValues.Components[exifData[tag][1]] +
+						StringValues.Components[exifData[tag][2]] +
+						StringValues.Components[exifData[tag][3]];
+					break;
+			}
+			tags[tag] = exifData[tag];
+		}
+	}
+
+	if (tags.GPSInfoIFDPointer) {
+		gpsData = readTags(file, tiffOffset, tiffOffset + tags.GPSInfoIFDPointer, GPSTags, bigEnd);
+		for (tag in gpsData) {
+			switch (tag) {
+				case "GPSVersionID":
+					gpsData[tag] = gpsData[tag][0] +
+						"." + gpsData[tag][1] +
+						"." + gpsData[tag][2] +
+						"." + gpsData[tag][3];
+					break;
+			}
+			tags[tag] = gpsData[tag];
+		}
+	}
+
+	// extract thumbnail
+	tags['thumbnail'] = readThumbnailImage(file, tiffOffset, firstIFDOffset, bigEnd);
+
+	return tags;
+}
+
+function findXMPinJPEG(file: ArrayBuffer) {
+
+	if (!('DOMParser' in self)) {
+		// console.warn('XML parsing not supported without DOMParser');
+		return;
+	}
+	const dataView = new DataView(file);
+
+	if (exif.debug) console.log("Got file of length " + file.byteLength);
+	if ((dataView.getUint8(0) != 0xFF) || (dataView.getUint8(1) != 0xD8)) {
+		if (exif.debug) console.log("Not a valid JPEG");
+		return false; // not a valid jpeg
+	}
+
+	let offset = 2,
+		length = file.byteLength,
+		dom = new DOMParser();
+
+	while (offset < (length - 4)) {
+		if (getStringFromDB(dataView, offset, 4) == "http") {
+			const startOffset = offset - 1;
+			const sectionLength = dataView.getUint16(offset - 2) - 1;
+			let xmpString = getStringFromDB(dataView, startOffset, sectionLength)
+			const xmpEndIndex = xmpString.indexOf('xmpmeta>') + 8;
+			xmpString = xmpString.substring(xmpString.indexOf('<x:xmpmeta'), xmpEndIndex);
+
+			const indexOfXmp = xmpString.indexOf('x:xmpmeta') + 10
+			//Many custom written programs embed xmp/xml without any namespace. Following are some of them.
+			//Without these namespaces, XML is thought to be invalid by parsers
+			xmpString = xmpString.slice(0, indexOfXmp) +
+				'xmlns:Iptc4xmpCore="http://iptc.org/std/Iptc4xmpCore/1.0/xmlns/" ' +
+				'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' +
+				'xmlns:tiff="http://ns.adobe.com/tiff/1.0/" ' +
+				'xmlns:plus="http://schemas.android.com/apk/lib/com.google.android.gms.plus" ' +
+				'xmlns:ext="http://www.gettyimages.com/xsltExtension/1.0" ' +
+				'xmlns:exif="http://ns.adobe.com/exif/1.0/" ' +
+				'xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#" ' +
+				'xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#" ' +
+				'xmlns:crs="http://ns.adobe.com/camera-raw-settings/1.0/" ' +
+				'xmlns:xapGImg="http://ns.adobe.com/xap/1.0/g/img/" ' +
+				'xmlns:Iptc4xmpExt="http://iptc.org/std/Iptc4xmpExt/2008-02-29/" ' +
+				xmpString.slice(indexOfXmp)
+
+			var domDocument = dom.parseFromString(xmpString, 'text/xml');
+			return xml2Object(domDocument);
+		} else {
+			offset++;
+		}
+	}
+}
+
+
+function xml2json(xml: any) {
+	var json = {};
+
+	if (xml.nodeType == 1) { // element node
+		if (xml.attributes.length > 0) {
+			json['@attributes'] = {};
+			for (var j = 0; j < xml.attributes.length; j++) {
+				var attribute = xml.attributes.item(j);
+				json['@attributes'][attribute.nodeName] = attribute.nodeValue;
+			}
+		}
+	} else if (xml.nodeType == 3) { // text node
+		return xml.nodeValue;
+	}
+
+	// deal with children
+	if (xml.hasChildNodes()) {
+		for (var i = 0; i < xml.childNodes.length; i++) {
+			var child = xml.childNodes.item(i);
+			var nodeName = child.nodeName;
+			if (json[nodeName] == null) {
+				json[nodeName] = xml2json(child);
+			} else {
+				if (json[nodeName].push == null) {
+					var old = json[nodeName];
+					json[nodeName] = [];
+					json[nodeName].push(old);
+				}
+				json[nodeName].push(xml2json(child));
+			}
+		}
+	}
+
+	return json;
+}
+
+function xml2Object(xml: any) {
+	try {
+		var obj = {};
+		if (xml.children.length > 0) {
+			for (var i = 0; i < xml.children.length; i++) {
+				var item = xml.children.item(i);
+				var attributes = item.attributes;
+				for (var idx in attributes) {
+					var itemAtt = attributes[idx];
+					var dataKey = itemAtt.nodeName;
+					var dataValue = itemAtt.nodeValue;
+
+					if (dataKey !== undefined) {
+						obj[dataKey] = dataValue;
+					}
+				}
+				var nodeName = item.nodeName;
+
+				if (typeof (obj[nodeName]) == "undefined") {
+					obj[nodeName] = xml2json(item);
+				} else {
+					if (typeof (obj[nodeName].push) == "undefined") {
+						var old = obj[nodeName];
+
+						obj[nodeName] = [];
+						obj[nodeName].push(old);
+					}
+					obj[nodeName].push(xml2json(item));
+				}
+			}
+		} else {
+			obj = xml.textContent;
+		}
+		return obj;
+	} catch (e) {
+		console.log(e.message);
+	}
+}

+ 11 - 0
uni_modules/lime-shared/fillZero/index.ts

@@ -0,0 +1,11 @@
+// @ts-nocheck
+/**
+ * 在数字前填充零,返回字符串形式的结果
+ * @param number 要填充零的数字
+ * @param length 填充零后的字符串长度,默认为2
+ * @returns 填充零后的字符串
+ */
+export function fillZero(number: number, length: number = 2): string {
+  // 将数字转换为字符串,然后使用 padStart 方法填充零到指定长度
+  return `${number}`.padStart(length, '0');
+}

+ 36 - 0
uni_modules/lime-shared/floatAdd/index.ts

@@ -0,0 +1,36 @@
+import { isNumber } from '../isNumber'
+/**
+ * 返回两个浮点数相加的结果
+ * @param num1 第一个浮点数
+ * @param num2 第二个浮点数
+ * @returns 两个浮点数的相加结果
+ */
+export function floatAdd(num1 : number, num2 : number) : number {
+	// 检查 num1 和 num2 是否为数字类型
+	if (!(isNumber(num1) || isNumber(num2))) {
+		console.warn('Please pass in the number type');
+		return NaN;
+	}
+
+	let r1 : number, r2 : number, m : number;
+
+	try {
+		// 获取 num1 小数点后的位数
+		r1 = num1.toString().split('.')[1].length;
+	} catch (error) {
+		r1 = 0;
+	}
+
+	try {
+		// 获取 num2 小数点后的位数
+		r2 = num2.toString().split('.')[1].length;
+	} catch (error) {
+		r2 = 0;
+	}
+
+	// 计算需要扩大的倍数
+	m = Math.pow(10, Math.max(r1, r2));
+
+	// 返回相加结果
+	return (num1 * m + num2 * m) / m;
+}

+ 45 - 0
uni_modules/lime-shared/floatDiv/index.ts

@@ -0,0 +1,45 @@
+import { floatMul } from '../floatMul';
+import { isNumber } from '../isNumber';
+
+/**
+ * 除法函数,用于处理浮点数除法并保持精度。
+ * @param {number} num1 - 被除数。
+ * @param {number} num2 - 除数。
+ * @returns {number} 除法运算的结果,保留正确的精度。
+ */
+export function floatDiv(num1:number, num2:number):number {
+  // 如果传入的不是数字类型,则打印警告并返回NaN
+  if (!isNumber(num1) || !isNumber(num2)) {
+    console.warn('请传入数字类型');
+    return NaN;
+  }
+
+  let m1 = 0, // 被除数小数点后的位数
+    m2 = 0, // 除数小数点后的位数
+    s1 = num1.toString(), // 将被除数转换为字符串
+    s2 = num2.toString(); // 将除数转换为字符串
+
+  // 计算被除数小数点后的位数
+  try {
+    m1 += s1.split('.')[1].length;
+  } catch (error) {}
+
+  // 计算除数小数点后的位数
+  try {
+    m2 += s2.split('.')[1].length;
+  } catch (error) {}
+
+  // 进行除法运算并处理小数点后的位数,使用之前定义的乘法函数保持精度
+  // #ifdef APP-ANDROID
+  return floatMul(
+    parseFloat(s1.replace('.', '')) / parseFloat(s2.replace('.', '')),
+    Math.pow(10, m2 - m1),
+  );
+  // #endif
+  // #ifndef APP-ANDROID
+  return floatMul(
+    Number(s1.replace('.', '')) / Number(s2.replace('.', '')),
+    Math.pow(10, m2 - m1),
+  );
+  // #endif
+}

+ 44 - 0
uni_modules/lime-shared/floatMul/index.ts

@@ -0,0 +1,44 @@
+// @ts-nocheck
+import {isNumber} from '../isNumber';
+// #ifdef APP-ANDROID
+import BigDecimal from 'java.math.BigDecimal'
+// import BigDecimal from 'java.math.BigDecimal'
+// import StringBuilder from 'java.lang.StringBuilder'
+// import java.math.BigDecimal;
+// #endif
+
+/**
+ * 乘法函数,用于处理浮点数乘法并保持精度。
+ * @param {number} num1 - 第一个乘数。
+ * @param {number} num2 - 第二个乘数。
+ * @returns {number} 乘法运算的结果,保留正确的精度。
+ */
+export function floatMul(num1 : number, num2 : number) : number {
+	if (!(isNumber(num1) || isNumber(num2))) {
+		console.warn('Please pass in the number type');
+		return NaN;
+	}
+	let m = 0;
+	// #ifdef APP-ANDROID
+	let	s1 = BigDecimal.valueOf(num1.toDouble()).toPlainString(); //new UTSNumber(num1).toString() // //`${num1.toFloat()}`// num1.toString(),
+	let	s2 = BigDecimal.valueOf(num2.toDouble()).toPlainString(); //new UTSNumber(num2).toString() //`${num2.toFloat()}`//.toString();
+	// #endif
+	// #ifndef APP-ANDROID
+	let	s1:string = `${num1}`// num1.toString(),
+	let	s2:string = `${num2}`//.toString();
+	// #endif
+	
+	try {
+		m += s1.split('.')[1].length;
+	} catch (error) { }
+	try {
+		m += s2.split('.')[1].length;
+	} catch (error) { }
+	
+	// #ifdef APP-ANDROID
+	return parseFloat(s1.replace('.', '')) * parseFloat(s2.replace('.', '')) / Math.pow(10, m);
+	// #endif
+	// #ifndef APP-ANDROID
+	return Number(s1.replace('.', '')) * Number(s2.replace('.', '')) / Math.pow(10, m);
+	// #endif
+}

+ 32 - 0
uni_modules/lime-shared/floatSub/index.ts

@@ -0,0 +1,32 @@
+import { isNumber } from '../isNumber';
+/**
+ * 减法函数,用于处理浮点数减法并保持精度。
+ * @param {number} num1 - 被减数。
+ * @param {number} num2 - 减数。
+ * @returns {number} 减法运算的结果,保留正确的精度。
+ */
+export function floatSub(num1 : number, num2 : number) : number {
+	if (!(isNumber(num1) || isNumber(num2))) {
+		console.warn('Please pass in the number type');
+		return NaN;
+	}
+	let r1:number, r2:number, m:number, n:number;
+	try {
+		r1 = num1.toString().split('.')[1].length;
+	} catch (error) {
+		r1 = 0;
+	}
+	try {
+		r2 = num2.toString().split('.')[1].length;
+	} catch (error) {
+		r2 = 0;
+	}
+	m = Math.pow(10, Math.max(r1, r2));
+	n = r1 >= r2 ? r1 : r2;
+	// #ifndef APP-ANDROID
+	return Number(((num1 * m - num2 * m) / m).toFixed(n));
+	// #endif
+	// #ifdef APP-ANDROID
+	return parseFloat(((num1 * m - num2 * m) / m).toFixed(n));
+	// #endif
+}

+ 53 - 0
uni_modules/lime-shared/getClassStr/index.ts

@@ -0,0 +1,53 @@
+// @ts-nocheck
+
+// #ifdef UNI-APP-X && APP
+import { isNumber } from '../isNumber'
+import { isString } from '../isString'
+import { isDef } from '../isDef'
+// #endif
+
+/**
+ * 获取对象的类名字符串
+ * @param obj - 需要处理的对象
+ * @returns 由对象属性作为类名组成的字符串
+ */
+export function getClassStr<T>(obj : T) : string {
+	let classNames : string[] = [];
+	// #ifdef UNI-APP-X && APP
+	if (obj instanceof UTSJSONObject) {
+		(obj as UTSJSONObject).toMap().forEach((value, key) => {
+			if (isDef(value)) {
+				if (isNumber(value)) {
+					classNames.push(key);
+				}
+				if (isString(value) && value !== '') {
+					classNames.push(key);
+				}
+				if (typeof value == 'boolean' && (value as boolean)) {
+					classNames.push(key);
+				}
+			}
+		})
+	} 
+	// #endif
+	// #ifndef UNI-APP-X && APP
+	// 遍历对象的属性
+	for (let key in obj) {
+		// 检查属性确实属于对象自身且其值为true
+		if ((obj as any).hasOwnProperty(key) && obj[key]) {
+			// 将属性名添加到类名数组中
+			classNames.push(key);
+		}
+	}
+	// #endif
+
+
+	// 将类名数组用空格连接成字符串并返回
+	return classNames.join(' ');
+}
+
+
+// 示例
+// const obj = { foo: true, bar: false, baz: true };
+// const classNameStr = getClassStr(obj);
+// console.log(classNameStr); // 输出: "foo baz"

+ 11 - 0
uni_modules/lime-shared/getCurrentPage/index.ts

@@ -0,0 +1,11 @@
+// @ts-nocheck
+// #ifndef UNI-APP-X && APP
+// export * from './vue.ts'
+export { getCurrentPage } from './vue.ts'
+// #endif
+
+
+// #ifdef UNI-APP-X && APP
+// export * from './uvue.uts'
+export { getCurrentPage } from './uvue.uts'
+// #endif

+ 5 - 0
uni_modules/lime-shared/getCurrentPage/uvue.uts

@@ -0,0 +1,5 @@
+// @ts-nocheck
+export const getCurrentPage = ():Page => {
+  const pages = getCurrentPages();
+  return pages[pages.length - 1]
+};

+ 6 - 0
uni_modules/lime-shared/getCurrentPage/vue.ts

@@ -0,0 +1,6 @@
+// @ts-nocheck
+/** 获取当前页 */
+export const getCurrentPage = () => {
+  const pages = getCurrentPages();
+  return pages[pages.length - 1] //as T & WechatMiniprogram.Page.TrivialInstance;
+};

+ 62 - 0
uni_modules/lime-shared/getLocalFilePath/index.ts

@@ -0,0 +1,62 @@
+// @ts-nocheck
+// #ifdef APP-NVUE  || APP-VUE
+export const getLocalFilePath = (path : string) => {
+	if (typeof plus == 'undefined') return path
+	if (/^(_www|_doc|_documents|_downloads|file:\/\/|\/storage\/emulated\/0\/)/.test(path)) return path
+	if (/^\//.test(path)) {
+		const localFilePath = plus.io.convertAbsoluteFileSystem(path)
+		if (localFilePath !== path) {
+			return localFilePath
+		} else {
+			path = path.slice(1)
+		}
+	}
+	return '_www/' + path
+}
+// #endif
+
+
+// #ifdef UNI-APP-X && APP
+export { getResourcePath as getLocalFilePath } from '@/uni_modules/lime-file-utils'
+// export const getLocalFilePath = (path : string) : string => {
+// 	let uri = path
+// 	if (uri.startsWith("http") || uri.startsWith("<svg") || uri.startsWith("data:image/svg+xml")) {
+// 		return uri
+// 	}
+// 	if (uri.startsWith("file://")) {
+// 		uri = uri.substring("file://".length)
+// 	} else if (uri.startsWith("unifile://")) {
+// 		uri = UTSAndroid.convert2AbsFullPath(uri)
+// 	} else {
+// 		uri = UTSAndroid.convert2AbsFullPath(uri)
+// 		if (uri.startsWith("/android_asset/")) {
+// 			uri = uri.replace("/android_asset/", "")
+// 		}
+// 	}
+// 	if (new File(uri).exists()) {
+// 		return uri
+// 	} else {
+// 		return null
+// 	}
+// 	// return UTSAndroid.convert2AbsFullPath(path)
+// }
+// #endif
+// #ifdef APP-IOS
+// export const getLocalFilePath = (path : string) : string => {
+// 	try {
+// 		let uri = path
+// 		if (uri.startsWith("http") || uri.startsWith("<svg") || uri.startsWith("data:image/svg+xml")) {
+// 			return uri
+// 		}
+// 		if (uri.startsWith("file://")) {
+// 			return uri.substring("file://".length)
+// 		} else if (path.startsWith("/var/")) {
+// 			return path
+// 		}
+// 		return UTSiOS.getResourcePath(path)
+// 	} catch (e) {
+// 		return null
+// 	}
+// 	// return UTSiOS.getResourcePath(path)
+// }
+// #endif

+ 138 - 0
uni_modules/lime-shared/getRect/index.ts

@@ -0,0 +1,138 @@
+// @ts-nocheck
+// #ifdef UNI-APP-X && APP
+// export * from './uvue.uts'
+export { getRect, getAllRect } from './uvue.uts'
+// #endif
+
+
+// #ifndef UNI-APP-X && APP
+// export * from './vue.ts'
+export { getRect, getAllRect } from './vue.ts'
+// #endif
+
+
+
+/**
+ * 获取视口滚动条位置信息
+ */
+export function getViewportScrollInfo() : Promise<any> {
+	return new Promise(resolve => {
+		uni.createSelectorQuery()
+			.selectViewport()
+			.scrollOffset((res) => {
+				resolve(res);
+			}).exec();
+	})
+}
+
+/**
+```
+                      page
+                     ╱
+    ╭───────────────╮    viewport
+  ╭─│─ ─ ─ ─ ─ ─ ─ ─│─╮ ╱
+  │ │ ╭───────────╮ │ │
+  │ │ │  element  │ │ │
+  │ │ ╰───────────╯ │ │
+  ╰─│─ ─ ─ ─ ─ ─ ─ ─│─╯
+    │               │
+    │               │
+    ╰───────────────╯
+```
+
+# 参数
+- viewportHeight: viewport 高度
+- viewportScrollTop: viewport 垂直滚动值
+- elementHeight: element 高度
+- elementOffsetTop: element 距离页面顶部距离
+
+# 选项
+- position: element 在视窗中的位置(start, center, end, nearest)
+- startOffset: element 距离视窗顶部的偏移量
+- endOffset: element 距离视窗底部的偏移量
+
+# 结果值
+- viewportScrollTop: viewport 新的垂直滚动值
+
+*/
+
+export type ScrollIntoViewOptions = {
+	/** 元素顶部需要保留的缓冲距离(默认 0) */
+	startOffset ?: number;
+	/** 元素底部需要保留的缓冲距离(默认 0) */
+	endOffset ?: number;
+	/** 滚动对齐方式:start/center/end/nearest(默认 nearest) */
+	position ?: 'start' | 'center' | 'end' | 'nearest';
+}
+
+/**
+ * 计算元素需要滚动到可视区域的目标滚动位置
+ * @param viewportHeight 视口高度(像素)
+ * @param viewportScrollTop 当前滚动位置(像素)
+ * @param elementHeight 元素高度(像素)
+ * @param elementOffsetTop 元素相对于父容器顶部的偏移量(像素)
+ * @param options 配置选项
+ * @returns 计算后的目标滚动位置(像素)
+ *
+ * @example
+ * // 示例:将元素滚动到视口顶部对齐
+ * const scrollTop = getScrollIntoViewValue(
+ *   500,  // 视口高度
+ *   200,  // 当前滚动位置
+ *   100,  // 元素高度
+ *   300,  // 元素偏移量
+ *   { position: 'start' }
+ * );
+ */
+export function getScrollIntoViewValue(
+	viewportHeight : number,
+	viewportScrollTop : number,
+	elementHeight : number,
+	elementOffsetTop : number,
+	options : ScrollIntoViewOptions = {}
+) : number {
+	let { startOffset = 0, endOffset = 0, position = 'nearest'} = options;
+
+	// 计算元素相对于视口的上下偏移量
+	const elementToViewportTopOffset = elementOffsetTop - viewportScrollTop - startOffset;
+	const elementToViewportBottomOffset =
+		elementOffsetTop +
+		elementHeight -
+		viewportScrollTop -
+		viewportHeight +
+		endOffset;
+
+	// 处理 nearest 模式,自动选择最近边缘
+	if (position == 'nearest') {
+		if (elementToViewportTopOffset >= 0 && elementToViewportBottomOffset <= 0) {
+			return viewportScrollTop;
+		}
+		position =
+			Math.abs(elementToViewportTopOffset) > Math.abs(elementToViewportBottomOffset)
+				? 'end'
+				: 'start';
+	}
+
+	// 根据不同的对齐位置计算目标滚动位置
+	let nextScrollTop = 0;
+	switch (position) {
+		case 'start':
+			// 顶部对齐:元素顶部对齐视口顶部(考虑顶部缓冲)
+			nextScrollTop = elementOffsetTop - startOffset;
+			break;
+		case 'center':
+			// 居中对齐:元素中心对齐视口中心(考虑上下缓冲)
+			nextScrollTop =
+				elementOffsetTop -
+				(viewportHeight - elementHeight - endOffset - startOffset) / 2 +
+				startOffset;
+			break;
+		case 'end':
+			// 底部对齐:元素底部对齐视口底部(考虑底部缓冲)
+			nextScrollTop =
+				elementOffsetTop + elementHeight - viewportHeight + endOffset;
+			break;
+	}
+
+	return nextScrollTop;
+}

+ 17 - 0
uni_modules/lime-shared/getRect/uvue.uts

@@ -0,0 +1,17 @@
+// @ts-nocheck
+export function getRect(selector : string, context: ComponentPublicInstance):Promise<NodeInfo> {
+	return new Promise((resolve)=>{
+		uni.createSelectorQuery().in(context).select(selector).boundingClientRect(res =>{
+			resolve(res as NodeInfo)
+		}).exec();
+	})
+}
+
+export function getAllRect(selector : string, context: ComponentPublicInstance):Promise<NodeInfo[]> {
+	return new Promise((resolve)=>{
+		uni.createSelectorQuery().in(context).selectAll(selector).boundingClientRect(res =>{
+			resolve(res as NodeInfo[])
+		}).exec();
+	})
+}
+

+ 117 - 0
uni_modules/lime-shared/getRect/vue.ts

@@ -0,0 +1,117 @@
+// @ts-nocheck
+
+// #ifdef APP-NVUE
+// 当编译环境是 APP-NVUE 时,引入 uni.requireNativePlugin('dom'),具体插件用途未知
+const dom = uni.requireNativePlugin('dom')
+// #endif
+
+/** 
+ * 获取节点信息
+ * @param selector 选择器字符串
+ * @param context ComponentInternalInstance 对象
+ * @param node 是否获取node
+ * @returns 包含节点信息的 Promise 对象
+ */
+export function getRect(selector : string, context : ComponentInternalInstance|ComponentPublicInstance, node: boolean = false) {
+	// 之前是个对象,现在改成实例,防止旧版会报错
+	if(context== null) {
+		return Promise.reject('context is null')
+	}
+	if(context.context){
+		context = context.context
+	}
+	// #ifdef MP || VUE2
+	if (context.proxy) context = context.proxy
+	// #endif
+	return new Promise<UniNamespace.NodeInfo>((resolve, reject) => {
+		// #ifndef APP-NVUE
+		const dom = uni.createSelectorQuery().in(context).select(selector);
+		const result = (rect: UniNamespace.NodeInfo) => {
+			if (rect) {
+				resolve(rect)
+			} else {
+				reject('no rect')
+			}
+		}
+		
+		if (!node) {
+			dom.boundingClientRect(result).exec()
+		} else {
+			dom.fields({
+				node: true,
+				size: true,
+				rect: true
+			}, result).exec()
+		}
+		// #endif
+		// #ifdef APP-NVUE
+		const refs = context.refs || context.$refs
+		if (/#|\./.test(selector) && refs) {
+			selector = selector.replace(/#|\./, '')
+			if (refs[selector]) {
+				selector = refs[selector]
+				if(Array.isArray(selector)) {
+					selector = selector[0]
+				}
+			}
+		}
+		dom.getComponentRect(selector, (res) => {
+			if (res.size) {
+				resolve(res.size)
+			} else {
+				reject('no rect')
+			}
+		})
+		// #endif
+	});
+};
+
+
+export function getAllRect(selector : string, context: ComponentInternalInstance|ComponentPublicInstance, node:boolean = false) {
+	if(context== null) {
+		return Promise.reject('context is null')
+	}
+	// #ifdef MP || VUE2
+	if (context.proxy) context = context.proxy
+	// #endif
+	return new Promise<UniNamespace.NodeInfo>((resolve, reject) => {
+		// #ifndef APP-NVUE
+		const dom = uni.createSelectorQuery().in(context).selectAll(selector);
+		const result = (rect: UniNamespace.NodeInfo[]) => {
+			if (rect) {
+				resolve(rect)
+			} else {
+				reject('no rect')
+			}
+		}
+		if (!node) {
+			dom.boundingClientRect(result).exec()
+		} else {
+			dom.fields({
+				node: true,
+				size: true,
+				rect: true
+			}, result).exec()
+		}
+		// #endif
+		// #ifdef APP-NVUE
+		let { context } = options
+		if (/#|\./.test(selector) && context.refs) {
+			selector = selector.replace(/#|\./, '')
+			if (context.refs[selector]) {
+				selector = context.refs[selector]
+				if(Array.isArray(selector)) {
+					selector = selector[0]
+				}
+			}
+		}
+		dom.getComponentRect(selector, (res) => {
+			if (res.size) {
+				resolve([res.size])
+			} else {
+				reject('no rect')
+			}
+		})
+		// #endif
+	});
+};

+ 54 - 0
uni_modules/lime-shared/getStyleStr/index.ts

@@ -0,0 +1,54 @@
+// @ts-nocheck
+// #ifndef UNI-APP-X && APP
+interface CSSProperties {
+	[key : string] : string | number | null
+}
+// #endif
+
+// #ifdef VUE3
+// #ifdef UNI-APP-X && APP
+type CSSProperties = UTSJSONObject
+// #endif
+// #endif
+/**
+ * 将字符串转换为带有连字符分隔的小写形式
+ * @param key - 要转换的字符串
+ * @returns 转换后的字符串
+ */
+export function toLowercaseSeparator(key : string):string {
+	return key.replace(/([A-Z])/g, '-$1').toLowerCase();
+}
+
+/**
+ * 获取样式对象对应的样式字符串
+ * @param style - CSS样式对象
+ * @returns 由非空有效样式属性键值对组成的字符串
+ */
+export function getStyleStr(style : CSSProperties) : string {
+	
+	// #ifdef UNI-APP-X && APP
+	let styleStr = '';
+	style.toMap().forEach((value, key) => {
+		if(value !== null && value != '') {
+			styleStr += `${toLowercaseSeparator(key as string)}: ${value};`
+		}
+	})
+	return styleStr
+	// #endif
+	// #ifndef UNI-APP-X && APP
+	return Object.keys(style)
+		.filter(
+			(key) => 
+				style[key] !== undefined && 
+				style[key] !== null && 
+				style[key] !== '')
+		.map((key : string) => `${toLowercaseSeparator(key)}: ${style[key]};`)
+		.join(' ');
+	// #endif
+}
+
+// 示例
+// const style = { color: 'red', fontSize: '16px', backgroundColor: '', border: null };
+// const styleStr = getStyleStr(style);
+// console.log(styleStr);
+// 输出: "color: red; font-size: 16px;"

+ 28 - 0
uni_modules/lime-shared/guid/index.ts

@@ -0,0 +1,28 @@
+/**
+ * 生成指定长度的伪随机字符串,通常用作唯一标识符(非标准GUID)
+ * 
+ * 此函数使用Math.random()生成基于36进制(数字+小写字母)的随机字符串。当长度超过11位时,
+ * 会通过递归拼接多个随机段实现。注意:该方法生成的并非标准GUID/UUID,不适合高安全性场景。
+ * 
+ * @param {number} [len=32] - 要生成的字符串长度,默认32位
+ * @returns {string} 生成的伪随机字符串,包含0-9和a-z字符
+ * 
+ * @example
+ * guid();    // 返回32位字符串,例如"3zyf6a5f3kb4ayy9jq9v1a70z0qdm0bk"
+ * guid(5);   // 返回5位字符串,例如"kf3a9"
+ * guid(20);  // 返回20位字符串,由两段随机字符串拼接而成
+ * 
+ * @note
+ * 1. 由于使用Math.random(),随机性存在安全缺陷,不适用于密码学用途
+ * 2. 当长度>11时采用递归拼接,可能略微影响性能(在极端大长度情况下)
+ * 3. 字符串补全时使用'0'填充,可能略微降低末尾字符的随机性
+ */
+export function guid(len:number = 32):string {
+	// crypto.randomUUID();
+	return len <= 11 
+		? Math.random()
+			.toString(36)
+			.substring(2, 2 + len)
+			.padEnd(len, '0')
+		: guid(11) + guid(len - 11);
+}

+ 11 - 0
uni_modules/lime-shared/hasOwn/index.ts

@@ -0,0 +1,11 @@
+// @ts-nocheck
+// #ifdef UNI-APP-X && APP
+// export * from './uvue.uts'
+export { hasOwn } from './uvue.uts'
+// #endif
+
+
+// #ifndef UNI-APP-X && APP
+// export * from './vue.ts'
+export { hasOwn } from './vue.ts'
+// #endif

+ 43 - 0
uni_modules/lime-shared/hasOwn/uvue.uts

@@ -0,0 +1,43 @@
+// @ts-nocheck
+/**
+ * 检查对象或数组是否具有指定的属性或键
+ * @param obj 要检查的对象或数组
+ * @param key 指定的属性或键
+ * @returns 如果对象或数组具有指定的属性或键,则返回true;否则返回false
+ */
+function hasOwn(obj: UTSJSONObject, key: string): boolean
+function hasOwn(obj: Map<string, unknown>, key: string): boolean
+function hasOwn(obj: any, key: string): boolean {
+  if(obj instanceof UTSJSONObject){
+	 return obj[key] != null
+  }
+  if(obj instanceof Map<string, unknown>){
+  	 return (obj as Map<string, unknown>).has(key)
+  }
+  if(typeof obj == 'object') {
+	const obj2 = {...toRaw(obj)}
+	return obj2[key] != null
+  }
+  return false
+}
+export {
+	hasOwn
+}
+// 示例
+// const obj = { name: 'John', age: 30 };
+
+// if (hasOwn(obj, 'name')) {
+//   console.log("对象具有 'name' 属性");
+// } else {
+//   console.log("对象不具有 'name' 属性");
+// }
+// // 输出: 对象具有 'name' 属性
+
+// const arr = [1, 2, 3];
+
+// if (hasOwn(arr, 'length')) {
+//   console.log("数组具有 'length' 属性");
+// } else {
+//   console.log("数组不具有 'length' 属性");
+// }
+// 输出: 数组具有 'length' 属性

+ 30 - 0
uni_modules/lime-shared/hasOwn/vue.ts

@@ -0,0 +1,30 @@
+// @ts-nocheck
+const hasOwnProperty = Object.prototype.hasOwnProperty
+/**
+ * 检查对象或数组是否具有指定的属性或键
+ * @param obj 要检查的对象或数组
+ * @param key 指定的属性或键
+ * @returns 如果对象或数组具有指定的属性或键,则返回true;否则返回false
+ */
+export function hasOwn(obj: Object | Array<any>, key: string): boolean {
+  return hasOwnProperty.call(obj, key);
+}
+
+// 示例
+// const obj = { name: 'John', age: 30 };
+
+// if (hasOwn(obj, 'name')) {
+//   console.log("对象具有 'name' 属性");
+// } else {
+//   console.log("对象不具有 'name' 属性");
+// }
+// // 输出: 对象具有 'name' 属性
+
+// const arr = [1, 2, 3];
+
+// if (hasOwn(arr, 'length')) {
+//   console.log("数组具有 'length' 属性");
+// } else {
+//   console.log("数组不具有 'length' 属性");
+// }
+// 输出: 数组具有 'length' 属性

+ 43 - 0
uni_modules/lime-shared/index.ts

@@ -0,0 +1,43 @@
+// @ts-nocheck
+// validator
+// export * from './isString'
+// export * from './isNumber'
+// export * from './isNumeric'
+// export * from './isDef'
+// export * from './isFunction'
+// export * from './isObject'
+// export * from './isPromise'
+// export * from './isBase64'
+
+// export * from './hasOwn'
+
+// // 单位转换
+// export * from './addUnit'
+// export * from './unitConvert'
+// export * from './toNumber'
+
+// export * from './random'
+// export * from './range'
+// export * from './fillZero'
+
+// // image 
+// export * from './base64ToPath'
+// export * from './pathToBase64'
+// export * from './exif'
+
+// // canvas
+// export * from './canIUseCanvas2d'
+
+// // page
+// export * from './getCurrentPage'
+
+// // dom
+// export * from './getRect'
+// export * from './selectComponent'
+// export * from './createAnimation'
+
+// // delay
+// export * from './sleep'
+// export * from './debounce'
+// export * from './throttle'
+

+ 23 - 0
uni_modules/lime-shared/isBase64/index.ts

@@ -0,0 +1,23 @@
+// @ts-nocheck
+
+/**
+ * 判断一个字符串是否为Base64编码。
+ * Base64编码的字符串只包含A-Z、a-z、0-9、+、/ 和 = 这些字符。
+ * @param {string} str - 要检查的字符串。
+ * @returns {boolean} 如果字符串是Base64编码,返回true,否则返回false。
+ */
+export function isBase64(str: string): boolean {
+    const base64Regex = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
+    return base64Regex.test(str);
+}
+
+/**
+ * 判断一个字符串是否为Base64编码的data URI。
+ * Base64编码的data URI通常以"data:"开头,后面跟着MIME类型和编码信息,然后是Base64编码的数据。
+ * @param {string} str - 要检查的字符串。
+ * @returns {boolean} 如果字符串是Base64编码的data URI,返回true,否则返回false。
+ */
+export function isDataURI(str: string): boolean {
+    const dataUriRegex = /^data:([a-zA-Z]+\/[a-zA-Z0-9-+.]+)(;base64)?,([a-zA-Z0-9+/]+={0,2})$/;
+    return dataUriRegex.test(str);
+}

+ 24 - 0
uni_modules/lime-shared/isBoolean/index.ts

@@ -0,0 +1,24 @@
+/**
+ * 检查一个值是否为严格的布尔值(仅限 `true` 或 `false`)
+ * 
+ * @example
+ * isBoolean(true);   // true
+ * isBoolean(false);  // true
+ * isBoolean(0);      // false
+ * isBoolean(null);   // false
+ * 
+ * @param {unknown} value - 要检查的值
+ * @returns {value is boolean} 如果值是 `true` 或 `false` 则返回 `true`,否则返回 `false`
+ * 
+ * @description
+ * 此函数使用严格相等(`===`)检查,避免隐式类型转换。
+ * 注意:不适用于 `Boolean` 包装对象(如 `new Boolean(true)`)。
+ */
+export function isBoolean(value: any|null): boolean {
+	// #ifdef APP-ANDROID
+	return value == true || value == false
+	// #endif
+	// #ifndef APP-ANDROID
+	return value === true || value === false
+	// #endif
+}

+ 8 - 0
uni_modules/lime-shared/isBrowser/index.ts

@@ -0,0 +1,8 @@
+// @ts-nocheck
+// #ifdef WEB
+export const isBrowser = typeof window !== 'undefined';
+// #endif
+
+// #ifndef WEB
+export const isBrowser = false;
+// #endif

+ 86 - 0
uni_modules/lime-shared/isByteLength/index.ts

@@ -0,0 +1,86 @@
+// @ts-nocheck
+// import assertString from './util/assertString';
+
+/**
+ * 字节长度验证配置选项
+ */
+export type IsByteLengthOptions = {
+	/** 允许的最小字节长度 */
+	min ?: number;
+	/** 允许的最大字节长度 */
+	max ?: number;
+}
+
+/**
+ * 检查字符串字节长度是否在指定范围内
+ * @function
+ * @overload 使用配置对象
+ * @param str - 要检查的字符串
+ * @param options - 配置选项对象
+ * @returns 是否满足字节长度要求
+ *
+ * @overload 使用独立参数
+ * @param str - 要检查的字符串
+ * @param min - 最小字节长度
+ * @param max - 最大字节长度(可选)
+ * @returns 是否满足字节长度要求
+ *
+ * @example
+ * // 使用配置对象
+ * isByteLength('🇨🇳', { min: 4, max: 8 }); // true(unicode 国旗符号占 8 字节)
+ *
+ * @example
+ * // 旧式参数调用
+ * isByteLength('hello', 3, 7); // true(实际字节长度 5)
+ *
+ * @description
+ * 1. 使用 URL 编码计算字节长度(更准确处理多字节字符)
+ * 2. 同时支持两种参数格式:
+ *    - 配置对象格式 { min, max }
+ *    - 独立参数格式 (min, max)
+ * 3. 不传 max 参数时只验证最小长度
+ * 4. 严格空值处理,允许设置 0 值
+ */
+export function isByteLength(str : string, optionsOrMin ?: IsByteLengthOptions) : boolean;
+export function isByteLength(str : string, optionsOrMin ?: number) : boolean;
+export function isByteLength(str : string, optionsOrMin : number, maxParam : number | null) : boolean;
+export function isByteLength(
+	str : string,
+	optionsOrMin ?: IsByteLengthOptions | number,
+	maxParam : number | null = null
+) : boolean {
+	// assertString(str);
+
+	/** 最终计算的最小长度 */
+	let min: number;
+
+	/** 最终计算的最大长度 */
+	let max : number | null;
+
+	// 参数逻辑处理
+	if (optionsOrMin != null && typeof optionsOrMin == 'object') {
+		// 使用对象配置的情况
+		const options = optionsOrMin as IsByteLengthOptions;
+		min = Math.max(options.min ?? 0, 0);  // 确保最小值为正整数
+		max = options.max;
+	} else {
+		// 使用独立参数的情况
+		min = Math.max(
+			typeof optionsOrMin == 'number' ? optionsOrMin : 0,
+			0
+		);
+		max = maxParam;
+	}
+
+	// URL 编码后的字节长度计算
+	const encoded = encodeURI(str);
+	const len = (encoded?.split(/%..|./).length ?? 0) - 1;
+
+	// 执行验证逻辑
+	// #ifndef APP-ANDROID
+	return len >= min && (typeof max == 'undefined' || len <= (max ?? 0));
+	// #endif
+	// #ifdef APP-ANDROID
+	return len >= min && (max == null || len <= max);
+	// #endif
+}

+ 189 - 0
uni_modules/lime-shared/isDate/index.ts

@@ -0,0 +1,189 @@
+// @ts-nocheck
+
+/**
+ * 日期验证配置选项
+ */
+export type IsDateOptions = {
+	/** 日期格式字符串,默认 'YYYY/MM/DD' */
+	format ?: string;
+	/** 允许的分隔符数组,默认 ['/', '-'] */
+	delimiters ?: string[];
+	/** 是否严格匹配格式,默认 false */
+	strictMode ?: boolean;
+}
+
+/**
+ * 验证日期格式字符串是否合法
+ * @param format - 需要验证的格式字符串
+ * @returns 是否合法格式
+ */
+function isValidFormat(format : string) : boolean {
+	return /(^(y{4}|y{2})[年./-](m{1,2})[月./-](d{1,2}(日)?)$)|(^(m{1,2})[./-](d{1,2})[./-]((y{4}|y{2})$))|(^(d{1,2})[./-](m{1,2})[./-]((y{4}|y{2})$))/i.test(format);
+}
+
+/**
+ * 将日期部分和格式部分组合成键值对数组
+ * @param date - 分割后的日期部分数组
+ * @param format - 分割后的格式部分数组
+ * @returns 组合后的二维数组
+ */
+function zip(date : string[], format : string[]) : string[][] {
+	const zippedArr : string[][] = [];
+	const len = Math.max(date.length, format.length);
+
+	for (let i = 0; i < len; i++) {
+		const key = i < date.length ? date[i] : ''
+		const value = i < format.length ? format[i] : ''
+
+		zippedArr.push([key, value])
+	}
+
+	return zippedArr;
+}
+
+
+/** 验证日期对象 */
+function validateDateObject(date : Date, strictMode : boolean) : boolean {
+	// #ifndef APP-ANDROID
+	return !strictMode && Object.prototype.toString.call(date) === '[object Date]' && !isNaN(date.getTime());
+	// #endif
+	// #ifdef APP-ANDROID
+	return !strictMode && !isNaN(date.getTime())
+	// #endif
+}
+
+
+function escapeRegExp(str: string): string {
+	return str//.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+}
+
+function enhancedSplit(
+	str: string,
+	delimiters: string[]
+): string[] {
+	// 构建动态分隔符正则表达式
+	const escapedDelimiters = delimiters.map(d => escapeRegExp(d));
+	const pattern = new RegExp(
+		`[${escapedDelimiters.join('')}]+`, // 匹配任意允许的分隔符
+		'g'
+	);
+	
+	return str.split(pattern).filter(p => p != '');
+}
+
+/**
+ * 验证输入是否为有效日期
+ * @param input - 输入值,可以是字符串或 Date 对象
+ * @param options - 配置选项,可以是字符串(简写格式)或配置对象
+ * @returns 是否为有效日期
+ * 
+ * @example
+ * isDate('2023/12/31'); // true
+ * isDate(new Date()); // true
+ * isDate('02-29-2023', { strictMode: true }); // false(2023年不是闰年)
+ */
+export function isDate(input : Date, options ?: IsDateOptions) : boolean;
+export function isDate(input : string, options ?: string | IsDateOptions) : boolean;
+export function isDate(input : string | Date, options : string | IsDateOptions | null = null) : boolean {
+	// 处理参数重载:允许第二个参数直接传格式字符串
+	// Date对象验证
+
+
+	let format = 'YYYY/MM/DD'
+	let delimiters = ['/', '-']
+	let strictMode = false
+
+
+	if (options != null) {
+		if (typeof options == 'string') {
+			format = options as string
+		} else {
+			format = (options as IsDateOptions).format ?? format
+			delimiters = (options as IsDateOptions).delimiters ?? delimiters
+			strictMode = (options as IsDateOptions).strictMode ?? strictMode
+		}
+	}
+	if (input instanceof Date) {
+		return validateDateObject(input, strictMode);
+	}
+
+
+	// 字符串类型验证
+	if (!isValidFormat(format)) return false;
+	// 严格模式长度检查
+	if (strictMode && input.length != format.length) {
+		return false;
+	}
+	// 获取格式中的分隔符
+	const formatDelimiter = delimiters.find((d) : boolean => format.indexOf(d) != -1);
+	// 获取实际使用的分隔符
+	const dateDelimiter = strictMode
+		? formatDelimiter
+		: delimiters.find((d) : boolean => input.indexOf(d) != -1);
+	// 分割日期和格式
+	const dateParts = strictMode ? enhancedSplit(input, delimiters) : input.split(dateDelimiter ?? '');
+	const formatParts = strictMode ? enhancedSplit(format.toLowerCase(), delimiters) : format.toLowerCase().split(formatDelimiter ?? '');
+	// 组合成键值对
+	const dateAndFormat = zip(dateParts, formatParts);
+	const dateObj = new Map<string, string>();
+
+
+	// 解析日期组成部分
+	for (const [dateWord, formatWord] of dateAndFormat) {
+		if (dateWord == '' || formatWord == '' || dateWord.length != formatWord.length) {
+			return false;
+		}
+		dateObj.set(formatWord.charAt(0), dateWord)
+	}
+
+	// 年份处理
+	let fullYear = dateObj.get('y');
+
+	if (fullYear == null) return false;
+
+	// 检查年份前导负号
+	if (fullYear.startsWith('-')) return false;
+
+	// 两位年份转四位
+	if (fullYear.length == 2) {
+		const parsedYear = parseInt(fullYear, 10);
+
+		if (isNaN(parsedYear)) {
+			return false;
+		}
+
+		const currentYear = new Date().getFullYear();
+		const century = currentYear - (currentYear % 100);
+		fullYear = (parseInt(fullYear, 10) < (currentYear % 100))
+			? `${century + 100 + parseInt(fullYear, 10)}`
+			: `${century + parseInt(fullYear, 10)}`;
+	}
+
+	// 月份补零
+	const month = dateObj.get('m')?.padStart(2, '0') ?? '';
+	// 日期补零
+	const day = dateObj.get('d')?.padStart(2, '0') ?? '';
+
+	const isoDate = `${fullYear}-${month}-${day}T00:00:00.000Z`;
+
+	// return new Date(time).getDate() == parseInt(day);
+
+	// 构造 ISO 日期字符串验证
+	try {
+		// #ifndef APP-ANDROID
+		const date = new Date(isoDate);
+		return date.getUTCDate() === parseInt(day, 10) &&
+			(date.getUTCMonth() + 1) === parseInt(month, 10) &&
+			date.getUTCFullYear() === parseInt(fullYear, 10);
+		// #endif
+		// #ifdef APP-ANDROID
+		const date = new Date(isoDate);
+		return date.getDate() == parseInt(day, 10) &&
+			(date.getMonth() + 1) == parseInt(month, 10) &&
+			date.getFullYear() == parseInt(fullYear, 10);
+		// #endif
+	} catch {
+		return false;
+	}
+
+}

+ 23 - 0
uni_modules/lime-shared/isDef/index.ts

@@ -0,0 +1,23 @@
+// @ts-nocheck
+/**
+ * 检查一个值是否已定义(不为 undefined)且不为 null
+ * @param value 要检查的值
+ * @returns 如果值已定义且不为 null,则返回 true;否则返回 false
+ */
+// #ifndef UNI-APP-X
+export function isDef(value: unknown): boolean {
+  return value !== undefined && value !== null;
+}
+// #endif
+
+
+// #ifdef UNI-APP-X
+export function isDef(value : any|null) : boolean {
+	// #ifdef UNI-APP-X && APP
+	return value != null;
+	// #endif
+	// #ifndef UNI-APP-X && APP
+	return value != null && value != undefined;
+	// #endif
+}
+// #endif

+ 11 - 0
uni_modules/lime-shared/isEmail/index.ts

@@ -0,0 +1,11 @@
+// @ts-nocheck
+
+/**
+ * 验证电子邮件地址格式
+ * @param email - 要验证的字符串
+ * @returns 是否通过验证
+ */
+export function isEmail(email : string) : boolean {
+	const emailRegex = /\S+@\S+\.\S+/;
+	return emailRegex.test(email);
+}

+ 81 - 0
uni_modules/lime-shared/isEmpty/index.ts

@@ -0,0 +1,81 @@
+// @ts-nocheck
+import {isDef} from '../isDef'
+import {isString} from '../isString'
+import {isNumber} from '../isNumber'
+/**
+ * 判断一个值是否为空。
+ *
+ * 对于字符串,去除首尾空格后判断长度是否为0。
+ * 对于数组,判断长度是否为0。
+ * 对于对象,判断键的数量是否为0。
+ * 对于null或undefined,直接返回true。
+ * 其他类型(如数字、布尔值等)默认不为空。
+ *
+ * @param {any} value - 要检查的值。
+ * @returns {boolean} 如果值为空,返回true,否则返回false。
+ */
+
+
+// #ifdef UNI-APP-X && APP
+export function isEmpty(value : any | null) : boolean {
+	// 为null
+	if(!isDef(value)){
+		return true
+	}
+	// 为空字符
+	if(isString(value)){
+		return value.toString().trim().length == 0
+	}
+	// 为数值
+	if(isNumber(value)){
+		return false
+	}
+	if(typeof value == 'object'){
+		// 数组
+		if(Array.isArray(value)){
+			return (value as Array<unknown>).length == 0
+		}
+		// Map
+		if(value instanceof Map<unknown, unknown>) {
+			return value.size == 0
+		}
+		// Set
+		if(value instanceof Set<unknown>) {
+			return value.size == 0
+		}
+		if(value instanceof UTSJSONObject) {
+			return value.toMap().size == 0
+		}
+		return JSON.stringify(value) == '{}'
+	}
+	return false
+}
+// #endif
+
+
+// #ifndef UNI-APP-X && APP
+export function isEmpty(value: any): boolean {
+    // 检查是否为null或undefined
+    if (value == null || value == undefined || value == '') {
+        return true;
+    }
+
+    // 检查字符串是否为空
+    if (typeof value === 'string') {
+        return value.trim().length === 0;
+    }
+
+    // 检查数组是否为空
+    if (Array.isArray(value)) {
+        return value.length === 0;
+    }
+
+    // 检查对象是否为空
+    if (typeof value === 'object') {
+        return Object.keys(value).length === 0;
+    }
+
+    // 其他类型(如数字、布尔值等)不为空
+    return false;
+}
+// #endif

+ 16 - 0
uni_modules/lime-shared/isFunction/index.ts

@@ -0,0 +1,16 @@
+// @ts-nocheck
+/**
+ * 检查一个值是否为函数类型
+ * @param val 要检查的值
+ * @returns 如果值的类型是函数类型,则返回 true;否则返回 false
+ */
+
+// #ifdef UNI-APP-X && APP
+export const isFunction = (val: any):boolean => typeof val == 'function';
+ // #endif
+
+
+// #ifndef UNI-APP-X && APP
+export const isFunction = (val: unknown): val is Function =>
+  typeof val === 'function';
+// #endif

+ 64 - 0
uni_modules/lime-shared/isIP/index.ts

@@ -0,0 +1,64 @@
+// @ts-nocheck
+
+// #ifndef APP-ANDROID || APP-HARMONY || APP-IOS
+type UTSJSONObject = {
+	version : string | number | null;
+};
+// #endif
+// #ifdef APP-ANDROID || APP-HARMONY || APP-IOS
+// type Options = UTSJSONObject
+// #endif
+
+const IPv4SegmentFormat = '(?:[0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])';
+const IPv4AddressFormat = `(${IPv4SegmentFormat}\\.){3}${IPv4SegmentFormat}`;
+const IPv4AddressRegExp = new RegExp(`^${IPv4AddressFormat}$`);
+
+const IPv6SegmentFormat = '(?:[0-9a-fA-F]{1,4})';
+const IPv6AddressRegExp = new RegExp(
+	'^(' +
+	`(?:${IPv6SegmentFormat}:){7}(?:${IPv6SegmentFormat}|:)|` +
+	`(?:${IPv6SegmentFormat}:){6}(?:${IPv4AddressFormat}|:${IPv6SegmentFormat}|:)|` +
+	`(?:${IPv6SegmentFormat}:){5}(?::${IPv4AddressFormat}|(:${IPv6SegmentFormat}){1,2}|:)|` +
+	`(?:${IPv6SegmentFormat}:){4}(?:(:${IPv6SegmentFormat}){0,1}:${IPv4AddressFormat}|(:${IPv6SegmentFormat}){1,3}|:)|` +
+	`(?:${IPv6SegmentFormat}:){3}(?:(:${IPv6SegmentFormat}){0,2}:${IPv4AddressFormat}|(:${IPv6SegmentFormat}){1,4}|:)|` +
+	`(?:${IPv6SegmentFormat}:){2}(?:(:${IPv6SegmentFormat}){0,3}:${IPv4AddressFormat}|(:${IPv6SegmentFormat}){1,5}|:)|` +
+	`(?:${IPv6SegmentFormat}:){1}(?:(:${IPv6SegmentFormat}){0,4}:${IPv4AddressFormat}|(:${IPv6SegmentFormat}){1,6}|:)|` +
+	`(?::((?::${IPv6SegmentFormat}){0,5}:${IPv4AddressFormat}|(?::${IPv6SegmentFormat}){1,7}|:))` +
+	')(%[0-9a-zA-Z.]{1,})?$'
+);
+
+
+/**
+ * 验证IP地址格式
+ * @param {string} ipAddress - 要验证的IP地址
+ * @param {Options|string|number} options - 配置选项或版本号
+ * @returns {boolean} 是否匹配有效的IP地址格式
+ */
+export function isIP(ipAddress : string | null, options : UTSJSONObject | string | number | null = null) : boolean {
+	// assertString(ipAddress);
+	if(ipAddress == null) return false
+	let version : string | number | null;
+
+	if (typeof options == 'object') {
+		version = (options as UTSJSONObject|null)?.['version'];
+	} else {
+		version = options;
+	}
+
+	const versionStr = version != null ? `${version}` : '';
+
+	if (versionStr == '') {
+		return isIP(ipAddress, 4) || isIP(ipAddress, 6);
+	}
+
+	if (versionStr == '4') {
+		return IPv4AddressRegExp.test(ipAddress.trim());
+	}
+
+	if (versionStr == '6') {
+		return IPv6AddressRegExp.test(ipAddress.trim());
+	}
+
+	return false;
+}
+

+ 26 - 0
uni_modules/lime-shared/isNumber/index.ts

@@ -0,0 +1,26 @@
+// @ts-nocheck
+/**
+ * 检查一个值是否为数字类型
+ * @param value 要检查的值,可以是 number 类型或 string 类型的数字
+ * @returns 如果值是数字类型且不是 NaN,则返回 true;否则返回 false
+ */
+
+// #ifndef UNI-APP-X
+export function isNumber(value: number | string | null): boolean {
+  return typeof value === 'number' && !isNaN(value);
+}
+// #endif
+
+// #ifdef UNI-APP-X
+export function isNumber(value: any|null): boolean {
+	// #ifdef APP-ANDROID
+	return ['Byte', 'UByte','Short','UShort','Int','UInt','Long','ULong','Float','Double','number'].includes(typeof value)
+	// #endif
+	// #ifdef APP-IOS
+	return ['Int8', 'UInt8','Int16','UInt16','Int32','UInt32','Int64','UInt64','Int','UInt','Float','Float16','Float32','Float64','Double', 'number'].includes(typeof value)
+	// #endif
+	// #ifndef APP-ANDROID || APP-IOS
+	return typeof value === 'number' && !isNaN(value);
+	// #endif
+}
+// #endif

+ 33 - 0
uni_modules/lime-shared/isNumeric/index.ts

@@ -0,0 +1,33 @@
+// @ts-nocheck
+
+/**
+ * 检查一个值是否为数字类型或表示数字的字符串
+ * @param value 要检查的值,可以是 string 类型或 number 类型
+ * @returns 如果值是数字类型或表示数字的字符串,则返回 true;否则返回 false
+ */
+
+// #ifndef UNI-APP-X && APP
+export function isNumeric(value: string | number | undefined | null): boolean {
+  return /^(-)?\d+(\.\d+)?$/.test(value);
+}
+// #endif
+
+
+// #ifdef UNI-APP-X && APP
+import {isNumber} from '../isNumber';
+import {isString} from '../isString';
+export function isNumeric(value : any|null) : boolean {
+	if(value == null) {
+		return false
+	}
+	if(isNumber(value)) {
+		return true
+	} else if(isString(value)) {
+		// const regex = "-?\\d+(\\.\\d+)?".toRegex()
+		const regex = new RegExp("^(-)?\\d+(\\.\\d+)?$")
+		return  regex.test(value as string) //regex.matches(value as string) 
+	}
+	return false
+	// return /^(-)?\d+(\.\d+)?$/.test(value);
+}
+// #endif

+ 19 - 0
uni_modules/lime-shared/isObject/index.ts

@@ -0,0 +1,19 @@
+// @ts-nocheck
+/**
+ * 检查一个值是否为对象类型
+ * @param val 要检查的值
+ * @returns 如果值的类型是对象类型,则返回 true;否则返回 false
+ */
+
+// #ifndef APP-ANDROID
+export const isObject = (val : unknown) : val is Record<any, any> =>
+	val !== null && typeof val === 'object';
+	
+// #endif
+
+
+// #ifdef APP-ANDROID
+export const isObject = (val : any | null) : boolean =>{
+	return val != null && typeof val == 'object';
+}
+// #endif

+ 22 - 0
uni_modules/lime-shared/isPromise/index.ts

@@ -0,0 +1,22 @@
+// @ts-nocheck
+import {isFunction} from '../isFunction'
+import {isObject} from '../isObject'
+/**
+ * 检查一个值是否为 Promise 类型
+ * @param val 要检查的值
+ * @returns 如果值的类型是 Promise 类型,则返回 true;否则返回 false
+ */
+// #ifndef APP-ANDROID
+export const isPromise = <T = any>(val: unknown): val is Promise<T> => {
+  // 使用 isObject 函数判断值是否为对象类型
+  // 使用 isFunction 函数判断值是否具有 then 方法和 catch 方法
+  return isObject(val) && isFunction(val.then) && isFunction(val.catch);
+};
+// #endif
+
+
+// #ifdef APP-ANDROID
+export const isPromise = (val: any): boolean => {
+  return val instanceof Promise<unknown>
+};
+// #endif

+ 33 - 0
uni_modules/lime-shared/isRegExp/index.ts

@@ -0,0 +1,33 @@
+// @ts-nocheck
+/**
+ * 检测输入值是否为正则表达式对象
+ * @param obj - 需要检测的任意类型值
+ * @returns 如果检测值是正则表达式返回 true,否则返回 false
+ * 
+ * @example
+ * // 基础检测
+ * isRegExp(/abc/);                // true
+ * isRegExp(new RegExp('abc'));    // true
+ * 
+ * @example
+ * // 非正则表达式检测
+ * isRegExp('hello');              // false
+ * isRegExp({});                   // false
+ * isRegExp(null);                 // false
+ * 
+ * @description
+ * 1. 通过 Object.prototype.toString 的可靠类型检测
+ * 2. 支持跨执行环境的可靠检测:
+ *    - 浏览器多 iframe 环境
+ *    - Node.js 的 vm 模块
+ * 3. 比 instanceof 检测更可靠
+ * 4. 支持 ES3+ 全环境兼容
+ */
+export function isRegExp(obj : any) : boolean {
+	// #ifndef APP-ANDROID
+	return Object.prototype.toString.call(obj) === '[object RegExp]';
+	// #endif
+	// #ifdef APP-ANDROID
+	return obj instanceof RegExp//Object.prototype.toString.call(obj) === '[object RegExp]';
+	// #endif
+}

+ 19 - 0
uni_modules/lime-shared/isString/index.ts

@@ -0,0 +1,19 @@
+// @ts-nocheck
+/**
+ * 检查一个值是否为字符串类型
+ * @param str 要检查的值
+ * @returns 如果值的类型是字符串类型,则返回 true;否则返回 false
+ */
+// #ifndef UNI-APP-X && APP
+// export const isString = (str: unknown): str is string => typeof str === 'string';
+export function isString (str: unknown): str is string {
+	return typeof str == 'string'
+}
+// #endif
+
+
+// #ifdef UNI-APP-X && APP
+export function isString (str: any|null): boolean {
+	return typeof str == 'string'
+}
+// #endif

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů