addTree.vue 12.3 KB
<template>
  <view class="container">
    <up-form :model="formData" ref="formRef" label-width="140rpx" border-bottom>
      <up-form-item label="名称" prop="treetype" required>
        <up-input v-model="formData.treetype" placeholder="请输入名称" maxlength="30" border="none" />
      </up-form-item>

      <up-row gutter="10">
        <up-col span="6">
          <up-form-item label="胸径" prop="dbh" required>
            <up-input v-model="formData.dbh" placeholder="请输入" maxlength="10" border="none" input-align="left" />
            <template #right>
              <text style="padding-left: 12rpx;color:#ccc;font-size:12px">厘米</text>
            </template>
          </up-form-item>
        </up-col>
        <up-col span="6">
          <up-form-item label="高度" prop="treeheight">
            <up-input v-model="formData.treeheight" placeholder="请输入" maxlength="10" border="none" input-align="left" />
            <template #right>
              <text style="padding-left: 12rpx;color:#ccc;font-size:14px;">米</text>
            </template>
          </up-form-item>
        </up-col>
      </up-row>

      <up-form-item label="位置" prop="growlocation" required class="location-form-item" @click="openMap">
        <up-input v-model="formData.growlocation" placeholder="请选择" disabled border="none" />
        <template #right>
          <up-icon name="map" size="22"></up-icon>
        </template>
      </up-form-item>

      <up-row gutter="10">
        <up-col span="6">
          <up-form-item label="经度" label-color="#ccc" prop="longitude" border-bottom="none">
            <up-input v-model="formData.longitude" placeholder="" disabled border="none" />
          </up-form-item>
        </up-col>
        <up-col span="6">
          <up-form-item label="纬度" label-color="#ccc" prop="latitude" border-bottom="none">
            <up-input v-model="formData.latitude" placeholder="" disabled border="none" />
          </up-form-item>
        </up-col>
      </up-row>

      <up-form-item label="管护单位" prop="managedutyunit" required>
        <up-input v-model="formData.managedutyunit" placeholder="请输入" maxlength="30" border="none" />
      </up-form-item>

      <up-form-item label="权属分类" prop="oldtreeownershipText" required arrow @click="pickerShow = true">
        <up-input v-model="formData.oldtreeownershipText" placeholder="请选择" disabled border="none" bg-color="transparent" />
      </up-form-item>

      <!-- ✅✅✅ 核心修改:图片上传 完全对标参考代码写法 start -->
      <up-form-item label="图片信息" prop="treeImgList" required>
        <up-upload
            :file-list="treeImgs.imgList.value || []"
            @after-read="treeImgs.uploadImgs"
            @delete="treeImgs.deleteImg"
            multiple
            :width="70"
            :height="70"
            :max-count="treeImgs.uploadConfig.maxCount"
            :upload-text="treeImgs.uploadConfig.uploadText"
            :size-type="treeImgs.uploadConfig.sizeType"
        ></up-upload>
      </up-form-item>
      <!-- ✅✅✅ 图片上传 修改结束 -->

      <!-- 动画区域(初始隐藏)保留原逻辑 -->
      <view
          class="animated-area"
          :style="{
          height: isShow ? contentHeight + 'px' : '0',
          opacity: isShow ? 1 : 0,
          overflow: 'hidden'
        }"
      >
        <up-row gutter="10">
          <up-col span="6">
            <up-form-item label="拉丁文" prop="latinname">
              <up-input v-model="formData.latinname" placeholder="请输入" maxlength="30" border="none" />
            </up-form-item>
          </up-col>
          <up-col span="6">
            <up-form-item label="级别" arrow @click="levelshow = true">
              <up-input v-model="formData.treeleveltext" placeholder="请选择" disabled border="none" bg-color="transparent" />
            </up-form-item>
          </up-col>
        </up-row>

        <up-form-item label="生长环境" prop="growthenvironment">
          <up-input v-model="formData.growthenvironment" placeholder="请输入" maxlength="50" border="none" />
        </up-form-item>

        <up-row gutter="10">
          <up-col span="6">
            <up-form-item label="预估树龄" prop="estimationtreeage">
              <up-input v-model="formData.estimationtreeage" placeholder="请输入" maxlength="10" border="none" input-align="left" />
              <template #right>
                <text style="padding-left:12rpx;color:#ccc;font-size:14px">年</text>
              </template>
            </up-form-item>
          </up-col>
          <up-col span="6">
            <up-form-item label="干周" prop="weekday">
              <up-input v-model="formData.weekday" placeholder="请输入" maxlength="10" border="none" input-align="left" />
              <template #right>
                <text style="padding-left:12rpx;color:#ccc;font-size:14px">厘米</text>
              </template>
            </up-form-item>
          </up-col>
        </up-row>

        <up-row gutter="10">
          <up-col span="6">
            <up-form-item label="东西冠幅" prop="canopyeastwest">
              <up-input v-model="formData.canopyeastwest" placeholder="请输入" maxlength="10" border="none" input-align="left" />
              <template #right>
                <text style="padding-left:12rpx;color:#ccc;font-size:14px">米</text>
              </template>
            </up-form-item>
          </up-col>
          <up-col span="6">
            <up-form-item label="南北冠幅" prop="canopysouthnorth">
              <up-input v-model="formData.canopysouthnorth" placeholder="请输入" maxlength="10" border="none" input-align="left" />
              <template #right>
                <text style="padding-left:12rpx;color:#ccc;font-size:14px">米</text>
              </template>
            </up-form-item>
          </up-col>
        </up-row>
      </view>

      <!-- 触发按钮 -->
      <up-button
          @click="toggleArea"
          type="primary"
          plain
          size="large"
          style="margin-top:20rpx"
      >
        {{ isShow ? '- 隐藏区域' : '+ 显示区域' }}
      </up-button>
    </up-form>

    <view style="height: 60px;width: 100%"></view>

    <!-- 底部提交按钮 -->
    <view class="fixed-bottom-btn-wrap">
      <up-button type="primary" @click="submit" :loading="loadingFlag" size="large" bold>提交</up-button>
    </view>

    <up-picker
        v-model="pickerShow"
        :list="treeOwnershipData"
        label-key="dictLabel"
        value-key="dictValue"
        @confirm="pickerChange"
    ></up-picker>

    <up-picker
        v-model="levelshow"
        :list="treeLevelData"
        label-key="dictLabel"
        value-key="dictValue"
        @confirm="pickerLevelChange"
    ></up-picker>
  </view>
