Commit 131ebdff by xuyanyang

初始化提交

parents
# Windows
[Dd]esktop.ini
Thumbs.db
$RECYCLE.BIN/
# macOS
.DS_Store
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
# Node.js
node_modules/
# 云开发 quickstart
这是云开发的快速启动指引,其中演示了如何上手使用云开发的三大基础能力:
- 数据库:一个既可在小程序前端操作,也能在云函数中读写的 JSON 文档型数据库
- 文件存储:在小程序前端直接上传/下载云端文件,在云开发控制台可视化管理
- 云函数:在云端运行的代码,微信私有协议天然鉴权,开发者只需编写业务逻辑代码
## 参考文档
- [云开发文档](https://developers.weixin.qq.com/miniprogram/dev/wxcloud/basis/getting-started.html)
{
"permissions": {
"openapi": [
"customerServiceMessage.send"
]
}
}
\ No newline at end of file
const cloud = require('wx-server-sdk')
cloud.init({
// API 调用都保持和云函数当前所在环境一致
env: cloud.DYNAMIC_CURRENT_ENV
})
// 云函数入口函数
exports.main = async (event, context) => {
console.log(event)
const { OPENID } = cloud.getWXContext()
const result = await cloud.openapi.customerServiceMessage.send({
touser: OPENID,
msgtype: 'text',
text: {
content: '收到:' + event.Content,
}
})
console.log(result)
return result
}
{
"name": "callback",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"wx-server-sdk": "~1.5.5"
}
}
\ No newline at end of file
{
"permissions": {
"openapi": []
}
}
const cloud = require('wx-server-sdk')
exports.main = async (event, context) => {
// event.userInfo 是已废弃的保留字段,在此不做展示
// 获取 OPENID 等微信上下文请使用 cloud.getWXContext()
delete event.userInfo
return event
}
{
"name": "echo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"wx-server-sdk": "~1.5.5"
}
}
\ No newline at end of file
{
"permissions": {
"openapi": []
}
}
// 云函数模板
// 部署:在 cloud-functions/login 文件夹右击选择 “上传并部署”
const cloud = require('wx-server-sdk')
// 初始化 cloud
cloud.init({
// API 调用都保持和云函数当前所在环境一致
env: cloud.DYNAMIC_CURRENT_ENV
})
/**
* 这个示例将经自动鉴权过的小程序用户 openid 返回给小程序端
*
* event 参数包含小程序端调用传入的 data
*
*/
exports.main = (event, context) => {
console.log(event)
console.log(context)
// 可执行其他自定义逻辑
// console.log 的内容可以在云开发云函数调用日志查看
// 获取 WX Context (微信调用上下文),包括 OPENID、APPID、及 UNIONID(需满足 UNIONID 获取条件)等信息
const wxContext = cloud.getWXContext()
return {
event,
openid: wxContext.OPENID,
appid: wxContext.APPID,
unionid: wxContext.UNIONID,
env: wxContext.ENV,
}
}
{
"name": "login",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"wx-server-sdk": "~1.5.5"
}
}
{
"permissions": {
"openapi": [
"wxacode.get",
"templateMessage.send",
"templateMessage.addTemplate",
"templateMessage.deleteTemplate",
"templateMessage.getTemplateList",
"templateMessage.getTemplateLibraryById",
"templateMessage.getTemplateLibraryList"
]
}
}
\ No newline at end of file
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init({
// API 调用都保持和云函数当前所在环境一致
env: cloud.DYNAMIC_CURRENT_ENV
})
// 云函数入口函数
exports.main = async (event, context) => {
console.log(event)
switch (event.action) {
case 'sendTemplateMessage': {
return sendTemplateMessage(event)
}
case 'getWXACode': {
return getWXACode(event)
}
case 'getOpenData': {
return getOpenData(event)
}
default: {
return
}
}
}
async function sendTemplateMessage(event) {
const { OPENID } = cloud.getWXContext()
// 接下来将新增模板、发送模板消息、然后删除模板
// 注意:新增模板然后再删除并不是建议的做法,此处只是为了演示,模板 ID 应在添加后保存起来后续使用
const addResult = await cloud.openapi.templateMessage.addTemplate({
id: 'AT0002',
keywordIdList: [3, 4, 5]
})
const templateId = addResult.templateId
const sendResult = await cloud.openapi.templateMessage.send({
touser: OPENID,
templateId,
formId: event.formId,
page: 'pages/openapi/openapi',
data: {
keyword1: {
value: '未名咖啡屋',
},
keyword2: {
value: '2019 年 1 月 1 日',
},
keyword3: {
value: '拿铁',
},
}
})
await cloud.openapi.templateMessage.deleteTemplate({
templateId,
})
return sendResult
}
async function getWXACode(event) {
// 此处将获取永久有效的小程序码,并将其保存在云文件存储中,最后返回云文件 ID 给前端使用
const wxacodeResult = await cloud.openapi.wxacode.get({
path: 'pages/openapi/openapi',
})
const fileExtensionMatches = wxacodeResult.contentType.match(/\/([^\/]+)/)
const fileExtension = (fileExtensionMatches && fileExtensionMatches[1]) || 'jpg'
const uploadResult = await cloud.uploadFile({
// 云文件路径,此处为演示采用一个固定名称
cloudPath: `wxacode_default_openapi_page.${fileExtension}`,
// 要上传的文件内容可直接传入图片 Buffer
fileContent: wxacodeResult.buffer,
})
if (!uploadResult.fileID) {
throw new Error(`upload failed with empty fileID and storage server status code ${uploadResult.statusCode}`)
}
return uploadResult.fileID
}
async function getOpenData(event) {
// 需 wx-server-sdk >= 0.5.0
return cloud.getOpenData({
list: event.openData.list,
})
}
{
"name": "openapi",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"wx-server-sdk": "~1.5.5"
}
}
//app.js
App({
onLaunch: function () {
if (!wx.cloud) {
console.error('请使用 2.2.3 或以上的基础库以使用云能力')
} else {
wx.cloud.init({
// env 参数说明:
// env 参数决定接下来小程序发起的云开发调用(wx.cloud.xxx)会默认请求到哪个云环境的资源
// 此处请填入环境 ID, 环境 ID 可打开云控制台查看
// 如不填则使用默认环境(第一个创建的环境)
// env: 'my-env-id',
traceUser: true,
})
}
this.globalData = {}
globalData: ({
userInfo: null,
navHeight: 0
})
// 获取手机系统信息
wx.getSystemInfo({
success: res => {
//导航高度
this.globalData.navHeight = res.statusBarHeight + 42;
}, fail(err) {
console.log(err);
}
})
var that = this
wx.getSystemInfo({
success: function (res) {
that.globalData.platform = res.platform
let totalTopHeight = 68
if (res.model.indexOf('iPhone X') !== -1) {
totalTopHeight = 88
} else if (res.model.indexOf('iPhone') !== -1) {
totalTopHeight = 64
}
that.globalData.statusBarHeight = res.statusBarHeight
that.globalData.titleBarHeight = totalTopHeight - res.statusBarHeight
},
failure() {
that.globalData.statusBarHeight = 0
that.globalData.titleBarHeight = 0
}
})
}
})
{
"pages": [
"pages/user/user",
"pages/index/index",
"pages/login/login",
"pages/header/header",
"pages/helper/helper",
"pages/summary/summary"
],
"window": {
"backgroundColor": "#F6F6F6",
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#F6F6F6",
"navigationBarTitleText": "111",
"navigationBarTextStyle": "black",
"navigationStyle": "custom"
},
"tabBar": {
"color": "#a9b7b7",
"selectedColor": "#11cd6e",
"borderStyle": "black",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页"
},
{
"pagePath": "pages/index/index",
"text": "首页"
},
{
"pagePath": "pages/helper/helper",
"text": "小地助手"
},
{
"pagePath": "pages/index/index",
"text": "首页"
},
{
"pagePath": "pages/user/user",
"text": "我的"
}
]
},
"sitemapLocation": "sitemap.json",
"style": "v2"
}
\ No newline at end of file
/**app.wxss**/
page{
height: 100%;
background: #fff;
color: #333;
display: flex;
flex-direction: column;
font: normal 30rpx/1.68 -apple-system-font, 'Helvetica Neue', Helvetica, 'Microsoft YaHei', sans-serif;
}
.container {
flex: 1;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
/**app.wxss**/
.container {
display: flex;
flex-direction: column;
align-items: center;
box-sizing: border-box;
}
button {
background: initial;
}
button:focus{
outline: 0;
}
button::after{
border: none;
}
page {
background: #f6f6f6;
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.userinfo, .uploader, .tunnel {
margin-top: 40rpx;
height: 140rpx;
width: 100%;
background: #fff;
border: 1px solid rgba(0, 0, 0, 0.1);
border-left: none;
border-right: none;
display: flex;
flex-direction: row;
align-items: center;
transition: all 300ms ease;
}
.userinfo-avatar {
width: 100rpx;
height: 100rpx;
margin: 20rpx;
border-radius: 50%;
background-size: cover;
background-color: white;
}
.userinfo-avatar:after {
border: none;
}
.userinfo-nickname {
font-size: 32rpx;
color: #007aff;
background-color: white;
background-size: cover;
}
.userinfo-nickname::after {
border: none;
}
.uploader, .tunnel {
height: auto;
padding: 0 0 0 40rpx;
flex-direction: column;
align-items: flex-start;
box-sizing: border-box;
}
.uploader-text, .tunnel-text {
width: 100%;
line-height: 52px;
font-size: 34rpx;
color: #007aff;
}
.uploader-container {
width: 100%;
height: 400rpx;
padding: 20rpx 20rpx 20rpx 0;
display: flex;
align-content: center;
justify-content: center;
box-sizing: border-box;
border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.uploader-image {
width: 100%;
height: 360rpx;
}
.tunnel {
padding: 0 0 0 40rpx;
}
.tunnel-text {
position: relative;
color: #222;
display: flex;
flex-direction: row;
align-content: center;
justify-content: space-between;
box-sizing: border-box;
border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.tunnel-text:first-child {
border-top: none;
}
.tunnel-switch {
position: absolute;
right: 20rpx;
top: -2rpx;
}
.disable {
color: #888;
}
.service {
position: fixed;
right: 40rpx;
bottom: 40rpx;
width: 140rpx;
height: 140rpx;
border-radius: 50%;
background: linear-gradient(#007aff, #0063ce);
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.3);
display: flex;
align-content: center;
justify-content: center;
transition: all 300ms ease;
}
.service-button {
position: absolute;
top: 40rpx;
}
.service:active {
box-shadow: none;
}
.request-text {
padding: 20rpx 0;
font-size: 24rpx;
line-height: 36rpx;
word-break: break-all;
}
/* 头部公用的样式*/
.nav{
width: 100%;
overflow: hidden;
position: relative;
top: 0;
left: 0;
z-index: 10;
}
.nav-title{
width: 100%;
height: 45px;
line-height: 45px;
text-align: center;
position: absolute;
bottom: 0;
left: 0;
z-index: 10;
font-family:PingFang-SC-Medium;
font-size:36rpx;
letter-spacing:2px;
}
.nav .back{
width: 22px;
height: 22px;
position: absolute;
bottom: 0;
left: 0;
padding: 10px 15px;
}
.bg-white{
background-color: #ffffff;
}
.bg-gray{
background-color: #f7f7f7;
}
.overflow{
overflow: auto;
}
.hidden{
overflow: hidden;
}
.custom_nav {
width: 100%;
background: #fff;
}
.custom_nav_box {
position: fixed;
width: 100%;
background: #fff;
}
.custom_nav_bar{
position: relative;
}
.custom_nav_box .nav_title {
font-size: 34rpx;
color: #000;
text-align: center;
position: absolute;
max-width: 360rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
font-weight: 600;
}
.custom_nav_box .custom_nav_icon {
position: absolute;
border: .5rpx solid rgba(0, 0, 0, .1);
border-radius: 50%;
display: flex;
padding: 0 10rpx
}
.custom_nav_icon .gobank {
background: url('https://www.easyicon.net/api/resizeApi.php?id=1225467&size=128') no-repeat center center;
background-size: 60%;
padding:0 5px;
margin: 4px 0;
}
.custom_nav_icon .home {
background: url('https://www.easyicon.net/api/resizeApi.php?id=1223065&size=128') no-repeat center center;
background-size: 60%;
padding:0 5px;
margin: 4px 0;
border-left: 1px solid rgba(0, 0, 0, .1)
}
.nav{
width: 100%;
overflow: hidden;
position: relative;
top: 0;
left: 0;
z-index: 10;
}
.nav-title{
width: 100%;
height: 45px;
line-height: 45px;
text-align: center;
position: absolute;
bottom: 0;
left: 0;
z-index: 10;
font-family:PingFang-SC-Medium;
font-size:36rpx;
letter-spacing:2px;
}
.nav .back{
width: 22px;
height: 22px;
position: absolute;
bottom: 0;
left: 0;
padding: 10px 15px;
}
.bg-white{
background-color: #ffffff;
}
.bg-gray{
background-color: #f7f7f7;
}
.overflow{
overflow: auto;
}
.hidden{
overflow: hidden;
}
/* end */
\ No newline at end of file
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
},
})
{
"component": true,
"usingComponents": {}
}
\ No newline at end of file
<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>
.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;
}
const app = getApp()
Component({
properties: {
// 这里定义了innerText属性,属性值可以在组件使用时指定
innerTitle: {
type: String,
value: '头部标题'
},
isShowBack: {
type: String,
value: "true"
},
isShowPop:{
type: String,
value: "true"
}
},
data: {
// 这里是一些组件内部数据
someData: {
statusBarHeight: app.globalData.statusBarHeight,
titleBarHeight: app.globalData.titleBarHeight
}
},
onLoad: function (options) {
this.setData({
navH: App.globalData.navHeight
})
},
methods: {
// 这里是一个自定义方法
goback: function () {
wx.navigateBack({
delta: 1,
})
},
goUser:function(){
wx.navigateBack({
delta: 1,
})
}
}
})
\ No newline at end of file
{
"component": true
}
\ No newline at end of file
<!--template.wxml-->
<!-- 这是自定义组件的内部WXML结构 -->
<view style="padding-top:{{someData.statusBarHeight+someData.titleBarHeight}}px">
<view class="hh-header">
<view class="status-bar" style="height:{{someData.statusBarHeight}}px"></view>
<view class="title-bar" style="height:{{someData.titleBarHeight}}px">
<view wx:if="{{isShowBack=='true'}}" class='hh-nav-back'>
<view wx:if="{{isShowPop=='true'}}" class='back ico-back' bindtap='goback'></view>
<view wx:if="{{isShowPop=='false'}}" class='back ico-pop ' bindtap='goback'>
<!-- <image src='../../images/user.png' mode='aspectFit' class=''></image> -->
</view>
</view>
<view wx:if="{{isShowBack=='false'}}" class='hh-nav-back'></view>
<view class="hh-title">{{innerTitle}}</view>
<view class="hh-nav-right"></view>
</view>
</view>
</view>
<slot></slot>
\ No newline at end of file
.ico-back{
width: 44rpx;
height: 36rpx;
background-size: contain;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDY3IDc5LjE1Nzc0NywgMjAxNS8wMy8zMC0yMzo0MDo0MiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjAwRjFBMThDOEU1NDExRThCQUMxRTFBRUNDRDNCMkJEIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjAwRjFBMThEOEU1NDExRThCQUMxRTFBRUNDRDNCMkJEIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MDBGMUExOEE4RTU0MTFFOEJBQzFFMUFFQ0NEM0IyQkQiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MDBGMUExOEI4RTU0MTFFOEJBQzFFMUFFQ0NEM0IyQkQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7a0EjNAAAA80lEQVR42sTYOw7DIAwGYNxuPXHnTtygvUAuWalyE6WRMlBj7N/GEkOiCD4B4eHCzEUq3ljruPMe9fcstxcJOmGOqNNADcwR+SABs6SDOphrKqiHSZ3UGkwaSItJAY1gwkGjmFCQBRMGsmJCQB4MHOTFQEEIDAyEwkBASIwGRIrFr/XBZy03InpbQFJcFHW8Gu+2nnmUiFAM2daLzz/DVtHtaSc1DIX87SEo9MLoRkVsHS5U1OZqRkUeP0yo6APaMCrjCDuEyjrkq1GZ1yAVKvui2EXNuEqLqFnJBgk1LR3TQi08OWF1RqmyH8SAtB0yvgIMAGA41d9Fo4AZAAAAAElFTkSuQmCC);
background-repeat: no-repeat;
background-position-x: 20rpx;
}
.ico-pop{width: 36rpx;
height: 36rpx;
margin-left: 22rpx; background-image: url(data:image/png;base64,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);
background-size: 100%;
}
.hh-header {
position: fixed;
top: 0;
width: 100%;
background-color: #6cb6f8;
z-index: 99;
}
.hh-title{
font-size: 38rpx;
text-align: center;
color: #fff;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.title-bar {
display: flex;
justify-content: space-between;
align-items: center;
}
.hh-nav-right{
width: 116px;
}
.hh-nav-back{
width: 116px;
}
\ No newline at end of file
// miniprogram/pages/helper/helper.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
\ No newline at end of file
{
"usingComponents": {}
}
\ No newline at end of file
<!--miniprogram/pages/helper/helper.wxml-->
<text>miniprogram/pages/helper/helper.wxml</text>
/* miniprogram/pages/helper/helper.wxss */
\ No newline at end of file
// miniprogram/pages/index/index.js
Page({
/**
* 页面的初始数据
*/
data: {
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
\ No newline at end of file
{
"usingComponents": {}
}
\ No newline at end of file
<!--miniprogram/pages/index/index.wxml-->
<text>miniprogram/pages/index/index.wxml</text>
/* miniprogram/pages/index/index.wxss */
\ No newline at end of file
// miniprogram/pages/login/login.js
const App = getApp();
Page({
onLoad: function (options) { //全部 减去 头部
this.setData({
navH: App.globalData.navHeight
})
},
data: {
title: '登录',
// 验证手机号
loginPhone: false,
loginPwd: false,
loveChange: true,
hongyzphone: '',
// 验证码是否正确
zhengLove: true,
huoLove: '',
getText2: '获取验证码',
},
// 手机验证
lovePhone: function (e) {
let phone = e.detail.value;
this.setData({ hongyzphone: phone })
if (!(/^1[34578]\d{9}$/.test(phone))) {
this.setData({
lovePhone: false
})
console.log(phone.length)
if (phone.length >= 11) {
wx.showToast({
title: '手机号有误',
icon: 'none',
duration: 1000
})
}
} else {
this.setData({
lovePhone: true
})
}
},
// 验证码输入
yanLoveInput: function (e) {
let that = this;
let yanLove = e.detail.value;
let huoLove = this.data.huoLove;
that.setData({
yanLove: yanLove,
zhengLove: false,
})
if (yanLove.length >= 4) {
if (yanLove == huoLove) {
that.setData({
zhengLove: true,
})
} else {
that.setData({
zhengLove: false,
})
wx.showModal({
content: '输入验证码有误',
showCancel: false,
success: function (res) { }
})
}
}
},
// 验证码按钮
yanLoveBtn: function () {
let loveChange = this.data.loveChange;
console.log(loveChange)
let lovePhone = this.data.lovePhone;
console.log(lovePhone)
let phone = this.data.hongyzphone;
console.log(phone)
let n = 59;
let that = this;
if (!lovePhone) {
wx.showToast({
title: '手机号有误',
icon: 'success',
duration: 1000
})
} else {
if (loveChange) {
this.setData({
loveChange: false
})
let lovetime = setInterval(function () {
let str = '(' + n + ')' + '重新获取'
that.setData({
getText2: str
})
if (n <= 0) {
that.setData({
loveChange: true,
getText2: '重新获取'
})
clearInterval(lovetime);
}
n--;
}, 1000);
//获取验证码接口写在这里
//例子 并非真实接口
app.agriknow.sendMsg(phone).then(res => {
console.log('请求获取验证码.res =>', res)
}).catch(err => {
console.log(err)
})
}
}
},
//form表单提交
formSubmit(e) {
let val = e.detail.value
console.log('val', val)
var phone = val.phone //电话
var phoneCode = val.phoneCode //验证码
wx.navigateTo({
url: '../user/user',
})
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh: function () {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom: function () {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage: function () {
}
})
\ No newline at end of file
{
"usingComponents": {
"component-topnav": "/pages/header/header"
}
}
\ No newline at end of file
<view class="login-wrap">
<component-topnav inner-title="{{title}}" inner-icon="{{icon}}" is-show-back="true" is-show-pop="true"></component-topnav> <!--//显示返回按钮 -->
<!-- 中间 -->
<scroll-view class=' overflow' style='height:calc(100vh - {{navH}}px)' scroll-y >
<!-- 绑定手机号 -->
<view class='content'>
<form bindsubmit="formSubmit">
<view class='phone-box'>
<text class='phone'>手机号</text>
<input name="phone" type='number' placeholder="请输入手机号" maxlength='11' name="phone" class='number' bindinput='lovePhone' />
</view>
<view class='phone-box'>
<text class='phone'>验证码</text>
<input name="phoneCode" placeholder="请输入验证码" class='number' placeholder-style='color:#bbb' bindinput="yanLoveInput" />
<view bindtap='yanLoveBtn' class='getNum'>{{getText2}}</view>
</view>
<button formType="submit" class='submit'>绑定</button>
</form>
</view>
<image src='/images/login-bj_02.jpg' class="login-btm"></image>
</scroll-view>
</view>
\ No newline at end of file
/* miniprogram/pages/login/login.wxss */
.content {
width: 100%;
height: auto;
padding: 0 50rpx;
box-sizing: border-box;
}
.phone-box {
width: 100%;
height: 89rpx;
border-bottom: 1rpx solid #efefef;
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
}
.phone {
color: #333;
margin-right: 60rpx;
font-size: 28rpx;
}
.number {
color: #333;
font-size: 28rpx;
width: 200rpx;
}
.getNum {
width:210rpx;
height:48rpx;
background:#2995fa;
border-radius:8rpx;
font-size:28rpx;
font-family:PingFang-SC-Medium;
color:rgba(255, 255, 255, 1);
line-height:48rpx;
margin-right:36rpx;
text-align:center;
}
.submit {
padding: 10px 24px;
width: 480rpx;
height: 80rpx;
background: #2995fa;
border-radius: 8rpx;
margin-top: 80rpx;
color: #fff;
font-size: 32rpx;
}
.login-wrap{background: #fff}
.login-btm{position: absolute;background-size:100%;bottom: 0;height: 30%;width: 100%;
}
\ No newline at end of file
const App = getApp();
{
}
Page({
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) { //全部 减去 头部
this.setData({
navH: App.globalData.navHeight
})
},
data: {
motto: 'Hello World',
userInfo: {},
title: '年度总结',
scrollindex: 0, //当前页面的索引值
totalnum: 4, //总共页面数
starty: 0, //开始的位置x
endy: 0, //结束的位置y
critical: 100, //触发翻页的临界值
margintop: 0, //滑动下拉距离
},
scrollTouchstart: function (e) {
let py = e.touches[0].pageY;
this.setData({
starty: py
})
},
scrollTouchmove: function (e) {
let py = e.touches[0].pageY;
let d = this.data;
this.setData({
endy: py,
})
if (py - d.starty < 100 && py - d.starty > -100) {
this.setData({
margintop: py - d.starty
})
}
},
scrollTouchend: function (e) {
let d = this.data;
if (d.endy - d.starty > 100 && d.scrollindex > 0) {
this.setData({
scrollindex: d.scrollindex - 1
})
} else if (d.endy - d.starty < -100 && d.scrollindex < this.data.totalnum - 1) {
this.setData({
scrollindex: d.scrollindex + 1
})
}
this.setData({
starty: 0,
endy: 0,
margintop: 0
})
},
})
\ No newline at end of file
{
"usingComponents": {
"component-topnav": "/pages/header/header"
}
}
\ No newline at end of file
<view>
<component-topnav inner-title="{{title}}" inner-icon="{{icon}}" is-show-back="true" is-show-pop="false"></component-topnav> <!--//显示返回按钮 -->
<!-- 中间 -->
<scroll-view class='bg-gray overflow' style='height:calc(100vh - {{navH}}px)' scroll-y >
<view class="container1 container-fill">
<view class="scroll-fullpage" bindtouchstart="scrollTouchstart" bindtouchmove="scrollTouchmove" bindtouchend="scrollTouchend" style="transform:translateY(-{{scrollindex*100}}%);margin-top: {{margintop}}px">
<view class="section section01 {{scrollindex==0?'active':''}}" style="background: #3399FF;">
<image src="/images/ndzj_01.jpg"></image>
</view>
<view class="section section02 {{scrollindex==1?'active':''}}" style="background: #00CC66;">
<image src="/images/ndzj_02.jpg"></image>
</view>
<view class="section section03 {{scrollindex==2?'active':''}}" style="background: #33CCCC;">
<image src="/images/ndzj_03.jpg"></image>
</view>
<view class="section section04 {{scrollindex==3?'active':''}}" style="background: #6699FF;">
<image src="/images/ndzj_04.jpg"></image>
</view>
<!-- <view class="section section05 {{scrollindex==4?'active':''}}" style="background: #9966FF;">
<text class="section-maintitle">测试测试测试5</text>
<text class="section-subtitle">cinoLiu--5</text>
</view> -->
</view>
</view>
</scroll-view>
</view>
\ No newline at end of file
.section image{height: 100%; width: 100%}
.container-fill{
height: 100%;
overflow: hidden;
}
.scroll-fullpage{
height: 100%;
transition: all 0.3s;
}
.section{
height: 100%;
}
.section-maintitle{
display: block;
text-align: center;
font-size: 50rpx;
color: #fff;
font-weight: bold;
letter-spacing: 10rpx;
padding-top: 140rpx;
}
.section-subtitle{
display: block;
text-align: center;
font-size: 40rpx;
color: #fff;
font-weight: bold;
letter-spacing: 10rpx;
}
.active .section-maintitle,
.active .section-subtitle{
animation: mymove 0.8s;
}
@keyframes mymove{
from {
transform: translateY(-400rpx) scale(0.5) rotateY(90deg);
}
to {
transform: translateY(0) scale(1) rotateY(0);
}
}
\ No newline at end of file
// miniprogram/pages/user/user.js
const App = getApp();
Page({
data: {
title: '个人中心',
},
joinVip: function () { //加入VIP
wx.navigateTo({
url: '../summary/summary',
})
},
shezhi:function(){
wx.navigateTo({
url: '../login/login',
})
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
this.setData({
navH: App.globalData.navHeight
})
}
})
{
"usingComponents": {
"component-topnav": "/pages/header/header"
}
}
\ No newline at end of file
<view>
<component-topnav inner-title="{{title}}" inner-icon="{{icon}}" is-show-back="false"></component-topnav> <!--//显示返回按钮 -->
<!-- 中间 -->
<scroll-view class='bg-gray overflow' style='height:calc(100vh - {{navH}}px)' scroll-y >
<!-- 开始 -->
<!--pages/my/my.wxml-->
<form reportSubmit bindsubmit="submitFormId">
<view class="header">
<view class="user" hoverClass="none">
<view class="user_box">
<view catchtap="previewImage" class="logo">
<image src="{{userInfo.avatarUrl}}"></image>
<view class="cu-tag badge {{male==1?'icon-male bg-blue':'icon-female bg-pink'}}"></view>
</view>
<block wx:if="{{vip}}">
<view class="user_info">
<view class="user_name">
<text>{{userInfo.nickName}}</text>
<image src="/images/main/vip.png"></image>
</view>
<view class="vip_expires">vip到期时间:{{vip_time}},<button class="joinVip" bindtap='joinVip'>马上续费</button></view>
</view>
</block>
<block wx:else>
<view class="user_info">
<view class="user_name">
<text>{{userInfo.nickName}}</text>
</view>
<view class="vip_expires" >小珊珊
</view>
<view class="vip_iphone"> 183****2312</view>
</view>
</block>
</view>
</view>
<view class="vip_shezhi">
<image src='/images/icon_03.png' class="img" bindtap='shezhi'></image></view>
<view class="vip_title" bindtap='joinVip'>
<button class=" item item-buttom">
<image src='/images/icon_15.png' style="width:35rpx; height:35rpx;padding-right:8rpx;"></image>
<text>年度总结</text>
</button>
</view>
</view>
<!-- 功能列表 -->
<view class="nav">
<view bindtap="openPage" class="item" data-url="/pages/my_course/my_course" formType="submit" hoverClass="none">
<view class='wallet'>
<!-- <text class='icon-news icon'></text> -->
<image src='/images/icon_19.png' class="img" bindtap='shezhi'></image>
<text decode="{{true}}" space="{{true}}">&nbsp;&nbsp;</text>
<text>单位名称</text>
<text></text>
</view>
<view class="icon">
<text class='icon-right'></text>
</view>
</view>
<view bindtap="openPage" class="item" data-url="/pages/collect/collect" formType="submit" hoverClass="none">
<view class='wallet'>
<!-- <text class='icon-favor icon'></text> -->
<image src='/images/icon_22.png' class="img" bindtap='shezhi'></image>
<text decode="{{true}}" space="{{true}}">&nbsp;&nbsp;</text>
<text>所处级别</text>
</view>
<view class="icon">
<text class='icon-right'></text>
</view>
</view>
<view bindtap="openPage" class="item" data-url="/pages/purchase_history/purchase_history" formType="submit" hoverClass="none">
<view class='wallet'>
<!-- <text class='icon-form icon'></text> -->
<image src='/images/icon_24.png' class="img" bindtap='shezhi'></image>
<text decode="{{true}}" space="{{true}}">&nbsp;&nbsp;</text>
<text>技术级别</text>
</view>
<view class="icon">
<text class='icon-right'></text>
</view>
</view>
<view bindtap="chooseGeren" class="item">
<view class='wallet'>
<!-- <text class='icon-location icon'></text> -->
<image src='/images/icon_26.png' class="img" bindtap='shezhi'></image>
<text decode="{{true}}" space="{{true}}">&nbsp;&nbsp;</text>
<text>任职日期</text>
</view>
<view class="icon">
<text class='icon-right'></text>
</view>
</view>
<view bindtap="openPage" class="item" data-url="/pages/about/about" formType="submit" hoverClass="none">
<view class='wallet'>
<!-- <text class='icon-info icon'></text> -->
<image src='/images/icon_28.png' class="img" bindtap='shezhi'></image>
<text decode="{{true}}" space="{{true}}">&nbsp;&nbsp;</text>
<text>技术职位</text>
</view>
<view class="icon">
<text class='icon-right'></text>
</view>
</view>
<view class="item" bindtap='changeView'>
<view class='wallet'>
<!-- <text class='icon-settings icon'></text> -->
<image src='/images/icon_30.png' class="img" bindtap='shezhi'></image>
<text decode="{{true}}" space="{{true}}">&nbsp;&nbsp;</text>
<text>政治面貌</text>
</view>
<view class="icon">
<text class='icon-right'></text>
</view>
</view>
<view class="item" formType="submit" hoverClass="none" openType="contact">
<view class='wallet'>
<image src='/images/icon_32.png' class="img" bindtap='shezhi'></image>
<!-- <text class='icon-service icon'></text> -->
<text decode="{{true}}" space="{{true}}">&nbsp;&nbsp;</text>
<text>邮箱</text>
</view>
<view class="icon">
<text class='icon-right'></text>
</view>
</view>
</view>
</form>
<!-- end-->
</scroll-view>
</view>
\ No newline at end of file
{
"desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
"rules": [{
"action": "allow",
"page": "*"
}]
}
\ No newline at end of file
page {
background: #f6f6f6;
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.list {
margin-top: 40rpx;
height: auto;
width: 100%;
background: #fff;
padding: 0 40rpx;
border: 1px solid rgba(0, 0, 0, 0.1);
border-left: none;
border-right: none;
transition: all 300ms ease;
display: flex;
flex-direction: column;
align-items: stretch;
box-sizing: border-box;
}
.list-item {
width: 100%;
padding: 0;
line-height: 104rpx;
font-size: 34rpx;
color: #007aff;
border-top: 1px solid rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: row;
align-content: center;
justify-content: space-between;
box-sizing: border-box;
}
.list-item:first-child {
border-top: none;
}
.list-item image {
max-width: 100%;
max-height: 20vh;
margin: 20rpx 0;
}
.request-text {
color: #222;
padding: 20rpx 0;
font-size: 24rpx;
line-height: 36rpx;
word-break: break-all;
}
.guide {
width: 100%;
padding: 40rpx;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
.guide .headline {
font-size: 34rpx;
font-weight: bold;
color: #555;
line-height: 40rpx;
}
.guide .p {
margin-top: 20rpx;
font-size: 28rpx;
line-height: 36rpx;
color: #666;
}
.guide .code {
margin-top: 20rpx;
font-size: 28rpx;
line-height: 36rpx;
color: #666;
background: white;
white-space: pre;
}
.guide .code-dark {
margin-top: 20rpx;
background: rgba(0, 0, 0, 0.8);
padding: 20rpx;
font-size: 28rpx;
line-height: 36rpx;
border-radius: 6rpx;
color: #fff;
white-space: pre
}
.guide image {
max-width: 100%;
}
.guide .image1 {
margin-top: 20rpx;
max-width: 100%;
width: 356px;
height: 47px;
}
.guide .image2 {
margin-top: 20rpx;
width: 264px;
height: 100px;
}
.guide .flat-image {
height: 100px;
}
.guide .code-image {
max-width: 100%;
}
.guide .copyBtn {
width: 180rpx;
font-size: 20rpx;
margin-top: 16rpx;
margin-left: 0;
}
.guide .nav {
margin-top: 50rpx;
display: flex;
flex-direction: row;
align-content: space-between;
}
.guide .nav .prev {
margin-left: unset;
}
.guide .nav .next {
margin-right: unset;
}
{
"miniprogramRoot": "miniprogram/",
"cloudfunctionRoot": "cloudfunctions/",
"setting": {
"urlCheck": true,
"es6": true,
"postcss": true,
"minified": true,
"newFeature": true,
"enhance": true
},
"appid": "wxf63104bcd784e195",
"projectname": "weixinDemo",
"libVersion": "2.8.1",
"simulatorType": "wechat",
"simulatorPluginLibVersion": {},
"compileType": "miniprogram",
"condition": {
"search": {
"current": -1,
"list": []
},
"conversation": {
"current": -1,
"list": []
},
"plugin": {
"current": -1,
"list": []
},
"game": {
"list": []
},
"miniprogram": {
"current": 0,
"list": [
{
"id": -1,
"name": "db guide",
"pathName": "pages/databaseGuide/databaseGuide"
}
]
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment