-
7.gitignore
-
20App.vue
-
0README.md
-
65common/css/app.scss
-
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
-
10config/api.js
-
52config/request.js
-
20index.html
-
37main.js
-
100manifest.json
-
15package.json
-
104pages.json
-
60pages/index/index.vue
-
27pages/other/webView/webView.vue
-
404pages/tabbar/index/index.vue
-
30pages/tabbar/learnCar/index.vue
-
31pages/tabbar/mine/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/index_banner.png
-
BINstatic/images/index/dingwei.png
-
BINstatic/images/index/ic_baoming.png
-
BINstatic/images/index/ic_jiaxiao.png
-
BINstatic/images/index/ic_kaochang.png
-
BINstatic/images/index/ic_lilun.png
-
BINstatic/images/index/ic_peilian.png
-
BINstatic/images/index/img_1@2x.png
-
BINstatic/images/index/img_2@2x.png
-
BINstatic/images/index/img_3@2x.png
-
BINstatic/images/index/img_4@2x.png
-
BINstatic/images/index/img_5@2x.png
-
BINstatic/images/index/img_6@2x.png
-
BINstatic/images/index/scan.png
-
BINstatic/images/index/searchIcon.png
-
BINstatic/images/index/我的@2x.png
-
BINstatic/images/index/报名@2x.png
-
BINstatic/images/index/首页@2x.png
-
BINstatic/images/logo.png
-
BINstatic/images/tabbar/btn_shouye_cli.png
-
BINstatic/images/tabbar/btn_shouye_nor.png
-
BINstatic/images/tabbar/btn_wode_cli.png
-
BINstatic/images/tabbar/btn_wode_nor.png
-
BINstatic/images/tabbar/btn_xueche_cli.png
-
BINstatic/images/tabbar/btn_xueche_nor.png
-
BINstatic/images/tabbar/sy.png
-
BINstatic/images/tabbar/syActive.png
-
BINstatic/images/tabbar/tk.png
-
BINstatic/images/tabbar/tkActive.png
-
BINstatic/images/tabbar/wd.png
-
BINstatic/images/tabbar/wdActive.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
-
1uni_modules/uni-scss/index.scss
-
82uni_modules/uni-scss/package.json
-
4uni_modules/uni-scss/readme.md
-
7uni_modules/uni-scss/styles/index.scss
-
3uni_modules/uni-scss/styles/setting/_border.scss
-
66uni_modules/uni-scss/styles/setting/_color.scss
@ -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,65 @@ |
|||
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; |
|||
} |
|||
.pad { |
|||
padding: 0 28rpx; |
|||
} |
|||
.status_bar { |
|||
height: var(--status-bar-height); |
|||
width: 100%; |
|||
} |
|||
image { |
|||
display: block; |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
.placeholderClassFFF { |
|||
color: #fff !important; |
|||
} |
|||
.star { |
|||
display: flex; |
|||
align-items: center; |
|||
.starText { |
|||
font-size: 26rpx; |
|||
color: #F5682D; |
|||
} |
|||
} |
|||
|
|||
.my .u-input { |
|||
height: 100%; |
|||
} |
@ -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,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,37 @@ |
|||
import App from './App' |
|||
import Vue from 'vue' |
|||
import store from './store'; |
|||
|
|||
// import config from "./utils/config.js"
|
|||
// import {storage, goPage} from "./utils/utils.js"
|
|||
// Vue.prototype.$config = config;
|
|||
// 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,104 @@ |
|||
{ |
|||
"pages": [ |
|||
{ |
|||
"path": "pages/tabbar/index/index", |
|||
"style": { |
|||
"navigationBarTitleText": "首页", |
|||
"navigationStyle": "custom", |
|||
"enablePullDownRefresh": true, |
|||
"backgroundTextStyle": "dark" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/tabbar/mine/index", |
|||
"style": { |
|||
"navigationBarTitleText": "", |
|||
"navigationStyle": "custom", |
|||
"enablePullDownRefresh": true, |
|||
"backgroundTextStyle": "dark" |
|||
} |
|||
}, |
|||
{ |
|||
"path": "pages/tabbar/learnCar/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/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/index/index", |
|||
"text": "首页", |
|||
"iconPath": "static/images/tabbar/btn_shouye_nor.png", |
|||
"selectedIconPath": "static/images/tabbar/btn_shouye_cli.png" |
|||
}, |
|||
{ |
|||
"pagePath": "pages/tabbar/learnCar/index", |
|||
"text": "学车", |
|||
"iconPath": "static/images/tabbar/btn_xueche_nor.png", |
|||
"selectedIconPath": "static/images/tabbar/btn_xueche_cli.png" |
|||
}, |
|||
{ |
|||
"pagePath": "pages/tabbar/mine/index", |
|||
"text": "我的", |
|||
"iconPath": "static/images/tabbar/btn_wode_nor.png", |
|||
"selectedIconPath": "static/images/tabbar/btn_wode_cli.png" |
|||
} |
|||
] |
|||
}, |
|||
"easycom": { |
|||
"^u-(.*)": "@/uni_modules/uview-ui/components/u-$1/u-$1.vue" |
|||
} |
|||
} |
@ -0,0 +1,60 @@ |
|||
<template> |
|||
<view class="content"> |
|||
<image class="logo" src="/static/logo.png" @click="goPage"></image> |
|||
<view class="text-area"> |
|||
<text class="title">你好</text> |
|||
</view> |
|||
<UserTab tabNumber="兴趣小组"></UserTab> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
title: 'Hello' |
|||
} |
|||
}, |
|||
onLoad() { |
|||
|
|||
}, |
|||
methods: { |
|||
goPage() { |
|||
// uni.navigateTo({ |
|||
// url: '/pages/index/test' |
|||
// }) |
|||
// plus.runtime.openURL("car://paymoney/carstep:8888://"); |
|||
// plus.runtime.openURL("paymoney://car:8898/carstep"); |
|||
|
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style> |
|||
.content { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.logo { |
|||
height: 200rpx; |
|||
width: 200rpx; |
|||
margin-top: 200rpx; |
|||
margin-left: auto; |
|||
margin-right: auto; |
|||
margin-bottom: 50rpx; |
|||
} |
|||
|
|||
.text-area { |
|||
display: flex; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.title { |
|||
font-size: 36rpx; |
|||
color: #8f8f94; |
|||
} |
|||
</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,404 @@ |
|||
<template> |
|||
<view class="main pageBg"> |
|||
<view style="background-color: #2170FD; width: 100%;height: 20rpx;"></view> |
|||
<view class="TopCon"> |
|||
<view class="status_bar" ></view> |
|||
<!-- 地址、扫一扫 --> |
|||
<view class="flex-b"> |
|||
<view class="flex"> |
|||
<view class="adrsIcon"> |
|||
<image src="@/static/images/index/dingwei.png" mode=""></image> |
|||
</view> |
|||
<view class="adr">南昌市</view> |
|||
</view> |
|||
<view class="scan" @click="scanCodeFn"> |
|||
<image src="@/static/images/index/scan.png" mode=""></image> |
|||
</view> |
|||
</view> |
|||
<!-- 搜索 --> |
|||
<view class="searchCon"> |
|||
<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="搜索驾校、教练…" border="none" clearable v-model="keywords" :color="'#fff'" placeholderClass="placeholderClassFFF"></u--input> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view class="pad"> |
|||
<!-- 精钢区 --> |
|||
<view class="card traTop"> |
|||
<view class="ul"> |
|||
<view class="li" v-for="(item,index) in entrySection" :key="index"> |
|||
<view class="icon"> |
|||
<image :src="item.icon" mode=""></image> |
|||
</view> |
|||
<view class="name">{{ item.text }}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<!-- 行业资讯 --> |
|||
<view class="card"> |
|||
<view class="information"> |
|||
<view class="flex-b border"> |
|||
<view class="h1">行业资讯</view> |
|||
<view class="more"> |
|||
<view class="text">更多</view> |
|||
<view class="icon"> |
|||
<u-icon name="arrow-right"></u-icon> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<uni-swiper-dot class="uni-swiper-dot-box" @clickItem=clickItem :info="swiperInfo" :current="current" :mode="mode" style="height: 230rpx;" |
|||
:dots-styles="dotsStyles" field="content"> |
|||
<swiper class="swiper-box" @change="change" :current="swiperDotIndex" style="height: 230rpx;"> |
|||
<swiper-item v-for="(item, index) in swiperInfo" :key="index"> |
|||
<view class="swiper-item" :class="'swiper-item' + index"> |
|||
<view class="flex-b"> |
|||
<view class="imgBox"> |
|||
<image src="../../../static/images/logo.png" mode=""></image> |
|||
</view> |
|||
<view class="rightText"> |
|||
<view class="text towRowText">{{ item.text }}</view> |
|||
<view class="date">{{ item.date}}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</swiper-item> |
|||
</swiper> |
|||
</uni-swiper-dot> |
|||
</view> |
|||
</view> |
|||
<!-- 服务专区 --> |
|||
<view class="card serviceCon"> |
|||
<view class="h1">服务专区</view> |
|||
<view class="ul2"> |
|||
<view class="li2" v-for="(item,index) in serviceSector" :key="index" :class="'li2Bg' + index"> |
|||
<view class="icon"> |
|||
<image :src="item.icon" mode=""></image> |
|||
</view> |
|||
<view class="textCon"> |
|||
<view class="text">{{ item.text }}</view> |
|||
<view class="tps">{{ item.tps}}</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
</view> |
|||
<view style="height: 20rpx;width: 100%;"></view> |
|||
</view> |
|||
|
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
keywords: '', |
|||
entrySection: [ |
|||
{text: '我要报名', icon: require('../../../static/images/index/ic_baoming.png'), }, |
|||
{text: '找驾校', icon: require('../../../static/images/index/ic_jiaxiao.png'), }, |
|||
{text: '找考场', icon: require('../../../static/images/index/ic_kaochang.png'), }, |
|||
{text: '找陪练', icon: require('../../../static/images/index/ic_peilian.png'), }, |
|||
{text: '理论学习', icon: require('../../../static/images/index/ic_lilun.png'), }, |
|||
], |
|||
serviceSector: [ |
|||
{text: '学车指南', tps:'政府平台 一站服务', icon: require('../../../static/images/index/img_1@2x.png'), url: ''}, |
|||
{text: '公益视频', tps:'立体呈现 学驾无忧', icon: require('../../../static/images/index/img_2@2x.png'), url: ''}, |
|||
{text: '合格率排行', tps:'官方数据 阳光透明', icon: require('../../../static/images/index/img_3@2x.png'), url: ''}, |
|||
{text: '行业政策', tps:'权威发布 精准解读', icon: require('../../../static/images/index/img_4@2x.png'), url: ''}, |
|||
{text: '质量信誉排行', tps:'官方数据 阳光透明', icon: require('../../../static/images/index/img_5@2x.png'), url: ''}, |
|||
{text: '咨询投诉', tps:'畅达沟通 听取民声', icon: require('../../../static/images/index/img_6@2x.png'), url: ''}, |
|||
], |
|||
swiperDotIndex: 1, |
|||
current: 1, |
|||
mode: 'default', |
|||
swiperInfo: [ |
|||
{img: require('../../../static/images/index/ic_lilun.png'),text: '2023年6月份江西省机动车驾驶培训机构考试合格率的通报',date: '2023/08/09' }, |
|||
{img: require('../../../static/images/index/ic_lilun.png'),text: '2023年6月份江西省机动车驾驶培训机构考试合格率的通报',date: '2023/08/10' }, |
|||
{img: require('../../../static/images/index/ic_lilun.png'),text: '2023年6月份江西省机动车驾驶培训机构考试合格率的通报',date: '2023/08/11' }, |
|||
], |
|||
dotsStyles: { |
|||
backgroundColor: '#E8E9EC', |
|||
border: '1px #E8E9EC solid', |
|||
color: '#fff', |
|||
selectedBackgroundColor: '#1989FA', |
|||
selectedBorder: '1px #1989FA solid' |
|||
}, |
|||
} |
|||
}, |
|||
onLoad() { |
|||
|
|||
}, |
|||
onShow() { |
|||
// this.initFn() |
|||
}, |
|||
methods: { |
|||
// 扫码 |
|||
scanCodeFn() { |
|||
let _this = this |
|||
uni.scanCode({ |
|||
success: function (res) { |
|||
console.log('条码类型:' + res.scanType); |
|||
console.log('条码内容:' + res.result); |
|||
_this.$store.commit('updateWebVeiwUrl', res.result) |
|||
uni.navigateTo({ |
|||
url: '/pages/other/webView/webView' |
|||
}) |
|||
} |
|||
}); |
|||
}, |
|||
clickItem(e) { |
|||
this.swiperDotIndex = e |
|||
}, |
|||
change(e) { |
|||
this.current = e.detail.current |
|||
}, |
|||
goPage() { |
|||
uni.navigateTo({ |
|||
url: '/pages/userCenter/login/loginByPhone' |
|||
}) |
|||
}, |
|||
initFn() { |
|||
uni.requestSubscribeMessage({ |
|||
tmplIds: ['0yaIdyI9NlHvGYwb3IIaIQq6uBhulYGN-rGVnJk4hZ4'], |
|||
success (res) { |
|||
console.log('消息是否有权限呢') |
|||
console.log(res) |
|||
} |
|||
}) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
|
|||
<style lang="scss" scoped> |
|||
|
|||
.main { |
|||
width: 100%; |
|||
.TopCon { |
|||
width: 100%; |
|||
height: 476rpx; |
|||
// background: url('../../../static/images/bigImg/index_banner.png') no-repeat; |
|||
background: url('http://192.168.1.20:81/zhili/image/20230809/e7086ccf82ed4aa09d156f2590a50fba.png') no-repeat; |
|||
|
|||
background-size: 100% 100%; |
|||
position: relative; |
|||
|
|||
.flex-b { |
|||
padding: 10rpx 212rpx 0 50rpx; |
|||
.flex { |
|||
.adrsIcon { |
|||
width: 26rpx; |
|||
height: 38rpx; |
|||
margin-top: 4rpx; |
|||
} |
|||
|
|||
.adr { |
|||
padding-left: 14rpx; |
|||
font-size: 28rpx; |
|||
color: #fff; |
|||
} |
|||
} |
|||
|
|||
.scan { |
|||
width: 64rpx; |
|||
height: 64rpx; |
|||
} |
|||
} |
|||
|
|||
.searchCon { |
|||
position: absolute; |
|||
left: 0; |
|||
bottom: 68rpx; |
|||
padding: 0 28rpx; |
|||
width: 100%; |
|||
.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; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
.card { |
|||
background: #FFFFFF; |
|||
border-radius: 16rpx; |
|||
margin-bottom: 20rpx; |
|||
&.traTop { |
|||
// transform: translateY(-40rpx); |
|||
margin-top: -40rpx; |
|||
position: relative; |
|||
z-index: 9; |
|||
} |
|||
.ul { |
|||
height: 236rpx; |
|||
display: flex; |
|||
justify-content: space-between; |
|||
align-items: center; |
|||
padding: 0 20rpx; |
|||
.li { |
|||
flex: 1; |
|||
display: flex; |
|||
align-items: center; |
|||
flex-direction: column; |
|||
.icon { |
|||
width: 92rpx; |
|||
height: 92rpx; |
|||
} |
|||
|
|||
.name { |
|||
font-size: 26rpx; |
|||
color: #333; |
|||
padding-top: 20rpx; |
|||
text-align: center; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.information { |
|||
padding: 0 20rpx; |
|||
height: 320rpx; |
|||
.border { |
|||
height: 86rpx; |
|||
border-bottom: 2px dashed #E8E9EC; |
|||
.h1 { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
} |
|||
.more { |
|||
font-size: 24rpx; |
|||
display: flex; |
|||
.text { |
|||
// margin-right: 8rpx; |
|||
color: #686B73; |
|||
} |
|||
} |
|||
} |
|||
.swiper-item { |
|||
height: 148rpx; |
|||
.flex-b { |
|||
padding: 30rpx 0 28rpx 0; |
|||
.imgBox { |
|||
width: 184rpx; |
|||
height: 148rpx; |
|||
background: linear-gradient(180deg, rgba(0,122,255,0.5) 0%, #007AFF 100%); |
|||
border-radius: 6rpx; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.rightText { |
|||
flex: 1; |
|||
padding: 0 0 0 30rpx; |
|||
height: 148rpx; |
|||
display: flex; |
|||
flex-direction: column; |
|||
justify-content: space-between; |
|||
.text { |
|||
font-size: 24rpx; |
|||
color: #333; |
|||
} |
|||
|
|||
.date { |
|||
text-align: right; |
|||
font-size: 20rpx; |
|||
color: #686B73; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
.serviceCon { |
|||
width: 100%; |
|||
padding-bottom: 20rpx; |
|||
.h1 { |
|||
font-size: 28rpx; |
|||
color: #333; |
|||
padding: 0 0 0 20rpx; |
|||
font-weight: 500; |
|||
line-height: 90rpx; |
|||
} |
|||
|
|||
.ul2 { |
|||
padding: 0 20rpx; |
|||
display: flex; |
|||
flex-wrap: wrap; |
|||
justify-content: space-between; |
|||
.li2 { |
|||
width: 48.8%; |
|||
display: flex; |
|||
align-items: center; |
|||
padding: 14rpx 0 14rpx 14rpx; |
|||
margin-bottom: 20rpx; |
|||
border-radius: 16rpx; |
|||
height: 160rpx; |
|||
&.li2Bg0 { |
|||
background: linear-gradient(180deg, #F7FBFF 0%, #EFF6FF 100%); |
|||
} |
|||
&.li2Bg1 { |
|||
background: linear-gradient(180deg, #FFFAF3 0%, #FFF4EA 100%); |
|||
} |
|||
&.li2Bg2 { |
|||
background: linear-gradient(180deg, #F4FFF5 0%, #F3FFED 100%); |
|||
} |
|||
&.li2Bg3 { |
|||
background: linear-gradient(180deg, #EFFFF9 0%, #E3FFF5 100%); |
|||
} |
|||
&.li2Bg4 { |
|||
background: linear-gradient(180deg, #FAF9FF 0%, #F9F5FF 100%); |
|||
} |
|||
&.li2Bg5 { |
|||
background: linear-gradient(180deg, #FCF9FB 0%, #FFF5F8 100%); |
|||
} |
|||
.icon { |
|||
width: 80rpx; |
|||
height: 80rpx; |
|||
} |
|||
|
|||
.textCon { |
|||
// flex: 1; |
|||
padding-left: 16rpx; |
|||
.text { |
|||
font-size: 32rpx; |
|||
color: #333; |
|||
font-weight: 500; |
|||
} |
|||
|
|||
.tps { |
|||
margin-top: 6rpx; |
|||
font-size: 20rpx; |
|||
color: #949494; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</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,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: 476 | Size: 292 KiB |
After Width: 26 | Height: 38 | Size: 1015 B |
After Width: 92 | Height: 92 | Size: 2.7 KiB |
After Width: 92 | Height: 92 | Size: 2.3 KiB |
After Width: 92 | Height: 92 | Size: 2.8 KiB |
After Width: 92 | Height: 92 | Size: 2.1 KiB |
After Width: 92 | Height: 92 | Size: 2.3 KiB |
After Width: 80 | Height: 80 | Size: 2.4 KiB |
After Width: 80 | Height: 80 | Size: 1.8 KiB |
After Width: 80 | Height: 80 | Size: 2.4 KiB |
After Width: 80 | Height: 80 | Size: 2.6 KiB |
After Width: 80 | Height: 80 | Size: 2.7 KiB |
After Width: 80 | Height: 80 | Size: 2.6 KiB |
After Width: 64 | Height: 64 | Size: 891 B |
After Width: 40 | Height: 40 | Size: 737 B |
After Width: 56 | Height: 56 | Size: 981 B |
After Width: 56 | Height: 56 | Size: 1.3 KiB |
After Width: 56 | Height: 56 | Size: 1.2 KiB |
After Width: 100 | Height: 100 | Size: 10 KiB |
After Width: 56 | Height: 56 | Size: 1.7 KiB |
After Width: 56 | Height: 56 | Size: 2.7 KiB |
After Width: 56 | Height: 56 | Size: 1.3 KiB |
After Width: 56 | Height: 56 | Size: 2.1 KiB |
After Width: 56 | Height: 56 | Size: 1.6 KiB |
After Width: 56 | Height: 56 | Size: 1.9 KiB |
After Width: 58 | Height: 56 | Size: 1.0 KiB |
After Width: 58 | Height: 56 | Size: 861 B |
After Width: 58 | Height: 56 | Size: 929 B |
After Width: 58 | Height: 56 | Size: 826 B |
After Width: 58 | Height: 56 | Size: 1.6 KiB |
After Width: 58 | Height: 56 | Size: 1.3 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 |
@ -0,0 +1 @@ |
|||
@import './styles/index.scss'; |
@ -0,0 +1,82 @@ |
|||
{ |
|||
"id": "uni-scss", |
|||
"displayName": "uni-scss 辅助样式", |
|||
"version": "1.0.3", |
|||
"description": "uni-sass是uni-ui提供的一套全局样式 ,通过一些简单的类名和sass变量,实现简单的页面布局操作,比如颜色、边距、圆角等。", |
|||
"keywords": [ |
|||
"uni-scss", |
|||
"uni-ui", |
|||
"辅助样式" |
|||
], |
|||
"repository": "https://github.com/dcloudio/uni-ui", |
|||
"engines": { |
|||
"HBuilderX": "^3.1.0" |
|||
}, |
|||
"dcloudext": { |
|||
"category": [ |
|||
"JS SDK", |
|||
"通用 SDK" |
|||
], |
|||
"sale": { |
|||
"regular": { |
|||
"price": "0.00" |
|||
}, |
|||
"sourcecode": { |
|||
"price": "0.00" |
|||
} |
|||
}, |
|||
"contact": { |
|||
"qq": "" |
|||
}, |
|||
"declaration": { |
|||
"ads": "无", |
|||
"data": "无", |
|||
"permissions": "无" |
|||
}, |
|||
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui" |
|||
}, |
|||
"uni_modules": { |
|||
"dependencies": [], |
|||
"encrypt": [], |
|||
"platforms": { |
|||
"cloud": { |
|||
"tcb": "y", |
|||
"aliyun": "y" |
|||
}, |
|||
"client": { |
|||
"App": { |
|||
"app-vue": "y", |
|||
"app-nvue": "u" |
|||
}, |
|||
"H5-mobile": { |
|||
"Safari": "y", |
|||
"Android Browser": "y", |
|||
"微信浏览器(Android)": "y", |
|||
"QQ浏览器(Android)": "y" |
|||
}, |
|||
"H5-pc": { |
|||
"Chrome": "y", |
|||
"IE": "y", |
|||
"Edge": "y", |
|||
"Firefox": "y", |
|||
"Safari": "y" |
|||
}, |
|||
"小程序": { |
|||
"微信": "y", |
|||
"阿里": "y", |
|||
"百度": "y", |
|||
"字节跳动": "y", |
|||
"QQ": "y" |
|||
}, |
|||
"快应用": { |
|||
"华为": "n", |
|||
"联盟": "n" |
|||
}, |
|||
"Vue": { |
|||
"vue2": "y", |
|||
"vue3": "y" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,4 @@ |
|||
`uni-sass` 是 `uni-ui`提供的一套全局样式 ,通过一些简单的类名和`sass`变量,实现简单的页面布局操作,比如颜色、边距、圆角等。 |
|||
|
|||
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-sass) |
|||
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839 |
@ -0,0 +1,7 @@ |
|||
@import './setting/_variables.scss'; |
|||
@import './setting/_border.scss'; |
|||
@import './setting/_color.scss'; |
|||
@import './setting/_space.scss'; |
|||
@import './setting/_radius.scss'; |
|||
@import './setting/_text.scss'; |
|||
@import './setting/_styles.scss'; |
@ -0,0 +1,3 @@ |
|||
.uni-border { |
|||
border: 1px $uni-border-1 solid; |
|||
} |
@ -0,0 +1,66 @@ |
|||
|
|||
// TODO 暂时不需要 class ,需要用户使用变量实现 ,如果使用类名其实并不推荐 |
|||
// @mixin get-styles($k,$c) { |
|||
// @if $k == size or $k == weight{ |
|||
// font-#{$k}:#{$c} |
|||
// }@else{ |
|||
// #{$k}:#{$c} |
|||
// } |
|||
// } |
|||
$uni-ui-color:( |
|||
// 主色 |
|||
primary: $uni-primary, |
|||
primary-disable: $uni-primary-disable, |
|||
primary-light: $uni-primary-light, |
|||
// 辅助色 |
|||
success: $uni-success, |
|||
success-disable: $uni-success-disable, |
|||
success-light: $uni-success-light, |
|||
warning: $uni-warning, |
|||
warning-disable: $uni-warning-disable, |
|||
warning-light: $uni-warning-light, |
|||
error: $uni-error, |
|||
error-disable: $uni-error-disable, |
|||
error-light: $uni-error-light, |
|||
info: $uni-info, |
|||
info-disable: $uni-info-disable, |
|||
info-light: $uni-info-light, |
|||
// 中性色 |
|||
main-color: $uni-main-color, |
|||
base-color: $uni-base-color, |
|||
secondary-color: $uni-secondary-color, |
|||
extra-color: $uni-extra-color, |
|||
// 背景色 |
|||
bg-color: $uni-bg-color, |
|||
// 边框颜色 |
|||
border-1: $uni-border-1, |
|||
border-2: $uni-border-2, |
|||
border-3: $uni-border-3, |
|||
border-4: $uni-border-4, |
|||
// 黑色 |
|||
black:$uni-black, |
|||
// 白色 |
|||
white:$uni-white, |
|||
// 透明 |
|||
transparent:$uni-transparent |
|||
) !default; |
|||
@each $key, $child in $uni-ui-color { |
|||
.uni-#{"" + $key} { |
|||
color: $child; |
|||
} |
|||
.uni-#{"" + $key}-bg { |
|||
background-color: $child; |
|||
} |
|||
} |
|||
.uni-shadow-sm { |
|||
box-shadow: $uni-shadow-sm; |
|||
} |
|||
.uni-shadow-base { |
|||
box-shadow: $uni-shadow-base; |
|||
} |
|||
.uni-shadow-lg { |
|||
box-shadow: $uni-shadow-lg; |
|||
} |
|||
.uni-mask { |
|||
background-color:$uni-mask; |
|||
} |