</template>

<script setup>
import { ref, reactive, nextTick } from 'vue'
import { onReady, onLoad, onShow } from '@dcloudio/uni-app';
import { addTree } from "@/api/tree-archive/tree-archive.js";

import { useUploadImgs } from '@/common/utils/useUploadImgs'
import { useUserStore } from '@/pinia/user';

// ========== 状态管理 ==========
const userStore = useUserStore();

// ✅ 全局响应式数据
const formRef = ref(null)
const isShow = ref(false)
const contentHeight = ref(700)
const treeOwnershipData = ref([])
const treeLevelData = ref([])
const pickerShow = ref(false)
const levelshow = ref(false)
const loadingFlag = ref(false)

// ✅✅✅ 核心修改:图片上传配置 完全对标参考代码写法
const treeImgs = useUploadImgs({
  maxCount: 3,
  uploadText: '选择图片',
  sizeType: ['compressed'],
  formRef: formRef,
  fieldName: 'treeImgList'
})
// 图片数组兜底,防止非数组报错
if (!Array.isArray(treeImgs.rawImgList.value)) treeImgs.rawImgList.value = [];

// ✅ 表单数据 - 替代vue2的data
const formData = reactive({
  treetype: '',
  treeheight: '',
  dbh: '',
  treelevel: '',
  treeleveltext: '',
  managedutyunit: '',
  oldtreeownership: '',
  oldtreeownershipText: '',
  latinname: '',
  estimationtreeage: '',
  canopysouthnorth: '',
  canopyeastwest: '',
  weekday: '',
  growlocation: '',
  growthenvironment: '',
  treeImgList: [],
  address: '',
  latitude: '',
  longitude: '',
  road: '',
  maintainunit: ''
})

