<template>
|
|
<view class="maintenance-submit">
|
|
<!-- 保养基本信息 -->
|
|
<view class="maintenance-info">
|
|
<view class="info-header">
|
|
<view class="red-line"></view>
|
|
<text class="info-title">保养项目</text>
|
|
</view>
|
|
|
|
<!-- 保养人 -->
|
|
<view class="form-item">
|
|
<text class="label">保养人</text>
|
|
<view class="input-area" >
|
|
<input
|
|
v-model="maintenanceName"
|
|
placeholder="请填写"
|
|
class="input-field"
|
|
ref="maintainerInput"
|
|
/>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 保养日期 -->
|
|
<view class="form-item" @click="showDatePicker">
|
|
<text class="label">保养日期</text>
|
|
<view class="select-area">
|
|
<text class="value" :class="{ placeholder: !maintenanceDate }">{{ maintenanceDate || '请选择' }}</text>
|
|
<uv-icon name="arrow-down" size="18" color="#000"></uv-icon>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 保养前状态 -->
|
|
<view class="form-item">
|
|
<text class="label">保养前状态</text>
|
|
</view>
|
|
<view class="textarea-container">
|
|
<uv-textarea
|
|
v-model="stateFrontText"
|
|
placeholder="请填写保养前的设备内容"
|
|
:maxlength="200"
|
|
:show-confirm-bar="false"
|
|
height="60"
|
|
border="none"
|
|
:custom-style="{ backgroundColor: '#f5f5f5' }"
|
|
></uv-textarea>
|
|
</view>
|
|
|
|
<!-- 保养前图片 -->
|
|
<view class="image-upload">
|
|
<view v-for="(img, index) in stateFrontImage" :key="index" class="image-item">
|
|
<image :src="img" mode="aspectFill" @click="previewImage(img, stateFrontImage)"></image>
|
|
<view class="delete-btn" @click="deleteBeforeImage(index)">
|
|
<uv-icon name="close" size="12" color="#fff"></uv-icon>
|
|
</view>
|
|
</view>
|
|
<view class="upload-btn" @click="uploadBeforeImage">
|
|
<uv-icon name="camera" size="34" color="#C70019"></uv-icon>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 保养后状态 -->
|
|
<view class="form-item">
|
|
<text class="label">保养后状态</text>
|
|
</view>
|
|
<view class="textarea-container">
|
|
<uv-textarea
|
|
v-model="stateBackText"
|
|
placeholder="请填写保养后的设备内容"
|
|
:maxlength="200"
|
|
:show-confirm-bar="false"
|
|
height="60"
|
|
border="none"
|
|
:custom-style="{ backgroundColor: '#f5f5f5' }"
|
|
></uv-textarea>
|
|
</view>
|
|
|
|
<!-- 保养后图片 -->
|
|
<view class="image-upload">
|
|
<view v-for="(img, index) in stateBackImage" :key="index" class="image-item">
|
|
<image :src="img" mode="aspectFill" @click="previewImage(img, stateBackImage)"></image>
|
|
<view class="delete-btn" @click="deleteAfterImage(index)">
|
|
<uv-icon name="close" size="12" color="#fff"></uv-icon>
|
|
</view>
|
|
</view>
|
|
<view class="upload-btn" @click="uploadAfterImage">
|
|
<uv-icon name="camera" size="34" color="#C70019"></uv-icon>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 是否产生费用 -->
|
|
<view class="form-item">
|
|
<text class="label">是否产生费用</text>
|
|
<view class="radio-options">
|
|
<view
|
|
class="radio-item"
|
|
:class="{ active: isExpend === '1' }"
|
|
@click="selectCost('1')"
|
|
>
|
|
<view class="radio-dot" :class="{ active: isExpend === '1' }"></view>
|
|
<text :class="{ active: isExpend === '1' }">是</text>
|
|
</view>
|
|
<view
|
|
class="radio-item"
|
|
:class="{ active: isExpend === '0' }"
|
|
@click="selectCost('0')"
|
|
>
|
|
<view class="radio-dot" :class="{ active: isExpend === '0' }"></view>
|
|
<text :class="{ active: isExpend === '0' }">否</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 产生费用 -->
|
|
<view v-if="isExpend === '1'" class="cost-section">
|
|
<view class="form-item form-item-header">
|
|
<text class="label active">产生费用</text>
|
|
</view>
|
|
|
|
<view class="cost-input">
|
|
<text class="label">费用名称</text>
|
|
<uv-input
|
|
v-model="newCostName"
|
|
placeholder="请输入费用"
|
|
border="none"
|
|
:custom-style="{ backgroundColor: '#fff', borderRadius: '4px', textAlign: 'right', marginLeft: '24rpx' }"
|
|
></uv-input>
|
|
</view>
|
|
|
|
<view class="cost-list">
|
|
<view class="cost-header">
|
|
<text class="header-item">费用名称</text>
|
|
<text class="header-item">数量</text>
|
|
<text class="header-item">金额</text>
|
|
</view>
|
|
|
|
<view v-for="(item, index) in costList" :key="index" class="cost-item">
|
|
<text class="cost-name">{{ item.name }}</text>
|
|
<view class="quantity-control">
|
|
<uv-icon
|
|
name="minus-circle"
|
|
size="20"
|
|
:color="item.quantity > 1 ? '#C70019' : '#ccc'"
|
|
@click="decreaseQuantity(index)"
|
|
></uv-icon>
|
|
<text class="quantity">{{ item.quantity }}</text>
|
|
<uv-icon
|
|
name="plus-circle"
|
|
size="20"
|
|
color="#C70019"
|
|
@click="increaseQuantity(index)"
|
|
></uv-icon>
|
|
</view>
|
|
<uv-input
|
|
v-model="item.amount"
|
|
placeholder="0.00"
|
|
type="digit"
|
|
border="none"
|
|
:custom-style="{ backgroundColor: '#f5f5f5', borderRadius: '4px', textAlign: 'right' }"
|
|
></uv-input>
|
|
<uv-icon
|
|
name="close-circle"
|
|
size="20"
|
|
color="#C70019"
|
|
@click="removeCostItem(index)"
|
|
></uv-icon>
|
|
</view>
|
|
|
|
<view class="add-cost-btn" @click="addCostItem">
|
|
<uv-icon name="plus-circle" size="20" color="#C70019"></uv-icon>
|
|
<text>添加费用项目</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 附件信息 -->
|
|
<view class="form-item form-item-header">
|
|
<text class="label active">附件信息</text>
|
|
</view>
|
|
|
|
<!-- 保养备注 -->
|
|
<view class="form-item">
|
|
<text class="label">保养备注</text>
|
|
</view>
|
|
<view class="textarea-container">
|
|
<uv-textarea
|
|
v-model="remarkText"
|
|
placeholder="请填写备注"
|
|
:maxlength="200"
|
|
:show-confirm-bar="false"
|
|
height="60"
|
|
border="none"
|
|
:custom-style="{ backgroundColor: '#f5f5f5' }"
|
|
></uv-textarea>
|
|
</view>
|
|
|
|
<!-- 附件图片 -->
|
|
<view class="image-upload">
|
|
<view v-for="(img, index) in remarkImage" :key="index" class="image-item">
|
|
<image :src="img" mode="aspectFill" @click="previewImage(img, remarkImage)"></image>
|
|
<view class="delete-btn" @click="deleteAttachment(index)">
|
|
<uv-icon name="close" size="12" color="#fff"></uv-icon>
|
|
</view>
|
|
</view>
|
|
<view class="upload-btn" @click="uploadAttachment">
|
|
<uv-icon name="camera" size="34" color="#C70019"></uv-icon>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 下次保养日期 -->
|
|
<view class="form-item" @click="showNextDatePicker">
|
|
<text class="label">下次保养日期</text>
|
|
<view class="select-area">
|
|
<text class="value" :class="{ placeholder: !malfunctionDate }">{{ malfunctionDate || '请选择' }}</text>
|
|
<uv-icon name="arrow-down" size="18" color="#000"></uv-icon>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 备注 -->
|
|
<view class="form-item">
|
|
<text class="label">备注</text>
|
|
</view>
|
|
<view class="textarea-container">
|
|
<uv-textarea
|
|
v-model="remark"
|
|
placeholder="请填写备注"
|
|
:maxlength="200"
|
|
:show-confirm-bar="false"
|
|
height="60"
|
|
border="none"
|
|
:custom-style="{ backgroundColor: '#f5f5f5' }"
|
|
></uv-textarea>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 提交按钮 -->
|
|
<view class="submit-container">
|
|
<uv-button
|
|
type="primary"
|
|
text="立即提交"
|
|
:disabled="submiting"
|
|
:custom-style="{ backgroundColor: '#C70019', borderRadius: '25px' }"
|
|
@click="submitMaintenance"
|
|
></uv-button>
|
|
</view>
|
|
|
|
<!-- 日期选择器 -->
|
|
<uv-datetime-picker
|
|
confirm-color="#C70019"
|
|
ref="datePicker"
|
|
mode="date"
|
|
@confirm="confirmDate"
|
|
></uv-datetime-picker>
|
|
|
|
<uv-datetime-picker
|
|
confirm-color="#C70019"
|
|
ref="nextDatePicker"
|
|
mode="date"
|
|
@confirm="confirmNextDate"
|
|
></uv-datetime-picker>
|
|
</view>
|
|
</template>
|
|
|
|
<script>
|
|
export default {
|
|
data() {
|
|
return {
|
|
// 表单数据
|
|
maintenanceName: '',
|
|
maintenanceDate: '',
|
|
stateFrontText: '',
|
|
stateFrontImage: [],
|
|
stateBackText: '',
|
|
stateBackImage: [],
|
|
isExpend: '0',
|
|
newCostName: '',
|
|
costList: [],
|
|
remarkText: '',
|
|
remarkImage: [],
|
|
malfunctionDate: '',
|
|
remark: '',
|
|
showpieceId: '',
|
|
submiting: false
|
|
}
|
|
},
|
|
computed: {
|
|
// 计算总金额
|
|
amount() {
|
|
return this.costList.reduce((sum, item) => sum + (parseFloat(item.amount) * Number(item.quantity) || 0), 0)
|
|
}
|
|
},
|
|
methods: {
|
|
// 显示日期选择器
|
|
showDatePicker() {
|
|
this.$refs.datePicker.open()
|
|
},
|
|
|
|
// 确认日期
|
|
confirmDate(e) {
|
|
// uv-datetime-picker返回的是时间戳,需要转换为日期格式
|
|
this.maintenanceDate = this.$utils.formatTime(e.value)
|
|
},
|
|
|
|
// 显示下次保养日期选择器
|
|
showNextDatePicker() {
|
|
this.$refs.nextDatePicker.open()
|
|
},
|
|
|
|
// 确认下次保养日期
|
|
confirmNextDate(e) {
|
|
// uv-datetime-picker返回的是时间戳,需要转换为日期格式
|
|
this.malfunctionDate = this.$utils.formatTime(e.value)
|
|
},
|
|
|
|
// 选择是否产生费用
|
|
selectCost(value) {
|
|
this.isExpend = value
|
|
if (!value) {
|
|
this.costList = []
|
|
this.newCostName = ''
|
|
}
|
|
},
|
|
|
|
// 添加费用项目
|
|
addCostItem() {
|
|
if (!this.newCostName.trim()) {
|
|
uni.showToast({ title: '请输入费用名称', icon: 'none' })
|
|
return
|
|
}
|
|
|
|
this.costList.push({
|
|
name: this.newCostName,
|
|
quantity: 1,
|
|
amount: ''
|
|
})
|
|
this.newCostName = ''
|
|
},
|
|
|
|
// 删除费用项目
|
|
removeCostItem(index) {
|
|
if (this.costList.length > 1) {
|
|
this.costList.splice(index, 1)
|
|
} else {
|
|
uni.showToast({ title: '至少保留一个费用项目', icon: 'none' })
|
|
}
|
|
},
|
|
|
|
// 增加数量
|
|
increaseQuantity(index) {
|
|
this.costList[index].quantity++
|
|
},
|
|
|
|
// 减少数量
|
|
decreaseQuantity(index) {
|
|
if (this.costList[index].quantity > 1) {
|
|
this.costList[index].quantity--
|
|
}
|
|
},
|
|
|
|
// 上传保养前图片
|
|
async uploadBeforeImage() {
|
|
try {
|
|
const result = await this.$utils.chooseAndUpload()
|
|
if (result && result.success) {
|
|
console.log(result);
|
|
|
|
this.stateFrontImage.push(result.url)
|
|
}
|
|
} catch (error) {
|
|
console.error('图片上传失败:', error)
|
|
uni.showToast({
|
|
title: '图片上传失败',
|
|
icon: 'error'
|
|
})
|
|
}
|
|
},
|
|
|
|
// 删除保养前图片
|
|
deleteBeforeImage(index) {
|
|
this.stateFrontImage.splice(index, 1)
|
|
},
|
|
|
|
// 上传保养后图片
|
|
async uploadAfterImage() {
|
|
try {
|
|
const result = await this.$utils.chooseAndUpload()
|
|
if (result && result.success) {
|
|
console.log(result);
|
|
|
|
this.stateBackImage.push(result.url)
|
|
}
|
|
} catch (error) {
|
|
console.error('头像上传失败:', error)
|
|
uni.showToast({
|
|
title: '头像上传失败',
|
|
icon: 'error'
|
|
})
|
|
}
|
|
},
|
|
|
|
// 删除保养后图片
|
|
deleteAfterImage(index) {
|
|
this.stateBackImage.splice(index, 1)
|
|
},
|
|
|
|
// 上传附件
|
|
async uploadAttachment() {
|
|
|
|
try {
|
|
const result = await this.$utils.chooseAndUpload()
|
|
if (result && result.success) {
|
|
console.log(result);
|
|
|
|
this.remarkImage.push(result.url)
|
|
}
|
|
} catch (error) {
|
|
console.error('头像上传失败:', error)
|
|
uni.showToast({
|
|
title: '头像上传失败',
|
|
icon: 'error'
|
|
})
|
|
}
|
|
},
|
|
|
|
// 删除附件
|
|
deleteAttachment(index) {
|
|
this.remarkImage.splice(index, 1)
|
|
},
|
|
|
|
// 预览图片
|
|
previewImage(url, imageList) {
|
|
uni.previewImage({
|
|
urls: imageList,
|
|
current: url
|
|
})
|
|
},
|
|
|
|
|
|
// 提交保养
|
|
async submitMaintenance() {
|
|
// 表单验证
|
|
if (!this.maintenanceName.trim()) {
|
|
uni.showToast({ title: '请填写保养人', icon: 'none' })
|
|
return
|
|
}
|
|
|
|
if (!this.stateFrontText.trim()) {
|
|
uni.showToast({ title: '请填写保养前状态', icon: 'none' })
|
|
return
|
|
}
|
|
if (!this.stateBackText.trim()) {
|
|
uni.showToast({ title: '请填写保养后状态', icon: 'none' })
|
|
return
|
|
}
|
|
|
|
if (this.isExpend === '1' && !this.amount){
|
|
uni.showToast({ title: '请填写消费', icon: 'none' })
|
|
return
|
|
}
|
|
// 把costList切换成字符串并用,,;分割
|
|
// 提交数据
|
|
const formData = {
|
|
maintenanceName: this.maintenanceName,
|
|
maintenanceDate: this.maintenanceDate,
|
|
stateFrontText: this.stateFrontText,
|
|
stateFrontImage: this.stateFrontImage?.join(',') || '',
|
|
stateBackText: this.stateBackText,
|
|
stateBackImage: this.stateBackImage?.join(',') || '',
|
|
expenseList: this.costList.map(item => {
|
|
return `${item.name},${item.quantity},${item.amount}`
|
|
}).join(';'),
|
|
isExpend: this.isExpend,
|
|
amount: this.amount,
|
|
remarkText: this.remarkText,
|
|
remarkImage: this.remarkImage?.join(',') || '',
|
|
malfunctionDate: this.malfunctionDate,
|
|
remark: this.remark,
|
|
showpieceId: this.showpieceId
|
|
}
|
|
|
|
|
|
this.submiting = true
|
|
try{
|
|
|
|
const subRes = await this.$api.exhibit.addMaintenance(formData)
|
|
if(subRes.code == 200){
|
|
uni.showToast({ title: subRes.message, icon: 'success' })
|
|
// 返回上一页
|
|
setTimeout(() => {
|
|
uni.navigateBack()
|
|
}, 1000)
|
|
}else{
|
|
uni.showToast({ title: subRes.message, icon: 'none' })
|
|
}
|
|
}catch(err){
|
|
// uni.showToast({ title: err.message, icon: 'none' })
|
|
this.submiting = false
|
|
}
|
|
}
|
|
},
|
|
onLoad(options) {
|
|
this.showpieceId = options.id
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.maintenance-submit {
|
|
min-height: 100vh;
|
|
background-color: #f5f5f5;
|
|
padding-bottom: 200rpx;
|
|
}
|
|
|
|
.maintenance-info {
|
|
margin: 18rpx;
|
|
background: #ffffff;
|
|
border-radius: 15rpx;
|
|
box-shadow: 0rpx 3rpx 6rpx 0rpx rgba(0,0,0,0.16);
|
|
padding: 40rpx;
|
|
|
|
.info-header {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 40rpx;
|
|
|
|
.red-line {
|
|
width: 9rpx;
|
|
height: 33rpx;
|
|
background-color: $primary-color;
|
|
margin-right: 7rpx;
|
|
border-radius: 5rpx;
|
|
}
|
|
|
|
.info-title {
|
|
font-size: 30rpx;
|
|
font-weight: bold;
|
|
color: $primary-text-color;
|
|
}
|
|
}
|
|
|
|
.form-item-header {
|
|
border-bottom: none;
|
|
margin-top: 20rpx;
|
|
}
|
|
|
|
.form-item {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 24rpx 0;
|
|
border-bottom: 2rpx solid #f0f0f0;
|
|
|
|
&:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.label {
|
|
font-size: 30rpx;
|
|
color: $primary-text-color;
|
|
flex-shrink: 0;
|
|
|
|
&.active {
|
|
font-weight: bold;
|
|
}
|
|
}
|
|
|
|
.value {
|
|
font-size: 30rpx;
|
|
color: $secondary-text-color;
|
|
|
|
&.placeholder {
|
|
color: $secondary-text-color;
|
|
}
|
|
}
|
|
|
|
.select-area {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16rpx;
|
|
}
|
|
|
|
.input-area {
|
|
flex: 1;
|
|
// background-color: #f5f5f5;
|
|
border-radius: 8rpx;
|
|
padding: 16rpx 24rpx;
|
|
margin-left: 24rpx;
|
|
|
|
.input-field {
|
|
width: 100%;
|
|
font-size: 30rpx;
|
|
color: $primary-text-color;
|
|
background: transparent;
|
|
border: none;
|
|
outline: none;
|
|
text-align: right;
|
|
|
|
&::placeholder {
|
|
color: $secondary-text-color;
|
|
}
|
|
}
|
|
}
|
|
|
|
.radio-options {
|
|
display: flex;
|
|
gap: 60rpx;
|
|
|
|
.radio-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16rpx;
|
|
|
|
.radio-dot {
|
|
width: 32rpx;
|
|
height: 32rpx;
|
|
border: 4rpx solid #ddd;
|
|
border-radius: 50%;
|
|
position: relative;
|
|
|
|
&.active {
|
|
border-color: $primary-color;
|
|
|
|
&::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
width: 16rpx;
|
|
height: 16rpx;
|
|
background-color: $primary-color;
|
|
border-radius: 50%;
|
|
}
|
|
}
|
|
}
|
|
|
|
text {
|
|
font-size: 30rpx;
|
|
color: $secondary-text-color;
|
|
|
|
&.active {
|
|
color: $primary-color;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.textarea-container {
|
|
border-radius: 8rpx;
|
|
}
|
|
|
|
.image-upload {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 24rpx;
|
|
margin: 16rpx 0;
|
|
|
|
.upload-btn {
|
|
width: 160rpx;
|
|
height: 160rpx;
|
|
border: 2rpx dashed $primary-color;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background-color: #fff;
|
|
}
|
|
|
|
.image-item {
|
|
position: relative;
|
|
width: 160rpx;
|
|
height: 160rpx;
|
|
|
|
image {
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: 8rpx;
|
|
}
|
|
|
|
.delete-btn {
|
|
position: absolute;
|
|
top: -12rpx;
|
|
right: -12rpx;
|
|
width: 40rpx;
|
|
height: 40rpx;
|
|
background-color: #ff4757;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
}
|
|
}
|
|
|
|
.cost-section {
|
|
.cost-input {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
padding: 24rpx 0;
|
|
border-bottom: 2rpx solid #f0f0f0;
|
|
|
|
.label {
|
|
font-size: 30rpx;
|
|
color: $primary-text-color;
|
|
flex-shrink: 0;
|
|
margin-right: 24rpx;
|
|
}
|
|
}
|
|
|
|
.cost-list {
|
|
.cost-header {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 24rpx 0;
|
|
border-bottom: 4rpx solid #f0f0f0;
|
|
|
|
.header-item {
|
|
flex: 1;
|
|
font-size: 28rpx;
|
|
font-weight: bold;
|
|
color: $primary-text-color;
|
|
text-align: center;
|
|
|
|
&:first-child {
|
|
text-align: left;
|
|
}
|
|
}
|
|
}
|
|
|
|
.cost-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 24rpx 0;
|
|
border-bottom: 2rpx solid #f0f0f0;
|
|
gap: 24rpx;
|
|
|
|
.cost-name {
|
|
flex: 1;
|
|
font-size: 28rpx;
|
|
color: $primary-text-color;
|
|
}
|
|
|
|
.quantity-control {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16rpx;
|
|
|
|
.quantity {
|
|
font-size: 28rpx;
|
|
color: $primary-text-color;
|
|
min-width: 40rpx;
|
|
text-align: center;
|
|
}
|
|
}
|
|
}
|
|
|
|
.add-cost-btn {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 16rpx;
|
|
padding: 24rpx 0;
|
|
color: $primary-color;
|
|
|
|
text {
|
|
font-size: 28rpx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.submit-container {
|
|
position: fixed;
|
|
bottom: 0;
|
|
left: 0;
|
|
right: 0;
|
|
padding: 32rpx;
|
|
background-color: #fff;
|
|
border-top: 2rpx solid #f0f0f0;
|
|
}
|
|
</style>
|