租房小程序前端代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

622 lines
20 KiB

  1. <template>
  2. <view class="container">
  3. <view class="header">
  4. <view class="title">闲置农房信息录入</view>
  5. </view>
  6. <view class="form-container">
  7. <uv-form labelPosition="left" :model="form" :rules="rules" ref="form" labelWidth="80" labelStyle="font-size:28rpx;">
  8. <!-- 必填项 -->
  9. <view class="section-title">基本信息必填</view>
  10. <!-- 1. 出租/流转 -->
  11. <uv-form-item label="类型" prop="type" required>
  12. <uv-radio-group v-model="form.type" placement="row">
  13. <uv-radio name="rent" label="出租"></uv-radio>
  14. <uv-radio name="transfer" customStyle="margin-left:30rpx;" label="流转"></uv-radio>
  15. </uv-radio-group>
  16. </uv-form-item>
  17. <!-- 2. 地址 -->
  18. <uv-form-item label="地址" prop="address" required @click="handleAddressSelect()">
  19. <uv-input v-model="form.address" @click="handleAddressSelect()" disabled disabledColor="#ffffff" placeholder="请选择房屋位置" border="none">
  20. </uv-input>
  21. <template v-slot:right>
  22. <uv-icon name="arrow-right"></uv-icon>
  23. </template>
  24. </uv-form-item>
  25. <!-- 3. 联系人和电话 -->
  26. <uv-form-item label="联系人" prop="contactName" required>
  27. <uv-input v-model="form.contactName" type="text" placeholder="请输入联系人姓名" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;"></uv-input>
  28. </uv-form-item>
  29. <uv-form-item label="联系电话" prop="contactPhone" required>
  30. <uv-input v-model="form.contactPhone" type="number" placeholder="请输入联系电话" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;"></uv-input>
  31. </uv-form-item>
  32. <!-- 4. 房屋状况 -->
  33. <uv-form-item label="房屋状况" prop="houseCondition" required @click="handleHouseConditionSelect()">
  34. <uv-input v-model="form.houseConditionName" @click="handleHouseConditionSelect()" disabled disabledColor="#ffffff" placeholder="请选择房屋状况" border="none">
  35. </uv-input>
  36. <template v-slot:right>
  37. <uv-icon name="arrow-right"></uv-icon>
  38. </template>
  39. </uv-form-item>
  40. <!-- 5. 产权证照片 -->
  41. <uv-form-item label="产权证照片" labelWidth="250" prop="propertyImages" labelPosition="top" required>
  42. <view class="upload-tip">请上传房产证土地证或不动产权证照片</view>
  43. <uv-upload customStyle="margin-top:20rpx;" :fileList="form.propertyImages" @afterRead="afterPropertyRead" @delete="deletePropertyPic" name="1"
  44. multiple :maxCount="5"></uv-upload>
  45. </uv-form-item>
  46. <!-- 6. 产权面积 -->
  47. <uv-form-item label="房屋面积" prop="houseArea" required>
  48. <view class="input-with-unit">
  49. <uv-input v-model="form.houseArea" type="digit" placeholder="请输入房屋面积" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;"></uv-input>
  50. <text class="unit">平米</text>
  51. </view>
  52. <view class="input-tip">请录入房屋证或不动产权证登记面积</view>
  53. </uv-form-item>
  54. <uv-form-item label="土地面积" prop="landArea" required>
  55. <view class="input-with-unit">
  56. <uv-input v-model="form.landArea" type="digit" placeholder="请输入土地面积" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;"></uv-input>
  57. <text class="unit">平米</text>
  58. </view>
  59. <view class="input-tip">请录入土地使用证或不动产权证面积</view>
  60. </uv-form-item>
  61. <!-- 7. 房屋正面照片 -->
  62. <uv-form-item label="房屋正面照片" labelWidth="250" prop="frontImages" labelPosition="top" required>
  63. <view class="upload-tip">作为封面展示建议拍摄房屋正面全貌</view>
  64. <uv-upload customStyle="margin-top:20rpx;" :fileList="form.frontImages" @afterRead="afterFrontRead" @delete="deleteFrontPic" name="1"
  65. multiple :maxCount="3"></uv-upload>
  66. </uv-form-item>
  67. <!-- 8. 房屋视频 -->
  68. <uv-form-item label="房屋视频" labelWidth="250" prop="videos" labelPosition="top" required>
  69. <view class="upload-tip">请上传房屋内部和外部视频1分钟内</view>
  70. <uv-upload customStyle="margin-top:20rpx;" accept="video" :fileList="form.videos" @afterRead="afterVideoRead" @delete="deleteVideoPic" name="1"
  71. multiple :maxCount="2"></uv-upload>
  72. </uv-form-item>
  73. <!-- 9. 价格 -->
  74. <uv-form-item label="价格" prop="price" required>
  75. <view class="price-container">
  76. <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>
  77. <text class="price-unit" v-if="form.type === 'rent'">/</text>
  78. <text class="price-unit" v-else-if="form.type === 'transfer'">万元</text>
  79. <text class="price-unit" v-else></text>
  80. </view>
  81. <view class="input-tip">请输入数字支持小数点后两位</view>
  82. </uv-form-item>
  83. <!-- 分类标识 -->
  84. <uv-form-item label="分类标识" prop="classId" @click="handleClass()">
  85. <uv-input v-model="form.className" @click="handleClass()" disabled disabledColor="#ffffff" placeholder="选择分类标识" border="none">
  86. </uv-input>
  87. <template v-slot:right>
  88. <uv-icon name="arrow-right"></uv-icon>
  89. </template>
  90. </uv-form-item>
  91. <!-- 选填项 -->
  92. <view class="section-title">详细信息选填</view>
  93. <!-- 10. 可用菜地 -->
  94. <uv-form-item label="可用菜地" prop="vegetableGarden">
  95. <view class="input-with-unit">
  96. <uv-input v-model="form.vegetableGarden" type="digit" placeholder="请输入菜地面积" customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:5px 10px;"></uv-input>
  97. <text class="unit">平米</text>
  98. </view>
  99. </uv-form-item>
  100. <!-- 11. 房屋亮点 -->
  101. <uv-form-item label="房屋亮点" prop="highlights" labelPosition="top">
  102. <view class="tags-container">
  103. <view
  104. class="tag-item"
  105. :class="{ 'tag-selected': form.highlights.includes(item) }"
  106. v-for="item in highlightOptions"
  107. :key="item"
  108. @click="toggleHighlight(item)"
  109. >
  110. {{item}}
  111. </view>
  112. </view>
  113. </uv-form-item>
  114. <!-- 12. 不利因素 -->
  115. <uv-form-item label="不利因素" prop="disadvantages" labelPosition="top">
  116. <view class="tags-container">
  117. <view
  118. class="tag-item disadvantage-tag"
  119. :class="{ 'tag-selected': form.disadvantages.includes(item) }"
  120. v-for="item in disadvantageOptions"
  121. :key="item"
  122. @click="toggleDisadvantage(item)"
  123. >
  124. {{item}}
  125. </view>
  126. </view>
  127. </uv-form-item>
  128. <!-- 13. 房屋介绍 -->
  129. <uv-form-item label="房屋介绍" prop="description" labelPosition="top">
  130. <uv-input
  131. v-model="form.description"
  132. type="textarea"
  133. placeholder="请详细介绍房屋情况、周边环境等"
  134. customStyle="border-radius: 5px;margin-top:5px;background-color: #f5f5f5;padding:10px;"
  135. :autoHeight="true"
  136. :maxlength="500"
  137. ></uv-input>
  138. </uv-form-item>
  139. <uv-form-item>
  140. <uv-button type="primary" text="提交信息" customStyle="margin-top: 30px;background-color: #1EC77A;border-radius: 30px;" @click="submit"></uv-button>
  141. </uv-form-item>
  142. </uv-form>
  143. </view>
  144. <!-- 房屋状况选择器 -->
  145. <uv-picker ref="houseConditionPicker" :columns="houseConditionColumns" @confirm="confirmHouseCondition"></uv-picker>
  146. <!-- 分类选择器 -->
  147. <uv-picker ref="picker" :columns="columns" @confirm="confirm"></uv-picker>
  148. </view>
  149. </template>
  150. <script>
  151. import { saveOrUpdateHouse, houseType } from "@/common/api.js"
  152. export default {
  153. data() {
  154. return {
  155. commonClass: '', // 所属分类ID
  156. form: {
  157. type: '', // 出租/流转
  158. address: '', // 地址
  159. contactName: '', // 联系人
  160. contactPhone: '', // 联系电话
  161. houseCondition: '', // 房屋状况ID
  162. houseConditionName: '', // 房屋状况名称
  163. propertyImages: [], // 产权证照片
  164. houseArea: '', // 房屋面积
  165. landArea: '', // 土地面积
  166. frontImages: [], // 房屋正面照片
  167. videos: [], // 房屋视频
  168. price: '', // 价格
  169. longitude: '', // 经度
  170. latitude: '', // 纬度
  171. vegetableGarden: '', // 可用菜地
  172. highlights: [], // 房屋亮点
  173. disadvantages: [], // 不利因素
  174. description: '', // 房屋介绍
  175. classId: '', // 分类标识
  176. className: '' // 分类名称
  177. },
  178. houseConditionColumns: [
  179. ['老旧房屋', '装修较好可拎包入住', '新房']
  180. ],
  181. highlightOptions: [
  182. '靠河', '靠山', '通自来水', '通天然气', '近场镇或城市',
  183. '双车道到家', '精装修', '四合院', '周边无坟墓', '周边无电线塔'
  184. ],
  185. disadvantageOptions: [
  186. '可见坟墓', '周边有电塔', '非正常死亡'
  187. ],
  188. columns: [], // 分类选择器数据
  189. houseTypeList: [], // 分类列表
  190. rules: {
  191. type: [
  192. { required: true, message: '请选择出租或流转', trigger: ['blur', 'change'] }
  193. ],
  194. address: [
  195. { required: true, message: '请选择房屋地址', trigger: ['blur', 'change'] }
  196. ],
  197. contactName: [
  198. { required: true, message: '请输入联系人姓名', trigger: ['blur', 'change'] }
  199. ],
  200. contactPhone: [
  201. { required: true, message: '请输入联系电话', trigger: ['blur', 'change'] },
  202. { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: ['blur', 'change'] }
  203. ],
  204. houseCondition: [
  205. { required: true, message: '请选择房屋状况', trigger: ['blur', 'change'] }
  206. ],
  207. houseArea: [
  208. { required: true, message: '请输入房屋面积', trigger: ['blur', 'change'] },
  209. { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: ['blur', 'change'] }
  210. ],
  211. landArea: [
  212. { required: true, message: '请输入土地面积', trigger: ['blur', 'change'] },
  213. { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: ['blur', 'change'] }
  214. ],
  215. price: [
  216. { required: true, message: '请输入价格', trigger: ['blur', 'change'] },
  217. { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的价格格式', trigger: ['blur', 'change'] }
  218. ],
  219. classId: [
  220. { required: true, message: '请选择分类标识', trigger: ['blur', 'change'] }
  221. ]
  222. }
  223. }
  224. },
  225. onReady() {
  226. this.$refs.form.setRules(this.rules)
  227. },
  228. onLoad(options) {
  229. // 设置页面标题
  230. uni.setNavigationBarTitle({
  231. title: '闲置农房录入'
  232. })
  233. // 接收传递的commonClass参数
  234. if(options.commonClass) {
  235. this.commonClass = options.commonClass
  236. }
  237. // 如果是编辑模式,设置classId用于回显
  238. if(options.classId) {
  239. this.form.classId = options.classId
  240. }
  241. // 初始化分类数据
  242. this.onHouseType()
  243. },
  244. methods: {
  245. // 获取分类数据
  246. onHouseType(){
  247. let that = this
  248. houseType({}).then(response=>{
  249. let arr=[]
  250. that.houseTypeList = response.result
  251. response.result.forEach(items=>{
  252. arr.push(items.title)
  253. // 数据回显:如果当前classId匹配,设置className
  254. if(items.id == that.form.classId){
  255. that.form.className = items.title
  256. }
  257. })
  258. that.columns[0]=arr
  259. }).catch(error=>{
  260. })
  261. },
  262. // 地址选择
  263. handleAddressSelect() {
  264. const that = this;
  265. wx.chooseLocation({
  266. success: function (res) {
  267. console.log('选择的位置:', res);
  268. that.form.longitude = res.longitude
  269. that.form.latitude = res.latitude
  270. that.form.address = res.address
  271. }
  272. })
  273. },
  274. // 房屋状况选择
  275. handleHouseConditionSelect() {
  276. this.$refs.houseConditionPicker.open();
  277. },
  278. confirmHouseCondition(e) {
  279. const { indexs, value } = e;
  280. this.form.houseCondition = value[0]; // 修改:直接使用选择的值而不是索引
  281. this.form.houseConditionName = value[0];
  282. },
  283. // 分类标识选择
  284. handleClass() {
  285. this.$refs.picker.open();
  286. },
  287. confirm(e) {
  288. let that = this
  289. let {indexs,value,values} = e
  290. that.form.classId = that.houseTypeList[indexs[0]].id;
  291. that.form.className = that.houseTypeList[indexs[0]].title;
  292. },
  293. // 产权证照片上传
  294. async afterPropertyRead(e) {
  295. let self = this
  296. e.file.forEach(file => {
  297. self.$Oss.ossUpload(file.url).then(url => {
  298. self.form.propertyImages.push({
  299. url
  300. })
  301. })
  302. })
  303. },
  304. deletePropertyPic(event) {
  305. this.form.propertyImages.splice(event.index, 1)
  306. },
  307. // 房屋正面照片上传
  308. async afterFrontRead(e) {
  309. let self = this
  310. e.file.forEach(file => {
  311. self.$Oss.ossUpload(file.url).then(url => {
  312. self.form.frontImages.push({
  313. url
  314. })
  315. })
  316. })
  317. },
  318. deleteFrontPic(event) {
  319. this.form.frontImages.splice(event.index, 1)
  320. },
  321. // 视频上传
  322. async afterVideoRead(e) {
  323. let self = this
  324. e.file.forEach(file => {
  325. self.$Oss.ossUpload(file.url).then(url => {
  326. self.form.videos.push({
  327. url
  328. })
  329. })
  330. })
  331. },
  332. deleteVideoPic(event) {
  333. this.form.videos.splice(event.index, 1)
  334. },
  335. // 切换房屋亮点
  336. toggleHighlight(item) {
  337. const index = this.form.highlights.indexOf(item);
  338. if (index > -1) {
  339. this.form.highlights.splice(index, 1);
  340. } else {
  341. this.form.highlights.push(item);
  342. }
  343. },
  344. // 切换不利因素
  345. toggleDisadvantage(item) {
  346. const index = this.form.disadvantages.indexOf(item);
  347. if (index > -1) {
  348. this.form.disadvantages.splice(index, 1);
  349. } else {
  350. this.form.disadvantages.push(item);
  351. }
  352. },
  353. // 提交表单
  354. submit() {
  355. this.$refs.form.validate().then(res => {
  356. // 验证必填的图片和视频
  357. if (this.form.propertyImages.length === 0) {
  358. uni.showToast({
  359. title: '请上传产权证照片',
  360. icon: 'none'
  361. });
  362. return;
  363. }
  364. if (this.form.frontImages.length === 0) {
  365. uni.showToast({
  366. title: '请上传房屋正面照片',
  367. icon: 'none'
  368. });
  369. return;
  370. }
  371. if (this.form.videos.length === 0) {
  372. uni.showToast({
  373. title: '请上传房屋视频',
  374. icon: 'none'
  375. });
  376. return;
  377. }
  378. // 构建与index.vue兼容的提交参数
  379. const params = {
  380. userId: uni.getStorageSync('userInfo')?.id || "",
  381. id: "", // 新增数据,无ID
  382. classId: this.form.classId, // 使用分类标识
  383. commonClass: this.commonClass, // 所属分类
  384. address: this.form.address, // 地址
  385. homeAge: "", // 户主年龄 - 农房录入无此字段
  386. homeAz: "", // 是否经过安置 - 默认否
  387. homeBian: this.form.highlights.join(','), // 房屋周边 - 使用亮点代替
  388. homeBjsx: "", // 报建手续 - 农房录入无此字段
  389. homeCai: this.form.vegetableGarden || "", // 菜地面积
  390. homeCat: "", // 停车 - 农房录入无此字段
  391. homeGz: "", // 房屋主体是否改造 - 农房录入无此字段
  392. homeHb: "", // 房屋朝向及海拔 - 农房录入无此字段
  393. homeBz: this.form.description, // 备注 - 使用房屋介绍
  394. homeJg: this.form.houseCondition, // 房屋结构 - 使用房屋状况
  395. homeJl: "", // 距离场镇距离 - 农房录入无此字段
  396. homeJt: "", // 交通 - 农房录入无此字段
  397. homeJtzy: "", // 户主家庭职业 - 农房录入无此字段
  398. homeMi: "", // 面积 - 使用房屋面积
  399. homeMj: this.form.houseArea, // 房屋面积
  400. homeMoney: "", // 佣金 - 农房录入无此字段
  401. homeNo: "", // 房屋编号 - 农房录入无此字段
  402. homeNum: "1", // 房间数量 - 农房录入无此字段
  403. homePay: "", // 付款方式及押金 - 农房录入无此字段
  404. homePj: "", // 邻居对房东评价 - 农房录入无此字段
  405. homeSd: "", // 水电气网 - 农房录入无此字段
  406. homeShjl: "", // 距离成都西三环 - 农房录入无此字段
  407. homeSw: this.form.disadvantages.join(','), // 非正常死亡 - 显示不利因素信息
  408. homeTf: "", // 府市民云房屋信息档案查询 - 农房录入无此字段
  409. homeTime: "", // 租期 - 农房录入无此字段
  410. homeType: this.form.type === 'rent' ? '出租' : '流转', // 户型 - 使用类型
  411. homeYs: "", // 钥匙 - 默认无
  412. homeYzmj: this.form.landArea, // 院子总面积 - 使用土地面积
  413. homeZy: this.form.disadvantages.join(','), // 坟包及电塔 工厂噪音 - 使用不利因素
  414. iconName: "闲置农房", // 热点名称
  415. iconTitle: this.form.highlights.join(','), // 标签 - 使用亮点
  416. num: "0", // 浏览量 - 默认0
  417. price: this.form.price, // 价格
  418. timeGo: "", // 年限 - 农房录入无此字段
  419. title: `${this.form.type === 'rent' ? '出租' : '流转'}-${this.form.address.split('市')[1] || this.form.address}`, // 标题 - 自动生成
  420. unit: this.form.type === 'rent' ? '元/年' : '万元', // 单位
  421. image: this.form.frontImages.map(item => item.url).join(','), // 图片 - 使用正面照片
  422. iconImage: "", // 左上角图标
  423. homeImage: this.form.propertyImages.map(item => item.url).join(','), // 产权证照片
  424. homeMp4: this.form.videos.map(item => item.url).join(','), // 视频
  425. latitude: this.form.latitude,
  426. longitude: this.form.longitude,
  427. // 新增字段用于标识农房
  428. category: 'farmhouse',
  429. contactName: this.form.contactName,
  430. contactPhone: this.form.contactPhone
  431. };
  432. console.log('农房提交参数:', params);
  433. uni.showLoading({
  434. title: '提交中...'
  435. });
  436. // 调用统一API
  437. saveOrUpdateHouse(params).then(response => {
  438. uni.hideLoading();
  439. uni.showToast({
  440. title: response.message || '提交成功',
  441. icon: 'success'
  442. });
  443. setTimeout(() => {
  444. uni.redirectTo({
  445. url: "/pages_subpack/successful-apply/index"
  446. });
  447. }, 2000);
  448. }).catch(error => {
  449. uni.hideLoading();
  450. uni.showToast({
  451. title: error.message || '提交失败',
  452. icon: 'none'
  453. });
  454. console.error('农房提交失败:', error);
  455. });
  456. }).catch(errors => {
  457. console.log('表单验证失败:', errors);
  458. uni.showToast({
  459. title: '请补全必填项',
  460. icon: 'none'
  461. });
  462. });
  463. }
  464. }
  465. }
  466. </script>
  467. <style scoped>
  468. .container {
  469. min-height: 100vh;
  470. background-color: #f5f5f5;
  471. }
  472. .header {
  473. background: linear-gradient(135deg, #1EC77A 0%, #4CAF50 100%);
  474. padding: 40rpx 40rpx 60rpx;
  475. color: white;
  476. }
  477. .title {
  478. font-size: 36rpx;
  479. font-weight: bold;
  480. text-align: center;
  481. }
  482. .form-container {
  483. background: white;
  484. margin: -30rpx 20rpx 20rpx;
  485. border-radius: 20rpx;
  486. padding: 40rpx;
  487. box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.1);
  488. }
  489. .section-title {
  490. font-size: 32rpx;
  491. font-weight: bold;
  492. color: #333;
  493. margin: 40rpx 0 30rpx;
  494. padding-left: 20rpx;
  495. border-left: 6rpx solid #1EC77A;
  496. }
  497. .section-title:first-child {
  498. margin-top: 0;
  499. }
  500. .input-with-unit {
  501. display: flex;
  502. align-items: center;
  503. gap: 10rpx;
  504. }
  505. .unit {
  506. font-size: 26rpx;
  507. color: #666;
  508. margin-left: 10rpx;
  509. }
  510. .input-tip {
  511. font-size: 22rpx;
  512. color: #999;
  513. margin-top: 10rpx;
  514. line-height: 1.4;
  515. }
  516. .upload-tip {
  517. font-size: 24rpx;
  518. color: #666;
  519. margin-bottom: 10rpx;
  520. line-height: 1.5;
  521. }
  522. .price-container {
  523. display: flex;
  524. align-items: center;
  525. gap: 10rpx;
  526. }
  527. .price-unit {
  528. font-size: 26rpx;
  529. color: #1EC77A;
  530. font-weight: bold;
  531. margin-left: 10rpx;
  532. }
  533. .tags-container {
  534. display: flex;
  535. flex-wrap: wrap;
  536. gap: 15rpx;
  537. margin-top: 20rpx;
  538. }
  539. .tag-item {
  540. padding: 15rpx 25rpx;
  541. border: 2rpx solid #e0e0e0;
  542. border-radius: 25rpx;
  543. font-size: 24rpx;
  544. color: #666;
  545. background: #f9f9f9;
  546. transition: all 0.3s ease;
  547. }
  548. .tag-item.tag-selected {
  549. border-color: #1EC77A;
  550. background: #1EC77A;
  551. color: white;
  552. }
  553. .disadvantage-tag.tag-selected {
  554. border-color: #ff4757;
  555. background: #ff4757;
  556. color: white;
  557. }
  558. </style>