commit a3d1d75a5423cb8db8d3007fda264a7e504d7d15 Author: hengtou <717691034@qq.com> Date: Mon Dec 2 17:22:50 2024 +0800 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..58138f3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +.DS_Store +node_modules/ +dist/ +unpackage/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* +package-lock.json +tests/**/coverage/ + + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln diff --git a/.hbuilderx/launch.json b/.hbuilderx/launch.json new file mode 100644 index 0000000..1b93662 --- /dev/null +++ b/.hbuilderx/launch.json @@ -0,0 +1,21 @@ +{ + "version" : "1.0", + "configurations" : [ + { + "default" : + { + "launchtype" : "local" + }, + "h5" : + { + "launchtype" : "local" + }, + "mp-weixin" : + { + "launchtype" : "local" + }, + "provider" : "aliyun", + "type" : "uniCloud" + } + ] +} diff --git a/API/index.js b/API/index.js new file mode 100644 index 0000000..e418d77 --- /dev/null +++ b/API/index.js @@ -0,0 +1,711 @@ +import { + httpUrlFormat, + ajaxCarryAuthorization,ajaxSync +} from '@/utils/httpUtils.js' + +import { ApiVersion,AppVersion } from '@/config/baseConfig.js' + +const headerVersion = { + 'API-Version': ApiVersion(), + 'APP-Version':AppVersion() +} + +const _flag = 'apiBaseUrl' // 请求的api空间 + +const apiUrl = { + 'boxesPinnedApi': httpUrlFormat('/boxes/pinned', _flag), + 'boxesTagsApi': httpUrlFormat('/boxes/tags', _flag), + 'boxesApi': httpUrlFormat('/boxes', _flag), + 'boxRecordApi': httpUrlFormat('/box/record', _flag), + 'boxOrderApi': httpUrlFormat('/box/order', _flag), + 'boxOrderReviewApi': httpUrlFormat('/box/order/review', _flag), + 'boxOrderPaidApi': httpUrlFormat('/box/order/paid', _flag), + 'orderPaidApi': httpUrlFormat('/order/paid', _flag), + 'boxRecordResultApi': httpUrlFormat('/box/record/result', _flag), + 'boxDeliveryPreviewApi': httpUrlFormat('/order/box/delivery/preview', _flag), + 'boxDeliveryApi': httpUrlFormat('/order/box/delivery', _flag), + 'boxActivityApi': httpUrlFormat('/boxes/activity', _flag),//活动盲盒 + 'boxActivityListApi': httpUrlFormat('/boxes/activity/list', _flag),//活动盲盒 + 'promptCountApi': httpUrlFormat('/user/prompt/count', _flag),//用户提示卡数量 + 'usePromptApi': httpUrlFormat('/box/order/use/prompt', _flag),//使用提示卡 + 'activityDetailApi': httpUrlFormat('/boxes/activity/detail', _flag),// + 'activityDetailSourceApi': httpUrlFormat('/boxes/activity/detail/source', _flag),// + 'activityBuyApi': httpUrlFormat('/coin/gear/activity/box', _flag),//活动盲盒购买 + 'activitySourceBuyApi': httpUrlFormat('/box/order/activity/source', _flag),//活动盲盒购买 + + 'activityReviewApi': httpUrlFormat('/box/order/activity/review', _flag),//活动盲盒订单预览 + 'activityReviewSourceApi': httpUrlFormat('/box/order/activity/review/source', _flag),//活动盲盒订单预览-新 + + 'activityOrderApi': httpUrlFormat('/box/order/activity', _flag), + 'recoveryBatchApi': httpUrlFormat('/box/record/recovery/batch', _flag), + 'deliveryReviewBatchApi': httpUrlFormat('/order/box/delivery/preview/batch', _flag), + 'deliveryBatchApi': httpUrlFormat('/order/box/delivery/batch', _flag), + 'promptExchangeBatchApi': httpUrlFormat('/user/prompt/exchange/batch', _flag), + 'boxResultApi': httpUrlFormat('/misc/box/result', _flag), + 'noOpenListApi': httpUrlFormat('/box/record/no/open/list', _flag),//未开奖记录 + 'openListApi': httpUrlFormat('/box/record/open', _flag),//开奖记录 + 'boxesChannelPinnedApi': httpUrlFormat('/boxes/channel/pinned', _flag),//首页盲盒-渠道 + + + + + + + 'orderReceive': httpUrlFormat('/order/receive', _flag), + 'orderList': httpUrlFormat('/order/mall_order', _flag), + 'boxOrder': httpUrlFormat('/order/box_order', _flag), + 'boxRecord': httpUrlFormat('/order/box_record', _flag), + 'boxOpen': httpUrlFormat('/order/box_open', _flag), + 'boxPickup': httpUrlFormat('/order/box_pickup', _flag), + 'boxRecycle': httpUrlFormat('/order/box_recycle', _flag), + 'boxInfo': httpUrlFormat('/order/box_info', _flag), + 'orderCancel': httpUrlFormat('/order/cancel', _flag), + 'boxOpenByBoxId': httpUrlFormat('/order/box_open_by_box_id', _flag), + + 'popupAdPageApi': httpUrlFormat('/misc/popup/ad/page', _flag), + 'popupAdPageChannelApi': httpUrlFormat('/misc/popup/ad/page/channel', _flag), + + + + 'activityIconApi': httpUrlFormat('/activity/icon', _flag), + 'activityDetailNewApi': httpUrlFormat('/activity/detail', _flag), + + + 'pointClearApi': httpUrlFormat('/user/point/clear', _flag), + 'activityTaskAwardApi': httpUrlFormat('/activity/task/award', _flag), + + + + + 'activityTaskCreateApi': httpUrlFormat('/box/order/activity/create', _flag), + 'freeBoxApi': httpUrlFormat('/boxes/free/box', _flag), + 'activityGuideApi': httpUrlFormat('/activity/guide', _flag), + + + 'indexGuideApi': httpUrlFormat('/user/index/guide', _flag), + + 'activityTopLastApi': httpUrlFormat('/activity/top/last', _flag), + + + + +} + + + + +export function boxRecoveryApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: httpUrlFormat(`/box/record/recovery/${data.id}`, _flag), + method: 'PUT', + data + }) +} +//分页盲盒 +export function boxesApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxesApi, + method: 'GET', + data: data + }) +} +//首页盲盒 +export function boxesPinnedApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.boxesPinnedApi, + method: 'GET', + data: data + }) +} +//盲盒标签 +export function boxesTagsApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxesTagsApi, + method: 'GET', + data: data + }) +} + +//盲盒开奖记录 +export function boxRecordApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxRecordApi, + method: 'GET', + data: data + }) +} +// 盲盒详情 +export function boxesDetail(data,header = {}) { + const headerObj = {...headerVersion,...header} + // header['API-Version'] = ApiVersion() + return ajaxCarryAuthorization({ + header:headerObj, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: httpUrlFormat(`/boxes/${data.id}`, _flag), + method: 'GET', + data + }) +} +// 创建盲盒订单 +export function boxOrderApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxOrderApi, + method: 'POST', + data + }) +} +export function boxOrderListApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxOrderApi, + method: 'GET', + data + }) +} +// 活动盲盒 +export function boxActivityApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxActivityApi, + method: 'GET', + data + }) +} +// 活动盲盒 +export function boxActivityListApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxActivityListApi, + method: 'GET', + data + }) +} + + +// 创建盲盒订单 +export function boxOrderReviewApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxOrderReviewApi, + method: 'GET', + data + }) +} +// 创建盲盒订单 +export function boxOrderPaidApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxOrderPaidApi, + method: 'GET', + data + }) +} +export function orderPaidApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.orderPaidApi, + method: 'GET', + data + }) +} + +// 盲盒开奖结果 +export function boxRecordResultApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxRecordResultApi, + method: 'GET', + data + }) +} + + + +export function boxDeliveryPreviewApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + + return ajaxCarryAuthorization({ + header:headerObj, + // header: {'Content-Type': 'application/x-www-form-urlencoded','API-Version': ApiVersion()}, + // url: apiUrl.cart_item, + url: apiUrl.boxDeliveryPreviewApi, + // url: httpUrlFormat(`/order/box/delivery/preview?boxRecordId=${data.boxRecordId}&quantity=${data.quantity}`, _flag), + method: 'POST', + data: data + }) +} +export function boxDeliveryApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // url: apiUrl.cart_item, + url: apiUrl.boxDeliveryApi, + method: 'POST', + data: data + }) +} + + + +export function boxesChannelPinnedApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxesChannelPinnedApi, + method: 'GET', + data + }) +} + + + +//商城订单列表 +export function orderList(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.order, + method: 'GET', + data: data + }) +} +// 删除订单 +export function delOrder(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // url: apiUrl.cart_item, + url: apiUrl.order, + method: 'DELETE', + data: data + }) +} +// 取消订单 +export function orderCancel(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // url: apiUrl.cart_item, + url: apiUrl.orderCancel, + method: 'PUT', + data: data + }) +} +// 确认收货 +export function orderReceive(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // url: apiUrl.cart_item, + url: apiUrl.orderReceive, + method: 'POST', + data: data + }) +} +//创建商城订单 +export function createOrder(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.orderList, + method: 'POST', + data: data + }) +} +//订单预览 +export function orderPreview(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.orderPreview, + method: 'POST', + data: data + }) +} +//盲盒订单列表 +export function boxOrderList(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxOrder, + method: 'GET', + data: data + }) +} + +//创建盲盒订单 +export function boxCreateOrder(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxOrder, + method: 'POST', + data: data + }) +} +//礼盒/物品列表 +export function boxRecord(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxRecord, + method: 'GET', + data: data + }) +} +//开盲盒 +export function boxOpen(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + header: headerObj, + url: apiUrl.boxOpen, + method: 'POST', + data: data + }) +} +//提取盲盒 +export function boxPickup(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxPickup, + method: 'POST', + data: data + }) +} +//回收盲盒 +export function boxRecycle(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.boxRecycle, + method: 'POST', + data: data + }) +} +// 订单详情 +export function orderDetail(no,data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: httpUrlFormat(`/order/${no}`, _flag), + method: 'GET', + data: data + }) +} +//盲盒详情 +export function boxInfo(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.boxInfo, + method: 'GET', + data: data + }) +} +// 根据盲盒id开盒 +export function boxOpenByBoxId(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.boxOpenByBoxId, + method: 'POST', + data: data + }) +} +// 用户提示卡数量 +export function promptCountApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.promptCountApi, + method: 'GET', + data: data + }) +} +// 使用提示卡 +export function usePromptApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.usePromptApi, + method: 'POST', + data: data + }) +} +export function activityDetailApi(data,header = {}) { + // header['API-Version'] = ApiVersion() + const headerObj = {...headerVersion,...header} + return ajaxCarryAuthorization({ + header:headerObj, + url: apiUrl.activityDetailApi, + method: 'GET', + data: data + }) +} +export function activityDetailSourceApi(data,header = {}) { + // header['API-Version'] = ApiVersion() + const headerObj = {...headerVersion,...header} + return ajaxCarryAuthorization({ + header:headerObj, + url: apiUrl.activityDetailSourceApi, + method: 'GET', + data: data + }) +} + +export function activityBuyApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.activityBuyApi, + method: 'POST', + data: data + }) +} +export function activitySourceBuyApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.activitySourceBuyApi, + method: 'POST', + data: data + }) +} + + +export function activityReviewApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.activityReviewApi, + method: 'GET', + data: data + }) +} +export function activityReviewSourceApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.activityReviewSourceApi, + method: 'GET', + data: data + }) +} +export function activityOrderApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.activityOrderApi, + method: 'POST', + data: data + }) +} +export function recoveryBatchApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.recoveryBatchApi, + method: 'PUT', + data: data + }) +} +export function deliveryReviewBatchApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.deliveryReviewBatchApi, + method: 'POST', + data: data + }) +} +export function deliveryBatchApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.deliveryBatchApi, + method: 'POST', + data: data + }) +} +export function promptExchangeBatchApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.promptExchangeBatchApi, + method: 'POST', + data: data + }) +} +export function boxResultApi(data,header = {}) { + const headerObj = {...headerVersion,...header} + return ajaxCarryAuthorization({ + header:headerObj, + url: apiUrl.boxResultApi, + method: 'GET', + data: data + }) +} +export function noOpenListApi(data,header = {}) { + const headerObj = {...headerVersion,...header} + // header['API-Version'] = ApiVersion() + return ajaxCarryAuthorization({ + header:headerObj, + url: apiUrl.noOpenListApi, + method: 'GET', + data: data + }) +} +// export function openListApi(data,header = {}) { +// // header['API-Version'] = ApiVersion() +// const headerObj = {...headerVersion,...header} +// return ajaxCarryAuthorization({ +// header:headerObj, +// url: apiUrl.openListApi, +// method: 'GET', +// data: data +// }) +// } +export function openListApi(data,header = {}) { + // header['API-Version'] = ApiVersion() + const headerObj = {...headerVersion,...header} + return ajaxCarryAuthorization({ + header:headerObj, + url: httpUrlFormat(`/box/record/open?ids=${data}`, _flag), + method: 'GET', + data: data + }) +} +export function popupAdPageApi(data) { + return ajaxCarryAuthorization({ + header:headerVersion, + url: apiUrl.popupAdPageApi, + method: 'GET', + data: data + }) +} +export function popupAdPageChannelApi(data) { + return ajaxCarryAuthorization({ + header:headerVersion, + url: apiUrl.popupAdPageChannelApi, + method: 'GET', + data: data + }) +} + + +export function activityIconApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.activityIconApi, + method: 'POST', + data: data + }) +} + + +export function activityDetailNewApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.activityDetailNewApi, + method: 'POST', + data: data + }) +} + + +export function pointClearApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.pointClearApi, + method: 'POST', + data: data + }) +} +export function activityTaskAwardApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.activityTaskAwardApi, + method: 'POST', + data: data + }) +} +export function activityTaskCreateApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.activityTaskCreateApi, + method: 'POST', + data: data + }) +} + +// 免费开盲盒 +export function freeBoxApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.freeBoxApi, + method: 'GET', + data + }) +} + + +export function activityGuideApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.activityGuideApi, + method: 'GET', + data: data + }) +} +export function setActivityGuideApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.activityGuideApi, + method: 'POST', + data: data + }) +} + +export function indexGuideApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.indexGuideApi, + method: 'GET', + data: data + }) +} +export function setIndexGuideApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.indexGuideApi, + method: 'POST', + data: data + }) +} +export function activityTopLastApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.activityTopLastApi, + method: 'GET', + data: data + }) +} diff --git a/API/indexApi.js b/API/indexApi.js new file mode 100644 index 0000000..b063c3b --- /dev/null +++ b/API/indexApi.js @@ -0,0 +1,29 @@ +import { + httpUrlFormat, + ajaxCarryAuthorization,ajaxSync +} from '@/utils/httpUtils.js' + + +import { ApiVersion,AppVersion } from '@/config/baseConfig.js' + +const headerVersion = { + 'API-Version': ApiVersion(), + 'APP-Version':AppVersion() +} + + +const _flag = 'apiBaseUrl' // 请求的api空间 + +const apiUrl = { + 'index': httpUrlFormat('/index', _flag), +} + +export function index(data) { + return ajaxSync({ + header: headerVersion, + url: apiUrl.index, + method: 'GET', + data: data + }) +} + diff --git a/API/login.js b/API/login.js new file mode 100644 index 0000000..26cbcd1 --- /dev/null +++ b/API/login.js @@ -0,0 +1,148 @@ +import { + httpUrlFormat, + ajaxCarryAuthorization,ajaxSync +} from '@/utils/httpUtils.js' + + +import { ApiVersion,AppVersion } from '@/config/baseConfig.js' + +const headerVersion = { + 'API-Version': ApiVersion(), + 'APP-Version':AppVersion() +} + +const _flag = 'apiBaseUrl' // 请求的api空间 + +const apiUrl = { + 'generateCode': httpUrlFormat('/generate/code', _flag),//发送短信验证码 + 'sms_check': httpUrlFormat('/sms_check', _flag),//验证短信验证码 + 'register': httpUrlFormat('/register', _flag),//注册 + 'login': httpUrlFormat('/login', _flag),//登录 + 'loginCode': httpUrlFormat('/login/code', _flag),//验证码登录 + 'wechatAppid': httpUrlFormat('/wechat/appid', _flag),//微信获取appid + 'loginWechat': httpUrlFormat('/login/wechat', _flag),//微信登录 + 'phoneWechat': httpUrlFormat('/wechat/user/phone', _flag),//微信登录 + 'reset_password': httpUrlFormat('/reset_password', _flag),//重置密码 + 'bindPhoneApi': httpUrlFormat('/user/bind/phone', _flag),//绑定手机号 + + + + + 'loginXc': httpUrlFormat('/login/xiaochuan', _flag),//用户登录第三方小川 + 'agreementDetailApi': httpUrlFormat('/misc/user/agreement/detail', _flag),//用户协议 + + + +} +export function loginXc(data) { + return ajaxSync({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.loginXc, + method: 'POST', + data: data + }) +} + + +export function smsSend(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxSync({ + header: headerObj, + url: apiUrl.generateCode, + method: 'POST', + data: data + }) +} +export function smsCheck(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxSync({ + header: headerObj, + url: apiUrl.sms_check, + method: 'POST', + data: data + }) +} + +export function register(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxSync({ + header: headerObj, + url: apiUrl.register, + method: 'POST', + data: data + }) +} +export function loginCode(data) { + return ajaxSync({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.loginCode, + method: 'POST', + data: data + }) +} +export function loginWechat(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxSync({ + header: headerObj, + url: apiUrl.loginWechat, + method: 'POST', + data: data + }) +} +export function loginApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxSync({ + header: headerObj, + url: apiUrl.login, + method: 'POST', + data: data + }) +} +export function resetPassword(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxSync({ + header: headerObj, + url: apiUrl.reset_password, + method: 'POST', + data: data + }) +} +export function wechatAppid(data) { + return ajaxSync({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.wechatAppid, + method: 'GET', + data: data + }) +} +export function phoneWechat(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxSync({ + header: headerObj, + url: apiUrl.phoneWechat, + method: 'POST', + data: data + }) +} +export function bindPhoneApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.bindPhoneApi, + method: 'POST', + data: data + }) +} + +export function agreementDetailApi(data) { + return ajaxSync({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.agreementDetailApi, + method: 'GET', + data: data + }) +} diff --git a/API/order.js b/API/order.js new file mode 100644 index 0000000..2216904 --- /dev/null +++ b/API/order.js @@ -0,0 +1,288 @@ +import { + httpUrlFormat, + ajaxCarryAuthorization,ajaxSync +} from '@/utils/httpUtils.js' + + +import { ApiVersion,AppVersion } from '@/config/baseConfig.js' + +const headerVersion = { + 'API-Version': ApiVersion(), + 'APP-Version':AppVersion() +} + + +const _flag = 'apiBaseUrl' // 请求的api空间 + +const apiUrl = { + 'order': httpUrlFormat('/order', _flag), + 'orderPreview': httpUrlFormat('/order/preview', _flag), + 'orderReceive': httpUrlFormat('/order/receive', _flag), + 'orderList': httpUrlFormat('/order/mall_order', _flag), + 'boxOrder': httpUrlFormat('/order/box_order', _flag), + 'boxRecord': httpUrlFormat('/order/box_record', _flag), + 'boxOpen': httpUrlFormat('/order/box_open', _flag), + 'boxPickup': httpUrlFormat('/order/box_pickup', _flag), + 'boxRecycle': httpUrlFormat('/order/box_recycle', _flag), + 'boxInfo': httpUrlFormat('/order/box_info', _flag), + 'orderCancel': httpUrlFormat('/order/cancel', _flag), + 'boxOpenByBoxId': httpUrlFormat('/order/box_open_by_box_id', _flag), + 'orderRefundApi': httpUrlFormat('/order/refund', _flag), + + + + + 'channelGetApi': httpUrlFormat('/pay/channel/get', _flag), + 'orderReceiptApi': httpUrlFormat('/order/receipt', _flag), + + 'refundTimeApi': httpUrlFormat('/misc/mall/refund/expire/time', _flag),//商品退款-过期时间 + 'boxRefundTimeApi': httpUrlFormat('/order/box/record/expire/time', _flag),//盲盒退款-过期时间 + 'boxRefundTimeExpiredApi': httpUrlFormat('/order/box/record/expired', _flag),//盲盒退款-过期时间 + +} + +//订单预览 +export function orderPreview(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + console.log(headerObj) + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.orderPreview, + method: 'POST', + data: data + }) +} + +export function channelGetApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.channelGetApi, + method: 'GET', + data: data + }) +} +export function createShopOrder(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.order, + method: 'POST', + data: data + }) +} + + + + + + + + +//商城订单列表 +export function orderList(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.order, + method: 'GET', + data: data + }) +} +// 删除订单 +export function delOrder(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // url: apiUrl.cart_item, + url: apiUrl.order, + method: 'DELETE', + data: data + }) +} +// 取消订单 +export function orderCancel(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // url: apiUrl.cart_item, + url: apiUrl.orderCancel, + method: 'PUT', + data: data + }) +} +// 确认收货 +export function orderReceive(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // url: apiUrl.cart_item, + url: apiUrl.orderReceive, + method: 'POST', + data: data + }) +} +//创建商城订单 +export function createOrder(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.orderList, + method: 'POST', + data: data + }) +} +//盲盒订单列表 +export function boxOrderList(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxOrder, + method: 'GET', + data: data + }) +} + +//创建盲盒订单 +export function boxCreateOrder(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxOrder, + method: 'POST', + data: data + }) +} +//礼盒/物品列表 +export function boxRecord(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxRecord, + method: 'GET', + data: data + }) +} +//开盲盒 +export function boxOpen(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxOpen, + method: 'POST', + data: data + }) +} +//提取盲盒 +export function boxPickup(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxPickup, + method: 'POST', + data: data + }) +} +//回收盲盒 +export function boxRecycle(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxRecycle, + method: 'POST', + data: data + }) +} +// 订单详情 +export function orderDetail(no,data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: httpUrlFormat(`/order/no/${no}`, _flag), + method: 'GET', + data: data + }) +} +export function orderIdDetail(id) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: httpUrlFormat(`/box/order/${id}`, _flag), + method: 'GET', + }) +} +export function orderDetailId(id) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: httpUrlFormat(`/order/${id}`, _flag), + method: 'GET', + }) +} +//盲盒详情 +export function boxInfo(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.boxInfo, + method: 'GET', + data: data + }) +} +// 根据盲盒id开盒 +export function boxOpenByBoxId(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxOpenByBoxId, + method: 'POST', + data: data + }) +} + + + +export function orderReceiptApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + // url: apiUrl.cart_item, + url: apiUrl.orderReceiptApi, + method: 'PUT', + data: data + }) +} +export function orderRefundApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + // url: apiUrl.cart_item, + url: apiUrl.orderRefundApi, + method: 'PUT', + data: data + }) +} + + +// 商品退款过期时间 +export function refundTimeApi(data) { + return ajaxCarryAuthorization({ + url: apiUrl.refundTimeApi, + method: 'GET', + data: data + }) +} +// 盲盒退款过期时间 +export function boxRefundTimeApi(data) { + return ajaxCarryAuthorization({ + url: apiUrl.boxRefundTimeApi, + method: 'GET', + data: data + }) +} +export function boxRefundTimeExpiredApi(data) { + return ajaxCarryAuthorization({ + url: apiUrl.boxRefundTimeExpiredApi, + method: 'GET', + data: data + }) +} \ No newline at end of file diff --git a/API/pay.js b/API/pay.js new file mode 100644 index 0000000..3820450 --- /dev/null +++ b/API/pay.js @@ -0,0 +1,65 @@ +import { + httpUrlFormat, + ajaxCarryAuthorization,ajaxSync +} from '@/utils/httpUtils.js' + + +import { ApiVersion,AppVersion } from '@/config/baseConfig.js' + +const headerVersion = { + 'API-Version': ApiVersion(), + 'APP-Version':AppVersion() +} + +const _flag = 'apiBaseUrl' // 请求的api空间 + +const apiUrl = { + 'createOrderPay': httpUrlFormat('/pay/create_order', _flag), + 'orderPaid': httpUrlFormat('/order/box_order_paid', _flag), + 'orderShopPaid': httpUrlFormat('/order/order_paid', _flag), + 'mpScheme': httpUrlFormat('/other/wechat/mp/scheme', _flag), + +} + +export function createOrderPay(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.createOrderPay, + method: 'POST', + data: data + }) +} + +// 查询盲盒订单是否成功 +export function orderPaid(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.orderPaid, + method: 'GET', + data: data + }) +} +// 查询商品订单是否成功 +export function orderShopPaid(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.orderShopPaid, + method: 'GET', + data: data + }) +} + +// https://test.06zk.com/test/pay/create_order + +export function mpScheme(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.mpScheme, + method: 'GET', + data + }) +} \ No newline at end of file diff --git a/API/product.js b/API/product.js new file mode 100644 index 0000000..136bb30 --- /dev/null +++ b/API/product.js @@ -0,0 +1,261 @@ +import { + httpUrlFormat, + ajaxCarryAuthorization,ajaxSync +} from '@/utils/httpUtils.js' + + +import { ApiVersion,AppVersion } from '@/config/baseConfig.js' + +const headerVersion = { + 'API-Version': ApiVersion(), + 'APP-Version':AppVersion() +} + + +const _flag = 'apiBaseUrl' // 请求的api空间 + +const apiUrl = { + 'productApi': httpUrlFormat('/product', _flag), + 'productTagsApi': httpUrlFormat('/product/tags', _flag), + 'boxesTagsApi': httpUrlFormat('/boxes/tags', _flag), + 'boxesApi': httpUrlFormat('/boxes', _flag), + 'favorItemApi': httpUrlFormat('/user/favor/item', _flag), + 'favorItemProductApi': httpUrlFormat('/user/favor/item/product', _flag), + + + 'orderPreview': httpUrlFormat('/order/preview', _flag), + 'orderReceive': httpUrlFormat('/order/receive', _flag), + 'orderList': httpUrlFormat('/order/mall_order', _flag), + 'boxOrder': httpUrlFormat('/order/box_order', _flag), + 'boxRecord': httpUrlFormat('/order/box_record', _flag), + 'boxOpen': httpUrlFormat('/order/box_open', _flag), + 'boxPickup': httpUrlFormat('/order/box_pickup', _flag), + 'boxRecycle': httpUrlFormat('/order/box_recycle', _flag), + 'boxInfo': httpUrlFormat('/order/box_info', _flag), + 'orderCancel': httpUrlFormat('/order/cancel', _flag), + 'boxOpenByBoxId': httpUrlFormat('/order/box_open_by_box_id', _flag), + +} + + + + +//商品标签 +export function productTagsApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.productTagsApi, + method: 'GET', + data: data + }) +} +//商品分页 +export function productApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.productApi, + method: 'GET', + data: data + }) +} +//盲盒标签 +export function boxesTagsApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxesTagsApi, + method: 'GET', + data: data + }) +} + +export function productDetailApi(data,header = {}) { + const headerObj = {...header,...headerVersion} + return ajaxCarryAuthorization({ + header:headerObj, + url: httpUrlFormat(`/product/${data.id}`, _flag), + method: 'GET', + data: data + }) +} +// 收藏 +export function favorItemApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.favorItemApi, + method: 'POST', + data: data + }) +} +// 删除收藏 +export function delFavorItemApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.favorItemProductApi, + method: 'DELETE', + data: data + }) +} + + + + + + +//商城订单列表 +export function orderList(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.order, + method: 'GET', + data: data + }) +} +// 删除订单 +export function delOrder(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // url: apiUrl.cart_item, + url: apiUrl.order, + method: 'DELETE', + data: data + }) +} +// 取消订单 +export function orderCancel(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // url: apiUrl.cart_item, + url: apiUrl.orderCancel, + method: 'PUT', + data: data + }) +} +// 确认收货 +export function orderReceive(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // url: apiUrl.cart_item, + url: apiUrl.orderReceive, + method: 'POST', + data: data + }) +} +//创建商城订单 +export function createOrder(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.orderList, + method: 'POST', + data: data + }) +} +//订单预览 +export function orderPreview(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.orderPreview, + method: 'POST', + data: data + }) +} +//盲盒订单列表 +export function boxOrderList(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxOrder, + method: 'GET', + data: data + }) +} + +//创建盲盒订单 +export function boxCreateOrder(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxOrder, + method: 'POST', + data: data + }) +} +//礼盒/物品列表 +export function boxRecord(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxRecord, + method: 'GET', + data: data + }) +} +//开盲盒 +export function boxOpen(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + header: headerObj, + url: apiUrl.boxOpen, + method: 'POST', + data: data + }) +} +//提取盲盒 +export function boxPickup(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxPickup, + method: 'POST', + data: data + }) +} +//回收盲盒 +export function boxRecycle(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.boxRecycle, + method: 'POST', + data: data + }) +} +// 订单详情 +export function orderDetail(no,data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: httpUrlFormat(`/order/${no}`, _flag), + method: 'GET', + data: data + }) +} +//盲盒详情 +export function boxInfo(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.boxInfo, + method: 'GET', + data: data + }) +} +// 根据盲盒id开盒 +export function boxOpenByBoxId(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.boxOpenByBoxId, + method: 'POST', + data: data + }) +} diff --git a/API/ranking.js b/API/ranking.js new file mode 100644 index 0000000..8983c3d --- /dev/null +++ b/API/ranking.js @@ -0,0 +1,89 @@ +import { + httpUrlFormat, + ajaxCarryAuthorization,ajaxSync +} from '@/utils/httpUtils.js' + + +import { ApiVersion,AppVersion } from '@/config/baseConfig.js' + +const headerVersion = { + 'API-Version': ApiVersion(), + 'APP-Version':AppVersion() +} + + +const _flag = 'apiBaseUrl' // 请求的api空间 + +const apiUrl = { + 'topStatusApi': httpUrlFormat('/top/status', _flag), +} + + +export function topUserListApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: httpUrlFormat(`/top/user/list/${data.type}`, _flag), + method: 'GET', + data + }) +} +export function topUserSelfApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: httpUrlFormat(`/top/user/self/${data.type}`, _flag), + method: 'GET', + data + }) +} +export function topStatusApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.topStatusApi, + method: 'GET', + data + }) +} + + +export function topUserListLastApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: httpUrlFormat(`/top/user/list/last/${data.type}`, _flag), + method: 'GET', + data + }) +} +export function topUserSelfLastApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: httpUrlFormat(`/top/user/self/last/${data.type}`, _flag), + method: 'GET', + data + }) +} +export function topRuleApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: httpUrlFormat(`/top/rule/${data.type}`, _flag), + method: 'GET', + data + }) +} +export function topExpiredTimeApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: httpUrlFormat(`/top/expired/time/${data.type}`, _flag), + method: 'GET', + data + }) +} + +export function topDetailApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: httpUrlFormat(`/top/${data.type}`, _flag), + method: 'GET', + data + }) +} + diff --git a/API/report.js b/API/report.js new file mode 100644 index 0000000..1d82462 --- /dev/null +++ b/API/report.js @@ -0,0 +1,44 @@ + +import { + httpUrlFormat, + ajaxCarryAuthorization,ajaxSync +} from '@/utils/httpUtils.js' + + +import { ApiVersion,AppVersion } from '@/config/baseConfig.js' + +const headerVersion = { + 'API-Version': ApiVersion(), + 'APP-Version':AppVersion() +} + + +const _flag = 'apiBaseUrl' // 请求的api空间 + +const apiUrl = { + 'reportHeartbeat': httpUrlFormat('/report/heartbeat', _flag), + 'reportClick': httpUrlFormat('/report/click', _flag), + + +} + +//心跳埋点 +export function reportHeartbeatApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.reportHeartbeat, + method: 'POST', + data: data + }) +} +//点击埋点 +export function reportClickApi(data) { + // const headerObj = {'Content-Type': 'application/x-www-form-urlencoded',...headerVersion} + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.reportClick, + method: 'POST', + data: data + }) +} diff --git a/API/shop.js b/API/shop.js new file mode 100644 index 0000000..345180c --- /dev/null +++ b/API/shop.js @@ -0,0 +1,232 @@ +import { + httpUrlFormat, + ajaxCarryAuthorization,ajaxSync +} from '@/utils/httpUtils.js' + + +import { ApiVersion,AppVersion } from '@/config/baseConfig.js' + +const headerVersion = { + 'API-Version': ApiVersion(), + 'APP-Version':AppVersion() +} + + +const _flag = 'apiBaseUrl' // 请求的api空间 + +const apiUrl = { + 'product': httpUrlFormat('/product', _flag),//商品分页 + 'categories': httpUrlFormat('/product/categories', _flag),//商品分类 + 'rollingImgs': httpUrlFormat('/rolling_imgs', _flag),//商品分类 + 'favorItem': httpUrlFormat('/user/favor_item', _flag),//收藏 + 'deliveryFee': httpUrlFormat('/product/delivery_fee', _flag),//运费 + 'favorItemProduct': httpUrlFormat('/user/favor_item_product', _flag),//运费 + 'searchHistoryRecommend': httpUrlFormat('/search_history/recommend', _flag),//搜索推荐 + 'searchHistoryPersonal': httpUrlFormat('/search/history/personal', _flag),//搜索推荐 + 'orderBoxRecordCount': httpUrlFormat('/order/box_record_count', _flag),//盲盒统计 + 'carriageRule': httpUrlFormat('/misc/carriage/rule', _flag), + 'carriageGetRule': httpUrlFormat('/misc/carriage/get', _flag), + 'tagsChannelApi': httpUrlFormat('/product/tags/channel', _flag), + 'productChannelApi': httpUrlFormat('/product/channel', _flag), + 'productRecommendChannel': httpUrlFormat('/product/product/recommend/channel', _flag), + 'productChannelPointApi': httpUrlFormat('/product/channel/points', _flag), + + 'tagsPointApi': httpUrlFormat('/misc/product/points/tag', _flag), + +} + + +// 渠道商品tag +export function tagsChannelApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.tagsChannelApi, + method: 'GET', + data: data + }) +} +// 渠道商品 +export function productChannelApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.productChannelApi, + method: 'GET', + data: data + }) +} + +export function productRecommendChannel(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.productRecommendChannel, + method: 'GET', + data: data + }) +} + +// 渠道商品积分筛选 +export function productChannelPointApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.productChannelPointApi, + method: 'GET', + data: data + }) +} + +// 运费 +export function deliveryFee() { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.deliveryFee, + method: 'GET', + }) +} +export function product(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.product, + method: 'GET', + data: data + }) +} +// 商品分类 +export function categories(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.categories, + method: 'GET', + data: data + }) +} +// 商品详情 +export function productDetail(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: httpUrlFormat(`/product/${data}`, _flag), + method: 'GET', + }) +} +// 商城轮播 +export function rollingImgs(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.rollingImgs, + method: 'GET', + }) +} +// 收藏列表 +export function favorItemList(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.favorItem, + method: 'GET', + data + }) +} +// 收藏 +export function favorItem(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.favorItem, + method: 'POST', + data + }) +} + +// 删除收藏 +export function delFavorItem(ids) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // url: apiUrl.cart_item, + url: httpUrlFormat(`/user/favor_item${ids}`, _flag), + method: 'DELETE' + }) +} +// 删除商品详情收藏 +export function favorItemProduct(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // url: apiUrl.cart_item, + url: httpUrlFormat(`/user/favor_item_product${data}`, _flag), + method: 'DELETE', + // data: data + }) +} +// 搜索推荐 +export function searchHistoryRecommend(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.searchHistoryRecommend, + method: 'GET', + data + }) +} +// 搜索历史 +export function searchHistoryPersonal(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.searchHistoryPersonal, + method: 'GET', + data + }) +} +// 删除搜索历史 +export function delSearchHistoryPersonal() { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.searchHistoryPersonal, + method: 'DELETE', + }) +} +// 盲盒统计 +export function orderBoxRecordCount(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.orderBoxRecordCount, + method: 'GET', + data + }) +} +export function carriageRule(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.carriageRule, + method: 'GET', + data + }) +} +export function carriageGetRule(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.carriageGetRule, + method: 'GET', + data + }) +} + +export function tagsPointApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.tagsPointApi, + method: 'GET', + data + }) +} + diff --git a/API/sign.js b/API/sign.js new file mode 100644 index 0000000..a7591b1 --- /dev/null +++ b/API/sign.js @@ -0,0 +1,57 @@ +import { + httpUrlFormat, + ajaxCarryAuthorization,ajaxSync +} from '@/utils/httpUtils.js' + + +import { ApiVersion,AppVersion } from '@/config/baseConfig.js' + +const headerVersion = { + 'API-Version': ApiVersion(), + 'APP-Version':AppVersion() +} + + + +const _flag = 'apiBaseUrl' // 请求的api空间 + +const apiUrl = { + 'signInInfo': httpUrlFormat('/user/sign/in/info', _flag),//用户签到信息 + 'signIn': httpUrlFormat('/user/sign/in', _flag),//用户签到 + 'taskList': httpUrlFormat('/task/list', _flag),//任务列表 + + +} + +export function signInInfo(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.signInInfo, + method: 'GET', + data: data + }) +} +export function signIn(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.signIn, + method: 'POST', + data + }) +} +export function taskListApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: apiUrl.taskList, + method: 'GET', + data: data + }) +} +export function taskReceive(taskId) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: httpUrlFormat(`/task/receive/${taskId}`, _flag), + method: 'POST', + }) +} \ No newline at end of file diff --git a/API/user.js b/API/user.js new file mode 100644 index 0000000..2b92bd9 --- /dev/null +++ b/API/user.js @@ -0,0 +1,393 @@ +import { + httpUrlFormat, + ajaxCarryAuthorization,ajaxSync +} from '@/utils/httpUtils.js' + + +import { ApiVersion,AppVersion } from '@/config/baseConfig.js' + +const headerVersion = { + 'API-Version': ApiVersion(), + 'APP-Version':AppVersion() +} + + +const _flag = 'apiBaseUrl' // 请求的api空间 + +const apiUrl = { + 'userInfo': httpUrlFormat('/user/info', _flag),//用户信息 + 'userPoint': httpUrlFormat('/user/point', _flag),// + 'favorItemApi': httpUrlFormat('/user/favor/item', _flag),// + 'userAddress': httpUrlFormat('/user/address', _flag),//收获地址 + 'boxCount': httpUrlFormat('/user/box_count', _flag),// + 'notice': httpUrlFormat('/misc/notice', _flag),//公告 + 'noticeTopApi': httpUrlFormat('/misc/notice/top', _flag),//置顶公告 + 'uploadToken': httpUrlFormat('/user/upload_token', _flag),//上传oss凭证 + 'feedback': httpUrlFormat('/user/feedback', _flag),//意见反馈 + 'customer': httpUrlFormat('/misc/customer', _flag),// + 'popupAdApi': httpUrlFormat('/misc/popup/ad', _flag),// + 'couponApi': httpUrlFormat('/coupon', _flag),//优惠券 + 'userCouponApi': httpUrlFormat('/user/conpon', _flag),//用户优惠券 + 'userCouponBatchApi': httpUrlFormat('/user/conpon/reward/batch', _flag),//用户优惠券 + + 'userCouponRewardApi': httpUrlFormat('/user/conpon/reward', _flag),//兑换优惠券 + 'coinGearApi': httpUrlFormat('/coin/gear', _flag),//代币充值 + 'coinGearRechargeApi': httpUrlFormat('/coin/gear/recharge', _flag),//代币充值订单 + 'payMethodApi': httpUrlFormat('/misc/pay/method', _flag),//获取支付方式 + 'coinPaidApi': httpUrlFormat('/coin/gear/recharge/paid', _flag),// + 'couponCountApi': httpUrlFormat('/user/coupon/count', _flag),// + 'miscPromptApi': httpUrlFormat('/misc/prompt', _flag),// + 'shareApi': httpUrlFormat('/misc/build/share', _flag),// + 'updateNickNameApi': httpUrlFormat('/user/update/nickname', _flag),//更新用户昵称 + + + + + 'recordCountApi': httpUrlFormat('/user/box/record/count', _flag),//用户盲盒开奖结果数量 + 'aliyunUploadTokenApi': httpUrlFormat('/misc/aliyun_upload_token', _flag),//获取oss上传凭证 + 'updateAvatarApi': httpUrlFormat('/user/update/avatar', _flag),//更新头像 + 'versionControlApi': httpUrlFormat('/misc/version/control', _flag),//版本控制 + 'userPromptListApi': httpUrlFormat('/user/prompt', _flag),//版本控制 + + + + + + +} + +// 更新用户昵称 +export function updateNickNameApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.updateNickNameApi, + method: 'POST', + data: data + }) +} +export function favorItemDelApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.favorItemApi, + method: 'DELETE', + data: data + }) +} +export function favorItemApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.favorItemApi, + method: 'GET', + data: data + }) +} +export function recordCountApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.recordCountApi, + method: 'GET', + data: data + }) +} + +export function userPoint(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.userPoint, + method: 'GET', + data: data + }) +} + + + +export function userInfo(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.userInfo, + method: 'GET', + data: data + }) +} +// 收货地址列表 +export function userAddress(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.userAddress, + method: 'GET', + data: data + }) +} +// 新增收货地址 +export function addAddress(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.userAddress, + method: 'POST', + data: data + }) +} +// 收货地址详情 +export function addressDetail(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: httpUrlFormat(`/user/address/${data}`, _flag), + method: 'GET', + }) +} +// 编辑收货地址 +export function editAddress(id,data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: httpUrlFormat(`/user/address/${id}`, _flag), + method: 'PUT', + data: data + }) +} + +// 删除地址 +export function delAddress(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: httpUrlFormat(`/user/address?ids=${data.id}`, _flag), + method: 'DELETE', + data,data + }) +} + +// 礼盒物品数量 +export function boxCount(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.boxCount, + method: 'GET', + }) +} +// 系统公告 +export function notice(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.notice, + method: 'GET', + data,data + }) +} +// 系统公告详情 +export function noticeDetail(id,data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: httpUrlFormat(`/misc/notice/${id}`, _flag), + method: 'GET', + data,data + }) +} +// 系统公告详情 +export function uploadToken(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.uploadToken, + method: 'GET', + data,data + }) +} +// 意见反馈 +export function feedback(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.feedback, + method: 'POST', + data,data + }) +} +export function customerApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.customer, + method: 'GET', + data,data + }) +} +export function noticeTopApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.noticeTopApi, + method: 'GET', + data + }) +} +export function popupAdApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.popupAdApi, + method: 'GET', + data + }) +} + +export function couponApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.couponApi, + method: 'GET', + data + }) +} + + +export function userCouponApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.userCouponApi, + method: 'GET', + data + }) +} +export function userCouponRewardApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.userCouponRewardApi, + method: 'POST', + data: data + }) +} + + +export function coinGearApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.coinGearApi, + method: 'GET', + data + }) +} +export function payMethodApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.payMethodApi, + method: 'GET', + data + }) +} + + +export function coinGearRechargeApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.coinGearRechargeApi, + method: 'POST', + data: data + }) +} +export function coinPaidApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.coinPaidApi, + method: 'GET', + data + }) +} + +export function userCouponBatchApi(userId,data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: httpUrlFormat(`/user/conpon/reward/batch?userId=${userId}`, _flag), + method: 'POST', + data: data + }) +} +export function couponCountApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.couponCountApi, + method: 'GET', + data: data + }) +} +export function miscPromptApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.miscPromptApi, + method: 'GET', + data: data + }) +} +export function shareApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.shareApi, + method: 'GET', + data: data + }) +} +export function aliyunUploadTokenApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.aliyunUploadTokenApi, + method: 'GET', + data + }) +} + + +export function updateAvatarApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.updateAvatarApi, + method: 'POST', + data: data + }) +} + +export function versionControlApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.versionControlApi, + method: 'POST', + data + }) +} + +export function userPromptListApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.userPromptListApi, + method: 'GET', + data + }) +} + diff --git a/API/virtual.js b/API/virtual.js new file mode 100644 index 0000000..38c581a --- /dev/null +++ b/API/virtual.js @@ -0,0 +1,95 @@ +import { + httpUrlFormat, + ajaxCarryAuthorization,ajaxSync +} from '@/utils/httpUtils.js' + +import { ApiVersion,AppVersion } from '@/config/baseConfig.js' + +const headerVersion = { + 'API-Version': ApiVersion(), + 'APP-Version':AppVersion() +} + +const _flag = 'apiBaseUrl' // 请求的api空间 + +const apiUrl = { + 'virtualOrderPreviewApi': httpUrlFormat('/virtual/order/preview', _flag),//商城订单预览 + 'virtualOrderBoxPreviewApi': httpUrlFormat('/virtual/order/box/delivery/preview', _flag),//盲盒订单预览 + 'virtualOrderApi': httpUrlFormat('/virtual/order/box/delivery', _flag), + 'virtualOrderPaidApi': httpUrlFormat('/virtual/order/paid', _flag), + 'virtualOrderListApi': httpUrlFormat('/virtual/order', _flag), +} + + +export function virtualShopOrderApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.virtualOrderListApi, + method: 'POST', + data + }) +} +export function virtualOrderPreviewApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.virtualOrderPreviewApi, + method: 'POST', + data: data + }) +} +export function virtualOrderBoxPreviewApi(data) { + const headerObj = {...headerVersion,'Content-Type': 'application/x-www-form-urlencoded'} + return ajaxCarryAuthorization({ + header: headerObj, + url: apiUrl.virtualOrderBoxPreviewApi, + method: 'POST', + data: data + }) +} + +// 创建订单 +export function virtualOrderApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.virtualOrderApi, + method: 'POST', + data + }) +} +export function virtualOrderPaidApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.virtualOrderPaidApi, + method: 'GET', + data + }) +} +export function virtualOrderListApi(data) { + return ajaxCarryAuthorization({ + header: headerVersion, + // header: {'Content-Type': 'application/x-www-form-urlencoded'}, + url: apiUrl.virtualOrderListApi, + method: 'GET', + data: data + }) +} + +export function virtualOrderDetailId(id) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: httpUrlFormat(`/virtual/order/${id}`, _flag), + method: 'GET', + }) +} +export function virtualOrderDetail(no,data) { + return ajaxCarryAuthorization({ + header: headerVersion, + url: httpUrlFormat(`/virtual/order/no/${no}`, _flag), + method: 'GET', + data: data + }) +} \ No newline at end of file diff --git a/App.vue b/App.vue new file mode 100644 index 0000000..4d64b6b --- /dev/null +++ b/App.vue @@ -0,0 +1,84 @@ + + + diff --git a/Dockerfile b/Dockerfile new file mode 100755 index 0000000..50c0882 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,3 @@ +FROM nginx +EXPOSE 80 +COPY /unpackage/dist/build/h5 /usr/share/nginx/html \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..83ee196 --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +# 盲盒H5基础版 +## 登录 +```bash + 1.登录页面('账号密码登录、验证码登录') +``` + + +## 首页 +```bash + 1.对接首页盲盒 + 2.盲盒标签以及标签下的盲盒 + 3.盲盒搜索 + 4.对接置顶公告 + 5.广告弹窗、轮播 + 7.对接盲盒详情 + 8.提示卡('页面完成没有对接功能') + 9.购买盲盒订单预览页面 + 10.支付('暂未对接支付通道')、购买成功页面 + 11.开奖页面('暂无动画') +``` +## 商城 +```bash + 1.商场首页('轮播未完成') + 2.商场搜索,搜索历史 + 3.商品详情 + 4.商品收藏/取消收藏 + 5.购买提交订单 + 6.购买成功页 +``` +## 签到 +```bash + 1.页面完成 暂未对接 +``` + + +## 个人中心 +```bash + 1.个人中心已完成 + 2.设置页面('更换头像、修改昵称、关于我们暂未对接') + 3.隐私政策、用户协议页面完成 暂未更新内容 + 4.优惠券、更多优惠券页面完成 暂未对接 + 5.积分使用记录已完成 + 6.物品页面完成 发货 回收接口已完成('发货回收接口需改成批量 页面已完成暂未对接') + 7.订单详情已完成(订单详情、确认收货、查看物流) + 8.盲盒订单已完成 + 9.地址管理已完成(新增地址、设置默认地址) + 10.我的收藏已完成(取消收藏) +``` diff --git a/components/ai-progress/ai-progress.vue b/components/ai-progress/ai-progress.vue new file mode 100644 index 0000000..d47b45e --- /dev/null +++ b/components/ai-progress/ai-progress.vue @@ -0,0 +1,176 @@ + + + + + diff --git a/components/bottom-fixed/bottom-fixed.vue b/components/bottom-fixed/bottom-fixed.vue new file mode 100644 index 0000000..68a7ee8 --- /dev/null +++ b/components/bottom-fixed/bottom-fixed.vue @@ -0,0 +1,69 @@ + + + + + + diff --git a/components/code-elf-guide/code-elf-guide.vue b/components/code-elf-guide/code-elf-guide.vue new file mode 100644 index 0000000..012b72e --- /dev/null +++ b/components/code-elf-guide/code-elf-guide.vue @@ -0,0 +1,120 @@ + + + + + + diff --git a/components/custom-radio-item/custom-radio-item.vue b/components/custom-radio-item/custom-radio-item.vue new file mode 100644 index 0000000..d1a4cf4 --- /dev/null +++ b/components/custom-radio-item/custom-radio-item.vue @@ -0,0 +1,68 @@ + + + + + + diff --git a/components/empty/empty.vue b/components/empty/empty.vue new file mode 100644 index 0000000..ee547d8 --- /dev/null +++ b/components/empty/empty.vue @@ -0,0 +1,58 @@ + + + + + + diff --git a/components/icon-view/icon-view.vue b/components/icon-view/icon-view.vue new file mode 100644 index 0000000..72a6212 --- /dev/null +++ b/components/icon-view/icon-view.vue @@ -0,0 +1,269 @@ + + + + + \ No newline at end of file diff --git a/components/icon-view/iconfont.css b/components/icon-view/iconfont.css new file mode 100644 index 0000000..f8d929a --- /dev/null +++ b/components/icon-view/iconfont.css @@ -0,0 +1,897 @@ +/* #ifdef APP-PLUS */ +@font-face { + font-family: "uicon-iconfont"; + font-weight: normal; + font-style: normal; + font-display: auto; + src: url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'); +} + +/* #endif */ + +/* 支付宝,百度,头条小程序目前读取大的本地字体文件,导致无法显示图标,故用在线加载的方式-2020-05-12 */ +/* #ifndef APP-PLUS */ +@font-face {font-family: "uicon-iconfont"; + src: url('//at.alicdn.com/t/font_1529455_adug8z8qzbi.eot?t=1595859460686'); /* IE9 */ + src: url('//at.alicdn.com/t/font_1529455_adug8z8qzbi.eot?t=1595859460686#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'), + url('//at.alicdn.com/t/font_1529455_adug8z8qzbi.woff?t=1595859460686') format('woff'), + url('//at.alicdn.com/t/font_1529455_adug8z8qzbi.ttf?t=1595859460686') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ + url('//at.alicdn.com/t/font_1529455_adug8z8qzbi.svg?t=1595859460686#iconfont') format('svg'); /* iOS 4.1- */ +} +/* #endif */ + +.u-iconfont { + position: relative; + display: flex; + font: normal normal normal 14px/1 "uicon-iconfont"; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.u-iconfont::before { + display: flex; + align-items: center; +} + +.uicon-level:before { + content: "\e693"; +} + +.uicon-woman:before { + content: "\e69c"; +} + +.uicon-man:before { + content: "\e697"; +} + +.uicon-column-line:before { + content: "\e68e"; +} + +.uicon-empty-page:before { + content: "\e627"; +} + +.uicon-empty-data:before { + content: "\e62f"; +} + +.uicon-empty-car:before { + content: "\e602"; +} + +.uicon-empty-order:before { + content: "\e639"; +} + +.uicon-empty-address:before { + content: "\e646"; +} + +.uicon-empty-message:before { + content: "\e6a9"; +} + +.uicon-empty-search:before { + content: "\e664"; +} + +.uicon-empty-favor:before { + content: "\e67c"; +} + +.uicon-empty-coupon:before { + content: "\e682"; +} + +.uicon-empty-history:before { + content: "\e684"; +} + +.uicon-empty-permission:before { + content: "\e686"; +} + +.uicon-empty-news:before { + content: "\e687"; +} + +.uicon-empty-wifi:before { + content: "\e688"; +} + +.uicon-empty-list:before { + content: "\e68b"; +} + +.uicon-arrow-left-double:before { + content: "\e68c"; +} + +.uicon-arrow-right-double:before { + content: "\e68d"; +} + +.uicon-red-packet:before { + content: "\e691"; +} + +.uicon-red-packet-fill:before { + content: "\e690"; +} + +.uicon-order:before { + content: "\e68f"; +} + +.uicon-nav-back-arrow:before { + content: "\e67f"; +} + +.uicon-nav-back:before { + content: "\e683"; +} + +.uicon-checkbox-mark:before { + content: "\e6a8"; +} + +.uicon-arrow-up-fill:before { + content: "\e6b0"; +} + +.uicon-arrow-down-fill:before { + content: "\e600"; +} + +.uicon-backspace:before { + content: "\e67b"; +} + +.uicon-android-circle-fill:before { + content: "\e67e"; +} + +.uicon-android-fill:before { + content: "\e67d"; +} + +.uicon-question:before { + content: "\e715"; +} + +.uicon-pause:before { + content: "\e8fa"; +} + +.uicon-close:before { + content: "\e685"; +} + +.uicon-volume-up:before { + content: "\e633"; +} + +.uicon-volume-off:before { + content: "\e644"; +} + +.uicon-info:before { + content: "\e653"; +} + +.uicon-error:before { + content: "\e6d3"; +} + +.uicon-lock-opened-fill:before { + content: "\e974"; +} + +.uicon-lock-fill:before { + content: "\e979"; +} + +.uicon-lock:before { + content: "\e97a"; +} + +.uicon-photo-fill:before { + content: "\e98b"; +} + +.uicon-photo:before { + content: "\e98d"; +} + +.uicon-account-fill:before { + content: "\e614"; +} + +.uicon-minus-people-fill:before { + content: "\e615"; +} + +.uicon-plus-people-fill:before { + content: "\e626"; +} + +.uicon-account:before { + content: "\e628"; +} + +.uicon-thumb-down-fill:before { + content: "\e726"; +} + +.uicon-thumb-down:before { + content: "\e727"; +} + +.uicon-thumb-up-fill:before { + content: "\e72f"; +} + +.uicon-thumb-up:before { + content: "\e733"; +} + +.uicon-person-delete-fill:before { + content: "\e66a"; +} + +.uicon-cut:before { + content: "\e948"; +} + +.uicon-fingerprint:before { + content: "\e955"; +} + +.uicon-home-fill:before { + content: "\e964"; +} + +.uicon-home:before { + content: "\e965"; +} + +.uicon-hourglass-half-fill:before { + content: "\e966"; +} + +.uicon-hourglass:before { + content: "\e967"; +} + +.uicon-lock-open:before { + content: "\e973"; +} + +.uicon-integral-fill:before { + content: "\e703"; +} + +.uicon-integral:before { + content: "\e704"; +} + +.uicon-coupon:before { + content: "\e8ae"; +} + +.uicon-coupon-fill:before { + content: "\e8c4"; +} + +.uicon-kefu-ermai:before { + content: "\e656"; +} + +.uicon-scan:before { + content: "\e662"; +} + +.uicon-rmb:before { + content: "\e608"; +} + +.uicon-rmb-circle-fill:before { + content: "\e657"; +} + +.uicon-rmb-circle:before { + content: "\e677"; +} + +.uicon-gift:before { + content: "\e65b"; +} + +.uicon-gift-fill:before { + content: "\e65c"; +} + +.uicon-bookmark-fill:before { + content: "\e63b"; +} + +.uicon-zhuanfa:before { + content: "\e60b"; +} + +.uicon-eye-off-outline:before { + content: "\e62b"; +} + +.uicon-eye-off:before { + content: "\e648"; +} + +.uicon-pause-circle:before { + content: "\e643"; +} + +.uicon-play-circle:before { + content: "\e647"; +} + +.uicon-pause-circle-fill:before { + content: "\e654"; +} + +.uicon-play-circle-fill:before { + content: "\e655"; +} + +.uicon-grid:before { + content: "\e673"; +} + +.uicon-play-right:before { + content: "\e610"; +} + +.uicon-play-left:before { + content: "\e66d"; +} + +.uicon-calendar:before { + content: "\e66e"; +} + +.uicon-rewind-right:before { + content: "\e66f"; +} + +.uicon-rewind-left:before { + content: "\e671"; +} + +.uicon-skip-forward-right:before { + content: "\e672"; +} + +.uicon-skip-back-left:before { + content: "\e674"; +} + +.uicon-play-left-fill:before { + content: "\e675"; +} + +.uicon-play-right-fill:before { + content: "\e676"; +} + +.uicon-grid-fill:before { + content: "\e678"; +} + +.uicon-rewind-left-fill:before { + content: "\e679"; +} + +.uicon-rewind-right-fill:before { + content: "\e67a"; +} + +.uicon-pushpin:before { + content: "\e7e3"; +} + +.uicon-star:before { + content: "\e65f"; +} + +.uicon-star-fill:before { + content: "\e669"; +} + +.uicon-server-fill:before { + content: "\e751"; +} + +.uicon-server-man:before { + content: "\e6bc"; +} + +.uicon-edit-pen:before { + content: "\e612"; +} + +.uicon-edit-pen-fill:before { + content: "\e66b"; +} + +.uicon-wifi:before { + content: "\e667"; +} + +.uicon-wifi-off:before { + content: "\e668"; +} + +.uicon-file-text:before { + content: "\e663"; +} + +.uicon-file-text-fill:before { + content: "\e665"; +} + +.uicon-more-dot-fill:before { + content: "\e630"; +} + +.uicon-minus:before { + content: "\e618"; +} + +.uicon-minus-circle:before { + content: "\e61b"; +} + +.uicon-plus:before { + content: "\e62d"; +} + +.uicon-plus-circle:before { + content: "\e62e"; +} + +.uicon-minus-circle-fill:before { + content: "\e652"; +} + +.uicon-plus-circle-fill:before { + content: "\e661"; +} + +.uicon-email:before { + content: "\e611"; +} + +.uicon-email-fill:before { + content: "\e642"; +} + +.uicon-phone:before { + content: "\e622"; +} + +.uicon-phone-fill:before { + content: "\e64f"; +} + +.uicon-clock:before { + content: "\e60f"; +} + +.uicon-car:before { + content: "\e60c"; +} + +.uicon-car-fill:before { + content: "\e636"; +} + +.uicon-warning:before { + content: "\e694"; +} + +.uicon-warning-fill:before { + content: "\e64d"; +} + +.uicon-search:before { + content: "\e62a"; +} + +.uicon-baidu-circle-fill:before { + content: "\e680"; +} + +.uicon-baidu:before { + content: "\e681"; +} + +.uicon-facebook:before { + content: "\e689"; +} + +.uicon-facebook-circle-fill:before { + content: "\e68a"; +} + +.uicon-qzone:before { + content: "\e695"; +} + +.uicon-qzone-circle-fill:before { + content: "\e696"; +} + +.uicon-moments-circel-fill:before { + content: "\e69a"; +} + +.uicon-moments:before { + content: "\e69b"; +} + +.uicon-qq-circle-fill:before { + content: "\e6a0"; +} + +.uicon-qq-fill:before { + content: "\e6a1"; +} + +.uicon-weibo:before { + content: "\e6a4"; +} + +.uicon-weibo-circle-fill:before { + content: "\e6a5"; +} + +.uicon-taobao:before { + content: "\e6a6"; +} + +.uicon-taobao-circle-fill:before { + content: "\e6a7"; +} + +.uicon-twitter:before { + content: "\e6aa"; +} + +.uicon-twitter-circle-fill:before { + content: "\e6ab"; +} + +.uicon-weixin-circle-fill:before { + content: "\e6b1"; +} + +.uicon-weixin-fill:before { + content: "\e6b2"; +} + +.uicon-zhifubao-circle-fill:before { + content: "\e6b8"; +} + +.uicon-zhifubao:before { + content: "\e6b9"; +} + +.uicon-zhihu:before { + content: "\e6ba"; +} + +.uicon-zhihu-circle-fill:before { + content: "\e709"; +} + +.uicon-list:before { + content: "\e650"; +} + +.uicon-list-dot:before { + content: "\e616"; +} + +.uicon-setting:before { + content: "\e61f"; +} + +.uicon-bell:before { + content: "\e609"; +} + +.uicon-bell-fill:before { + content: "\e640"; +} + +.uicon-attach:before { + content: "\e632"; +} + +.uicon-shopping-cart:before { + content: "\e621"; +} + +.uicon-shopping-cart-fill:before { + content: "\e65d"; +} + +.uicon-tags:before { + content: "\e629"; +} + +.uicon-share:before { + content: "\e631"; +} + +.uicon-question-circle-fill:before { + content: "\e666"; +} + +.uicon-question-circle:before { + content: "\e625"; +} + +.uicon-error-circle:before { + content: "\e624"; +} + +.uicon-checkmark-circle:before { + content: "\e63d"; +} + +.uicon-close-circle:before { + content: "\e63f"; +} + +.uicon-info-circle:before { + content: "\e660"; +} + +.uicon-md-person-add:before { + content: "\e6e4"; +} + +.uicon-md-person-fill:before { + content: "\e6ea"; +} + +.uicon-bag-fill:before { + content: "\e617"; +} + +.uicon-bag:before { + content: "\e619"; +} + +.uicon-chat-fill:before { + content: "\e61e"; +} + +.uicon-chat:before { + content: "\e620"; +} + +.uicon-more-circle:before { + content: "\e63e"; +} + +.uicon-more-circle-fill:before { + content: "\e645"; +} + +.uicon-volume:before { + content: "\e66c"; +} + +.uicon-volume-fill:before { + content: "\e670"; +} + +.uicon-reload:before { + content: "\e788"; +} + +.uicon-camera:before { + content: "\e7d7"; +} + +.uicon-heart:before { + content: "\e7df"; +} + +.uicon-heart-fill:before { + content: "\e851"; +} + +.uicon-minus-square-fill:before { + content: "\e855"; +} + +.uicon-plus-square-fill:before { + content: "\e856"; +} + +.uicon-pushpin-fill:before { + content: "\e86e"; +} + +.uicon-camera-fill:before { + content: "\e870"; +} + +.uicon-setting-fill:before { + content: "\e872"; +} + +.uicon-google:before { + content: "\e87a"; +} + +.uicon-ie:before { + content: "\e87b"; +} + +.uicon-apple-fill:before { + content: "\e881"; +} + +.uicon-chrome-circle-fill:before { + content: "\e885"; +} + +.uicon-github-circle-fill:before { + content: "\e887"; +} + +.uicon-IE-circle-fill:before { + content: "\e889"; +} + +.uicon-google-circle-fill:before { + content: "\e88a"; +} + +.uicon-arrow-down:before { + content: "\e60d"; +} + +.uicon-arrow-left:before { + content: "\e60e"; +} + +.uicon-map:before { + content: "\e61d"; +} + +.uicon-man-add-fill:before { + content: "\e64c"; +} + +.uicon-tags-fill:before { + content: "\e651"; +} + +.uicon-arrow-leftward:before { + content: "\e601"; +} + +.uicon-arrow-rightward:before { + content: "\e603"; +} + +.uicon-arrow-downward:before { + content: "\e604"; +} + +.uicon-arrow-right:before { + content: "\e605"; +} + +.uicon-arrow-up:before { + content: "\e606"; +} + +.uicon-arrow-upward:before { + content: "\e607"; +} + +.uicon-bookmark:before { + content: "\e60a"; +} + +.uicon-eye:before { + content: "\e613"; +} + +.uicon-man-delete:before { + content: "\e61a"; +} + +.uicon-man-add:before { + content: "\e61c"; +} + +.uicon-trash:before { + content: "\e623"; +} + +.uicon-error-circle-fill:before { + content: "\e62c"; +} + +.uicon-calendar-fill:before { + content: "\e634"; +} + +.uicon-checkmark-circle-fill:before { + content: "\e635"; +} + +.uicon-close-circle-fill:before { + content: "\e637"; +} + +.uicon-clock-fill:before { + content: "\e638"; +} + +.uicon-checkmark:before { + content: "\e63a"; +} + +.uicon-download:before { + content: "\e63c"; +} + +.uicon-eye-fill:before { + content: "\e641"; +} + +.uicon-mic-off:before { + content: "\e649"; +} + +.uicon-mic:before { + content: "\e64a"; +} + +.uicon-info-circle-fill:before { + content: "\e64b"; +} + +.uicon-map-fill:before { + content: "\e64e"; +} + +.uicon-trash-fill:before { + content: "\e658"; +} + +.uicon-volume-off-fill:before { + content: "\e659"; +} + +.uicon-volume-up-fill:before { + content: "\e65a"; +} + +.uicon-share-fill:before { + content: "\e65e"; +} \ No newline at end of file diff --git a/components/index-entrance/index-entrance.vue b/components/index-entrance/index-entrance.vue new file mode 100644 index 0000000..ac95407 --- /dev/null +++ b/components/index-entrance/index-entrance.vue @@ -0,0 +1,107 @@ + + + + + + diff --git a/components/lb-picker/README.md b/components/lb-picker/README.md new file mode 100644 index 0000000..5366935 --- /dev/null +++ b/components/lb-picker/README.md @@ -0,0 +1,434 @@ +

+ + + + + + + + + + + + + + + + + + + +

+ +插件市场里面的 picker 选择器不满足自己的需求,所以自己写了一个简单的 picker 选择器,可扩展、可自定义,一般满足日常需要。 +Github:[uni-lb-picker](https://github.com/liub1934/uni-lb-picker) +插件市场:[uni-lb-picker](https://ext.dcloud.net.cn/plugin?id=1111) + +> 如果问题最好去 github 反馈,插件市场评论区留下五星好评即可,[点我去反馈](https://github.com/liub1934/uni-lb-picker/issues/new) + +> **由于之前`cancel`拼写失误,写成了`cancle`,`v1.08`现已修正,如果之前版本有使用`cancel`事件的,更新后请及时修正。** + +## 兼容性 + +App + H5 + 各平台小程序(快应用及 360 未测试,nvue 待支持) + +## 功能 + +1、单选 +2、多级联动,非多级联动,理论支持任意级数 +3、省市区选择,基于多级联动 +4、自定义选择器头部确定取消按钮颜色及插槽支持 +5、选择器可视区自定义滚动个数 +6、自定义数据字段,满足不同人的需求 +7、自定义选择器样式 +8、单选及非联动选择支持扁平化的简单数据,如下形式: + +```javascript +// 单选列表 +list1: ['选项1', '选项2', '选项2'], +// 非联动选择列表 +list2: [ + ['选项1', '选项2', '选项3'], + ['选项11', '选项22', '选项33'], + ['选项111', '选项222', '选项333'] +] +``` + +## 引入插件 + +单独引入,在需要使用的页面上 import 引入即可 + +```html + + + +``` + +全局引入,`main.js`中 import 引入并注册即可全局使用 + +```jsvascript +import LbPicker from '@/components/lb-picker' +Vue.component("lb-picker", LbPicker) +``` + +easycom 引入 + +`pages.json`加上如下配置: + +```json +"easycom": { + "autoscan": true, + "custom": { + "lb-picker": "@/components/lb-picker/index.vue" + } +} +``` + +npm 安装引入: + +```shell +npm install uni-lb-picker +``` + +```jsvascript +import LbPicker from 'uni-lb-picker' +``` + +## 选择器数据格式 + +### 单选 + +常规数据 + +```javascript +list: [ + { + label: '选项1', + value: '1' + }, + { + label: '选项2', + value: '2' + } +] +``` + +扁平化简单数据 + +```javascript +list: ['选项1', '选项2'] +``` + +### 多级联动 + +```javascript +list: [ + { + label: '选项1', + value: '1', + children: [ + { + label: '选项1-1', + value: '1-1', + children: [ + { + label: '选项1-1-1', + value: '1-1-1' + } + ] + } + ] + } +] +``` + +### 非联动选择 + +常规数据 + +```javascript +list: [ + [ + { label: '选项1', value: '1' }, + { label: '选项2', value: '2' }, + { label: '选项3', value: '3' } + ], + [ + { label: '选项11', value: '11' }, + { label: '选项22', value: '22' }, + { label: '选项33', value: '33' } + ], + [ + { label: '选项111', value: '111' }, + { label: '选项222', value: '222' }, + { label: '选项333', value: '333' } + ] +] +``` + +扁平化简单数据 + +```javascript +list: [ + ['选项1', '选项2', '选项3'], + ['选项11', '选项22', '选项33'], + ['选项111', '选项222', '选项333'] +] +``` + +## 调用显示选择器 + +通过`ref`形式手动调用`show`方法显示,隐藏同理调用`hide` + +```text + + +this.$refs.picker.show() // 显示 +this.$refs.picker.hide() // 隐藏 +``` + +## 绑定值及设置默认值 + +支持 vue 中`v-model`写法绑定值,无需自己维护选中值的索引。 + +```javascript + + + +data () { + return { + value1: '' // 单选 + value2: [] // 多列联动选择 + } +} +``` + +## 多个选择器 + +通过设置不同的`ref`,然后调用即可 + +```javascript + + + +this.$refs.picker1.show() // picker1显示 +this.$refs.picker2.show() // picker2显示 +``` + +## 省市区选择 + +省市区选择是基于多列联动选择,数据来源:[https://github.com/modood/Administrative-divisions-of-China](https://github.com/modood/Administrative-divisions-of-China), +省市区文件位于`/pages/demos/area-data-min.js`,自行引入即可,可参考`demo3省市区选择`, +也可使用自己已有的省市区数据,如果数据字段不一样,也可以自定义,参考下方自定义数据字段。 + +## 自定义数据字段 + +为了满足不同人的需求,插件支持自定义数据字段名称, 插件默认的数据字段如下形式: + +```javascript +list: [ + { + label: '选择1', + value: 1, + children: [] + }, + { + label: '选择1', + value: 1, + children: [] + } +] +``` + +如果你的数据字段和上面不一样,如下形式: + +```javascript +list: [ + { + text: '选择1', + id: 1, + child: [] + }, + { + text: '选择1', + id: 1, + child: [] + } +] +``` + +通过设置参数中的`props`即可,如下所示: + +```javascript + + +data () { + return { + myProps: { + label: 'text', + value: 'id', + children: 'child' + } + } +} +``` + +## 插槽使用 + +选择器支持一些可自定义化的插槽,如选择器的取消和确定文字按钮,如果需要对其自定义处理的话,比如加个 icon 图标之类的,可使用插槽,使用方法如下: + +```html + + 我是自定义取消 + 我是自定义确定 + +``` + +其他插槽见下。 + +## 参数及事件 + +### Props + +| 参数 | 说明 | 类型 | 可选值 | 默认值 | +| :---------------------- | :--------------------------------------------------------------------------------------------------------------------------------- | :------------------ | :--------------------------------------------------------------- | :------------------------------------------------ | +| value/v-model | 绑定值,联动选择为 Array 类型 | String/Number/Array | - | - | +| mode | 选择器类型,支持单列,多列联动 | String | selector 单选/multiSelector 多级联动/unlinkedSelector 多级非联动 | selector | +| list | 选择器数据(v1.0.7 单选及非联动多选支持扁平数据:['选项 1', '选项 2']) | Array | - | - | +| level | 多列联动层级,仅 mode 为 multiSelector 有效 | Number | - | 2 | +| props | 自定义数据字段 | Object | - | {label:'label',value:'value',children:'children'} | +| cancel-text | 取消文字 | String | - | 取消 | +| cancel-color | 取消文字颜色 | String | - | #999 | +| confirm-text | 确定文字 | String | - | 确定 | +| confirm-color | 确定文字颜色 | String | - | #007aff | +| empty-text | (v1.0.7 新增)选择器列表为空的时候显示的文字 | String | - | 暂无数据 | +| empty-color | (v1.0.7 新增)暂无数据文字颜色 | String | - | #999 | +| column-num | 可视滚动区域内滚动个数,最好设置奇数值 | Number | - | 5 | +| radius | 选择器顶部圆角,支持 rpx,如 radius="10rpx" | String | - | - | +| ~~column-style~~ | ~~选择器默认样式(已弃用,见下方自定义样式说明)~~ | Object | - | - | +| ~~active-column-style~~ | ~~选择器选中样式(已弃用,见下方自定义样式说明)~~ | Object | - | - | +| loading | 选择器是否显示加载中,可使用 loading 插槽自定义加载效果 | Boolean | - | - | +| mask-color | 遮罩层颜色 | String | - | rgba(0, 0, 0, 0.4) | +| close-on-click-mask | 点击遮罩层是否关闭选择器 | Boolean | true/false | true | +| ~~change-on-init~~ | ~~(v1.0.7 已弃用)初始化时是否触发 change 事件~~ | Boolean | true/false | - | +| dataset | (v1.0.7 新增)可以向组件中传递任意的自定义的数据(对象形式数据),如`:dataset="{name:'test'}"`,在`confirm`或`change`事件中可以取到 | Object | - | - | +| show-header | (v1.0.8 新增)是否显示选择器头部 | Boolean | - | true | +| inline | (v1.0.8 新增)inline 模式,开启后默认显示选择器,无需点击弹出,可以配合`show-header`一起使用 | Boolean | - | - | +| z-index | (v1.0.9 新增)选择器层级,遮罩层默认-1 | Number | - | 999 | + +### 方法 + +| 方法名 | 说明 | 参数 | 返回值 | +| :------------- | :------------------------------------- | :-------------- | :----------------------------------------------------------------------------------------------------------- | +| show | 打开选择器 | - | | +| hide | 关闭选择器 | - | | +| getColumnsInfo | (v1.1.0 新增)根据 value 获取选择器信息 | 绑定值的`value` | 同`change` `confirm`回调参数,如果传入的`value`获取不到信息则只返回一个含有`dataset`的对象,具体自行打印查看 | + +### Events + +| 事件名称 | 说明 | 回调参数 | +| :------- | :--------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| show | 选择器打开时触发 | - | +| hide | 选择器隐藏时触发 | - | +| change | 选择器滚动时触发,此时不会改变绑定的值 | `{ index, item, value, change }` `index`触发滚动后新的索引,单选时是具体的索引值,多列联动选择时为数组。`item`触发滚动后新的的完整内容,包括`label`、`value`等,单选时为对象,多列选择时为数组对象。`value`触发滚动后新的 value 值,单列选择时为具体值,多列联动选择时为数组。`change`触发事件的类型,详情参考下面的 change 事件备注 | +| confirm | 点击选择器确定时触发,此时会改变绑定的值 | 同上`change`事件说明 | +| cancel | 点击选择器取消时触发 | 同上`change`事件说明 | + +### `change` 事件备注 + +如果绑定的值是空的,`change`触发后里面的内容都是列表的第一项。 +`change`事件会在以下情况触发: + +- 初始化 +- 绑定值 value 变化 +- 选择器 list 列表变化 +- 滚动选择器 + +以上情况会在回调函数中都可以取到`change`变化的类型,对应上面的情况包括以下: + +- `init` +- `value` +- `list` +- `scroll` + +根据这些类型大家可以在`change`的时候按需处理自己的业务逻辑,`init`现在指挥在调用选择器弹出的时候触发。 +下面的说明情况已失效,如需要在页面显示的时候根据`value`的值显示相应的中文,调用`v1.10`新增的方法`getColumnsInfo`,传入绑定的值即可获取到你想要的所有信息。 +~~比如一种常见的情况,有默认值的时候需要显示默认值的文字,此时可以`change`事件中判断`change`的类型是否是`init`,如果是的话可以取事件回调中的`item`进行显示绑定值对应的文字信息。~~ + +```javascript +handleChange (e) { + if (e.change === 'init') { + console.log(e.item.label) // 单选 选项1 + console.log(e.item.map(item => item.label).join('-')) // 多选 选项1-选项11 + } +} +``` + +### 插槽 + +| 插槽名 | 说明 | +| :------------ | :------------------ | +| cancel-text | 选择器取消文字插槽 | +| action-center | 选择器顶部中间插槽 | +| confirm-text | 选择器确定文字插槽 | +| loading | 选择器 loading 插槽 | +| empty | 选择器 空数据 插槽 | + +### 选择器自定义样式 + +原先的`column-style`和`active-column-style`已弃用,如需修改默认样式及选中样式参考`demo9` + +```css + +``` + +### 获取选中值的文字 + +`@confirm`事件中可以拿到: + +单选: + +```javascript +handleConfirm (e) { + console.log(e.item.label) // 选项1 +} +``` + +联动选择: + +```javascript +handleConfirm (e) { + console.log(e.item.map(item => item.label).join('-')) // 选项1-选项11 +} +``` + +## Tips + +微信小程序端,滚动时在 iOS 自带振动反馈,可在系统设置 -> 声音与触感 -> 系统触感反馈中关闭 + +## 其他 + +其他功能参考示例 Demo 代码。 diff --git a/components/lb-picker/index.vue b/components/lb-picker/index.vue new file mode 100644 index 0000000..c844a4c --- /dev/null +++ b/components/lb-picker/index.vue @@ -0,0 +1,313 @@ + + + + + diff --git a/components/lb-picker/mixins/index.js b/components/lb-picker/mixins/index.js new file mode 100644 index 0000000..505d74f --- /dev/null +++ b/components/lb-picker/mixins/index.js @@ -0,0 +1,45 @@ +import { getColumns } from '../utils' +export const commonMixin = { + data () { + return { + indicatorStyle: `height: 34px` + } + }, + created () { + this.init('init') + }, + methods: { + init (changeType) { + if (this.list && this.list.length) { + const column = getColumns({ + value: this.value, + list: this.list, + mode: this.mode, + props: this.props, + level: this.level + }) + const { columns, value, item, index } = column + this.selectValue = value + this.selectItem = item + this.pickerColumns = columns + this.pickerValue = index + this.$emit('change', { + value: this.selectValue, + item: this.selectItem, + index: this.pickerValue, + change: changeType + }) + } + } + }, + watch: { + value () { + if (!this.isConfirmChange) { + this.init('value') + } + }, + list () { + this.init('list') + } + } +} diff --git a/components/lb-picker/pickers/multi-selector-picker.vue b/components/lb-picker/pickers/multi-selector-picker.vue new file mode 100644 index 0000000..87ac229 --- /dev/null +++ b/components/lb-picker/pickers/multi-selector-picker.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/components/lb-picker/pickers/selector-picker.vue b/components/lb-picker/pickers/selector-picker.vue new file mode 100644 index 0000000..b9dbfa2 --- /dev/null +++ b/components/lb-picker/pickers/selector-picker.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/components/lb-picker/pickers/unlinked-selector-picker.vue b/components/lb-picker/pickers/unlinked-selector-picker.vue new file mode 100644 index 0000000..8081382 --- /dev/null +++ b/components/lb-picker/pickers/unlinked-selector-picker.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/components/lb-picker/style/picker-item.scss b/components/lb-picker/style/picker-item.scss new file mode 100644 index 0000000..fc497d1 --- /dev/null +++ b/components/lb-picker/style/picker-item.scss @@ -0,0 +1,23 @@ +.lb-picker-column { + height: 34px; + /* #ifndef APP-NVUE */ + display: flex; + box-sizing: border-box; + white-space: nowrap; + overflow: hidden; + /* #endif */ + flex-direction: row; + align-items: center; + justify-content: center; +} + +.lb-picker-column-label { + font-size: 16px; + text-align: center; + text-overflow: ellipsis; + transition-property: color; + transition-duration: 0.3s; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} \ No newline at end of file diff --git a/components/lb-picker/style/picker.scss b/components/lb-picker/style/picker.scss new file mode 100644 index 0000000..73720b0 --- /dev/null +++ b/components/lb-picker/style/picker.scss @@ -0,0 +1,151 @@ +.lb-picker { + position: relative; +} + +.lb-picker-mask { + background-color: rgba(0, 0, 0, 0.0); + position: fixed; + top: 0; + right: 0; + left: 0; + bottom: 0; +} + +.lb-picker-mask-animation { + transition-property: background-color; + transition-duration: 0.3s; +} + +.lb-picker-container { + position: relative; +} + +.lb-picker-container-fixed { + position: fixed; + left: 0; + right: 0; + bottom: 0; + transform: translateY(100%); + /* #ifndef APP-PLUS */ + overflow: hidden; + /* #endif */ +} + +.lb-picker-container-animation { + transition-property: transform; + transition-duration: 0.3s; +} + +.lb-picker-container-show { + transform: translateY(0); +} + +.lb-picker-header { + position: relative; + height: 45px; + background-color: #fff; + /* #ifdef APP-NVUE */ + border-width: 1px; + border-style: solid; + border-color: #e5e5e5; + /* #endif */ + /* #ifndef APP-NVUE */ + box-sizing: border-box; + display: flex; + /* #endif */ + flex-direction: row; + justify-content: space-between; + flex-wrap: nowrap; +} + +/* #ifndef APP-PLUS */ +.lb-picker-header::after { + content: ""; + position: absolute; + left: 0; + bottom: 0; + right: 0; + height: 1px; + clear: both; + border-bottom: 1px solid #e5e5e5; + color: #e5e5e5; + transform-origin: 0 100%; + -webkit-transform: scaleY(0.5); + transform: scaleY(0.5); +} + +/* #endif */ + +.lb-picker-action { + padding-left: 14px; + padding-right: 14px; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + flex-direction: row; + align-items: center; + justify-content: center; +} + +.lb-picker-action-cancel { + text-align: center; +} + +.lb-picker-action-cancel-text { + font-size: 16px; + color: #999; +} + +.lb-picker-action-confirm { + text-align: center; +} + +.lb-picker-action-confirm-text { + font-size: 16px; + color: #007aff; +} + +.lb-picker-content { + position: relative; + background-color: #fff; + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + justify-content: center; + flex-direction: column; +} + +.lb-picker-loading, +.lb-picker-empty { + /* #ifndef APP-NVUE */ + display: flex; + /* #endif */ + justify-content: center; + align-items: center; +} + +.lb-picker-empty-text { + color: #999; + font-size: 16px; +} + +.lb-picker-loading-img { + width: 25px; + height: 25px; + /* #ifndef APP-NVUE */ + animation: rotating 2s linear infinite; + /* #endif */ +} + +/* #ifndef APP-NVUE */ +@keyframes rotating { + 0% { + transform: rotate(0deg) + } + + to { + transform: rotate(1turn) + } +} + +/* #endif */ \ No newline at end of file diff --git a/components/lb-picker/utils.js b/components/lb-picker/utils.js new file mode 100644 index 0000000..5330d9b --- /dev/null +++ b/components/lb-picker/utils.js @@ -0,0 +1,110 @@ +/** + * 判断是否是对象 + * + * @export + * @param {*} val + * @returns true/false + */ +export function isObject (val) { + return Object.prototype.toString.call(val) === '[object Object]' +} + +/** + * 根据value获取columns信息 + * + * @export + * @param {*} { value, list, mode, props, level } + * @param {number} [type=2] 查询不到value数据返回数据类型 1空值null 2默认第一个选项 + * @returns + */ +export function getColumns ({ value, list, mode, props, level }, type = 2) { + let pickerValue = [] + let pickerColumns = [] + let selectValue = [] + let selectItem = [] + let columnsInfo = null + switch (mode) { + case 'selector': + let index = list.findIndex(item => { + return isObject(item) ? item[props.value] === value : item === value + }) + if (index === -1 && type === 1) { + columnsInfo = null + } else { + index = index > -1 ? index : 0 + selectItem = list[index] + selectValue = isObject(selectItem) + ? selectItem[props.value] + : selectItem + pickerColumns = list + pickerValue = [index] + columnsInfo = { + index: pickerValue, + value: selectValue, + item: selectItem, + columns: pickerColumns + } + } + break + case 'multiSelector': + const setPickerItems = (data = [], index = 0) => { + if (!data.length) return + const defaultValue = value || [] + if (index < level) { + const value = defaultValue[index] || '' + let i = data.findIndex(item => item[props.value] === value) + if (i === -1 && type === 1) return + i = i > -1 ? i : 0 + pickerValue[index] = i + pickerColumns[index] = data + if (data[i]) { + selectValue[index] = data[i][props.value] + selectItem[index] = data[i] + setPickerItems(data[i][props.children] || [], index + 1) + } + } + } + setPickerItems(list) + if (!selectValue.length && type === 1) { + columnsInfo = null + } else { + columnsInfo = { + index: pickerValue, + value: selectValue, + item: selectItem, + columns: pickerColumns + } + } + break + case 'unlinkedSelector': + list.forEach((item, i) => { + let index = item.findIndex(item => { + return isObject(item) + ? item[props.value] === value[i] + : item === value[i] + }) + if (index === -1 && type === 1) return + index = index > -1 ? index : 0 + const columnItem = list[i][index] + const valueItem = isObject(columnItem) + ? columnItem[props.value] + : columnItem + pickerValue[i] = index + selectValue[i] = valueItem + selectItem[i] = columnItem + }) + pickerColumns = list + if (!selectValue.length && type === 1) { + columnsInfo = null + } else { + columnsInfo = { + index: pickerValue, + value: selectValue, + item: selectItem, + columns: pickerColumns + } + } + break + } + return columnsInfo +} diff --git a/components/mask-view/mask-view.vue b/components/mask-view/mask-view.vue new file mode 100644 index 0000000..b343078 --- /dev/null +++ b/components/mask-view/mask-view.vue @@ -0,0 +1,120 @@ + + + + + + diff --git a/components/mescroll-uni/components/mescroll-down.css b/components/mescroll-uni/components/mescroll-down.css new file mode 100644 index 0000000..72bf106 --- /dev/null +++ b/components/mescroll-uni/components/mescroll-down.css @@ -0,0 +1,55 @@ +/* 下拉刷新区域 */ +.mescroll-downwarp { + position: absolute; + top: -100%; + left: 0; + width: 100%; + height: 100%; + text-align: center; +} + +/* 下拉刷新--内容区,定位于区域底部 */ +.mescroll-downwarp .downwarp-content { + position: absolute; + left: 0; + bottom: 0; + width: 100%; + min-height: 60rpx; + padding: 20rpx 0; + text-align: center; +} + +/* 下拉刷新--提示文本 */ +.mescroll-downwarp .downwarp-tip { + display: inline-block; + font-size: 28rpx; + vertical-align: middle; + margin-left: 16rpx; + /* color: gray; 已在style设置color,此处删去*/ +} + +/* 下拉刷新--旋转进度条 */ +.mescroll-downwarp .downwarp-progress { + display: inline-block; + width: 32rpx; + height: 32rpx; + border-radius: 50%; + border: 2rpx solid gray; + border-bottom-color: transparent !important; /*已在style设置border-color,此处需加 !important*/ + vertical-align: middle; +} + +/* 旋转动画 */ +.mescroll-downwarp .mescroll-rotate { + animation: mescrollDownRotate 0.6s linear infinite; +} + +@keyframes mescrollDownRotate { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/components/mescroll-uni/components/mescroll-down.vue b/components/mescroll-uni/components/mescroll-down.vue new file mode 100644 index 0000000..9fd1567 --- /dev/null +++ b/components/mescroll-uni/components/mescroll-down.vue @@ -0,0 +1,47 @@ + + + + + + diff --git a/components/mescroll-uni/components/mescroll-empty.vue b/components/mescroll-uni/components/mescroll-empty.vue new file mode 100644 index 0000000..6d1f2e0 --- /dev/null +++ b/components/mescroll-uni/components/mescroll-empty.vue @@ -0,0 +1,90 @@ + + + + + + diff --git a/components/mescroll-uni/components/mescroll-top.vue b/components/mescroll-uni/components/mescroll-top.vue new file mode 100644 index 0000000..5115fd8 --- /dev/null +++ b/components/mescroll-uni/components/mescroll-top.vue @@ -0,0 +1,83 @@ + + + + + + diff --git a/components/mescroll-uni/components/mescroll-up.css b/components/mescroll-uni/components/mescroll-up.css new file mode 100644 index 0000000..cbf48cd --- /dev/null +++ b/components/mescroll-uni/components/mescroll-up.css @@ -0,0 +1,47 @@ +/* 上拉加载区域 */ +.mescroll-upwarp { + box-sizing: border-box; + min-height: 110rpx; + padding: 30rpx 0; + text-align: center; + clear: both; +} + +/*提示文本 */ +.mescroll-upwarp .upwarp-tip, +.mescroll-upwarp .upwarp-nodata { + display: inline-block; + font-size: 28rpx; + vertical-align: middle; + /* color: gray; 已在style设置color,此处删去*/ +} + +.mescroll-upwarp .upwarp-tip { + margin-left: 16rpx; +} + +/*旋转进度条 */ +.mescroll-upwarp .upwarp-progress { + display: inline-block; + width: 32rpx; + height: 32rpx; + border-radius: 50%; + border: 2rpx solid gray; + border-bottom-color: transparent !important; /*已在style设置border-color,此处需加 !important*/ + vertical-align: middle; +} + +/* 旋转动画 */ +.mescroll-upwarp .mescroll-rotate { + animation: mescrollUpRotate 0.6s linear infinite; +} + +@keyframes mescrollUpRotate { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/components/mescroll-uni/components/mescroll-up.vue b/components/mescroll-uni/components/mescroll-up.vue new file mode 100644 index 0000000..11c2e1f --- /dev/null +++ b/components/mescroll-uni/components/mescroll-up.vue @@ -0,0 +1,39 @@ + + + + + + diff --git a/components/mescroll-uni/mescroll-body.css b/components/mescroll-uni/mescroll-body.css new file mode 100644 index 0000000..9cfa255 --- /dev/null +++ b/components/mescroll-uni/mescroll-body.css @@ -0,0 +1,14 @@ +.mescroll-body { + position: relative; /* 下拉刷新区域相对自身定位 */ + height: auto; /* 不可固定高度,否则overflow:hidden导致无法滑动; 同时使设置的最小高生效,实现列表不满屏仍可下拉*/ + overflow: hidden; /* 当有元素写在mescroll-body标签前面时,可遮住下拉刷新区域 */ + box-sizing: border-box; /* 避免设置padding出现双滚动条的问题 */ +} + +/* 适配 iPhoneX */ +@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) { + .mescroll-safearea { + padding-bottom: constant(safe-area-inset-bottom); + padding-bottom: env(safe-area-inset-bottom); + } +} \ No newline at end of file diff --git a/components/mescroll-uni/mescroll-body.vue b/components/mescroll-uni/mescroll-body.vue new file mode 100644 index 0000000..96e0e65 --- /dev/null +++ b/components/mescroll-uni/mescroll-body.vue @@ -0,0 +1,327 @@ + + + + + + + + + + + + + + + diff --git a/components/mescroll-uni/mescroll-mixins.js b/components/mescroll-uni/mescroll-mixins.js new file mode 100644 index 0000000..a379739 --- /dev/null +++ b/components/mescroll-uni/mescroll-mixins.js @@ -0,0 +1,65 @@ +// mescroll-body 和 mescroll-uni 通用 + +// import MescrollUni from "./mescroll-uni.vue"; +// import MescrollBody from "./mescroll-body.vue"; + +const MescrollMixin = { + // components: { // 非H5端无法通过mixin注册组件, 只能在main.js中注册全局组件或具体界面中注册 + // MescrollUni, + // MescrollBody + // }, + data() { + return { + mescroll: null //mescroll实例对象 + } + }, + // 注册系统自带的下拉刷新 (配置down.native为true时生效, 还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例) + onPullDownRefresh(){ + this.mescroll && this.mescroll.onPullDownRefresh(); + }, + // 注册列表滚动事件,用于判定在顶部可下拉刷新,在指定位置可显示隐藏回到顶部按钮 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效) + onPageScroll(e) { + this.mescroll && this.mescroll.onPageScroll(e); + }, + // 注册滚动到底部的事件,用于上拉加载 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效) + onReachBottom() { + this.mescroll && this.mescroll.onReachBottom(); + }, + methods: { + // mescroll组件初始化的回调,可获取到mescroll对象 + mescrollInit(mescroll) { + this.mescroll = mescroll; + this.mescrollInitByRef(); // 兼容字节跳动小程序 + }, + // 以ref的方式初始化mescroll对象 (兼容字节跳动小程序: http://www.mescroll.com/qa.html?v=20200107#q26) + mescrollInitByRef() { + if(!this.mescroll || !this.mescroll.resetUpScroll){ + let mescrollRef = this.$refs.mescrollRef; + if(mescrollRef) this.mescroll = mescrollRef.mescroll + } + }, + // 下拉刷新的回调 (mixin默认resetUpScroll) + downCallback() { + if(this.mescroll.optUp.use){ + this.mescroll.resetUpScroll() + }else{ + setTimeout(()=>{ + this.mescroll.endSuccess(); + }, 500) + } + }, + // 上拉加载的回调 + upCallback() { + // mixin默认延时500自动结束加载 + setTimeout(()=>{ + this.mescroll.endErr(); + }, 500) + } + }, + mounted() { + this.mescrollInitByRef(); // 兼容字节跳动小程序, 避免未设置@init或@init此时未能取到ref的情况 + } + +} + +export default MescrollMixin; diff --git a/components/mescroll-uni/mescroll-uni-option.js b/components/mescroll-uni/mescroll-uni-option.js new file mode 100644 index 0000000..d9b71d2 --- /dev/null +++ b/components/mescroll-uni/mescroll-uni-option.js @@ -0,0 +1,33 @@ +// 全局配置 +// mescroll-body 和 mescroll-uni 通用 +const GlobalOption = { + down: { + // 其他down的配置参数也可以写,这里只展示了常用的配置: + textInOffset: '下拉刷新', // 下拉的距离在offset范围内的提示文本 + textOutOffset: '释放更新', // 下拉的距离大于offset范围的提示文本 + textLoading: '加载中 ...', // 加载中的提示文本 + offset: 80, // 在列表顶部,下拉大于80px,松手即可触发下拉刷新的回调 + native: false // 是否使用系统自带的下拉刷新; 默认false; 仅在mescroll-body生效 (值为true时,还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例) + }, + up: { + // 其他up的配置参数也可以写,这里只展示了常用的配置: + textLoading: '加载中 ...', // 加载中的提示文本 + textNoMore: '-- END --', // 没有更多数据的提示文本 + offset: 80, // 距底部多远时,触发upCallback + toTop: { + // 回到顶部按钮,需配置src才显示 + src: "http://www.mescroll.com/img/mescroll-totop.png?v=1", // 图片路径 (建议放入static目录, 如 /static/img/mescroll-totop.png ) + offset: 1000, // 列表滚动多少距离才显示回到顶部按钮,默认1000px + right: 20, // 到右边的距离, 默认20 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) + bottom: 120, // 到底部的距离, 默认120 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) + width: 72 // 回到顶部图标的宽度, 默认72 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) + }, + empty: { + use: true, // 是否显示空布局 + icon: "http://www.mescroll.com/img/mescroll-empty.png?v=1", // 图标路径 (建议放入static目录, 如 /static/img/mescroll-empty.png ) + tip: '~ 空空如也 ~' // 提示 + } + } +} + +export default GlobalOption diff --git a/components/mescroll-uni/mescroll-uni.css b/components/mescroll-uni/mescroll-uni.css new file mode 100644 index 0000000..39438cd --- /dev/null +++ b/components/mescroll-uni/mescroll-uni.css @@ -0,0 +1,36 @@ +.mescroll-uni-warp{ + height: 100%; +} + +.mescroll-uni-content{ + height: 100%; +} + +.mescroll-uni { + position: relative; + width: 100%; + height: 100%; + min-height: 200rpx; + overflow-y: auto; + box-sizing: border-box; /* 避免设置padding出现双滚动条的问题 */ +} + +/* 定位的方式固定高度 */ +.mescroll-uni-fixed{ + z-index: 1; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: auto; /* 使right生效 */ + height: auto; /* 使bottom生效 */ +} + +/* 适配 iPhoneX */ +@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) { + .mescroll-safearea { + padding-bottom: constant(safe-area-inset-bottom); + padding-bottom: env(safe-area-inset-bottom); + } +} diff --git a/components/mescroll-uni/mescroll-uni.js b/components/mescroll-uni/mescroll-uni.js new file mode 100644 index 0000000..34cf4ff --- /dev/null +++ b/components/mescroll-uni/mescroll-uni.js @@ -0,0 +1,788 @@ +/* mescroll + * version 1.3.1 + * 2020-07-27 wenju + * http://www.mescroll.com + */ + +export default function MeScroll(options, isScrollBody) { + let me = this; + me.version = '1.3.1'; // mescroll版本号 + me.options = options || {}; // 配置 + me.isScrollBody = isScrollBody || false; // 滚动区域是否为原生页面滚动; 默认为scroll-view + + me.isDownScrolling = false; // 是否在执行下拉刷新的回调 + me.isUpScrolling = false; // 是否在执行上拉加载的回调 + let hasDownCallback = me.options.down && me.options.down.callback; // 是否配置了down的callback + + // 初始化下拉刷新 + me.initDownScroll(); + // 初始化上拉加载,则初始化 + me.initUpScroll(); + + // 自动加载 + setTimeout(function() { // 待主线程执行完毕再执行,避免new MeScroll未初始化,在回调获取不到mescroll的实例 + // 自动触发下拉刷新 (只有配置了down的callback才自动触发下拉刷新) + if ((me.optDown.use || me.optDown.native) && me.optDown.auto && hasDownCallback) { + if (me.optDown.autoShowLoading) { + me.triggerDownScroll(); // 显示下拉进度,执行下拉回调 + } else { + me.optDown.callback && me.optDown.callback(me); // 不显示下拉进度,直接执行下拉回调 + } + } + // 自动触发上拉加载 + if(!me.isUpAutoLoad){ // 部分小程序(头条小程序)emit是异步, 会导致isUpAutoLoad判断有误, 先延时确保先执行down的callback,再执行up的callback + setTimeout(function(){ + me.optUp.use && me.optUp.auto && !me.isUpAutoLoad && me.triggerUpScroll(); + },100) + } + }, 30); // 需让me.optDown.inited和me.optUp.inited先执行 +} + +/* 配置参数:下拉刷新 */ +MeScroll.prototype.extendDownScroll = function(optDown) { + // 下拉刷新的配置 + MeScroll.extend(optDown, { + use: true, // 是否启用下拉刷新; 默认true + auto: true, // 是否在初始化完毕之后自动执行下拉刷新的回调; 默认true + native: false, // 是否使用系统自带的下拉刷新; 默认false; 仅mescroll-body生效 (值为true时,还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例) + autoShowLoading: false, // 如果设置auto=true(在初始化完毕之后自动执行下拉刷新的回调),那么是否显示下拉刷新的进度; 默认false + isLock: false, // 是否锁定下拉刷新,默认false; + offset: 80, // 在列表顶部,下拉大于80px,松手即可触发下拉刷新的回调 + startTop: 100, // scroll-view快速滚动到顶部时,此时的scroll-top可能大于0, 此值用于控制最大的误差 + inOffsetRate: 1, // 在列表顶部,下拉的距离小于offset时,改变下拉区域高度比例;值小于1且越接近0,高度变化越小,表现为越往下越难拉 + outOffsetRate: 0.2, // 在列表顶部,下拉的距离大于offset时,改变下拉区域高度比例;值小于1且越接近0,高度变化越小,表现为越往下越难拉 + bottomOffset: 20, // 当手指touchmove位置在距离body底部20px范围内的时候结束上拉刷新,避免Webview嵌套导致touchend事件不执行 + minAngle: 45, // 向下滑动最少偏移的角度,取值区间 [0,90];默认45度,即向下滑动的角度大于45度则触发下拉;而小于45度,将不触发下拉,避免与左右滑动的轮播等组件冲突; + textInOffset: '下拉刷新', // 下拉的距离在offset范围内的提示文本 + textOutOffset: '释放更新', // 下拉的距离大于offset范围的提示文本 + textLoading: '加载中 ...', // 加载中的提示文本 + bgColor: "transparent", // 背景颜色 (建议在pages.json中再设置一下backgroundColorTop) + textColor: "gray", // 文本颜色 (当bgColor配置了颜色,而textColor未配置时,则textColor会默认为白色) + inited: null, // 下拉刷新初始化完毕的回调 + inOffset: null, // 下拉的距离进入offset范围内那一刻的回调 + outOffset: null, // 下拉的距离大于offset那一刻的回调 + onMoving: null, // 下拉过程中的回调,滑动过程一直在执行; rate下拉区域当前高度与指定距离的比值(inOffset: rate<1; outOffset: rate>=1); downHight当前下拉区域的高度 + beforeLoading: null, // 准备触发下拉刷新的回调: 如果return true,将不触发showLoading和callback回调; 常用来完全自定义下拉刷新, 参考案例【淘宝 v6.8.0】 + showLoading: null, // 显示下拉刷新进度的回调 + afterLoading: null, // 显示下拉刷新进度的回调之后,马上要执行的代码 (如: 在wxs中使用) + beforeEndDownScroll: null, // 准备结束下拉的回调. 返回结束下拉的延时执行时间,默认0ms; 常用于结束下拉之前再显示另外一小段动画,才去隐藏下拉刷新的场景, 参考案例【dotJump】 + endDownScroll: null, // 结束下拉刷新的回调 + afterEndDownScroll: null, // 结束下拉刷新的回调,马上要执行的代码 (如: 在wxs中使用) + callback: function(mescroll) { + // 下拉刷新的回调;默认重置上拉加载列表为第一页 + mescroll.resetUpScroll(); + } + }) +} + +/* 配置参数:上拉加载 */ +MeScroll.prototype.extendUpScroll = function(optUp) { + // 上拉加载的配置 + MeScroll.extend(optUp, { + use: true, // 是否启用上拉加载; 默认true + auto: true, // 是否在初始化完毕之后自动执行上拉加载的回调; 默认true + isLock: false, // 是否锁定上拉加载,默认false; + isBoth: true, // 上拉加载时,如果滑动到列表顶部是否可以同时触发下拉刷新;默认true,两者可同时触发; + callback: null, // 上拉加载的回调;function(page,mescroll){ } + page: { + num: 0, // 当前页码,默认0,回调之前会加1,即callback(page)会从1开始 + size: 10, // 每页数据的数量 + time: null // 加载第一页数据服务器返回的时间; 防止用户翻页时,后台新增了数据从而导致下一页数据重复; + }, + noMoreSize: 5, // 如果列表已无数据,可设置列表的总数量要大于等于5条才显示无更多数据;避免列表数据过少(比如只有一条数据),显示无更多数据会不好看 + offset: 80, // 距底部多远时,触发upCallback + textLoading: '加载中 ...', // 加载中的提示文本 + textNoMore: '-- END --', // 没有更多数据的提示文本 + bgColor: "transparent", // 背景颜色 (建议在pages.json中再设置一下backgroundColorBottom) + textColor: "gray", // 文本颜色 (当bgColor配置了颜色,而textColor未配置时,则textColor会默认为白色) + inited: null, // 初始化完毕的回调 + showLoading: null, // 显示加载中的回调 + showNoMore: null, // 显示无更多数据的回调 + hideUpScroll: null, // 隐藏上拉加载的回调 + errDistance: 60, // endErr的时候需往上滑动一段距离,使其往下滑动时再次触发onReachBottom,仅mescroll-body生效 + toTop: { + // 回到顶部按钮,需配置src才显示 + src: null, // 图片路径,默认null (绝对路径或网络图) + offset: 1000, // 列表滚动多少距离才显示回到顶部按钮,默认1000 + duration: 300, // 回到顶部的动画时长,默认300ms (当值为0或300则使用系统自带回到顶部,更流畅; 其他值则通过step模拟,部分机型可能不够流畅,所以非特殊情况不建议修改此项) + btnClick: null, // 点击按钮的回调 + onShow: null, // 是否显示的回调 + zIndex: 9990, // fixed定位z-index值 + left: null, // 到左边的距离, 默认null. 此项有值时,right不生效. (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx) + right: 20, // 到右边的距离, 默认20 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx) + bottom: 120, // 到底部的距离, 默认120 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx) + safearea: false, // bottom的偏移量是否加上底部安全区的距离, 默认false, 需要适配iPhoneX时使用 (具体的界面如果不配置此项,则取本vue的safearea值) + width: 72, // 回到顶部图标的宽度, 默认72 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx) + radius: "50%" // 圆角, 默认"50%" (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx) + }, + empty: { + use: true, // 是否显示空布局 + icon: null, // 图标路径 + tip: '~ 暂无相关数据 ~', // 提示 + btnText: '', // 按钮 + btnClick: null, // 点击按钮的回调 + onShow: null, // 是否显示的回调 + fixed: false, // 是否使用fixed定位,默认false; 配置fixed为true,以下的top和zIndex才生效 (transform会使fixed失效,最终会降级为absolute) + top: "100rpx", // fixed定位的top值 (完整的单位值,如 "10%"; "100rpx") + zIndex: 99 // fixed定位z-index值 + }, + onScroll: false // 是否监听滚动事件 + }) +} + +/* 配置参数 */ +MeScroll.extend = function(userOption, defaultOption) { + if (!userOption) return defaultOption; + for (let key in defaultOption) { + if (userOption[key] == null) { + let def = defaultOption[key]; + if (def != null && typeof def === 'object') { + userOption[key] = MeScroll.extend({}, def); // 深度匹配 + } else { + userOption[key] = def; + } + } else if (typeof userOption[key] === 'object') { + MeScroll.extend(userOption[key], defaultOption[key]); // 深度匹配 + } + } + return userOption; +} + +/* 简单判断是否配置了颜色 (非透明,非白色) */ +MeScroll.prototype.hasColor = function(color) { + if(!color) return false; + let c = color.toLowerCase(); + return c != "#fff" && c != "#ffffff" && c != "transparent" && c != "white" +} + +/* -------初始化下拉刷新------- */ +MeScroll.prototype.initDownScroll = function() { + let me = this; + // 配置参数 + me.optDown = me.options.down || {}; + if(!me.optDown.textColor && me.hasColor(me.optDown.bgColor)) me.optDown.textColor = "#fff"; // 当bgColor有值且textColor未设置,则textColor默认白色 + me.extendDownScroll(me.optDown); + + // 如果是mescroll-body且配置了native,则禁止自定义的下拉刷新 + if(me.isScrollBody && me.optDown.native){ + me.optDown.use = false + }else{ + me.optDown.native = false // 仅mescroll-body支持,mescroll-uni不支持 + } + + me.downHight = 0; // 下拉区域的高度 + + // 在页面中加入下拉布局 + if (me.optDown.use && me.optDown.inited) { + // 初始化完毕的回调 + setTimeout(function() { // 待主线程执行完毕再执行,避免new MeScroll未初始化,在回调获取不到mescroll的实例 + me.optDown.inited(me); + }, 0) + } +} + +/* 列表touchstart事件 */ +MeScroll.prototype.touchstartEvent = function(e) { + if (!this.optDown.use) return; + + this.startPoint = this.getPoint(e); // 记录起点 + this.startTop = this.getScrollTop(); // 记录此时的滚动条位置 + this.startAngle = 0; // 初始角度 + this.lastPoint = this.startPoint; // 重置上次move的点 + this.maxTouchmoveY = this.getBodyHeight() - this.optDown.bottomOffset; // 手指触摸的最大范围(写在touchstart避免body获取高度为0的情况) + this.inTouchend = false; // 标记不是touchend +} + +/* 列表touchmove事件 */ +MeScroll.prototype.touchmoveEvent = function(e) { + if (!this.optDown.use) return; + let me = this; + + let scrollTop = me.getScrollTop(); // 当前滚动条的距离 + let curPoint = me.getPoint(e); // 当前点 + + let moveY = curPoint.y - me.startPoint.y; // 和起点比,移动的距离,大于0向下拉,小于0向上拉 + + // 向下拉 && 在顶部 + // mescroll-body,直接判定在顶部即可 + // scroll-view在滚动时不会触发touchmove,当触顶/底/左/右时,才会触发touchmove + // scroll-view滚动到顶部时,scrollTop不一定为0,也有可能大于0; 在iOS的APP中scrollTop可能为负数,不一定和startTop相等 + if (moveY > 0 && ( + (me.isScrollBody && scrollTop <= 0) + || + (!me.isScrollBody && (scrollTop <= 0 || (scrollTop <= me.optDown.startTop && scrollTop === me.startTop)) ) + )) { + // 可下拉的条件 + if (!me.inTouchend && !me.isDownScrolling && !me.optDown.isLock && (!me.isUpScrolling || (me.isUpScrolling && + me.optUp.isBoth))) { + + // 下拉的初始角度是否在配置的范围内 + if(!me.startAngle) me.startAngle = me.getAngle(me.lastPoint, curPoint); // 两点之间的角度,区间 [0,90] + if (me.startAngle < me.optDown.minAngle) return; // 如果小于配置的角度,则不往下执行下拉刷新 + + // 如果手指的位置超过配置的距离,则提前结束下拉,避免Webview嵌套导致touchend无法触发 + if (me.maxTouchmoveY > 0 && curPoint.y >= me.maxTouchmoveY) { + me.inTouchend = true; // 标记执行touchend + me.touchendEvent(); // 提前触发touchend + return; + } + + me.preventDefault(e); // 阻止默认事件 + + let diff = curPoint.y - me.lastPoint.y; // 和上次比,移动的距离 (大于0向下,小于0向上) + + // 下拉距离 < 指定距离 + if (me.downHight < me.optDown.offset) { + if (me.movetype !== 1) { + me.movetype = 1; // 加入标记,保证只执行一次 + me.optDown.inOffset && me.optDown.inOffset(me); // 进入指定距离范围内那一刻的回调,只执行一次 + me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来 + } + me.downHight += diff * me.optDown.inOffsetRate; // 越往下,高度变化越小 + + // 指定距离 <= 下拉距离 + } else { + if (me.movetype !== 2) { + me.movetype = 2; // 加入标记,保证只执行一次 + me.optDown.outOffset && me.optDown.outOffset(me); // 下拉超过指定距离那一刻的回调,只执行一次 + me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来 + } + if (diff > 0) { // 向下拉 + me.downHight += diff * me.optDown.outOffsetRate; // 越往下,高度变化越小 + } else { // 向上收 + me.downHight += diff; // 向上收回高度,则向上滑多少收多少高度 + } + } + + me.downHight = Math.round(me.downHight) // 取整 + let rate = me.downHight / me.optDown.offset; // 下拉区域当前高度与指定距离的比值 + me.optDown.onMoving && me.optDown.onMoving(me, rate, me.downHight); // 下拉过程中的回调,一直在执行 + } + } + + me.lastPoint = curPoint; // 记录本次移动的点 +} + +/* 列表touchend事件 */ +MeScroll.prototype.touchendEvent = function(e) { + if (!this.optDown.use) return; + // 如果下拉区域高度已改变,则需重置回来 + if (this.isMoveDown) { + if (this.downHight >= this.optDown.offset) { + // 符合触发刷新的条件 + this.triggerDownScroll(); + } else { + // 不符合的话 则重置 + this.downHight = 0; + this.endDownScrollCall(this); + } + this.movetype = 0; + this.isMoveDown = false; + } else if (!this.isScrollBody && this.getScrollTop() === this.startTop) { // scroll-view到顶/左/右/底的滑动事件 + let isScrollUp = this.getPoint(e).y - this.startPoint.y < 0; // 和起点比,移动的距离,大于0向下拉,小于0向上拉 + // 上滑 + if (isScrollUp) { + // 需检查滑动的角度 + let angle = this.getAngle(this.getPoint(e), this.startPoint); // 两点之间的角度,区间 [0,90] + if (angle > 80) { + // 检查并触发上拉 + this.triggerUpScroll(true); + } + } + } +} + +/* 根据点击滑动事件获取第一个手指的坐标 */ +MeScroll.prototype.getPoint = function(e) { + if (!e) { + return { + x: 0, + y: 0 + } + } + if (e.touches && e.touches[0]) { + return { + x: e.touches[0].pageX, + y: e.touches[0].pageY + } + } else if (e.changedTouches && e.changedTouches[0]) { + return { + x: e.changedTouches[0].pageX, + y: e.changedTouches[0].pageY + } + } else { + return { + x: e.clientX, + y: e.clientY + } + } +} + +/* 计算两点之间的角度: 区间 [0,90]*/ +MeScroll.prototype.getAngle = function(p1, p2) { + let x = Math.abs(p1.x - p2.x); + let y = Math.abs(p1.y - p2.y); + let z = Math.sqrt(x * x + y * y); + let angle = 0; + if (z !== 0) { + angle = Math.asin(y / z) / Math.PI * 180; + } + return angle +} + +/* 触发下拉刷新 */ +MeScroll.prototype.triggerDownScroll = function() { + if (this.optDown.beforeLoading && this.optDown.beforeLoading(this)) { + //return true则处于完全自定义状态 + } else { + this.showDownScroll(); // 下拉刷新中... + !this.optDown.native && this.optDown.callback && this.optDown.callback(this); // 执行回调,联网加载数据 + } +} + +/* 显示下拉进度布局 */ +MeScroll.prototype.showDownScroll = function() { + this.isDownScrolling = true; // 标记下拉中 + if (this.optDown.native) { + uni.startPullDownRefresh(); // 系统自带的下拉刷新 + this.showDownLoadingCall(0); // 仍触发showLoading,因为上拉加载用到 + } else{ + this.downHight = this.optDown.offset; // 更新下拉区域高度 + this.showDownLoadingCall(this.downHight); // 下拉刷新中... + } +} + +MeScroll.prototype.showDownLoadingCall = function(downHight) { + this.optDown.showLoading && this.optDown.showLoading(this, downHight); // 下拉刷新中... + this.optDown.afterLoading && this.optDown.afterLoading(this, downHight); // 下拉刷新中...触发之后马上要执行的代码 +} + +/* 显示系统自带的下拉刷新时需要处理的业务 */ +MeScroll.prototype.onPullDownRefresh = function() { + this.isDownScrolling = true; // 标记下拉中 + this.showDownLoadingCall(0); // 仍触发showLoading,因为上拉加载用到 + this.optDown.callback && this.optDown.callback(this); // 执行回调,联网加载数据 +} + +/* 结束下拉刷新 */ +MeScroll.prototype.endDownScroll = function() { + if (this.optDown.native) { // 结束原生下拉刷新 + this.isDownScrolling = false; + this.endDownScrollCall(this); + uni.stopPullDownRefresh(); + return + } + let me = this; + // 结束下拉刷新的方法 + let endScroll = function() { + me.downHight = 0; + me.isDownScrolling = false; + me.endDownScrollCall(me); + if(!me.isScrollBody){ + me.setScrollHeight(0) // scroll-view重置滚动区域,使数据不满屏时仍可检查触发翻页 + me.scrollTo(0,0) // scroll-view需重置滚动条到顶部,避免startTop大于0时,对下拉刷新的影响 + } + } + // 结束下拉刷新时的回调 + let delay = 0; + if (me.optDown.beforeEndDownScroll) delay = me.optDown.beforeEndDownScroll(me); // 结束下拉刷新的延时,单位ms + if (typeof delay === 'number' && delay > 0) { + setTimeout(endScroll, delay); + } else { + endScroll(); + } +} + +MeScroll.prototype.endDownScrollCall = function() { + this.optDown.endDownScroll && this.optDown.endDownScroll(this); + this.optDown.afterEndDownScroll && this.optDown.afterEndDownScroll(this); +} + +/* 锁定下拉刷新:isLock=ture,null锁定;isLock=false解锁 */ +MeScroll.prototype.lockDownScroll = function(isLock) { + if (isLock == null) isLock = true; + this.optDown.isLock = isLock; +} + +/* 锁定上拉加载:isLock=ture,null锁定;isLock=false解锁 */ +MeScroll.prototype.lockUpScroll = function(isLock) { + if (isLock == null) isLock = true; + this.optUp.isLock = isLock; +} + +/* -------初始化上拉加载------- */ +MeScroll.prototype.initUpScroll = function() { + let me = this; + // 配置参数 + me.optUp = me.options.up || {use: false} + if(!me.optUp.textColor && me.hasColor(me.optUp.bgColor)) me.optUp.textColor = "#fff"; // 当bgColor有值且textColor未设置,则textColor默认白色 + me.extendUpScroll(me.optUp); + + if (me.optUp.use === false) return; // 配置不使用上拉加载时,则不初始化上拉布局 + me.optUp.hasNext = true; // 如果使用上拉,则默认有下一页 + me.startNum = me.optUp.page.num + 1; // 记录page开始的页码 + + // 初始化完毕的回调 + if (me.optUp.inited) { + setTimeout(function() { // 待主线程执行完毕再执行,避免new MeScroll未初始化,在回调获取不到mescroll的实例 + me.optUp.inited(me); + }, 0) + } +} + +/*滚动到底部的事件 (仅mescroll-body生效)*/ +MeScroll.prototype.onReachBottom = function() { + if (this.isScrollBody && !this.isUpScrolling) { // 只能支持下拉刷新的时候同时可以触发上拉加载,否则滚动到底部就需要上滑一点才能触发onReachBottom + if (!this.optUp.isLock && this.optUp.hasNext) { + this.triggerUpScroll(); + } + } +} + +/*列表滚动事件 (仅mescroll-body生效)*/ +MeScroll.prototype.onPageScroll = function(e) { + if (!this.isScrollBody) return; + + // 更新滚动条的位置 (主要用于判断下拉刷新时,滚动条是否在顶部) + this.setScrollTop(e.scrollTop); + + // 顶部按钮的显示隐藏 + if (e.scrollTop >= this.optUp.toTop.offset) { + this.showTopBtn(); + } else { + this.hideTopBtn(); + } +} + +/*列表滚动事件*/ +MeScroll.prototype.scroll = function(e, onScroll) { + // 更新滚动条的位置 + this.setScrollTop(e.scrollTop); + // 更新滚动内容高度 + this.setScrollHeight(e.scrollHeight); + + // 向上滑还是向下滑动 + if (this.preScrollY == null) this.preScrollY = 0; + this.isScrollUp = e.scrollTop - this.preScrollY > 0; + this.preScrollY = e.scrollTop; + + // 上滑 && 检查并触发上拉 + this.isScrollUp && this.triggerUpScroll(true); + + // 顶部按钮的显示隐藏 + if (e.scrollTop >= this.optUp.toTop.offset) { + this.showTopBtn(); + } else { + this.hideTopBtn(); + } + + // 滑动监听 + this.optUp.onScroll && onScroll && onScroll() +} + +/* 触发上拉加载 */ +MeScroll.prototype.triggerUpScroll = function(isCheck) { + if (!this.isUpScrolling && this.optUp.use && this.optUp.callback) { + // 是否校验在底部; 默认不校验 + if (isCheck === true) { + let canUp = false; + // 还有下一页 && 没有锁定 && 不在下拉中 + if (this.optUp.hasNext && !this.optUp.isLock && !this.isDownScrolling) { + if (this.getScrollBottom() <= this.optUp.offset) { // 到底部 + canUp = true; // 标记可上拉 + } + } + if (canUp === false) return; + } + this.showUpScroll(); // 上拉加载中... + this.optUp.page.num++; // 预先加一页,如果失败则减回 + this.isUpAutoLoad = true; // 标记上拉已经自动执行过,避免初始化时多次触发上拉回调 + this.num = this.optUp.page.num; // 把最新的页数赋值在mescroll上,避免对page的影响 + this.size = this.optUp.page.size; // 把最新的页码赋值在mescroll上,避免对page的影响 + this.time = this.optUp.page.time; // 把最新的页码赋值在mescroll上,避免对page的影响 + this.optUp.callback(this); // 执行回调,联网加载数据 + } +} + +/* 显示上拉加载中 */ +MeScroll.prototype.showUpScroll = function() { + this.isUpScrolling = true; // 标记上拉加载中 + this.optUp.showLoading && this.optUp.showLoading(this); // 回调 +} + +/* 显示上拉无更多数据 */ +MeScroll.prototype.showNoMore = function() { + this.optUp.hasNext = false; // 标记无更多数据 + this.optUp.showNoMore && this.optUp.showNoMore(this); // 回调 +} + +/* 隐藏上拉区域**/ +MeScroll.prototype.hideUpScroll = function() { + this.optUp.hideUpScroll && this.optUp.hideUpScroll(this); // 回调 +} + +/* 结束上拉加载 */ +MeScroll.prototype.endUpScroll = function(isShowNoMore) { + if (isShowNoMore != null) { // isShowNoMore=null,不处理下拉状态,下拉刷新的时候调用 + if (isShowNoMore) { + this.showNoMore(); // isShowNoMore=true,显示无更多数据 + } else { + this.hideUpScroll(); // isShowNoMore=false,隐藏上拉加载 + } + } + this.isUpScrolling = false; // 标记结束上拉加载 +} + +/* 重置上拉加载列表为第一页 + *isShowLoading 是否显示进度布局; + * 1.默认null,不传参,则显示上拉加载的进度布局 + * 2.传参true, 则显示下拉刷新的进度布局 + * 3.传参false,则不显示上拉和下拉的进度 (常用于静默更新列表数据) + */ +MeScroll.prototype.resetUpScroll = function(isShowLoading) { + if (this.optUp && this.optUp.use) { + let page = this.optUp.page; + this.prePageNum = page.num; // 缓存重置前的页码,加载失败可退回 + this.prePageTime = page.time; // 缓存重置前的时间,加载失败可退回 + page.num = this.startNum; // 重置为第一页 + page.time = null; // 重置时间为空 + if (!this.isDownScrolling && isShowLoading !== false) { // 如果不是下拉刷新触发的resetUpScroll并且不配置列表静默更新,则显示进度; + if (isShowLoading == null) { + this.removeEmpty(); // 移除空布局 + this.showUpScroll(); // 不传参,默认显示上拉加载的进度布局 + } else { + this.showDownScroll(); // 传true,显示下拉刷新的进度布局,不清空列表 + } + } + this.isUpAutoLoad = true; // 标记上拉已经自动执行过,避免初始化时多次触发上拉回调 + this.num = page.num; // 把最新的页数赋值在mescroll上,避免对page的影响 + this.size = page.size; // 把最新的页码赋值在mescroll上,避免对page的影响 + this.time = page.time; // 把最新的页码赋值在mescroll上,避免对page的影响 + this.optUp.callback && this.optUp.callback(this); // 执行上拉回调 + } +} + +/* 设置page.num的值 */ +MeScroll.prototype.setPageNum = function(num) { + this.optUp.page.num = num - 1; +} + +/* 设置page.size的值 */ +MeScroll.prototype.setPageSize = function(size) { + this.optUp.page.size = size; +} + +/* 联网回调成功,结束下拉刷新和上拉加载 + * dataSize: 当前页的数据量(必传) + * totalPage: 总页数(必传) + * systime: 服务器时间 (可空) + */ +MeScroll.prototype.endByPage = function(dataSize, totalPage, systime) { + let hasNext; + if (this.optUp.use && totalPage != null) hasNext = this.optUp.page.num < totalPage; // 是否还有下一页 + this.endSuccess(dataSize, hasNext, systime); +} + +/* 联网回调成功,结束下拉刷新和上拉加载 + * dataSize: 当前页的数据量(必传) + * totalSize: 列表所有数据总数量(必传) + * systime: 服务器时间 (可空) + */ +MeScroll.prototype.endBySize = function(dataSize, totalSize, systime) { + let hasNext; + if (this.optUp.use && totalSize != null) { + let loadSize = (this.optUp.page.num - 1) * this.optUp.page.size + dataSize; // 已加载的数据总数 + hasNext = loadSize < totalSize; // 是否还有下一页 + } + this.endSuccess(dataSize, hasNext, systime); +} + +/* 联网回调成功,结束下拉刷新和上拉加载 + * dataSize: 当前页的数据个数(不是所有页的数据总和),用于上拉加载判断是否还有下一页.如果不传,则会判断还有下一页 + * hasNext: 是否还有下一页,布尔类型;用来解决这个小问题:比如列表共有20条数据,每页加载10条,共2页.如果只根据dataSize判断,则需翻到第三页才会知道无更多数据,如果传了hasNext,则翻到第二页即可显示无更多数据. + * systime: 服务器时间(可空);用来解决这个小问题:当准备翻下一页时,数据库新增了几条记录,此时翻下一页,前面的几条数据会和上一页的重复;这里传入了systime,那么upCallback的page.time就会有值,把page.time传给服务器,让后台过滤新加入的那几条记录 + */ +MeScroll.prototype.endSuccess = function(dataSize, hasNext, systime) { + let me = this; + // 结束下拉刷新 + if (me.isDownScrolling) me.endDownScroll(); + + // 结束上拉加载 + if (me.optUp.use) { + let isShowNoMore; // 是否已无更多数据 + if (dataSize != null) { + let pageNum = me.optUp.page.num; // 当前页码 + let pageSize = me.optUp.page.size; // 每页长度 + // 如果是第一页 + if (pageNum === 1) { + if (systime) me.optUp.page.time = systime; // 设置加载列表数据第一页的时间 + } + if (dataSize < pageSize || hasNext === false) { + // 返回的数据不满一页时,则说明已无更多数据 + me.optUp.hasNext = false; + if (dataSize === 0 && pageNum === 1) { + // 如果第一页无任何数据且配置了空布局 + isShowNoMore = false; + me.showEmpty(); + } else { + // 总列表数少于配置的数量,则不显示无更多数据 + let allDataSize = (pageNum - 1) * pageSize + dataSize; + if (allDataSize < me.optUp.noMoreSize) { + isShowNoMore = false; + } else { + isShowNoMore = true; + } + me.removeEmpty(); // 移除空布局 + } + } else { + // 还有下一页 + isShowNoMore = false; + me.optUp.hasNext = true; + me.removeEmpty(); // 移除空布局 + } + } + + // 隐藏上拉 + me.endUpScroll(isShowNoMore); + } +} + +/* 回调失败,结束下拉刷新和上拉加载 */ +MeScroll.prototype.endErr = function(errDistance) { + // 结束下拉,回调失败重置回原来的页码和时间 + if (this.isDownScrolling) { + let page = this.optUp.page; + if (page && this.prePageNum) { + page.num = this.prePageNum; + page.time = this.prePageTime; + } + this.endDownScroll(); + } + // 结束上拉,回调失败重置回原来的页码 + if (this.isUpScrolling) { + this.optUp.page.num--; + this.endUpScroll(false); + // 如果是mescroll-body,则需往回滚一定距离 + if(this.isScrollBody && errDistance !== 0){ // 不处理0 + if(!errDistance) errDistance = this.optUp.errDistance; // 不传,则取默认 + this.scrollTo(this.getScrollTop() - errDistance, 0) // 往上回滚的距离 + } + } +} + +/* 显示空布局 */ +MeScroll.prototype.showEmpty = function() { + this.optUp.empty.use && this.optUp.empty.onShow && this.optUp.empty.onShow(true) +} + +/* 移除空布局 */ +MeScroll.prototype.removeEmpty = function() { + this.optUp.empty.use && this.optUp.empty.onShow && this.optUp.empty.onShow(false) +} + +/* 显示回到顶部的按钮 */ +MeScroll.prototype.showTopBtn = function() { + if (!this.topBtnShow) { + this.topBtnShow = true; + this.optUp.toTop.onShow && this.optUp.toTop.onShow(true); + } +} + +/* 隐藏回到顶部的按钮 */ +MeScroll.prototype.hideTopBtn = function() { + if (this.topBtnShow) { + this.topBtnShow = false; + this.optUp.toTop.onShow && this.optUp.toTop.onShow(false); + } +} + +/* 获取滚动条的位置 */ +MeScroll.prototype.getScrollTop = function() { + return this.scrollTop || 0 +} + +/* 记录滚动条的位置 */ +MeScroll.prototype.setScrollTop = function(y) { + this.scrollTop = y; +} + +/* 滚动到指定位置 */ +MeScroll.prototype.scrollTo = function(y, t) { + this.myScrollTo && this.myScrollTo(y, t) // scrollview需自定义回到顶部方法 +} + +/* 自定义scrollTo */ +MeScroll.prototype.resetScrollTo = function(myScrollTo) { + this.myScrollTo = myScrollTo +} + +/* 滚动条到底部的距离 */ +MeScroll.prototype.getScrollBottom = function() { + return this.getScrollHeight() - this.getClientHeight() - this.getScrollTop() +} + +/* 计步器 + star: 开始值 + end: 结束值 + callback(step,timer): 回调step值,计步器timer,可自行通过window.clearInterval(timer)结束计步器; + t: 计步时长,传0则直接回调end值;不传则默认300ms + rate: 周期;不传则默认30ms计步一次 + * */ +MeScroll.prototype.getStep = function(star, end, callback, t, rate) { + let diff = end - star; // 差值 + if (t === 0 || diff === 0) { + callback && callback(end); + return; + } + t = t || 300; // 时长 300ms + rate = rate || 30; // 周期 30ms + let count = t / rate; // 次数 + let step = diff / count; // 步长 + let i = 0; // 计数 + let timer = setInterval(function() { + if (i < count - 1) { + star += step; + callback && callback(star, timer); + i++; + } else { + callback && callback(end, timer); // 最后一次直接设置end,避免计算误差 + clearInterval(timer); + } + }, rate); +} + +/* 滚动容器的高度 */ +MeScroll.prototype.getClientHeight = function(isReal) { + let h = this.clientHeight || 0 + if (h === 0 && isReal !== true) { // 未获取到容器的高度,可临时取body的高度 (可能会有误差) + h = this.getBodyHeight() + } + return h +} +MeScroll.prototype.setClientHeight = function(h) { + this.clientHeight = h; +} + +/* 滚动内容的高度 */ +MeScroll.prototype.getScrollHeight = function() { + return this.scrollHeight || 0; +} +MeScroll.prototype.setScrollHeight = function(h) { + this.scrollHeight = h; +} + +/* body的高度 */ +MeScroll.prototype.getBodyHeight = function() { + return this.bodyHeight || 0; +} +MeScroll.prototype.setBodyHeight = function(h) { + this.bodyHeight = h; +} + +/* 阻止浏览器默认滚动事件 */ +MeScroll.prototype.preventDefault = function(e) { + // 小程序不支持e.preventDefault, 已在wxs中禁止 + // app的bounce只能通过配置pages.json的style.app-plus.bounce为"none"来禁止, 或使用renderjs禁止 + // cancelable:是否可以被禁用; defaultPrevented:是否已经被禁用 + if (e && e.cancelable && !e.defaultPrevented) e.preventDefault() +} \ No newline at end of file diff --git a/components/mescroll-uni/mescroll-uni.vue b/components/mescroll-uni/mescroll-uni.vue new file mode 100644 index 0000000..c1536e9 --- /dev/null +++ b/components/mescroll-uni/mescroll-uni.vue @@ -0,0 +1,413 @@ + + + + + + + + + + + + + + + diff --git a/components/mescroll-uni/mixins/mescroll-comp.js b/components/mescroll-uni/mixins/mescroll-comp.js new file mode 100644 index 0000000..6aea07b --- /dev/null +++ b/components/mescroll-uni/mixins/mescroll-comp.js @@ -0,0 +1,50 @@ +/** + * mescroll-body写在子组件时,需通过mescroll的mixins补充子组件缺少的生命周期: + * 当一个页面只有一个mescroll-body写在子组件时, 则使用mescroll-comp.js (参考 mescroll-comp 案例) + * 当一个页面有多个mescroll-body写在子组件时, 则使用mescroll-more.js (参考 mescroll-more 案例) + */ +const MescrollCompMixin = { + // 因为子组件无onPageScroll和onReachBottom的页面生命周期,需在页面传递进到子组件 (一级) + onPageScroll(e) { + this.handlePageScroll(e) + }, + onReachBottom() { + this.handleReachBottom() + }, + // 当down的native: true时, 还需传递此方法进到子组件 + onPullDownRefresh(){ + this.handlePullDownRefresh() + }, + // mescroll-body写在子子子...组件的情况 (多级) + data() { + return { + mescroll: { + onPageScroll: e=>{ + this.handlePageScroll(e) + }, + onReachBottom: ()=>{ + this.handleReachBottom() + }, + onPullDownRefresh: ()=>{ + this.handlePullDownRefresh() + } + } + } + }, + methods:{ + handlePageScroll(e){ + let item = this.$refs["mescrollItem"]; + if(item && item.mescroll) item.mescroll.onPageScroll(e); + }, + handleReachBottom(){ + let item = this.$refs["mescrollItem"]; + if(item && item.mescroll) item.mescroll.onReachBottom(); + }, + handlePullDownRefresh(){ + let item = this.$refs["mescrollItem"]; + if(item && item.mescroll) item.mescroll.onPullDownRefresh(); + } + } +} + +export default MescrollCompMixin; diff --git a/components/mescroll-uni/mixins/mescroll-more-item.js b/components/mescroll-uni/mixins/mescroll-more-item.js new file mode 100644 index 0000000..2549158 --- /dev/null +++ b/components/mescroll-uni/mixins/mescroll-more-item.js @@ -0,0 +1,51 @@ +/** + * mescroll-more-item的mixins, 仅在多个 mescroll-body 写在子组件时使用 (参考 mescroll-more 案例) + */ +const MescrollMoreItemMixin = { + // 支付宝小程序不支持props的mixin,需写在具体的页面中 + // #ifndef MP-ALIPAY + props:{ + i: Number, // 每个tab页的专属下标 + index: { // 当前tab的下标 + type: Number, + default(){ + return 0 + } + } + }, + // #endif + data() { + return { + downOption:{ + auto:false // 不自动加载 + }, + upOption:{ + auto:false // 不自动加载 + }, + isInit: false // 当前tab是否已初始化 + } + }, + watch:{ + // 监听下标的变化 + index(val){ + if (this.i === val && !this.isInit) { + this.isInit = true; // 标记为true + this.mescroll && this.mescroll.triggerDownScroll(); + } + } + }, + methods: { + // mescroll组件初始化的回调,可获取到mescroll对象 (覆盖mescroll-mixins.js的mescrollInit, 为了标记isInit) + mescrollInit(mescroll) { + this.mescroll = mescroll; + this.mescrollInitByRef && this.mescrollInitByRef(); // 兼容字节跳动小程序 + // 自动加载当前tab的数据 + if(this.i === this.index){ + this.isInit = true; // 标记为true + this.mescroll.triggerDownScroll(); + } + }, + } +} + +export default MescrollMoreItemMixin; diff --git a/components/mescroll-uni/mixins/mescroll-more.js b/components/mescroll-uni/mixins/mescroll-more.js new file mode 100644 index 0000000..142aa75 --- /dev/null +++ b/components/mescroll-uni/mixins/mescroll-more.js @@ -0,0 +1,56 @@ +/** + * mescroll-body写在子组件时,需通过mescroll的mixins补充子组件缺少的生命周期: + * 当一个页面只有一个mescroll-body写在子组件时, 则使用mescroll-comp.js (参考 mescroll-comp 案例) + * 当一个页面有多个mescroll-body写在子组件时, 则使用mescroll-more.js (参考 mescroll-more 案例) + */ +const MescrollMoreMixin = { + data() { + return { + tabIndex: 0 // 当前tab下标 + } + }, + // 因为子组件无onPageScroll和onReachBottom的页面生命周期,需在页面传递进到子组件 + onPageScroll(e) { + let mescroll = this.getMescroll(this.tabIndex); + mescroll && mescroll.onPageScroll(e); + }, + onReachBottom() { + let mescroll = this.getMescroll(this.tabIndex); + mescroll && mescroll.onReachBottom(); + }, + // 当down的native: true时, 还需传递此方法进到子组件 + onPullDownRefresh(){ + let mescroll = this.getMescroll(this.tabIndex); + mescroll && mescroll.onPullDownRefresh(); + }, + methods:{ + // 根据下标获取对应子组件的mescroll + getMescroll(i){ + if(!this.mescrollItems) this.mescrollItems = []; + if(!this.mescrollItems[i]) { + // v-for中的refs + let vForItem = this.$refs["mescrollItem"]; + if(vForItem){ + this.mescrollItems[i] = vForItem[i] + }else{ + // 普通的refs,不可重复 + this.mescrollItems[i] = this.$refs["mescrollItem"+i]; + } + } + let item = this.mescrollItems[i] + return item ? item.mescroll : null + }, + // 切换tab,恢复滚动条位置 + tabChange(i){ + let mescroll = this.getMescroll(i); + if(mescroll){ + // 延时(比$nextTick靠谱一些),确保元素已渲染 + setTimeout(()=>{ + mescroll.scrollTo(mescroll.getScrollTop(),0) + },30) + } + } + } +} + +export default MescrollMoreMixin; diff --git a/components/mescroll-uni/wxs/mixins.js b/components/mescroll-uni/wxs/mixins.js new file mode 100644 index 0000000..7f49ff7 --- /dev/null +++ b/components/mescroll-uni/wxs/mixins.js @@ -0,0 +1,102 @@ +// 定义在wxs (含renderjs) 逻辑层的数据和方法, 与视图层相互通信 +const WxsMixin = { + data() { + return { + // 传入wxs视图层的数据 (响应式) + wxsProp: { + optDown:{}, // 下拉刷新的配置 + scrollTop:0, // 滚动条的距离 + bodyHeight:0, // body的高度 + isDownScrolling:false, // 是否正在下拉刷新中 + isUpScrolling:false, // 是否正在上拉加载中 + isScrollBody:true, // 是否为mescroll-body滚动 + isUpBoth:true, // 上拉加载时,是否同时可以下拉刷新 + t: 0 // 数据更新的标记 (只有数据更新了,才会触发wxs的Observer) + }, + + // 标记调用wxs视图层的方法 + callProp: { + callType: '', // 方法名 + t: 0 // 数据更新的标记 (只有数据更新了,才会触发wxs的Observer) + }, + + // 不用wxs的平台使用此处的wxsBiz对象,抹平wxs的写法 (微信小程序和APP使用的wxsBiz对象是./wxs/wxs.wxs) + // #ifndef MP-WEIXIN || APP-PLUS || H5 + wxsBiz: { + //注册列表touchstart事件,用于下拉刷新 + touchstartEvent: e=> { + this.mescroll.touchstartEvent(e); + }, + //注册列表touchmove事件,用于下拉刷新 + touchmoveEvent: e=> { + this.mescroll.touchmoveEvent(e); + }, + //注册列表touchend事件,用于下拉刷新 + touchendEvent: e=> { + this.mescroll.touchendEvent(e); + }, + propObserver(){}, // 抹平wxs的写法 + callObserver(){} // 抹平wxs的写法 + }, + // #endif + + // 不用renderjs的平台使用此处的renderBiz对象,抹平renderjs的写法 (app 和 h5 使用的renderBiz对象是./wxs/renderjs.js) + // #ifndef APP-PLUS || H5 + renderBiz: { + propObserver(){} // 抹平renderjs的写法 + } + // #endif + } + }, + methods: { + // wxs视图层调用逻辑层的回调 + wxsCall(msg){ + if(msg.type === 'setWxsProp'){ + // 更新wxsProp数据 (值改变才触发更新) + this.wxsProp = { + optDown: this.mescroll.optDown, + scrollTop: this.mescroll.getScrollTop(), + bodyHeight: this.mescroll.getBodyHeight(), + isDownScrolling: this.mescroll.isDownScrolling, + isUpScrolling: this.mescroll.isUpScrolling, + isUpBoth: this.mescroll.optUp.isBoth, + isScrollBody:this.mescroll.isScrollBody, + t: Date.now() + } + }else if(msg.type === 'setLoadType'){ + // 设置inOffset,outOffset的状态 + this.downLoadType = msg.downLoadType + }else if(msg.type === 'triggerDownScroll'){ + // 主动触发下拉刷新 + this.mescroll.triggerDownScroll(); + }else if(msg.type === 'endDownScroll'){ + // 结束下拉刷新 + this.mescroll.endDownScroll(); + }else if(msg.type === 'triggerUpScroll'){ + // 主动触发上拉加载 + this.mescroll.triggerUpScroll(true); + } + } + }, + mounted() { + // #ifdef MP-WEIXIN || APP-PLUS || H5 + // 配置主动触发wxs显示加载进度的回调 + this.mescroll.optDown.afterLoading = ()=>{ + this.callProp = {callType: "showLoading", t: Date.now()} // 触发wxs的方法 (值改变才触发更新) + } + // 配置主动触发wxs隐藏加载进度的回调 + this.mescroll.optDown.afterEndDownScroll = ()=>{ + this.callProp = {callType: "endDownScroll", t: Date.now()} // 触发wxs的方法 (值改变才触发更新) + setTimeout(()=>{ + if(this.downLoadType === 4 || this.downLoadType === 0){ + this.callProp = {callType: "clearTransform", t: Date.now()} // 触发wxs的方法 (值改变才触发更新) + } + },320) + } + // 初始化wxs的数据 + this.wxsCall({type: 'setWxsProp'}) + // #endif + } +} + +export default WxsMixin; diff --git a/components/mescroll-uni/wxs/renderjs.js b/components/mescroll-uni/wxs/renderjs.js new file mode 100644 index 0000000..207f388 --- /dev/null +++ b/components/mescroll-uni/wxs/renderjs.js @@ -0,0 +1,92 @@ +// 使用renderjs直接操作window对象,实现动态控制app和h5的bounce +// bounce: iOS橡皮筋,Android半月弧,h5浏览器下拉背景等效果 (下拉刷新时禁止) +// https://uniapp.dcloud.io/frame?id=renderjs + +// 与wxs的me实例一致 +var me = {} + +// 初始化window对象的touch事件 (仅初始化一次) +if(window && !window.$mescrollRenderInit){ + window.$mescrollRenderInit = true + + + window.addEventListener('touchstart', function(e){ + if (me.disabled()) return; + me.startPoint = me.getPoint(e); // 记录起点 + }, {passive: true}) + + + window.addEventListener('touchmove', function(e){ + if (me.disabled()) return; + if (me.getScrollTop() > 0) return; // 需在顶部下拉,才禁止bounce + + var curPoint = me.getPoint(e); // 当前点 + var moveY = curPoint.y - me.startPoint.y; // 和起点比,移动的距离,大于0向下拉,小于0向上拉 + // 向下拉 + if (moveY > 0) { + // 可下拉的条件 + if (!me.isDownScrolling && !me.optDown.isLock && (!me.isUpScrolling || (me.isUpScrolling && me.isUpBoth))) { + + // 只有touch在mescroll的view上面,才禁止bounce + var el = e.target; + var isMescrollTouch = false; + while (el && el.tagName && el.tagName !== 'UNI-PAGE-BODY' && el.tagName != "BODY") { + var cls = el.classList; + if (cls && cls.contains('mescroll-render-touch')) { + isMescrollTouch = true + break; + } + el = el.parentNode; // 继续检查其父元素 + } + // 禁止bounce (不会对swiper和iOS侧滑返回造成影响) + if (isMescrollTouch && e.cancelable && !e.defaultPrevented) e.preventDefault(); + } + } + }, {passive: false}) +} + +/* 获取滚动条的位置 */ +me.getScrollTop = function() { + return me.scrollTop || 0 +} + +/* 是否禁用下拉刷新 */ +me.disabled = function(){ + return !me.optDown || !me.optDown.use || me.optDown.native +} + +/* 根据点击滑动事件获取第一个手指的坐标 */ +me.getPoint = function(e) { + if (!e) { + return {x: 0,y: 0} + } + if (e.touches && e.touches[0]) { + return {x: e.touches[0].pageX,y: e.touches[0].pageY} + } else if (e.changedTouches && e.changedTouches[0]) { + return {x: e.changedTouches[0].pageX,y: e.changedTouches[0].pageY} + } else { + return {x: e.clientX,y: e.clientY} + } +} + +/** + * 监听逻辑层数据的变化 (实时更新数据) + */ +function propObserver(wxsProp) { + me.optDown = wxsProp.optDown + me.scrollTop = wxsProp.scrollTop + me.isDownScrolling = wxsProp.isDownScrolling + me.isUpScrolling = wxsProp.isUpScrolling + me.isUpBoth = wxsProp.isUpBoth +} + +/* 导出模块 */ +const renderBiz = { + data() { + return { + propObserver: propObserver, + } + } +} + +export default renderBiz; \ No newline at end of file diff --git a/components/mescroll-uni/wxs/wxs.wxs b/components/mescroll-uni/wxs/wxs.wxs new file mode 100644 index 0000000..3fb4ad9 --- /dev/null +++ b/components/mescroll-uni/wxs/wxs.wxs @@ -0,0 +1,268 @@ +// 使用wxs处理交互动画, 提高性能, 同时避免小程序bounce对下拉刷新的影响 +// https://uniapp.dcloud.io/frame?id=wxs +// https://developers.weixin.qq.com/miniprogram/dev/framework/view/interactive-animation.html + +// 模拟mescroll实例, 与mescroll.js的写法尽量保持一致 +var me = {} + +// ------ 自定义下拉刷新动画 start ------ + +/* 下拉过程中的回调,滑动过程一直在执行 (rate<1为inOffset; rate>1为outOffset) */ +me.onMoving = function (ins, rate, downHight){ + ins.requestAnimationFrame(function () { + ins.selectComponent('.mescroll-wxs-content').setStyle({ + 'will-change': 'transform', // 可解决下拉过程中, image和swiper脱离文档流的问题 + 'transform': 'translateY(' + downHight + 'px)', + 'transition': '' + }) + // 环形进度条 + var progress = ins.selectComponent('.mescroll-wxs-progress') + progress && progress.setStyle({transform: 'rotate(' + 360 * rate + 'deg)'}) + }) +} + +/* 显示下拉刷新进度 */ +me.showLoading = function (ins){ + me.downHight = me.optDown.offset + ins.requestAnimationFrame(function () { + ins.selectComponent('.mescroll-wxs-content').setStyle({ + 'will-change': 'auto', + 'transform': 'translateY(' + me.downHight + 'px)', + 'transition': 'transform 300ms' + }) + }) +} + +/* 结束下拉 */ +me.endDownScroll = function (ins){ + me.downHight = 0; + me.isDownScrolling = false; + ins.requestAnimationFrame(function () { + ins.selectComponent('.mescroll-wxs-content').setStyle({ + 'will-change': 'auto', + 'transform': 'translateY(0)', // 不可以写空串,否则scroll-view渲染不完整 (延时350ms会调clearTransform置空) + 'transition': 'transform 300ms' + }) + }) +} + +/* 结束下拉动画执行完毕后, 清除transform和transition, 避免对列表内容样式造成影响, 如: h5的list-msg示例下拉进度条漏出来等 */ +me.clearTransform = function (ins){ + ins.requestAnimationFrame(function () { + ins.selectComponent('.mescroll-wxs-content').setStyle({ + 'will-change': '', + 'transform': '', + 'transition': '' + }) + }) +} + +// ------ 自定义下拉刷新动画 end ------ + +/** + * 监听逻辑层数据的变化 (实时更新数据) + */ +function propObserver(wxsProp) { + me.optDown = wxsProp.optDown + me.scrollTop = wxsProp.scrollTop + me.bodyHeight = wxsProp.bodyHeight + me.isDownScrolling = wxsProp.isDownScrolling + me.isUpScrolling = wxsProp.isUpScrolling + me.isUpBoth = wxsProp.isUpBoth + me.isScrollBody = wxsProp.isScrollBody + me.startTop = wxsProp.scrollTop // 及时更新touchstart触发的startTop, 避免scroll-view快速惯性滚动到顶部取值不准确 +} + +/** + * 监听逻辑层数据的变化 (调用wxs的方法) + */ +function callObserver(callProp, oldValue, ins) { + if (me.disabled()) return; + if(callProp.callType){ + // 逻辑层(App Service)的style已失效,需在视图层(Webview)设置style + if(callProp.callType === 'showLoading'){ + me.showLoading(ins) + }else if(callProp.callType === 'endDownScroll'){ + me.endDownScroll(ins) + }else if(callProp.callType === 'clearTransform'){ + me.clearTransform(ins) + } + } +} + +/** + * touch事件 + */ +function touchstartEvent(e, ins) { + me.downHight = 0; // 下拉的距离 + me.startPoint = me.getPoint(e); // 记录起点 + me.startTop = me.getScrollTop(); // 记录此时的滚动条位置 + me.startAngle = 0; // 初始角度 + me.lastPoint = me.startPoint; // 重置上次move的点 + me.maxTouchmoveY = me.getBodyHeight() - me.optDown.bottomOffset; // 手指触摸的最大范围(写在touchstart避免body获取高度为0的情况) + me.inTouchend = false; // 标记不是touchend + + me.callMethod(ins, {type: 'setWxsProp'}) // 同步更新wxsProp的数据 (小程序是异步的,可能touchmove先执行,才到propObserver; h5和app是同步) +} + +function touchmoveEvent(e, ins) { + var isPrevent = true // false表示不往上冒泡,相当于调用了同时调用了stopPropagation和preventDefault (对小程序生效, h5和app无效) + + if (me.disabled()) return isPrevent; + + var scrollTop = me.getScrollTop(); // 当前滚动条的距离 + var curPoint = me.getPoint(e); // 当前点 + + var moveY = curPoint.y - me.startPoint.y; // 和起点比,移动的距离,大于0向下拉,小于0向上拉 + + // 向下拉 && 在顶部 + // mescroll-body,直接判定在顶部即可 + // scroll-view在滚动时不会触发touchmove,当触顶/底/左/右时,才会触发touchmove + // scroll-view滚动到顶部时,scrollTop不一定为0,也有可能大于0; 在iOS的APP中scrollTop可能为负数,不一定和startTop相等 + if (moveY > 0 && ( + (me.isScrollBody && scrollTop <= 0) + || + (!me.isScrollBody && (scrollTop <= 0 || (scrollTop <= me.optDown.startTop && scrollTop === me.startTop)) ) + )) { + // 可下拉的条件 + if (!me.inTouchend && !me.isDownScrolling && !me.optDown.isLock && (!me.isUpScrolling || (me.isUpScrolling && + me.isUpBoth))) { + + // 下拉的角度是否在配置的范围内 + if(!me.startAngle) me.startAngle = me.getAngle(me.lastPoint, curPoint); // 两点之间的角度,区间 [0,90] + if (me.startAngle < me.optDown.minAngle) return isPrevent; // 如果小于配置的角度,则不往下执行下拉刷新 + + // 如果手指的位置超过配置的距离,则提前结束下拉,避免Webview嵌套导致touchend无法触发 + if (me.maxTouchmoveY > 0 && curPoint.y >= me.maxTouchmoveY) { + me.inTouchend = true; // 标记执行touchend + touchendEvent(e, ins); // 提前触发touchend + return isPrevent; + } + + isPrevent = false // 小程序是return false + + var diff = curPoint.y - me.lastPoint.y; // 和上次比,移动的距离 (大于0向下,小于0向上) + + // 下拉距离 < 指定距离 + if (me.downHight < me.optDown.offset) { + if (me.movetype !== 1) { + me.movetype = 1; // 加入标记,保证只执行一次 + // me.optDown.inOffset && me.optDown.inOffset(me); // 进入指定距离范围内那一刻的回调,只执行一次 + me.callMethod(ins, {type: 'setLoadType', downLoadType: 1}) + me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来 + } + me.downHight += diff * me.optDown.inOffsetRate; // 越往下,高度变化越小 + + // 指定距离 <= 下拉距离 + } else { + if (me.movetype !== 2) { + me.movetype = 2; // 加入标记,保证只执行一次 + // me.optDown.outOffset && me.optDown.outOffset(me); // 下拉超过指定距离那一刻的回调,只执行一次 + me.callMethod(ins, {type: 'setLoadType', downLoadType: 2}) + me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来 + } + if (diff > 0) { // 向下拉 + me.downHight += diff * me.optDown.outOffsetRate; // 越往下,高度变化越小 + } else { // 向上收 + me.downHight += diff; // 向上收回高度,则向上滑多少收多少高度 + } + } + + me.downHight = Math.round(me.downHight) // 取整 + var rate = me.downHight / me.optDown.offset; // 下拉区域当前高度与指定距离的比值 + // me.optDown.onMoving && me.optDown.onMoving(me, rate, me.downHight); // 下拉过程中的回调,一直在执行 + me.onMoving(ins, rate, me.downHight) + } + } + + me.lastPoint = curPoint; // 记录本次移动的点 + + return isPrevent // false表示不往上冒泡,相当于调用了同时调用了stopPropagation和preventDefault (对小程序生效, h5和app无效) +} + +function touchendEvent(e, ins) { + // 如果下拉区域高度已改变,则需重置回来 + if (me.isMoveDown) { + if (me.downHight >= me.optDown.offset) { + // 符合触发刷新的条件 + me.downHight = me.optDown.offset; // 更新下拉区域高度 + // me.triggerDownScroll(); + me.callMethod(ins, {type: 'triggerDownScroll'}) + } else { + // 不符合的话 则重置 + me.downHight = 0; + // me.optDown.endDownScroll && me.optDown.endDownScroll(me); + me.callMethod(ins, {type: 'endDownScroll'}) + } + me.movetype = 0; + me.isMoveDown = false; + } else if (!me.isScrollBody && me.getScrollTop() === me.startTop) { // scroll-view到顶/左/右/底的滑动事件 + var isScrollUp = me.getPoint(e).y - me.startPoint.y < 0; // 和起点比,移动的距离,大于0向下拉,小于0向上拉 + // 上滑 + if (isScrollUp) { + // 需检查滑动的角度 + var angle = me.getAngle(me.getPoint(e), me.startPoint); // 两点之间的角度,区间 [0,90] + if (angle > 80) { + // 检查并触发上拉 + // me.triggerUpScroll(true); + me.callMethod(ins, {type: 'triggerUpScroll'}) + } + } + } + me.callMethod(ins, {type: 'setWxsProp'}) // 同步更新wxsProp的数据 (小程序是异步的,可能touchmove先执行,才到propObserver; h5和app是同步) +} + +/* 是否禁用下拉刷新 */ +me.disabled = function(){ + return !me.optDown || !me.optDown.use || me.optDown.native +} + +/* 根据点击滑动事件获取第一个手指的坐标 */ +me.getPoint = function(e) { + if (!e) { + return {x: 0,y: 0} + } + if (e.touches && e.touches[0]) { + return {x: e.touches[0].pageX,y: e.touches[0].pageY} + } else if (e.changedTouches && e.changedTouches[0]) { + return {x: e.changedTouches[0].pageX,y: e.changedTouches[0].pageY} + } else { + return {x: e.clientX,y: e.clientY} + } +} + +/* 计算两点之间的角度: 区间 [0,90]*/ +me.getAngle = function (p1, p2) { + var x = Math.abs(p1.x - p2.x); + var y = Math.abs(p1.y - p2.y); + var z = Math.sqrt(x * x + y * y); + var angle = 0; + if (z !== 0) { + angle = Math.asin(y / z) / Math.PI * 180; + } + return angle +} + +/* 获取滚动条的位置 */ +me.getScrollTop = function() { + return me.scrollTop || 0 +} + +/* 获取body的高度 */ +me.getBodyHeight = function() { + return me.bodyHeight || 0; +} + +/* 调用逻辑层的方法 */ +me.callMethod = function(ins, param) { + if(ins) ins.callMethod('wxsCall', param) +} + +/* 导出模块 */ +module.exports = { + propObserver: propObserver, + callObserver: callObserver, + touchstartEvent: touchstartEvent, + touchmoveEvent: touchmoveEvent, + touchendEvent: touchendEvent +} \ No newline at end of file diff --git a/components/notice-list/notice-list.vue b/components/notice-list/notice-list.vue new file mode 100644 index 0000000..ce6819f --- /dev/null +++ b/components/notice-list/notice-list.vue @@ -0,0 +1,118 @@ + + + + + + diff --git a/components/pick-regions/pick-regions.vue b/components/pick-regions/pick-regions.vue new file mode 100755 index 0000000..035e068 --- /dev/null +++ b/components/pick-regions/pick-regions.vue @@ -0,0 +1,138 @@ + + + diff --git a/components/pick-regions/regions.json b/components/pick-regions/regions.json new file mode 100755 index 0000000..310abee --- /dev/null +++ b/components/pick-regions/regions.json @@ -0,0 +1 @@ +[{"code":"11","name":"北京市","childs":[{"code":"1101","name":"市辖区","childs":[{"code":"110101","name":"东城区"},{"code":"110102","name":"西城区"},{"code":"110105","name":"朝阳区"},{"code":"110106","name":"丰台区"},{"code":"110107","name":"石景山区"},{"code":"110108","name":"海淀区"},{"code":"110109","name":"门头沟区"},{"code":"110111","name":"房山区"},{"code":"110112","name":"通州区"},{"code":"110113","name":"顺义区"},{"code":"110114","name":"昌平区"},{"code":"110115","name":"大兴区"},{"code":"110116","name":"怀柔区"},{"code":"110117","name":"平谷区"},{"code":"110118","name":"密云区"},{"code":"110119","name":"延庆区"}]}]},{"code":"12","name":"天津市","childs":[{"code":"1201","name":"市辖区","childs":[{"code":"120101","name":"和平区"},{"code":"120102","name":"河东区"},{"code":"120103","name":"河西区"},{"code":"120104","name":"南开区"},{"code":"120105","name":"河北区"},{"code":"120106","name":"红桥区"},{"code":"120110","name":"东丽区"},{"code":"120111","name":"西青区"},{"code":"120112","name":"津南区"},{"code":"120113","name":"北辰区"},{"code":"120114","name":"武清区"},{"code":"120115","name":"宝坻区"},{"code":"120116","name":"滨海新区"},{"code":"120117","name":"宁河区"},{"code":"120118","name":"静海区"},{"code":"120119","name":"蓟州区"}]}]},{"code":"13","name":"河北省","childs":[{"code":"1301","name":"石家庄市","childs":[{"code":"130102","name":"长安区"},{"code":"130104","name":"桥西区"},{"code":"130105","name":"新华区"},{"code":"130107","name":"井陉矿区"},{"code":"130108","name":"裕华区"},{"code":"130109","name":"藁城区"},{"code":"130110","name":"鹿泉区"},{"code":"130111","name":"栾城区"},{"code":"130121","name":"井陉县"},{"code":"130123","name":"正定县"},{"code":"130125","name":"行唐县"},{"code":"130126","name":"灵寿县"},{"code":"130127","name":"高邑县"},{"code":"130128","name":"深泽县"},{"code":"130129","name":"赞皇县"},{"code":"130130","name":"无极县"},{"code":"130131","name":"平山县"},{"code":"130132","name":"元氏县"},{"code":"130133","name":"赵县"},{"code":"130183","name":"晋州市"},{"code":"130184","name":"新乐市"}]},{"code":"1302","name":"唐山市","childs":[{"code":"130202","name":"路南区"},{"code":"130203","name":"路北区"},{"code":"130204","name":"古冶区"},{"code":"130205","name":"开平区"},{"code":"130207","name":"丰南区"},{"code":"130208","name":"丰润区"},{"code":"130209","name":"曹妃甸区"},{"code":"130223","name":"滦县"},{"code":"130224","name":"滦南县"},{"code":"130225","name":"乐亭县"},{"code":"130227","name":"迁西县"},{"code":"130229","name":"玉田县"},{"code":"130281","name":"遵化市"},{"code":"130283","name":"迁安市"}]},{"code":"1303","name":"秦皇岛市","childs":[{"code":"130302","name":"海港区"},{"code":"130303","name":"山海关区"},{"code":"130304","name":"北戴河区"},{"code":"130306","name":"抚宁区"},{"code":"130321","name":"青龙满族自治县"},{"code":"130322","name":"昌黎县"},{"code":"130324","name":"卢龙县"}]},{"code":"1304","name":"邯郸市","childs":[{"code":"130402","name":"邯山区"},{"code":"130403","name":"丛台区"},{"code":"130404","name":"复兴区"},{"code":"130406","name":"峰峰矿区"},{"code":"130421","name":"邯郸县"},{"code":"130423","name":"临漳县"},{"code":"130424","name":"成安县"},{"code":"130425","name":"大名县"},{"code":"130426","name":"涉县"},{"code":"130427","name":"磁县"},{"code":"130428","name":"肥乡县"},{"code":"130429","name":"永年县"},{"code":"130430","name":"邱县"},{"code":"130431","name":"鸡泽县"},{"code":"130432","name":"广平县"},{"code":"130433","name":"馆陶县"},{"code":"130434","name":"魏县"},{"code":"130435","name":"曲周县"},{"code":"130481","name":"武安市"}]},{"code":"1305","name":"邢台市","childs":[{"code":"130502","name":"桥东区"},{"code":"130503","name":"桥西区"},{"code":"130521","name":"邢台县"},{"code":"130522","name":"临城县"},{"code":"130523","name":"内丘县"},{"code":"130524","name":"柏乡县"},{"code":"130525","name":"隆尧县"},{"code":"130526","name":"任县"},{"code":"130527","name":"南和县"},{"code":"130528","name":"宁晋县"},{"code":"130529","name":"巨鹿县"},{"code":"130530","name":"新河县"},{"code":"130531","name":"广宗县"},{"code":"130532","name":"平乡县"},{"code":"130533","name":"威县"},{"code":"130534","name":"清河县"},{"code":"130535","name":"临西县"},{"code":"130581","name":"南宫市"},{"code":"130582","name":"沙河市"}]},{"code":"1306","name":"保定市","childs":[{"code":"130602","name":"竞秀区"},{"code":"130606","name":"莲池区"},{"code":"130607","name":"满城区"},{"code":"130608","name":"清苑区"},{"code":"130609","name":"徐水区"},{"code":"130623","name":"涞水县"},{"code":"130624","name":"阜平县"},{"code":"130626","name":"定兴县"},{"code":"130627","name":"唐县"},{"code":"130628","name":"高阳县"},{"code":"130629","name":"容城县"},{"code":"130630","name":"涞源县"},{"code":"130631","name":"望都县"},{"code":"130632","name":"安新县"},{"code":"130633","name":"易县"},{"code":"130634","name":"曲阳县"},{"code":"130635","name":"蠡县"},{"code":"130636","name":"顺平县"},{"code":"130637","name":"博野县"},{"code":"130638","name":"雄县"},{"code":"130681","name":"涿州市"},{"code":"130683","name":"安国市"},{"code":"130684","name":"高碑店市"}]},{"code":"1307","name":"张家口市","childs":[{"code":"130702","name":"桥东区"},{"code":"130703","name":"桥西区"},{"code":"130705","name":"宣化区"},{"code":"130706","name":"下花园区"},{"code":"130708","name":"万全区"},{"code":"130709","name":"崇礼区"},{"code":"130722","name":"张北县"},{"code":"130723","name":"康保县"},{"code":"130724","name":"沽源县"},{"code":"130725","name":"尚义县"},{"code":"130726","name":"蔚县"},{"code":"130727","name":"阳原县"},{"code":"130728","name":"怀安县"},{"code":"130730","name":"怀来县"},{"code":"130731","name":"涿鹿县"},{"code":"130732","name":"赤城县"}]},{"code":"1308","name":"承德市","childs":[{"code":"130802","name":"双桥区"},{"code":"130803","name":"双滦区"},{"code":"130804","name":"鹰手营子矿区"},{"code":"130821","name":"承德县"},{"code":"130822","name":"兴隆县"},{"code":"130823","name":"平泉县"},{"code":"130824","name":"滦平县"},{"code":"130825","name":"隆化县"},{"code":"130826","name":"丰宁满族自治县"},{"code":"130827","name":"宽城满族自治县"},{"code":"130828","name":"围场满族蒙古族自治县"}]},{"code":"1309","name":"沧州市","childs":[{"code":"130902","name":"新华区"},{"code":"130903","name":"运河区"},{"code":"130921","name":"沧县"},{"code":"130922","name":"青县"},{"code":"130923","name":"东光县"},{"code":"130924","name":"海兴县"},{"code":"130925","name":"盐山县"},{"code":"130926","name":"肃宁县"},{"code":"130927","name":"南皮县"},{"code":"130928","name":"吴桥县"},{"code":"130929","name":"献县"},{"code":"130930","name":"孟村回族自治县"},{"code":"130981","name":"泊头市"},{"code":"130982","name":"任丘市"},{"code":"130983","name":"黄骅市"},{"code":"130984","name":"河间市"}]},{"code":"1310","name":"廊坊市","childs":[{"code":"131002","name":"安次区"},{"code":"131003","name":"广阳区"},{"code":"131022","name":"固安县"},{"code":"131023","name":"永清县"},{"code":"131024","name":"香河县"},{"code":"131025","name":"大城县"},{"code":"131026","name":"文安县"},{"code":"131028","name":"大厂回族自治县"},{"code":"131081","name":"霸州市"},{"code":"131082","name":"三河市"}]},{"code":"1311","name":"衡水市","childs":[{"code":"131102","name":"桃城区"},{"code":"131103","name":"冀州区"},{"code":"131121","name":"枣强县"},{"code":"131122","name":"武邑县"},{"code":"131123","name":"武强县"},{"code":"131124","name":"饶阳县"},{"code":"131125","name":"安平县"},{"code":"131126","name":"故城县"},{"code":"131127","name":"景县"},{"code":"131128","name":"阜城县"},{"code":"131182","name":"深州市"}]},{"code":"1390","name":"省直辖县级行政区划","childs":[{"code":"139001","name":"定州市"},{"code":"139002","name":"辛集市"}]}]},{"code":"14","name":"山西省","childs":[{"code":"1401","name":"太原市","childs":[{"code":"140105","name":"小店区"},{"code":"140106","name":"迎泽区"},{"code":"140107","name":"杏花岭区"},{"code":"140108","name":"尖草坪区"},{"code":"140109","name":"万柏林区"},{"code":"140110","name":"晋源区"},{"code":"140121","name":"清徐县"},{"code":"140122","name":"阳曲县"},{"code":"140123","name":"娄烦县"},{"code":"140181","name":"古交市"}]},{"code":"1402","name":"大同市","childs":[{"code":"140202","name":"城区"},{"code":"140203","name":"矿区"},{"code":"140211","name":"南郊区"},{"code":"140212","name":"新荣区"},{"code":"140221","name":"阳高县"},{"code":"140222","name":"天镇县"},{"code":"140223","name":"广灵县"},{"code":"140224","name":"灵丘县"},{"code":"140225","name":"浑源县"},{"code":"140226","name":"左云县"},{"code":"140227","name":"大同县"}]},{"code":"1403","name":"阳泉市","childs":[{"code":"140302","name":"城区"},{"code":"140303","name":"矿区"},{"code":"140311","name":"郊区"},{"code":"140321","name":"平定县"},{"code":"140322","name":"盂县"}]},{"code":"1404","name":"长治市","childs":[{"code":"140402","name":"城区"},{"code":"140411","name":"郊区"},{"code":"140421","name":"长治县"},{"code":"140423","name":"襄垣县"},{"code":"140424","name":"屯留县"},{"code":"140425","name":"平顺县"},{"code":"140426","name":"黎城县"},{"code":"140427","name":"壶关县"},{"code":"140428","name":"长子县"},{"code":"140429","name":"武乡县"},{"code":"140430","name":"沁县"},{"code":"140431","name":"沁源县"},{"code":"140481","name":"潞城市"}]},{"code":"1405","name":"晋城市","childs":[{"code":"140502","name":"城区"},{"code":"140521","name":"沁水县"},{"code":"140522","name":"阳城县"},{"code":"140524","name":"陵川县"},{"code":"140525","name":"泽州县"},{"code":"140581","name":"高平市"}]},{"code":"1406","name":"朔州市","childs":[{"code":"140602","name":"朔城区"},{"code":"140603","name":"平鲁区"},{"code":"140621","name":"山阴县"},{"code":"140622","name":"应县"},{"code":"140623","name":"右玉县"},{"code":"140624","name":"怀仁县"}]},{"code":"1407","name":"晋中市","childs":[{"code":"140702","name":"榆次区"},{"code":"140721","name":"榆社县"},{"code":"140722","name":"左权县"},{"code":"140723","name":"和顺县"},{"code":"140724","name":"昔阳县"},{"code":"140725","name":"寿阳县"},{"code":"140726","name":"太谷县"},{"code":"140727","name":"祁县"},{"code":"140728","name":"平遥县"},{"code":"140729","name":"灵石县"},{"code":"140781","name":"介休市"}]},{"code":"1408","name":"运城市","childs":[{"code":"140802","name":"盐湖区"},{"code":"140821","name":"临猗县"},{"code":"140822","name":"万荣县"},{"code":"140823","name":"闻喜县"},{"code":"140824","name":"稷山县"},{"code":"140825","name":"新绛县"},{"code":"140826","name":"绛县"},{"code":"140827","name":"垣曲县"},{"code":"140828","name":"夏县"},{"code":"140829","name":"平陆县"},{"code":"140830","name":"芮城县"},{"code":"140881","name":"永济市"},{"code":"140882","name":"河津市"}]},{"code":"1409","name":"忻州市","childs":[{"code":"140902","name":"忻府区"},{"code":"140921","name":"定襄县"},{"code":"140922","name":"五台县"},{"code":"140923","name":"代县"},{"code":"140924","name":"繁峙县"},{"code":"140925","name":"宁武县"},{"code":"140926","name":"静乐县"},{"code":"140927","name":"神池县"},{"code":"140928","name":"五寨县"},{"code":"140929","name":"岢岚县"},{"code":"140930","name":"河曲县"},{"code":"140931","name":"保德县"},{"code":"140932","name":"偏关县"},{"code":"140981","name":"原平市"}]},{"code":"1410","name":"临汾市","childs":[{"code":"141002","name":"尧都区"},{"code":"141021","name":"曲沃县"},{"code":"141022","name":"翼城县"},{"code":"141023","name":"襄汾县"},{"code":"141024","name":"洪洞县"},{"code":"141025","name":"古县"},{"code":"141026","name":"安泽县"},{"code":"141027","name":"浮山县"},{"code":"141028","name":"吉县"},{"code":"141029","name":"乡宁县"},{"code":"141030","name":"大宁县"},{"code":"141031","name":"隰县"},{"code":"141032","name":"永和县"},{"code":"141033","name":"蒲县"},{"code":"141034","name":"汾西县"},{"code":"141081","name":"侯马市"},{"code":"141082","name":"霍州市"}]},{"code":"1411","name":"吕梁市","childs":[{"code":"141102","name":"离石区"},{"code":"141121","name":"文水县"},{"code":"141122","name":"交城县"},{"code":"141123","name":"兴县"},{"code":"141124","name":"临县"},{"code":"141125","name":"柳林县"},{"code":"141126","name":"石楼县"},{"code":"141127","name":"岚县"},{"code":"141128","name":"方山县"},{"code":"141129","name":"中阳县"},{"code":"141130","name":"交口县"},{"code":"141181","name":"孝义市"},{"code":"141182","name":"汾阳市"}]}]},{"code":"15","name":"内蒙古自治区","childs":[{"code":"1501","name":"呼和浩特市","childs":[{"code":"150102","name":"新城区"},{"code":"150103","name":"回民区"},{"code":"150104","name":"玉泉区"},{"code":"150105","name":"赛罕区"},{"code":"150121","name":"土默特左旗"},{"code":"150122","name":"托克托县"},{"code":"150123","name":"和林格尔县"},{"code":"150124","name":"清水河县"},{"code":"150125","name":"武川县"}]},{"code":"1502","name":"包头市","childs":[{"code":"150202","name":"东河区"},{"code":"150203","name":"昆都仑区"},{"code":"150204","name":"青山区"},{"code":"150205","name":"石拐区"},{"code":"150206","name":"白云鄂博矿区"},{"code":"150207","name":"九原区"},{"code":"150221","name":"土默特右旗"},{"code":"150222","name":"固阳县"},{"code":"150223","name":"达尔罕茂明安联合旗"}]},{"code":"1503","name":"乌海市","childs":[{"code":"150302","name":"海勃湾区"},{"code":"150303","name":"海南区"},{"code":"150304","name":"乌达区"}]},{"code":"1504","name":"赤峰市","childs":[{"code":"150402","name":"红山区"},{"code":"150403","name":"元宝山区"},{"code":"150404","name":"松山区"},{"code":"150421","name":"阿鲁科尔沁旗"},{"code":"150422","name":"巴林左旗"},{"code":"150423","name":"巴林右旗"},{"code":"150424","name":"林西县"},{"code":"150425","name":"克什克腾旗"},{"code":"150426","name":"翁牛特旗"},{"code":"150428","name":"喀喇沁旗"},{"code":"150429","name":"宁城县"},{"code":"150430","name":"敖汉旗"}]},{"code":"1505","name":"通辽市","childs":[{"code":"150502","name":"科尔沁区"},{"code":"150521","name":"科尔沁左翼中旗"},{"code":"150522","name":"科尔沁左翼后旗"},{"code":"150523","name":"开鲁县"},{"code":"150524","name":"库伦旗"},{"code":"150525","name":"奈曼旗"},{"code":"150526","name":"扎鲁特旗"},{"code":"150581","name":"霍林郭勒市"}]},{"code":"1506","name":"鄂尔多斯市","childs":[{"code":"150602","name":"东胜区"},{"code":"150603","name":"康巴什区"},{"code":"150621","name":"达拉特旗"},{"code":"150622","name":"准格尔旗"},{"code":"150623","name":"鄂托克前旗"},{"code":"150624","name":"鄂托克旗"},{"code":"150625","name":"杭锦旗"},{"code":"150626","name":"乌审旗"},{"code":"150627","name":"伊金霍洛旗"}]},{"code":"1507","name":"呼伦贝尔市","childs":[{"code":"150702","name":"海拉尔区"},{"code":"150703","name":"扎赉诺尔区"},{"code":"150721","name":"阿荣旗"},{"code":"150722","name":"莫力达瓦达斡尔族自治旗"},{"code":"150723","name":"鄂伦春自治旗"},{"code":"150724","name":"鄂温克族自治旗"},{"code":"150725","name":"陈巴尔虎旗"},{"code":"150726","name":"新巴尔虎左旗"},{"code":"150727","name":"新巴尔虎右旗"},{"code":"150781","name":"满洲里市"},{"code":"150782","name":"牙克石市"},{"code":"150783","name":"扎兰屯市"},{"code":"150784","name":"额尔古纳市"},{"code":"150785","name":"根河市"}]},{"code":"1508","name":"巴彦淖尔市","childs":[{"code":"150802","name":"临河区"},{"code":"150821","name":"五原县"},{"code":"150822","name":"磴口县"},{"code":"150823","name":"乌拉特前旗"},{"code":"150824","name":"乌拉特中旗"},{"code":"150825","name":"乌拉特后旗"},{"code":"150826","name":"杭锦后旗"}]},{"code":"1509","name":"乌兰察布市","childs":[{"code":"150902","name":"集宁区"},{"code":"150921","name":"卓资县"},{"code":"150922","name":"化德县"},{"code":"150923","name":"商都县"},{"code":"150924","name":"兴和县"},{"code":"150925","name":"凉城县"},{"code":"150926","name":"察哈尔右翼前旗"},{"code":"150927","name":"察哈尔右翼中旗"},{"code":"150928","name":"察哈尔右翼后旗"},{"code":"150929","name":"四子王旗"},{"code":"150981","name":"丰镇市"}]},{"code":"1522","name":"兴安盟","childs":[{"code":"152201","name":"乌兰浩特市"},{"code":"152202","name":"阿尔山市"},{"code":"152221","name":"科尔沁右翼前旗"},{"code":"152222","name":"科尔沁右翼中旗"},{"code":"152223","name":"扎赉特旗"},{"code":"152224","name":"突泉县"}]},{"code":"1525","name":"锡林郭勒盟","childs":[{"code":"152501","name":"二连浩特市"},{"code":"152502","name":"锡林浩特市"},{"code":"152522","name":"阿巴嘎旗"},{"code":"152523","name":"苏尼特左旗"},{"code":"152524","name":"苏尼特右旗"},{"code":"152525","name":"东乌珠穆沁旗"},{"code":"152526","name":"西乌珠穆沁旗"},{"code":"152527","name":"太仆寺旗"},{"code":"152528","name":"镶黄旗"},{"code":"152529","name":"正镶白旗"},{"code":"152530","name":"正蓝旗"},{"code":"152531","name":"多伦县"}]},{"code":"1529","name":"阿拉善盟","childs":[{"code":"152921","name":"阿拉善左旗"},{"code":"152922","name":"阿拉善右旗"},{"code":"152923","name":"额济纳旗"}]}]},{"code":"21","name":"辽宁省","childs":[{"code":"2101","name":"沈阳市","childs":[{"code":"210102","name":"和平区"},{"code":"210103","name":"沈河区"},{"code":"210104","name":"大东区"},{"code":"210105","name":"皇姑区"},{"code":"210106","name":"铁西区"},{"code":"210111","name":"苏家屯区"},{"code":"210112","name":"浑南区"},{"code":"210113","name":"沈北新区"},{"code":"210114","name":"于洪区"},{"code":"210115","name":"辽中区"},{"code":"210123","name":"康平县"},{"code":"210124","name":"法库县"},{"code":"210181","name":"新民市"}]},{"code":"2102","name":"大连市","childs":[{"code":"210202","name":"中山区"},{"code":"210203","name":"西岗区"},{"code":"210204","name":"沙河口区"},{"code":"210211","name":"甘井子区"},{"code":"210212","name":"旅顺口区"},{"code":"210213","name":"金州区"},{"code":"210214","name":"普兰店区"},{"code":"210224","name":"长海县"},{"code":"210281","name":"瓦房店市"},{"code":"210283","name":"庄河市"}]},{"code":"2103","name":"鞍山市","childs":[{"code":"210302","name":"铁东区"},{"code":"210303","name":"铁西区"},{"code":"210304","name":"立山区"},{"code":"210311","name":"千山区"},{"code":"210321","name":"台安县"},{"code":"210323","name":"岫岩满族自治县"},{"code":"210381","name":"海城市"}]},{"code":"2104","name":"抚顺市","childs":[{"code":"210402","name":"新抚区"},{"code":"210403","name":"东洲区"},{"code":"210404","name":"望花区"},{"code":"210411","name":"顺城区"},{"code":"210421","name":"抚顺县"},{"code":"210422","name":"新宾满族自治县"},{"code":"210423","name":"清原满族自治县"}]},{"code":"2105","name":"本溪市","childs":[{"code":"210502","name":"平山区"},{"code":"210503","name":"溪湖区"},{"code":"210504","name":"明山区"},{"code":"210505","name":"南芬区"},{"code":"210521","name":"本溪满族自治县"},{"code":"210522","name":"桓仁满族自治县"}]},{"code":"2106","name":"丹东市","childs":[{"code":"210602","name":"元宝区"},{"code":"210603","name":"振兴区"},{"code":"210604","name":"振安区"},{"code":"210624","name":"宽甸满族自治县"},{"code":"210681","name":"东港市"},{"code":"210682","name":"凤城市"}]},{"code":"2107","name":"锦州市","childs":[{"code":"210702","name":"古塔区"},{"code":"210703","name":"凌河区"},{"code":"210711","name":"太和区"},{"code":"210726","name":"黑山县"},{"code":"210727","name":"义县"},{"code":"210781","name":"凌海市"},{"code":"210782","name":"北镇市"}]},{"code":"2108","name":"营口市","childs":[{"code":"210802","name":"站前区"},{"code":"210803","name":"西市区"},{"code":"210804","name":"鲅鱼圈区"},{"code":"210811","name":"老边区"},{"code":"210881","name":"盖州市"},{"code":"210882","name":"大石桥市"}]},{"code":"2109","name":"阜新市","childs":[{"code":"210902","name":"海州区"},{"code":"210903","name":"新邱区"},{"code":"210904","name":"太平区"},{"code":"210905","name":"清河门区"},{"code":"210911","name":"细河区"},{"code":"210921","name":"阜新蒙古族自治县"},{"code":"210922","name":"彰武县"}]},{"code":"2110","name":"辽阳市","childs":[{"code":"211002","name":"白塔区"},{"code":"211003","name":"文圣区"},{"code":"211004","name":"宏伟区"},{"code":"211005","name":"弓长岭区"},{"code":"211011","name":"太子河区"},{"code":"211021","name":"辽阳县"},{"code":"211081","name":"灯塔市"}]},{"code":"2111","name":"盘锦市","childs":[{"code":"211102","name":"双台子区"},{"code":"211103","name":"兴隆台区"},{"code":"211104","name":"大洼区"},{"code":"211122","name":"盘山县"}]},{"code":"2112","name":"铁岭市","childs":[{"code":"211202","name":"银州区"},{"code":"211204","name":"清河区"},{"code":"211221","name":"铁岭县"},{"code":"211223","name":"西丰县"},{"code":"211224","name":"昌图县"},{"code":"211281","name":"调兵山市"},{"code":"211282","name":"开原市"}]},{"code":"2113","name":"朝阳市","childs":[{"code":"211302","name":"双塔区"},{"code":"211303","name":"龙城区"},{"code":"211321","name":"朝阳县"},{"code":"211322","name":"建平县"},{"code":"211324","name":"喀喇沁左翼蒙古族自治县"},{"code":"211381","name":"北票市"},{"code":"211382","name":"凌源市"}]},{"code":"2114","name":"葫芦岛市","childs":[{"code":"211402","name":"连山区"},{"code":"211403","name":"龙港区"},{"code":"211404","name":"南票区"},{"code":"211421","name":"绥中县"},{"code":"211422","name":"建昌县"},{"code":"211481","name":"兴城市"}]}]},{"code":"22","name":"吉林省","childs":[{"code":"2201","name":"长春市","childs":[{"code":"220102","name":"南关区"},{"code":"220103","name":"宽城区"},{"code":"220104","name":"朝阳区"},{"code":"220105","name":"二道区"},{"code":"220106","name":"绿园区"},{"code":"220112","name":"双阳区"},{"code":"220113","name":"九台区"},{"code":"220122","name":"农安县"},{"code":"220182","name":"榆树市"},{"code":"220183","name":"德惠市"}]},{"code":"2202","name":"吉林市","childs":[{"code":"220202","name":"昌邑区"},{"code":"220203","name":"龙潭区"},{"code":"220204","name":"船营区"},{"code":"220211","name":"丰满区"},{"code":"220221","name":"永吉县"},{"code":"220281","name":"蛟河市"},{"code":"220282","name":"桦甸市"},{"code":"220283","name":"舒兰市"},{"code":"220284","name":"磐石市"}]},{"code":"2203","name":"四平市","childs":[{"code":"220302","name":"铁西区"},{"code":"220303","name":"铁东区"},{"code":"220322","name":"梨树县"},{"code":"220323","name":"伊通满族自治县"},{"code":"220381","name":"公主岭市"},{"code":"220382","name":"双辽市"}]},{"code":"2204","name":"辽源市","childs":[{"code":"220402","name":"龙山区"},{"code":"220403","name":"西安区"},{"code":"220421","name":"东丰县"},{"code":"220422","name":"东辽县"}]},{"code":"2205","name":"通化市","childs":[{"code":"220502","name":"东昌区"},{"code":"220503","name":"二道江区"},{"code":"220521","name":"通化县"},{"code":"220523","name":"辉南县"},{"code":"220524","name":"柳河县"},{"code":"220581","name":"梅河口市"},{"code":"220582","name":"集安市"}]},{"code":"2206","name":"白山市","childs":[{"code":"220602","name":"浑江区"},{"code":"220605","name":"江源区"},{"code":"220621","name":"抚松县"},{"code":"220622","name":"靖宇县"},{"code":"220623","name":"长白朝鲜族自治县"},{"code":"220681","name":"临江市"}]},{"code":"2207","name":"松原市","childs":[{"code":"220702","name":"宁江区"},{"code":"220721","name":"前郭尔罗斯蒙古族自治县"},{"code":"220722","name":"长岭县"},{"code":"220723","name":"乾安县"},{"code":"220781","name":"扶余市"}]},{"code":"2208","name":"白城市","childs":[{"code":"220802","name":"洮北区"},{"code":"220821","name":"镇赉县"},{"code":"220822","name":"通榆县"},{"code":"220881","name":"洮南市"},{"code":"220882","name":"大安市"}]},{"code":"2224","name":"延边朝鲜族自治州","childs":[{"code":"222401","name":"延吉市"},{"code":"222402","name":"图们市"},{"code":"222403","name":"敦化市"},{"code":"222404","name":"珲春市"},{"code":"222405","name":"龙井市"},{"code":"222406","name":"和龙市"},{"code":"222424","name":"汪清县"},{"code":"222426","name":"安图县"}]}]},{"code":"23","name":"黑龙江省","childs":[{"code":"2301","name":"哈尔滨市","childs":[{"code":"230102","name":"道里区"},{"code":"230103","name":"南岗区"},{"code":"230104","name":"道外区"},{"code":"230108","name":"平房区"},{"code":"230109","name":"松北区"},{"code":"230110","name":"香坊区"},{"code":"230111","name":"呼兰区"},{"code":"230112","name":"阿城区"},{"code":"230113","name":"双城区"},{"code":"230123","name":"依兰县"},{"code":"230124","name":"方正县"},{"code":"230125","name":"宾县"},{"code":"230126","name":"巴彦县"},{"code":"230127","name":"木兰县"},{"code":"230128","name":"通河县"},{"code":"230129","name":"延寿县"},{"code":"230183","name":"尚志市"},{"code":"230184","name":"五常市"}]},{"code":"2302","name":"齐齐哈尔市","childs":[{"code":"230202","name":"龙沙区"},{"code":"230203","name":"建华区"},{"code":"230204","name":"铁锋区"},{"code":"230205","name":"昂昂溪区"},{"code":"230206","name":"富拉尔基区"},{"code":"230207","name":"碾子山区"},{"code":"230208","name":"梅里斯达斡尔族区"},{"code":"230221","name":"龙江县"},{"code":"230223","name":"依安县"},{"code":"230224","name":"泰来县"},{"code":"230225","name":"甘南县"},{"code":"230227","name":"富裕县"},{"code":"230229","name":"克山县"},{"code":"230230","name":"克东县"},{"code":"230231","name":"拜泉县"},{"code":"230281","name":"讷河市"}]},{"code":"2303","name":"鸡西市","childs":[{"code":"230302","name":"鸡冠区"},{"code":"230303","name":"恒山区"},{"code":"230304","name":"滴道区"},{"code":"230305","name":"梨树区"},{"code":"230306","name":"城子河区"},{"code":"230307","name":"麻山区"},{"code":"230321","name":"鸡东县"},{"code":"230381","name":"虎林市"},{"code":"230382","name":"密山市"}]},{"code":"2304","name":"鹤岗市","childs":[{"code":"230402","name":"向阳区"},{"code":"230403","name":"工农区"},{"code":"230404","name":"南山区"},{"code":"230405","name":"兴安区"},{"code":"230406","name":"东山区"},{"code":"230407","name":"兴山区"},{"code":"230421","name":"萝北县"},{"code":"230422","name":"绥滨县"}]},{"code":"2305","name":"双鸭山市","childs":[{"code":"230502","name":"尖山区"},{"code":"230503","name":"岭东区"},{"code":"230505","name":"四方台区"},{"code":"230506","name":"宝山区"},{"code":"230521","name":"集贤县"},{"code":"230522","name":"友谊县"},{"code":"230523","name":"宝清县"},{"code":"230524","name":"饶河县"}]},{"code":"2306","name":"大庆市","childs":[{"code":"230602","name":"萨尔图区"},{"code":"230603","name":"龙凤区"},{"code":"230604","name":"让胡路区"},{"code":"230605","name":"红岗区"},{"code":"230606","name":"大同区"},{"code":"230621","name":"肇州县"},{"code":"230622","name":"肇源县"},{"code":"230623","name":"林甸县"},{"code":"230624","name":"杜尔伯特蒙古族自治县"}]},{"code":"2307","name":"伊春市","childs":[{"code":"230702","name":"伊春区"},{"code":"230703","name":"南岔区"},{"code":"230704","name":"友好区"},{"code":"230705","name":"西林区"},{"code":"230706","name":"翠峦区"},{"code":"230707","name":"新青区"},{"code":"230708","name":"美溪区"},{"code":"230709","name":"金山屯区"},{"code":"230710","name":"五营区"},{"code":"230711","name":"乌马河区"},{"code":"230712","name":"汤旺河区"},{"code":"230713","name":"带岭区"},{"code":"230714","name":"乌伊岭区"},{"code":"230715","name":"红星区"},{"code":"230716","name":"上甘岭区"},{"code":"230722","name":"嘉荫县"},{"code":"230781","name":"铁力市"}]},{"code":"2308","name":"佳木斯市","childs":[{"code":"230803","name":"向阳区"},{"code":"230804","name":"前进区"},{"code":"230805","name":"东风区"},{"code":"230811","name":"郊区"},{"code":"230822","name":"桦南县"},{"code":"230826","name":"桦川县"},{"code":"230828","name":"汤原县"},{"code":"230881","name":"同江市"},{"code":"230882","name":"富锦市"},{"code":"230883","name":"抚远市"}]},{"code":"2309","name":"七台河市","childs":[{"code":"230902","name":"新兴区"},{"code":"230903","name":"桃山区"},{"code":"230904","name":"茄子河区"},{"code":"230921","name":"勃利县"}]},{"code":"2310","name":"牡丹江市","childs":[{"code":"231002","name":"东安区"},{"code":"231003","name":"阳明区"},{"code":"231004","name":"爱民区"},{"code":"231005","name":"西安区"},{"code":"231025","name":"林口县"},{"code":"231081","name":"绥芬河市"},{"code":"231083","name":"海林市"},{"code":"231084","name":"宁安市"},{"code":"231085","name":"穆棱市"},{"code":"231086","name":"东宁市"}]},{"code":"2311","name":"黑河市","childs":[{"code":"231102","name":"爱辉区"},{"code":"231121","name":"嫩江县"},{"code":"231123","name":"逊克县"},{"code":"231124","name":"孙吴县"},{"code":"231181","name":"北安市"},{"code":"231182","name":"五大连池市"}]},{"code":"2312","name":"绥化市","childs":[{"code":"231202","name":"北林区"},{"code":"231221","name":"望奎县"},{"code":"231222","name":"兰西县"},{"code":"231223","name":"青冈县"},{"code":"231224","name":"庆安县"},{"code":"231225","name":"明水县"},{"code":"231226","name":"绥棱县"},{"code":"231281","name":"安达市"},{"code":"231282","name":"肇东市"},{"code":"231283","name":"海伦市"}]},{"code":"2327","name":"大兴安岭地区","childs":[{"code":"232721","name":"呼玛县"},{"code":"232722","name":"塔河县"},{"code":"232723","name":"漠河县"}]}]},{"code":"31","name":"上海市","childs":[{"code":"3101","name":"市辖区","childs":[{"code":"310101","name":"黄浦区"},{"code":"310104","name":"徐汇区"},{"code":"310105","name":"长宁区"},{"code":"310106","name":"静安区"},{"code":"310107","name":"普陀区"},{"code":"310109","name":"虹口区"},{"code":"310110","name":"杨浦区"},{"code":"310112","name":"闵行区"},{"code":"310113","name":"宝山区"},{"code":"310114","name":"嘉定区"},{"code":"310115","name":"浦东新区"},{"code":"310116","name":"金山区"},{"code":"310117","name":"松江区"},{"code":"310118","name":"青浦区"},{"code":"310120","name":"奉贤区"},{"code":"310151","name":"崇明区"}]}]},{"code":"32","name":"江苏省","childs":[{"code":"3201","name":"南京市","childs":[{"code":"320102","name":"玄武区"},{"code":"320104","name":"秦淮区"},{"code":"320105","name":"建邺区"},{"code":"320106","name":"鼓楼区"},{"code":"320111","name":"浦口区"},{"code":"320113","name":"栖霞区"},{"code":"320114","name":"雨花台区"},{"code":"320115","name":"江宁区"},{"code":"320116","name":"六合区"},{"code":"320117","name":"溧水区"},{"code":"320118","name":"高淳区"}]},{"code":"3202","name":"无锡市","childs":[{"code":"320205","name":"锡山区"},{"code":"320206","name":"惠山区"},{"code":"320211","name":"滨湖区"},{"code":"320213","name":"梁溪区"},{"code":"320214","name":"新吴区"},{"code":"320281","name":"江阴市"},{"code":"320282","name":"宜兴市"}]},{"code":"3203","name":"徐州市","childs":[{"code":"320302","name":"鼓楼区"},{"code":"320303","name":"云龙区"},{"code":"320305","name":"贾汪区"},{"code":"320311","name":"泉山区"},{"code":"320312","name":"铜山区"},{"code":"320321","name":"丰县"},{"code":"320322","name":"沛县"},{"code":"320324","name":"睢宁县"},{"code":"320381","name":"新沂市"},{"code":"320382","name":"邳州市"}]},{"code":"3204","name":"常州市","childs":[{"code":"320402","name":"天宁区"},{"code":"320404","name":"钟楼区"},{"code":"320411","name":"新北区"},{"code":"320412","name":"武进区"},{"code":"320413","name":"金坛区"},{"code":"320481","name":"溧阳市"}]},{"code":"3205","name":"苏州市","childs":[{"code":"320505","name":"虎丘区"},{"code":"320506","name":"吴中区"},{"code":"320507","name":"相城区"},{"code":"320508","name":"姑苏区"},{"code":"320509","name":"吴江区"},{"code":"320581","name":"常熟市"},{"code":"320582","name":"张家港市"},{"code":"320583","name":"昆山市"},{"code":"320585","name":"太仓市"}]},{"code":"3206","name":"南通市","childs":[{"code":"320602","name":"崇川区"},{"code":"320611","name":"港闸区"},{"code":"320612","name":"通州区"},{"code":"320621","name":"海安县"},{"code":"320623","name":"如东县"},{"code":"320681","name":"启东市"},{"code":"320682","name":"如皋市"},{"code":"320684","name":"海门市"}]},{"code":"3207","name":"连云港市","childs":[{"code":"320703","name":"连云区"},{"code":"320706","name":"海州区"},{"code":"320707","name":"赣榆区"},{"code":"320722","name":"东海县"},{"code":"320723","name":"灌云县"},{"code":"320724","name":"灌南县"}]},{"code":"3208","name":"淮安市","childs":[{"code":"320803","name":"淮安区"},{"code":"320804","name":"淮阴区"},{"code":"320812","name":"清江浦区"},{"code":"320813","name":"洪泽区"},{"code":"320826","name":"涟水县"},{"code":"320830","name":"盱眙县"},{"code":"320831","name":"金湖县"}]},{"code":"3209","name":"盐城市","childs":[{"code":"320902","name":"亭湖区"},{"code":"320903","name":"盐都区"},{"code":"320904","name":"大丰区"},{"code":"320921","name":"响水县"},{"code":"320922","name":"滨海县"},{"code":"320923","name":"阜宁县"},{"code":"320924","name":"射阳县"},{"code":"320925","name":"建湖县"},{"code":"320981","name":"东台市"}]},{"code":"3210","name":"扬州市","childs":[{"code":"321002","name":"广陵区"},{"code":"321003","name":"邗江区"},{"code":"321012","name":"江都区"},{"code":"321023","name":"宝应县"},{"code":"321081","name":"仪征市"},{"code":"321084","name":"高邮市"}]},{"code":"3211","name":"镇江市","childs":[{"code":"321102","name":"京口区"},{"code":"321111","name":"润州区"},{"code":"321112","name":"丹徒区"},{"code":"321181","name":"丹阳市"},{"code":"321182","name":"扬中市"},{"code":"321183","name":"句容市"}]},{"code":"3212","name":"泰州市","childs":[{"code":"321202","name":"海陵区"},{"code":"321203","name":"高港区"},{"code":"321204","name":"姜堰区"},{"code":"321281","name":"兴化市"},{"code":"321282","name":"靖江市"},{"code":"321283","name":"泰兴市"}]},{"code":"3213","name":"宿迁市","childs":[{"code":"321302","name":"宿城区"},{"code":"321311","name":"宿豫区"},{"code":"321322","name":"沭阳县"},{"code":"321323","name":"泗阳县"},{"code":"321324","name":"泗洪县"}]}]},{"code":"33","name":"浙江省","childs":[{"code":"3301","name":"杭州市","childs":[{"code":"330102","name":"上城区"},{"code":"330103","name":"下城区"},{"code":"330104","name":"江干区"},{"code":"330105","name":"拱墅区"},{"code":"330106","name":"西湖区"},{"code":"330108","name":"滨江区"},{"code":"330109","name":"萧山区"},{"code":"330110","name":"余杭区"},{"code":"330111","name":"富阳区"},{"code":"330122","name":"桐庐县"},{"code":"330127","name":"淳安县"},{"code":"330182","name":"建德市"},{"code":"330185","name":"临安市"}]},{"code":"3302","name":"宁波市","childs":[{"code":"330203","name":"海曙区"},{"code":"330204","name":"江东区"},{"code":"330205","name":"江北区"},{"code":"330206","name":"北仑区"},{"code":"330211","name":"镇海区"},{"code":"330212","name":"鄞州区"},{"code":"330225","name":"象山县"},{"code":"330226","name":"宁海县"},{"code":"330281","name":"余姚市"},{"code":"330282","name":"慈溪市"},{"code":"330283","name":"奉化市"}]},{"code":"3303","name":"温州市","childs":[{"code":"330302","name":"鹿城区"},{"code":"330303","name":"龙湾区"},{"code":"330304","name":"瓯海区"},{"code":"330305","name":"洞头区"},{"code":"330324","name":"永嘉县"},{"code":"330326","name":"平阳县"},{"code":"330327","name":"苍南县"},{"code":"330328","name":"文成县"},{"code":"330329","name":"泰顺县"},{"code":"330381","name":"瑞安市"},{"code":"330382","name":"乐清市"}]},{"code":"3304","name":"嘉兴市","childs":[{"code":"330402","name":"南湖区"},{"code":"330411","name":"秀洲区"},{"code":"330421","name":"嘉善县"},{"code":"330424","name":"海盐县"},{"code":"330481","name":"海宁市"},{"code":"330482","name":"平湖市"},{"code":"330483","name":"桐乡市"}]},{"code":"3305","name":"湖州市","childs":[{"code":"330502","name":"吴兴区"},{"code":"330503","name":"南浔区"},{"code":"330521","name":"德清县"},{"code":"330522","name":"长兴县"},{"code":"330523","name":"安吉县"}]},{"code":"3306","name":"绍兴市","childs":[{"code":"330602","name":"越城区"},{"code":"330603","name":"柯桥区"},{"code":"330604","name":"上虞区"},{"code":"330624","name":"新昌县"},{"code":"330681","name":"诸暨市"},{"code":"330683","name":"嵊州市"}]},{"code":"3307","name":"金华市","childs":[{"code":"330702","name":"婺城区"},{"code":"330703","name":"金东区"},{"code":"330723","name":"武义县"},{"code":"330726","name":"浦江县"},{"code":"330727","name":"磐安县"},{"code":"330781","name":"兰溪市"},{"code":"330782","name":"义乌市"},{"code":"330783","name":"东阳市"},{"code":"330784","name":"永康市"}]},{"code":"3308","name":"衢州市","childs":[{"code":"330802","name":"柯城区"},{"code":"330803","name":"衢江区"},{"code":"330822","name":"常山县"},{"code":"330824","name":"开化县"},{"code":"330825","name":"龙游县"},{"code":"330881","name":"江山市"}]},{"code":"3309","name":"舟山市","childs":[{"code":"330902","name":"定海区"},{"code":"330903","name":"普陀区"},{"code":"330921","name":"岱山县"},{"code":"330922","name":"嵊泗县"}]},{"code":"3310","name":"台州市","childs":[{"code":"331002","name":"椒江区"},{"code":"331003","name":"黄岩区"},{"code":"331004","name":"路桥区"},{"code":"331021","name":"玉环县"},{"code":"331022","name":"三门县"},{"code":"331023","name":"天台县"},{"code":"331024","name":"仙居县"},{"code":"331081","name":"温岭市"},{"code":"331082","name":"临海市"}]},{"code":"3311","name":"丽水市","childs":[{"code":"331102","name":"莲都区"},{"code":"331121","name":"青田县"},{"code":"331122","name":"缙云县"},{"code":"331123","name":"遂昌县"},{"code":"331124","name":"松阳县"},{"code":"331125","name":"云和县"},{"code":"331126","name":"庆元县"},{"code":"331127","name":"景宁畲族自治县"},{"code":"331181","name":"龙泉市"}]}]},{"code":"34","name":"安徽省","childs":[{"code":"3401","name":"合肥市","childs":[{"code":"340102","name":"瑶海区"},{"code":"340103","name":"庐阳区"},{"code":"340104","name":"蜀山区"},{"code":"340111","name":"包河区"},{"code":"340121","name":"长丰县"},{"code":"340122","name":"肥东县"},{"code":"340123","name":"肥西县"},{"code":"340124","name":"庐江县"},{"code":"340181","name":"巢湖市"}]},{"code":"3402","name":"芜湖市","childs":[{"code":"340202","name":"镜湖区"},{"code":"340203","name":"弋江区"},{"code":"340207","name":"鸠江区"},{"code":"340208","name":"三山区"},{"code":"340221","name":"芜湖县"},{"code":"340222","name":"繁昌县"},{"code":"340223","name":"南陵县"},{"code":"340225","name":"无为县"}]},{"code":"3403","name":"蚌埠市","childs":[{"code":"340302","name":"龙子湖区"},{"code":"340303","name":"蚌山区"},{"code":"340304","name":"禹会区"},{"code":"340311","name":"淮上区"},{"code":"340321","name":"怀远县"},{"code":"340322","name":"五河县"},{"code":"340323","name":"固镇县"}]},{"code":"3404","name":"淮南市","childs":[{"code":"340402","name":"大通区"},{"code":"340403","name":"田家庵区"},{"code":"340404","name":"谢家集区"},{"code":"340405","name":"八公山区"},{"code":"340406","name":"潘集区"},{"code":"340421","name":"凤台县"},{"code":"340422","name":"寿县"}]},{"code":"3405","name":"马鞍山市","childs":[{"code":"340503","name":"花山区"},{"code":"340504","name":"雨山区"},{"code":"340506","name":"博望区"},{"code":"340521","name":"当涂县"},{"code":"340522","name":"含山县"},{"code":"340523","name":"和县"}]},{"code":"3406","name":"淮北市","childs":[{"code":"340602","name":"杜集区"},{"code":"340603","name":"相山区"},{"code":"340604","name":"烈山区"},{"code":"340621","name":"濉溪县"}]},{"code":"3407","name":"铜陵市","childs":[{"code":"340705","name":"铜官区"},{"code":"340706","name":"义安区"},{"code":"340711","name":"郊区"},{"code":"340722","name":"枞阳县"}]},{"code":"3408","name":"安庆市","childs":[{"code":"340802","name":"迎江区"},{"code":"340803","name":"大观区"},{"code":"340811","name":"宜秀区"},{"code":"340822","name":"怀宁县"},{"code":"340824","name":"潜山县"},{"code":"340825","name":"太湖县"},{"code":"340826","name":"宿松县"},{"code":"340827","name":"望江县"},{"code":"340828","name":"岳西县"},{"code":"340881","name":"桐城市"}]},{"code":"3410","name":"黄山市","childs":[{"code":"341002","name":"屯溪区"},{"code":"341003","name":"黄山区"},{"code":"341004","name":"徽州区"},{"code":"341021","name":"歙县"},{"code":"341022","name":"休宁县"},{"code":"341023","name":"黟县"},{"code":"341024","name":"祁门县"}]},{"code":"3411","name":"滁州市","childs":[{"code":"341102","name":"琅琊区"},{"code":"341103","name":"南谯区"},{"code":"341122","name":"来安县"},{"code":"341124","name":"全椒县"},{"code":"341125","name":"定远县"},{"code":"341126","name":"凤阳县"},{"code":"341181","name":"天长市"},{"code":"341182","name":"明光市"}]},{"code":"3412","name":"阜阳市","childs":[{"code":"341202","name":"颍州区"},{"code":"341203","name":"颍东区"},{"code":"341204","name":"颍泉区"},{"code":"341221","name":"临泉县"},{"code":"341222","name":"太和县"},{"code":"341225","name":"阜南县"},{"code":"341226","name":"颍上县"},{"code":"341282","name":"界首市"}]},{"code":"3413","name":"宿州市","childs":[{"code":"341302","name":"埇桥区"},{"code":"341321","name":"砀山县"},{"code":"341322","name":"萧县"},{"code":"341323","name":"灵璧县"},{"code":"341324","name":"泗县"}]},{"code":"3415","name":"六安市","childs":[{"code":"341502","name":"金安区"},{"code":"341503","name":"裕安区"},{"code":"341504","name":"叶集区"},{"code":"341522","name":"霍邱县"},{"code":"341523","name":"舒城县"},{"code":"341524","name":"金寨县"},{"code":"341525","name":"霍山县"}]},{"code":"3416","name":"亳州市","childs":[{"code":"341602","name":"谯城区"},{"code":"341621","name":"涡阳县"},{"code":"341622","name":"蒙城县"},{"code":"341623","name":"利辛县"}]},{"code":"3417","name":"池州市","childs":[{"code":"341702","name":"贵池区"},{"code":"341721","name":"东至县"},{"code":"341722","name":"石台县"},{"code":"341723","name":"青阳县"}]},{"code":"3418","name":"宣城市","childs":[{"code":"341802","name":"宣州区"},{"code":"341821","name":"郎溪县"},{"code":"341822","name":"广德县"},{"code":"341823","name":"泾县"},{"code":"341824","name":"绩溪县"},{"code":"341825","name":"旌德县"},{"code":"341881","name":"宁国市"}]}]},{"code":"35","name":"福建省","childs":[{"code":"3501","name":"福州市","childs":[{"code":"350102","name":"鼓楼区"},{"code":"350103","name":"台江区"},{"code":"350104","name":"仓山区"},{"code":"350105","name":"马尾区"},{"code":"350111","name":"晋安区"},{"code":"350121","name":"闽侯县"},{"code":"350122","name":"连江县"},{"code":"350123","name":"罗源县"},{"code":"350124","name":"闽清县"},{"code":"350125","name":"永泰县"},{"code":"350128","name":"平潭县"},{"code":"350181","name":"福清市"},{"code":"350182","name":"长乐市"}]},{"code":"3502","name":"厦门市","childs":[{"code":"350203","name":"思明区"},{"code":"350205","name":"海沧区"},{"code":"350206","name":"湖里区"},{"code":"350211","name":"集美区"},{"code":"350212","name":"同安区"},{"code":"350213","name":"翔安区"}]},{"code":"3503","name":"莆田市","childs":[{"code":"350302","name":"城厢区"},{"code":"350303","name":"涵江区"},{"code":"350304","name":"荔城区"},{"code":"350305","name":"秀屿区"},{"code":"350322","name":"仙游县"}]},{"code":"3504","name":"三明市","childs":[{"code":"350402","name":"梅列区"},{"code":"350403","name":"三元区"},{"code":"350421","name":"明溪县"},{"code":"350423","name":"清流县"},{"code":"350424","name":"宁化县"},{"code":"350425","name":"大田县"},{"code":"350426","name":"尤溪县"},{"code":"350427","name":"沙县"},{"code":"350428","name":"将乐县"},{"code":"350429","name":"泰宁县"},{"code":"350430","name":"建宁县"},{"code":"350481","name":"永安市"}]},{"code":"3505","name":"泉州市","childs":[{"code":"350502","name":"鲤城区"},{"code":"350503","name":"丰泽区"},{"code":"350504","name":"洛江区"},{"code":"350505","name":"泉港区"},{"code":"350521","name":"惠安县"},{"code":"350524","name":"安溪县"},{"code":"350525","name":"永春县"},{"code":"350526","name":"德化县"},{"code":"350527","name":"金门县"},{"code":"350581","name":"石狮市"},{"code":"350582","name":"晋江市"},{"code":"350583","name":"南安市"}]},{"code":"3506","name":"漳州市","childs":[{"code":"350602","name":"芗城区"},{"code":"350603","name":"龙文区"},{"code":"350622","name":"云霄县"},{"code":"350623","name":"漳浦县"},{"code":"350624","name":"诏安县"},{"code":"350625","name":"长泰县"},{"code":"350626","name":"东山县"},{"code":"350627","name":"南靖县"},{"code":"350628","name":"平和县"},{"code":"350629","name":"华安县"},{"code":"350681","name":"龙海市"}]},{"code":"3507","name":"南平市","childs":[{"code":"350702","name":"延平区"},{"code":"350703","name":"建阳区"},{"code":"350721","name":"顺昌县"},{"code":"350722","name":"浦城县"},{"code":"350723","name":"光泽县"},{"code":"350724","name":"松溪县"},{"code":"350725","name":"政和县"},{"code":"350781","name":"邵武市"},{"code":"350782","name":"武夷山市"},{"code":"350783","name":"建瓯市"}]},{"code":"3508","name":"龙岩市","childs":[{"code":"350802","name":"新罗区"},{"code":"350803","name":"永定区"},{"code":"350821","name":"长汀县"},{"code":"350823","name":"上杭县"},{"code":"350824","name":"武平县"},{"code":"350825","name":"连城县"},{"code":"350881","name":"漳平市"}]},{"code":"3509","name":"宁德市","childs":[{"code":"350902","name":"蕉城区"},{"code":"350921","name":"霞浦县"},{"code":"350922","name":"古田县"},{"code":"350923","name":"屏南县"},{"code":"350924","name":"寿宁县"},{"code":"350925","name":"周宁县"},{"code":"350926","name":"柘荣县"},{"code":"350981","name":"福安市"},{"code":"350982","name":"福鼎市"}]}]},{"code":"36","name":"江西省","childs":[{"code":"3601","name":"南昌市","childs":[{"code":"360102","name":"东湖区"},{"code":"360103","name":"西湖区"},{"code":"360104","name":"青云谱区"},{"code":"360105","name":"湾里区"},{"code":"360111","name":"青山湖区"},{"code":"360112","name":"新建区"},{"code":"360121","name":"南昌县"},{"code":"360123","name":"安义县"},{"code":"360124","name":"进贤县"}]},{"code":"3602","name":"景德镇市","childs":[{"code":"360202","name":"昌江区"},{"code":"360203","name":"珠山区"},{"code":"360222","name":"浮梁县"},{"code":"360281","name":"乐平市"}]},{"code":"3603","name":"萍乡市","childs":[{"code":"360302","name":"安源区"},{"code":"360313","name":"湘东区"},{"code":"360321","name":"莲花县"},{"code":"360322","name":"上栗县"},{"code":"360323","name":"芦溪县"}]},{"code":"3604","name":"九江市","childs":[{"code":"360402","name":"濂溪区"},{"code":"360403","name":"浔阳区"},{"code":"360421","name":"九江县"},{"code":"360423","name":"武宁县"},{"code":"360424","name":"修水县"},{"code":"360425","name":"永修县"},{"code":"360426","name":"德安县"},{"code":"360428","name":"都昌县"},{"code":"360429","name":"湖口县"},{"code":"360430","name":"彭泽县"},{"code":"360481","name":"瑞昌市"},{"code":"360482","name":"共青城市"},{"code":"360483","name":"庐山市"}]},{"code":"3605","name":"新余市","childs":[{"code":"360502","name":"渝水区"},{"code":"360521","name":"分宜县"}]},{"code":"3606","name":"鹰潭市","childs":[{"code":"360602","name":"月湖区"},{"code":"360622","name":"余江县"},{"code":"360681","name":"贵溪市"}]},{"code":"3607","name":"赣州市","childs":[{"code":"360702","name":"章贡区"},{"code":"360703","name":"南康区"},{"code":"360721","name":"赣县"},{"code":"360722","name":"信丰县"},{"code":"360723","name":"大余县"},{"code":"360724","name":"上犹县"},{"code":"360725","name":"崇义县"},{"code":"360726","name":"安远县"},{"code":"360727","name":"龙南县"},{"code":"360728","name":"定南县"},{"code":"360729","name":"全南县"},{"code":"360730","name":"宁都县"},{"code":"360731","name":"于都县"},{"code":"360732","name":"兴国县"},{"code":"360733","name":"会昌县"},{"code":"360734","name":"寻乌县"},{"code":"360735","name":"石城县"},{"code":"360781","name":"瑞金市"}]},{"code":"3608","name":"吉安市","childs":[{"code":"360802","name":"吉州区"},{"code":"360803","name":"青原区"},{"code":"360821","name":"吉安县"},{"code":"360822","name":"吉水县"},{"code":"360823","name":"峡江县"},{"code":"360824","name":"新干县"},{"code":"360825","name":"永丰县"},{"code":"360826","name":"泰和县"},{"code":"360827","name":"遂川县"},{"code":"360828","name":"万安县"},{"code":"360829","name":"安福县"},{"code":"360830","name":"永新县"},{"code":"360881","name":"井冈山市"}]},{"code":"3609","name":"宜春市","childs":[{"code":"360902","name":"袁州区"},{"code":"360921","name":"奉新县"},{"code":"360922","name":"万载县"},{"code":"360923","name":"上高县"},{"code":"360924","name":"宜丰县"},{"code":"360925","name":"靖安县"},{"code":"360926","name":"铜鼓县"},{"code":"360981","name":"丰城市"},{"code":"360982","name":"樟树市"},{"code":"360983","name":"高安市"}]},{"code":"3610","name":"抚州市","childs":[{"code":"361002","name":"临川区"},{"code":"361021","name":"南城县"},{"code":"361022","name":"黎川县"},{"code":"361023","name":"南丰县"},{"code":"361024","name":"崇仁县"},{"code":"361025","name":"乐安县"},{"code":"361026","name":"宜黄县"},{"code":"361027","name":"金溪县"},{"code":"361028","name":"资溪县"},{"code":"361029","name":"东乡县"},{"code":"361030","name":"广昌县"}]},{"code":"3611","name":"上饶市","childs":[{"code":"361102","name":"信州区"},{"code":"361103","name":"广丰区"},{"code":"361121","name":"上饶县"},{"code":"361123","name":"玉山县"},{"code":"361124","name":"铅山县"},{"code":"361125","name":"横峰县"},{"code":"361126","name":"弋阳县"},{"code":"361127","name":"余干县"},{"code":"361128","name":"鄱阳县"},{"code":"361129","name":"万年县"},{"code":"361130","name":"婺源县"},{"code":"361181","name":"德兴市"}]}]},{"code":"37","name":"山东省","childs":[{"code":"3701","name":"济南市","childs":[{"code":"370102","name":"历下区"},{"code":"370103","name":"市中区"},{"code":"370104","name":"槐荫区"},{"code":"370105","name":"天桥区"},{"code":"370112","name":"历城区"},{"code":"370113","name":"长清区"},{"code":"370124","name":"平阴县"},{"code":"370125","name":"济阳县"},{"code":"370126","name":"商河县"},{"code":"370181","name":"章丘市"}]},{"code":"3702","name":"青岛市","childs":[{"code":"370202","name":"市南区"},{"code":"370203","name":"市北区"},{"code":"370211","name":"黄岛区"},{"code":"370212","name":"崂山区"},{"code":"370213","name":"李沧区"},{"code":"370214","name":"城阳区"},{"code":"370281","name":"胶州市"},{"code":"370282","name":"即墨市"},{"code":"370283","name":"平度市"},{"code":"370285","name":"莱西市"}]},{"code":"3703","name":"淄博市","childs":[{"code":"370302","name":"淄川区"},{"code":"370303","name":"张店区"},{"code":"370304","name":"博山区"},{"code":"370305","name":"临淄区"},{"code":"370306","name":"周村区"},{"code":"370321","name":"桓台县"},{"code":"370322","name":"高青县"},{"code":"370323","name":"沂源县"}]},{"code":"3704","name":"枣庄市","childs":[{"code":"370402","name":"市中区"},{"code":"370403","name":"薛城区"},{"code":"370404","name":"峄城区"},{"code":"370405","name":"台儿庄区"},{"code":"370406","name":"山亭区"},{"code":"370481","name":"滕州市"}]},{"code":"3705","name":"东营市","childs":[{"code":"370502","name":"东营区"},{"code":"370503","name":"河口区"},{"code":"370505","name":"垦利区"},{"code":"370522","name":"利津县"},{"code":"370523","name":"广饶县"}]},{"code":"3706","name":"烟台市","childs":[{"code":"370602","name":"芝罘区"},{"code":"370611","name":"福山区"},{"code":"370612","name":"牟平区"},{"code":"370613","name":"莱山区"},{"code":"370634","name":"长岛县"},{"code":"370681","name":"龙口市"},{"code":"370682","name":"莱阳市"},{"code":"370683","name":"莱州市"},{"code":"370684","name":"蓬莱市"},{"code":"370685","name":"招远市"},{"code":"370686","name":"栖霞市"},{"code":"370687","name":"海阳市"}]},{"code":"3707","name":"潍坊市","childs":[{"code":"370702","name":"潍城区"},{"code":"370703","name":"寒亭区"},{"code":"370704","name":"坊子区"},{"code":"370705","name":"奎文区"},{"code":"370724","name":"临朐县"},{"code":"370725","name":"昌乐县"},{"code":"370781","name":"青州市"},{"code":"370782","name":"诸城市"},{"code":"370783","name":"寿光市"},{"code":"370784","name":"安丘市"},{"code":"370785","name":"高密市"},{"code":"370786","name":"昌邑市"}]},{"code":"3708","name":"济宁市","childs":[{"code":"370811","name":"任城区"},{"code":"370812","name":"兖州区"},{"code":"370826","name":"微山县"},{"code":"370827","name":"鱼台县"},{"code":"370828","name":"金乡县"},{"code":"370829","name":"嘉祥县"},{"code":"370830","name":"汶上县"},{"code":"370831","name":"泗水县"},{"code":"370832","name":"梁山县"},{"code":"370881","name":"曲阜市"},{"code":"370883","name":"邹城市"}]},{"code":"3709","name":"泰安市","childs":[{"code":"370902","name":"泰山区"},{"code":"370911","name":"岱岳区"},{"code":"370921","name":"宁阳县"},{"code":"370923","name":"东平县"},{"code":"370982","name":"新泰市"},{"code":"370983","name":"肥城市"}]},{"code":"3710","name":"威海市","childs":[{"code":"371002","name":"环翠区"},{"code":"371003","name":"文登区"},{"code":"371082","name":"荣成市"},{"code":"371083","name":"乳山市"}]},{"code":"3711","name":"日照市","childs":[{"code":"371102","name":"东港区"},{"code":"371103","name":"岚山区"},{"code":"371121","name":"五莲县"},{"code":"371122","name":"莒县"}]},{"code":"3712","name":"莱芜市","childs":[{"code":"371202","name":"莱城区"},{"code":"371203","name":"钢城区"}]},{"code":"3713","name":"临沂市","childs":[{"code":"371302","name":"兰山区"},{"code":"371311","name":"罗庄区"},{"code":"371312","name":"河东区"},{"code":"371321","name":"沂南县"},{"code":"371322","name":"郯城县"},{"code":"371323","name":"沂水县"},{"code":"371324","name":"兰陵县"},{"code":"371325","name":"费县"},{"code":"371326","name":"平邑县"},{"code":"371327","name":"莒南县"},{"code":"371328","name":"蒙阴县"},{"code":"371329","name":"临沭县"}]},{"code":"3714","name":"德州市","childs":[{"code":"371402","name":"德城区"},{"code":"371403","name":"陵城区"},{"code":"371422","name":"宁津县"},{"code":"371423","name":"庆云县"},{"code":"371424","name":"临邑县"},{"code":"371425","name":"齐河县"},{"code":"371426","name":"平原县"},{"code":"371427","name":"夏津县"},{"code":"371428","name":"武城县"},{"code":"371481","name":"乐陵市"},{"code":"371482","name":"禹城市"}]},{"code":"3715","name":"聊城市","childs":[{"code":"371502","name":"东昌府区"},{"code":"371521","name":"阳谷县"},{"code":"371522","name":"莘县"},{"code":"371523","name":"茌平县"},{"code":"371524","name":"东阿县"},{"code":"371525","name":"冠县"},{"code":"371526","name":"高唐县"},{"code":"371581","name":"临清市"}]},{"code":"3716","name":"滨州市","childs":[{"code":"371602","name":"滨城区"},{"code":"371603","name":"沾化区"},{"code":"371621","name":"惠民县"},{"code":"371622","name":"阳信县"},{"code":"371623","name":"无棣县"},{"code":"371625","name":"博兴县"},{"code":"371626","name":"邹平县"}]},{"code":"3717","name":"菏泽市","childs":[{"code":"371702","name":"牡丹区"},{"code":"371703","name":"定陶区"},{"code":"371721","name":"曹县"},{"code":"371722","name":"单县"},{"code":"371723","name":"成武县"},{"code":"371724","name":"巨野县"},{"code":"371725","name":"郓城县"},{"code":"371726","name":"鄄城县"},{"code":"371728","name":"东明县"}]}]},{"code":"41","name":"河南省","childs":[{"code":"4101","name":"郑州市","childs":[{"code":"410102","name":"中原区"},{"code":"410103","name":"二七区"},{"code":"410104","name":"管城回族区"},{"code":"410105","name":"金水区"},{"code":"410106","name":"上街区"},{"code":"410108","name":"惠济区"},{"code":"410122","name":"中牟县"},{"code":"410181","name":"巩义市"},{"code":"410182","name":"荥阳市"},{"code":"410183","name":"新密市"},{"code":"410184","name":"新郑市"},{"code":"410185","name":"登封市"}]},{"code":"4102","name":"开封市","childs":[{"code":"410202","name":"龙亭区"},{"code":"410203","name":"顺河回族区"},{"code":"410204","name":"鼓楼区"},{"code":"410205","name":"禹王台区"},{"code":"410211","name":"金明区"},{"code":"410212","name":"祥符区"},{"code":"410221","name":"杞县"},{"code":"410222","name":"通许县"},{"code":"410223","name":"尉氏县"},{"code":"410225","name":"兰考县"}]},{"code":"4103","name":"洛阳市","childs":[{"code":"410302","name":"老城区"},{"code":"410303","name":"西工区"},{"code":"410304","name":"瀍河回族区"},{"code":"410305","name":"涧西区"},{"code":"410306","name":"吉利区"},{"code":"410311","name":"洛龙区"},{"code":"410322","name":"孟津县"},{"code":"410323","name":"新安县"},{"code":"410324","name":"栾川县"},{"code":"410325","name":"嵩县"},{"code":"410326","name":"汝阳县"},{"code":"410327","name":"宜阳县"},{"code":"410328","name":"洛宁县"},{"code":"410329","name":"伊川县"},{"code":"410381","name":"偃师市"}]},{"code":"4104","name":"平顶山市","childs":[{"code":"410402","name":"新华区"},{"code":"410403","name":"卫东区"},{"code":"410404","name":"石龙区"},{"code":"410411","name":"湛河区"},{"code":"410421","name":"宝丰县"},{"code":"410422","name":"叶县"},{"code":"410423","name":"鲁山县"},{"code":"410425","name":"郏县"},{"code":"410481","name":"舞钢市"},{"code":"410482","name":"汝州市"}]},{"code":"4105","name":"安阳市","childs":[{"code":"410502","name":"文峰区"},{"code":"410503","name":"北关区"},{"code":"410505","name":"殷都区"},{"code":"410506","name":"龙安区"},{"code":"410522","name":"安阳县"},{"code":"410523","name":"汤阴县"},{"code":"410526","name":"滑县"},{"code":"410527","name":"内黄县"},{"code":"410581","name":"林州市"}]},{"code":"4106","name":"鹤壁市","childs":[{"code":"410602","name":"鹤山区"},{"code":"410603","name":"山城区"},{"code":"410611","name":"淇滨区"},{"code":"410621","name":"浚县"},{"code":"410622","name":"淇县"}]},{"code":"4107","name":"新乡市","childs":[{"code":"410702","name":"红旗区"},{"code":"410703","name":"卫滨区"},{"code":"410704","name":"凤泉区"},{"code":"410711","name":"牧野区"},{"code":"410721","name":"新乡县"},{"code":"410724","name":"获嘉县"},{"code":"410725","name":"原阳县"},{"code":"410726","name":"延津县"},{"code":"410727","name":"封丘县"},{"code":"410728","name":"长垣县"},{"code":"410781","name":"卫辉市"},{"code":"410782","name":"辉县市"}]},{"code":"4108","name":"焦作市","childs":[{"code":"410802","name":"解放区"},{"code":"410803","name":"中站区"},{"code":"410804","name":"马村区"},{"code":"410811","name":"山阳区"},{"code":"410821","name":"修武县"},{"code":"410822","name":"博爱县"},{"code":"410823","name":"武陟县"},{"code":"410825","name":"温县"},{"code":"410882","name":"沁阳市"},{"code":"410883","name":"孟州市"}]},{"code":"4109","name":"濮阳市","childs":[{"code":"410902","name":"华龙区"},{"code":"410922","name":"清丰县"},{"code":"410923","name":"南乐县"},{"code":"410926","name":"范县"},{"code":"410927","name":"台前县"},{"code":"410928","name":"濮阳县"}]},{"code":"4110","name":"许昌市","childs":[{"code":"411002","name":"魏都区"},{"code":"411023","name":"许昌县"},{"code":"411024","name":"鄢陵县"},{"code":"411025","name":"襄城县"},{"code":"411081","name":"禹州市"},{"code":"411082","name":"长葛市"}]},{"code":"4111","name":"漯河市","childs":[{"code":"411102","name":"源汇区"},{"code":"411103","name":"郾城区"},{"code":"411104","name":"召陵区"},{"code":"411121","name":"舞阳县"},{"code":"411122","name":"临颍县"}]},{"code":"4112","name":"三门峡市","childs":[{"code":"411202","name":"湖滨区"},{"code":"411203","name":"陕州区"},{"code":"411221","name":"渑池县"},{"code":"411224","name":"卢氏县"},{"code":"411281","name":"义马市"},{"code":"411282","name":"灵宝市"}]},{"code":"4113","name":"南阳市","childs":[{"code":"411302","name":"宛城区"},{"code":"411303","name":"卧龙区"},{"code":"411321","name":"南召县"},{"code":"411322","name":"方城县"},{"code":"411323","name":"西峡县"},{"code":"411324","name":"镇平县"},{"code":"411325","name":"内乡县"},{"code":"411326","name":"淅川县"},{"code":"411327","name":"社旗县"},{"code":"411328","name":"唐河县"},{"code":"411329","name":"新野县"},{"code":"411330","name":"桐柏县"},{"code":"411381","name":"邓州市"}]},{"code":"4114","name":"商丘市","childs":[{"code":"411402","name":"梁园区"},{"code":"411403","name":"睢阳区"},{"code":"411421","name":"民权县"},{"code":"411422","name":"睢县"},{"code":"411423","name":"宁陵县"},{"code":"411424","name":"柘城县"},{"code":"411425","name":"虞城县"},{"code":"411426","name":"夏邑县"},{"code":"411481","name":"永城市"}]},{"code":"4115","name":"信阳市","childs":[{"code":"411502","name":"浉河区"},{"code":"411503","name":"平桥区"},{"code":"411521","name":"罗山县"},{"code":"411522","name":"光山县"},{"code":"411523","name":"新县"},{"code":"411524","name":"商城县"},{"code":"411525","name":"固始县"},{"code":"411526","name":"潢川县"},{"code":"411527","name":"淮滨县"},{"code":"411528","name":"息县"}]},{"code":"4116","name":"周口市","childs":[{"code":"411602","name":"川汇区"},{"code":"411621","name":"扶沟县"},{"code":"411622","name":"西华县"},{"code":"411623","name":"商水县"},{"code":"411624","name":"沈丘县"},{"code":"411625","name":"郸城县"},{"code":"411626","name":"淮阳县"},{"code":"411627","name":"太康县"},{"code":"411628","name":"鹿邑县"},{"code":"411681","name":"项城市"}]},{"code":"4117","name":"驻马店市","childs":[{"code":"411702","name":"驿城区"},{"code":"411721","name":"西平县"},{"code":"411722","name":"上蔡县"},{"code":"411723","name":"平舆县"},{"code":"411724","name":"正阳县"},{"code":"411725","name":"确山县"},{"code":"411726","name":"泌阳县"},{"code":"411727","name":"汝南县"},{"code":"411728","name":"遂平县"},{"code":"411729","name":"新蔡县"}]},{"code":"4190","name":"省直辖县级行政区划","childs":[{"code":"419001","name":"济源市"}]}]},{"code":"42","name":"湖北省","childs":[{"code":"4201","name":"武汉市","childs":[{"code":"420102","name":"江岸区"},{"code":"420103","name":"江汉区"},{"code":"420104","name":"硚口区"},{"code":"420105","name":"汉阳区"},{"code":"420106","name":"武昌区"},{"code":"420107","name":"青山区"},{"code":"420111","name":"洪山区"},{"code":"420112","name":"东西湖区"},{"code":"420113","name":"汉南区"},{"code":"420114","name":"蔡甸区"},{"code":"420115","name":"江夏区"},{"code":"420116","name":"黄陂区"},{"code":"420117","name":"新洲区"}]},{"code":"4202","name":"黄石市","childs":[{"code":"420202","name":"黄石港区"},{"code":"420203","name":"西塞山区"},{"code":"420204","name":"下陆区"},{"code":"420205","name":"铁山区"},{"code":"420222","name":"阳新县"},{"code":"420281","name":"大冶市"}]},{"code":"4203","name":"十堰市","childs":[{"code":"420302","name":"茅箭区"},{"code":"420303","name":"张湾区"},{"code":"420304","name":"郧阳区"},{"code":"420322","name":"郧西县"},{"code":"420323","name":"竹山县"},{"code":"420324","name":"竹溪县"},{"code":"420325","name":"房县"},{"code":"420381","name":"丹江口市"}]},{"code":"4205","name":"宜昌市","childs":[{"code":"420502","name":"西陵区"},{"code":"420503","name":"伍家岗区"},{"code":"420504","name":"点军区"},{"code":"420505","name":"猇亭区"},{"code":"420506","name":"夷陵区"},{"code":"420525","name":"远安县"},{"code":"420526","name":"兴山县"},{"code":"420527","name":"秭归县"},{"code":"420528","name":"长阳土家族自治县"},{"code":"420529","name":"五峰土家族自治县"},{"code":"420581","name":"宜都市"},{"code":"420582","name":"当阳市"},{"code":"420583","name":"枝江市"}]},{"code":"4206","name":"襄阳市","childs":[{"code":"420602","name":"襄城区"},{"code":"420606","name":"樊城区"},{"code":"420607","name":"襄州区"},{"code":"420624","name":"南漳县"},{"code":"420625","name":"谷城县"},{"code":"420626","name":"保康县"},{"code":"420682","name":"老河口市"},{"code":"420683","name":"枣阳市"},{"code":"420684","name":"宜城市"}]},{"code":"4207","name":"鄂州市","childs":[{"code":"420702","name":"梁子湖区"},{"code":"420703","name":"华容区"},{"code":"420704","name":"鄂城区"}]},{"code":"4208","name":"荆门市","childs":[{"code":"420802","name":"东宝区"},{"code":"420804","name":"掇刀区"},{"code":"420821","name":"京山县"},{"code":"420822","name":"沙洋县"},{"code":"420881","name":"钟祥市"}]},{"code":"4209","name":"孝感市","childs":[{"code":"420902","name":"孝南区"},{"code":"420921","name":"孝昌县"},{"code":"420922","name":"大悟县"},{"code":"420923","name":"云梦县"},{"code":"420981","name":"应城市"},{"code":"420982","name":"安陆市"},{"code":"420984","name":"汉川市"}]},{"code":"4210","name":"荆州市","childs":[{"code":"421002","name":"沙市区"},{"code":"421003","name":"荆州区"},{"code":"421022","name":"公安县"},{"code":"421023","name":"监利县"},{"code":"421024","name":"江陵县"},{"code":"421081","name":"石首市"},{"code":"421083","name":"洪湖市"},{"code":"421087","name":"松滋市"}]},{"code":"4211","name":"黄冈市","childs":[{"code":"421102","name":"黄州区"},{"code":"421121","name":"团风县"},{"code":"421122","name":"红安县"},{"code":"421123","name":"罗田县"},{"code":"421124","name":"英山县"},{"code":"421125","name":"浠水县"},{"code":"421126","name":"蕲春县"},{"code":"421127","name":"黄梅县"},{"code":"421181","name":"麻城市"},{"code":"421182","name":"武穴市"}]},{"code":"4212","name":"咸宁市","childs":[{"code":"421202","name":"咸安区"},{"code":"421221","name":"嘉鱼县"},{"code":"421222","name":"通城县"},{"code":"421223","name":"崇阳县"},{"code":"421224","name":"通山县"},{"code":"421281","name":"赤壁市"}]},{"code":"4213","name":"随州市","childs":[{"code":"421303","name":"曾都区"},{"code":"421321","name":"随县"},{"code":"421381","name":"广水市"}]},{"code":"4228","name":"恩施土家族苗族自治州","childs":[{"code":"422801","name":"恩施市"},{"code":"422802","name":"利川市"},{"code":"422822","name":"建始县"},{"code":"422823","name":"巴东县"},{"code":"422825","name":"宣恩县"},{"code":"422826","name":"咸丰县"},{"code":"422827","name":"来凤县"},{"code":"422828","name":"鹤峰县"}]},{"code":"4290","name":"省直辖县级行政区划","childs":[{"code":"429004","name":"仙桃市"},{"code":"429005","name":"潜江市"},{"code":"429006","name":"天门市"},{"code":"429021","name":"神农架林区"}]}]},{"code":"43","name":"湖南省","childs":[{"code":"4301","name":"长沙市","childs":[{"code":"430102","name":"芙蓉区"},{"code":"430103","name":"天心区"},{"code":"430104","name":"岳麓区"},{"code":"430105","name":"开福区"},{"code":"430111","name":"雨花区"},{"code":"430112","name":"望城区"},{"code":"430121","name":"长沙县"},{"code":"430124","name":"宁乡县"},{"code":"430181","name":"浏阳市"}]},{"code":"4302","name":"株洲市","childs":[{"code":"430202","name":"荷塘区"},{"code":"430203","name":"芦淞区"},{"code":"430204","name":"石峰区"},{"code":"430211","name":"天元区"},{"code":"430221","name":"株洲县"},{"code":"430223","name":"攸县"},{"code":"430224","name":"茶陵县"},{"code":"430225","name":"炎陵县"},{"code":"430281","name":"醴陵市"}]},{"code":"4303","name":"湘潭市","childs":[{"code":"430302","name":"雨湖区"},{"code":"430304","name":"岳塘区"},{"code":"430321","name":"湘潭县"},{"code":"430381","name":"湘乡市"},{"code":"430382","name":"韶山市"}]},{"code":"4304","name":"衡阳市","childs":[{"code":"430405","name":"珠晖区"},{"code":"430406","name":"雁峰区"},{"code":"430407","name":"石鼓区"},{"code":"430408","name":"蒸湘区"},{"code":"430412","name":"南岳区"},{"code":"430421","name":"衡阳县"},{"code":"430422","name":"衡南县"},{"code":"430423","name":"衡山县"},{"code":"430424","name":"衡东县"},{"code":"430426","name":"祁东县"},{"code":"430481","name":"耒阳市"},{"code":"430482","name":"常宁市"}]},{"code":"4305","name":"邵阳市","childs":[{"code":"430502","name":"双清区"},{"code":"430503","name":"大祥区"},{"code":"430511","name":"北塔区"},{"code":"430521","name":"邵东县"},{"code":"430522","name":"新邵县"},{"code":"430523","name":"邵阳县"},{"code":"430524","name":"隆回县"},{"code":"430525","name":"洞口县"},{"code":"430527","name":"绥宁县"},{"code":"430528","name":"新宁县"},{"code":"430529","name":"城步苗族自治县"},{"code":"430581","name":"武冈市"}]},{"code":"4306","name":"岳阳市","childs":[{"code":"430602","name":"岳阳楼区"},{"code":"430603","name":"云溪区"},{"code":"430611","name":"君山区"},{"code":"430621","name":"岳阳县"},{"code":"430623","name":"华容县"},{"code":"430624","name":"湘阴县"},{"code":"430626","name":"平江县"},{"code":"430681","name":"汨罗市"},{"code":"430682","name":"临湘市"}]},{"code":"4307","name":"常德市","childs":[{"code":"430702","name":"武陵区"},{"code":"430703","name":"鼎城区"},{"code":"430721","name":"安乡县"},{"code":"430722","name":"汉寿县"},{"code":"430723","name":"澧县"},{"code":"430724","name":"临澧县"},{"code":"430725","name":"桃源县"},{"code":"430726","name":"石门县"},{"code":"430781","name":"津市市"}]},{"code":"4308","name":"张家界市","childs":[{"code":"430802","name":"永定区"},{"code":"430811","name":"武陵源区"},{"code":"430821","name":"慈利县"},{"code":"430822","name":"桑植县"}]},{"code":"4309","name":"益阳市","childs":[{"code":"430902","name":"资阳区"},{"code":"430903","name":"赫山区"},{"code":"430921","name":"南县"},{"code":"430922","name":"桃江县"},{"code":"430923","name":"安化县"},{"code":"430981","name":"沅江市"}]},{"code":"4310","name":"郴州市","childs":[{"code":"431002","name":"北湖区"},{"code":"431003","name":"苏仙区"},{"code":"431021","name":"桂阳县"},{"code":"431022","name":"宜章县"},{"code":"431023","name":"永兴县"},{"code":"431024","name":"嘉禾县"},{"code":"431025","name":"临武县"},{"code":"431026","name":"汝城县"},{"code":"431027","name":"桂东县"},{"code":"431028","name":"安仁县"},{"code":"431081","name":"资兴市"}]},{"code":"4311","name":"永州市","childs":[{"code":"431102","name":"零陵区"},{"code":"431103","name":"冷水滩区"},{"code":"431121","name":"祁阳县"},{"code":"431122","name":"东安县"},{"code":"431123","name":"双牌县"},{"code":"431124","name":"道县"},{"code":"431125","name":"江永县"},{"code":"431126","name":"宁远县"},{"code":"431127","name":"蓝山县"},{"code":"431128","name":"新田县"},{"code":"431129","name":"江华瑶族自治县"}]},{"code":"4312","name":"怀化市","childs":[{"code":"431202","name":"鹤城区"},{"code":"431221","name":"中方县"},{"code":"431222","name":"沅陵县"},{"code":"431223","name":"辰溪县"},{"code":"431224","name":"溆浦县"},{"code":"431225","name":"会同县"},{"code":"431226","name":"麻阳苗族自治县"},{"code":"431227","name":"新晃侗族自治县"},{"code":"431228","name":"芷江侗族自治县"},{"code":"431229","name":"靖州苗族侗族自治县"},{"code":"431230","name":"通道侗族自治县"},{"code":"431281","name":"洪江市"}]},{"code":"4313","name":"娄底市","childs":[{"code":"431302","name":"娄星区"},{"code":"431321","name":"双峰县"},{"code":"431322","name":"新化县"},{"code":"431381","name":"冷水江市"},{"code":"431382","name":"涟源市"}]},{"code":"4331","name":"湘西土家族苗族自治州","childs":[{"code":"433101","name":"吉首市"},{"code":"433122","name":"泸溪县"},{"code":"433123","name":"凤凰县"},{"code":"433124","name":"花垣县"},{"code":"433125","name":"保靖县"},{"code":"433126","name":"古丈县"},{"code":"433127","name":"永顺县"},{"code":"433130","name":"龙山县"}]}]},{"code":"44","name":"广东省","childs":[{"code":"4401","name":"广州市","childs":[{"code":"440103","name":"荔湾区"},{"code":"440104","name":"越秀区"},{"code":"440105","name":"海珠区"},{"code":"440106","name":"天河区"},{"code":"440111","name":"白云区"},{"code":"440112","name":"黄埔区"},{"code":"440113","name":"番禺区"},{"code":"440114","name":"花都区"},{"code":"440115","name":"南沙区"},{"code":"440117","name":"从化区"},{"code":"440118","name":"增城区"}]},{"code":"4402","name":"韶关市","childs":[{"code":"440203","name":"武江区"},{"code":"440204","name":"浈江区"},{"code":"440205","name":"曲江区"},{"code":"440222","name":"始兴县"},{"code":"440224","name":"仁化县"},{"code":"440229","name":"翁源县"},{"code":"440232","name":"乳源瑶族自治县"},{"code":"440233","name":"新丰县"},{"code":"440281","name":"乐昌市"},{"code":"440282","name":"南雄市"}]},{"code":"4403","name":"深圳市","childs":[{"code":"440303","name":"罗湖区"},{"code":"440304","name":"福田区"},{"code":"440305","name":"南山区"},{"code":"440306","name":"宝安区"},{"code":"440307","name":"龙岗区"},{"code":"440308","name":"盐田区"}]},{"code":"4404","name":"珠海市","childs":[{"code":"440402","name":"香洲区"},{"code":"440403","name":"斗门区"},{"code":"440404","name":"金湾区"}]},{"code":"4405","name":"汕头市","childs":[{"code":"440507","name":"龙湖区"},{"code":"440511","name":"金平区"},{"code":"440512","name":"濠江区"},{"code":"440513","name":"潮阳区"},{"code":"440514","name":"潮南区"},{"code":"440515","name":"澄海区"},{"code":"440523","name":"南澳县"}]},{"code":"4406","name":"佛山市","childs":[{"code":"440604","name":"禅城区"},{"code":"440605","name":"南海区"},{"code":"440606","name":"顺德区"},{"code":"440607","name":"三水区"},{"code":"440608","name":"高明区"}]},{"code":"4407","name":"江门市","childs":[{"code":"440703","name":"蓬江区"},{"code":"440704","name":"江海区"},{"code":"440705","name":"新会区"},{"code":"440781","name":"台山市"},{"code":"440783","name":"开平市"},{"code":"440784","name":"鹤山市"},{"code":"440785","name":"恩平市"}]},{"code":"4408","name":"湛江市","childs":[{"code":"440802","name":"赤坎区"},{"code":"440803","name":"霞山区"},{"code":"440804","name":"坡头区"},{"code":"440811","name":"麻章区"},{"code":"440823","name":"遂溪县"},{"code":"440825","name":"徐闻县"},{"code":"440881","name":"廉江市"},{"code":"440882","name":"雷州市"},{"code":"440883","name":"吴川市"}]},{"code":"4409","name":"茂名市","childs":[{"code":"440902","name":"茂南区"},{"code":"440904","name":"电白区"},{"code":"440981","name":"高州市"},{"code":"440982","name":"化州市"},{"code":"440983","name":"信宜市"}]},{"code":"4412","name":"肇庆市","childs":[{"code":"441202","name":"端州区"},{"code":"441203","name":"鼎湖区"},{"code":"441204","name":"高要区"},{"code":"441223","name":"广宁县"},{"code":"441224","name":"怀集县"},{"code":"441225","name":"封开县"},{"code":"441226","name":"德庆县"},{"code":"441284","name":"四会市"}]},{"code":"4413","name":"惠州市","childs":[{"code":"441302","name":"惠城区"},{"code":"441303","name":"惠阳区"},{"code":"441322","name":"博罗县"},{"code":"441323","name":"惠东县"},{"code":"441324","name":"龙门县"}]},{"code":"4414","name":"梅州市","childs":[{"code":"441402","name":"梅江区"},{"code":"441403","name":"梅县区"},{"code":"441422","name":"大埔县"},{"code":"441423","name":"丰顺县"},{"code":"441424","name":"五华县"},{"code":"441426","name":"平远县"},{"code":"441427","name":"蕉岭县"},{"code":"441481","name":"兴宁市"}]},{"code":"4415","name":"汕尾市","childs":[{"code":"441502","name":"城区"},{"code":"441521","name":"海丰县"},{"code":"441523","name":"陆河县"},{"code":"441581","name":"陆丰市"}]},{"code":"4416","name":"河源市","childs":[{"code":"441602","name":"源城区"},{"code":"441621","name":"紫金县"},{"code":"441622","name":"龙川县"},{"code":"441623","name":"连平县"},{"code":"441624","name":"和平县"},{"code":"441625","name":"东源县"}]},{"code":"4417","name":"阳江市","childs":[{"code":"441702","name":"江城区"},{"code":"441704","name":"阳东区"},{"code":"441721","name":"阳西县"},{"code":"441781","name":"阳春市"}]},{"code":"4418","name":"清远市","childs":[{"code":"441802","name":"清城区"},{"code":"441803","name":"清新区"},{"code":"441821","name":"佛冈县"},{"code":"441823","name":"阳山县"},{"code":"441825","name":"连山壮族瑶族自治县"},{"code":"441826","name":"连南瑶族自治县"},{"code":"441881","name":"英德市"},{"code":"441882","name":"连州市"}]},{"code":"441900","name":"东莞市","childs":[{"code":"441900003","name":"东城街道办事处"},{"code":"441900004","name":"南城街道办事处"},{"code":"441900005","name":"万江街道办事处"},{"code":"441900006","name":"莞城街道办事处"},{"code":"441900101","name":"石碣镇"},{"code":"441900102","name":"石龙镇"},{"code":"441900103","name":"茶山镇"},{"code":"441900104","name":"石排镇"},{"code":"441900105","name":"企石镇"},{"code":"441900106","name":"横沥镇"},{"code":"441900107","name":"桥头镇"},{"code":"441900108","name":"谢岗镇"},{"code":"441900109","name":"东坑镇"},{"code":"441900110","name":"常平镇"},{"code":"441900111","name":"寮步镇"},{"code":"441900112","name":"樟木头镇"},{"code":"441900113","name":"大朗镇"},{"code":"441900114","name":"黄江镇"},{"code":"441900115","name":"清溪镇"},{"code":"441900116","name":"塘厦镇"},{"code":"441900117","name":"凤岗镇"},{"code":"441900118","name":"大岭山镇"},{"code":"441900119","name":"长安镇"},{"code":"441900121","name":"虎门镇"},{"code":"441900122","name":"厚街镇"},{"code":"441900123","name":"沙田镇"},{"code":"441900124","name":"道滘镇"},{"code":"441900125","name":"洪梅镇"},{"code":"441900126","name":"麻涌镇"},{"code":"441900127","name":"望牛墩镇"},{"code":"441900128","name":"中堂镇"},{"code":"441900129","name":"高埗镇"},{"code":"441900401","name":"松山湖管委会"},{"code":"441900402","name":"虎门港管委会"},{"code":"441900403","name":"东莞生态园"}]},{"code":"442000","name":"中山市","childs":[{"code":"442000001","name":"石岐区街道办事处"},{"code":"442000002","name":"东区街道办事处"},{"code":"442000003","name":"火炬开发区街道办事处"},{"code":"442000004","name":"西区街道办事处"},{"code":"442000005","name":"南区街道办事处"},{"code":"442000006","name":"五桂山街道办事处"},{"code":"442000100","name":"小榄镇"},{"code":"442000101","name":"黄圃镇"},{"code":"442000102","name":"民众镇"},{"code":"442000103","name":"东凤镇"},{"code":"442000104","name":"东升镇"},{"code":"442000105","name":"古镇镇"},{"code":"442000106","name":"沙溪镇"},{"code":"442000107","name":"坦洲镇"},{"code":"442000108","name":"港口镇"},{"code":"442000109","name":"三角镇"},{"code":"442000110","name":"横栏镇"},{"code":"442000111","name":"南头镇"},{"code":"442000112","name":"阜沙镇"},{"code":"442000113","name":"南朗镇"},{"code":"442000114","name":"三乡镇"},{"code":"442000115","name":"板芙镇"},{"code":"442000116","name":"大涌镇"},{"code":"442000117","name":"神湾镇"}]},{"code":"4451","name":"潮州市","childs":[{"code":"445102","name":"湘桥区"},{"code":"445103","name":"潮安区"},{"code":"445122","name":"饶平县"}]},{"code":"4452","name":"揭阳市","childs":[{"code":"445202","name":"榕城区"},{"code":"445203","name":"揭东区"},{"code":"445222","name":"揭西县"},{"code":"445224","name":"惠来县"},{"code":"445281","name":"普宁市"}]},{"code":"4453","name":"云浮市","childs":[{"code":"445302","name":"云城区"},{"code":"445303","name":"云安区"},{"code":"445321","name":"新兴县"},{"code":"445322","name":"郁南县"},{"code":"445381","name":"罗定市"}]}]},{"code":"45","name":"广西壮族自治区","childs":[{"code":"4501","name":"南宁市","childs":[{"code":"450102","name":"兴宁区"},{"code":"450103","name":"青秀区"},{"code":"450105","name":"江南区"},{"code":"450107","name":"西乡塘区"},{"code":"450108","name":"良庆区"},{"code":"450109","name":"邕宁区"},{"code":"450110","name":"武鸣区"},{"code":"450123","name":"隆安县"},{"code":"450124","name":"马山县"},{"code":"450125","name":"上林县"},{"code":"450126","name":"宾阳县"},{"code":"450127","name":"横县"}]},{"code":"4502","name":"柳州市","childs":[{"code":"450202","name":"城中区"},{"code":"450203","name":"鱼峰区"},{"code":"450204","name":"柳南区"},{"code":"450205","name":"柳北区"},{"code":"450206","name":"柳江区"},{"code":"450222","name":"柳城县"},{"code":"450223","name":"鹿寨县"},{"code":"450224","name":"融安县"},{"code":"450225","name":"融水苗族自治县"},{"code":"450226","name":"三江侗族自治县"}]},{"code":"4503","name":"桂林市","childs":[{"code":"450302","name":"秀峰区"},{"code":"450303","name":"叠彩区"},{"code":"450304","name":"象山区"},{"code":"450305","name":"七星区"},{"code":"450311","name":"雁山区"},{"code":"450312","name":"临桂区"},{"code":"450321","name":"阳朔县"},{"code":"450323","name":"灵川县"},{"code":"450324","name":"全州县"},{"code":"450325","name":"兴安县"},{"code":"450326","name":"永福县"},{"code":"450327","name":"灌阳县"},{"code":"450328","name":"龙胜各族自治县"},{"code":"450329","name":"资源县"},{"code":"450330","name":"平乐县"},{"code":"450331","name":"荔浦县"},{"code":"450332","name":"恭城瑶族自治县"}]},{"code":"4504","name":"梧州市","childs":[{"code":"450403","name":"万秀区"},{"code":"450405","name":"长洲区"},{"code":"450406","name":"龙圩区"},{"code":"450421","name":"苍梧县"},{"code":"450422","name":"藤县"},{"code":"450423","name":"蒙山县"},{"code":"450481","name":"岑溪市"}]},{"code":"4505","name":"北海市","childs":[{"code":"450502","name":"海城区"},{"code":"450503","name":"银海区"},{"code":"450512","name":"铁山港区"},{"code":"450521","name":"合浦县"}]},{"code":"4506","name":"防城港市","childs":[{"code":"450602","name":"港口区"},{"code":"450603","name":"防城区"},{"code":"450621","name":"上思县"},{"code":"450681","name":"东兴市"}]},{"code":"4507","name":"钦州市","childs":[{"code":"450702","name":"钦南区"},{"code":"450703","name":"钦北区"},{"code":"450721","name":"灵山县"},{"code":"450722","name":"浦北县"}]},{"code":"4508","name":"贵港市","childs":[{"code":"450802","name":"港北区"},{"code":"450803","name":"港南区"},{"code":"450804","name":"覃塘区"},{"code":"450821","name":"平南县"},{"code":"450881","name":"桂平市"}]},{"code":"4509","name":"玉林市","childs":[{"code":"450902","name":"玉州区"},{"code":"450903","name":"福绵区"},{"code":"450921","name":"容县"},{"code":"450922","name":"陆川县"},{"code":"450923","name":"博白县"},{"code":"450924","name":"兴业县"},{"code":"450981","name":"北流市"}]},{"code":"4510","name":"百色市","childs":[{"code":"451002","name":"右江区"},{"code":"451021","name":"田阳县"},{"code":"451022","name":"田东县"},{"code":"451023","name":"平果县"},{"code":"451024","name":"德保县"},{"code":"451026","name":"那坡县"},{"code":"451027","name":"凌云县"},{"code":"451028","name":"乐业县"},{"code":"451029","name":"田林县"},{"code":"451030","name":"西林县"},{"code":"451031","name":"隆林各族自治县"},{"code":"451081","name":"靖西市"}]},{"code":"4511","name":"贺州市","childs":[{"code":"451102","name":"八步区"},{"code":"451103","name":"平桂区"},{"code":"451121","name":"昭平县"},{"code":"451122","name":"钟山县"},{"code":"451123","name":"富川瑶族自治县"}]},{"code":"4512","name":"河池市","childs":[{"code":"451202","name":"金城江区"},{"code":"451221","name":"南丹县"},{"code":"451222","name":"天峨县"},{"code":"451223","name":"凤山县"},{"code":"451224","name":"东兰县"},{"code":"451225","name":"罗城仫佬族自治县"},{"code":"451226","name":"环江毛南族自治县"},{"code":"451227","name":"巴马瑶族自治县"},{"code":"451228","name":"都安瑶族自治县"},{"code":"451229","name":"大化瑶族自治县"},{"code":"451281","name":"宜州市"}]},{"code":"4513","name":"来宾市","childs":[{"code":"451302","name":"兴宾区"},{"code":"451321","name":"忻城县"},{"code":"451322","name":"象州县"},{"code":"451323","name":"武宣县"},{"code":"451324","name":"金秀瑶族自治县"},{"code":"451381","name":"合山市"}]},{"code":"4514","name":"崇左市","childs":[{"code":"451402","name":"江州区"},{"code":"451421","name":"扶绥县"},{"code":"451422","name":"宁明县"},{"code":"451423","name":"龙州县"},{"code":"451424","name":"大新县"},{"code":"451425","name":"天等县"},{"code":"451481","name":"凭祥市"}]}]},{"code":"46","name":"海南省","childs":[{"code":"4601","name":"海口市","childs":[{"code":"460105","name":"秀英区"},{"code":"460106","name":"龙华区"},{"code":"460107","name":"琼山区"},{"code":"460108","name":"美兰区"}]},{"code":"4602","name":"三亚市","childs":[{"code":"460202","name":"海棠区"},{"code":"460203","name":"吉阳区"},{"code":"460204","name":"天涯区"},{"code":"460205","name":"崖州区"}]},{"code":"4603","name":"三沙市","childs":[{"code":"460321","name":"西沙群岛"},{"code":"460322","name":"南沙群岛"},{"code":"460323","name":"中沙群岛的岛礁及其海域"}]},{"code":"460400","name":"儋州市","childs":[{"code":"460400100","name":"那大镇"},{"code":"460400101","name":"和庆镇"},{"code":"460400102","name":"南丰镇"},{"code":"460400103","name":"大成镇"},{"code":"460400104","name":"雅星镇"},{"code":"460400105","name":"兰洋镇"},{"code":"460400106","name":"光村镇"},{"code":"460400107","name":"木棠镇"},{"code":"460400108","name":"海头镇"},{"code":"460400109","name":"峨蔓镇"},{"code":"460400110","name":"三都镇"},{"code":"460400111","name":"王五镇"},{"code":"460400112","name":"白马井镇"},{"code":"460400113","name":"中和镇"},{"code":"460400114","name":"排浦镇"},{"code":"460400115","name":"东成镇"},{"code":"460400116","name":"新州镇"},{"code":"460400400","name":"国营西培农场"},{"code":"460400404","name":"国营西联农场"},{"code":"460400405","name":"国营蓝洋农场"},{"code":"460400407","name":"国营八一农场"},{"code":"460400499","name":"洋浦经济开发区"},{"code":"460400500","name":"华南热作学院"}]},{"code":"4690","name":"省直辖县级行政区划","childs":[{"code":"469001","name":"五指山市"},{"code":"469002","name":"琼海市"},{"code":"469005","name":"文昌市"},{"code":"469006","name":"万宁市"},{"code":"469007","name":"东方市"},{"code":"469021","name":"定安县"},{"code":"469022","name":"屯昌县"},{"code":"469023","name":"澄迈县"},{"code":"469024","name":"临高县"},{"code":"469025","name":"白沙黎族自治县"},{"code":"469026","name":"昌江黎族自治县"},{"code":"469027","name":"乐东黎族自治县"},{"code":"469028","name":"陵水黎族自治县"},{"code":"469029","name":"保亭黎族苗族自治县"},{"code":"469030","name":"琼中黎族苗族自治县"}]}]},{"code":"50","name":"重庆市","childs":[{"code":"5001","name":"市辖区","childs":[{"code":"500101","name":"万州区"},{"code":"500102","name":"涪陵区"},{"code":"500103","name":"渝中区"},{"code":"500104","name":"大渡口区"},{"code":"500105","name":"江北区"},{"code":"500106","name":"沙坪坝区"},{"code":"500107","name":"九龙坡区"},{"code":"500108","name":"南岸区"},{"code":"500109","name":"北碚区"},{"code":"500110","name":"綦江区"},{"code":"500111","name":"大足区"},{"code":"500112","name":"渝北区"},{"code":"500113","name":"巴南区"},{"code":"500114","name":"黔江区"},{"code":"500115","name":"长寿区"},{"code":"500116","name":"江津区"},{"code":"500117","name":"合川区"},{"code":"500118","name":"永川区"},{"code":"500119","name":"南川区"},{"code":"500120","name":"璧山区"},{"code":"500151","name":"铜梁区"},{"code":"500152","name":"潼南区"},{"code":"500153","name":"荣昌区"},{"code":"500154","name":"开州区"}]},{"code":"5002","name":"县","childs":[{"code":"500228","name":"梁平县"},{"code":"500229","name":"城口县"},{"code":"500230","name":"丰都县"},{"code":"500231","name":"垫江县"},{"code":"500232","name":"武隆县"},{"code":"500233","name":"忠县"},{"code":"500235","name":"云阳县"},{"code":"500236","name":"奉节县"},{"code":"500237","name":"巫山县"},{"code":"500238","name":"巫溪县"},{"code":"500240","name":"石柱土家族自治县"},{"code":"500241","name":"秀山土家族苗族自治县"},{"code":"500242","name":"酉阳土家族苗族自治县"},{"code":"500243","name":"彭水苗族土家族自治县"}]}]},{"code":"51","name":"四川省","childs":[{"code":"5101","name":"成都市","childs":[{"code":"510104","name":"锦江区"},{"code":"510105","name":"青羊区"},{"code":"510106","name":"金牛区"},{"code":"510107","name":"武侯区"},{"code":"510108","name":"成华区"},{"code":"510112","name":"龙泉驿区"},{"code":"510113","name":"青白江区"},{"code":"510114","name":"新都区"},{"code":"510115","name":"温江区"},{"code":"510116","name":"双流区"},{"code":"510121","name":"金堂县"},{"code":"510124","name":"郫县"},{"code":"510129","name":"大邑县"},{"code":"510131","name":"蒲江县"},{"code":"510132","name":"新津县"},{"code":"510181","name":"都江堰市"},{"code":"510182","name":"彭州市"},{"code":"510183","name":"邛崃市"},{"code":"510184","name":"崇州市"},{"code":"510185","name":"简阳市"}]},{"code":"5103","name":"自贡市","childs":[{"code":"510302","name":"自流井区"},{"code":"510303","name":"贡井区"},{"code":"510304","name":"大安区"},{"code":"510311","name":"沿滩区"},{"code":"510321","name":"荣县"},{"code":"510322","name":"富顺县"}]},{"code":"5104","name":"攀枝花市","childs":[{"code":"510402","name":"东区"},{"code":"510403","name":"西区"},{"code":"510411","name":"仁和区"},{"code":"510421","name":"米易县"},{"code":"510422","name":"盐边县"}]},{"code":"5105","name":"泸州市","childs":[{"code":"510502","name":"江阳区"},{"code":"510503","name":"纳溪区"},{"code":"510504","name":"龙马潭区"},{"code":"510521","name":"泸县"},{"code":"510522","name":"合江县"},{"code":"510524","name":"叙永县"},{"code":"510525","name":"古蔺县"}]},{"code":"5106","name":"德阳市","childs":[{"code":"510603","name":"旌阳区"},{"code":"510623","name":"中江县"},{"code":"510626","name":"罗江县"},{"code":"510681","name":"广汉市"},{"code":"510682","name":"什邡市"},{"code":"510683","name":"绵竹市"}]},{"code":"5107","name":"绵阳市","childs":[{"code":"510703","name":"涪城区"},{"code":"510704","name":"游仙区"},{"code":"510705","name":"安州区"},{"code":"510722","name":"三台县"},{"code":"510723","name":"盐亭县"},{"code":"510725","name":"梓潼县"},{"code":"510726","name":"北川羌族自治县"},{"code":"510727","name":"平武县"},{"code":"510781","name":"江油市"}]},{"code":"5108","name":"广元市","childs":[{"code":"510802","name":"利州区"},{"code":"510811","name":"昭化区"},{"code":"510812","name":"朝天区"},{"code":"510821","name":"旺苍县"},{"code":"510822","name":"青川县"},{"code":"510823","name":"剑阁县"},{"code":"510824","name":"苍溪县"}]},{"code":"5109","name":"遂宁市","childs":[{"code":"510903","name":"船山区"},{"code":"510904","name":"安居区"},{"code":"510921","name":"蓬溪县"},{"code":"510922","name":"射洪县"},{"code":"510923","name":"大英县"}]},{"code":"5110","name":"内江市","childs":[{"code":"511002","name":"市中区"},{"code":"511011","name":"东兴区"},{"code":"511024","name":"威远县"},{"code":"511025","name":"资中县"},{"code":"511028","name":"隆昌县"}]},{"code":"5111","name":"乐山市","childs":[{"code":"511102","name":"市中区"},{"code":"511111","name":"沙湾区"},{"code":"511112","name":"五通桥区"},{"code":"511113","name":"金口河区"},{"code":"511123","name":"犍为县"},{"code":"511124","name":"井研县"},{"code":"511126","name":"夹江县"},{"code":"511129","name":"沐川县"},{"code":"511132","name":"峨边彝族自治县"},{"code":"511133","name":"马边彝族自治县"},{"code":"511181","name":"峨眉山市"}]},{"code":"5113","name":"南充市","childs":[{"code":"511302","name":"顺庆区"},{"code":"511303","name":"高坪区"},{"code":"511304","name":"嘉陵区"},{"code":"511321","name":"南部县"},{"code":"511322","name":"营山县"},{"code":"511323","name":"蓬安县"},{"code":"511324","name":"仪陇县"},{"code":"511325","name":"西充县"},{"code":"511381","name":"阆中市"}]},{"code":"5114","name":"眉山市","childs":[{"code":"511402","name":"东坡区"},{"code":"511403","name":"彭山区"},{"code":"511421","name":"仁寿县"},{"code":"511423","name":"洪雅县"},{"code":"511424","name":"丹棱县"},{"code":"511425","name":"青神县"}]},{"code":"5115","name":"宜宾市","childs":[{"code":"511502","name":"翠屏区"},{"code":"511503","name":"南溪区"},{"code":"511521","name":"宜宾县"},{"code":"511523","name":"江安县"},{"code":"511524","name":"长宁县"},{"code":"511525","name":"高县"},{"code":"511526","name":"珙县"},{"code":"511527","name":"筠连县"},{"code":"511528","name":"兴文县"},{"code":"511529","name":"屏山县"}]},{"code":"5116","name":"广安市","childs":[{"code":"511602","name":"广安区"},{"code":"511603","name":"前锋区"},{"code":"511621","name":"岳池县"},{"code":"511622","name":"武胜县"},{"code":"511623","name":"邻水县"},{"code":"511681","name":"华蓥市"}]},{"code":"5117","name":"达州市","childs":[{"code":"511702","name":"通川区"},{"code":"511703","name":"达川区"},{"code":"511722","name":"宣汉县"},{"code":"511723","name":"开江县"},{"code":"511724","name":"大竹县"},{"code":"511725","name":"渠县"},{"code":"511781","name":"万源市"}]},{"code":"5118","name":"雅安市","childs":[{"code":"511802","name":"雨城区"},{"code":"511803","name":"名山区"},{"code":"511822","name":"荥经县"},{"code":"511823","name":"汉源县"},{"code":"511824","name":"石棉县"},{"code":"511825","name":"天全县"},{"code":"511826","name":"芦山县"},{"code":"511827","name":"宝兴县"}]},{"code":"5119","name":"巴中市","childs":[{"code":"511902","name":"巴州区"},{"code":"511903","name":"恩阳区"},{"code":"511921","name":"通江县"},{"code":"511922","name":"南江县"},{"code":"511923","name":"平昌县"}]},{"code":"5120","name":"资阳市","childs":[{"code":"512002","name":"雁江区"},{"code":"512021","name":"安岳县"},{"code":"512022","name":"乐至县"}]},{"code":"5132","name":"阿坝藏族羌族自治州","childs":[{"code":"513201","name":"马尔康市"},{"code":"513221","name":"汶川县"},{"code":"513222","name":"理县"},{"code":"513223","name":"茂县"},{"code":"513224","name":"松潘县"},{"code":"513225","name":"九寨沟县"},{"code":"513226","name":"金川县"},{"code":"513227","name":"小金县"},{"code":"513228","name":"黑水县"},{"code":"513230","name":"壤塘县"},{"code":"513231","name":"阿坝县"},{"code":"513232","name":"若尔盖县"},{"code":"513233","name":"红原县"}]},{"code":"5133","name":"甘孜藏族自治州","childs":[{"code":"513301","name":"康定市"},{"code":"513322","name":"泸定县"},{"code":"513323","name":"丹巴县"},{"code":"513324","name":"九龙县"},{"code":"513325","name":"雅江县"},{"code":"513326","name":"道孚县"},{"code":"513327","name":"炉霍县"},{"code":"513328","name":"甘孜县"},{"code":"513329","name":"新龙县"},{"code":"513330","name":"德格县"},{"code":"513331","name":"白玉县"},{"code":"513332","name":"石渠县"},{"code":"513333","name":"色达县"},{"code":"513334","name":"理塘县"},{"code":"513335","name":"巴塘县"},{"code":"513336","name":"乡城县"},{"code":"513337","name":"稻城县"},{"code":"513338","name":"得荣县"}]},{"code":"5134","name":"凉山彝族自治州","childs":[{"code":"513401","name":"西昌市"},{"code":"513422","name":"木里藏族自治县"},{"code":"513423","name":"盐源县"},{"code":"513424","name":"德昌县"},{"code":"513425","name":"会理县"},{"code":"513426","name":"会东县"},{"code":"513427","name":"宁南县"},{"code":"513428","name":"普格县"},{"code":"513429","name":"布拖县"},{"code":"513430","name":"金阳县"},{"code":"513431","name":"昭觉县"},{"code":"513432","name":"喜德县"},{"code":"513433","name":"冕宁县"},{"code":"513434","name":"越西县"},{"code":"513435","name":"甘洛县"},{"code":"513436","name":"美姑县"},{"code":"513437","name":"雷波县"}]}]},{"code":"52","name":"贵州省","childs":[{"code":"5201","name":"贵阳市","childs":[{"code":"520102","name":"南明区"},{"code":"520103","name":"云岩区"},{"code":"520111","name":"花溪区"},{"code":"520112","name":"乌当区"},{"code":"520113","name":"白云区"},{"code":"520115","name":"观山湖区"},{"code":"520121","name":"开阳县"},{"code":"520122","name":"息烽县"},{"code":"520123","name":"修文县"},{"code":"520181","name":"清镇市"}]},{"code":"5202","name":"六盘水市","childs":[{"code":"520201","name":"钟山区"},{"code":"520203","name":"六枝特区"},{"code":"520221","name":"水城县"},{"code":"520222","name":"盘县"}]},{"code":"5203","name":"遵义市","childs":[{"code":"520302","name":"红花岗区"},{"code":"520303","name":"汇川区"},{"code":"520304","name":"播州区"},{"code":"520322","name":"桐梓县"},{"code":"520323","name":"绥阳县"},{"code":"520324","name":"正安县"},{"code":"520325","name":"道真仡佬族苗族自治县"},{"code":"520326","name":"务川仡佬族苗族自治县"},{"code":"520327","name":"凤冈县"},{"code":"520328","name":"湄潭县"},{"code":"520329","name":"余庆县"},{"code":"520330","name":"习水县"},{"code":"520381","name":"赤水市"},{"code":"520382","name":"仁怀市"}]},{"code":"5204","name":"安顺市","childs":[{"code":"520402","name":"西秀区"},{"code":"520403","name":"平坝区"},{"code":"520422","name":"普定县"},{"code":"520423","name":"镇宁布依族苗族自治县"},{"code":"520424","name":"关岭布依族苗族自治县"},{"code":"520425","name":"紫云苗族布依族自治县"}]},{"code":"5205","name":"毕节市","childs":[{"code":"520502","name":"七星关区"},{"code":"520521","name":"大方县"},{"code":"520522","name":"黔西县"},{"code":"520523","name":"金沙县"},{"code":"520524","name":"织金县"},{"code":"520525","name":"纳雍县"},{"code":"520526","name":"威宁彝族回族苗族自治县"},{"code":"520527","name":"赫章县"}]},{"code":"5206","name":"铜仁市","childs":[{"code":"520602","name":"碧江区"},{"code":"520603","name":"万山区"},{"code":"520621","name":"江口县"},{"code":"520622","name":"玉屏侗族自治县"},{"code":"520623","name":"石阡县"},{"code":"520624","name":"思南县"},{"code":"520625","name":"印江土家族苗族自治县"},{"code":"520626","name":"德江县"},{"code":"520627","name":"沿河土家族自治县"},{"code":"520628","name":"松桃苗族自治县"}]},{"code":"5223","name":"黔西南布依族苗族自治州","childs":[{"code":"522301","name":"兴义市"},{"code":"522322","name":"兴仁县"},{"code":"522323","name":"普安县"},{"code":"522324","name":"晴隆县"},{"code":"522325","name":"贞丰县"},{"code":"522326","name":"望谟县"},{"code":"522327","name":"册亨县"},{"code":"522328","name":"安龙县"}]},{"code":"5226","name":"黔东南苗族侗族自治州","childs":[{"code":"522601","name":"凯里市"},{"code":"522622","name":"黄平县"},{"code":"522623","name":"施秉县"},{"code":"522624","name":"三穗县"},{"code":"522625","name":"镇远县"},{"code":"522626","name":"岑巩县"},{"code":"522627","name":"天柱县"},{"code":"522628","name":"锦屏县"},{"code":"522629","name":"剑河县"},{"code":"522630","name":"台江县"},{"code":"522631","name":"黎平县"},{"code":"522632","name":"榕江县"},{"code":"522633","name":"从江县"},{"code":"522634","name":"雷山县"},{"code":"522635","name":"麻江县"},{"code":"522636","name":"丹寨县"}]},{"code":"5227","name":"黔南布依族苗族自治州","childs":[{"code":"522701","name":"都匀市"},{"code":"522702","name":"福泉市"},{"code":"522722","name":"荔波县"},{"code":"522723","name":"贵定县"},{"code":"522725","name":"瓮安县"},{"code":"522726","name":"独山县"},{"code":"522727","name":"平塘县"},{"code":"522728","name":"罗甸县"},{"code":"522729","name":"长顺县"},{"code":"522730","name":"龙里县"},{"code":"522731","name":"惠水县"},{"code":"522732","name":"三都水族自治县"}]}]},{"code":"53","name":"云南省","childs":[{"code":"5301","name":"昆明市","childs":[{"code":"530102","name":"五华区"},{"code":"530103","name":"盘龙区"},{"code":"530111","name":"官渡区"},{"code":"530112","name":"西山区"},{"code":"530113","name":"东川区"},{"code":"530114","name":"呈贡区"},{"code":"530122","name":"晋宁县"},{"code":"530124","name":"富民县"},{"code":"530125","name":"宜良县"},{"code":"530126","name":"石林彝族自治县"},{"code":"530127","name":"嵩明县"},{"code":"530128","name":"禄劝彝族苗族自治县"},{"code":"530129","name":"寻甸回族彝族自治县"},{"code":"530181","name":"安宁市"}]},{"code":"5303","name":"曲靖市","childs":[{"code":"530302","name":"麒麟区"},{"code":"530303","name":"沾益区"},{"code":"530321","name":"马龙县"},{"code":"530322","name":"陆良县"},{"code":"530323","name":"师宗县"},{"code":"530324","name":"罗平县"},{"code":"530325","name":"富源县"},{"code":"530326","name":"会泽县"},{"code":"530381","name":"宣威市"}]},{"code":"5304","name":"玉溪市","childs":[{"code":"530402","name":"红塔区"},{"code":"530403","name":"江川区"},{"code":"530422","name":"澄江县"},{"code":"530423","name":"通海县"},{"code":"530424","name":"华宁县"},{"code":"530425","name":"易门县"},{"code":"530426","name":"峨山彝族自治县"},{"code":"530427","name":"新平彝族傣族自治县"},{"code":"530428","name":"元江哈尼族彝族傣族自治县"}]},{"code":"5305","name":"保山市","childs":[{"code":"530502","name":"隆阳区"},{"code":"530521","name":"施甸县"},{"code":"530523","name":"龙陵县"},{"code":"530524","name":"昌宁县"},{"code":"530581","name":"腾冲市"}]},{"code":"5306","name":"昭通市","childs":[{"code":"530602","name":"昭阳区"},{"code":"530621","name":"鲁甸县"},{"code":"530622","name":"巧家县"},{"code":"530623","name":"盐津县"},{"code":"530624","name":"大关县"},{"code":"530625","name":"永善县"},{"code":"530626","name":"绥江县"},{"code":"530627","name":"镇雄县"},{"code":"530628","name":"彝良县"},{"code":"530629","name":"威信县"},{"code":"530630","name":"水富县"}]},{"code":"5307","name":"丽江市","childs":[{"code":"530702","name":"古城区"},{"code":"530721","name":"玉龙纳西族自治县"},{"code":"530722","name":"永胜县"},{"code":"530723","name":"华坪县"},{"code":"530724","name":"宁蒗彝族自治县"}]},{"code":"5308","name":"普洱市","childs":[{"code":"530802","name":"思茅区"},{"code":"530821","name":"宁洱哈尼族彝族自治县"},{"code":"530822","name":"墨江哈尼族自治县"},{"code":"530823","name":"景东彝族自治县"},{"code":"530824","name":"景谷傣族彝族自治县"},{"code":"530825","name":"镇沅彝族哈尼族拉祜族自治县"},{"code":"530826","name":"江城哈尼族彝族自治县"},{"code":"530827","name":"孟连傣族拉祜族佤族自治县"},{"code":"530828","name":"澜沧拉祜族自治县"},{"code":"530829","name":"西盟佤族自治县"}]},{"code":"5309","name":"临沧市","childs":[{"code":"530902","name":"临翔区"},{"code":"530921","name":"凤庆县"},{"code":"530922","name":"云县"},{"code":"530923","name":"永德县"},{"code":"530924","name":"镇康县"},{"code":"530925","name":"双江拉祜族佤族布朗族傣族自治县"},{"code":"530926","name":"耿马傣族佤族自治县"},{"code":"530927","name":"沧源佤族自治县"}]},{"code":"5323","name":"楚雄彝族自治州","childs":[{"code":"532301","name":"楚雄市"},{"code":"532322","name":"双柏县"},{"code":"532323","name":"牟定县"},{"code":"532324","name":"南华县"},{"code":"532325","name":"姚安县"},{"code":"532326","name":"大姚县"},{"code":"532327","name":"永仁县"},{"code":"532328","name":"元谋县"},{"code":"532329","name":"武定县"},{"code":"532331","name":"禄丰县"}]},{"code":"5325","name":"红河哈尼族彝族自治州","childs":[{"code":"532501","name":"个旧市"},{"code":"532502","name":"开远市"},{"code":"532503","name":"蒙自市"},{"code":"532504","name":"弥勒市"},{"code":"532523","name":"屏边苗族自治县"},{"code":"532524","name":"建水县"},{"code":"532525","name":"石屏县"},{"code":"532527","name":"泸西县"},{"code":"532528","name":"元阳县"},{"code":"532529","name":"红河县"},{"code":"532530","name":"金平苗族瑶族傣族自治县"},{"code":"532531","name":"绿春县"},{"code":"532532","name":"河口瑶族自治县"}]},{"code":"5326","name":"文山壮族苗族自治州","childs":[{"code":"532601","name":"文山市"},{"code":"532622","name":"砚山县"},{"code":"532623","name":"西畴县"},{"code":"532624","name":"麻栗坡县"},{"code":"532625","name":"马关县"},{"code":"532626","name":"丘北县"},{"code":"532627","name":"广南县"},{"code":"532628","name":"富宁县"}]},{"code":"5328","name":"西双版纳傣族自治州","childs":[{"code":"532801","name":"景洪市"},{"code":"532822","name":"勐海县"},{"code":"532823","name":"勐腊县"}]},{"code":"5329","name":"大理白族自治州","childs":[{"code":"532901","name":"大理市"},{"code":"532922","name":"漾濞彝族自治县"},{"code":"532923","name":"祥云县"},{"code":"532924","name":"宾川县"},{"code":"532925","name":"弥渡县"},{"code":"532926","name":"南涧彝族自治县"},{"code":"532927","name":"巍山彝族回族自治县"},{"code":"532928","name":"永平县"},{"code":"532929","name":"云龙县"},{"code":"532930","name":"洱源县"},{"code":"532931","name":"剑川县"},{"code":"532932","name":"鹤庆县"}]},{"code":"5331","name":"德宏傣族景颇族自治州","childs":[{"code":"533102","name":"瑞丽市"},{"code":"533103","name":"芒市"},{"code":"533122","name":"梁河县"},{"code":"533123","name":"盈江县"},{"code":"533124","name":"陇川县"}]},{"code":"5333","name":"怒江傈僳族自治州","childs":[{"code":"533301","name":"泸水市"},{"code":"533323","name":"福贡县"},{"code":"533324","name":"贡山独龙族怒族自治县"},{"code":"533325","name":"兰坪白族普米族自治县"}]},{"code":"5334","name":"迪庆藏族自治州","childs":[{"code":"533401","name":"香格里拉市"},{"code":"533422","name":"德钦县"},{"code":"533423","name":"维西傈僳族自治县"}]}]},{"code":"54","name":"西藏自治区","childs":[{"code":"5401","name":"拉萨市","childs":[{"code":"540102","name":"城关区"},{"code":"540103","name":"堆龙德庆区"},{"code":"540121","name":"林周县"},{"code":"540122","name":"当雄县"},{"code":"540123","name":"尼木县"},{"code":"540124","name":"曲水县"},{"code":"540126","name":"达孜县"},{"code":"540127","name":"墨竹工卡县"}]},{"code":"5402","name":"日喀则市","childs":[{"code":"540202","name":"桑珠孜区"},{"code":"540221","name":"南木林县"},{"code":"540222","name":"江孜县"},{"code":"540223","name":"定日县"},{"code":"540224","name":"萨迦县"},{"code":"540225","name":"拉孜县"},{"code":"540226","name":"昂仁县"},{"code":"540227","name":"谢通门县"},{"code":"540228","name":"白朗县"},{"code":"540229","name":"仁布县"},{"code":"540230","name":"康马县"},{"code":"540231","name":"定结县"},{"code":"540232","name":"仲巴县"},{"code":"540233","name":"亚东县"},{"code":"540234","name":"吉隆县"},{"code":"540235","name":"聂拉木县"},{"code":"540236","name":"萨嘎县"},{"code":"540237","name":"岗巴县"}]},{"code":"5403","name":"昌都市","childs":[{"code":"540302","name":"卡若区"},{"code":"540321","name":"江达县"},{"code":"540322","name":"贡觉县"},{"code":"540323","name":"类乌齐县"},{"code":"540324","name":"丁青县"},{"code":"540325","name":"察雅县"},{"code":"540326","name":"八宿县"},{"code":"540327","name":"左贡县"},{"code":"540328","name":"芒康县"},{"code":"540329","name":"洛隆县"},{"code":"540330","name":"边坝县"}]},{"code":"5404","name":"林芝市","childs":[{"code":"540402","name":"巴宜区"},{"code":"540421","name":"工布江达县"},{"code":"540422","name":"米林县"},{"code":"540423","name":"墨脱县"},{"code":"540424","name":"波密县"},{"code":"540425","name":"察隅县"},{"code":"540426","name":"朗县"}]},{"code":"5405","name":"山南市","childs":[{"code":"540502","name":"乃东区"},{"code":"540521","name":"扎囊县"},{"code":"540522","name":"贡嘎县"},{"code":"540523","name":"桑日县"},{"code":"540524","name":"琼结县"},{"code":"540525","name":"曲松县"},{"code":"540526","name":"措美县"},{"code":"540527","name":"洛扎县"},{"code":"540528","name":"加查县"},{"code":"540529","name":"隆子县"},{"code":"540530","name":"错那县"},{"code":"540531","name":"浪卡子县"}]},{"code":"5424","name":"那曲地区","childs":[{"code":"542421","name":"那曲县"},{"code":"542422","name":"嘉黎县"},{"code":"542423","name":"比如县"},{"code":"542424","name":"聂荣县"},{"code":"542425","name":"安多县"},{"code":"542426","name":"申扎县"},{"code":"542427","name":"索县"},{"code":"542428","name":"班戈县"},{"code":"542429","name":"巴青县"},{"code":"542430","name":"尼玛县"},{"code":"542431","name":"双湖县"}]},{"code":"5425","name":"阿里地区","childs":[{"code":"542521","name":"普兰县"},{"code":"542522","name":"札达县"},{"code":"542523","name":"噶尔县"},{"code":"542524","name":"日土县"},{"code":"542525","name":"革吉县"},{"code":"542526","name":"改则县"},{"code":"542527","name":"措勤县"}]}]},{"code":"61","name":"陕西省","childs":[{"code":"6101","name":"西安市","childs":[{"code":"610102","name":"新城区"},{"code":"610103","name":"碑林区"},{"code":"610104","name":"莲湖区"},{"code":"610111","name":"灞桥区"},{"code":"610112","name":"未央区"},{"code":"610113","name":"雁塔区"},{"code":"610114","name":"阎良区"},{"code":"610115","name":"临潼区"},{"code":"610116","name":"长安区"},{"code":"610117","name":"高陵区"},{"code":"610122","name":"蓝田县"},{"code":"610124","name":"周至县"},{"code":"610125","name":"户县"}]},{"code":"6102","name":"铜川市","childs":[{"code":"610202","name":"王益区"},{"code":"610203","name":"印台区"},{"code":"610204","name":"耀州区"},{"code":"610222","name":"宜君县"}]},{"code":"6103","name":"宝鸡市","childs":[{"code":"610302","name":"渭滨区"},{"code":"610303","name":"金台区"},{"code":"610304","name":"陈仓区"},{"code":"610322","name":"凤翔县"},{"code":"610323","name":"岐山县"},{"code":"610324","name":"扶风县"},{"code":"610326","name":"眉县"},{"code":"610327","name":"陇县"},{"code":"610328","name":"千阳县"},{"code":"610329","name":"麟游县"},{"code":"610330","name":"凤县"},{"code":"610331","name":"太白县"}]},{"code":"6104","name":"咸阳市","childs":[{"code":"610402","name":"秦都区"},{"code":"610403","name":"杨陵区"},{"code":"610404","name":"渭城区"},{"code":"610422","name":"三原县"},{"code":"610423","name":"泾阳县"},{"code":"610424","name":"乾县"},{"code":"610425","name":"礼泉县"},{"code":"610426","name":"永寿县"},{"code":"610427","name":"彬县"},{"code":"610428","name":"长武县"},{"code":"610429","name":"旬邑县"},{"code":"610430","name":"淳化县"},{"code":"610431","name":"武功县"},{"code":"610481","name":"兴平市"}]},{"code":"6105","name":"渭南市","childs":[{"code":"610502","name":"临渭区"},{"code":"610503","name":"华州区"},{"code":"610522","name":"潼关县"},{"code":"610523","name":"大荔县"},{"code":"610524","name":"合阳县"},{"code":"610525","name":"澄城县"},{"code":"610526","name":"蒲城县"},{"code":"610527","name":"白水县"},{"code":"610528","name":"富平县"},{"code":"610581","name":"韩城市"},{"code":"610582","name":"华阴市"}]},{"code":"6106","name":"延安市","childs":[{"code":"610602","name":"宝塔区"},{"code":"610603","name":"安塞区"},{"code":"610621","name":"延长县"},{"code":"610622","name":"延川县"},{"code":"610623","name":"子长县"},{"code":"610625","name":"志丹县"},{"code":"610626","name":"吴起县"},{"code":"610627","name":"甘泉县"},{"code":"610628","name":"富县"},{"code":"610629","name":"洛川县"},{"code":"610630","name":"宜川县"},{"code":"610631","name":"黄龙县"},{"code":"610632","name":"黄陵县"}]},{"code":"6107","name":"汉中市","childs":[{"code":"610702","name":"汉台区"},{"code":"610721","name":"南郑县"},{"code":"610722","name":"城固县"},{"code":"610723","name":"洋县"},{"code":"610724","name":"西乡县"},{"code":"610725","name":"勉县"},{"code":"610726","name":"宁强县"},{"code":"610727","name":"略阳县"},{"code":"610728","name":"镇巴县"},{"code":"610729","name":"留坝县"},{"code":"610730","name":"佛坪县"}]},{"code":"6108","name":"榆林市","childs":[{"code":"610802","name":"榆阳区"},{"code":"610803","name":"横山区"},{"code":"610821","name":"神木县"},{"code":"610822","name":"府谷县"},{"code":"610824","name":"靖边县"},{"code":"610825","name":"定边县"},{"code":"610826","name":"绥德县"},{"code":"610827","name":"米脂县"},{"code":"610828","name":"佳县"},{"code":"610829","name":"吴堡县"},{"code":"610830","name":"清涧县"},{"code":"610831","name":"子洲县"}]},{"code":"6109","name":"安康市","childs":[{"code":"610902","name":"汉滨区"},{"code":"610921","name":"汉阴县"},{"code":"610922","name":"石泉县"},{"code":"610923","name":"宁陕县"},{"code":"610924","name":"紫阳县"},{"code":"610925","name":"岚皋县"},{"code":"610926","name":"平利县"},{"code":"610927","name":"镇坪县"},{"code":"610928","name":"旬阳县"},{"code":"610929","name":"白河县"}]},{"code":"6110","name":"商洛市","childs":[{"code":"611002","name":"商州区"},{"code":"611021","name":"洛南县"},{"code":"611022","name":"丹凤县"},{"code":"611023","name":"商南县"},{"code":"611024","name":"山阳县"},{"code":"611025","name":"镇安县"},{"code":"611026","name":"柞水县"}]}]},{"code":"62","name":"甘肃省","childs":[{"code":"6201","name":"兰州市","childs":[{"code":"620102","name":"城关区"},{"code":"620103","name":"七里河区"},{"code":"620104","name":"西固区"},{"code":"620105","name":"安宁区"},{"code":"620111","name":"红古区"},{"code":"620121","name":"永登县"},{"code":"620122","name":"皋兰县"},{"code":"620123","name":"榆中县"}]},{"code":"620201","name":"嘉峪关市","childs":[{"code":"620201100","name":"新城镇"},{"code":"620201101","name":"峪泉镇"},{"code":"620201102","name":"文殊镇"},{"code":"620201401","name":"雄关区"},{"code":"620201402","name":"镜铁区"},{"code":"620201403","name":"长城区"}]},{"code":"6203","name":"金昌市","childs":[{"code":"620302","name":"金川区"},{"code":"620321","name":"永昌县"}]},{"code":"6204","name":"白银市","childs":[{"code":"620402","name":"白银区"},{"code":"620403","name":"平川区"},{"code":"620421","name":"靖远县"},{"code":"620422","name":"会宁县"},{"code":"620423","name":"景泰县"}]},{"code":"6205","name":"天水市","childs":[{"code":"620502","name":"秦州区"},{"code":"620503","name":"麦积区"},{"code":"620521","name":"清水县"},{"code":"620522","name":"秦安县"},{"code":"620523","name":"甘谷县"},{"code":"620524","name":"武山县"},{"code":"620525","name":"张家川回族自治县"}]},{"code":"6206","name":"武威市","childs":[{"code":"620602","name":"凉州区"},{"code":"620621","name":"民勤县"},{"code":"620622","name":"古浪县"},{"code":"620623","name":"天祝藏族自治县"}]},{"code":"6207","name":"张掖市","childs":[{"code":"620702","name":"甘州区"},{"code":"620721","name":"肃南裕固族自治县"},{"code":"620722","name":"民乐县"},{"code":"620723","name":"临泽县"},{"code":"620724","name":"高台县"},{"code":"620725","name":"山丹县"}]},{"code":"6208","name":"平凉市","childs":[{"code":"620802","name":"崆峒区"},{"code":"620821","name":"泾川县"},{"code":"620822","name":"灵台县"},{"code":"620823","name":"崇信县"},{"code":"620824","name":"华亭县"},{"code":"620825","name":"庄浪县"},{"code":"620826","name":"静宁县"}]},{"code":"6209","name":"酒泉市","childs":[{"code":"620902","name":"肃州区"},{"code":"620921","name":"金塔县"},{"code":"620922","name":"瓜州县"},{"code":"620923","name":"肃北蒙古族自治县"},{"code":"620924","name":"阿克塞哈萨克族自治县"},{"code":"620981","name":"玉门市"},{"code":"620982","name":"敦煌市"}]},{"code":"6210","name":"庆阳市","childs":[{"code":"621002","name":"西峰区"},{"code":"621021","name":"庆城县"},{"code":"621022","name":"环县"},{"code":"621023","name":"华池县"},{"code":"621024","name":"合水县"},{"code":"621025","name":"正宁县"},{"code":"621026","name":"宁县"},{"code":"621027","name":"镇原县"}]},{"code":"6211","name":"定西市","childs":[{"code":"621102","name":"安定区"},{"code":"621121","name":"通渭县"},{"code":"621122","name":"陇西县"},{"code":"621123","name":"渭源县"},{"code":"621124","name":"临洮县"},{"code":"621125","name":"漳县"},{"code":"621126","name":"岷县"}]},{"code":"6212","name":"陇南市","childs":[{"code":"621202","name":"武都区"},{"code":"621221","name":"成县"},{"code":"621222","name":"文县"},{"code":"621223","name":"宕昌县"},{"code":"621224","name":"康县"},{"code":"621225","name":"西和县"},{"code":"621226","name":"礼县"},{"code":"621227","name":"徽县"},{"code":"621228","name":"两当县"}]},{"code":"6229","name":"临夏回族自治州","childs":[{"code":"622901","name":"临夏市"},{"code":"622921","name":"临夏县"},{"code":"622922","name":"康乐县"},{"code":"622923","name":"永靖县"},{"code":"622924","name":"广河县"},{"code":"622925","name":"和政县"},{"code":"622926","name":"东乡族自治县"},{"code":"622927","name":"积石山保安族东乡族撒拉族自治县"}]},{"code":"6230","name":"甘南藏族自治州","childs":[{"code":"623001","name":"合作市"},{"code":"623021","name":"临潭县"},{"code":"623022","name":"卓尼县"},{"code":"623023","name":"舟曲县"},{"code":"623024","name":"迭部县"},{"code":"623025","name":"玛曲县"},{"code":"623026","name":"碌曲县"},{"code":"623027","name":"夏河县"}]}]},{"code":"63","name":"青海省","childs":[{"code":"6301","name":"西宁市","childs":[{"code":"630102","name":"城东区"},{"code":"630103","name":"城中区"},{"code":"630104","name":"城西区"},{"code":"630105","name":"城北区"},{"code":"630121","name":"大通回族土族自治县"},{"code":"630122","name":"湟中县"},{"code":"630123","name":"湟源县"}]},{"code":"6302","name":"海东市","childs":[{"code":"630202","name":"乐都区"},{"code":"630203","name":"平安区"},{"code":"630222","name":"民和回族土族自治县"},{"code":"630223","name":"互助土族自治县"},{"code":"630224","name":"化隆回族自治县"},{"code":"630225","name":"循化撒拉族自治县"}]},{"code":"6322","name":"海北藏族自治州","childs":[{"code":"632221","name":"门源回族自治县"},{"code":"632222","name":"祁连县"},{"code":"632223","name":"海晏县"},{"code":"632224","name":"刚察县"}]},{"code":"6323","name":"黄南藏族自治州","childs":[{"code":"632321","name":"同仁县"},{"code":"632322","name":"尖扎县"},{"code":"632323","name":"泽库县"},{"code":"632324","name":"河南蒙古族自治县"}]},{"code":"6325","name":"海南藏族自治州","childs":[{"code":"632521","name":"共和县"},{"code":"632522","name":"同德县"},{"code":"632523","name":"贵德县"},{"code":"632524","name":"兴海县"},{"code":"632525","name":"贵南县"}]},{"code":"6326","name":"果洛藏族自治州","childs":[{"code":"632621","name":"玛沁县"},{"code":"632622","name":"班玛县"},{"code":"632623","name":"甘德县"},{"code":"632624","name":"达日县"},{"code":"632625","name":"久治县"},{"code":"632626","name":"玛多县"}]},{"code":"6327","name":"玉树藏族自治州","childs":[{"code":"632701","name":"玉树市"},{"code":"632722","name":"杂多县"},{"code":"632723","name":"称多县"},{"code":"632724","name":"治多县"},{"code":"632725","name":"囊谦县"},{"code":"632726","name":"曲麻莱县"}]},{"code":"6328","name":"海西蒙古族藏族自治州","childs":[{"code":"632801","name":"格尔木市"},{"code":"632802","name":"德令哈市"},{"code":"632821","name":"乌兰县"},{"code":"632822","name":"都兰县"},{"code":"632823","name":"天峻县"}]}]},{"code":"64","name":"宁夏回族自治区","childs":[{"code":"6401","name":"银川市","childs":[{"code":"640104","name":"兴庆区"},{"code":"640105","name":"西夏区"},{"code":"640106","name":"金凤区"},{"code":"640121","name":"永宁县"},{"code":"640122","name":"贺兰县"},{"code":"640181","name":"灵武市"}]},{"code":"6402","name":"石嘴山市","childs":[{"code":"640202","name":"大武口区"},{"code":"640205","name":"惠农区"},{"code":"640221","name":"平罗县"}]},{"code":"6403","name":"吴忠市","childs":[{"code":"640302","name":"利通区"},{"code":"640303","name":"红寺堡区"},{"code":"640323","name":"盐池县"},{"code":"640324","name":"同心县"},{"code":"640381","name":"青铜峡市"}]},{"code":"6404","name":"固原市","childs":[{"code":"640402","name":"原州区"},{"code":"640422","name":"西吉县"},{"code":"640423","name":"隆德县"},{"code":"640424","name":"泾源县"},{"code":"640425","name":"彭阳县"}]},{"code":"6405","name":"中卫市","childs":[{"code":"640502","name":"沙坡头区"},{"code":"640521","name":"中宁县"},{"code":"640522","name":"海原县"}]}]},{"code":"65","name":"新疆维吾尔自治区","childs":[{"code":"6501","name":"乌鲁木齐市","childs":[{"code":"650102","name":"天山区"},{"code":"650103","name":"沙依巴克区"},{"code":"650104","name":"新市区"},{"code":"650105","name":"水磨沟区"},{"code":"650106","name":"头屯河区"},{"code":"650107","name":"达坂城区"},{"code":"650109","name":"米东区"},{"code":"650121","name":"乌鲁木齐县"}]},{"code":"6502","name":"克拉玛依市","childs":[{"code":"650202","name":"独山子区"},{"code":"650203","name":"克拉玛依区"},{"code":"650204","name":"白碱滩区"},{"code":"650205","name":"乌尔禾区"}]},{"code":"6504","name":"吐鲁番市","childs":[{"code":"650402","name":"高昌区"},{"code":"650421","name":"鄯善县"},{"code":"650422","name":"托克逊县"}]},{"code":"6505","name":"哈密市","childs":[{"code":"650502","name":"伊州区"},{"code":"650521","name":"巴里坤哈萨克自治县"},{"code":"650522","name":"伊吾县"}]},{"code":"6523","name":"昌吉回族自治州","childs":[{"code":"652301","name":"昌吉市"},{"code":"652302","name":"阜康市"},{"code":"652323","name":"呼图壁县"},{"code":"652324","name":"玛纳斯县"},{"code":"652325","name":"奇台县"},{"code":"652327","name":"吉木萨尔县"},{"code":"652328","name":"木垒哈萨克自治县"}]},{"code":"6527","name":"博尔塔拉蒙古自治州","childs":[{"code":"652701","name":"博乐市"},{"code":"652702","name":"阿拉山口市"},{"code":"652722","name":"精河县"},{"code":"652723","name":"温泉县"}]},{"code":"6528","name":"巴音郭楞蒙古自治州","childs":[{"code":"652801","name":"库尔勒市"},{"code":"652822","name":"轮台县"},{"code":"652823","name":"尉犁县"},{"code":"652824","name":"若羌县"},{"code":"652825","name":"且末县"},{"code":"652826","name":"焉耆回族自治县"},{"code":"652827","name":"和静县"},{"code":"652828","name":"和硕县"},{"code":"652829","name":"博湖县"}]},{"code":"6529","name":"阿克苏地区","childs":[{"code":"652901","name":"阿克苏市"},{"code":"652922","name":"温宿县"},{"code":"652923","name":"库车县"},{"code":"652924","name":"沙雅县"},{"code":"652925","name":"新和县"},{"code":"652926","name":"拜城县"},{"code":"652927","name":"乌什县"},{"code":"652928","name":"阿瓦提县"},{"code":"652929","name":"柯坪县"}]},{"code":"6530","name":"克孜勒苏柯尔克孜自治州","childs":[{"code":"653001","name":"阿图什市"},{"code":"653022","name":"阿克陶县"},{"code":"653023","name":"阿合奇县"},{"code":"653024","name":"乌恰县"}]},{"code":"6531","name":"喀什地区","childs":[{"code":"653101","name":"喀什市"},{"code":"653121","name":"疏附县"},{"code":"653122","name":"疏勒县"},{"code":"653123","name":"英吉沙县"},{"code":"653124","name":"泽普县"},{"code":"653125","name":"莎车县"},{"code":"653126","name":"叶城县"},{"code":"653127","name":"麦盖提县"},{"code":"653128","name":"岳普湖县"},{"code":"653129","name":"伽师县"},{"code":"653130","name":"巴楚县"},{"code":"653131","name":"塔什库尔干塔吉克自治县"}]},{"code":"6532","name":"和田地区","childs":[{"code":"653201","name":"和田市"},{"code":"653221","name":"和田县"},{"code":"653222","name":"墨玉县"},{"code":"653223","name":"皮山县"},{"code":"653224","name":"洛浦县"},{"code":"653225","name":"策勒县"},{"code":"653226","name":"于田县"},{"code":"653227","name":"民丰县"}]},{"code":"6540","name":"伊犁哈萨克自治州","childs":[{"code":"654002","name":"伊宁市"},{"code":"654003","name":"奎屯市"},{"code":"654004","name":"霍尔果斯市"},{"code":"654021","name":"伊宁县"},{"code":"654022","name":"察布查尔锡伯自治县"},{"code":"654023","name":"霍城县"},{"code":"654024","name":"巩留县"},{"code":"654025","name":"新源县"},{"code":"654026","name":"昭苏县"},{"code":"654027","name":"特克斯县"},{"code":"654028","name":"尼勒克县"}]},{"code":"6542","name":"塔城地区","childs":[{"code":"654201","name":"塔城市"},{"code":"654202","name":"乌苏市"},{"code":"654221","name":"额敏县"},{"code":"654223","name":"沙湾县"},{"code":"654224","name":"托里县"},{"code":"654225","name":"裕民县"},{"code":"654226","name":"和布克赛尔蒙古自治县"}]},{"code":"6543","name":"阿勒泰地区","childs":[{"code":"654301","name":"阿勒泰市"},{"code":"654321","name":"布尔津县"},{"code":"654322","name":"富蕴县"},{"code":"654323","name":"福海县"},{"code":"654324","name":"哈巴河县"},{"code":"654325","name":"青河县"},{"code":"654326","name":"吉木乃县"}]},{"code":"6590","name":"自治区直辖县级行政区划","childs":[{"code":"659001","name":"石河子市"},{"code":"659002","name":"阿拉尔市"},{"code":"659003","name":"图木舒克市"},{"code":"659004","name":"五家渠市"},{"code":"659006","name":"铁门关市"}]}]},{"code":"71","name":"台湾省","childs":[]},{"code":"81","name":"香港特别行政区","childs":[]},{"code":"82","name":"澳门特别行政区","childs":[]}] \ No newline at end of file diff --git a/components/popup-view/popup-view.vue b/components/popup-view/popup-view.vue new file mode 100644 index 0000000..b144ed1 --- /dev/null +++ b/components/popup-view/popup-view.vue @@ -0,0 +1,474 @@ + + + + + diff --git a/components/tab-control/tab-control.vue b/components/tab-control/tab-control.vue new file mode 100644 index 0000000..9bde305 --- /dev/null +++ b/components/tab-control/tab-control.vue @@ -0,0 +1,322 @@ + + + + + + diff --git a/components/u-parse/components/wxParseAudio.vue b/components/u-parse/components/wxParseAudio.vue new file mode 100644 index 0000000..86df246 --- /dev/null +++ b/components/u-parse/components/wxParseAudio.vue @@ -0,0 +1,27 @@ + + + diff --git a/components/u-parse/components/wxParseImg.vue b/components/u-parse/components/wxParseImg.vue new file mode 100644 index 0000000..00747e4 --- /dev/null +++ b/components/u-parse/components/wxParseImg.vue @@ -0,0 +1,86 @@ + + + diff --git a/components/u-parse/components/wxParseTemplate0.vue b/components/u-parse/components/wxParseTemplate0.vue new file mode 100644 index 0000000..0c76e74 --- /dev/null +++ b/components/u-parse/components/wxParseTemplate0.vue @@ -0,0 +1,107 @@ + + + diff --git a/components/u-parse/components/wxParseTemplate1.vue b/components/u-parse/components/wxParseTemplate1.vue new file mode 100644 index 0000000..a864f23 --- /dev/null +++ b/components/u-parse/components/wxParseTemplate1.vue @@ -0,0 +1,99 @@ + + + diff --git a/components/u-parse/components/wxParseTemplate10.vue b/components/u-parse/components/wxParseTemplate10.vue new file mode 100644 index 0000000..9a8d8b6 --- /dev/null +++ b/components/u-parse/components/wxParseTemplate10.vue @@ -0,0 +1,97 @@ + + + diff --git a/components/u-parse/components/wxParseTemplate11.vue b/components/u-parse/components/wxParseTemplate11.vue new file mode 100644 index 0000000..1402d11 --- /dev/null +++ b/components/u-parse/components/wxParseTemplate11.vue @@ -0,0 +1,87 @@ + + + diff --git a/components/u-parse/components/wxParseTemplate2.vue b/components/u-parse/components/wxParseTemplate2.vue new file mode 100644 index 0000000..d6d027d --- /dev/null +++ b/components/u-parse/components/wxParseTemplate2.vue @@ -0,0 +1,98 @@ + + + diff --git a/components/u-parse/components/wxParseTemplate3.vue b/components/u-parse/components/wxParseTemplate3.vue new file mode 100644 index 0000000..f899edd --- /dev/null +++ b/components/u-parse/components/wxParseTemplate3.vue @@ -0,0 +1,98 @@ + + + diff --git a/components/u-parse/components/wxParseTemplate4.vue b/components/u-parse/components/wxParseTemplate4.vue new file mode 100644 index 0000000..9bd558c --- /dev/null +++ b/components/u-parse/components/wxParseTemplate4.vue @@ -0,0 +1,98 @@ + + + diff --git a/components/u-parse/components/wxParseTemplate5.vue b/components/u-parse/components/wxParseTemplate5.vue new file mode 100644 index 0000000..4f6cc27 --- /dev/null +++ b/components/u-parse/components/wxParseTemplate5.vue @@ -0,0 +1,98 @@ + + + diff --git a/components/u-parse/components/wxParseTemplate6.vue b/components/u-parse/components/wxParseTemplate6.vue new file mode 100644 index 0000000..4781c64 --- /dev/null +++ b/components/u-parse/components/wxParseTemplate6.vue @@ -0,0 +1,98 @@ + + + diff --git a/components/u-parse/components/wxParseTemplate7.vue b/components/u-parse/components/wxParseTemplate7.vue new file mode 100644 index 0000000..1efc4dc --- /dev/null +++ b/components/u-parse/components/wxParseTemplate7.vue @@ -0,0 +1,98 @@ + + + diff --git a/components/u-parse/components/wxParseTemplate8.vue b/components/u-parse/components/wxParseTemplate8.vue new file mode 100644 index 0000000..2ac546f --- /dev/null +++ b/components/u-parse/components/wxParseTemplate8.vue @@ -0,0 +1,98 @@ + + + diff --git a/components/u-parse/components/wxParseTemplate9.vue b/components/u-parse/components/wxParseTemplate9.vue new file mode 100644 index 0000000..c771e5f --- /dev/null +++ b/components/u-parse/components/wxParseTemplate9.vue @@ -0,0 +1,98 @@ + + + diff --git a/components/u-parse/components/wxParseVideo.vue b/components/u-parse/components/wxParseVideo.vue new file mode 100644 index 0000000..a952f58 --- /dev/null +++ b/components/u-parse/components/wxParseVideo.vue @@ -0,0 +1,15 @@ + + + diff --git a/components/u-parse/libs/html2json.js b/components/u-parse/libs/html2json.js new file mode 100644 index 0000000..0927382 --- /dev/null +++ b/components/u-parse/libs/html2json.js @@ -0,0 +1,261 @@ +/** + * html2Json 改造来自: https://github.com/Jxck/html2json + * + * + * author: Di (微信小程序开发工程师) + * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com) + * 垂直微信小程序开发交流社区 + * + * github地址: https://github.com/icindy/wxParse + * + * for: 微信小程序富文本解析 + * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184 + */ + +import wxDiscode from './wxDiscode'; +import HTMLParser from './htmlparser'; + +function makeMap(str) { + const obj = {}; + const items = str.split(','); + for (let i = 0; i < items.length; i += 1) obj[items[i]] = true; + return obj; +} + +// Block Elements - HTML 5 +const block = makeMap('br,code,address,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video'); + +// Inline Elements - HTML 5 +const inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'); + +// Elements that you can, intentionally, leave open +// (and which close themselves) +const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'); + +function removeDOCTYPE(html) { + const isDocument = /([^]*)<\/body>/.test(html); + return isDocument ? RegExp.$1 : html; +} + +function trimHtml(html) { + return html + .replace(//gi, '') + .replace(/\/\*.*?\*\//gi, '') + .replace(/[ ]+/gi, '') + .replace(//gi, ''); +} + +function getScreenInfo() { + const screen = {}; + wx.getSystemInfo({ + success: (res) => { + screen.width = res.windowWidth; + screen.height = res.windowHeight; + }, + }); + return screen; +} + +function html2json(html, customHandler, imageProp, host) { + // 处理字符串 + html = removeDOCTYPE(html); + html = trimHtml(html); + html = wxDiscode.strDiscode(html); + // 生成node节点 + const bufArray = []; + const results = { + nodes: [], + imageUrls: [], + }; + + const screen = getScreenInfo(); + function Node(tag) { + this.node = 'element'; + this.tag = tag; + + this.$screen = screen; + } + + HTMLParser(html, { + start(tag, attrs, unary) { + // node for this element + const node = new Node(tag); + + if (bufArray.length !== 0) { + const parent = bufArray[0]; + if (parent.nodes === undefined) { + parent.nodes = []; + } + } + + if (block[tag]) { + node.tagType = 'block'; + } else if (inline[tag]) { + node.tagType = 'inline'; + } else if (closeSelf[tag]) { + node.tagType = 'closeSelf'; + } + + node.attr = attrs.reduce((pre, attr) => { + const { name } = attr; + let { value } = attr; + if (name === 'class') { + node.classStr = value; + } + // has multi attibutes + // make it array of attribute + if (name === 'style') { + node.styleStr = value; + } + if (value.match(/ /)) { + value = value.split(' '); + } + + // if attr already exists + // merge it + if (pre[name]) { + if (Array.isArray(pre[name])) { + // already array, push to last + pre[name].push(value); + } else { + // single value, make it array + pre[name] = [pre[name], value]; + } + } else { + // not exist, put it + pre[name] = value; + } + + return pre; + }, {}); + + // 优化样式相关属性 + if (node.classStr) { + node.classStr += ` ${node.tag}`; + } else { + node.classStr = node.tag; + } + if (node.tagType === 'inline') { + node.classStr += ' inline'; + } + + // 对img添加额外数据 + if (node.tag === 'img') { + let imgUrl = node.attr.src; + imgUrl = wxDiscode.urlToHttpUrl(imgUrl, imageProp.domain); + Object.assign(node.attr, imageProp, { + src: imgUrl || '', + }); + if (imgUrl) { + results.imageUrls.push(imgUrl); + } + } + + // 处理a标签属性 + if (node.tag === 'a') { + node.attr.href = node.attr.href || ''; + } + + // 处理font标签样式属性 + if (node.tag === 'font') { + const fontSize = [ + 'x-small', + 'small', + 'medium', + 'large', + 'x-large', + 'xx-large', + '-webkit-xxx-large', + ]; + const styleAttrs = { + color: 'color', + face: 'font-family', + size: 'font-size', + }; + if (!node.styleStr) node.styleStr = ''; + Object.keys(styleAttrs).forEach((key) => { + if (node.attr[key]) { + const value = key === 'size' ? fontSize[node.attr[key] - 1] : node.attr[key]; + node.styleStr += `${styleAttrs[key]}: ${value};`; + } + }); + } + + // 临时记录source资源 + if (node.tag === 'source') { + results.source = node.attr.src; + } + + if (customHandler.start) { + customHandler.start(node, results); + } + + if (unary) { + // if this tag doesn't have end tag + // like + // add to parents + const parent = bufArray[0] || results; + if (parent.nodes === undefined) { + parent.nodes = []; + } + parent.nodes.push(node); + } else { + bufArray.unshift(node); + } + }, + end(tag) { + // merge into parent tag + const node = bufArray.shift(); + if (node.tag !== tag) { + console.error('invalid state: mismatch end tag'); + } + + // 当有缓存source资源时于于video补上src资源 + if (node.tag === 'video' && results.source) { + node.attr.src = results.source; + delete results.source; + } + + if (customHandler.end) { + customHandler.end(node, results); + } + + if (bufArray.length === 0) { + results.nodes.push(node); + } else { + const parent = bufArray[0]; + if (!parent.nodes) { + parent.nodes = []; + } + parent.nodes.push(node); + } + }, + chars(text) { + if (!text.trim()) return; + + const node = { + node: 'text', + text, + }; + + if (customHandler.chars) { + customHandler.chars(node, results); + } + + if (bufArray.length === 0) { + results.nodes.push(node); + } else { + const parent = bufArray[0]; + if (parent.nodes === undefined) { + parent.nodes = []; + } + parent.nodes.push(node); + } + }, + }); + + return results; +} + +export default html2json; diff --git a/components/u-parse/libs/htmlparser.js b/components/u-parse/libs/htmlparser.js new file mode 100644 index 0000000..2939da3 --- /dev/null +++ b/components/u-parse/libs/htmlparser.js @@ -0,0 +1,156 @@ +/** + * + * htmlParser改造自: https://github.com/blowsie/Pure-JavaScript-HTML5-Parser + * + * author: Di (微信小程序开发工程师) + * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com) + * 垂直微信小程序开发交流社区 + * + * github地址: https://github.com/icindy/wxParse + * + * for: 微信小程序富文本解析 + * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184 + */ +// Regular Expressions for parsing tags and attributes + +const startTag = /^<([-A-Za-z0-9_]+)((?:\s+[a-zA-Z0-9_:][-a-zA-Z0-9_:.]*(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/; +const endTag = /^<\/([-A-Za-z0-9_]+)[^>]*>/; +const attr = /([a-zA-Z0-9_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:(?:"((?:\\.|[^"])*)")|(?:'((?:\\.|[^'])*)')|([^>\s]+)))?/g; + +function makeMap(str) { + const obj = {}; + const items = str.split(','); + for (let i = 0; i < items.length; i += 1) obj[items[i]] = true; + return obj; +} + +// Empty Elements - HTML 5 +const empty = makeMap('area,base,basefont,br,col,frame,hr,img,input,link,meta,param,embed,command,keygen,source,track,wbr'); + +// Block Elements - HTML 5 +const block = makeMap('address,code,article,applet,aside,audio,blockquote,button,canvas,center,dd,del,dir,div,dl,dt,fieldset,figcaption,figure,footer,form,frameset,h1,h2,h3,h4,h5,h6,header,hgroup,hr,iframe,ins,isindex,li,map,menu,noframes,noscript,object,ol,output,p,pre,section,script,table,tbody,td,tfoot,th,thead,tr,ul,video'); + +// Inline Elements - HTML 5 +const inline = makeMap('a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,script,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'); + +// Elements that you can, intentionally, leave open +// (and which close themselves) +const closeSelf = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'); + +// Attributes that have their values filled in disabled="disabled" +const fillAttrs = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'); + +function HTMLParser(html, handler) { + let index; + let chars; + let match; + let last = html; + const stack = []; + + stack.last = () => stack[stack.length - 1]; + + function parseEndTag(tag, tagName) { + // If no tag name is provided, clean shop + let pos; + if (!tagName) { + pos = 0; + } else { + // Find the closest opened tag of the same type + tagName = tagName.toLowerCase(); + for (pos = stack.length - 1; pos >= 0; pos -= 1) { + if (stack[pos] === tagName) break; + } + } + if (pos >= 0) { + // Close all the open elements, up the stack + for (let i = stack.length - 1; i >= pos; i -= 1) { + if (handler.end) handler.end(stack[i]); + } + + // Remove the open elements from the stack + stack.length = pos; + } + } + + function parseStartTag(tag, tagName, rest, unary) { + tagName = tagName.toLowerCase(); + + if (block[tagName]) { + while (stack.last() && inline[stack.last()]) { + parseEndTag('', stack.last()); + } + } + + if (closeSelf[tagName] && stack.last() === tagName) { + parseEndTag('', tagName); + } + + unary = empty[tagName] || !!unary; + + if (!unary) stack.push(tagName); + + if (handler.start) { + const attrs = []; + + rest.replace(attr, function genAttr(matches, name) { + const value = arguments[2] || arguments[3] || arguments[4] || (fillAttrs[name] ? name : ''); + + attrs.push({ + name, + value, + escaped: value.replace(/(^|[^\\])"/g, '$1\\"'), // " + }); + }); + + if (handler.start) { + handler.start(tagName, attrs, unary); + } + } + } + + while (html) { + chars = true; + + if (html.indexOf(''); + str = str.replace(/•/g, '•'); + + return str; +} + +// HTML 支持的其他实体 +function strOtherDiscode(str) { + str = str.replace(/Œ/g, 'Œ'); + str = str.replace(/œ/g, 'œ'); + str = str.replace(/Š/g, 'Š'); + str = str.replace(/š/g, 'š'); + str = str.replace(/Ÿ/g, 'Ÿ'); + str = str.replace(/ƒ/g, 'ƒ'); + str = str.replace(/ˆ/g, 'ˆ'); + str = str.replace(/˜/g, '˜'); + str = str.replace(/ /g, ''); + str = str.replace(/ /g, ''); + str = str.replace(/ /g, ''); + str = str.replace(/‌/g, ''); + str = str.replace(/‍/g, ''); + str = str.replace(/‎/g, ''); + str = str.replace(/‏/g, ''); + str = str.replace(/–/g, '–'); + str = str.replace(/—/g, '—'); + str = str.replace(/‘/g, '‘'); + str = str.replace(/’/g, '’'); + str = str.replace(/‚/g, '‚'); + str = str.replace(/“/g, '“'); + str = str.replace(/”/g, '”'); + str = str.replace(/„/g, '„'); + str = str.replace(/†/g, '†'); + str = str.replace(/‡/g, '‡'); + str = str.replace(/•/g, '•'); + str = str.replace(/…/g, '…'); + str = str.replace(/‰/g, '‰'); + str = str.replace(/′/g, '′'); + str = str.replace(/″/g, '″'); + str = str.replace(/‹/g, '‹'); + str = str.replace(/›/g, '›'); + str = str.replace(/‾/g, '‾'); + str = str.replace(/€/g, '€'); + str = str.replace(/™/g, '™'); + + str = str.replace(/←/g, '←'); + str = str.replace(/↑/g, '↑'); + str = str.replace(/→/g, '→'); + str = str.replace(/↓/g, '↓'); + str = str.replace(/↔/g, '↔'); + str = str.replace(/↵/g, '↵'); + str = str.replace(/⌈/g, '⌈'); + str = str.replace(/⌉/g, '⌉'); + + str = str.replace(/⌊/g, '⌊'); + str = str.replace(/⌋/g, '⌋'); + str = str.replace(/◊/g, '◊'); + str = str.replace(/♠/g, '♠'); + str = str.replace(/♣/g, '♣'); + str = str.replace(/♥/g, '♥'); + + str = str.replace(/♦/g, '♦'); + str = str.replace(/'/g, "'"); + return str; +} + +function strDiscode(str) { + str = strNumDiscode(str); + str = strGreeceDiscode(str); + str = strcharacterDiscode(str); + str = strOtherDiscode(str); + return str; +} + +function urlToHttpUrl(url, domain) { + if (/^\/\//.test(url)) { + return `https:${url}`; + } else if (/^\//.test(url)) { + return `https://${domain}${url}`; + } + return url; +} + +export default { + strDiscode, + urlToHttpUrl, +}; diff --git a/components/u-parse/readme.md b/components/u-parse/readme.md new file mode 100644 index 0000000..f79b9c3 --- /dev/null +++ b/components/u-parse/readme.md @@ -0,0 +1,102 @@ +## uParse 适用于 uni-app/mpvue 的富文本解析组件 + +> 支持 Html、Markdown 解析,Fork自: [mpvue-wxParse](https://github.com/F-loat/mpvue-wxParse) + + +## 属性 + +| 名称 | 类型 | 默认值 | 描述 | +| -----------------|--------------- | ------------- | ---------------- | +| loading | Boolean | false | 数据加载状态 | +| className | String | — | 自定义 class 名称 | +| content | String | — | 渲染内容 | +| noData | String | 数据不能为空 | 空数据时的渲染展示 | +| startHandler | Function | 见源码 | 自定义 parser 函数 | +| endHandler | Function | null | 自定义 parser 函数 | +| charsHandler | Function | null | 自定义 parser 函数 | +| imageProp | Object | 见下文 | 图片相关参数 | + +### 自定义 parser 函数具体介绍 + +* 传入的参数为当前节点 `node` 对象及解析结果 `results` 对象,例如 `startHandler(node, results)` +* 无需返回值,通过对传入的参数直接操作来完成需要的改动 +* 自定义函数会在原解析函数处理之后执行 + +### imageProp 对象具体属性 + +| 名称 | 类型 | 默认值 | 描述 | +| -----------------|--------------- | ------------- | ------------------ | +| mode | String | 'aspectFit' | 图片裁剪、缩放的模式 | +| padding | Number | 0 | 图片内边距 | +| lazyLoad | Boolean | false | 图片懒加载 | +| domain | String | '' | 图片服务域名 | + +## 事件 + +| 名称 | 参数 | 描述 | +| -----------------|----------------- | ---------------- | +| preview | 图片地址,原始事件 | 预览图片时触发 | +| navigate | 链接地址,原始事件 | 点击链接时触发 | + +## 基本使用方法 + + +``` vue + + + + + +``` + + +## 渲染 Markdown + +> 先将 markdown 转换为 html 即可 + +``` +npm install marked +``` + +``` js +import marked from 'marked' +import uParse from '@/components/u-parse/u-parse.vue' + +export default { + components: { + uParse + }, + data () { + return { + article: marked(`#hello, markdown!`) + } + } +} +``` diff --git a/components/u-parse/u-parse.css b/components/u-parse/u-parse.css new file mode 100644 index 0000000..9be67be --- /dev/null +++ b/components/u-parse/u-parse.css @@ -0,0 +1,232 @@ +/** + * author: Di (微信小程序开发工程师) + * organization: WeAppDev(微信小程序开发论坛)(http://weappdev.com) + * 垂直微信小程序开发交流社区 + * + * github地址: https://github.com/icindy/wxParse + * + * for: 微信小程序富文本解析 + * detail : http://weappdev.com/t/wxparse-alpha0-1-html-markdown/184 + */ + +.wxParse { + width: 100%; + font-family: Helvetica, sans-serif; + font-size: 30upx; + color: #666; + line-height: 1.8; +} + +.wxParse view { + word-break: hyphenate; +} + +.wxParse .inline { + display: inline; + margin: 0; + padding: 0; +} + +.wxParse .div { + margin: 0; + padding: 0; +} + +.wxParse .h1 .text { + font-size: 2em; + margin: 0.67em 0; +} +.wxParse .h2 .text { + font-size: 1.5em; + margin: 0.83em 0; +} +.wxParse .h3 .text { + font-size: 1.17em; + margin: 1em 0; +} +.wxParse .h4 .text { + margin: 1.33em 0; +} +.wxParse .h5 .text { + font-size: 0.83em; + margin: 1.67em 0; +} +.wxParse .h6 .text { + font-size: 0.67em; + margin: 2.33em 0; +} + +.wxParse .h1 .text, +.wxParse .h2 .text, +.wxParse .h3 .text, +.wxParse .h4 .text, +.wxParse .h5 .text, +.wxParse .h6 .text, +.wxParse .b, +.wxParse .strong { + font-weight: bolder; +} + + +.wxParse .p { + margin: 1em 0; +} + +.wxParse .i, +.wxParse .cite, +.wxParse .em, +.wxParse .var, +.wxParse .address { + font-style: italic; +} + +.wxParse .pre, +.wxParse .tt, +.wxParse .code, +.wxParse .kbd, +.wxParse .samp { + font-family: monospace; +} +.wxParse .pre { + overflow: auto; + background: #f5f5f5; + /* padding: 16upx; */ + white-space: pre; + margin: 1em 0upx; +} +.wxParse .code { + display: inline; + background: #f5f5f5; +} + +.wxParse .big { + font-size: 1.17em; +} + +.wxParse .small, +.wxParse .sub, +.wxParse .sup { + font-size: 0.83em; +} + +.wxParse .sub { + vertical-align: sub; +} +.wxParse .sup { + vertical-align: super; +} + +.wxParse .s, +.wxParse .strike, +.wxParse .del { + text-decoration: line-through; +} + +.wxParse .strong, +.wxParse .s { + display: inline; +} + +.wxParse .a { + color: deepskyblue; +} + +.wxParse .video { + text-align: center; + margin: 22upx 0; +} + +.wxParse .video-video { + width: 100%; +} + +.wxParse .img { + display: inline-block; + width: 0; + height: 0; + max-width: 100%; + overflow: hidden; +} + +.wxParse .blockquote { + margin: 10upx 0; + padding: 22upx 0 22upx 22upx; + font-family: Courier, Calibri, "宋体"; + background: #f5f5f5; + border-left: 6upx solid #dbdbdb; +} +.wxParse .blockquote .p { + margin: 0; +} + +.wxParse .ul, .wxParse .ol { + display: block; + margin: 1em 0; + padding-left: 33upx; +} +.wxParse .ol { + list-style-type: disc; +} +.wxParse .ol { + list-style-type: decimal; +} +.wxParse .ol>weixin-parse-template,.wxParse .ul>weixin-parse-template { + display: list-item; + align-items: baseline; + text-align: match-parent; +} + +.wxParse .ol>.li,.wxParse .ul>.li { + display: list-item; + align-items: baseline; + text-align: match-parent; +} +.wxParse .ul .ul, .wxParse .ol .ul { + list-style-type: circle; +} +.wxParse .ol .ol .ul, .wxParse .ol .ul .ul, .wxParse .ul .ol .ul, .wxParse .ul .ul .ul { + list-style-type: square; +} + +.wxParse .u { + text-decoration: underline; +} +.wxParse .hide { + display: none; +} +.wxParse .del { + display: inline; +} +.wxParse .figure { + overflow: hidden; +} + +.wxParse .table { + width: 100%; +} +.wxParse .thead, .wxParse .tfoot, .wxParse .tr { + display: flex; + flex-direction: row; +} +.wxParse .tr { + width:100%; + display: flex; + border-right: 2upx solid #e0e0e0; + border-bottom: 2upx solid #e0e0e0; +} +.wxParse .th, +.wxParse .td { + display: flex; + width: 1276upx; + overflow: auto; + flex: 1; + padding: 11upx; + border-left: 2upx solid #e0e0e0; +} +.wxParse .td:last { + border-top: 2upx solid #e0e0e0; +} +.wxParse .th { + background: #f0f0f0; + border-top: 2upx solid #e0e0e0; +} diff --git a/components/u-parse/u-parse.vue b/components/u-parse/u-parse.vue new file mode 100644 index 0000000..494e60c --- /dev/null +++ b/components/u-parse/u-parse.vue @@ -0,0 +1,118 @@ + + + + + diff --git a/components/under-development/under-development.vue b/components/under-development/under-development.vue new file mode 100644 index 0000000..a579c50 --- /dev/null +++ b/components/under-development/under-development.vue @@ -0,0 +1,55 @@ + + + + + + diff --git a/components/uni-grid-item/uni-grid-item.vue b/components/uni-grid-item/uni-grid-item.vue new file mode 100644 index 0000000..1504ba5 --- /dev/null +++ b/components/uni-grid-item/uni-grid-item.vue @@ -0,0 +1,109 @@ + + + + + diff --git a/components/uni-grid/uni-grid.vue b/components/uni-grid/uni-grid.vue new file mode 100644 index 0000000..e8dabd1 --- /dev/null +++ b/components/uni-grid/uni-grid.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/components/uni-icons/icons.js b/components/uni-icons/icons.js new file mode 100644 index 0000000..1f5a778 --- /dev/null +++ b/components/uni-icons/icons.js @@ -0,0 +1,96 @@ +export default { + 'contact': '\ue100', + 'person': '\ue101', + 'personadd': '\ue102', + 'contact-filled': '\ue130', + 'person-filled': '\ue131', + 'personadd-filled': '\ue132', + 'phone': '\ue200', + 'email': '\ue201', + 'chatbubble': '\ue202', + 'chatboxes': '\ue203', + 'phone-filled': '\ue230', + 'email-filled': '\ue231', + 'chatbubble-filled': '\ue232', + 'chatboxes-filled': '\ue233', + 'weibo': '\ue260', + 'weixin': '\ue261', + 'pengyouquan': '\ue262', + 'chat': '\ue263', + 'qq': '\ue264', + 'videocam': '\ue300', + 'camera': '\ue301', + 'mic': '\ue302', + 'location': '\ue303', + 'mic-filled': '\ue332', + 'speech': '\ue332', + 'location-filled': '\ue333', + 'micoff': '\ue360', + 'image': '\ue363', + 'map': '\ue364', + 'compose': '\ue400', + 'trash': '\ue401', + 'upload': '\ue402', + 'download': '\ue403', + 'close': '\ue404', + 'redo': '\ue405', + 'undo': '\ue406', + 'refresh': '\ue407', + 'star': '\ue408', + 'plus': '\ue409', + 'minus': '\ue410', + 'circle': '\ue411', + 'checkbox': '\ue411', + 'close-filled': '\ue434', + 'clear': '\ue434', + 'refresh-filled': '\ue437', + 'star-filled': '\ue438', + 'plus-filled': '\ue439', + 'minus-filled': '\ue440', + 'circle-filled': '\ue441', + 'checkbox-filled': '\ue442', + 'closeempty': '\ue460', + 'refreshempty': '\ue461', + 'reload': '\ue462', + 'starhalf': '\ue463', + 'spinner': '\ue464', + 'spinner-cycle': '\ue465', + 'search': '\ue466', + 'plusempty': '\ue468', + 'forward': '\ue470', + 'back': '\ue471', + 'left-nav': '\ue471', + 'checkmarkempty': '\ue472', + 'home': '\ue500', + 'navigate': '\ue501', + 'gear': '\ue502', + 'paperplane': '\ue503', + 'info': '\ue504', + 'help': '\ue505', + 'locked': '\ue506', + 'more': '\ue507', + 'flag': '\ue508', + 'home-filled': '\ue530', + 'gear-filled': '\ue532', + 'info-filled': '\ue534', + 'help-filled': '\ue535', + 'more-filled': '\ue537', + 'settings': '\ue560', + 'list': '\ue562', + 'bars': '\ue563', + 'loop': '\ue565', + 'paperclip': '\ue567', + 'eye': '\ue568', + 'arrowup': '\ue580', + 'arrowdown': '\ue581', + 'arrowleft': '\ue582', + 'arrowright': '\ue583', + 'arrowthinup': '\ue584', + 'arrowthindown': '\ue585', + 'arrowthinleft': '\ue586', + 'arrowthinright': '\ue587', + 'pulldown': '\ue588', + 'closefill': '\ue589', + 'sound': '\ue590', + 'scan': '\ue612' +} diff --git a/components/uni-icons/uni-icons.vue b/components/uni-icons/uni-icons.vue new file mode 100644 index 0000000..85b4180 --- /dev/null +++ b/components/uni-icons/uni-icons.vue @@ -0,0 +1,57 @@ + + + + + diff --git a/components/uni-nav-bar/uni-nav-bar.vue b/components/uni-nav-bar/uni-nav-bar.vue new file mode 100644 index 0000000..0d4500d --- /dev/null +++ b/components/uni-nav-bar/uni-nav-bar.vue @@ -0,0 +1,237 @@ + + + + + diff --git a/components/uni-status-bar/uni-status-bar.vue b/components/uni-status-bar/uni-status-bar.vue new file mode 100644 index 0000000..4d9fb30 --- /dev/null +++ b/components/uni-status-bar/uni-status-bar.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/components/virtual-button/virtual-button.vue b/components/virtual-button/virtual-button.vue new file mode 100644 index 0000000..94eff05 --- /dev/null +++ b/components/virtual-button/virtual-button.vue @@ -0,0 +1,157 @@ + + + + + + diff --git a/components/xinyu-logistics/xinyu-logistics.vue b/components/xinyu-logistics/xinyu-logistics.vue new file mode 100644 index 0000000..14aa218 --- /dev/null +++ b/components/xinyu-logistics/xinyu-logistics.vue @@ -0,0 +1,306 @@ + + + + + diff --git a/config/baseConfig.js b/config/baseConfig.js new file mode 100644 index 0000000..83e195f --- /dev/null +++ b/config/baseConfig.js @@ -0,0 +1,63 @@ +// 环境判断:开发、生产 +const envType = process.env.NODE_ENV === 'development' ? 'develop' : 'produce'; +// console.log(envType); +// 获取当前app的版本 +const systemInfo = uni.getSystemInfoSync(); +// 应用程序版本号 +// 条件编译,只在H5渲染 +const version_number = systemInfo.appVersion ? systemInfo.appVersion : '0.0.1'; +console.log(version_number,'版本号'); +const apiUrl = { + develop: { + // apiBaseUrl:'http://192.168.2.17:8080', // cky + // apiBaseUrl:'http://192.168.2.130:8905', // 130 + // apiBaseUrl: 'http://192.168.2.51:9321', // 正式 + // apiBaseUrl:'http://192.168.2.130:8905', // 130 + // apiBaseUrl: 'http://192.168.2.51:9321', // 正式 + // apiBaseUrl: 'http://192.168.2.130:8905', + apiBaseUrl: 'https://api.app.blindbox.06zk.com', // 正式 + // apiBaseUrl:'https://test.blindbox.06zk.com/api', // 101 + // apiBaseUrl:'http://192.168.2.71:8080', // 101 + + wsUrl: 'ws://xxx', // 正式WebSocket连接地址 + weChatCode: 'https://auth.wechat.06zk.com', + apiVersion:'0.0.1', + appVersion:version_number + }, + produce: { + // apiBaseUrl:'http://192.168.2.130:8905', // 130 + // apiBaseUrl: 'https://api.app.blindbox.06zk.com', // 正式 + // apiBaseUrl:'https://test.blindbox.06zk.com/api', // 101 + // apiBaseUrl: 'http://192.168.2.51:9321', // 正式 + apiBaseUrl: 'https://api.app.blindbox.06zk.com', // 正式 + // apiBaseUrl:'https://test.blindbox.06zk.com/api', // 101 + // apiBaseUrl: 'http://192.168.2.51:9321', // 正式 + wsUrl: 'ws://xxxx', // 正式WebSocket连接地址 + weChatCode: 'https://auth.wechat.06zk.com', + apiVersion:'0.0.1', + appVersion:version_number + // weChatCode: 'https://auth.wechat.miyamama.cn' //正式 + } +}; + +const ApiVersion = function() { + return apiUrl[envType]['apiVersion'] +}; +const AppVersion = function() { + return apiUrl[envType]['appVersion'] +}; +const baseUrl = function(nameSpace) { + return apiUrl[envType][nameSpace] +}; + +// 其他服务地址配置 +const otherServerUrl = { + // gameUrl: 'http://web.wgmwdt.com/games' +} + +export { + baseUrl, + otherServerUrl, + ApiVersion, + AppVersion +}; \ No newline at end of file diff --git a/get-weixin-code.html b/get-weixin-code.html new file mode 100755 index 0000000..eeca52e --- /dev/null +++ b/get-weixin-code.html @@ -0,0 +1,95 @@ + + + + + + 微信登录 + + + + + + + + \ No newline at end of file diff --git a/js_sdk/nl-precisionNum/package.json b/js_sdk/nl-precisionNum/package.json new file mode 100644 index 0000000..dd62125 --- /dev/null +++ b/js_sdk/nl-precisionNum/package.json @@ -0,0 +1,19 @@ +{ + "id": "nl-precisionNum", + "name": "防止加减乘除精度丢失", + "version": "1.0.2", + "description": "运算时防止数据精度丢失", + "keywords": [ + "numAdd", + "numSub", + "numMulti", + "numDiv" + ], + "dcloudext": { + "category": [ + "JS SDK", + "通用 SDK" + ] + }, + "displayName": "防止加减乘除精度丢失" +} \ No newline at end of file diff --git a/js_sdk/nl-precisionNum/precisionNum.js b/js_sdk/nl-precisionNum/precisionNum.js new file mode 100644 index 0000000..2f34f2d --- /dev/null +++ b/js_sdk/nl-precisionNum/precisionNum.js @@ -0,0 +1,104 @@ +/* + * 判断obj是否为一个整数 整数取整后还是等于自己。利用这个特性来判断是否是整数 + */ +function isInteger(obj) { + // 或者使用 Number.isInteger() + return Math.floor(obj) === obj +} +/* + * 将一个浮点数转成整数,返回整数和倍数。如 3.14 >> 314,倍数是 100 + * @param floatNum {number} 小数 + * @return {object} + * {times:100, num: 314} + */ +function toInteger(floatNum) { + // 初始化数字与精度 times精度倍数 num转化后的整数 + var ret = { + times: 1, + num: 0 + } + var isNegative = floatNum < 0 //是否是小数 + if (isInteger(floatNum)) { // 是否是整数 + ret.num = floatNum + return ret //是整数直接返回 + } + var strfi = floatNum + '' // 转换为字符串 + var dotPos = strfi.indexOf('.') + var len = strfi.substr(dotPos + 1).length // 拿到小数点之后的位数 + var times = Math.pow(10, len) // 精度倍数 + /* 为什么加0.5? + 前面讲过乘法也会出现精度问题 + 假设传入0.16344556此时倍数为100000000 + Math.abs(0.16344556) * 100000000=0.16344556*10000000=1634455.5999999999 + 少了0.0000000001 + 加上0.5 0.16344556*10000000+0.5=1634456.0999999999 parseInt之后乘法的精度问题得以矫正 + */ + var intNum = parseInt(Math.abs(floatNum) * times + 0.5, 10) + ret.times = times + if (isNegative) { + intNum = -intNum + } + ret.num = intNum + return ret +} + +/* + * 核心方法,实现加减乘除运算,确保不丢失精度 + * 思路:把小数放大为整数(乘),进行算术运算,再缩小为小数(除) + * @param a {number} 运算数1 + * @param b {number} 运算数2 + */ +function operation(a, b, op) { + var o1 = toInteger(a) + var o2 = toInteger(b) + var n1 = o1.num // 3.25+3.153 + var n2 = o2.num + var t1 = o1.times + var t2 = o2.times + var max = t1 > t2 ? t1 : t2 + var result = null + switch (op) { + // 加减需要根据倍数关系来处理 + case 'add': + if (t1 === t2) { // 两个小数倍数相同 + result = n1 + n2 + } else if (t1 > t2) { + // o1 小数位 大于 o2 + result = n1 + n2 * (t1 / t2) + } else { // o1小数位小于 o2 + result = n1 * (t2 / t1) + n2 + } + return result / max + case 'subtract': + if (t1 === t2) { + result = n1 - n2 + } else if (t1 > t2) { + result = n1 - n2 * (t1 / t2) + } else { + result = n1 * (t2 / t1) - n2 + } + return result / max + case 'multiply': + // 325*3153/(100*1000) 扩大100倍 ==>缩小100倍 + result = (n1 * n2) / (t1 * t2) + return result + case 'divide': + // (325/3153)*(1000/100) 缩小100倍 ==>扩大100倍 + result = (n1 / n2) * (t2 / t1) + return result + } +} + +// 加减乘除的四个接口 +export function numAdd(a, b) { + return operation(a, b, 'add') +} +export function numSub(a, b) { + return operation(a, b, 'subtract') +} +export function numMulti(a, b) { + return operation(a, b, 'multiply') +} +export function numDiv(a, b) { + return operation(a*100, b*100, 'divide') +} diff --git a/login.html b/login.html new file mode 100755 index 0000000..177113f --- /dev/null +++ b/login.html @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/main.js b/main.js new file mode 100644 index 0000000..06ae30e --- /dev/null +++ b/main.js @@ -0,0 +1,38 @@ +import Vue from 'vue' +import App from './App' + +import msgUtils from './utils/msgUtils.js' +import path from './utils/skip' +import '@/utils/filter/filterUtils.js' + +// 注册全局组件 +import MescrollBody from "@/components/mescroll-uni/mescroll-body.vue" +import MescrollUni from "@/components/mescroll-uni/mescroll-uni.vue" +Vue.component('mescroll-body', MescrollBody) +Vue.component('mescroll-uni', MescrollUni) + + + + +// #ifdef H5 +// 提交前需要注释 本地调试使用 +// const vconsole = require('vconsole') +// Vue.prototype.$vconsole = new vconsole() // 使用vconsole +// #endif + +import CustomNavbarPage from '@/pages/components/customNavbarPage.vue' +import CropStatusbarHeight from '@/pages/components/crop-statusbar-height/crop-statusbar-height.vue' +Vue.component('custom-navbar-page', CustomNavbarPage) +Vue.component('crop-statusbar-height', CropStatusbarHeight) + +Vue.config.productionTip = false +Vue.prototype.$api = msgUtils +Vue.prototype.$path = path + +App.mpType = 'app' + +const app = new Vue({ + ...App, + path +}) +app.$mount() diff --git a/make-dev.sh b/make-dev.sh new file mode 100644 index 0000000..84c2175 --- /dev/null +++ b/make-dev.sh @@ -0,0 +1,3 @@ +docker build -t registry.cn-shanghai.aliyuncs.com/box-mall/box-mall-app-web:2.0 --platform=linux/amd64 . + +docker push registry.cn-shanghai.aliyuncs.com/box-mall/box-mall-app-web:2.0 \ No newline at end of file diff --git a/make-test.sh b/make-test.sh new file mode 100644 index 0000000..731836c --- /dev/null +++ b/make-test.sh @@ -0,0 +1,3 @@ +docker build -t registry.cn-shanghai.aliyuncs.com/box-mall/box-mall-app-web:1.0 --platform=linux/amd64 . + +docker push registry.cn-shanghai.aliyuncs.com/box-mall/box-mall-app-web:1.0 \ No newline at end of file diff --git a/make.sh b/make.sh new file mode 100644 index 0000000..bf1c9a2 --- /dev/null +++ b/make.sh @@ -0,0 +1,3 @@ +docker build -t registry.cn-shanghai.aliyuncs.com/miyamama_box/box-mall-app-web:1.0 --platform=linux/amd64 . + +docker push registry.cn-shanghai.aliyuncs.com/miyamama_box/box-mall-app-web:1.0 \ No newline at end of file diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..7fee793 --- /dev/null +++ b/manifest.json @@ -0,0 +1,181 @@ +{ + "name" : "妙趣盲盒", + "appid" : "__UNI__8AC2CA7", + "description" : "", + "versionName" : "1.0.0", + "versionCode" : 100, + "transformPx" : false, + /* 5+App特有相关 */ + "app-plus" : { + "safearea" : { + "bottom" : { + "offset" : "auto" + } + }, + "usingComponents" : true, + "nvueCompiler" : "uni-app", + "compilerVersion" : 3, + "splashscreen" : { + "alwaysShowBeforeRender" : false, + "waiting" : false, + "autoclose" : true, + "delay" : 0 + }, + /* 模块配置 */ + "modules" : { + "Maps" : {}, + "OAuth" : {}, + "Payment" : {}, + "Share" : {} + }, + /* 应用发布信息 */ + "distribute" : { + /* android打包配置 */ + "android" : { + "permissions" : [ + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "" + ], + "autoSdkPermissions" : false + }, + /* ios打包配置 */ + "ios" : {}, + /* SDK配置 */ + "sdkConfigs" : { + "ad" : {}, + "maps" : { + "amap" : { + "appkey_ios" : "40a745f83e5c11c12aa6c7dea464dbb9", + "appkey_android" : "40a745f83e5c11c12aa6c7dea464dbb9" + } + }, + "oauth" : { + "weixin" : { + "appid" : "wx836b447885f16f22", + "UniversalLinks" : "" + } + }, + "payment" : { + "weixin" : { + "__platform__" : [ "ios", "android" ], + "appid" : "wx836b447885f16f22", + "UniversalLinks" : "" + }, + "alipay" : { + "__platform__" : [ "ios", "android" ] + } + }, + "share" : { + "weixin" : { + "appid" : "wx836b447885f16f22", + "UniversalLinks" : "" + } + } + }, + "splashscreen" : { + "androidStyle" : "common", + "android" : { + "hdpi" : "static/common/splash.9.png", + "xhdpi" : "static/common/splash.9.png", + "xxhdpi" : "static/common/splash.9.png" + } + }, + "icons" : { + "android" : { + "hdpi" : "unpackage/res/icons/72x72.png", + "xhdpi" : "unpackage/res/icons/96x96.png", + "xxhdpi" : "unpackage/res/icons/144x144.png", + "xxxhdpi" : "unpackage/res/icons/192x192.png" + }, + "ios" : { + "appstore" : "unpackage/res/icons/1024x1024.png", + "ipad" : { + "app" : "unpackage/res/icons/76x76.png", + "app@2x" : "unpackage/res/icons/152x152.png", + "notification" : "unpackage/res/icons/20x20.png", + "notification@2x" : "unpackage/res/icons/40x40.png", + "proapp@2x" : "unpackage/res/icons/167x167.png", + "settings" : "unpackage/res/icons/29x29.png", + "settings@2x" : "unpackage/res/icons/58x58.png", + "spotlight" : "unpackage/res/icons/40x40.png", + "spotlight@2x" : "unpackage/res/icons/80x80.png" + }, + "iphone" : { + "app@2x" : "unpackage/res/icons/120x120.png", + "app@3x" : "unpackage/res/icons/180x180.png", + "notification@2x" : "unpackage/res/icons/40x40.png", + "notification@3x" : "unpackage/res/icons/60x60.png", + "settings@2x" : "unpackage/res/icons/58x58.png", + "settings@3x" : "unpackage/res/icons/87x87.png", + "spotlight@2x" : "unpackage/res/icons/80x80.png", + "spotlight@3x" : "unpackage/res/icons/120x120.png" + } + } + } + }, + "uniStatistics" : { + "enable" : false + } + }, + /* 快应用特有相关 */ + "quickapp" : {}, + /* 小程序特有相关 */ + "mp-weixin" : { + "appid" : "wx836b447885f16f22", + "setting" : { + "urlCheck" : false, + "es6" : true + }, + "usingComponents" : true, + "permission" : { + "scope.userLocation" : { + "desc" : "获取与门店距离" + } + }, + "requiredPrivateInfos" : [ "getLocation" ] + }, + "mp-alipay" : { + "usingComponents" : true + }, + "mp-baidu" : { + "usingComponents" : true + }, + "mp-toutiao" : { + "usingComponents" : true + }, + "uniStatistics" : { + "enable" : false + }, + "h5" : { + "router" : { + "mode" : "hash", + "base" : "./" + } + }, + "uniCloud" : { + "provider" : "aliyun", + "spaceId" : "mp-ee8153d2-d55b-4e47-82d3-64303d9910ea", + "clientSecret" : "c8SiFkxUtsnS/CBjDJBgbg==" + } +} diff --git a/mixins/mixins.js b/mixins/mixins.js new file mode 100755 index 0000000..d8498cb --- /dev/null +++ b/mixins/mixins.js @@ -0,0 +1,76 @@ +export const myMixins = { + components: {}, + data() { + return { + mixinsTimer:null, + mixinsTime:0, + btnTimer:null + }; + }, + onShow(){ + // pages/index/index //首页 + // pages/index/detail //盲盒详情 + // pages/index/card //使用提示卡 + // pages/index/confirmOrder //盲盒确认订单 + // pages/index/confirmOrder //盲盒支付成功页面 + // pages/index/prize //开奖页面 + + // pages/product/product //商品列表 + // pages/search/index//商品搜索 + // pages/search/search-list//商品搜索列表 + // pages/product/detail //商品详情页 + // pages/order/confirm //商品确认订单 + // pages/shop/paySuccess //商品支付成功页面 + + + // pages/mine/sign//签到 + + + // pages/mine/index //个人中心 + // pages/mine/setting //设置 + // pages/mine/editName //修改昵称 + // pages/agreement/index //用户协议 + // pages/agreement/privacy //隐私政策 + // pages/mine/about //关于我们 + // pages/mine/point //积分使用记录 + // pages/mine/coupon //优惠券 + // pages/mine/moreCoupon //更多优惠券 + // pages/mine/boxRecrd //物品 + // pages/mine/boxConfirm//物品发货提交订单 + // pages/order/index//我的订单 + // pages/mine/orderStatusDetail//订单详情 + // pages/mine/boxOrder//盲盒订单 + // pages/mine/address//地址管理 + // pages/mine/addAddress //编辑新增地址 + // pages/mine/collect//收藏列表 + + + const pages = getCurrentPages(); + const currentPage = pages[pages.length - 1]; + const url = currentPage.route; // 当前页面路径 + const options = currentPage.options; // 当前页面参数 + console.log(url); + this.mixinsTimer = setInterval(() => { + this.mixinsTime++ + },1000) + }, + onHide(){ + clearInterval(this.mixinsTimer) + console.log(this.mixinsTime) + this.mixinsTimer = null + this.mixinsTime = 0 + console.log('页面隐藏,即将返回上一页,'); + + this.btnTimer = Math.floor(Math.random() * (1 - 100000 + 1)) + 100000 + clearInterval(this.btnTimer) + + }, + onUnload(){ + console.log('页面卸载,即将返回上一页'); + }, + mounted() { + + }, + methods: { + }, +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..becc6e2 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "exchangeMatch", + "version": "1.0.0", + "description": "", + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "crypto-js": "^4.2.0", + "decimal": "^0.0.2", + "decimal.js": "^10.4.3", + "hqchart": "^1.1.8790", + "jquery": "^3.5.1", + "lottie-web": "^5.7.3", + "vconsole": "^3.14.6", + "wx-server-sdk": "^2.5.3" + } +} diff --git a/pages.json b/pages.json new file mode 100644 index 0000000..7135f47 --- /dev/null +++ b/pages.json @@ -0,0 +1,938 @@ +{ + "pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocati,n/pages + + { + "path": "pages/index/new-index", // 首页 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "首页", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/index/sign", // 签到 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "签到", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/index/activity", // 活动 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "活动", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/index/webview", // 首页 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "客服", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/index/new-index-y", // 首页 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "首页", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/index/ranking", // 排行榜 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "排行榜", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/index/lastRanking", // 上期排行榜 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "上期排行榜", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/index/boxDetail", // 盲盒详情 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "详情", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/index/paySuc", // + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "支付", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/index/boxOrderConfirm", + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "提交订单", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/index/boxPaySuccess", + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "支付成功", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/index/draw", + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "盲盒开奖", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/index/drawNine", + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "盲盒开奖", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/index/drawFree", + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "盲盒开奖", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/shop/index", + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "商城", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/shop/detail", + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "商品详情", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/shop/confirm", + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "提交订单", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/shop/search", // 搜索 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "搜索", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/shop/search-list", // 搜索 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "搜索", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/search/index", // 搜索 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "搜索", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/index/index", // 首页 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/index/card", // 提示卡 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "提示卡", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/index/order", // 盲盒购买订单 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/login/login", // 登录 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "登录", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/login/shut-down", // 封停 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "禁用", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/agreement/index", // 用户协议 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "用户协议", + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/agreement/privacy", // 隐私政策 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "隐私政策", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + // "bounce": "none" + } + } + }, + { + "path": "pages/login/bindPhone", // 绑定手机号 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/testPay/testPay", // 测试支付 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "支付", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/login/registerAndForget", // 忘记密码注册 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/shop/paySuccess", // 商城支付成功 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "支付成功", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none", + "scrollIndicator":"none" + } + } + }, + { + "path": "pages/mine/index", // 我的 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/white", // 我的 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/virtual", // 商城支付成功 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "虚拟订单", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none", + "scrollIndicator":"none" + } + } + }, + { + "path": "pages/mine/virtualDetail", // 商城支付成功 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "订单详情", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none", + "scrollIndicator":"none" + } + } + }, + { + "path": "pages/mine/payVirtualSuccess", // 商城支付成功 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "兑换成功", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none", + "scrollIndicator":"none" + } + } + }, + { + "path": "pages/mine/prompt", // 提示卡 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "提示卡", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/customer", // 我的 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "客服", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/editName", // 修改昵称 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "修改昵称", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/login/bind", // 绑定手机号 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/login/password", // 输入密码 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/search/search-list", // 搜索商品 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/order/confirm", //订单 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/order/index", //订单 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "onReachBottomDistance": 100, + "navigationBarTitleText": "我的订单", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/mine", //个人中心 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "个人中心", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/boxConfirm", //盲盒物品发货预览 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/boxOrder", //盲盒物品发货预览 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "盲盒购买订单", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/sign", //签到 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/point", // + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "积分使用记录", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/setting", //设置 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "设置", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/boxRecrd", //物品 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "我的物品", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + + { + "path": "pages/mine/collect", //收藏 + "style": { + "navigationBarTextStyle": "white", + "navigationBarTitleText": "我的收藏", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/orderStatusDetail", //我的订单状态详情 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "订单详情", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/address", //收获地址 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "我的地址", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/addAddress", //新增地址 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "新增地址", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/notice", //公告 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/noticeDetail", //公告详情 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/about", //关于我们 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": true, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/coupon", //优惠券 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "我的优惠券", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/moreCoupon", //更多优惠券 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "更多优惠券", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/feedback", //意见反馈 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/topUp", //充值 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "充值", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/topUpOrder", //充值提交订单 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "提交订单", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/topUpSuc", //充值成功 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "充值成功", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + { + "path": "pages/mine/orderBoxDetail", //盲盒订单详情 + "style": { + "navigationBarTextStyle": "white", + "enablePullDownRefresh": false, + "navigationBarTitleText": "订单详情", + "app-plus": { + // 将回弹属性关掉 + "bounce": "none" + } + } + }, + + // { + // "path" : "pages/index/index", + // "style" : + // { + // "navigationBarTitleText" : "", + // "enablePullDownRefresh" : false, + // "onReachBottomDistance": 100 + // } + // }, + { + "path" : "pages/index/detail", + "style" : + { + "navigationBarTitleText" : "", + "enablePullDownRefresh" : false + } + }, + { + "path" : "pages/index/confirmOrder", + "style" : + { + "navigationBarTitleText" : "", + "enablePullDownRefresh" : false + } + }, + { + "path" : "pages/index/prize", + "style" : + { + "navigationBarTitleText" : "", + "enablePullDownRefresh" : false + } + }, + { + "path" : "pages/product/product", + "style" : + { + "navigationBarTitleText" : "", + "enablePullDownRefresh" : false + } + }, + { + "path" : "pages/product/detail", + "style" : + { + "navigationBarTitleText" : "", + "enablePullDownRefresh" : false + } + }, + { + "path" : "pages/agreement/nonage-rule", + "style" : + { + "navigationBarTitleText": "儿童个人信息保护规则", + "enablePullDownRefresh" : false + } + }, + { + "path" : "pages/agreement/nonage", + "style" : + { + "navigationBarTitleText": "支付协议", + "enablePullDownRefresh" : false + } + }, + { + "path" : "pages/agreement/total", + "style" : + { + "navigationBarTitleText": "协议", + "enablePullDownRefresh" : false + } + }, + { + "path" : "pages/agreement/rule", + "style" : + { + "navigationBarTitleText": "规则", + "enablePullDownRefresh" : false + } + }, + { + "path" : "pages/login/past-due", + "style" : + { + "navigationBarTitleText": "登录已过期", + "enablePullDownRefresh" : false + } + } + + + ], + "globalStyle": { + "navigationStyle": "custom", + "navigationBarTextStyle": "black", + "navigationBarTitleText": "妙趣盲盒", + "navigationBarBackgroundColor": "#FFFFFF", + "backgroundColor": "#F2F2F9" + }, + "tabBar": { + "color": "#888888", + "selectedColor": "#333333", + "borderStyle": "white", + "backgroundColor": "#ffffff", + "iconWidth": "20px", + "list": [{ + "pagePath": "pages/index/new-index", + "iconPath": "static/btnNavBarIcon/home.png", + "selectedIconPath": "static/btnNavBarIcon/home_active.png", + "text": "首页" + }, + { + "pagePath": "pages/shop/index", + "iconPath": "static/btnNavBarIcon/shop.png", + "selectedIconPath": "static/btnNavBarIcon/shop_active.png", + "text": "商城" + }, + { + "pagePath": "pages/mine/boxRecrd", + "iconPath": "static/btnNavBarIcon/qd.png", + "selectedIconPath": "static/btnNavBarIcon/qd_active.png", + "text": "仓库" + }, + { + "pagePath": "pages/mine/mine", + "iconPath": "static/btnNavBarIcon/mine.png", + "selectedIconPath": "static/btnNavBarIcon/mine_acitve.png", + "text": "我的" + } + ] + }, + "easycom": { + "autoscan": true, + "custom": { + "lb-picker": "@/components/lb-picker/index.vue", + "page-popup": "@/pages/components/pagePopUp.vue" + } + }, + "condition": { //模式配置,仅开发期间生效 + "current": 0, //当前激活的模式(list 的索引项) + "list": [{ + "name": "", //模式名称 + "path": "", //启动页面,必选 + "query": "" //启动参数,在页面的onLoad函数里面得到 + }] + } +} diff --git a/pages/agreement/index.vue b/pages/agreement/index.vue new file mode 100644 index 0000000..77e3bff --- /dev/null +++ b/pages/agreement/index.vue @@ -0,0 +1,184 @@ + + + + + + diff --git a/pages/agreement/nonage-rule.vue b/pages/agreement/nonage-rule.vue new file mode 100644 index 0000000..0a4dd7e --- /dev/null +++ b/pages/agreement/nonage-rule.vue @@ -0,0 +1,168 @@ + + + + + + diff --git a/pages/agreement/nonage.vue b/pages/agreement/nonage.vue new file mode 100644 index 0000000..544ff34 --- /dev/null +++ b/pages/agreement/nonage.vue @@ -0,0 +1,115 @@ + + + + + + + diff --git a/pages/agreement/privacy.vue b/pages/agreement/privacy.vue new file mode 100644 index 0000000..19e16b0 --- /dev/null +++ b/pages/agreement/privacy.vue @@ -0,0 +1,378 @@ + + + + + + + + diff --git a/pages/agreement/rule.vue b/pages/agreement/rule.vue new file mode 100644 index 0000000..aa61a6e --- /dev/null +++ b/pages/agreement/rule.vue @@ -0,0 +1,123 @@ + + + + + + + diff --git a/pages/agreement/total.vue b/pages/agreement/total.vue new file mode 100644 index 0000000..62feb0c --- /dev/null +++ b/pages/agreement/total.vue @@ -0,0 +1,329 @@ + + + + + \ No newline at end of file diff --git a/pages/components/crop-statusbar-height/crop-statusbar-height.vue b/pages/components/crop-statusbar-height/crop-statusbar-height.vue new file mode 100644 index 0000000..303c773 --- /dev/null +++ b/pages/components/crop-statusbar-height/crop-statusbar-height.vue @@ -0,0 +1,54 @@ + + + + diff --git a/pages/components/customNavbarPage.vue b/pages/components/customNavbarPage.vue new file mode 100644 index 0000000..9c74563 --- /dev/null +++ b/pages/components/customNavbarPage.vue @@ -0,0 +1,36 @@ + + + + diff --git a/pages/components/customer.vue b/pages/components/customer.vue new file mode 100644 index 0000000..22ed21c --- /dev/null +++ b/pages/components/customer.vue @@ -0,0 +1,53 @@ + + + + + \ No newline at end of file diff --git a/pages/components/empyt.vue b/pages/components/empyt.vue new file mode 100644 index 0000000..cd28c85 --- /dev/null +++ b/pages/components/empyt.vue @@ -0,0 +1,63 @@ + + + + + \ No newline at end of file diff --git a/pages/components/floatWindow copy 1.vue b/pages/components/floatWindow copy 1.vue new file mode 100644 index 0000000..946469e --- /dev/null +++ b/pages/components/floatWindow copy 1.vue @@ -0,0 +1,321 @@ + + + + + \ No newline at end of file diff --git a/pages/components/floatWindow copy.vue b/pages/components/floatWindow copy.vue new file mode 100644 index 0000000..5f4b373 --- /dev/null +++ b/pages/components/floatWindow copy.vue @@ -0,0 +1,210 @@ + + + + + \ No newline at end of file diff --git a/pages/components/floatWindow.vue b/pages/components/floatWindow.vue new file mode 100644 index 0000000..f21c3d2 --- /dev/null +++ b/pages/components/floatWindow.vue @@ -0,0 +1,549 @@ + + + + + \ No newline at end of file diff --git a/pages/components/header.vue b/pages/components/header.vue new file mode 100644 index 0000000..4fab1bc --- /dev/null +++ b/pages/components/header.vue @@ -0,0 +1,67 @@ + + + + + \ No newline at end of file diff --git a/pages/components/indexNavBarSkeletonPage.vue b/pages/components/indexNavBarSkeletonPage.vue new file mode 100644 index 0000000..21a0eb6 --- /dev/null +++ b/pages/components/indexNavBarSkeletonPage.vue @@ -0,0 +1,90 @@ + + + + + \ No newline at end of file diff --git a/pages/components/isPayDlg.vue b/pages/components/isPayDlg.vue new file mode 100644 index 0000000..e662619 --- /dev/null +++ b/pages/components/isPayDlg.vue @@ -0,0 +1,173 @@ + + + + + \ No newline at end of file diff --git a/pages/components/mixins/navBarPageMixin.js b/pages/components/mixins/navBarPageMixin.js new file mode 100644 index 0000000..8dbd83b --- /dev/null +++ b/pages/components/mixins/navBarPageMixin.js @@ -0,0 +1,88 @@ +/** + * 自定义导航栏的骨架页面的属性配置 + */ +const navBarPageMixin = { + props: { + leftIcon: { + type: String, + default: '' + }, + leftText: { + type: String, + default: "" + }, + rightText: { + type: String, + default: '' + }, + rightTextColor: { + type: String, + default: '#5FC48D' + }, + backgroundColor: { + type: String, + default: "#FFFFFF" + }, + title: { + type: String, + default: '' + }, + // 标题字体颜色 + color: { + type: String, + default: "#fff" + }, + fixed: { + type: Boolean, + default: true + }, + clickLeftFn: { + type: [Boolean, Function], + default: false + }, + clickRightFn: { + type: [Boolean, Function], + default: false + }, + // 右侧是否需要显示 + rightShow: { + type: [String, Boolean], + default: true + }, + // BottomNavBar配置 + curKey: { + type: String, + default: 'mall' + }, + // 是否需要增加平台状态栏高度 + platformsHeight: { + type: [Boolean, String], + default: true + }, + // 左侧icon的颜色配置 + leftIconColor: { + type: String, + default: "" + } + }, + methods: { + clickLeft () { + !this.clickLeftFn ? this.back() : this.clickLeftFn() + }, + clickRight () { + this.clickRightFn && this.clickRightFn() + }, + back(){ + let pages = getCurrentPages() + if(pages.length == 1){ + uni.reLaunch({ + url:'/pages/home/index' + }) + }else{ + uni.navigateBack() + } + } + } +} + +export default navBarPageMixin; diff --git a/pages/components/nav.vue b/pages/components/nav.vue new file mode 100644 index 0000000..361d04d --- /dev/null +++ b/pages/components/nav.vue @@ -0,0 +1,54 @@ + + + + + \ No newline at end of file diff --git a/pages/components/navBarSkeletonPage.vue b/pages/components/navBarSkeletonPage.vue new file mode 100644 index 0000000..c1ba845 --- /dev/null +++ b/pages/components/navBarSkeletonPage.vue @@ -0,0 +1,90 @@ + + + + diff --git a/pages/components/pagePopUp.vue b/pages/components/pagePopUp.vue new file mode 100644 index 0000000..98bc83f --- /dev/null +++ b/pages/components/pagePopUp.vue @@ -0,0 +1,231 @@ + + + + + \ No newline at end of file diff --git a/pages/components/paymentPassword.vue b/pages/components/paymentPassword.vue new file mode 100644 index 0000000..91769fb --- /dev/null +++ b/pages/components/paymentPassword.vue @@ -0,0 +1,104 @@ + + + + + diff --git a/pages/components/quotationList.vue b/pages/components/quotationList.vue new file mode 100644 index 0000000..a4a304b --- /dev/null +++ b/pages/components/quotationList.vue @@ -0,0 +1,294 @@ + + + + + + diff --git a/pages/components/spine.vue b/pages/components/spine.vue new file mode 100644 index 0000000..e1b4a0a --- /dev/null +++ b/pages/components/spine.vue @@ -0,0 +1,114 @@ + + + + + + + \ No newline at end of file diff --git a/pages/index/activity.vue b/pages/index/activity.vue new file mode 100644 index 0000000..6cec5ab --- /dev/null +++ b/pages/index/activity.vue @@ -0,0 +1,1686 @@ + + + + + \ No newline at end of file diff --git a/pages/index/boxDetail.vue b/pages/index/boxDetail.vue new file mode 100644 index 0000000..730328e --- /dev/null +++ b/pages/index/boxDetail.vue @@ -0,0 +1,908 @@ + + + + + \ No newline at end of file diff --git a/pages/index/boxOrderConfirm.vue b/pages/index/boxOrderConfirm.vue new file mode 100644 index 0000000..9c88d17 --- /dev/null +++ b/pages/index/boxOrderConfirm.vue @@ -0,0 +1,590 @@ + + + + + \ No newline at end of file diff --git a/pages/index/boxPaySuccess.vue b/pages/index/boxPaySuccess.vue new file mode 100644 index 0000000..d6db93c --- /dev/null +++ b/pages/index/boxPaySuccess.vue @@ -0,0 +1,291 @@ + + + + + \ No newline at end of file diff --git a/pages/index/card copy 1.vue b/pages/index/card copy 1.vue new file mode 100644 index 0000000..7d5fc0b --- /dev/null +++ b/pages/index/card copy 1.vue @@ -0,0 +1,597 @@ + + + + + \ No newline at end of file diff --git a/pages/index/card copy.vue b/pages/index/card copy.vue new file mode 100644 index 0000000..fc27d5a --- /dev/null +++ b/pages/index/card copy.vue @@ -0,0 +1,223 @@ + + + + + \ No newline at end of file diff --git a/pages/index/card.vue b/pages/index/card.vue new file mode 100644 index 0000000..253c694 --- /dev/null +++ b/pages/index/card.vue @@ -0,0 +1,798 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/bgGuang copy.vue b/pages/index/components/bgGuang copy.vue new file mode 100644 index 0000000..3a19c82 --- /dev/null +++ b/pages/index/components/bgGuang copy.vue @@ -0,0 +1,49 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/bgGuang.vue b/pages/index/components/bgGuang.vue new file mode 100644 index 0000000..35acdf1 --- /dev/null +++ b/pages/index/components/bgGuang.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/pages/index/components/box.vue b/pages/index/components/box.vue new file mode 100644 index 0000000..65bb6f7 --- /dev/null +++ b/pages/index/components/box.vue @@ -0,0 +1,89 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/btn.vue b/pages/index/components/btn.vue new file mode 100644 index 0000000..54b94e2 --- /dev/null +++ b/pages/index/components/btn.vue @@ -0,0 +1,76 @@ + + + + + + diff --git a/pages/index/components/bubble.vue b/pages/index/components/bubble.vue new file mode 100644 index 0000000..a6ba5cd --- /dev/null +++ b/pages/index/components/bubble.vue @@ -0,0 +1,90 @@ + + + + + + \ No newline at end of file diff --git a/pages/index/components/buy.vue b/pages/index/components/buy.vue new file mode 100644 index 0000000..f79f3d5 --- /dev/null +++ b/pages/index/components/buy.vue @@ -0,0 +1,366 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/buyActivityBox copy.vue b/pages/index/components/buyActivityBox copy.vue new file mode 100644 index 0000000..b078dd8 --- /dev/null +++ b/pages/index/components/buyActivityBox copy.vue @@ -0,0 +1,984 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/buyActivityBox.vue b/pages/index/components/buyActivityBox.vue new file mode 100644 index 0000000..72d4ba0 --- /dev/null +++ b/pages/index/components/buyActivityBox.vue @@ -0,0 +1,1213 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/buyBox copy.vue b/pages/index/components/buyBox copy.vue new file mode 100644 index 0000000..7cd7b02 --- /dev/null +++ b/pages/index/components/buyBox copy.vue @@ -0,0 +1,1238 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/buyBox.vue b/pages/index/components/buyBox.vue new file mode 100644 index 0000000..b4b5c7c --- /dev/null +++ b/pages/index/components/buyBox.vue @@ -0,0 +1,1404 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/buyBoxRun.vue b/pages/index/components/buyBoxRun.vue new file mode 100644 index 0000000..6097e68 --- /dev/null +++ b/pages/index/components/buyBoxRun.vue @@ -0,0 +1,1569 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/buyFreeBox.vue b/pages/index/components/buyFreeBox.vue new file mode 100644 index 0000000..66be037 --- /dev/null +++ b/pages/index/components/buyFreeBox.vue @@ -0,0 +1,608 @@ + + + + + + \ No newline at end of file diff --git a/pages/index/components/coinDeficit.vue b/pages/index/components/coinDeficit.vue new file mode 100644 index 0000000..64c470d --- /dev/null +++ b/pages/index/components/coinDeficit.vue @@ -0,0 +1,516 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/lihua copy.vue b/pages/index/components/lihua copy.vue new file mode 100644 index 0000000..e5f924d --- /dev/null +++ b/pages/index/components/lihua copy.vue @@ -0,0 +1,66 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/lihua.vue b/pages/index/components/lihua.vue new file mode 100644 index 0000000..280e99c --- /dev/null +++ b/pages/index/components/lihua.vue @@ -0,0 +1,66 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/line.vue b/pages/index/components/line.vue new file mode 100644 index 0000000..8a6e885 --- /dev/null +++ b/pages/index/components/line.vue @@ -0,0 +1,163 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/listBonus.vue b/pages/index/components/listBonus.vue new file mode 100644 index 0000000..19bae7c --- /dev/null +++ b/pages/index/components/listBonus.vue @@ -0,0 +1,377 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/noOpen.vue b/pages/index/components/noOpen.vue new file mode 100644 index 0000000..0eb0f18 --- /dev/null +++ b/pages/index/components/noOpen.vue @@ -0,0 +1,101 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/openBox copy.vue b/pages/index/components/openBox copy.vue new file mode 100644 index 0000000..67f9c37 --- /dev/null +++ b/pages/index/components/openBox copy.vue @@ -0,0 +1,226 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/openBox.vue b/pages/index/components/openBox.vue new file mode 100644 index 0000000..4ff7e8a --- /dev/null +++ b/pages/index/components/openBox.vue @@ -0,0 +1,264 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/openBoxFive.vue b/pages/index/components/openBoxFive.vue new file mode 100644 index 0000000..2cef358 --- /dev/null +++ b/pages/index/components/openBoxFive.vue @@ -0,0 +1,265 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/openBoxNine.vue b/pages/index/components/openBoxNine.vue new file mode 100644 index 0000000..22320e1 --- /dev/null +++ b/pages/index/components/openBoxNine.vue @@ -0,0 +1,295 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/openBoxThree.vue b/pages/index/components/openBoxThree.vue new file mode 100644 index 0000000..c1cc1d5 --- /dev/null +++ b/pages/index/components/openBoxThree.vue @@ -0,0 +1,267 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/openFreeBox.vue b/pages/index/components/openFreeBox.vue new file mode 100644 index 0000000..8b76f55 --- /dev/null +++ b/pages/index/components/openFreeBox.vue @@ -0,0 +1,221 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/openFreeBoxFive.vue b/pages/index/components/openFreeBoxFive.vue new file mode 100644 index 0000000..738ed87 --- /dev/null +++ b/pages/index/components/openFreeBoxFive.vue @@ -0,0 +1,255 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/openFreeBoxThree.vue b/pages/index/components/openFreeBoxThree.vue new file mode 100644 index 0000000..8c978ff --- /dev/null +++ b/pages/index/components/openFreeBoxThree.vue @@ -0,0 +1,264 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/qp.vue b/pages/index/components/qp.vue new file mode 100644 index 0000000..fd8e2a0 --- /dev/null +++ b/pages/index/components/qp.vue @@ -0,0 +1,389 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/raffle.vue b/pages/index/components/raffle.vue new file mode 100644 index 0000000..e201ca8 --- /dev/null +++ b/pages/index/components/raffle.vue @@ -0,0 +1,187 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/rankNum.vue b/pages/index/components/rankNum.vue new file mode 100644 index 0000000..edbac4c --- /dev/null +++ b/pages/index/components/rankNum.vue @@ -0,0 +1,40 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/sign.vue b/pages/index/components/sign.vue new file mode 100644 index 0000000..9aef904 --- /dev/null +++ b/pages/index/components/sign.vue @@ -0,0 +1,348 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/tip.vue b/pages/index/components/tip.vue new file mode 100644 index 0000000..93a37b9 --- /dev/null +++ b/pages/index/components/tip.vue @@ -0,0 +1,293 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/top.vue b/pages/index/components/top.vue new file mode 100644 index 0000000..44e3478 --- /dev/null +++ b/pages/index/components/top.vue @@ -0,0 +1,180 @@ + + + + + \ No newline at end of file diff --git a/pages/index/components/trumpet.vue b/pages/index/components/trumpet.vue new file mode 100644 index 0000000..845c08f --- /dev/null +++ b/pages/index/components/trumpet.vue @@ -0,0 +1,113 @@ + + + + + \ No newline at end of file diff --git a/pages/index/confirmOrder.vue b/pages/index/confirmOrder.vue new file mode 100644 index 0000000..13734c7 --- /dev/null +++ b/pages/index/confirmOrder.vue @@ -0,0 +1,482 @@ + + + + + \ No newline at end of file diff --git a/pages/index/detail.vue b/pages/index/detail.vue new file mode 100644 index 0000000..b97bad6 --- /dev/null +++ b/pages/index/detail.vue @@ -0,0 +1,1361 @@ + + + + + + \ No newline at end of file diff --git a/pages/index/draw copy.vue b/pages/index/draw copy.vue new file mode 100644 index 0000000..5f88d8e --- /dev/null +++ b/pages/index/draw copy.vue @@ -0,0 +1,671 @@ + + + + + \ No newline at end of file diff --git a/pages/index/draw.vue b/pages/index/draw.vue new file mode 100644 index 0000000..69d4fdf --- /dev/null +++ b/pages/index/draw.vue @@ -0,0 +1,736 @@ + + + + + \ No newline at end of file diff --git a/pages/index/drawFree.vue b/pages/index/drawFree.vue new file mode 100644 index 0000000..cb4119e --- /dev/null +++ b/pages/index/drawFree.vue @@ -0,0 +1,549 @@ + + + + + \ No newline at end of file diff --git a/pages/index/drawNine.vue b/pages/index/drawNine.vue new file mode 100644 index 0000000..7913d03 --- /dev/null +++ b/pages/index/drawNine.vue @@ -0,0 +1,675 @@ + + + + + \ No newline at end of file diff --git a/pages/index/index.vue b/pages/index/index.vue new file mode 100644 index 0000000..01eb791 --- /dev/null +++ b/pages/index/index.vue @@ -0,0 +1,743 @@ + + + + + \ No newline at end of file diff --git a/pages/index/lastRanking.vue b/pages/index/lastRanking.vue new file mode 100644 index 0000000..2df1a9e --- /dev/null +++ b/pages/index/lastRanking.vue @@ -0,0 +1,293 @@ + + + + + \ No newline at end of file diff --git a/pages/index/new-index copy 1.vue b/pages/index/new-index copy 1.vue new file mode 100644 index 0000000..b31278c --- /dev/null +++ b/pages/index/new-index copy 1.vue @@ -0,0 +1,1837 @@ + + + + + \ No newline at end of file diff --git a/pages/index/new-index copy.vue b/pages/index/new-index copy.vue new file mode 100644 index 0000000..eb84ad4 --- /dev/null +++ b/pages/index/new-index copy.vue @@ -0,0 +1,1826 @@ + + + + + \ No newline at end of file diff --git a/pages/index/new-index-y.vue b/pages/index/new-index-y.vue new file mode 100644 index 0000000..6329d50 --- /dev/null +++ b/pages/index/new-index-y.vue @@ -0,0 +1,1292 @@ + + + + + \ No newline at end of file diff --git a/pages/index/new-index.vue b/pages/index/new-index.vue new file mode 100644 index 0000000..1bf2d2b --- /dev/null +++ b/pages/index/new-index.vue @@ -0,0 +1,3120 @@ + + + + + \ No newline at end of file diff --git a/pages/index/order.vue b/pages/index/order.vue new file mode 100644 index 0000000..8ff8625 --- /dev/null +++ b/pages/index/order.vue @@ -0,0 +1,317 @@ + + + + + + \ No newline at end of file diff --git a/pages/index/paySuc.vue b/pages/index/paySuc.vue new file mode 100644 index 0000000..aef51d6 --- /dev/null +++ b/pages/index/paySuc.vue @@ -0,0 +1,155 @@ + + + + + + \ No newline at end of file diff --git a/pages/index/prize.vue b/pages/index/prize.vue new file mode 100644 index 0000000..633a7e0 --- /dev/null +++ b/pages/index/prize.vue @@ -0,0 +1,490 @@ + + + + + + \ No newline at end of file diff --git a/pages/index/ranking.vue b/pages/index/ranking.vue new file mode 100644 index 0000000..bcf8f94 --- /dev/null +++ b/pages/index/ranking.vue @@ -0,0 +1,1043 @@ + + + + + \ No newline at end of file diff --git a/pages/index/sign.vue b/pages/index/sign.vue new file mode 100644 index 0000000..1e6e1d6 --- /dev/null +++ b/pages/index/sign.vue @@ -0,0 +1,349 @@ + + + + + \ No newline at end of file diff --git a/pages/index/webview.vue b/pages/index/webview.vue new file mode 100644 index 0000000..279ac52 --- /dev/null +++ b/pages/index/webview.vue @@ -0,0 +1,22 @@ + + + + + \ No newline at end of file diff --git a/pages/index/首页-zuiyou.vue b/pages/index/首页-zuiyou.vue new file mode 100644 index 0000000..eac8178 --- /dev/null +++ b/pages/index/首页-zuiyou.vue @@ -0,0 +1,1099 @@ + + + + + \ No newline at end of file diff --git a/pages/login/bind.vue b/pages/login/bind.vue new file mode 100644 index 0000000..71f8c15 --- /dev/null +++ b/pages/login/bind.vue @@ -0,0 +1,179 @@ + + + + + + diff --git a/pages/login/bindPhone.vue b/pages/login/bindPhone.vue new file mode 100644 index 0000000..6683545 --- /dev/null +++ b/pages/login/bindPhone.vue @@ -0,0 +1,213 @@ + + + + + \ No newline at end of file diff --git a/pages/login/get-weixin-code.html b/pages/login/get-weixin-code.html new file mode 100755 index 0000000..1120153 --- /dev/null +++ b/pages/login/get-weixin-code.html @@ -0,0 +1,92 @@ + + + + + + 微信登录 + + + + + + + \ No newline at end of file diff --git a/pages/login/index.vue b/pages/login/index.vue new file mode 100644 index 0000000..8b5c9e4 --- /dev/null +++ b/pages/login/index.vue @@ -0,0 +1,214 @@ + + + + + + diff --git a/pages/login/login copy.vue b/pages/login/login copy.vue new file mode 100644 index 0000000..a0e1e11 --- /dev/null +++ b/pages/login/login copy.vue @@ -0,0 +1,522 @@ + + + + + + diff --git a/pages/login/login.vue b/pages/login/login.vue new file mode 100644 index 0000000..f02b88e --- /dev/null +++ b/pages/login/login.vue @@ -0,0 +1,344 @@ + + + + + \ No newline at end of file diff --git a/pages/login/password.vue b/pages/login/password.vue new file mode 100644 index 0000000..be9d61e --- /dev/null +++ b/pages/login/password.vue @@ -0,0 +1,187 @@ + + + + + + \ No newline at end of file diff --git a/pages/login/past-due.vue b/pages/login/past-due.vue new file mode 100644 index 0000000..d0d84af --- /dev/null +++ b/pages/login/past-due.vue @@ -0,0 +1,76 @@ + + + + + \ No newline at end of file diff --git a/pages/login/registerAndForget.vue b/pages/login/registerAndForget.vue new file mode 100644 index 0000000..4079809 --- /dev/null +++ b/pages/login/registerAndForget.vue @@ -0,0 +1,236 @@ + + + + + + diff --git a/pages/login/shut-down.vue b/pages/login/shut-down.vue new file mode 100644 index 0000000..90debe3 --- /dev/null +++ b/pages/login/shut-down.vue @@ -0,0 +1,88 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/about.vue b/pages/mine/about.vue new file mode 100644 index 0000000..79ce137 --- /dev/null +++ b/pages/mine/about.vue @@ -0,0 +1,79 @@ + + + + + + \ No newline at end of file diff --git a/pages/mine/addAddress copy.vue b/pages/mine/addAddress copy.vue new file mode 100644 index 0000000..9888d37 --- /dev/null +++ b/pages/mine/addAddress copy.vue @@ -0,0 +1,367 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/addAddress.vue b/pages/mine/addAddress.vue new file mode 100644 index 0000000..fe7f288 --- /dev/null +++ b/pages/mine/addAddress.vue @@ -0,0 +1,239 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/address copy.vue b/pages/mine/address copy.vue new file mode 100644 index 0000000..97e3cd0 --- /dev/null +++ b/pages/mine/address copy.vue @@ -0,0 +1,352 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/address.vue b/pages/mine/address.vue new file mode 100644 index 0000000..a68ed53 --- /dev/null +++ b/pages/mine/address.vue @@ -0,0 +1,269 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/boxConfirm copy 1.vue b/pages/mine/boxConfirm copy 1.vue new file mode 100644 index 0000000..9804c31 --- /dev/null +++ b/pages/mine/boxConfirm copy 1.vue @@ -0,0 +1,481 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/boxConfirm copy.vue b/pages/mine/boxConfirm copy.vue new file mode 100644 index 0000000..d16cc6e --- /dev/null +++ b/pages/mine/boxConfirm copy.vue @@ -0,0 +1,682 @@ + + + + + + diff --git a/pages/mine/boxConfirm.vue b/pages/mine/boxConfirm.vue new file mode 100644 index 0000000..63e0177 --- /dev/null +++ b/pages/mine/boxConfirm.vue @@ -0,0 +1,483 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/boxOrder copy.vue b/pages/mine/boxOrder copy.vue new file mode 100644 index 0000000..ee00f2d --- /dev/null +++ b/pages/mine/boxOrder copy.vue @@ -0,0 +1,327 @@ + + + + \ No newline at end of file diff --git a/pages/mine/boxOrder.vue b/pages/mine/boxOrder.vue new file mode 100644 index 0000000..120b561 --- /dev/null +++ b/pages/mine/boxOrder.vue @@ -0,0 +1,214 @@ + + + + \ No newline at end of file diff --git a/pages/mine/boxRecrd copy.vue b/pages/mine/boxRecrd copy.vue new file mode 100644 index 0000000..c9c7c63 --- /dev/null +++ b/pages/mine/boxRecrd copy.vue @@ -0,0 +1,1858 @@ + + + + \ No newline at end of file diff --git a/pages/mine/boxRecrd.vue b/pages/mine/boxRecrd.vue new file mode 100644 index 0000000..d1ce940 --- /dev/null +++ b/pages/mine/boxRecrd.vue @@ -0,0 +1,2118 @@ + + + + \ No newline at end of file diff --git a/pages/mine/collect copy.vue b/pages/mine/collect copy.vue new file mode 100644 index 0000000..dada2ac --- /dev/null +++ b/pages/mine/collect copy.vue @@ -0,0 +1,270 @@ + + + + + + \ No newline at end of file diff --git a/pages/mine/collect.vue b/pages/mine/collect.vue new file mode 100644 index 0000000..4e9188e --- /dev/null +++ b/pages/mine/collect.vue @@ -0,0 +1,227 @@ + + + + + + \ No newline at end of file diff --git a/pages/mine/components/countdow.vue b/pages/mine/components/countdow.vue new file mode 100644 index 0000000..c63deba --- /dev/null +++ b/pages/mine/components/countdow.vue @@ -0,0 +1,78 @@ + + + \ No newline at end of file diff --git a/pages/mine/coupon copy.vue b/pages/mine/coupon copy.vue new file mode 100644 index 0000000..a1bcf8b --- /dev/null +++ b/pages/mine/coupon copy.vue @@ -0,0 +1,183 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/coupon.vue b/pages/mine/coupon.vue new file mode 100644 index 0000000..45a5031 --- /dev/null +++ b/pages/mine/coupon.vue @@ -0,0 +1,261 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/customer.vue b/pages/mine/customer.vue new file mode 100644 index 0000000..ae0c179 --- /dev/null +++ b/pages/mine/customer.vue @@ -0,0 +1,63 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/editName copy.vue b/pages/mine/editName copy.vue new file mode 100644 index 0000000..f7b5d37 --- /dev/null +++ b/pages/mine/editName copy.vue @@ -0,0 +1,79 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/editName.vue b/pages/mine/editName.vue new file mode 100644 index 0000000..5ec1c4f --- /dev/null +++ b/pages/mine/editName.vue @@ -0,0 +1,105 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/feedback.vue b/pages/mine/feedback.vue new file mode 100644 index 0000000..f781cae --- /dev/null +++ b/pages/mine/feedback.vue @@ -0,0 +1,327 @@ + + + + + + diff --git a/pages/mine/index.vue b/pages/mine/index.vue new file mode 100644 index 0000000..2de7133 --- /dev/null +++ b/pages/mine/index.vue @@ -0,0 +1,703 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/mine.vue b/pages/mine/mine.vue new file mode 100644 index 0000000..bf9df5f --- /dev/null +++ b/pages/mine/mine.vue @@ -0,0 +1,574 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/moreCoupon copy.vue b/pages/mine/moreCoupon copy.vue new file mode 100644 index 0000000..83ea54b --- /dev/null +++ b/pages/mine/moreCoupon copy.vue @@ -0,0 +1,167 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/moreCoupon.vue b/pages/mine/moreCoupon.vue new file mode 100644 index 0000000..c635add --- /dev/null +++ b/pages/mine/moreCoupon.vue @@ -0,0 +1,324 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/notice.vue b/pages/mine/notice.vue new file mode 100644 index 0000000..3e4c351 --- /dev/null +++ b/pages/mine/notice.vue @@ -0,0 +1,182 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/noticeDetail.vue b/pages/mine/noticeDetail.vue new file mode 100644 index 0000000..e329396 --- /dev/null +++ b/pages/mine/noticeDetail.vue @@ -0,0 +1,121 @@ + + + + + + \ No newline at end of file diff --git a/pages/mine/orderBoxDetail.vue b/pages/mine/orderBoxDetail.vue new file mode 100644 index 0000000..5f2ace4 --- /dev/null +++ b/pages/mine/orderBoxDetail.vue @@ -0,0 +1,528 @@ + + + + + + \ No newline at end of file diff --git a/pages/mine/orderStatusDetail copy.vue b/pages/mine/orderStatusDetail copy.vue new file mode 100644 index 0000000..9b7b732 --- /dev/null +++ b/pages/mine/orderStatusDetail copy.vue @@ -0,0 +1,779 @@ + + + + + + \ No newline at end of file diff --git a/pages/mine/orderStatusDetail.vue b/pages/mine/orderStatusDetail.vue new file mode 100644 index 0000000..0e1e63d --- /dev/null +++ b/pages/mine/orderStatusDetail.vue @@ -0,0 +1,895 @@ + + + + + + \ No newline at end of file diff --git a/pages/mine/payVirtualSuccess.vue b/pages/mine/payVirtualSuccess.vue new file mode 100644 index 0000000..eb4885e --- /dev/null +++ b/pages/mine/payVirtualSuccess.vue @@ -0,0 +1,164 @@ + + + + + + \ No newline at end of file diff --git a/pages/mine/point copy.vue b/pages/mine/point copy.vue new file mode 100644 index 0000000..9541672 --- /dev/null +++ b/pages/mine/point copy.vue @@ -0,0 +1,156 @@ + + + + \ No newline at end of file diff --git a/pages/mine/point.vue b/pages/mine/point.vue new file mode 100644 index 0000000..8fda7de --- /dev/null +++ b/pages/mine/point.vue @@ -0,0 +1,167 @@ + + + + \ No newline at end of file diff --git a/pages/mine/prompt.vue b/pages/mine/prompt.vue new file mode 100644 index 0000000..f4497ec --- /dev/null +++ b/pages/mine/prompt.vue @@ -0,0 +1,255 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/setting copy.vue b/pages/mine/setting copy.vue new file mode 100644 index 0000000..f7ab606 --- /dev/null +++ b/pages/mine/setting copy.vue @@ -0,0 +1,256 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/setting.vue b/pages/mine/setting.vue new file mode 100644 index 0000000..1bdff9d --- /dev/null +++ b/pages/mine/setting.vue @@ -0,0 +1,392 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/sign copy.vue b/pages/mine/sign copy.vue new file mode 100644 index 0000000..cf87fa1 --- /dev/null +++ b/pages/mine/sign copy.vue @@ -0,0 +1,241 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/sign.vue b/pages/mine/sign.vue new file mode 100644 index 0000000..a71b87d --- /dev/null +++ b/pages/mine/sign.vue @@ -0,0 +1,582 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/topUp copy.vue b/pages/mine/topUp copy.vue new file mode 100644 index 0000000..1ff8d3b --- /dev/null +++ b/pages/mine/topUp copy.vue @@ -0,0 +1,230 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/topUp.vue b/pages/mine/topUp.vue new file mode 100644 index 0000000..26da742 --- /dev/null +++ b/pages/mine/topUp.vue @@ -0,0 +1,689 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/topUpOrder copy.vue b/pages/mine/topUpOrder copy.vue new file mode 100644 index 0000000..1d3cff2 --- /dev/null +++ b/pages/mine/topUpOrder copy.vue @@ -0,0 +1,158 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/topUpOrder.vue b/pages/mine/topUpOrder.vue new file mode 100644 index 0000000..d834edf --- /dev/null +++ b/pages/mine/topUpOrder.vue @@ -0,0 +1,277 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/topUpSuc copy.vue b/pages/mine/topUpSuc copy.vue new file mode 100644 index 0000000..4f212ec --- /dev/null +++ b/pages/mine/topUpSuc copy.vue @@ -0,0 +1,270 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/topUpSuc.vue b/pages/mine/topUpSuc.vue new file mode 100644 index 0000000..22889ce --- /dev/null +++ b/pages/mine/topUpSuc.vue @@ -0,0 +1,147 @@ + + + + + \ No newline at end of file diff --git a/pages/mine/virtual.vue b/pages/mine/virtual.vue new file mode 100644 index 0000000..901c7e6 --- /dev/null +++ b/pages/mine/virtual.vue @@ -0,0 +1,812 @@ + + + + \ No newline at end of file diff --git a/pages/mine/virtualDetail.vue b/pages/mine/virtualDetail.vue new file mode 100644 index 0000000..ce5a910 --- /dev/null +++ b/pages/mine/virtualDetail.vue @@ -0,0 +1,910 @@ + + + + + + \ No newline at end of file diff --git a/pages/mine/white.vue b/pages/mine/white.vue new file mode 100644 index 0000000..e122449 --- /dev/null +++ b/pages/mine/white.vue @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/pages/order/confirm.vue b/pages/order/confirm.vue new file mode 100644 index 0000000..e9b7431 --- /dev/null +++ b/pages/order/confirm.vue @@ -0,0 +1,593 @@ + + + + + + diff --git a/pages/order/index copy.vue b/pages/order/index copy.vue new file mode 100644 index 0000000..56cd4c8 --- /dev/null +++ b/pages/order/index copy.vue @@ -0,0 +1,433 @@ + + + + \ No newline at end of file diff --git a/pages/order/index.vue b/pages/order/index.vue new file mode 100644 index 0000000..677cd8b --- /dev/null +++ b/pages/order/index.vue @@ -0,0 +1,818 @@ + + + + \ No newline at end of file diff --git a/pages/product/detail.vue b/pages/product/detail.vue new file mode 100644 index 0000000..be1a537 --- /dev/null +++ b/pages/product/detail.vue @@ -0,0 +1,668 @@ + + + + + + diff --git a/pages/product/product.vue b/pages/product/product.vue new file mode 100644 index 0000000..17b00ae --- /dev/null +++ b/pages/product/product.vue @@ -0,0 +1,458 @@ + + + + + diff --git a/pages/search/index.vue b/pages/search/index.vue new file mode 100644 index 0000000..2c04e06 --- /dev/null +++ b/pages/search/index.vue @@ -0,0 +1,236 @@ + + + + + + diff --git a/pages/search/search-list.vue b/pages/search/search-list.vue new file mode 100644 index 0000000..320d6a4 --- /dev/null +++ b/pages/search/search-list.vue @@ -0,0 +1,228 @@ + + + + + \ No newline at end of file diff --git a/pages/shop/cashier copy.vue b/pages/shop/cashier copy.vue new file mode 100644 index 0000000..d181429 --- /dev/null +++ b/pages/shop/cashier copy.vue @@ -0,0 +1,494 @@ + + + + + + \ No newline at end of file diff --git a/pages/shop/confirm copy.vue b/pages/shop/confirm copy.vue new file mode 100644 index 0000000..c266eb2 --- /dev/null +++ b/pages/shop/confirm copy.vue @@ -0,0 +1,447 @@ + + + + + \ No newline at end of file diff --git a/pages/shop/confirm.vue b/pages/shop/confirm.vue new file mode 100644 index 0000000..d1a6f37 --- /dev/null +++ b/pages/shop/confirm.vue @@ -0,0 +1,451 @@ + + + + + \ No newline at end of file diff --git a/pages/shop/detail copy.vue b/pages/shop/detail copy.vue new file mode 100644 index 0000000..39cf6b8 --- /dev/null +++ b/pages/shop/detail copy.vue @@ -0,0 +1,567 @@ + + + + + \ No newline at end of file diff --git a/pages/shop/detail.vue b/pages/shop/detail.vue new file mode 100644 index 0000000..af38fc0 --- /dev/null +++ b/pages/shop/detail.vue @@ -0,0 +1,1406 @@ + + + + + \ No newline at end of file diff --git a/pages/shop/index copy.vue b/pages/shop/index copy.vue new file mode 100644 index 0000000..6fdb2b5 --- /dev/null +++ b/pages/shop/index copy.vue @@ -0,0 +1,479 @@ + + + + + \ No newline at end of file diff --git a/pages/shop/index.vue b/pages/shop/index.vue new file mode 100644 index 0000000..903347b --- /dev/null +++ b/pages/shop/index.vue @@ -0,0 +1,489 @@ + + + + + \ No newline at end of file diff --git a/pages/shop/paySuccess copy.vue b/pages/shop/paySuccess copy.vue new file mode 100644 index 0000000..ffc10aa --- /dev/null +++ b/pages/shop/paySuccess copy.vue @@ -0,0 +1,275 @@ + + + + + + \ No newline at end of file diff --git a/pages/shop/paySuccess.vue b/pages/shop/paySuccess.vue new file mode 100644 index 0000000..6274a65 --- /dev/null +++ b/pages/shop/paySuccess.vue @@ -0,0 +1,168 @@ + + + + + + \ No newline at end of file diff --git a/pages/shop/search-list.vue b/pages/shop/search-list.vue new file mode 100644 index 0000000..33f39eb --- /dev/null +++ b/pages/shop/search-list.vue @@ -0,0 +1,263 @@ + + + + + \ No newline at end of file diff --git a/pages/shop/search.vue b/pages/shop/search.vue new file mode 100644 index 0000000..0e3b0e2 --- /dev/null +++ b/pages/shop/search.vue @@ -0,0 +1,171 @@ + + + + + \ No newline at end of file diff --git a/pages/testPay/testPay.vue b/pages/testPay/testPay.vue new file mode 100644 index 0000000..0aa694d --- /dev/null +++ b/pages/testPay/testPay.vue @@ -0,0 +1,869 @@ + + + + + + \ No newline at end of file diff --git a/uni.scss b/uni.scss new file mode 100644 index 0000000..ee19cd1 --- /dev/null +++ b/uni.scss @@ -0,0 +1,81 @@ +/** + * 这里是uni-app内置的常用样式变量 + * + * uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 + * 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App + * + */ + +/** + * 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 + * + * 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 + */ + +/* 颜色变量 */ +/* 主题 */ +$uni-color376AF5: #376AF5; //基本颜色 +$uni-color32C28C: #32C28C; +$uni-colorFF6363: #FF6363; +$uni-color404C69: #404C69; + +/* 行为相关颜色 */ +$uni-color-primary: #007aff; +$uni-color-success: #4cd964; +$uni-color-warning: #f0ad4e; +$uni-color-error: #dd524d; + +/* 文字基本颜色 */ +$uni-text-color:#333;//基本色 +$uni-text-color-inverse:#fff;//反色 +$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息 +$uni-text-color-placeholder: #808080; +$uni-text-color-disable:#c0c0c0; + +/* 背景颜色 */ +$uni-bg-color:#ffffff; +$uni-bg-color-grey:#f8f8f8; +$uni-bg-color-hover:#f1f1f1;//点击状态颜色 +$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色 + +/* 边框颜色 */ +$uni-border-color:#c8c7cc; + +/* 尺寸变量 */ + +/* 文字尺寸 */ +$uni-font-size-sm:24rpx; +$uni-font-size-base:28rpx; +$uni-font-size-lg:32rpx; + +/* 图片尺寸 */ +$uni-img-size-sm:40rpx; +$uni-img-size-base:52rpx; +$uni-img-size-lg:80rpx; + +/* Border Radius */ +$uni-border-radius-sm: 4rpx; +$uni-border-radius-base: 6rpx; +$uni-border-radius-lg: 12rpx; +$uni-border-radius-circle: 50%; + +/* 水平间距 */ +$uni-spacing-row-sm: 10px; +$uni-spacing-row-base: 20rpx; +$uni-spacing-row-lg: 30rpx; + +/* 垂直间距 */ +$uni-spacing-col-sm: 8rpx; +$uni-spacing-col-base: 16rpx; +$uni-spacing-col-lg: 24rpx; + +/* 透明度 */ +$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 + +/* 文章场景相关 */ +$uni-color-title: #2C405A; // 文章标题颜色 +$uni-font-size-title:40rpx; +$uni-color-subtitle: #555555; // 二级标题颜色 +$uni-font-size-subtitle:36rpx; +$uni-color-paragraph: #3F536E; // 文章段落颜色 +$uni-font-size-paragraph:30rpx; \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/public/index.js b/uniCloud-aliyun/cloudfunctions/public/index.js new file mode 100644 index 0000000..268b1f8 --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/public/index.js @@ -0,0 +1,26 @@ +// 云函数入口文件 +const cloud = require('wx-server-sdk') +cloud.init() +// 云函数入口函数 +exports.main = async (event, context) => { + const wxContext = cloud.getWXContext() + switch (event.action) { + case 'getUrlScheme': { + return getUrlScheme(event.options)//与官方文档区别:小程序页面接受的参数 + } + } + return 'action not found' +} +async function getUrlScheme(options) { + //return options; + return cloud.openapi.urlscheme.generate({ + jumpWxa: { + path: '/pages/pay/pay', // 调转到小程序要打开的页面路径,根据实际业务设置 + query: options,//与官方文档区别:小程序页面接受的参数 + }, + // 如果想不过期则置为 false,并可以存到数据库 + isExpire: false, + // 一分钟有效期 + expireTime: parseInt(Date.now() / 1000 + 60), + }) +} \ No newline at end of file diff --git a/uniCloud-aliyun/cloudfunctions/public/package.json b/uniCloud-aliyun/cloudfunctions/public/package.json new file mode 100644 index 0000000..d0f62be --- /dev/null +++ b/uniCloud-aliyun/cloudfunctions/public/package.json @@ -0,0 +1,7 @@ +{ + "name": "public", + "dependencies": {}, + "extensions": { + "uni-cloud-jql": {} + } +} \ No newline at end of file diff --git a/uniCloud-aliyun/database/JQL查询.jql b/uniCloud-aliyun/database/JQL查询.jql new file mode 100644 index 0000000..35d21de --- /dev/null +++ b/uniCloud-aliyun/database/JQL查询.jql @@ -0,0 +1,12 @@ +// 本文件用于,使用JQL语法操作项目关联的uniCloud空间的数据库,方便开发调试和远程数据库管理 +// 编写clientDB的js API(也支持常规js语法,比如var),可以对云数据库进行增删改查操作。不支持uniCloud-db组件写法 +// 可以全部运行,也可以选中部分代码运行。点击工具栏上的运行按钮或者按下【F5】键运行代码 +// 如果文档中存在多条JQL语句,只有最后一条语句生效 +// 如果混写了普通js,最后一条语句需是数据库操作语句 +// 此处代码运行不受DB Schema的权限控制,移植代码到实际业务中注意在schema中配好permission +// 不支持clientDB的action +// 数据库查询有最大返回条数限制,详见:https://uniapp.dcloud.net.cn/uniCloud/cf-database.html#limit +// 详细JQL语法,请参考:https://uniapp.dcloud.net.cn/uniCloud/jql.html + +// 下面示例查询uni-id-users表的所有数据 +db.collection('uni-id-users').get(); diff --git a/uni_modules/uni-config-center/changelog.md b/uni_modules/uni-config-center/changelog.md new file mode 100644 index 0000000..57dbcb5 --- /dev/null +++ b/uni_modules/uni-config-center/changelog.md @@ -0,0 +1,6 @@ +## 0.0.3(2022-11-11) +- 修复 config 方法获取根节点为数组格式配置时错误的转化为了对象的Bug +## 0.0.2(2021-04-16) +- 修改插件package信息 +## 0.0.1(2021-03-15) +- 初始化项目 diff --git a/uni_modules/uni-config-center/package.json b/uni_modules/uni-config-center/package.json new file mode 100644 index 0000000..bace866 --- /dev/null +++ b/uni_modules/uni-config-center/package.json @@ -0,0 +1,81 @@ +{ + "id": "uni-config-center", + "displayName": "uni-config-center", + "version": "0.0.3", + "description": "uniCloud 配置中心", + "keywords": [ + "配置", + "配置中心" +], + "repository": "", + "engines": { + "HBuilderX": "^3.1.0" + }, +"dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "", + "type": "unicloud-template-function" + }, + "directories": { + "example": "../../../scripts/dist" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "u", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "u", + "Android Browser": "u", + "微信浏览器(Android)": "u", + "QQ浏览器(Android)": "u" + }, + "H5-pc": { + "Chrome": "u", + "IE": "u", + "Edge": "u", + "Firefox": "u", + "Safari": "u" + }, + "小程序": { + "微信": "u", + "阿里": "u", + "百度": "u", + "字节跳动": "u", + "QQ": "u" + }, + "快应用": { + "华为": "u", + "联盟": "u" + }, + "Vue": { + "vue2": "y", + "vue3": "u" + } + } + } + } +} diff --git a/uni_modules/uni-config-center/readme.md b/uni_modules/uni-config-center/readme.md new file mode 100644 index 0000000..03f7fc2 --- /dev/null +++ b/uni_modules/uni-config-center/readme.md @@ -0,0 +1,93 @@ +# 为什么使用uni-config-center + +实际开发中很多插件需要配置文件才可以正常运行,如果每个插件都单独进行配置的话就会产生下面这样的目录结构 + +```bash +cloudfunctions +└─────common 公共模块 + ├─plugin-a // 插件A对应的目录 + │ ├─index.js + │ ├─config.json // plugin-a对应的配置文件 + │ └─other-file.cert // plugin-a依赖的其他文件 + └─plugin-b // plugin-b对应的目录 + ├─index.js + └─config.json // plugin-b对应的配置文件 +``` + +假设插件作者要发布一个项目模板,里面使用了很多需要配置的插件,无论是作者发布还是用户使用都是一个大麻烦。 + +uni-config-center就是用了统一管理这些配置文件的,使用uni-config-center后的目录结构如下 + +```bash +cloudfunctions +└─────common 公共模块 + ├─plugin-a // 插件A对应的目录 + │ └─index.js + ├─plugin-b // plugin-b对应的目录 + │ └─index.js + └─uni-config-center + ├─index.js // config-center入口文件 + ├─plugin-a + │ ├─config.json // plugin-a对应的配置文件 + │ └─other-file.cert // plugin-a依赖的其他文件 + └─plugin-b + └─config.json // plugin-b对应的配置文件 +``` + +使用uni-config-center后的优势 + +- 配置文件统一管理,分离插件主体和配置信息,更新插件更方便 +- 支持对config.json设置schema,插件使用者在HBuilderX内编写config.json文件时会有更好的提示(后续HBuilderX会提供支持) + +# 用法 + +在要使用uni-config-center的公共模块或云函数内引入uni-config-center依赖,请参考:[使用公共模块](https://uniapp.dcloud.net.cn/uniCloud/cf-common) + +```js +const createConfig = require('uni-config-center') + +const uniIdConfig = createConfig({ + pluginId: 'uni-id', // 插件id + defaultConfig: { // 默认配置 + tokenExpiresIn: 7200, + tokenExpiresThreshold: 600, + }, + customMerge: function(defaultConfig, userConfig) { // 自定义默认配置和用户配置的合并规则,不设置的情况侠会对默认配置和用户配置进行深度合并 + // defaudltConfig 默认配置 + // userConfig 用户配置 + return Object.assign(defaultConfig, userConfig) + } +}) + + +// 以如下配置为例 +// { +// "tokenExpiresIn": 7200, +// "passwordErrorLimit": 6, +// "bindTokenToDevice": false, +// "passwordErrorRetryTime": 3600, +// "app-plus": { +// "tokenExpiresIn": 2592000 +// }, +// "service": { +// "sms": { +// "codeExpiresIn": 300 +// } +// } +// } + +// 获取配置 +uniIdConfig.config() // 获取全部配置,注意:uni-config-center内不存在对应插件目录时会返回空对象 +uniIdConfig.config('tokenExpiresIn') // 指定键值获取配置,返回:7200 +uniIdConfig.config('service.sms.codeExpiresIn') // 指定键值获取配置,返回:300 +uniIdConfig.config('tokenExpiresThreshold', 600) // 指定键值获取配置,如果不存在则取传入的默认值,返回:600 + +// 获取文件绝对路径 +uniIdConfig.resolve('custom-token.js') // 获取uni-config-center/uni-id/custom-token.js文件的路径 + +// 引用文件(require) +uniIDConfig.requireFile('custom-token.js') // 使用require方式引用uni-config-center/uni-id/custom-token.js文件。文件不存在时返回undefined,文件内有其他错误导致require失败时会抛出错误。 + +// 判断是否包含某文件 +uniIDConfig.hasFile('custom-token.js') // 配置目录是否包含某文件,true: 文件存在,false: 文件不存在 +``` \ No newline at end of file diff --git a/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js b/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js new file mode 100644 index 0000000..00ba62f --- /dev/null +++ b/uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js @@ -0,0 +1 @@ +"use strict";var t=require("fs"),r=require("path");function e(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var n=e(t),o=e(r),i="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};var u=function(t){var r={exports:{}};return t(r,r.exports),r.exports}((function(t,r){var e="__lodash_hash_undefined__",n=9007199254740991,o="[object Arguments]",u="[object Function]",c="[object Object]",a=/^\[object .+?Constructor\]$/,f=/^(?:0|[1-9]\d*)$/,s={};s["[object Float32Array]"]=s["[object Float64Array]"]=s["[object Int8Array]"]=s["[object Int16Array]"]=s["[object Int32Array]"]=s["[object Uint8Array]"]=s["[object Uint8ClampedArray]"]=s["[object Uint16Array]"]=s["[object Uint32Array]"]=!0,s[o]=s["[object Array]"]=s["[object ArrayBuffer]"]=s["[object Boolean]"]=s["[object DataView]"]=s["[object Date]"]=s["[object Error]"]=s[u]=s["[object Map]"]=s["[object Number]"]=s[c]=s["[object RegExp]"]=s["[object Set]"]=s["[object String]"]=s["[object WeakMap]"]=!1;var l="object"==typeof i&&i&&i.Object===Object&&i,h="object"==typeof self&&self&&self.Object===Object&&self,p=l||h||Function("return this")(),_=r&&!r.nodeType&&r,v=_&&t&&!t.nodeType&&t,d=v&&v.exports===_,y=d&&l.process,g=function(){try{var t=v&&v.require&&v.require("util").types;return t||y&&y.binding&&y.binding("util")}catch(t){}}(),b=g&&g.isTypedArray;function j(t,r,e){switch(e.length){case 0:return t.call(r);case 1:return t.call(r,e[0]);case 2:return t.call(r,e[0],e[1]);case 3:return t.call(r,e[0],e[1],e[2])}return t.apply(r,e)}var w,O,m,A=Array.prototype,z=Function.prototype,M=Object.prototype,x=p["__core-js_shared__"],C=z.toString,F=M.hasOwnProperty,U=(w=/[^.]+$/.exec(x&&x.keys&&x.keys.IE_PROTO||""))?"Symbol(src)_1."+w:"",S=M.toString,I=C.call(Object),P=RegExp("^"+C.call(F).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$"),T=d?p.Buffer:void 0,q=p.Symbol,E=p.Uint8Array,$=T?T.allocUnsafe:void 0,D=(O=Object.getPrototypeOf,m=Object,function(t){return O(m(t))}),k=Object.create,B=M.propertyIsEnumerable,N=A.splice,L=q?q.toStringTag:void 0,R=function(){try{var t=vt(Object,"defineProperty");return t({},"",{}),t}catch(t){}}(),G=T?T.isBuffer:void 0,V=Math.max,W=Date.now,H=vt(p,"Map"),J=vt(Object,"create"),K=function(){function t(){}return function(r){if(!xt(r))return{};if(k)return k(r);t.prototype=r;var e=new t;return t.prototype=void 0,e}}();function Q(t){var r=-1,e=null==t?0:t.length;for(this.clear();++r-1},X.prototype.set=function(t,r){var e=this.__data__,n=nt(e,t);return n<0?(++this.size,e.push([t,r])):e[n][1]=r,this},Y.prototype.clear=function(){this.size=0,this.__data__={hash:new Q,map:new(H||X),string:new Q}},Y.prototype.delete=function(t){var r=_t(this,t).delete(t);return this.size-=r?1:0,r},Y.prototype.get=function(t){return _t(this,t).get(t)},Y.prototype.has=function(t){return _t(this,t).has(t)},Y.prototype.set=function(t,r){var e=_t(this,t),n=e.size;return e.set(t,r),this.size+=e.size==n?0:1,this},Z.prototype.clear=function(){this.__data__=new X,this.size=0},Z.prototype.delete=function(t){var r=this.__data__,e=r.delete(t);return this.size=r.size,e},Z.prototype.get=function(t){return this.__data__.get(t)},Z.prototype.has=function(t){return this.__data__.has(t)},Z.prototype.set=function(t,r){var e=this.__data__;if(e instanceof X){var n=e.__data__;if(!H||n.length<199)return n.push([t,r]),this.size=++e.size,this;e=this.__data__=new Y(n)}return e.set(t,r),this.size=e.size,this};var it,ut=function(t,r,e){for(var n=-1,o=Object(t),i=e(t),u=i.length;u--;){var c=i[it?u:++n];if(!1===r(o[c],c,o))break}return t};function ct(t){return null==t?void 0===t?"[object Undefined]":"[object Null]":L&&L in Object(t)?function(t){var r=F.call(t,L),e=t[L];try{t[L]=void 0;var n=!0}catch(t){}var o=S.call(t);n&&(r?t[L]=e:delete t[L]);return o}(t):function(t){return S.call(t)}(t)}function at(t){return Ct(t)&&ct(t)==o}function ft(t){return!(!xt(t)||function(t){return!!U&&U in t}(t))&&(zt(t)?P:a).test(function(t){if(null!=t){try{return C.call(t)}catch(t){}try{return t+""}catch(t){}}return""}(t))}function st(t){if(!xt(t))return function(t){var r=[];if(null!=t)for(var e in Object(t))r.push(e);return r}(t);var r=yt(t),e=[];for(var n in t)("constructor"!=n||!r&&F.call(t,n))&&e.push(n);return e}function lt(t,r,e,n,o){t!==r&&ut(r,(function(i,u){if(o||(o=new Z),xt(i))!function(t,r,e,n,o,i,u){var a=gt(t,e),f=gt(r,e),s=u.get(f);if(s)return void rt(t,e,s);var l=i?i(a,f,e+"",t,r,u):void 0,h=void 0===l;if(h){var p=Ot(f),_=!p&&At(f),v=!p&&!_&&Ft(f);l=f,p||_||v?Ot(a)?l=a:Ct(j=a)&&mt(j)?l=function(t,r){var e=-1,n=t.length;r||(r=Array(n));for(;++e-1&&t%1==0&&t0){if(++r>=800)return arguments[0]}else r=0;return t.apply(void 0,arguments)}}(pt);function jt(t,r){return t===r||t!=t&&r!=r}var wt=at(function(){return arguments}())?at:function(t){return Ct(t)&&F.call(t,"callee")&&!B.call(t,"callee")},Ot=Array.isArray;function mt(t){return null!=t&&Mt(t.length)&&!zt(t)}var At=G||function(){return!1};function zt(t){if(!xt(t))return!1;var r=ct(t);return r==u||"[object GeneratorFunction]"==r||"[object AsyncFunction]"==r||"[object Proxy]"==r}function Mt(t){return"number"==typeof t&&t>-1&&t%1==0&&t<=n}function xt(t){var r=typeof t;return null!=t&&("object"==r||"function"==r)}function Ct(t){return null!=t&&"object"==typeof t}var Ft=b?function(t){return function(r){return t(r)}}(b):function(t){return Ct(t)&&Mt(t.length)&&!!s[ct(t)]};function Ut(t){return mt(t)?tt(t,!0):st(t)}var St,It=(St=function(t,r,e){lt(t,r,e)},ht((function(t,r){var e=-1,n=r.length,o=n>1?r[n-1]:void 0,i=n>2?r[2]:void 0;for(o=St.length>3&&"function"==typeof o?(n--,o):void 0,i&&function(t,r,e){if(!xt(e))return!1;var n=typeof r;return!!("number"==n?mt(e)&&dt(r,e.length):"string"==n&&r in e)&&jt(e[r],t)}(r[0],r[1],i)&&(o=n<3?void 0:o,n=1),t=Object(t);++ec.call(t,r);class f{constructor({pluginId:t,defaultConfig:r={},customMerge:e,root:n}){this.pluginId=t,this.defaultConfig=r,this.pluginConfigPath=o.default.resolve(n||__dirname,t),this.customMerge=e,this._config=void 0}resolve(t){return o.default.resolve(this.pluginConfigPath,t)}hasFile(t){return n.default.existsSync(this.resolve(t))}requireFile(t){try{return require(this.resolve(t))}catch(t){if("MODULE_NOT_FOUND"===t.code)return;throw t}}_getUserConfig(){return this.requireFile("config.json")}config(t,r){if(!this._config){const t=this._getUserConfig();this._config=Array.isArray(t)?t:(this.customMerge||u)(this.defaultConfig,t)}let e=this._config;return t?function(t,r,e){if("number"==typeof r)return t[r];if("symbol"==typeof r)return a(t,r)?t[r]:e;const n="string"!=typeof(o=r)?o:o.split(".").reduce(((t,r)=>(r.split(/\[([^}]+)\]/g).forEach((r=>r&&t.push(r))),t)),[]);var o;let i=t;for(let t=0;tparseInt(e)):void 0}function o(e,t){const n=r(e),i=r(t);return n?i?function(e,t){const n=Math.max(e.length,t.length);for(let i=0;ir)return 1;if(n=e)throw new Error("Config error, tokenExpiresThreshold should be less than tokenExpiresIn");t>e/2&&console.warn(`Please check whether the tokenExpiresThreshold configuration is set too large, tokenExpiresThreshold: ${t}, tokenExpiresIn: ${e}`)}get customToken(){return this.uniId.interceptorMap.get("customToken")}isTokenInDb(e){return o(e,"1.0.10")>=0}async getUserRecord(){if(this.userRecord)return this.userRecord;const e=await C.doc(this.uid).get();if(this.userRecord=e.data[0],!this.userRecord)throw{errCode:n.ACCOUNT_NOT_EXISTS};switch(this.userRecord.status){case void 0:case 0:break;case 1:throw{errCode:n.ACCOUNT_BANNED};case 2:throw{errCode:n.ACCOUNT_AUDITING};case 3:throw{errCode:n.ACCOUNT_AUDIT_FAILED};case 4:throw{errCode:n.ACCOUNT_CLOSED}}if(this.oldTokenPayload){if(this.isTokenInDb(this.oldTokenPayload.uniIdVersion)){if(-1===(this.userRecord.token||[]).indexOf(this.oldToken))throw{errCode:n.CHECK_TOKEN_FAILED}}if(this.userRecord.valid_token_date&&this.userRecord.valid_token_date>1e3*this.oldTokenPayload.iat)throw{errCode:n.TOKEN_EXPIRED}}return this.userRecord}async updateUserRecord(e){await C.doc(this.uid).update(e)}async getUserPermission(){if(this.userPermission)return this.userPermission;const e=(await this.getUserRecord()).role||[];if(0===e.length)return this.userPermission={role:[],permission:[]},this.userPermission;if(e.includes("admin"))return this.userPermission={role:e,permission:[]},this.userPermission;const t=await T.where({role_id:_.in(e)}).get(),n=(i=t.data.reduce((e,t)=>(t.permission&&e.push(...t.permission),e),[]),Array.from(new Set(i)));var i;return this.userPermission={role:e,permission:n},this.userPermission}async _createToken({uid:e,role:t,permission:i}={}){if(!t||!i){const e=await this.getUserPermission();t=e.role,i=e.permission}let r={uid:e,role:t,permission:i};if(this.uniId.interceptorMap.has("customToken")){const n=this.uniId.interceptorMap.get("customToken");if("function"!=typeof n)throw new Error("Invalid custom token file");r=await n({uid:e,role:t,permission:i})}const o=Date.now(),{tokenSecret:s,tokenExpiresIn:c,maxTokenLength:a=10}=this.config,u=g({...r,uniIdVersion:"1.0.17"},s,{expiresIn:c}),d=await this.getUserRecord(),l=(d.token||[]).filter(e=>{try{const t=this._checkToken(e);if(d.valid_token_date&&d.valid_token_date>1e3*t.iat)return!1}catch(e){if(e.errCode===n.TOKEN_EXPIRED)return!1}return!0});return l.push(u),l.length>a&&l.splice(0,l.length-a),await this.updateUserRecord({last_login_ip:this.clientInfo.clientIP,last_login_date:o,token:l}),{token:u,tokenExpired:o+1e3*c}}async createToken({uid:e,role:t,permission:i}={}){if(!e)throw{errCode:n.PARAM_REQUIRED,errMsgValue:{param:"uid"}};this.uid=e;const{token:r,tokenExpired:o}=await this._createToken({uid:e,role:t,permission:i});return{errCode:0,token:r,tokenExpired:o}}async refreshToken({token:e}={}){if(!e)throw{errCode:n.PARAM_REQUIRED,errMsgValue:{param:"token"}};this.oldToken=e;const t=this._checkToken(e);this.uid=t.uid,this.oldTokenPayload=t;const{uid:i}=t,{role:r,permission:o}=await this.getUserPermission(),{token:s,tokenExpired:c}=await this._createToken({uid:i,role:r,permission:o});return{errCode:0,token:s,tokenExpired:c}}_checkToken(e){const{tokenSecret:t}=this.config;let i;try{i=k(e,t)}catch(e){if("TokenExpiredError"===e.name)throw{errCode:n.TOKEN_EXPIRED};throw{errCode:n.CHECK_TOKEN_FAILED}}return i}async checkToken(e,{autoRefresh:t=!0}={}){if(!e)throw{errCode:n.PARAM_REQUIRED,errMsgValue:{param:"token"}};this.oldToken=e;const i=this._checkToken(e);this.uid=i.uid,this.oldTokenPayload=i;const{tokenExpiresThreshold:r}=this.config,{uid:o,role:s,permission:c}=i,a={role:s,permission:c};if(!s&&!c){const{role:e,permission:t}=await this.getUserPermission();a.role=e,a.permission=t}if(!r||!t){const e={code:0,errCode:0,...i,...a};return delete e.uniIdVersion,e}const u=Date.now();let d={};1e3*i.exp-u<1e3*r&&(d=await this._createToken({uid:o}));const l={code:0,errCode:0,...i,...a,...d};return delete l.uniIdVersion,l}}var E=Object.freeze({__proto__:null,checkToken:async function(e,{autoRefresh:t=!0}={}){return new m({uniId:this}).checkToken(e,{autoRefresh:t})},createToken:async function({uid:e,role:t,permission:n}={}){return new m({uniId:this}).createToken({uid:e,role:t,permission:n})},refreshToken:async function({token:e}={}){return new m({uniId:this}).refreshToken({token:e})}});const w=require("uni-config-center")({pluginId:"uni-id"});class x{constructor({context:e,clientInfo:t,config:n}={}){this._clientInfo=e?function(e){return{appId:e.APPID,platform:e.PLATFORM,locale:e.LOCALE,clientIP:e.CLIENTIP,deviceId:e.DEVICEID}}(e):t,this._config=n,this.config=this._getOriginConfig(),this.interceptorMap=new Map,w.hasFile("custom-token.js")&&this.setInterceptor("customToken",require(w.resolve("custom-token.js")));this._i18n=uniCloud.initI18n({locale:this._clientInfo.locale,fallbackLocale:"zh-Hans",messages:JSON.parse(JSON.stringify(d))}),d[this._i18n.locale]||this._i18n.setLocale("zh-Hans")}setInterceptor(e,t){this.interceptorMap.set(e,t)}_t(...e){return this._i18n.t(...e)}_parseOriginConfig(e){return Array.isArray(e)?e:e[0]?Object.values(e):e}_getOriginConfig(){if(this._config)return this._config;if(w.hasFile("config.json")){let e;try{e=w.config()}catch(e){throw new Error("Invalid uni-id config file\n"+e.message)}return this._parseOriginConfig(e)}try{return this._parseOriginConfig(require("uni-id/config.json"))}catch(e){throw new Error("Invalid uni-id config file")}}_getAppConfig(){const e=this._getOriginConfig();return Array.isArray(e)?e.find(e=>e.dcloudAppid===this._clientInfo.appId)||e.find(e=>e.isDefaultConfig):e}_getPlatformConfig(){const e=this._getAppConfig();if(!e)throw new Error(`Config for current app (${this._clientInfo.appId}) was not found, please check your config file or client appId`);let t;switch(["app-plus","app-android","app-ios"].indexOf(this._clientInfo.platform)>-1&&(this._clientInfo.platform="app"),"h5"===this._clientInfo.platform&&(this._clientInfo.platform="web"),this._clientInfo.platform){case"web":t="h5";break;case"app":t="app-plus"}const n=[{tokenExpiresIn:7200,tokenExpiresThreshold:1200,passwordErrorLimit:6,passwordErrorRetryTime:3600},e];t&&e[t]&&n.push(e[t]),n.push(e[this._clientInfo.platform]);const i=Object.assign(...n);return["tokenSecret","tokenExpiresIn"].forEach(e=>{if(!i||!i[e])throw new Error(`Config parameter missing, ${e} is required`)}),i}_getConfig(){return this._getPlatformConfig()}}for(const e in E)x.prototype[e]=E[e];function y(e){const t=new x(e);return new Proxy(t,{get(e,t){if(t in e&&0!==t.indexOf("_")){if("function"==typeof e[t])return(n=e[t],function(){let e;try{e=n.apply(this,arguments)}catch(e){if(a(e))return c.call(this,e),e;throw e}return i(e)?e.then(e=>(a(e)&&c.call(this,e),e),e=>{if(a(e))return c.call(this,e),e;throw e}):(a(e)&&c.call(this,e),e)}).bind(e);if("context"!==t&&"config"!==t)return e[t]}var n}})}x.prototype.createInstance=y;const A={createInstance:y};module.exports=A; diff --git a/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/package.json b/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/package.json new file mode 100644 index 0000000..3cf41f3 --- /dev/null +++ b/uni_modules/uni-id-common/uniCloud/cloudfunctions/common/uni-id-common/package.json @@ -0,0 +1,16 @@ +{ + "name": "uni-id-common", + "version": "1.0.17", + "description": "uni-id token生成、校验、刷新", + "main": "index.js", + "homepage": "https://uniapp.dcloud.io/uniCloud/uni-id-common.html", + "repository": { + "type": "git", + "url": "git+https://gitee.com/dcloud/uni-id-common.git" + }, + "author": "DCloud", + "license": "Apache-2.0", + "dependencies": { + "uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" + } +} \ No newline at end of file diff --git a/uni_modules/uni-link/changelog.md b/uni_modules/uni-link/changelog.md new file mode 100644 index 0000000..2cfbf59 --- /dev/null +++ b/uni_modules/uni-link/changelog.md @@ -0,0 +1,17 @@ +## 1.0.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-link](https://uniapp.dcloud.io/component/uniui/uni-link) +## 1.1.7(2021-11-08) +## 0.0.7(2021-09-03) +- 修复 在 nvue 下不显示的 bug +## 0.0.6(2021-07-30) +- 新增 支持自定义插槽 +## 0.0.5(2021-06-21) +- 新增 download 属性,H5平台下载文件名 +## 0.0.4(2021-05-12) +- 新增 组件示例地址 +## 0.0.3(2021-03-09) +- 新增 href 属性支持 tel:|mailto: + +## 0.0.2(2021-02-05) +- 调整为uni_modules目录规范 diff --git a/uni_modules/uni-link/components/uni-link/uni-link.vue b/uni_modules/uni-link/components/uni-link/uni-link.vue new file mode 100644 index 0000000..27c5468 --- /dev/null +++ b/uni_modules/uni-link/components/uni-link/uni-link.vue @@ -0,0 +1,128 @@ + + + + + diff --git a/uni_modules/uni-link/package.json b/uni_modules/uni-link/package.json new file mode 100644 index 0000000..77b1986 --- /dev/null +++ b/uni_modules/uni-link/package.json @@ -0,0 +1,87 @@ +{ + "id": "uni-link", + "displayName": "uni-link 超链接", + "version": "1.0.0", + "description": "uni-link是一个外部网页超链接组件,在小程序内复制url,在app内打开外部浏览器,在h5端打", + "keywords": [ + "uni-ui", + "uniui", + "link", + "超链接", + "" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "category": [ + "前端组件", + "通用组件" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": ["uni-scss"], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "y" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "y", + "联盟": "y" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-link/readme.md b/uni_modules/uni-link/readme.md new file mode 100644 index 0000000..7f09e94 --- /dev/null +++ b/uni_modules/uni-link/readme.md @@ -0,0 +1,11 @@ + + +## Link 链接 +> **组件名:uni-link** +> 代码块: `uLink` + + +uni-link是一个外部网页超链接组件,在小程序内复制url,在app内打开外部浏览器,在h5端打开新网页。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-link) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-scss/changelog.md b/uni_modules/uni-scss/changelog.md new file mode 100644 index 0000000..b863bb0 --- /dev/null +++ b/uni_modules/uni-scss/changelog.md @@ -0,0 +1,8 @@ +## 1.0.3(2022-01-21) +- 优化 组件示例 +## 1.0.2(2021-11-22) +- 修复 / 符号在 vue 不同版本兼容问题引起的报错问题 +## 1.0.1(2021-11-22) +- 修复 vue3中scss语法兼容问题 +## 1.0.0(2021-11-18) +- init diff --git a/uni_modules/uni-scss/index.scss b/uni_modules/uni-scss/index.scss new file mode 100644 index 0000000..1744a5f --- /dev/null +++ b/uni_modules/uni-scss/index.scss @@ -0,0 +1 @@ +@import './styles/index.scss'; diff --git a/uni_modules/uni-scss/package.json b/uni_modules/uni-scss/package.json new file mode 100644 index 0000000..7cc0ccb --- /dev/null +++ b/uni_modules/uni-scss/package.json @@ -0,0 +1,82 @@ +{ + "id": "uni-scss", + "displayName": "uni-scss 辅助样式", + "version": "1.0.3", + "description": "uni-sass是uni-ui提供的一套全局样式 ,通过一些简单的类名和sass变量,实现简单的页面布局操作,比如颜色、边距、圆角等。", + "keywords": [ + "uni-scss", + "uni-ui", + "辅助样式" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "^3.1.0" + }, + "dcloudext": { + "category": [ + "JS SDK", + "通用 SDK" + ], + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y" + }, + "client": { + "App": { + "app-vue": "y", + "app-nvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y" + }, + "快应用": { + "华为": "n", + "联盟": "n" + }, + "Vue": { + "vue2": "y", + "vue3": "y" + } + } + } + } +} diff --git a/uni_modules/uni-scss/readme.md b/uni_modules/uni-scss/readme.md new file mode 100644 index 0000000..b7d1c25 --- /dev/null +++ b/uni_modules/uni-scss/readme.md @@ -0,0 +1,4 @@ +`uni-sass` 是 `uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass) +#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 \ No newline at end of file diff --git a/uni_modules/uni-scss/styles/index.scss b/uni_modules/uni-scss/styles/index.scss new file mode 100644 index 0000000..ffac4fe --- /dev/null +++ b/uni_modules/uni-scss/styles/index.scss @@ -0,0 +1,7 @@ +@import './setting/_variables.scss'; +@import './setting/_border.scss'; +@import './setting/_color.scss'; +@import './setting/_space.scss'; +@import './setting/_radius.scss'; +@import './setting/_text.scss'; +@import './setting/_styles.scss'; diff --git a/uni_modules/uni-scss/styles/setting/_border.scss b/uni_modules/uni-scss/styles/setting/_border.scss new file mode 100644 index 0000000..12a11c3 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_border.scss @@ -0,0 +1,3 @@ +.uni-border { + border: 1px $uni-border-1 solid; +} \ No newline at end of file diff --git a/uni_modules/uni-scss/styles/setting/_color.scss b/uni_modules/uni-scss/styles/setting/_color.scss new file mode 100644 index 0000000..1ededd9 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_color.scss @@ -0,0 +1,66 @@ + +// TODO 暂时不需要 class ,需要用户使用变量实现 ,如果使用类名其实并不推荐 +// @mixin get-styles($k,$c) { +// @if $k == size or $k == weight{ +// font-#{$k}:#{$c} +// }@else{ +// #{$k}:#{$c} +// } +// } +$uni-ui-color:( + // 主色 + primary: $uni-primary, + primary-disable: $uni-primary-disable, + primary-light: $uni-primary-light, + // 辅助色 + success: $uni-success, + success-disable: $uni-success-disable, + success-light: $uni-success-light, + warning: $uni-warning, + warning-disable: $uni-warning-disable, + warning-light: $uni-warning-light, + error: $uni-error, + error-disable: $uni-error-disable, + error-light: $uni-error-light, + info: $uni-info, + info-disable: $uni-info-disable, + info-light: $uni-info-light, + // 中性色 + main-color: $uni-main-color, + base-color: $uni-base-color, + secondary-color: $uni-secondary-color, + extra-color: $uni-extra-color, + // 背景色 + bg-color: $uni-bg-color, + // 边框颜色 + border-1: $uni-border-1, + border-2: $uni-border-2, + border-3: $uni-border-3, + border-4: $uni-border-4, + // 黑色 + black:$uni-black, + // 白色 + white:$uni-white, + // 透明 + transparent:$uni-transparent +) !default; +@each $key, $child in $uni-ui-color { + .uni-#{"" + $key} { + color: $child; + } + .uni-#{"" + $key}-bg { + background-color: $child; + } +} +.uni-shadow-sm { + box-shadow: $uni-shadow-sm; +} +.uni-shadow-base { + box-shadow: $uni-shadow-base; +} +.uni-shadow-lg { + box-shadow: $uni-shadow-lg; +} +.uni-mask { + background-color:$uni-mask; +} diff --git a/uni_modules/uni-scss/styles/setting/_radius.scss b/uni_modules/uni-scss/styles/setting/_radius.scss new file mode 100644 index 0000000..9a0428b --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_radius.scss @@ -0,0 +1,55 @@ +@mixin radius($r,$d:null ,$important: false){ + $radius-value:map-get($uni-radius, $r) if($important, !important, null); + // Key exists within the $uni-radius variable + @if (map-has-key($uni-radius, $r) and $d){ + @if $d == t { + border-top-left-radius:$radius-value; + border-top-right-radius:$radius-value; + }@else if $d == r { + border-top-right-radius:$radius-value; + border-bottom-right-radius:$radius-value; + }@else if $d == b { + border-bottom-left-radius:$radius-value; + border-bottom-right-radius:$radius-value; + }@else if $d == l { + border-top-left-radius:$radius-value; + border-bottom-left-radius:$radius-value; + }@else if $d == tl { + border-top-left-radius:$radius-value; + }@else if $d == tr { + border-top-right-radius:$radius-value; + }@else if $d == br { + border-bottom-right-radius:$radius-value; + }@else if $d == bl { + border-bottom-left-radius:$radius-value; + } + }@else{ + border-radius:$radius-value; + } +} + +@each $key, $child in $uni-radius { + @if($key){ + .uni-radius-#{"" + $key} { + @include radius($key) + } + }@else{ + .uni-radius { + @include radius($key) + } + } +} + +@each $direction in t, r, b, l,tl, tr, br, bl { + @each $key, $child in $uni-radius { + @if($key){ + .uni-radius-#{"" + $direction}-#{"" + $key} { + @include radius($key,$direction,false) + } + }@else{ + .uni-radius-#{$direction} { + @include radius($key,$direction,false) + } + } + } +} diff --git a/uni_modules/uni-scss/styles/setting/_space.scss b/uni_modules/uni-scss/styles/setting/_space.scss new file mode 100644 index 0000000..3c89528 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_space.scss @@ -0,0 +1,56 @@ + +@mixin fn($space,$direction,$size,$n) { + @if $n { + #{$space}-#{$direction}: #{$size*$uni-space-root}px + } @else { + #{$space}-#{$direction}: #{-$size*$uni-space-root}px + } +} +@mixin get-styles($direction,$i,$space,$n){ + @if $direction == t { + @include fn($space, top,$i,$n); + } + @if $direction == r { + @include fn($space, right,$i,$n); + } + @if $direction == b { + @include fn($space, bottom,$i,$n); + } + @if $direction == l { + @include fn($space, left,$i,$n); + } + @if $direction == x { + @include fn($space, left,$i,$n); + @include fn($space, right,$i,$n); + } + @if $direction == y { + @include fn($space, top,$i,$n); + @include fn($space, bottom,$i,$n); + } + @if $direction == a { + @if $n { + #{$space}:#{$i*$uni-space-root}px; + } @else { + #{$space}:#{-$i*$uni-space-root}px; + } + } +} + +@each $orientation in m,p { + $space: margin; + @if $orientation == m { + $space: margin; + } @else { + $space: padding; + } + @for $i from 0 through 16 { + @each $direction in t, r, b, l, x, y, a { + .uni-#{$orientation}#{$direction}-#{$i} { + @include get-styles($direction,$i,$space,true); + } + .uni-#{$orientation}#{$direction}-n#{$i} { + @include get-styles($direction,$i,$space,false); + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-scss/styles/setting/_styles.scss b/uni_modules/uni-scss/styles/setting/_styles.scss new file mode 100644 index 0000000..689afec --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_styles.scss @@ -0,0 +1,167 @@ +/* #ifndef APP-NVUE */ + +$-color-white:#fff; +$-color-black:#000; +@mixin base-style($color) { + color: #fff; + background-color: $color; + border-color: mix($-color-black, $color, 8%); + &:not([hover-class]):active { + background: mix($-color-black, $color, 10%); + border-color: mix($-color-black, $color, 20%); + color: $-color-white; + outline: none; + } +} +@mixin is-color($color) { + @include base-style($color); + &[loading] { + @include base-style($color); + &::before { + margin-right:5px; + } + } + &[disabled] { + &, + &[loading], + &:not([hover-class]):active { + color: $-color-white; + border-color: mix(darken($color,10%), $-color-white); + background-color: mix($color, $-color-white); + } + } + +} +@mixin base-plain-style($color) { + color:$color; + background-color: mix($-color-white, $color, 90%); + border-color: mix($-color-white, $color, 70%); + &:not([hover-class]):active { + background: mix($-color-white, $color, 80%); + color: $color; + outline: none; + border-color: mix($-color-white, $color, 50%); + } +} +@mixin is-plain($color){ + &[plain] { + @include base-plain-style($color); + &[loading] { + @include base-plain-style($color); + &::before { + margin-right:5px; + } + } + &[disabled] { + &, + &:active { + color: mix($-color-white, $color, 40%); + background-color: mix($-color-white, $color, 90%); + border-color: mix($-color-white, $color, 80%); + } + } + } +} + + +.uni-btn { + margin: 5px; + color: #393939; + border:1px solid #ccc; + font-size: 16px; + font-weight: 200; + background-color: #F9F9F9; + // TODO 暂时处理边框隐藏一边的问题 + overflow: visible; + &::after{ + border: none; + } + + &:not([type]),&[type=default] { + color: #999; + &[loading] { + background: none; + &::before { + margin-right:5px; + } + } + + + + &[disabled]{ + color: mix($-color-white, #999, 60%); + &, + &[loading], + &:active { + color: mix($-color-white, #999, 60%); + background-color: mix($-color-white,$-color-black , 98%); + border-color: mix($-color-white, #999, 85%); + } + } + + &[plain] { + color: #999; + background: none; + border-color: $uni-border-1; + &:not([hover-class]):active { + background: none; + color: mix($-color-white, $-color-black, 80%); + border-color: mix($-color-white, $-color-black, 90%); + outline: none; + } + &[disabled]{ + &, + &[loading], + &:active { + background: none; + color: mix($-color-white, #999, 60%); + border-color: mix($-color-white, #999, 85%); + } + } + } + } + + &:not([hover-class]):active { + color: mix($-color-white, $-color-black, 50%); + } + + &[size=mini] { + font-size: 16px; + font-weight: 200; + border-radius: 8px; + } + + + + &.uni-btn-small { + font-size: 14px; + } + &.uni-btn-mini { + font-size: 12px; + } + + &.uni-btn-radius { + border-radius: 999px; + } + &[type=primary] { + @include is-color($uni-primary); + @include is-plain($uni-primary) + } + &[type=success] { + @include is-color($uni-success); + @include is-plain($uni-success) + } + &[type=error] { + @include is-color($uni-error); + @include is-plain($uni-error) + } + &[type=warning] { + @include is-color($uni-warning); + @include is-plain($uni-warning) + } + &[type=info] { + @include is-color($uni-info); + @include is-plain($uni-info) + } +} +/* #endif */ diff --git a/uni_modules/uni-scss/styles/setting/_text.scss b/uni_modules/uni-scss/styles/setting/_text.scss new file mode 100644 index 0000000..a34d08f --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_text.scss @@ -0,0 +1,24 @@ +@mixin get-styles($k,$c) { + @if $k == size or $k == weight{ + font-#{$k}:#{$c} + }@else{ + #{$k}:#{$c} + } +} + +@each $key, $child in $uni-headings { + /* #ifndef APP-NVUE */ + .uni-#{$key} { + @each $k, $c in $child { + @include get-styles($k,$c) + } + } + /* #endif */ + /* #ifdef APP-NVUE */ + .container .uni-#{$key} { + @each $k, $c in $child { + @include get-styles($k,$c) + } + } + /* #endif */ +} diff --git a/uni_modules/uni-scss/styles/setting/_variables.scss b/uni_modules/uni-scss/styles/setting/_variables.scss new file mode 100644 index 0000000..557d3d7 --- /dev/null +++ b/uni_modules/uni-scss/styles/setting/_variables.scss @@ -0,0 +1,146 @@ +// @use "sass:math"; +@import '../tools/functions.scss'; +// 间距基础倍数 +$uni-space-root: 2 !default; +// 边框半径默认值 +$uni-radius-root:5px !default; +$uni-radius: () !default; +// 边框半径断点 +$uni-radius: map-deep-merge( + ( + 0: 0, + // TODO 当前版本暂时不支持 sm 属性 + // 'sm': math.div($uni-radius-root, 2), + null: $uni-radius-root, + 'lg': $uni-radius-root * 2, + 'xl': $uni-radius-root * 6, + 'pill': 9999px, + 'circle': 50% + ), + $uni-radius +); +// 字体家族 +$body-font-family: 'Roboto', sans-serif !default; +// 文本 +$heading-font-family: $body-font-family !default; +$uni-headings: () !default; +$letterSpacing: -0.01562em; +$uni-headings: map-deep-merge( + ( + 'h1': ( + size: 32px, + weight: 300, + line-height: 50px, + // letter-spacing:-0.01562em + ), + 'h2': ( + size: 28px, + weight: 300, + line-height: 40px, + // letter-spacing: -0.00833em + ), + 'h3': ( + size: 24px, + weight: 400, + line-height: 32px, + // letter-spacing: normal + ), + 'h4': ( + size: 20px, + weight: 400, + line-height: 30px, + // letter-spacing: 0.00735em + ), + 'h5': ( + size: 16px, + weight: 400, + line-height: 24px, + // letter-spacing: normal + ), + 'h6': ( + size: 14px, + weight: 500, + line-height: 18px, + // letter-spacing: 0.0125em + ), + 'subtitle': ( + size: 12px, + weight: 400, + line-height: 20px, + // letter-spacing: 0.00937em + ), + 'body': ( + font-size: 14px, + font-weight: 400, + line-height: 22px, + // letter-spacing: 0.03125em + ), + 'caption': ( + 'size': 12px, + 'weight': 400, + 'line-height': 20px, + // 'letter-spacing': 0.03333em, + // 'text-transform': false + ) + ), + $uni-headings +); + + + +// 主色 +$uni-primary: #2979ff !default; +$uni-primary-disable:lighten($uni-primary,20%) !default; +$uni-primary-light: lighten($uni-primary,25%) !default; + +// 辅助色 +// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。 +$uni-success: #18bc37 !default; +$uni-success-disable:lighten($uni-success,20%) !default; +$uni-success-light: lighten($uni-success,25%) !default; + +$uni-warning: #f3a73f !default; +$uni-warning-disable:lighten($uni-warning,20%) !default; +$uni-warning-light: lighten($uni-warning,25%) !default; + +$uni-error: #e43d33 !default; +$uni-error-disable:lighten($uni-error,20%) !default; +$uni-error-light: lighten($uni-error,25%) !default; + +$uni-info: #8f939c !default; +$uni-info-disable:lighten($uni-info,20%) !default; +$uni-info-light: lighten($uni-info,25%) !default; + +// 中性色 +// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。 +$uni-main-color: #3a3a3a !default; // 主要文字 +$uni-base-color: #6a6a6a !default; // 常规文字 +$uni-secondary-color: #909399 !default; // 次要文字 +$uni-extra-color: #c7c7c7 !default; // 辅助说明 + +// 边框颜色 +$uni-border-1: #F0F0F0 !default; +$uni-border-2: #EDEDED !default; +$uni-border-3: #DCDCDC !default; +$uni-border-4: #B9B9B9 !default; + +// 常规色 +$uni-black: #000000 !default; +$uni-white: #ffffff !default; +$uni-transparent: rgba($color: #000000, $alpha: 0) !default; + +// 背景色 +$uni-bg-color: #f7f7f7 !default; + +/* 水平间距 */ +$uni-spacing-sm: 8px !default; +$uni-spacing-base: 15px !default; +$uni-spacing-lg: 30px !default; + +// 阴影 +$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5) !default; +$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2) !default; +$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5) !default; + +// 蒙版 +$uni-mask: rgba($color: #000000, $alpha: 0.4) !default; diff --git a/uni_modules/uni-scss/styles/tools/functions.scss b/uni_modules/uni-scss/styles/tools/functions.scss new file mode 100644 index 0000000..ac6f63e --- /dev/null +++ b/uni_modules/uni-scss/styles/tools/functions.scss @@ -0,0 +1,19 @@ +// 合并 map +@function map-deep-merge($parent-map, $child-map){ + $result: $parent-map; + @each $key, $child in $child-map { + $parent-has-key: map-has-key($result, $key); + $parent-value: map-get($result, $key); + $parent-type: type-of($parent-value); + $child-type: type-of($child); + $parent-is-map: $parent-type == map; + $child-is-map: $child-type == map; + + @if (not $parent-has-key) or ($parent-type != $child-type) or (not ($parent-is-map and $child-is-map)){ + $result: map-merge($result, ( $key: $child )); + }@else { + $result: map-merge($result, ( $key: map-deep-merge($parent-value, $child) )); + } + } + @return $result; +}; diff --git a/uni_modules/uni-scss/theme.scss b/uni_modules/uni-scss/theme.scss new file mode 100644 index 0000000..80ee62f --- /dev/null +++ b/uni_modules/uni-scss/theme.scss @@ -0,0 +1,31 @@ +// 间距基础倍数 +$uni-space-root: 2; +// 边框半径默认值 +$uni-radius-root:5px; +// 主色 +$uni-primary: #2979ff; +// 辅助色 +$uni-success: #4cd964; +// 警告色 +$uni-warning: #f0ad4e; +// 错误色 +$uni-error: #dd524d; +// 描述色 +$uni-info: #909399; +// 中性色 +$uni-main-color: #303133; +$uni-base-color: #606266; +$uni-secondary-color: #909399; +$uni-extra-color: #C0C4CC; +// 背景色 +$uni-bg-color: #f5f5f5; +// 边框颜色 +$uni-border-1: #DCDFE6; +$uni-border-2: #E4E7ED; +$uni-border-3: #EBEEF5; +$uni-border-4: #F2F6FC; + +// 常规色 +$uni-black: #000000; +$uni-white: #ffffff; +$uni-transparent: rgba($color: #000000, $alpha: 0); diff --git a/uni_modules/uni-scss/variables.scss b/uni_modules/uni-scss/variables.scss new file mode 100644 index 0000000..1c062d4 --- /dev/null +++ b/uni_modules/uni-scss/variables.scss @@ -0,0 +1,62 @@ +@import './styles/setting/_variables.scss'; +// 间距基础倍数 +$uni-space-root: 2; +// 边框半径默认值 +$uni-radius-root:5px; + +// 主色 +$uni-primary: #2979ff; +$uni-primary-disable:mix(#fff,$uni-primary,50%); +$uni-primary-light: mix(#fff,$uni-primary,80%); + +// 辅助色 +// 除了主色外的场景色,需要在不同的场景中使用(例如危险色表示危险的操作)。 +$uni-success: #18bc37; +$uni-success-disable:mix(#fff,$uni-success,50%); +$uni-success-light: mix(#fff,$uni-success,80%); + +$uni-warning: #f3a73f; +$uni-warning-disable:mix(#fff,$uni-warning,50%); +$uni-warning-light: mix(#fff,$uni-warning,80%); + +$uni-error: #e43d33; +$uni-error-disable:mix(#fff,$uni-error,50%); +$uni-error-light: mix(#fff,$uni-error,80%); + +$uni-info: #8f939c; +$uni-info-disable:mix(#fff,$uni-info,50%); +$uni-info-light: mix(#fff,$uni-info,80%); + +// 中性色 +// 中性色用于文本、背景和边框颜色。通过运用不同的中性色,来表现层次结构。 +$uni-main-color: #3a3a3a; // 主要文字 +$uni-base-color: #6a6a6a; // 常规文字 +$uni-secondary-color: #909399; // 次要文字 +$uni-extra-color: #c7c7c7; // 辅助说明 + +// 边框颜色 +$uni-border-1: #F0F0F0; +$uni-border-2: #EDEDED; +$uni-border-3: #DCDCDC; +$uni-border-4: #B9B9B9; + +// 常规色 +$uni-black: #000000; +$uni-white: #ffffff; +$uni-transparent: rgba($color: #000000, $alpha: 0); + +// 背景色 +$uni-bg-color: #f7f7f7; + +/* 水平间距 */ +$uni-spacing-sm: 8px; +$uni-spacing-base: 15px; +$uni-spacing-lg: 30px; + +// 阴影 +$uni-shadow-sm:0 0 5px rgba($color: #d8d8d8, $alpha: 0.5); +$uni-shadow-base:0 1px 8px 1px rgba($color: #a5a5a5, $alpha: 0.2); +$uni-shadow-lg:0px 1px 10px 2px rgba($color: #a5a4a4, $alpha: 0.5); + +// 蒙版 +$uni-mask: rgba($color: #000000, $alpha: 0.4); diff --git a/uni_modules/yaor-webview/changelog.md b/uni_modules/yaor-webview/changelog.md new file mode 100644 index 0000000..6c27063 --- /dev/null +++ b/uni_modules/yaor-webview/changelog.md @@ -0,0 +1,4 @@ + +## 1.0.1(2024-04-09) +精简的webview 跳外链及分享 +小程序(点击广告或弹出)跳转外链,及外链分享 diff --git a/uni_modules/yaor-webview/components/yaor-webview/yaor-webview.vue b/uni_modules/yaor-webview/components/yaor-webview/yaor-webview.vue new file mode 100644 index 0000000..9db2b1e --- /dev/null +++ b/uni_modules/yaor-webview/components/yaor-webview/yaor-webview.vue @@ -0,0 +1,41 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/yaor-webview/package.json b/uni_modules/yaor-webview/package.json new file mode 100644 index 0000000..9a6b305 --- /dev/null +++ b/uni_modules/yaor-webview/package.json @@ -0,0 +1,87 @@ +{ + "id": "yaor-webview", + "displayName": "小程序webview跳转(及分享)H5外链", + "version": "1.0.1", + "description": "点击广告或者推广活动大图,完成H5外链跳转及分享", + "keywords": [ + "webview", + "外链", + "H5", + "分享", + "广告推广活动" + ], + "repository": "", + "engines": { + "HBuilderX": "^3.96" + }, + "dcloudext": { + "type": "component-vue", + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "是", + "data": "无", + "permissions": "无" + }, + "npmurl": "" + }, + "uni_modules": { + "dependencies": [], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "y", + "aliyun": "y", + "alipay": "y" + }, + "client": { + "Vue": { + "vue2": "y", + "vue3": "y" + }, + "App": { + "app-vue": "y", + "app-nvue": "u", + "app-uvue": "u" + }, + "H5-mobile": { + "Safari": "y", + "Android Browser": "y", + "微信浏览器(Android)": "y", + "QQ浏览器(Android)": "y" + }, + "H5-pc": { + "Chrome": "y", + "IE": "y", + "Edge": "y", + "Firefox": "y", + "Safari": "y" + }, + "小程序": { + "微信": "y", + "阿里": "y", + "百度": "y", + "字节跳动": "y", + "QQ": "y", + "钉钉": "y", + "快手": "y", + "飞书": "y", + "京东": "y" + }, + "快应用": { + "华为": "y", + "联盟": "y" + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/yaor-webview/readme.md b/uni_modules/yaor-webview/readme.md new file mode 100644 index 0000000..c964e6e --- /dev/null +++ b/uni_modules/yaor-webview/readme.md @@ -0,0 +1 @@ +# 点击广告或者推广活动大图,完成H5外链跳转及分享 diff --git a/utils/filter/filterUtils.js b/utils/filter/filterUtils.js new file mode 100644 index 0000000..d9311d5 --- /dev/null +++ b/utils/filter/filterUtils.js @@ -0,0 +1,33 @@ +import Vue from 'vue' +// import { formatDate } from '@/utils/dateAndTimeUtils.js'; + + +Vue.filter("numberFormat",(value) => { + if(!value) value = 0; + var param = {}; + var k = 10000, + sizes = ['', '万', '亿', '万亿'], + i; + if(value < k){ + param.value =value + param.unit='' + }else{ + i = Math.floor(Math.log(value) / Math.log(k)); + param.value = ((value / Math.pow(k, i))).toFixed(2); + param.unit = sizes[i]; + } + let str = param.value + param.unit; + return str; +}) + + +// Vue.filter("formatDate",(data)=>{ +// const nDate=new Date(data); +// const year = nDate.getFullYear().toString().padStart(2,0); +// const month = nDate.getMonth().toString().padStart(2,0); +// const day = nDate.getDay().toString().padStart(2,0); +// const h = nDate.getHours().toString().padStart(2,0); +// const mm = nDate.getMinutes().toString().padStart(2,0); +// const s = nDate.getSeconds().toString().padStart(2,0); +// return year +'-'+ month +'-'+ day + " " + h + ":" + mm + ":"+ s +// }) \ No newline at end of file diff --git a/utils/httpUtils.js b/utils/httpUtils.js new file mode 100644 index 0000000..589fa5e --- /dev/null +++ b/utils/httpUtils.js @@ -0,0 +1,117 @@ +/* + http 请求工具方法 + */ +const querystring = require('querystring'); +const Signture = require('crypto') +import { baseUrl } from '@/config/baseConfig.js' +import msgUtils from '@/utils/msgUtils.js' + +// import store from '@/store/index.js' + +/* + * 格式化http url + * @params {String} url 请求地址 + * @params {String} nameSpace 请求api的空间 + */ +export function httpUrlFormat (url, nameSpace = 'exchange') { + return baseUrl(nameSpace) + url +} + +/* + 发起异步请求 + */ +export function ajaxSync(config) { + return new Promise(function(resolve, reject) { + const success = config.success; + const error = config.error; + // 发起请求 + uni.request(Object.assign(config, { + success(data) { + if(data.header.authorization){ + uni.setStorageSync('box-token',data.header.authorization) + } + // 401 未登录 或token已过期 + // 403 没有相关权限 + // 10000 登录失败 + if(data.data.code === 11000 || data.data.code === 401){ + msgUtils.msg(data.data.message); + uni.navigateTo({ + url:`/pages/login/login?type=back` + }) + }else if(data.data.code === 10001){ + msgUtils.msg(data.data.message); + uni.reLaunch({ + url:`/pages/login/past-due` + }) + }else if(data.data.code === 11010){ + msgUtils.msg(data.data.message); + uni.reLaunch({ + url:`/pages/login/shut-down` + }) + } + if(data.data.code === 403){ + msgUtils.msg(data.data.message); + } + if(data.data.code === 10000){ + msgUtils.msg(data.data.message); + } + + // if(data.data.code === 401){ + // msgUtils.msg("请登录"); + // uni.navigateTo({ + // url:`/pages/login/login?type='back'` + // }) + // } + success && success(data.data); + resolve(data.data); + }, + fail(data) { + // console.log(data) + // config.showTips && msgUtils.msg(data.data.msg); + error && error(data.data); + reject(data.data); + } + })); + }); +} + +/* + 发起row格式数据请求 + */ +export function ajaxForRawData(config) { + config.header = Object.assign(config.header || {}, { + // 'Content-Type': 'application/json; charset=UTF-8' + 'Content-Type': 'application/x-www-form-urlencoded' + }); + + if (typeof config.data === "object") { + config.data = JSON.stringify(config.data); + } + return ajaxSync(config); +}; + +/* + 发起需要携带校验凭证的请求:oauthAccessToken + */ +function getAuthorization(url, type, param) { + try { + // console.log("uni.getStorageSync('box-token'):",uni.getStorageSync('box-token')) + // return `Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MTc2ODQ3OTg2MDAxMjk1MzYwMSwibmlja25hbWUiOiLojonov7jmjqPnjJznl4UiLCJ1c2VybmFtZSI6IjE1MjgwMTE2MzgzIiwicGFzc3dvcmQiOiJxd2VyMTIzNDUiLCJzdGF0dXMiOjF9.ahpZGI8CdmPYYkywF62tNrpGniVrYKSWWh1XXfISUN8` + return `${uni.getStorageSync('box-token')}` + } catch { + // 跳转登录页 + // uni.navigateTo({ + // url: '/pages/login/login?type=back' + // }); + } +} + +export function ajaxCarryAuthorization(config) { + config.header = Object.assign(config.header || {}, { + Authorization: getAuthorization(config.url, config.method, config.data) + }); + if (config.isRawData) { + return ajaxForRawData(config); + } + return ajaxSync(config); +} \ No newline at end of file diff --git a/utils/index copy 1.html b/utils/index copy 1.html new file mode 100755 index 0000000..8e468d8 --- /dev/null +++ b/utils/index copy 1.html @@ -0,0 +1,1113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/utils/index copy 2.html b/utils/index copy 2.html new file mode 100755 index 0000000..8072999 --- /dev/null +++ b/utils/index copy 2.html @@ -0,0 +1,1128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/utils/index copy.html b/utils/index copy.html new file mode 100755 index 0000000..0ea5391 --- /dev/null +++ b/utils/index copy.html @@ -0,0 +1,1011 @@ + + + + + + + + + + +
+
+
请阅读并同意以下条款
+
+ 为保障您的合法权益,请您先阅读并同意《用户协议》以及《隐私政策》 +
+ +
+
+ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/utils/index.html b/utils/index.html new file mode 100755 index 0000000..8e468d8 --- /dev/null +++ b/utils/index.html @@ -0,0 +1,1113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/utils/jq.js b/utils/jq.js new file mode 100644 index 0000000..450a1a8 --- /dev/null +++ b/utils/jq.js @@ -0,0 +1,9814 @@ +/*! + * jQuery JavaScript Library v2.2.4 + * http://jquery.com/ + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2016-05-20T17:23Z + */ + +(function( global, factory ) { + + if ( typeof module === "object" && typeof module.exports === "object" ) { + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Support: Firefox 18+ +// Can't be in strict mode, several libs including ASP.NET trace +// the stack via arguments.caller.callee and Firefox dies if +// you try to trace through "use strict" call chains. (#13335) +//"use strict"; +var arr = []; + +var document = window.document; + +var slice = arr.slice; + +var concat = arr.concat; + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var support = {}; + + + +var + version = "2.2.4", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }, + + // Support: Android<4.1 + // Make sure we trim BOM and NBSP + rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + + // Matches dashed string for camelizing + rmsPrefix = /^-ms-/, + rdashAlpha = /-([\da-z])/gi, + + // Used by jQuery.camelCase as callback to replace() + fcamelCase = function( all, letter ) { + return letter.toUpperCase(); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // Start with an empty selector + selector: "", + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num != null ? + + // Return just the one element from the set + ( num < 0 ? this[ num + this.length ] : this[ num ] ) : + + // Return all the elements in a clean array + slice.call( this ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + ret.context = this.context; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = jQuery.isArray( copy ) ) ) ) { + + if ( copyIsArray ) { + copyIsArray = false; + clone = src && jQuery.isArray( src ) ? src : []; + + } else { + clone = src && jQuery.isPlainObject( src ) ? src : {}; + } + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isFunction: function( obj ) { + return jQuery.type( obj ) === "function"; + }, + + isArray: Array.isArray, + + isWindow: function( obj ) { + return obj != null && obj === obj.window; + }, + + isNumeric: function( obj ) { + + // parseFloat NaNs numeric-cast false positives (null|true|false|"") + // ...but misinterprets leading-number strings, particularly hex literals ("0x...") + // subtraction forces infinities to NaN + // adding 1 corrects loss of precision from parseFloat (#15100) + var realStringObj = obj && obj.toString(); + return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0; + }, + + isPlainObject: function( obj ) { + var key; + + // Not plain objects: + // - Any object or value whose internal [[Class]] property is not "[object Object]" + // - DOM nodes + // - window + if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { + return false; + } + + // Not own constructor property must be Object + if ( obj.constructor && + !hasOwn.call( obj, "constructor" ) && + !hasOwn.call( obj.constructor.prototype || {}, "isPrototypeOf" ) ) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own + for ( key in obj ) {} + + return key === undefined || hasOwn.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + var name; + for ( name in obj ) { + return false; + } + return true; + }, + + type: function( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android<4.0, iOS<6 (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; + }, + + // Evaluates a script in a global context + globalEval: function( code ) { + var script, + indirect = eval; + + code = jQuery.trim( code ); + + if ( code ) { + + // If the code includes a valid, prologue position + // strict mode pragma, execute code by injecting a + // script tag into the document. + if ( code.indexOf( "use strict" ) === 1 ) { + script = document.createElement( "script" ); + script.text = code; + document.head.appendChild( script ).parentNode.removeChild( script ); + } else { + + // Otherwise, avoid the DOM node creation, insertion + // and removal by using an indirect global eval + + indirect( code ); + } + } + }, + + // Convert dashed to camelCase; used by the css and data modules + // Support: IE9-11+ + // Microsoft forgot to hump their vendor prefix (#9572) + camelCase: function( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // Support: Android<4.1 + trim: function( text ) { + return text == null ? + "" : + ( text + "" ).replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // Bind a function to a context, optionally partially applying any + // arguments. + proxy: function( fn, context ) { + var tmp, args, proxy; + + if ( typeof context === "string" ) { + tmp = fn[ context ]; + context = fn; + fn = tmp; + } + + // Quick check to determine if target is callable, in the spec + // this throws a TypeError, but we will just return undefined. + if ( !jQuery.isFunction( fn ) ) { + return undefined; + } + + // Simulated bind + args = slice.call( arguments, 2 ); + proxy = function() { + return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); + }; + + // Set the guid of unique handler to the same of original handler, so it can be removed + proxy.guid = fn.guid = fn.guid || jQuery.guid++; + + return proxy; + }, + + now: Date.now, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +// JSHint would error on this code due to the Symbol not being defined in ES5. +// Defining this global in .jshintrc would create a danger of using the global +// unguarded in another place, it seems safer to just disable JSHint for these +// three lines. +/* jshint ignore: start */ +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} +/* jshint ignore: end */ + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: iOS 8.2 (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = jQuery.type( obj ); + + if ( type === "function" || jQuery.isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.2.1 + * http://sizzlejs.com/ + * + * Copyright jQuery Foundation and other contributors + * Released under the MIT license + * http://jquery.org/license + * + * Date: 2015-10-17 + */ +(function( window ) { + +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // General-purpose constants + MAX_NEGATIVE = 1 << 31, + + // Instance methods + hasOwn = ({}).hasOwnProperty, + arr = [], + pop = arr.pop, + push_native = arr.push, + push = arr.push, + slice = arr.slice, + // Use a stripped-down indexOf as it's faster than native + // http://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[i] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier + identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), + + rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + + whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + rescape = /'|\\/g, + + // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), + funescape = function( _, escaped, escapedWhitespace ) { + var high = "0x" + escaped - 0x10000; + // NaN means non-codepoint + // Support: Firefox<24 + // Workaround erroneous numeric interpretation of +"0x" + return high !== high || escapedWhitespace ? + escaped : + high < 0 ? + // BMP codepoint + String.fromCharCode( high + 0x10000 ) : + // Supplemental Plane codepoint (surrogate pair) + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }; + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + (arr = slice.call( preferredDoc.childNodes )), + preferredDoc.childNodes + ); + // Support: Android<4.0 + // Detect silently failing push.apply + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + push_native.apply( target, slice.call(els) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + // Can't trust NodeList.length + while ( (target[j++] = els[i++]) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, nidselect, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + + if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { + setDocument( context ); + } + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { + + // ID selector + if ( (m = match[1]) ) { + + // Document context + if ( nodeType === 9 ) { + if ( (elem = context.getElementById( m )) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && (elem = newContext.getElementById( m )) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[2] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( (m = match[3]) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !compilerCache[ selector + " " ] && + (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { + + if ( nodeType !== 1 ) { + newContext = context; + newSelector = selector; + + // qSA looks outside Element context, which is not what we want + // Thanks to Andrew Dupont for this workaround technique + // Support: IE <=8 + // Exclude object elements + } else if ( context.nodeName.toLowerCase() !== "object" ) { + + // Capture the context ID, setting it first if necessary + if ( (nid = context.getAttribute( "id" )) ) { + nid = nid.replace( rescape, "\\$&" ); + } else { + context.setAttribute( "id", (nid = expando) ); + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + nidselect = ridentifier.test( nid ) ? "#" + nid : "[id='" + nid + "']"; + while ( i-- ) { + groups[i] = nidselect + " " + toSelector( groups[i] ); + } + newSelector = groups.join( "," ); + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + } + + if ( newSelector ) { + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return (cache[ key + " " ] = value); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created div and expects a boolean result + */ +function assert( fn ) { + var div = document.createElement("div"); + + try { + return !!fn( div ); + } catch (e) { + return false; + } finally { + // Remove from its parent by default + if ( div.parentNode ) { + div.parentNode.removeChild( div ); + } + // release memory in IE + div = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split("|"), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[i] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + ( ~b.sourceIndex || MAX_NEGATIVE ) - + ( ~a.sourceIndex || MAX_NEGATIVE ); + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( (cur = cur.nextSibling) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return (name === "input" || name === "button") && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction(function( argument ) { + argument = +argument; + return markFunction(function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ (j = matchIndexes[i]) ] ) { + seed[j] = !(matches[j] = seed[j]); + } + } + }); + }); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = elem && (elem.ownerDocument || elem).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, parent, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9-11, Edge + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + if ( (parent = document.defaultView) && parent.top !== parent ) { + // Support: IE 11 + if ( parent.addEventListener ) { + parent.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( parent.attachEvent ) { + parent.attachEvent( "onunload", unloadHandler ); + } + } + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert(function( div ) { + div.className = "i"; + return !div.getAttribute("className"); + }); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert(function( div ) { + div.appendChild( document.createComment("") ); + return !div.getElementsByTagName("*").length; + }); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert(function( div ) { + docElem.appendChild( div ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + }); + + // ID find and filter + if ( support.getById ) { + Expr.find["ID"] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var m = context.getElementById( id ); + return m ? [ m ] : []; + } + }; + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute("id") === attrId; + }; + }; + } else { + // Support: IE6/7 + // getElementById is not reliable as a find shortcut + delete Expr.find["ID"]; + + Expr.filter["ID"] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode("id"); + return node && node.value === attrId; + }; + }; + } + + // Tag + Expr.find["TAG"] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( (elem = results[i++]) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See http://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert(function( div ) { + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // http://bugs.jquery.com/ticket/12359 + docElem.appendChild( div ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( div.querySelectorAll("[msallowcapture^='']").length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !div.querySelectorAll("[selected]").length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push("~="); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":checked").length ) { + rbuggyQSA.push(":checked"); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibing-combinator selector` fails + if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push(".#.+[+~]"); + } + }); + + assert(function( div ) { + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement("input"); + input.setAttribute( "type", "hidden" ); + div.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( div.querySelectorAll("[name=d]").length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( !div.querySelectorAll(":enabled").length ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Opera 10-11 does not throw on post-comma invalid pseudos + div.querySelectorAll("*,:x"); + rbuggyQSA.push(",.*:"); + }); + } + + if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector) )) ) { + + assert(function( div ) { + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( div, "div" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( div, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + }); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + )); + } : + function( a, b ) { + if ( b ) { + while ( (b = b.parentNode) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { + + // Choose the first element that is related to our preferred document + if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { + return -1; + } + if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + return a === document ? -1 : + b === document ? 1 : + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( (cur = cur.parentNode) ) { + ap.unshift( cur ); + } + cur = b; + while ( (cur = cur.parentNode) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[i] === bp[i] ) { + i++; + } + + return i ? + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[i], bp[i] ) : + + // Otherwise nodes in our document sort first + ap[i] === preferredDoc ? -1 : + bp[i] === preferredDoc ? 1 : + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + // Make sure that attribute selectors are quoted + expr = expr.replace( rattributeQuotes, "='$1']" ); + + if ( support.matchesSelector && documentIsHTML && + !compilerCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch (e) {} + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + // Set document vars if needed + if ( ( context.ownerDocument || context ) !== document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + // Set document vars if needed + if ( ( elem.ownerDocument || elem ) !== document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + (val = elem.getAttributeNode(name)) && val.specified ? + val.value : + null; +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( (elem = results[i++]) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + // If no nodeType, this is expected to be an array + while ( (node = elem[i++]) ) { + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[1] = match[1].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); + + if ( match[2] === "~=" ) { + match[3] = " " + match[3] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[1] = match[1].toLowerCase(); + + if ( match[1].slice( 0, 3 ) === "nth" ) { + // nth-* requires argument + if ( !match[3] ) { + Sizzle.error( match[0] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); + match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); + + // other types prohibit arguments + } else if ( match[3] ) { + Sizzle.error( match[0] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[6] && match[2]; + + if ( matchExpr["CHILD"].test( match[0] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[3] ) { + match[2] = match[4] || match[5] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + // Get excess from tokenize (recursively) + (excess = tokenize( unquoted, true )) && + // advance to the next closing parenthesis + (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { + + // excess is a negative index + match[0] = match[0].slice( 0, excess ); + match[2] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { return true; } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && + classCache( className, function( elem ) { + return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); + }); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + }; + }, + + "CHILD": function( type, what, argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( (node = node[ dir ]) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( (node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + (diff = nodeIndex = 0) || start.pop()) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + // Use previously-cached element index if available + if ( useCache ) { + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + // Use the same loop as above to seek `elem` from the start + while ( (node = ++nodeIndex && node && node[ dir ] || + (diff = nodeIndex = 0) || start.pop()) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || (node[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + (outerCache[ node.uniqueID ] = {}); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction(function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[i] ); + seed[ idx ] = !( matches[ idx ] = matched[i] ); + } + }) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + // Potentially complex pseudos + "not": markFunction(function( selector ) { + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction(function( seed, matches, context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( (elem = unmatched[i]) ) { + seed[i] = !(matches[i] = elem); + } + } + }) : + function( elem, context, xml ) { + input[0] = elem; + matcher( input, null, xml, results ); + // Don't keep the element (issue #299) + input[0] = null; + return !results.pop(); + }; + }), + + "has": markFunction(function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + }), + + "contains": markFunction(function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; + }; + }), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + // lang value must be a valid identifier + if ( !ridentifier.test(lang || "") ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( (elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); + return false; + }; + }), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); + }, + + // Boolean properties + "enabled": function( elem ) { + return elem.disabled === false; + }, + + "disabled": function( elem ) { + return elem.disabled === true; + }, + + "checked": function( elem ) { + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); + }, + + "selected": function( elem ) { + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos["empty"]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo(function() { + return [ 0 ]; + }), + + "last": createPositionalPseudo(function( matchIndexes, length ) { + return [ length - 1 ]; + }), + + "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + }), + + "even": createPositionalPseudo(function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "odd": createPositionalPseudo(function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }), + + "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + }) + } +}; + +Expr.pseudos["nth"] = Expr.pseudos["eq"]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || (match = rcomma.exec( soFar )) ) { + if ( match ) { + // Don't consume trailing commas as valid + soFar = soFar.slice( match[0].length ) || soFar; + } + groups.push( (tokens = []) ); + } + + matched = false; + + // Combinators + if ( (match = rcombinators.exec( soFar )) ) { + matched = match.shift(); + tokens.push({ + value: matched, + // Cast descendant combinators to space + type: match[0].replace( rtrim, " " ) + }); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || + (match = preFilters[ type ]( match ))) ) { + matched = match.shift(); + tokens.push({ + value: matched, + type: type, + matches: match + }); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[i].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + checkNonElements = base && dir === "parentNode", + doneName = done++; + + return combinator.first ? + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( (elem = elem[ dir ]) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || (elem[ expando ] = {}); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); + + if ( (oldCache = uniqueCache[ dir ]) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return (newCache[ 2 ] = oldCache[ 2 ]); + } else { + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ dir ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { + return true; + } + } + } + } + } + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[i]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[0]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[i], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( (elem = unmatched[i]) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction(function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( (elem = temp[i]) ) { + matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) ) { + // Restore matcherIn since elem is not yet a final match + temp.push( (matcherIn[i] = elem) ); + } + } + postFinder( null, (matcherOut = []), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( (elem = matcherOut[i]) && + (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { + + seed[temp] = !(results[temp] = elem); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + }); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[0].type ], + implicitRelative = leadingRelative || Expr.relative[" "], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + (checkContext = context).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( (matcher = Expr.relative[ tokens[i].type ]) ) { + matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; + } else { + matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[j].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), + len = elems.length; + + if ( outermost ) { + outermostContext = context === document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && (elem = elems[i]) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + if ( !context && elem.ownerDocument !== document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( (matcher = elementMatchers[j++]) ) { + if ( matcher( elem, context || document, xml) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + // They will have gone through all possible matchers + if ( (elem = !matcher && elem) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( (matcher = setMatchers[j++]) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !(unmatched[i] || setMatched[i]) ) { + setMatched[i] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[i] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( (selector = compiled.selector || selector) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[0] = match[0].slice( 0 ); + if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && + support.getById && context.nodeType === 9 && documentIsHTML && + Expr.relative[ tokens[1].type ] ) { + + context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[i]; + + // Abort if we hit a combinator + if ( Expr.relative[ (type = token.type) ] ) { + break; + } + if ( (find = Expr.find[ type ]) ) { + // Search, expanding context for leading sibling combinators + if ( (seed = find( + token.matches[0].replace( runescape, funescape ), + rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context + )) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert(function( div1 ) { + // Should return 1, but returns 4 (following) + return div1.compareDocumentPosition( document.createElement("div") ) & 1; +}); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert(function( div ) { + div.innerHTML = ""; + return div.firstChild.getAttribute("href") === "#" ; +}) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + }); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert(function( div ) { + div.innerHTML = ""; + div.firstChild.setAttribute( "value", "" ); + return div.firstChild.getAttribute( "value" ) === ""; +}) ) { + addHandle( "value", function( elem, name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + }); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert(function( div ) { + return div.getAttribute("disabled") == null; +}) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + (val = elem.getAttributeNode( name )) && val.specified ? + val.value : + null; + } + }); +} + +return Sizzle; + +})( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + +var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ ); + + + +var risSimple = /^.[^:#\[\.,]*$/; + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + /* jshint -W018 */ + return !!qualifier.call( elem, i, elem ) !== not; + } ); + + } + + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + + } + + if ( typeof qualifier === "string" ) { + if ( risSimple.test( qualifier ) ) { + return jQuery.filter( qualifier, elements, not ); + } + + qualifier = jQuery.filter( qualifier, elements ); + } + + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return elems.length === 1 && elem.nodeType === 1 ? + jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : + jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, + len = this.length, + ret = [], + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + // Needed because $( selector, context ) becomes $( context ).find( selector ) + ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); + ret.selector = this.selector ? this.selector + " " + selector : selector; + return ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( jQuery.isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + // Support: Blackberry 4.6 + // gEBID returns nodes no longer in the document (#6963) + if ( elem && elem.parentNode ) { + + // Inject the element directly into the jQuery object + this.length = 1; + this[ 0 ] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this.context = this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + if ( selector.selector !== undefined ) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? + jQuery( selectors, context || this.context ) : + 0; + + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( pos ? + pos.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + return elem.contentDocument || jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnotwhite = ( /\S+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( jQuery.isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, listener list, final state + [ "resolve", "done", jQuery.Callbacks( "once memory" ), "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), "rejected" ], + [ "notify", "progress", jQuery.Callbacks( "memory" ) ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + then: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( i, tuple ) { + var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; + + // deferred[ done | fail | progress ] for forwarding actions to newDefer + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && jQuery.isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this === promise ? newDefer.promise() : this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Keep pipe for back-compat + promise.pipe = promise.then; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 3 ]; + + // promise[ done | fail | progress ] = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( function() { + + // state = [ resolved | rejected ] + state = stateString; + + // [ reject_list | resolve_list ].disable; progress_list.lock + }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); + } + + // deferred[ resolve | reject | notify ] + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments ); + return this; + }; + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( subordinate /* , ..., subordinateN */ ) { + var i = 0, + resolveValues = slice.call( arguments ), + length = resolveValues.length, + + // the count of uncompleted subordinates + remaining = length !== 1 || + ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, + + // the master Deferred. + // If resolveValues consist of only a single Deferred, just use that. + deferred = remaining === 1 ? subordinate : jQuery.Deferred(), + + // Update function for both resolve and progress values + updateFunc = function( i, contexts, values ) { + return function( value ) { + contexts[ i ] = this; + values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( values === progressValues ) { + deferred.notifyWith( contexts, values ); + } else if ( !( --remaining ) ) { + deferred.resolveWith( contexts, values ); + } + }; + }, + + progressValues, progressContexts, resolveContexts; + + // Add listeners to Deferred subordinates; treat others as resolved + if ( length > 1 ) { + progressValues = new Array( length ); + progressContexts = new Array( length ); + resolveContexts = new Array( length ); + for ( ; i < length; i++ ) { + if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { + resolveValues[ i ].promise() + .progress( updateFunc( i, progressContexts, progressValues ) ) + .done( updateFunc( i, resolveContexts, resolveValues ) ) + .fail( deferred.reject ); + } else { + --remaining; + } + } + } + + // If we're not waiting on anything, resolve the master + if ( !remaining ) { + deferred.resolveWith( resolveContexts, resolveValues ); + } + + return deferred.promise(); + } +} ); + + +// The deferred used on DOM ready +var readyList; + +jQuery.fn.ready = function( fn ) { + + // Add the callback + jQuery.ready.promise().done( fn ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Hold (or release) the ready event + holdReady: function( hold ) { + if ( hold ) { + jQuery.readyWait++; + } else { + jQuery.ready( true ); + } + }, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + + // Trigger any bound ready events + if ( jQuery.fn.triggerHandler ) { + jQuery( document ).triggerHandler( "ready" ); + jQuery( document ).off( "ready" ); + } + } +} ); + +/** + * The ready event handler and self cleanup method + */ +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +jQuery.ready.promise = function( obj ) { + if ( !readyList ) { + + readyList = jQuery.Deferred(); + + // Catch cases where $(document).ready() is called + // after the browser event has already occurred. + // Support: IE9-10 only + // Older IE sometimes signals "interactive" too soon + if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + + } else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); + } + } + return readyList.promise( obj ); +}; + +// Kick off the DOM ready check even if the user does not +jQuery.ready.promise(); + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( jQuery.type( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !jQuery.isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + return chainable ? + elems : + + // Gets + bulk ? + fn.call( elems ) : + len ? fn( elems[ 0 ], key ) : emptyGet; +}; +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + /* jshint -W018 */ + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + register: function( owner, initial ) { + var value = initial || {}; + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable, non-writable property + // configurability must be true to allow the property to be + // deleted with the delete operator + } else { + Object.defineProperty( owner, this.expando, { + value: value, + writable: true, + configurable: true + } ); + } + return owner[ this.expando ]; + }, + cache: function( owner ) { + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( !acceptData( owner ) ) { + return {}; + } + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + if ( typeof data === "string" ) { + cache[ data ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ prop ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + owner[ this.expando ] && owner[ this.expando ][ key ]; + }, + access: function( owner, key, value ) { + var stored; + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + stored = this.get( owner, key ); + + return stored !== undefined ? + stored : this.get( owner, jQuery.camelCase( key ) ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, name, camel, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key === undefined ) { + this.register( owner ); + + } else { + + // Support array or space separated string of keys + if ( jQuery.isArray( key ) ) { + + // If "name" is an array of keys... + // When data is initially created, via ("key", "val") signature, + // keys will be converted to camelCase. + // Since there is no way to tell _how_ a key was added, remove + // both plain key and camelCase key. #12786 + // This will only penalize the array argument path. + name = key.concat( key.map( jQuery.camelCase ) ); + } else { + camel = jQuery.camelCase( key ); + + // Try the string as a key before any manipulation + if ( key in cache ) { + name = [ key, camel ]; + } else { + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + name = camel; + name = name in cache ? + [ name ] : ( name.match( rnotwhite ) || [] ); + } + } + + i = name.length; + + while ( i-- ) { + delete cache[ name[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <= 35-45+ + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://code.google.com/p/chromium/issues/detail?id=378607 + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = data === "true" ? true : + data === "false" ? false : + data === "null" ? null : + + // Only convert to a number if it doesn't change the string + +data + "" === data ? +data : + rbrace.test( data ) ? jQuery.parseJSON( data ) : + data; + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE11+ + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = jQuery.camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data, camelKey; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // with the key as-is + data = dataUser.get( elem, key ) || + + // Try to find dashed key if it exists (gh-2779) + // This is for 2.2.x only + dataUser.get( elem, key.replace( rmultiDash, "-$&" ).toLowerCase() ); + + if ( data !== undefined ) { + return data; + } + + camelKey = jQuery.camelCase( key ); + + // Attempt to get data from the cache + // with the key camelized + data = dataUser.get( elem, camelKey ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, camelKey, undefined ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + camelKey = jQuery.camelCase( key ); + this.each( function() { + + // First, attempt to store a copy or reference of any + // data that might've been store with a camelCased key. + var data = dataUser.get( this, camelKey ); + + // For HTML5 data-* attribute interop, we have to + // store property names with dashes in a camelCase form. + // This might not apply to all properties...* + dataUser.set( this, camelKey, value ); + + // *... In the case of properties that might _actually_ + // have dashes, we need to also store a copy of that + // unchanged property. + if ( key.indexOf( "-" ) > -1 && data !== undefined ) { + dataUser.set( this, key, value ); + } + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || jQuery.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var isHidden = function( elem, el ) { + + // isHidden might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + return jQuery.css( elem, "display" ) === "none" || + !jQuery.contains( elem.ownerDocument, elem ); + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, + scale = 1, + maxIterations = 20, + currentValue = tween ? + function() { return tween.cur(); } : + function() { return jQuery.css( elem, prop, "" ); }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + do { + + // If previous iteration zeroed out, double until we get *something*. + // Use string for doubling so we don't accidentally see scale as unchanged below + scale = scale || ".5"; + + // Adjust and apply + initialInUnit = initialInUnit / scale; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Update scale, tolerating zero or NaN from tween.cur() + // Break the loop if scale is unchanged or perfect, or if we've just had enough. + } while ( + scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations + ); + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([\w:-]+)/ ); + +var rscriptType = ( /^$|\/(?:java|ecma)script/i ); + + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // Support: IE9 + option: [ 1, "" ], + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
" ], + col: [ 2, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + + _default: [ 0, "", "" ] +}; + +// Support: IE9 +wrapMap.optgroup = wrapMap.option; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + + +function getAll( context, tag ) { + + // Support: IE9-11+ + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret = typeof context.getElementsByTagName !== "undefined" ? + context.getElementsByTagName( tag || "*" ) : + typeof context.querySelectorAll !== "undefined" ? + context.querySelectorAll( tag || "*" ) : + []; + + return tag === undefined || tag && jQuery.nodeName( context, tag ) ? + jQuery.merge( [ context ], ret ) : + ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, contains, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( jQuery.type( elem ) === "object" ) { + + // Support: Android<4.1, PhantomJS<2 + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android<4.1, PhantomJS<2 + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + contains = jQuery.contains( elem.ownerDocument, elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( contains ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0-4.3, Safari<=5.1 + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Safari<=5.1, Android<4.2 + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE<=11+ + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; +} )(); + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE9 +// See #13393 for more info +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Don't attach events to noData or text/comment nodes (but allow plain objects) + if ( !elemData ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = {}; + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnotwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( event ) { + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( event ); + + var i, j, ret, matched, handleObj, + handlerQueue = [], + args = slice.call( arguments ), + handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // Triggered event must either 1) have no namespace, or 2) have namespace(s) + // a subset or equal to those in the bound event (both can have no namespace). + if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, matches, sel, handleObj, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Support (at least): Chrome, IE9 + // Find delegate handlers + // Black-hole SVG instance trees (#13180) + // + // Support: Firefox<=42+ + // Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343) + if ( delegateCount && cur.nodeType && + ( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) { + matches = []; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matches[ sel ] === undefined ) { + matches[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matches[ sel ] ) { + matches.push( handleObj ); + } + } + if ( matches.length ) { + handlerQueue.push( { elem: cur, handlers: matches } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + // Includes some event props shared by KeyEvent and MouseEvent + props: ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " + + "metaKey relatedTarget shiftKey target timeStamp view which" ).split( " " ), + + fixHooks: {}, + + keyHooks: { + props: "char charCode key keyCode".split( " " ), + filter: function( event, original ) { + + // Add which for key events + if ( event.which == null ) { + event.which = original.charCode != null ? original.charCode : original.keyCode; + } + + return event; + } + }, + + mouseHooks: { + props: ( "button buttons clientX clientY offsetX offsetY pageX pageY " + + "screenX screenY toElement" ).split( " " ), + filter: function( event, original ) { + var eventDoc, doc, body, + button = original.button; + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && original.clientX != null ) { + eventDoc = event.target.ownerDocument || document; + doc = eventDoc.documentElement; + body = eventDoc.body; + + event.pageX = original.clientX + + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - + ( doc && doc.clientLeft || body && body.clientLeft || 0 ); + event.pageY = original.clientY + + ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - + ( doc && doc.clientTop || body && body.clientTop || 0 ); + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && button !== undefined ) { + event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); + } + + return event; + } + }, + + fix: function( event ) { + if ( event[ jQuery.expando ] ) { + return event; + } + + // Create a writable copy of the event object and normalize some properties + var i, prop, copy, + type = event.type, + originalEvent = event, + fixHook = this.fixHooks[ type ]; + + if ( !fixHook ) { + this.fixHooks[ type ] = fixHook = + rmouseEvent.test( type ) ? this.mouseHooks : + rkeyEvent.test( type ) ? this.keyHooks : + {}; + } + copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; + + event = new jQuery.Event( originalEvent ); + + i = copy.length; + while ( i-- ) { + prop = copy[ i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Support: Cordova 2.5 (WebKit) (#13255) + // All events should have a target; Cordova deviceready doesn't + if ( !event.target ) { + event.target = document; + } + + // Support: Safari 6.0+, Chrome<28 + // Target should not be a text node (#504, #13143) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + focus: { + + // Fire native event if possible so blur/focus sequence is correct + trigger: function() { + if ( this !== safeActiveElement() && this.focus ) { + this.focus(); + return false; + } + }, + delegateType: "focusin" + }, + blur: { + trigger: function() { + if ( this === safeActiveElement() && this.blur ) { + this.blur(); + return false; + } + }, + delegateType: "focusout" + }, + click: { + + // For checkbox, fire native event so checked state will be right + trigger: function() { + if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) { + this.click(); + return false; + } + }, + + // For cross-browser consistency, don't fire native .click() on links + _default: function( event ) { + return jQuery.nodeName( event.target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android<4.0 + src.returnValue === false ? + returnTrue : + returnFalse; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || jQuery.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://code.google.com/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi, + + // Support: IE 10-11, Edge 10240+ + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Manipulating tables requires a tbody +function manipulationTarget( elem, content ) { + return jQuery.nodeName( elem, "table" ) && + jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? + + elem.getElementsByTagName( "tbody" )[ 0 ] || + elem.appendChild( elem.ownerDocument.createElement( "tbody" ) ) : + elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + var match = rscriptTypeMasked.exec( elem.type ); + + if ( match ) { + elem.type = match[ 1 ]; + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.access( src ); + pdataCur = dataPriv.set( dest, pdataOld ); + events = pdataOld.events; + + if ( events ) { + delete pdataCur.handle; + pdataCur.events = {}; + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = concat.apply( [], args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + isFunction = jQuery.isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( isFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( isFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android<4.1, PhantomJS<2 + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl ) { + jQuery._evalUrl( node.src ); + } + } else { + jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html.replace( rxhtmlTag, "<$1>" ); + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = jQuery.contains( elem.ownerDocument, elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <= 35-45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <= 35-45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + + // Keep domManip exposed until 3.0 (gh-2225) + domManip: domManip, + + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: QtWebKit + // .get() because push.apply(_, arraylike) throws + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); + + +var iframe, + elemdisplay = { + + // Support: Firefox + // We have to pre-define these values for FF (#10227) + HTML: "block", + BODY: "block" + }; + +/** + * Retrieve the actual display of a element + * @param {String} name nodeName of the element + * @param {Object} doc Document object + */ + +// Called only from within defaultDisplay +function actualDisplay( name, doc ) { + var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), + + display = jQuery.css( elem[ 0 ], "display" ); + + // We don't have any data stored on the element, + // so use "detach" method as fast way to get rid of the element + elem.detach(); + + return display; +} + +/** + * Try to determine the default display value of an element + * @param {String} nodeName + */ +function defaultDisplay( nodeName ) { + var doc = document, + display = elemdisplay[ nodeName ]; + + if ( !display ) { + display = actualDisplay( nodeName, doc ); + + // If the simple way fails, read from inside an iframe + if ( display === "none" || !display ) { + + // Use the already-created iframe if possible + iframe = ( iframe || jQuery( "