微信小程序上传照片主要代码

wxml部分

<!--sub_tool/article/edit/edit.wxml-->

<custom-page>
  <nav-bar slot="nav" title="修改文章" show-back="{{true}}" background-color="#fff">
  </nav-bar>

  <view slot="content">
    <van-notify id="van-notify" />
    <view class="container">
      <!-- 行业门类 -->
      <view class="info">
        <view class="name">行业门类(必选)</view>
        <van-dropdown-menu active-color="#1989fa" duration="{{50}}" overlay="{{true}}">
          <van-dropdown-item value="{{ catalogId }}" options="{{ catalogs }}" bind:change="changeCatalog" />
        </van-dropdown-menu>
      </view>
      <!-- 行业大类 -->
      <view class="info">
        <view class="name">行业大类(必选)</view>
        <van-dropdown-menu active-color="#1989fa" duration="{{50}}" overlay="{{true}}">
          <van-dropdown-item value="{{ subcatalogId }}" options="{{ subcatalogs }}" 
          bind:change="changeSubcatalog" />
        </van-dropdown-menu>
      </view>
      <!-- 标题 -->
      <view class="info">
        <view class="name">标题(必填)</view>
        <view class="content">
          <textarea bindinput="bindTitleInput" value="{{title}}" auto-height placeholder="请输入标题" />
        </view>
      </view>
      <!-- 内容 -->
      <view class="info">
        <view class="name">内容(必填),要显示图片处请输入@img</view>
        <view class="content">
          <textarea bindinput="bindSummaryInput" maxlength="-1" value="{{content}}" auto-height placeholder="请输入内容" />
        </view>
      </view>
      <!-- 图片集 -->
      <view class="info">
        <view class="name">图片集(至少3张)</view>
        <view class="buttons" bindtap="choosePhoto">
          <button type="default">添加图片</button>
        </view>
        <view class="list">
          <view wx:for="{{photos}}" wx:key="*this" class="item">
            <view class="pic">
              <view class="pic_tool">
                <view class="pic_tool_del" data-id="{{item.articlePhotoId}}" bindtap="handleDeletePhoto">
                  <mp-icon icon="close" color="#666" size="{{25}}"></mp-icon>
                </view>
              </view>
              <image src="{{item.fullUrl}}" />
            </view>
            <view class="desc">
              <view class="title">{{item.title}}</view>
              <view class="desc_edit_btn" data-id="{{item.articlePhotoId}}" data-title="{{item.title}}" bindtap="handleEditPhoto">
                <mp-icon icon="pencil" color="#666" size="{{22}}"></mp-icon>
              </view>
            </view>
          </view>
        </view>
      </view>
      <!-- 保存/丢弃 -->
      <view class="buttons">
        <button type="primary" bindtap="handleSubmit">保存</button>
        <button type="warn" bindtap="handleDelete">删除</button>
      </view>
      <view class="placeholder">.</view>
    </view>
  </view>
</custom-page>

json部分

{
  "usingComponents": {
    "nav-bar": "/components/nav/nav",
    "custom-page": "/components/page/page",
    "mp-icon": "weui-miniprogram/icon/icon",
    "van-notify": "@vant/weapp/notify/index",
    "van-dropdown-menu": "@vant/weapp/dropdown-menu/index",
    "van-dropdown-item": "@vant/weapp/dropdown-item/index"
  }
}

wxss部分

/* sub_tool/article/edit/edit.wxss */

page {
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  background-color: #eee;
}

