feat(approval): 添加退还申请页面及文档更新
添加退还申请页面 submit.vue,实现表单提交、图片上传压缩功能 更新迁移文档,添加退还申请页面的迁移说明 在 pages.json 中注册新页面
This commit is contained in:
parent
077db01306
commit
e37764de95
|
|
@ -13,3 +13,8 @@
|
|||
@doc\thirdParty\src\pages\rental\index.vue
|
||||
我的柜子页面也迁移到本项目。注意thirdParty下的是H5项目,现在需要改为微信小程序uni-app。api需要使用原Product
|
||||
List.vue中已经移植到本项目的相应api,stores也需要使用移植后的pinia。生成的代码写到 @src\pages\order\ 文件夹下
|
||||
|
||||
参考已迁移至本项目的代码 @src\pages\index\ 和迁移文档 @doc\迁移工作总结.md 。将
|
||||
@doc\thirdParty\src\pages\approval\submit.vue
|
||||
退还申请页面也迁移到本项目。注意thirdParty下的是H5项目,现在需要改为微信小程序uni-app。api需要使用原项目中已经移
|
||||
植到本项目的相应api,stores也需要使用移植后的pinia。生成的代码写到 @src\pages\approval\ 文件夹下
|
||||
|
|
@ -61,6 +61,14 @@
|
|||
},
|
||||
"excludeLoginPath": false
|
||||
},
|
||||
{
|
||||
"path": "pages/approval/submit",
|
||||
"type": "page",
|
||||
"style": {
|
||||
"navigationBarTitleText": "退还"
|
||||
},
|
||||
"enablePullDownRefresh": false
|
||||
},
|
||||
{
|
||||
"path": "pages/index/checkout",
|
||||
"type": "page"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,372 @@
|
|||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import { submitApprovalApi } from '@/api/approval'
|
||||
import type { SubmitApprovalRequestData } from '@/api/approval/types'
|
||||
import { useOrderStore } from '@/pinia/stores/order'
|
||||
import { useWxStoreOutside } from '@/pinia/stores/wx'
|
||||
import { getEnvBaseUploadUrl } from '@/utils'
|
||||
|
||||
// 页面配置
|
||||
definePage({
|
||||
style: {
|
||||
navigationBarTitleText: '退还',
|
||||
},
|
||||
enablePullDownRefresh: false,
|
||||
})
|
||||
|
||||
const orderStore = useOrderStore()
|
||||
const wxStore = useWxStoreOutside()
|
||||
|
||||
// 获取页面参数
|
||||
const orderGoodsId = ref<number>(0)
|
||||
const orderId = ref<number>(0)
|
||||
|
||||
onLoad((options: any) => {
|
||||
console.log('页面参数:', options)
|
||||
if (options.orderGoodsId) {
|
||||
orderGoodsId.value = Number(options.orderGoodsId)
|
||||
}
|
||||
if (options.orderId) {
|
||||
orderId.value = Number(options.orderId)
|
||||
}
|
||||
})
|
||||
|
||||
const formData = ref<SubmitApprovalRequestData>({
|
||||
orderGoodsId: orderGoodsId.value,
|
||||
returnQuantity: 1,
|
||||
returnImages: '',
|
||||
returnRemark: '',
|
||||
corpid: wxStore.corpid,
|
||||
applyUserid: wxStore.userid,
|
||||
})
|
||||
|
||||
watch(orderGoodsId, (newVal) => {
|
||||
formData.value.orderGoodsId = newVal
|
||||
})
|
||||
|
||||
const submitting = ref(false)
|
||||
|
||||
// 图片上传相关
|
||||
interface UploadedFile {
|
||||
url: string
|
||||
}
|
||||
const uploadedFiles = ref<UploadedFile[]>([])
|
||||
const uploading = ref(false)
|
||||
|
||||
// 获取上传地址
|
||||
const uploadUrl = `${getEnvBaseUploadUrl()}/file/upload`
|
||||
|
||||
// 选择图片
|
||||
const chooseImages = () => {
|
||||
uni.chooseMedia({
|
||||
count: 3 - uploadedFiles.value.length,
|
||||
mediaType: ['image'],
|
||||
sourceType: ['album', 'camera'],
|
||||
maxDuration: 30,
|
||||
camera: 'back',
|
||||
success: (res) => {
|
||||
console.log('选择图片成功:', res)
|
||||
uploadImages(res.tempFiles)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('选择图片失败:', err)
|
||||
uni.showToast({
|
||||
title: '选择图片失败',
|
||||
icon: 'none',
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// 压缩图片(微信小程序替代方案)
|
||||
// 注意:H5版本使用 compressorjs 库进行压缩
|
||||
// 但小程序环境没有 File API 和 Canvas,因此使用 uni.compressImage 作为替代
|
||||
const compressImage = (tempFilePath: string): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.compressImage({
|
||||
src: tempFilePath,
|
||||
quality: 0.8, // 压缩质量,范围0-1(类似 compressorjs 的 quality 参数)
|
||||
maxWidth: 1280, // 最大宽度(类似 compressorjs 的 maxWidth 参数)
|
||||
maxHeight: 1280, // 最大高度(类似 compressorjs 的 maxHeight 参数)
|
||||
success: (res) => {
|
||||
console.log('图片压缩成功:', res)
|
||||
resolve(res.tempFilePath)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('图片压缩失败:', err)
|
||||
// 压缩失败则使用原图
|
||||
resolve(tempFilePath)
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// 上传图片
|
||||
const uploadImages = (files: UniApp.MediaFile[]) => {
|
||||
uploading.value = true
|
||||
|
||||
const uploadPromises = files.map(async (file) => {
|
||||
// 先压缩图片
|
||||
const compressedPath = await compressImage(file.tempFilePath)
|
||||
|
||||
return new Promise<UploadedFile>((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: uploadUrl,
|
||||
filePath: compressedPath,
|
||||
name: 'file',
|
||||
formData: {},
|
||||
header: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
success: (uploadRes) => {
|
||||
try {
|
||||
const data = JSON.parse(uploadRes.data)
|
||||
if (data.code === 0) {
|
||||
resolve({ url: data.data.url })
|
||||
} else {
|
||||
reject(new Error(data.message || '上传失败'))
|
||||
}
|
||||
} catch (error) {
|
||||
reject(new Error('响应解析失败'))
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err)
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Promise.all(uploadPromises)
|
||||
.then((results) => {
|
||||
uploadedFiles.value.push(...results)
|
||||
uni.showToast({
|
||||
title: '上传成功',
|
||||
icon: 'success',
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('上传失败:', error)
|
||||
uni.showToast({
|
||||
title: error.message || '上传失败',
|
||||
icon: 'none',
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
uploading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
// 删除图片
|
||||
const deleteImage = (index: number) => {
|
||||
uploadedFiles.value.splice(index, 1)
|
||||
}
|
||||
|
||||
// 表单验证
|
||||
const validateForm = () => {
|
||||
if (!formData.value.orderGoodsId || isNaN(formData.value.orderGoodsId)) {
|
||||
uni.showToast({
|
||||
title: '订单ID参数错误',
|
||||
icon: 'none',
|
||||
})
|
||||
return false
|
||||
}
|
||||
if (formData.value.returnQuantity < 1) {
|
||||
uni.showToast({
|
||||
title: '退还数量至少为1',
|
||||
icon: 'none',
|
||||
})
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// 提交表单
|
||||
const handleSubmit = async () => {
|
||||
if (!validateForm()) return
|
||||
|
||||
submitting.value = true
|
||||
try {
|
||||
// 组装图片URL
|
||||
formData.value.returnImages = uploadedFiles.value.map(item => item.url).join(',')
|
||||
formData.value.corpid = wxStore.corpid
|
||||
formData.value.applyUserid = wxStore.userid
|
||||
|
||||
console.log('提交数据:', formData.value)
|
||||
|
||||
const { code, data } = await submitApprovalApi(formData.value)
|
||||
|
||||
if (code === 0) {
|
||||
// 刷新订单列表
|
||||
orderStore.getOrders(
|
||||
wxStore.corpid,
|
||||
wxStore.openid,
|
||||
wxStore.qyUserId,
|
||||
0
|
||||
)
|
||||
|
||||
uni.showModal({
|
||||
title: '提交成功',
|
||||
content: '退货申请已提交,等待管理员审核',
|
||||
showCancel: false,
|
||||
success: () => {
|
||||
// 返回上一页
|
||||
uni.navigateBack()
|
||||
},
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交失败:', error)
|
||||
uni.showModal({
|
||||
title: '提交失败',
|
||||
content: error instanceof Error ? error.message : '网络请求异常',
|
||||
showCancel: false,
|
||||
})
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="approval-container">
|
||||
<view class="content-wrapper">
|
||||
<wd-cell-group>
|
||||
<wd-input
|
||||
v-model="formData.returnQuantity"
|
||||
label="退还数量"
|
||||
type="number"
|
||||
:min="1"
|
||||
placeholder="请输入退还数量"
|
||||
/>
|
||||
<wd-textarea
|
||||
v-model="formData.returnRemark"
|
||||
label="退货备注"
|
||||
auto-height
|
||||
placeholder="请输入退货备注"
|
||||
/>
|
||||
</wd-cell-group>
|
||||
|
||||
<wd-cell-group custom-class="upload-section">
|
||||
<wd-cell title="凭证图片" value="">
|
||||
<template #extra>
|
||||
<view class="upload-area">
|
||||
<view
|
||||
v-for="(file, index) in uploadedFiles"
|
||||
:key="index"
|
||||
class="uploaded-image"
|
||||
>
|
||||
<image
|
||||
:src="file.url"
|
||||
mode="aspectFill"
|
||||
class="image-preview"
|
||||
/>
|
||||
<view class="delete-btn" @tap="() => deleteImage(index)">
|
||||
<wd-icon name="delete" size="16px" color="#fff" />
|
||||
</view>
|
||||
</view>
|
||||
<view
|
||||
v-if="uploadedFiles.length < 3"
|
||||
class="upload-button"
|
||||
@tap="chooseImages"
|
||||
>
|
||||
<wd-icon name="camera" size="32px" color="#ccc" />
|
||||
<text class="upload-text">
|
||||
{{ uploading ? '上传中...' : '点击上传' }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</wd-cell>
|
||||
</wd-cell-group>
|
||||
|
||||
<view class="submit-bar">
|
||||
<wd-button
|
||||
type="primary"
|
||||
block
|
||||
:loading="submitting"
|
||||
:disabled="uploading"
|
||||
@tap="handleSubmit"
|
||||
>
|
||||
{{ submitting ? '提交中...' : '提交申请' }}
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.approval-container {
|
||||
min-height: 100vh;
|
||||
background-color: #f7f8fa;
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
padding-top: 20rpx;
|
||||
padding-bottom: 160rpx;
|
||||
}
|
||||
|
||||
.upload-section {
|
||||
margin: 20rpx 0;
|
||||
}
|
||||
|
||||
.upload-area {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.uploaded-image {
|
||||
position: relative;
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 8rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
position: absolute;
|
||||
top: 8rpx;
|
||||
right: 8rpx;
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.upload-button {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border: 2rpx dashed #ddd;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.upload-text {
|
||||
margin-top: 16rpx;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.submit-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 20rpx 32rpx;
|
||||
background-color: #fff;
|
||||
box-shadow: 0 -4rpx 24rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
</style>
|
||||
Loading…
Reference in New Issue