feat: 订单列表接口对接
This commit is contained in:
BIN
pages/order/components/CustomEmpty/images/empty.png
Normal file
BIN
pages/order/components/CustomEmpty/images/empty.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
26
pages/order/components/CustomEmpty/index.vue
Normal file
26
pages/order/components/CustomEmpty/index.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
<template>
|
||||
<view class="empty-container">
|
||||
<image
|
||||
class="empty-image"
|
||||
mode="aspectFit"
|
||||
src="./images/empty.png"
|
||||
></image>
|
||||
<text class="empty-text">{{ statusText }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { defineProps } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
statusText: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
19
pages/order/components/CustomEmpty/styles/index.scss
Normal file
19
pages/order/components/CustomEmpty/styles/index.scss
Normal file
@@ -0,0 +1,19 @@
|
||||
.empty-container {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.empty-image {
|
||||
height: 130px;
|
||||
width: 130px;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
margin-top: 10px;
|
||||
font-size: 14px;
|
||||
color: #666666;
|
||||
}
|
||||
BIN
pages/order/components/CustomNoMore/images/no_more.png
Normal file
BIN
pages/order/components/CustomNoMore/images/no_more.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
14
pages/order/components/CustomNoMore/index.vue
Normal file
14
pages/order/components/CustomNoMore/index.vue
Normal file
@@ -0,0 +1,14 @@
|
||||
<template>
|
||||
<view class="nomore">
|
||||
<image
|
||||
class="nomore-image"
|
||||
mode="aspectFit"
|
||||
src="./images/no_more.png"
|
||||
></image>
|
||||
<text class="nomore-text">已经到达宇宙尽头啦~</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
17
pages/order/components/CustomNoMore/styles/index.scss
Normal file
17
pages/order/components/CustomNoMore/styles/index.scss
Normal file
@@ -0,0 +1,17 @@
|
||||
.nomore {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 10px 0;
|
||||
}
|
||||
.nomore-image {
|
||||
width: 100px;
|
||||
height: 65px;
|
||||
}
|
||||
.nomore-text {
|
||||
margin-top: 5px;
|
||||
font-size: 12px;
|
||||
color: #222963;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 97 KiB |
39
pages/order/components/CustomRefresher/index.vue
Normal file
39
pages/order/components/CustomRefresher/index.vue
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
<!-- z-paging自定义的下拉刷新view -->
|
||||
<template>
|
||||
<view class="refresher-container">
|
||||
<image
|
||||
class="refresher-image"
|
||||
mode="aspectFit"
|
||||
src="./images/refresher_loading.gif"
|
||||
></image>
|
||||
<text class="refresher-text">{{ statusText }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
status: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
|
||||
const statusText = computed(() => {
|
||||
// 这里可以做i18n国际化相关操作,可以通过uni.getLocale()获取当前语言(具体操作见i18n-demo.vue);
|
||||
// 获取到当前语言之后,就可以自定义不同语言下的展示内容了
|
||||
const statusTextMap = {
|
||||
default: "哎呀,用点力继续下拉!",
|
||||
"release-to-refresh": "拉疼我啦,松手刷新~~",
|
||||
loading: "正在努力刷新中...",
|
||||
complete: "刷新成功啦~",
|
||||
};
|
||||
return statusTextMap[this.status];
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
21
pages/order/components/CustomRefresher/styles/index.scss
Normal file
21
pages/order/components/CustomRefresher/styles/index.scss
Normal file
@@ -0,0 +1,21 @@
|
||||
.refresher-container {
|
||||
/* #ifndef APP-NVUE */
|
||||
display: flex;
|
||||
/* #endif */
|
||||
height: 150rpx;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.refresher-image {
|
||||
margin-top: 10rpx;
|
||||
height: 45px;
|
||||
width: 45px;
|
||||
}
|
||||
|
||||
.refresher-text {
|
||||
margin-top: 10rpx;
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
}
|
||||
@@ -1,322 +0,0 @@
|
||||
<template>
|
||||
<view class="demo-container">
|
||||
<view class="demo-header">
|
||||
<text class="demo-title">OrderList组件演示</text>
|
||||
<text class="demo-subtitle">集成z-paging组件,支持虚拟列表、下拉刷新、上拉加载更多</text>
|
||||
</view>
|
||||
|
||||
<!-- 功能控制区 -->
|
||||
<view class="control-section">
|
||||
<view class="control-row">
|
||||
<button class="control-btn" @click="toggleVirtualList">
|
||||
{{ useVirtualList ? '关闭' : '开启' }}虚拟列表
|
||||
</button>
|
||||
<button class="control-btn" @click="toggleEmptyState">
|
||||
{{ showEmpty ? '显示数据' : '显示空状态' }}
|
||||
</button>
|
||||
</view>
|
||||
<view class="control-row">
|
||||
<button class="control-btn" @click="addMoreData">
|
||||
添加更多数据
|
||||
</button>
|
||||
<button class="control-btn" @click="clearData">
|
||||
清空数据
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- OrderList组件演示 -->
|
||||
<view class="demo-list">
|
||||
<OrderList
|
||||
:orderList="orderList"
|
||||
:hasMore="hasMore"
|
||||
:isLoading="isLoading"
|
||||
:currentTab="currentTab"
|
||||
:emptyText="emptyText"
|
||||
:useVirtualList="useVirtualList"
|
||||
:virtualListHeight="'500px'"
|
||||
:cellHeightMode="cellHeightMode"
|
||||
:fixedHeight="120"
|
||||
@refresh="handleRefresh"
|
||||
@loadMore="handleLoadMore"
|
||||
@orderClick="handleOrderClick"
|
||||
@orderCall="handleOrderCall"
|
||||
@orderComplete="handleOrderComplete"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 功能说明 -->
|
||||
<view class="feature-section">
|
||||
<text class="feature-title">新功能特性:</text>
|
||||
<view class="feature-list">
|
||||
<text class="feature-item">✅ 集成z-paging组件</text>
|
||||
<text class="feature-item">✅ 支持虚拟列表,提升大数据渲染性能</text>
|
||||
<text class="feature-item">✅ 自定义下拉刷新样式和文案</text>
|
||||
<text class="feature-item">✅ 自定义上拉加载更多样式和文案</text>
|
||||
<text class="feature-item">✅ 自动管理空数据状态</text>
|
||||
<text class="feature-item">✅ 支持固定高度和自适应高度模式</text>
|
||||
<text class="feature-item">✅ 完整的事件回调机制</text>
|
||||
<text class="feature-item">✅ 响应式设计,适配各种屏幕</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
import OrderList from './index.vue'
|
||||
|
||||
// 响应式数据
|
||||
const orderList = ref([])
|
||||
const hasMore = ref(true)
|
||||
const isLoading = ref(false)
|
||||
const currentTab = ref('all')
|
||||
const useVirtualList = ref(true)
|
||||
const cellHeightMode = ref('auto')
|
||||
const showEmpty = ref(false)
|
||||
|
||||
// 计算属性
|
||||
const emptyText = computed(() => {
|
||||
return showEmpty.value ? '暂无数据,点击刷新重试' : '暂无工单数据'
|
||||
})
|
||||
|
||||
// 模拟数据
|
||||
const generateMockData = (count = 10, startId = 1) => {
|
||||
const data = []
|
||||
for (let i = 0; i < count; i++) {
|
||||
data.push({
|
||||
id: `${startId + i}`,
|
||||
title: `工单标题 ${startId + i} - ${['空调维修', '水管漏水', '电路故障', '网络异常', '设备更换'][i % 5]}`,
|
||||
createTime: new Date(Date.now() - Math.random() * 7 * 24 * 60 * 60 * 1000).toLocaleString(),
|
||||
contactName: ['张先生', '李女士', '王先生', '赵女士', '刘先生'][i % 5],
|
||||
contactPhone: `138****${String(Math.floor(Math.random() * 10000)).padStart(4, '0')}`,
|
||||
status: ['pending', 'processing', 'completed'][i % 3],
|
||||
type: 'service'
|
||||
})
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// 初始化数据
|
||||
const initData = () => {
|
||||
orderList.value = generateMockData(20)
|
||||
}
|
||||
|
||||
// 切换虚拟列表
|
||||
const toggleVirtualList = () => {
|
||||
useVirtualList.value = !useVirtualList.value
|
||||
uni.showToast({
|
||||
title: `虚拟列表已${useVirtualList.value ? '开启' : '关闭'}`,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
// 切换空状态
|
||||
const toggleEmptyState = () => {
|
||||
showEmpty.value = !showEmpty.value
|
||||
if (showEmpty.value) {
|
||||
orderList.value = []
|
||||
hasMore.value = false
|
||||
} else {
|
||||
initData()
|
||||
hasMore.value = true
|
||||
}
|
||||
}
|
||||
|
||||
// 添加更多数据
|
||||
const addMoreData = () => {
|
||||
const newData = generateMockData(10, orderList.value.length + 1)
|
||||
orderList.value.push(...newData)
|
||||
uni.showToast({
|
||||
title: '已添加10条数据',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
|
||||
// 清空数据
|
||||
const clearData = () => {
|
||||
orderList.value = []
|
||||
hasMore.value = false
|
||||
uni.showToast({
|
||||
title: '数据已清空',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
// 下拉刷新
|
||||
const handleRefresh = async () => {
|
||||
console.log('下拉刷新')
|
||||
isLoading.value = true
|
||||
|
||||
// 模拟网络请求
|
||||
await new Promise(resolve => setTimeout(resolve, 1500))
|
||||
|
||||
// 重新加载数据
|
||||
orderList.value = generateMockData(15)
|
||||
hasMore.value = true
|
||||
isLoading.value = false
|
||||
|
||||
uni.showToast({
|
||||
title: '刷新成功',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
|
||||
// 上拉加载更多
|
||||
const handleLoadMore = async () => {
|
||||
console.log('上拉加载更多')
|
||||
|
||||
if (!hasMore.value) return
|
||||
|
||||
// 模拟网络请求
|
||||
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||
|
||||
// 添加新数据
|
||||
const newData = generateMockData(10, orderList.value.length + 1)
|
||||
orderList.value.push(...newData)
|
||||
|
||||
// 模拟没有更多数据
|
||||
if (orderList.value.length >= 50) {
|
||||
hasMore.value = false
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: `加载了${newData.length}条数据`,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
// 工单点击
|
||||
const handleOrderClick = (orderData) => {
|
||||
console.log('点击工单:', orderData)
|
||||
uni.showToast({
|
||||
title: `点击了工单: ${orderData.title}`,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
// 工单呼叫
|
||||
const handleOrderCall = (orderData) => {
|
||||
console.log('呼叫工单:', orderData)
|
||||
uni.showToast({
|
||||
title: `呼叫: ${orderData.contactName}`,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
// 工单完成
|
||||
const handleOrderComplete = (orderData) => {
|
||||
console.log('完成工单:', orderData)
|
||||
// 更新状态
|
||||
const index = orderList.value.findIndex(item => item.id === orderData.id)
|
||||
if (index !== -1) {
|
||||
orderList.value[index].status = 'completed'
|
||||
}
|
||||
uni.showToast({
|
||||
title: '工单已标记为完成',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
|
||||
// 初始化
|
||||
initData()
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.demo-container {
|
||||
padding: 20rpx;
|
||||
background-color: #f5f5f5;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.demo-header {
|
||||
text-align: center;
|
||||
margin-bottom: 40rpx;
|
||||
|
||||
.demo-title {
|
||||
display: block;
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.demo-subtitle {
|
||||
display: block;
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
.control-section {
|
||||
background: white;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.control-row {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.control-btn {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
background: linear-gradient(135deg, #007aff 0%, #0056cc 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 12rpx;
|
||||
font-size: 26rpx;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
background: linear-gradient(135deg, #0056cc 0%, #003d99 100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.demo-list {
|
||||
height: 500px;
|
||||
background: white;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.feature-section {
|
||||
background: white;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.feature-title {
|
||||
display: block;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.feature-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.feature-item {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
padding-left: 10rpx;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,265 +0,0 @@
|
||||
<template>
|
||||
<view class="order-list-container">
|
||||
<!-- z-paging组件 -->
|
||||
<z-paging
|
||||
ref="paging"
|
||||
v-model="dataList"
|
||||
:refresher-enabled="true"
|
||||
:refresher-threshold="45"
|
||||
refresher-default-text="下拉刷新"
|
||||
refresher-pulling-text="下拉刷新"
|
||||
refresher-refreshing-text="正在刷新..."
|
||||
refresher-complete-text="刷新完成"
|
||||
:loading-more-enabled="true"
|
||||
loading-more-default-text="点击加载更多"
|
||||
loading-more-loading-text="正在加载..."
|
||||
loading-more-no-more-text="没有更多了"
|
||||
loading-more-fail-text="加载失败,点击重试"
|
||||
:empty-view-text="emptyText"
|
||||
:empty-view-img="emptyIcon"
|
||||
:auto="false"
|
||||
:use-virtual-list="false"
|
||||
:virtual-list-height="virtualListHeight"
|
||||
:cell-height-mode="cellHeightMode"
|
||||
:fixed-height="fixedHeight"
|
||||
:safe-area-inset-top="true"
|
||||
:use-page-scroll="true"
|
||||
:top-offset="120"
|
||||
@query="queryList"
|
||||
@emptyViewReload="handleEmptyReload"
|
||||
>
|
||||
<!-- 非虚拟列表模式下的数据渲染 -->
|
||||
<view class="order-list-content">
|
||||
<OrderCard
|
||||
v-for="(item, index) in currentDataList"
|
||||
:key="item.id || index"
|
||||
:orderData="item"
|
||||
@click="handleOrderClick"
|
||||
@call="handleOrderCall"
|
||||
@complete="handleOrderComplete"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<!-- 虚拟列表模式下的数据渲染 -->
|
||||
<template #cell="{ item }" v-if="useVirtualList">
|
||||
<OrderCard
|
||||
:orderData="item"
|
||||
@click="handleOrderClick"
|
||||
@call="handleOrderCall"
|
||||
@complete="handleOrderComplete"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- 自定义空状态 -->
|
||||
<template #empty v-if="customEmptyView">
|
||||
<view class="custom-empty">
|
||||
<image :src="emptyIcon" class="empty-icon" />
|
||||
<text class="empty-text">{{ emptyText }}</text>
|
||||
<button
|
||||
class="refresh-btn"
|
||||
@click="handleEmptyReload"
|
||||
v-if="showRefreshBtn"
|
||||
>
|
||||
刷新重试
|
||||
</button>
|
||||
</view>
|
||||
</template>
|
||||
</z-paging>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, defineProps, watch, onMounted, computed, nextTick } from "vue";
|
||||
import OrderCard from "../OrderCard/index.vue";
|
||||
|
||||
// Props
|
||||
const props = defineProps({
|
||||
// 工单数据列表
|
||||
orderList: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
// 是否有更多数据
|
||||
hasMore: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 是否正在加载
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
// 空状态文案
|
||||
emptyText: {
|
||||
type: String,
|
||||
default: "暂无工单数据",
|
||||
},
|
||||
// 空状态图标
|
||||
emptyIcon: {
|
||||
type: String,
|
||||
default: "/static/images/empty.png",
|
||||
},
|
||||
// 是否显示刷新按钮
|
||||
showRefreshBtn: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 当前Tab类型
|
||||
currentTab: {
|
||||
type: String,
|
||||
default: "all",
|
||||
},
|
||||
// 是否启用虚拟列表
|
||||
useVirtualList: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
// 虚拟列表高度
|
||||
virtualListHeight: {
|
||||
type: [String, Number],
|
||||
default: "100%",
|
||||
},
|
||||
// 单元格高度模式
|
||||
cellHeightMode: {
|
||||
type: String,
|
||||
default: "auto", // auto | fixed
|
||||
},
|
||||
// 固定高度(当cellHeightMode为fixed时使用)
|
||||
fixedHeight: {
|
||||
type: Number,
|
||||
default: 120,
|
||||
},
|
||||
// 是否使用自定义空状态
|
||||
customEmptyView: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
// Emits
|
||||
const emit = defineEmits([
|
||||
"refresh",
|
||||
"loadMore",
|
||||
"orderClick",
|
||||
"orderCall",
|
||||
"orderComplete",
|
||||
]);
|
||||
|
||||
// 响应式数据
|
||||
const paging = ref(null);
|
||||
const dataList = ref([]);
|
||||
const pageNum = ref(1);
|
||||
const pageSize = ref(10);
|
||||
|
||||
// 计算属性
|
||||
const currentDataList = computed(() => {
|
||||
return props.orderList || [];
|
||||
});
|
||||
|
||||
// 查询列表数据
|
||||
const queryList = async (pageNo, pageSize, from) => {
|
||||
console.log("z-paging查询:", { pageNo, pageSize, from });
|
||||
|
||||
try {
|
||||
// 触发父组件的数据加载事件
|
||||
if (pageNo === 1) {
|
||||
// 下拉刷新
|
||||
emit("refresh");
|
||||
} else {
|
||||
// 上拉加载更多
|
||||
emit("loadMore");
|
||||
}
|
||||
|
||||
// 等待数据更新
|
||||
await nextTick();
|
||||
|
||||
// 直接使用当前的orderList数据
|
||||
const currentData = props.orderList || [];
|
||||
|
||||
// 在非虚拟列表模式下,z-paging主要用于下拉刷新和上拉加载
|
||||
// 数据渲染通过模板中的v-for完成
|
||||
paging.value?.complete(currentData, !props.hasMore);
|
||||
|
||||
} catch (error) {
|
||||
console.error("查询列表失败:", error);
|
||||
paging.value?.complete(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理空状态重新加载
|
||||
const handleEmptyReload = () => {
|
||||
console.log("空状态重新加载");
|
||||
paging.value?.reload();
|
||||
};
|
||||
|
||||
// 处理工单点击
|
||||
const handleOrderClick = (orderData) => {
|
||||
emit("orderClick", orderData);
|
||||
};
|
||||
|
||||
// 处理工单呼叫
|
||||
const handleOrderCall = (orderData) => {
|
||||
emit("orderCall", orderData);
|
||||
};
|
||||
|
||||
// 处理工单完成
|
||||
const handleOrderComplete = (orderData) => {
|
||||
emit("orderComplete", orderData);
|
||||
};
|
||||
|
||||
// 监听orderList变化,更新z-paging数据
|
||||
watch(
|
||||
() => props.orderList,
|
||||
(newList) => {
|
||||
if (newList && newList.length >= 0) {
|
||||
dataList.value = [...newList];
|
||||
// 在非虚拟列表模式下,主要是通知z-paging数据已更新
|
||||
if (paging.value) {
|
||||
paging.value.complete(newList, !props.hasMore);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
|
||||
// 监听Tab切换,重新加载数据
|
||||
watch(
|
||||
() => props.currentTab,
|
||||
() => {
|
||||
nextTick(() => {
|
||||
paging.value?.reload();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// 组件挂载后初始化
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
// 初始化数据
|
||||
if (currentDataList.value.length > 0) {
|
||||
dataList.value = [...currentDataList.value];
|
||||
// 手动触发z-paging的数据更新
|
||||
if (paging.value) {
|
||||
paging.value.complete(currentDataList.value, !props.hasMore);
|
||||
}
|
||||
} else {
|
||||
// 如果没有初始数据,触发第一次查询
|
||||
if (paging.value) {
|
||||
paging.value.reload();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 暴露方法
|
||||
defineExpose({
|
||||
reload: () => paging.value?.reload(),
|
||||
refresh: () => paging.value?.reload(),
|
||||
complete: (data, noMore) => paging.value?.complete(data, noMore),
|
||||
getPaging: () => paging.value,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import "./styles/index.scss";
|
||||
</style>
|
||||
@@ -1,298 +0,0 @@
|
||||
.order-list-container {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding-top: 120rpx; /* 为固定导航栏留出空间 */
|
||||
|
||||
.z-paging-container {
|
||||
width: 100%;
|
||||
min-height: calc(100vh - 120rpx);
|
||||
}
|
||||
|
||||
// z-paging内部列表项样式
|
||||
:deep(.z-paging-content) {
|
||||
padding: 0 32rpx;
|
||||
|
||||
.order-card {
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 非虚拟列表内容区域样式
|
||||
.order-list-content {
|
||||
padding: 0 32rpx;
|
||||
|
||||
.order-card {
|
||||
margin-bottom: 24rpx;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 空状态样式(z-paging内置)
|
||||
:deep(.z-paging-empty-view) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 60rpx;
|
||||
text-align: center;
|
||||
|
||||
.z-paging-empty-view-img {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 40rpx;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.z-paging-empty-view-text {
|
||||
font-size: 28rpx;
|
||||
color: #999999;
|
||||
margin-bottom: 40rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.z-paging-empty-view-reload-btn {
|
||||
padding: 20rpx 40rpx;
|
||||
background-color: #007aff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 12rpx;
|
||||
font-size: 28rpx;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
background-color: #0056cc;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 自定义空状态样式
|
||||
.custom-empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 60rpx;
|
||||
text-align: center;
|
||||
|
||||
.empty-icon {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
margin-bottom: 40rpx;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999999;
|
||||
margin-bottom: 40rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
padding: 20rpx 40rpx;
|
||||
background-color: #007aff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 12rpx;
|
||||
font-size: 28rpx;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
background-color: #0056cc;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// z-paging加载更多样式
|
||||
:deep(.z-paging-load-more) {
|
||||
padding: 40rpx 0;
|
||||
text-align: center;
|
||||
|
||||
.z-paging-load-more-line {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 20rpx;
|
||||
|
||||
.z-paging-load-more-loading {
|
||||
width: 32rpx;
|
||||
height: 32rpx;
|
||||
border: 4rpx solid #e5e5e5;
|
||||
border-top: 4rpx solid #007aff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.z-paging-load-more-text {
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
|
||||
.z-paging-load-more-no-more-line {
|
||||
.z-paging-load-more-text {
|
||||
font-size: 26rpx;
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// z-paging刷新器样式
|
||||
:deep(.z-paging-refresh) {
|
||||
.z-paging-refresh-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20rpx;
|
||||
|
||||
.z-paging-refresh-loading {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
border: 4rpx solid #e5e5e5;
|
||||
border-top: 4rpx solid #007aff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.z-paging-refresh-text {
|
||||
font-size: 26rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 下拉刷新样式优化 */
|
||||
:deep(.uni-scroll-view-refresher) {
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
/* 滚动条样式 */
|
||||
.scroll-area::-webkit-scrollbar {
|
||||
width: 0;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 375px) {
|
||||
.order-list {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
padding: 60px 16px;
|
||||
min-height: 50vh;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 15px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
padding: 8px 20px;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 暗色模式支持 */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.order-list-container {
|
||||
background: linear-gradient(180deg, #1a1a1a 0%, #2d2d2d 50%, #404040 100%);
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
.no-more-text {
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
border-color: #404040;
|
||||
border-top-color: #409EFF;
|
||||
}
|
||||
}
|
||||
|
||||
/* 列表项动画 */
|
||||
.order-list view {
|
||||
animation: fadeInUp 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 加载状态过渡 */
|
||||
.global-loading {
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.load-more {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* 空状态动画 */
|
||||
.empty-state {
|
||||
animation: fadeIn 0.5s ease-out;
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 刷新状态优化 */
|
||||
.scroll-area[refresher-triggered="true"] {
|
||||
.order-list {
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
<template>
|
||||
<view class="test-page">
|
||||
<view class="test-header">
|
||||
<text class="test-title">OrderList 组件测试</text>
|
||||
<button @click="toggleData" class="test-btn">{{ hasData ? '清空数据' : '加载数据' }}</button>
|
||||
</view>
|
||||
|
||||
<view class="test-content">
|
||||
<OrderList
|
||||
:orderList="testOrderList"
|
||||
:hasMore="hasMore"
|
||||
:isLoading="isLoading"
|
||||
:currentTab="currentTab"
|
||||
:emptyText="'暂无测试数据'"
|
||||
:useVirtualList="true"
|
||||
:virtualListHeight="'400px'"
|
||||
:cellHeightMode="'auto'"
|
||||
:fixedHeight="120"
|
||||
@refresh="handleRefresh"
|
||||
@loadMore="handleLoadMore"
|
||||
@orderClick="handleOrderClick"
|
||||
@orderCall="handleOrderCall"
|
||||
@orderComplete="handleOrderComplete"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="test-info">
|
||||
<text class="info-text">当前数据量: {{ testOrderList.length }}</text>
|
||||
<text class="info-text">是否有更多: {{ hasMore ? '是' : '否' }}</text>
|
||||
<text class="info-text">是否加载中: {{ isLoading ? '是' : '否' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import OrderList from './index.vue'
|
||||
|
||||
// 测试数据
|
||||
const testOrderList = ref([])
|
||||
const hasMore = ref(true)
|
||||
const isLoading = ref(false)
|
||||
const currentTab = ref('all')
|
||||
const hasData = ref(false)
|
||||
|
||||
// 模拟订单数据
|
||||
const mockData = [
|
||||
{
|
||||
id: '001',
|
||||
title: '空调维修服务',
|
||||
createTime: '2024-01-15 14:30',
|
||||
contactName: '张先生',
|
||||
contactPhone: '138****8888',
|
||||
status: 'pending',
|
||||
type: 'service'
|
||||
},
|
||||
{
|
||||
id: '002',
|
||||
title: '水管漏水维修',
|
||||
createTime: '2024-01-15 10:20',
|
||||
contactName: '李女士',
|
||||
contactPhone: '139****9999',
|
||||
status: 'processing',
|
||||
type: 'service'
|
||||
},
|
||||
{
|
||||
id: '003',
|
||||
title: '电灯安装服务',
|
||||
createTime: '2024-01-14 16:45',
|
||||
contactName: '王先生',
|
||||
contactPhone: '137****7777',
|
||||
status: 'completed',
|
||||
type: 'service'
|
||||
}
|
||||
]
|
||||
|
||||
// 切换数据
|
||||
const toggleData = () => {
|
||||
if (hasData.value) {
|
||||
testOrderList.value = []
|
||||
hasData.value = false
|
||||
} else {
|
||||
testOrderList.value = [...mockData]
|
||||
hasData.value = true
|
||||
}
|
||||
}
|
||||
|
||||
// 处理刷新
|
||||
const handleRefresh = () => {
|
||||
console.log('测试: 刷新事件触发')
|
||||
isLoading.value = true
|
||||
setTimeout(() => {
|
||||
testOrderList.value = [...mockData]
|
||||
isLoading.value = false
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 处理加载更多
|
||||
const handleLoadMore = () => {
|
||||
console.log('测试: 加载更多事件触发')
|
||||
isLoading.value = true
|
||||
setTimeout(() => {
|
||||
const newData = mockData.map((item, index) => ({
|
||||
...item,
|
||||
id: item.id + '_' + Date.now(),
|
||||
title: item.title + ' (新增)'
|
||||
}))
|
||||
testOrderList.value.push(...newData)
|
||||
isLoading.value = false
|
||||
hasMore.value = testOrderList.value.length < 20
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
// 处理订单点击
|
||||
const handleOrderClick = (orderData) => {
|
||||
console.log('测试: 订单点击', orderData)
|
||||
uni.showToast({
|
||||
title: `点击了订单: ${orderData.title}`,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
// 处理订单呼叫
|
||||
const handleOrderCall = (orderData) => {
|
||||
console.log('测试: 订单呼叫', orderData)
|
||||
uni.showToast({
|
||||
title: `呼叫: ${orderData.contactName}`,
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
// 处理订单完成
|
||||
const handleOrderComplete = (orderData) => {
|
||||
console.log('测试: 订单完成', orderData)
|
||||
uni.showToast({
|
||||
title: `完成订单: ${orderData.title}`,
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.test-page {
|
||||
padding: 20rpx;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.test-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
background: #f5f5f5;
|
||||
border-radius: 10rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.test-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.test-btn {
|
||||
padding: 10rpx 20rpx;
|
||||
background: #007aff;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 6rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.test-content {
|
||||
flex: 1;
|
||||
border: 2rpx solid #e0e0e0;
|
||||
border-radius: 10rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.test-info {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 20rpx;
|
||||
background: #f9f9f9;
|
||||
border-radius: 10rpx;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.info-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
@@ -1,7 +1,11 @@
|
||||
<template>
|
||||
<view class="order-page">
|
||||
<!-- 顶部导航栏 - 固定定位 -->
|
||||
<view class="top-nav-fixed">
|
||||
<z-paging
|
||||
ref="paging"
|
||||
v-model="dataList"
|
||||
safe-area-inset-bottom
|
||||
@query="queryList"
|
||||
>
|
||||
<template #top>
|
||||
<TopNavBar>
|
||||
<template #title>
|
||||
<Tabs
|
||||
@@ -11,33 +15,40 @@
|
||||
/>
|
||||
</template>
|
||||
</TopNavBar>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<!-- 工单列表区域 - 全屏模式 -->
|
||||
<OrderList
|
||||
:orderList="currentOrderList"
|
||||
:hasMore="hasMore"
|
||||
:isLoading="isLoading"
|
||||
:currentTab="currentTab"
|
||||
:emptyText="getEmptyText()"
|
||||
:useVirtualList="false"
|
||||
:virtualListHeight="'100vh'"
|
||||
:cellHeightMode="'auto'"
|
||||
:fixedHeight="120"
|
||||
@refresh="handleRefresh"
|
||||
@loadMore="handleLoadMore"
|
||||
@orderClick="handleOrderClick"
|
||||
@orderCall="handleOrderCall"
|
||||
@orderComplete="handleOrderComplete"
|
||||
<template #empty>
|
||||
<CustomEmpty statusText="您暂无订单" />
|
||||
</template>
|
||||
|
||||
<template #refresher="{ refresherStatus }">
|
||||
<CustomRefresher :status="refresherStatus" />
|
||||
</template>
|
||||
|
||||
<template #loadingMoreNoMore>
|
||||
<CustomNoMore />
|
||||
</template>
|
||||
|
||||
<OrderCard
|
||||
v-for="(item, index) in dataList"
|
||||
:key="item.id || index"
|
||||
:orderData="item"
|
||||
@click="handleOrderClick"
|
||||
@call="handleOrderCall"
|
||||
@complete="handleOrderComplete"
|
||||
/>
|
||||
</view>
|
||||
</z-paging>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from "vue";
|
||||
import TopNavBar from "./components/TopNavBar/index.vue";
|
||||
import Tabs from "./components/Tabs/index.vue";
|
||||
import OrderList from "./components/OrderList/index.vue";
|
||||
import OrderCard from "./components/OrderCard/index.vue";
|
||||
import CustomEmpty from "./components/CustomEmpty/index.vue";
|
||||
import CustomRefresher from "./components/CustomRefresher/index.vue";
|
||||
import CustomNoMore from "./components/CustomNoMore/index.vue";
|
||||
import { userOrderList, userWorkOrderList } from "@/request/api/OrderApi";
|
||||
|
||||
// Tab配置
|
||||
const tabList = ref([
|
||||
@@ -46,214 +57,69 @@ const tabList = ref([
|
||||
]);
|
||||
|
||||
// 当前状态
|
||||
const currentTab = ref("all");
|
||||
const currentTabIndex = ref(0);
|
||||
const isLoading = ref(false);
|
||||
const hasMore = ref(true);
|
||||
const pageNum = ref(1);
|
||||
const pageSize = ref(10);
|
||||
const showConsultationBar = ref(false);
|
||||
const dataList = ref([]);
|
||||
const paging = ref(null);
|
||||
|
||||
// 工单数据
|
||||
const allOrderList = ref([]);
|
||||
const serviceOrderList = ref([]);
|
||||
const queryList = async (pageNum, pageSize) => {
|
||||
try {
|
||||
let apiCall;
|
||||
// 根据当前Tab选择不同的API
|
||||
if (currentTabIndex.value === 0) {
|
||||
// 全部订单
|
||||
apiCall = userOrderList({ pageNum, pageSize });
|
||||
} else {
|
||||
// 服务工单
|
||||
apiCall = userWorkOrderList({ pageNum, pageSize });
|
||||
}
|
||||
|
||||
// 模拟工单数据
|
||||
const mockOrderData = [
|
||||
{
|
||||
id: "001",
|
||||
title: "空调不制冷,需要维修",
|
||||
createTime: "2024-01-15 14:30",
|
||||
contactName: "张先生",
|
||||
contactPhone: "138****8888",
|
||||
status: "pending",
|
||||
type: "service",
|
||||
},
|
||||
{
|
||||
id: "002",
|
||||
title: "卫生间水龙头漏水",
|
||||
createTime: "2024-01-15 10:20",
|
||||
contactName: "李女士",
|
||||
contactPhone: "139****9999",
|
||||
status: "processing",
|
||||
type: "service",
|
||||
},
|
||||
{
|
||||
id: "003",
|
||||
title: "客厅灯泡需要更换",
|
||||
createTime: "2024-01-14 16:45",
|
||||
contactName: "王先生",
|
||||
contactPhone: "137****7777",
|
||||
status: "completed",
|
||||
type: "service",
|
||||
},
|
||||
{
|
||||
id: "004",
|
||||
title: "普通订单 - 商品配送",
|
||||
createTime: "2024-01-14 09:15",
|
||||
contactName: "赵女士",
|
||||
contactPhone: "136****6666",
|
||||
status: "completed",
|
||||
type: "order",
|
||||
},
|
||||
{
|
||||
id: "005",
|
||||
title: "网络连接异常",
|
||||
createTime: "2024-01-15 11:30",
|
||||
contactName: "刘先生",
|
||||
contactPhone: "135****5555",
|
||||
status: "pending",
|
||||
type: "service",
|
||||
},
|
||||
];
|
||||
const res = await apiCall;
|
||||
console.log("API响应:", res);
|
||||
|
||||
// 计算当前显示的工单列表
|
||||
const currentOrderList = computed(() => {
|
||||
return currentTab.value === "all"
|
||||
? allOrderList.value
|
||||
: serviceOrderList.value;
|
||||
});
|
||||
if (res && res.data && res.data.records) {
|
||||
const records = res.data.records;
|
||||
const hasMore = pageNum < res.data.pages; // 判断是否还有更多数据
|
||||
|
||||
// 获取空状态文案
|
||||
const getEmptyText = () => {
|
||||
return currentTab.value === "all" ? "暂无订单数据" : "暂无服务工单";
|
||||
// 完成数据加载,第二个参数表示是否还有更多数据
|
||||
paging.value.complete(records, !hasMore);
|
||||
console.log("数据加载完成", records.length, "条记录,hasMore:", hasMore);
|
||||
} else {
|
||||
// 没有数据
|
||||
paging.value.complete([], true);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("查询列表失败:", error);
|
||||
// 加载失败
|
||||
paging.value.complete(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Tab切换处理
|
||||
const handleTabChange = ({ index, item }) => {
|
||||
console.log("切换到:", item.label);
|
||||
currentTab.value = item.value;
|
||||
const handleTabChange = ({ index }) => {
|
||||
console.log("Tab切换到:", index);
|
||||
currentTabIndex.value = index;
|
||||
|
||||
// 如果当前Tab没有数据,则加载数据
|
||||
if (currentOrderList.value.length === 0) {
|
||||
loadOrderData(true);
|
||||
}
|
||||
// 清空当前数据并重新加载
|
||||
dataList.value = [];
|
||||
paging.value.reload();
|
||||
};
|
||||
|
||||
// 加载工单数据
|
||||
const loadOrderData = async (isRefresh = false) => {
|
||||
if (isLoading.value) return;
|
||||
|
||||
isLoading.value = true;
|
||||
|
||||
try {
|
||||
// 模拟API请求延迟
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
|
||||
// 模拟数据过滤
|
||||
let filteredData = [];
|
||||
if (currentTab.value === "all") {
|
||||
filteredData = mockOrderData;
|
||||
} else {
|
||||
filteredData = mockOrderData.filter((item) => item.type === "service");
|
||||
}
|
||||
|
||||
if (isRefresh) {
|
||||
// 刷新数据
|
||||
if (currentTab.value === "all") {
|
||||
allOrderList.value = [...filteredData];
|
||||
} else {
|
||||
serviceOrderList.value = [...filteredData];
|
||||
}
|
||||
pageNum.value = 1;
|
||||
hasMore.value = true;
|
||||
} else {
|
||||
// 加载更多
|
||||
if (currentTab.value === "all") {
|
||||
allOrderList.value.push(...filteredData.slice(0, 2));
|
||||
} else {
|
||||
serviceOrderList.value.push(...filteredData.slice(0, 2));
|
||||
}
|
||||
pageNum.value++;
|
||||
|
||||
// 模拟没有更多数据
|
||||
if (pageNum.value >= 3) {
|
||||
hasMore.value = false;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("加载数据失败:", error);
|
||||
uni.showToast({
|
||||
title: "加载失败,请重试",
|
||||
icon: "none",
|
||||
});
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 下拉刷新
|
||||
const handleRefresh = async () => {
|
||||
await loadOrderData(true);
|
||||
};
|
||||
|
||||
// 上拉加载更多
|
||||
const handleLoadMore = async () => {
|
||||
if (!hasMore.value) return;
|
||||
await loadOrderData(false);
|
||||
};
|
||||
|
||||
// 工单点击处理
|
||||
// 处理订单点击
|
||||
const handleOrderClick = (orderData) => {
|
||||
console.log("点击工单:", orderData);
|
||||
uni.navigateTo({
|
||||
url: `/pages/order/detail?id=${orderData.id}`,
|
||||
});
|
||||
console.log("订单点击:", orderData);
|
||||
// 这里可以添加订单详情跳转逻辑
|
||||
};
|
||||
|
||||
// 工单呼叫处理
|
||||
// 处理订单呼叫
|
||||
const handleOrderCall = (orderData) => {
|
||||
console.log("呼叫:", orderData);
|
||||
|
||||
// 显示底部咨询栏
|
||||
showConsultationBar.value = true;
|
||||
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: orderData.contactPhone.replace(/\*/g, ""),
|
||||
fail: () => {
|
||||
uni.showToast({
|
||||
title: "拨号失败",
|
||||
icon: "none",
|
||||
});
|
||||
},
|
||||
});
|
||||
console.log("订单呼叫:", orderData);
|
||||
// 这里可以添加呼叫逻辑
|
||||
};
|
||||
|
||||
// 工单完成处理
|
||||
// 处理订单完成
|
||||
const handleOrderComplete = (orderData) => {
|
||||
console.log("标记完成:", orderData);
|
||||
|
||||
uni.showModal({
|
||||
title: "确认操作",
|
||||
content: "确定要标记此工单为已完成吗?",
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 更新工单状态
|
||||
const targetList =
|
||||
currentTab.value === "all"
|
||||
? allOrderList.value
|
||||
: serviceOrderList.value;
|
||||
const orderIndex = targetList.findIndex(
|
||||
(item) => item.id === orderData.id
|
||||
);
|
||||
if (orderIndex !== -1) {
|
||||
targetList[orderIndex].status = "completed";
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: "操作成功",
|
||||
icon: "success",
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
console.log("订单完成:", orderData);
|
||||
// 这里可以添加订单完成逻辑
|
||||
};
|
||||
|
||||
// 页面加载时初始化数据
|
||||
onMounted(() => {
|
||||
loadOrderData(true);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
.order-page {
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.top-nav-fixed {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
Reference in New Issue
Block a user