.container {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.info {
  width: 720rpx;
  margin-top: 25rpx;
  display: flex;
  flex-direction: column;
  color: #888;
  background-color: #fff;
  border-radius: 20rpx;
}
.info .name {
  margin: 0 auto;
  width: calc(100% - 25rpx);
  height: 80rpx;
  line-height: 80rpx;
  font-size: 32rpx;
}
.info .content {
  display: flex;
  margin: 0 auto;
  width: calc(100% - 25rpx);
  padding-bottom: 30rpx;
  font-size: 36rpx;
  color: #333;
}

.info .content .logo {
  width: 200rpx;
  height: 200rpx;
  margin: 0 auto;
  border-radius: 10rpx;
  background-color: #aaa;
  overflow: hidden;
}

.info .content .left {
  width: calc(100% - 60rpx);
  line-height: 50rpx;
}
.info .content .right {
  width: 60rpx;
  text-align: center;
}

input {
  width: 100%;
  height: 60rpx;
  border-radius: 10rpx;
  padding: 16rpx;
  background-color: #f1f1f1;
}

textarea {
  width: 100%;
  min-height: 200rpx;
  border-radius: 10rpx;
  padding: 6rpx;
  background-color: #f1f1f1;
}

.buttons {
  margin: 0 auto;
}
.buttons button {
  width: 700rpx;
  margin: 25rpx 0rpx;
}

.buttons-max {
  width: 680rpx;
  height: 200rpx;
  margin-top: 25rpx;
}

.info .list {
  margin: 0 auto;
  width: 700rpx;
  display: flex;
  flex-wrap: wrap;
  padding-bottom: 15rpx;
}

.info .list .item {
  width: 350rpx;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* height: 150rpx; */
}

.info .list .item .pic_tool {
  position: relative;
  top: 0rpx;
  text-align: right;
  display: flex;
  justify-content: flex-end;
}
.info .list .item .pic_tool_del {
  width: 50rpx;
  height: 50rpx;
  display: flex;
  justify-content: center;
  align-items: center;
}

.info .list .item .pic{
  width: 330rpx;
  height: 248rpx;
  background-color: #ddd;
  overflow: hidden;
}
.info .list .item .pic image{
  width: 100%;
  height: 100%;
}
.info .list .item .desc{
  width: 330rpx;
  height: 80rpx;
  background-color: #fff;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
}
.info .list .item .desc .title {
  width: 270rpx;
  font-size: 30rpx;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  -webkit-box-orient: vertical;
}
.info .list .item .desc_edit_btn {
  width: 50rpx;
  height: 44rpx;
  display: flex;
  justify-content: center;
}

.placeholder {
  width: 750rpx;
  height: 40rpx;
  color: #eee;
}

.inputPlaceholder {
  font-size: 30rpx;
}

/* 定制下拉列表组件的样式 */
.custom-class {
  width: 500rpx;
}
.custom-class .van-dropdown-menu__item {
  display: flex;
  justify-content: flex-start !important;
}
.custom-class .van-dropdown-menu__item .title-class {
  font-size: 32rpx !important;
  color: #333;
}

.item-custom-class {
  width: 720rpx;
  margin: 0 auto;
}
.item-title-class {
  font-size: 32rpx !important;
}

.no-company {
  margin-left: 10rpx;
  font-size: 32rpx;
  line-height: 80rpx;
  color: rgb(136, 136, 136);
}

js部分

// sub_tool/article/edit/edit.js

import api from '@/api/api.js'
import config from '@/config/index.js'
import storesToken from '@/stores/token.js'
import storesConfig from '@/stores/config.js'
import Notify from '@vant/weapp/notify/notify'
import { getFullUrl } from '@/config/setting'

const { API_BASE_URL } = config.get()

// 上传的路径
const UPLOAD_PATH = '/weixin/api/article_photo/upload/photo'
const PHOTO_ID_NAME = 'articlePhotoId'

Page({
  data: {
    articleId: '',
    title: '',
    content: '',
    photos: [],
    catalogs: [
      {
        text: '请选择门类',
        value: '-1',
      }
    ],
    catalogId: '-1',
    subcatalogs: [
      {
        text: '暂无大类',
        value: '-1',
      }
    ],
    subcatalogId: '-1',
  },

  enableAlert() {
    wx.enableAlertBeforeUnload({
      message: '放弃编写信息吗?',
    })
  },

  disableAlert() {
    wx.disableAlertBeforeUnload()
  },

  hasContent() {
    const { title, content, photos } = this.data
    return (title.trim() || content.trim() || photos.length)
  },

  setAlertState() {
    if(this.hasContent()) {
      this.enableAlert()
    }
    else {
      this.disableAlert()
    }
  },

  async getArticle(articleId) {
    const result = await api.getById('article', articleId)
    const { code, data } = result
    if(code == 200) {
      const { catalogId, subcatalogId, title, content, photoIds, photoDataJson } = data
      const photos = photoIds.map(photoId => {
        const item = photoDataJson[photoId]
        item.fullUrl = getFullUrl(item.minDir)
        return item
      })
      this.setData({
        articleId,
        catalogId,
        subcatalogId,
        title,
        content,
        photos,
      })
      this.getCatalogs()
      this.getSubcatalogs(catalogId, subcatalogId)
    }
  },

  // 获取门类
  async getCatalogs() {
    api.list('article_catalog', {
      level: 1,
      pageNum: 1,
      pageSize: 100,
    }).then(response => {
      const { rows } = response
      const catalogs = rows.map(item => {
        return {text: item.catalogName, value: item.catalogId}
      })
      this.setData({
        catalogs: [{text:'请选择门类', value:'-1'}, ...catalogs],
      })
    }).catch(e => {
      console.log('@@ e -> ', e)
    })
  },

  // 根据门类ID获取门类
  async getSubcatalogs(catalogId, subcatalogId) {
    const result = await api.list('article_catalog', {
      parentId: catalogId,
      pageNum: 1,
      pageSize: 100,
    })
    const { rows } = result
    const subcatalogs = rows.map(item => {
      return {
        text: item.catalogName,
        value: item.catalogId,
      }
    })
    this.setData({
      catalogId,
      subcatalogId: subcatalogId || '-1',
      subcatalogs: [{text:'请选择大类', value: '-1'}, ...subcatalogs]
    })
  },

  // 选择行业门类
  async changeCatalog(e) {
    const catalogId = e.detail
    // 选择默认提示项,大类显示“暂无大类”
    if(catalogId == '-1') {
      this.setData({
        catalogId: '-1',
        subcatalogId: '-1',
        subcatalogs: [
          {
            text: '暂无大类',
            value: '-1',
          }
        ],
      })
      return
    }
    // 选择内容项
    await this.getSubcatalogs(catalogId)
  },

  // 选择行业大类
  changeSubcatalog(e) {
    const subcatalogId = e.detail
    this.setData({
      subcatalogId,
    })
  },

  bindTitleInput(e) {
    this.setData({
      title: e.detail.value
    })
    this.setAlertState()
  },

  bindSummaryInput(e) {
    this.setData({
      content: e.detail.value
    })
    this.setAlertState()
  },
  
  // 选择图片集
  choosePhoto() {
    const _this = this
    const { photos } = this.data
    this.chooseImage(photos, (images) => {
      _this.setData({
        photos: images,
      })
    })
  },

  // 选择相册
  chooseImage(images, callback) {
    const _this = this
    wx.chooseMedia({
      count: 5, // 最多可以选择的图片张数
      sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
      sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
      camera: 'back',
      success: async (res) => {
        // 返回选定照片的本地文件路径列表
        const tempFiles = res.tempFiles
        // 循环上传图片
        for(const { tempFilePath } of tempFiles) {
          const list = await this.uploadFile(tempFilePath)
          for(const item of list) {
            if(!images.find(p => p[PHOTO_ID_NAME] == item[PHOTO_ID_NAME])) {
              item.fullUrl = getFullUrl(item.minDir)
              images.push(item)
            }
          }
          _this.setAlertState()
          callback(images)
        }
      },
      fail(res) {
      }
    })
  },
  
  async uploadFile(filePath) {
    wx.showLoading({
      title: '正在上传...'
    })
    return new Promise((resolve, reject) => {
      wx.uploadFile({
        url: API_BASE_URL + UPLOAD_PATH, // 上传的服务器地址
        filePath: filePath,
        name: 'file', // 文件对应的 key
        header: {
          'Authorization': `Bearer ${storesToken.get()}`
        },
        formData: {
          // HTTP 请求中其他额外的 form data
        },
        success: (res) => {
          // 上传成功后的处理
          console.log(res.data)
          if(res.statusCode == 200) {
            const result = JSON.parse(res.data)
            if(result.code == 200) {
              const list = result.data
              resolve(list)
            }
          }
          wx.hideLoading()
        },
        fail: (err) => {
          // 上传失败后的处理
          console.error(err)
          reject(err)
          wx.hideLoading()
        }
      })
    })
  },

  handleDeletePhoto(e) {
    const { id } = e.currentTarget.dataset
    const _this = this
    wx.showModal({
      title: '提示',
      content: '要删除图片吗?',
      success: async (res) => {
        if (res.confirm) { //点击了确认
          const photos = _this.data.photos.filter(item => item[PHOTO_ID_NAME] != id)
          _this.setData({
            photos,
          })
          _this.setAlertState()
        } else {
          console.log('用户点击了取消')
        }
      }
    })
  },

  async handleEditPhoto(e) {
    const _this = this
    const { id, title } = e.currentTarget.dataset
    this.handleEditImage(title, async(content) => {
      const photos = _this.data.photos
      const photo = photos.find(item => item[PHOTO_ID_NAME] == id)
      const result = await api.update('article_photo', {
        [PHOTO_ID_NAME]: photo[PHOTO_ID_NAME],
        title: content
      })
      photo.title = content
      _this.setData({
        photos,
      })
    })
  },

  handleEditImage(content, callback) {
    wx.showModal({
      title: '修改图片描述',
      editable: true,//显示输入框
      content, // photo.originalFilename,
      placeholderText: '输入图片描述',//显示输入框提示信息
      success: async (res) => {
        if (res.confirm) { //点击了确认
          console.log(res.content)//用户输入的值
          const content = (res.content || '').trim()
          if(content) {
            callback(content)
          }
        } else {
          console.log('用户点击了取消')
        }
      }
    })
  },

  // 保存商品基本信息
  async handleSubmit() {
    const _this = this
    const { articleId, catalogId, subcatalogId, title, content, photos } = this.data
    if(catalogId == '-1' || subcatalogId == '-1') {
      Notify({ 
        type: 'danger',
        message: '请选择行业门类和大类',
        top: getApp().globalData.navTopHeight,
      })
      return
    }
    if(!title.trim()) {
      Notify({ 
        type: 'danger',
        message: '标题不能为空',
        top: getApp().globalData.navTopHeight,
      })
      return
    }
    if(!content.trim()) {
      Notify({ 
        type: 'danger',
        message: '内容不能为空',
        top: getApp().globalData.navTopHeight,
      })
      return
    }
    if(photos.length < 3) {
      Notify({ 
        type: 'danger',
        message: '上传照片至少3张',
        top: getApp().globalData.navTopHeight,
      })
      return
    }

    this.disableAlert()
    let photoIds = []
    if(photos.length) {
      photoIds = photos.map(item => item[PHOTO_ID_NAME])
    }
    const data = {
      articleId,
      catalogId,
      subcatalogId,
      title, 
      content, 
      photoIds,
    }
    console.log('@@ handleSubmit data -> ', data)
    api.update('article', data)
    .then(res => {
      wx.navigateBack()
    })
    .catch(res => {
      Notify({
        type: 'danger', 
        message: res.msg || '发生错误',
        top: getApp().globalData.navTopHeight,
      })
    })
  },

  // 删除文章
  handleDelete() {
    const { articleId } = this.data
    wx.showModal({
      title: '提示',
      content: '确认删除本篇文章吗?',
      complete: async (res) => {
        if (res.cancel) {
          
        }
        if (res.confirm) {
          const result = await api.remove('article', [articleId])
          if(result.code == 200) {
            wx.navigateBack()
          }
          else {
            Notify({ 
              type: 'danger', 
              message: '删除失败',
              top: getApp().globalData.navTopHeight,
            })
            return
          }
        }
      }
    })
  },

  onLoad(options) {
    const { articleId } = options
    this.getArticle(articleId)
  },

  onShow() {
    // 设置顶部title
    wx.setNavigationBarTitle({
      title: '发布展文',
    })
  },

})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值