index.vue 9.11 KB
<template>
  <view class="u-page">
    <!-- 核心:将所有 up-form-item 包裹在同一个 up-form 内 -->
    <view class="inspect-form-content commonPageLRpadding">
      <up-form
          label-position="left"
          :model="inspectForm"
          ref="inspectFormRef"
          labelWidth="140rpx"
      >
        <!-- 1. 巡查描述(文本域) -->
        <up-form-item
            prop="content"
            class="form-item"
        >
          <up-textarea
              v-model="inspectForm.content"
              placeholder="请输入巡查描述"
              maxlength="200"
              count
          ></up-textarea>
        </up-form-item>

        <!-- 2. 上传图片 -->
        <up-form-item
            label="上传图片"
            prop="images"
            required
            border-bottom
            class="form-item"
        >
          <up-upload
              :file-list="imagesList"
              @after-read="(event) => uploadImgs(event)"
              @delete="(event) => deleteImg(event)"
              @on-exceed="handleExceed"
              multiple
              :max-count="3"
              upload-text="选择图片"
              del-color="#ff4d4f"
              class="upload-wrap"
          ></up-upload>
          <view class="tips">(最少1张,最多3张)</view>
        </up-form-item>

        <!-- 3. 转为工单(单选框) -->
        <up-form-item
            label="转为工单"
            prop="isWorkOrder"
            required
            class="form-item"
        >
          <up-radio-group
              v-model="inspectForm.isWorkOrder"
              active-color="#1989fa"
              direction="row"
              class="radio-group"
          >
            <up-radio
                :custom-style="{marginRight: '40rpx'}"
                v-for="(item, index) in radioList"
                :key="index"
                :label="item.label"
                :name="item.value"
            >
              {{ item.label }}
            </up-radio>
          </up-radio-group>
        </up-form-item>

      </up-form>
    </view>

    <!-- 底部提交按钮 -->
    <view class="fixed-bottom-btn-wrap">
      <up-button
          type="primary"
          text="提交"
          @click="submitInspect"
          :style="{ width: '100%', height: '88rpx', fontSize: '32rpx', borderRadius: 0 }"
      ></up-button>
    </view>
  </view>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import type { UniFormRef } from '@/uni_modules/uview-plus/types'
// 定义ref供选项式API使用
const inspectFormRef = ref<UniFormRef>(null)
</script>

<script lang="ts">
import { uploadImages } from '@/common/utils/upload';

