初始化
14
.gitignore
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# Windows
|
||||
[Dd]esktop.ini
|
||||
Thumbs.db
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
|
||||
# Node.js
|
||||
node_modules/
|
||||
231
README.md
Normal file
@@ -0,0 +1,231 @@
|
||||
// var devUrl = "http://192.168.0.166:8080"
|
||||
var devUrl = "https://kyb.sxlyb.com";
|
||||
// var devUrl = "http://192.168.0.194:8080";
|
||||
// var kamo56Url = "http://101.201.181.3:8131";
|
||||
|
||||
const app = getApp()
|
||||
|
||||
|
||||
function getCode(phone) {
|
||||
|
||||
var md4 = "appkeyandroid_ea031a3f-f130-43c4-8c95-6897d8a03697phone" + phone + "role1timestamp" + getTimestamp() +
|
||||
"type3version2.0"
|
||||
|
||||
var md5 = require("../utils/md5.js");
|
||||
var md5 = md5.hex_md5(md4).toUpperCase();
|
||||
return md5;
|
||||
|
||||
}
|
||||
|
||||
function getTimestamp() {
|
||||
var myDate = new Date();
|
||||
var timestamp = formatTime(myDate.getTime(), "YMDHMS");
|
||||
return timestamp;
|
||||
|
||||
}
|
||||
|
||||
function formatTime(value, type) {
|
||||
var dataTime = "";
|
||||
var data = new Date();
|
||||
data.setTime(value);
|
||||
var year = data.getFullYear();
|
||||
var month = addZero(data.getMonth() + 1);
|
||||
var day = addZero(data.getDate());
|
||||
var hour = addZero(data.getHours());
|
||||
var minute = addZero(data.getMinutes());
|
||||
var second = addZero(data.getSeconds());
|
||||
if (type == "YMD") {
|
||||
dataTime = year + "-" + month + "-" + day;
|
||||
} else if (type == "YMDHMS") {
|
||||
dataTime = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
|
||||
} else if (type == "MDHMS") {
|
||||
dataTime = month + "-" + day + " " + hour + ":" + minute + ":" + second;
|
||||
// dataTime =123;
|
||||
} else if (type == "HMS") {
|
||||
dataTime = hour + ":" + minute + ":" + second;
|
||||
} else if (type == "YM") {
|
||||
dataTime = year + "-" + month;
|
||||
|
||||
}
|
||||
return dataTime; //灏嗘牸寮忓寲鍚庣殑瀛楃涓茶緭鍑哄埌鍓嶇鏄剧ず
|
||||
|
||||
};
|
||||
|
||||
function addZero(val) {
|
||||
if (val < 10) {
|
||||
return "0" + val;
|
||||
} else {
|
||||
return val;
|
||||
}
|
||||
};
|
||||
|
||||
function maskFlag(that) {
|
||||
if (that.data.maskFlag == true) {
|
||||
that.setData({
|
||||
maskFlag: false,
|
||||
|
||||
})
|
||||
|
||||
} else {
|
||||
that.setData({
|
||||
maskFlag: true,
|
||||
boxDetail: true,
|
||||
payBox: true,
|
||||
showNotice: true,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function weChat(that) {
|
||||
// 登录
|
||||
wx.login({
|
||||
success: function (res) {
|
||||
if (res.code) {
|
||||
//发起网络请求
|
||||
wx.request({
|
||||
url: devUrl + '/api/v1/cooperation/openId',
|
||||
data: {
|
||||
code: res.code
|
||||
},
|
||||
success: function (res) {
|
||||
if (res.data.code == 0) {
|
||||
wx.setStorageSync('sessionKey', res.data.data.sessionKey);
|
||||
if (res.data.data.state == 1) {
|
||||
wx.setStorageSync('cooperation', res.data.data.cooperation);
|
||||
wx.navigateTo({
|
||||
url: '/pages/oilManage/oilManage',
|
||||
})
|
||||
} else if(res.data.data.state == 0) {
|
||||
wx.setStorageSync('weChatId', res.data.data.weChatId);
|
||||
// wx.navigateTo({
|
||||
// url: '/pages/login-wx/login-wx?weChatId=' + res.data.data.weChatId,
|
||||
// })
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function (res) {
|
||||
console.log(res.data)
|
||||
},
|
||||
fail: function (data) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '网络传输异常',
|
||||
showCancel: false,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
} else {
|
||||
wx.redirectTo({
|
||||
url: '../login/login',
|
||||
})
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
fail: function () {
|
||||
// wx.showModal({
|
||||
// title: '警告通知',
|
||||
// content: '您点击了拒绝授权,将无法正常显示个人信息,点击确定重新获取授权。',
|
||||
// })
|
||||
|
||||
wx.navigateTo({
|
||||
url: '../login/login'
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
function findId(that) {
|
||||
wx.setStorageSync('name', "")
|
||||
wx.setStorageSync('number', "")
|
||||
// var that = this;
|
||||
wx.request({
|
||||
url: devUrl + '/api/v1/supply/detail/info',
|
||||
data: {
|
||||
phone: wx.getStorageSync("phone")
|
||||
},
|
||||
success: function(res) {
|
||||
if (res.data.code == 0) {
|
||||
wx.setStorageSync('id', res.data.data.id)
|
||||
// wx.setStorageSync('payPassword', res.data.object.user.payPassword)
|
||||
wx.setStorageSync('name', res.data.data.name)
|
||||
if (res.data.data.vehicle) {
|
||||
wx.setStorageSync('number', res.data.data.vehicle)
|
||||
}
|
||||
// var state = res.data.object.user.state;
|
||||
// 1 "审核状态:审核中"
|
||||
// 2 "审核状态:审核失败(认证通过,即可发货)"
|
||||
// 3 "审核状态:已认证"
|
||||
// 4 "审核状态:未认证(认证通过,即可发货)
|
||||
// if (state == 1) {
|
||||
// state = "审核中"
|
||||
// } else if (state == 2) {
|
||||
// state = "审核失败"
|
||||
// } else if (state == 3) {
|
||||
// state = "已认证"
|
||||
// } else if (state == 4) {
|
||||
// state = "未认证"
|
||||
// }
|
||||
// wx.setStorageSync('state', state)
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
wx.hideLoading()
|
||||
console.log(res)
|
||||
},
|
||||
fail: function (data) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '网络传输异常',
|
||||
showCancel: false,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function showMsg(msg){
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: msg,
|
||||
showCancel: false,
|
||||
})
|
||||
}
|
||||
function ifNull(str){
|
||||
if(str==null){
|
||||
str=""
|
||||
}
|
||||
return str;
|
||||
|
||||
}
|
||||
function ifNullMoney(str) {
|
||||
if (str == null) {
|
||||
str = ""
|
||||
}else{
|
||||
str = str+"元"
|
||||
}
|
||||
return str;
|
||||
|
||||
}
|
||||
function renderTime(date) {
|
||||
var dateee = new Date(date).toJSON();
|
||||
return new Date(+new Date(dateee) + 8 * 3600 * 1000).toISOString().replace(/T/g, ' ').replace(/\.[\d]{3}Z/, '').replace(/-/g, "/")
|
||||
|
||||
}
|
||||
module.exports = {
|
||||
devUrl: devUrl,
|
||||
formatTime: formatTime,
|
||||
maskFlag: maskFlag,
|
||||
weChat: weChat,
|
||||
findId: findId,
|
||||
showMsg: showMsg,
|
||||
ifNull: ifNull,
|
||||
ifNullMoney: ifNullMoney,
|
||||
renderTime: renderTime
|
||||
}
|
||||
61
app.js
Normal file
@@ -0,0 +1,61 @@
|
||||
// var devUrl = "http://39.106.44.112:8701"; //测试
|
||||
var devUrl = "https://oil-server.sxlyb.com"; // 生产
|
||||
// var devUrl = "http://192.168.10.250:8701"; // 开发
|
||||
var http = require("/utils/http.js");
|
||||
|
||||
//app.js
|
||||
App({
|
||||
onLaunch: function (options) {
|
||||
// 展示本地存储能力
|
||||
var logs = wx.getStorageSync("logs") || [];
|
||||
logs.unshift(Date.now());
|
||||
wx.setStorageSync("logs", logs);
|
||||
|
||||
// 获取小程序更新机制兼容
|
||||
if (wx.canIUse("getUpdateManager")) {
|
||||
const updateManager = wx.getUpdateManager();
|
||||
updateManager.onCheckForUpdate(function (res) {
|
||||
// 请求完新版本信息的回调
|
||||
if (res.hasUpdate) {
|
||||
updateManager.onUpdateReady(function () {
|
||||
updateManager.applyUpdate();
|
||||
});
|
||||
updateManager.onUpdateFailed(function () {
|
||||
// 新的版本下载失败
|
||||
wx.showModal({
|
||||
title: "已经有新版本了哟~",
|
||||
content: "新版本已经上线啦~,请您删除当前小程序,重新搜索打开哟~",
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 如果希望用户在最新版本的客户端上体验您的小程序,可以这样子提示
|
||||
wx.showModal({
|
||||
title: "提示",
|
||||
content:
|
||||
"当前微信版本过低,无法使用该功能,请升级到最新微信版本后重试。",
|
||||
});
|
||||
}
|
||||
|
||||
// 自定义导航
|
||||
if (options.scene == 1007 || options.scene == 1008) {
|
||||
this.globalData.share = true;
|
||||
} else {
|
||||
this.globalData.share = false;
|
||||
}
|
||||
wx.getSystemInfo({
|
||||
success: (res) => {
|
||||
this.globalData.height = res.statusBarHeight;
|
||||
},
|
||||
});
|
||||
|
||||
http.weChat();
|
||||
},
|
||||
globalData: {
|
||||
userInfo: null,
|
||||
devUrl: devUrl,
|
||||
share: false, // 分享默认为false
|
||||
height: 0,
|
||||
},
|
||||
});
|
||||
61
app.json
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"pages": [
|
||||
"pages/login-wx/login-wx",
|
||||
"pages/oilManage/oilManage",
|
||||
"pages/state/state",
|
||||
"pages/login/login",
|
||||
"pages/wodeOil/wodeOil",
|
||||
"pages/agreement/index",
|
||||
"pages/agreement/login-agree",
|
||||
"pages/userManagement/userManagement",
|
||||
"pages/oilHistory/oilHistory",
|
||||
"pages/updateUser/updateUser",
|
||||
"pages/statistics/statistics",
|
||||
"pages/paySuccess/paySuccess",
|
||||
"pages/wallet/detail",
|
||||
"pages/wallet/withdraw",
|
||||
"pages/wallet/withdrawList",
|
||||
"pages/password/password",
|
||||
"pages/limitDetail/limitDetail"
|
||||
],
|
||||
"window": {
|
||||
"backgroundTextStyle": "light",
|
||||
"navigationBarBackgroundColor": "#fff",
|
||||
"navigationBarTitleText": "WeChat",
|
||||
"navigationBarTextStyle": "black",
|
||||
"navigationStyle": "custom"
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#808080",
|
||||
"selectedColor": "#367DF9",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"borderStyle": "black",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/oilManage/oilManage",
|
||||
"text": "记录",
|
||||
"iconPath": "/pages/images/ic_tab_record_off.png",
|
||||
"selectedIconPath": "/pages/images/ic_tab_record_on.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/statistics/statistics",
|
||||
"text": "统计",
|
||||
"iconPath": "/pages/images/statistics.png",
|
||||
"selectedIconPath": "/pages/images/statisticsActive.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/wodeOil/wodeOil",
|
||||
"text": "我的",
|
||||
"iconPath": "/pages/images/ic_tab_mine_off.png",
|
||||
"selectedIconPath": "/pages/images/ic_tab_mine_on.png"
|
||||
}
|
||||
]
|
||||
},
|
||||
"debug": true,
|
||||
"permission": {
|
||||
"scope.userLocation": {
|
||||
"desc": "你的位置信息将用于位置效果展示"
|
||||
}
|
||||
},
|
||||
"sitemapLocation": "sitemap.json"
|
||||
}
|
||||
185
app.wxss
Normal file
@@ -0,0 +1,185 @@
|
||||
/**app.wxss**/
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
color: transparent;
|
||||
}
|
||||
.home-page {
|
||||
height: 160rpx;
|
||||
width: 100%;
|
||||
/* border: 1rpx solid red; */
|
||||
font-size: 60rpx;
|
||||
}
|
||||
|
||||
page {
|
||||
height: 100%;
|
||||
background-color: #fff;
|
||||
}
|
||||
pages {
|
||||
position: relative;
|
||||
z-index: 9999998;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.container {
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0rpx 0;
|
||||
box-sizing: border-box;
|
||||
font-family: 微软雅黑;
|
||||
background: #f9f8f7;
|
||||
}
|
||||
|
||||
.clear:after {
|
||||
display: block;
|
||||
clear: both;
|
||||
content: "";
|
||||
visibility: hidden;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.clear1 {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.lf {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.rt {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: block;
|
||||
margin: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.col {
|
||||
display: flex;
|
||||
font-family: -apple-system-font, "Helvetica Neue", sans-serif;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.col>.col-1, .col-2, .col-3, .col-4, .col-5, .col-6, .col-7, .col-8, .col-9,
|
||||
.col-10, .col-11, .col-12 {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.col-1 {
|
||||
width: 8.33333333333333%;
|
||||
}
|
||||
|
||||
.col-2 {
|
||||
width: 16.6666666666666%;
|
||||
}
|
||||
|
||||
.col-3 {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.col-4 {
|
||||
width: 33.3333333333333%;
|
||||
}
|
||||
|
||||
.col-5 {
|
||||
width: 41.6666666666666%;
|
||||
}
|
||||
|
||||
.col-6 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.col-7 {
|
||||
width: 58.333333333333333%;
|
||||
}
|
||||
|
||||
.col-8 {
|
||||
width: 66.66666666666666%;
|
||||
}
|
||||
|
||||
.col-9 {
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
.col-10 {
|
||||
width: 83.33333333333333%;
|
||||
}
|
||||
|
||||
.col-11 {
|
||||
width: 91.66666666666666%;
|
||||
}
|
||||
|
||||
.col-12 {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.x-center {
|
||||
text-align: center;
|
||||
}
|
||||
.btnBox{
|
||||
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: #f28455;
|
||||
border: none;
|
||||
color: #fff;
|
||||
border-radius: 0px;
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
|
||||
.mask {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
background-color: black;
|
||||
z-index: 19999;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.pas {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 65%;
|
||||
background: #fff;
|
||||
/* padding: 20rpx; */
|
||||
border-radius: 10rpx;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 20000;
|
||||
}
|
||||
|
||||
.cha {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
position: absolute;
|
||||
top: 25rpx;
|
||||
left: 20rpx;
|
||||
}
|
||||
.no-img {
|
||||
width: 120px;
|
||||
height: 140px;
|
||||
margin: 40% auto;
|
||||
display: block;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.no-text {
|
||||
color: gray;
|
||||
font-size: 32rpx;
|
||||
display: block;
|
||||
margin: 5px auto;
|
||||
text-align: center;
|
||||
}
|
||||
336
components/chatroom/chatroom.js
Normal file
@@ -0,0 +1,336 @@
|
||||
const FATAL_REBUILD_TOLERANCE = 10
|
||||
const SETDATA_SCROLL_TO_BOTTOM = {
|
||||
scrollTop: 100000,
|
||||
scrollWithAnimation: true,
|
||||
}
|
||||
|
||||
Component({
|
||||
properties: {
|
||||
envId: String,
|
||||
collection: String,
|
||||
groupId: String,
|
||||
groupName: String,
|
||||
userInfo: Object,
|
||||
onGetUserInfo: {
|
||||
type: Function,
|
||||
},
|
||||
getOpenID: {
|
||||
type: Function,
|
||||
},
|
||||
},
|
||||
|
||||
data: {
|
||||
chats: [],
|
||||
textInputValue: '',
|
||||
openId: '',
|
||||
scrollTop: 0,
|
||||
scrollToMessage: '',
|
||||
hasKeyboard: false,
|
||||
},
|
||||
|
||||
methods: {
|
||||
onGetUserInfo(e) {
|
||||
this.properties.onGetUserInfo(e)
|
||||
},
|
||||
|
||||
getOpenID() {
|
||||
return this.properties.getOpenID()
|
||||
},
|
||||
|
||||
mergeCommonCriteria(criteria) {
|
||||
return {
|
||||
groupId: this.data.groupId,
|
||||
...criteria,
|
||||
}
|
||||
},
|
||||
|
||||
async initRoom() {
|
||||
this.try(async () => {
|
||||
await this.initOpenID()
|
||||
|
||||
const { envId, collection } = this.properties
|
||||
const db = this.db = wx.cloud.database({
|
||||
env: envId,
|
||||
})
|
||||
const _ = db.command
|
||||
|
||||
const { data: initList } = await db.collection(collection).where(this.mergeCommonCriteria()).orderBy('sendTimeTS', 'desc').get()
|
||||
|
||||
console.log('init query chats', initList)
|
||||
|
||||
this.setData({
|
||||
chats: initList.reverse(),
|
||||
scrollTop: 10000,
|
||||
})
|
||||
|
||||
this.initWatch(initList.length ? {
|
||||
sendTimeTS: _.gt(initList[initList.length - 1].sendTimeTS),
|
||||
} : {})
|
||||
}, '初始化失败')
|
||||
},
|
||||
|
||||
async initOpenID() {
|
||||
return this.try(async () => {
|
||||
const openId = await this.getOpenID()
|
||||
|
||||
this.setData({
|
||||
openId,
|
||||
})
|
||||
}, '初始化 openId 失败')
|
||||
},
|
||||
|
||||
async initWatch(criteria) {
|
||||
this.try(() => {
|
||||
const { collection } = this.properties
|
||||
const db = this.db
|
||||
const _ = db.command
|
||||
|
||||
console.warn(`开始监听`, criteria)
|
||||
this.messageListener = db.collection(collection).where(this.mergeCommonCriteria(criteria)).watch({
|
||||
onChange: this.onRealtimeMessageSnapshot.bind(this),
|
||||
onError: e => {
|
||||
if (!this.inited || this.fatalRebuildCount >= FATAL_REBUILD_TOLERANCE) {
|
||||
this.showError(this.inited ? '监听错误,已断开' : '初始化监听失败', e, '重连', () => {
|
||||
this.initWatch(this.data.chats.length ? {
|
||||
sendTimeTS: _.gt(this.data.chats[this.data.chats.length - 1].sendTimeTS),
|
||||
} : {})
|
||||
})
|
||||
} else {
|
||||
this.initWatch(this.data.chats.length ? {
|
||||
sendTimeTS: _.gt(this.data.chats[this.data.chats.length - 1].sendTimeTS),
|
||||
} : {})
|
||||
}
|
||||
},
|
||||
})
|
||||
}, '初始化监听失败')
|
||||
},
|
||||
|
||||
onRealtimeMessageSnapshot(snapshot) {
|
||||
console.warn(`收到消息`, snapshot)
|
||||
|
||||
if (snapshot.type === 'init') {
|
||||
this.setData({
|
||||
chats: [
|
||||
...this.data.chats,
|
||||
...[...snapshot.docs].sort((x, y) => x.sendTimeTS - y.sendTimeTS),
|
||||
],
|
||||
})
|
||||
this.scrollToBottom()
|
||||
this.inited = true
|
||||
} else {
|
||||
let hasNewMessage = false
|
||||
let hasOthersMessage = false
|
||||
const chats = [...this.data.chats]
|
||||
for (const docChange of snapshot.docChanges) {
|
||||
switch (docChange.queueType) {
|
||||
case 'enqueue': {
|
||||
hasOthersMessage = docChange.doc._openid !== this.data.openId
|
||||
const ind = chats.findIndex(chat => chat._id === docChange.doc._id)
|
||||
if (ind > -1) {
|
||||
if (chats[ind].msgType === 'image' && chats[ind].tempFilePath) {
|
||||
chats.splice(ind, 1, {
|
||||
...docChange.doc,
|
||||
tempFilePath: chats[ind].tempFilePath,
|
||||
})
|
||||
} else chats.splice(ind, 1, docChange.doc)
|
||||
} else {
|
||||
hasNewMessage = true
|
||||
chats.push(docChange.doc)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
this.setData({
|
||||
chats: chats.sort((x, y) => x.sendTimeTS - y.sendTimeTS),
|
||||
})
|
||||
if (hasOthersMessage || hasNewMessage) {
|
||||
this.scrollToBottom()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
async onConfirmSendText(e) {
|
||||
this.try(async () => {
|
||||
if (!e.detail.value) {
|
||||
return
|
||||
}
|
||||
|
||||
const { collection } = this.properties
|
||||
const db = this.db
|
||||
const _ = db.command
|
||||
|
||||
const doc = {
|
||||
_id: `${Math.random()}_${Date.now()}`,
|
||||
groupId: this.data.groupId,
|
||||
avatar: this.data.userInfo.avatarUrl,
|
||||
nickName: this.data.userInfo.nickName,
|
||||
msgType: 'text',
|
||||
textContent: e.detail.value,
|
||||
sendTime: new Date(),
|
||||
sendTimeTS: Date.now(), // fallback
|
||||
}
|
||||
|
||||
this.setData({
|
||||
textInputValue: '',
|
||||
chats: [
|
||||
...this.data.chats,
|
||||
{
|
||||
...doc,
|
||||
_openid: this.data.openId,
|
||||
writeStatus: 'pending',
|
||||
},
|
||||
],
|
||||
})
|
||||
this.scrollToBottom(true)
|
||||
|
||||
await db.collection(collection).add({
|
||||
data: doc,
|
||||
})
|
||||
|
||||
this.setData({
|
||||
chats: this.data.chats.map(chat => {
|
||||
if (chat._id === doc._id) {
|
||||
return {
|
||||
...chat,
|
||||
writeStatus: 'written',
|
||||
}
|
||||
} else return chat
|
||||
}),
|
||||
})
|
||||
}, '发送文字失败')
|
||||
},
|
||||
|
||||
async onChooseImage(e) {
|
||||
wx.chooseImage({
|
||||
count: 1,
|
||||
sourceType: ['album', 'camera'],
|
||||
success: async res => {
|
||||
const { envId, collection } = this.properties
|
||||
const doc = {
|
||||
_id: `${Math.random()}_${Date.now()}`,
|
||||
groupId: this.data.groupId,
|
||||
avatar: this.data.userInfo.avatarUrl,
|
||||
nickName: this.data.userInfo.nickName,
|
||||
msgType: 'image',
|
||||
sendTime: new Date(),
|
||||
sendTimeTS: Date.now(), // fallback
|
||||
}
|
||||
|
||||
this.setData({
|
||||
chats: [
|
||||
...this.data.chats,
|
||||
{
|
||||
...doc,
|
||||
_openid: this.data.openId,
|
||||
tempFilePath: res.tempFilePaths[0],
|
||||
writeStatus: 0,
|
||||
},
|
||||
]
|
||||
})
|
||||
this.scrollToBottom(true)
|
||||
|
||||
const uploadTask = wx.cloud.uploadFile({
|
||||
cloudPath: `${this.data.openId}/${Math.random()}_${Date.now()}.${res.tempFilePaths[0].match(/\.(\w+)$/)[1]}`,
|
||||
filePath: res.tempFilePaths[0],
|
||||
config: {
|
||||
env: envId,
|
||||
},
|
||||
success: res => {
|
||||
this.try(async () => {
|
||||
await this.db.collection(collection).add({
|
||||
data: {
|
||||
...doc,
|
||||
imgFileID: res.fileID,
|
||||
},
|
||||
})
|
||||
}, '发送图片失败')
|
||||
},
|
||||
fail: e => {
|
||||
this.showError('发送图片失败', e)
|
||||
},
|
||||
})
|
||||
|
||||
uploadTask.onProgressUpdate(({ progress }) => {
|
||||
this.setData({
|
||||
chats: this.data.chats.map(chat => {
|
||||
if (chat._id === doc._id) {
|
||||
return {
|
||||
...chat,
|
||||
writeStatus: progress,
|
||||
}
|
||||
} else return chat
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
onMessageImageTap(e) {
|
||||
wx.previewImage({
|
||||
urls: [e.target.dataset.fileid],
|
||||
})
|
||||
},
|
||||
|
||||
scrollToBottom(force) {
|
||||
if (force) {
|
||||
console.log('force scroll to bottom')
|
||||
this.setData(SETDATA_SCROLL_TO_BOTTOM)
|
||||
return
|
||||
}
|
||||
|
||||
this.createSelectorQuery().select('.body').boundingClientRect(bodyRect => {
|
||||
this.createSelectorQuery().select(`.body`).scrollOffset(scroll => {
|
||||
if (scroll.scrollTop + bodyRect.height * 3 > scroll.scrollHeight) {
|
||||
console.log('should scroll to bottom')
|
||||
this.setData(SETDATA_SCROLL_TO_BOTTOM)
|
||||
}
|
||||
}).exec()
|
||||
}).exec()
|
||||
},
|
||||
|
||||
async onScrollToUpper() {
|
||||
if (this.db && this.data.chats.length) {
|
||||
const { collection } = this.properties
|
||||
const _ = this.db.command
|
||||
const { data } = await this.db.collection(collection).where(this.mergeCommonCriteria({
|
||||
sendTimeTS: _.lt(this.data.chats[0].sendTimeTS),
|
||||
})).orderBy('sendTimeTS', 'desc').get()
|
||||
this.data.chats.unshift(...data.reverse())
|
||||
this.setData({
|
||||
chats: this.data.chats,
|
||||
scrollToMessage: `item-${data.length}`,
|
||||
scrollWithAnimation: false,
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
async try(fn, title) {
|
||||
try {
|
||||
await fn()
|
||||
} catch (e) {
|
||||
this.showError(title, e)
|
||||
}
|
||||
},
|
||||
|
||||
showError(title, content, confirmText, confirmCallback) {
|
||||
console.error(title, content)
|
||||
wx.showModal({
|
||||
title,
|
||||
content: content.toString(),
|
||||
showCancel: confirmText ? true : false,
|
||||
confirmText,
|
||||
success: res => {
|
||||
res.confirm && confirmCallback()
|
||||
},
|
||||
})
|
||||
},
|
||||
},
|
||||
|
||||
ready() {
|
||||
global.chatroom = this
|
||||
this.initRoom()
|
||||
this.fatalRebuildCount = 0
|
||||
},
|
||||
})
|
||||
4
components/chatroom/chatroom.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
85
components/chatroom/chatroom.wxml
Normal file
@@ -0,0 +1,85 @@
|
||||
<view class="chatroom">
|
||||
<view class="header">
|
||||
<!-- display number of people in the room -->
|
||||
<view class="left"></view>
|
||||
<!-- room name -->
|
||||
<view class="middle">{{groupName}}</view>
|
||||
<!-- reserved -->
|
||||
<view class="right"></view>
|
||||
</view>
|
||||
|
||||
<!-- chats -->
|
||||
<scroll-view
|
||||
class="body"
|
||||
scroll-y
|
||||
scroll-with-animation="{{scrollWithAnimation}}"
|
||||
scroll-top="{{scrollTop}}"
|
||||
scroll-into-view="{{scrollToMessage}}"
|
||||
bindscrolltoupper="onScrollToUpper"
|
||||
>
|
||||
<view
|
||||
wx:for="{{chats}}"
|
||||
wx:key="{{item._id}}"
|
||||
id="item-{{index}}"
|
||||
class="message {{openId == item._openid ? 'message__self' : ''}}"
|
||||
>
|
||||
<image
|
||||
class="avatar"
|
||||
src="{{item.avatar}}"
|
||||
mode="scaleToFill"
|
||||
></image>
|
||||
<view class="main">
|
||||
<view class="nickname">{{item.nickName}}</view>
|
||||
<block wx:if="{{item.msgType === 'image'}}">
|
||||
<view class="image-wrapper">
|
||||
<view class="loading" wx:if="{{item.writeStatus > -1}}">{{item.writeStatus}}%</view>
|
||||
<image
|
||||
src="{{item.tempFilePath || item.imgFileID}}"
|
||||
data-fileid="{{item.tempFilePath || item.imgFileID}}"
|
||||
class="image-content"
|
||||
style="{{item.imgStyle}}"
|
||||
mode="scallToFill"
|
||||
bindtap="onMessageImageTap"></image>
|
||||
</view>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<view class="text-wrapper">
|
||||
<view class="loading" wx:if="{{item.writeStatus === 'pending'}}">···</view>
|
||||
<view class="text-content">{{item.textContent}}</view>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- message sender -->
|
||||
<view class="footer">
|
||||
<view class="message-sender" wx:if="{{userInfo}}">
|
||||
<input
|
||||
class="text-input"
|
||||
type="text"
|
||||
confirm-type="send"
|
||||
bindconfirm="onConfirmSendText"
|
||||
cursor-spacing="20"
|
||||
value="{{textInputValue}}"
|
||||
></input>
|
||||
|
||||
<image
|
||||
src="./photo.png"
|
||||
class="btn-send-image"
|
||||
mode="scaleToFill"
|
||||
bindtap="onChooseImage"
|
||||
></image>
|
||||
</view>
|
||||
|
||||
<view class="message-sender" wx:if="{{!userInfo}}">
|
||||
<button
|
||||
open-type="getUserInfo"
|
||||
bindgetuserinfo="onGetUserInfo"
|
||||
class="userinfo"
|
||||
>请先登录后参与聊天</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
161
components/chatroom/chatroom.wxss
Normal file
@@ -0,0 +1,161 @@
|
||||
.chatroom {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.chatroom .header {
|
||||
flex-basis: fit-content;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding: 20rpx 0 30rpx;
|
||||
font-size: 30rpx;
|
||||
/* background: rgb(34, 187, 47);
|
||||
color: rgba(255, 255, 255, 1) */
|
||||
/* font-family: 'Microsoft YaHei' */
|
||||
}
|
||||
|
||||
.chatroom .header .left {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.chatroom .header .middle {
|
||||
flex: 2;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.chatroom .header .right {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.chatroom .body {
|
||||
flex: 2;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: rgb(237,237,237);
|
||||
padding-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.body .message {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
position: relative;
|
||||
margin: 12rpx 0;
|
||||
}
|
||||
|
||||
.body .message.message__self {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
.body .message .avatar {
|
||||
position: relative;
|
||||
top: 5rpx;
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border-radius: 5rpx;
|
||||
margin: 15rpx;
|
||||
}
|
||||
|
||||
.body .message .main {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.body .message.message__self .main {
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.body .message .nickname {
|
||||
font-size: 24rpx;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.body .message .text-content {
|
||||
border: 1px solid transparent;
|
||||
border-radius: 3px;
|
||||
background-color: #fff;
|
||||
margin: 2px 0 0 0;
|
||||
padding: 4px 10px;
|
||||
font-size: 30rpx;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.body .message.message__self .text-content {
|
||||
background-color: paleturquoise;
|
||||
}
|
||||
|
||||
.body .message .text-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
max-width: 80%;
|
||||
}
|
||||
|
||||
.body .message.message__self .text-wrapper .loading{
|
||||
font-size: 16rpx;
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
|
||||
.body .message .image-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.body .message .image-content {
|
||||
max-width: 240rpx;
|
||||
max-height: 240rpx;
|
||||
}
|
||||
|
||||
.body .message.message__self .image-wrapper .loading {
|
||||
font-size: 20rpx;
|
||||
margin-right: 18rpx;
|
||||
}
|
||||
|
||||
.chatroom .footer {
|
||||
flex-basis: fit-content;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
border-top: 1px solid #ddd;
|
||||
font-size: 10rpx;
|
||||
padding: 20rpx 30rpx;
|
||||
background: rgb(246,246,246);
|
||||
}
|
||||
|
||||
.chatroom .footer .message-sender {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.message-sender .text-input {
|
||||
flex: 1;
|
||||
font-size: 16px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 5px;
|
||||
padding: 3px 6px;
|
||||
margin: 0 10px 0 5px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.message-sender .btn-send-image {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
button {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
button.userinfo {
|
||||
background: darkturquoise;
|
||||
color: aliceblue;
|
||||
padding: 0 100rpx;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 20px;
|
||||
}
|
||||
BIN
components/chatroom/dots.gif
Normal file
|
After Width: | Height: | Size: 244 KiB |
601
components/datetimePicker/datetimePicker.js
Normal file
@@ -0,0 +1,601 @@
|
||||
Component({
|
||||
/**
|
||||
* 组件的属性列表
|
||||
*/
|
||||
properties: {
|
||||
is_show: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
observer:function(val){ //弹出动画
|
||||
// console.log(this.data);
|
||||
if(val){
|
||||
let animation = wx.createAnimation({
|
||||
duration: 500,
|
||||
timingFunction: "ease"
|
||||
});
|
||||
let animationOpacity = wx.createAnimation({
|
||||
duration: 500,
|
||||
timingFunction: "ease"
|
||||
});
|
||||
setTimeout(() => {
|
||||
animation.bottom(0).step();
|
||||
animationOpacity.opacity(0.7).step();
|
||||
this.setData({
|
||||
animationOpacity: animationOpacity.export(),
|
||||
animationData: animation.export()
|
||||
})
|
||||
}, 0);
|
||||
}else{
|
||||
let animation = wx.createAnimation({
|
||||
duration: 100,
|
||||
timingFunction: "ease"
|
||||
});
|
||||
let animationOpacity = wx.createAnimation({
|
||||
duration: 500,
|
||||
timingFunction: "ease"
|
||||
});
|
||||
animation.bottom(-320).step();
|
||||
animationOpacity.opacity(0).step();
|
||||
this.setData({
|
||||
animationOpacity: animationOpacity.export(),
|
||||
animationData: animation.export()
|
||||
});
|
||||
}
|
||||
|
||||
// 在picker滚动未停止前点确定,会使startValue数组各项归零,发生错误,这里判断并重新初始化
|
||||
// 微信新增了picker滚动的回调函数,已进行兼容
|
||||
if(this.data.startValue&&this.data.endValue){
|
||||
let s = 0, e = 0;
|
||||
let conf = this.data.config;
|
||||
|
||||
this.data.startValue.map(val => {
|
||||
if (val == 0) {
|
||||
s++
|
||||
}
|
||||
})
|
||||
this.data.endValue.map(val => {
|
||||
if (val == 0) {
|
||||
e++;
|
||||
}
|
||||
});
|
||||
let tmp={
|
||||
hour:4,
|
||||
minute:5,
|
||||
second:6
|
||||
}
|
||||
let n = tmp[conf.column];
|
||||
if (s>=n || e>=n) {
|
||||
this.initPick();
|
||||
this.setData({
|
||||
startValue: this.data.startValue,
|
||||
endValue: this.data.endValue,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
},
|
||||
config: Object
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的初始数据
|
||||
*/
|
||||
data: {
|
||||
value: [],
|
||||
currentTag:'start'
|
||||
},
|
||||
ready: function () {
|
||||
this.readConfig();
|
||||
this.initPick(this.data.config || null);
|
||||
this.setData({
|
||||
startValue: this.data.startValue,
|
||||
endValue: this.data.endValue,
|
||||
});
|
||||
},
|
||||
/**
|
||||
* 组件的方法列表
|
||||
*/
|
||||
methods: {
|
||||
// 关闭弹框
|
||||
cancel() {
|
||||
this.setData({
|
||||
is_show: false
|
||||
})
|
||||
this.triggerEvent('cancel')
|
||||
},
|
||||
chooseTime(e){
|
||||
console.log(e);
|
||||
const {name}=e.currentTarget.dataset
|
||||
this.setData({
|
||||
currentTag:name
|
||||
})
|
||||
console.log(this.data.currentTag,'currentTag');
|
||||
},
|
||||
onConfirm: function() {
|
||||
//滚动未结束时不能确认
|
||||
if(this.data.isPicking){return}
|
||||
let startTime = new Date(this.data.startPickTime.replace(/-/g, "/"));
|
||||
let endTime = new Date(this.data.endPickTime.replace(/-/g, "/"));
|
||||
console.log(startTime,'startTime');
|
||||
console.log(endTime,'endTime');
|
||||
if (startTime <= endTime || !this.data.endDate) {
|
||||
this.setData({
|
||||
startTime,
|
||||
endTime
|
||||
});
|
||||
let startArr = formatTime(startTime).arr;
|
||||
let endArr = formatTime(endTime).arr;
|
||||
let format0 = function(num){
|
||||
return num<10?'0'+num:num
|
||||
}
|
||||
|
||||
let startTimeBack =
|
||||
startArr[0] +
|
||||
"-" +
|
||||
format0(startArr[1]) +
|
||||
"-" +
|
||||
format0(startArr[2]) +
|
||||
" " +
|
||||
(this.data.hourColumn ? format0(startArr[3]) : "00") +
|
||||
":" +
|
||||
(this.data.minColumn ? format0(startArr[4]) : "00") +
|
||||
":" +
|
||||
(this.data.secColumn ? format0(startArr[5]) : "00");
|
||||
|
||||
let endTimeBack =
|
||||
endArr[0] +
|
||||
"-" +
|
||||
format0(endArr[1]) +
|
||||
"-" +
|
||||
format0(endArr[2]) +
|
||||
" " +
|
||||
(this.data.hourColumn ? format0(endArr[3]) : "00") +
|
||||
":" +
|
||||
(this.data.minColumn ? format0(endArr[4]) : "00") +
|
||||
":" +
|
||||
(this.data.secColumn ? format0(endArr[5]) : "00");
|
||||
const days=this.calculateTimeSpan(startTimeBack,endTimeBack)
|
||||
let time = {
|
||||
startTime: startTimeBack,
|
||||
endTime: endTimeBack
|
||||
};
|
||||
if(days>90){
|
||||
wx.showModal({
|
||||
title: "提示",
|
||||
content: "时间跨度不能超过90天,请重新选择!",
|
||||
showCancel:false
|
||||
});
|
||||
}else{
|
||||
//触发自定义事件
|
||||
this.triggerEvent("setPickerTime", time);
|
||||
this.triggerEvent("hidePicker", {});
|
||||
}
|
||||
} else {
|
||||
wx.showToast({
|
||||
icon: "none",
|
||||
title: "时间不合理"
|
||||
});
|
||||
}
|
||||
},
|
||||
calculateTimeSpan(startDate, endDate) {
|
||||
const startTime = new Date(startDate);
|
||||
const endTime = new Date(endDate);
|
||||
const timeSpanMilliseconds = endTime - startTime;
|
||||
const timeSpanDays = Math.ceil(timeSpanMilliseconds / (1000 * 60 * 60 * 24)) ;
|
||||
return timeSpanDays;
|
||||
},
|
||||
bindChange: function (e) {
|
||||
const val = e.detail.value
|
||||
this.setData({
|
||||
year: this.data.years[val[0]],
|
||||
month: this.data.months[val[1]],
|
||||
day: this.data.days[val[2]]
|
||||
})
|
||||
},
|
||||
//读取配置项
|
||||
readConfig() {
|
||||
let limitEndTime = new Date().getTime();
|
||||
// let limitStartTime = new Date().getTime() - 1000 * 60 * 60 * 24 * 30*3;
|
||||
let limitStartTime = '';
|
||||
if (this.data.config) {
|
||||
let conf = this.data.config;
|
||||
if (typeof conf.dateLimit == "number") {
|
||||
limitStartTime =
|
||||
new Date().getTime() - 1000 * 60 * 60 * 24 * conf.dateLimit;
|
||||
}
|
||||
if (conf.limitStartTime) {
|
||||
limitStartTime = new Date(conf.limitStartTime.replace(/-/g, '/')).getTime();
|
||||
}
|
||||
if (conf.limitEndTime) {
|
||||
limitEndTime = new Date(conf.limitEndTime.replace(/-/g, '/')).getTime();
|
||||
}
|
||||
this.setData({
|
||||
yearStart: conf.yearStart || 2000,
|
||||
yearEnd: conf.yearEnd || 2100,
|
||||
endDate: conf.endDate || false,
|
||||
dateLimit: conf.dateLimit || false,
|
||||
hourColumn:
|
||||
conf.column == "hour" ||
|
||||
conf.column == "minute" ||
|
||||
conf.column == "second",
|
||||
minColumn: conf.column == "minute" || conf.column == "second",
|
||||
// secColumn: conf.column == "second"
|
||||
});
|
||||
}
|
||||
|
||||
let limitStartTimeArr = formatTime(limitStartTime);
|
||||
let limitEndTimeArr = formatTime(limitEndTime);
|
||||
|
||||
this.setData({
|
||||
limitStartTime,
|
||||
limitStartTimeArr,
|
||||
limitEndTime,
|
||||
limitEndTimeArr
|
||||
});
|
||||
},
|
||||
//滚动开始
|
||||
handlePickStart: function (e) {
|
||||
this.setData({
|
||||
isPicking: true
|
||||
})
|
||||
},
|
||||
//滚动结束
|
||||
handlePickEnd: function (e) {
|
||||
this.setData({
|
||||
isPicking: false
|
||||
})
|
||||
},
|
||||
changeStartDateTime: function (e) {
|
||||
let val = e.detail.value;
|
||||
this.compareTime(val, "start");
|
||||
},
|
||||
|
||||
changeEndDateTime: function (e) {
|
||||
let val = e.detail.value;
|
||||
this.compareTime(val, "end");
|
||||
},
|
||||
//比较时间是否在范围内
|
||||
compareTime(val, type) {
|
||||
let h = val[3] ? this.data.HourList[val[3]] : "00";
|
||||
let m = val[4] ? this.data.MinuteList[val[4]] : "00";
|
||||
let s = val[5] ? this.data.SecondList[val[5]] : "00";
|
||||
let time =
|
||||
this.data.YearList[val[0]] +
|
||||
"-" +
|
||||
this.data.MonthList[val[1]] +
|
||||
"-" +
|
||||
this.data.DayList[val[2]] +
|
||||
" " +
|
||||
h +
|
||||
":" +
|
||||
m +
|
||||
":" +
|
||||
s;
|
||||
|
||||
let start = this.data.limitStartTime;
|
||||
let end = this.data.limitEndTime;
|
||||
let timeNum = new Date(time.replace(/-/g, '/')).getTime();
|
||||
let year, month, day, hour, min, sec, limitDate;
|
||||
let tempArr = []
|
||||
|
||||
if (!this.data.dateLimit) {
|
||||
limitDate = [
|
||||
this.data.YearList[val[0]],
|
||||
this.data.MonthList[val[1]],
|
||||
this.data.DayList[val[2]],
|
||||
this.data.HourList[val[3]],
|
||||
this.data.MinuteList[val[4]],
|
||||
this.data.SecondList[val[5]]]
|
||||
} else if (type == "start" && timeNum > new Date(this.data.endPickTime.replace(/-/g, '/')) && this.data.config.endDate) {
|
||||
limitDate = formatTime(this.data.endPickTime).arr;
|
||||
|
||||
} else if (type == "end" && timeNum < new Date(this.data.startPickTime.replace(/-/g, '/'))) {
|
||||
limitDate = formatTime(this.data.startPickTime).arr;
|
||||
|
||||
} else if (timeNum < start) {
|
||||
limitDate = this.data.limitStartTimeArr.arr;
|
||||
|
||||
} else if (timeNum > end) {
|
||||
limitDate = this.data.limitEndTimeArr.arr;
|
||||
|
||||
} else {
|
||||
limitDate = [
|
||||
this.data.YearList[val[0]],
|
||||
this.data.MonthList[val[1]],
|
||||
this.data.DayList[val[2]],
|
||||
this.data.HourList[val[3]],
|
||||
this.data.MinuteList[val[4]],
|
||||
this.data.SecondList[val[5]]
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
year = limitDate[0];
|
||||
month = limitDate[1];
|
||||
day = limitDate[2];
|
||||
hour = limitDate[3];
|
||||
min = limitDate[4];
|
||||
sec = limitDate[5];
|
||||
|
||||
if (type == "start") {
|
||||
this.setStartDate(year, month, day, hour, min, 0);
|
||||
} else if (type == "end") {
|
||||
this.setEndDate(year, month, day, hour, min, 0);
|
||||
}
|
||||
},
|
||||
getDays: function (year, month) {
|
||||
let daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||
if (month === 2) {
|
||||
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0
|
||||
? 29
|
||||
: 28;
|
||||
} else {
|
||||
return daysInMonth[month - 1];
|
||||
}
|
||||
},
|
||||
initPick: function (initData) {
|
||||
const date = initData.initStartTime ? new Date(initData.initStartTime.replace(/-/g, '/')) : new Date();
|
||||
const endDate = initData.initEndTime ? new Date(initData.initEndTime.replace(/-/g, '/')) : new Date();
|
||||
// const startDate = new Date(date.getTime() - 1000 * 60 * 60 * 24);
|
||||
const startDate = date;
|
||||
const startYear = date.getFullYear();
|
||||
const startMonth = date.getMonth() + 1;
|
||||
const startDay = date.getDate();
|
||||
const startHour = date.getHours();
|
||||
const startMinute = date.getMinutes();
|
||||
const startSecond = date.getSeconds();
|
||||
|
||||
const endYear = endDate.getFullYear();
|
||||
const endMonth = endDate.getMonth() + 1;
|
||||
const endDay = endDate.getDate();
|
||||
const endHour = endDate.getHours();
|
||||
const endMinute = endDate.getMinutes();
|
||||
const endSecond = endDate.getSeconds();
|
||||
|
||||
let YearList = [];
|
||||
let MonthList = [];
|
||||
let DayList = [];
|
||||
let HourList = [];
|
||||
let MinuteList = [];
|
||||
let SecondList = [];
|
||||
|
||||
//设置年份列表
|
||||
for (let i = this.data.yearStart; i <= this.data.yearEnd; i++) {
|
||||
YearList.push(i);
|
||||
}
|
||||
|
||||
// 设置月份列表
|
||||
for (let i = 1; i <= 12; i++) {
|
||||
MonthList.push(i);
|
||||
}
|
||||
// 设置日期列表
|
||||
for (let i = 1; i <= 31; i++) {
|
||||
DayList.push(i);
|
||||
}
|
||||
// 设置时列表
|
||||
for (let i = 0; i <= 23; i++) {
|
||||
if (0 <= i && i < 10) {
|
||||
i = "0" + i;
|
||||
}
|
||||
HourList.push(i);
|
||||
}
|
||||
// 分|秒
|
||||
for (let i = 0; i <= 59; i++) {
|
||||
if (0 <= i && i < 10) {
|
||||
i = "0" + i;
|
||||
}
|
||||
MinuteList.push(i);
|
||||
SecondList.push(i);
|
||||
}
|
||||
|
||||
this.setData({
|
||||
YearList,
|
||||
MonthList,
|
||||
DayList,
|
||||
HourList,
|
||||
MinuteList,
|
||||
SecondList
|
||||
});
|
||||
|
||||
this.setStartDate(startYear, startMonth, startDay, startHour, startMinute, 0);
|
||||
this.setEndDate(endYear, endMonth, endDay, endHour, endMinute, 0);
|
||||
|
||||
//!!!
|
||||
// setTimeout(() => {
|
||||
// this.setStartDate(nowYear, nowMonth, nowDay, nowHour, nowMinute)
|
||||
// this.setEndDate(nowYear, nowMonth, nowDay, nowHour, nowMinute)
|
||||
// }, 0);
|
||||
},
|
||||
setPickerDateArr(type, year, month, day, hour, minute, second) {
|
||||
let yearIdx = 0;
|
||||
let monthIdx = 0;
|
||||
let dayIdx = 0;
|
||||
let hourIdx = 0;
|
||||
let minuteIdx = 0;
|
||||
let secondIdx = 0;
|
||||
|
||||
this.data.YearList.map((v, idx) => {
|
||||
if (parseInt(v) === year) {
|
||||
yearIdx = idx;
|
||||
}
|
||||
});
|
||||
|
||||
this.data.MonthList.map((v, idx) => {
|
||||
if (parseInt(v) === month) {
|
||||
monthIdx = idx;
|
||||
}
|
||||
});
|
||||
|
||||
// 重新设置日期列表
|
||||
let DayList = [];
|
||||
for (let i = 1; i <= this.getDays(year, month); i++) {
|
||||
DayList.push(i);
|
||||
}
|
||||
|
||||
DayList.map((v, idx) => {
|
||||
if (parseInt(v) === day) {
|
||||
dayIdx = idx;
|
||||
}
|
||||
});
|
||||
if (type == "start") {
|
||||
this.setData({ startDayList: DayList });
|
||||
} else if (type == "end") {
|
||||
this.setData({ endDayList: DayList });
|
||||
}
|
||||
|
||||
this.data.HourList.map((v, idx) => {
|
||||
if (parseInt(v) === parseInt(hour)) {
|
||||
hourIdx = idx;
|
||||
}
|
||||
});
|
||||
|
||||
this.data.MinuteList.map((v, idx) => {
|
||||
if (parseInt(v) === parseInt(minute)) {
|
||||
minuteIdx = idx;
|
||||
}
|
||||
});
|
||||
this.data.SecondList.map((v, idx) => {
|
||||
if (parseInt(v) === parseInt(second)) {
|
||||
secondIdx = idx;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
yearIdx,
|
||||
monthIdx,
|
||||
dayIdx,
|
||||
hourIdx,
|
||||
minuteIdx,
|
||||
secondIdx
|
||||
};
|
||||
},
|
||||
setStartDate: function (year, month, day, hour, minute, second) {
|
||||
let pickerDateArr = this.setPickerDateArr(
|
||||
"start",
|
||||
year,
|
||||
month,
|
||||
day,
|
||||
hour,
|
||||
minute,
|
||||
second
|
||||
);
|
||||
this.setData({
|
||||
startYearList: this.data.YearList,
|
||||
startMonthList: this.data.MonthList,
|
||||
// startDayList: this.data.DayList,
|
||||
startHourList: this.data.HourList,
|
||||
startMinuteList: this.data.MinuteList,
|
||||
startSecondList: this.data.SecondList,
|
||||
startValue: [
|
||||
pickerDateArr.yearIdx,
|
||||
pickerDateArr.monthIdx,
|
||||
pickerDateArr.dayIdx,
|
||||
pickerDateArr.hourIdx,
|
||||
pickerDateArr.minuteIdx,
|
||||
pickerDateArr.secondIdx
|
||||
],
|
||||
|
||||
startPickTime:
|
||||
this.data.YearList[pickerDateArr.yearIdx] +
|
||||
"-" +
|
||||
this.data.MonthList[pickerDateArr.monthIdx] +
|
||||
"-" +
|
||||
this.data.DayList[pickerDateArr.dayIdx] +
|
||||
" " +
|
||||
this.data.HourList[pickerDateArr.hourIdx] +
|
||||
":" +
|
||||
this.data.MinuteList[pickerDateArr.minuteIdx]
|
||||
// startPickTime:
|
||||
// this.data.YearList[pickerDateArr.yearIdx] +
|
||||
// "-" +
|
||||
// this.data.MonthList[pickerDateArr.monthIdx] +
|
||||
// "-" +
|
||||
// this.data.DayList[pickerDateArr.dayIdx] +
|
||||
// " " +
|
||||
// this.data.HourList[pickerDateArr.hourIdx] +
|
||||
// ":" +
|
||||
// this.data.MinuteList[pickerDateArr.minuteIdx] +
|
||||
// ":" +
|
||||
// this.data.SecondList[pickerDateArr.secondIdx]
|
||||
});
|
||||
},
|
||||
setEndDate: function (year, month, day, hour, minute, second) {
|
||||
let pickerDateArr = this.setPickerDateArr(
|
||||
"end",
|
||||
year,
|
||||
month,
|
||||
day,
|
||||
hour,
|
||||
minute,
|
||||
second
|
||||
);
|
||||
|
||||
this.setData({
|
||||
endYearList: this.data.YearList,
|
||||
endMonthList: this.data.MonthList,
|
||||
// endDayList: this.data.DayList,
|
||||
endHourList: this.data.HourList,
|
||||
endMinuteList: this.data.MinuteList,
|
||||
endSecondList: this.data.SecondList,
|
||||
endValue: [
|
||||
pickerDateArr.yearIdx,
|
||||
pickerDateArr.monthIdx,
|
||||
pickerDateArr.dayIdx,
|
||||
pickerDateArr.hourIdx,
|
||||
pickerDateArr.minuteIdx,
|
||||
pickerDateArr.secondIdx
|
||||
],
|
||||
endPickTime:
|
||||
this.data.YearList[pickerDateArr.yearIdx] +
|
||||
"-" +
|
||||
this.data.MonthList[pickerDateArr.monthIdx] +
|
||||
"-" +
|
||||
this.data.DayList[pickerDateArr.dayIdx] +
|
||||
" " +
|
||||
this.data.HourList[pickerDateArr.hourIdx] +
|
||||
":" +
|
||||
this.data.MinuteList[pickerDateArr.minuteIdx]
|
||||
// endPickTime:
|
||||
// this.data.YearList[pickerDateArr.yearIdx] +
|
||||
// "-" +
|
||||
// this.data.MonthList[pickerDateArr.monthIdx] +
|
||||
// "-" +
|
||||
// this.data.DayList[pickerDateArr.dayIdx] +
|
||||
// " " +
|
||||
// this.data.HourList[pickerDateArr.hourIdx] +
|
||||
// ":" +
|
||||
// this.data.MinuteList[pickerDateArr.minuteIdx] +
|
||||
// ":" +
|
||||
// this.data.SecondList[pickerDateArr.secondIdx]
|
||||
});
|
||||
},
|
||||
}
|
||||
})
|
||||
function formatTime(date) {
|
||||
|
||||
if (typeof date == 'string' || 'number') {
|
||||
try {
|
||||
date = date.replace(/-/g, '/')//兼容ios
|
||||
} catch (error) {
|
||||
}
|
||||
date = new Date(date)
|
||||
}
|
||||
|
||||
const year = date.getFullYear()
|
||||
const month = date.getMonth() + 1
|
||||
const day = date.getDate()
|
||||
const hour = date.getHours()
|
||||
const minute = date.getMinutes()
|
||||
const second = date.getSeconds()
|
||||
|
||||
return {
|
||||
str: [year, month, day].map(formatNumber).join('-') + ' ' + [hour, minute, second].map(formatNumber).join(':'),
|
||||
arr: [year, month, day, hour, minute, second]
|
||||
}
|
||||
}
|
||||
function formatNumber(n) {
|
||||
n = n.toString()
|
||||
return n[1] ? n : '0' + n
|
||||
}
|
||||
4
components/datetimePicker/datetimePicker.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
69
components/datetimePicker/datetimePicker.wxml
Normal file
@@ -0,0 +1,69 @@
|
||||
<view class="mask" hidden="{{!is_show}}" catchtouchmove="true"></view>
|
||||
<view class="modal_info fixed" hidden="{{!is_show}}">
|
||||
<!-- 头部 -->
|
||||
<view class="header">
|
||||
<view class="left">选择时间</view>
|
||||
<view class="right" bind:tap="onConfirm">确定</view>
|
||||
</view>
|
||||
<!-- 日期显示 -->
|
||||
<view class="body">
|
||||
<view class="{{currentTag==='start'?'left':'currentTag'}}" bind:tap="chooseTime" data-name="start">{{startPickTime}}</view>
|
||||
<view class="{{currentTag==='end'?'right':'currentTag'}}"bind:tap="chooseTime"data-name="end">{{endPickTime}}</view>
|
||||
</view>
|
||||
<view class="footer">
|
||||
<view class="timeNav">
|
||||
<view class="item">年</view>
|
||||
<view class="item">月</view>
|
||||
<view class="item">日</view>
|
||||
<view class="item">时</view>
|
||||
<view class="item">分</view>
|
||||
</view>
|
||||
<view wx:if="{{currentTag==='start'}}">
|
||||
<picker-view class='sensorTypePicker'bindchange="changeStartDateTime"
|
||||
indicator-class='indicator'
|
||||
value="{{startValue}}" style="height: {{endDate?'120px':'250px'}};" bindpickstart="handlePickStart" bindpickend="handlePickEnd">
|
||||
<picker-view-column style="min-width: 70px;flex-shrink: 0">
|
||||
<view class="{{[startValue[0]===index?'picker-item-active':'picker-item']}}" wx:for="{{startYearList}}" wx:key='*this'>{{item}}</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view class="{{[startValue[1]===index?'picker-item-active':'picker-item']}}" wx:for="{{startMonthList}}" wx:key='*this'>{{item}}</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view class="{{[startValue[2]===index?'picker-item-active':'picker-item']}}" wx:for="{{startDayList}}" wx:key='*this'>{{item}}</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column hidden="{{!hourColumn}}">
|
||||
<view class="{{[startValue[3]===index?'picker-item-active':'picker-item']}}" wx:for="{{startHourList}}" wx:key='*this'>{{item}}</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column hidden="{{!minColumn}}">
|
||||
<view class="{{[startValue[4]===index?'picker-item-active':'picker-item']}}" wx:for="{{startMinuteList}}" wx:key='*this'>{{item}}</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column hidden="{{!secColumn}}">
|
||||
<view class="{{[startValue[5]===index?'picker-item-active':'picker-item']}}" wx:for="{{startSecondList}}" wx:key='*this'>{{item}}</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
</view>
|
||||
<view wx:else>
|
||||
<picker-view class='sensorTypePicker' indicator-style='height: 35px;' bindchange="changeEndDateTime" bindpickstart="handlePickStart" bindpickend="handlePickEnd"
|
||||
value="{{endValue}}">
|
||||
<picker-view-column style="min-width: 70px;flex-shrink: 0">
|
||||
<view class="{{[endValue[0]===index?'picker-item-active':'picker-item']}}" wx:for="{{endYearList}}" wx:key='*this' style="min-width: 70px;">{{item}}</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view class="{{[endValue[1]===index?'picker-item-active':'picker-item']}}" wx:for="{{endMonthList}}" wx:key='*this'>{{item}}</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column>
|
||||
<view class="{{[endValue[2]===index?'picker-item-active':'picker-item']}}" wx:for="{{endDayList}}" wx:key='*this'>{{item}}</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column hidden="{{!hourColumn}}" >
|
||||
<view class="{{[endValue[3]===index?'picker-item-active':'picker-item']}}" wx:for="{{endHourList}}" wx:key='*this'>{{item}}</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column hidden="{{!minColumn}}">
|
||||
<view class="{{[endValue[4]===index?'picker-item-active':'picker-item']}}" wx:for="{{endMinuteList}}" wx:key='*this'>{{item}}</view>
|
||||
</picker-view-column>
|
||||
<picker-view-column hidden="{{!secColumn}}">
|
||||
<view class="{{[endValue[5]===index?'picker-item-active':'picker-item']}}" wx:for="{{startSecondList}}" wx:key='*this'>{{item}}</view>
|
||||
</picker-view-column>
|
||||
</picker-view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
193
components/datetimePicker/datetimePicker.wxss
Normal file
@@ -0,0 +1,193 @@
|
||||
/* components/datetimePicker/datetimePicker.wxss */
|
||||
/* 遮罩 */
|
||||
.mask {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, .6);
|
||||
-webkit-transition-duration: .3s;
|
||||
transition-duration: .3s;
|
||||
}
|
||||
|
||||
.fixed {
|
||||
z-index: 1003;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
/* top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%); */
|
||||
}
|
||||
|
||||
.modal_info {
|
||||
width: 100%;
|
||||
background: #FFFFFF;
|
||||
border-radius: 20rpx 20rpx 0 0;
|
||||
padding-top: 16rpx;
|
||||
overflow: hidden;
|
||||
font-size: 32rpx;
|
||||
line-height: 49rpx;
|
||||
color: #333333;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 22rpx 30rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.header .left {
|
||||
color: #191b27;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.header .right {
|
||||
display: flex;
|
||||
width: 130rpx;
|
||||
box-sizing: border-box;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background: #367DF9;
|
||||
color: #ffffff;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.body {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
padding: 22rpx 30rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.body .left,
|
||||
.right {
|
||||
display: flex;
|
||||
width: 320rpx;
|
||||
height: 72rpx;
|
||||
padding: 16rpx 0rpx;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
flex-shrink: 0;
|
||||
border-radius: 8rpx;
|
||||
border: 2rpx solid #367DF9;
|
||||
background: #F5F8FE;
|
||||
color: #367df9;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
line-height: normal;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.body .currentTag {
|
||||
display: flex;
|
||||
width: 320rpx;
|
||||
height: 72rpx;
|
||||
padding: 16rpx 0rpx;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
flex-shrink: 0;
|
||||
border-radius: 8rpx;
|
||||
/* border: 2rpx solid #367DF9; */
|
||||
background: #F5F8FE;
|
||||
color: #8fb8ff;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
line-height: normal;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.footer {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.picker {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.picker .item {
|
||||
width: 100%;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8rpx;
|
||||
background: #F5F8FE;
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.sensorTypePicker {
|
||||
width: 100%;
|
||||
height: 120px;
|
||||
/* padding: 45px 0; */
|
||||
}
|
||||
/* 至 */
|
||||
.to{
|
||||
width:100%;
|
||||
display: flex;
|
||||
justify-content: center;align-items: center;
|
||||
color:rgb(138,138,138);
|
||||
border-radius: 8rpx;
|
||||
color: #367df9;
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
background: #F5F8FE;
|
||||
/* font-size:30rpx; */
|
||||
}
|
||||
.picker-item {
|
||||
line-height: 50px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 16px;
|
||||
/* overflow: hidden; */
|
||||
}
|
||||
|
||||
.indicator {
|
||||
border-radius: 8rpx;
|
||||
text-align: center;
|
||||
font-size: 32rpx;
|
||||
font-weight: 700;
|
||||
border: none !important;
|
||||
}
|
||||
.picker-item-active{
|
||||
line-height: 50px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 17px;
|
||||
color: #367df9;
|
||||
font-weight: 700;
|
||||
background: rgba(245, 248, 254, 1);
|
||||
}
|
||||
.timeNav{
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
}
|
||||
.timeNav .item{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
color: #808080;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
284
components/ec-canvas/ec-canvas.js
Normal file
@@ -0,0 +1,284 @@
|
||||
import WxCanvas from './wx-canvas';
|
||||
import * as echarts from './echarts';
|
||||
|
||||
let ctx;
|
||||
|
||||
function compareVersion(v1, v2) {
|
||||
v1 = v1.split('.')
|
||||
v2 = v2.split('.')
|
||||
const len = Math.max(v1.length, v2.length)
|
||||
|
||||
while (v1.length < len) {
|
||||
v1.push('0')
|
||||
}
|
||||
while (v2.length < len) {
|
||||
v2.push('0')
|
||||
}
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
const num1 = parseInt(v1[i])
|
||||
const num2 = parseInt(v2[i])
|
||||
|
||||
if (num1 > num2) {
|
||||
return 1
|
||||
} else if (num1 < num2) {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
Component({
|
||||
properties: {
|
||||
canvasId: {
|
||||
type: String,
|
||||
value: 'ec-canvas'
|
||||
},
|
||||
|
||||
ec: {
|
||||
type: Object
|
||||
},
|
||||
|
||||
forceUseOldCanvas: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
}
|
||||
},
|
||||
|
||||
data: {
|
||||
isUseNewCanvas: false
|
||||
},
|
||||
|
||||
ready: function () {
|
||||
// Disable prograssive because drawImage doesn't support DOM as parameter
|
||||
// See https://developers.weixin.qq.com/miniprogram/dev/api/canvas/CanvasContext.drawImage.html
|
||||
echarts.registerPreprocessor(option => {
|
||||
if (option && option.series) {
|
||||
if (option.series.length > 0) {
|
||||
option.series.forEach(series => {
|
||||
series.progressive = 0;
|
||||
});
|
||||
}
|
||||
else if (typeof option.series === 'object') {
|
||||
option.series.progressive = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.data.ec) {
|
||||
console.warn('组件需绑定 ec 变量,例:<ec-canvas id="mychart-dom-bar" '
|
||||
+ 'canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.data.ec.lazyLoad) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
init: function (callback) {
|
||||
const version = wx.getSystemInfoSync().SDKVersion
|
||||
|
||||
const canUseNewCanvas = compareVersion(version, '2.9.0') >= 0;
|
||||
const forceUseOldCanvas = this.data.forceUseOldCanvas;
|
||||
const isUseNewCanvas = canUseNewCanvas && !forceUseOldCanvas;
|
||||
this.setData({ isUseNewCanvas });
|
||||
|
||||
if (forceUseOldCanvas && canUseNewCanvas) {
|
||||
console.warn('开发者强制使用旧canvas,建议关闭');
|
||||
}
|
||||
|
||||
if (isUseNewCanvas) {
|
||||
// console.log('微信基础库版本大于2.9.0,开始使用<canvas type="2d"/>');
|
||||
// 2.9.0 可以使用 <canvas type="2d"></canvas>
|
||||
this.initByNewWay(callback);
|
||||
} else {
|
||||
const isValid = compareVersion(version, '1.9.91') >= 0
|
||||
if (!isValid) {
|
||||
console.error('微信基础库版本过低,需大于等于 1.9.91。'
|
||||
+ '参见:https://github.com/ecomfe/echarts-for-weixin'
|
||||
+ '#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82');
|
||||
return;
|
||||
} else {
|
||||
console.warn('建议将微信基础库调整大于等于2.9.0版本。升级后绘图将有更好性能');
|
||||
this.initByOldWay(callback);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
initByOldWay(callback) {
|
||||
// 1.9.91 <= version < 2.9.0:原来的方式初始化
|
||||
ctx = wx.createCanvasContext(this.data.canvasId, this);
|
||||
const canvas = new WxCanvas(ctx, this.data.canvasId, false);
|
||||
|
||||
if (echarts.setPlatformAPI) {
|
||||
echarts.setPlatformAPI({
|
||||
createCanvas: () => canvas,
|
||||
});
|
||||
} else {
|
||||
echarts.setCanvasCreator(() => canvas);
|
||||
};
|
||||
// const canvasDpr = wx.getSystemInfoSync().pixelRatio // 微信旧的canvas不能传入dpr
|
||||
const canvasDpr = 1
|
||||
var query = wx.createSelectorQuery().in(this);
|
||||
query.select('.ec-canvas').boundingClientRect(res => {
|
||||
if (typeof callback === 'function') {
|
||||
this.chart = callback(canvas, res.width, res.height, canvasDpr);
|
||||
}
|
||||
else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
|
||||
this.chart = this.data.ec.onInit(canvas, res.width, res.height, canvasDpr);
|
||||
}
|
||||
else {
|
||||
this.triggerEvent('init', {
|
||||
canvas: canvas,
|
||||
width: res.width,
|
||||
height: res.height,
|
||||
canvasDpr: canvasDpr // 增加了dpr,可方便外面echarts.init
|
||||
});
|
||||
}
|
||||
}).exec();
|
||||
},
|
||||
|
||||
initByNewWay(callback) {
|
||||
// version >= 2.9.0:使用新的方式初始化
|
||||
const query = wx.createSelectorQuery().in(this)
|
||||
query
|
||||
.select('.ec-canvas')
|
||||
.fields({ node: true, size: true })
|
||||
.exec(res => {
|
||||
const canvasNode = res[0].node
|
||||
this.canvasNode = canvasNode
|
||||
|
||||
const canvasDpr = wx.getSystemInfoSync().pixelRatio
|
||||
const canvasWidth = res[0].width
|
||||
const canvasHeight = res[0].height
|
||||
|
||||
const ctx = canvasNode.getContext('2d')
|
||||
|
||||
const canvas = new WxCanvas(ctx, this.data.canvasId, true, canvasNode)
|
||||
if (echarts.setPlatformAPI) {
|
||||
echarts.setPlatformAPI({
|
||||
createCanvas: () => canvas,
|
||||
loadImage: (src, onload, onerror) => {
|
||||
if (canvasNode.createImage) {
|
||||
const image = canvasNode.createImage();
|
||||
image.onload = onload;
|
||||
image.onerror = onerror;
|
||||
image.src = src;
|
||||
return image;
|
||||
}
|
||||
console.error('加载图片依赖 `Canvas.createImage()` API,要求小程序基础库版本在 2.7.0 及以上。');
|
||||
// PENDING fallback?
|
||||
}
|
||||
})
|
||||
} else {
|
||||
echarts.setCanvasCreator(() => canvas)
|
||||
}
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
this.chart = callback(canvas, canvasWidth, canvasHeight, canvasDpr)
|
||||
} else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
|
||||
this.chart = this.data.ec.onInit(canvas, canvasWidth, canvasHeight, canvasDpr)
|
||||
} else {
|
||||
this.triggerEvent('init', {
|
||||
canvas: canvas,
|
||||
width: canvasWidth,
|
||||
height: canvasHeight,
|
||||
dpr: canvasDpr
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
canvasToTempFilePath(opt) {
|
||||
if (this.data.isUseNewCanvas) {
|
||||
// 新版
|
||||
const query = wx.createSelectorQuery().in(this)
|
||||
query
|
||||
.select('.ec-canvas')
|
||||
.fields({ node: true, size: true })
|
||||
.exec(res => {
|
||||
const canvasNode = res[0].node
|
||||
opt.canvas = canvasNode
|
||||
wx.canvasToTempFilePath(opt)
|
||||
})
|
||||
} else {
|
||||
// 旧的
|
||||
if (!opt.canvasId) {
|
||||
opt.canvasId = this.data.canvasId;
|
||||
}
|
||||
ctx.draw(true, () => {
|
||||
wx.canvasToTempFilePath(opt, this);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
touchStart(e) {
|
||||
if (this.chart && e.touches.length > 0) {
|
||||
var touch = e.touches[0];
|
||||
var handler = this.chart.getZr().handler;
|
||||
handler.dispatch('mousedown', {
|
||||
zrX: touch.x,
|
||||
zrY: touch.y,
|
||||
preventDefault: () => {},
|
||||
stopImmediatePropagation: () => {},
|
||||
stopPropagation: () => {}
|
||||
});
|
||||
handler.dispatch('mousemove', {
|
||||
zrX: touch.x,
|
||||
zrY: touch.y,
|
||||
preventDefault: () => {},
|
||||
stopImmediatePropagation: () => {},
|
||||
stopPropagation: () => {}
|
||||
});
|
||||
handler.processGesture(wrapTouch(e), 'start');
|
||||
}
|
||||
},
|
||||
|
||||
touchMove(e) {
|
||||
if (this.chart && e.touches.length > 0) {
|
||||
var touch = e.touches[0];
|
||||
var handler = this.chart.getZr().handler;
|
||||
handler.dispatch('mousemove', {
|
||||
zrX: touch.x,
|
||||
zrY: touch.y,
|
||||
preventDefault: () => {},
|
||||
stopImmediatePropagation: () => {},
|
||||
stopPropagation: () => {}
|
||||
});
|
||||
handler.processGesture(wrapTouch(e), 'change');
|
||||
}
|
||||
},
|
||||
|
||||
touchEnd(e) {
|
||||
if (this.chart) {
|
||||
const touch = e.changedTouches ? e.changedTouches[0] : {};
|
||||
var handler = this.chart.getZr().handler;
|
||||
handler.dispatch('mouseup', {
|
||||
zrX: touch.x,
|
||||
zrY: touch.y,
|
||||
preventDefault: () => {},
|
||||
stopImmediatePropagation: () => {},
|
||||
stopPropagation: () => {}
|
||||
});
|
||||
handler.dispatch('click', {
|
||||
zrX: touch.x,
|
||||
zrY: touch.y,
|
||||
preventDefault: () => {},
|
||||
stopImmediatePropagation: () => {},
|
||||
stopPropagation: () => {}
|
||||
});
|
||||
handler.processGesture(wrapTouch(e), 'end');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function wrapTouch(event) {
|
||||
for (let i = 0; i < event.touches.length; ++i) {
|
||||
const touch = event.touches[i];
|
||||
touch.offsetX = touch.x;
|
||||
touch.offsetY = touch.y;
|
||||
}
|
||||
return event;
|
||||
}
|
||||
4
components/ec-canvas/ec-canvas.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
4
components/ec-canvas/ec-canvas.wxml
Normal file
@@ -0,0 +1,4 @@
|
||||
<!-- 新的:接口对其了H5 -->
|
||||
<canvas wx:if="{{isUseNewCanvas}}" type="2d" class="ec-canvas" canvas-id="{{ canvasId }}" bindinit="init" bindtouchstart="{{ ec.disableTouch ? '' : 'touchStart' }}" bindtouchmove="{{ ec.disableTouch ? '' : 'touchMove' }}" bindtouchend="{{ ec.disableTouch ? '' : 'touchEnd' }}"></canvas>
|
||||
<!-- 旧的 -->
|
||||
<canvas wx:else class="ec-canvas" canvas-id="{{ canvasId }}" bindinit="init" bindtouchstart="{{ ec.disableTouch ? '' : 'touchStart' }}" bindtouchmove="{{ ec.disableTouch ? '' : 'touchMove' }}" bindtouchend="{{ ec.disableTouch ? '' : 'touchEnd' }}"></canvas>
|
||||
4
components/ec-canvas/ec-canvas.wxss
Normal file
@@ -0,0 +1,4 @@
|
||||
.ec-canvas {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
45
components/ec-canvas/echarts.js
Normal file
111
components/ec-canvas/wx-canvas.js
Normal file
@@ -0,0 +1,111 @@
|
||||
export default class WxCanvas {
|
||||
constructor(ctx, canvasId, isNew, canvasNode) {
|
||||
this.ctx = ctx;
|
||||
this.canvasId = canvasId;
|
||||
this.chart = null;
|
||||
this.isNew = isNew
|
||||
if (isNew) {
|
||||
this.canvasNode = canvasNode;
|
||||
}
|
||||
else {
|
||||
this._initStyle(ctx);
|
||||
}
|
||||
|
||||
// this._initCanvas(zrender, ctx);
|
||||
|
||||
this._initEvent();
|
||||
}
|
||||
|
||||
getContext(contextType) {
|
||||
if (contextType === '2d') {
|
||||
return this.ctx;
|
||||
}
|
||||
}
|
||||
|
||||
// canvasToTempFilePath(opt) {
|
||||
// if (!opt.canvasId) {
|
||||
// opt.canvasId = this.canvasId;
|
||||
// }
|
||||
// return wx.canvasToTempFilePath(opt, this);
|
||||
// }
|
||||
|
||||
setChart(chart) {
|
||||
this.chart = chart;
|
||||
}
|
||||
|
||||
addEventListener() {
|
||||
// noop
|
||||
}
|
||||
|
||||
attachEvent() {
|
||||
// noop
|
||||
}
|
||||
|
||||
detachEvent() {
|
||||
// noop
|
||||
}
|
||||
|
||||
_initCanvas(zrender, ctx) {
|
||||
zrender.util.getContext = function () {
|
||||
return ctx;
|
||||
};
|
||||
|
||||
zrender.util.$override('measureText', function (text, font) {
|
||||
ctx.font = font || '12px sans-serif';
|
||||
return ctx.measureText(text);
|
||||
});
|
||||
}
|
||||
|
||||
_initStyle(ctx) {
|
||||
ctx.createRadialGradient = () => {
|
||||
return ctx.createCircularGradient(arguments);
|
||||
};
|
||||
}
|
||||
|
||||
_initEvent() {
|
||||
this.event = {};
|
||||
const eventNames = [{
|
||||
wxName: 'touchStart',
|
||||
ecName: 'mousedown'
|
||||
}, {
|
||||
wxName: 'touchMove',
|
||||
ecName: 'mousemove'
|
||||
}, {
|
||||
wxName: 'touchEnd',
|
||||
ecName: 'mouseup'
|
||||
}, {
|
||||
wxName: 'touchEnd',
|
||||
ecName: 'click'
|
||||
}];
|
||||
eventNames.forEach(name => {
|
||||
this.event[name.wxName] = e => {
|
||||
const touch = e.touches[0];
|
||||
this.chart.getZr().handler.dispatch(name.ecName, {
|
||||
zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
|
||||
zrY: name.wxName === 'tap' ? touch.clientY : touch.y,
|
||||
preventDefault: () => {},
|
||||
stopImmediatePropagation: () => {},
|
||||
stopPropagation: () => {}
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
set width(w) {
|
||||
if (this.canvasNode) this.canvasNode.width = w
|
||||
}
|
||||
set height(h) {
|
||||
if (this.canvasNode) this.canvasNode.height = h
|
||||
}
|
||||
|
||||
get width() {
|
||||
if (this.canvasNode)
|
||||
return this.canvasNode.width
|
||||
return 0
|
||||
}
|
||||
get height() {
|
||||
if (this.canvasNode)
|
||||
return this.canvasNode.height
|
||||
return 0
|
||||
}
|
||||
}
|
||||
126
components/load-more/index.js
Normal file
@@ -0,0 +1,126 @@
|
||||
// components/load-more/index.js
|
||||
Component({
|
||||
/**
|
||||
* 组件的属性列表
|
||||
*/
|
||||
properties: {
|
||||
hasMore: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
},
|
||||
// 加载中的显示文本
|
||||
loadingText: {
|
||||
type: String,
|
||||
value: '加载中...'
|
||||
},
|
||||
// 加载失败的显示文本
|
||||
failText: {
|
||||
type: String,
|
||||
value: '加载失败, 请点击重试!'
|
||||
},
|
||||
// 没有更多后的显示文本, 默认没有则隐藏加载更多控件
|
||||
finishText: {
|
||||
type: String,
|
||||
value: '没有数据了...'
|
||||
},
|
||||
// 列表渲染延时, 默认为 500 ms, 我在开发工具中测试列表渲染速度时快时慢, 可根据实际使用中界面复杂度自行调整
|
||||
// ps 如果能监听setData() 渲染结束的话则可以不需要延时
|
||||
listRenderingDelay: {
|
||||
type: Number,
|
||||
value: 500
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的初始数据
|
||||
*/
|
||||
data: {
|
||||
showThis: false,
|
||||
text: '',
|
||||
showIcon: false,
|
||||
isLoading: false
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的方法列表
|
||||
*/
|
||||
methods: {
|
||||
|
||||
//加载更多的入口方法, 直接在page中使用时请在onReachBottom() 方法中调用这个方法, 并实现loadMoreListener方法去获取数据
|
||||
loadMore: function () {
|
||||
if (!this.properties.hasMore) {
|
||||
console.log('load more finish')
|
||||
return
|
||||
}
|
||||
if (this.data.isLoading) {
|
||||
console.log('loading ...')
|
||||
return
|
||||
}
|
||||
this.setData({
|
||||
isLoading: true
|
||||
})
|
||||
this.triggerEvent('loadMoreListener')
|
||||
},
|
||||
//加载完成, 传入hasMore
|
||||
loadMoreComplete: function (res) {
|
||||
// var hasMore = data.curPage < data.pageCount && data.pageCount != 1
|
||||
var hasMore = false;
|
||||
if (res.length == 0) {
|
||||
hasMore = false;
|
||||
}
|
||||
if (res.length > 0) {
|
||||
hasMore = true;
|
||||
}
|
||||
|
||||
if (res.length < 10) {
|
||||
hasMore = false;
|
||||
}
|
||||
|
||||
var text = '', showThis = false, showIcon = false
|
||||
if (hasMore) {
|
||||
showIcon = true
|
||||
showThis = true
|
||||
text = this.properties.loadingText
|
||||
} else if (this.properties.finishText.length > 0) {
|
||||
text = this.properties.finishText
|
||||
showThis = true
|
||||
}
|
||||
this.setData({
|
||||
hasMore: hasMore,
|
||||
text: text,
|
||||
showIcon: showIcon,
|
||||
showThis: showThis
|
||||
})
|
||||
//界面渲染延迟, 避免列表还未渲染完成就再次触发 loadMore 方法
|
||||
setTimeout(function () {
|
||||
this.setData({
|
||||
isLoading: false
|
||||
})
|
||||
}.bind(this), this.properties.listRenderingDelay)
|
||||
},
|
||||
// 加载失败
|
||||
loadMoreFail: function () {
|
||||
this.setData({
|
||||
showIcon: false,
|
||||
text: this.properties.failText
|
||||
})
|
||||
|
||||
//界面渲染延迟, 避免列表还未渲染完成就再次触发 loadMore 方法
|
||||
setTimeout(function () {
|
||||
this.setData({
|
||||
isLoading: false
|
||||
})
|
||||
}.bind(this), this.properties.listRenderingDelay)
|
||||
},
|
||||
//点击 loadmore 控件时触发, 只有加载失败时才会进入页面回调方法
|
||||
clickLoadMore: function () {
|
||||
if (this.data.text != this.properties.failText) return
|
||||
this.setData({
|
||||
showIcon: true,
|
||||
text: this.properties.loadingText,
|
||||
isLoading: true
|
||||
})
|
||||
this.triggerEvent('clickLoadMore')
|
||||
}
|
||||
}
|
||||
})
|
||||
4
components/load-more/index.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
5
components/load-more/index.wxml
Normal file
@@ -0,0 +1,5 @@
|
||||
<!--components/load-more/index.wxml-->
|
||||
<view class="loadmore" hidden='{{!showThis}}' bindtap='clickLoadMore'>
|
||||
<image class="icon {{showIcon?'active':''}}" src='http://static.sxlyb.com/images/loading01.png' hidden='{{!showIcon}}'/>
|
||||
<text>{{text}}</text>
|
||||
</view>
|
||||
36
components/load-more/index.wxss
Normal file
@@ -0,0 +1,36 @@
|
||||
/* components/load-more/index.wxss */
|
||||
|
||||
.loadmore {
|
||||
height: 35px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.loadmore text{
|
||||
font-size: 13px;
|
||||
color: #bfbfbf;
|
||||
font-weight: bold;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
.icon{
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.active {
|
||||
animation: weuiLoading 0.6s steps(12, end) infinite;
|
||||
}
|
||||
|
||||
@keyframes weuiLoading {
|
||||
0% {
|
||||
transform: rotate3d(0, 0, 1, 0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate3d(0, 0, 1, 360deg);
|
||||
}
|
||||
}
|
||||
36
components/navbarMyOil/index.js
Normal file
@@ -0,0 +1,36 @@
|
||||
const app = getApp()
|
||||
Component({
|
||||
properties: {
|
||||
navbarData: { //navbarData 由父页面传递的数据,变量名字自命名
|
||||
type: Object,
|
||||
value: {},
|
||||
observer: function (newVal, oldVal) { }
|
||||
}
|
||||
},
|
||||
data: {
|
||||
height: '',
|
||||
//默认值 默认显示左上角
|
||||
navbarData: {
|
||||
showCapsule: 1
|
||||
}
|
||||
},
|
||||
attached: function () {
|
||||
// 获取是否是通过分享进入的小程序
|
||||
this.setData({
|
||||
share: app.globalData.share
|
||||
})
|
||||
// 定义导航栏的高度 方便对齐
|
||||
this.setData({
|
||||
height: app.globalData.height
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// 返回上一页面
|
||||
_navback() {
|
||||
wx.navigateBack();
|
||||
// wx.navigateTo({
|
||||
// url: '../oilManage/oilManage'
|
||||
// })
|
||||
}
|
||||
}
|
||||
})
|
||||
3
components/navbarMyOil/index.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"component": true
|
||||
}
|
||||
12
components/navbarMyOil/index.wxml
Normal file
@@ -0,0 +1,12 @@
|
||||
<view class='nav-wrap' style='height: {{height*2 + 20}}px;'>
|
||||
<view class='nav-title' style='line-height: {{height*2 + 44}}px;'>{{navbarData.title}}</view>
|
||||
<view style='display: flex; justify-content: space-around;flex-direction: column'>
|
||||
|
||||
<view class='nav-capsule' style='height: {{height*2 + 44}}px;' wx:if='{{navbarData.showCapsule}}'>
|
||||
|
||||
<view bindtap='_navback' >
|
||||
<image src='../../pages/images/you.png' mode='aspectFill' class='back-pre'></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
53
components/navbarMyOil/index.wxss
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 顶部要固定定位 标题要居中 自定义按钮和标题要和右边微信原生的胶囊上下对齐 */
|
||||
|
||||
.nav-wrap {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
z-index: 9999999;
|
||||
}
|
||||
|
||||
/* 标题要居中 */
|
||||
|
||||
.nav-title {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
max-width: 400rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
font-size: 36rpx;
|
||||
color: #2c2b2b;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.nav-capsule {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 10px;
|
||||
width: 90px;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.back-pre, .back-home {
|
||||
width: 10px;
|
||||
height: 20px;
|
||||
margin-top: 8px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.nav-capsule .back-home {
|
||||
width: 70px;
|
||||
height: 28px;
|
||||
margin-top: 3rpx;
|
||||
}
|
||||
43
components/navbarOil/index.js
Normal file
@@ -0,0 +1,43 @@
|
||||
const app = getApp()
|
||||
Component({
|
||||
properties: {
|
||||
navbarData: { //navbarData 由父页面传递的数据,变量名字自命名
|
||||
type: Object,
|
||||
value: {},
|
||||
observer: function (newVal, oldVal) { }
|
||||
}
|
||||
},
|
||||
data: {
|
||||
height: '',
|
||||
//默认值 默认显示左上角
|
||||
navbarData: {
|
||||
showCapsule: 1
|
||||
}
|
||||
},
|
||||
attached: function () {
|
||||
// 获取是否是通过分享进入的小程序
|
||||
this.setData({
|
||||
share: app.globalData.share
|
||||
})
|
||||
// 定义导航栏的高度 方便对齐
|
||||
this.setData({
|
||||
height: app.globalData.height
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// 返回上一页面
|
||||
_navback() {
|
||||
wx.navigateBack();
|
||||
// wx.navigateTo({
|
||||
// url: '../wodeOil/wodeOil'
|
||||
// })
|
||||
},
|
||||
//返回到首页
|
||||
_backhome() {
|
||||
wx.switchTab({
|
||||
url: '/pages/index/index',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
3
components/navbarOil/index.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"component": true
|
||||
}
|
||||
12
components/navbarOil/index.wxml
Normal file
@@ -0,0 +1,12 @@
|
||||
<view class='nav-wrap' style='height: {{height*2 + 20}}px;'>
|
||||
<view class='nav-title' style='line-height: {{height*2 + 44}}px;'>{{navbarData.title}}</view>
|
||||
<view style='display: flex; justify-content: space-around;flex-direction: column'>
|
||||
|
||||
<view class='nav-capsule' style='height: {{height*2 + 44}}px;' wx:if='{{navbarData.showCapsule}}'>
|
||||
|
||||
<view bindtap='_navback' >
|
||||
<image src='../../pages/images/avatar.png' mode='aspectFill' class='back-pre'></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
56
components/navbarOil/index.wxss
Normal file
@@ -0,0 +1,56 @@
|
||||
/* 顶部要固定定位 标题要居中 自定义按钮和标题要和右边微信原生的胶囊上下对齐 */
|
||||
|
||||
.nav-wrap {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
z-index: 9999999;
|
||||
}
|
||||
|
||||
/* 标题要居中 */
|
||||
|
||||
.nav-title {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
max-width: 400rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
font-size: 36rpx;
|
||||
color: #2c2b2b;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.nav-capsule {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 10px;
|
||||
width: 90px;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.back-pre, .back-home {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
margin-top: 8px;
|
||||
padding: 10px;
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
/* margin-left: 25px; */
|
||||
}
|
||||
|
||||
.nav-capsule .back-home {
|
||||
width: 70px;
|
||||
height: 28px;
|
||||
margin-top: 3rpx;
|
||||
}
|
||||
33
components/navbarTwo/index.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const app = getApp()
|
||||
Component({
|
||||
properties: {
|
||||
navbarData: { //navbarData 由父页面传递的数据,变量名字自命名
|
||||
type: Object,
|
||||
value: {},
|
||||
observer: function (newVal, oldVal) { }
|
||||
}
|
||||
},
|
||||
data: {
|
||||
height: '',
|
||||
//默认值 默认显示左上角
|
||||
navbarData: {
|
||||
showCapsule: 1
|
||||
}
|
||||
},
|
||||
attached: function () {
|
||||
// 获取是否是通过分享进入的小程序
|
||||
this.setData({
|
||||
share: app.globalData.share
|
||||
})
|
||||
// 定义导航栏的高度 方便对齐
|
||||
this.setData({
|
||||
height: app.globalData.height
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// 返回上一页面
|
||||
_navback() {
|
||||
wx.navigateBack()
|
||||
}
|
||||
}
|
||||
})
|
||||
3
components/navbarTwo/index.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"component": true
|
||||
}
|
||||
12
components/navbarTwo/index.wxml
Normal file
@@ -0,0 +1,12 @@
|
||||
<view class='nav-wrap' style='height: {{height*2 + 20}}px;'>
|
||||
<view class='nav-title' style='line-height: {{height*2 + 40}}px;'>{{navbarData.title}}</view>
|
||||
<view style='display: flex; justify-content: space-around;flex-direction: column'>
|
||||
|
||||
<view class='nav-capsule' style='height: {{height*2 + 40}}px;' wx:if='{{navbarData.showCapsule}}'>
|
||||
|
||||
<view bindtap='_navback' >
|
||||
<image src='../../pages/images/you.png' mode='aspectFill' class='back-pre'></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
53
components/navbarTwo/index.wxss
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 顶部要固定定位 标题要居中 自定义按钮和标题要和右边微信原生的胶囊上下对齐 */
|
||||
|
||||
.nav-wrap {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
z-index: 9999999;
|
||||
}
|
||||
|
||||
/* 标题要居中 */
|
||||
|
||||
.nav-title {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
max-width: 400rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
font-size: 36rpx;
|
||||
color: #2c2b2b;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.nav-capsule {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 10px;
|
||||
width: 90px;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.back-pre, .back-home {
|
||||
width: 10px;
|
||||
height: 20px;
|
||||
margin-top: 8px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.nav-capsule .back-home {
|
||||
width: 70px;
|
||||
height: 28px;
|
||||
margin-top: 3rpx;
|
||||
}
|
||||
33
components/navbarWeChat/index.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const app = getApp()
|
||||
Component({
|
||||
properties: {
|
||||
navbarData: { //navbarData 由父页面传递的数据,变量名字自命名
|
||||
type: Object,
|
||||
value: {},
|
||||
observer: function (newVal, oldVal) { }
|
||||
}
|
||||
},
|
||||
data: {
|
||||
height: '',
|
||||
//默认值 默认显示左上角
|
||||
navbarData: {
|
||||
showCapsule: 1
|
||||
}
|
||||
},
|
||||
attached: function () {
|
||||
// 获取是否是通过分享进入的小程序
|
||||
this.setData({
|
||||
share: app.globalData.share
|
||||
})
|
||||
// 定义导航栏的高度 方便对齐
|
||||
this.setData({
|
||||
height: app.globalData.height
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// 返回上一页面
|
||||
_navback() {
|
||||
wx.navigateBack()
|
||||
}
|
||||
}
|
||||
})
|
||||
3
components/navbarWeChat/index.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"component": true
|
||||
}
|
||||
12
components/navbarWeChat/index.wxml
Normal file
@@ -0,0 +1,12 @@
|
||||
<view class='nav-wrap' style='height: {{height*2 + 20}}px;'>
|
||||
<view class='nav-title' style='line-height: {{height*2 + 40}}px;'>{{navbarData.title}}</view>
|
||||
<view style='display: flex; justify-content: space-around;flex-direction: column'>
|
||||
|
||||
<view class='nav-capsule' style='height: {{height*2 + 40}}px;' wx:if='{{navbarData.showCapsule}}'>
|
||||
|
||||
<!-- <view bindtap='_navback' >
|
||||
<image src='../../pages/images/you.png' mode='aspectFill' class='back-pre'></image>
|
||||
</view> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
53
components/navbarWeChat/index.wxss
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 顶部要固定定位 标题要居中 自定义按钮和标题要和右边微信原生的胶囊上下对齐 */
|
||||
|
||||
.nav-wrap {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
background: #fff;
|
||||
color: #000;
|
||||
z-index: 9999999;
|
||||
}
|
||||
|
||||
/* 标题要居中 */
|
||||
|
||||
.nav-title {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
max-width: 400rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
font-size: 36rpx;
|
||||
color: #2c2b2b;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.nav-capsule {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 10px;
|
||||
width: 90px;
|
||||
justify-content: space-between;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.back-pre, .back-home {
|
||||
width: 10px;
|
||||
height: 20px;
|
||||
margin-top: 8px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.nav-capsule .back-home {
|
||||
width: 70px;
|
||||
height: 28px;
|
||||
margin-top: 3rpx;
|
||||
}
|
||||
30
components/pay-list/pay-list.js
Normal file
@@ -0,0 +1,30 @@
|
||||
// components/pay-list/pay-list.js
|
||||
Component({
|
||||
/**
|
||||
* 组件的属性列表
|
||||
*/
|
||||
properties: {
|
||||
item: {
|
||||
type: Object,
|
||||
value: {},
|
||||
},
|
||||
settlementType:{
|
||||
type:Number,
|
||||
value:1
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的初始数据
|
||||
*/
|
||||
data: {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的方法列表
|
||||
*/
|
||||
methods: {
|
||||
|
||||
}
|
||||
})
|
||||
4
components/pay-list/pay-list.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
||||
41
components/pay-list/pay-list.wxml
Normal file
@@ -0,0 +1,41 @@
|
||||
<wxs src="../../utils/filter.wxs" module="filter"></wxs>
|
||||
<view class="box">
|
||||
<view class="top">
|
||||
<view class="left">
|
||||
<block>
|
||||
<!-- 钱包支付 -->
|
||||
<image class="walletType" wx:if="{{item.walletType===613}}" src="../../pages/images/ic_list_pay_wallet.png" mode="widthFix" />
|
||||
<!-- 电子油卡支付 -->
|
||||
<image class="walletType" wx:if="{{item.walletType===611||item.walletType===405||item.walletType===621}}" src="../../pages/images/ic_list_pay_card.png" mode="widthFix" />
|
||||
<!-- 司机优惠微信支付 -->
|
||||
<image class="walletType" wx:if="{{item.walletType===610||item.walletType===612 || item.walletType===622}}" src="../../pages/images/ic_list_pay_discount.png" mode="widthFix" />
|
||||
<!-- 信用油卡支付 -->
|
||||
<image class="walletType" wx:if="{{item.walletType===1402}}" src="../../pages/images/ic_oil_pay_credit.png" mode="widthFix" />
|
||||
<!-- 退款 -->
|
||||
<image class="walletType" wx:if="{{item.walletType===6131||item.walletType===6121||item.walletType===6211||item.walletType===6111||item.walletType===6221}}" src="../../pages/images/ic_list_money_back.png" mode="widthFix" />
|
||||
</block>
|
||||
<view>{{item.description}}</view>
|
||||
<view>-{{filter.extractLastFourDigits(item.userPhone)}}</view>
|
||||
</view>
|
||||
<view class="right">{{item.created}}</view>
|
||||
</view>
|
||||
<view class="bottom">
|
||||
<view class="left">
|
||||
<view class="money" wx:if="{{settlementType===2}}">
|
||||
<view class="desc">加油量</view>
|
||||
<view class="num">{{item.oilQuantity||0}}</view>
|
||||
</view>
|
||||
<view class="money">
|
||||
<view class="desc">优惠</view>
|
||||
<view class="num">{{item.payGift||0}}</view>
|
||||
</view>
|
||||
<view class="money">
|
||||
<view class="desc">{{settlementType===1?'实收':'应收'}}</view>
|
||||
<view class="num">{{(settlementType===1?item.actual:item.money)||0}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="right {{item.type==1?'negativeGasReceipts':'positiveGasReceipts'}}">
|
||||
{{item.type==1?'-':'+'}}¥{{settlementType===1?item.money:item.gasReceipts}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
79
components/pay-list/pay-list.wxss
Normal file
@@ -0,0 +1,79 @@
|
||||
.box {
|
||||
display: flex;
|
||||
width: 682rpx;
|
||||
padding: 24rpx 0;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
box-shadow: 0 0 8rpx 0 #f3f5f7;
|
||||
box-sizing: border-box;
|
||||
/* height: 162rpx; */
|
||||
}
|
||||
.top {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 11rpx;
|
||||
}
|
||||
.top .left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #363636;
|
||||
font-family: "PingFang SC";
|
||||
font-size: 26rpx;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
}
|
||||
.walletType {
|
||||
display: block;
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
.top .right {
|
||||
color: #808080;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
.bottom {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.bottom .left {
|
||||
display: flex;
|
||||
color: #363636;
|
||||
font-family: "PingFang SC";
|
||||
font-size: 26rpx;
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
}
|
||||
.money {
|
||||
margin-right: 60rpx;
|
||||
}
|
||||
.money .desc {
|
||||
margin-right: 8rpx;
|
||||
color: #808080;
|
||||
font-size: 26rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
.money .num {
|
||||
color: #363636;
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
.bottom .right {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
.bottom .negativeGasReceipts{
|
||||
color: #FF7A7A;
|
||||
}
|
||||
.bottom .positiveGasReceipts{
|
||||
color: #367df9;
|
||||
}
|
||||
3
package-lock.json
generated
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"lockfileVersion": 1
|
||||
}
|
||||
60
pages/addFunction/addFunction.js
Normal file
@@ -0,0 +1,60 @@
|
||||
// pages/addFunction/addFunction.js
|
||||
|
||||
const code = `// 云函数入口函数
|
||||
exports.main = (event, context) => {
|
||||
console.log(event)
|
||||
console.log(context)
|
||||
return {
|
||||
sum: event.a + event.b
|
||||
}
|
||||
}`
|
||||
|
||||
Page({
|
||||
|
||||
data: {
|
||||
result: '',
|
||||
canIUseClipboard: wx.canIUse('setClipboardData'),
|
||||
},
|
||||
|
||||
onLoad: function (options) {
|
||||
|
||||
},
|
||||
|
||||
copyCode: function() {
|
||||
wx.setClipboardData({
|
||||
data: code,
|
||||
success: function () {
|
||||
wx.showToast({
|
||||
title: '复制成功',
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
testFunction() {
|
||||
wx.cloud.callFunction({
|
||||
name: 'sum',
|
||||
data: {
|
||||
a: 1,
|
||||
b: 2
|
||||
},
|
||||
success: res => {
|
||||
wx.showToast({
|
||||
title: '调用成功',
|
||||
})
|
||||
this.setData({
|
||||
result: JSON.stringify(res.result)
|
||||
})
|
||||
},
|
||||
fail: err => {
|
||||
wx.showToast({
|
||||
icon: 'none',
|
||||
title: '调用失败',
|
||||
})
|
||||
console.error('[云函数] [sum] 调用失败:', err)
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
})
|
||||
|
||||
4
pages/addFunction/addFunction.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"navigationBarTitleText": "云函数指引",
|
||||
"usingComponents": {}
|
||||
}
|
||||
29
pages/addFunction/addFunction.wxml
Normal file
@@ -0,0 +1,29 @@
|
||||
<!--pages/addFunction/addFunction.wxml-->
|
||||
<view class="container">
|
||||
|
||||
<view class="list">
|
||||
<view class="list-item" bindtap="testFunction">
|
||||
<text>测试云函数</text>
|
||||
</view>
|
||||
<view class="list-item">
|
||||
<text class="request-text">期望输出:{"sum":3}</text>
|
||||
</view>
|
||||
<view class="list-item" wx:if="{{result}}">
|
||||
<text class="request-text">调用结果:{{result}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="guide">
|
||||
<text class="headline">新增云函数</text>
|
||||
<text class="p">1. 在云函数根目录 cloudfunctions 上右键选择新建云函数,命名为 sum</text>
|
||||
<text class="p">2. 在创建的 cloudfunctions/sum/index.js 文件中添加如下代码</text>
|
||||
<image class="image1" src="../../images/code-func-sum.png" mode="aspectFit"></image>
|
||||
<button class="copyBtn" wx:if="{{canIUseClipboard}}" bindtap="copyCode">复制代码</button>
|
||||
<text class="p">3. 在 cloudfunctions/sum 目录上右键上传并部署</text>
|
||||
<text class="p">4. 点击测试云函数测试</text>
|
||||
<text class="p">5. 打开云开发云函数管理页,选择 sum 云函数</text>
|
||||
<text class="p">6. 查看 sum 的调用日志</text>
|
||||
<text class="p">进阶:可在云函数中使用 wx-server-sdk 操作数据库,文件存储和调用其他云函数,详见文档</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
3
pages/addFunction/addFunction.wxss
Normal file
@@ -0,0 +1,3 @@
|
||||
/* pages/addFunction/addFunction.wxss */
|
||||
|
||||
@import "../../style/guide.wxss";
|
||||
66
pages/agreement/index.js
Normal file
@@ -0,0 +1,66 @@
|
||||
// pages/agreement/index.js
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad: function (options) {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage: function () {
|
||||
|
||||
}
|
||||
})
|
||||
7
pages/agreement/index.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"navigationBarBackgroundColor": "#f48218",
|
||||
"navigationBarTextStyle": "white",
|
||||
"navigationBarTitleText": "电子油卡使用须知",
|
||||
"backgroundColor": "#eeeeee",
|
||||
"backgroundTextStyle": "light"
|
||||
}
|
||||
16
pages/agreement/index.wxml
Normal file
@@ -0,0 +1,16 @@
|
||||
<view class="title">电子油卡使用须知</view>
|
||||
|
||||
<view class="section">
|
||||
1、“运费油卡”仅用于展示本平台(无车承运人)向实际承运人(以下简称“您”或“司机”)提供油品物资情况的虚拟记录,并不涉及发行任何电子卡、虚拟卡或实体卡等,不涉及开立任何类型的账户,不涉及进行任何类型的销售,不涉及任何支付、充值、消费等资金结算。
|
||||
</view>
|
||||
|
||||
<view class="section">2、“当前余额”表示本平台作为无车承运人分配给司机的、可用的油费额度,仅作为向司机展示可领物资(油品/天然气)信息的一个记录,并不对应任何财产,不支持退款和提现。</view>
|
||||
|
||||
<view class="section">3、您可基于“运费油卡”的记录,选择与本平台合作的加油站/加气站(具体以本平台上显示的加油站/加气站为准,该等加油站/加气站仅为本平台代为交付物资,而非对您销售)领取油品/天然气。在您领取油品/天然气后,您的可领物资(油品/天然气)的额度将相应减少,即您的“当前余额”将相应减少。</view>
|
||||
|
||||
<view class="section">4、您在使用“运费油卡”领取油品/天然气时,所使用的二维码仅作为识别您的身份的便利设置,并非付款凭证。</view>
|
||||
|
||||
<view class="section">5、您在使用“运费油卡”过程中,请您务必审慎阅读、充分理解特殊说明事项,包括但不限于本说明的全部内容以及页面提示的不支持开票/优惠券、不可用于其他消费、不支持退还和提现等内容;如果您不同意上述特殊说明的任何内容,或者无法准确理其含义,请不要进行确认及后续操作。若您进行确认或后续操作,即视为您知悉并同意上述特殊说明事项。</view>
|
||||
|
||||
<view class="section">6、平台声明:本平台上所有关于“运费油卡”、“当前余额”等名称/表述的使用,仅为用户阅读方便,不能作为法律关系实质解释的依据。本平台享有对该等名称/表述的最终解释权。</view>
|
||||
|
||||
14
pages/agreement/index.wxss
Normal file
@@ -0,0 +1,14 @@
|
||||
/* pages/agreement/index.wxss */
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
text-align: center;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
|
||||
.section {
|
||||
font-size: 30rpx;
|
||||
padding: 0.5em 1em;
|
||||
line-height: 1.4em;
|
||||
text-indent: 2em;
|
||||
}
|
||||
71
pages/agreement/login-agree.js
Normal file
@@ -0,0 +1,71 @@
|
||||
// pages/agreement/login-agree.js
|
||||
const app = getApp()
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
nvabarData: {
|
||||
showCapsule: 1, //是否显示左上角图标 1表示显示 0表示不显示
|
||||
title: '登录', //导航栏 中间的标题
|
||||
}, // 此页面 页面内容距最顶部的距离
|
||||
height: app.globalData.height * 2 + 20,
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad: function (options) {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage: function () {
|
||||
|
||||
}
|
||||
})
|
||||
10
pages/agreement/login-agree.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"navigationBarBackgroundColor": "#f48218",
|
||||
"navigationBarTextStyle": "white",
|
||||
"navigationBarTitleText": "卡运帮注册服务协议",
|
||||
"backgroundColor": "#eeeeee",
|
||||
"backgroundTextStyle": "light",
|
||||
"usingComponents": {
|
||||
"nav-bar": "/components/navbarTwo/index"
|
||||
}
|
||||
}
|
||||
86
pages/agreement/login-agree.wxml
Normal file
@@ -0,0 +1,86 @@
|
||||
|
||||
<nav-bar navbar-data='{{nvabarData}}'></nav-bar>
|
||||
<view class="title" style='margin-top: {{height}}px'>陆运帮客户端服务协议</view>
|
||||
|
||||
<view class="section">
|
||||
陕西陆运帮网络科技有限公司(以下简称“陆运帮”)所提供的一切服务的所有权、运营权、解释权、相关应用的知识产权均归陆运帮所有。注册会员时,请您认真阅读本协议,审阅后决定接受或不接受本协议。若您注册为会员,即表示您已充分阅读、理解并同意自己与陆运帮订立本协议,且您自愿受本协议条款的所有内容。本协议内容包括协议正文及陆运帮所有已经发布的各类规则。陆运帮已发布的所有规则为本协议不可分割的一部分,与本协议正文具有同等法律效力。
|
||||
</view>
|
||||
|
||||
<view class="section">陆运帮有权在必要时修改本协议,并通过在名为“陆运帮”的微信应用(以下简称“本应用”)上公告或名为“陆运帮”的微信公众号(以下简称“公众号”)上公告等合理方式告知会员。经修订的条款在本应用或公众号上公告后即自动生效。会员在享受各项服务时,应当及时查阅了解修改的内容,并自觉遵守本协议条款以及该单项服务的相关条款。会员如继续使用本协议条款涉及的服务,则视为对修改内容的同意,当发生有关争议时,以最新的协议条款为准;会员在不同意相关修改内容的情况下,必须停止使用本应用。除非得到陆运帮的书面授权,任何人将不得修改本协议。</view>
|
||||
|
||||
<view class="section">1、会员资格</view>
|
||||
|
||||
<view class="section">只有符合下列条件之一的自然人或法人才能申请成为本应用会员,可以使用本应用提供的服务:
|
||||
A、年满十八周岁,并具备相应的民事行为能力的自然人;
|
||||
B、根据中国法律、法规、行政规章成立并合法存在的机关、企事业单位、社团组织和其他组织。
|
||||
</view>
|
||||
|
||||
<view class="section">2、会员的账号、密码及其安全性</view>
|
||||
|
||||
<view class="section">
|
||||
您一旦注册成功成为会员,将得到一个账号和密码。会员可随时改变自己的密码,也可以结束旧的账号重开一个新账号。会员应对账号和密码的安全性负全部责任。陆运帮将不承担会员的账号和密码的一切安全及保密责任以及因会员的账号和密码的泄露所导致的一切损失。如果会员未保管好自己的帐号和密码而对会员、陆运帮或第三方造成损害,会员将负全部责任。会员同意若发现有任何非法使用自己的账号或者存在其他安全漏洞的情况,有义务立即通知陆运帮。
|
||||
</view>
|
||||
|
||||
<view class="section">3、会员权利与义务</view>
|
||||
|
||||
|
||||
<view>
|
||||
(1)会员有权根据本协议、本应用及公众号发布的相关规则,利用本应用发布货源、寻找货源、查询车辆信息,在本应用及相关产品发布信息,参加本应用的有关活动及有权享受本应用提供的其他有关资讯及信息服务。
|
||||
(2)会员应当向本应用提供真实准确完整的注册信息。同时,会员也应当在相关资料实际变更时及时更新有关注册资料。会员进一步同意其一旦将信息或资料在使用服务时提供,则表示同意放弃对此信息或资料所享有的隐私权、版权和相关财产权利。
|
||||
(3)会员不得以任何形式擅自转让或授权他人使用自己在本应用的会员账号。
|
||||
(4)会员有义务确保在本应用上发布的货源信息真实、准确无误。
|
||||
(5)会员有义务确保在规定的时间里完成订单的货运,若有变更必须提前征得货主同意。
|
||||
(6)会员承诺自己在使用本应用实施的所有行为遵守法律、法规、行政规章和本应用的相关规定以及各种社会公共利益或公共道德。如有违反导致任何法律后果的发生,会员将以自己的名义独立承担相应的法律责任。
|
||||
(7)会员不得使用以下方式登录应用或破坏其所提供的服务:
|
||||
A、以任何机器人软件、蜘蛛软件、爬虫软件、刷单软件或其它自动方式访问或登录本应用;
|
||||
B、通过任何方式对本公司 内部结构造成或可能造成不合理或不合比例的重大负荷的行为;
|
||||
C、通过任何方式干扰或试图干扰本应用的正常工作或本应用上进行的任何活动。
|
||||
(8)会员同意接收来自本应用的信息。
|
||||
</view>
|
||||
|
||||
<view class="section">4、违约责任</view>
|
||||
|
||||
<view>
|
||||
会员违反本协议规定的内容,给陆运帮造成损失的,应当承担违约责任,赔偿陆运帮因此所受的一切损失,包括但不限于本金损失、利息损失、因追索或诉讼而支出的诉讼费、合理的通讯费、交通费、住宿费、律师费等。
|
||||
</view>
|
||||
|
||||
<view class="section">5、免责条款</view>
|
||||
|
||||
<view class="section">
|
||||
(1)本应用作为一个信息交换平台,其信息是由各地方用户提供,各提供者对提供信息的内容承担全部责任。本应用要求信息提供者发布合法、真实、有效的信息,但本应用对此不承担任何责任。
|
||||
|
||||
(2)对任何经由本应用或从官网链接、下载或从任何与本应用有关信息服务所获得的信息、资料及广告,陆运帮不保证其内容的有效性、正确性或可靠性;对于会员通过本应用、公众号等获取的信息服务,如信息、广告或资讯,而发布、查询或取得的任何信息或资料,陆运帮概不负保证责任。会员因此所产生的风险应自行承担。本应用有权但无义务修改或更正在服务的信息内容或资料中存在的任何错误或疏漏。
|
||||
(3)本应用的信息、资料或广告是基于为会员服务的目的而存在的,陆运帮明确地拒绝对服务、信息内容或资料给予任何明示或暗示的保证,包括但不限于为商业使用或适合某一特定的目的的保证,除非有其它特别规定或声明。陆运帮对于因服务、信息内容或资料所产生的任何直接、间接、附带的或因此而导致的连带性损失概不负责。
|
||||
(4)陆运帮尊重他人的权利(包括知识产权),同时也要求会员也尊重他人的权利。陆运帮在适当情况下,可以自行决定终止向违反或侵害他人权利者提供服务。
|
||||
|
||||
</view>
|
||||
|
||||
<view class="section">6、不可抗力条款</view>
|
||||
|
||||
|
||||
|
||||
<view class="section">
|
||||
由于不可抗力或意外事件而影响本应用提供正常的服务和支持时,本应用不承担任何责任。
|
||||
“不可抗力”是指不能预见、不能克服且无法避免的客观事件,如战争、自然灾害、法律法规和政府规范修订、因网络服务特性而特有的原因(如境内外基础电信运营商的故障、计算机或互联网相关技术缺陷、互联网覆盖范围限制、计算机病毒、黑客攻击等因素)等;“意外事件”指诸如光缆出现故障的影响或损坏;通信线路或服务器发生超出本应用防范与预见能力的故障等类似事件。
|
||||
</view>
|
||||
|
||||
<view class="section">7、系统维护</view>
|
||||
|
||||
<view class="section">
|
||||
为提升服务水平,陆运帮在必要时会对本应用、公众号等进行维护,该种情况下需要短时间中断服务,维护通常会在会员休息的时间内进行,也可能在会员正常使用时进行,因此给会员造成的影响陆运帮并不承担任何责任。陆运帮会在时间许可的情况下,会将维护的相关信息以公告的方式通知会员。如因网络通路的偶然阻塞造成本应用访问速度减慢或中断,此种情况属于网络运营商故障,陆运帮对此不负责任,但事后会予以公告。
|
||||
</view>
|
||||
|
||||
|
||||
<view class="section">8、其他</view>
|
||||
|
||||
<view class="section">
|
||||
(1)陆运帮对本服务协议包括基于服务协议制定的各项规则拥有最终解释权。
|
||||
(2)本应用或公众号等由陆运帮提供的服务仅向会员提供服务。会员对本应用或公众号等的使用,即表明同意承担浏览本应用可能带来的各种风险。
|
||||
|
||||
</view>
|
||||
|
||||
<view class="section">9、争议解决</view>
|
||||
|
||||
<view class="section">
|
||||
如使用本协议项下服务中出现纠纷的,您与陆运帮应友好协商解决,若协商不成,您同意将纠纷提交西安市仲裁委员会解决 。
|
||||
</view>
|
||||
14
pages/agreement/login-agree.wxss
Normal file
@@ -0,0 +1,14 @@
|
||||
/* pages/agreement/index.wxss */
|
||||
|
||||
.title {
|
||||
font-size: 32rpx;
|
||||
text-align: center;
|
||||
line-height: 1.6em;
|
||||
}
|
||||
|
||||
.section {
|
||||
font-size: 30rpx;
|
||||
padding: 0.5em 1em;
|
||||
line-height: 1.4em;
|
||||
text-indent: 2em;
|
||||
}
|
||||
66
pages/chooseLib/chooseLib.js
Normal file
@@ -0,0 +1,66 @@
|
||||
// pages/chooseLib/chooseLib.js
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad: function (options) {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage: function () {
|
||||
|
||||
}
|
||||
})
|
||||
4
pages/chooseLib/chooseLib.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"navigationBarTitleText": "选择基础库",
|
||||
"usingComponents": {}
|
||||
}
|
||||
14
pages/chooseLib/chooseLib.wxml
Normal file
@@ -0,0 +1,14 @@
|
||||
<!--pages/chooseLib/chooseLib.wxml-->
|
||||
<view class="container">
|
||||
|
||||
<view class="list">
|
||||
<view class="list-item">
|
||||
<text class="black">初始化失败</text>
|
||||
</view>
|
||||
<view class="list-item">
|
||||
<text class="request-text">请使用 2.2.3 或以上的基础库以使用云能力</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
7
pages/chooseLib/chooseLib.wxss
Normal file
@@ -0,0 +1,7 @@
|
||||
/* pages/chooseLib/chooseLib.wxss */
|
||||
|
||||
@import "../../style/guide.wxss";
|
||||
|
||||
.black {
|
||||
color: black;
|
||||
}
|
||||
193
pages/databaseGuide/databaseGuide.js
Normal file
@@ -0,0 +1,193 @@
|
||||
// pages/databaseGuide/databaseGuide.js
|
||||
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
|
||||
data: {
|
||||
step: 1,
|
||||
counterId: '',
|
||||
openid: '',
|
||||
count: null,
|
||||
queryResult: '',
|
||||
},
|
||||
|
||||
onLoad: function (options) {
|
||||
if (app.globalData.openid) {
|
||||
this.setData({
|
||||
openid: app.globalData.openid
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onAdd: function () {
|
||||
// const db = wx.cloud.database()
|
||||
// db.collection('counters').add({
|
||||
// data: {
|
||||
// count: 1
|
||||
// },
|
||||
// success: res => {
|
||||
// // 在返回结果中会包含新创建的记录的 _id
|
||||
// this.setData({
|
||||
// counterId: res._id,
|
||||
// count: 1
|
||||
// })
|
||||
// wx.showToast({
|
||||
// title: '新增记录成功',
|
||||
// })
|
||||
// console.log('[数据库] [新增记录] 成功,记录 _id: ', res._id)
|
||||
// },
|
||||
// fail: err => {
|
||||
// wx.showToast({
|
||||
// icon: 'none',
|
||||
// title: '新增记录失败'
|
||||
// })
|
||||
// console.error('[数据库] [新增记录] 失败:', err)
|
||||
// }
|
||||
// })
|
||||
},
|
||||
|
||||
onQuery: function() {
|
||||
// const db = wx.cloud.database()
|
||||
// // 查询当前用户所有的 counters
|
||||
// db.collection('counters').where({
|
||||
// _openid: this.data.openid
|
||||
// }).get({
|
||||
// success: res => {
|
||||
// this.setData({
|
||||
// queryResult: JSON.stringify(res.data, null, 2)
|
||||
// })
|
||||
// console.log('[数据库] [查询记录] 成功: ', res)
|
||||
// },
|
||||
// fail: err => {
|
||||
// wx.showToast({
|
||||
// icon: 'none',
|
||||
// title: '查询记录失败'
|
||||
// })
|
||||
// console.error('[数据库] [查询记录] 失败:', err)
|
||||
// }
|
||||
// })
|
||||
},
|
||||
|
||||
onCounterInc: function() {
|
||||
// const db = wx.cloud.database()
|
||||
// const newCount = this.data.count + 1
|
||||
// db.collection('counters').doc(this.data.counterId).update({
|
||||
// data: {
|
||||
// count: newCount
|
||||
// },
|
||||
// success: res => {
|
||||
// this.setData({
|
||||
// count: newCount
|
||||
// })
|
||||
// },
|
||||
// fail: err => {
|
||||
// icon: 'none',
|
||||
// console.error('[数据库] [更新记录] 失败:', err)
|
||||
// }
|
||||
// })
|
||||
},
|
||||
|
||||
onCounterDec: function() {
|
||||
// const db = wx.cloud.database()
|
||||
// const newCount = this.data.count - 1
|
||||
// db.collection('counters').doc(this.data.counterId).update({
|
||||
// data: {
|
||||
// count: newCount
|
||||
// },
|
||||
// success: res => {
|
||||
// this.setData({
|
||||
// count: newCount
|
||||
// })
|
||||
// },
|
||||
// fail: err => {
|
||||
// icon: 'none',
|
||||
// console.error('[数据库] [更新记录] 失败:', err)
|
||||
// }
|
||||
// })
|
||||
},
|
||||
|
||||
onRemove: function() {
|
||||
// if (this.data.counterId) {
|
||||
// const db = wx.cloud.database()
|
||||
// db.collection('counters').doc(this.data.counterId).remove({
|
||||
// success: res => {
|
||||
// wx.showToast({
|
||||
// title: '删除成功',
|
||||
// })
|
||||
// this.setData({
|
||||
// counterId: '',
|
||||
// count: null,
|
||||
// })
|
||||
// },
|
||||
// fail: err => {
|
||||
// wx.showToast({
|
||||
// icon: 'none',
|
||||
// title: '删除失败',
|
||||
// })
|
||||
// console.error('[数据库] [删除记录] 失败:', err)
|
||||
// }
|
||||
// })
|
||||
// } else {
|
||||
// wx.showToast({
|
||||
// title: '无记录可删,请见创建一个记录',
|
||||
// })
|
||||
// }
|
||||
},
|
||||
|
||||
nextStep: function () {
|
||||
// 在第一步,需检查是否有 openid,如无需获取
|
||||
if (this.data.step === 1 && !this.data.openid) {
|
||||
wx.cloud.callFunction({
|
||||
name: 'login',
|
||||
data: {},
|
||||
success: res => {
|
||||
app.globalData.openid = res.result.openid
|
||||
this.setData({
|
||||
step: 2,
|
||||
openid: res.result.openid
|
||||
})
|
||||
},
|
||||
fail: err => {
|
||||
wx.showToast({
|
||||
icon: 'none',
|
||||
title: '获取 openid 失败,请检查是否有部署 login 云函数',
|
||||
})
|
||||
console.log('[云函数] [login] 获取 openid 失败,请检查是否有部署云函数,错误信息:', err)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
const callback = this.data.step !== 6 ? function() {} : function() {
|
||||
console.group('数据库文档')
|
||||
console.log('https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/database.html')
|
||||
console.groupEnd()
|
||||
}
|
||||
|
||||
this.setData({
|
||||
step: this.data.step + 1
|
||||
}, callback)
|
||||
}
|
||||
},
|
||||
|
||||
prevStep: function () {
|
||||
this.setData({
|
||||
step: this.data.step - 1
|
||||
})
|
||||
},
|
||||
|
||||
goHome: function() {
|
||||
const pages = getCurrentPages()
|
||||
if (pages.length === 2) {
|
||||
wx.navigateBack()
|
||||
} else if (pages.length === 1) {
|
||||
wx.redirectTo({
|
||||
url: '../index/index',
|
||||
})
|
||||
} else {
|
||||
wx.reLaunch({
|
||||
url: '../index/index',
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
4
pages/databaseGuide/databaseGuide.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"navigationBarTitleText": "数据库指引",
|
||||
"usingComponents": {}
|
||||
}
|
||||
134
pages/databaseGuide/databaseGuide.wxml
Normal file
@@ -0,0 +1,134 @@
|
||||
<!--pages/databaseGuide/databaseGuide.wxml-->
|
||||
<view class="container">
|
||||
|
||||
<!-- 导航 -->
|
||||
<view class="list">
|
||||
<view class="list-item">
|
||||
<text class="request-text">数据库指引</text>
|
||||
</view>
|
||||
<view class="list-item">
|
||||
<text class="request-text" wx:for="{{7}}" style="color: {{step === index + 1 ? 'red': 'black'}}">{{index + 1}}</text>
|
||||
</view>
|
||||
<view class="list-item" wx:if="{{openid}}">
|
||||
<text class="request-text">openid:{{openid}}</text>
|
||||
</view>
|
||||
<view class="list-item" wx:if="{{counterId}}">
|
||||
<text class="request-text">当前记录 ID:{{counterId}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 快速操作数据库指引 -->
|
||||
|
||||
<!-- 简介 -->
|
||||
<view class="guide" wx:if="{{step === 1}}">
|
||||
<text class="headline">示例介绍</text>
|
||||
<text class="p">1. 以计数器为例,在此演示如何操作数据库</text>
|
||||
<text class="p">2. 数据库操作大多需要用户 openid,需先配置好 login 云函数,如已配置好,点击下一步,获取用户 openid 并开始我们的指引</text>
|
||||
<div class="nav">
|
||||
<button class="next" size="mini" type="default" bindtap="nextStep">下一步</button>
|
||||
</div>
|
||||
</view>
|
||||
|
||||
<!-- 新建集合 -->
|
||||
<view class="guide" wx:if="{{step === 2}}">
|
||||
<text class="headline">新建集合</text>
|
||||
<text class="p">1. 打开云开发控制台,进入到数据库管理页</text>
|
||||
<image class="image1" src="../../images/console-entrance.png" mode="aspectFit"></image>
|
||||
<text class="p">2. 选择添加集合,集合名为 counters</text>
|
||||
<image class="flat-image" src="../../images/create-collection.png" mode="aspectFit"></image>
|
||||
<text class="p">3. 可以看到 counters 集合出现在左侧集合列表中</text>
|
||||
<text class="p">注:集合必须在云开发控制台中创建</text>
|
||||
|
||||
<div class="nav">
|
||||
<button class="prev" size="mini" type="default" bindtap="prevStep">上一步</button>
|
||||
<button class="next" size="mini" type="default" bindtap="nextStep">下一步</button>
|
||||
</div>
|
||||
</view>
|
||||
|
||||
<!-- 新增记录 -->
|
||||
<view class="guide" wx:if="{{step === 3}}">
|
||||
<text class="headline">新增记录</text>
|
||||
<text class="p">1. 打开 pages/databaseGuide/databaseGuide.js 文件,定位到 onAdd 方法</text>
|
||||
<text class="p">2. 把注释掉的代码解除注释</text>
|
||||
<image class="code-image" src="../../images/code-db-onAdd.png" mode="aspectFit"></image>
|
||||
<text class="p">3. onAdd 方法会往 counters 集合新增一个记录,新增如下格式的一个 JSON 记录</text>
|
||||
<text class="code">
|
||||
{
|
||||
"_id": "数据库自动生成记录 ID 字段",
|
||||
"_openid": "数据库自动插入记录创建者的 openid",
|
||||
"count": 1
|
||||
}
|
||||
</text>
|
||||
<text class="p">4. 点击按钮</text>
|
||||
<button size="mini" type="default" bindtap="onAdd">新增记录</button>
|
||||
<text class="p" wx:if="{{counterId}}">新增的记录 _id 为:{{counterId}}</text>
|
||||
<text class="p">5. 在云开发 -> 数据库 -> counters 集合中可以看到新增的记录</text>
|
||||
|
||||
<div class="nav">
|
||||
<button class="prev" size="mini" type="default" bindtap="prevStep">上一步</button>
|
||||
<button class="next" size="mini" type="default" bindtap="nextStep" wx:if="{{counterId}}">下一步</button>
|
||||
</div>
|
||||
</view>
|
||||
|
||||
<!-- 查询记录 -->
|
||||
<view class="guide" wx:if="{{step === 4}}">
|
||||
<text class="headline">查询记录</text>
|
||||
<text class="p">1. 打开 pages/databaseGuide/databaseGuide.js 文件,定位到 onQuery 方法</text>
|
||||
<text class="p">2. 把注释掉的代码解除注释,onQuery 方法会在下方按钮被点击时触发</text>
|
||||
<image class="code-image" src="../../images/code-db-onQuery.png" mode="aspectFit"></image>
|
||||
<text class="p">3. 点击按钮</text>
|
||||
<button size="mini" type="default" bindtap="onQuery">查询记录</button>
|
||||
<text class="code" wx:if="{{queryResult}}">{{queryResult}}</text>
|
||||
|
||||
<div class="nav">
|
||||
<button class="prev" size="mini" type="default" bindtap="prevStep">上一步</button>
|
||||
<button class="next" size="mini" type="default" bindtap="nextStep">下一步</button>
|
||||
</div>
|
||||
</view>
|
||||
|
||||
<!-- 更新记录 -->
|
||||
<view class="guide" wx:if="{{step === 5}}">
|
||||
<text class="headline">更新记录</text>
|
||||
<text class="p">1. 打开 pages/databaseGuide/databaseGuide.js 文件,定位到 onCounterInc 和 onCounterDec 方法</text>
|
||||
<text class="p">2. 把注释掉的代码解除注释</text>
|
||||
<image class="code-image" src="../../images/code-db-inc-dec.png" mode="aspectFit"></image>
|
||||
<text class="p">3. 点击下方按钮更新计数器</text>
|
||||
<div class="counter">
|
||||
<button class="minus" size="mini" type="default" bindtap="onCounterDec">-</button>
|
||||
<text class="p">{{count}}</text>
|
||||
<button class="plus" size="mini" type="default" bindtap="onCounterInc">+</button>
|
||||
</div>
|
||||
|
||||
<div class="nav">
|
||||
<button class="prev" size="mini" type="default" bindtap="prevStep">上一步</button>
|
||||
<button class="next" size="mini" type="default" bindtap="nextStep">下一步</button>
|
||||
</div>
|
||||
</view>
|
||||
|
||||
<!-- 删除记录 -->
|
||||
<view class="guide" wx:if="{{step === 6}}">
|
||||
<text class="headline">删除记录</text>
|
||||
<text class="p">1. 打开 pages/databaseGuide/databaseGuide.js 文件,定位到 onRemove 方法</text>
|
||||
<text class="p">2. 把注释掉的代码解除注释</text>
|
||||
<image class="code-image" src="../../images/code-db-onRemove.png" mode="aspectFit"></image>
|
||||
<text class="p">3. 点击下方按钮删除计数器</text>
|
||||
<button size="mini" type="default" bindtap="onRemove">删除记录</button>
|
||||
|
||||
<div class="nav">
|
||||
<button class="prev" size="mini" type="default" bindtap="prevStep" wx:if="{{counterId}}">上一步</button>
|
||||
<button class="next" size="mini" type="default" bindtap="nextStep">下一步</button>
|
||||
</div>
|
||||
</view>
|
||||
|
||||
<!-- 结语 -->
|
||||
<view class="guide" wx:if="{{step === 7}}">
|
||||
<text class="headline">完成指引 !</text>
|
||||
<text class="p">恭喜你,至此已完成数据库操作入门基础,可以点击调试器中的链接,查看详尽的数据库文档</text>
|
||||
|
||||
<div class="nav">
|
||||
<button class="prev" size="mini" type="default" bindtap="prevStep">上一步</button>
|
||||
<button class="next" size="mini" type="default" bindtap="goHome">回到首页</button>
|
||||
</div>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
10
pages/databaseGuide/databaseGuide.wxss
Normal file
@@ -0,0 +1,10 @@
|
||||
/* pages/databaseGuide/databaseGuide.wxss */
|
||||
|
||||
@import "../../style/guide.wxss";
|
||||
|
||||
.guide .counter {
|
||||
margin-top: 50rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: space-between;
|
||||
}
|
||||
66
pages/deployFunctions/deployFunctions.js
Normal file
@@ -0,0 +1,66 @@
|
||||
// pages/deployFunctions/deployFunctions.js
|
||||
Page({
|
||||
|
||||
/**
|
||||
* 页面的初始数据
|
||||
*/
|
||||
data: {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面加载
|
||||
*/
|
||||
onLoad: function (options) {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面初次渲染完成
|
||||
*/
|
||||
onReady: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面显示
|
||||
*/
|
||||
onShow: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面隐藏
|
||||
*/
|
||||
onHide: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听页面卸载
|
||||
*/
|
||||
onUnload: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面相关事件处理函数--监听用户下拉动作
|
||||
*/
|
||||
onPullDownRefresh: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 页面上拉触底事件的处理函数
|
||||
*/
|
||||
onReachBottom: function () {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 用户点击右上角分享
|
||||
*/
|
||||
onShareAppMessage: function () {
|
||||
|
||||
}
|
||||
})
|
||||
4
pages/deployFunctions/deployFunctions.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"navigationBarTitleText": "部署云函数",
|
||||
"usingComponents": {}
|
||||
}
|
||||
21
pages/deployFunctions/deployFunctions.wxml
Normal file
@@ -0,0 +1,21 @@
|
||||
<!--pages/deployFunctions/deployFunctions.wxml-->
|
||||
<view class="container">
|
||||
|
||||
<view class="list">
|
||||
<view class="list-item">
|
||||
<text class="black">调用失败</text>
|
||||
</view>
|
||||
<view class="list-item">
|
||||
<text class="request-text">请检查 login 云函数是否已部署</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="guide">
|
||||
<text class="headline">部署 login 云函数</text>
|
||||
<text class="p">1. 确保已通过工具栏云开发入口开通云开发</text>
|
||||
<text class="p">2. 在 cloudfunctions/login 目录上右键上传并部署</text>
|
||||
<text class="p">3. 回到首页,重新点击获取 openid</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
|
||||
7
pages/deployFunctions/deployFunctions.wxss
Normal file
@@ -0,0 +1,7 @@
|
||||
/* pages/deployFunctions/deployFunctions.wxss */
|
||||
|
||||
@import "../../style/guide.wxss";
|
||||
|
||||
.black {
|
||||
color: black;
|
||||
}
|
||||
18
pages/im/im.js
Normal file
@@ -0,0 +1,18 @@
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: {
|
||||
},
|
||||
|
||||
onLoad: function (options) {
|
||||
if (app.globalData.openid) {
|
||||
this.setData({
|
||||
openid: app.globalData.openid
|
||||
})
|
||||
}
|
||||
|
||||
console.group('数据库"实时数据推送"文档')
|
||||
console.log('https://developers.weixin.qq.com/miniprogram/dev/wxcloud/guide/database/realtime.html')
|
||||
console.groupEnd()
|
||||
},
|
||||
})
|
||||
4
pages/im/im.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"navigationBarTitleText": "数据库指引",
|
||||
"usingComponents": {}
|
||||
}
|
||||
21
pages/im/im.wxml
Normal file
@@ -0,0 +1,21 @@
|
||||
<view class="container">
|
||||
<!-- 简介 -->
|
||||
<view class="guide">
|
||||
<text class="headline">即时通信 demo 介绍</text>
|
||||
<text class="p">本 demo 以《聊天室》为例,在此演示如何使用数据库《实时数据推送》能力</text>
|
||||
<text class="p">1. 确保正在使用基础库 2.8.1</text>
|
||||
<text class="p">2. 打开云开发控制台,进入到数据库管理页</text>
|
||||
<text class="p">3. 选择添加集合,集合名设置为 chatroom</text>
|
||||
<text class="p">4. 将集合设置为所有用户可读、仅创建者可写</text>
|
||||
<text class="p">5. 确保IDE增强编译已开启(如无,到工具详情页中开启)</text>
|
||||
<text class="p">6. 点击下方按钮进入聊天室!</text>
|
||||
<text class="p">注1:可使用(菜单栏-工具)多账号调试的功能在工具中模拟多账号登录调试</text>
|
||||
<text class="p">注2:实时数据推送的文档链接已在调试器中打印,可打开查看</text>
|
||||
</view>
|
||||
|
||||
<view class="uploader">
|
||||
<navigator url="./room/room" open-type="navigate" class="uploader-text">
|
||||
<text>进入聊天室</text>
|
||||
</navigator>
|
||||
</view>
|
||||
</view>
|
||||
10
pages/im/im.wxss
Normal file
@@ -0,0 +1,10 @@
|
||||
/* pages/databaseGuide/databaseGuide.wxss */
|
||||
|
||||
@import "../../style/guide.wxss";
|
||||
|
||||
.guide .counter {
|
||||
margin-top: 50rpx;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: space-between;
|
||||
}
|
||||
88
pages/im/room/index.js
Normal file
@@ -0,0 +1,88 @@
|
||||
//index.js
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: {
|
||||
avatarUrl: './user-unlogin.png',
|
||||
userInfo: null,
|
||||
logged: false,
|
||||
takeSession: false,
|
||||
requestResult: '',
|
||||
chatRoomEnvId: 'release-f8415a',
|
||||
chatRoomCollection: 'kecun',
|
||||
chatRoomGroupId: 'tit-bricker',
|
||||
chatRoomGroupName: '深夜话题',
|
||||
|
||||
// functions for used in chatroom components
|
||||
onGetUserInfo: null,
|
||||
getOpenID: null,
|
||||
},
|
||||
|
||||
onLoad: function() {
|
||||
// 获取用户信息
|
||||
wx.getSetting({
|
||||
success: res => {
|
||||
if (res.authSetting['scope.userInfo']) {
|
||||
// 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
|
||||
wx.getUserInfo({
|
||||
success: res => {
|
||||
this.setData({
|
||||
avatarUrl: res.userInfo.avatarUrl,
|
||||
userInfo: res.userInfo
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.setData({
|
||||
onGetUserInfo: this.onGetUserInfo,
|
||||
getOpenID: this.getOpenID,
|
||||
})
|
||||
|
||||
wx.getSystemInfo({
|
||||
success: res => {
|
||||
console.log('system info', res)
|
||||
if (res.safeArea) {
|
||||
const { top, bottom } = res.safeArea
|
||||
this.setData({
|
||||
containerStyle: `padding-top: ${(/ios/i.test(res.system) ? 10 : 20) + top}px; padding-bottom: ${20 + res.windowHeight - bottom}px`,
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
getOpenID: async function() {
|
||||
if (this.openid) {
|
||||
return this.openid
|
||||
}
|
||||
|
||||
const { result } = await wx.cloud.callFunction({
|
||||
name: 'login',
|
||||
config: {
|
||||
env: 'release-f8415a',
|
||||
},
|
||||
})
|
||||
|
||||
return result.openid
|
||||
},
|
||||
|
||||
onGetUserInfo: function(e) {
|
||||
if (!this.logged && e.detail.userInfo) {
|
||||
this.setData({
|
||||
logged: true,
|
||||
avatarUrl: e.detail.userInfo.avatarUrl,
|
||||
userInfo: e.detail.userInfo
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '深夜话题',
|
||||
path: '/pages/index/index',
|
||||
}
|
||||
},
|
||||
})
|
||||
84
pages/im/room/room.js
Normal file
@@ -0,0 +1,84 @@
|
||||
const app = getApp()
|
||||
|
||||
Page({
|
||||
data: {
|
||||
avatarUrl: './user-unlogin.png',
|
||||
userInfo: null,
|
||||
logged: false,
|
||||
takeSession: false,
|
||||
requestResult: '',
|
||||
// chatRoomEnvId: 'release-f8415a',
|
||||
chatRoomCollection: 'chatroom',
|
||||
chatRoomGroupId: 'demo',
|
||||
chatRoomGroupName: '聊天室',
|
||||
|
||||
// functions for used in chatroom components
|
||||
onGetUserInfo: null,
|
||||
getOpenID: null,
|
||||
},
|
||||
|
||||
onLoad: function() {
|
||||
// 获取用户信息
|
||||
wx.getSetting({
|
||||
success: res => {
|
||||
if (res.authSetting['scope.userInfo']) {
|
||||
// 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
|
||||
wx.getUserInfo({
|
||||
success: res => {
|
||||
this.setData({
|
||||
avatarUrl: res.userInfo.avatarUrl,
|
||||
userInfo: res.userInfo
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.setData({
|
||||
onGetUserInfo: this.onGetUserInfo,
|
||||
getOpenID: this.getOpenID,
|
||||
})
|
||||
|
||||
wx.getSystemInfo({
|
||||
success: res => {
|
||||
console.log('system info', res)
|
||||
if (res.safeArea) {
|
||||
const { top, bottom } = res.safeArea
|
||||
this.setData({
|
||||
containerStyle: `padding-top: ${(/ios/i.test(res.system) ? 10 : 20) + top}px; padding-bottom: ${20 + res.windowHeight - bottom}px`,
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
},
|
||||
|
||||
getOpenID: async function() {
|
||||
if (this.openid) {
|
||||
return this.openid
|
||||
}
|
||||
|
||||
const { result } = await wx.cloud.callFunction({
|
||||
name: 'login',
|
||||
})
|
||||
|
||||
return result.openid
|
||||
},
|
||||
|
||||
onGetUserInfo: function(e) {
|
||||
if (!this.logged && e.detail.userInfo) {
|
||||
this.setData({
|
||||
logged: true,
|
||||
avatarUrl: e.detail.userInfo.avatarUrl,
|
||||
userInfo: e.detail.userInfo
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '即时通信 Demo',
|
||||
path: '/pages/im/room/room',
|
||||
}
|
||||
},
|
||||
})
|
||||
5
pages/im/room/room.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"usingComponents": {
|
||||
"chatroom": "/components/chatroom/chatroom"
|
||||
}
|
||||
}
|
||||
12
pages/im/room/room.wxml
Normal file
@@ -0,0 +1,12 @@
|
||||
<view class="container" style="{{containerStyle}}">
|
||||
<chatroom
|
||||
style="width: 100%; height: 100%"
|
||||
envId="{{chatRoomEnvId}}"
|
||||
collection="{{chatRoomCollection}}"
|
||||
groupId="{{chatRoomGroupId}}"
|
||||
groupName="{{chatRoomGroupName}}"
|
||||
userInfo="{{userInfo}}"
|
||||
onGetUserInfo="{{onGetUserInfo}}"
|
||||
getOpenID="{{getOpenID}}"
|
||||
></chatroom>
|
||||
</view>
|
||||
10
pages/im/room/room.wxss
Normal file
@@ -0,0 +1,10 @@
|
||||
.container {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding-top: 80rpx;
|
||||
padding-bottom: 30rpx;
|
||||
}
|
||||
BIN
pages/images/RILI_111.gif
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
pages/images/arrow_down.png
Normal file
|
After Width: | Height: | Size: 381 B |
BIN
pages/images/delet.png
Normal file
|
After Width: | Height: | Size: 856 B |
BIN
pages/images/edit.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
pages/images/headshot.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
pages/images/huoche.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
pages/images/ic_form_hide1.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
pages/images/ic_form_hide2.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
pages/images/ic_list_account.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
pages/images/ic_list_arrow.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
pages/images/ic_list_change.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
pages/images/ic_list_company.png
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
pages/images/ic_list_history.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
pages/images/ic_list_money_back.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
pages/images/ic_list_password.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
pages/images/ic_list_pay_card.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
pages/images/ic_list_pay_discount.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
pages/images/ic_list_pay_wallet.png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
BIN
pages/images/ic_list_price.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
pages/images/ic_oil_pay_credit.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
pages/images/ic_tab_mine_off.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
pages/images/ic_tab_mine_on.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |