租房小程序前端代码
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.

736 lines
23 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" @change="debounceSaveFormData">
  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;" @input="debounceSaveFormData"></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;" @input="debounceSaveFormData"></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;" @input="debounceSaveFormData"></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;" @input="debounceSaveFormData"></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分钟最多上传2个视频</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;" @input="debounceSaveFormData"></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;" @input="debounceSaveFormData"></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. @input="debounceSaveFormData"
  138. ></uv-input>
  139. </uv-form-item>
  140. <uv-form-item>
  141. <uv-button type="primary" text="提交信息" customStyle="margin-top: 30px;background-color: #1EC77A;border-radius: 30px;" @click="submit"></uv-button>
  142. </uv-form-item>
  143. </uv-form>
  144. </view>
  145. <!-- 房屋状况选择器 -->
  146. <uv-picker ref="houseConditionPicker" :columns="houseConditionColumns" @confirm="confirmHouseCondition"></uv-picker>
  147. <!-- 分类选择器 -->
  148. <uv-picker ref="picker" :columns="columns" @confirm="confirm"></uv-picker>
  149. </view>
  150. </template>
  151. <script>
  152. import { saveOrUpdateHouse, houseType } from "@/common/api.js"
  153. import formStorage from "@/utils/formStorage.js"
  154. export default {
  155. data() {
  156. return {
  157. formKey: 'farmhouse_form', // 表单存储唯一标识
  158. saveTimer: null, // 防抖定时器
  159. commonClass: '', // 所属分类ID
  160. form: {
  161. type: '', // 出租/流转
  162. address: '', // 地址
  163. contactName: '', // 联系人
  164. contactPhone: '', // 联系电话
  165. houseCondition: '', // 房屋状况ID
  166. houseConditionName: '', // 房屋状况名称
  167. propertyImages: [], // 产权证照片
  168. houseArea: '', // 房屋面积
  169. landArea: '', // 土地面积
  170. frontImages: [], // 房屋正面照片
  171. videos: [], // 房屋视频
  172. price: '', // 价格
  173. longitude: '', // 经度
  174. latitude: '', // 纬度
  175. vegetableGarden: '', // 可用菜地
  176. highlights: [], // 房屋亮点
  177. disadvantages: [], // 不利因素
  178. description: '', // 房屋介绍
  179. classId: '', // 分类标识
  180. className: '' // 分类名称
  181. },
  182. houseConditionColumns: [
  183. ['老旧房屋', '装修较好可拎包入住', '新房']
  184. ],
  185. highlightOptions: [
  186. '靠河', '靠山', '通自来水', '通天然气', '近场镇或城市',
  187. '双车道到家', '精装修', '四合院', '周边无坟墓', '周边无电线塔'
  188. ],
  189. disadvantageOptions: [
  190. '可见坟墓', '周边有电塔', '非正常死亡'
  191. ],
  192. columns: [], // 分类选择器数据
  193. houseTypeList: [], // 分类列表
  194. rules: {
  195. type: [
  196. { required: true, message: '请选择出租或流转', trigger: ['blur', 'change'] }
  197. ],
  198. address: [
  199. { required: true, message: '请选择房屋地址', trigger: ['blur', 'change'] }
  200. ],
  201. contactName: [
  202. { required: true, message: '请输入联系人姓名', trigger: ['blur', 'change'] }
  203. ],
  204. contactPhone: [
  205. { required: true, message: '请输入联系电话', trigger: ['blur', 'change'] },
  206. { pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号码', trigger: ['blur', 'change'] }
  207. ],
  208. houseCondition: [
  209. { required: true, message: '请选择房屋状况', trigger: ['blur', 'change'] }
  210. ],
  211. houseArea: [
  212. { required: true, message: '请输入房屋面积', trigger: ['blur', 'change'] },
  213. { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: ['blur', 'change'] }
  214. ],
  215. landArea: [
  216. { required: true, message: '请输入土地面积', trigger: ['blur', 'change'] },
  217. { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的数字格式', trigger: ['blur', 'change'] }
  218. ],
  219. price: [
  220. { required: true, message: '请输入价格', trigger: ['blur', 'change'] },
  221. { pattern: /^\d+(\.\d{1,2})?$/, message: '请输入正确的价格格式', trigger: ['blur', 'change'] }
  222. ],
  223. classId: [
  224. { required: true, message: '请选择分类标识', trigger: ['blur', 'change'] }
  225. ]
  226. }
  227. }
  228. },
  229. onReady() {
  230. this.$refs.form.setRules(this.rules)
  231. },
  232. onLoad(options) {
  233. // 设置页面标题
  234. uni.setNavigationBarTitle({
  235. title: '闲置农房录入'
  236. })
  237. // 接收传递的commonClass参数
  238. if(options.commonClass) {
  239. this.commonClass = options.commonClass
  240. }
  241. // 如果是编辑模式,设置classId用于回显
  242. if(options.classId) {
  243. this.form.classId = options.classId
  244. }
  245. // 初始化分类数据
  246. this.onHouseType()
  247. // 恢复表单数据
  248. this.restoreFormData()
  249. },
  250. onUnload() {
  251. // 页面卸载时保存数据
  252. this.saveFormData()
  253. // 清除定时器
  254. if (this.saveTimer) {
  255. clearTimeout(this.saveTimer)
  256. }
  257. },
  258. methods: {
  259. // 恢复表单数据
  260. restoreFormData() {
  261. const savedData = formStorage.getFormData(this.formKey)
  262. if (savedData) {
  263. // 合并保存的数据到表单
  264. this.form = { ...this.form, ...savedData }
  265. }
  266. },
  267. // 保存表单数据
  268. saveFormData() {
  269. formStorage.saveFormData(this.formKey, this.form)
  270. },
  271. // 防抖保存表单数据
  272. debounceSaveFormData() {
  273. clearTimeout(this.saveTimer)
  274. this.saveTimer = setTimeout(() => {
  275. this.saveFormData()
  276. }, 1000)
  277. },
  278. // 获取分类数据
  279. onHouseType(){
  280. let that = this
  281. houseType({}).then(response=>{
  282. let arr=[]
  283. that.houseTypeList = response.result
  284. response.result.forEach(items=>{
  285. arr.push(items.title)
  286. // 数据回显:如果当前classId匹配,设置className
  287. if(items.id == that.form.classId){
  288. that.form.className = items.title
  289. }
  290. })
  291. that.columns[0]=arr
  292. }).catch(error=>{
  293. })
  294. },
  295. // 地址选择
  296. handleAddressSelect() {
  297. const that = this;
  298. wx.chooseLocation({
  299. success: function (res) {
  300. console.log('选择的位置:', res);
  301. that.form.longitude = res.longitude
  302. that.form.latitude = res.latitude
  303. that.form.address = res.address
  304. }
  305. })
  306. },
  307. // 房屋状况选择
  308. handleHouseConditionSelect() {
  309. this.$refs.houseConditionPicker.open();
  310. },
  311. confirmHouseCondition(e) {
  312. const { indexs, value } = e;
  313. this.form.houseCondition = value[0]; // 修改:直接使用选择的值而不是索引
  314. this.form.houseConditionName = value[0];
  315. // 选择后保存表单数据
  316. this.debounceSaveFormData()
  317. },
  318. // 分类标识选择
  319. handleClass() {
  320. this.$refs.picker.open();
  321. },
  322. confirm(e) {
  323. let that = this
  324. let {indexs,value,values} = e
  325. that.form.classId = that.houseTypeList[indexs[0]].id;
  326. that.form.className = that.houseTypeList[indexs[0]].title;
  327. // 选择后保存表单数据
  328. that.debounceSaveFormData()
  329. },
  330. // 产权证照片上传
  331. async afterPropertyRead(e) {
  332. let self = this
  333. e.file.forEach(file => {
  334. self.$Oss.ossUpload(file.url).then(url => {
  335. self.form.propertyImages.push({
  336. url
  337. })
  338. // 上传完成后保存表单数据
  339. self.debounceSaveFormData()
  340. })
  341. })
  342. },
  343. deletePropertyPic(event) {
  344. this.form.propertyImages.splice(event.index, 1)
  345. // 删除后保存表单数据
  346. this.debounceSaveFormData()
  347. },
  348. // 房屋正面照片上传
  349. async afterFrontRead(e) {
  350. let self = this
  351. e.file.forEach(file => {
  352. self.$Oss.ossUpload(file.url).then(url => {
  353. self.form.frontImages.push({
  354. url
  355. })
  356. // 上传完成后保存表单数据
  357. self.debounceSaveFormData()
  358. })
  359. })
  360. },
  361. deleteFrontPic(event) {
  362. this.form.frontImages.splice(event.index, 1)
  363. // 删除后保存表单数据
  364. this.debounceSaveFormData()
  365. },
  366. // 视频上传
  367. async afterVideoRead(e) {
  368. let self = this
  369. for (let file of e.file) {
  370. try {
  371. // 检查视频时长
  372. const duration = await this.getVideoDuration(file.url)
  373. if (duration > 60) {
  374. uni.showToast({
  375. title: '视频时长不能超过1分钟',
  376. icon: 'none'
  377. })
  378. continue // 跳过这个视频
  379. }
  380. self.$Oss.ossUpload(file.url).then(url => {
  381. self.form.videos.push({
  382. url
  383. })
  384. // 上传完成后保存表单数据
  385. self.debounceSaveFormData()
  386. })
  387. } catch (error) {
  388. console.error('视频处理失败:', error)
  389. // 如果获取时长失败,仍然允许上传
  390. self.$Oss.ossUpload(file.url).then(url => {
  391. self.form.videos.push({
  392. url
  393. })
  394. // 上传完成后保存表单数据
  395. self.debounceSaveFormData()
  396. })
  397. }
  398. }
  399. },
  400. // 获取视频时长的辅助方法
  401. getVideoDuration(videoUrl) {
  402. return new Promise((resolve, reject) => {
  403. // #ifdef MP-WEIXIN
  404. uni.getVideoInfo({
  405. src: videoUrl,
  406. success: (res) => {
  407. resolve(res.duration)
  408. },
  409. fail: (err) => {
  410. reject(err)
  411. }
  412. })
  413. // #endif
  414. // #ifdef APP-PLUS
  415. plus.io.getVideoInfo({
  416. filePath: videoUrl,
  417. success: (res) => {
  418. resolve(res.duration)
  419. },
  420. fail: (err) => {
  421. reject(err)
  422. }
  423. })
  424. // #endif
  425. // #ifdef H5
  426. // H5环境暂不支持视频时长检测,直接通过
  427. resolve(0)
  428. // #endif
  429. })
  430. },
  431. deleteVideoPic(event) {
  432. this.form.videos.splice(event.index, 1)
  433. // 删除后保存表单数据
  434. this.debounceSaveFormData()
  435. },
  436. // 切换房屋亮点
  437. toggleHighlight(item) {
  438. const index = this.form.highlights.indexOf(item);
  439. if (index > -1) {
  440. this.form.highlights.splice(index, 1);
  441. } else {
  442. this.form.highlights.push(item);
  443. }
  444. // 选择后保存表单数据
  445. this.debounceSaveFormData()
  446. },
  447. // 切换不利因素
  448. toggleDisadvantage(item) {
  449. const index = this.form.disadvantages.indexOf(item);
  450. if (index > -1) {
  451. this.form.disadvantages.splice(index, 1);
  452. } else {
  453. this.form.disadvantages.push(item);
  454. }
  455. // 选择后保存表单数据
  456. this.debounceSaveFormData()
  457. },
  458. // 提交表单
  459. submit() {
  460. this.$refs.form.validate().then(res => {
  461. // 验证必填的图片和视频
  462. if (this.form.propertyImages.length === 0) {
  463. uni.showToast({
  464. title: '请上传产权证照片',
  465. icon: 'none'
  466. });
  467. return;
  468. }
  469. if (this.form.frontImages.length === 0) {
  470. uni.showToast({
  471. title: '请上传房屋正面照片',
  472. icon: 'none'
  473. });
  474. return;
  475. }
  476. if (this.form.videos.length === 0) {
  477. uni.showToast({
  478. title: '请上传房屋视频',
  479. icon: 'none'
  480. });
  481. return;
  482. }
  483. // 构建与index.vue兼容的提交参数
  484. const params = {
  485. userId: uni.getStorageSync('userInfo')?.id || "",
  486. id: "", // 新增数据,无ID
  487. classId: this.form.classId, // 使用分类标识
  488. commonClass: this.commonClass, // 所属分类
  489. address: this.form.address, // 地址
  490. homeAge: "", // 户主年龄 - 农房录入无此字段
  491. homeAz: "", // 是否经过安置 - 默认否
  492. homeBian: this.form.highlights.join(','), // 房屋周边 - 使用亮点代替
  493. homeBjsx: "", // 报建手续 - 农房录入无此字段
  494. homeCai: this.form.vegetableGarden || "", // 菜地面积
  495. homeCat: "", // 停车 - 农房录入无此字段
  496. homeGz: "", // 房屋主体是否改造 - 农房录入无此字段
  497. homeHb: "", // 房屋朝向及海拔 - 农房录入无此字段
  498. homeBz: this.form.description, // 备注 - 使用房屋介绍
  499. homeJg: this.form.houseCondition, // 房屋结构 - 使用房屋状况
  500. homeJl: "", // 距离场镇距离 - 农房录入无此字段
  501. homeJt: "", // 交通 - 农房录入无此字段
  502. homeJtzy: "", // 户主家庭职业 - 农房录入无此字段
  503. homeMi: "", // 面积 - 使用房屋面积
  504. homeMj: this.form.houseArea, // 房屋面积
  505. homeMoney: "", // 佣金 - 农房录入无此字段
  506. homeNo: "", // 房屋编号 - 农房录入无此字段
  507. homeNum: "1", // 房间数量 - 农房录入无此字段
  508. homePay: "", // 付款方式及押金 - 农房录入无此字段
  509. homePj: "", // 邻居对房东评价 - 农房录入无此字段
  510. homeSd: "", // 水电气网 - 农房录入无此字段
  511. homeShjl: "", // 距离成都西三环 - 农房录入无此字段
  512. homeSw: this.form.disadvantages.join(','), // 非正常死亡 - 显示不利因素信息
  513. homeTf: "", // 府市民云房屋信息档案查询 - 农房录入无此字段
  514. homeTime: "", // 租期 - 农房录入无此字段
  515. homeType: this.form.type === 'rent' ? '出租' : '流转', // 户型 - 使用类型
  516. homeYs: "", // 钥匙 - 默认无
  517. homeYzmj: this.form.landArea, // 院子总面积 - 使用土地面积
  518. homeZy: this.form.disadvantages.join(','), // 坟包及电塔 工厂噪音 - 使用不利因素
  519. iconName: "闲置农房", // 热点名称
  520. iconTitle: this.form.highlights.join(','), // 标签 - 使用亮点
  521. num: "0", // 浏览量 - 默认0
  522. price: this.form.price, // 价格
  523. timeGo: "", // 年限 - 农房录入无此字段
  524. title: `${this.form.type === 'rent' ? '出租' : '流转'}-${this.form.address.split('市')[1] || this.form.address}`, // 标题 - 自动生成
  525. unit: this.form.type === 'rent' ? '元/年' : '万元', // 单位
  526. image: this.form.frontImages.map(item => item.url).join(','), // 图片 - 使用正面照片
  527. iconImage: "", // 左上角图标
  528. homeImage: this.form.propertyImages.map(item => item.url).join(','), // 产权证照片
  529. homeMp4: this.form.videos.map(item => item.url).join(','), // 视频
  530. latitude: this.form.latitude,
  531. longitude: this.form.longitude,
  532. // 新增字段用于标识农房
  533. category: 'farmhouse',
  534. contactName: this.form.contactName,
  535. contactPhone: this.form.contactPhone
  536. };
  537. console.log('农房提交参数:', params);
  538. uni.showLoading({
  539. title: '提交中...'
  540. });
  541. // 调用统一API
  542. saveOrUpdateHouse(params).then(response => {
  543. uni.hideLoading();
  544. // 提交成功后清除本地存储的表单数据
  545. formStorage.removeFormData(this.formKey);
  546. uni.showToast({
  547. title: response.message || '提交成功',
  548. icon: 'success'
  549. });
  550. setTimeout(() => {
  551. uni.redirectTo({
  552. url: "/pages_subpack/successful-apply/index"
  553. });
  554. }, 2000);
  555. }).catch(error => {
  556. uni.hideLoading();
  557. uni.showToast({
  558. title: error.message || '提交失败',
  559. icon: 'none'
  560. });
  561. console.error('农房提交失败:', error);
  562. });
  563. }).catch(errors => {
  564. console.log('表单验证失败:', errors);
  565. uni.showToast({
  566. title: '请补全必填项',
  567. icon: 'none'
  568. });
  569. });
  570. }
  571. }
  572. }
  573. </script>
  574. <style scoped>
  575. .container {
  576. min-height: 100vh;
  577. background-color: #f5f5f5;
  578. }
  579. .header {
  580. background: linear-gradient(135deg, #1EC77A 0%, #4CAF50 100%);
  581. padding: 40rpx 40rpx 60rpx;
  582. color: white;
  583. }
  584. .title {
  585. font-size: 36rpx;
  586. font-weight: bold;
  587. text-align: center;
  588. }
  589. .form-container {
  590. background: white;
  591. margin: -30rpx 20rpx 20rpx;
  592. border-radius: 20rpx;
  593. padding: 40rpx;
  594. box-shadow: 0 4rpx 20rpx rgba(0,0,0,0.1);
  595. }
  596. .section-title {
  597. font-size: 32rpx;
  598. font-weight: bold;
  599. color: #333;
  600. margin: 40rpx 0 30rpx;
  601. padding-left: 20rpx;
  602. border-left: 6rpx solid #1EC77A;
  603. }
  604. .section-title:first-child {
  605. margin-top: 0;
  606. }
  607. .input-with-unit {
  608. display: flex;
  609. align-items: center;
  610. gap: 10rpx;
  611. }
  612. .unit {
  613. font-size: 26rpx;
  614. color: #666;
  615. margin-left: 10rpx;
  616. }
  617. .input-tip {
  618. font-size: 22rpx;
  619. color: #999;
  620. margin-top: 10rpx;
  621. line-height: 1.4;
  622. }
  623. .upload-tip {
  624. font-size: 24rpx;
  625. color: #666;
  626. margin-bottom: 10rpx;
  627. line-height: 1.5;
  628. }
  629. .price-container {
  630. display: flex;
  631. align-items: center;
  632. gap: 10rpx;
  633. }
  634. .price-unit {
  635. font-size: 26rpx;
  636. color: #1EC77A;
  637. font-weight: bold;
  638. margin-left: 10rpx;
  639. }
  640. .tags-container {
  641. display: flex;
  642. flex-wrap: wrap;
  643. gap: 15rpx;
  644. margin-top: 20rpx;
  645. }
  646. .tag-item {
  647. padding: 15rpx 25rpx;
  648. border: 2rpx solid #e0e0e0;
  649. border-radius: 25rpx;
  650. font-size: 24rpx;
  651. color: #666;
  652. background: #f9f9f9;
  653. transition: all 0.3s ease;
  654. }
  655. .tag-item.tag-selected {
  656. border-color: #1EC77A;
  657. background: #1EC77A;
  658. color: white;
  659. }
  660. .disadvantage-tag.tag-selected {
  661. border-color: #ff4757;
  662. background: #ff4757;
  663. color: white;
  664. }
  665. </style>