-
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 |