feat(portal): redesign tenant home view with enhanced layout and interactive features

This commit is contained in:
2025-12-26 19:24:40 +08:00
parent 35b46386c7
commit d7ea411f25
2 changed files with 291 additions and 73 deletions

View File

@@ -18,14 +18,13 @@
class="h-9 px-3 rounded border border-slate-200 text-sm focus:border-primary-500 outline-none bg-white cursor-pointer">
<option value="all">全部</option>
<option value="completed">已完成</option>
<option value="refunding">退款申请中</option>
<option value="refunded">已退款</option>
<optiefunde value="refunding">退款申请中</optiefunde <option value="refunded">退</option>
</select>
</div>
<div class="ml-auto relative w-64">
<i class="pi pi-search absolute left-3 top-1/2 -translate-y-1/2 text-slate-400"></i>
<input type="text" placeholder="搜索订单号或买家..."
class="w-full h-9 pl-9 pr-4 rounded border border-slate-200 text-sm focus:border-primary-500 outline-none transition-all">
class="w-full h-9 pl-9 pr-4 rounded border border-slate-200 text-sm focus:border-primary-500 outline-none transition-all" />
</div>
</div>
@@ -45,34 +44,46 @@
</thead>
<tbody class="divide-y divide-slate-100">
<tr v-for="order in filteredOrders" :key="order.id" class="hover:bg-slate-50 transition-colors">
<td class="px-6 py-4 font-mono text-slate-600 align-middle">{{ order.id }}</td>
<td class="px-6 py-4 font-mono text-slate-600 align-middle">
{{ order.id }}
</td>
<td class="px-6 py-4 align-middle">
<div class="flex items-center gap-3">
<img :src="order.cover"
class="w-16 h-10 object-cover rounded bg-slate-100 flex-shrink-0">
class="w-16 h-10 object-cover rounded bg-slate-100 flex-shrink-0" />
<span class="font-bold text-slate-900 truncate max-w-[240px]" :title="order.title">{{
order.title }}</span>
</div>
</td>
<td class="px-6 py-4 align-middle">
<div class="flex items-center gap-2">
<img :src="order.buyerAvatar" class="w-8 h-8 rounded-full flex-shrink-0">
<span class="text-slate-700 truncate max-w-[100px]">{{ order.buyerName }}</span>
<img :src="order.buyerAvatar" class="w-8 h-8 rounded-full flex-shrink-0" />
<span class="text-slate-700 truncate max-w-[100px]">{{
order.buyerName
}}</span>
</div>
</td>
<td class="px-6 py-4 text-right font-bold text-slate-900 align-middle">¥ {{ order.amount }}</td>
<td class="px-6 py-4 text-slate-500 whitespace-nowrap align-middle">{{ order.date }}</td>
<td class="px-6 py-4 text-right font-bold text-slate-900 align-middle">
¥ {{ order.amount }}
</td>
<td class="px-6 py-4 text-slate-500 whitespace-nowrap align-middle">
{{ order.date }}
</td>
<td class="px-6 py-4 align-middle">
<span class="inline-block px-2.5 py-1 rounded text-xs font-bold whitespace-nowrap"
:class="statusStyle(order.status).bg + ' ' + statusStyle(order.status).text">
<span class="inline-block px-2.5 py-1 rounded text-xs font-bold whitespace-nowrap" :class="statusStyle(order.status).bg + ' ' + statusStyle(order.status).text
">
{{ statusStyle(order.status).label }}
</span>
</td>
<td class="px-6 py-4 text-right align-middle whitespace-nowrap">
<button @click="viewDetail(order)"
class="text-primary-600 hover:text-primary-700 font-medium mr-4 cursor-pointer hover:bg-primary-50 px-2 py-1 rounded transition-colors">详情</button>
class="text-primary-600 hover:text-primary-700 font-medium mr-4 cursor-pointer hover:bg-primary-50 px-2 py-1 rounded transition-colors">
详情
</button>
<button v-if="order.status === 'refunding'" @click="handleRefund(order)"
class="text-red-600 hover:text-red-700 font-medium cursor-pointer hover:bg-red-50 px-2 py-1 rounded transition-colors">处理退款</button>
class="text-red-600 hover:text-red-700 font-medium cursor-pointer hover:bg-red-50 px-2 py-1 rounded transition-colors">
处理退款
</button>
</td>
</tr>
</tbody>
@@ -92,7 +103,7 @@
<span class="font-mono font-bold">{{ selectedOrder.id }}</span>
</div>
<div class="flex gap-4">
<img :src="selectedOrder.cover" class="w-20 h-14 object-cover rounded">
<img :src="selectedOrder.cover" class="w-20 h-14 object-cover rounded" />
<div>
<h3 class="font-bold text-slate-900">{{ selectedOrder.title }}</h3>
<p class="text-sm text-slate-500 mt-1">类型: {{ selectedOrder.type }}</p>
@@ -121,26 +132,33 @@
</div>
<template #footer>
<button @click="detailDialog = false"
class="px-4 py-2 border border-slate-200 rounded text-sm hover:bg-slate-50">关闭</button>
class="px-4 py-2 border border-slate-200 rounded text-sm hover:bg-slate-50">
关闭
</button>
<button
class="px-4 py-2 border border-primary-200 text-primary-600 rounded text-sm hover:bg-primary-50 ml-2">联系买家</button>
class="px-4 py-2 border border-primary-200 text-primary-600 rounded text-sm hover:bg-primary-50 ml-2">
联系买家
</button>
</template>
</Dialog>
<!-- Refund Dialog -->
<Dialog v-model:visible="refundDialog" modal header="处理退款申请" :style="{ width: '25rem' }">
<div class="text-sm text-slate-600 mb-6">
您正在处理订单 <span class="font-mono font-bold">{{ selectedOrder?.id }}</span> 的退款申请
<br>同意后金额将原路退回给买家
您正在处理订单
<span class="font-mono font-bold">{{ selectedOrder?.id }}</span> 的退款申请
<br />同意后金额将原路退回给买家
</div>
<div class="space-y-3">
<label class="flex items-center gap-3 p-3 border rounded-lg cursor-pointer hover:bg-slate-50"
:class="refundAction === 'accept' ? 'border-green-500 bg-green-50' : 'border-slate-200'">
<label class="flex items-center gap-3 p-3 border rounded-lg cursor-pointer hover:bg-slate-50" :class="refundAction === 'accept'
? 'border-green-500 bg-green-50'
: 'border-slate-200'
">
<RadioButton v-model="refundAction" value="accept" />
<span>同意退款</span>
</label>
<label class="flex items-center gap-3 p-3 border rounded-lg cursor-pointer hover:bg-slate-50"
:class="refundAction === 'reject' ? 'border-red-500 bg-red-50' : 'border-slate-200'">
<label class="flex items-center gap-3 p-3 border rounded-lg cursor-pointer hover:bg-slate-50" :class="refundAction === 'reject' ? 'border-red-500 bg-red-50' : 'border-slate-200'
">
<RadioButton v-model="refundAction" value="reject" />
<span>拒绝退款</span>
</label>
@@ -150,10 +168,13 @@
rows="2" placeholder="请输入拒绝理由..."></textarea>
</div>
<template #footer>
<button @click="refundDialog = false"
class="px-4 py-2 text-slate-500 hover:text-slate-700 text-sm">取消</button>
<button @click="refundDialog = false" class="px-4 py-2 text-slate-500 hover:text-slate-700 text-sm">
取消
</button>
<button @click="confirmRefund"
class="px-4 py-2 bg-slate-900 text-white rounded text-sm hover:bg-slate-800">确认处理</button>
class="px-4 py-2 bg-slate-900 text-white rounded text-sm hover:bg-slate-800">
确认处理
</button>
</template>
</Dialog>
@@ -162,57 +183,63 @@
</template>
<script setup>
import Dialog from 'primevue/dialog';
import RadioButton from 'primevue/radiobutton';
import Toast from 'primevue/toast';
import { useToast } from 'primevue/usetoast';
import { computed, ref } from 'vue';
import Dialog from "primevue/dialog";
import RadioButton from "primevue/radiobutton";
import Toast from "primevue/toast";
import { useToast } from "primevue/usetoast";
import { computed, ref } from "vue";
const toast = useToast();
const filterStatus = ref('all');
const filterStatus = ref("all");
const detailDialog = ref(false);
const refundDialog = ref(false);
const selectedOrder = ref(null);
const refundAction = ref('accept');
const refundAction = ref("accept");
const orders = ref([
{
id: '82934712',
title: '《霸王别姬》全本实录珍藏版',
type: '视频',
cover: 'https://images.unsplash.com/photo-1514306191717-452ec28c7f31?ixlib=rb-1.2.1&auto=format&fit=crop&w=100&q=60',
buyerName: '戏迷小张',
buyerAvatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Zhang',
buyerId: '9527',
amount: '9.90',
date: '2025-12-24 14:30',
status: 'completed'
id: "82934712",
title: "《霸王别姬》全本实录珍藏版",
type: "视频",
cover:
"https://images.unsplash.com/photo-1514306191717-452ec28c7f31?ixlib=rb-1.2.1&auto=format&fit=crop&w=100&q=60",
buyerName: "戏迷小张",
buyerAvatar: "https://api.dicebear.com/7.x/avataaars/svg?seed=Zhang",
buyerId: "9527",
amount: "9.90",
date: "2025-12-24 14:30",
status: "completed",
},
{
id: '82934715',
title: '京剧打击乐基础教程',
type: '视频',
cover: 'https://images.unsplash.com/photo-1533174072545-e8d4aa97edf9?ixlib=rb-1.2.1&auto=format&fit=crop&w=100&q=60',
buyerName: '票友老李',
buyerAvatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Li',
buyerId: '8848',
amount: '19.90',
date: '2025-12-25 09:15',
status: 'refunding'
}
id: "82934715",
title: "京剧打击乐基础教程",
type: "视频",
cover:
"https://images.unsplash.com/photo-1533174072545-e8d4aa97edf9?ixlib=rb-1.2.1&auto=format&fit=crop&w=100&q=60",
buyerName: "票友老李",
buyerAvatar: "https://api.dicebear.com/7.x/avataaars/svg?seed=Li",
buyerId: "8848",
amount: "19.90",
date: "2025-12-25 09:15",
status: "refunding",
},
]);
const filteredOrders = computed(() => {
if (filterStatus.value === 'all') return orders.value;
return orders.value.filter(o => o.status === filterStatus.value);
if (filterStatus.value === "all") return orders.value;
return orders.value.filter((o) => o.status === filterStatus.value);
});
const statusStyle = (status) => {
switch (status) {
case 'completed': return { bg: 'bg-green-50', text: 'text-green-600', label: '已完成' };
case 'refunding': return { bg: 'bg-orange-50', text: 'text-orange-600', label: '退款申请中' };
case 'refunded': return { bg: 'bg-slate-100', text: 'text-slate-500', label: '已退款' };
default: return { bg: 'bg-slate-100', text: 'text-slate-500', label: '未知' };
case "completed":
return { bg: "bg-green-50", text: "text-green-600", label: "已完成" };
case "refunding":
return { bg: "bg-orange-50", text: "text-orange-600", label: "退款申请中" };
case "refunded":
return { bg: "bg-slate-100", text: "text-slate-500", label: "已退款" };
default:
return { bg: "bg-slate-100", text: "text-slate-500", label: "未知" };
}
};
@@ -223,7 +250,7 @@ const viewDetail = (order) => {
const handleRefund = (order) => {
selectedOrder.value = order;
refundAction.value = 'accept';
refundAction.value = "accept";
refundDialog.value = true;
};
@@ -231,11 +258,11 @@ const confirmRefund = () => {
// Mock API
refundDialog.value = false;
toast.add({
severity: 'success',
summary: '处理完成',
detail: refundAction.value === 'accept' ? '已同意退款' : '已拒绝退款申请',
life: 3000
severity: "success",
summary: "处理完成",
detail: refundAction.value === "accept" ? "已同意退款" : "已拒绝退款申请",
life: 3000,
});
// In real app, refresh list
};
</script>
</script>