|
|
- <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>
|