@@ -0,0 +1,12 @@ | |||
const {request} = require("../request/index") | |||
/** | |||
* 申请志愿者服务 | |||
* @param {*} data | |||
*/ | |||
export const applyVolunteer = function (data) { | |||
return request({ | |||
url: '/westreamVolunteer/add', | |||
method: 'POST', | |||
data | |||
}) | |||
} |
@@ -0,0 +1,295 @@ | |||
// package_A/pages/volunteer-page/index.js | |||
import { getOssAuth } from '../../../api/uploadOss.js' | |||
import { Base64 } from 'js-base64' | |||
const crypto = require('crypto-js') | |||
import { applyVolunteer } from '../../../api/volunteer-service.js' | |||
import {isPositiveInteger, isNoCharacters} from '../../../utils/check.js' | |||
Page({ | |||
/** | |||
* 页面的初始数据 | |||
*/ | |||
data: { | |||
checkAgree: false, // 是否勾选用户协议 | |||
form: {}, | |||
ossForm: {}, | |||
imagePreviewList: [], // 上传图片预览列表 | |||
imageList: [], // 图片列表 | |||
// 表单验证 | |||
formRules: { | |||
activityNum: { | |||
validator: function (value) { | |||
return value && isPositiveInteger(value) && value<= 1000; | |||
}, | |||
warning: false | |||
}, | |||
activityDate: { | |||
validator: function (value) { | |||
return value; | |||
}, | |||
warning: false | |||
}, | |||
activityPoints: { | |||
validator: function (value) { | |||
return value && isPositiveInteger(value) && value<= 1000; | |||
}, | |||
warning: false | |||
}, | |||
companyName: { | |||
validator: function (value) { | |||
return value && isNoCharacters(value); | |||
}, | |||
warning: false | |||
}, | |||
contactName: { | |||
validator: function (value) { | |||
return value && isNoCharacters(value); | |||
}, | |||
warning: false | |||
}, | |||
contactPhone: { | |||
validator: function (value) { | |||
return value && isPositiveInteger(value); | |||
}, | |||
warning: false | |||
}, | |||
imageList: { | |||
validator: function (value) { | |||
return value.length != 0; | |||
}, | |||
warning: false | |||
} | |||
} | |||
}, | |||
/** | |||
* 生命周期函数--监听页面显示 | |||
*/ | |||
onShow: function () { | |||
this.getOssAuthForm() | |||
const openid = wx.getStorageSync('openid') | |||
let form = this.data.form | |||
form.openid = openid | |||
this.setData({form}) | |||
}, | |||
/* 获取图片上传鉴权 */ | |||
getOssAuthForm() { | |||
let that = this | |||
getOssAuth().then((res) => { | |||
let client = { | |||
region: 'oss-cn-shanghai', | |||
secure: true, | |||
accessKeyId: res.accessKeyId, | |||
accessKeySecret: res.accessKeySecret, | |||
securityToken: res.securityToken, | |||
bucket: 'ta-tech-image' | |||
} | |||
// 计算签名 | |||
function computeSignature(accessKeySecret, canonicalString) { | |||
return crypto.enc.Base64.stringify(crypto.HmacSHA1(canonicalString, accessKeySecret)); | |||
} | |||
const date = new Date(); | |||
date.setHours(date.getHours() + 1); | |||
const policyText = { | |||
expiration: date.toISOString(), // 设置policy过期时间。 | |||
conditions: [ | |||
// 限制上传大小。 | |||
["content-length-range", 0, 1024 * 1024 * 1024], | |||
], | |||
}; | |||
// 获取签名 | |||
const policy = Base64.encode(JSON.stringify(policyText)) // policy必须为base64的string。 | |||
const signature = computeSignature(client.accessKeySecret, policy) | |||
let ossForm = that.data.ossForm | |||
ossForm = { | |||
OSSAccessKeyId: client.accessKeyId, | |||
signature, | |||
policy, | |||
SecurityToken: client.securityToken | |||
} | |||
that.setData({ | |||
ossForm | |||
}) | |||
}) | |||
}, | |||
/* 上传图片 */ | |||
uploadImage(){ | |||
wx.chooseMedia({ | |||
count: 5 - this.data.imageList.length, // 最多可以选择的图片张数,默认9 | |||
mediaType: ['image'], // 图片 | |||
sizeType: ['original'], // original 原图,compressed 压缩图,默认二者都有 | |||
sourceType: ['album', 'camera'], // album 从相册选图,camera 使用相机,默认二者都有 | |||
success:(res) =>{ | |||
const list = res.tempFiles.map((item)=> { | |||
return item.tempFilePath | |||
}) | |||
// success | |||
let imagePreviewList = this.data.imagePreviewList.concat(list) | |||
let imageList = this.data.imageList.concat(list); | |||
this.setData({ imageList, imagePreviewList }) | |||
this.validate('imageList') | |||
}, | |||
fail: (e) => { | |||
console.log(e); | |||
} | |||
}) | |||
}, | |||
// 删除图片 | |||
deleteImage(e) { | |||
let index = this.getCurrentData(e); | |||
let imageList = this.data.imageList | |||
imageList.splice(index, 1) | |||
let imagePreviewList = this.data.imagePreviewList | |||
imagePreviewList.splice(index, 1) | |||
this.setData({ imageList, imagePreviewList }) | |||
this.validate('imageList') | |||
}, | |||
getCurrentData(e) { | |||
return e.currentTarget.dataset.current; | |||
}, | |||
validate(name) { | |||
let formRules = this.data.formRules; | |||
let validator = formRules[name].validator | |||
let result | |||
if(name === 'imageList') { | |||
result = validator ? !validator(this.data.imageList) : false | |||
} else { | |||
result = validator ? !validator(this.data.form[name]) : false; | |||
} | |||
formRules[name].warning = result | |||
this.setData({formRules}) | |||
return result | |||
}, | |||
// 表单验证 | |||
validateForm() { | |||
return new Promise((resolve, reject) => { | |||
try { | |||
let formRules = this.data.formRules; | |||
let result = false; | |||
for (let key in formRules) { | |||
let temp = this.validate(key) | |||
if (temp) { | |||
result = temp | |||
} | |||
} | |||
resolve(!result) | |||
} catch (e) { | |||
reject(e) | |||
} | |||
}) | |||
}, | |||
// 输入 | |||
bindValue(e) { | |||
let name = e.currentTarget.dataset.name; | |||
let form = this.data.form; | |||
form[name] = e.detail.value; | |||
this.setData({ | |||
form, | |||
}) | |||
this.validate(name) | |||
}, | |||
// 选择时间 | |||
selectDate(e) { | |||
let form = this.data.form | |||
form.activityDate = e.detail.value | |||
this.setData({form}) | |||
}, | |||
/* 表单上传 */ | |||
submit(){ | |||
if(this.data.checkAgree) { | |||
this.validateForm().then(res => { | |||
let ossForm = this.data.ossForm | |||
let temp = [] | |||
if (this.data.imageList.length > 0) { | |||
wx.showLoading({title:"上传中",mask:true}) | |||
temp = this.data.imageList.map(item => { | |||
// 设置文件上传路径 | |||
const randomString = Math.random().toString(36).slice(2) | |||
const timestamp = new Date().getTime() | |||
const key = `imagedir/${randomString}_${timestamp}.png` | |||
// 上传图片 | |||
return new Promise((resolve, reject)=> { | |||
wx.uploadFile({ | |||
url: 'https://ta-tech-image.oss-cn-shanghai.aliyuncs.com', | |||
filePath: item, | |||
name: 'file', | |||
formData: { | |||
key, | |||
OSSAccessKeyId: ossForm.OSSAccessKeyId, | |||
signature: ossForm.signature, | |||
policy: ossForm.policy, | |||
'x-oss-security-token': ossForm.SecurityToken | |||
}, | |||
success: (res)=> { | |||
if(res.statusCode === 204) { | |||
// 上传成功,将图片路径resolve出去 | |||
resolve(key) | |||
} else { | |||
wx.showToast({ | |||
title: '图片上传失败', | |||
}) | |||
reject('图片上传失败') | |||
} | |||
}, | |||
fail: (e)=> { | |||
console.log(e); | |||
reject('图片上传失败') | |||
} | |||
}) | |||
}) | |||
}) | |||
Promise.all(temp).then((res)=> { | |||
let form = this.data.form; | |||
form.photoUrl = res.join(',') | |||
applyVolunteer(form).then(res => { | |||
if (res.code === 0) { | |||
wx.showModal({ | |||
title: '提交成功', | |||
confirmColor: '#3175E8', | |||
showCancel: false, | |||
content: '等待审核,审核通过后就可以获得积分。', | |||
success(res) { | |||
if(res.confirm) { | |||
wx.navigateBack() | |||
} | |||
} | |||
}) | |||
} | |||
}).finally(()=>{ | |||
wx.hideLoading(); | |||
}) | |||
}).catch(()=> { | |||
wx.hideLoading() | |||
}) | |||
} | |||
}) | |||
} else { | |||
wx.showToast({ | |||
icon: 'none', | |||
title: '请先勾选用户服务协议以及隐私政策!', | |||
}) | |||
} | |||
}, | |||
/** | |||
* 同意用户协议 | |||
*/ | |||
checkBoxChange() { | |||
let checkAgree = this.data.checkAgree | |||
this.setData({ | |||
checkAgree: !checkAgree | |||
}) | |||
}, | |||
// 用户服务协议 | |||
showAgree() { | |||
wx.navigateTo({ | |||
url: '/package_A/pages/agree/index', | |||
}) | |||
}, | |||
// 隐私政策 | |||
showConceal() { | |||
wx.navigateTo({ | |||
url: '/package_A/pages/conceal/index', | |||
}) | |||
} | |||
}) |
@@ -0,0 +1,4 @@ | |||
{ | |||
"usingComponents": {}, | |||
"navigationBarTitleText": "志愿者服务" | |||
} |
@@ -0,0 +1,83 @@ | |||
<!--package_A/pages/volunteer-page/index.wxml--> | |||
<view class="page_container"> | |||
<image class="page_head" mode="widthFix" src="../../img/volunteer_head.png"></image> | |||
<view class="form_container"> | |||
<view class="form_item {{formRules.activityNum.warning ? 'warning' : ''}}"> | |||
<text class="form_label"><text style="color: red;">*</text>活动人数</text> | |||
<view class="value_box"> | |||
<input style="width: 100%;height: 100%;" type="number" maxlength="100" placeholder="请输入活动人数" placeholder-style="font-size: 28rpx; color: #A6A6A6;" adjust-position="{{true}}" value="{{form.activityNum}}" data-name="activityNum" name="activityNum" bindblur="bindValue" /> | |||
</view> | |||
<text class="tips">请输入活动人数(仅可以输入数字,不超过1000)</text> | |||
</view> | |||
<view class="form_item {{formRules.activityDate.warning ? 'warning' : ''}}"> | |||
<text class="form_label"><text style="color: red;">*</text>活动日期</text> | |||
<picker class="picker_box" bindchange="selectDate" value="{{form.activityDate}}" mode="date"> | |||
<view class="picker_value" wx:if="{{form.activityDate}}"> | |||
<text>{{form.activityDate}}</text> | |||
<image class="select_img" src="../../img/date.png"></image> | |||
</view> | |||
<view wx:else class="picker_value" style="color: #A6A6A6; font-size: 26rpx;"> | |||
<text>请选择活动日期</text> | |||
<image class="select_img" src="../../img/date.png"></image> | |||
</view> | |||
</picker> | |||
<text class="tips">请选择活动日期</text> | |||
</view> | |||
<view class="form_item {{formRules.activityPoints.warning ? 'warning' : ''}}"> | |||
<text class="form_label"><text style="color: red;">*</text>获取积分</text> | |||
<view class="value_box"> | |||
<input style="width: 100%;height: 100%;" type="number" maxlength="4" placeholder="请输入获取积分" placeholder-style="font-size: 28rpx; color: #A6A6A6;" adjust-position="{{true}}" value="{{form.activityPoints}}" data-name="activityPoints" name="activityPoints" bindblur="bindValue" /> | |||
</view> | |||
<text class="tips">请输入获取积分(仅可以输入数字,不超过1000)</text> | |||
</view> | |||
<view class="form_item {{formRules.companyName.warning ? 'warning' : ''}}"> | |||
<text class="form_label"><text style="color: red;">*</text>单位名称</text> | |||
<view class="value_box"> | |||
<input style="width: 100%;height: 100%;" type="text" maxlength="100" placeholder="请输入单位名称" placeholder-style="font-size: 28rpx; color: #A6A6A6;" adjust-position="{{true}}" value="{{form.companyName}}" data-name="companyName" name="companyName" bindblur="bindValue" /> | |||
</view> | |||
<text class="tips">请输入单位名称(可输入数字、字母和汉字)</text> | |||
</view> | |||
<view class="form_item {{formRules.contactName.warning ? 'warning' : ''}}"> | |||
<text class="form_label"><text style="color: red;">*</text>联系人</text> | |||
<view class="value_box"> | |||
<input style="width: 100%;height: 100%;" type="text" maxlength="100" placeholder="请输入联系人" placeholder-style="font-size: 28rpx; color: #A6A6A6;" adjust-position="{{true}}" value="{{form.contactName}}" data-name="contactName" name="contactName" bindblur="bindValue" /> | |||
</view> | |||
<text class="tips">请输入联系人(可输入数字、字母和汉字)</text> | |||
</view> | |||
<view class="form_item {{formRules.contactPhone.warning ? 'warning' : ''}}"> | |||
<text class="form_label"><text style="color: red;">*</text>电话</text> | |||
<view class="value_box"> | |||
<input style="width: 100%;height: 100%;" type="text" maxlength="11" placeholder="请输入电话" placeholder-style="font-size: 28rpx; color: #A6A6A6;" adjust-position="{{true}}" value="{{form.contactPhone}}" data-name="contactPhone" name="contactPhone" bindblur="bindValue" /> | |||
</view> | |||
<text class="tips">请输入电话(仅可输入11位数字)</text> | |||
</view> | |||
<view class="upload_images {{formRules.imageList.warning? 'warning': ''}}"> | |||
<text> | |||
<text style="color: red;">* </text> | |||
<text style="font-size:30rpx; color: #262E38;">上传照片</text> | |||
<text style="font-size:26rpx; color: #999999;">(最多5张照片)</text> | |||
</text> | |||
<view class="image_list"> | |||
<view class="image_preview" wx:for="{{imagePreviewList}}" wx:key="index"> | |||
<image class="image_item" src="{{item}}" mode="aspectFill" data-item="{{item}}"> | |||
</image> | |||
<div class="close" data-current="{{index}}" catchtap="deleteImage"></div> | |||
</view> | |||
<view class="upload_image" bindtap="uploadImage" wx:if="{{imageList.length<5}}"> | |||
<image style="height: 53rpx;width: 53rpx;" mode="widthFix" src="../../../assets/img/open_upload.png"></image> | |||
</view> | |||
</view> | |||
<text class="tips">请上传照片</text> | |||
</view> | |||
<!-- 用户服务协议和隐私协议 --> | |||
<view class="safe_box"> | |||
<label class="checkbox" bindtap="checkBoxChange"> | |||
<checkbox value="{{checkAgree}}" /><text>同意</text> | |||
</label> | |||
<text style="color: #2a82e4;" bindtap="showAgree">《用户服务协议》</text>和<text style="color: #2a82e4;" bindtap="showConceal">《隐私政策》</text> | |||
</view> | |||
<!-- 按钮 --> | |||
<view class="{{checkAgree? 'btn_item submit_btn' : 'btn_item'}}" bindtap="submit">提交</view> | |||
</view> | |||
</view> |
@@ -0,0 +1,185 @@ | |||
/* package_A/pages/volunteer-page/index.wxss */ | |||
.page_head { | |||
width: 100vw; | |||
} | |||
.form_container { | |||
width: 100%; | |||
padding: 0 30rpx; | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: flex-start; | |||
align-items: flex-start; | |||
} | |||
.form_item { | |||
width: 100%; | |||
padding: 30rpx 0; | |||
display: flex; | |||
justify-content: flex-start; | |||
align-items: center; | |||
border-bottom: 1rpx solid #EAE8E8; | |||
position: relative; | |||
} | |||
.form_label { | |||
width: 160rpx; | |||
color: #262E38; | |||
font-size: 30rpx; | |||
} | |||
.tips{ | |||
position: absolute; | |||
bottom: -6rpx; | |||
left: -10rpx; | |||
color: red; | |||
font-size: 24rpx; | |||
transform: translate(27rpx, -5rpx); | |||
display: none; | |||
} | |||
.form_item.warning .tips, .use_purpose.warning .tips, .upload_images.warning .tips{ | |||
display: block; | |||
} | |||
.value_box { | |||
flex: 1; | |||
display: flex; | |||
justify-content: space-between; | |||
align-items: center; | |||
border-radius: 4rpx; | |||
position: relative; | |||
color: #333333; | |||
font-size: 24rpx; | |||
} | |||
.picker_box { | |||
flex: 1; | |||
} | |||
.picker_value { | |||
width: 100%; | |||
display: flex; | |||
justify-content: space-between; | |||
align-items: center; | |||
} | |||
.select_img { | |||
width: 33rpx; | |||
height: 37rpx; | |||
} | |||
/* 上传图片 */ | |||
.upload_images { | |||
width: 100%; | |||
padding: 25rpx 0; | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: flex-start; | |||
align-items: flex-start; | |||
font-size: 28rpx; | |||
color: #666666; | |||
position: relative; | |||
border-top: 1rpx solid #EDEDED; | |||
} | |||
.image_list { | |||
width: 100%; | |||
margin-top: 30rpx; | |||
display: flex; | |||
flex-wrap: wrap; | |||
justify-content: flex-start; | |||
align-content: flex-start; | |||
} | |||
.image_preview { | |||
height: 150rpx; | |||
width: 150rpx; | |||
margin-right: 20rpx; | |||
margin-bottom: 20rpx; | |||
position: relative; | |||
} | |||
.image_item { | |||
height:100%; | |||
width: 100%; | |||
margin-bottom: 20rpx; | |||
margin-right: 30rpx; | |||
border-radius: 10rpx; | |||
} | |||
.close{ | |||
position: absolute; | |||
top:0; | |||
right:0; | |||
transform: translate(40%,-40%); | |||
height: 40rpx; | |||
width: 40rpx; | |||
background:rgba(179, 179, 179, 0.5); | |||
border-radius: 50%; | |||
z-index: 10; | |||
} | |||
.close::before{ | |||
content: ""; | |||
display: block; | |||
position: absolute; | |||
width: 60%; | |||
height: 6rpx; | |||
top:50%; | |||
left:50%; | |||
background:rgb(124, 124, 124); | |||
transform-origin: center; | |||
transform: translate(-50%,-50%) rotate(45deg); | |||
} | |||
.close::after{ | |||
content: ""; | |||
display: block; | |||
position: absolute; | |||
width: 60%; | |||
height: 6rpx; | |||
top:50%; | |||
left:50%; | |||
background:rgb(124, 124, 124); | |||
transform-origin: center; | |||
transform: translate(-50%,-50%) rotate(-45deg); | |||
} | |||
.upload_image { | |||
width: 150rpx; | |||
height: 150rpx; | |||
display: flex; | |||
flex-direction: column; | |||
align-items: center; | |||
justify-content: center; | |||
border-radius: 4rpx; | |||
background-color: #EEEEEE; | |||
border: 1px solid #D2D2D2; | |||
} | |||
.note_mark { | |||
margin-top: 20rpx; | |||
font-size: 24rpx; | |||
color: rgba(153, 153, 153, 1); | |||
} | |||
/* 用户协议确认框 */ | |||
.safe_box { | |||
width: 100%; | |||
margin-top: 110rpx; | |||
margin-bottom: 30rpx; | |||
display: flex; | |||
justify-content: flex-start; | |||
align-items: center; | |||
font-size: 26rpx; | |||
color: #959595; | |||
} | |||
.checkbox { | |||
display: flex; | |||
justify-content: flex-start; | |||
align-items: center; | |||
} | |||
checkbox { | |||
transform: scale(0.8); | |||
} | |||
/* 按钮区 */ | |||
.btn_item { | |||
width: 100%; | |||
height: 80rpx; | |||
margin-bottom: 30rpx; | |||
border-radius: 40rpx; | |||
text-align: center; | |||
line-height: 80rpx; | |||
font-size: 32rpx; | |||
color: #6F6F6F; | |||
background-color: #EEEEEE; | |||
} | |||
.submit_btn { | |||
color: #ffffff; | |||
background-color: #2a82e4; | |||
} |