fix SalesOrderList.vue style
This commit is contained in:
@@ -0,0 +1,272 @@
|
||||
<template>
|
||||
<div class="sales-order-cell bg-white">
|
||||
<div class="header">
|
||||
<div class="left">
|
||||
<t-image
|
||||
v-if="photoURL"
|
||||
:src="photoURL"
|
||||
:alt="customerName"
|
||||
fit="cover"
|
||||
class="avatar"
|
||||
/>
|
||||
<div v-else class="avatar fallback" v-text="avatarText" />
|
||||
</div>
|
||||
<div class="main">
|
||||
<div class="customer-status">
|
||||
<strong class="customer" v-text="customerName" />
|
||||
<div class="status">
|
||||
<t-tag
|
||||
:content="getSalesOrderStatusText(props.order.status)"
|
||||
size="small"
|
||||
variant="light-outline"
|
||||
:theme="getStatusTheme(props.order.status)"
|
||||
/>
|
||||
<t-tag
|
||||
:content="getSalesPaymentStatusText(props.order.paymentStatus)"
|
||||
:theme="getPaymentStatusTheme(props.order.paymentStatus)"
|
||||
size="small"
|
||||
variant="light-outline"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="order-no" v-text="orderNoText" />
|
||||
</div>
|
||||
</div>
|
||||
<t-divider />
|
||||
<div class="product">
|
||||
<div class="items">
|
||||
<t-tag
|
||||
v-for="(item, index) in itemList"
|
||||
:key="item.id || `${item.productId}-${index}`"
|
||||
:content="item.productNameSnapshot || '未命名产品'"
|
||||
theme="primary"
|
||||
variant="light"
|
||||
/>
|
||||
<t-tag v-if="!itemList.length" content="暂无产品" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary">
|
||||
<span v-text="productSummaryText" />
|
||||
</div>
|
||||
<t-divider />
|
||||
<div class="time-payment">
|
||||
<pass-time-label class="time gray" :timestamp="props.order.purchasedAt" underline />
|
||||
<div class="amount">
|
||||
<span class="red">¥</span>
|
||||
<strong class="value red" v-text="formatPackageAmount(props.order.saleAmount)" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="showActions" class="actions" @click.stop>
|
||||
<t-button
|
||||
v-if="showReceiveAction"
|
||||
variant="outline"
|
||||
size="extra-small"
|
||||
@click.stop="emit('receive')"
|
||||
>登记收款</t-button>
|
||||
<t-button
|
||||
v-if="showFulfillAction"
|
||||
variant="outline"
|
||||
size="extra-small"
|
||||
@click.stop="emit('fulfill')"
|
||||
>履约产品</t-button>
|
||||
<t-button
|
||||
class="detail"
|
||||
size="extra-small"
|
||||
theme="primary"
|
||||
content="详情"
|
||||
@click="emit('click')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { PassTimeLabel, Time } from "timi-web";
|
||||
import type { SalesOrder, SalesPaymentStatus } from "@/types/SalesOrder";
|
||||
import { getCustomerPhotoURL } from "@/utils/customer";
|
||||
import { formatPackageAmount, getPackageQuantityText } from "@/utils/package";
|
||||
import { getSalesOrderStatusText, getSalesPaymentStatusText, getStatusTheme } from "@/utils/salesOrder";
|
||||
|
||||
defineOptions({ name: "SalesOrderListCell" });
|
||||
|
||||
const props = defineProps<{
|
||||
order: SalesOrder;
|
||||
canReceive: boolean;
|
||||
canFulfill: boolean;
|
||||
}>();
|
||||
const emit = defineEmits<{
|
||||
click: [];
|
||||
receive: [];
|
||||
fulfill: [];
|
||||
}>();
|
||||
const itemList = computed(() => props.order.itemList || []);
|
||||
const customerName = computed(() => props.order.customer?.name || props.order.customer?.code || props.order.customerId || "未知客户");
|
||||
const avatarText = computed(() => customerName.value.slice(0, 1) || "客");
|
||||
const photoURL = computed(() => getCustomerPhotoURL(props.order.customer, 64));
|
||||
const orderNoText = computed(() => `订单号:${props.order.orderNo || props.order.id || "未知"}`);
|
||||
const totalProductQuantity = computed(() => sumProductQuantity("quantity"));
|
||||
const fulfilledProductQuantity = computed(() => sumProductQuantity("fulfilledQuantity"));
|
||||
const productSummaryText = computed(() => `共 ${itemList.value.length} 项 · 总数量 ${totalProductQuantity.value} · 已履约 ${fulfilledProductQuantity.value}`);
|
||||
const showReceiveAction = computed(() => props.canReceive && props.order.status !== "CANCELLED" && props.order.paymentStatus !== "PAID");
|
||||
const showFulfillAction = computed(() => props.canFulfill && props.order.orderType === "DIRECT_PRODUCT" && props.order.status === "ACTIVE");
|
||||
const showActions = computed(() => showReceiveAction.value || showFulfillAction.value);
|
||||
|
||||
function getPaymentStatusTheme(status?: SalesPaymentStatus): "success" | "warning" | "danger" | "default" {
|
||||
if (status === "PAID") {
|
||||
return "success";
|
||||
}
|
||||
if (status === "PARTIALLY_PAID") {
|
||||
return "warning";
|
||||
}
|
||||
if (status === "UNPAID") {
|
||||
return "danger";
|
||||
}
|
||||
return "default";
|
||||
}
|
||||
|
||||
function sumProductQuantity(field: "quantity" | "fulfilledQuantity"): string {
|
||||
let total = 0;
|
||||
for (const item of itemList.value) {
|
||||
const quantity = Number(item[field] || 0);
|
||||
if (Number.isFinite(quantity)) {
|
||||
total += quantity;
|
||||
}
|
||||
}
|
||||
return getPackageQuantityText(total.toFixed(3));
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="less">
|
||||
.sales-order-cell {
|
||||
gap: .5rem;
|
||||
padding: 10px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.header {
|
||||
gap: .5rem;
|
||||
display: flex;
|
||||
|
||||
.left {
|
||||
|
||||
.avatar {
|
||||
width: 3.5rem;
|
||||
height: 3.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.main {
|
||||
gap: .5rem;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.customer-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
|
||||
.customer {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.status {
|
||||
gap: .25rem;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.order-no {
|
||||
color: var(--td-text-color-secondary);
|
||||
font-size: .75rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.product {
|
||||
gap: .5rem;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
|
||||
.items {
|
||||
flex: 1;
|
||||
gap: .35rem;
|
||||
display: flex;
|
||||
min-width: 0;
|
||||
flex-wrap: nowrap;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
white-space: nowrap;
|
||||
scrollbar-width: none;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
|
||||
:deep(.t-tag) {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.summary {
|
||||
color: var(--td-text-color-secondary);
|
||||
font-size: .75rem;
|
||||
text-align: right;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.time-payment {
|
||||
gap: 1rem;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
|
||||
.time {
|
||||
font-size: .75rem;
|
||||
}
|
||||
|
||||
.amount {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: end;
|
||||
|
||||
.value {
|
||||
font-size: 1.5rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.actions {
|
||||
--td-button-border-radius: .5rem;
|
||||
|
||||
gap: .5rem;
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
|
||||
.detail {
|
||||
padding-left: 1.5rem;
|
||||
padding-right: 1.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.sales-order-cell .avatar .t-image__img) {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
:global(html.theme-dark) .sales-order-cell {
|
||||
.fallback {
|
||||
background: #115e59;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user