前端-胡立永 1 month ago
parent
commit
d8bb1f3426
5 changed files with 552 additions and 50 deletions
  1. +57
    -9
      pages_subpack/house/commercial.vue
  2. +82
    -22
      pages_subpack/house/farmhouse.vue
  3. +71
    -19
      pages_subpack/house/other.vue
  4. +146
    -0
      utils/README_formStorage.md
  5. +196
    -0
      utils/formStorage.js

+ 57
- 9
pages_subpack/house/commercial.vue View File

@ -12,7 +12,7 @@
<!-- 1. 出租/出让 --> <!-- 1. 出租/出让 -->
<uv-form-item label="类型" prop="type" required> <uv-form-item label="类型" prop="type" required>
<uv-radio-group v-model="form.type" placement="row">
<uv-radio-group v-model="form.type" placement="row" @change="debounceSaveFormData">
<uv-radio name="rent" label="出租"></uv-radio> <uv-radio name="rent" label="出租"></uv-radio>
<uv-radio name="transfer" customStyle="margin-left:30rpx;" label="出让"></uv-radio> <uv-radio name="transfer" customStyle="margin-left:30rpx;" label="出让"></uv-radio>
</uv-radio-group> </uv-radio-group>
@ -29,11 +29,11 @@
<!-- 3. 联系人和电话 --> <!-- 3. 联系人和电话 -->
<uv-form-item label="联系人" prop="contactName" required> <uv-form-item label="联系人" prop="contactName" required>
<uv-input v-model="form.contactName" type="text" placeholder="请输入联系人姓名" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;"></uv-input>
<uv-input v-model="form.contactName" type="text" placeholder="请输入联系人姓名" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;" @input="debounceSaveFormData"></uv-input>
</uv-form-item> </uv-form-item>
<uv-form-item label="联系电话" prop="contactPhone" required> <uv-form-item label="联系电话" prop="contactPhone" required>
<uv-input v-model="form.contactPhone" type="number" placeholder="请输入联系电话" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;"></uv-input>
<uv-input v-model="form.contactPhone" type="number" placeholder="请输入联系电话" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;" @input="debounceSaveFormData"></uv-input>
</uv-form-item> </uv-form-item>
<!-- 4. 产权证照片 --> <!-- 4. 产权证照片 -->
@ -46,7 +46,7 @@
<!-- 5. 土地面积 --> <!-- 5. 土地面积 -->
<uv-form-item label="土地面积" prop="landArea" required> <uv-form-item label="土地面积" prop="landArea" required>
<view class="input-with-unit"> <view class="input-with-unit">
<uv-input v-model="form.landArea" type="digit" placeholder="请输入土地面积" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;"></uv-input>
<uv-input v-model="form.landArea" type="digit" placeholder="请输入土地面积" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;" @input="debounceSaveFormData"></uv-input>
<text class="unit"></text> <text class="unit"></text>
</view> </view>
<view class="input-tip">请录入土地使用证或不动产权证面积仅输入数字</view> <view class="input-tip">请录入土地使用证或不动产权证面积仅输入数字</view>
@ -62,7 +62,7 @@
<!-- 7. 价格 --> <!-- 7. 价格 -->
<uv-form-item label="价格" prop="price" required> <uv-form-item label="价格" prop="price" required>
<view class="price-container"> <view class="price-container">
<uv-input v-model="form.price" type="digit" placeholder="请输入价格" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;flex:1;"></uv-input>
<uv-input v-model="form.price" type="digit" placeholder="请输入价格" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;flex:1;" @input="debounceSaveFormData"></uv-input>
<text class="price-unit" v-if="form.type === 'rent'">//</text> <text class="price-unit" v-if="form.type === 'rent'">//</text>
<text class="price-unit" v-else-if="form.type === 'transfer'">万元/</text> <text class="price-unit" v-else-if="form.type === 'transfer'">万元/</text>
<text class="price-unit" v-else></text> <text class="price-unit" v-else></text>
@ -91,6 +91,7 @@
customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:10px;" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:10px;"
:autoHeight="true" :autoHeight="true"
:maxlength="500" :maxlength="500"
@input="debounceSaveFormData"
></uv-input> ></uv-input>
</uv-form-item> </uv-form-item>
@ -107,11 +108,14 @@
<script> <script>
import { saveOrUpdateHouse, houseType } from "@/common/api.js" import { saveOrUpdateHouse, houseType } from "@/common/api.js"
import formStorage from "@/utils/formStorage.js"
export default { export default {
data() {
return {
commonClass: '', // ID
data() {
return {
formKey: 'commercial_form', //
saveTimer: null, //
commonClass: '', // ID
form: { form: {
type: '', // / type: '', // /
address: '', // address: '', //
@ -178,8 +182,40 @@
// //
this.onHouseType() this.onHouseType()
//
this.restoreFormData()
},
onUnload() {
//
this.saveFormData()
//
if (this.saveTimer) {
clearTimeout(this.saveTimer)
}
}, },
methods: {
methods: {
//
restoreFormData() {
const savedData = formStorage.getFormData(this.formKey)
if (savedData) {
//
this.form = { ...this.form, ...savedData }
}
},
//
saveFormData() {
formStorage.saveFormData(this.formKey, this.form)
},
//
debounceSaveFormData() {
clearTimeout(this.saveTimer)
this.saveTimer = setTimeout(() => {
this.saveFormData()
}, 1000)
},
// //
onHouseType(){ onHouseType(){
let that = this let that = this
@ -222,6 +258,8 @@
let {indexs,value,values} = e let {indexs,value,values} = e
that.form.classId = that.houseTypeList[indexs[0]].id; that.form.classId = that.houseTypeList[indexs[0]].id;
that.form.className = that.houseTypeList[indexs[0]].title; that.form.className = that.houseTypeList[indexs[0]].title;
//
that.debounceSaveFormData()
}, },
// //
@ -232,12 +270,16 @@
self.form.propertyImages.push({ self.form.propertyImages.push({
url url
}) })
//
self.debounceSaveFormData()
}) })
}) })
}, },
deletePropertyPic(event) { deletePropertyPic(event) {
this.form.propertyImages.splice(event.index, 1) this.form.propertyImages.splice(event.index, 1)
//
this.debounceSaveFormData()
}, },
// //
@ -264,6 +306,8 @@
self.form.videos.push({ self.form.videos.push({
url url
}) })
//
self.debounceSaveFormData()
}) })
} catch (error) { } catch (error) {
console.error('获取视频时长失败:', error) console.error('获取视频时长失败:', error)
@ -311,6 +355,8 @@
deleteVideoPic(event) { deleteVideoPic(event) {
this.form.videos.splice(event.index, 1) this.form.videos.splice(event.index, 1)
//
this.debounceSaveFormData()
}, },
// //
@ -397,6 +443,8 @@
// API // API
saveOrUpdateHouse(params).then(response => { saveOrUpdateHouse(params).then(response => {
uni.hideLoading(); uni.hideLoading();
//
formStorage.removeFormData(this.formKey);
uni.showToast({ uni.showToast({
title: response.message || '提交成功', title: response.message || '提交成功',
icon: 'success' icon: 'success'


+ 82
- 22
pages_subpack/house/farmhouse.vue View File

@ -12,7 +12,7 @@
<!-- 1. 出租/流转 --> <!-- 1. 出租/流转 -->
<uv-form-item label="类型" prop="type" required> <uv-form-item label="类型" prop="type" required>
<uv-radio-group v-model="form.type" placement="row">
<uv-radio-group v-model="form.type" placement="row" @change="debounceSaveFormData">
<uv-radio name="rent" label="出租"></uv-radio> <uv-radio name="rent" label="出租"></uv-radio>
<uv-radio name="transfer" customStyle="margin-left:30rpx;" label="流转"></uv-radio> <uv-radio name="transfer" customStyle="margin-left:30rpx;" label="流转"></uv-radio>
</uv-radio-group> </uv-radio-group>
@ -29,11 +29,11 @@
<!-- 3. 联系人和电话 --> <!-- 3. 联系人和电话 -->
<uv-form-item label="联系人" prop="contactName" required> <uv-form-item label="联系人" prop="contactName" required>
<uv-input v-model="form.contactName" type="text" placeholder="请输入联系人姓名" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;"></uv-input>
<uv-input v-model="form.contactName" type="text" placeholder="请输入联系人姓名" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;" @input="debounceSaveFormData"></uv-input>
</uv-form-item> </uv-form-item>
<uv-form-item label="联系电话" prop="contactPhone" required> <uv-form-item label="联系电话" prop="contactPhone" required>
<uv-input v-model="form.contactPhone" type="number" placeholder="请输入联系电话" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;"></uv-input>
<uv-input v-model="form.contactPhone" type="number" placeholder="请输入联系电话" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;" @input="debounceSaveFormData"></uv-input>
</uv-form-item> </uv-form-item>
<!-- 4. 房屋状况 --> <!-- 4. 房屋状况 -->
@ -55,7 +55,7 @@
<!-- 6. 产权面积 --> <!-- 6. 产权面积 -->
<uv-form-item label="房屋面积" prop="houseArea" required> <uv-form-item label="房屋面积" prop="houseArea" required>
<view class="input-with-unit"> <view class="input-with-unit">
<uv-input v-model="form.houseArea" type="digit" placeholder="请输入房屋面积" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;"></uv-input>
<uv-input v-model="form.houseArea" type="digit" placeholder="请输入房屋面积" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;" @input="debounceSaveFormData"></uv-input>
<text class="unit">平米</text> <text class="unit">平米</text>
</view> </view>
<view class="input-tip">请录入房屋证或不动产权证登记面积</view> <view class="input-tip">请录入房屋证或不动产权证登记面积</view>
@ -63,7 +63,7 @@
<uv-form-item label="土地面积" prop="landArea" required> <uv-form-item label="土地面积" prop="landArea" required>
<view class="input-with-unit"> <view class="input-with-unit">
<uv-input v-model="form.landArea" type="digit" placeholder="请输入土地面积" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;"></uv-input>
<uv-input v-model="form.landArea" type="digit" placeholder="请输入土地面积" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;" @input="debounceSaveFormData"></uv-input>
<text class="unit">平米</text> <text class="unit">平米</text>
</view> </view>
<view class="input-tip">请录入土地使用证或不动产权证面积</view> <view class="input-tip">请录入土地使用证或不动产权证面积</view>
@ -86,7 +86,7 @@
<!-- 9. 价格 --> <!-- 9. 价格 -->
<uv-form-item label="价格" prop="price" required> <uv-form-item label="价格" prop="price" required>
<view class="price-container"> <view class="price-container">
<uv-input v-model="form.price" type="digit" placeholder="请输入价格" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;flex:1;"></uv-input>
<uv-input v-model="form.price" type="digit" placeholder="请输入价格" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;flex:1;" @input="debounceSaveFormData"></uv-input>
<text class="price-unit" v-if="form.type === 'rent'">/</text> <text class="price-unit" v-if="form.type === 'rent'">/</text>
<text class="price-unit" v-else-if="form.type === 'transfer'">万元</text> <text class="price-unit" v-else-if="form.type === 'transfer'">万元</text>
<text class="price-unit" v-else></text> <text class="price-unit" v-else></text>
@ -109,7 +109,7 @@
<!-- 10. 可用菜地 --> <!-- 10. 可用菜地 -->
<uv-form-item label="可用菜地" prop="vegetableGarden"> <uv-form-item label="可用菜地" prop="vegetableGarden">
<view class="input-with-unit"> <view class="input-with-unit">
<uv-input v-model="form.vegetableGarden" type="digit" placeholder="请输入菜地面积" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;"></uv-input>
<uv-input v-model="form.vegetableGarden" type="digit" placeholder="请输入菜地面积" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;" @input="debounceSaveFormData"></uv-input>
<text class="unit">平米</text> <text class="unit">平米</text>
</view> </view>
</uv-form-item> </uv-form-item>
@ -153,6 +153,7 @@
customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:10px;" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:10px;"
:autoHeight="true" :autoHeight="true"
:maxlength="500" :maxlength="500"
@input="debounceSaveFormData"
></uv-input> ></uv-input>
</uv-form-item> </uv-form-item>
@ -172,11 +173,14 @@
<script> <script>
import { saveOrUpdateHouse, houseType } from "@/common/api.js" import { saveOrUpdateHouse, houseType } from "@/common/api.js"
import formStorage from "@/utils/formStorage.js"
export default { export default {
data() {
return {
commonClass: '', // ID
data() {
return {
formKey: 'farmhouse_form', //
saveTimer: null, //
commonClass: '', // ID
form: { form: {
type: '', // / type: '', // /
address: '', // address: '', //
@ -267,8 +271,40 @@
// //
this.onHouseType() this.onHouseType()
//
this.restoreFormData()
},
onUnload() {
//
this.saveFormData()
//
if (this.saveTimer) {
clearTimeout(this.saveTimer)
}
}, },
methods: { methods: {
//
restoreFormData() {
const savedData = formStorage.getFormData(this.formKey)
if (savedData) {
//
this.form = { ...this.form, ...savedData }
}
},
//
saveFormData() {
formStorage.saveFormData(this.formKey, this.form)
},
//
debounceSaveFormData() {
clearTimeout(this.saveTimer)
this.saveTimer = setTimeout(() => {
this.saveFormData()
}, 1000)
},
// //
onHouseType(){ onHouseType(){
let that = this let that = this
@ -310,6 +346,8 @@
const { indexs, value } = e; const { indexs, value } = e;
this.form.houseCondition = value[0]; // 使 this.form.houseCondition = value[0]; // 使
this.form.houseConditionName = value[0]; this.form.houseConditionName = value[0];
//
this.debounceSaveFormData()
}, },
// //
@ -322,6 +360,8 @@
let {indexs,value,values} = e let {indexs,value,values} = e
that.form.classId = that.houseTypeList[indexs[0]].id; that.form.classId = that.houseTypeList[indexs[0]].id;
that.form.className = that.houseTypeList[indexs[0]].title; that.form.className = that.houseTypeList[indexs[0]].title;
//
that.debounceSaveFormData()
}, },
// //
@ -332,12 +372,16 @@
self.form.propertyImages.push({ self.form.propertyImages.push({
url url
}) })
//
self.debounceSaveFormData()
}) })
}) })
}, },
deletePropertyPic(event) { deletePropertyPic(event) {
this.form.propertyImages.splice(event.index, 1) this.form.propertyImages.splice(event.index, 1)
//
this.debounceSaveFormData()
}, },
// //
@ -348,12 +392,16 @@
self.form.frontImages.push({ self.form.frontImages.push({
url url
}) })
//
self.debounceSaveFormData()
}) })
}) })
}, },
deleteFrontPic(event) { deleteFrontPic(event) {
this.form.frontImages.splice(event.index, 1) this.form.frontImages.splice(event.index, 1)
//
this.debounceSaveFormData()
}, },
// //
@ -375,6 +423,8 @@
self.form.videos.push({ self.form.videos.push({
url url
}) })
//
self.debounceSaveFormData()
}) })
} catch (error) { } catch (error) {
console.error('视频处理失败:', error) console.error('视频处理失败:', error)
@ -383,6 +433,8 @@
self.form.videos.push({ self.form.videos.push({
url url
}) })
//
self.debounceSaveFormData()
}) })
} }
} }
@ -424,6 +476,8 @@
deleteVideoPic(event) { deleteVideoPic(event) {
this.form.videos.splice(event.index, 1) this.form.videos.splice(event.index, 1)
//
this.debounceSaveFormData()
}, },
// //
@ -434,6 +488,8 @@
} else { } else {
this.form.highlights.push(item); this.form.highlights.push(item);
} }
//
this.debounceSaveFormData()
}, },
// //
@ -444,6 +500,8 @@
} else { } else {
this.form.disadvantages.push(item); this.form.disadvantages.push(item);
} }
//
this.debounceSaveFormData()
}, },
// //
@ -536,18 +594,20 @@
}); });
// API // API
saveOrUpdateHouse(params).then(response => {
uni.hideLoading();
uni.showToast({
title: response.message || '提交成功',
icon: 'success'
});
setTimeout(() => {
uni.redirectTo({
url: "/pages_subpack/successful-apply/index"
});
}, 2000);
}).catch(error => {
saveOrUpdateHouse(params).then(response => {
uni.hideLoading();
//
formStorage.removeFormData(this.formKey);
uni.showToast({
title: response.message || '提交成功',
icon: 'success'
});
setTimeout(() => {
uni.redirectTo({
url: "/pages_subpack/successful-apply/index"
});
}, 2000);
}).catch(error => {
uni.hideLoading(); uni.hideLoading();
uni.showToast({ uni.showToast({
title: error.message || '提交失败', title: error.message || '提交失败',


+ 71
- 19
pages_subpack/house/other.vue View File

@ -12,7 +12,7 @@
<!-- 1. 出租/流转 --> <!-- 1. 出租/流转 -->
<uv-form-item label="类型" prop="type" required> <uv-form-item label="类型" prop="type" required>
<uv-radio-group v-model="form.type" placement="row">
<uv-radio-group v-model="form.type" placement="row" @change="debounceSaveFormData">
<uv-radio name="rent" label="出租"></uv-radio> <uv-radio name="rent" label="出租"></uv-radio>
<uv-radio name="transfer" customStyle="margin-left:30rpx;" label="流转"></uv-radio> <uv-radio name="transfer" customStyle="margin-left:30rpx;" label="流转"></uv-radio>
</uv-radio-group> </uv-radio-group>
@ -29,11 +29,11 @@
<!-- 3. 联系人和电话 --> <!-- 3. 联系人和电话 -->
<uv-form-item label="联系人" prop="contactName" required> <uv-form-item label="联系人" prop="contactName" required>
<uv-input v-model="form.contactName" type="text" placeholder="请输入联系人姓名" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;"></uv-input>
<uv-input v-model="form.contactName" type="text" placeholder="请输入联系人姓名" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;" @input="debounceSaveFormData"></uv-input>
</uv-form-item> </uv-form-item>
<uv-form-item label="联系电话" prop="contactPhone" required> <uv-form-item label="联系电话" prop="contactPhone" required>
<uv-input v-model="form.contactPhone" type="number" placeholder="请输入联系电话" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;"></uv-input>
<uv-input v-model="form.contactPhone" type="number" placeholder="请输入联系电话" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;" @input="debounceSaveFormData"></uv-input>
</uv-form-item> </uv-form-item>
<!-- 4. 照片和视频 --> <!-- 4. 照片和视频 -->
@ -52,7 +52,7 @@
<!-- 5. 价格 --> <!-- 5. 价格 -->
<uv-form-item label="价格" prop="price" required> <uv-form-item label="价格" prop="price" required>
<view class="price-container"> <view class="price-container">
<uv-input v-model="form.price" type="digit" placeholder="请输入价格" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;flex:1;"></uv-input>
<uv-input v-model="form.price" type="digit" placeholder="请输入价格" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;flex:1;" @input="debounceSaveFormData"></uv-input>
<text class="price-unit"></text> <text class="price-unit"></text>
</view> </view>
<view class="input-tip">请输入数字支持小数点后两位</view> <view class="input-tip">请输入数字支持小数点后两位</view>
@ -67,6 +67,7 @@
customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:10px;" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:10px;"
:autoHeight="true" :autoHeight="true"
:maxlength="1000" :maxlength="1000"
@input="debounceSaveFormData"
></uv-input> ></uv-input>
<view class="char-count">{{form.description.length}}/1000</view> <view class="char-count">{{form.description.length}}/1000</view>
<view class="input-tip">请详细描述资源的类型用途特色规模优势等</view> <view class="input-tip">请详细描述资源的类型用途特色规模优势等</view>
@ -111,11 +112,14 @@
<script> <script>
import { saveOrUpdateHouse, houseType } from "@/common/api.js" import { saveOrUpdateHouse, houseType } from "@/common/api.js"
import formStorage from "@/utils/formStorage.js"
export default { export default {
data() {
return {
commonClass: '', // ID
data() {
return {
formKey: 'other_form', //
saveTimer: null, //
commonClass: '', // ID
form: { form: {
type: '', // / type: '', // /
address: '', // address: '', //
@ -182,8 +186,40 @@
// //
this.onHouseType() this.onHouseType()
//
this.restoreFormData()
},
onUnload() {
//
this.saveFormData()
//
if (this.saveTimer) {
clearTimeout(this.saveTimer)
}
}, },
methods: { methods: {
//
restoreFormData() {
const savedData = formStorage.getFormData(this.formKey)
if (savedData) {
//
this.form = { ...this.form, ...savedData }
}
},
//
saveFormData() {
formStorage.saveFormData(this.formKey, this.form)
},
//
debounceSaveFormData() {
clearTimeout(this.saveTimer)
this.saveTimer = setTimeout(() => {
this.saveFormData()
}, 1000)
},
// //
onHouseType(){ onHouseType(){
let that = this let that = this
@ -224,12 +260,16 @@
self.form.images.push({ self.form.images.push({
url url
}) })
//
self.debounceSaveFormData()
}) })
}) })
}, },
deleteImagePic(event) { deleteImagePic(event) {
this.form.images.splice(event.index, 1) this.form.images.splice(event.index, 1)
//
this.debounceSaveFormData()
}, },
// //
@ -251,6 +291,8 @@
self.form.videos.push({ self.form.videos.push({
url url
}) })
//
self.debounceSaveFormData()
}) })
} catch (error) { } catch (error) {
console.error('视频处理失败:', error) console.error('视频处理失败:', error)
@ -259,6 +301,8 @@
self.form.videos.push({ self.form.videos.push({
url url
}) })
//
self.debounceSaveFormData()
}) })
} }
} }
@ -300,6 +344,8 @@
deleteVideoPic(event) { deleteVideoPic(event) {
this.form.videos.splice(event.index, 1) this.form.videos.splice(event.index, 1)
//
this.debounceSaveFormData()
}, },
// //
@ -311,6 +357,8 @@
onAgreementChange(e) { onAgreementChange(e) {
console.log('代理协议状态变化:', e); console.log('代理协议状态变化:', e);
this.form.agreeProtocol = e; this.form.agreeProtocol = e;
//
this.debounceSaveFormData()
}, },
confirm(e) { confirm(e) {
@ -318,6 +366,8 @@
let {indexs,value,values} = e let {indexs,value,values} = e
that.form.classId = that.houseTypeList[indexs[0]].id; that.form.classId = that.houseTypeList[indexs[0]].id;
that.form.className = that.houseTypeList[indexs[0]].title; that.form.className = that.houseTypeList[indexs[0]].title;
//
that.debounceSaveFormData()
}, },
// //
@ -412,18 +462,20 @@
}); });
// API // API
saveOrUpdateHouse(params).then(response => {
uni.hideLoading();
uni.showToast({
title: response.message || '提交成功',
icon: 'success'
});
setTimeout(() => {
uni.redirectTo({
url: "/pages_subpack/successful-apply/index"
});
}, 2000);
}).catch(error => {
saveOrUpdateHouse(params).then(response => {
uni.hideLoading();
//
formStorage.removeFormData(this.formKey);
uni.showToast({
title: response.message || '提交成功',
icon: 'success'
});
setTimeout(() => {
uni.redirectTo({
url: "/pages_subpack/successful-apply/index"
});
}, 2000);
}).catch(error => {
uni.hideLoading(); uni.hideLoading();
uni.showToast({ uni.showToast({
title: error.message || '提交失败', title: error.message || '提交失败',


+ 146
- 0
utils/README_formStorage.md View File

@ -0,0 +1,146 @@
# 表单数据本地存储工具使用说明
## 概述
`formStorage.js` 是一个专门用于防止用户意外退出导致表单数据丢失的工具类。它会自动保存用户填写的表单数据到本地存储,并在用户重新进入页面时恢复数据。
## 功能特性
- ✅ **自动保存**: 用户输入时自动保存表单数据
- ✅ **数据恢复**: 页面重新加载时自动恢复之前填写的数据
- ✅ **防抖机制**: 避免频繁保存操作,提升性能
- ✅ **数据过期**: 支持设置数据过期时间(默认7天)
- ✅ **提交清理**: 表单提交成功后自动清除本地数据
- ✅ **多表单支持**: 支持多个表单页面独立存储
## 已集成页面
目前已为以下三个表单页面集成了数据存储功能:
1. **经营性建设用地录入** (`commercial.vue`) - formKey: `commercial_form`
2. **闲置农房信息录入** (`farmhouse.vue`) - formKey: `farmhouse_form`
3. **其他农村资源录入** (`other.vue`) - formKey: `other_form`
## 工作流程
### 1. 页面加载时
- 自动检查是否有保存的表单数据
- 如果有数据且未过期,则恢复到表单中
- 显示提示信息告知用户数据已恢复
### 2. 用户操作时
- 监听所有表单输入事件(input、change等)
- 使用防抖机制(1秒延迟)自动保存数据
- 包括文本输入、选择器、文件上传等所有操作
### 3. 页面卸载时
- 保存当前表单状态
- 清理防抖定时器
### 4. 表单提交成功后
- 自动清除本地存储的表单数据
- 避免下次进入时恢复已提交的数据
## 监听的操作类型
### 基础输入
- 文本输入框 (`@input`)
- 数字输入框 (`@input`)
- 文本域 (`@input`)
- 单选按钮组 (`@change`)
- 复选框 (`@change`)
### 选择器操作
- 地址选择
- 分类选择
- 房屋状况选择
### 文件操作
- 图片上传完成
- 视频上传完成
- 文件删除
### 特殊操作
- 标签选择(房屋亮点、不利因素)
- 协议勾选状态变化
## 数据存储格式
```javascript
{
data: {}, // 表单数据对象
timestamp: 1234567890 // 保存时间戳
}
```
## 存储键名规则
- 前缀: `form_data_`
- 完整键名: `form_data_{formKey}`
- 示例: `form_data_commercial_form`
## 用户体验
### 数据恢复提示
当检测到有保存的数据时,会显示Toast提示:
```
已恢复上次填写的数据
```
### 自动保存
- 用户无需手动保存
- 所有操作都会触发自动保存
- 使用防抖机制避免频繁操作
### 数据清理
- 表单提交成功后自动清理
- 数据过期后自动清理(7天)
- 支持手动清理所有表单数据
## 技术实现
### 防抖机制
```javascript
debounceSaveFormData() {
clearTimeout(this.saveTimer)
this.saveTimer = setTimeout(() => {
this.saveFormData()
}, 1000)
}
```
### 数据恢复
```javascript
restoreFormData() {
const savedData = formStorage.getFormData(this.formKey)
if (savedData) {
this.form = { ...this.form, ...savedData }
// 显示恢复提示
}
}
```
### 生命周期集成
- `onLoad`: 恢复数据
- `onUnload`: 保存数据
- 提交成功: 清除数据
## 注意事项
1. **数据安全**: 敏感信息不会被保存(如密码等)
2. **存储限制**: 受浏览器本地存储容量限制
3. **数据同步**: 仅在本地设备有效,不跨设备同步
4. **过期清理**: 超过7天的数据会自动清理
5. **性能优化**: 使用防抖机制避免频繁保存
## 扩展使用
如需为其他表单页面添加此功能,请参考已集成页面的实现方式:
1. 导入工具类
2. 设置唯一的 `formKey`
3. 在生命周期中调用相应方法
4. 为表单控件添加事件监听
5. 在提交成功后清理数据
这样可以确保用户在填写表单时不会因为意外退出而丢失数据,大大提升用户体验。

+ 196
- 0
utils/formStorage.js View File

@ -0,0 +1,196 @@
/**
* 表单数据本地存储工具类
* 用于防止用户意外退出导致表单数据丢失
*/
class FormStorage {
constructor() {
this.prefix = 'form_data_';
}
/**
* 保存表单数据到本地存储
* @param {string} formKey - 表单唯一标识
* @param {object} formData - 表单数据
*/
saveFormData(formKey, formData) {
try {
const key = this.prefix + formKey;
const dataToSave = {
data: formData,
timestamp: Date.now()
};
uni.setStorageSync(key, JSON.stringify(dataToSave));
console.log(`表单数据已保存: ${formKey}`);
} catch (error) {
console.error('保存表单数据失败:', error);
}
}
/**
* 从本地存储恢复表单数据
* @param {string} formKey - 表单唯一标识
* @param {number} expireTime - 过期时间(毫秒)默认7天
* @returns {object|null} 表单数据或null
*/
getFormData(formKey, expireTime = 7 * 24 * 60 * 60 * 1000) {
try {
const key = this.prefix + formKey;
const savedData = uni.getStorageSync(key);
if (!savedData) {
return null;
}
const parsedData = JSON.parse(savedData);
const now = Date.now();
// 检查数据是否过期
if (now - parsedData.timestamp > expireTime) {
this.removeFormData(formKey);
console.log(`表单数据已过期并清除: ${formKey}`);
return null;
}
console.log(`表单数据已恢复: ${formKey}`);
return parsedData.data;
} catch (error) {
console.error('恢复表单数据失败:', error);
return null;
}
}
/**
* 删除指定表单的本地存储数据
* @param {string} formKey - 表单唯一标识
*/
removeFormData(formKey) {
try {
const key = this.prefix + formKey;
uni.removeStorageSync(key);
console.log(`表单数据已清除: ${formKey}`);
} catch (error) {
console.error('清除表单数据失败:', error);
}
}
/**
* 清除所有表单数据
*/
clearAllFormData() {
try {
const storageInfo = uni.getStorageInfoSync();
const keysToRemove = storageInfo.keys.filter(key => key.startsWith(this.prefix));
keysToRemove.forEach(key => {
uni.removeStorageSync(key);
});
console.log(`已清除所有表单数据,共${keysToRemove.length}`);
} catch (error) {
console.error('清除所有表单数据失败:', error);
}
}
/**
* 检查是否存在指定表单的数据
* @param {string} formKey - 表单唯一标识
* @returns {boolean}
*/
hasFormData(formKey) {
try {
const key = this.prefix + formKey;
const savedData = uni.getStorageSync(key);
return !!savedData;
} catch (error) {
console.error('检查表单数据失败:', error);
return false;
}
}
/**
* 获取所有已保存的表单列表
* @returns {Array} 表单key列表
*/
getAllFormKeys() {
try {
const storageInfo = uni.getStorageInfoSync();
return storageInfo.keys
.filter(key => key.startsWith(this.prefix))
.map(key => key.replace(this.prefix, ''));
} catch (error) {
console.error('获取表单列表失败:', error);
return [];
}
}
}
// 创建单例实例
const formStorage = new FormStorage();
// 导出实例和类
export default formStorage;
export { FormStorage };
/**
* 使用示例
*
* // 在表单页面中使用
* import formStorage from '@/utils/formStorage.js';
*
* export default {
* data() {
* return {
* form: {
* name: '',
* phone: '',
* // ... 其他字段
* },
* formKey: 'commercial_form' // 每个表单页面使用不同的key
* }
* },
*
* onLoad() {
* // 页面加载时恢复数据
* this.restoreFormData();
* },
*
* onUnload() {
* // 页面卸载时保存数据
* this.saveFormData();
* },
*
* methods: {
* // 恢复表单数据
* restoreFormData() {
* const savedData = formStorage.getFormData(this.formKey);
* if (savedData) {
* this.form = { ...this.form, ...savedData };
* uni.showToast({
* title: '已恢复上次填写的数据',
* icon: 'none'
* });
* }
* },
*
* // 保存表单数据
* saveFormData() {
* formStorage.saveFormData(this.formKey, this.form);
* },
*
* // 表单提交成功后清除数据
* onSubmitSuccess() {
* formStorage.removeFormData(this.formKey);
* },
*
* // 监听表单变化自动保存(可选)
* onFormChange() {
* // 防抖保存,避免频繁操作
* clearTimeout(this.saveTimer);
* this.saveTimer = setTimeout(() => {
* this.saveFormData();
* }, 1000);
* }
* }
* }
*/

Loading…
Cancel
Save