add product stock preview
This commit is contained in:
@@ -203,7 +203,7 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { BottomPopup } from "timi-tdesign-mobile";
|
||||
import type { ColorObject } from "tdesign-mobile-vue";
|
||||
import { DialogPlugin, type ColorObject } from "tdesign-mobile-vue";
|
||||
import { type Attachment, AttachmentAPI, useUserStore } from "timi-web-api";
|
||||
import ProductAPI from "@/api/ProductAPI";
|
||||
import PhotoScroller from "@/components/PhotoScroller.vue";
|
||||
@@ -212,7 +212,7 @@ import ProductSkuUnitEditor from "@/pages/product/component/ProductSkuUnitEditor
|
||||
import ProductSkuUnitBatchEditor from "@/pages/product/component/ProductSkuUnitBatchEditor.vue";
|
||||
import { useNavBarStore } from "@/store/navBarStore";
|
||||
import type { PhotoItem } from "@/types/Photo";
|
||||
import type { Product, ProductAttachmentType, ProductCategory, ProductSku, ProductSkuUnit, ProductSpec } from "@/types/Product";
|
||||
import type { Product, ProductAttachmentType, ProductCategory, ProductSku, ProductSkuUnit, ProductSpec, ProductType } from "@/types/Product";
|
||||
import type { ProductAttachmentItem, ProductForm, ProductSkuForm as SkuForm, ProductSkuUnitForm as UnitForm, ProductSpecForm as SpecForm, ProductSpecValueForm as SpecValueForm } from "@/types/ProductEditor";
|
||||
import { compressUploadImage } from "@/utils/imageCompression";
|
||||
import { getAttachmentReadURL } from "@/utils/attachment";
|
||||
@@ -464,19 +464,64 @@ function openTypePicker(): void {
|
||||
typePickerVisible.value = true;
|
||||
}
|
||||
|
||||
function confirmType(value: Array<string | number>): void {
|
||||
async function confirmType(value: Array<string | number>): Promise<void> {
|
||||
const type = String(value[0] || "");
|
||||
if (type === "SERVICE" || type === "GOODS" || type === "CONSUMABLE") {
|
||||
form.productType = type;
|
||||
if (type === "SERVICE") {
|
||||
form.stockEnabled = false;
|
||||
form.skuList.forEach(sku => {
|
||||
sku.stockEnabled = false;
|
||||
sku.unitList.forEach(unit => { unit.allowPurchase = false; });
|
||||
});
|
||||
}
|
||||
if (type !== "SERVICE" && type !== "GOODS" && type !== "CONSUMABLE") {
|
||||
typePickerVisible.value = false;
|
||||
return;
|
||||
}
|
||||
typePickerVisible.value = false;
|
||||
if (type !== "SERVICE" || form.productType === "SERVICE") {
|
||||
applyProductType(type);
|
||||
return;
|
||||
}
|
||||
if (!await canChangeToService()) {
|
||||
return;
|
||||
}
|
||||
const dialog = DialogPlugin.confirm({
|
||||
title: "切换为服务产品",
|
||||
content: "切换后将关闭产品及全部 SKU 的库存管理,并清空最低库存设置;已有库存流水会保留。确定继续吗?",
|
||||
cancelBtn: "取消",
|
||||
confirmBtn: "确定切换",
|
||||
onCancel() {
|
||||
dialog.destroy();
|
||||
},
|
||||
onConfirm() {
|
||||
dialog.destroy();
|
||||
applyProductType("SERVICE");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function applyProductType(type: ProductType): void {
|
||||
form.productType = type;
|
||||
if (type !== "SERVICE") {
|
||||
return;
|
||||
}
|
||||
form.stockEnabled = false;
|
||||
form.skuList.forEach(sku => {
|
||||
sku.stockEnabled = false;
|
||||
sku.minStockQuantityText = "";
|
||||
sku.unitList.forEach(unit => { unit.allowPurchase = false; });
|
||||
});
|
||||
}
|
||||
|
||||
async function canChangeToService(): Promise<boolean> {
|
||||
const skuIdList = form.skuList.map(sku => sku.id).filter((id): id is string => !!id);
|
||||
if (!skuIdList.length) {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
const stockList = await ProductAPI.stockBatchDetail({ skuIdList });
|
||||
if (stockList.some(stock => 0 < Number(stock.reservedQuantity || 0))) {
|
||||
Message.warning("当前产品存在预占库存,不能切换为服务产品,请先完成或取消相关订单");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (error) {
|
||||
Message.error(getErrorMessage(error, "无法确认预占库存,暂不能切换为服务产品"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function openCategoryPicker(): void {
|
||||
|
||||
@@ -29,7 +29,14 @@
|
||||
@click="toSkuList(item)"
|
||||
>
|
||||
<template #leftIcon>
|
||||
<div class="avatar fallback" v-text="(item.productName || '产').slice(0, 1)" />
|
||||
<t-image
|
||||
v-if="getProductPhotoURL(item)"
|
||||
:src="getProductPhotoURL(item)"
|
||||
:alt="item.productName || '产品图片'"
|
||||
fit="cover"
|
||||
class="avatar"
|
||||
/>
|
||||
<div v-else class="avatar fallback" v-text="(item.productName || '产').slice(0, 1)" />
|
||||
</template>
|
||||
<template #title>
|
||||
<div class="title">
|
||||
@@ -67,7 +74,7 @@ import ProductAPI from "@/api/ProductAPI";
|
||||
import { useNavBarStore } from "@/store/navBarStore";
|
||||
import type { ProductStockProduct } from "@/types/Product";
|
||||
import { getErrorMessage } from "@/utils/error";
|
||||
import { getProductQuantityText } from "@/utils/product";
|
||||
import { getProductPhotoURL, getProductQuantityText } from "@/utils/product";
|
||||
import { Message } from "@/utils/message";
|
||||
import { permissionCodes } from "@/utils/permission";
|
||||
|
||||
|
||||
@@ -32,7 +32,14 @@
|
||||
@click="toDetail(item)"
|
||||
>
|
||||
<template #leftIcon>
|
||||
<div class="avatar fallback" v-text="(item.sku?.name || 'S').slice(0, 1)" />
|
||||
<t-image
|
||||
v-if="getSkuPhotoURL(item)"
|
||||
:src="getSkuPhotoURL(item)"
|
||||
:alt="item.sku?.name || 'SKU 图片'"
|
||||
fit="cover"
|
||||
class="avatar"
|
||||
/>
|
||||
<div v-else class="avatar fallback" v-text="(item.sku?.name || 'S').slice(0, 1)" />
|
||||
</template>
|
||||
<template #title>
|
||||
<div class="title">
|
||||
@@ -71,7 +78,7 @@ import ProductAPI from "@/api/ProductAPI";
|
||||
import { useNavBarStore } from "@/store/navBarStore";
|
||||
import type { Product, ProductStock } from "@/types/Product";
|
||||
import { getErrorMessage } from "@/utils/error";
|
||||
import { getProductQuantityText } from "@/utils/product";
|
||||
import { getProductPhotoURL, getProductQuantityText } from "@/utils/product";
|
||||
import { Message } from "@/utils/message";
|
||||
import { permissionCodes } from "@/utils/permission";
|
||||
|
||||
@@ -102,6 +109,11 @@ const emptyText = computed(() => {
|
||||
}
|
||||
return "该产品暂无启用库存管理的 SKU";
|
||||
});
|
||||
|
||||
function getSkuPhotoURL(item: ProductStock): string {
|
||||
return item.sku ? getProductPhotoURL(item.sku) : "";
|
||||
}
|
||||
|
||||
let keywordTimer: number | undefined;
|
||||
let requestToken = 0;
|
||||
let suppressKeywordFetch = false;
|
||||
|
||||
Reference in New Issue
Block a user