1 简介

  采用的时有赞的组件

  采用的模式是把图片转换成base64,随其它数据一起提交到后台

image

 

2 小程序端编码(新增)

2.1 json文件

  引入组件

"van-uploader": "@vant/weapp/uploader/index",

  完整的

{
  "navigationBarTitleText": "申请用车",
  "usingComponents": {
    "van-button": "@vant/weapp/button/index",
    "van-picker": "@vant/weapp/picker/index",
    "van-field": "@vant/weapp/field/index",
    "van-popup": "@vant/weapp/popup/index",
    "van-uploader": "@vant/weapp/uploader/index",
    "van-row": "@vant/weapp/row/index",
    "van-col": "@vant/weapp/col/index",
    "van-datetime-picker": "@vant/weapp/datetime-picker/index",
    "van-toast": "@vant/weapp/toast/index"
  }
}

 

2.2 wxml文件

  添加图片组件

<view class="search-img">
      <view class="search-img-tt">上传图片:</view>
      <van-uploader
        file-list="{{ fileList }}"
        deletable="{{ true }}"
        max-count="1"
        accept="image"
        max-size="5242880"
        preview-image="{{true}}"
        bind:delete="deleteImg"
        bind:before-read="beforeRead"
        bind:after-read="afterRead" />
    </view>

  完整

<!--index.wxml-->
<view class="box">
  <view class="search">
    <view class="search-tt ,require-label:before">车辆: </view>
    <view class="search-kk st" bindtap='bindCar' rules="{{[{ required: true, message: '请选择车辆' }]}}" 
    error-message="{{error.carCode}}">{{formshowdata.carCode}}</view>
    <view class="search-tt st,require-label:before">加油量L: </view>
    <view class="search-kk st">
      <van-field
      value="{{ formdata.amount }}"
      bind:change="amountChange"
      type="number"
      placeholder=""
      border="{{ false }}"
      />
    </view>
    <view class="search-tt st,require-label:before">金额: </view>
    <view class="search-kk st">
      <van-field
      value="{{ formdata.money }}"
      bind:change="moneyChange"
      type="number"
      placeholder=""
      border="{{ false }}"
      />
    </view>

    <view class="search-tt st,require-label:before">日期: </view>
    <view class="search-kk st" bindtap='bindgasTime'>{{formdata.gasTime}}</view>


    <view class="search-tt st,notrequire-label:before">说明: </view>
    <view class="search-textarea st">
      <van-field
            maxlength="100"
            autosize="true"
            input-class="fieldarea"
            value="{{ formdata.remark }}"
            bind:change="remarkChange"
            type="textarea"
            placeholder=""
            border="{{ false }}"
        />
    </view>

    <view class="search-img">
      <view class="search-img-tt">上传图片:</view>
      <van-uploader
        file-list="{{ fileList }}"
        deletable="{{ true }}"
        max-count="1"
        accept="image"
        max-size="5242880"
        preview-image="{{true}}"
        bind:delete="deleteImg"
        bind:before-read="beforeRead"
        bind:after-read="afterRead" />
    </view>

  </view>

  <view class="search-btn">
    <van-button type="primary" disabled="{{disabled}}" loading="{{formshowdata.submitLoad}}" bind:click="submit" size="large">
      提交
    </van-button>
  </view>
 
  <van-popup show="{{ formshowdata.carShow }}" position="bottom" custom-style="height: 60%;" >
    <van-picker show-toolbar
    title="车辆"
    value-key="name"
    columns="{{ formshowdata.carList }}"
    bind:cancel="onCancel"
    bind:confirm="onCarConfirm" />
  </van-popup>
  


  <van-popup
  show="{{ formshowdata.gasTimeShow }}"
  position="bottom"
  custom-style="height: 60%;"
  bind:close="onClose">
    <van-datetime-picker
    type="date"
    value="{{currentDate}}"
    bind:confirm="ongasTimeConfirm"
    bind:cancel="onCancel"
    min-date="{{minDate}}"
    max-date="{{maxDate}}"/>
  </van-popup>

  <van-toast id="van-toast"  />
</view>

 

2.3 wxss文件

  添加样式

.search-img {
  width: 100%;
  box-sizing: border-box;
  padding: 0 20rpx;
  margin: 20rpx 0;
  text-align: center;
}

.search-img-tt {
  width: 100%;
  height: 80rpx;
  line-height: 80rpx;
  font-size: 32rpx;
  color: #333;
  text-align: left;
}

  完整

