在做taro 项目是,遇到图片上传,来做个笔记。
1.评论上传图片,多张图片上传
import Taro, { Component } from '@tarojs/taro'
import { View, Text, Image } from '@tarojs/components'
import { AtRate, AtTextarea, AtButton, AtCheckbox, AtImagePicker } from 'taro-ui'
import { pickBy, formatTime, showToast,hasNavBar } from '@/utils'
import { NavBar } from '@/components'
import S from '@/spx'
import api from '@/api'
import './rate.scss'
import WxAuth from '../auth/comps/auth'
export default class Rate extends Component {
config = {
navigationBarTitleText: '订单评价'
}
constructor (props) {
super(props)
this.state = {
desValue: 0,
serviceValue: 0,
logisValue: 0,
info: {},
checkedList: [],
shopLogo: '',
goodsRate: [],
shop_type: ''
}
}
handleDescChange (value) {
this.setState({
desValue: value
})
}
handleSeviceChange (value) {
this.setState({
serviceValue: value
})
}
handleLogisChange (value) {
this.setState({
logisValue: value
})
}
handleChange (value) {
this.setState({
checkedList: value
})
}
componentDidMount () {
this.fetch()
}
async fetch () {
const { tid } = this.$router.params
const data = await api.trade.detail(tid)
const { shopInfo: { shop_logo, shop_type } } = await api.shop.basic(data.shop_id)
this.setState({
shopLogo: shop_logo,
shop_type
})
const goodsRate = []
data.orders.map((item) => {
goodsRate.push({
oid: item.oid,
result: 'good',
content: '',
rate_pic: []
})
})
this.setState({
goodsRate
})
const info = pickBy(data, {
tid: 'tid',
shopname: 'shopname',
orders: ({ orders }) =>
pickBy(orders, {
status: 'status',
order_id: 'oid',
item_id: 'item_id',
aftersales_status: 'aftersales_status',
complaints_status: 'complaints_status',
refund_enabled: 'refund_enabled',
pic_path: 'pic_path',
title: 'title',
goods_props: 'spec_nature_info',
delivery_status: 'delivery_status',
price: 'price',
spec_nature_info: 'spec_nature_info',
gift_data: 'gift_data',
changing_enabled: 'changing_enabled',
// point: 'item_point',
num: 'num',
buyer_rate: 'buyer_rate'
})
})
info.ziti = !!data.ziti
info.totalNum = info.orders.reduce((val, o) => val + Number(o.num), 0)
this.setState({
info
})
}
clickGrade (key, rate) {
let a = []
a = this.state.goodsRate
a[key].result = rate
this.setState({
goodsRate: a
})
}
onChangeText (key, e) {
let a = []
a = this.state.goodsRate
a[key].content = e.target.value
this.setState({
goodsRate: a
})
}
onChangeImage (key, files) {
let a = []
a = this.state.goodsRate
a[key].rate_pic = files
this.setState({
goodsRate: a
})
}
async uploadImgs(imgFiles =[] ) {
const imgs = []
const promises = imgFiles.map(item =>{
return new Promise((resolve) =>{
if(item.file){
if(process.env.TARO_ENV == 'weapp'){
//const base64 = 'data:image/jpeg;base64,'+ Taro.getFileSystemManager().readFilesSync(item.file.path,'base64')
const base64 = 'data:image/png;base64,'+ wx.getFileSystemManager().readFileSync(item.file.path,'base64')
const data = api.member.uploadFile({
image:base64,
upload_type:'base64',
image_input_title:'image.jpg',
image_type:'rate'
})
data.then((r) =>{
console.log(r)
imgs.push(r.url)
resolve(r.url)
})
}else {
Taro.request({
url:item.url,
responseType:'arraybuffer',
success:async(res) =>{
let base64 = Taro.arrayBufferToBase64(new Uint8Array(res.data))
base64 = 'data:image/png;base64,' + base64
const data = await api.member.uploadFile({
image:base64,
upload_type:'base64',
image_input_title:'image.jpg',
image_type:'rate'
})
imgs.push(data.url)
resolve(data.url)
}
})
}
}else {
resolve(item.url)
}
})
})
await Promise.all(promises)
return imgs
}
async toRate () {
const { shop_type} = this.state
const a = this.state.goodsRate
const promises = a.map((item) =>{
return new Promise((resolve) =>{
this.uploadImgs(item.rate_pic).then(res =>{
item.rate_pic = res.join(',')
resolve(item)
})
})
})
await Promise.all(promises)
const { tid } = this.$router.params
const res = await api.member.rateAdd({
tid,
anony: this.state.checkedList.length > 0,
tally_score: shop_type === 'self' ? 5 : this.state.desValue,
attitude_score: shop_type === 'self' ? 5 : this.state.serviceValue,
delivery_speed_score:shop_type === 'self' ? 5 : this.state.logisValue,
rate_data: JSON.stringify(a)
})
if (res.status == 'success') {
showToast('评价成功!')
if(Taro.getEnv()==='SAPP' && APP_BUILD_ENV ==='app'){
SAPP.on('cancelTrade',()=>{
this.setState({
status: this.$router.params.status,
list:[]
},() =>{
this.resetPage()
setTimeout(()=>{
this.nextPage()
},500)
})
})
}
return Taro.navigateBack()
}
}
// TODO: 确认原有功能
render () {
const { info } = this.state
const { orders } = info
const options = [
{
label: '匿名评价',
value: 'nickname'
}
]
const navBar = hasNavBar()
return (
<View className={`trade-rate ${navBar}`}>
<NavBar fixed = {false} title='订单评价'
rightFirstIcontype='search' parentClassName='page-goods-list__navbar'
onClickRgIconSt = {this.onClickRgIconSt}/>
<View className='trade-rate-header'>
<View className='shop-info'>
<View className='shop-info-logo'>
<Image className='shop-logo' src={this.state.shopLogo} alt='' />
</View>
<View>
{info.shopname}
</View>
</View>
{
this.state.shop_type != 'self' && (<View>
<View className='rate-star'>
<View className='rating-issue'>描述相符</View>
<AtRate max={5} value={this.state.desValue} onChange={this.handleDescChange.bind(this)} />
</View>
<View className='rate-star'>
<View className='rating-issue'>服务态度</View>
<AtRate max={5} value={this.state.serviceValue} onChange={this.handleSeviceChange.bind(this)} />
</View>
<View className='rate-star'>
<View className='rating-issue'>发货速度</View>
<AtRate max={5} value={this.state.logisValue} onChange={this.handleLogisChange.bind(this)} />
</View>
</View>)
}
</View>
{
orders && orders.length > 0 && orders.map((item, key) => {
if (item.buyer_rate == 0) {
return (<View className='good-info' key={item.oid}>
<View className='good-info-header'>
<View className='good-info-logo'>
<Image className="goods-img" src={item.pic_path} alt='' />
</View>
<View>
{item.title}
</View>
</View>
<View className='good-rate'>
<View className='good-rate-grade'>
<View className={this.state.goodsRate[key].result === 'good' ? 'grade praise active' : 'grade praise'} onClick={this.clickGrade.bind(this, key, 'good')}>
<Text className='mb-iconfont mb-iconfont-pingjia'></Text><Text> 好评</Text>
</View>
<View className={this.state.goodsRate[key].result === 'neutral' ? 'grade commonly active' : 'grade commonly'} onClick={this.clickGrade.bind(this, key, 'neutral')}>
<Text className='mb-iconfont mb-iconfont-pingjia'></Text><Text> 中评</Text>
</View>
<View className={this.state.goodsRate[key].result === 'bad' ? 'grade bad active' : 'grade bad'} onClick={this.clickGrade.bind(this, key, 'bad')}>
<Text className='mb-iconfont mb-iconfont-pingjia'></Text><Text> 差评</Text>
</View>
</View>
<View className='good-rate-text'>
<AtTextarea onBlur={(e) => { this.onChangeText.bind(this, key, e)() }} value={this.state.goodsRate[key].content} maxLength={300} placeholder='评价内容最多300字'></AtTextarea>
</View>
</View>
<Text className='image-upload-title'>上传图片:</Text>
<AtImagePicker
style='float: left; margin-left: 20px'
showAddBtn={!(this.state.goodsRate[key].rate_pic.length >= 5)}
files={this.state.goodsRate[key].rate_pic}
onChange={(e) => { this.onChangeImage.bind(this, key, e)() }}
/>
</View>)
}
})
}
<View style='height: 100px; width: 100%'></View>
<View className='footer-btn'>
<AtCheckbox
options={options}
selectedList={this.state.checkedList}
onChange={this.handleChange.bind(this)}
/>
<AtButton type='primary' onClick={this.toRate.bind(this)}>发布评论</AtButton>
</View>
</View>
)
}
}
2.上传头像
import Taro, { Component, showToast } from '@tarojs/taro'
import { AtNavBar } from 'taro-ui'
import { View, Text, Image,ScrollView, Picker } from '@tarojs/components'
import { NavBar, SpToast, HeaderBar, FooterBar, SpCell } from '@/components'
import api from '@/api'
import { withLogin } from '@/hocs'
import S from '@/spx'
import './userinfo.scss'
import SpAvatar from './comps/sp-avatar'
@withLogin()
export default class UserInfo extends Component {
config = {
navigationBarTitleText: '用户信息'
};
constructor (props) {
super(props)
this.state = {
info: {},
selector: ['男', '女'],
selectorChecked: '男',
imgs:[]
}
}
componentDidShow () {
this.fetch()
}
async fetch () {
const memberInfo = await api.member.memberBasicInfo()
this.setState({
info: {
login_account: memberInfo.login_account,
username: memberInfo.username,
name: memberInfo.name,
sex: memberInfo.sex,
birthday: memberInfo.birthday,
portrait_url: memberInfo.portrait_url
},
selectorChecked: memberInfo.sex == '0' ? '女' : memberInfo.sex == '1' ? '男' : '保密'
})
}
handleChange = (name, val) => {
const { info } = this.state
info[name] = val
};
handleSubmit = async e => {
const { value } = e.detail
const data = {
...this.state.info,
...value
}
try {
await api.member.updateBasicInfo(data)
S.toast('修改成功')
} catch (error) {
console.log(error)
}
};
onChange (e) {
const { selector, info } = this.state
this.setState({
info: {
...info,
sex: selector[e.detail.value] == '男' ? '1' : '2'
},
selectorChecked: selector[e.detail.value]
})
}
onTimeChange (e) {
const { info } = this.state
this.setState({
info: {
...info,
birthday: e.detail.value
}
})
this.updateBirthday(e.detail.value)
}
async updateBirthday (value) {
const res = await api.member.updateBasicInfo({
birthday: value
})
if (res.status === 'success') {
S.toast('修改成功')
}
}
async updatePortraitUrl (base64) {
const data = await api.member.uploadFile({
image:base64,
upload_type:'base64',
image_input_title:'image.jpg',
image_type:'portrait'
})
try {
await api.member.updateBasicInfo({
...this.state.info,
portrait_url:data.url
})
this.fetch()
Taro.hideLoading()
S.toast('头像修改成功')
}catch(res){
Taro.hideLoading()
}
}
handleImageChange () {
Taro.chooseImage({
number: 1, // 默认9
success: (res)=> {
if(process.env.TARO_ENV == 'weapp'){
const base64 = 'data:image/png;base64,'+ wx.getFileSystemManager().readFileSync(res.tempFilePaths[0],'base64')
this.updatePortraitUrl(base64)
}else{
Taro.request({
url:res.tempFilePaths[0],
responseType:'arraybuffer',
success:(res2)=>{
let base64 = Taro.arrayBufferToBase64(new Uint8Array(res2.data))
base64 = 'data:image/png;base64,' + base64
this.updatePortraitUrl(base64)
},
fail:()=>{
Taro.hideLoading()
}
})
}
}
})
}
redircteBack=()=>{
Taro.redirectTo({
url:'/pages/member/index'
})
// Taro.switchTab({
// url:'/pages/member/index'
// })
}
render () {
const { info,imgs } = this.state
return (
<View className='userinfo'>
{/* <HeaderBar /> */}
{/* <AtNavBar
onClickLeftIcon={this.redircteBack}
title='会员信息'
leftText='返回'
/> */}
<NavBar title='会员信息'fixed={false} onClickLeftIcon={this.redircteBack}/>
<View className='avatar sp-cell'>
<View className='avatar-title'>头像:</View>
<View className='avatar-photo'>
<View className='avatar-photo_box'
onClick={this.handleImageChange.bind(this)}
>
<Image className='avatar-img' src={info.portrait_url || ''} mode='aspectFill'></Image>
</View>
</View>
</View>
<SpCell title='用户名:' value={info.login_account} />
<SpCell title='姓名:' isLink to='/pages/member/modifyUserName' value={info.username} />
{/* <SpCell title='身份证信息' isLink to='/pages/member/setIdCardNo' /> */}
<SpCell title='昵称:' isLink to='/pages/member/modifyNickName' value={info.name} />
<SpCell title='性别:' isLink to='/pages/member/modifySex' value={this.state.selectorChecked} />
<View className='birthday-picker'>
<Text className='birthday-picker-label'>生日:</Text>
<Picker
mode='date'
className='birthday-picker-content'
value={info.birthday}
onChange={this.onTimeChange.bind(this)}
>
<View className='picker'>
<Text className='picker-input__title'>{info.birthday}</Text>
<Text className='birthday-picker__ft-icon at-icon at-icon-chevron-right'></Text>
</View>
</Picker>
</View>
<SpCell title='收货地址' isLink to='/pages/member/address' />
</View>
)
}
}