微信小程序---上传图片到腾讯cos组件封装

前端

html

<view class="container">
  <view class="chose-image" bindtap="uploadImage">
    <image src="/static/images/icon/picupload_icon_show.png"></image>
    <text>+图片</text>
  </view>
  <view class="image-list" wx:if="{{imageList.length > 0}}">
    <view class="item" wx:for="{{imageList}}" wx:key="key">
      <image src="{{item.path}}"></image>
      <icon wx:if="{{item.percent==100}}" class="rm" type="clear" color="red" data-index="{{index}}" data-item="{{item}}" bindtap="removeImage"></icon>
      <progress percent="{{item.percent}}" wx:if="{{item.error}}" color="#FF0000" />
      <progress percent="{{item.percent}}" wx:else  />
    </view>
  </view>
  <view class="text">
    <textarea placeholder=" 来呀,写下你的心情" value="{{content}}" bindinput="bindContentInput" />
  </view>
  
  <view class="function-view">
    <view class="row" bindtap="getLocation">
      <view class="left" wx:if="{{address}}">{{address}}</view>
      <view class="left" wx:else>请选择位置</view>
      <view class="right">
        <image class="go-icon" src='/static/images/icon/to_icon_show_small.png'></image>
      </view>
    </view>
    <navigator url="/pages/topic/topic" class="row" >
      <view class="left">{{topicTitle}}</view>
      <view class="right">
        <image class="go-icon" src='/static/images/icon/to_icon_show_small.png'></image>
      </view>
    </navigator>
  </view>
</view>
<view class="publish-btn" bindtap="publishNews">发 布</view>

css

/* pages/publish/publish.wxss */

.container{
  padding: 40rpx;
  padding-bottom: 140rpx;
}

.chose-image{
  width: 100rpx;
  padding: 10rpx 0;
  border: 1rpx solid #ddd;
  display: flex;
  flex-direction: column;
  align-items: center;
  color: #8c8c8c;
  font-size: 28rpx;
}

.chose-image image{
  width: 60rpx;
  height: 60rpx;
}

.image-list{
  margin-top: 20rpx;
  display: flex;
  flex-direction: row;
  justify-content: start;

  flex-wrap: wrap;
}
.image-list .item{
  position:relative;
  padding: 15rpx;
}
.image-list .item image{
  width: 150rpx;
  height: 150rpx;
}

.image-list .item .rm{
  position: absolute;
  right: -10rpx;
  top: -10rpx; 
}

.text{
  margin: 30rpx 0;
}



.function-view{
  font-size: 28rpx;
}

.function-view .row{
  padding: 30rpx 0;
  border-bottom: 1px solid #efefef;
  
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}

.function-view .row .right{
  color: #8c8c8c;
}
.function-view .row .go-icon{
  margin: 0 20rpx;
  width: 16rpx;
  height: 16rpx;
}


.publish-btn{
  position: fixed;
  background-color: #4cc5b6; 
  color:#fff;
  width: 100%;
  bottom: 0;
  height: 100rpx;
  display: flex;
  justify-content: center;
  align-items: center;
}

js