/**index.wxss**/
page {
  width: 100%;
  height: 100%;
  overflow-y: scroll;
  background-color: #EAF1FE;
  box-sizing: border-box;
  padding: 40rpx 40rpx;
}

.box {
  width: 100%;
  height: 100%;
  overflow-y: scroll;
  box-sizing: border-box;
  background-color: #fff;
  border-radius: 10rpx;
}

.search {
  width: 100%;
  box-sizing: border-box;
  padding: 0 20rpx;
  margin: 20rpx 0;
}

.search::after {
  content: " ";
  display: block;
  height: 0;
  clear: both;
  visibility: hidden;
}

.search-tt {
  float: left;
  width: 180rpx;
  height: 80rpx;
  line-height: 80rpx;
  font-size: 32rpx;
  color: #333;
  margin-left: 70rpx; 
}

.search-kk {
  width: calc(80% - 150rpx);
  height: 80rpx;
  border: 1px solid rgb(169, 167, 167);
  box-sizing: border-box;
  padding: 0 20rpx;
  line-height: 70rpx;
  font-size: 28rpx;
  color: #333;
  overflow-x: hidden;
  border-radius: 10rpx;
}

.search-textarea {
  width: calc(80% - 150rpx);
  height: 180rpx;
  border: 1px solid rgb(169, 167, 167);
  box-sizing: border-box;
  padding: 0 20rpx;
  line-height: 50rpx;
  font-size: 28rpx;
  color: #333;
  overflow-x: hidden;
  border-radius: 10rpx;
  position: relative; /* 或者 absolute,取决于你的具体布局 */
}
.fieldarea {
  min-height: 170rpx !important; /* 使 van-field 组件撑满容器 */
}
.fieldarea2 {
  min-height: 100rpx !important; /* 使 van-field 组件撑满容器 */
}

input {
  height: 80rpx !important;
  line-height: 80rpx !important;
  font-size: 32rpx;
  color: #333;
  padding: 0 !important;
}


.van-cell {
  padding: 0 !important;

}

.st {
  margin-top: 20rpx;
}

.search-img {
  width: 100%;
  box-sizing: border-box;
  padding: 0 20rpx;
  margin: 20rpx 0;
  text-align: center;
}

.search-img-tt {
  width: 100%;
  height: 80rpx;
  line-height: 80rpx;
  font-size: 32rpx;
  color: #333;
  text-align: left;
}

.van-uploader__upload {
  width: 400rpx !important;
  height: 400rpx !important;
}

.van-uploader__preview-image{
  width: 400rpx !important;
  height: 400rpx !important;
}

.search-btn {
  width: 80%;
  box-sizing: border-box;
  padding: 20rpx;
  margin-left: 40px;
  margin-top: 30px;
}

/* 必填 */
.require-label:before { 
  content: '* ';
  color: red;
}

/* 非必填 */
.notrequire-label:before { 
  content: '* ';
  color: rgb(24, 23, 23);
}

.search-img {
  width: 100%;
  box-sizing: border-box;
  padding: 0 20rpx;
  margin: 20rpx 0;
  text-align: center;
}

.search-img-tt {
  width: 100%;
  height: 80rpx;
  line-height: 80rpx;
  font-size: 32rpx;
  color: #333;
  text-align: left;
}

 

2.4 js文件

  图片相关data

data: {
    fileList:[],  存储组件的图片列表,对象格式{url:''},url是临时存储路径
    fileBase64List:[] 存储转换成base64的字符串图片列表
}

  图片相关方法

beforeRead(event) {
    const { file, callback } = event.detail;
    callback(file.type === 'image');
  },

  // 选择图片后触发
  afterRead(event){
    var that = this
    var img = event.detail.file;
    // 读取图片,转换为base64
    wx.getFileSystemManager().readFile({
      filePath: event.detail.file.url,
      encoding: 'base64',
      success: (res) => {
        const base64Data = res.data;
        var base64Img = 'data:image/png;base64,' + base64Data
        var li = that.data.fileList
        li.push(img)
        var li2 = that.data.fileBase64List
        li2.push(base64Img)
        that.setData({
          fileList:li,
          fileBase64List:li2
        })
      },
      fail: (err) => {
        console.error(err);
      }
    });
    console.log('this.data.fileList',this.data.fileList)
    console.log('this.data.fileBase64List',this.data.fileBase64List)
  },

  // 点击删除图片
  deleteImg(event) {
    let id = event.detail.index //能获取到对应的下标
     //根据下标来删除对应的图片
    var li = this.data.fileList
    li.splice(id, 1)
    var li2 = this.data.fileBase64List
    li2.splice(id, 1)
    this.setData({
      fileList:li,
      fileBase64List:li2
    })
    console.log('this.data.fileList',this.data.fileList)
    console.log('this.data.fileBase64List',this.data.fileBase64List)
  },

  提交到服务器

