forked from gxwebsoft/mp-10550
feat(ticket): 将核销记录替换为送水订单功能并优化用户体验
- 替换核销记录为送水订单展示功能 - 在订单模型中新增门店、配送员、仓库的名称和联系方式字段 - 添加用户昵称、头像、手机号等个人信息字段 - 实现配送时间选择器功能 - 设置最低起送数量限制为10桶 - 优化订单列表展示界面和交互逻辑 - 添加订单状态显示功能 - 实现订单数据分页加载和搜索功能 - 优化页面数据加载性能,支持静默刷新
This commit is contained in:
@@ -16,8 +16,8 @@ import {
|
||||
import { View, Text, Image } from '@tarojs/components';
|
||||
import { pageGltUserTicket } from '@/api/glt/gltUserTicket';
|
||||
import type { GltUserTicket } from '@/api/glt/gltUserTicket/model';
|
||||
import { pageGltUserTicketLog } from '@/api/glt/gltUserTicketLog';
|
||||
import type { GltUserTicketLog } from '@/api/glt/gltUserTicketLog/model';
|
||||
import { pageGltTicketOrder } from '@/api/glt/gltTicketOrder';
|
||||
import type { GltTicketOrder } from '@/api/glt/gltTicketOrder/model';
|
||||
import { BaseUrl } from '@/config/app';
|
||||
import dayjs from "dayjs";
|
||||
|
||||
@@ -31,13 +31,13 @@ const UserTicketList = () => {
|
||||
const [ticketPage, setTicketPage] = useState(1);
|
||||
const [ticketTotal, setTicketTotal] = useState(0);
|
||||
|
||||
const [logList, setLogList] = useState<GltUserTicketLog[]>([]);
|
||||
const [logLoading, setLogLoading] = useState(false);
|
||||
const [logHasMore, setLogHasMore] = useState(true);
|
||||
const [logPage, setLogPage] = useState(1);
|
||||
const [logTotal, setLogTotal] = useState(0);
|
||||
const [orderList, setOrderList] = useState<GltTicketOrder[]>([]);
|
||||
const [orderLoading, setOrderLoading] = useState(false);
|
||||
const [orderHasMore, setOrderHasMore] = useState(true);
|
||||
const [orderPage, setOrderPage] = useState(1);
|
||||
const [orderTotal, setOrderTotal] = useState(0);
|
||||
|
||||
const [activeTab, setActiveTab] = useState<'ticket' | 'log'>('ticket');
|
||||
const [activeTab, setActiveTab] = useState<'ticket' | 'order'>('ticket');
|
||||
|
||||
const [qrVisible, setQrVisible] = useState(false);
|
||||
const [qrTicket, setQrTicket] = useState<GltUserTicket | null>(null);
|
||||
@@ -154,27 +154,27 @@ const UserTicketList = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const reloadLogs = async (isRefresh = true, keywords?: string) => {
|
||||
if (logLoading) return;
|
||||
const reloadOrders = async (isRefresh = true, keywords?: string) => {
|
||||
if (orderLoading) return;
|
||||
|
||||
const userId = getUserId();
|
||||
if (!userId) {
|
||||
setLogList([]);
|
||||
setLogTotal(0);
|
||||
setLogHasMore(false);
|
||||
setOrderList([]);
|
||||
setOrderTotal(0);
|
||||
setOrderHasMore(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isRefresh) {
|
||||
setLogPage(1);
|
||||
setLogList([]);
|
||||
setLogHasMore(true);
|
||||
setOrderPage(1);
|
||||
setOrderList([]);
|
||||
setOrderHasMore(true);
|
||||
}
|
||||
|
||||
setLogLoading(true);
|
||||
setOrderLoading(true);
|
||||
try {
|
||||
const currentPage = isRefresh ? 1 : logPage;
|
||||
const res = await pageGltUserTicketLog({
|
||||
const currentPage = isRefresh ? 1 : orderPage;
|
||||
const res = await pageGltTicketOrder({
|
||||
page: currentPage,
|
||||
limit: PAGE_SIZE,
|
||||
userId,
|
||||
@@ -182,23 +182,23 @@ const UserTicketList = () => {
|
||||
});
|
||||
|
||||
const resList = res?.list || [];
|
||||
const nextList = isRefresh ? resList : [...logList, ...resList];
|
||||
setLogList(nextList);
|
||||
const nextList = isRefresh ? resList : [...orderList, ...resList];
|
||||
setOrderList(nextList);
|
||||
const count = typeof res?.count === 'number' ? res.count : nextList.length;
|
||||
setLogTotal(count);
|
||||
setLogHasMore(nextList.length < count);
|
||||
setOrderTotal(count);
|
||||
setOrderHasMore(nextList.length < count);
|
||||
|
||||
if (resList.length > 0) {
|
||||
setLogPage(currentPage + 1);
|
||||
setOrderPage(currentPage + 1);
|
||||
} else {
|
||||
setLogHasMore(false);
|
||||
setOrderHasMore(false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取核销记录失败:', error);
|
||||
Taro.showToast({ title: '获取核销记录失败', icon: 'error' });
|
||||
setLogHasMore(false);
|
||||
console.error('获取送水订单失败:', error);
|
||||
Taro.showToast({ title: '获取送水订单失败', icon: 'error' });
|
||||
setOrderHasMore(false);
|
||||
} finally {
|
||||
setLogLoading(false);
|
||||
setOrderLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -207,7 +207,7 @@ const UserTicketList = () => {
|
||||
if (activeTab === 'ticket') {
|
||||
reloadTickets(true, value);
|
||||
} else {
|
||||
reloadLogs(true, value);
|
||||
reloadOrders(true, value);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -215,12 +215,12 @@ const UserTicketList = () => {
|
||||
if (activeTab === 'ticket') {
|
||||
await reloadTickets(true);
|
||||
} else {
|
||||
await reloadLogs(true);
|
||||
await reloadOrders(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleTabChange = (value: string | number) => {
|
||||
const tab = String(value) as 'ticket' | 'log';
|
||||
const tab = String(value) as 'ticket' | 'order';
|
||||
setActiveTab(tab);
|
||||
if (tab === 'ticket') {
|
||||
setTicketPage(1);
|
||||
@@ -228,10 +228,10 @@ const UserTicketList = () => {
|
||||
setTicketHasMore(true);
|
||||
reloadTickets(true);
|
||||
} else {
|
||||
setLogPage(1);
|
||||
setLogList([]);
|
||||
setLogHasMore(true);
|
||||
reloadLogs(true);
|
||||
setOrderPage(1);
|
||||
setOrderList([]);
|
||||
setOrderHasMore(true);
|
||||
reloadOrders(true);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -241,23 +241,30 @@ const UserTicketList = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const loadMoreLogs = async () => {
|
||||
if (!logLoading && logHasMore) {
|
||||
await reloadLogs(false);
|
||||
const loadMoreOrders = async () => {
|
||||
if (!orderLoading && orderHasMore) {
|
||||
await reloadOrders(false);
|
||||
}
|
||||
};
|
||||
|
||||
const formatSigned = (n?: number) => {
|
||||
const val = Number(n || 0);
|
||||
if (val === 0) return '0';
|
||||
return val > 0 ? `+${val}` : `${val}`;
|
||||
const formatDateTime = (v?: string) => {
|
||||
if (!v) return '-';
|
||||
const d = dayjs(v);
|
||||
return d.isValid() ? d.format('YYYY年MM月DD日 HH:mm:ss') : v;
|
||||
};
|
||||
|
||||
const getOrderStatusText = (status?: number) => {
|
||||
// Backend field meaning may vary; page asks for "是否送达".
|
||||
if (status === 1) return { text: '已送达', type: 'success' as const };
|
||||
if (status === 0) return { text: '未送达', type: 'warning' as const };
|
||||
return { text: status == null ? '-' : String(status), type: 'primary' as const };
|
||||
};
|
||||
|
||||
useDidShow(() => {
|
||||
if (activeTab === 'ticket') {
|
||||
reloadTickets(true).then();
|
||||
} else {
|
||||
reloadLogs(true).then();
|
||||
reloadOrders(true).then();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -277,7 +284,7 @@ const UserTicketList = () => {
|
||||
<View className="bg-white">
|
||||
<Tabs value={activeTab} onChange={handleTabChange}>
|
||||
<TabPane title="我的水票" value="ticket"></TabPane>
|
||||
<TabPane title="核销记录" value="log"></TabPane>
|
||||
<TabPane title="送水订单" value="order"></TabPane>
|
||||
</Tabs>
|
||||
</View>
|
||||
|
||||
@@ -287,9 +294,9 @@ const UserTicketList = () => {
|
||||
</View>
|
||||
)}
|
||||
|
||||
{activeTab === 'log' && logTotal > 0 && (
|
||||
{activeTab === 'order' && orderTotal > 0 && (
|
||||
<View className="px-4 py-2 text-sm text-gray-500 bg-gray-50 hidden">
|
||||
共 {logTotal} 条核销记录
|
||||
共 {orderTotal} 条送水订单
|
||||
</View>
|
||||
)}
|
||||
|
||||
@@ -306,12 +313,12 @@ const UserTicketList = () => {
|
||||
style={{ backgroundColor: 'transparent' }}
|
||||
/>
|
||||
</View>
|
||||
) : activeTab === 'log' && logList.length === 0 && !logLoading ? (
|
||||
) : activeTab === 'order' && orderList.length === 0 && !orderLoading ? (
|
||||
<View
|
||||
className="flex flex-col justify-center items-center"
|
||||
style={{ height: 'calc(100vh - 160px)' }}
|
||||
>
|
||||
<Empty description="暂无核销记录" style={{ backgroundColor: 'transparent' }} />
|
||||
<Empty description="暂无送水订单" style={{ backgroundColor: 'transparent' }} />
|
||||
</View>
|
||||
) : activeTab === 'ticket' ? (
|
||||
<InfiniteLoading
|
||||
@@ -393,8 +400,8 @@ const UserTicketList = () => {
|
||||
) : (
|
||||
<InfiniteLoading
|
||||
target="ticket-scroll"
|
||||
hasMore={logHasMore}
|
||||
onLoadMore={loadMoreLogs}
|
||||
hasMore={orderHasMore}
|
||||
onLoadMore={loadMoreOrders}
|
||||
loadingText={
|
||||
<View className="flex justify-center items-center py-4">
|
||||
<Loading />
|
||||
@@ -403,68 +410,35 @@ const UserTicketList = () => {
|
||||
}
|
||||
loadMoreText={
|
||||
<View className="text-center py-4 text-gray-500">
|
||||
{logList.length === 0 ? '暂无数据' : '没有更多了'}
|
||||
{orderList.length === 0 ? '暂无数据' : '没有更多了'}
|
||||
</View>
|
||||
}
|
||||
>
|
||||
<View className="px-4 py-3">
|
||||
{logList.map((item, index) => (
|
||||
{orderList.map((item, index) => (
|
||||
<View
|
||||
key={String(item.id ?? `log-${index}`)}
|
||||
key={String(item.id ?? `order-${index}`)}
|
||||
className="bg-white rounded-xl p-4 mb-3"
|
||||
>
|
||||
<View className="flex items-start justify-between">
|
||||
<View className="flex-1 pr-3">
|
||||
<Text className="text-base font-semibold text-gray-900">
|
||||
票号:{item.userTicketId}
|
||||
票号:{item.userTicketId ?? '-'}
|
||||
</Text>
|
||||
{item.createTime && (
|
||||
<View className="mt-1">
|
||||
<Text className="text-xs text-gray-400">时间:{item.createTime}</Text>
|
||||
</View>
|
||||
)}
|
||||
{item.orderNo && (
|
||||
<View className="mt-1">
|
||||
<Text className="text-xs text-gray-500">订单编号:{item.orderNo}</Text>
|
||||
</View>
|
||||
)}
|
||||
{item.comments && (
|
||||
<View className="mt-1">
|
||||
<Text className="text-xs text-gray-500">{item.comments}</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<Tag type="warning">变更</Tag>
|
||||
</View>
|
||||
|
||||
<View className="mt-3 flex justify-between">
|
||||
<View className="flex flex-col">
|
||||
<Text className="text-xs text-gray-500">可用变更</Text>
|
||||
<Text className="text-sm text-gray-900">{formatSigned(item.changeAvailable)}</Text>
|
||||
</View>
|
||||
<View className="flex flex-col items-center">
|
||||
<Text className="text-xs text-gray-500">已用变更</Text>
|
||||
<Text className="text-sm text-gray-900">{formatSigned(item.changeUsed)}</Text>
|
||||
</View>
|
||||
<View className="flex flex-col items-end">
|
||||
<Text className="text-xs text-gray-500">冻结变更</Text>
|
||||
<Text className="text-sm text-gray-900">{formatSigned(item.changeFrozen)}</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className="mt-2 flex justify-between">
|
||||
<View className="flex flex-col">
|
||||
<Text className="text-xs text-gray-500">可用后</Text>
|
||||
<Text className="text-sm text-gray-900">{item.availableAfter ?? '-'}</Text>
|
||||
</View>
|
||||
<View className="flex flex-col items-center">
|
||||
<Text className="text-xs text-gray-500">已用后</Text>
|
||||
<Text className="text-sm text-gray-900">{item.usedAfter ?? '-'}</Text>
|
||||
</View>
|
||||
<View className="flex flex-col items-end">
|
||||
<Text className="text-xs text-gray-500">冻结后</Text>
|
||||
<Text className="text-sm text-gray-900">{item.frozenAfter ?? '-'}</Text>
|
||||
<View className="mt-1">
|
||||
<Text className="text-xs text-gray-400">下单时间:{formatDateTime(item.createTime)}</Text>
|
||||
</View>
|
||||
<View className="mt-1">
|
||||
<Text className="text-xs text-gray-400">配送时间:{formatDateTime(item.sendTime)}</Text>
|
||||
</View>
|
||||
<View className="mt-1">
|
||||
<Text className="text-xs text-gray-500">送水数量:{item.totalNum ?? 0}</Text>
|
||||
</View>
|
||||
</View>
|
||||
{(() => {
|
||||
const meta = getOrderStatusText(item.status);
|
||||
return <Tag type={meta.type}>{meta.text}</Tag>;
|
||||
})()}
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user