export default {
  data() {
    return {
      // 图片列表
      imagesList: [],
      // 单选列表
      radioList: [
        { label: '是', value: '1' },
        { label: '否', value: '2' }
      ],
      // 巡查表单数据
      inspectForm: {
        content: '',        // 巡查描述
        isWorkOrder: '1'    // 是否转为工单 1:是(默认) 2:否
      },
      // 表单校验规则
      inspectFormRules: {
        images: [
          {
            required: true,
            message: '请上传图片',
            trigger: 'change',
            validator: (rule, value, callback) => {
              // 自定义校验规则:检查是否有成功上传的图片
              const hasSuccessImg = this.imagesList.some(item => item.status === 'success')
              const imgCount = this.imagesList.filter(item => item.status === 'success').length

              if (!hasSuccessImg || imgCount < 1) {
                callback(new Error('最少需要上传1张图片'))
              } else if (imgCount > 3) {
                callback(new Error('最多只能上传3张图片'))
              } else {
                callback()
              }
            }
          }
        ],
        isWorkOrder: [
          { type: 'string', required: true, message: '请选择是否转为工单', trigger: ['change'] }
        ]
      }
    }
  },
  onReady() {
    // 兼容微信小程序,通过setRules设置校验规则
    this.$refs.inspectFormRef.setRules(this.inspectFormRules)
    console.log('巡查表单规则初始化完成')
  },
  methods: {
    /**
     * 删除图片
     */
    deleteImg(event) {
      console.log('删除图片事件:', event)
      this.imagesList.splice(event.index, 1)
      // 删除图片后重新校验图片字段
      this.$refs.inspectFormRef.validateField('images')
      uni.showToast({ title: '图片删除成功', icon: 'success' })
    },

    /**
     * 上传图片
     */
    async uploadImgs(event) {
      console.log('上传图片事件:', event)
      const fileList = Array.isArray(event.file) ? event.file : [event.file]
      const targetImgList = this.imagesList

      const filePaths = fileList.map(item => item.url)
      const tempItems = fileList.map(item => ({
        ...item,
        status: 'uploading',
        message: '上传中'
      }))
      const startIndex = targetImgList.length
      targetImgList.push(...tempItems)

      try {
        const uploadResultUrls = await uploadImages({
          filePaths: filePaths,
          ignoreError: true
        })
        console.log('上传成功的URL列表:', uploadResultUrls)

        uploadResultUrls.forEach((url, index) => {
          if (targetImgList[startIndex + index]) {
            targetImgList.splice(startIndex + index, 1, {
              ...fileList[index],
              status: 'success',
              message: '',
              url: url
            })
          }
        })

        if (uploadResultUrls.length < fileList.length) {
          const failCount = fileList.length - uploadResultUrls.length
          for (let i = uploadResultUrls.length; i < fileList.length; i++) {
            if (targetImgList[startIndex + i]) {
              targetImgList.splice(startIndex + i, 1, {
                ...fileList[i],
                status: 'failed',
                message: '上传失败'
              })
            }
          }
          uni.showToast({ title: `成功上传${uploadResultUrls.length}张,失败${failCount}张`, icon: 'none' })
        } else {
          uni.showToast({ title: `成功上传${fileList.length}张图片`, icon: 'success' })
        }

        // 上传完成后重新校验图片字段
        this.$refs.inspectFormRef.validateField('images')
      } catch (err) {
        console.error('图片上传失败:', err)
        for (let i = 0; i < fileList.length; i++) {
          if (targetImgList[startIndex + i]) {
            targetImgList.splice(startIndex + i, 1, {
              ...fileList[i],
              status: 'failed',
              message: '上传失败'
            })
          }
        }
        uni.showToast({ title: '图片上传失败,请重试', icon: 'none' })

        // 上传失败后重新校验图片字段
        this.$refs.inspectFormRef.validateField('images')
      }
    },

    /**
     * 处理图片超出数量限制
     */
    handleExceed() {
      uni.showToast({ title: '最多只能上传3张图片', icon: 'none' })
    },

    /**
     * 提取图片URL数组
     */
    getImgUrlList(imgList) {
      return imgList.filter(item => item.status === 'success').map(item => item.url)
    },

    /**
     * 提交巡查表单
     */
    async submitInspect() {
      console.log('当前选择是否转为工单:', this.inspectForm.isWorkOrder)
      try {
        // 先执行表单校验
        await this.$refs.inspectFormRef.validate()

        // 构造提交数据
        const submitData = {
          content: this.inspectForm.content,
          images: this.getImgUrlList(this.imagesList),
          isWorkOrder: this.inspectForm.isWorkOrder // 1=是,2=否
        }

        // 显示加载中
        uni.showLoading({ title: '提交中...' })

        // 这里替换为实际的接口调用
        // const res = await yourSubmitApi(submitData)

        // 模拟接口调用延迟
        await new Promise(resolve => setTimeout(resolve, 1500))

        uni.hideLoading()
        uni.showToast({
          title: '提交成功',
          icon: 'success',
          duration: 1500
        })

        // 重置表单(保留默认值:转为工单=是)
        setTimeout(() => {
          this.$refs.inspectFormRef.resetFields()
          this.imagesList = []
          this.inspectForm = {
            content: '',
            isWorkOrder: '1' // 重置后仍默认选中“是”
          }
        }, 1500)

      } catch (error) {
        // 隐藏加载框
        uni.hideLoading()

        // 区分是表单校验失败还是接口调用失败
        if (Array.isArray(error)) {
          // 表单校验失败 - 静默处理(uView会自动提示)
        } else {
          // 接口调用失败
          console.error('巡查表单提交失败:', error)
          uni.showToast({
            title: '提交失败,请重试',
            icon: 'none',
            duration: 2000
          })
        }
      }
    }
  }
}
</script>

<style lang="scss" scoped>
// 全局页面样式
.u-page {
}

// 巡查表单内容容器
.inspect-form-content {
  background: #fff;
  padding: 20rpx;
}

</style>