fix sku display
This commit is contained in:
@@ -89,10 +89,6 @@ html.theme-dark body {
|
|||||||
text-overflow: unset;
|
text-overflow: unset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.t-cell__description {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.t-dialog__footer {
|
.t-dialog__footer {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
>
|
>
|
||||||
<span class="picker-text" v-text="selectedProductName || props.placeholder" />
|
<span class="picker-text" v-text="selectedProductName || props.placeholder" />
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
|
<product-sku-form-item :sku="selectedSku" :unit="selectedUnit" />
|
||||||
<bottom-popup
|
<bottom-popup
|
||||||
v-model="visible"
|
v-model="visible"
|
||||||
title="选择产品 SKU"
|
title="选择产品 SKU"
|
||||||
@@ -103,6 +104,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { BottomPopup } from "timi-tdesign-mobile";
|
import { BottomPopup } from "timi-tdesign-mobile";
|
||||||
import ProductAPI from "@/api/ProductAPI";
|
import ProductAPI from "@/api/ProductAPI";
|
||||||
|
import ProductSkuFormItem from "@/components/ProductSkuFormItem.vue";
|
||||||
import type {
|
import type {
|
||||||
Product,
|
Product,
|
||||||
ProductSelection,
|
ProductSelection,
|
||||||
@@ -143,6 +145,8 @@ const selectedProduct = computed(() => {
|
|||||||
return props.selectedProduct || productList.value.find(item => item.skuList?.some(sku => sku.id === props.modelValue?.skuId));
|
return props.selectedProduct || productList.value.find(item => item.skuList?.some(sku => sku.id === props.modelValue?.skuId));
|
||||||
});
|
});
|
||||||
const selectedProductName = computed(() => selectedProduct.value?.name || "");
|
const selectedProductName = computed(() => selectedProduct.value?.name || "");
|
||||||
|
const selectedSku = computed(() => selectedProduct.value?.skuList?.find(sku => sku.id === props.modelValue?.skuId));
|
||||||
|
const selectedUnit = computed(() => selectedSku.value?.unitList?.find(unit => unit.id === props.modelValue?.skuUnitId));
|
||||||
const filteredProductList = computed(() => {
|
const filteredProductList = computed(() => {
|
||||||
const text = keyword.value.toLocaleLowerCase();
|
const text = keyword.value.toLocaleLowerCase();
|
||||||
return productList.value.filter(item => !text || `${item.name}${item.code}`.toLocaleLowerCase().includes(text));
|
return productList.value.filter(item => !text || `${item.name}${item.code}`.toLocaleLowerCase().includes(text));
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<template>
|
||||||
|
<t-form-item v-if="skuText || unitText" label="产品 SKU" content-align="right">
|
||||||
|
<product-sku-tags :fallback="skuText" :unit="unitText" />
|
||||||
|
</t-form-item>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import ProductSkuTags from "@/components/ProductSkuTags.vue";
|
||||||
|
import type { ProductSku, ProductSkuUnit } from "@/types/Product";
|
||||||
|
|
||||||
|
defineOptions({ name: "ProductSkuFormItem" });
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
sku?: ProductSku;
|
||||||
|
unit?: ProductSkuUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>();
|
||||||
|
|
||||||
|
const skuText = computed(() => props.sku?.name?.trim() || props.sku?.specSummary?.trim() || "");
|
||||||
|
const unitText = computed(() => props.unit?.name?.trim() || "");
|
||||||
|
</script>
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
variant="light-outline"
|
variant="light-outline"
|
||||||
:content="tag.content"
|
:content="tag.content"
|
||||||
/>
|
/>
|
||||||
|
<t-tag v-if="unitText" size="small" :content="unitText" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -15,7 +16,7 @@
|
|||||||
import type { ProductSkuSpecSnapshot } from "@/types/Product";
|
import type { ProductSkuSpecSnapshot } from "@/types/Product";
|
||||||
import { getProductSkuSnapshotText } from "@/utils/product";
|
import { getProductSkuSnapshotText } from "@/utils/product";
|
||||||
|
|
||||||
defineOptions({ name: "ProductSkuSnapshotTags" });
|
defineOptions({ name: "ProductSkuTags" });
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
productName?: string | null;
|
productName?: string | null;
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
v-if="item.skuCodeSnapshot || item.skuSpecSnapshot?.length || item.skuNameSnapshot || item.specSummarySnapshot || item.unitSnapshot"
|
v-if="item.skuCodeSnapshot || item.skuSpecSnapshot?.length || item.skuNameSnapshot || item.specSummarySnapshot || item.unitSnapshot"
|
||||||
class="sku-tags"
|
class="sku-tags"
|
||||||
>
|
>
|
||||||
<product-sku-snapshot-tags
|
<product-sku-tags
|
||||||
:product-name="item.productNameSnapshot"
|
:product-name="item.productNameSnapshot"
|
||||||
:snapshot="item.skuSpecSnapshot"
|
:snapshot="item.skuSpecSnapshot"
|
||||||
:fallback="item.specSummarySnapshot || item.skuNameSnapshot"
|
:fallback="item.specSummarySnapshot || item.skuNameSnapshot"
|
||||||
@@ -128,7 +128,7 @@ import SalesOrderAPI from "@/api/SalesOrderAPI";
|
|||||||
import FulfillmentAPI from "@/api/FulfillmentAPI";
|
import FulfillmentAPI from "@/api/FulfillmentAPI";
|
||||||
import ProductAPI from "@/api/ProductAPI";
|
import ProductAPI from "@/api/ProductAPI";
|
||||||
import MediaSelector from "@/components/mediaSelector/MediaSelector.vue";
|
import MediaSelector from "@/components/mediaSelector/MediaSelector.vue";
|
||||||
import ProductSkuSnapshotTags from "@/components/ProductSkuSnapshotTags.vue";
|
import ProductSkuTags from "@/components/ProductSkuTags.vue";
|
||||||
import ProductStockPreview from "@/components/ProductStockPreview.vue";
|
import ProductStockPreview from "@/components/ProductStockPreview.vue";
|
||||||
import { useNavBarStore } from "@/store/navBarStore";
|
import { useNavBarStore } from "@/store/navBarStore";
|
||||||
import type { Attachment } from "timi-web-api";
|
import type { Attachment } from "timi-web-api";
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
<template #description>
|
<template #description>
|
||||||
<div class="item-description">
|
<div class="item-description">
|
||||||
<t-tag v-if="isGiftedFulfillmentItem(item)" size="small" theme="success" content="赠送" />
|
<t-tag v-if="isGiftedFulfillmentItem(item)" size="small" theme="success" content="赠送" />
|
||||||
<product-sku-snapshot-tags
|
<product-sku-tags
|
||||||
:product-name="item.productNameSnapshot"
|
:product-name="item.productNameSnapshot"
|
||||||
:snapshot="item.skuSpecSnapshot"
|
:snapshot="item.skuSpecSnapshot"
|
||||||
:fallback="item.specSummarySnapshot || item.skuNameSnapshot || '默认 SKU'"
|
:fallback="item.specSummarySnapshot || item.skuNameSnapshot || '默认 SKU'"
|
||||||
@@ -152,7 +152,7 @@ import FulfillmentAPI from "@/api/FulfillmentAPI";
|
|||||||
import ProductAPI from "@/api/ProductAPI";
|
import ProductAPI from "@/api/ProductAPI";
|
||||||
import SalesOrderAPI from "@/api/SalesOrderAPI";
|
import SalesOrderAPI from "@/api/SalesOrderAPI";
|
||||||
import MediaSelector from "@/components/mediaSelector/MediaSelector.vue";
|
import MediaSelector from "@/components/mediaSelector/MediaSelector.vue";
|
||||||
import ProductSkuSnapshotTags from "@/components/ProductSkuSnapshotTags.vue";
|
import ProductSkuTags from "@/components/ProductSkuTags.vue";
|
||||||
import ProductStockPreview from "@/components/ProductStockPreview.vue";
|
import ProductStockPreview from "@/components/ProductStockPreview.vue";
|
||||||
import { useNavBarStore } from "@/store/navBarStore";
|
import { useNavBarStore } from "@/store/navBarStore";
|
||||||
import type { OrderFulfillment, OrderFulfillmentItem } from "@/types/Fulfillment";
|
import type { OrderFulfillment, OrderFulfillmentItem } from "@/types/Fulfillment";
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
<t-cell
|
<t-cell
|
||||||
class="item"
|
class="item"
|
||||||
v-for="item in config.itemList || []"
|
v-for="item in config.itemList || []"
|
||||||
:title="getItemTitle(item)"
|
|
||||||
:key="item.id || `${item.skuId}-${item.skuUnitId}`"
|
:key="item.id || `${item.skuId}-${item.skuUnitId}`"
|
||||||
:note="`${item.defaultQuantity} ${item.unitSnapshot || ''}${item.remark ? `|${item.remark}` : ''}`"
|
:note="`${item.defaultQuantity} ${item.unitSnapshot || ''}${item.remark ? `|${item.remark}` : ''}`"
|
||||||
>
|
>
|
||||||
@@ -48,12 +47,14 @@
|
|||||||
v-text="(item.productNameSnapshot || '产').slice(0, 1)"
|
v-text="(item.productNameSnapshot || '产').slice(0, 1)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #description>
|
<template #title>
|
||||||
<t-tag
|
<div class="title">
|
||||||
:content="item.skuCodeSnapshot || item.sku?.code || 'SKU'"
|
<span v-text="item.productNameSnapshot || '未命名产品'" />
|
||||||
theme="primary"
|
<product-sku-tags
|
||||||
variant="light"
|
:product-name="item.productNameSnapshot"
|
||||||
/>
|
:fallback="item.specSummarySnapshot || item.skuNameSnapshot || '默认 SKU'"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</t-cell>
|
</t-cell>
|
||||||
<div v-if="!config.itemList?.length" class="empty" v-text="'暂无产品权益'" />
|
<div v-if="!config.itemList?.length" class="empty" v-text="'暂无产品权益'" />
|
||||||
@@ -82,6 +83,7 @@ import { DialogPlugin } from "tdesign-mobile-vue";
|
|||||||
import { Time } from "timi-web";
|
import { Time } from "timi-web";
|
||||||
import { useUserStore } from "timi-web-api";
|
import { useUserStore } from "timi-web-api";
|
||||||
import PackageAPI from "@/api/PackageAPI";
|
import PackageAPI from "@/api/PackageAPI";
|
||||||
|
import ProductSkuTags from "@/components/ProductSkuTags.vue";
|
||||||
import { useCurrentStoreStore } from "@/store/currentStoreStore";
|
import { useCurrentStoreStore } from "@/store/currentStoreStore";
|
||||||
import { useNavBarStore } from "@/store/navBarStore";
|
import { useNavBarStore } from "@/store/navBarStore";
|
||||||
import type { GaoPackageConfig, PackageConfigItem, PackageConfigStatus } from "@/types/Package";
|
import type { GaoPackageConfig, PackageConfigItem, PackageConfigStatus } from "@/types/Package";
|
||||||
@@ -89,7 +91,7 @@ import { getErrorMessage } from "@/utils/error";
|
|||||||
import { formatPackageAmount, getPackageConfigStatusText } from "@/utils/package";
|
import { formatPackageAmount, getPackageConfigStatusText } from "@/utils/package";
|
||||||
import { Message } from "@/utils/message";
|
import { Message } from "@/utils/message";
|
||||||
import { gaoRoleCodes, permissionCodes } from "@/utils/permission";
|
import { gaoRoleCodes, permissionCodes } from "@/utils/permission";
|
||||||
import { getProductPhotoURL as getProductPhotoUrl, getProductSkuSnapshotText } from "@/utils/product";
|
import { getProductPhotoURL as getProductPhotoUrl } from "@/utils/product";
|
||||||
|
|
||||||
defineOptions({ name: "PackageConfigDetail" });
|
defineOptions({ name: "PackageConfigDetail" });
|
||||||
|
|
||||||
@@ -116,11 +118,6 @@ function getItemPhotoURL(item: PackageConfigItem): string {
|
|||||||
return getProductPhotoUrl(item.sku || {});
|
return getProductPhotoUrl(item.sku || {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getItemTitle(item: PackageConfigItem): string {
|
|
||||||
const skuText = getProductSkuSnapshotText(item.productNameSnapshot, item.skuNameSnapshot, item.specSummarySnapshot);
|
|
||||||
return `${item.productNameSnapshot || "未命名产品"}${skuText ? ` · ${skuText}` : ""}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadData(): Promise<void> {
|
async function loadData(): Promise<void> {
|
||||||
const id = String(route.params.id || "");
|
const id = String(route.params.id || "");
|
||||||
if (!id) {
|
if (!id) {
|
||||||
@@ -286,16 +283,20 @@ onUnmounted(() => navBarStore.clearRight());
|
|||||||
.item {
|
.item {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|
||||||
.item-title {
|
:deep(.t-cell__title) {
|
||||||
gap: .5rem;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
width: 3.5rem;
|
width: 2.5rem;
|
||||||
height: 3.5rem;
|
height: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
gap: .5rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,9 +52,6 @@
|
|||||||
@update:model-value="applyProduct(index, $event)"
|
@update:model-value="applyProduct(index, $event)"
|
||||||
@select="applyProductSelection(index, $event)"
|
@select="applyProductSelection(index, $event)"
|
||||||
/>
|
/>
|
||||||
<t-form-item v-if="item.skuId" label="SKU 单位" content-align="right">
|
|
||||||
<span v-text="getUnit(item)?.name || '未选择单位'" />
|
|
||||||
</t-form-item>
|
|
||||||
<t-form-item label="默认配额" content-align="right" required-mark>
|
<t-form-item label="默认配额" content-align="right" required-mark>
|
||||||
<t-stepper
|
<t-stepper
|
||||||
v-model="item.defaultQuantity"
|
v-model="item.defaultQuantity"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
v-model="selection"
|
v-model="selection"
|
||||||
:selected-product="form.product"
|
:selected-product="form.product"
|
||||||
required-mark
|
required-mark
|
||||||
|
@select="handleProductSelection"
|
||||||
/>
|
/>
|
||||||
<t-form-item label="默认积分" required-mark>
|
<t-form-item label="默认积分" required-mark>
|
||||||
<t-input
|
<t-input
|
||||||
@@ -34,10 +35,14 @@
|
|||||||
<t-textarea v-model.trim="form.remark" maxlength="500" autosize />
|
<t-textarea v-model.trim="form.remark" maxlength="500" autosize />
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
</t-form>
|
</t-form>
|
||||||
<div v-if="form.id" class="actions" v-entrance-transition="70">
|
<t-button
|
||||||
<t-button class="bg-white" theme="danger" variant="outline" @click="disable">停用配置</t-button>
|
v-if="form.id"
|
||||||
<t-button theme="danger" @click="remove">删除</t-button>
|
class="cell-button"
|
||||||
</div>
|
theme="danger"
|
||||||
|
v-entrance-transition="70"
|
||||||
|
content="删除"
|
||||||
|
@click="remove"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<t-popup v-model="statusVisible" placement="bottom">
|
<t-popup v-model="statusVisible" placement="bottom">
|
||||||
<t-picker
|
<t-picker
|
||||||
@@ -55,6 +60,7 @@ import PointAPI from "@/api/PointAPI";
|
|||||||
import ProductSelector from "@/components/ProductSelector.vue";
|
import ProductSelector from "@/components/ProductSelector.vue";
|
||||||
import { useNavBarStore } from "@/store/navBarStore";
|
import { useNavBarStore } from "@/store/navBarStore";
|
||||||
import type { PointRedeemSku, PointRedeemSkuStatus } from "@/types/Point";
|
import type { PointRedeemSku, PointRedeemSkuStatus } from "@/types/Point";
|
||||||
|
import type { ProductSelection } from "@/types/Product";
|
||||||
import { getErrorMessage } from "@/utils/error";
|
import { getErrorMessage } from "@/utils/error";
|
||||||
import { Message } from "@/utils/message";
|
import { Message } from "@/utils/message";
|
||||||
import { normalizePackageQuantity } from "@/utils/package";
|
import { normalizePackageQuantity } from "@/utils/package";
|
||||||
@@ -71,6 +77,8 @@ const isSaving = ref(false);
|
|||||||
const form = reactive({
|
const form = reactive({
|
||||||
id: "",
|
id: "",
|
||||||
product: undefined as PointRedeemSku["product"],
|
product: undefined as PointRedeemSku["product"],
|
||||||
|
sku: undefined as PointRedeemSku["sku"],
|
||||||
|
unit: undefined as PointRedeemSku["unit"],
|
||||||
pointText: "",
|
pointText: "",
|
||||||
status: "DRAFT" as PointRedeemSkuStatus,
|
status: "DRAFT" as PointRedeemSkuStatus,
|
||||||
totalText: "",
|
totalText: "",
|
||||||
@@ -97,6 +105,12 @@ function parseLimit(value: string): string | null | undefined {
|
|||||||
return value ? normalizePackageQuantity(value) : null;
|
return value ? normalizePackageQuantity(value) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleProductSelection(value: ProductSelection): void {
|
||||||
|
form.product = value.product;
|
||||||
|
form.sku = value.sku;
|
||||||
|
form.unit = value.unit;
|
||||||
|
}
|
||||||
|
|
||||||
function confirmStatus(value: Array<string | number>): void {
|
function confirmStatus(value: Array<string | number>): void {
|
||||||
form.status = String(value[0]) as PointRedeemSkuStatus;
|
form.status = String(value[0]) as PointRedeemSkuStatus;
|
||||||
statusVisible.value = false;
|
statusVisible.value = false;
|
||||||
@@ -110,6 +124,8 @@ async function load(): Promise<void> {
|
|||||||
const item = await PointAPI.redeemSkuDetail(id);
|
const item = await PointAPI.redeemSkuDetail(id);
|
||||||
form.id = item.id || "";
|
form.id = item.id || "";
|
||||||
form.product = item.product;
|
form.product = item.product;
|
||||||
|
form.sku = item.sku;
|
||||||
|
form.unit = item.unit;
|
||||||
selection.value = item.skuId && item.skuUnitId ? { skuId: item.skuId, skuUnitId: item.skuUnitId } : undefined;
|
selection.value = item.skuId && item.skuUnitId ? { skuId: item.skuId, skuUnitId: item.skuUnitId } : undefined;
|
||||||
form.pointText = String(item.defaultPointCost || "");
|
form.pointText = String(item.defaultPointCost || "");
|
||||||
form.status = item.status || "DRAFT";
|
form.status = item.status || "DRAFT";
|
||||||
@@ -155,22 +171,6 @@ async function save(): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function disable(): Promise<void> {
|
|
||||||
if (!form.id || isSaving.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
isSaving.value = true;
|
|
||||||
try {
|
|
||||||
await PointAPI.redeemSkuDisable(form.id);
|
|
||||||
Message.success("兑换配置已停用");
|
|
||||||
await router.replace({ name: "PointRedeemSkuList" });
|
|
||||||
} catch (error) {
|
|
||||||
Message.error(getErrorMessage(error, "兑换配置停用失败"));
|
|
||||||
} finally {
|
|
||||||
isSaving.value = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function remove(): Promise<void> {
|
async function remove(): Promise<void> {
|
||||||
if (!form.id || isSaving.value) {
|
if (!form.id || isSaving.value) {
|
||||||
return;
|
return;
|
||||||
@@ -209,17 +209,5 @@ onUnmounted(() => navBarStore.clearRight());
|
|||||||
.tips {
|
.tips {
|
||||||
font-size: .875rem;
|
font-size: .875rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.actions {
|
|
||||||
--td-button-border-radius: 1rem;
|
|
||||||
|
|
||||||
gap: .75rem;
|
|
||||||
margin: 0 1rem;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.t-button {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -16,8 +16,8 @@
|
|||||||
v-for="(item, index) in result.list"
|
v-for="(item, index) in result.list"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
class="item"
|
class="item"
|
||||||
|
:title="item.product?.name || item.sku?.name || '未命名产品'"
|
||||||
arrow
|
arrow
|
||||||
:description="item.unit?.name || '单位未知'"
|
|
||||||
v-entrance-transition="index * 30"
|
v-entrance-transition="index * 30"
|
||||||
@click="toEdit(item)"
|
@click="toEdit(item)"
|
||||||
>
|
>
|
||||||
@@ -35,19 +35,23 @@
|
|||||||
v-text="(item.product?.name || item.sku?.name || '产').slice(0, 1)"
|
v-text="(item.product?.name || item.sku?.name || '产').slice(0, 1)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #title>
|
<template #note>
|
||||||
<div class="title">
|
<span class="orange" v-text="formatPoint(item.defaultPointCost)" />
|
||||||
<strong v-text="item.product?.name || item.sku?.name || '未命名产品'" />
|
</template>
|
||||||
|
<template #description>
|
||||||
|
<div class="description">
|
||||||
<t-tag
|
<t-tag
|
||||||
size="small"
|
size="small"
|
||||||
:theme="item.status === 'ACTIVE' ? 'success' : 'default'"
|
:theme="item.status === 'ACTIVE' ? 'success' : 'default'"
|
||||||
:content="statusText(item.status)"
|
:content="statusText(item.status)"
|
||||||
/>
|
/>
|
||||||
|
<product-sku-tags
|
||||||
|
:product-name="item.product?.name"
|
||||||
|
:fallback="item.sku?.specSummary || item.sku?.name || '默认 SKU'"
|
||||||
|
:unit="item.unit?.name"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #note>
|
|
||||||
<span class="orange" v-text="formatPoint(item.defaultPointCost)" />
|
|
||||||
</template>
|
|
||||||
</t-cell>
|
</t-cell>
|
||||||
</t-cell-group>
|
</t-cell-group>
|
||||||
<t-empty v-else :description="isLoading ? '正在加载兑换配置' : '暂无兑换配置'" />
|
<t-empty v-else :description="isLoading ? '正在加载兑换配置' : '暂无兑换配置'" />
|
||||||
@@ -63,6 +67,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Toolkit } from "timi-web";
|
import { Toolkit } from "timi-web";
|
||||||
import PointAPI from "@/api/PointAPI";
|
import PointAPI from "@/api/PointAPI";
|
||||||
|
import ProductSkuTags from "@/components/ProductSkuTags.vue";
|
||||||
import { useNavBarStore } from "@/store/navBarStore";
|
import { useNavBarStore } from "@/store/navBarStore";
|
||||||
import type { PointRedeemSku, PointRedeemSkuStatus } from "@/types/Point";
|
import type { PointRedeemSku, PointRedeemSkuStatus } from "@/types/Point";
|
||||||
import { Message } from "@/utils/message";
|
import { Message } from "@/utils/message";
|
||||||
@@ -202,12 +207,16 @@ onUnmounted(() => {
|
|||||||
|
|
||||||
.item {
|
.item {
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-radius: 1rem;
|
|
||||||
|
|
||||||
.avatar {
|
.avatar {
|
||||||
width: 3.5rem;
|
width: 3.5rem;
|
||||||
height: 3.5rem;
|
height: 3.5rem;
|
||||||
border-radius: .875rem;
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
gap: .5rem;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,10 @@
|
|||||||
<t-form-item label="兑换商品" required-mark content-align="right" arrow @click="skuVisible = true">
|
<t-form-item label="兑换商品" required-mark content-align="right" arrow @click="skuVisible = true">
|
||||||
<span v-text="skuName || '请选择兑换商品'" />
|
<span v-text="skuName || '请选择兑换商品'" />
|
||||||
</t-form-item>
|
</t-form-item>
|
||||||
|
<product-sku-form-item
|
||||||
|
:sku="selectedSku?.sku"
|
||||||
|
:unit="selectedSku?.unit"
|
||||||
|
/>
|
||||||
<t-form-item label="兑换数量" content-align="right" required-mark>
|
<t-form-item label="兑换数量" content-align="right" required-mark>
|
||||||
<t-stepper
|
<t-stepper
|
||||||
v-model="quantity"
|
v-model="quantity"
|
||||||
@@ -97,10 +101,26 @@
|
|||||||
v-for="item in skuList"
|
v-for="item in skuList"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
:title="item.product?.name || item.sku?.name || '未命名产品'"
|
:title="item.product?.name || item.sku?.name || '未命名产品'"
|
||||||
:note="`${item.sku?.specSummary || item.sku?.code || '默认 SKU'} · ${item.unit?.name || ''} · ${formatPoint(item.defaultPointCost)} / 单位`"
|
:note="`${formatPoint(item.defaultPointCost)} / ${item.unit?.name || '单位未知'}`"
|
||||||
|
class="item"
|
||||||
arrow
|
arrow
|
||||||
@click="selectSku(item)"
|
@click="selectSku(item)"
|
||||||
/>
|
>
|
||||||
|
<template #left-icon>
|
||||||
|
<t-image
|
||||||
|
v-if="getProductPhoto(item)"
|
||||||
|
:src="getProductPhoto(item)"
|
||||||
|
:alt="item.product?.name || item.sku?.name || '产品图片'"
|
||||||
|
fit="cover"
|
||||||
|
class="avatar"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="avatar fallback"
|
||||||
|
v-text="(item.product?.name || item.sku?.name || '产').slice(0, 1)"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</t-cell>
|
||||||
<t-empty v-if="!skuList.length" description="暂无启用的兑换商品" />
|
<t-empty v-if="!skuList.length" description="暂无启用的兑换商品" />
|
||||||
</div>
|
</div>
|
||||||
</bottom-popup>
|
</bottom-popup>
|
||||||
@@ -124,7 +144,7 @@ import { getErrorMessage } from "@/utils/error";
|
|||||||
import { Message } from "@/utils/message";
|
import { Message } from "@/utils/message";
|
||||||
import { formatWanInteger } from "@/utils/money";
|
import { formatWanInteger } from "@/utils/money";
|
||||||
import { normalizePackageQuantity } from "@/utils/package";
|
import { normalizePackageQuantity } from "@/utils/package";
|
||||||
import { getProductQuantityStep } from "@/utils/product";
|
import { getProductPhotoURL, getProductQuantityStep } from "@/utils/product";
|
||||||
import { uploadPhotoList } from "@/utils/photo";
|
import { uploadPhotoList } from "@/utils/photo";
|
||||||
import { permissionCodes } from "@/utils/permission";
|
import { permissionCodes } from "@/utils/permission";
|
||||||
|
|
||||||
@@ -254,6 +274,11 @@ function selectSku(item: PointRedeemSku): void {
|
|||||||
skuVisible.value = false;
|
skuVisible.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getProductPhoto(item: PointRedeemSku): string {
|
||||||
|
const product = item.product || item.sku;
|
||||||
|
return product ? getProductPhotoURL(product) : "";
|
||||||
|
}
|
||||||
|
|
||||||
function closeSkuPicker(): void {
|
function closeSkuPicker(): void {
|
||||||
skuVisible.value = false;
|
skuVisible.value = false;
|
||||||
}
|
}
|
||||||
@@ -351,6 +376,32 @@ onUnmounted(() => navBarStore.clearRight());
|
|||||||
max-height: 70vh;
|
max-height: 70vh;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
padding: 1rem 0;
|
padding: 1rem 0;
|
||||||
|
|
||||||
|
.item {
|
||||||
|
padding: .625rem 1rem;
|
||||||
|
border-radius: 1rem;
|
||||||
|
|
||||||
|
:deep(.t-cell__title) {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
width: 2.5rem;
|
||||||
|
height: 2.5rem;
|
||||||
|
border-radius: .5rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fallback {
|
||||||
|
color: var(--td-brand-color);
|
||||||
|
display: flex;
|
||||||
|
font-size: 1rem;
|
||||||
|
background: var(--td-brand-color-1);
|
||||||
|
font-weight: 600;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(html.theme-dark) {
|
:global(html.theme-dark) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<section class="snapshot-head" v-entrance-transition>
|
<section class="snapshot-head" v-entrance-transition>
|
||||||
<div class="eyebrow">库存 SKU 快照</div>
|
<div class="eyebrow">库存 SKU 快照</div>
|
||||||
<h2 v-text="record.productNameSnapshot || '未命名产品'" />
|
<h2 v-text="record.productNameSnapshot || '未命名产品'" />
|
||||||
<product-sku-snapshot-tags
|
<product-sku-tags
|
||||||
class="sku"
|
class="sku"
|
||||||
:product-name="record.productNameSnapshot"
|
:product-name="record.productNameSnapshot"
|
||||||
:snapshot="record.skuSpecSnapshot"
|
:snapshot="record.skuSpecSnapshot"
|
||||||
@@ -138,7 +138,7 @@ import { PassTimeLabel } from "timi-web";
|
|||||||
import { useUserStore, type Attachment } from "timi-web-api";
|
import { useUserStore, type Attachment } from "timi-web-api";
|
||||||
import ProductAPI from "@/api/ProductAPI";
|
import ProductAPI from "@/api/ProductAPI";
|
||||||
import MediaSelector from "@/components/mediaSelector/MediaSelector.vue";
|
import MediaSelector from "@/components/mediaSelector/MediaSelector.vue";
|
||||||
import ProductSkuSnapshotTags from "@/components/ProductSkuSnapshotTags.vue";
|
import ProductSkuTags from "@/components/ProductSkuTags.vue";
|
||||||
import { useNavBarStore } from "@/store/navBarStore";
|
import { useNavBarStore } from "@/store/navBarStore";
|
||||||
import type { PhotoItem } from "@/types/Photo";
|
import type { PhotoItem } from "@/types/Photo";
|
||||||
import type { StockBizType, StockRecord } from "@/types/Product";
|
import type { StockBizType, StockRecord } from "@/types/Product";
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ const editorVisible = ref(false);
|
|||||||
const skuEditorZIndex = 12000;
|
const skuEditorZIndex = 12000;
|
||||||
const photoUrlList = computed(() => sku.value.photoItemList.map(item => item.url));
|
const photoUrlList = computed(() => sku.value.photoItemList.map(item => item.url));
|
||||||
const skuSpecEntries = computed(() => getProductSkuSpecEntries(sku.value, props.specList));
|
const skuSpecEntries = computed(() => getProductSkuSpecEntries(sku.value, props.specList));
|
||||||
const skuTitle = computed(() => props.specList.length ? `SKU 明细 ${props.skuIndex + 1}` : "默认 SKU");
|
const skuTitle = computed(() => sku.value.name?.trim() || sku.value.specSummary?.trim() || (props.specList.length ? `SKU 明细 ${props.skuIndex + 1}` : "默认 SKU"));
|
||||||
|
|
||||||
function openEditor(): void {
|
function openEditor(): void {
|
||||||
editorVisible.value = true;
|
editorVisible.value = true;
|
||||||
|
|||||||
@@ -62,9 +62,6 @@
|
|||||||
required-mark
|
required-mark
|
||||||
@update:model-value="applyProduct(index, $event)"
|
@update:model-value="applyProduct(index, $event)"
|
||||||
/>
|
/>
|
||||||
<t-form-item v-if="item.skuId" label="SKU 单位" content-align="right">
|
|
||||||
<span v-text="getUnit(item)?.name || '未选择单位'" />
|
|
||||||
</t-form-item>
|
|
||||||
<t-form-item :label="canPriceOverride ? '成交单价' : '单价'">
|
<t-form-item :label="canPriceOverride ? '成交单价' : '单价'">
|
||||||
<t-input
|
<t-input
|
||||||
v-model.trim="item.unitPriceText"
|
v-model.trim="item.unitPriceText"
|
||||||
|
|||||||
@@ -113,7 +113,7 @@
|
|||||||
v-text="`¥${formatPackageAmount(item.lineAmount)}`"
|
v-text="`¥${formatPackageAmount(item.lineAmount)}`"
|
||||||
/>
|
/>
|
||||||
<t-tag v-else size="small" content="套餐权益" />
|
<t-tag v-else size="small" content="套餐权益" />
|
||||||
<product-sku-snapshot-tags
|
<product-sku-tags
|
||||||
:product-name="item.productNameSnapshot"
|
:product-name="item.productNameSnapshot"
|
||||||
:snapshot="item.skuSpecSnapshot"
|
:snapshot="item.skuSpecSnapshot"
|
||||||
:fallback="item.specSummarySnapshot || item.skuNameSnapshot"
|
:fallback="item.specSummarySnapshot || item.skuNameSnapshot"
|
||||||
@@ -226,7 +226,7 @@ import FulfillmentAPI from "@/api/FulfillmentAPI";
|
|||||||
import SalesOrderAPI from "@/api/SalesOrderAPI";
|
import SalesOrderAPI from "@/api/SalesOrderAPI";
|
||||||
import CustomerProfileCard from "@/components/CustomerProfileCard.vue";
|
import CustomerProfileCard from "@/components/CustomerProfileCard.vue";
|
||||||
import MediaSelector from "@/components/mediaSelector/MediaSelector.vue";
|
import MediaSelector from "@/components/mediaSelector/MediaSelector.vue";
|
||||||
import ProductSkuSnapshotTags from "@/components/ProductSkuSnapshotTags.vue";
|
import ProductSkuTags from "@/components/ProductSkuTags.vue";
|
||||||
import { useNavBarStore } from "@/store/navBarStore";
|
import { useNavBarStore } from "@/store/navBarStore";
|
||||||
import type { GaoSalesOrderItem, GaoSalesPaymentStatus, SalesOrder } from "@/types/SalesOrder";
|
import type { GaoSalesOrderItem, GaoSalesPaymentStatus, SalesOrder } from "@/types/SalesOrder";
|
||||||
import type { PhotoItem } from "@/types/Photo";
|
import type { PhotoItem } from "@/types/Photo";
|
||||||
|
|||||||
Reference in New Issue
Block a user