submit(){
    var that = this
    // 校验
    console.log(that.data.formdata)
    var flag = formUtils.validateForm(that.data.formdata,that.data.rules)
    console.log(flag)
    if(!flag){
      return
    }// 按钮禁用
    that.setData({
      'formshowdata.submitLoad': true
    })
    var openid = wx.getStorageSync("openid")
    console.log('发送请求',that.data.base64List)
    wx.request({
      url: app.globalData.url + 'publiccar/gasrecord/manager/add',
      method: 'POST',
      data: {
        publicCarId:that.data.formdata.publicCarId,
        operateOpenid:openid,
        amount:that.data.formdata.amount,
        money:that.data.formdata.money,
        gasTimeSt:that.data.formdata.gasTime,
        remark:that.data.formdata.remark,
        base64List:that.data.fileBase64List
      },
      header: {
        'content-type': 'application/json;charset=utf-8',
        'openid': openid // 默认值
      },
      success(res) {
        if(res.data.code ==200 ){
          wx.showToast({
            title: res.data.msg,
            icon: 'none',
            duration:500
           })
           setTimeout(function() {
            wx.navigateBack()
        }, 500);
          
        } else {
          Toast.fail(res.data.msg);
        }
      }
    })

  完整

// index.js
// 获取应用实例
const app = getApp()
import Toast from '../../../../miniprogram_npm/@vant/weapp/toast/toast';
const dateutils = require('../../../../utils/dateUtil');
const formUtils = require('../../../../utils/formUtils');

Page({
  data: {
    formdata:{
      publicCarId:'',
      amount:0.0,
      money:0.0,
      gasTime:dateutils.formatTimeStamp(new Date())
    },
    formshowdata:{
      carShow:false,
      carList:[],
      carCode:'',
      gasTimeShow:false,
      submitLoad:false
    },
    fileList:[],
    fileBase64List:[],
    minDate:new Date((new Date().getFullYear() - 2), 10, 1).getTime() ,
    maxDate: new Date().getTime(),
    currentDate: new Date().getTime(),
    rules: {
      publicCarId: [{ required: true, message: '请选择车辆' }],
      amount: [{ required: true, message: '请选择地点' }],
      money: [{ required: true, message: '请选择距离' }],
      gasTime: [{ required: true, message: '请选择出发时间' }]
    },
  },

  
  onLoad() {
    var that = this
    that.getCarList() // 查询车辆下拉框
  },

   // 查询车辆下拉框
   getCarList(){
    var that = this
    var token = wx.getStorageSync("wxtoken")
    wx.request({
      url: app.globalData.url + 'publiccar/search/getNameAndValueList',
      method: 'POST',
      data: {
      },
      header: {
        'content-type': 'application/json;charset=utf-8',
        'authorization': token // 默认值
      },
      success(res) {
        if(res.data.code ==200 ){
          that.setData({
            'formshowdata.carList': res.data.data,
            'formshowdata.carCode':res.data.data[0].name,
            'formdata.publicCarId':res.data.data[0].value
          })
        } else {
          Toast.fail(res.data.msg);
        }
      }
    })
  },

  bindCar(){
    this.setData({
      'formshowdata.carShow': true
    })
  },

  onCancel(){
    this.setData({
      'formshowdata.carShow': false,
      'formshowdata.gasTimeShow': false,
    })
  },
  
  onCarConfirm(event){
    this.setData({
      'formshowdata.carShow': false,
      'formshowdata.carCode': event.detail.value.name,
      'formdata.publicCarId': event.detail.value.value
    })
  },

  amountChange(e){
    var that = this
    that.setData({
      'formdata.amount':e.detail
    })
  },

  moneyChange(e){
    var that = this
    that.setData({
      'formdata.money':e.detail
    })
  },

  bindgasTime(){
    this.setData({
      'formshowdata.gasTimeShow': true
    })
  },

  ongasTimeConfirm(event){
    this.setData({
      'formshowdata.gasTimeShow': false,
      'formdata.gasTime': dateutils.formatTimeStamp(event.detail),
    })
  },

  remarkChange(e){
    var that = this
    that.setData({
      'formdata.remark':e.detail
    })
  },
  
  beforeRead(event) {
    const { file, callback } = event.detail;
    callback(file.type === 'image');
  },

  // 选择图片后触发
  afterRead(event){
    var that = this
    var img = event.detail.file;
    // 读取图片,转换为base64
    wx.getFileSystemManager().readFile({
      filePath: event.detail.file.url,
      encoding: 'base64',
      success: (res) => {
        const base64Data = res.data;
        var base64Img = 'data:image/png;base64,' + base64Data
        var li = that.data.fileList
        li.push(img)
        var li2 = that.data.fileBase64List
        li2.push(base64Img)
        that.setData({
          fileList:li,
          fileBase64List:li2
        })
      },
      fail: (err) => {
        console.error(err);
      }
    });
    console.log('this.data.fileList',this.data.fileList)
    console.log('this.data.fileBase64List',this.data.fileBase64List)
  },

  // 点击删除图片
  deleteImg(event) {
    let id = event.detail.index //能获取到对应的下标
     //根据下标来删除对应的图片
    var li = this.data.fileList
    li.splice(id, 1)
    var li2 = this.data.fileBase64List
    li2.splice(id, 1)
    this.setData({
      fileList:li,
      fileBase64List:li2
    })
    console.log('this.data.fileList',this.data.fileList)
    console.log('this.data.fileBase64List',this.data.fileBase64List)
  },
 
  submit(){
    var that = this
    // 校验
    console.log(that.data.formdata)
    var flag = formUtils.validateForm(that.data.formdata,that.data.rules)
    console.log(flag)
    if(!flag){
      return
    }

    if(! /^(0*[1-9]\d*(\.\d+)?|0+\.\d*[1-9]\d*)$/.test(that.data.formdata.amount.toString())){
      wx.showToast({
        title: '加油量仅限大于0数字',
        icon: 'none',
        duration:1000
       })
       return
    }
    if(! /^(0*[1-9]\d*(\.\d+)?|0+\.\d*[1-9]\d*)$/.test(that.data.formdata.money.toString())){
      wx.showToast({
        title: '金额距离仅限大于0数字',
        icon: 'none',
        duration:1000
       })
       return
    }
    // 按钮禁用
    that.setData({
      'formshowdata.submitLoad': true
    })
    var openid = wx.getStorageSync("openid")
    console.log('发送请求',that.data.base64List)
    wx.request({
      url: app.globalData.url + 'publiccar/gasrecord/manager/add',
      method: 'POST',
      data: {
        publicCarId:that.data.formdata.publicCarId,
        operateOpenid:openid,
        amount:that.data.formdata.amount,
        money:that.data.formdata.money,
        gasTimeSt:that.data.formdata.gasTime,
        remark:that.data.formdata.remark,
        base64List:that.data.fileBase64List
      },
      header: {
        'content-type': 'application/json;charset=utf-8',
        'openid': openid // 默认值
      },
      success(res) {
        if(res.data.code ==200 ){
          wx.showToast({
            title: res.data.msg,
            icon: 'none',
            duration:500
           })
           setTimeout(function() {
            wx.navigateBack()
        }, 500);
          
        } else {
          Toast.fail(res.data.msg);
        }
      }
    })

    setTimeout(function () {
      // 1s后按钮取消禁用
      that.setData({
        'formshowdata.submitLoad':false
      })
    }, 1000);
  },

  resetForm(){
    var that = this
    that.setData({
      'formdata.publicCarId':'',
      'formdata.applyReasonType':'',
      'formdata.applyReasonDetail':'',
      'formdata.startTime':'',
      'formdata.placeOfDeparture':'',
      'formdata.distance':'',
      'formshowdata.carCode':'',
      'formshowdata.applyReasonTypeSt':'',
    })
  }


})

 

 

3 编码(编辑)

3.1 简介

  编辑主要涉及回显,需要初始化fileBase64List和fileList

  that.data.applyDetail.billImageUrlList是后台返回的图片网络路径集合
 在onLoad中初始化fileBase64List和fileList
if(that.data.applyDetail.billImageUrlList){
      var li = []
      that.data.applyDetail.billImageUrlList.forEach(function (item){
          var vo = {'url':item}
          li.push(vo)
      })
      that.setData({ 
        fileBase64List:that.data.applyDetail.billImageUrlList,
        fileList:li
      });
    }