feat(车辆管理): 实现品牌型号和学校数据从API加载
重构品牌型号选择器组件,移除模拟数据 添加学校列表和品牌型号列表的API调用 更新车辆列表页面使用真实API数据
Showing
5 changed files
with
161 additions
and
261 deletions
| ... | @@ -15,6 +15,7 @@ declare module 'vue' { | ... | @@ -15,6 +15,7 @@ declare module 'vue' { |
| 15 | NutConfigProvider: typeof import('@nutui/nutui-taro')['ConfigProvider'] | 15 | NutConfigProvider: typeof import('@nutui/nutui-taro')['ConfigProvider'] |
| 16 | NutDatePicker: typeof import('@nutui/nutui-taro')['DatePicker'] | 16 | NutDatePicker: typeof import('@nutui/nutui-taro')['DatePicker'] |
| 17 | NutDialog: typeof import('@nutui/nutui-taro')['Dialog'] | 17 | NutDialog: typeof import('@nutui/nutui-taro')['Dialog'] |
| 18 | + NutEllipsis: typeof import('@nutui/nutui-taro')['Ellipsis'] | ||
| 18 | NutForm: typeof import('@nutui/nutui-taro')['Form'] | 19 | NutForm: typeof import('@nutui/nutui-taro')['Form'] |
| 19 | NutFormItem: typeof import('@nutui/nutui-taro')['FormItem'] | 20 | NutFormItem: typeof import('@nutui/nutui-taro')['FormItem'] |
| 20 | NutImagePreview: typeof import('@nutui/nutui-taro')['ImagePreview'] | 21 | NutImagePreview: typeof import('@nutui/nutui-taro')['ImagePreview'] | ... | ... |
| 1 | /* | 1 | /* |
| 2 | * @Date: 2025-07-09 14:58:51 | 2 | * @Date: 2025-07-09 14:58:51 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-07-09 16:07:38 | 4 | + * @LastEditTime: 2025-07-10 14:45:49 |
| 5 | * @FilePath: /jgdl/src/api/car.js | 5 | * @FilePath: /jgdl/src/api/car.js |
| 6 | * @Description: 车辆相关API接口 | 6 | * @Description: 车辆相关API接口 |
| 7 | */ | 7 | */ | ... | ... |
| ... | @@ -115,6 +115,14 @@ import Taro from '@tarojs/taro' | ... | @@ -115,6 +115,14 @@ import Taro from '@tarojs/taro' |
| 115 | import { Right } from '@nutui/icons-vue-taro' | 115 | import { Right } from '@nutui/icons-vue-taro' |
| 116 | import { $ } from '@tarojs/extend' | 116 | import { $ } from '@tarojs/extend' |
| 117 | 117 | ||
| 118 | +// 定义props | ||
| 119 | +const props = defineProps({ | ||
| 120 | + brandOptions: { | ||
| 121 | + type: Array, | ||
| 122 | + default: () => [] | ||
| 123 | + } | ||
| 124 | +}) | ||
| 125 | + | ||
| 118 | // 定义事件 | 126 | // 定义事件 |
| 119 | const emit = defineEmits(['confirm', 'cancel']) | 127 | const emit = defineEmits(['confirm', 'cancel']) |
| 120 | 128 | ||
| ... | @@ -129,128 +137,26 @@ const searchKeyword = ref('') // 搜索关键词 | ... | @@ -129,128 +137,26 @@ const searchKeyword = ref('') // 搜索关键词 |
| 129 | const customBrand = ref('') // 自定义品牌 | 137 | const customBrand = ref('') // 自定义品牌 |
| 130 | const customModel = ref('') // 自定义型号 | 138 | const customModel = ref('') // 自定义型号 |
| 131 | 139 | ||
| 132 | -const allBrands = ref([ | 140 | +// 使用父组件传入的品牌数据,并添加"其他"选项 |
| 133 | - { text: '爱玛', value: 'aima' }, | 141 | +const allBrands = computed(() => { |
| 134 | - { text: '雅迪', value: 'yadi' }, | 142 | + const brands = [...props.brandOptions] |
| 135 | - { text: '小牛', value: 'xiaoniu' }, | 143 | + // 添加"其他"选项 |
| 136 | - { text: '台铃', value: 'tailing' }, | 144 | + brands.push({ text: '其他', value: 'other' }) |
| 137 | - { text: '绿源', value: 'lvyuan' }, | 145 | + return brands |
| 138 | - { text: '立马', value: 'lima' }, | 146 | +}) |
| 139 | - { text: '新日', value: 'xinri' }, | 147 | + |
| 140 | - { text: '宗申', value: 'zongshen' }, | 148 | +// 根据API数据构建品牌型号映射 |
| 141 | - { text: '奇瑞', value: 'qirui' }, | 149 | +const brandModelMap = computed(() => { |
| 142 | - { text: '比德文', value: 'bidewen' }, | 150 | + const map = {} |
| 143 | - { text: '欧派', value: 'oupai' }, | 151 | + props.brandOptions.forEach(brand => { |
| 144 | - { text: '捷安特', value: 'jiante' }, | 152 | + if (brand.models && brand.models.length > 0) { |
| 145 | - { text: '美利达', value: 'meilida' }, | 153 | + map[brand.value] = brand.models.map(model => ({ |
| 146 | - { text: '凤凰', value: 'fenghuang' }, | 154 | + text: model.name, |
| 147 | - { text: '永久', value: 'yongjiu' }, | 155 | + value: model.id |
| 148 | - { text: '飞鸽', value: 'feige' }, | 156 | + })) |
| 149 | - { text: '小刀', value: 'xiaodao' }, | 157 | + } |
| 150 | - { text: '速派奇', value: 'supaiqi' }, | 158 | + }) |
| 151 | - { text: '金箭', value: 'jinjian' }, | 159 | + return map |
| 152 | - { text: '森蓝', value: 'senlan' }, | ||
| 153 | - { text: '其他', value: 'other' } | ||
| 154 | -]) | ||
| 155 | - | ||
| 156 | -// 品牌型号映射 | ||
| 157 | -const brandModelMap = ref({ | ||
| 158 | - 'aima': [ | ||
| 159 | - { text: 'A1 Pro', value: 'aima_a1_pro' }, | ||
| 160 | - { text: 'A2 Max', value: 'aima_a2_max' }, | ||
| 161 | - { text: 'A3 Plus', value: 'aima_a3_plus' }, | ||
| 162 | - { text: 'A4 Elite', value: 'aima_a4_elite' }, | ||
| 163 | - { text: 'A4i', value: 'aima_a4i' }, | ||
| 164 | - { text: 'A4i+', value: 'aima_a4i_plus' }, | ||
| 165 | - { text: 'A5', value: 'aima_a5' }, | ||
| 166 | - { text: 'A5i', value: 'aima_a5i' }, | ||
| 167 | - { text: 'A6', value: 'aima_a6' }, | ||
| 168 | - { text: 'A6i', value: 'aima_a6i' }, | ||
| 169 | - ], | ||
| 170 | - 'yadi': [ | ||
| 171 | - { text: 'Y1 智享版', value: 'yadi_y1_smart' }, | ||
| 172 | - { text: 'Y2 豪华版', value: 'yadi_y2_luxury' }, | ||
| 173 | - { text: 'Y3 运动版', value: 'yadi_y3_sport' }, | ||
| 174 | - { text: 'Y4 旗舰版', value: 'yadi_y4_flagship' } | ||
| 175 | - ], | ||
| 176 | - 'xiaoniu': [ | ||
| 177 | - { text: 'N1S', value: 'xiaoniu_n1s' }, | ||
| 178 | - { text: 'N-GT', value: 'xiaoniu_ngt' }, | ||
| 179 | - { text: 'NGT Pro', value: 'xiaoniu_ngt_pro' }, | ||
| 180 | - { text: 'U1 Pro', value: 'xiaoniu_u1_pro' } | ||
| 181 | - ], | ||
| 182 | - 'tailing': [ | ||
| 183 | - { text: 'T1 经典版', value: 'tailing_t1_classic' }, | ||
| 184 | - { text: 'T2 时尚版', value: 'tailing_t2_fashion' }, | ||
| 185 | - { text: 'T3 豪华版', value: 'tailing_t3_luxury' } | ||
| 186 | - ], | ||
| 187 | - 'lvyuan': [ | ||
| 188 | - { text: 'L1 标准版', value: 'lvyuan_l1_standard' }, | ||
| 189 | - { text: 'L2 升级版', value: 'lvyuan_l2_upgrade' }, | ||
| 190 | - { text: 'L3 旗舰版', value: 'lvyuan_l3_flagship' } | ||
| 191 | - ], | ||
| 192 | - 'lima': [ | ||
| 193 | - { text: 'LM-1', value: 'lima_lm1' }, | ||
| 194 | - { text: 'LM-2', value: 'lima_lm2' }, | ||
| 195 | - { text: 'LM-3 Pro', value: 'lima_lm3_pro' } | ||
| 196 | - ], | ||
| 197 | - 'xinri': [ | ||
| 198 | - { text: 'XR-1', value: 'xinri_xr1' }, | ||
| 199 | - { text: 'XR-2 Plus', value: 'xinri_xr2_plus' }, | ||
| 200 | - { text: 'XR-3 Max', value: 'xinri_xr3_max' } | ||
| 201 | - ], | ||
| 202 | - 'zongshen': [ | ||
| 203 | - { text: 'ZS-1', value: 'zongshen_zs1' }, | ||
| 204 | - { text: 'ZS-2 Pro', value: 'zongshen_zs2_pro' } | ||
| 205 | - ], | ||
| 206 | - 'qirui': [ | ||
| 207 | - { text: 'QR-1', value: 'qirui_qr1' }, | ||
| 208 | - { text: 'QR-2 智能版', value: 'qirui_qr2_smart' } | ||
| 209 | - ], | ||
| 210 | - 'bidewen': [ | ||
| 211 | - { text: 'BD-1', value: 'bidewen_bd1' }, | ||
| 212 | - { text: 'BD-2 Plus', value: 'bidewen_bd2_plus' } | ||
| 213 | - ], | ||
| 214 | - 'oupai': [ | ||
| 215 | - { text: 'OP-1', value: 'oupai_op1' }, | ||
| 216 | - { text: 'OP-2 Pro', value: 'oupai_op2_pro' } | ||
| 217 | - ], | ||
| 218 | - 'jiante': [ | ||
| 219 | - { text: 'JT-1', value: 'jiante_jt1' }, | ||
| 220 | - { text: 'JT-2 运动版', value: 'jiante_jt2_sport' } | ||
| 221 | - ], | ||
| 222 | - 'meilida': [ | ||
| 223 | - { text: 'MD-1', value: 'meilida_md1' }, | ||
| 224 | - { text: 'MD-2 Pro', value: 'meilida_md2_pro' } | ||
| 225 | - ], | ||
| 226 | - 'fenghuang': [ | ||
| 227 | - { text: 'FH-1 经典', value: 'fenghuang_fh1_classic' }, | ||
| 228 | - { text: 'FH-2 现代', value: 'fenghuang_fh2_modern' } | ||
| 229 | - ], | ||
| 230 | - 'yongjiu': [ | ||
| 231 | - { text: 'YJ-1', value: 'yongjiu_yj1' }, | ||
| 232 | - { text: 'YJ-2 Plus', value: 'yongjiu_yj2_plus' } | ||
| 233 | - ], | ||
| 234 | - 'feige': [ | ||
| 235 | - { text: 'FG-1', value: 'feige_fg1' }, | ||
| 236 | - { text: 'FG-2 Pro', value: 'feige_fg2_pro' } | ||
| 237 | - ], | ||
| 238 | - 'xiaodao': [ | ||
| 239 | - { text: 'XD-1', value: 'xiaodao_xd1' }, | ||
| 240 | - { text: 'XD-2 Max', value: 'xiaodao_xd2_max' } | ||
| 241 | - ], | ||
| 242 | - 'supaiqi': [ | ||
| 243 | - { text: 'SP-1', value: 'supaiqi_sp1' }, | ||
| 244 | - { text: 'SP-2 Pro', value: 'supaiqi_sp2_pro' } | ||
| 245 | - ], | ||
| 246 | - 'jinjian': [ | ||
| 247 | - { text: 'JJ-1', value: 'jinjian_jj1' }, | ||
| 248 | - { text: 'JJ-2 Plus', value: 'jinjian_jj2_plus' } | ||
| 249 | - ], | ||
| 250 | - 'senlan': [ | ||
| 251 | - { text: 'SL-1', value: 'senlan_sl1' }, | ||
| 252 | - { text: 'SL-2 Pro', value: 'senlan_sl2_pro' } | ||
| 253 | - ] | ||
| 254 | }) | 160 | }) |
| 255 | 161 | ||
| 256 | // 过滤后的品牌列表 | 162 | // 过滤后的品牌列表 |
| ... | @@ -323,10 +229,13 @@ const selectBrand = (brand) => { | ... | @@ -323,10 +229,13 @@ const selectBrand = (brand) => { |
| 323 | 229 | ||
| 324 | // 选择型号 | 230 | // 选择型号 |
| 325 | const selectModel = (model) => { | 231 | const selectModel = (model) => { |
| 232 | + // 找到对应的品牌ID | ||
| 233 | + const selectedBrand = props.brandOptions.find(brand => brand.text === selectedBrandName.value) | ||
| 234 | + | ||
| 326 | const result = { | 235 | const result = { |
| 327 | brand: selectedBrandName.value, | 236 | brand: selectedBrandName.value, |
| 328 | model: model.text, | 237 | model: model.text, |
| 329 | - brandValue: selectedBrandName.value, | 238 | + brandValue: selectedBrand ? selectedBrand.value : selectedBrandName.value, |
| 330 | modelValue: model.value | 239 | modelValue: model.value |
| 331 | } | 240 | } |
| 332 | 241 | ... | ... |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2022-09-19 14:11:06 | 2 | * @Date: 2022-09-19 14:11:06 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-07-07 16:38:18 | 4 | + * @LastEditTime: 2025-07-10 16:26:10 |
| 5 | * @FilePath: /jgdl/src/pages/myCar/index.vue | 5 | * @FilePath: /jgdl/src/pages/myCar/index.vue |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | --> | 7 | --> |
| ... | @@ -20,9 +20,9 @@ | ... | @@ -20,9 +20,9 @@ |
| 20 | > | 20 | > |
| 21 | <!-- 空状态 --> | 21 | <!-- 空状态 --> |
| 22 | <view v-if="!loading && carList.length === 0" class="empty-state"> | 22 | <view v-if="!loading && carList.length === 0" class="empty-state"> |
| 23 | - <image src="/static/images/empty-car.png" class="empty-image" mode="aspectFit" /> | 23 | + <!-- <image src="/static/images/empty-car.png" class="empty-image" mode="aspectFit" /> --> |
| 24 | <text class="empty-text">暂无车源信息</text> | 24 | <text class="empty-text">暂无车源信息</text> |
| 25 | - <nut-button color="#f97316" size="small" @click="goToSell">发布车源</nut-button> | 25 | + <!-- <nut-button color="#f97316" @click="goToSell">发布车源</nut-button> --> |
| 26 | </view> | 26 | </view> |
| 27 | 27 | ||
| 28 | <!-- 车辆卡片列表 --> | 28 | <!-- 车辆卡片列表 --> |
| ... | @@ -31,34 +31,34 @@ | ... | @@ -31,34 +31,34 @@ |
| 31 | <!-- 使用 nut-row 和 nut-col 布局 --> | 31 | <!-- 使用 nut-row 和 nut-col 布局 --> |
| 32 | <nut-row :gutter="10"> | 32 | <nut-row :gutter="10"> |
| 33 | <!-- 左侧:车辆图片 --> | 33 | <!-- 左侧:车辆图片 --> |
| 34 | - <nut-col :span="8"> | 34 | + <nut-col :span="6"> |
| 35 | <view class="car-image-container"> | 35 | <view class="car-image-container"> |
| 36 | - <image :src="car.image" class="car-image" mode="aspectFill" /> | 36 | + <image :src="car.front_photo" class="car-image" mode="aspectFill" /> |
| 37 | </view> | 37 | </view> |
| 38 | </nut-col> | 38 | </nut-col> |
| 39 | 39 | ||
| 40 | <!-- 右侧:车辆信息 --> | 40 | <!-- 右侧:车辆信息 --> |
| 41 | - <nut-col :span="16"> | 41 | + <nut-col :span="18"> |
| 42 | <view class="car-info"> | 42 | <view class="car-info"> |
| 43 | - <view class="car-title">{{ car.brand }} {{ car.model }}</view> | 43 | + <view class="car-title">{{ car.manufacture_year }}款 {{ car.brand }} {{ car.model }}</view> |
| 44 | <!-- 状态标识 --> | 44 | <!-- 状态标识 --> |
| 45 | <view class="status-badges"> | 45 | <view class="status-badges"> |
| 46 | - <view v-if="car.isAuthenticated" class="status-badge verified"> | 46 | + <view v-if="car.verification_status" class="status-badge verified"> |
| 47 | - <text>已认证</text> | 47 | + <text>{{ verifyStatus[car.verification_status] }}</text> |
| 48 | </view> | 48 | </view> |
| 49 | - <view v-if="car.isOffline" class="status-badge offline"> | 49 | + <view v-if="car.status === 5" class="status-badge offline"> |
| 50 | - <text>已下架</text> | 50 | + <text>{{ carStatus[car.status] }}</text> |
| 51 | </view> | 51 | </view> |
| 52 | </view> | 52 | </view> |
| 53 | - <!-- <view class="car-details"> | 53 | + <view class="car-details"> |
| 54 | - <text class="detail-item">{{ car.year }}</text> | 54 | + <text class="detail-item">续航 {{ car.range_km }}km | 最高时速 {{ car.max_speed_kmh }}km/h</text> |
| 55 | - <text class="detail-item">{{ car.condition }}</text> | 55 | + </view> |
| 56 | - <text class="detail-item">{{ car.mileage }}公里</text> | 56 | + <view class="car-description"> |
| 57 | - </view> --> | 57 | + <nut-ellipsis direction="end" :content="car.note" :rows="2"></nut-ellipsis> |
| 58 | - <view class="car-description">{{ car.description }}</view> | 58 | + </view> |
| 59 | <view class="price-section"> | 59 | <view class="price-section"> |
| 60 | <view class="current-price">¥{{ car.price }}</view> | 60 | <view class="current-price">¥{{ car.price }}</view> |
| 61 | - <view class="market-price">市场价 ¥{{ car.marketPrice }}</view> | 61 | + <view class="market-price">市场价 ¥{{ car.market_price }}</view> |
| 62 | </view> | 62 | </view> |
| 63 | </view> | 63 | </view> |
| 64 | </nut-col> | 64 | </nut-col> |
| ... | @@ -69,13 +69,12 @@ | ... | @@ -69,13 +69,12 @@ |
| 69 | <nut-button size="small" type="default" @click="editCar(car.id)">编辑</nut-button> | 69 | <nut-button size="small" type="default" @click="editCar(car.id)">编辑</nut-button> |
| 70 | <nut-button | 70 | <nut-button |
| 71 | size="small" | 71 | size="small" |
| 72 | - :type="car.isOffline ? 'success' : 'warning'" | 72 | + :type="car.status === 5 ? 'success' : 'warning'" |
| 73 | @click="toggleOffline(car)" | 73 | @click="toggleOffline(car)" |
| 74 | > | 74 | > |
| 75 | - {{ car.isOffline ? '上架' : '下架' }} | 75 | + {{ car.status === 5 ? '上架' : '下架' }} |
| 76 | </nut-button> | 76 | </nut-button> |
| 77 | <nut-button | 77 | <nut-button |
| 78 | - v-if="!car.isAuthenticated" | ||
| 79 | size="small" | 78 | size="small" |
| 80 | type="primary" | 79 | type="primary" |
| 81 | @click="authCar(car.id)" | 80 | @click="authCar(car.id)" |
| ... | @@ -115,9 +114,25 @@ | ... | @@ -115,9 +114,25 @@ |
| 115 | </template> | 114 | </template> |
| 116 | 115 | ||
| 117 | <script setup> | 116 | <script setup> |
| 118 | -import { ref, computed, onMounted } from 'vue' | 117 | +import { ref, computed } from 'vue' |
| 119 | -import Taro from '@tarojs/taro' | 118 | +import Taro, { useDidShow } from '@tarojs/taro' |
| 120 | import './index.less' | 119 | import './index.less' |
| 120 | +// 导入接口 | ||
| 121 | +import { getMyListingVehicleAPI, changeVehicleStatusAPI } from '@/api/car'; | ||
| 122 | + | ||
| 123 | +// 认证状态映射 | ||
| 124 | +const verifyStatus = ref({ | ||
| 125 | + 1: '未认证', | ||
| 126 | + 3: '认证待审核', | ||
| 127 | + 5: '已认证', | ||
| 128 | + 7: '认证失败' | ||
| 129 | +}) | ||
| 130 | + | ||
| 131 | +// 上架状态映射 | ||
| 132 | +const carStatus = ref({ | ||
| 133 | + 3: '已上架', | ||
| 134 | + 5: '已下架', | ||
| 135 | +}) | ||
| 121 | 136 | ||
| 122 | /** | 137 | /** |
| 123 | * 滚动样式 - 考虑header和TabBar的高度 | 138 | * 滚动样式 - 考虑header和TabBar的高度 |
| ... | @@ -133,7 +148,7 @@ const scrollStyle = computed(() => { | ... | @@ -133,7 +148,7 @@ const scrollStyle = computed(() => { |
| 133 | // 页面状态 | 148 | // 页面状态 |
| 134 | const loading = ref(false) | 149 | const loading = ref(false) |
| 135 | const hasMore = ref(true) | 150 | const hasMore = ref(true) |
| 136 | -const currentPage = ref(1) | 151 | +const currentPage = ref(0) |
| 137 | const pageSize = ref(10) | 152 | const pageSize = ref(10) |
| 138 | 153 | ||
| 139 | // 车辆列表数据 | 154 | // 车辆列表数据 |
| ... | @@ -149,11 +164,11 @@ const currentOfflineCar = ref(null) | ... | @@ -149,11 +164,11 @@ const currentOfflineCar = ref(null) |
| 149 | /** | 164 | /** |
| 150 | * 跳转到发布车源页面 | 165 | * 跳转到发布车源页面 |
| 151 | */ | 166 | */ |
| 152 | -const goToSell = () => { | 167 | +// const goToSell = () => { |
| 153 | - Taro.navigateTo({ | 168 | +// Taro.navigateTo({ |
| 154 | - url: '/pages/sell/index' | 169 | +// url: '/pages/sell/index' |
| 155 | - }) | 170 | +// }) |
| 156 | -} | 171 | +// } |
| 157 | 172 | ||
| 158 | /** | 173 | /** |
| 159 | * 编辑车源 | 174 | * 编辑车源 |
| ... | @@ -178,25 +193,30 @@ const authCar = (carId) => { | ... | @@ -178,25 +193,30 @@ const authCar = (carId) => { |
| 178 | */ | 193 | */ |
| 179 | const toggleOffline = (car) => { | 194 | const toggleOffline = (car) => { |
| 180 | currentOfflineCar.value = car | 195 | currentOfflineCar.value = car |
| 181 | - offlineDialogContent.value = car.isOffline ? '确认要上架此车源吗?' : '确认要下架此车源吗?' | 196 | + offlineDialogContent.value = car.status === 5 ? '确认要上架此车源吗?' : '确认要下架此车源吗?' |
| 182 | offlineDialogVisible.value = true | 197 | offlineDialogVisible.value = true |
| 183 | } | 198 | } |
| 184 | 199 | ||
| 185 | /** | 200 | /** |
| 186 | * 确认上下架操作 | 201 | * 确认上下架操作 |
| 187 | */ | 202 | */ |
| 188 | -const confirmOffline = () => { | 203 | +const confirmOffline = async () => { |
| 189 | if (currentOfflineCar.value) { | 204 | if (currentOfflineCar.value) { |
| 190 | const car = currentOfflineCar.value | 205 | const car = currentOfflineCar.value |
| 191 | - car.isOffline = !car.isOffline | 206 | + if (car.status === 3) { |
| 192 | - | 207 | + car.status = 5 |
| 193 | - // TODO: 调用API更新车源状态 | 208 | + } else { |
| 194 | - // updateCarStatus(car.id, { isOffline: car.isOffline }) | 209 | + car.status = 3 |
| 210 | + } | ||
| 195 | 211 | ||
| 196 | - Taro.showToast({ | 212 | + // 调用API更新车源状态 |
| 197 | - title: car.isOffline ? '已下架' : '已上架', | 213 | + const { code } = await changeVehicleStatusAPI({ id: car.id, status: car.status }) |
| 198 | - icon: 'success' | 214 | + if (code) { |
| 199 | - }) | 215 | + Taro.showToast({ |
| 216 | + title: car.status === 3 ? '已下架' : '已上架', | ||
| 217 | + icon: 'success' | ||
| 218 | + }) | ||
| 219 | + } | ||
| 200 | } | 220 | } |
| 201 | offlineDialogVisible.value = false | 221 | offlineDialogVisible.value = false |
| 202 | currentOfflineCar.value = null | 222 | currentOfflineCar.value = null |
| ... | @@ -213,27 +233,30 @@ const cancelOffline = () => { | ... | @@ -213,27 +233,30 @@ const cancelOffline = () => { |
| 213 | /** | 233 | /** |
| 214 | * 获取车辆列表数据 | 234 | * 获取车辆列表数据 |
| 215 | */ | 235 | */ |
| 216 | -const fetchCarList = async (page = 1, append = false) => { | 236 | +const fetchCarList = async (page = 0, append = false) => { |
| 217 | loading.value = true | 237 | loading.value = true |
| 218 | 238 | ||
| 219 | try { | 239 | try { |
| 220 | - // 模拟API调用延迟 | 240 | + // 调用真实API获取车辆列表 |
| 221 | - await new Promise(resolve => setTimeout(resolve, 800)) | 241 | + const response = await getMyListingVehicleAPI({ page, limit: pageSize.value }) |
| 222 | 242 | ||
| 223 | - const mockData = generateMockCarData(page, pageSize.value) | 243 | + if (response.code === 1) { |
| 244 | + const { list, total } = response.data | ||
| 224 | 245 | ||
| 225 | - if (append) { | 246 | + if (append) { |
| 226 | - carList.value.push(...mockData) | 247 | + carList.value.push(...list) |
| 227 | - } else { | 248 | + } else { |
| 228 | - carList.value = mockData | 249 | + carList.value = list |
| 229 | - } | 250 | + } |
| 230 | 251 | ||
| 231 | - // 模拟分页逻辑 | 252 | + // 根据总数和当前数据量判断是否还有更多数据 |
| 232 | - if (page >= 3) { | 253 | + const currentTotal = append ? carList.value.length : list.length |
| 233 | - hasMore.value = false | 254 | + hasMore.value = currentTotal < total |
| 234 | - } | ||
| 235 | 255 | ||
| 236 | - currentPage.value = page | 256 | + currentPage.value = page |
| 257 | + } else { | ||
| 258 | + showToast(response.msg || '获取车辆列表失败', 'error') | ||
| 259 | + } | ||
| 237 | } catch (error) { | 260 | } catch (error) { |
| 238 | console.error('获取车辆列表失败:', error) | 261 | console.error('获取车辆列表失败:', error) |
| 239 | showToast('加载失败,请重试', 'error') | 262 | showToast('加载失败,请重试', 'error') |
| ... | @@ -267,57 +290,11 @@ const showToast = (message, type = 'success') => { | ... | @@ -267,57 +290,11 @@ const showToast = (message, type = 'success') => { |
| 267 | }) | 290 | }) |
| 268 | } | 291 | } |
| 269 | 292 | ||
| 270 | -/** | ||
| 271 | - * 生成模拟车辆数据 | ||
| 272 | - */ | ||
| 273 | -const generateMockCarData = (page = 1, size = 10) => { | ||
| 274 | - const brands = ['奔驰', '宝马', '奥迪', '大众', '丰田', '本田', '日产', '现代'] | ||
| 275 | - const models = ['C级', 'E级', 'S级', '3系', '5系', '7系', 'A4', 'A6', 'A8'] | ||
| 276 | - const conditions = ['准新车', '车况良好', '车况一般'] | ||
| 277 | - const images = [ | ||
| 278 | - 'https://images.unsplash.com/photo-1549924231-f129b911e442?w=400', | ||
| 279 | - 'https://images.unsplash.com/photo-1552519507-da3b142c6e3d?w=400', | ||
| 280 | - 'https://images.unsplash.com/photo-1494976388531-d1058494cdd8?w=400', | ||
| 281 | - 'https://images.unsplash.com/photo-1503376780353-7e6692767b70?w=400', | ||
| 282 | - 'https://images.unsplash.com/photo-1525609004556-c46c7d6cf023?w=400' | ||
| 283 | - ] | ||
| 284 | - | ||
| 285 | - const list = [] | ||
| 286 | - | ||
| 287 | - for (let i = 0; i < size; i++) { | ||
| 288 | - const index = (page - 1) * size + i | ||
| 289 | - const brand = brands[Math.floor(Math.random() * brands.length)] | ||
| 290 | - const model = models[Math.floor(Math.random() * models.length)] | ||
| 291 | - const condition = conditions[Math.floor(Math.random() * conditions.length)] | ||
| 292 | - const image = images[Math.floor(Math.random() * images.length)] | ||
| 293 | - const price = Math.floor(Math.random() * 20000) + 500 | ||
| 294 | - const marketPrice = Math.floor(price * 1.2) | ||
| 295 | - const year = 2018 + Math.floor(Math.random() * 6) | ||
| 296 | - const mileage = Math.floor(Math.random() * 1000) + 100 | ||
| 297 | - | ||
| 298 | - list.push({ | ||
| 299 | - id: `car_${index + 1}`, | ||
| 300 | - brand, | ||
| 301 | - model, | ||
| 302 | - year, | ||
| 303 | - condition, | ||
| 304 | - mileage, | ||
| 305 | - price, | ||
| 306 | - marketPrice, | ||
| 307 | - image, | ||
| 308 | - description: `${year}年${brand}${model},${condition},里程${mileage}公里`, | ||
| 309 | - isAuthenticated: Math.random() > 0.5, | ||
| 310 | - isOffline: Math.random() > 0.7, | ||
| 311 | - publishTime: new Date(Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000).toISOString() | ||
| 312 | - }) | ||
| 313 | - } | ||
| 314 | 293 | ||
| 315 | - return list | ||
| 316 | -} | ||
| 317 | 294 | ||
| 318 | // 页面加载时获取数据 | 295 | // 页面加载时获取数据 |
| 319 | -onMounted(() => { | 296 | +useDidShow(() => { |
| 320 | - fetchCarList(1, false) | 297 | + fetchCarList(0, false) |
| 321 | }) | 298 | }) |
| 322 | </script> | 299 | </script> |
| 323 | 300 | ... | ... |
| ... | @@ -274,7 +274,7 @@ | ... | @@ -274,7 +274,7 @@ |
| 274 | </nut-popup> | 274 | </nut-popup> |
| 275 | 275 | ||
| 276 | <!-- 品牌型号选择器组件 --> | 276 | <!-- 品牌型号选择器组件 --> |
| 277 | - <BrandModelPicker ref="brandModelPickerRef" @confirm="onBrandModelConfirm" @cancel="onBrandModelCancel" /> | 277 | + <BrandModelPicker ref="brandModelPickerRef" :brand-options="brandOptions" @confirm="onBrandModelConfirm" @cancel="onBrandModelCancel" /> |
| 278 | 278 | ||
| 279 | <!-- 年份选择 --> | 279 | <!-- 年份选择 --> |
| 280 | <nut-popup v-model:visible="yearPickerVisible" position="bottom"> | 280 | <nut-popup v-model:visible="yearPickerVisible" position="bottom"> |
| ... | @@ -416,39 +416,10 @@ const conditionValue = ref([]) | ... | @@ -416,39 +416,10 @@ const conditionValue = ref([]) |
| 416 | const brakeWearValue = ref([]) | 416 | const brakeWearValue = ref([]) |
| 417 | const tireWearValue = ref([]) | 417 | const tireWearValue = ref([]) |
| 418 | 418 | ||
| 419 | -// TODO: 模拟数据需要等接口 | ||
| 420 | // 选择器选项数据 | 419 | // 选择器选项数据 |
| 421 | -const schoolOptions = ref([ | 420 | +const schoolOptions = ref([]) |
| 422 | - { text: '上海理工大学', value: '上海理工大学' }, | 421 | +const brandOptions = ref([]) |
| 423 | - { text: '复旦大学', value: '复旦大学' }, | 422 | +const modelOptions = ref([]) |
| 424 | - { text: '上海交通大学', value: '上海交通大学' }, | ||
| 425 | - { text: '同济大学', value: '同济大学' }, | ||
| 426 | - { text: '华东师范大学', value: '华东师范大学' }, | ||
| 427 | - { text: '上海大学', value: '上海大学' }, | ||
| 428 | - { text: '东华大学', value: '东华大学' }, | ||
| 429 | - { text: '上海财经大学', value: '上海财经大学' } | ||
| 430 | -]) | ||
| 431 | - | ||
| 432 | -const brandOptions = ref([ | ||
| 433 | - { text: '小牛电动', value: '小牛电动' }, | ||
| 434 | - { text: '雅迪', value: '雅迪' }, | ||
| 435 | - { text: '爱玛', value: '爱玛' }, | ||
| 436 | - { text: '台铃', value: '台铃' }, | ||
| 437 | - { text: '绿源', value: '绿源' }, | ||
| 438 | - { text: '新日', value: '新日' }, | ||
| 439 | - { text: '立马', value: '立马' }, | ||
| 440 | - { text: '其他', value: '其他' } | ||
| 441 | -]) | ||
| 442 | - | ||
| 443 | -const modelOptions = ref([ | ||
| 444 | - { text: 'NGT', value: 'NGT' }, | ||
| 445 | - { text: 'UQi+', value: 'UQi+' }, | ||
| 446 | - { text: 'Gova G2', value: 'Gova G2' }, | ||
| 447 | - { text: 'MQi+', value: 'MQi+' }, | ||
| 448 | - { text: 'NQi GTS', value: 'NQi GTS' }, | ||
| 449 | - { text: 'RQi', value: 'RQi' }, | ||
| 450 | - { text: '其他型号', value: '其他型号' } | ||
| 451 | -]) | ||
| 452 | 423 | ||
| 453 | 424 | ||
| 454 | 425 | ||
| ... | @@ -636,9 +607,9 @@ const showTireWearPicker = () => { | ... | @@ -636,9 +607,9 @@ const showTireWearPicker = () => { |
| 636 | /** | 607 | /** |
| 637 | * 学校选择确认 | 608 | * 学校选择确认 |
| 638 | */ | 609 | */ |
| 639 | -const onSchoolConfirm = ({ selectedValue }) => { | 610 | +const onSchoolConfirm = ({ selectedValue, selectedOptions }) => { |
| 640 | - formData.school_id = selectedValue[0].id | 611 | + formData.school_id = selectedValue[0] |
| 641 | - formData.school_name = selectedValue[0].name | 612 | + formData.school_name = selectedOptions[0].text |
| 642 | schoolPickerVisible.value = false | 613 | schoolPickerVisible.value = false |
| 643 | } | 614 | } |
| 644 | 615 | ||
| ... | @@ -939,6 +910,42 @@ const loadCarData = async () => { | ... | @@ -939,6 +910,42 @@ const loadCarData = async () => { |
| 939 | } | 910 | } |
| 940 | } | 911 | } |
| 941 | 912 | ||
| 913 | +/** | ||
| 914 | + * 加载学校列表 | ||
| 915 | + */ | ||
| 916 | +const loadSchools = async () => { | ||
| 917 | + try { | ||
| 918 | + const { code, data } = await getSchoolsAPI() | ||
| 919 | + if (code && data) { | ||
| 920 | + schoolOptions.value = data.map(school => ({ | ||
| 921 | + text: school.name, | ||
| 922 | + value: school.id | ||
| 923 | + })) | ||
| 924 | + } | ||
| 925 | + } catch (error) { | ||
| 926 | + console.error('加载学校列表失败:', error) | ||
| 927 | + } | ||
| 928 | +} | ||
| 929 | + | ||
| 930 | +/** | ||
| 931 | + * 加载品牌型号列表 | ||
| 932 | + */ | ||
| 933 | +const loadBrandsModels = async () => { | ||
| 934 | + try { | ||
| 935 | + const { code, data } = await getBrandsModelsAPI() | ||
| 936 | + if (code && data) { | ||
| 937 | + // 转换品牌数据格式 | ||
| 938 | + brandOptions.value = data.map(brand => ({ | ||
| 939 | + text: brand.name, | ||
| 940 | + value: brand.id, | ||
| 941 | + models: brand.models || [] | ||
| 942 | + })) | ||
| 943 | + } | ||
| 944 | + } catch (error) { | ||
| 945 | + console.error('加载品牌型号列表失败:', error) | ||
| 946 | + } | ||
| 947 | +} | ||
| 948 | + | ||
| 942 | // 页面加载时执行 | 949 | // 页面加载时执行 |
| 943 | onMounted(async () => { | 950 | onMounted(async () => { |
| 944 | // 检查卖车权限 | 951 | // 检查卖车权限 |
| ... | @@ -947,6 +954,12 @@ onMounted(async () => { | ... | @@ -947,6 +954,12 @@ onMounted(async () => { |
| 947 | return | 954 | return |
| 948 | } | 955 | } |
| 949 | 956 | ||
| 957 | + // 加载基础数据 | ||
| 958 | + await Promise.all([ | ||
| 959 | + loadSchools(), | ||
| 960 | + loadBrandsModels() | ||
| 961 | + ]) | ||
| 962 | + | ||
| 950 | if (isEditMode.value) { | 963 | if (isEditMode.value) { |
| 951 | loadCarData() | 964 | loadCarData() |
| 952 | } | 965 | } | ... | ... |
-
Please register or login to post a comment