Commit 727bc60da3cae258de027bbabe7fcdc17b9f47d5

Authored by 刘淇
1 parent 8ddc6f6e

新增树

api/tree-archive/tree-archive.js
... ... @@ -26,8 +26,8 @@ export const treeRoadReq = (params) => {
26 26 * @param {Object} params
27 27 * @returns {Promise}
28 28 */
29   -export const addTree = (params) => {
30   - return get('/app-api/garden/tree/create', params);
  29 +export const addTree = (data) => {
  30 + return post('/app-api/garden/tree/create', data);
31 31 };
32 32  
33 33  
... ...
pages-sub/data/tree-archive/addTree.vue
... ... @@ -2,30 +2,34 @@
2 2 <view class="container">
3 3 <up-form :model="formData" ref="formRef" label-width="140rpx" border-bottom>
4 4 <up-form-item label="名称" prop="treetype" required>
5   - <up-input v-model="formData.treetype" placeholder="请输入名称" maxlength="30" border="none" />
  5 + <up-input v-model="formData.treetype" placeholder="请输入名称" maxlength="30" border="none"/>
6 6 </up-form-item>
7 7  
8   - <up-row gutter="10">
9   - <up-col span="6">
10   - <up-form-item label="胸径" prop="dbh" required>
11   - <up-input v-model="formData.dbh" placeholder="请输入" maxlength="10" border="none" input-align="left" />
12   - <template #right>
13   - <text style="padding-left: 12rpx;color:#ccc;font-size:12px">厘米</text>
14   - </template>
15   - </up-form-item>
16   - </up-col>
17   - <up-col span="6">
18   - <up-form-item label="高度" prop="treeheight">
19   - <up-input v-model="formData.treeheight" placeholder="请输入" maxlength="10" border="none" input-align="left" />
20   - <template #right>
21   - <text style="padding-left: 12rpx;color:#ccc;font-size:14px;">米</text>
22   - </template>
23   - </up-form-item>
24   - </up-col>
25   - </up-row>
  8 + <!-- ✅ 核心修复1:给同行的两个表单外层包一层 弹性布局容器,彻底解决错位问题 -->
  9 + <view class="form-row-wrap">
  10 + <up-row gutter="10">
  11 + <up-col span="6">
  12 + <up-form-item label="胸径" prop="dbh" required>
  13 + <up-input v-model="formData.dbh" placeholder="请输入" maxlength="10" border="none" input-align="left"/>
  14 + <template #right>
  15 + <text style="padding-left: 12rpx;color:#ccc;font-size:12px">厘米</text>
  16 + </template>
  17 + </up-form-item>
  18 + </up-col>
  19 + <up-col span="6">
  20 + <up-form-item label="高度" prop="treeheight">
  21 + <up-input v-model="formData.treeheight" placeholder="请输入" maxlength="10" border="none"
  22 + input-align="left"/>
  23 + <template #right>
  24 + <text style="padding-left: 12rpx;color:#ccc;font-size:14px;">米</text>
  25 + </template>
  26 + </up-form-item>
  27 + </up-col>
  28 + </up-row>
  29 + </view>
26 30  
27 31 <up-form-item label="位置" prop="growlocation" required class="location-form-item" @click="openMap">
28   - <up-input v-model="formData.growlocation" placeholder="请选择" disabled border="none" />
  32 + <up-input v-model="formData.growlocation" placeholder="请选择" readonly border="none"/>
29 33 <template #right>
30 34 <up-icon name="map" size="22"></up-icon>
31 35 </template>
... ... @@ -33,26 +37,26 @@
33 37  
34 38 <up-row gutter="10">
35 39 <up-col span="6">
36   - <up-form-item label="经度" label-color="#ccc" prop="longitude" border-bottom="none">
37   - <up-input v-model="formData.longitude" placeholder="" disabled border="none" />
  40 + <up-form-item label="经度" prop="longitude" :borderBottom="false">
  41 + <up-input v-model="formData.longitude" placeholder="" readonly border="none"/>
38 42 </up-form-item>
39 43 </up-col>
40 44 <up-col span="6">
41   - <up-form-item label="纬度" label-color="#ccc" prop="latitude" border-bottom="none">
42   - <up-input v-model="formData.latitude" placeholder="" disabled border="none" />
  45 + <up-form-item label="纬度" prop="latitude" :borderBottom="false">
  46 + <up-input v-model="formData.latitude" placeholder="" readonly border="none"/>
43 47 </up-form-item>
44 48 </up-col>
45 49 </up-row>
46 50  
47 51 <up-form-item label="管护单位" prop="managedutyunit" required>
48   - <up-input v-model="formData.managedutyunit" placeholder="请输入" maxlength="30" border="none" />
  52 + <up-input v-model="formData.managedutyunit" placeholder="请输入" maxlength="30" border="none"/>
49 53 </up-form-item>
50 54  
51   - <up-form-item label="权属分类" prop="oldtreeownershipText" required arrow @click="pickerShow = true">
52   - <up-input v-model="formData.oldtreeownershipText" placeholder="请选择" disabled border="none" bg-color="transparent" />
  55 + <up-form-item label="权属分类" prop="oldtreeownershipText" required arrow @click="handleActionSheetOpen('ownership')">
  56 + <up-input v-model="formData.oldtreeownershipText" placeholder="请选择" readonly border="none"
  57 + bg-color="transparent" />
53 58 </up-form-item>
54 59  
55   - <!-- ✅✅✅ 核心修改:图片上传 完全对标参考代码写法 start -->
56 60 <up-form-item label="图片信息" prop="treeImgList" required>
57 61 <up-upload
58 62 :file-list="treeImgs.imgList.value || []"
... ... @@ -66,9 +70,7 @@
66 70 :size-type="treeImgs.uploadConfig.sizeType"
67 71 ></up-upload>
68 72 </up-form-item>
69   - <!-- ✅✅✅ 图片上传 修改结束 -->
70 73  
71   - <!-- 动画区域(初始隐藏)保留原逻辑 -->
72 74 <view
73 75 class="animated-area"
74 76 :style="{
... ... @@ -80,60 +82,69 @@
80 82 <up-row gutter="10">
81 83 <up-col span="6">
82 84 <up-form-item label="拉丁文" prop="latinname">
83   - <up-input v-model="formData.latinname" placeholder="请输入" maxlength="30" border="none" />
  85 + <up-input v-model="formData.latinname" placeholder="请输入" maxlength="30" border="none"/>
84 86 </up-form-item>
85 87 </up-col>
86 88 <up-col span="6">
87   - <up-form-item label="级别" arrow @click="levelshow = true">
88   - <up-input v-model="formData.treeleveltext" placeholder="请选择" disabled border="none" bg-color="transparent" />
  89 + <up-form-item label="级别" arrow @click="handleActionSheetOpen('level')">
  90 + <up-input v-model="formData.treeleveltext" placeholder="请选择" readonly border="none"
  91 + bg-color="transparent"/>
89 92 </up-form-item>
90 93 </up-col>
91 94 </up-row>
92 95  
93 96 <up-form-item label="生长环境" prop="growthenvironment">
94   - <up-input v-model="formData.growthenvironment" placeholder="请输入" maxlength="50" border="none" />
  97 + <up-input v-model="formData.growthenvironment" placeholder="请输入" maxlength="50" border="none"/>
95 98 </up-form-item>
96 99  
97   - <up-row gutter="10">
98   - <up-col span="6">
99   - <up-form-item label="预估树龄" prop="estimationtreeage">
100   - <up-input v-model="formData.estimationtreeage" placeholder="请输入" maxlength="10" border="none" input-align="left" />
101   - <template #right>
102   - <text style="padding-left:12rpx;color:#ccc;font-size:14px">年</text>
103   - </template>
104   - </up-form-item>
105   - </up-col>
106   - <up-col span="6">
107   - <up-form-item label="干周" prop="weekday">
108   - <up-input v-model="formData.weekday" placeholder="请输入" maxlength="10" border="none" input-align="left" />
109   - <template #right>
110   - <text style="padding-left:12rpx;color:#ccc;font-size:14px">厘米</text>
111   - </template>
112   - </up-form-item>
113   - </up-col>
114   - </up-row>
115   -
116   - <up-row gutter="10">
117   - <up-col span="6">
118   - <up-form-item label="东西冠幅" prop="canopyeastwest">
119   - <up-input v-model="formData.canopyeastwest" placeholder="请输入" maxlength="10" border="none" input-align="left" />
120   - <template #right>
121   - <text style="padding-left:12rpx;color:#ccc;font-size:14px">米</text>
122   - </template>
123   - </up-form-item>
124   - </up-col>
125   - <up-col span="6">
126   - <up-form-item label="南北冠幅" prop="canopysouthnorth">
127   - <up-input v-model="formData.canopysouthnorth" placeholder="请输入" maxlength="10" border="none" input-align="left" />
128   - <template #right>
129   - <text style="padding-left:12rpx;color:#ccc;font-size:14px">米</text>
130   - </template>
131   - </up-form-item>
132   - </up-col>
133   - </up-row>
  100 + <!-- ✅ 核心修复2:所有同行的表单都统一加样式,预防其他行也错位 -->
  101 + <view class="form-row-wrap">
  102 + <up-row gutter="10">
  103 + <up-col span="6">
  104 + <up-form-item label="预估树龄" prop="estimationtreeage">
  105 + <up-input v-model="formData.estimationtreeage" placeholder="请输入" maxlength="10" border="none"
  106 + input-align="left"/>
  107 + <template #right>
  108 + <text style="padding-left:12rpx;color:#ccc;font-size:14px">年</text>
  109 + </template>
  110 + </up-form-item>
  111 + </up-col>
  112 + <up-col span="6">
  113 + <up-form-item label="干周" prop="weekday">
  114 + <up-input v-model="formData.weekday" placeholder="请输入" maxlength="10" border="none"
  115 + input-align="left"/>
  116 + <template #right>
  117 + <text style="padding-left:12rpx;color:#ccc;font-size:14px">厘米</text>
  118 + </template>
  119 + </up-form-item>
  120 + </up-col>
  121 + </up-row>
  122 + </view>
  123 +
  124 + <view class="form-row-wrap">
  125 + <up-row gutter="10">
  126 + <up-col span="6">
  127 + <up-form-item label="东西冠幅" prop="canopyeastwest">
  128 + <up-input v-model="formData.canopyeastwest" placeholder="请输入" maxlength="10" border="none"
  129 + input-align="left"/>
  130 + <template #right>
  131 + <text style="padding-left:12rpx;color:#ccc;font-size:14px">米</text>
  132 + </template>
  133 + </up-form-item>
  134 + </up-col>
  135 + <up-col span="6">
  136 + <up-form-item label="南北冠幅" prop="canopysouthnorth">
  137 + <up-input v-model="formData.canopysouthnorth" placeholder="请输入" maxlength="10" border="none"
  138 + input-align="left"/>
  139 + <template #right>
  140 + <text style="padding-left:12rpx;color:#ccc;font-size:14px">米</text>
  141 + </template>
  142 + </up-form-item>
  143 + </up-col>
  144 + </up-row>
  145 + </view>
134 146 </view>
135 147  
136   - <!-- 触发按钮 -->
137 148 <up-button
138 149 @click="toggleArea"
139 150 type="primary"
... ... @@ -147,26 +158,18 @@
147 158  
148 159 <view style="height: 60px;width: 100%"></view>
149 160  
150   - <!-- 底部提交按钮 -->
151 161 <view class="fixed-bottom-btn-wrap">
152 162 <up-button type="primary" @click="submit" :loading="loadingFlag" size="large" bold>提交</up-button>
153 163 </view>
154 164  
155   - <up-picker
156   - v-model="pickerShow"
157   - :list="treeOwnershipData"
158   - label-key="dictLabel"
159   - value-key="dictValue"
160   - @confirm="pickerChange"
161   - ></up-picker>
  165 + <up-action-sheet
  166 + :show="showActionSheet"
  167 + :actions="currentActionSheetData.list"
  168 + :title="currentActionSheetData.title"
  169 + @close="handleActionSheetClose"
  170 + @select="handleActionSheetSelect"
  171 + ></up-action-sheet>
162 172  
163   - <up-picker
164   - v-model="levelshow"
165   - :list="treeLevelData"
166   - label-key="dictLabel"
167   - value-key="dictValue"
168   - @confirm="pickerLevelChange"
169   - ></up-picker>
170 173 </view>
171 174 </template>
172 175  
... ... @@ -174,24 +177,21 @@
174 177 import { ref, reactive, nextTick } from 'vue'
175 178 import { onReady, onLoad, onShow } from '@dcloudio/uni-app';
176 179 import { addTree } from "@/api/tree-archive/tree-archive.js";
177   -
178 180 import { useUploadImgs } from '@/common/utils/useUploadImgs'
179 181 import { useUserStore } from '@/pinia/user';
180 182  
181 183 // ========== 状态管理 ==========
182 184 const userStore = useUserStore();
183   -
184   -// ✅ 全局响应式数据
185 185 const formRef = ref(null)
186 186 const isShow = ref(false)
187   -const contentHeight = ref(700)
  187 +const contentHeight = ref(200)
188 188 const treeOwnershipData = ref([])
189 189 const treeLevelData = ref([])
190   -const pickerShow = ref(false)
191   -const levelshow = ref(false)
192 190 const loadingFlag = ref(false)
  191 +const showActionSheet = ref(false);
  192 +const currentActionSheetData = reactive({ type: '', list: [], title: '' });
193 193  
194   -// ✅✅✅ 核心修改:图片上传配置 完全对标参考代码写法
  194 +// 图片上传配置
195 195 const treeImgs = useUploadImgs({
196 196 maxCount: 3,
197 197 uploadText: '选择图片',
... ... @@ -199,10 +199,9 @@ const treeImgs = useUploadImgs({
199 199 formRef: formRef,
200 200 fieldName: 'treeImgList'
201 201 })
202   -// 图片数组兜底,防止非数组报错
203 202 if (!Array.isArray(treeImgs.rawImgList.value)) treeImgs.rawImgList.value = [];
204 203  
205   -// ✅ 表单数据 - 替代vue2的data
  204 +// 表单数据
206 205 const formData = reactive({
207 206 treetype: '',
208 207 treeheight: '',
... ... @@ -227,59 +226,89 @@ const formData = reactive({
227 226 maintainunit: ''
228 227 })
229 228  
230   -// ✅✅✅ 核心修改:表单校验规则 - 图片校验改为参考代码同款
  229 +// ✅ 核心修复3:修复所有校验规则里的 语法错误 【trigger: ['blur','change]'] → trigger: ['blur','change']】
231 230 const rules = reactive({
232   - treetype: [{ required: true, message: '请输入名称', trigger: 'blur' }],
233   - treeheight: [{ max: 10, message: '树高不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }],
234   - dbh: [{ required: true, message: '请输入胸径', trigger: 'blur' }, { max: 10, message: '胸径不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }],
235   - estimationtreeage: [{ max: 10, message: '预估树龄不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }],
236   - weekday: [{ max: 10, message: '干周不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }],
237   - canopyeastwest: [{ max: 10, message: '东西冠幅不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }],
238   - canopysouthnorth: [{ max: 10, message: '南北冠幅不能超过10个字符', trigger: 'blur' }, { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: 'blur' }],
239   - growlocation: [{ required: true, message: '请地图选择位置', trigger: 'change' }],
240   - managedutyunit: [{ required: true, message: '请输入管护单位', trigger: 'blur' }],
241   - oldtreeownershipText: [{ required: true, message: '请选择权属分类', trigger: 'change' }],
242   - treeImgList: [treeImgs.imgValidateRule] // ✅ 图片校验规则和参考代码一致
  231 + treetype: [{required: true, message: '请输入名称', trigger: ['blur','change']}],
  232 + treeheight: [{max: 10, message: '树高不能超过10个字符', trigger: ['blur','change']}, {
  233 + pattern: /^\d+(\.\d{1,2})?$/,
  234 + message: '格式不正确',
  235 + trigger: ['blur','change']
  236 + }],
  237 + dbh: [{required: true, message: '请输入胸径',trigger: ['blur','change']}, {
  238 + max: 10,
  239 + message: '胸径不能超过10个字符',
  240 + trigger: ['blur','change']
  241 + }, {pattern: /^\d+(\.\d{1,2})?$/, message: '格式不正确',trigger: ['blur','change']}],
  242 + estimationtreeage: [{max: 10, message: '预估树龄不能超过10个字符', trigger: ['blur','change']}, {
  243 + pattern: /^\d+(\.\d{1,2})?$/,
  244 + message: '格式不正确',
  245 + trigger: ['blur','change']
  246 + }],
  247 + weekday: [{max: 10, message: '干周不能超过10个字符', trigger: ['blur','change']}, {
  248 + pattern: /^\d+(\.\d{1,2})?$/,
  249 + message: '格式不正确',
  250 + trigger: ['blur','change']
  251 + }],
  252 + canopyeastwest: [{max: 10, message: '东西冠幅不能超过10个字符',trigger: ['blur','change']}, {
  253 + pattern: /^\d+(\.\d{1,2})?$/,
  254 + message: '格式不正确',
  255 + trigger: ['blur','change']
  256 + }],
  257 + canopysouthnorth: [{max: 10, message: '南北冠幅不能超过10个字符', trigger: ['blur','change']}, {
  258 + pattern: /^\d+(\.\d{1,2})?$/,
  259 + message: '格式不正确',
  260 + trigger: ['blur','change']
  261 + }],
  262 + growlocation: [{required: true, message: '请地图选择位置', trigger: ['blur','change']}],
  263 + managedutyunit: [{required: true, message: '请输入管护单位', trigger: ['blur','change']}],
  264 + oldtreeownershipText: [{required: true, message: '请选择权属分类', trigger: ['blur','change']}],
  265 + treeImgList: [treeImgs.imgValidateRule]
243 266 })
244 267  
245   -// 生命周期
  268 +// 生命周期
246 269 onLoad((options) => {
247 270 formData.road = options.roadId
248 271 })
249   -
250 272 onShow(async () => {
251   -
252   - treeLevelData.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('tree_level'));
253   - treeOwnershipData.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('tree_ownership'));
  273 + treeLevelData.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('tree_level'))
  274 + treeOwnershipData.value = uni.$dict.transformLabelValueToNameValue(uni.$dict.getDictSimpleList('tree_ownership'))
254 275 })
255   -
256   -// 修复表单ref挂载问题,和参考代码一致
257 276 onReady(() => {
258 277 nextTick(() => {
259 278 formRef.value?.setRules(rules);
260 279 });
261 280 });
262 281  
263   -
264   -
265 282 const toggleArea = () => {
266 283 isShow.value = !isShow.value
267 284 }
268 285  
269   -
270   -// 权属分类选择回调
271   -const pickerChange = (val) => {
272   - formData.oldtreeownership = val.value
273   - formData.oldtreeownershipText = val.label
274   - pickerShow.value = false
275   -}
276   -
277   -// 树木级别选择回调
278   -const pickerLevelChange = (val) => {
279   - formData.treelevel = val.value
280   - formData.treeleveltext = val.label
281   - levelshow.value = false
282   -}
  286 +const handleActionSheetOpen = (type) => {
  287 + const configMap = {
  288 + ownership: { title: '请选择权属分类', list: treeOwnershipData.value },
  289 + level: { title: '请选择树木级别', list: treeLevelData.value }
  290 + };
  291 + Object.assign(currentActionSheetData, configMap[type], { type });
  292 + showActionSheet.value = true;
  293 +};
  294 +
  295 +const handleActionSheetClose = () => {
  296 + showActionSheet.value = false;
  297 + Object.assign(currentActionSheetData, { type: '', list: [], title: '' });
  298 +};
  299 +
  300 +const handleActionSheetSelect = (e) => {
  301 + const { type } = currentActionSheetData;
  302 + if (type === 'ownership') {
  303 + formData.oldtreeownership = e.value
  304 + formData.oldtreeownershipText = e.name
  305 + formRef.value?.validateField('oldtreeownershipText');
  306 + } else if (type === 'level') {
  307 + formData.treelevel = e.value
  308 + formData.treeleveltext = e.name
  309 + }
  310 + handleActionSheetClose();
  311 +};
283 312  
284 313 // 打开地图选址
285 314 const openMap = () => {
... ... @@ -292,7 +321,7 @@ const openMap = () =&gt; {
292 321 fail: (err) => {
293 322 console.error('地图选择失败', err);
294 323 if (err.errMsg.includes('auth deny')) {
295   - uni.showToast({ title: '请授权位置权限', icon: 'none' });
  324 + uni.showToast({title: '请授权位置权限', icon: 'none'});
296 325 }
297 326 }
298 327 });
... ... @@ -301,26 +330,18 @@ const openMap = () =&gt; {
301 330 // 表单提交核心方法
302 331 const submit = async () => {
303 332 if (loadingFlag.value) return
304   - // 表单校验
305 333 const valid = await formRef.value.validate()
306 334 if (!valid) return
307   -
308   - // ✅✅✅ 核心修改:获取上传成功的图片地址,和参考代码一致
309 335 const uploadImgUrls = treeImgs.getSuccessImgUrls()
310   -
311   - // 组装提交参数
312 336 formData.maintainunit = uni.getStorageSync('userInfo')?.belongCompanyId || ''
313   - formData.treeImgList = uploadImgUrls // 赋值图片数组
  337 + formData.treeImgList = uploadImgUrls
314 338 loadingFlag.value = true
315   -
316 339 try {
317   - const res = await addTree({ data: { ...formData } })
318   - if (res.code == '200') {
319   - uni.showToast({ title: "新增成功", icon: "success" });
320   - uni.redirectTo({ url: '/subPackages/treePage/treeFiles' });
321   - }
  340 + const res = await addTree(formData)
  341 + uni.showToast({title: "新增成功", icon: "success"});
  342 + uni.redirectTo({url: '/pages-sub/data/tree-archive/index'});
322 343 } catch (err) {
323   - uni.showToast({ title: "新增失败,请重试", icon: "none" });
  344 + uni.showToast({title: "新增失败,请重试", icon: "none"});
324 345 console.error(err)
325 346 } finally {
326 347 loadingFlag.value = false
... ... @@ -339,7 +360,35 @@ const submit = async () =&gt; {
339 360 transition: all 0.3s ease-out;
340 361 margin-top: 10rpx;
341 362 }
  363 +
342 364 .location-form-item {
343 365 padding-right: 10rpx;
344 366 }
  367 +
  368 +// ✅ ✅ ✅ 核心修复样式:解决校验提示导致的布局错位问题,优先级最高
  369 +.form-row-wrap {
  370 + width: 100%;
  371 + display: flex;
  372 + flex-direction: column;
  373 + // 关键:让校验提示文字 不撑开单元格,而是相对父容器定位
  374 + :deep(.u-form-item) {
  375 + position: relative;
  376 + margin-bottom: 0 !important;
  377 + }
  378 + // 关键:校验错误提示文字 绝对定位在输入框下方,两行的提示互不影响
  379 + :deep(.u-form-item__body__right__message ) {
  380 + position: absolute;
  381 + left: 0;
  382 + bottom: -20rpx;
  383 + line-height: 20rpx;
  384 + font-size: 22rpx;
  385 + color: #f56c6c;
  386 + width: 100%;
  387 + box-sizing: border-box;
  388 + }
  389 +}
  390 +// 给同行表单底部留足提示文字的间距,防止和下一行重叠
  391 +.form-row-wrap + .u-form-item {
  392 + margin-top: 25rpx !important;
  393 +}
345 394 </style>
346 395 \ No newline at end of file
... ...