feat(车辆发布): 重构车辆发布页面,使用NutUI组件优化表单交互
- 使用NutUI组件重构整个表单页面,包括导航栏、上传组件、选择器等 - 新增多个表单字段,完善车辆信息收集能力 - 实现表单验证逻辑,确保必填字段完整性 - 添加多种选择器弹窗,优化用户选择体验 - 更新全局组件声明文件,添加所需NutUI组件
Showing
4 changed files
with
702 additions
and
407 deletions
| ... | @@ -9,12 +9,20 @@ declare module 'vue' { | ... | @@ -9,12 +9,20 @@ declare module 'vue' { |
| 9 | export interface GlobalComponents { | 9 | export interface GlobalComponents { |
| 10 | NavBar: typeof import('./src/components/navBar.vue')['default'] | 10 | NavBar: typeof import('./src/components/navBar.vue')['default'] |
| 11 | NutButton: typeof import('@nutui/nutui-taro')['Button'] | 11 | NutButton: typeof import('@nutui/nutui-taro')['Button'] |
| 12 | - NutLoading: typeof import('@nutui/nutui-taro')['Loading'] | 12 | + NutConfigProvider: typeof import('@nutui/nutui-taro')['ConfigProvider'] |
| 13 | + NutForm: typeof import('@nutui/nutui-taro')['Form'] | ||
| 14 | + NutFormItem: typeof import('@nutui/nutui-taro')['FormItem'] | ||
| 15 | + NutInput: typeof import('@nutui/nutui-taro')['Input'] | ||
| 13 | NutMenu: typeof import('@nutui/nutui-taro')['Menu'] | 16 | NutMenu: typeof import('@nutui/nutui-taro')['Menu'] |
| 14 | NutMenuItem: typeof import('@nutui/nutui-taro')['MenuItem'] | 17 | NutMenuItem: typeof import('@nutui/nutui-taro')['MenuItem'] |
| 18 | + NutNavbar: typeof import('@nutui/nutui-taro')['Navbar'] | ||
| 19 | + NutPicker: typeof import('@nutui/nutui-taro')['Picker'] | ||
| 20 | + NutPopup: typeof import('@nutui/nutui-taro')['Popup'] | ||
| 15 | NutSearchbar: typeof import('@nutui/nutui-taro')['Searchbar'] | 21 | NutSearchbar: typeof import('@nutui/nutui-taro')['Searchbar'] |
| 16 | NutSwiper: typeof import('@nutui/nutui-taro')['Swiper'] | 22 | NutSwiper: typeof import('@nutui/nutui-taro')['Swiper'] |
| 17 | NutSwiperItem: typeof import('@nutui/nutui-taro')['SwiperItem'] | 23 | NutSwiperItem: typeof import('@nutui/nutui-taro')['SwiperItem'] |
| 24 | + NutTextarea: typeof import('@nutui/nutui-taro')['Textarea'] | ||
| 25 | + NutUploader: typeof import('@nutui/nutui-taro')['Uploader'] | ||
| 18 | Picker: typeof import('./src/components/time-picker-data/picker.vue')['default'] | 26 | Picker: typeof import('./src/components/time-picker-data/picker.vue')['default'] |
| 19 | PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] | 27 | PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] |
| 20 | RouterLink: typeof import('vue-router')['RouterLink'] | 28 | RouterLink: typeof import('vue-router')['RouterLink'] | ... | ... |
| 1 | +/* | ||
| 2 | + * @Date: 2025-07-01 17:00:22 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-07-02 10:02:29 | ||
| 5 | + * @FilePath: /jgdl/src/pages/index/index.config.js | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | + */ | ||
| 1 | export default { | 8 | export default { |
| 2 | - navigationBarTitleText: '首页' | 9 | + navigationBarTitleText: '首页', |
| 10 | + enableShareAppMessage: true, | ||
| 11 | + // navigationBarBackgroundColor: '#fb923c' | ||
| 3 | } | 12 | } | ... | ... |
| 1 | +/* | ||
| 2 | + * @Date: 2025-07-01 17:55:11 | ||
| 3 | + * @LastEditors: hookehuyr hookehuyr@gmail.com | ||
| 4 | + * @LastEditTime: 2025-07-02 10:02:19 | ||
| 5 | + * @FilePath: /jgdl/src/pages/sell/index.config.js | ||
| 6 | + * @Description: 文件描述 | ||
| 7 | + */ | ||
| 1 | export default { | 8 | export default { |
| 2 | - navigationBarTitleText: '首页' | 9 | + navigationBarTitleText: '', |
| 10 | + // navigationBarBackgroundColor: '#fb923c' | ||
| 3 | } | 11 | } | ... | ... |
| 1 | <template> | 1 | <template> |
| 2 | <view class="sell-page"> | 2 | <view class="sell-page"> |
| 3 | - <!-- 顶部标题 --> | 3 | + <!-- 顶部导航 --> |
| 4 | - <view class="header"> | 4 | + <nut-config-provider :theme-vars="themeVars"> |
| 5 | - <text class="header-title">发布车辆</text> | 5 | + <nut-navbar |
| 6 | - <text class="header-subtitle">填写车辆信息,快速出售</text> | 6 | + title="发布车源" |
| 7 | - </view> | 7 | + left-show |
| 8 | + @on-click-back="goBack" | ||
| 9 | + > | ||
| 10 | + <template #left-show> | ||
| 11 | + <RectLeft /> | ||
| 12 | + </template> | ||
| 13 | + </nut-navbar> | ||
| 14 | + </nut-config-provider> | ||
| 8 | 15 | ||
| 9 | <!-- 表单内容 --> | 16 | <!-- 表单内容 --> |
| 10 | <view class="form-container"> | 17 | <view class="form-container"> |
| 11 | - <!-- 车辆图片 --> | 18 | + <!-- 车辆照片上传 --> |
| 12 | <view class="form-section"> | 19 | <view class="form-section"> |
| 13 | - <text class="section-title">车辆图片 <text class="required">*</text></text> | 20 | + <text class="section-title">添加车辆照片</text> |
| 14 | - <view class="image-upload-container"> | 21 | + <nut-uploader |
| 15 | - <view | 22 | + v-model:file-list="fileList" |
| 16 | - v-for="(image, index) in vehicleImages" | 23 | + :maximum="4" |
| 17 | - :key="index" | 24 | + :multiple="true" |
| 18 | - class="image-item" | 25 | + :preview-type="'picture'" |
| 19 | - > | 26 | + @oversize="onOversize" |
| 20 | - <image :src="image" class="uploaded-image" mode="aspectFill" /> | 27 | + @delete="onDelete" |
| 21 | - <view class="image-delete" @click="removeImage(index)"> | 28 | + > |
| 22 | - <Close size="16" color="#ffffff" /> | 29 | + <nut-button type="success" size="small"> |
| 23 | - </view> | 30 | + <template #icon> |
| 24 | - </view> | 31 | + <Plus /> |
| 25 | - <view | 32 | + </template> |
| 26 | - v-if="vehicleImages.length < 6" | 33 | + 上传文件 |
| 27 | - class="image-upload-btn" | 34 | + </nut-button> |
| 28 | - @click="uploadImage" | 35 | + </nut-uploader> |
| 29 | - > | 36 | + <view class="upload-tips"> |
| 30 | - <Plus size="24" color="#9ca3af" /> | 37 | + <text class="tip-item">正面照</text> |
| 31 | - <text class="upload-text">添加图片</text> | 38 | + <text class="tip-item">左侧照</text> |
| 32 | - </view> | 39 | + <text class="tip-item">右侧照</text> |
| 40 | + <text class="tip-item">其他</text> | ||
| 33 | </view> | 41 | </view> |
| 34 | - <text class="form-tip">最多上传6张图片,第一张为封面图</text> | ||
| 35 | </view> | 42 | </view> |
| 36 | 43 | ||
| 37 | - <!-- 基本信息 --> | 44 | + <!-- 所在学校 --> |
| 38 | <view class="form-section"> | 45 | <view class="form-section"> |
| 39 | - <text class="section-title">基本信息</text> | 46 | + <view class="form-item" @click="showSchoolPicker"> |
| 40 | - | 47 | + <view class="form-item-left"> |
| 41 | - <view class="form-item"> | 48 | + <Location class="form-icon" /> |
| 42 | - <text class="form-label">车辆名称 <text class="required">*</text></text> | 49 | + <text class="form-label">所在学校</text> |
| 43 | - <input | 50 | + </view> |
| 44 | - v-model="formData.name" | 51 | + <view class="form-item-right"> |
| 45 | - placeholder="请输入车辆名称" | 52 | + <text class="form-value">{{ formData.school || '上海理工大学' }}</text> |
| 46 | - class="form-input" | 53 | + <Right class="arrow-icon" /> |
| 47 | - /> | 54 | + </view> |
| 48 | </view> | 55 | </view> |
| 56 | + </view> | ||
| 49 | 57 | ||
| 50 | - <view class="form-item"> | 58 | + <!-- 车辆详情表单 --> |
| 51 | - <text class="form-label">车辆品牌 <text class="required">*</text></text> | 59 | + <nut-form ref="formRef" :model-value="formData"> |
| 52 | - <picker | 60 | + <view class="form-section"> |
| 53 | - :range="brands" | 61 | + <!-- 车型品牌 --> |
| 54 | - :value="brandIndex" | 62 | + <nut-form-item |
| 55 | - @change="onBrandChange" | 63 | + label="车型品牌" |
| 56 | - class="form-picker" | 64 | + prop="brand" |
| 65 | + required | ||
| 66 | + :rules="[{ required: true, message: '请选择车型品牌' }]" | ||
| 57 | > | 67 | > |
| 58 | - <view class="picker-content"> | 68 | + <view class="form-item-content" @click="showBrandPicker"> |
| 59 | - <text class="picker-text">{{ brands[brandIndex] || '请选择品牌' }}</text> | 69 | + <text class="form-value">{{ formData.brand || '请选择' }}</text> |
| 60 | - <Right size="16" color="#9ca3af" /> | 70 | + <Right class="arrow-icon" /> |
| 61 | </view> | 71 | </view> |
| 62 | - </picker> | 72 | + </nut-form-item> |
| 63 | - </view> | ||
| 64 | 73 | ||
| 65 | - <view class="form-item"> | 74 | + <!-- 车辆型号 --> |
| 66 | - <text class="form-label">购买年份 <text class="required">*</text></text> | 75 | + <nut-form-item label="车辆型号" prop="model"> |
| 67 | - <picker | 76 | + <view class="form-item-content" @click="showModelPicker"> |
| 68 | - :range="years" | 77 | + <text class="form-value">{{ formData.model || '请选择' }}</text> |
| 69 | - :value="yearIndex" | 78 | + <Right class="arrow-icon" /> |
| 70 | - @change="onYearChange" | ||
| 71 | - class="form-picker" | ||
| 72 | - > | ||
| 73 | - <view class="picker-content"> | ||
| 74 | - <text class="picker-text">{{ years[yearIndex] || '请选择年份' }}</text> | ||
| 75 | - <Right size="16" color="#9ca3af" /> | ||
| 76 | </view> | 79 | </view> |
| 77 | - </picker> | 80 | + </nut-form-item> |
| 78 | - </view> | ||
| 79 | 81 | ||
| 80 | - <view class="form-item"> | 82 | + <!-- 车辆出厂年份 --> |
| 81 | - <text class="form-label">车辆类型 <text class="required">*</text></text> | 83 | + <nut-form-item label="车辆出厂年份" prop="year"> |
| 82 | - <picker | 84 | + <view class="form-item-content" @click="showYearPicker"> |
| 83 | - :range="types" | 85 | + <text class="form-value">{{ formData.year || '请选择' }}</text> |
| 84 | - :value="typeIndex" | 86 | + <Right class="arrow-icon" /> |
| 85 | - @change="onTypeChange" | 87 | + </view> |
| 86 | - class="form-picker" | 88 | + </nut-form-item> |
| 89 | + | ||
| 90 | + <!-- 新旧程度 --> | ||
| 91 | + <nut-form-item | ||
| 92 | + label="新旧程度" | ||
| 93 | + prop="condition" | ||
| 94 | + required | ||
| 95 | + :rules="[{ required: true, message: '请选择新旧程度' }]" | ||
| 96 | + > | ||
| 97 | + <view class="form-item-content" @click="showConditionPicker"> | ||
| 98 | + <text class="form-value">{{ formData.condition || '请选择' }}</text> | ||
| 99 | + <Right class="arrow-icon" /> | ||
| 100 | + </view> | ||
| 101 | + </nut-form-item> | ||
| 102 | + | ||
| 103 | + <!-- 行驶里程 --> | ||
| 104 | + <nut-form-item | ||
| 105 | + label="行驶里程" | ||
| 106 | + prop="mileage" | ||
| 107 | + required | ||
| 108 | + :rules="[{ required: true, message: '请输入行驶里程' }]" | ||
| 87 | > | 109 | > |
| 88 | - <view class="picker-content"> | 110 | + <nut-input |
| 89 | - <text class="picker-text">{{ types[typeIndex] || '请选择类型' }}</text> | 111 | + v-model="formData.mileage" |
| 90 | - <Right size="16" color="#9ca3af" /> | 112 | + placeholder="1200" |
| 113 | + type="number" | ||
| 114 | + input-align="right" | ||
| 115 | + > | ||
| 116 | + <template #right> | ||
| 117 | + <text class="unit">公里</text> | ||
| 118 | + </template> | ||
| 119 | + </nut-input> | ||
| 120 | + </nut-form-item> | ||
| 121 | + | ||
| 122 | + <!-- 续航里程 --> | ||
| 123 | + <nut-form-item label="续航里程" prop="range"> | ||
| 124 | + <nut-input | ||
| 125 | + v-model="formData.range" | ||
| 126 | + placeholder="60" | ||
| 127 | + type="number" | ||
| 128 | + input-align="right" | ||
| 129 | + > | ||
| 130 | + <template #right> | ||
| 131 | + <text class="unit">公里</text> | ||
| 132 | + </template> | ||
| 133 | + </nut-input> | ||
| 134 | + </nut-form-item> | ||
| 135 | + | ||
| 136 | + <!-- 最高时速 --> | ||
| 137 | + <nut-form-item label="最高时速" prop="maxSpeed"> | ||
| 138 | + <nut-input | ||
| 139 | + v-model="formData.maxSpeed" | ||
| 140 | + placeholder="25" | ||
| 141 | + type="number" | ||
| 142 | + input-align="right" | ||
| 143 | + > | ||
| 144 | + <template #right> | ||
| 145 | + <text class="unit">km/h</text> | ||
| 146 | + </template> | ||
| 147 | + </nut-input> | ||
| 148 | + </nut-form-item> | ||
| 149 | + | ||
| 150 | + <!-- 电池容量 --> | ||
| 151 | + <nut-form-item label="电池容量" prop="batteryCapacity"> | ||
| 152 | + <nut-input | ||
| 153 | + v-model="formData.batteryCapacity" | ||
| 154 | + placeholder="20" | ||
| 155 | + type="number" | ||
| 156 | + input-align="right" | ||
| 157 | + > | ||
| 158 | + <template #right> | ||
| 159 | + <text class="unit">Ah</text> | ||
| 160 | + </template> | ||
| 161 | + </nut-input> | ||
| 162 | + </nut-form-item> | ||
| 163 | + | ||
| 164 | + <!-- 电池损耗度 --> | ||
| 165 | + <nut-form-item label="电池损耗度" prop="batteryWear"> | ||
| 166 | + <view class="form-item-content" @click="showBatteryWearPicker"> | ||
| 167 | + <text class="form-value">{{ formData.batteryWear || '请选择' }}</text> | ||
| 168 | + <Right class="arrow-icon" /> | ||
| 169 | + </view> | ||
| 170 | + </nut-form-item> | ||
| 171 | + | ||
| 172 | + <!-- 刹车磨损度 --> | ||
| 173 | + <nut-form-item label="刹车磨损度" prop="brakeWear"> | ||
| 174 | + <view class="form-item-content" @click="showBrakeWearPicker"> | ||
| 175 | + <text class="form-value">{{ formData.brakeWear || '请选择' }}</text> | ||
| 176 | + <Right class="arrow-icon" /> | ||
| 91 | </view> | 177 | </view> |
| 92 | - </picker> | 178 | + </nut-form-item> |
| 179 | + | ||
| 180 | + <!-- 轮胎磨损度 --> | ||
| 181 | + <nut-form-item label="轮胎磨损度" prop="tireWear"> | ||
| 182 | + <view class="form-item-content" @click="showTireWearPicker"> | ||
| 183 | + <text class="form-value">{{ formData.tireWear || '请选择' }}</text> | ||
| 184 | + <Right class="arrow-icon" /> | ||
| 185 | + </view> | ||
| 186 | + </nut-form-item> | ||
| 93 | </view> | 187 | </view> |
| 188 | + </nut-form> | ||
| 94 | 189 | ||
| 190 | + <!-- 价格信息 --> | ||
| 191 | + <view class="form-section"> | ||
| 95 | <view class="form-item"> | 192 | <view class="form-item"> |
| 96 | - <text class="form-label">出售价格 <text class="required">*</text></text> | 193 | + <view class="form-item-left"> |
| 97 | - <view class="price-input-container"> | 194 | + <Location class="form-icon" /> |
| 195 | + <text class="form-label">出让价格</text> | ||
| 196 | + </view> | ||
| 197 | + <view class="form-item-right"> | ||
| 98 | <text class="price-symbol">¥</text> | 198 | <text class="price-symbol">¥</text> |
| 99 | - <input | 199 | + <input |
| 100 | - v-model="formData.price" | 200 | + v-model="formData.sellingPrice" |
| 101 | - placeholder="请输入价格" | 201 | + placeholder="3,200" |
| 102 | - type="number" | 202 | + type="text" |
| 103 | class="price-input" | 203 | class="price-input" |
| 104 | /> | 204 | /> |
| 105 | </view> | 205 | </view> |
| 106 | </view> | 206 | </view> |
| 107 | - </view> | ||
| 108 | - | ||
| 109 | - <!-- 车辆状况 --> | ||
| 110 | - <view class="form-section"> | ||
| 111 | - <text class="section-title">车辆状况</text> | ||
| 112 | - | ||
| 113 | - <view class="form-item"> | ||
| 114 | - <text class="form-label">使用时长</text> | ||
| 115 | - <picker | ||
| 116 | - :range="usagePeriods" | ||
| 117 | - :value="usageIndex" | ||
| 118 | - @change="onUsageChange" | ||
| 119 | - class="form-picker" | ||
| 120 | - > | ||
| 121 | - <view class="picker-content"> | ||
| 122 | - <text class="picker-text">{{ usagePeriods[usageIndex] || '请选择使用时长' }}</text> | ||
| 123 | - <Right size="16" color="#9ca3af" /> | ||
| 124 | - </view> | ||
| 125 | - </picker> | ||
| 126 | - </view> | ||
| 127 | 207 | ||
| 128 | <view class="form-item"> | 208 | <view class="form-item"> |
| 129 | - <text class="form-label">车辆描述</text> | 209 | + <view class="form-item-left"> |
| 130 | - <textarea | 210 | + <Location class="form-icon" /> |
| 131 | - v-model="formData.description" | 211 | + <text class="form-label">市场价</text> |
| 132 | - placeholder="请描述车辆的具体情况,如外观、性能、配件等" | 212 | + </view> |
| 133 | - class="form-textarea" | 213 | + <view class="form-item-right"> |
| 134 | - maxlength="500" | 214 | + <text class="market-price-symbol">¥</text> |
| 135 | - /> | 215 | + <input |
| 136 | - <text class="char-count">{{ formData.description.length }}/500</text> | 216 | + v-model="formData.marketPrice" |
| 217 | + placeholder="6,500" | ||
| 218 | + type="text" | ||
| 219 | + class="market-price-input" | ||
| 220 | + /> | ||
| 221 | + </view> | ||
| 137 | </view> | 222 | </view> |
| 138 | </view> | 223 | </view> |
| 139 | 224 | ||
| 140 | - <!-- 联系方式 --> | 225 | + <!-- 车辆描述 --> |
| 141 | <view class="form-section"> | 226 | <view class="form-section"> |
| 142 | - <text class="section-title">联系方式</text> | 227 | + <nut-textarea |
| 143 | - | 228 | + v-model="formData.description" |
| 144 | - <view class="form-item"> | 229 | + placeholder="请描述车辆详情,如使用感受、车况特点等" |
| 145 | - <text class="form-label">手机号码 <text class="required">*</text></text> | 230 | + :max-length="200" |
| 146 | - <input | 231 | + :rows="4" |
| 147 | - v-model="formData.phone" | 232 | + show-word-limit |
| 148 | - placeholder="请输入手机号码" | 233 | + /> |
| 149 | - type="number" | ||
| 150 | - class="form-input" | ||
| 151 | - /> | ||
| 152 | - </view> | ||
| 153 | - | ||
| 154 | - <view class="form-item"> | ||
| 155 | - <text class="form-label">所在学校 <text class="required">*</text></text> | ||
| 156 | - <input | ||
| 157 | - v-model="formData.school" | ||
| 158 | - placeholder="请输入所在学校" | ||
| 159 | - class="form-input" | ||
| 160 | - /> | ||
| 161 | - </view> | ||
| 162 | - | ||
| 163 | - <view class="form-item"> | ||
| 164 | - <text class="form-label">交易地点</text> | ||
| 165 | - <input | ||
| 166 | - v-model="formData.location" | ||
| 167 | - placeholder="请输入具体交易地点" | ||
| 168 | - class="form-input" | ||
| 169 | - /> | ||
| 170 | - </view> | ||
| 171 | </view> | 234 | </view> |
| 172 | </view> | 235 | </view> |
| 173 | 236 | ||
| 174 | <!-- 底部按钮 --> | 237 | <!-- 底部按钮 --> |
| 175 | <view class="bottom-actions"> | 238 | <view class="bottom-actions"> |
| 176 | - <button class="preview-btn" @click="onPreview">预览</button> | 239 | + <nut-button |
| 177 | - <button class="publish-btn" @click="onPublish">发布车辆</button> | 240 | + color="#f97316" |
| 241 | + size="large" | ||
| 242 | + block | ||
| 243 | + @click="onPublish" | ||
| 244 | + > | ||
| 245 | + 确认发布 | ||
| 246 | + </nut-button> | ||
| 178 | </view> | 247 | </view> |
| 179 | - | 248 | + |
| 180 | - <!-- 自定义TabBar --> | 249 | + <!-- 选择器弹窗 --> |
| 181 | - <TabBar /> | 250 | + <!-- 学校选择 --> |
| 251 | + <nut-popup v-model:visible="schoolPickerVisible" position="bottom"> | ||
| 252 | + <nut-picker | ||
| 253 | + v-model="schoolValue" | ||
| 254 | + :columns="schoolOptions" | ||
| 255 | + title="选择学校" | ||
| 256 | + @confirm="onSchoolConfirm" | ||
| 257 | + @cancel="schoolPickerVisible = false" | ||
| 258 | + /> | ||
| 259 | + </nut-popup> | ||
| 260 | + | ||
| 261 | + <!-- 品牌选择 --> | ||
| 262 | + <nut-popup v-model:visible="brandPickerVisible" position="bottom"> | ||
| 263 | + <nut-picker | ||
| 264 | + v-model="brandValue" | ||
| 265 | + :columns="brandOptions" | ||
| 266 | + title="选择车型品牌" | ||
| 267 | + @confirm="onBrandConfirm" | ||
| 268 | + @cancel="brandPickerVisible = false" | ||
| 269 | + /> | ||
| 270 | + </nut-popup> | ||
| 271 | + | ||
| 272 | + <!-- 型号选择 --> | ||
| 273 | + <nut-popup v-model:visible="modelPickerVisible" position="bottom"> | ||
| 274 | + <nut-picker | ||
| 275 | + v-model="modelValue" | ||
| 276 | + :columns="modelOptions" | ||
| 277 | + title="选择车辆型号" | ||
| 278 | + @confirm="onModelConfirm" | ||
| 279 | + @cancel="modelPickerVisible = false" | ||
| 280 | + /> | ||
| 281 | + </nut-popup> | ||
| 282 | + | ||
| 283 | + <!-- 年份选择 --> | ||
| 284 | + <nut-popup v-model:visible="yearPickerVisible" position="bottom"> | ||
| 285 | + <nut-picker | ||
| 286 | + v-model="yearValue" | ||
| 287 | + :columns="yearOptions" | ||
| 288 | + title="选择出厂年份" | ||
| 289 | + @confirm="onYearConfirm" | ||
| 290 | + @cancel="yearPickerVisible = false" | ||
| 291 | + /> | ||
| 292 | + </nut-popup> | ||
| 293 | + | ||
| 294 | + <!-- 新旧程度选择 --> | ||
| 295 | + <nut-popup v-model:visible="conditionPickerVisible" position="bottom"> | ||
| 296 | + <nut-picker | ||
| 297 | + v-model="conditionValue" | ||
| 298 | + :columns="conditionOptions" | ||
| 299 | + title="选择新旧程度" | ||
| 300 | + @confirm="onConditionConfirm" | ||
| 301 | + @cancel="conditionPickerVisible = false" | ||
| 302 | + /> | ||
| 303 | + </nut-popup> | ||
| 304 | + | ||
| 305 | + <!-- 电池损耗度选择 --> | ||
| 306 | + <nut-popup v-model:visible="batteryWearPickerVisible" position="bottom"> | ||
| 307 | + <nut-picker | ||
| 308 | + v-model="batteryWearValue" | ||
| 309 | + :columns="wearLevelOptions" | ||
| 310 | + title="选择电池损耗度" | ||
| 311 | + @confirm="onBatteryWearConfirm" | ||
| 312 | + @cancel="batteryWearPickerVisible = false" | ||
| 313 | + /> | ||
| 314 | + </nut-popup> | ||
| 315 | + | ||
| 316 | + <!-- 刹车磨损度选择 --> | ||
| 317 | + <nut-popup v-model:visible="brakeWearPickerVisible" position="bottom"> | ||
| 318 | + <nut-picker | ||
| 319 | + v-model="brakeWearValue" | ||
| 320 | + :columns="wearLevelOptions" | ||
| 321 | + title="选择刹车磨损度" | ||
| 322 | + @confirm="onBrakeWearConfirm" | ||
| 323 | + @cancel="brakeWearPickerVisible = false" | ||
| 324 | + /> | ||
| 325 | + </nut-popup> | ||
| 326 | + | ||
| 327 | + <!-- 轮胎磨损度选择 --> | ||
| 328 | + <nut-popup v-model:visible="tireWearPickerVisible" position="bottom"> | ||
| 329 | + <nut-picker | ||
| 330 | + v-model="tireWearValue" | ||
| 331 | + :columns="wearLevelOptions" | ||
| 332 | + title="选择轮胎磨损度" | ||
| 333 | + @confirm="onTireWearConfirm" | ||
| 334 | + @cancel="tireWearPickerVisible = false" | ||
| 335 | + /> | ||
| 336 | + </nut-popup> | ||
| 182 | </view> | 337 | </view> |
| 183 | </template> | 338 | </template> |
| 184 | 339 | ||
| 185 | <script setup> | 340 | <script setup> |
| 186 | import { ref, reactive } from 'vue' | 341 | import { ref, reactive } from 'vue' |
| 187 | -import { Close, Plus, Right } from '@nutui/icons-vue-taro' | 342 | +import { Plus, Right, Location, RectLeft } from '@nutui/icons-vue-taro' |
| 188 | import Taro from '@tarojs/taro' | 343 | import Taro from '@tarojs/taro' |
| 189 | -import TabBar from '@/components/TabBar.vue' | ||
| 190 | 344 | ||
| 191 | -// 响应式数据 | 345 | +const themeVars = ref({ |
| 192 | -const vehicleImages = ref([]) | 346 | + // navbarBackground: '#FFA135', |
| 193 | -const brandIndex = ref(-1) | 347 | + // navbarColor: '#ffffff', |
| 194 | -const yearIndex = ref(-1) | 348 | +}) |
| 195 | -const typeIndex = ref(-1) | 349 | + |
| 196 | -const usageIndex = ref(-1) | 350 | +// 文件上传列表 |
| 351 | +const fileList = ref([]) | ||
| 197 | 352 | ||
| 198 | // 表单数据 | 353 | // 表单数据 |
| 199 | const formData = reactive({ | 354 | const formData = reactive({ |
| 200 | - name: '', | 355 | + school: '', |
| 201 | brand: '', | 356 | brand: '', |
| 357 | + model: '', | ||
| 202 | year: '', | 358 | year: '', |
| 203 | - type: '', | 359 | + condition: '', |
| 204 | - price: '', | 360 | + mileage: '1200', |
| 205 | - usage: '', | 361 | + range: '60', |
| 206 | - description: '', | 362 | + maxSpeed: '25', |
| 207 | - phone: '', | 363 | + batteryCapacity: '20', |
| 208 | - school: '', | 364 | + batteryWear: '', |
| 209 | - location: '' | 365 | + brakeWear: '', |
| 366 | + tireWear: '', | ||
| 367 | + sellingPrice: '3,200', | ||
| 368 | + marketPrice: '6,500', | ||
| 369 | + description: '' | ||
| 210 | }) | 370 | }) |
| 211 | 371 | ||
| 212 | -// 选择器数据 | 372 | +// 选择器显示状态 |
| 213 | -const brands = ['小牛电动', '雅迪', '爱玛', '台铃', '绿源', '新日', '立马', '其他'] | 373 | +const schoolPickerVisible = ref(false) |
| 214 | -const years = ['2024年', '2023年', '2022年', '2021年', '2020年', '2019年', '2018年', '更早'] | 374 | +const brandPickerVisible = ref(false) |
| 215 | -const types = ['电动自行车', '电动摩托车', '电动汽车', '平衡车', '滑板车', '其他'] | 375 | +const modelPickerVisible = ref(false) |
| 216 | -const usagePeriods = ['3个月以内', '3-6个月', '6个月-1年', '1-2年', '2-3年', '3年以上'] | 376 | +const yearPickerVisible = ref(false) |
| 377 | +const conditionPickerVisible = ref(false) | ||
| 378 | +const batteryWearPickerVisible = ref(false) | ||
| 379 | +const brakeWearPickerVisible = ref(false) | ||
| 380 | +const tireWearPickerVisible = ref(false) | ||
| 381 | + | ||
| 382 | +// 选择器值 | ||
| 383 | +const schoolValue = ref([]) | ||
| 384 | +const brandValue = ref([]) | ||
| 385 | +const modelValue = ref([]) | ||
| 386 | +const yearValue = ref([]) | ||
| 387 | +const conditionValue = ref([]) | ||
| 388 | +const batteryWearValue = ref([]) | ||
| 389 | +const brakeWearValue = ref([]) | ||
| 390 | +const tireWearValue = ref([]) | ||
| 391 | + | ||
| 392 | +// 选择器选项数据 | ||
| 393 | +const schoolOptions = ref([ | ||
| 394 | + { text: '上海理工大学', value: '上海理工大学' }, | ||
| 395 | + { text: '复旦大学', value: '复旦大学' }, | ||
| 396 | + { text: '上海交通大学', value: '上海交通大学' }, | ||
| 397 | + { text: '同济大学', value: '同济大学' }, | ||
| 398 | + { text: '华东师范大学', value: '华东师范大学' }, | ||
| 399 | + { text: '上海大学', value: '上海大学' }, | ||
| 400 | + { text: '东华大学', value: '东华大学' }, | ||
| 401 | + { text: '上海财经大学', value: '上海财经大学' } | ||
| 402 | +]) | ||
| 403 | + | ||
| 404 | +const brandOptions = ref([ | ||
| 405 | + { text: '小牛电动', value: '小牛电动' }, | ||
| 406 | + { text: '雅迪', value: '雅迪' }, | ||
| 407 | + { text: '爱玛', value: '爱玛' }, | ||
| 408 | + { text: '台铃', value: '台铃' }, | ||
| 409 | + { text: '绿源', value: '绿源' }, | ||
| 410 | + { text: '新日', value: '新日' }, | ||
| 411 | + { text: '立马', value: '立马' }, | ||
| 412 | + { text: '其他', value: '其他' } | ||
| 413 | +]) | ||
| 414 | + | ||
| 415 | +const modelOptions = ref([ | ||
| 416 | + { text: 'NGT', value: 'NGT' }, | ||
| 417 | + { text: 'UQi+', value: 'UQi+' }, | ||
| 418 | + { text: 'Gova G2', value: 'Gova G2' }, | ||
| 419 | + { text: 'MQi+', value: 'MQi+' }, | ||
| 420 | + { text: 'NQi GTS', value: 'NQi GTS' }, | ||
| 421 | + { text: 'RQi', value: 'RQi' }, | ||
| 422 | + { text: '其他型号', value: '其他型号' } | ||
| 423 | +]) | ||
| 424 | + | ||
| 425 | +const yearOptions = ref([ | ||
| 426 | + { text: '2024年', value: '2024年' }, | ||
| 427 | + { text: '2023年', value: '2023年' }, | ||
| 428 | + { text: '2022年', value: '2022年' }, | ||
| 429 | + { text: '2021年', value: '2021年' }, | ||
| 430 | + { text: '2020年', value: '2020年' }, | ||
| 431 | + { text: '2019年', value: '2019年' }, | ||
| 432 | + { text: '2018年及以前', value: '2018年及以前' } | ||
| 433 | +]) | ||
| 434 | + | ||
| 435 | +const conditionOptions = ref([ | ||
| 436 | + { text: '全新', value: '全新' }, | ||
| 437 | + { text: '9成新', value: '9成新' }, | ||
| 438 | + { text: '8成新', value: '8成新' }, | ||
| 439 | + { text: '7成新', value: '7成新' }, | ||
| 440 | + { text: '6成新', value: '6成新' }, | ||
| 441 | + { text: '5成新及以下', value: '5成新及以下' } | ||
| 442 | +]) | ||
| 443 | + | ||
| 444 | +const wearLevelOptions = ref([ | ||
| 445 | + { text: '全新', value: '全新' }, | ||
| 446 | + { text: '轻微磨损', value: '轻微磨损' }, | ||
| 447 | + { text: '中度磨损', value: '中度磨损' }, | ||
| 448 | + { text: '重度磨损', value: '重度磨损' }, | ||
| 449 | + { text: '需要更换', value: '需要更换' } | ||
| 450 | +]) | ||
| 451 | + | ||
| 452 | +/** | ||
| 453 | + * 返回上一页 | ||
| 454 | + */ | ||
| 455 | +const goBack = () => { | ||
| 456 | + Taro.redirectTo({ | ||
| 457 | + url: '/pages/index/index' | ||
| 458 | + }) | ||
| 459 | +} | ||
| 217 | 460 | ||
| 218 | /** | 461 | /** |
| 219 | - * 上传图片 | 462 | + * 文件上传超出限制 |
| 220 | */ | 463 | */ |
| 221 | -const uploadImage = () => { | 464 | +const onOversize = () => { |
| 222 | - Taro.chooseImage({ | 465 | + Taro.showToast({ |
| 223 | - count: 6 - vehicleImages.value.length, | 466 | + title: '文件大小超出限制', |
| 224 | - sizeType: ['compressed'], | 467 | + icon: 'none' |
| 225 | - sourceType: ['album', 'camera'], | ||
| 226 | - success: (res) => { | ||
| 227 | - vehicleImages.value.push(...res.tempFilePaths) | ||
| 228 | - } | ||
| 229 | }) | 468 | }) |
| 230 | } | 469 | } |
| 231 | 470 | ||
| 232 | /** | 471 | /** |
| 233 | - * 删除图片 | 472 | + * 删除上传的文件 |
| 234 | - * @param {number} index - 图片索引 | ||
| 235 | */ | 473 | */ |
| 236 | -const removeImage = (index) => { | 474 | +const onDelete = () => { |
| 237 | - vehicleImages.value.splice(index, 1) | 475 | + // 删除逻辑已由组件内部处理 |
| 238 | } | 476 | } |
| 239 | 477 | ||
| 240 | /** | 478 | /** |
| 241 | - * 品牌选择事件 | 479 | + * 显示学校选择器 |
| 242 | - * @param {object} e - 事件对象 | ||
| 243 | */ | 480 | */ |
| 244 | -const onBrandChange = (e) => { | 481 | +const showSchoolPicker = () => { |
| 245 | - brandIndex.value = e.detail.value | 482 | + schoolPickerVisible.value = true |
| 246 | - formData.brand = brands[e.detail.value] | ||
| 247 | } | 483 | } |
| 248 | 484 | ||
| 249 | /** | 485 | /** |
| 250 | - * 年份选择事件 | 486 | + * 显示品牌选择器 |
| 251 | - * @param {object} e - 事件对象 | ||
| 252 | */ | 487 | */ |
| 253 | -const onYearChange = (e) => { | 488 | +const showBrandPicker = () => { |
| 254 | - yearIndex.value = e.detail.value | 489 | + brandPickerVisible.value = true |
| 255 | - formData.year = years[e.detail.value] | ||
| 256 | } | 490 | } |
| 257 | 491 | ||
| 258 | /** | 492 | /** |
| 259 | - * 类型选择事件 | 493 | + * 显示型号选择器 |
| 260 | - * @param {object} e - 事件对象 | ||
| 261 | */ | 494 | */ |
| 262 | -const onTypeChange = (e) => { | 495 | +const showModelPicker = () => { |
| 263 | - typeIndex.value = e.detail.value | 496 | + if (!formData.brand) { |
| 264 | - formData.type = types[e.detail.value] | 497 | + Taro.showToast({ |
| 498 | + title: '请先选择品牌', | ||
| 499 | + icon: 'none' | ||
| 500 | + }) | ||
| 501 | + return | ||
| 502 | + } | ||
| 503 | + modelPickerVisible.value = true | ||
| 265 | } | 504 | } |
| 266 | 505 | ||
| 267 | /** | 506 | /** |
| 268 | - * 使用时长选择事件 | 507 | + * 显示年份选择器 |
| 269 | - * @param {object} e - 事件对象 | ||
| 270 | */ | 508 | */ |
| 271 | -const onUsageChange = (e) => { | 509 | +const showYearPicker = () => { |
| 272 | - usageIndex.value = e.detail.value | 510 | + yearPickerVisible.value = true |
| 273 | - formData.usage = usagePeriods[e.detail.value] | ||
| 274 | } | 511 | } |
| 275 | 512 | ||
| 276 | /** | 513 | /** |
| 277 | - * 预览功能 | 514 | + * 显示新旧程度选择器 |
| 278 | */ | 515 | */ |
| 279 | -const onPreview = () => { | 516 | +const showConditionPicker = () => { |
| 280 | - if (!validateForm()) return | 517 | + conditionPickerVisible.value = true |
| 281 | - | 518 | +} |
| 282 | - Taro.showToast({ | 519 | + |
| 283 | - title: '预览功能开发中', | 520 | +/** |
| 284 | - icon: 'none' | 521 | + * 显示电池损耗度选择器 |
| 285 | - }) | 522 | + */ |
| 523 | +const showBatteryWearPicker = () => { | ||
| 524 | + batteryWearPickerVisible.value = true | ||
| 525 | +} | ||
| 526 | + | ||
| 527 | +/** | ||
| 528 | + * 显示刹车磨损度选择器 | ||
| 529 | + */ | ||
| 530 | +const showBrakeWearPicker = () => { | ||
| 531 | + brakeWearPickerVisible.value = true | ||
| 532 | +} | ||
| 533 | + | ||
| 534 | +/** | ||
| 535 | + * 显示轮胎磨损度选择器 | ||
| 536 | + */ | ||
| 537 | +const showTireWearPicker = () => { | ||
| 538 | + tireWearPickerVisible.value = true | ||
| 539 | +} | ||
| 540 | + | ||
| 541 | +/** | ||
| 542 | + * 学校选择确认 | ||
| 543 | + */ | ||
| 544 | +const onSchoolConfirm = ({ selectedValue }) => { | ||
| 545 | + formData.school = selectedValue[0] | ||
| 546 | + schoolPickerVisible.value = false | ||
| 547 | +} | ||
| 548 | + | ||
| 549 | +/** | ||
| 550 | + * 品牌选择确认 | ||
| 551 | + */ | ||
| 552 | +const onBrandConfirm = ({ selectedValue }) => { | ||
| 553 | + formData.brand = selectedValue[0] | ||
| 554 | + formData.model = '' // 重置型号 | ||
| 555 | + brandPickerVisible.value = false | ||
| 556 | +} | ||
| 557 | + | ||
| 558 | +/** | ||
| 559 | + * 型号选择确认 | ||
| 560 | + */ | ||
| 561 | +const onModelConfirm = ({ selectedValue }) => { | ||
| 562 | + formData.model = selectedValue[0] | ||
| 563 | + modelPickerVisible.value = false | ||
| 564 | +} | ||
| 565 | + | ||
| 566 | +/** | ||
| 567 | + * 年份选择确认 | ||
| 568 | + */ | ||
| 569 | +const onYearConfirm = ({ selectedValue }) => { | ||
| 570 | + formData.year = selectedValue[0] | ||
| 571 | + yearPickerVisible.value = false | ||
| 572 | +} | ||
| 573 | + | ||
| 574 | +/** | ||
| 575 | + * 新旧程度选择确认 | ||
| 576 | + */ | ||
| 577 | +const onConditionConfirm = ({ selectedValue }) => { | ||
| 578 | + formData.condition = selectedValue[0] | ||
| 579 | + conditionPickerVisible.value = false | ||
| 580 | +} | ||
| 581 | + | ||
| 582 | +/** | ||
| 583 | + * 电池损耗度选择确认 | ||
| 584 | + */ | ||
| 585 | +const onBatteryWearConfirm = ({ selectedValue }) => { | ||
| 586 | + formData.batteryWear = selectedValue[0] | ||
| 587 | + batteryWearPickerVisible.value = false | ||
| 588 | +} | ||
| 589 | + | ||
| 590 | +/** | ||
| 591 | + * 刹车磨损度选择确认 | ||
| 592 | + */ | ||
| 593 | +const onBrakeWearConfirm = ({ selectedValue }) => { | ||
| 594 | + formData.brakeWear = selectedValue[0] | ||
| 595 | + brakeWearPickerVisible.value = false | ||
| 596 | +} | ||
| 597 | + | ||
| 598 | +/** | ||
| 599 | + * 轮胎磨损度选择确认 | ||
| 600 | + */ | ||
| 601 | +const onTireWearConfirm = ({ selectedValue }) => { | ||
| 602 | + formData.tireWear = selectedValue[0] | ||
| 603 | + tireWearPickerVisible.value = false | ||
| 286 | } | 604 | } |
| 287 | 605 | ||
| 288 | /** | 606 | /** |
| ... | @@ -290,9 +608,9 @@ const onPreview = () => { | ... | @@ -290,9 +608,9 @@ const onPreview = () => { |
| 290 | */ | 608 | */ |
| 291 | const onPublish = () => { | 609 | const onPublish = () => { |
| 292 | if (!validateForm()) return | 610 | if (!validateForm()) return |
| 293 | - | 611 | + |
| 294 | Taro.showLoading({ title: '发布中...' }) | 612 | Taro.showLoading({ title: '发布中...' }) |
| 295 | - | 613 | + |
| 296 | // 模拟发布请求 | 614 | // 模拟发布请求 |
| 297 | setTimeout(() => { | 615 | setTimeout(() => { |
| 298 | Taro.hideLoading() | 616 | Taro.hideLoading() |
| ... | @@ -300,7 +618,7 @@ const onPublish = () => { | ... | @@ -300,7 +618,7 @@ const onPublish = () => { |
| 300 | title: '发布成功', | 618 | title: '发布成功', |
| 301 | icon: 'success' | 619 | icon: 'success' |
| 302 | }) | 620 | }) |
| 303 | - | 621 | + |
| 304 | // 发布成功后跳转到首页 | 622 | // 发布成功后跳转到首页 |
| 305 | setTimeout(() => { | 623 | setTimeout(() => { |
| 306 | Taro.switchTab({ url: '/pages/index/index' }) | 624 | Taro.switchTab({ url: '/pages/index/index' }) |
| ... | @@ -313,51 +631,31 @@ const onPublish = () => { | ... | @@ -313,51 +631,31 @@ const onPublish = () => { |
| 313 | * @returns {boolean} 验证结果 | 631 | * @returns {boolean} 验证结果 |
| 314 | */ | 632 | */ |
| 315 | const validateForm = () => { | 633 | const validateForm = () => { |
| 316 | - if (vehicleImages.value.length === 0) { | 634 | + if (fileList.value.length === 0) { |
| 317 | Taro.showToast({ title: '请上传车辆图片', icon: 'none' }) | 635 | Taro.showToast({ title: '请上传车辆图片', icon: 'none' }) |
| 318 | return false | 636 | return false |
| 319 | } | 637 | } |
| 320 | - | 638 | + |
| 321 | - if (!formData.name.trim()) { | ||
| 322 | - Taro.showToast({ title: '请输入车辆名称', icon: 'none' }) | ||
| 323 | - return false | ||
| 324 | - } | ||
| 325 | - | ||
| 326 | if (!formData.brand) { | 639 | if (!formData.brand) { |
| 327 | - Taro.showToast({ title: '请选择车辆品牌', icon: 'none' }) | 640 | + Taro.showToast({ title: '请选择车型品牌', icon: 'none' }) |
| 328 | - return false | ||
| 329 | - } | ||
| 330 | - | ||
| 331 | - if (!formData.year) { | ||
| 332 | - Taro.showToast({ title: '请选择购买年份', icon: 'none' }) | ||
| 333 | - return false | ||
| 334 | - } | ||
| 335 | - | ||
| 336 | - if (!formData.type) { | ||
| 337 | - Taro.showToast({ title: '请选择车辆类型', icon: 'none' }) | ||
| 338 | return false | 641 | return false |
| 339 | } | 642 | } |
| 340 | - | 643 | + |
| 341 | - if (!formData.price || formData.price <= 0) { | 644 | + if (!formData.condition) { |
| 342 | - Taro.showToast({ title: '请输入正确的价格', icon: 'none' }) | 645 | + Taro.showToast({ title: '请选择新旧程度', icon: 'none' }) |
| 343 | - return false | ||
| 344 | - } | ||
| 345 | - | ||
| 346 | - if (!formData.phone.trim()) { | ||
| 347 | - Taro.showToast({ title: '请输入手机号码', icon: 'none' }) | ||
| 348 | return false | 646 | return false |
| 349 | } | 647 | } |
| 350 | - | 648 | + |
| 351 | - if (!/^1[3-9]\d{9}$/.test(formData.phone)) { | 649 | + if (!formData.mileage || formData.mileage <= 0) { |
| 352 | - Taro.showToast({ title: '请输入正确的手机号码', icon: 'none' }) | 650 | + Taro.showToast({ title: '请输入正确的行驶里程', icon: 'none' }) |
| 353 | return false | 651 | return false |
| 354 | } | 652 | } |
| 355 | - | 653 | + |
| 356 | - if (!formData.school.trim()) { | 654 | + if (!formData.sellingPrice) { |
| 357 | - Taro.showToast({ title: '请输入所在学校', icon: 'none' }) | 655 | + Taro.showToast({ title: '请输入出让价格', icon: 'none' }) |
| 358 | return false | 656 | return false |
| 359 | } | 657 | } |
| 360 | - | 658 | + |
| 361 | return true | 659 | return true |
| 362 | } | 660 | } |
| 363 | </script> | 661 | </script> |
| ... | @@ -365,202 +663,128 @@ const validateForm = () => { | ... | @@ -365,202 +663,128 @@ const validateForm = () => { |
| 365 | <style lang="less"> | 663 | <style lang="less"> |
| 366 | .sell-page { | 664 | .sell-page { |
| 367 | min-height: 100vh; | 665 | min-height: 100vh; |
| 368 | - background-color: #f9fafb; | 666 | + background-color: #f5f5f5; |
| 369 | - padding-bottom: 80px; | 667 | + padding-bottom: 120rpx; |
| 370 | -} | ||
| 371 | - | ||
| 372 | -.header { | ||
| 373 | - background-color: #ffffff; | ||
| 374 | - padding: 20px 16px; | ||
| 375 | - border-bottom: 1px solid #f3f4f6; | ||
| 376 | -} | ||
| 377 | - | ||
| 378 | -.header-title { | ||
| 379 | - font-size: 24px; | ||
| 380 | - font-weight: 700; | ||
| 381 | - color: #111827; | ||
| 382 | - display: block; | ||
| 383 | - margin-bottom: 4px; | ||
| 384 | -} | ||
| 385 | - | ||
| 386 | -.header-subtitle { | ||
| 387 | - font-size: 14px; | ||
| 388 | - color: #6b7280; | ||
| 389 | - display: block; | ||
| 390 | } | 668 | } |
| 391 | 669 | ||
| 392 | .form-container { | 670 | .form-container { |
| 393 | - padding: 0 16px; | 671 | + padding: 0 32rpx; |
| 394 | } | 672 | } |
| 395 | 673 | ||
| 396 | .form-section { | 674 | .form-section { |
| 397 | background-color: #ffffff; | 675 | background-color: #ffffff; |
| 398 | - border-radius: 12px; | 676 | + border-radius: 24rpx; |
| 399 | - padding: 20px; | 677 | + padding: 32rpx; |
| 400 | - margin: 12px 0; | 678 | + margin: 24rpx 0; |
| 401 | } | 679 | } |
| 402 | 680 | ||
| 403 | .section-title { | 681 | .section-title { |
| 404 | - font-size: 18px; | 682 | + font-size: 32rpx; |
| 405 | font-weight: 600; | 683 | font-weight: 600; |
| 406 | color: #111827; | 684 | color: #111827; |
| 407 | - margin-bottom: 16px; | 685 | + margin-bottom: 32rpx; |
| 408 | display: block; | 686 | display: block; |
| 409 | } | 687 | } |
| 410 | 688 | ||
| 411 | -.required { | 689 | +.upload-tips { |
| 412 | - color: #ef4444; | 690 | + display: flex; |
| 413 | -} | 691 | + margin-top: 16rpx; |
| 414 | - | 692 | + gap: 32rpx; |
| 415 | -.image-upload-container { | ||
| 416 | - display: grid; | ||
| 417 | - grid-template-columns: repeat(3, 1fr); | ||
| 418 | - gap: 12px; | ||
| 419 | - margin-bottom: 8px; | ||
| 420 | } | 693 | } |
| 421 | 694 | ||
| 422 | -.image-item { | 695 | +.tip-item { |
| 423 | - position: relative; | 696 | + font-size: 24rpx; |
| 424 | - aspect-ratio: 1; | 697 | + color: #9ca3af; |
| 425 | - border-radius: 8px; | ||
| 426 | - overflow: hidden; | ||
| 427 | } | 698 | } |
| 428 | 699 | ||
| 429 | -.uploaded-image { | 700 | +.form-item { |
| 430 | - width: 100%; | ||
| 431 | - height: 100%; | ||
| 432 | - object-fit: cover; | ||
| 433 | -} | ||
| 434 | - | ||
| 435 | -.image-delete { | ||
| 436 | - position: absolute; | ||
| 437 | - top: 4px; | ||
| 438 | - right: 4px; | ||
| 439 | - width: 24px; | ||
| 440 | - height: 24px; | ||
| 441 | - background-color: rgba(0, 0, 0, 0.6); | ||
| 442 | - border-radius: 50%; | ||
| 443 | display: flex; | 701 | display: flex; |
| 702 | + justify-content: space-between; | ||
| 444 | align-items: center; | 703 | align-items: center; |
| 445 | - justify-content: center; | 704 | + padding: 32rpx 0; |
| 705 | + border-bottom: 1rpx solid #f3f4f6; | ||
| 446 | } | 706 | } |
| 447 | 707 | ||
| 448 | -.image-upload-btn { | 708 | +.form-item:last-child { |
| 449 | - aspect-ratio: 1; | 709 | + border-bottom: none; |
| 450 | - border: 2px dashed #d1d5db; | ||
| 451 | - border-radius: 8px; | ||
| 452 | - display: flex; | ||
| 453 | - flex-direction: column; | ||
| 454 | - align-items: center; | ||
| 455 | - justify-content: center; | ||
| 456 | - gap: 4px; | ||
| 457 | - background-color: #f9fafb; | ||
| 458 | } | 710 | } |
| 459 | 711 | ||
| 460 | -.upload-text { | 712 | +.form-item-left { |
| 461 | - font-size: 12px; | 713 | + display: flex; |
| 462 | - color: #9ca3af; | 714 | + align-items: center; |
| 463 | } | 715 | } |
| 464 | 716 | ||
| 465 | -.form-tip { | 717 | +.form-icon { |
| 466 | - font-size: 12px; | 718 | + margin-right: 16rpx; |
| 467 | color: #9ca3af; | 719 | color: #9ca3af; |
| 468 | - display: block; | ||
| 469 | -} | ||
| 470 | - | ||
| 471 | -.form-item { | ||
| 472 | - margin-bottom: 16px; | ||
| 473 | } | 720 | } |
| 474 | 721 | ||
| 475 | .form-label { | 722 | .form-label { |
| 476 | - font-size: 14px; | 723 | + font-size: 28rpx; |
| 477 | - font-weight: 500; | ||
| 478 | color: #374151; | 724 | color: #374151; |
| 479 | - margin-bottom: 8px; | ||
| 480 | - display: block; | ||
| 481 | } | 725 | } |
| 482 | 726 | ||
| 483 | -.form-input { | 727 | +.form-item-right { |
| 484 | - width: 100%; | 728 | + display: flex; |
| 485 | - padding: 12px 16px; | 729 | + align-items: center; |
| 486 | - border: 1px solid #d1d5db; | ||
| 487 | - border-radius: 8px; | ||
| 488 | - font-size: 14px; | ||
| 489 | - color: #374151; | ||
| 490 | - background-color: #ffffff; | ||
| 491 | } | 730 | } |
| 492 | 731 | ||
| 493 | -.form-input:focus { | 732 | +.form-value { |
| 494 | - border-color: #f97316; | 733 | + font-size: 28rpx; |
| 495 | - outline: none; | 734 | + color: #9ca3af; |
| 735 | + margin-right: 16rpx; | ||
| 496 | } | 736 | } |
| 497 | 737 | ||
| 498 | -.form-picker { | 738 | +.arrow-icon { |
| 499 | - width: 100%; | 739 | + color: #9ca3af; |
| 500 | } | 740 | } |
| 501 | 741 | ||
| 502 | -.picker-content { | 742 | +.form-item-content { |
| 503 | display: flex; | 743 | display: flex; |
| 504 | justify-content: space-between; | 744 | justify-content: space-between; |
| 505 | align-items: center; | 745 | align-items: center; |
| 506 | - padding: 12px 16px; | 746 | + width: 100%; |
| 507 | - border: 1px solid #d1d5db; | 747 | + padding: 24rpx 0; |
| 508 | - border-radius: 8px; | ||
| 509 | - background-color: #ffffff; | ||
| 510 | -} | ||
| 511 | - | ||
| 512 | -.picker-text { | ||
| 513 | - font-size: 14px; | ||
| 514 | - color: #374151; | ||
| 515 | } | 748 | } |
| 516 | 749 | ||
| 517 | -.price-input-container { | 750 | +.unit { |
| 518 | - display: flex; | 751 | + font-size: 28rpx; |
| 519 | - align-items: center; | 752 | + color: #9ca3af; |
| 520 | - border: 1px solid #d1d5db; | 753 | + margin-left: 16rpx; |
| 521 | - border-radius: 8px; | ||
| 522 | - background-color: #ffffff; | ||
| 523 | } | 754 | } |
| 524 | 755 | ||
| 525 | .price-symbol { | 756 | .price-symbol { |
| 526 | - padding: 12px 0 12px 16px; | 757 | + font-size: 32rpx; |
| 527 | - font-size: 14px; | 758 | + color: #f97316; |
| 528 | - color: #374151; | 759 | + font-weight: 600; |
| 529 | - font-weight: 500; | 760 | + margin-right: 8rpx; |
| 530 | } | 761 | } |
| 531 | 762 | ||
| 532 | .price-input { | 763 | .price-input { |
| 533 | - flex: 1; | 764 | + font-size: 32rpx; |
| 534 | - padding: 12px 16px 12px 4px; | 765 | + color: #f97316; |
| 766 | + font-weight: 600; | ||
| 767 | + text-align: right; | ||
| 535 | border: none; | 768 | border: none; |
| 536 | - font-size: 14px; | 769 | + outline: none; |
| 537 | - color: #374151; | ||
| 538 | background: transparent; | 770 | background: transparent; |
| 771 | + width: 160rpx; | ||
| 539 | } | 772 | } |
| 540 | 773 | ||
| 541 | -.form-textarea { | 774 | +.market-price-symbol { |
| 542 | - width: 100%; | 775 | + font-size: 28rpx; |
| 543 | - min-height: 80px; | 776 | + color: #9ca3af; |
| 544 | - padding: 12px 16px; | 777 | + margin-right: 8rpx; |
| 545 | - border: 1px solid #d1d5db; | ||
| 546 | - border-radius: 8px; | ||
| 547 | - font-size: 14px; | ||
| 548 | - color: #374151; | ||
| 549 | - background-color: #ffffff; | ||
| 550 | - resize: none; | ||
| 551 | -} | ||
| 552 | - | ||
| 553 | -.form-textarea:focus { | ||
| 554 | - border-color: #f97316; | ||
| 555 | - outline: none; | ||
| 556 | } | 778 | } |
| 557 | 779 | ||
| 558 | -.char-count { | 780 | +.market-price-input { |
| 559 | - font-size: 12px; | 781 | + font-size: 28rpx; |
| 560 | color: #9ca3af; | 782 | color: #9ca3af; |
| 561 | text-align: right; | 783 | text-align: right; |
| 562 | - margin-top: 4px; | 784 | + border: none; |
| 563 | - display: block; | 785 | + outline: none; |
| 786 | + background: transparent; | ||
| 787 | + width: 160rpx; | ||
| 564 | } | 788 | } |
| 565 | 789 | ||
| 566 | .bottom-actions { | 790 | .bottom-actions { |
| ... | @@ -569,39 +793,85 @@ const validateForm = () => { | ... | @@ -569,39 +793,85 @@ const validateForm = () => { |
| 569 | left: 0; | 793 | left: 0; |
| 570 | right: 0; | 794 | right: 0; |
| 571 | background-color: #ffffff; | 795 | background-color: #ffffff; |
| 572 | - padding: 12px 16px; | 796 | + padding: 24rpx 32rpx; |
| 573 | - border-top: 1px solid #f3f4f6; | 797 | + border-top: 1rpx solid #f3f4f6; |
| 574 | - display: flex; | 798 | + z-index: 100; |
| 575 | - gap: 12px; | ||
| 576 | } | 799 | } |
| 577 | 800 | ||
| 578 | -.preview-btn { | 801 | +// NutUI组件样式覆盖 |
| 579 | - flex: 1; | 802 | +:deep(.nut-form-item) { |
| 580 | - padding: 12px; | 803 | + padding: 0; |
| 581 | - border: 1px solid #f97316; | 804 | + margin-bottom: 0; |
| 582 | - border-radius: 8px; | 805 | + border-bottom: 1rpx solid #f3f4f6; |
| 583 | - background-color: #ffffff; | ||
| 584 | - color: #f97316; | ||
| 585 | - font-size: 16px; | ||
| 586 | - font-weight: 500; | ||
| 587 | } | 806 | } |
| 588 | 807 | ||
| 589 | -.publish-btn { | 808 | +// :deep(.nut-form-item:last-child) { |
| 590 | - flex: 2; | 809 | +// border-bottom: none; |
| 591 | - padding: 12px; | 810 | +// } |
| 592 | - border: none; | 811 | + |
| 593 | - border-radius: 8px; | 812 | +:deep(.nut-form-item__body) { |
| 594 | - background-color: #f97316; | 813 | + padding: 32rpx 0; |
| 595 | - color: #ffffff; | 814 | +} |
| 596 | - font-size: 16px; | 815 | + |
| 597 | - font-weight: 500; | 816 | +:deep(.nut-form-item__label) { |
| 817 | + font-size: 28rpx; | ||
| 818 | + color: #374151; | ||
| 819 | + margin-right: 32rpx; | ||
| 820 | +} | ||
| 821 | + | ||
| 822 | +:deep(.nut-input) { | ||
| 823 | + text-align: right; | ||
| 824 | +} | ||
| 825 | + | ||
| 826 | +:deep(.nut-input__input) { | ||
| 827 | + font-size: 28rpx; | ||
| 828 | + color: #374151; | ||
| 829 | + text-align: right; | ||
| 830 | +} | ||
| 831 | + | ||
| 832 | +:deep(.nut-textarea) { | ||
| 833 | + border: 1rpx solid #e5e7eb; | ||
| 834 | + border-radius: 16rpx; | ||
| 835 | + padding: 24rpx; | ||
| 836 | +} | ||
| 837 | + | ||
| 838 | +:deep(.nut-textarea__textarea) { | ||
| 839 | + font-size: 28rpx; | ||
| 840 | + color: #374151; | ||
| 841 | + line-height: 1.5; | ||
| 598 | } | 842 | } |
| 599 | 843 | ||
| 600 | -.preview-btn:active { | 844 | +:deep(.nut-uploader) { |
| 601 | - background-color: #fef7ed; | 845 | + margin-bottom: 16rpx; |
| 602 | } | 846 | } |
| 603 | 847 | ||
| 604 | -.publish-btn:active { | 848 | +:deep(.nut-uploader__preview) { |
| 605 | - background-color: #ea580c; | 849 | + display: grid; |
| 850 | + grid-template-columns: repeat(4, 1fr); | ||
| 851 | + gap: 24rpx; | ||
| 852 | + margin-bottom: 24rpx; | ||
| 853 | +} | ||
| 854 | + | ||
| 855 | +:deep(.nut-uploader__preview-img) { | ||
| 856 | + width: 160rpx; | ||
| 857 | + height: 160rpx; | ||
| 858 | + border-radius: 16rpx; | ||
| 859 | +} | ||
| 860 | + | ||
| 861 | +:deep(.nut-picker__toolbar) { | ||
| 862 | + padding: 24rpx 32rpx; | ||
| 863 | +} | ||
| 864 | + | ||
| 865 | +:deep(.nut-picker__cancel) { | ||
| 866 | + color: #9ca3af; | ||
| 867 | +} | ||
| 868 | + | ||
| 869 | +:deep(.nut-picker__confirm) { | ||
| 870 | + color: #f97316; | ||
| 871 | +} | ||
| 872 | + | ||
| 873 | +:deep(.nut-picker__title) { | ||
| 874 | + font-size: 32rpx; | ||
| 875 | + font-weight: 600; | ||
| 606 | } | 876 | } |
| 607 | -</style> | ||
| ... | \ No newline at end of file | ... | \ No newline at end of file |
| 877 | +</style> | ... | ... |
-
Please register or login to post a comment