-
7.gitignore
-
20App.vue
-
0README.md
-
139common/css/app.scss
-
8common/js/uniExport.js
-
96common/js/utils.js
-
741common/sdk/qqmap-wx-jssdk.js
-
3common/sdk/qqmap-wx-jssdk.min.js
-
130components/UserTab/UserTab - 副本.vue
-
117components/UserTab/UserTab.vue
-
65components/cancelReservation/cancelReservation.vue
-
59components/commentItem/commentItem.vue
-
24components/moreRight/moreRight.vue
-
59components/pozCard/pozCard.vue
-
78components/privacyPopup/privacyPopup.vue
-
35components/privacyRadion/privacyRadion.vue
-
51components/searchRow/searchRow.vue
-
27components/topNavbar/topNavbar.vue
-
10config/api.js
-
52config/request.js
-
20index.html
-
35main.js
-
100manifest.json
-
15package.json
-
153pages.json
-
120pages/indexEntry/settlement/detail/detail.vue
-
264pages/indexEntry/settlement/settlement.vue
-
27pages/other/webView/webView.vue
-
30pages/tabbar/examSimulation/index.vue
-
31pages/tabbar/mine/index.vue
-
31pages/tabbar/operateTrain/index.vue
-
51pages/tabbar/statistics/comp/stage.vue
-
205pages/tabbar/statistics/index.vue
-
71pages/userCenter/login/login.vue
-
187pages/userCenter/login/loginByPhone.vue
-
28project.config.json
-
7project.private.config.json
-
12site.config.js
-
BINstatic/images/bigImg/indexTopBanner.png
-
BINstatic/images/bigImg/topPageBg.png
-
BINstatic/images/index/ic_jiaxiao.png
-
BINstatic/images/index/ic_shuaxin.png
-
BINstatic/images/index/radio_cli.png
-
BINstatic/images/index/radio_nor.png
-
BINstatic/images/index/searchIcon.png
-
BINstatic/images/index/searchIconHui.png
-
BINstatic/images/logo.png
-
BINstatic/images/tabbar/btn_xueche_cli.png
-
BINstatic/images/tabbar/btn_xueche_nor.png
-
BINstatic/images/tabbar/kc.png
-
BINstatic/images/tabbar/kcActive.png
-
BINstatic/images/tabbar/sc.png
-
BINstatic/images/tabbar/scActive.png
-
BINstatic/images/tabbar/sy.png
-
BINstatic/images/tabbar/syActive.png
-
BINstatic/images/tabbar/tj.png
-
BINstatic/images/tabbar/tjActive.png
-
BINstatic/images/tabbar/tk.png
-
BINstatic/images/tabbar/tkActive.png
-
BINstatic/images/tabbar/wd.png
-
BINstatic/images/tabbar/wdActive.png
-
BINstatic/images/tabbar/xy.png
-
BINstatic/images/tabbar/xyActive.png
-
BINstatic/images/tabbar/zx.png
-
BINstatic/images/tabbar/zxActive.png
-
BINstatic/images/userCenter/loginTopBg.png
-
BINstatic/images/userCenter/title_1.png
-
BINstatic/images/登录流程切图/__MACOSX/登录流程切图/._.DS_Store
-
BINstatic/images/登录流程切图/__MACOSX/登录流程切图/._btn_1.png
-
BINstatic/images/登录流程切图/登录流程切图/.DS_Store
-
BINstatic/images/登录流程切图/登录流程切图/bg_1.png
-
BINstatic/images/登录流程切图/登录流程切图/btn_1.png
-
BINstatic/images/登录流程切图/登录流程切图/btn_2.png
-
BINstatic/images/登录流程切图/登录流程切图/title_1.png
-
BINstatic/logo.png
-
21store/getters.js
-
90store/index.js
-
91store/modules/add.js
-
31store/modules/user.js
-
10uni.promisify.adaptor.js
-
80uni.scss
-
6uni_modules/uni-config-center/changelog.md
-
81uni_modules/uni-config-center/package.json
-
93uni_modules/uni-config-center/readme.md
-
1uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js
-
9uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/package.json
-
25uni_modules/uni-open-bridge-common/changelog.md
-
84uni_modules/uni-open-bridge-common/package.json
-
5uni_modules/uni-open-bridge-common/readme.md
-
26uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/bridge-error.js
-
124uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/config.js
-
30uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/consts.js
-
317uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/index.js
-
15uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/package.json
-
111uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/storage.js
-
324uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/uni-cloud-cache.js
-
31uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/validator.js
-
203uni_modules/uni-open-bridge-common/uniCloud/cloudfunctions/common/uni-open-bridge-common/weixin-server.js
-
19uni_modules/uni-open-bridge-common/uniCloud/database/opendb-open-data.schema.json
-
8uni_modules/uni-scss/changelog.md
@ -0,0 +1,7 @@ |
|||
node_modules |
|||
package-lock.json |
|||
unpackage/dist |
|||
unpackage/cache |
|||
.hbuilderx |
|||
unpackage |
|||
|
@ -0,0 +1,20 @@ |
|||
<script> |
|||
export default { |
|||
onLaunch: function() { |
|||
console.log('App Launch') |
|||
// uni.hideTabBar(); |
|||
}, |
|||
onShow: function() { |
|||
console.log('App Show') |
|||
}, |
|||
onHide: function() { |
|||
console.log('App Hide') |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
/*每个页面公共css */ |
|||
@import '@/uni_modules/uview-ui/index.scss'; |
|||
@import 'common/css/app.scss' |
|||
</style> |
@ -0,0 +1,139 @@ |
|||
page { |
|||
background-color: #fff; |
|||
font-size: 32rpx; |
|||
font-family: -apple-system-font, Helvetica Neue, Helvetica, sans-serif; |
|||
} |
|||
view { |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
.oneRowText { |
|||
white-space: nowrap; |
|||
overflow: hidden; |
|||
text-overflow: ellipsis; |
|||
} |
|||
.towRowText { |
|||
display: -webkit-box; |
|||
overflow: hidden; |
|||
white-space: normal; |
|||
text-overflow: ellipsis; |
|||
word-wrap: break-word; |
|||
-webkit-line-clamp: 2; |
|||
-webkit-box-orient: vertical |
|||
} |
|||
.bgLinear { |
|||
background: linear-gradient(180deg, #3593FB 0%, #53D3E5 100%); |
|||
} |
|||
.flex-b { |
|||
justify-content: space-between; |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
.flex { |
|||
display: flex; |
|||
align-items: center; |
|||
} |
|||
.pageBg { |
|||
background: #F6F6F6; |
|||
color: #333; |
|||
font-size: 28rpx; |
|||
min-height: 100vh; |
|||
} |
|||
.pageBgImg { |
|||
font-size: 28rpx;; |
|||
color: #333; |
|||
background: url('http://192.168.1.20:81/zhili/image/20230824/afabc8b8a39544dc9ee4aea739b716cc.png') #F6F6F6 no-repeat; |
|||
background-size: 100% 324rpx; |
|||
min-height: 100vh; |
|||
} |
|||
.pad { |
|||
padding: 0 28rpx; |
|||
} |
|||
.card { |
|||
width: 100%; |
|||
background: #fff; |
|||
border-radius: 16rpx; |
|||
} |
|||
.status_bar { |
|||
height: var(--status-bar-height); |
|||
width: 100%; |
|||
} |
|||
image { |
|||
display: block; |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
.placeholderClassFFF { |
|||
color: #fff !important; |
|||
} |
|||
.starBox { |
|||
display: flex; |
|||
.num { |
|||
color: $themC; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
|
|||
.my .u-input { |
|||
height: 100%; |
|||
} |
|||
|
|||
.h1 { |
|||
font-size: 32rpx; |
|||
color: #333; |
|||
font-weight: 500; |
|||
position: relative; |
|||
padding: 0 0 0 32rpx; |
|||
&::before { |
|||
position: absolute; |
|||
content: ''; |
|||
width: 8rpx; |
|||
height: 32rpx; |
|||
background: #1F6EFA; |
|||
border-radius: 4rpx; |
|||
top: 50%; |
|||
transform: translateY(-50%); |
|||
left: 0; |
|||
} |
|||
} |
|||
|
|||
.btnBg { |
|||
height: 72rpx; |
|||
background: #1989FA; |
|||
border-radius: 8rpx; |
|||
line-height: 72rpx; |
|||
text-align: center; |
|||
font-size: 28rpx; |
|||
color: #fff; |
|||
} |
|||
|
|||
.btnBorder { |
|||
height: 72rpx; |
|||
background: #DFEAF5; |
|||
border-radius: 8rpx; |
|||
line-height: 72rpx; |
|||
text-align: center; |
|||
font-size: 28rpx; |
|||
color:$themC; |
|||
border: 2rpx solid #1989FA; |
|||
} |
|||
|
|||
/* 通用 */ |
|||
::-webkit-input-placeholder { color:#ADADAD; } |
|||
::-moz-placeholder { color:#ADADAD; } /* firefox 19+ */ |
|||
:-ms-input-placeholder { color:#ADADAD; } /* ie */ |
|||
input:-moz-placeholder { color:#ADADAD; } |
|||
|
|||
input::-webkit-input-placeholder { color: #CDCDCD !important; } |
|||
input::-moz-input-placeholder { color: #CDCDCD !important; } |
|||
input::-ms-input-placeholder { color: #CDCDCD !important; } |
|||
|
|||
// /* webkit专用 */ |
|||
.input1::-webkit-input-placeholder { color:#00f; } |
|||
// #input2::-webkit-input-placeholder { color:#090; background:lightgreen; text-transform:uppercase; } |
|||
// #input3::-webkit-input-placeholder { font-style:italic; text-decoration:overline; color:#999; } |
|||
|
|||
// /* mozilla专用 */ |
|||
// #input1::-moz-placeholder { color:#00f; } |
|||
// #input2::-moz-placeholder { color:#090; background:lightgreen; text-transform:uppercase; } |
|||
// #input3::-moz-placeholder { font-style:italic; text-decoration:overline; color:#999; } |
@ -0,0 +1,8 @@ |
|||
|
|||
export let goPage = (url, params={}, type='navigateTo')=> { |
|||
uni.$u.route({ |
|||
url, |
|||
params, |
|||
type |
|||
}) |
|||
} |
@ -0,0 +1,96 @@ |
|||
import store from '@/store'; |
|||
|
|||
const install = (Vue, vm) => { |
|||
|
|||
// 打开地图
|
|||
const openMap = (lat, lng) => { |
|||
uni.openLocation({ |
|||
latitude: lat, |
|||
longitude: lng |
|||
}) |
|||
} |
|||
|
|||
// 距离换算
|
|||
const distanceFn = (val) => { |
|||
if (val * 1 < 1000) { |
|||
return val + '米' |
|||
} else { |
|||
return (val / 1000).toFixed(2) + '公里' |
|||
} |
|||
} |
|||
// 价格计算
|
|||
const priceTo = (price = 0) => { |
|||
// return (price / 100).toFixed(2)
|
|||
return (parseInt(price * 100) / 100 / 100).toFixed(2) |
|||
|
|||
} |
|||
|
|||
const distanceLatLng = (lat1, lng1) => { |
|||
var that = this; |
|||
let lat2 = store.state.latLng.lat; |
|||
let lng2 = store.state.latLng.lng; |
|||
let rad1 = lat1 * Math.PI / 180.0; |
|||
let rad2 = lat2 * Math.PI / 180.0; |
|||
let a = rad1 - rad2; |
|||
let b = lng1 * Math.PI / 180.0 - lng2 * Math.PI / 180.0; |
|||
let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(rad1) * |
|||
Math.cos( |
|||
rad2) * Math.pow( |
|||
Math.sin(b / 2), 2))); |
|||
s = s * 6378.137; |
|||
s = Math.round(s * 10000) / 10000; |
|||
s = s.toString(); |
|||
s = s.substring(0, s.indexOf('.') + 2); |
|||
return s |
|||
|
|||
} |
|||
|
|||
const getLocation = () => { |
|||
return new Promise((resolve, reject) => { |
|||
uni.getLocation({ |
|||
type: 'wgs84', |
|||
success: function(res) { |
|||
console.log('当前位置的经度:' + res.longitude); |
|||
console.log('当前位置的纬度:' + res.latitude); |
|||
let obj = { |
|||
lat: res.latitude, |
|||
lng: res.longitude |
|||
} |
|||
store.commit('updateLatLng', obj) |
|||
resolve(obj) |
|||
} |
|||
}); |
|||
}).catch((e) => {}) |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
function addZeroPrefix(number) { |
|||
return number < 10 ? `0${number}` : number |
|||
} |
|||
|
|||
let getDate = (date, splitor = '-') => { |
|||
const year = date.getFullYear() |
|||
const month = date.getMonth() + 1 |
|||
const day = date.getDate() |
|||
return `${year}${splitor}${addZeroPrefix(month)}${splitor}${addZeroPrefix(day)}` |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
vm.$u.utils = { |
|||
openMap, |
|||
getLocation, |
|||
priceTo, |
|||
distanceLatLng, |
|||
distanceFn, |
|||
getDate, |
|||
} |
|||
} |
|||
|
|||
export default { |
|||
install |
|||
} |
@ -0,0 +1,741 @@ |
|||
/** |
|||
* 微信小程序JavaScriptSDK |
|||
* |
|||
* @version 1.1 |
|||
* @date 2019-01-20 |
|||
*/ |
|||
|
|||
var ERROR_CONF = { |
|||
KEY_ERR: 311, |
|||
KEY_ERR_MSG: 'key格式错误', |
|||
PARAM_ERR: 310, |
|||
PARAM_ERR_MSG: '请求参数信息有误', |
|||
SYSTEM_ERR: 600, |
|||
SYSTEM_ERR_MSG: '系统错误', |
|||
WX_ERR_CODE: 1000, |
|||
WX_OK_CODE: 200 |
|||
}; |
|||
var BASE_URL = 'https://apis.map.qq.com/ws/'; |
|||
var URL_SEARCH = BASE_URL + 'place/v1/search'; |
|||
var URL_SUGGESTION = BASE_URL + 'place/v1/suggestion'; |
|||
var URL_GET_GEOCODER = BASE_URL + 'geocoder/v1/'; |
|||
var URL_CITY_LIST = BASE_URL + 'district/v1/list'; |
|||
var URL_AREA_LIST = BASE_URL + 'district/v1/getchildren'; |
|||
var URL_DISTANCE = BASE_URL + 'distance/v1/'; |
|||
var EARTH_RADIUS = 6378136.49; |
|||
var Utils = { |
|||
/** |
|||
* 得到终点query字符串 |
|||
* @param {Array|String} 检索数据 |
|||
*/ |
|||
location2query(data) { |
|||
if (typeof data == 'string') { |
|||
return data; |
|||
} |
|||
var query = ''; |
|||
for (var i = 0; i < data.length; i++) { |
|||
var d = data[i]; |
|||
if (!!query) { |
|||
query += ';'; |
|||
} |
|||
if (d.location) { |
|||
query = query + d.location.lat + ',' + d.location.lng; |
|||
} |
|||
if (d.latitude && d.longitude) { |
|||
query = query + d.latitude + ',' + d.longitude; |
|||
} |
|||
} |
|||
return query; |
|||
}, |
|||
|
|||
/** |
|||
* 计算角度 |
|||
*/ |
|||
rad(d) { |
|||
return d * Math.PI / 180.0; |
|||
}, |
|||
/** |
|||
* 处理终点location数组 |
|||
* @return 返回终点数组 |
|||
*/ |
|||
getEndLocation(location){ |
|||
var to = location.split(';'); |
|||
var endLocation = []; |
|||
for (var i = 0; i < to.length; i++) { |
|||
endLocation.push({ |
|||
lat: parseFloat(to[i].split(',')[0]), |
|||
lng: parseFloat(to[i].split(',')[1]) |
|||
}) |
|||
} |
|||
return endLocation; |
|||
}, |
|||
|
|||
/** |
|||
* 计算两点间直线距离 |
|||
* @param a 表示纬度差 |
|||
* @param b 表示经度差 |
|||
* @return 返回的是距离,单位m |
|||
*/ |
|||
getDistance(latFrom, lngFrom, latTo, lngTo) { |
|||
var radLatFrom = this.rad(latFrom); |
|||
var radLatTo = this.rad(latTo); |
|||
var a = radLatFrom - radLatTo; |
|||
var b = this.rad(lngFrom) - this.rad(lngTo); |
|||
var distance = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLatFrom) * Math.cos(radLatTo) * Math.pow(Math.sin(b / 2), 2))); |
|||
distance = distance * EARTH_RADIUS; |
|||
distance = Math.round(distance * 10000) / 10000; |
|||
return parseFloat(distance.toFixed(0)); |
|||
}, |
|||
/** |
|||
* 使用微信接口进行定位 |
|||
*/ |
|||
getWXLocation(success, fail, complete) { |
|||
wx.getLocation({ |
|||
type: 'gcj02', |
|||
success: success, |
|||
fail: fail, |
|||
complete: complete |
|||
}); |
|||
}, |
|||
|
|||
/** |
|||
* 获取location参数 |
|||
*/ |
|||
getLocationParam(location) { |
|||
if (typeof location == 'string') { |
|||
var locationArr = location.split(','); |
|||
if (locationArr.length === 2) { |
|||
location = { |
|||
latitude: location.split(',')[0], |
|||
longitude: location.split(',')[1] |
|||
}; |
|||
} else { |
|||
location = {}; |
|||
} |
|||
} |
|||
return location; |
|||
}, |
|||
|
|||
/** |
|||
* 回调函数默认处理 |
|||
*/ |
|||
polyfillParam(param) { |
|||
param.success = param.success || function () { }; |
|||
param.fail = param.fail || function () { }; |
|||
param.complete = param.complete || function () { }; |
|||
}, |
|||
|
|||
/** |
|||
* 验证param对应的key值是否为空 |
|||
* |
|||
* @param {Object} param 接口参数 |
|||
* @param {String} key 对应参数的key |
|||
*/ |
|||
checkParamKeyEmpty(param, key) { |
|||
if (!param[key]) { |
|||
var errconf = this.buildErrorConfig(ERROR_CONF.PARAM_ERR, ERROR_CONF.PARAM_ERR_MSG + key +'参数格式有误'); |
|||
param.fail(errconf); |
|||
param.complete(errconf); |
|||
return true; |
|||
} |
|||
return false; |
|||
}, |
|||
|
|||
/** |
|||
* 验证参数中是否存在检索词keyword |
|||
* |
|||
* @param {Object} param 接口参数 |
|||
*/ |
|||
checkKeyword(param){ |
|||
return !this.checkParamKeyEmpty(param, 'keyword'); |
|||
}, |
|||
|
|||
/** |
|||
* 验证location值 |
|||
* |
|||
* @param {Object} param 接口参数 |
|||
*/ |
|||
checkLocation(param) { |
|||
var location = this.getLocationParam(param.location); |
|||
if (!location || !location.latitude || !location.longitude) { |
|||
var errconf = this.buildErrorConfig(ERROR_CONF.PARAM_ERR, ERROR_CONF.PARAM_ERR_MSG + ' location参数格式有误'); |
|||
param.fail(errconf); |
|||
param.complete(errconf); |
|||
return false; |
|||
} |
|||
return true; |
|||
}, |
|||
|
|||
/** |
|||
* 构造错误数据结构 |
|||
* @param {Number} errCode 错误码 |
|||
* @param {Number} errMsg 错误描述 |
|||
*/ |
|||
buildErrorConfig(errCode, errMsg) { |
|||
return { |
|||
status: errCode, |
|||
message: errMsg |
|||
}; |
|||
}, |
|||
|
|||
/** |
|||
* |
|||
* 数据处理函数 |
|||
* 根据传入参数不同处理不同数据 |
|||
* @param {String} feature 功能名称 |
|||
* search 地点搜索 |
|||
* suggest关键词提示 |
|||
* reverseGeocoder逆地址解析 |
|||
* geocoder地址解析 |
|||
* getCityList获取城市列表:父集 |
|||
* getDistrictByCityId获取区县列表:子集 |
|||
* calculateDistance距离计算 |
|||
* @param {Object} param 接口参数 |
|||
* @param {Object} data 数据 |
|||
*/ |
|||
handleData(param,data,feature){ |
|||
if (feature === 'search') { |
|||
var searchResult = data.data; |
|||
var searchSimplify = []; |
|||
for (var i = 0; i < searchResult.length; i++) { |
|||
searchSimplify.push({ |
|||
id: searchResult[i].id || null, |
|||
title: searchResult[i].title || null, |
|||
latitude: searchResult[i].location && searchResult[i].location.lat || null, |
|||
longitude: searchResult[i].location && searchResult[i].location.lng || null, |
|||
address: searchResult[i].address || null, |
|||
category: searchResult[i].category || null, |
|||
tel: searchResult[i].tel || null, |
|||
adcode: searchResult[i].ad_info && searchResult[i].ad_info.adcode || null, |
|||
city: searchResult[i].ad_info && searchResult[i].ad_info.city || null, |
|||
district: searchResult[i].ad_info && searchResult[i].ad_info.district || null, |
|||
province: searchResult[i].ad_info && searchResult[i].ad_info.province || null |
|||
}) |
|||
} |
|||
param.success(data, { |
|||
searchResult: searchResult, |
|||
searchSimplify: searchSimplify |
|||
}) |
|||
} else if (feature === 'suggest') { |
|||
var suggestResult = data.data; |
|||
var suggestSimplify = []; |
|||
for (var i = 0; i < suggestResult.length; i++) { |
|||
suggestSimplify.push({ |
|||
adcode: suggestResult[i].adcode || null, |
|||
address: suggestResult[i].address || null, |
|||
category: suggestResult[i].category || null, |
|||
city: suggestResult[i].city || null, |
|||
district: suggestResult[i].district || null, |
|||
id: suggestResult[i].id || null, |
|||
latitude: suggestResult[i].location && suggestResult[i].location.lat || null, |
|||
longitude: suggestResult[i].location && suggestResult[i].location.lng || null, |
|||
province: suggestResult[i].province || null, |
|||
title: suggestResult[i].title || null, |
|||
type: suggestResult[i].type || null |
|||
}) |
|||
} |
|||
param.success(data, { |
|||
suggestResult: suggestResult, |
|||
suggestSimplify: suggestSimplify |
|||
}) |
|||
} else if (feature === 'reverseGeocoder') { |
|||
var reverseGeocoderResult = data.result; |
|||
var reverseGeocoderSimplify = { |
|||
address: reverseGeocoderResult.address || null, |
|||
latitude: reverseGeocoderResult.location && reverseGeocoderResult.location.lat || null, |
|||
longitude: reverseGeocoderResult.location && reverseGeocoderResult.location.lng || null, |
|||
adcode: reverseGeocoderResult.ad_info && reverseGeocoderResult.ad_info.adcode || null, |
|||
city: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.city || null, |
|||
district: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.district || null, |
|||
nation: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.nation || null, |
|||
province: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.province || null, |
|||
street: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.street || null, |
|||
street_number: reverseGeocoderResult.address_component && reverseGeocoderResult.address_component.street_number || null, |
|||
recommend: reverseGeocoderResult.formatted_addresses && reverseGeocoderResult.formatted_addresses.recommend || null, |
|||
rough: reverseGeocoderResult.formatted_addresses && reverseGeocoderResult.formatted_addresses.rough || null |
|||
}; |
|||
if (reverseGeocoderResult.pois) {//判断是否返回周边poi
|
|||
var pois = reverseGeocoderResult.pois; |
|||
var poisSimplify = []; |
|||
for (var i = 0;i < pois.length;i++) { |
|||
poisSimplify.push({ |
|||
id: pois[i].id || null, |
|||
title: pois[i].title || null, |
|||
latitude: pois[i].location && pois[i].location.lat || null, |
|||
longitude: pois[i].location && pois[i].location.lng || null, |
|||
address: pois[i].address || null, |
|||
category: pois[i].category || null, |
|||
adcode: pois[i].ad_info && pois[i].ad_info.adcode || null, |
|||
city: pois[i].ad_info && pois[i].ad_info.city || null, |
|||
district: pois[i].ad_info && pois[i].ad_info.district || null, |
|||
province: pois[i].ad_info && pois[i].ad_info.province || null |
|||
}) |
|||
} |
|||
param.success(data,{ |
|||
reverseGeocoderResult: reverseGeocoderResult, |
|||
reverseGeocoderSimplify: reverseGeocoderSimplify, |
|||
pois: pois, |
|||
poisSimplify: poisSimplify |
|||
}) |
|||
} else { |
|||
param.success(data, { |
|||
reverseGeocoderResult: reverseGeocoderResult, |
|||
reverseGeocoderSimplify: reverseGeocoderSimplify |
|||
}) |
|||
} |
|||
} else if (feature === 'geocoder') { |
|||
var geocoderResult = data.result; |
|||
var geocoderSimplify = { |
|||
title: geocoderResult.title || null, |
|||
latitude: geocoderResult.location && geocoderResult.location.lat || null, |
|||
longitude: geocoderResult.location && geocoderResult.location.lng || null, |
|||
adcode: geocoderResult.ad_info && geocoderResult.ad_info.adcode || null, |
|||
province: geocoderResult.address_components && geocoderResult.address_components.province || null, |
|||
city: geocoderResult.address_components && geocoderResult.address_components.city || null, |
|||
district: geocoderResult.address_components && geocoderResult.address_components.district || null, |
|||
street: geocoderResult.address_components && geocoderResult.address_components.street || null, |
|||
street_number: geocoderResult.address_components && geocoderResult.address_components.street_number || null, |
|||
level: geocoderResult.level || null |
|||
}; |
|||
param.success(data,{ |
|||
geocoderResult: geocoderResult, |
|||
geocoderSimplify: geocoderSimplify |
|||
}); |
|||
} else if (feature === 'getCityList') { |
|||
var provinceResult = data.result[0]; |
|||
var cityResult = data.result[1]; |
|||
var districtResult = data.result[2]; |
|||
param.success(data,{ |
|||
provinceResult: provinceResult, |
|||
cityResult: cityResult, |
|||
districtResult: districtResult |
|||
}); |
|||
} else if (feature === 'getDistrictByCityId') { |
|||
var districtByCity = data.result[0]; |
|||
param.success(data, districtByCity); |
|||
} else if (feature === 'calculateDistance') { |
|||
var calculateDistanceResult = data.result.elements; |
|||
var distance = []; |
|||
for (var i = 0; i < calculateDistanceResult.length; i++){ |
|||
distance.push(calculateDistanceResult[i].distance); |
|||
} |
|||
param.success(data, { |
|||
calculateDistanceResult: calculateDistanceResult, |
|||
distance: distance |
|||
}); |
|||
} else { |
|||
param.success(data); |
|||
} |
|||
}, |
|||
|
|||
/** |
|||
* 构造微信请求参数,公共属性处理 |
|||
* |
|||
* @param {Object} param 接口参数 |
|||
* @param {Object} param 配置项 |
|||
* @param {String} feature 方法名 |
|||
*/ |
|||
buildWxRequestConfig(param, options, feature) { |
|||
var that = this; |
|||
options.header = { "content-type": "application/json" }; |
|||
options.method = 'GET'; |
|||
options.success = function (res) { |
|||
var data = res.data; |
|||
if (data.status === 0) { |
|||
that.handleData(param, data, feature); |
|||
} else { |
|||
param.fail(data); |
|||
} |
|||
}; |
|||
options.fail = function (res) { |
|||
res.statusCode = ERROR_CONF.WX_ERR_CODE; |
|||
param.fail(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)); |
|||
}; |
|||
options.complete = function (res) { |
|||
var statusCode = +res.statusCode; |
|||
switch(statusCode) { |
|||
case ERROR_CONF.WX_ERR_CODE: { |
|||
param.complete(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)); |
|||
break; |
|||
} |
|||
case ERROR_CONF.WX_OK_CODE: { |
|||
var data = res.data; |
|||
if (data.status === 0) { |
|||
param.complete(data); |
|||
} else { |
|||
param.complete(that.buildErrorConfig(data.status, data.message)); |
|||
} |
|||
break; |
|||
} |
|||
default:{ |
|||
param.complete(that.buildErrorConfig(ERROR_CONF.SYSTEM_ERR, ERROR_CONF.SYSTEM_ERR_MSG)); |
|||
} |
|||
|
|||
} |
|||
}; |
|||
return options; |
|||
}, |
|||
|
|||
/** |
|||
* 处理用户参数是否传入坐标进行不同的处理 |
|||
*/ |
|||
locationProcess(param, locationsuccess, locationfail, locationcomplete) { |
|||
var that = this; |
|||
locationfail = locationfail || function (res) { |
|||
res.statusCode = ERROR_CONF.WX_ERR_CODE; |
|||
param.fail(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)); |
|||
}; |
|||
locationcomplete = locationcomplete || function (res) { |
|||
if (res.statusCode == ERROR_CONF.WX_ERR_CODE) { |
|||
param.complete(that.buildErrorConfig(ERROR_CONF.WX_ERR_CODE, res.errMsg)); |
|||
} |
|||
}; |
|||
if (!param.location) { |
|||
that.getWXLocation(locationsuccess, locationfail, locationcomplete); |
|||
} else if (that.checkLocation(param)) { |
|||
var location = Utils.getLocationParam(param.location); |
|||
locationsuccess(location); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
|
|||
class QQMapWX { |
|||
|
|||
/** |
|||
* 构造函数 |
|||
* |
|||
* @param {Object} options 接口参数,key 为必选参数 |
|||
*/ |
|||
constructor(options) { |
|||
if (!options.key) { |
|||
throw Error('key值不能为空'); |
|||
} |
|||
this.key = options.key; |
|||
}; |
|||
|
|||
/** |
|||
* POI周边检索 |
|||
* |
|||
* @param {Object} options 接口参数对象 |
|||
* |
|||
* 参数对象结构可以参考 |
|||
* @see http://lbs.qq.com/webservice_v1/guide-search.html
|
|||
*/ |
|||
search(options) { |
|||
var that = this; |
|||
options = options || {}; |
|||
|
|||
Utils.polyfillParam(options); |
|||
|
|||
if (!Utils.checkKeyword(options)) { |
|||
return; |
|||
} |
|||
|
|||
var requestParam = { |
|||
keyword: options.keyword, |
|||
orderby: options.orderby || '_distance', |
|||
page_size: options.page_size || 10, |
|||
page_index: options.page_index || 1, |
|||
output: 'json', |
|||
key: that.key |
|||
}; |
|||
|
|||
if (options.address_format) { |
|||
requestParam.address_format = options.address_format; |
|||
} |
|||
|
|||
if (options.filter) { |
|||
requestParam.filter = options.filter; |
|||
} |
|||
|
|||
var distance = options.distance || "1000"; |
|||
var auto_extend = options.auto_extend || 1; |
|||
var region = null; |
|||
var rectangle = null; |
|||
|
|||
//判断城市限定参数
|
|||
if (options.region) { |
|||
region = options.region; |
|||
} |
|||
|
|||
//矩形限定坐标(暂时只支持字符串格式)
|
|||
if (options.rectangle) { |
|||
rectangle = options.rectangle; |
|||
} |
|||
|
|||
var locationsuccess = function (result) { |
|||
if (region && !rectangle) { |
|||
//城市限定参数拼接
|
|||
requestParam.boundary = "region(" + region + "," + auto_extend + "," + result.latitude + "," + result.longitude + ")"; |
|||
} else if (rectangle && !region) { |
|||
//矩形搜索
|
|||
requestParam.boundary = "rectangle(" + rectangle + ")"; |
|||
} else { |
|||
requestParam.boundary = "nearby(" + result.latitude + "," + result.longitude + "," + distance + "," + auto_extend + ")"; |
|||
} |
|||
wx.request(Utils.buildWxRequestConfig(options, { |
|||
url: URL_SEARCH, |
|||
data: requestParam |
|||
}, 'search')); |
|||
}; |
|||
Utils.locationProcess(options, locationsuccess); |
|||
}; |
|||
|
|||
/** |
|||
* sug模糊检索 |
|||
* |
|||
* @param {Object} options 接口参数对象 |
|||
* |
|||
* 参数对象结构可以参考 |
|||
* http://lbs.qq.com/webservice_v1/guide-suggestion.html
|
|||
*/ |
|||
getSuggestion(options) { |
|||
var that = this; |
|||
options = options || {}; |
|||
Utils.polyfillParam(options); |
|||
|
|||
if (!Utils.checkKeyword(options)) { |
|||
return; |
|||
} |
|||
|
|||
var requestParam = { |
|||
keyword: options.keyword, |
|||
region: options.region || '全国', |
|||
region_fix: options.region_fix || 0, |
|||
policy: options.policy || 0, |
|||
page_size: options.page_size || 10,//控制显示条数
|
|||
page_index: options.page_index || 1,//控制页数
|
|||
get_subpois : options.get_subpois || 0,//返回子地点
|
|||
output: 'json', |
|||
key: that.key |
|||
}; |
|||
//长地址
|
|||
if (options.address_format) { |
|||
requestParam.address_format = options.address_format; |
|||
} |
|||
//过滤
|
|||
if (options.filter) { |
|||
requestParam.filter = options.filter; |
|||
} |
|||
//排序
|
|||
if (options.location) { |
|||
var locationsuccess = function (result) { |
|||
requestParam.location = result.latitude + ',' + result.longitude; |
|||
wx.request(Utils.buildWxRequestConfig(options, { |
|||
url: URL_SUGGESTION, |
|||
data: requestParam |
|||
}, "suggest")); |
|||
}; |
|||
Utils.locationProcess(options, locationsuccess); |
|||
} else { |
|||
wx.request(Utils.buildWxRequestConfig(options, { |
|||
url: URL_SUGGESTION, |
|||
data: requestParam |
|||
}, "suggest")); |
|||
} |
|||
}; |
|||
|
|||
/** |
|||
* 逆地址解析 |
|||
* |
|||
* @param {Object} options 接口参数对象 |
|||
* |
|||
* 请求参数结构可以参考 |
|||
* http://lbs.qq.com/webservice_v1/guide-gcoder.html
|
|||
*/ |
|||
reverseGeocoder(options) { |
|||
var that = this; |
|||
options = options || {}; |
|||
Utils.polyfillParam(options); |
|||
var requestParam = { |
|||
coord_type: options.coord_type || 5, |
|||
get_poi: options.get_poi || 0, |
|||
output: 'json', |
|||
key: that.key |
|||
}; |
|||
if (options.poi_options) { |
|||
requestParam.poi_options = options.poi_options |
|||
} |
|||
|
|||
var locationsuccess = function (result) { |
|||
requestParam.location = result.latitude + ',' + result.longitude; |
|||
wx.request(Utils.buildWxRequestConfig(options, { |
|||
url: URL_GET_GEOCODER, |
|||
data: requestParam |
|||
}, 'reverseGeocoder')); |
|||
}; |
|||
Utils.locationProcess(options, locationsuccess); |
|||
}; |
|||
|
|||
/** |
|||
* 地址解析 |
|||
* |
|||
* @param {Object} options 接口参数对象 |
|||
* |
|||
* 请求参数结构可以参考 |
|||
* http://lbs.qq.com/webservice_v1/guide-geocoder.html
|
|||
*/ |
|||
geocoder(options) { |
|||
var that = this; |
|||
options = options || {}; |
|||
Utils.polyfillParam(options); |
|||
|
|||
if (Utils.checkParamKeyEmpty(options, 'address')) { |
|||
return; |
|||
} |
|||
|
|||
var requestParam = { |
|||
address: options.address, |
|||
output: 'json', |
|||
key: that.key |
|||
}; |
|||
|
|||
//城市限定
|
|||
if (options.region) { |
|||
requestParam.region = options.region; |
|||
} |
|||
|
|||
wx.request(Utils.buildWxRequestConfig(options, { |
|||
url: URL_GET_GEOCODER, |
|||
data: requestParam |
|||
},'geocoder')); |
|||
}; |
|||
|
|||
|
|||
/** |
|||
* 获取城市列表 |
|||
* |
|||
* @param {Object} options 接口参数对象 |
|||
* |
|||
* 请求参数结构可以参考 |
|||
* http://lbs.qq.com/webservice_v1/guide-region.html
|
|||
*/ |
|||
getCityList(options) { |
|||
var that = this; |
|||
options = options || {}; |
|||
Utils.polyfillParam(options); |
|||
var requestParam = { |
|||
output: 'json', |
|||
key: that.key |
|||
}; |
|||
|
|||
wx.request(Utils.buildWxRequestConfig(options, { |
|||
url: URL_CITY_LIST, |
|||
data: requestParam |
|||
},'getCityList')); |
|||
}; |
|||
|
|||
/** |
|||
* 获取对应城市ID的区县列表 |
|||
* |
|||
* @param {Object} options 接口参数对象 |
|||
* |
|||
* 请求参数结构可以参考 |
|||
* http://lbs.qq.com/webservice_v1/guide-region.html
|
|||
*/ |
|||
getDistrictByCityId(options) { |
|||
var that = this; |
|||
options = options || {}; |
|||
Utils.polyfillParam(options); |
|||
|
|||
if (Utils.checkParamKeyEmpty(options, 'id')) { |
|||
return; |
|||
} |
|||
|
|||
var requestParam = { |
|||
id: options.id || '', |
|||
output: 'json', |
|||
key: that.key |
|||
}; |
|||
|
|||
wx.request(Utils.buildWxRequestConfig(options, { |
|||
url: URL_AREA_LIST, |
|||
data: requestParam |
|||
},'getDistrictByCityId')); |
|||
}; |
|||
|
|||
/** |
|||
* 用于单起点到多终点的路线距离(非直线距离)计算: |
|||
* 支持两种距离计算方式:步行和驾车。 |
|||
* 起点到终点最大限制直线距离10公里。 |
|||
* |
|||
* 新增直线距离计算。 |
|||
* |
|||
* @param {Object} options 接口参数对象 |
|||
* |
|||
* 请求参数结构可以参考 |
|||
* http://lbs.qq.com/webservice_v1/guide-distance.html
|
|||
*/ |
|||
calculateDistance(options) { |
|||
var that = this; |
|||
options = options || {}; |
|||
Utils.polyfillParam(options); |
|||
|
|||
if (Utils.checkParamKeyEmpty(options, 'to')) { |
|||
return; |
|||
} |
|||
|
|||
var requestParam = { |
|||
mode: options.mode || 'walking', |
|||
to: Utils.location2query(options.to), |
|||
output: 'json', |
|||
key: that.key |
|||
}; |
|||
|
|||
if (options.from) { |
|||
options.location = options.from; |
|||
} |
|||
|
|||
//计算直线距离
|
|||
if(requestParam.mode == 'straight'){ |
|||
var locationsuccess = function (result) { |
|||
var locationTo = Utils.getEndLocation(requestParam.to);//处理终点坐标
|
|||
var data = { |
|||
message:"query ok", |
|||
result:{ |
|||
elements:[] |
|||
}, |
|||
status:0 |
|||
}; |
|||
for (var i = 0; i < locationTo.length; i++) { |
|||
data.result.elements.push({//将坐标存入
|
|||
distance: Utils.getDistance(result.latitude, result.longitude, locationTo[i].lat, locationTo[i].lng), |
|||
duration:0, |
|||
from:{ |
|||
lat: result.latitude, |
|||
lng:result.longitude |
|||
}, |
|||
to:{ |
|||
lat: locationTo[i].lat, |
|||
lng: locationTo[i].lng |
|||
} |
|||
}); |
|||
} |
|||
var calculateResult = data.result.elements; |
|||
var distanceResult = []; |
|||
for (var i = 0; i < calculateResult.length; i++) { |
|||
distanceResult.push(calculateResult[i].distance); |
|||
} |
|||
return options.success(data,{ |
|||
calculateResult: calculateResult, |
|||
distanceResult: distanceResult |
|||
}); |
|||
}; |
|||
|
|||
Utils.locationProcess(options, locationsuccess); |
|||
} else { |
|||
var locationsuccess = function (result) { |
|||
requestParam.from = result.latitude + ',' + result.longitude; |
|||
wx.request(Utils.buildWxRequestConfig(options, { |
|||
url: URL_DISTANCE, |
|||
data: requestParam |
|||
},'calculateDistance')); |
|||
}; |
|||
|
|||
Utils.locationProcess(options, locationsuccess); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
module.exports = QQMapWX; |
3
common/sdk/qqmap-wx-jssdk.min.js
File diff suppressed because it is too large
View File
@ -0,0 +1,130 @@ |
|||
<template> |
|||
<view class=""> |
|||
<!-- 学生端 --> |
|||
<u-tabbar v-if="showWho=='student'" :value="student" @change="studentChange" :fixed="true" :placeholder="true" |
|||
:safeAreaInsetBottom="true" activeColor="#31aef1"> |
|||
<u-tabbar-item v-for="i in studentList" :key='i.id' :text="i.name" :name="i.name"> |
|||
<image class="u-page__item__slot-icon" slot="active-icon" :src="i.active" mode="widthFix"></image> |
|||
<image class="u-page__item__slot-icon" slot="inactive-icon" :src="i.inactive" mode="widthFix"></image> |
|||
</u-tabbar-item> |
|||
|
|||
</u-tabbar> |
|||
<!-- 教师端 --> |
|||
<u-tabbar :value="teacher" @change="teacherChange" :fixed="true" :placeholder="true" |
|||
:safeAreaInsetBottom="true" activeColor="#31aef1"> |
|||
<u-tabbar-item v-for="i in teacherList" :key='i.id' :text="i.name" :name="i.name"> |
|||
<image class="u-page__item__slot-icon" slot="active-icon" :src="i.active" mode="widthFix"></image> |
|||
<image class="u-page__item__slot-icon" slot="inactive-icon" :src="i.inactive" mode="widthFix"></image> |
|||
</u-tabbar-item> |
|||
</u-tabbar> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: ['tabNumber'], |
|||
data() { |
|||
return { |
|||
teacher: '课堂', |
|||
student: '', |
|||
showWho: 'teacher', |
|||
teacherList: [{ |
|||
id: 1, |
|||
name: '课堂', |
|||
active: '../../static/images/tabbar/syActive.png', |
|||
inactive: '../../static/images/tabbar/sy.png' |
|||
}, |
|||
{ |
|||
id: 2, |
|||
name: '兴趣小组', |
|||
active: '../../static/images/tabbar/tkActive.png', |
|||
inactive: '../../static/images/tabbar/tk.png' |
|||
}, |
|||
{ |
|||
id: 3, |
|||
name: '我的', |
|||
active: '../../static/images/tabbar/zxActive.png', |
|||
inactive: '../../static/images/tabbar/zx.png' |
|||
} |
|||
], |
|||
studentList: [{ |
|||
id: 1, |
|||
name: '学员课堂', |
|||
active: '../../static/images/tabbar/syActive.png', |
|||
inactive: '../../static/images/tabbar/sy.png' |
|||
}, |
|||
{ |
|||
id: 2, |
|||
name: '学员兴趣小组', |
|||
active: '../../static/images/tabbar/tkActive.png', |
|||
inactive: '../../static/images/tabbar/tk.png' |
|||
}, |
|||
{ |
|||
id: 3, |
|||
name: '学员我的', |
|||
active: '../../static/images/tabbar/zxActive.png', |
|||
inactive: '../../static/images/tabbar/zx.png' |
|||
} |
|||
], |
|||
} |
|||
}, |
|||
mounted() { |
|||
// if (uni.getStorageSync('status') == 'teacher') { |
|||
// this.showWho = 'student' |
|||
// } else { |
|||
// this.showWho = 'teacher' |
|||
// } |
|||
this.student = this.tabNumber |
|||
this.teacher = this.tabNumber |
|||
}, |
|||
methods: { |
|||
teacherChange(e) { |
|||
this.teacher = e |
|||
if (e == '课堂') { |
|||
uni.reLaunch({ |
|||
url: "/pages/tabbar/index/index" |
|||
}) |
|||
// uni.hideHomeButton() //为了防止跳转页面后,小程序右上角会出现一个回到主页的小房子 |
|||
} else if (e == "兴趣小组") { |
|||
uni.reLaunch({ |
|||
url: "/pages/tabbar/question/index" |
|||
}) |
|||
// uni.hideHomeButton() |
|||
} else if (e == "我的") { |
|||
uni.reLaunch({ |
|||
url: "/pages/tabbar/mine/index" |
|||
}) |
|||
// uni.hideHomeButton() |
|||
} |
|||
}, |
|||
studentChange(e) { |
|||
this.student = e |
|||
uni.hideHomeButton() |
|||
// if (e == '课堂') { |
|||
// uni.reLaunch({ |
|||
// url: "/pages/index/CourseTeacherIndex" |
|||
// }) |
|||
// uni.hideHomeButton() //为了防止跳转页面后,小程序右上角会出现一个回到主页的小房子 |
|||
// } else if (e == "兴趣小组") { |
|||
// uni.reLaunch({ |
|||
// url: "/pages/interestGroup/interestGroup" |
|||
// }) |
|||
// uni.hideHomeButton() |
|||
// } else if (e == "我的") { |
|||
// uni.reLaunch({ |
|||
// url: "/pages/mine/mine" |
|||
// }) |
|||
// uni.hideHomeButton() |
|||
// } |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.u-page__item__slot-icon { |
|||
display: block; |
|||
width: 56rpx; |
|||
height: 56rpx; |
|||
} |
|||
</style> |
@ -0,0 +1,117 @@ |
|||
<template> |
|||
<view class="tab-bar"> |
|||
<view v-for="(item,index) in list" :key="index" class="tab-bar-item" @click="switchTab(item, index)"> |
|||
<image class="tab_img" :src="currentIndex == index ? item.selectedIconPath : item.iconPath"></image> |
|||
<view class="tab_text" :style="{color: currentIndex == index ? selectedColor : color}">{{item.text}}</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: { |
|||
selectedIndex: { // 当前选中的tab index |
|||
default: 0 |
|||
}, |
|||
}, |
|||
data() { |
|||
return { |
|||
color: "#666666", |
|||
selectedColor: "#00BAB2", |
|||
list: [], |
|||
currentIndex:0, |
|||
} |
|||
}, |
|||
created() { |
|||
this.currentIndex = this.selectedIndex; |
|||
|
|||
var _this = this |
|||
|
|||
if (uni.getStorageSync('identify') == 'nurse') { |
|||
//护士 |
|||
_this.list = [ |
|||
{ |
|||
"pagePath": "/pages/tabbar/index/index", |
|||
"text": "首页", |
|||
"iconPath": "/static/images/tabbar/sy.png", |
|||
"selectedIconPath": "/static/images/tabbar/syActive.png" |
|||
}, |
|||
{ |
|||
"pagePath": "/pages/tabbar/question/index", |
|||
"text": "题库", |
|||
"iconPath": "/static/images/tabbar/tk.png", |
|||
"selectedIconPath": "/static/images/tabbar/tkActive.png" |
|||
}, |
|||
{ |
|||
"pagePath": "/pages/tabbar/mine/index", |
|||
"text": "我的", |
|||
"iconPath": "/static/images/tabbar/wd.png", |
|||
"selectedIconPath": "/static/images/tabbar/wdActive.png" |
|||
} |
|||
] |
|||
} else { |
|||
//医管 |
|||
_this.list = [{ |
|||
"pagePath": "/pages/tabbar/index/index", |
|||
"text": "首1页", |
|||
"iconPath": "/static/images/tabbar/sy.png", |
|||
"selectedIconPath": "/static/images/tabbar/syActive.png" |
|||
}, |
|||
{ |
|||
"pagePath": "/pages/tabbar/question/index", |
|||
"text": "题2库", |
|||
"iconPath": "/static/images/tabbar/tk.png", |
|||
"selectedIconPath": "/static/images/tabbar/tkActive.png" |
|||
}, |
|||
{ |
|||
"pagePath": "/pages/tabbar/mine/index", |
|||
"text": "我3的", |
|||
"iconPath": "/static/images/tabbar/wd.png", |
|||
"selectedIconPath": "/static/images/tabbar/wdActive.png" |
|||
} |
|||
] |
|||
} |
|||
}, |
|||
methods: { |
|||
switchTab(item, index) { |
|||
this.currentIndex = index; |
|||
|
|||
let url = item.pagePath; |
|||
console.log(url) |
|||
uni.reLaunch({url:url}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss"> |
|||
.tab-bar { |
|||
position: fixed; |
|||
bottom: 0; |
|||
left: 0; |
|||
right: 0; |
|||
height: 100rpx; |
|||
background: white; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
padding-bottom: env(safe-area-inset-bottom); // 适配iphoneX的底部 |
|||
|
|||
.tab-bar-item { |
|||
flex: 1; |
|||
text-align: center; |
|||
display: flex; |
|||
justify-content: center; |
|||
align-items: center; |
|||
flex-direction: column; |
|||
.tab_img { |
|||
width: 48rpx; |
|||
height: 48rpx; |
|||
} |
|||
.tab_text { |
|||
font-size: 24rpx; |
|||
margin-top: 4rpx; |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,65 @@ |
|||
<template> |
|||
<view class="popupCon"> |
|||
<view class="h2">确定取消预约?</view> |
|||
<view class="txt">某个训练预约取消规则</view> |
|||
<view class="btnBox"> |
|||
<view class="btn" @click="$emit('popupBtnClick',0)">取消</view> |
|||
<view class="btn right" @click="$emit('popupBtnClick',1)">确定</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.popupCon { |
|||
width: 558rpx; |
|||
background: linear-gradient(180deg, #C1DFFE 0%, #FFFFFF 20%); |
|||
border-radius: 16rpx; |
|||
|
|||
.h2 { |
|||
font-size: 36rpx; |
|||
color: #333; |
|||
font-weight: 600; |
|||
text-align: center; |
|||
padding: 90rpx 0 0rpx 0; |
|||
} |
|||
|
|||
.txt { |
|||
text-align: center; |
|||
padding: 28rpx; |
|||
color: #686B73; |
|||
} |
|||
|
|||
.btnBox { |
|||
width: 100%; |
|||
height: 110rpx; |
|||
border-top: 1rpx solid #E8E9EC; |
|||
display: flex; |
|||
padding: 30rpx 0; |
|||
|
|||
.btn { |
|||
flex: 1; |
|||
text-align: center; |
|||
color: #ADADAD; |
|||
font-size: 36rpx; |
|||
} |
|||
|
|||
.btn.right { |
|||
color: $themC; |
|||
position: relative; |
|||
|
|||
&::before { |
|||
content: ''; |
|||
position: absolute; |
|||
left: 0; |
|||
top: 0; |
|||
width: 2rpx; |
|||
height: 48rpx; |
|||
background: #E8E9EC; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,59 @@ |
|||
<template> |
|||
<view class="box"> |
|||
<view class="flex-b"> |
|||
<view class="name">匿名用户</view> |
|||
<view class="date">2023/08/08</view> |
|||
</view> |
|||
<view class="starBox"> |
|||
<u-rate active-color="#1989FA" inactive-color="#1989FA" gutter="1" :size="16" :value="4" disabled></u-rate> |
|||
<view class="num">4.9分</view> |
|||
</view> |
|||
<view class="text">教学质量高,技术好,超有耐心,有责任心,学车就找这个驾校,教练都超好,满意满意满意</view> |
|||
<view class="imgBox"> |
|||
<view class="img"> |
|||
<image src="@/static/images/logo.png" mode=""></image> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.flex-b { |
|||
align-items: center; |
|||
.name { |
|||
font-weight: 600; |
|||
font-size: 32rpx; |
|||
color: #333; |
|||
} |
|||
|
|||
.date { |
|||
font-size: 24rpx; |
|||
color: #686B73; |
|||
} |
|||
} |
|||
|
|||
.starBox { |
|||
padding: 10rpx 0 24rpx 0; |
|||
} |
|||
|
|||
.text { |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.imgBox { |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
padding-top: 20rpx; |
|||
.img { |
|||
margin-top: 20rpx; |
|||
width: 160rpx; |
|||
height: 160rpx; |
|||
border-radius: 8rpx; |
|||
overflow: hidden; |
|||
margin-right: 24rpx; |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,24 @@ |
|||
<template> |
|||
<view class="moreBox"> |
|||
<view class="txt">{{text}}</view> |
|||
<u-icon name="arrow-right" color="#686B73" size="14"></u-icon> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: ['text'] |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.moreBox { |
|||
display: flex; |
|||
align-items: center; |
|||
.txt { |
|||
font-size: 24rpx; |
|||
color: #686B73; |
|||
margin-right: 8rpx; |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,59 @@ |
|||
<template> |
|||
<view class="card"> |
|||
<view class="flex-b"> |
|||
<view class="left_text"> |
|||
<view class="adr ">江西省江西市江西区某某镇尚坤丁兰国际1190号820</view> |
|||
<view class="distance">距您100km</view> |
|||
</view> |
|||
<view class="mapEntry"> |
|||
<view class="icon"> |
|||
<image src="@/static/images/index/mapIcon.png" mode=""></image> |
|||
</view> |
|||
<view class="text">地图导航</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.card { |
|||
padding: 24rpx; |
|||
.flex-b { |
|||
align-items: center; |
|||
.left_text { |
|||
flex: 1; |
|||
.adr { |
|||
font-size: 28rpx; |
|||
color: #333333; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
.distance { |
|||
margin-top: 24rpx; |
|||
color: #686B73; |
|||
font-size: 24rpx; |
|||
} |
|||
} |
|||
|
|||
.mapEntry { |
|||
width: 130rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
.icon { |
|||
width: 32rpx; |
|||
height: 32rpx; |
|||
} |
|||
|
|||
.text { |
|||
font-size: 24rpx; |
|||
margin-top: 10rpx; |
|||
color: $themC; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,78 @@ |
|||
<template> |
|||
<view class="privacyPopup"> |
|||
<view class="h2">个人信息保护声明</view> |
|||
<view class="content"> |
|||
<view class="nickName">亲爱的用户</view> |
|||
<view class="text"> |
|||
感谢您信任并使用江西驾考公共服 |
|||
务平台小程序。我们深知个人信息对您 |
|||
的重要性,非常重视您的个人信息和隐 |
|||
私保护,并会尽全力保护您的个人信息 |
|||
安全可靠。我们承诺,我们将按业界成 |
|||
熟的安全标准,采取相应的安全保护措 |
|||
《隐私政策》帮助您了解我们收集、使 |
|||
用、存储和共享个人信息的情况。 |
|||
在您注册成为学员的过程中,您需要 |
|||
</view> |
|||
</view> |
|||
<view class="btnBox"> |
|||
<view class="btn" @click="$emit('disagree')">不同意</view> |
|||
<view class="btn right" @click="$emit('agree')">同意</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.privacyPopup { |
|||
width: 558rpx; |
|||
position: relative; |
|||
background: linear-gradient(180deg, #C1DFFE 0%, #FFFFFF 20%); |
|||
border-radius: 16rpx; |
|||
|
|||
.h2 { |
|||
padding: 42rpx 0 0 0; |
|||
font-size: 36rpx; |
|||
color: #333; |
|||
text-align: center; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.content { |
|||
padding: 30rpx 30rpx 120rpx 30rpx; |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
.nickName { |
|||
z-index: 2em; |
|||
} |
|||
|
|||
.text { |
|||
margin-top: 16rpx; |
|||
z-index: 2em; |
|||
} |
|||
} |
|||
|
|||
.btnBox { |
|||
width: 100%; |
|||
height: 110rpx; |
|||
border-top: 1rpx solid #E8E9EC; |
|||
display: flex; |
|||
padding: 30rpx 0; |
|||
position: absolute; |
|||
left: 0; |
|||
bottom: 0; |
|||
.btn { |
|||
flex: 1; |
|||
text-align: center; |
|||
color: #ADADAD; |
|||
font-size: 36rpx; |
|||
} |
|||
|
|||
.btn.right { |
|||
color: $themC; |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,35 @@ |
|||
<template> |
|||
<view class="radioWrap"> |
|||
<u-checkbox-group @change="changeRadio"> |
|||
<u-checkbox v-model="isCheck" shape="circle" label="已阅读并同意" :labelSize="12" ></u-checkbox> |
|||
</u-checkbox-group> |
|||
<view class="privacyText"> |
|||
<text>《用户协议》</text>和 <text>《隐私协议》</text> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: ['isCheck'], |
|||
methods: { |
|||
changeRadio(val) { |
|||
this.$emit('changeRadio', val) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.radioWrap { |
|||
display: flex; |
|||
align-items: center; |
|||
.privacyText { |
|||
font-size: 24rpx; |
|||
color: #888E94; |
|||
text { |
|||
color: $themC; |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,51 @@ |
|||
<template> |
|||
<view class="searchBg"> |
|||
<view class="flex"> |
|||
<view class="searchIcon"> |
|||
<image src="@/static/images/index/searchIcon.png" mode=""></image> |
|||
</view> |
|||
<view class="inputBox"> |
|||
<u--input :placeholder="placeholder" border="none" clearable v-model="keywords" :color="'#fff'" |
|||
placeholderClass="placeholderClassFFF"></u--input> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: ['placeholder'], |
|||
data() { |
|||
return { |
|||
keywords: '' |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.searchBg { |
|||
background: #8ABAED; |
|||
width: 100%; |
|||
height: 72rpx; |
|||
border-radius: 16rpx; |
|||
line-height: 72rpx; |
|||
|
|||
.flex { |
|||
height: 100%; |
|||
padding: 0 28rpx; |
|||
|
|||
.searchIcon { |
|||
width: 40rpx; |
|||
height: 40rpx; |
|||
} |
|||
|
|||
.inputBox { |
|||
padding-left: 28rpx; |
|||
flex: 1; |
|||
color: #fff; |
|||
font-size: 28rpx; |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,27 @@ |
|||
<template> |
|||
<view class="topNavbar"> |
|||
<u-navbar |
|||
:leftText="title" |
|||
:autoBack="true" |
|||
:bgColor="bgColor" |
|||
:leftIconColor="leftIconColor" |
|||
:fixed="false" |
|||
> |
|||
</u-navbar> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
props: ['title'], |
|||
data() { |
|||
return { |
|||
bgColor: 'transparent', |
|||
leftIconColor: '#fff' |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
</style> |
@ -0,0 +1,10 @@ |
|||
|
|||
|
|||
const http = uni.$u.http |
|||
|
|||
// 隐私政策
|
|||
export const getAgreement = (params, config = {}) => http.post('/util/manage/getAgreement.do', params, config) |
|||
// 验证码登录
|
|||
export const loginSMS = (data) => http.post('/account/manage/login.do', data) |
|||
// 登录发验证码
|
|||
export const getLoginCode = (data) => http.post('/util/manage/getLoginRegistCode.do', data) |
@ -0,0 +1,52 @@ |
|||
|
|||
// 此vm参数为页面的实例,可以通过它引用vuex中的变量
|
|||
module.exports = (vm) => { |
|||
// 初始化请求配置
|
|||
uni.$u.http.setConfig((config) => { |
|||
/* config 为默认全局配置*/ |
|||
config.baseURL = 'http://121.41.97.244:8090'; /* 根域名 */ |
|||
config.header['content-type'] = 'application/x-www-form-urlencoded; charset=UTF-8' |
|||
return config |
|||
}) |
|||
|
|||
// 请求拦截
|
|||
uni.$u.http.interceptors.request.use((config) => { // 可使用async await 做异步操作
|
|||
// 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
|
|||
config.data = config.data || {} |
|||
// 根据custom参数中配置的是否需要token,添加对应的请求头
|
|||
if(config?.custom?.auth) { |
|||
// 可以在此通过vm引用vuex中的变量,具体值在vm.$store.state中
|
|||
config.header.token = vm.$store.state.userInfo.token |
|||
} |
|||
return config |
|||
}, config => { // 可使用async await 做异步操作
|
|||
return Promise.reject(config) |
|||
}) |
|||
|
|||
// 响应拦截
|
|||
uni.$u.http.interceptors.response.use((response) => { /* 对响应成功做点什么 可使用async await 做异步操作*/ |
|||
const data = response.data |
|||
console.log('response') |
|||
console.log(data) |
|||
// 自定义参数
|
|||
const custom = response.config?.custom |
|||
if (data.code !== 0) { |
|||
// 如果没有显式定义custom的toast参数为false的话,默认对报错进行toast弹出提示
|
|||
if (custom.toast !== false) { |
|||
uni.$u.toast(data.message) |
|||
} |
|||
|
|||
// 如果需要catch返回,则进行reject
|
|||
if (custom?.catch) { |
|||
return Promise.reject(data) |
|||
} else { |
|||
// 否则返回一个pending中的promise,请求不会进入catch中
|
|||
return new Promise(() => { }) |
|||
} |
|||
} |
|||
return data === undefined ? {} : data |
|||
}, (response) => { |
|||
// 对响应错误做点什么 (statusCode !== 200)
|
|||
return Promise.reject(response) |
|||
}) |
|||
} |
@ -0,0 +1,20 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<meta charset="UTF-8" /> |
|||
<script> |
|||
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || |
|||
CSS.supports('top: constant(a)')) |
|||
document.write( |
|||
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + |
|||
(coverSupport ? ', viewport-fit=cover' : '') + '" />') |
|||
</script> |
|||
<title></title> |
|||
<!--preload-links--> |
|||
<!--app-context--> |
|||
</head> |
|||
<body> |
|||
<div id="app"><!--app-html--></div> |
|||
<script type="module" src="/main.js"></script> |
|||
</body> |
|||
</html> |
@ -0,0 +1,35 @@ |
|||
import App from './App' |
|||
import Vue from 'vue' |
|||
import store from './store'; |
|||
|
|||
import { goPage } from './common/js/uniExport.js' |
|||
Vue.prototype.$goPage = goPage; |
|||
|
|||
import './uni.promisify.adaptor' |
|||
Vue.config.productionTip = false |
|||
App.mpType = 'app' |
|||
|
|||
// main.js,注意要在use方法之后执行
|
|||
import uView from '@/uni_modules/uview-ui' |
|||
Vue.use(uView) |
|||
|
|||
import tabBar from "components/UserTab/UserTab.vue" |
|||
Vue.component('tabBar',tabBar) |
|||
|
|||
const app = new Vue({ |
|||
...App, |
|||
store |
|||
}) |
|||
|
|||
require('./config/request.js')(app) |
|||
|
|||
|
|||
import utils from "@/common/js/utils.js" |
|||
console.log(utils) |
|||
// 自定义工具
|
|||
|
|||
Vue.use(utils,app) |
|||
|
|||
app.$mount() |
|||
|
|||
|
@ -0,0 +1,100 @@ |
|||
{ |
|||
"name" : "recruitStudent", |
|||
"appid" : "__UNI__BD23957", |
|||
"description" : "", |
|||
"versionName" : "1.0.0", |
|||
"versionCode" : "100", |
|||
"transformPx" : false, |
|||
/* 5+App特有相关 */ |
|||
"app-plus" : { |
|||
"usingComponents" : true, |
|||
"nvueStyleCompiler" : "uni-app", |
|||
"compilerVersion" : 3, |
|||
"splashscreen" : { |
|||
"alwaysShowBeforeRender" : true, |
|||
"waiting" : true, |
|||
"autoclose" : true, |
|||
"delay" : 0 |
|||
}, |
|||
/* 模块配置 */ |
|||
"modules" : {}, |
|||
/* 应用发布信息 */ |
|||
"distribute" : { |
|||
/* android打包配置 */ |
|||
"android" : { |
|||
"permissions" : [ |
|||
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>", |
|||
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>", |
|||
"<uses-permission android:name=\"android.permission.VIBRATE\"/>", |
|||
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>", |
|||
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>", |
|||
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>", |
|||
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>", |
|||
"<uses-permission android:name=\"android.permission.CAMERA\"/>", |
|||
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>", |
|||
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>", |
|||
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>", |
|||
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", |
|||
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>", |
|||
"<uses-feature android:name=\"android.hardware.camera\"/>", |
|||
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>" |
|||
] |
|||
}, |
|||
/* ios打包配置 */ |
|||
"ios" : {}, |
|||
/* SDK配置 */ |
|||
"sdkConfigs" : {} |
|||
} |
|||
}, |
|||
/* 快应用特有相关 */ |
|||
"quickapp" : {}, |
|||
/* 小程序特有相关 */ |
|||
"mp-weixin" : { |
|||
"appid" : "wx2d71605af3b620e6", |
|||
"setting" : { |
|||
"urlCheck" : false, |
|||
"es6" : true |
|||
}, |
|||
"usingComponents" : true, |
|||
"permission" : { |
|||
"scope.userLocation" : { |
|||
"desc" : "查询用户地理位置,推荐本地驾校,提高用户服务" |
|||
} |
|||
} |
|||
}, |
|||
"mp-alipay" : { |
|||
"usingComponents" : true |
|||
}, |
|||
"mp-baidu" : { |
|||
"usingComponents" : true |
|||
}, |
|||
"mp-toutiao" : { |
|||
"usingComponents" : true |
|||
}, |
|||
"uniStatistics" : { |
|||
"enable" : false |
|||
}, |
|||
"vueVersion" : "2", |
|||
"h5" : { |
|||
"devServer" : { |
|||
"port" : 8000, |
|||
"disableHostCheck" : true, |
|||
"proxy" : { |
|||
"/api" : { |
|||
"target" : "http://121.41.97.244:8090", |
|||
"changeOrigin" : true, |
|||
"secure" : true, |
|||
"pathRewrite" : { |
|||
//使用代理; 告诉他你这个连接要用代理 |
|||
"^/api" : "" |
|||
} |
|||
} |
|||
}, |
|||
"https" : false |
|||
}, |
|||
"router" : { |
|||
"mode" : "hash", |
|||
"base" : "/h5" |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,15 @@ |
|||
{ |
|||
"name": "recruitStudent", |
|||
"version": "1.0.0", |
|||
"description": "", |
|||
"main": "main.js", |
|||
"scripts": { |
|||
"test": "echo \"Error: no test specified\" && exit 1" |
|||
}, |
|||
"keywords": [], |
|||
"author": "", |
|||
"license": "ISC", |
|||
"dependencies": { |
|||
"uview-ui": "^2.0.36" |
|||
} |
|||
} |
@ -0,0 +1,153 @@ |
|||
{ |
|||
"pages": [ |
|||
{ |
|||
"path": "pages/tabbar/statistics/index", |
|||
"style": { |
|||
"navigationBarTitleText": "首页", |
|||
"navigationStyle": "custom", |
|||
"enablePullDownRefresh": true, |
|||
"backgroundTextStyle": "dark" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/tabbar/examSimulation/index", |
|||
"style": { |
|||
"navigationBarTitleText": "考场模拟", |
|||
"navigationStyle": "custom", |
|||
"enablePullDownRefresh": true, |
|||
"backgroundTextStyle": "dark" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/tabbar/operateTrain/index", |
|||
"style": { |
|||
"navigationBarTitleText": "实操训练", |
|||
"navigationStyle": "custom", |
|||
"enablePullDownRefresh": true, |
|||
"backgroundTextStyle": "dark" |
|||
} |
|||
}, |
|||
|
|||
{ |
|||
"path": "pages/tabbar/mine/index", |
|||
"style": { |
|||
"navigationBarTitleText": "我的", |
|||
"navigationStyle": "custom", |
|||
"enablePullDownRefresh": true, |
|||
"backgroundTextStyle": "dark" |
|||
} |
|||
} |
|||
], |
|||
"subPackages": [ |
|||
{ |
|||
"root": "pages/userCenter", |
|||
"pages": [ |
|||
{ |
|||
"path": "login/login", |
|||
"style": { |
|||
"navigationBarTitleText": "登录", |
|||
"navigationStyle": "custom", |
|||
"enablePullDownRefresh": false, |
|||
"backgroundTextStyle": "dark" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "login/loginByPhone", |
|||
"style": { |
|||
"navigationBarTitleText": "手机号登录", |
|||
"navigationStyle": "custom", |
|||
"enablePullDownRefresh": false, |
|||
"backgroundTextStyle": "dark" |
|||
} |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"root": "pages/indexEntry", |
|||
"pages": [ |
|||
{ |
|||
"path": "settlement/settlement", |
|||
"style": { |
|||
"navigationBarTitleText": "", |
|||
"navigationStyle": "custom", |
|||
"enablePullDownRefresh": false, |
|||
"backgroundTextStyle": "dark" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "settlement/detail/detail", |
|||
"style": { |
|||
"navigationBarTitleText": "", |
|||
"navigationStyle": "custom", |
|||
"enablePullDownRefresh": false, |
|||
"backgroundTextStyle": "dark" |
|||
} |
|||
} |
|||
] |
|||
}, |
|||
{ |
|||
"root": "pages/other", |
|||
"pages": [ |
|||
{ |
|||
"path": "webView/webView", |
|||
"style": { |
|||
"navigationBarTitleText": "", |
|||
"navigationStyle": "custom", |
|||
"enablePullDownRefresh": false, |
|||
"backgroundTextStyle": "dark" |
|||
} |
|||
} |
|||
] |
|||
} |
|||
], |
|||
"globalStyle": { |
|||
"navigationBarTextStyle": "black", |
|||
"navigationBarTitleText": "学车小程序", |
|||
"navigationBarBackgroundColor": "#F8F8F8", |
|||
"backgroundColor": "#F8F8F8" |
|||
}, |
|||
"uniIdRouter": {}, |
|||
"tabBar": { |
|||
"color": "#999999", |
|||
"selectedColor": "#218DFF", |
|||
"backgroundColor": "#FFFFFF", |
|||
"list": [{ |
|||
"pagePath": "pages/tabbar/statistics/index", |
|||
"text": "首页", |
|||
"iconPath": "static/images/tabbar/tj.png", |
|||
"selectedIconPath": "static/images/tabbar/tjActive.png" |
|||
}, |
|||
{ |
|||
"pagePath": "pages/tabbar/examSimulation/index", |
|||
"text": "考场模拟", |
|||
"iconPath": "static/images/tabbar/kc.png", |
|||
"selectedIconPath": "static/images/tabbar/kcActive.png" |
|||
}, |
|||
{ |
|||
"pagePath": "pages/tabbar/operateTrain/index", |
|||
"text": "实操训练", |
|||
"iconPath": "static/images/tabbar/sc.png", |
|||
"selectedIconPath": "static/images/tabbar/scActive.png" |
|||
}, |
|||
{ |
|||
"pagePath": "pages/tabbar/mine/index", |
|||
"text": "我的", |
|||
"iconPath": "static/images/tabbar/wd.png", |
|||
"selectedIconPath": "static/images/tabbar/wdActive.png" |
|||
} |
|||
] |
|||
}, |
|||
"easycom": { |
|||
"^u-(.*)": "@/uni_modules/uview-ui/components/u-$1/u-$1.vue" |
|||
}, |
|||
"condition" : { //模式配置,仅开发期间生效 |
|||
"current": 0, //当前激活的模式(list 的索引项) |
|||
"list": [ |
|||
{ |
|||
"name": "", //模式名称 |
|||
"path": "", //启动页面,必选 |
|||
"query": "" //启动参数,在页面的onLoad函数里面得到 |
|||
} |
|||
] |
|||
} |
|||
} |
@ -0,0 +1,120 @@ |
|||
<template> |
|||
<view class="pageBgImg "> |
|||
<topNavbar title="结算明细"></topNavbar> |
|||
<view class="pad"> |
|||
<view class="card"> |
|||
<view class="top_row"> |
|||
<view class="name">张三三</view> |
|||
<view class="tab">第二阶段</view> |
|||
<view class="price_row"> |
|||
<view class="jia">+</view> |
|||
<view class="price">¥12256.33</view> |
|||
</view> |
|||
</view> |
|||
<view class="row"> |
|||
<view class="text">学员确认</view> |
|||
<view class="iconPass"> |
|||
<image src="@/static/images/index/radio_cli.png" mode=""></image> |
|||
</view> |
|||
<view class="text">2023/08/08 10:55:21</view> |
|||
</view> |
|||
<view class="row"> |
|||
<view class="text">教练确认</view> |
|||
<view class="iconPass"> |
|||
<image src="@/static/images/index/radio_cli.png" mode=""></image> |
|||
</view> |
|||
<view class="text">2023/08/08 10:55:21</view> |
|||
</view> |
|||
<view class="row"> |
|||
<view class="text">驾校确认</view> |
|||
<view class="iconPass"> |
|||
<image src="@/static/images/index/radio_cli.png" mode=""></image> |
|||
</view> |
|||
<view class="text">2023/08/08 10:55:21</view> |
|||
</view> |
|||
</view> |
|||
<view class="card"> |
|||
<view class="row"> |
|||
<view class="text">学员手机号</view> |
|||
<view class="text">182671031657</view> |
|||
</view> |
|||
<view class="row"> |
|||
<view class="text">到账时间</view> |
|||
<view class="text">2023/08/08 10:55:21</view> |
|||
</view> |
|||
<view class="row"> |
|||
<view class="text">返款类型</view> |
|||
<view class="text">三方确认</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return {} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
|
|||
.card { |
|||
padding: 0 28rpx; |
|||
padding-bottom: 16rpx; |
|||
margin-bottom: 20rpx; |
|||
.top_row { |
|||
display: flex; |
|||
align-items: center; |
|||
height: 98rpx; |
|||
border-bottom: 2px dashed #E8E9EC; |
|||
.name { |
|||
font-size: 32rpx; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
.tab { |
|||
width: 144rpx; |
|||
height: 60rpx; |
|||
background: rgba(25,137,250,0.1); |
|||
border-radius: 8rpx; |
|||
font-size: 28rpx; |
|||
text-align: center; |
|||
line-height: 60rpx; |
|||
color: $themC; |
|||
margin-left: 14rpx; |
|||
} |
|||
|
|||
.price_row { |
|||
color: $themC; |
|||
margin-left: auto; |
|||
display: flex; |
|||
align-items: flex-end; |
|||
.jia { |
|||
font-size: 24rpx; |
|||
} |
|||
|
|||
.price { |
|||
font-size: 32rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.row { |
|||
height: 80rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
.text { |
|||
color: #686B73; |
|||
} |
|||
|
|||
.iconPass { |
|||
width: 32rpx; |
|||
height: 32rpx; |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,264 @@ |
|||
<template> |
|||
<!-- 结算明细 --> |
|||
<view class="pageBgImg"> |
|||
<topNavbar title="结算明细"></topNavbar> |
|||
<view class="pad"> |
|||
<searchRow placeholder="搜索学员姓名/学员手机号"/> |
|||
</view> |
|||
<scroll-view class="scroll-view_w" scroll-x="true" scroll-with-animation :scroll-into-view="'tab'+currentTab" scroll-left="140"> |
|||
<view class="tabs"> |
|||
<view class="tab" v-for="(item,index) in tabData" :key="index" @click="changeTab(item)" :class="{active: currentTab==item.id}" :id="'tab'+item.id">{{ item.text }}</view> |
|||
<view class="rightPad"></view> |
|||
</view> |
|||
</scroll-view> |
|||
<view class="content pad"> |
|||
<view class="month_row" @click="showDate=true"> |
|||
<!-- <view class="month">8</view> |
|||
<view class="unit">月</view> --> |
|||
<view class="">{{ selectDate }}</view> |
|||
<view class="iconFont"> |
|||
<u-icon name="arrow-down" color="#686B73" size="14"></u-icon> |
|||
</view> |
|||
</view> |
|||
<view class="total">结算金额共计</view> |
|||
<view class="record"> |
|||
<view class="card" v-for="(item,index) in 10" :key="index" @click="$goPage('/pages/indexEntry/settlement/detail/detail')"> |
|||
<stage/> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<u-popup :show="showDate" mode="bottom" :round="20" > |
|||
<view class="popupCon"> |
|||
<view class="popTab"> |
|||
<view class="tabItem" :class="{active: currentPopTab==1}" @click="changePopTab(1)">月份选择</view> |
|||
<view class="tabItem" :class="{active: currentPopTab==2}" @click="changePopTab(2)">自定义时间</view> |
|||
</view> |
|||
<view class="timer"> |
|||
<view class="tabCon" v-if="currentPopTab==1"> |
|||
<view class="dateBtn" @click="showDatePickerFn(1)" :class="{hui: !data1}">{{ date1 }}</view> |
|||
<!-- <u-datetime-picker-my |
|||
:show="show" |
|||
v-model="value1" |
|||
mode="year-month" |
|||
:showToolbar="false" |
|||
:visibleItemCount="4" |
|||
@confirm="confirm" |
|||
></u-datetime-picker-my> --> |
|||
</view> |
|||
<view class="tabCon" v-else> |
|||
<view class="dateBtn" :class="{hui: !data2}" @click="showDatePickerFn(2)">{{ date2 }}</view> |
|||
<view class="to">至</view> |
|||
<view class="dateBtn" :class="{hui: !data3}" @click="showDatePickerFn(3)">{{ date3 }}</view> |
|||
</view> |
|||
<view class="btnBg" @click="selectDateClick">确定</view> |
|||
<!-- <u-picker-my></u-picker-my> --> |
|||
</view> |
|||
</view> |
|||
</u-popup> |
|||
<u-datetime-picker |
|||
:show="showDatePicker" |
|||
v-model="value1" |
|||
mode="year-month" |
|||
:visibleItemCount="4" |
|||
:closeOnClickOverlay="false" |
|||
@confirm="confirmDatePicker" |
|||
@cancel="cancelDatePicker" |
|||
></u-datetime-picker> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import stage from '../../tabbar/statistics/comp/stage.vue' |
|||
export default { |
|||
components: { stage }, |
|||
data() { |
|||
return { |
|||
date3: '', |
|||
date2: '', |
|||
date1: '', |
|||
value1: '', |
|||
showDate: false, |
|||
showDatePicker: false, |
|||
show: false, |
|||
tabData: [{ |
|||
text: '全部', |
|||
id: 10 |
|||
}, |
|||
{ |
|||
text: '阶段一', |
|||
id: 0 |
|||
}, |
|||
{ |
|||
text: '阶段二', |
|||
id: 1 |
|||
}, |
|||
{ |
|||
text: '阶段三', |
|||
id: 2 |
|||
}, |
|||
{ |
|||
text: '阶段四', |
|||
id: 3 |
|||
}, |
|||
{ |
|||
text: '阶段五', |
|||
id: 4 |
|||
}, |
|||
{ |
|||
text: '阶段六', |
|||
id: 5 |
|||
}, |
|||
], |
|||
currentTab: 2, |
|||
currentPopTab: 2, |
|||
currentBtnDate: 1, |
|||
selectDate: '',//筛选日期 |
|||
} |
|||
}, |
|||
methods: { |
|||
// tab切换 |
|||
changeTab(val) { |
|||
this.currentTab = val.id |
|||
}, |
|||
// 切换选择时间的类型 |
|||
changePopTab(num) { |
|||
this.currentPopTab = num |
|||
}, |
|||
// 1打开时间选择器 |
|||
showDatePickerFn(num) { |
|||
this.showDate = false |
|||
this.showDatePicker = true |
|||
this.currentBtnDate = num |
|||
}, |
|||
// 2选择时间选择器里的时间 |
|||
confirmDatePicker(val) { |
|||
this.showDate = true |
|||
this.showDatePicker = false |
|||
let date = uni.$u.date(val.value, 'yyyy-mm-dd') |
|||
if(this.currentBtnDate==1) { |
|||
date = uni.$u.date(val.value, 'yyyy-mm') |
|||
} |
|||
this['date'+this.currentBtnDate] = date |
|||
}, |
|||
// 3最后确定具体选择使用什么时间 |
|||
selectDateClick() { |
|||
this.showDate = false |
|||
this.selectDate = this['date'+this.currentBtnDate] |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.scroll-view_w { |
|||
width: 100%; |
|||
margin: 30rpx 0 40rpx 0; |
|||
.tabs { |
|||
display: flex; |
|||
flex-wrap: nowrap; |
|||
padding: 0 0rpx 10rpx 32rpx; |
|||
width: auto; |
|||
.tab { |
|||
width: 108rpx; |
|||
height: 60rpx; |
|||
border-radius: 8rpx; |
|||
border: 2rpx solid #FFFFFF; |
|||
font-size: 28rpx; |
|||
color: #fff; |
|||
text-align: center; |
|||
line-height: 60rpx; |
|||
margin-right: 28rpx; |
|||
flex-shrink: 0; |
|||
|
|||
&.active { |
|||
background-color: #fff; |
|||
color: $themC; |
|||
} |
|||
|
|||
&.all { |
|||
width: 96rpx; |
|||
} |
|||
} |
|||
.rightPad { |
|||
min-width: 10rpx; |
|||
height: 60rpx; |
|||
|
|||
} |
|||
} |
|||
} |
|||
.month_row { |
|||
display: flex; |
|||
align-items: center; |
|||
color: $themC; |
|||
.month { |
|||
font-size: 50rpx; |
|||
font-weight: 600; |
|||
} |
|||
.unit { |
|||
font-size: 30rpx; |
|||
margin: 0 4rpx; |
|||
} |
|||
} |
|||
.total { |
|||
padding: 20rpx 0; |
|||
} |
|||
.card { |
|||
margin-bottom: 24rpx; |
|||
} |
|||
.popupCon { |
|||
height: 430rpx; |
|||
.popTab { |
|||
display: flex; |
|||
padding: 40rpx 32rpx; |
|||
.tabItem { |
|||
font-size: 32rpx; |
|||
color: #333; |
|||
margin-right: 60rpx; |
|||
&.active { |
|||
color: $themC; |
|||
position: relative; |
|||
&::before { |
|||
content: ''; |
|||
position: absolute; |
|||
bottom: -20rpx; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
width: 128rpx; |
|||
height: 4rpx; |
|||
background: #1989FA; |
|||
border-radius: 3rpx; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
} |
|||
.tabCon { |
|||
display: flex; |
|||
align-items: center; |
|||
padding-left: 32rpx; |
|||
padding-top: 20rpx; |
|||
.dateBtn { |
|||
width: 280rpx; |
|||
height: 80rpx; |
|||
border-radius: 10rpx; |
|||
border: 2rpx solid #1989FA; |
|||
line-height: 80rpx; |
|||
text-align: center; |
|||
color: $themC; |
|||
font-size: 32rpx; |
|||
&.hui { |
|||
border: 2rpx solid #E8E9EC; |
|||
} |
|||
} |
|||
.to { |
|||
font-size: 32rpx; |
|||
margin: 0 40rpx; |
|||
} |
|||
} |
|||
|
|||
.btnBg { |
|||
width: 396rpx; |
|||
margin: 34rpx auto 42rpx auto; |
|||
} |
|||
</style> |
@ -0,0 +1,27 @@ |
|||
<template> |
|||
<view> |
|||
<web-view :webview-styles="webviewStyles" src="http://192.168.1.20/system/menu"></web-view> |
|||
<!-- <web-view :webview-styles="webviewStyles" :src="$store.state.webViewUrl"></web-view> --> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
webviewStyles: { |
|||
progress: { |
|||
color: '#FF3333' |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
onLoad() { |
|||
console.log('噜噜哇'+ this.$store.state.webViewUrl) |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
|
|||
</style> |
@ -0,0 +1,30 @@ |
|||
<template> |
|||
<view class="content"> |
|||
考场模拟 |
|||
<!-- <UserTab selectedIndex ='1'></UserTab> --> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
} |
|||
}, |
|||
onLoad() { |
|||
}, |
|||
onShow() { |
|||
// uni.hideTabBar(); |
|||
}, |
|||
methods: { |
|||
goPage() {} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.content { |
|||
width: 100vw; |
|||
height: 100vh; |
|||
} |
|||
</style> |
@ -0,0 +1,31 @@ |
|||
<template> |
|||
<view class="content"> |
|||
我的 |
|||
<!-- <UserTab selectedIndex ='2'></UserTab> --> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
} |
|||
}, |
|||
onLoad() { |
|||
console.log('我的页面') |
|||
}, |
|||
onShow() { |
|||
// uni.hideTabBar(); |
|||
}, |
|||
methods: { |
|||
goPage() {} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.content { |
|||
width: 100vw; |
|||
height: 100%; |
|||
} |
|||
</style> |
@ -0,0 +1,31 @@ |
|||
<template> |
|||
<view class="content"> |
|||
实操训练 |
|||
<!-- <UserTab selectedIndex ='2'></UserTab> --> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
} |
|||
}, |
|||
onLoad() { |
|||
console.log('我的页面') |
|||
}, |
|||
onShow() { |
|||
// uni.hideTabBar(); |
|||
}, |
|||
methods: { |
|||
goPage() {} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.content { |
|||
width: 100vw; |
|||
height: 100%; |
|||
} |
|||
</style> |
@ -0,0 +1,51 @@ |
|||
<template> |
|||
<view class="li"> |
|||
<view class="name_row"> |
|||
<view class="name">张三三</view> |
|||
<view class="price">+¥1,130.86</view> |
|||
</view> |
|||
<view class="stage"> |
|||
<view>第一阶段</view> |
|||
<view>2023/08/08 10:55:21</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.li { |
|||
height: 168rpx; |
|||
padding: 0 34rpx; |
|||
|
|||
.name_row { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
height: 98rpx; |
|||
align-items: center; |
|||
|
|||
.name { |
|||
font-weight: 500; |
|||
font-size: 32rpx; |
|||
} |
|||
|
|||
.price { |
|||
font-size: 32rpx; |
|||
color: $themC; |
|||
font-weight: 500; |
|||
} |
|||
} |
|||
|
|||
.stage { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
height: 68rpx; |
|||
align-items: center; |
|||
font-size: 24rpx; |
|||
color: #686B73; |
|||
border-top: 2rpx dashed #E8E9EC; |
|||
; |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,205 @@ |
|||
<template> |
|||
<view class="content pageBg"> |
|||
<view class="userInfo"> |
|||
<view class="tit">Hi,大乔教练</view> |
|||
<view class="flex userRow"> |
|||
<view class="schoolIcon"> |
|||
<image src="@/static/images/index/ic_jiaxiao.png" mode=""></image> |
|||
</view> |
|||
<view class="schoolName oneRowText">翔力驾校</view> |
|||
<view class="tag">合作教练</view> |
|||
</view> |
|||
</view> |
|||
<view class="card priceBox"> |
|||
<view class="blueLab">今日已结算金额</view> |
|||
<view class="price">¥36333.66</view> |
|||
<view class="flex-b"> |
|||
<view class="data">截止:2023/08/08 11:00:00</view> |
|||
<view class="refresh"> |
|||
<view class="text">刷新</view> |
|||
<view class="icon"> |
|||
<image src="@/static/images/index/ic_shuaxin.png" mode=""></image> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<view class="h1">结算统计</view> |
|||
<view class="tabs"> |
|||
<view class="tab">按日</view> |
|||
<view class="tab">按月</view> |
|||
<view class="tab">按年</view> |
|||
<view class="tab long">自定义日期</view> |
|||
</view> |
|||
<view class="card"> |
|||
<view class="chart"> |
|||
图表到时候一起调 |
|||
</view> |
|||
</view> |
|||
<view class="flex-b"> |
|||
<view class="h1">结算明细</view> |
|||
<moreRight text="更多"/> |
|||
</view> |
|||
<view class="record"> |
|||
<view class="card"> |
|||
<stage/> |
|||
</view> |
|||
</view> |
|||
<view class="moreBtn" @click="$goPage('/pages/indexEntry/settlement/settlement')">查看更多</view> |
|||
<!-- <UserTab selectedIndex ='2'></UserTab> --> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import stage from './comp/stage' |
|||
export default { |
|||
components: { stage }, |
|||
data() { |
|||
return { |
|||
} |
|||
}, |
|||
onLoad() { |
|||
console.log('我的页面') |
|||
}, |
|||
onShow() { |
|||
// uni.hideTabBar(); |
|||
}, |
|||
methods: { |
|||
goPage() {} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.content { |
|||
width: 100%; |
|||
background: url('http://192.168.1.20:81/zhili/image/20230824/30073140957f4349b6579cb0ff00d4b1.png') #F6F6F6 no-repeat; |
|||
background-size: 100% 492rpx; |
|||
padding: 0 28rpx; |
|||
padding-top: 142rpx; |
|||
.userInfo { |
|||
|
|||
.tit { |
|||
font-size: 48rpx; |
|||
color: #fff; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
.userRow { |
|||
align-items: center; |
|||
margin-bottom: 20rpx; |
|||
.schoolIcon { |
|||
width: 28rpx; |
|||
height: 28rpx; |
|||
} |
|||
|
|||
.schoolName { |
|||
font-size: 28rpx; |
|||
padding: 20rpx; |
|||
max-width: 220rpx; |
|||
color: #fff; |
|||
} |
|||
|
|||
.tag { |
|||
width: 112rpx; |
|||
height: 44rpx; |
|||
background: #82AFDD; |
|||
border-radius: 22rpx; |
|||
font-size: 20rpx; |
|||
color: #fff; |
|||
line-height: 44rpx; |
|||
text-align: center; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.priceBox { |
|||
padding: 32rpx; |
|||
color: $themC; |
|||
.blueLab { |
|||
font-weight: 500; |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.price { |
|||
font-size: 56rpx; |
|||
font-weight: 600; |
|||
padding: 12rpx 0 24rpx 0; |
|||
} |
|||
|
|||
.flex-b { |
|||
|
|||
.data { |
|||
font-size: 24rpx; |
|||
color: #363A44; |
|||
} |
|||
|
|||
.refresh { |
|||
width: 130rpx; |
|||
height: 60rpx; |
|||
background: rgba(25,137,250,0.1); |
|||
border-radius: 8rpx; |
|||
border: 2rpx solid #1989FA; |
|||
line-height: 60rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
.text { |
|||
font-size: 28rpx; |
|||
} |
|||
|
|||
.icon { |
|||
width: 24rpx; |
|||
height: 24rpx; |
|||
margin-left: 6rpx; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.h1 { |
|||
margin: 32rpx 0 24rpx 0; |
|||
} |
|||
|
|||
.tabs { |
|||
display: flex; |
|||
justify-content: space-between; |
|||
padding-bottom: 24rpx; |
|||
.tab { |
|||
width: 96rpx; |
|||
height: 60rpx; |
|||
background: rgba(25,137,250,0.1); |
|||
border-radius: 8rpx; |
|||
border: 2rpx solid #1989FA; |
|||
font-size: 28rpx; |
|||
text-align: center; |
|||
line-height: 60rpx; |
|||
color: $themC; |
|||
&.active { |
|||
color: #fff; |
|||
background-color: $themC; |
|||
} |
|||
&.long { |
|||
width: 336rpx; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.card { |
|||
.chart { |
|||
|
|||
} |
|||
} |
|||
.moreBtn { |
|||
width: 200rpx; |
|||
height: 60rpx; |
|||
background: #FFFFFF; |
|||
border-radius: 8rpx; |
|||
border: 2rpx solid #E8E9EC; |
|||
color: #ADADAD; |
|||
text-align: center; |
|||
line-height: 60rpx; |
|||
margin: 32rpx auto 8rpx auto; |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,71 @@ |
|||
<template> |
|||
<view class="main"> |
|||
登录方式 |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
|
|||
} |
|||
}, |
|||
onLoad() { |
|||
// this.init() |
|||
|
|||
}, |
|||
methods: { |
|||
init() { |
|||
uni.login({ |
|||
provider: 'weixin', |
|||
"onlyAuthorize": true, |
|||
success: function (loginRes) { |
|||
console.log('11') |
|||
console.log(loginRes) |
|||
// 登录成功 |
|||
uni.getUserInfo({ |
|||
provider: 'weixin', |
|||
success: function(info) { |
|||
// 获取用户信息成功, info.authResult保存用户信息 |
|||
console.log('11') |
|||
console.log(info) |
|||
} |
|||
}) |
|||
}, |
|||
fail: function (err) { |
|||
// 登录授权失败 |
|||
// err.code是错误码 |
|||
} |
|||
}); |
|||
}, |
|||
|
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
// .radioWrap { |
|||
// display: flex; |
|||
// justify-content: flex-start; |
|||
// align-items: center; |
|||
|
|||
// /deep/.radio-btn { |
|||
// margin-right: -9rpx !important; |
|||
// } |
|||
|
|||
// radio { |
|||
// zoom: .8; |
|||
// } |
|||
|
|||
// view:nth-child(2) { |
|||
// font-size: 24rpx; |
|||
// color: #bfbfbf; |
|||
// } |
|||
|
|||
// text { |
|||
// color: #218DFF; |
|||
// font-size: 24rpx; |
|||
// } |
|||
// } |
|||
</style> |
@ -0,0 +1,187 @@ |
|||
<template> |
|||
<view class="main"> |
|||
<view class="u-back-top"> |
|||
<view class="backBox"> |
|||
<u-icon name="arrow-left" color="#333" size="28"></u-icon> |
|||
</view> |
|||
</view> |
|||
<view class="title">短信验证码登录</view> |
|||
<view class="form"> |
|||
<view class="form-item"> |
|||
<view class="prefix"> |
|||
<view class="jia">+</view> |
|||
<view class="num">86</view> |
|||
<view class="" style="margin: 0 32rpx 0 12rpx;"> |
|||
<u-icon name="arrow-down" color="#333" size="16" ></u-icon> |
|||
</view> |
|||
</view> |
|||
<view class="inputBox my"> |
|||
<u--input placeholder="请输入手机号" border="none" clearable type="number" maxlength="11" v-model="FormData.phone"></u--input> |
|||
</view> |
|||
</view> |
|||
<view class="form-item"> |
|||
<view class="inputBox my"> |
|||
<u--input placeholder="请输入验证码" border="none" clearable style="height: 100%;" :clearable="false" v-model="FormData.code"></u--input> |
|||
</view> |
|||
<view class="code" @tap='goSms' :class="{active: isPhone&&!codeOn}">{{codeText}}</view> |
|||
</view> |
|||
<view class="loginBtn" :class="{active: btnHighlight}" @click="submitFn">登 录</view> |
|||
<view class="radioWrap"> |
|||
<u-checkbox-group > |
|||
<u-checkbox v-model="isCheck" shape="circle" label="已阅读并同意" :labelSize="12" ></u-checkbox> |
|||
</u-checkbox-group> |
|||
<view class="privacyText"> |
|||
<text>《用户协议》</text>和 <text>《隐私协议》</text> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
import { getLoginCode } from '@/config/api.js' |
|||
export default { |
|||
data() { |
|||
return { |
|||
isCheck: false, |
|||
codeText: '获取验证码', |
|||
FormData: {}, |
|||
codeOn: false |
|||
} |
|||
}, |
|||
onLoad() { |
|||
|
|||
}, |
|||
computed: { |
|||
isPhone() { |
|||
return uni.$u.test.mobile(this.FormData.phone) |
|||
}, |
|||
btnHighlight() { |
|||
return this.isPhone&&uni.$u.test.code(this.FormData.code, 4) |
|||
} |
|||
}, |
|||
methods: { |
|||
// 是否选择协议 |
|||
groupChangeEnvnt(e) { |
|||
this.isCheck = e.value |
|||
console.log('是否选择协议', this.isCheck) |
|||
}, |
|||
// 发送短信验证码 |
|||
async goSms() { |
|||
const { |
|||
FormData |
|||
} = this |
|||
if (!FormData.phone) return this.$u.toast('请输入手机号'); |
|||
if (!this.isPhone) return this.$u.toast('手机号格式有误'); |
|||
if (this.codeOn) return |
|||
const data = await getLoginCode({ |
|||
codeType: 1, |
|||
phone: FormData.phone, |
|||
}) |
|||
console.log(data) |
|||
// 获取验证码 |
|||
var time = 60; |
|||
var timer = setInterval(() => { |
|||
time--; |
|||
this.codeText = time + "秒后重新发送" |
|||
this.codeOn = true; |
|||
if (time == 0) { |
|||
clearInterval(timer); |
|||
this.codeText = "获取验证码"; |
|||
this.codeOn = false; |
|||
} |
|||
}, 1000); |
|||
}, |
|||
submitFn() { |
|||
uni.switchTab({ |
|||
url: '/pages/tabbar/index/index' |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
|
|||
.main { |
|||
width: 100%; |
|||
min-height: 100vh; |
|||
background: url('../../../static/images/userCenter/loginTopBg.png') no-repeat; |
|||
background-size: 100% 360rpx; |
|||
.u-back-top { |
|||
padding: 32rpx 0 0 0; |
|||
.backBox { |
|||
padding: 24rpx; |
|||
} |
|||
} |
|||
|
|||
.title { |
|||
font-size: 48rpx; |
|||
color: #333; |
|||
padding: 92rpx 0; |
|||
text-align: center; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.form { |
|||
padding: 0 46rpx; |
|||
.form-item { |
|||
height: 112rpx; |
|||
background: #F4F7FF; |
|||
border-radius: 16rpx; |
|||
width: 100%; |
|||
line-height: 112rpx; |
|||
display: flex; |
|||
margin-bottom: 40rpx; |
|||
padding: 0 40rpx; |
|||
.prefix { |
|||
display: flex; |
|||
align-items: center; |
|||
font-size: 32rpx; |
|||
color: #333; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.inputBox { |
|||
flex: 1; |
|||
} |
|||
.code { |
|||
color: #BBBBBB; |
|||
margin-left: 30rpx; |
|||
&.active { |
|||
color: $themC |
|||
} |
|||
} |
|||
} |
|||
|
|||
.loginBtn { |
|||
width: 100%; |
|||
height: 112rpx; |
|||
background: rgba(25,137,250,0.3); |
|||
border-radius: 16rpx; |
|||
text-align: center; |
|||
line-height: 112rpx; |
|||
font-size: 32rpx; |
|||
font-weight: 600; |
|||
color: #fff; |
|||
margin-top: 100rpx; |
|||
&.active { |
|||
background: rgba(25,137,250,1); |
|||
} |
|||
} |
|||
|
|||
.radioWrap { |
|||
display: flex; |
|||
align-items: center; |
|||
margin-top: 40rpx; |
|||
.privacyText { |
|||
font-size: 24rpx; |
|||
color: #888E94; |
|||
text { |
|||
color: $themC; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
@ -0,0 +1,28 @@ |
|||
{ |
|||
"appid": "wx0820ae1a0b635ae2", |
|||
"compileType": "miniprogram", |
|||
"libVersion": "2.32.2", |
|||
"packOptions": { |
|||
"ignore": [], |
|||
"include": [] |
|||
}, |
|||
"setting": { |
|||
"coverView": true, |
|||
"es6": true, |
|||
"postcss": true, |
|||
"minified": true, |
|||
"enhance": true, |
|||
"showShadowRootInWxmlPanel": true, |
|||
"packNpmRelationList": [], |
|||
"babelSetting": { |
|||
"ignore": [], |
|||
"disablePlugins": [], |
|||
"outputPath": "" |
|||
} |
|||
}, |
|||
"condition": {}, |
|||
"editorSetting": { |
|||
"tabIndent": "insertSpaces", |
|||
"tabSize": 2 |
|||
} |
|||
} |
@ -0,0 +1,7 @@ |
|||
{ |
|||
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html", |
|||
"projectname": "recruitStudent", |
|||
"setting": { |
|||
"compileHotReLoad": true |
|||
} |
|||
} |
@ -0,0 +1,12 @@ |
|||
const VUE_APP_PLATFORM = process.env.VUE_APP_PLATFORM; |
|||
module.exports = { |
|||
APP_API: VUE_APP_PLATFORM === 'h5' ? 'http://121.41.97.244:8090' : '', |
|||
APP_HOST: VUE_APP_PLATFORM === 'h5' ? '' : 'https://www.jaxc.cn/api', |
|||
TEMP_HOST: VUE_APP_PLATFORM === 'h5' ? '' : 'http://121.41.97.244:8090 https://www.jaxc.cn/api', |
|||
ADD_API: VUE_APP_PLATFORM === 'h5' ? '/addApi': 'http://121.41.97.244:48084', //http://121.41.97.244:48084
|
|||
APP_NAME: '', |
|||
VERSION: '1.0.0', |
|||
gaodeMapUrl: 'https://webapi.amap.com/maps?v=1.4.15&key=4545202996c625152b7f2c1aa0ffb8ea&plugin=AMap.DistrictSearch,AMap.CustomLayer,AMap.MarkerClusterer', |
|||
locationIcon: 'http://3dtest.hzhuishi.cn/images/location.png', |
|||
AThreeFace : true, //是否启用人脸识别
|
|||
}; |
After Width: 750 | Height: 492 | Size: 394 KiB |
After Width: 750 | Height: 324 | Size: 5.0 KiB |
After Width: 28 | Height: 28 | Size: 706 B |
After Width: 24 | Height: 26 | Size: 754 B |
After Width: 32 | Height: 32 | Size: 1.1 KiB |
After Width: 32 | Height: 32 | Size: 919 B |
After Width: 40 | Height: 40 | Size: 737 B |
After Width: 40 | Height: 40 | Size: 1.3 KiB |
After Width: 100 | Height: 100 | Size: 10 KiB |
After Width: 56 | Height: 56 | Size: 1.6 KiB |
After Width: 56 | Height: 56 | Size: 1.9 KiB |
After Width: 56 | Height: 56 | Size: 943 B |
After Width: 56 | Height: 56 | Size: 767 B |
After Width: 56 | Height: 56 | Size: 2.7 KiB |
After Width: 56 | Height: 56 | Size: 1.7 KiB |
After Width: 58 | Height: 56 | Size: 1.0 KiB |
After Width: 58 | Height: 56 | Size: 861 B |
After Width: 56 | Height: 56 | Size: 1.0 KiB |
After Width: 56 | Height: 56 | Size: 955 B |
After Width: 58 | Height: 56 | Size: 929 B |
After Width: 58 | Height: 56 | Size: 826 B |
After Width: 56 | Height: 56 | Size: 2.1 KiB |
After Width: 56 | Height: 56 | Size: 1.3 KiB |
After Width: 56 | Height: 56 | Size: 2.2 KiB |
After Width: 56 | Height: 56 | Size: 1.7 KiB |
After Width: 58 | Height: 56 | Size: 587 B |
After Width: 58 | Height: 56 | Size: 547 B |
After Width: 375 | Height: 180 | Size: 36 KiB |
After Width: 329 | Height: 47 | Size: 8.8 KiB |
After Width: 375 | Height: 180 | Size: 36 KiB |
After Width: 16 | Height: 16 | Size: 461 B |
After Width: 16 | Height: 16 | Size: 567 B |
After Width: 329 | Height: 47 | Size: 8.8 KiB |
After Width: 72 | Height: 72 | Size: 3.9 KiB |
@ -0,0 +1,21 @@ |
|||
// export default {
|
|||
// userInfo: state => state.user.userInfo,
|
|||
// pushMessage: state => state.push.pushMessage,
|
|||
// currentAdd: state=>{
|
|||
// };
|
|||
|
|||
export default { |
|||
pushMessage: state => state.push.pushMessage, |
|||
getCurrentAdd: function (state) { |
|||
//返回一个函数用于接收
|
|||
return function (id) { |
|||
let add = state.add.addList.find(item => item.id == id) |
|||
if(add) { |
|||
return add |
|||
}else { |
|||
return {} |
|||
} |
|||
} |
|||
} |
|||
}; |
|||
|
@ -0,0 +1,90 @@ |
|||
import Vue from 'vue'; |
|||
import Vuex from 'vuex'; |
|||
import add from './modules/add'; |
|||
import user from './modules/user'; |
|||
import getters from './getters'; |
|||
|
|||
Vue.use(Vuex); |
|||
|
|||
const store = new Vuex.Store({ |
|||
state: { |
|||
currentSchool: '', |
|||
userInfo: {}, |
|||
latLng: {}, |
|||
|
|||
classChooseItem: {}, |
|||
pdfUrl: '', |
|||
webViewUrl: '', |
|||
havePay: 0, //tabbar 页面是否显示报错小图标
|
|||
currentMyMsg: {}, |
|||
billPrice: 0, //开发票的id
|
|||
TrainingOrderId: '', //退款流程里的驾校id
|
|||
bankInfo: { |
|||
realName: uni.getStorageSync('userInfo').realName, |
|||
phoneCode: '' |
|||
}, |
|||
chooseCoachItem: { |
|||
coachId: '' |
|||
}, //报名时选择的教练
|
|||
realAuthsuccee: false, |
|||
|
|||
}, |
|||
getters, |
|||
mutations: { |
|||
// 选择学校
|
|||
upDateTrainingSchoolId(state, currentSchool) { |
|||
state.currentSchool = currentSchool |
|||
}, |
|||
// webViewUrl
|
|||
updateWebVeiwUrl(state, url) { |
|||
state.webViewUrl = url |
|||
}, |
|||
// 更新用户信息
|
|||
upDateUserInfo(state, userInfo) { |
|||
state.userInfo = userInfo |
|||
}, |
|||
updatePushMyMsg(state, item) { |
|||
state.currentMyMsg = item |
|||
}, |
|||
upDateBillPrice(state, billPrice) { |
|||
state.billPrice = billPrice |
|||
}, |
|||
upDateTrainingOrderId(state, trainingOrderId) { |
|||
state.trainingOrderId = trainingOrderId |
|||
}, |
|||
// tabbar 页面是否显示报错小图标
|
|||
updateHavePay(state, havePay) { |
|||
state.havePay = havePay |
|||
}, |
|||
// 报名时选择教练
|
|||
upDateCoachItem(state, item) { |
|||
state.chooseCoachItem = item |
|||
}, |
|||
// 申请退款时的银行卡信息
|
|||
upDateBankInfo(state, obj) { |
|||
for (let k in obj) { |
|||
if (state.bankInfo[k]) { |
|||
state.bankInfo[k] = obj[k] |
|||
} else { |
|||
uni.$set(state.bankInfo, k, obj[k]) |
|||
} |
|||
} |
|||
}, |
|||
// 更新经纬度
|
|||
updateLatLng(state, item) { |
|||
state.latLng = item |
|||
}, |
|||
|
|||
|
|||
}, |
|||
actions: { |
|||
|
|||
|
|||
}, |
|||
modules: { |
|||
add, |
|||
user, |
|||
}, |
|||
}); |
|||
|
|||
export default store; |
@ -0,0 +1,91 @@ |
|||
|
|||
// import addApi from '@/api/add.js'; // 引入
|
|||
|
|||
const add = { |
|||
state: { |
|||
addList: [] |
|||
}, |
|||
mutations: { |
|||
// 更新广告列表
|
|||
upDateAddList(state, list) { |
|||
state.addList = list |
|||
}, |
|||
|
|||
// 更新当前广告点击量
|
|||
upDateViews(state, id) { |
|||
let add = state.addList.find(item=>item.id==id) |
|||
add.clicks ++ |
|||
}, |
|||
|
|||
|
|||
|
|||
|
|||
}, |
|||
actions: { |
|||
// 点击广告
|
|||
async addClick({commit, dispatch}, curAdd) { |
|||
// await dispatch('updateStatistics')
|
|||
curAdd.clicks ++ |
|||
if(!curAdd.adBannerDO.jumpUrl) { |
|||
return false |
|||
} |
|||
|
|||
commit('updateWebVeiwUrl', curAdd.adBannerDO.jumpUrl) |
|||
uni.navigateTo({ |
|||
url:'/pages/commeWebView/addWebView' |
|||
}) |
|||
}, |
|||
// 获取当前广告
|
|||
getCurrentAdd({state},id) { |
|||
console.log(id) |
|||
console.log(state.addList) |
|||
let curAdd = state.addList.find(item=>item.id==id) |
|||
if(curAdd) { |
|||
curAdd.views ++ |
|||
return curAdd |
|||
}else { |
|||
return {} |
|||
} |
|||
}, |
|||
// // 广告
|
|||
// async addPageFn({commit,state, dispatch}) {
|
|||
// await dispatch('updateStatistics')
|
|||
// let obj = {
|
|||
// pageNo: 1,
|
|||
// pageSize: 30,
|
|||
// adClient: 1
|
|||
// }
|
|||
// const [err, res] = await addApi.addPage(obj)
|
|||
// let list = res.data.records.map(item=>{
|
|||
// item.views = 0
|
|||
// item.clicks = 0
|
|||
// return item
|
|||
// })
|
|||
// commit('upDateAddList', list)
|
|||
// console.log('广告列表')
|
|||
// console.log(list)
|
|||
|
|||
// },
|
|||
// 更新广告点击量
|
|||
async updateStatistics({ dispatch,state, commit }) { |
|||
let statistics = state.addList.filter(item=>item.views) |
|||
console.log('调用更新广告接口') |
|||
if(statistics.length) { |
|||
let stcsList = statistics.map(add=>{ |
|||
let obj = { |
|||
"adPositionId": add.id, |
|||
"adId": add.adId, |
|||
"views": add.views, |
|||
"clicks": add.clicks |
|||
} |
|||
return obj |
|||
}) |
|||
const [err, res] = await addApi.batchUpdate(stcsList) |
|||
console.log('更新广告点击量请求结果') |
|||
console.log(res) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
export default add |
@ -0,0 +1,31 @@ |
|||
|
|||
import addApi from '../../common/sdk/qqmap-wx-jssdk.min.js'; // 引入
|
|||
|
|||
const user = { |
|||
state: { |
|||
addList: [] |
|||
}, |
|||
mutations: { |
|||
// 更新广告列表
|
|||
upDateAddList(state, list) { |
|||
state.addList = list |
|||
}, |
|||
}, |
|||
actions: { |
|||
// 点击广告
|
|||
async addClick({commit, dispatch}, curAdd) { |
|||
// await dispatch('updateStatistics')
|
|||
curAdd.clicks ++ |
|||
if(!curAdd.adBannerDO.jumpUrl) { |
|||
return false |
|||
} |
|||
|
|||
commit('updateWebVeiwUrl', curAdd.adBannerDO.jumpUrl) |
|||
uni.navigateTo({ |
|||
url:'/pages/commeWebView/addWebView' |
|||
}) |
|||
}, |
|||
} |
|||
} |
|||
|
|||
export default user |
@ -0,0 +1,10 @@ |
|||
uni.addInterceptor({ |
|||
returnValue (res) { |
|||
if (!(!!res && (typeof res === "object" || typeof res === "function") && typeof res.then === "function")) { |
|||
return res; |
|||
} |
|||
return new Promise((resolve, reject) => { |
|||
res.then((res) => res[0] ? reject(res[0]) : resolve(res[1])); |
|||
}); |
|||
}, |
|||
}); |
@ -0,0 +1,80 @@ |
|||
/** |
|||
* 这里是uni-app内置的常用样式变量 |
|||
* |
|||
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量 |
|||
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App |
|||
* |
|||
*/ |
|||
|
|||
/** |
|||
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能 |
|||
* |
|||
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件 |
|||
*/ |
|||
|
|||
/* 颜色变量 */ |
|||
@import '@/uni_modules/uview-ui/theme.scss'; |
|||
|
|||
/* 行为相关颜色 */ |
|||
$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:12px; |
|||
$uni-font-size-base:14px; |
|||
$uni-font-size-lg:16; |
|||
|
|||
/* 图片尺寸 */ |
|||
$uni-img-size-sm:20px; |
|||
$uni-img-size-base:26px; |
|||
$uni-img-size-lg:40px; |
|||
|
|||
/* Border Radius */ |
|||
$uni-border-radius-sm: 2px; |
|||
$uni-border-radius-base: 3px; |
|||
$uni-border-radius-lg: 6px; |
|||
$uni-border-radius-circle: 50%; |
|||
|
|||
/* 水平间距 */ |
|||
$uni-spacing-row-sm: 5px; |
|||
$uni-spacing-row-base: 10px; |
|||
$uni-spacing-row-lg: 15px; |
|||
|
|||
/* 垂直间距 */ |
|||
$uni-spacing-col-sm: 4px; |
|||
$uni-spacing-col-base: 8px; |
|||
$uni-spacing-col-lg: 12px; |
|||
|
|||
/* 透明度 */ |
|||
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度 |
|||
|
|||
/* 文章场景相关 */ |
|||
$uni-color-title: #2C405A; // 文章标题颜色 |
|||
$uni-font-size-title:20px; |
|||
$uni-color-subtitle: #555555; // 二级标题颜色 |
|||
$uni-font-size-subtitle:26px; |
|||
$uni-color-paragraph: #3F536E; // 文章段落颜色 |
|||
$uni-font-size-paragraph:15px; |
|||
|
|||
// 自已定义的 |
|||
$themC: #1989FA, |
@ -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) |
|||
- 初始化项目 |
@ -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" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -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: 文件不存在 |
|||
``` |
1
uni_modules/uni-config-center/uniCloud/cloudfunctions/common/uni-config-center/index.js
File diff suppressed because it is too large
View File
@ -0,0 +1,9 @@ |
|||
{ |
|||
"name": "uni-config-center", |
|||
"version": "0.0.3", |
|||
"description": "配置中心", |
|||
"main": "index.js", |
|||
"keywords": [], |
|||
"author": "DCloud", |
|||
"license": "Apache-2.0" |
|||
} |
@ -0,0 +1,25 @@ |
|||
## 1.2.0(2023-04-27) |
|||
- 优化 微信小程序平台 使用微信新增 API getStableAccessToken 获取 access_token, access_token 有效期内重复调用该接口不会更新 access_token, [详情](https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-access-token/getStableAccessToken.html) |
|||
## 1.1.5(2023-03-27) |
|||
- 修复 微信小程序平台 某些情况下 encrypt_key 插入错误的问题 |
|||
## 1.1.4(2023-03-13) |
|||
- 修复 平台 weixin-web |
|||
## 1.1.3(2023-03-13) |
|||
- 新增 支持旧版本 uni-id 配置 |
|||
- 新增 支持平台 weixin-app|qq-mp|qq-app |
|||
## 1.1.2(2023-02-28) |
|||
- 新增 config 配置错误提示语 |
|||
## 1.1.1(2023-02-28) |
|||
- 新增 支持 provider 参数,和 platform 保持一致 |
|||
## 1.1.0(2023-02-27) |
|||
- 重要更新 调整数据库key格式,兼容旧版本API,如果开发者通过手动拼接key查询数据库需要修改现有逻辑 |
|||
+ 原格式: uni-id:[dcloudAppid]:[platform]:[openid]:[access-token|user-access-token|session-key|encrypt-key-version|ticket] |
|||
+ 新格式: uni-id:[provider]:[appid]:[openid]:[access-token|user-access-token|session-key|encrypt-key-version|ticket] |
|||
## 1.0.4(2022-09-21) |
|||
- 新增 支持使用阿里云固定IP获取微信公众号H5凭据 access_token、ticket,开发者需要在微信公众平台配置阿里云固定IP,[固定IP详情](https://uniapp.dcloud.net.cn/uniCloud/cf-functions.html#aliyun-eip) |
|||
## 1.0.3(2022-09-06) |
|||
- 修复 过期时间问题,容错 AccessToken 默认 fallback 逻辑,当微信服务器没有返回过期时间时设置为2小时后过期 |
|||
## 1.0.2(2022-09-02) |
|||
- 新增 依赖数据表schema opendb-open-data |
|||
## 1.0.0(2022-08-22) |
|||
- 首次发布 |
@ -0,0 +1,84 @@ |
|||
{ |
|||
"id": "uni-open-bridge-common", |
|||
"displayName": "uni-open-bridge-common", |
|||
"version": "1.2.0", |
|||
"description": "统一接管微信等三方平台认证凭据", |
|||
"keywords": [ |
|||
"uni-open-bridge-common", |
|||
"access_token", |
|||
"session_key", |
|||
"ticket" |
|||
], |
|||
"repository": "", |
|||
"engines": { |
|||
"HBuilderX": "^3.5.2" |
|||
}, |
|||
"dcloudext": { |
|||
"type": "unicloud-template-function", |
|||
"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" |
|||
}, |
|||
"client": { |
|||
"Vue": { |
|||
"vue2": "u", |
|||
"vue3": "u" |
|||
}, |
|||
"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", |
|||
"飞书": "u", |
|||
"京东": "u" |
|||
}, |
|||
"快应用": { |
|||
"华为": "u", |
|||
"联盟": "u" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,5 @@ |
|||
# uni-open-bridge-common |
|||
|
|||
`uni-open-bridge-common` 是统一接管微信等三方平台认证凭据(包括但不限于`access_token`、`session_key`、`encrypt_key`、`ticket`)的开源库。 |
|||
|
|||
文档链接 [https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge#common](https://uniapp.dcloud.net.cn/uniCloud/uni-open-bridge#common) |
@ -0,0 +1,26 @@ |
|||
'use strict'; |
|||
|
|||
class BridgeError extends Error { |
|||
|
|||
constructor(code, message) { |
|||
super(message) |
|||
|
|||
this._code = code |
|||
} |
|||
|
|||
get code() { |
|||
return this._code |
|||
} |
|||
|
|||
get errCode() { |
|||
return this._code |
|||
} |
|||
|
|||
get errMsg() { |
|||
return this.message |
|||
} |
|||
} |
|||
|
|||
module.exports = { |
|||
BridgeError |
|||
} |
@ -0,0 +1,124 @@ |
|||
'use strict'; |
|||
|
|||
const { |
|||
ProviderType |
|||
} = require('./consts.js') |
|||
|
|||
const configCenter = require('uni-config-center') |
|||
|
|||
// 多维数据为兼容uni-id以前版本配置
|
|||
const OauthConfig = { |
|||
'weixin-app': [ |
|||
['app', 'oauth', 'weixin'], |
|||
['app-plus', 'oauth', 'weixin'] |
|||
], |
|||
'weixin-mp': [ |
|||
['mp-weixin', 'oauth', 'weixin'] |
|||
], |
|||
'weixin-h5': [ |
|||
['web', 'oauth', 'weixin-h5'], |
|||
['h5-weixin', 'oauth', 'weixin'], |
|||
['h5', 'oauth', 'weixin'] |
|||
], |
|||
'weixin-web': [ |
|||
['web', 'oauth', 'weixin-web'] |
|||
], |
|||
'qq-app': [ |
|||
['app', 'oauth', 'qq'], |
|||
['app-plus', 'oauth', 'qq'] |
|||
], |
|||
'qq-mp': [ |
|||
['mp-qq', 'oauth', 'qq'] |
|||
] |
|||
} |
|||
|
|||
const Support_Platforms = [ |
|||
ProviderType.WEIXIN_MP, |
|||
ProviderType.WEIXIN_H5, |
|||
ProviderType.WEIXIN_APP, |
|||
ProviderType.WEIXIN_WEB, |
|||
ProviderType.QQ_MP, |
|||
ProviderType.QQ_APP |
|||
] |
|||
|
|||
class ConfigBase { |
|||
|
|||
constructor() { |
|||
const uniIdConfigCenter = configCenter({ |
|||
pluginId: 'uni-id' |
|||
}) |
|||
|
|||
this._uniIdConfig = uniIdConfigCenter.config() |
|||
} |
|||
|
|||
getAppConfig(appid) { |
|||
if (Array.isArray(this._uniIdConfig)) { |
|||
return this._uniIdConfig.find((item) => { |
|||
return (item.dcloudAppid === appid) |
|||
}) |
|||
} |
|||
return this._uniIdConfig |
|||
} |
|||
} |
|||
|
|||
class AppConfig extends ConfigBase { |
|||
|
|||
constructor() { |
|||
super() |
|||
} |
|||
|
|||
get(appid, platform) { |
|||
if (!this.isSupport(platform)) { |
|||
return null |
|||
} |
|||
|
|||
let appConfig = this.getAppConfig(appid) |
|||
if (!appConfig) { |
|||
return null |
|||
} |
|||
|
|||
return this.getOauthConfig(appConfig, platform) |
|||
} |
|||
|
|||
isSupport(platformName) { |
|||
return (Support_Platforms.indexOf(platformName) >= 0) |
|||
} |
|||
|
|||
getOauthConfig(appConfig, platformName) { |
|||
let treePath = OauthConfig[platformName] |
|||
let node = this.findNode(appConfig, treePath) |
|||
if (node && node.appid && node.appsecret) { |
|||
return { |
|||
appid: node.appid, |
|||
secret: node.appsecret |
|||
} |
|||
} |
|||
return null |
|||
} |
|||
|
|||
findNode(treeNode, arrayPath) { |
|||
let node = treeNode |
|||
for (let treePath of arrayPath) { |
|||
for (let name of treePath) { |
|||
const currentNode = node[name] |
|||
if (currentNode) { |
|||
node = currentNode |
|||
} else { |
|||
node = null |
|||
break |
|||
} |
|||
} |
|||
if (node === null) { |
|||
node = treeNode |
|||
} else { |
|||
break |
|||
} |
|||
} |
|||
return node |
|||
} |
|||
} |
|||
|
|||
|
|||
module.exports = { |
|||
AppConfig |
|||
}; |
@ -0,0 +1,30 @@ |
|||
'use strict'; |
|||
|
|||
const TAG = "UNI_OPEN_BRIDGE" |
|||
|
|||
const HTTP_STATUS = { |
|||
SUCCESS: 200 |
|||
} |
|||
|
|||
const ProviderType = { |
|||
WEIXIN_MP: 'weixin-mp', |
|||
WEIXIN_H5: 'weixin-h5', |
|||
WEIXIN_APP: 'weixin-app', |
|||
WEIXIN_WEB: 'weixin-web', |
|||
QQ_MP: 'qq-mp', |
|||
QQ_APP: 'qq-app' |
|||
} |
|||
|
|||
// old
|
|||
const PlatformType = ProviderType |
|||
|
|||
const ErrorCodeType = { |
|||
SYSTEM_ERROR: TAG + "_SYSTEM_ERROR" |
|||
} |
|||
|
|||
module.exports = { |
|||
HTTP_STATUS, |
|||
ProviderType, |
|||
PlatformType, |
|||
ErrorCodeType |
|||
} |
@ -0,0 +1,317 @@ |
|||
'use strict'; |
|||
|
|||
const { |
|||
PlatformType, |
|||
ProviderType, |
|||
ErrorCodeType |
|||
} = require('./consts.js') |
|||
|
|||
const { |
|||
AppConfig |
|||
} = require('./config.js') |
|||
|
|||
const { |
|||
Storage |
|||
} = require('./storage.js') |
|||
|
|||
const { |
|||
BridgeError |
|||
} = require('./bridge-error.js') |
|||
|
|||
const { |
|||
WeixinServer |
|||
} = require('./weixin-server.js') |
|||
|
|||
const appConfig = new AppConfig() |
|||
|
|||
class AccessToken extends Storage { |
|||
|
|||
constructor() { |
|||
super('access-token', ['provider', 'appid']) |
|||
} |
|||
|
|||
async update(key) { |
|||
super.update(key) |
|||
|
|||
const result = await this.getByWeixinServer(key) |
|||
|
|||
return this.set(key, result.value, result.duration) |
|||
} |
|||
|
|||
async fallback(key) { |
|||
return this.getByWeixinServer(key) |
|||
} |
|||
|
|||
async getByWeixinServer(key) { |
|||
const oauthConfig = appConfig.get(key.dcloudAppid, key.provider) |
|||
let methodName |
|||
if (key.provider === ProviderType.WEIXIN_MP) { |
|||
methodName = 'GetMPAccessTokenData' |
|||
} else if (key.provider === ProviderType.WEIXIN_H5) { |
|||
methodName = 'GetH5AccessTokenData' |
|||
} else { |
|||
throw new BridgeError(ErrorCodeType.SYSTEM_ERROR, "provider invalid") |
|||
} |
|||
|
|||
const responseData = await WeixinServer[methodName](oauthConfig) |
|||
|
|||
const duration = responseData.expires_in || (60 * 60 * 2) |
|||
delete responseData.expires_in |
|||
|
|||
return { |
|||
value: responseData, |
|||
duration |
|||
} |
|||
} |
|||
} |
|||
|
|||
class UserAccessToken extends Storage { |
|||
|
|||
constructor() { |
|||
super('user-access-token', ['provider', 'appid', 'openid']) |
|||
} |
|||
} |
|||
|
|||
class SessionKey extends Storage { |
|||
|
|||
constructor() { |
|||
super('session-key', ['provider', 'appid', 'openid']) |
|||
} |
|||
} |
|||
|
|||
class Encryptkey extends Storage { |
|||
|
|||
constructor() { |
|||
super('encrypt-key', ['provider', 'appid', 'openid']) |
|||
} |
|||
|
|||
async update(key) { |
|||
super.update(key) |
|||
|
|||
const result = await this.getByWeixinServer(key) |
|||
|
|||
return this.set(key, result.value, result.duration) |
|||
} |
|||
|
|||
getKeyString(key) { |
|||
return `${super.getKeyString(key)}-${key.version}` |
|||
} |
|||
|
|||
getExpiresIn(value) { |
|||
if (value <= 0) { |
|||
return 60 |
|||
} |
|||
return value |
|||
} |
|||
|
|||
async fallback(key) { |
|||
return this.getByWeixinServer(key) |
|||
} |
|||
|
|||
async getByWeixinServer(key) { |
|||
const accessToken = await Factory.Get(AccessToken, key) |
|||
const userSession = await Factory.Get(SessionKey, key) |
|||
|
|||
const responseData = await WeixinServer.GetUserEncryptKeyData({ |
|||
openid: key.openid, |
|||
access_token: accessToken.access_token, |
|||
session_key: userSession.session_key |
|||
}) |
|||
|
|||
const keyInfo = responseData.key_info_list.find((item) => { |
|||
return item.version === key.version |
|||
}) |
|||
|
|||
if (!keyInfo) { |
|||
throw new BridgeError(ErrorCodeType.SYSTEM_ERROR, 'key version invalid') |
|||
} |
|||
|
|||
const value = { |
|||
encrypt_key: keyInfo.encrypt_key, |
|||
iv: keyInfo.iv |
|||
} |
|||
|
|||
return { |
|||
value, |
|||
duration: keyInfo.expire_in |
|||
} |
|||
} |
|||
} |
|||
|
|||
class Ticket extends Storage { |
|||
|
|||
constructor() { |
|||
super('ticket', ['provider', 'appid']) |
|||
} |
|||
|
|||
async update(key) { |
|||
super.update(key) |
|||
|
|||
const result = await this.getByWeixinServer(key) |
|||
|
|||
return this.set(key, result.value, result.duration) |
|||
} |
|||
|
|||
async fallback(key) { |
|||
return this.getByWeixinServer(key) |
|||
} |
|||
|
|||
async getByWeixinServer(key) { |
|||
const accessToken = await Factory.Get(AccessToken, { |
|||
dcloudAppid: key.dcloudAppid, |
|||
provider: ProviderType.WEIXIN_H5 |
|||
}) |
|||
|
|||
const responseData = await WeixinServer.GetH5TicketData(accessToken) |
|||
|
|||
const duration = responseData.expires_in || (60 * 60 * 2) |
|||
delete responseData.expires_in |
|||
delete responseData.errcode |
|||
delete responseData.errmsg |
|||
|
|||
return { |
|||
value: responseData, |
|||
duration |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
const Factory = { |
|||
|
|||
async Get(T, key, fallback) { |
|||
Factory.FixOldKey(key) |
|||
return Factory.MakeUnique(T).get(key, fallback) |
|||
}, |
|||
|
|||
async Set(T, key, value, expiresIn) { |
|||
Factory.FixOldKey(key) |
|||
return Factory.MakeUnique(T).set(key, value, expiresIn) |
|||
}, |
|||
|
|||
async Remove(T, key) { |
|||
Factory.FixOldKey(key) |
|||
return Factory.MakeUnique(T).remove(key) |
|||
}, |
|||
|
|||
async Update(T, key) { |
|||
Factory.FixOldKey(key) |
|||
return Factory.MakeUnique(T).update(key) |
|||
}, |
|||
|
|||
FixOldKey(key) { |
|||
if (!key.provider) { |
|||
key.provider = key.platform |
|||
} |
|||
|
|||
const configData = appConfig.get(key.dcloudAppid, key.provider) |
|||
if (!configData) { |
|||
throw new BridgeError(ErrorCodeType.SYSTEM_ERROR, 'appid or provider invalid') |
|||
} |
|||
key.appid = configData.appid |
|||
}, |
|||
|
|||
MakeUnique(T) { |
|||
return new T() |
|||
} |
|||
} |
|||
|
|||
|
|||
// exports
|
|||
|
|||
async function getAccessToken(key, fallback) { |
|||
return Factory.Get(AccessToken, key, fallback) |
|||
} |
|||
|
|||
async function setAccessToken(key, value, expiresIn) { |
|||
return Factory.Set(AccessToken, key, value, expiresIn) |
|||
} |
|||
|
|||
async function removeAccessToken(key) { |
|||
return Factory.Remove(AccessToken, key) |
|||
} |
|||
|
|||
async function updateAccessToken(key) { |
|||
return Factory.Update(AccessToken, key) |
|||
} |
|||
|
|||
async function getUserAccessToken(key, fallback) { |
|||
return Factory.Get(UserAccessToken, key, fallback) |
|||
} |
|||
|
|||
async function setUserAccessToken(key, value, expiresIn) { |
|||
return Factory.Set(UserAccessToken, key, value, expiresIn) |
|||
} |
|||
|
|||
async function removeUserAccessToken(key) { |
|||
return Factory.Remove(UserAccessToken, key) |
|||
} |
|||
|
|||
async function getSessionKey(key, fallback) { |
|||
return Factory.Get(SessionKey, key, fallback) |
|||
} |
|||
|
|||
async function setSessionKey(key, value, expiresIn) { |
|||
return Factory.Set(SessionKey, key, value, expiresIn) |
|||
} |
|||
|
|||
async function removeSessionKey(key) { |
|||
return Factory.Remove(SessionKey, key) |
|||
} |
|||
|
|||
async function getEncryptKey(key, fallback) { |
|||
return Factory.Get(Encryptkey, key, fallback) |
|||
} |
|||
|
|||
async function setEncryptKey(key, value, expiresIn) { |
|||
return Factory.Set(Encryptkey, key, value, expiresIn) |
|||
} |
|||
|
|||
async function removeEncryptKey(key) { |
|||
return Factory.Remove(Encryptkey, key) |
|||
} |
|||
|
|||
async function updateEncryptKey(key) { |
|||
return Factory.Update(Encryptkey, key) |
|||
} |
|||
|
|||
async function getTicket(key, fallback) { |
|||
return Factory.Get(Ticket, key, fallback) |
|||
} |
|||
|
|||
async function setTicket(key, value, expiresIn) { |
|||
return Factory.Set(Ticket, key, value, expiresIn) |
|||
} |
|||
|
|||
async function removeTicket(key) { |
|||
return Factory.Remove(Ticket, key) |
|||
} |
|||
|
|||
async function updateTicket(key) { |
|||
return Factory.Update(Ticket, key) |
|||
} |
|||
|
|||
module.exports = { |
|||
getAccessToken, |
|||
setAccessToken, |
|||
removeAccessToken, |
|||
updateAccessToken, |
|||
getUserAccessToken, |
|||
setUserAccessToken, |
|||
removeUserAccessToken, |
|||
getSessionKey, |
|||
setSessionKey, |
|||
removeSessionKey, |
|||
getEncryptKey, |
|||
setEncryptKey, |
|||
removeEncryptKey, |
|||
updateEncryptKey, |
|||
getTicket, |
|||
setTicket, |
|||
removeTicket, |
|||
updateTicket, |
|||
ProviderType, |
|||
PlatformType, |
|||
WeixinServer, |
|||
ErrorCodeType |
|||
} |
@ -0,0 +1,15 @@ |
|||
{ |
|||
"name": "uni-open-bridge-common", |
|||
"version": "1.0.0", |
|||
"description": "", |
|||
"main": "index.js", |
|||
"scripts": { |
|||
"test": "echo \"Error: no test specified\" && exit 1" |
|||
}, |
|||
"keywords": [], |
|||
"author": "", |
|||
"license": "ISC", |
|||
"dependencies": { |
|||
"uni-config-center": "file:../../../../../uni-config-center/uniCloud/cloudfunctions/common/uni-config-center" |
|||
} |
|||
} |
@ -0,0 +1,111 @@ |
|||
'use strict'; |
|||
|
|||
const { |
|||
Validator |
|||
} = require('./validator.js') |
|||
|
|||
const { |
|||
CacheKeyCascade |
|||
} = require('./uni-cloud-cache.js') |
|||
|
|||
const { |
|||
BridgeError |
|||
} = require('./bridge-error.js') |
|||
|
|||
class Storage { |
|||
|
|||
constructor(type, keys) { |
|||
this._type = type || null |
|||
this._keys = keys || [] |
|||
} |
|||
|
|||
async get(key, fallback) { |
|||
this.validateKey(key) |
|||
const result = await this.create(key, fallback).get() |
|||
return result.value |
|||
} |
|||
|
|||
async set(key, value, expiresIn) { |
|||
this.validateKey(key) |
|||
this.validateValue(value) |
|||
const expires_in = this.getExpiresIn(expiresIn) |
|||
if (expires_in !== 0) { |
|||
await this.create(key).set(this.getValue(value), expires_in) |
|||
} |
|||
} |
|||
|
|||
async remove(key) { |
|||
this.validateKey(key) |
|||
await this.create(key).remove() |
|||
} |
|||
|
|||
// virtual
|
|||
async update(key) { |
|||
this.validateKey(key) |
|||
} |
|||
|
|||
async ttl(key) { |
|||
this.validateKey(key) |
|||
// 后续考虑支持
|
|||
} |
|||
|
|||
async fallback(key) {} |
|||
|
|||
getKeyString(key) { |
|||
const keyArray = [Storage.Prefix] |
|||
this._keys.forEach((name) => { |
|||
keyArray.push(key[name]) |
|||
}) |
|||
keyArray.push(this._type) |
|||
return keyArray.join(':') |
|||
} |
|||
|
|||
getValue(value) { |
|||
return value |
|||
} |
|||
|
|||
getExpiresIn(value) { |
|||
if (value !== undefined) { |
|||
return value |
|||
} |
|||
return -1 |
|||
} |
|||
|
|||
validateKey(key) { |
|||
Validator.Key(this._keys, key) |
|||
} |
|||
|
|||
validateValue(value) { |
|||
Validator.Value(value) |
|||
} |
|||
|
|||
create(key, fallback) { |
|||
const keyString = this.getKeyString(key) |
|||
const options = { |
|||
layers: [{ |
|||
type: 'database', |
|||
key: keyString |
|||
}, { |
|||
type: 'redis', |
|||
key: keyString |
|||
}] |
|||
} |
|||
|
|||
const _this = this |
|||
return new CacheKeyCascade({ |
|||
...options, |
|||
fallback: async function() { |
|||
if (fallback) { |
|||
return fallback(key) |
|||
} else if (_this.fallback) { |
|||
return _this.fallback(key) |
|||
} |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
Storage.Prefix = "uni-id" |
|||
|
|||
module.exports = { |
|||
Storage |
|||
}; |
@ -0,0 +1,324 @@ |
|||
const db = uniCloud.database() |
|||
|
|||
function getType(value) { |
|||
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase() |
|||
} |
|||
|
|||
const validator = { |
|||
key: function(value) { |
|||
const err = new Error('Invalid key') |
|||
if (typeof value !== 'string') { |
|||
throw err |
|||
} |
|||
const valueTrim = value.trim() |
|||
if (!valueTrim || valueTrim !== value) { |
|||
throw err |
|||
} |
|||
}, |
|||
value: function(value) { |
|||
// 仅作简单校验
|
|||
const type = getType(value) |
|||
const validValueType = ['null', 'number', 'string', 'array', 'object'] |
|||
if (validValueType.indexOf(type) === -1) { |
|||
throw new Error('Invalid value type') |
|||
} |
|||
}, |
|||
duration: function(value) { |
|||
const err = new Error('Invalid duration') |
|||
if (value === undefined) { |
|||
return |
|||
} |
|||
if (typeof value !== 'number' || value === 0) { |
|||
throw err |
|||
} |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* 入库时 expired 为过期时间对应的时间戳,永不过期用-1表示 |
|||
* 返回结果时 与redis对齐,-1表示永不过期,-2表示已过期或不存在 |
|||
*/ |
|||
class DatabaseCache { |
|||
constructor({ |
|||
collection = 'opendb-open-data' |
|||
} = {}) { |
|||
this.type = 'db' |
|||
this.collection = db.collection(collection) |
|||
} |
|||
|
|||
_serializeValue(value) { |
|||
return value === undefined ? null : JSON.stringify(value) |
|||
} |
|||
|
|||
_deserializeValue(value) { |
|||
return value ? JSON.parse(value) : value |
|||
} |
|||
|
|||
async set(key, value, duration) { |
|||
validator.key(key) |
|||
validator.value(value) |
|||
validator.duration(duration) |
|||
value = this._serializeValue(value) |
|||
await this.collection.doc(key).set({ |
|||
value, |
|||
expired: duration && duration !== -1 ? Date.now() + (duration * 1000) : -1 |
|||
}) |
|||
} |
|||
|
|||
async _getWithDuration(key) { |
|||
const getKeyRes = await this.collection.doc(key).get() |
|||
const record = getKeyRes.data[0] |
|||
if (!record) { |
|||
return { |
|||
value: null, |
|||
duration: -2 |
|||
} |
|||
} |
|||
const value = this._deserializeValue(record.value) |
|||
const expired = record.expired |
|||
if (expired === -1) { |
|||
return { |
|||
value, |
|||
duration: -1 |
|||
} |
|||
} |
|||
const duration = expired - Date.now() |
|||
if (duration <= 0) { |
|||
await this.remove(key) |
|||
return { |
|||
value: null, |
|||
duration: -2 |
|||
} |
|||
} |
|||
return { |
|||
value, |
|||
duration: Math.floor(duration / 1000) |
|||
} |
|||
} |
|||
|
|||
async get(key, { |
|||
withDuration = true |
|||
} = {}) { |
|||
const result = await this._getWithDuration(key) |
|||
if (!withDuration) { |
|||
delete result.duration |
|||
} |
|||
return result |
|||
} |
|||
|
|||
async remove(key) { |
|||
await this.collection.doc(key).remove() |
|||
} |
|||
} |
|||
|
|||
class RedisCache { |
|||
constructor() { |
|||
this.type = 'redis' |
|||
this.redis = uniCloud.redis() |
|||
} |
|||
|
|||
_serializeValue(value) { |
|||
return value === undefined ? null : JSON.stringify(value) |
|||
} |
|||
|
|||
_deserializeValue(value) { |
|||
return value ? JSON.parse(value) : value |
|||
} |
|||
|
|||
async set(key, value, duration) { |
|||
validator.key(key) |
|||
validator.value(value) |
|||
validator.duration(duration) |
|||
value = this._serializeValue(value) |
|||
if (!duration || duration === -1) { |
|||
await this.redis.set(key, value) |
|||
} else { |
|||
await this.redis.set(key, value, 'EX', duration) |
|||
} |
|||
} |
|||
|
|||
async get(key, { |
|||
withDuration = false |
|||
} = {}) { |
|||
let value = await this.redis.get(key) |
|||
value = this._deserializeValue(value) |
|||
if (!withDuration) { |
|||
return { |
|||
value |
|||
} |
|||
} |
|||
const durationSecond = await this.redis.ttl(key) |
|||
let duration |
|||
switch (durationSecond) { |
|||
case -1: |
|||
duration = -1 |
|||
break |
|||
case -2: |
|||
duration = -2 |
|||
break |
|||
default: |
|||
duration = durationSecond |
|||
break |
|||
} |
|||
return { |
|||
value, |
|||
duration |
|||
} |
|||
} |
|||
|
|||
async remove(key) { |
|||
await this.redis.del(key) |
|||
} |
|||
} |
|||
|
|||
class Cache { |
|||
constructor({ |
|||
type, |
|||
collection |
|||
} = {}) { |
|||
if (type === 'database') { |
|||
return new DatabaseCache({ |
|||
collection |
|||
}) |
|||
} else if (type === 'redis') { |
|||
return new RedisCache() |
|||
} else { |
|||
throw new Error('Invalid cache type') |
|||
} |
|||
} |
|||
} |
|||
|
|||
class CacheKey { |
|||
constructor({ |
|||
type, |
|||
collection, |
|||
cache, |
|||
key, |
|||
fallback |
|||
} = {}) { |
|||
this.cache = cache || new Cache({ |
|||
type, |
|||
collection |
|||
}) |
|||
this.key = key |
|||
this.fallback = fallback |
|||
} |
|||
|
|||
async set(value, duration) { |
|||
await this.cache.set(this.key, value, duration) |
|||
} |
|||
|
|||
async setWithSync(value, duration, syncMethod) { |
|||
await Promise.all([ |
|||
this.set(this.key, value, duration), |
|||
syncMethod(value, duration) |
|||
]) |
|||
} |
|||
|
|||
async get() { |
|||
let { |
|||
value, |
|||
duration |
|||
} = await this.cache.get(this.key) |
|||
if (value !== null && value !== undefined) { |
|||
return { |
|||
value, |
|||
duration |
|||
} |
|||
} |
|||
if (!this.fallback) { |
|||
return { |
|||
value: null, |
|||
duration: -2 |
|||
} |
|||
} |
|||
const fallbackResult = await this.fallback() |
|||
value = fallbackResult.value |
|||
duration = fallbackResult.duration |
|||
if (value !== null && duration !== undefined) { |
|||
await this.cache.set(this.key, value, duration) |
|||
} |
|||
return { |
|||
value, |
|||
duration |
|||
} |
|||
} |
|||
|
|||
async remove() { |
|||
await this.cache.remove(this.key) |
|||
} |
|||
} |
|||
|
|||
class CacheKeyCascade { |
|||
constructor({ |
|||
layers, // [{cache, type, collection, key}] 从低级到高级排序,[DbCacheKey, RedisCacheKey]
|
|||
fallback |
|||
} = {}) { |
|||
this.layers = layers |
|||
this.cacheLayers = [] |
|||
let lastCacheKey |
|||
for (let i = 0; i < layers.length; i++) { |
|||
const { |
|||
type, |
|||
cache, |
|||
collection, |
|||
key |
|||
} = layers[i] |
|||
const lastCacheKeyTemp = lastCacheKey |
|||
try { |
|||
const currentCacheKey = new CacheKey({ |
|||
type, |
|||
collection, |
|||
cache, |
|||
key, |
|||
fallback: i === 0 ? fallback : function() { |
|||
return lastCacheKeyTemp.get() |
|||
} |
|||
}) |
|||
this.cacheLayers.push(currentCacheKey) |
|||
lastCacheKey = currentCacheKey |
|||
} catch (e) {} |
|||
} |
|||
this.highLevelCache = lastCacheKey |
|||
} |
|||
|
|||
async set(value, duration) { |
|||
return Promise.all( |
|||
this.cacheLayers.map(item => { |
|||
return item.set(value, duration) |
|||
}) |
|||
) |
|||
} |
|||
|
|||
async setWithSync(value, duration, syncMethod) { |
|||
const setPromise = this.cacheLayers.map(item => { |
|||
return item.set(value, duration) |
|||
}) |
|||
return Promise.all( |
|||
[ |
|||
...setPromise, |
|||
syncMethod(value, duration) |
|||
] |
|||
) |
|||
} |
|||
|
|||
async get() { |
|||
return this.highLevelCache.get() |
|||
} |
|||
|
|||
async remove() { |
|||
await Promise.all( |
|||
this.cacheLayers.map(cacheKeyItem => { |
|||
return cacheKeyItem.remove() |
|||
}) |
|||
) |
|||
} |
|||
} |
|||
|
|||
module.exports = { |
|||
Cache, |
|||
DatabaseCache, |
|||
RedisCache, |
|||
CacheKey, |
|||
CacheKeyCascade |
|||
} |
@ -0,0 +1,31 @@ |
|||
const Validator = { |
|||
|
|||
Key(keyArray, parameters) { |
|||
for (let i = 0; i < keyArray.length; i++) { |
|||
const keyName = keyArray[i] |
|||
if (typeof parameters[keyName] !== 'string') { |
|||
Validator.ThrowNewError(`Invalid ${keyName}`) |
|||
} |
|||
if (parameters[keyName].length < 1) { |
|||
Validator.ThrowNewError(`Invalid ${keyName}`) |
|||
} |
|||
} |
|||
}, |
|||
|
|||
Value(value) { |
|||
if (value === undefined) { |
|||
Validator.ThrowNewError('Invalid Value') |
|||
} |
|||
if (typeof value !== 'object') { |
|||
Validator.ThrowNewError('Invalid Value Type') |
|||
} |
|||
}, |
|||
|
|||
ThrowNewError(message) { |
|||
throw new Error(message) |
|||
} |
|||
} |
|||
|
|||
module.exports = { |
|||
Validator |
|||
} |
@ -0,0 +1,203 @@ |
|||
'use strict'; |
|||
|
|||
const crypto = require('crypto') |
|||
|
|||
const { |
|||
HTTP_STATUS |
|||
} = require('./consts.js') |
|||
|
|||
const { |
|||
BridgeError |
|||
} = require('./bridge-error.js') |
|||
|
|||
class WeixinServer { |
|||
|
|||
constructor(options = {}) { |
|||
this._appid = options.appid |
|||
this._secret = options.secret |
|||
} |
|||
|
|||
getAccessToken() { |
|||
return uniCloud.httpclient.request(WeixinServer.AccessToken_Url, { |
|||
dataType: 'json', |
|||
method: 'POST', |
|||
contentType: 'json', |
|||
data: { |
|||
appid: this._appid, |
|||
secret: this._secret, |
|||
grant_type: "client_credential" |
|||
} |
|||
}) |
|||
} |
|||
|
|||
// 使用客户端获取的 code 从微信服务器换取 openid,code 仅可使用一次
|
|||
codeToSession(code) { |
|||
return uniCloud.httpclient.request(WeixinServer.Code2Session_Url, { |
|||
dataType: 'json', |
|||
data: { |
|||
appid: this._appid, |
|||
secret: this._secret, |
|||
js_code: code, |
|||
grant_type: 'authorization_code' |
|||
} |
|||
}) |
|||
} |
|||
|
|||
getUserEncryptKey({ |
|||
access_token, |
|||
openid, |
|||
session_key |
|||
}) { |
|||
console.log(access_token, openid, session_key); |
|||
const signature = crypto.createHmac('sha256', session_key).update('').digest('hex') |
|||
return uniCloud.httpclient.request(WeixinServer.User_Encrypt_Key_Url, { |
|||
dataType: 'json', |
|||
method: 'POST', |
|||
dataAsQueryString: true, |
|||
data: { |
|||
access_token, |
|||
openid: openid, |
|||
signature: signature, |
|||
sig_method: 'hmac_sha256' |
|||
} |
|||
}) |
|||
} |
|||
|
|||
getH5AccessToken() { |
|||
return uniCloud.httpclient.request(WeixinServer.AccessToken_H5_Url, { |
|||
dataType: 'json', |
|||
method: 'GET', |
|||
data: { |
|||
appid: this._appid, |
|||
secret: this._secret, |
|||
grant_type: "client_credential" |
|||
} |
|||
}) |
|||
} |
|||
|
|||
getH5Ticket(access_token) { |
|||
return uniCloud.httpclient.request(WeixinServer.Ticket_Url, { |
|||
dataType: 'json', |
|||
dataAsQueryString: true, |
|||
method: 'POST', |
|||
data: { |
|||
access_token |
|||
} |
|||
}) |
|||
} |
|||
|
|||
getH5AccessTokenForEip() { |
|||
return uniCloud.httpProxyForEip.postForm(WeixinServer.AccessToken_H5_Url, { |
|||
appid: this._appid, |
|||
secret: this._secret, |
|||
grant_type: "client_credential" |
|||
}, { |
|||
dataType: 'json' |
|||
}) |
|||
} |
|||
|
|||
getH5TicketForEip(access_token) { |
|||
return uniCloud.httpProxyForEip.postForm(WeixinServer.Ticket_Url, { |
|||
access_token |
|||
}, { |
|||
dataType: 'json', |
|||
dataAsQueryString: true |
|||
}) |
|||
} |
|||
} |
|||
|
|||
WeixinServer.AccessToken_Url = 'https://api.weixin.qq.com/cgi-bin/stable_token' |
|||
WeixinServer.Code2Session_Url = 'https://api.weixin.qq.com/sns/jscode2session' |
|||
WeixinServer.User_Encrypt_Key_Url = 'https://api.weixin.qq.com/wxa/business/getuserencryptkey' |
|||
WeixinServer.AccessToken_H5_Url = 'https://api.weixin.qq.com/cgi-bin/token' |
|||
WeixinServer.Ticket_Url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi' |
|||
|
|||
WeixinServer.GetMPAccessToken = function(options) { |
|||
return new WeixinServer(options).getAccessToken() |
|||
} |
|||
|
|||
WeixinServer.GetCodeToSession = function(options) { |
|||
return new WeixinServer(options).codeToSession(options.code) |
|||
} |
|||
|
|||
WeixinServer.GetUserEncryptKey = function(options) { |
|||
return new WeixinServer(options).getUserEncryptKey(options) |
|||
} |
|||
|
|||
WeixinServer.GetH5AccessToken = function(options) { |
|||
return new WeixinServer(options).getH5AccessToken() |
|||
} |
|||
|
|||
WeixinServer.GetH5Ticket = function(options) { |
|||
return new WeixinServer(options).getH5Ticket(options.access_token) |
|||
} |
|||
|
|||
////////////////////////////////////////////////////////////////
|
|||
|
|||
function isAliyun() { |
|||
return (uniCloud.getCloudInfos()[0].provider === 'aliyun') |
|||
} |
|||
|
|||
WeixinServer.GetResponseData = function(response) { |
|||
console.log("WeixinServer::response", response) |
|||
|
|||
if (!(response.status === HTTP_STATUS.SUCCESS || response.statusCodeValue === HTTP_STATUS.SUCCESS)) { |
|||
throw new BridgeError(response.status || response.statusCodeValue, response.status || response.statusCodeValue) |
|||
} |
|||
|
|||
const responseData = response.data || response.body |
|||
|
|||
if (responseData.errcode !== undefined && responseData.errcode !== 0) { |
|||
throw new BridgeError(responseData.errcode, responseData.errmsg) |
|||
} |
|||
|
|||
return responseData |
|||
} |
|||
|
|||
WeixinServer.GetMPAccessTokenData = async function(options) { |
|||
const response = await new WeixinServer(options).getAccessToken() |
|||
return WeixinServer.GetResponseData(response) |
|||
} |
|||
|
|||
WeixinServer.GetCodeToSessionData = async function(options) { |
|||
const response = await new WeixinServer(options).codeToSession(options.code) |
|||
return WeixinServer.GetResponseData(response) |
|||
} |
|||
|
|||
WeixinServer.GetUserEncryptKeyData = async function(options) { |
|||
const response = await new WeixinServer(options).getUserEncryptKey(options) |
|||
return WeixinServer.GetResponseData(response) |
|||
} |
|||
|
|||
WeixinServer.GetH5AccessTokenData = async function(options) { |
|||
const ws = new WeixinServer(options) |
|||
let response |
|||
if (isAliyun()) { |
|||
response = await ws.getH5AccessTokenForEip() |
|||
if (typeof response === 'string') { |
|||
response = JSON.parse(response) |
|||
} |
|||
} else { |
|||
response = await ws.getH5AccessToken() |
|||
} |
|||
return WeixinServer.GetResponseData(response) |
|||
} |
|||
|
|||
WeixinServer.GetH5TicketData = async function(options) { |
|||
const ws = new WeixinServer(options) |
|||
let response |
|||
if (isAliyun()) { |
|||
response = await ws.getH5TicketForEip(options.access_token) |
|||
if (typeof response === 'string') { |
|||
response = JSON.parse(response) |
|||
} |
|||
} else { |
|||
response = await ws.getH5Ticket(options.access_token) |
|||
} |
|||
return WeixinServer.GetResponseData(response) |
|||
} |
|||
|
|||
|
|||
module.exports = { |
|||
WeixinServer |
|||
} |
@ -0,0 +1,19 @@ |
|||
// 文档教程: https://uniapp.dcloud.net.cn/uniCloud/schema |
|||
{ |
|||
"bsonType": "object", |
|||
"required": ["_id", "value"], |
|||
"properties": { |
|||
"_id": { |
|||
"bsonType": "string", |
|||
"description": "key,格式:uni-id:[provider]:[appid]:[openid]:[access-token|user-access-token|session-key|encrypt-key-version|ticket]" |
|||
}, |
|||
"value": { |
|||
"bsonType": "object", |
|||
"description": "字段_id对应的值" |
|||
}, |
|||
"expired": { |
|||
"bsonType": "date", |
|||
"description": "过期时间" |
|||
} |
|||
} |
|||
} |
@ -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 |