|
@@ -23,14 +23,14 @@
|
|
|
<view class="search-wrap">
|
|
<view class="search-wrap">
|
|
|
<uni-icons type="search" size="14" color="#999"></uni-icons>
|
|
<uni-icons type="search" size="14" color="#999"></uni-icons>
|
|
|
<input class="search-input" v-model="searchValue" placeholder="订单号/商户/宠主/手机号"
|
|
<input class="search-input" v-model="searchValue" placeholder="订单号/商户/宠主/手机号"
|
|
|
- placeholder-class="placeholder-style" />
|
|
|
|
|
|
|
+ placeholder-class="placeholder-style" @confirm="onSearch" />
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
|
|
|
|
|
<!-- 订单列表内容 -->
|
|
<!-- 订单列表内容 -->
|
|
|
<view class="list-container">
|
|
<view class="list-container">
|
|
|
- <view class="order-card" v-for="order in filteredOrders" :key="order.id" @click="goToDetail(order)">
|
|
|
|
|
|
|
+ <view class="order-card" v-for="order in orders" :key="order.id" @click="goToDetail(order)">
|
|
|
<!-- 头部:订单号与状态 -->
|
|
<!-- 头部:订单号与状态 -->
|
|
|
<view class="order-head">
|
|
<view class="order-head">
|
|
|
<text class="order-no">{{ order.id }}</text>
|
|
<text class="order-no">{{ order.id }}</text>
|
|
@@ -110,9 +110,14 @@
|
|
|
</view>
|
|
</view>
|
|
|
|
|
|
|
|
<!-- 空状态 -->
|
|
<!-- 空状态 -->
|
|
|
- <view class="empty-state" v-if="filteredOrders.length === 0">
|
|
|
|
|
|
|
+ <view class="empty-state" v-if="!loading && orders.length === 0">
|
|
|
<text class="empty-text">暂无相关订单</text>
|
|
<text class="empty-text">暂无相关订单</text>
|
|
|
</view>
|
|
</view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 加载状态 -->
|
|
|
|
|
+ <view class="loading-state" v-if="loading">
|
|
|
|
|
+ <text class="loading-text">加载中...</text>
|
|
|
|
|
+ </view>
|
|
|
</view>
|
|
</view>
|
|
|
|
|
|
|
|
<custom-tabbar></custom-tabbar>
|
|
<custom-tabbar></custom-tabbar>
|
|
@@ -120,18 +125,30 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup>
|
|
<script setup>
|
|
|
-import { ref, computed } from 'vue'
|
|
|
|
|
|
|
+import { ref, computed, onMounted } from 'vue'
|
|
|
import { onLoad } from '@dcloudio/uni-app'
|
|
import { onLoad } from '@dcloudio/uni-app'
|
|
|
import navBar from '@/components/nav-bar/index.vue'
|
|
import navBar from '@/components/nav-bar/index.vue'
|
|
|
import customTabbar from '@/components/custom-tabbar/index.vue'
|
|
import customTabbar from '@/components/custom-tabbar/index.vue'
|
|
|
-import orderMockData from '@/mock/order.json'
|
|
|
|
|
import orderStatusData from '@/json/orderStatus.json'
|
|
import orderStatusData from '@/json/orderStatus.json'
|
|
|
|
|
+import { listAll } from '@/api/service/list'
|
|
|
|
|
+import { listSubOrder, cancelSubOrder } from '@/api/order/subOrder'
|
|
|
|
|
+import { listAreaStation } from '@/api/system/areaStation'
|
|
|
|
|
+
|
|
|
|
|
+// 加载状态
|
|
|
|
|
+const loading = ref(false)
|
|
|
|
|
|
|
|
// 筛选与搜索
|
|
// 筛选与搜索
|
|
|
const activeStatus = ref(-1) // -1 表示全部,其他值为枚举值
|
|
const activeStatus = ref(-1) // -1 表示全部,其他值为枚举值
|
|
|
const filterType = ref(0)
|
|
const filterType = ref(0)
|
|
|
const searchValue = ref('')
|
|
const searchValue = ref('')
|
|
|
|
|
|
|
|
|
|
+// 分页参数
|
|
|
|
|
+const pagination = ref({
|
|
|
|
|
+ current: 1,
|
|
|
|
|
+ size: 10,
|
|
|
|
|
+ total: 0
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
// 从 orderStatus.json 生成 tabList
|
|
// 从 orderStatus.json 生成 tabList
|
|
|
const tabList = ref([
|
|
const tabList = ref([
|
|
|
{ title: '全部订单', value: -1 },
|
|
{ title: '全部订单', value: -1 },
|
|
@@ -142,25 +159,60 @@ const tabList = ref([
|
|
|
}))
|
|
}))
|
|
|
])
|
|
])
|
|
|
|
|
|
|
|
-const typeOptions = [
|
|
|
|
|
- { text: '全部类型', value: 0 },
|
|
|
|
|
- { text: '宠物接送', value: 1 },
|
|
|
|
|
- { text: '上门喂遛', value: 2 },
|
|
|
|
|
- { text: '上门洗护', value: 3 }
|
|
|
|
|
-]
|
|
|
|
|
-
|
|
|
|
|
-const currentTypeName = computed(() => {
|
|
|
|
|
- return typeOptions[filterType.value].text
|
|
|
|
|
-})
|
|
|
|
|
|
|
+const typeOptions = ref([{ text: '全部类型', value: 0 }])
|
|
|
|
|
+const serviceList = ref([])
|
|
|
|
|
+const areaStationList = ref([])
|
|
|
|
|
+const areaStationMap = ref({})
|
|
|
|
|
+
|
|
|
|
|
+// 加载服务类型列表
|
|
|
|
|
+const loadServiceTypes = async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const services = await listAll()
|
|
|
|
|
+ if (services && services.length > 0) {
|
|
|
|
|
+ serviceList.value = services
|
|
|
|
|
+ const serviceTypes = services.map((service, index) => ({
|
|
|
|
|
+ text: service.name,
|
|
|
|
|
+ value: index + 1,
|
|
|
|
|
+ id: service.id
|
|
|
|
|
+ }))
|
|
|
|
|
+ typeOptions.value = [
|
|
|
|
|
+ { text: '全部类型', value: 0 },
|
|
|
|
|
+ ...serviceTypes
|
|
|
|
|
+ ]
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('加载服务类型失败:', error)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-// 从 URL 参数初始化状态
|
|
|
|
|
-onLoad((options) => {
|
|
|
|
|
- if (options.status !== undefined) {
|
|
|
|
|
- const statusValue = parseInt(options.status)
|
|
|
|
|
- if (!isNaN(statusValue)) {
|
|
|
|
|
- activeStatus.value = statusValue
|
|
|
|
|
|
|
+// 加载区域站点列表
|
|
|
|
|
+const loadAreaStations = async () => {
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await listAreaStation()
|
|
|
|
|
+ if (res && res.data) {
|
|
|
|
|
+ areaStationList.value = res.data
|
|
|
|
|
+ const map = {}
|
|
|
|
|
+ for (const item of res.data) {
|
|
|
|
|
+ if (item && item.id !== undefined && item.id !== null) {
|
|
|
|
|
+ map[item.id] = item
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ areaStationMap.value = map
|
|
|
}
|
|
}
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('加载区域站点失败:', error)
|
|
|
}
|
|
}
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+onMounted(() => {
|
|
|
|
|
+ loadServiceTypes()
|
|
|
|
|
+ loadAreaStations()
|
|
|
|
|
+ loadOrders()
|
|
|
|
|
+})
|
|
|
|
|
+
|
|
|
|
|
+const currentTypeName = computed(() => {
|
|
|
|
|
+ const option = typeOptions.value.find(opt => opt.value === filterType.value)
|
|
|
|
|
+ return option ? option.text : '全部类型'
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
// 根据枚举值获取状态信息
|
|
// 根据枚举值获取状态信息
|
|
@@ -168,62 +220,159 @@ const getStatusInfo = (value) => {
|
|
|
return orderStatusData.find(item => item.value === value)
|
|
return orderStatusData.find(item => item.value === value)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 根据服务ID获取服务名称
|
|
|
|
|
+const getServiceName = (serviceId) => {
|
|
|
|
|
+ const service = serviceList.value.find(s => s.id === serviceId)
|
|
|
|
|
+ return service ? service.name : '未知服务'
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 获取城市/区域文本
|
|
|
|
|
+const getCityDistrictText = (row) => {
|
|
|
|
|
+ if (!row || !row.site) return ''
|
|
|
|
|
+ const station = areaStationMap.value[row.site]
|
|
|
|
|
+ if (!station) return ''
|
|
|
|
|
+
|
|
|
|
|
+ const parent = station.parentId ? areaStationMap.value[station.parentId] : undefined
|
|
|
|
|
+ if (!parent) return station.name || ''
|
|
|
|
|
+
|
|
|
|
|
+ if (parent.type === 0) return parent.name || ''
|
|
|
|
|
+ if (parent.type === 1) {
|
|
|
|
|
+ const city = parent.parentId ? areaStationMap.value[parent.parentId] : undefined
|
|
|
|
|
+ return `${city?.name || ''}/${parent.name || ''}`
|
|
|
|
|
+ }
|
|
|
|
|
+ return parent.name || ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 获取服务模式标签
|
|
|
|
|
+const getServiceModeTag = (row) => {
|
|
|
|
|
+ const t = row?.type
|
|
|
|
|
+ if (t === 0 || t === '0' || t === 1 || t === '1') return '往返'
|
|
|
|
|
+ return ''
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 获取服务订单类型标签
|
|
|
|
|
+const getServiceOrderTypeTag = (row) => {
|
|
|
|
|
+ const t = row?.type
|
|
|
|
|
+ if (t === 0 || t === '0') return { label: '接', type: 'blue' }
|
|
|
|
|
+ if (t === 1 || t === '1') return { label: '送', type: 'green' }
|
|
|
|
|
+ if (t === 2 || t === '2') return { label: '单程接', type: 'blue' }
|
|
|
|
|
+ if (t === 3 || t === '3') return { label: '单程送', type: 'green' }
|
|
|
|
|
+ return null
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
const onTabClick = (value) => {
|
|
const onTabClick = (value) => {
|
|
|
activeStatus.value = value
|
|
activeStatus.value = value
|
|
|
|
|
+ pagination.value.current = 1
|
|
|
|
|
+ loadOrders()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const onTypeChange = (e) => {
|
|
const onTypeChange = (e) => {
|
|
|
- filterType.value = Number(e.detail.value)
|
|
|
|
|
-}
|
|
|
|
|
|
|
+ const index = Number(e.detail.value)
|
|
|
|
|
+ filterType.value = index
|
|
|
|
|
+ pagination.value.current = 1
|
|
|
|
|
+ loadOrders()
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 订单列表数据
|
|
|
|
|
+const orders = ref([])
|
|
|
|
|
+
|
|
|
|
|
+// 加载订单列表
|
|
|
|
|
+const loadOrders = async () => {
|
|
|
|
|
+ loading.value = true
|
|
|
|
|
+ try {
|
|
|
|
|
+ const selectedType = typeOptions.value.find(opt => opt.value === filterType.value)
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ pageNum: pagination.value.current,
|
|
|
|
|
+ pageSize: pagination.value.size,
|
|
|
|
|
+ status: activeStatus.value !== -1 ? activeStatus.value : undefined,
|
|
|
|
|
+ service: selectedType && selectedType.id ? selectedType.id : undefined,
|
|
|
|
|
+ content: searchValue.value || undefined
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
-// 搜索与过滤后的订单列表
|
|
|
|
|
-const filteredOrders = computed(() => {
|
|
|
|
|
- return orders.value.filter(order => {
|
|
|
|
|
- let statusMatch = true
|
|
|
|
|
- if (activeStatus.value !== -1) {
|
|
|
|
|
- const statusInfo = getStatusInfo(activeStatus.value)
|
|
|
|
|
- statusMatch = statusInfo && order.statusText === statusInfo.label
|
|
|
|
|
|
|
+ const res = await listSubOrder(params)
|
|
|
|
|
+ console.log('后端返回数据:', res)
|
|
|
|
|
+ if (res) {
|
|
|
|
|
+ const rows = res.rows || []
|
|
|
|
|
+ console.log('rows:', rows)
|
|
|
|
|
+ orders.value = rows.map(row => transformOrder(row))
|
|
|
|
|
+ console.log('转换后的orders:', orders.value)
|
|
|
|
|
+ pagination.value.total = res.total || 0
|
|
|
}
|
|
}
|
|
|
- const typeMap = { 1: '宠物接送', 2: '上门喂遛', 3: '上门洗护' }
|
|
|
|
|
- const typeMatch = filterType.value === 0 || order.serviceType === typeMap[filterType.value]
|
|
|
|
|
- const searchLower = searchValue.value.toLowerCase()
|
|
|
|
|
- const searchMatch = !searchValue.value ||
|
|
|
|
|
- order.id.toLowerCase().includes(searchLower) ||
|
|
|
|
|
- order.userName.toLowerCase().includes(searchLower) ||
|
|
|
|
|
- order.petName.toLowerCase().includes(searchLower) ||
|
|
|
|
|
- order.userPhone.includes(searchLower)
|
|
|
|
|
- return statusMatch && typeMatch && searchMatch
|
|
|
|
|
- })
|
|
|
|
|
-})
|
|
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('加载订单列表失败:', error)
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
-const orders = ref(orderMockData)
|
|
|
|
|
|
|
+// 转换订单数据格式
|
|
|
|
|
+const transformOrder = (row) => {
|
|
|
|
|
+ const statusInfo = getStatusInfo(row.status)
|
|
|
|
|
+ const serviceName = getServiceName(row.service)
|
|
|
|
|
+ const modeTag = getServiceModeTag(row)
|
|
|
|
|
+ const typeTag = getServiceOrderTypeTag(row)
|
|
|
|
|
+
|
|
|
|
|
+ const serviceTags = []
|
|
|
|
|
+ if (modeTag) serviceTags.push(modeTag)
|
|
|
|
|
+ if (typeTag) serviceTags.push(typeTag.label)
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ // 先展开原始字段,后面的手动赋值具有更高优先级
|
|
|
|
|
+ ...row,
|
|
|
|
|
+ // 显示用的单号(优先用业务编号 code,否则用数据库 ID)
|
|
|
|
|
+ id: row.code || row.id,
|
|
|
|
|
+ rawId: row.id,
|
|
|
|
|
+ serviceType: serviceName,
|
|
|
|
|
+ serviceTags: serviceTags,
|
|
|
|
|
+ petName: row.petName || '未知',
|
|
|
|
|
+ petBreed: row.petBreed || '未知',
|
|
|
|
|
+ userName: row.customerName || '未知',
|
|
|
|
|
+ address: row.toAddress || row.fromAddress || getCityDistrictText(row),
|
|
|
|
|
+ shopName: row.storeName || '未知',
|
|
|
|
|
+ userPhone: row.contactPhoneNumber || '',
|
|
|
|
|
+ bookTime: row.serviceTime || '',
|
|
|
|
|
+ createTime: row.createTime || '',
|
|
|
|
|
+ statusText: statusInfo ? statusInfo.label : '未知',
|
|
|
|
|
+ statusClass: statusInfo ? `text-${statusInfo.color.replace('#', '')}` : 'text-gray',
|
|
|
|
|
+ assigneeName: row.fulfillerName || '',
|
|
|
|
|
+ cancelTime: row.cancelTime || ''
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 搜索订单
|
|
|
|
|
+const onSearch = () => {
|
|
|
|
|
+ pagination.value.current = 1
|
|
|
|
|
+ loadOrders()
|
|
|
|
|
+}
|
|
|
|
|
|
|
|
|
|
+// 取消订单
|
|
|
const onCancelOrder = (order) => {
|
|
const onCancelOrder = (order) => {
|
|
|
uni.showModal({
|
|
uni.showModal({
|
|
|
title: '提示',
|
|
title: '提示',
|
|
|
content: `确定要取消订单 [${order.id}] 吗?`,
|
|
content: `确定要取消订单 [${order.id}] 吗?`,
|
|
|
- success: (res) => {
|
|
|
|
|
|
|
+ success: async (res) => {
|
|
|
if (res.confirm) {
|
|
if (res.confirm) {
|
|
|
- uni.showToast({ title: '订单已取消', icon: 'success' })
|
|
|
|
|
- order.statusText = '已取消'
|
|
|
|
|
- order.statusClass = 'text-gray'
|
|
|
|
|
- activeStatus.value = 5
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ await cancelSubOrder({ orderId: order.rawId })
|
|
|
|
|
+ uni.showToast({ title: '订单已取消', icon: 'success' })
|
|
|
|
|
+ loadOrders()
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('取消订单失败:', error)
|
|
|
|
|
+ uni.showToast({ title: '取消失败', icon: 'none' })
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 跳转到订单详情
|
|
|
const goToDetail = (order) => {
|
|
const goToDetail = (order) => {
|
|
|
- const serviceKey = order.serviceType === '宠物接送' ? 'transport' : (order.serviceType === '上门喂遛' ? 'feed' : 'wash')
|
|
|
|
|
- // 根据 statusText 查找对应的枚举值
|
|
|
|
|
- const statusInfo = orderStatusData.find(item => item.label === order.statusText)
|
|
|
|
|
- const statusValue = statusInfo ? statusInfo.value : 3
|
|
|
|
|
- const cancelTime = order.cancelTime ? encodeURIComponent(order.cancelTime) : ''
|
|
|
|
|
uni.navigateTo({
|
|
uni.navigateTo({
|
|
|
- url: `/pages/order/detail/index?service=${serviceKey}&status=${statusValue}${cancelTime ? '&cancelTime=' + cancelTime : ''}`
|
|
|
|
|
|
|
+ url: `/pages/order/detail/index?id=${order.rawId}`
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// 投诉
|
|
|
const onComplaint = (order) => {
|
|
const onComplaint = (order) => {
|
|
|
uni.navigateTo({
|
|
uni.navigateTo({
|
|
|
url: `/pages/my/complaint-submit/index?orderId=${order.id}`
|
|
url: `/pages/my/complaint-submit/index?orderId=${order.id}`
|
|
@@ -550,4 +699,14 @@ const onComplaint = (order) => {
|
|
|
font-size: 28rpx;
|
|
font-size: 28rpx;
|
|
|
color: #999;
|
|
color: #999;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+.loading-state {
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ padding: 100rpx 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.loading-text {
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ color: #999;
|
|
|
|
|
+}
|
|
|
</style>
|
|
</style>
|