// pages/release/release.js
var popup = require('../../config/Popup')
var api = require('../../config/api')
var app = getApp();
var COS = require('../../utils/cos-wx-sdk-v5.js')
var cos;
Page({

  /**
   * 页面的初始数据
   */
  data: {
    imageList: [],
    content: "",
    address: "",
    topicId: null,
    topicTitle: "选择合适的话题",
  },
  // 清空数据
  resetData: function () {
    this.setData({
      imageList: [],
      content: "",
      address: "",
      topicId: null,
      topicTitle: "选择合适的话题",
    });
  },
  // 获取位置
  getLocation: function () {
    console.log('123')
    wx.chooseLocation({
      success: (res) => {
        this.setData({
          address: res.address
        })
      }
    });
  },
  // 获取话题
  updateTopic: function (item) {
    this.setData({
      topicId: item.id,
      topicTitle: item.title
    })
  },
  // 获取内容
  bindContentInput: function (e) {
    this.setData({
      content: e.detail.value
    });
  },
  // 预览并上传图片
  uploadImage: function () {
    // 选择图片并上传
    wx.chooseImage({
      count: 9,
      sizeType: ['original', 'compressed'],
      sourceType: ['album', 'camera'],
      success: res => {
        var oldLength = parseInt(this.data.imageList.length);
        // 最多上传9张
        let totalCount = res.tempFiles.length + this.data.imageList.length;
        if (totalCount > 9) {
          popup.popup('图片最多选择9张', 'none')
          return false
        };
        // 这个数据是内存的图片地址
        // console.log(this.data.imageList.concat(res.tempFiles));
        // 本地图片在页面预览
        this.setData({
          imageList: this.data.imageList.concat(res.tempFiles)
        });

        // 获取腾讯对象存储上传文件临时秘钥,并设置到全局变量中。
          cos = new COS({
          getAuthorization: function (options, callback) {
            wx.request({
              url: api.TemporaryKeyAPI,
              header: {
                'authorization': app.globalData.userinfo.token
              },
              success: function (result) {
                var data = result.data;
                var credentials = data.credentials;
                callback({
                  TmpSecretId: credentials.tmpSecretId,
                  TmpSecretKey: credentials.tmpSecretKey,
                  XCosSecurityToken: credentials.sessionToken,
                  ExpiredTime: data.expiredTime,
                });
              }
            });
          }
        });

        // 上传新挑选的图片(原图片无需再上传)
        for (var index in res.tempFiles) {

          let imageFilePath = res.tempFiles[index].path;

          var filePathSplit = imageFilePath.split('.');
          var ext = filePathSplit[filePathSplit.length - 1];
          // 创建随机字符串
          let randowString = Math.random().toString(36).slice(-8) + String(new Date().getTime());
          var fileKey = randowString + "." + ext;

          var targetIndex = parseInt(oldLength) + parseInt(index);
          this.setData({
            ["imageList[" + targetIndex + "].key"]: fileKey
          });
          var that = this;
          // 上传文件(通过闭包做一个上传文件的操作)
          (function (idx) {
            cos.postObject({
              Bucket: app.globalData.userinfo.bucket,
              Region: app.globalData.userinfo.region,
              Key: fileKey,
              FilePath: imageFilePath,
              onProgress: (info) => {
                // console.log('info', info)
                that.setData({
                  ["imageList[" + idx + "].percent"]: info.percent * 100
                })
              }
            }, (err, data) => {
              // 上传成功或失败
              if (err) {
                popup.popup('上传失败', 'none')
                // wx.showToast({
                //   title: '上传失败',
                //   icon: 'none'
                // });
                that.setData({
                  ["imageList[" + idx + "].error"]: true,
                  ["imageList[" + idx + "].percent"]: 100
                })
                return false
              } else {
                // console.log('data', data)
                // console.log(idx, 'idx')
                // data是上传成功时候的数据,这里没有赋值成功,导致后面娶不到数据
                that.setData({
                  // 问题出在这
                  // ["imageList[" + idx + "].cos_path"]: data.headers.Location,
                  ["imageList[" + idx + "].path"]: data.headers.location
                });
                // console.log(that.data.imageList.imageList[1])
              }
              // console.log("imageList", that.data.imageList)
            });
          })(targetIndex)

        }
      }
    })
  },
  // 点击删除图片
  removeImage: function (event) {
    // 判断是否正在上传,如果正在上传就终止,否则就删除;
    // 删除图片,终止 & 删除
    var index = event.currentTarget.dataset['index'];
    var item = event.currentTarget.dataset['item'];
    if (item.percent == 100) {
      cos.deleteObject({
        Bucket: app.globalData.userinfo.bucket,
        Region: app.globalData.userinfo.region,
        Key: item.key
      }, (err, data) => {
        if (err) {
          popup.popup('删除失败', 'none')
          // wx.showToast({
          //   title: '删除失败',
          //   icon: 'none'
          // });
        } else {
          var imageList = this.data.imageList;
          imageList.splice(index, 1);
          this.setData({
            imageList: imageList
          });
        }
      });
    }
  },
  // 提交到后台
  publishNews: function () {

    //发布至少需要一张图片
    if (this.data.imageList.length < 1) {
      popup.popup('至少选择一张图片', 'none')
      // wx.showToast({
      //   title: '至少选择一张图片',
      //   icon: 'none'
      // });
      return
    }
    // 发布内容不能为空
    if (this.data.content.length < 1) {
      popup.popup('内容不能为空', 'none')
      // wx.showToast({
      //   title: '内容不能为空',
      //   icon: 'none'
      // });
      return
    }

    wx.showLoading({
      title: '发布中...',
    })
    // 提交数据
    wx.request({
      url: api.ReleaseAPI,
      header: {
        'authorization': app.globalData.userinfo.token
      },
      data: {
        position: this.data.address,
        content: this.data.content,
        cover: this.data.imageList[0].path,
        topic: this.data.topicId,
        imageList: this.data.imageList
      },
      method: 'POST',
      dataType: 'json',
      responseType: 'text',
      success: (res) => {
        if (res.data.status === 1000) {
          // 发布成功,跳转到一个页面进行提示
          // console.log('cover', this.data.imageList[0].path)
          // console.log('imageList', this.data.imageList)
          wx.navigateTo({
            url: '/pages/publishSuccess/publishSuccess',
          })
        } else {
          wx.showToast({
            title: '发布失败,服务器错误',
            icon: 'none'
          });
        }

      },
      fail: (res) => {
        wx.showToast({
          title: '发布失败,客户端错误',
          icon: 'none'
        });
      },
      complete: (res) => {
        wx.hideLoading();
      },
    })

  },


  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})

app.json配置

"permission": {
    "scope.userLocation": {
      "desc": "你的位置信息将用于小程序位置接口的效果展示"
    }
  },

cos上传js

cos-jsicon-default.png?t=M3C8https://download.csdn.net/download/qq_52385631/81776135

后端

临时密钥

url

  # cos临时密钥
    path('temporary_key/', TemporaryKeyAPIView.as_view()),