// ✅✅✅ 核心修改:表单校验规则 - 图片校验改为参考代码同款
const rules = reactive({
  treetype: [{ required: true, message: '请输入名称', trigger: 'blur' }],
  treeheight: [{ max: 10, message: '树高不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }],
  dbh: [{ required: true, message: '请输入胸径', trigger: 'blur' }, { max: 10, message: '胸径不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }],
  estimationtreeage: [{ max: 10, message: '预估树龄不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }],
  weekday: [{ max: 10, message: '干周不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }],
  canopyeastwest: [{ max: 10, message: '东西冠幅不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }],
  canopysouthnorth: [{ max: 10, message: '南北冠幅不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }],
  growlocation: [{ required: true, message: '请地图选择位置', trigger: 'change' }],
  managedutyunit: [{ required: true, message: '请输入管护单位', trigger: 'blur' }],
  oldtreeownershipText: [{ required: true, message: '请选择权属分类', trigger: 'change' }],
  treeImgList: [treeImgs.imgValidateRule] // ✅ 图片校验规则和参考代码一致
})

// ✅ 生命周期
onLoad((options) => {
  formData.road = options.roadId
})

onShow(async () => {

  treeLevelData.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('tree_level'));
  treeOwnershipData.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('tree_ownership'));
})

// 修复表单ref挂载问题,和参考代码一致
onReady(() => {
  nextTick(() => {
    formRef.value?.setRules(rules);
  });
});



const toggleArea = () => {
  isShow.value = !isShow.value
}


// 权属分类选择回调
const pickerChange = (val) => {
  formData.oldtreeownership = val.value
  formData.oldtreeownershipText = val.label
  pickerShow.value = false
}

// 树木级别选择回调
const pickerLevelChange = (val) => {
  formData.treelevel = val.value
  formData.treeleveltext = val.label
  levelshow.value = false
}

// 打开地图选址
const openMap = () => {
  uni.chooseLocation({
    success: (res) => {
      formData.growlocation = res.address
      formData.latitude = res.latitude
      formData.longitude = res.longitude
    },
    fail: (err) => {
      console.error('地图选择失败', err);
      if (err.errMsg.includes('auth deny')) {
        uni.showToast({ title: '请授权位置权限', icon: 'none' });
      }
    }
  });
}

// 表单提交核心方法
const submit = async () => {
  if (loadingFlag.value) return
  // 表单校验
  const valid = await formRef.value.validate()
  if (!valid) return

  // ✅✅✅ 核心修改:获取上传成功的图片地址,和参考代码一致
  const uploadImgUrls = treeImgs.getSuccessImgUrls()

  // 组装提交参数
  formData.maintainunit = uni.getStorageSync('userInfo')?.belongCompanyId || ''
  formData.treeImgList = uploadImgUrls // 赋值图片数组
  loadingFlag.value = true

  try {
    const res = await addTree({ data: { ...formData } })
    if (res.code == '200') {
      uni.showToast({ title: "新增成功", icon: "success" });
      uni.redirectTo({ url: '/subPackages/treePage/treeFiles' });
    }
  } catch (err) {
    uni.showToast({ title: "新增失败,请重试", icon: "none" });
    console.error(err)
  } finally {
    loadingFlag.value = false
  }
}
</script>

<style scoped lang="scss">
.container {
  padding: 25rpx;
  box-sizing: border-box;
  background: #fff;
}

.animated-area {
  transition: all 0.3s ease-out;
  margin-top: 10rpx;
}
.location-form-item {
  padding-right: 10rpx;
}
</style>