update order chart style
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
caption="排除已取消订单,前 10"
|
caption="排除已取消订单,前 10"
|
||||||
:option="chartOption"
|
:option="chartOption"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
height="17rem"
|
height="14rem"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -27,17 +27,18 @@ const chartOption = computed<EChartsOption>(() => {
|
|||||||
const list = props.list.slice(0, 10);
|
const list = props.list.slice(0, 10);
|
||||||
return {
|
return {
|
||||||
...buildHorizontalBarOption(list.map(getCustomerName)),
|
...buildHorizontalBarOption(list.map(getCustomerName)),
|
||||||
legend: { show: false },
|
grid: {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
showLabel: false
|
||||||
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: "value",
|
type: "value",
|
||||||
axisLabel: {
|
|
||||||
color: "#52607a",
|
|
||||||
formatter: (value: number) => `${formatChartYuan(value)} 元`
|
|
||||||
},
|
|
||||||
splitLine: { lineStyle: { color: "rgba(148, 163, 184, .2)" } }
|
splitLine: { lineStyle: { color: "rgba(148, 163, 184, .2)" } }
|
||||||
},
|
},
|
||||||
series: [{
|
series: [{
|
||||||
name: "净收款",
|
|
||||||
type: "bar",
|
type: "bar",
|
||||||
tooltip: { valueFormatter: value => `${formatChartYuan(Number(value))} 元` },
|
tooltip: { valueFormatter: value => `${formatChartYuan(Number(value))} 元` },
|
||||||
data: list.map(item => getNumber(item.netPaidAmount) / 100)
|
data: list.map(item => getNumber(item.netPaidAmount) / 100)
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ function buildOption(visibleDateTextList: string[]): EChartsOption {
|
|||||||
{
|
{
|
||||||
type: "value",
|
type: "value",
|
||||||
name: "订单",
|
name: "订单",
|
||||||
|
minInterval: 1,
|
||||||
axisLabel: { color: "#52607a" },
|
axisLabel: { color: "#52607a" },
|
||||||
splitLine: { lineStyle: { color: "rgba(148, 163, 184, .2)" } }
|
splitLine: { lineStyle: { color: "rgba(148, 163, 184, .2)" } }
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
caption="当前订单快照"
|
caption="当前订单快照"
|
||||||
:option="chartOption"
|
:option="chartOption"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
height="17rem"
|
height="6rem"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -27,16 +27,35 @@ const chartOption = computed<EChartsOption>(() => {
|
|||||||
const list = props.list;
|
const list = props.list;
|
||||||
return {
|
return {
|
||||||
...buildHorizontalBarOption(list.map(item => getPaymentStatusText(item.paymentStatus))),
|
...buildHorizontalBarOption(list.map(item => getPaymentStatusText(item.paymentStatus))),
|
||||||
legend: { show: false },
|
grid: {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
showLabel: false
|
||||||
|
},
|
||||||
series: [{
|
series: [{
|
||||||
name: "订单数",
|
|
||||||
type: "bar",
|
type: "bar",
|
||||||
data: list.map(item => getNumber(item.orderCount))
|
data: list.map(item => ({
|
||||||
|
value: getNumber(item.orderCount),
|
||||||
|
itemStyle: { color: getPaymentStatusColor(item.paymentStatus) }
|
||||||
|
}))
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
function getPaymentStatusText(value?: string): string {
|
function getPaymentStatusText(value?: string): string {
|
||||||
return ({ UNPAID: "未付款", PARTIALLY_PAID: "部分付款", PAID: "已付款" } as Record<string, string>)[value || ""] || "未知状态";
|
return ({
|
||||||
|
UNPAID: "未付款",
|
||||||
|
PARTIALLY_PAID: "部分付款",
|
||||||
|
PAID: "已付款"
|
||||||
|
} as Record<string, string>)[value || ""] || "未知状态";
|
||||||
|
}
|
||||||
|
function getPaymentStatusColor(value?: string): string {
|
||||||
|
return ({
|
||||||
|
UNPAID: "#F33434",
|
||||||
|
PARTIALLY_PAID: "#EB9C25",
|
||||||
|
PAID: "#0F766E"
|
||||||
|
} as Record<string, string>)[value || ""] || "#94A3B8";
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -2,25 +2,17 @@
|
|||||||
<section class="receivable-section">
|
<section class="receivable-section">
|
||||||
<div class="title-row">
|
<div class="title-row">
|
||||||
<h2 v-text="'应收构成'" />
|
<h2 v-text="'应收构成'" />
|
||||||
<span class="caption" v-text="'时间范围内创建订单的当前快照'" />
|
<span class="caption">成交金额拆分;待收余额已扣除待核销</span>
|
||||||
</div>
|
|
||||||
<div class="receivable-list">
|
|
||||||
<div v-for="item in detailList" :key="item.label" class="receivable-item">
|
|
||||||
<span v-text="item.label" />
|
|
||||||
<strong v-text="item.value" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div ref="chartElement" class="chart" />
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { EChartsOption } from "echarts";
|
||||||
import type { GaoSalesOrderReceivableStatView } from "@/types/GaoChart";
|
import type { GaoSalesOrderReceivableStatView } from "@/types/GaoChart";
|
||||||
import { formatMoney } from "@/pages/product/component/chartUtils";
|
import { buildPieChartOption, formatChartYuan, getNumber } from "@/pages/product/component/chartUtils";
|
||||||
|
import { useStoreChart } from "@/pages/store/component/useStoreChart";
|
||||||
type DetailItem = {
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: "OrderReceivableCard"
|
name: "OrderReceivableCard"
|
||||||
@@ -30,13 +22,40 @@ const props = defineProps<{
|
|||||||
receivable: GaoSalesOrderReceivableStatView;
|
receivable: GaoSalesOrderReceivableStatView;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const detailList = computed<DetailItem[]>(() => [
|
const chartOption = computed<EChartsOption>(() => {
|
||||||
{ label: "有效收款", value: formatMoney(props.receivable.paidAmount) },
|
const pendingPaidAmount = getNumber(props.receivable.pendingPaidAmount);
|
||||||
{ label: "待核销", value: formatMoney(props.receivable.pendingPaidAmount) },
|
const unpaidAmount = getNumber(props.receivable.unpaidAmount);
|
||||||
{ label: "未收", value: formatMoney(props.receivable.unpaidAmount) },
|
return {
|
||||||
{ label: "有效退款", value: formatMoney(props.receivable.refundedAmount) },
|
...buildPieChartOption(),
|
||||||
{ label: "净收款", value: formatMoney(props.receivable.netPaidAmount) }
|
tooltip: {
|
||||||
]);
|
trigger: "item",
|
||||||
|
confine: true,
|
||||||
|
formatter: params => {
|
||||||
|
const item = Array.isArray(params) ? params[0] : params;
|
||||||
|
return item
|
||||||
|
? `${item.name}:${formatChartYuan(Number(item.value))} 元(${item.percent}%)`
|
||||||
|
: "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: "成交金额",
|
||||||
|
type: "pie",
|
||||||
|
radius: ["0%", "58%"],
|
||||||
|
center: ["50%", "44%"],
|
||||||
|
label: { color: "#52607a", formatter: "{b} {d}%" },
|
||||||
|
data: [
|
||||||
|
{ name: "净收款", value: getNumber(props.receivable.netPaidAmount) / 100 },
|
||||||
|
{ name: "有效退款", value: getNumber(props.receivable.refundedAmount) / 100 },
|
||||||
|
{ name: "待核销", value: pendingPaidAmount / 100 },
|
||||||
|
{ name: "待收余额", value: Math.max(0, unpaidAmount - pendingPaidAmount) / 100 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const { chartElement } = useStoreChart(chartOption);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@@ -65,30 +84,9 @@ const detailList = computed<DetailItem[]>(() => [
|
|||||||
font-size: .6875rem;
|
font-size: .6875rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.receivable-list {
|
.chart {
|
||||||
gap: .5rem;
|
width: 100%;
|
||||||
display: grid;
|
height: 15rem;
|
||||||
grid-template-columns: repeat(5, minmax(0, 1fr));
|
|
||||||
}
|
|
||||||
|
|
||||||
.receivable-item {
|
|
||||||
padding: .625rem .5rem;
|
|
||||||
background: rgba(241, 245, 249, .8);
|
|
||||||
border-radius: .75rem;
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: #64748b;
|
|
||||||
display: block;
|
|
||||||
font-size: .6875rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
strong {
|
|
||||||
color: #0f172a;
|
|
||||||
margin-top: .25rem;
|
|
||||||
display: block;
|
|
||||||
font-size: .8125rem;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,23 +99,6 @@ const detailList = computed<DetailItem[]>(() => [
|
|||||||
color: #e2e8f0;
|
color: #e2e8f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.receivable-item {
|
|
||||||
background: rgba(30, 41, 59, .88);
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: #94a3b8;
|
|
||||||
}
|
|
||||||
|
|
||||||
strong {
|
|
||||||
color: #e2e8f0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 42rem) {
|
|
||||||
.receivable-list {
|
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
caption="当前订单快照"
|
caption="当前订单快照"
|
||||||
:option="chartOption"
|
:option="chartOption"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
height="17rem"
|
height="6rem"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -27,11 +27,19 @@ const chartOption = computed<EChartsOption>(() => {
|
|||||||
const list = props.list;
|
const list = props.list;
|
||||||
return {
|
return {
|
||||||
...buildHorizontalBarOption(list.map(item => getOrderStatusText(item.status))),
|
...buildHorizontalBarOption(list.map(item => getOrderStatusText(item.status))),
|
||||||
legend: { show: false },
|
grid: {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
showLabel: false
|
||||||
|
},
|
||||||
series: [{
|
series: [{
|
||||||
name: "订单数",
|
|
||||||
type: "bar",
|
type: "bar",
|
||||||
data: list.map(item => getNumber(item.orderCount))
|
data: list.map(item => ({
|
||||||
|
value: getNumber(item.orderCount),
|
||||||
|
itemStyle: { color: getOrderStatusColor(item.status) }
|
||||||
|
}))
|
||||||
}]
|
}]
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -39,4 +47,12 @@ const chartOption = computed<EChartsOption>(() => {
|
|||||||
function getOrderStatusText(value?: string): string {
|
function getOrderStatusText(value?: string): string {
|
||||||
return ({ ACTIVE: "进行中", FULFILLED: "已完成", CANCELLED: "已取消" } as Record<string, string>)[value || ""] || "未知状态";
|
return ({ ACTIVE: "进行中", FULFILLED: "已完成", CANCELLED: "已取消" } as Record<string, string>)[value || ""] || "未知状态";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getOrderStatusColor(value?: string): string {
|
||||||
|
return ({
|
||||||
|
ACTIVE: "#EB9C25",
|
||||||
|
FULFILLED: "#0F766E",
|
||||||
|
CANCELLED: "#F33434"
|
||||||
|
} as Record<string, string>)[value || ""] || "#94A3B8";
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
caption="按订单数量"
|
caption="按订单数量"
|
||||||
:option="chartOption"
|
:option="chartOption"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
height="17rem"
|
height="10rem"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -35,23 +35,43 @@ function buildOption(visibleDateTextList: string[]): EChartsOption {
|
|||||||
axisTick: { show: false },
|
axisTick: { show: false },
|
||||||
axisLabel: { color: "#52607a", interval: "auto", hideOverlap: true }
|
axisLabel: { color: "#52607a", interval: "auto", hideOverlap: true }
|
||||||
},
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: "value",
|
||||||
|
name: "基础单位",
|
||||||
|
minInterval: 1,
|
||||||
|
axisLabel: { color: "#52607a" },
|
||||||
|
splitLine: { lineStyle: { color: "rgba(148, 163, 184, .2)" } }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "value",
|
||||||
|
name: "订单",
|
||||||
|
position: "right",
|
||||||
|
minInterval: 1,
|
||||||
|
axisLabel: { color: "#52607a" },
|
||||||
|
splitLine: { show: false }
|
||||||
|
}
|
||||||
|
],
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: "直接销量",
|
name: "直接销量",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
stack: "quantity",
|
stack: "quantity",
|
||||||
|
yAxisIndex: 0,
|
||||||
data: visibleDateTextList.map(dateText => getNumber(getDailyItem(props.list, dateText)?.directBaseQuantity))
|
data: visibleDateTextList.map(dateText => getNumber(getDailyItem(props.list, dateText)?.directBaseQuantity))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "套餐权益",
|
name: "套餐权益",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
stack: "quantity",
|
stack: "quantity",
|
||||||
|
yAxisIndex: 0,
|
||||||
data: visibleDateTextList.map(dateText => getNumber(getDailyItem(props.list, dateText)?.packageBaseQuantity))
|
data: visibleDateTextList.map(dateText => getNumber(getDailyItem(props.list, dateText)?.packageBaseQuantity))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "订单数",
|
name: "订单数",
|
||||||
type: "line",
|
type: "line",
|
||||||
smooth: true,
|
smooth: true,
|
||||||
|
yAxisIndex: 1,
|
||||||
data: visibleDateTextList.map(dateText => getNumber(getDailyItem(props.list, dateText)?.orderCount))
|
data: visibleDateTextList.map(dateText => getNumber(getDailyItem(props.list, dateText)?.orderCount))
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -20,8 +20,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="item in sortedList" :key="item.productId">
|
<tr v-for="item in sortedList" :key="item.productId">
|
||||||
<td>
|
<td>
|
||||||
<div class="product-name" v-text="item.productName || '未命名产品'" />
|
<div class="product-name" v-text="item.productName + '长名称长名称长名称长名称长名称长名称长名称长名称长名称' || '未命名产品'" />
|
||||||
<div class="product-type" v-text="getProductTypeText(item.productType)" />
|
|
||||||
<div v-if="hasLowStockSku(item)" class="sku-list">
|
<div v-if="hasLowStockSku(item)" class="sku-list">
|
||||||
<div v-for="sku in getLowStockSkuList(item)" :key="`${sku.skuId}-${sku.skuCode}`" class="sku-item">
|
<div v-for="sku in getLowStockSkuList(item)" :key="`${sku.skuId}-${sku.skuCode}`" class="sku-item">
|
||||||
<span v-text="getSkuName(sku)" />
|
<span v-text="getSkuName(sku)" />
|
||||||
@@ -73,10 +72,6 @@ function getLowStockSkuList(item: GaoProductStockHealthView): GaoProductSkuStock
|
|||||||
function getSkuName(item: GaoProductSkuStockHealthView): string {
|
function getSkuName(item: GaoProductSkuStockHealthView): string {
|
||||||
return [item.skuName || "未命名规格", item.specSummary].filter(Boolean).join(" · ");
|
return [item.skuName || "未命名规格", item.specSummary].filter(Boolean).join(" · ");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProductTypeText(value?: string): string {
|
|
||||||
return ({ SERVICE: "服务", GOODS: "商品", CONSUMABLE: "耗材" } as Record<string, string>)[value || ""] || "未分类";
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
@@ -118,14 +113,14 @@ function getProductTypeText(value?: string): string {
|
|||||||
|
|
||||||
th {
|
th {
|
||||||
color: #94a3b8;
|
color: #94a3b8;
|
||||||
padding: .5rem .375rem;
|
padding: .25rem;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
td {
|
td {
|
||||||
color: #334155;
|
color: #334155;
|
||||||
padding: .625rem .375rem;
|
padding: .25rem;
|
||||||
border-top: 1px solid rgba(148, 163, 184, .16);
|
border-top: 1px solid rgba(148, 163, 184, .16);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +130,7 @@ function getProductTypeText(value?: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.product-name {
|
.product-name {
|
||||||
max-width: 7rem;
|
max-width: 6rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ function buildOption(visibleDateTextList: string[]): EChartsOption {
|
|||||||
xAxis: {
|
xAxis: {
|
||||||
type: "category",
|
type: "category",
|
||||||
data: labelList,
|
data: labelList,
|
||||||
|
axisLine: { onZero: true },
|
||||||
axisTick: { show: false },
|
axisTick: { show: false },
|
||||||
axisLabel: { color: "#52607a", interval: "auto", hideOverlap: true }
|
axisLabel: { color: "#52607a", interval: "auto", hideOverlap: true }
|
||||||
},
|
},
|
||||||
@@ -39,12 +40,12 @@ function buildOption(visibleDateTextList: string[]): EChartsOption {
|
|||||||
{
|
{
|
||||||
name: "入库",
|
name: "入库",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
data: visibleDateTextList.map(dateText => getNumber(getDailyItem(props.list, dateText)?.inQuantity))
|
data: visibleDateTextList.map(dateText => Math.abs(getNumber(getDailyItem(props.list, dateText)?.inQuantity)))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "出库",
|
name: "出库",
|
||||||
type: "bar",
|
type: "bar",
|
||||||
data: visibleDateTextList.map(dateText => getNumber(getDailyItem(props.list, dateText)?.outQuantity))
|
data: visibleDateTextList.map(dateText => -Math.abs(getNumber(getDailyItem(props.list, dateText)?.outQuantity)))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "库存净变化",
|
name: "库存净变化",
|
||||||
@@ -55,12 +56,12 @@ function buildOption(visibleDateTextList: string[]): EChartsOption {
|
|||||||
{
|
{
|
||||||
name: "新增预占",
|
name: "新增预占",
|
||||||
type: "line",
|
type: "line",
|
||||||
data: visibleDateTextList.map(dateText => getNumber(getDailyItem(props.list, dateText)?.reserveQuantity))
|
data: visibleDateTextList.map(dateText => Math.abs(getNumber(getDailyItem(props.list, dateText)?.reserveQuantity)))
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "释放预占",
|
name: "释放预占",
|
||||||
type: "line",
|
type: "line",
|
||||||
data: visibleDateTextList.map(dateText => getNumber(getDailyItem(props.list, dateText)?.releaseQuantity))
|
data: visibleDateTextList.map(dateText => -Math.abs(getNumber(getDailyItem(props.list, dateText)?.releaseQuantity)))
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -56,10 +56,10 @@ export function buildHorizontalBarOption(categoryList: string[]): EChartsOption
|
|||||||
return {
|
return {
|
||||||
color: chartColorList,
|
color: chartColorList,
|
||||||
grid: {
|
grid: {
|
||||||
top: 12,
|
top: 32,
|
||||||
left: 8,
|
left: 0,
|
||||||
right: 18,
|
right: 0,
|
||||||
bottom: 12,
|
bottom: 0,
|
||||||
containLabel: true
|
containLabel: true
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
|
|||||||
Reference in New Issue
Block a user