view

from rest_framework.views import APIView
from utils.centent.cos import credential
from rest_framework.response import Response


class TemporaryKeyAPIView(APIView):
    """cos临时密钥生成"""


    def get(self, request, *args, **kwargs):
        bucket = ''
        ret = credential(bucket=bucket)
        return Response(data=ret)

credential

def credential(bucket, region='ap-chengdu'):
    '''
    获取cos上传临时凭证
    pip install -U qcloud-python-sts
    # 下面的可以
    pip3 install qcloud-python-sts
    '''

    from sts.sts import Sts

    config = {
        # 临时密钥有效时长,单位是秒(30分钟=1800秒)
        'duration_seconds': 1800,
        # 固定密钥 id
        'secret_id': settings.TENCENT_COS_ID,
        # 固定密钥 key
        'secret_key': settings.TENCENT_COS_KEY,
        # 换成你的 bucket
        'bucket': bucket,
        # 换成 bucket 所在地区
        'region': region,
        # 这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径
        # 例子: a.jpg 或者 a/* 或者 * (使用通配符*存在重大安全风险, 请谨慎评估使用)
        'allow_prefix': '*',
        # 密钥的权限列表。简单上传和分片需要以下的权限,其他权限列表请看 https://cloud.tencent.com/document/product/436/31923
        'allow_actions': [
            # "name/cos:PutObject",
            # 'name/cos:PostObject',
            # 'name/cos:DeleteObject',
            # "name/cos:UploadPart",
            # "name/cos:UploadPartCopy",
            # "name/cos:CompleteMultipartUpload",
            # "name/cos:AbortMultipartUpload",
            "*",
        ],

    }

    sts = Sts(config)
    result_dict = sts.get_credential()
    return result_dict

发布界面

url

    # 发布保存视图
    path('release/', ReleaseAPIView.as_view()),

view

from utils.centent.cos import credential
from rest_framework.response import Response
from rest_framework.generics import CreateAPIView, ListAPIView, ListCreateAPIView

from api import models
from api.serializer import business
from utils.common.auth import JWTAuthentication



class ReleaseAPIView(CreateAPIView):
    """发布保存视图"""
    authentication_classes = [JWTAuthentication, ]
    serializer_class = business.ReleaseModelSerializer

    def post(self, request, *args, **kwargs):
        response = super(ReleaseAPIView, self).post(request, *args, **kwargs)
        # 进行自定义返回数
        data = {
            "status": 1000,
            'msg': '成功'
        }
        response.data = data
        return response

serializer

from rest_framework import serializers

from api import models


class MediaModelSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Media
        fields = ['path', 'key']


class ReleaseModelSerializer(serializers.ModelSerializer):
    """发布保存序列化器"""
    """
    {
    "position": "xx",
    "content": "xx",
    "topic": 1,
    "cover": "xx",
    "imageList": [
        {
            "path": "xx",
            "key": "xx"
        },
        {
            "path": "xx",
            "key": "xx"
        }
    ]
}
    """

    imageList = MediaModelSerializer(many=True, write_only=True)

    class Meta:
        model = models.Release
        fields = ['position', 'content', 'topic', 'imageList', 'cover']

    def validate(self, attrs):
        """校验数据"""
        # 校验数据
        # print(attrs.get('imageList'))
        # print(self.context['request'].data)
        self._is_legitimate(attrs)
        return attrs

    def _is_legitimate(self, attrs):
        """进行校验"""
        position = attrs.get('position')
        user_obj = self.context['request'].user
        content = attrs.get('content')
        topic_obj = attrs.get('topic')
        if not position:
            raise serializers.ValidationError('必须选择一个区域哦')
        if not user_obj:
            raise serializers.ValidationError('请先登录哦')
        if not content:
            raise serializers.ValidationError('内容不能为空哦')
        if not topic_obj:
            raise serializers.ValidationError('必须选一个话题哦')
        return position, user_obj, content, topic_obj

    def create(self, validated_data):
        """创建"""
        # pop数据库没有字段
        # print("validated_data", validated_data)
        imageList = validated_data.pop('imageList')
        # print('imageList', imageList)
        # 保存release
        release_obj = self._save_release(validated_data)
        # 保存Media
        self._save_media(release_obj, imageList)
        # 添加话题人数
        self._add_topic_num(release_obj)
        return release_obj

    def _save_release(self, validated_data):
        """保存release"""
        release_obj = models.Release.objects.create(
            **validated_data,
            userinfo=self.context['request'].user
        )
        return release_obj

    def _save_media(self, release_obj, imageList):
        """保存图片"""
        media_obj = [models.Media(release=release_obj, **media_item) for media_item in imageList]
        models.Media.objects.bulk_create(media_obj)

    def _add_topic_num(self, release_obj):
        """话题人数加一"""
        topic = models.Topic.objects.filter(id=release_obj.topic.id).first()
        if not topic:
            raise serializers.ValidationError('无当前话题')
        topic.follow_num += 1
        topic.save()

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骑猪去兜风z1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值