fix: 修复商品模块typecheck与lint
All checks were successful
Build and Deploy TenantUI / build-and-deploy (push) Successful in 51s
All checks were successful
Build and Deploy TenantUI / build-and-deploy (push) Successful in 51s
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { UploadProps } from 'ant-design-vue';
|
import type { UploadProps } from 'ant-design-vue';
|
||||||
|
|
||||||
import { Button, Select, Space, Upload } from 'ant-design-vue';
|
import { Button, Select, Space, Upload } from 'ant-design-vue';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -69,10 +70,7 @@ function setExportCategoryIds(value: unknown) {
|
|||||||
已选择:{{ props.selectedFileName }}
|
已选择:{{ props.selectedFileName }}
|
||||||
</div>
|
</div>
|
||||||
<Space class="pbt-upload-actions">
|
<Space class="pbt-upload-actions">
|
||||||
<Button
|
<Button :loading="props.submitting" @click="emit('downloadTemplate')">
|
||||||
:loading="props.submitting"
|
|
||||||
@click="emit('downloadTemplate')"
|
|
||||||
>
|
|
||||||
下载导入模板
|
下载导入模板
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
@@ -133,4 +131,3 @@ function setExportCategoryIds(value: unknown) {
|
|||||||
</footer>
|
</footer>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -84,4 +84,3 @@ function setTargetCategory(value: unknown) {
|
|||||||
</footer>
|
</footer>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import type { BatchPricePreviewRow, BatchScopeType } from '../types';
|
import type { BatchPricePreviewRow, BatchScopeType } from '../types';
|
||||||
|
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
import { Button, InputNumber, Select, Table } from 'ant-design-vue';
|
import { Button, InputNumber, Select, Table } from 'ant-design-vue';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -223,4 +224,3 @@ function setAmount(value: null | number | string) {
|
|||||||
</footer>
|
</footer>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { BatchScopeType } from '../types';
|
import type { BatchScopeType } from '../types';
|
||||||
|
|
||||||
import { Button, Select } from 'ant-design-vue';
|
import { Button, Select } from 'ant-design-vue';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -135,4 +136,3 @@ function setScopeProductIds(value: unknown) {
|
|||||||
</footer>
|
</footer>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -129,4 +129,3 @@ function setSyncStatus(value: boolean | string | undefined) {
|
|||||||
</footer>
|
</footer>
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
import type { BatchToolCard, BatchToolKey } from '../types';
|
import type { BatchToolCard, BatchToolKey } from '../types';
|
||||||
|
|
||||||
import { IconifyIcon } from '@vben/icons';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
|
|
||||||
import { Button } from 'ant-design-vue';
|
import { Button } from 'ant-design-vue';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -41,4 +42,3 @@ const emit = defineEmits<Emits>();
|
|||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -40,7 +40,10 @@ export const BATCH_TOOL_CARDS: BatchToolCard[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
/** 范围选项。 */
|
/** 范围选项。 */
|
||||||
export const BATCH_SCOPE_OPTIONS: Array<{ label: string; value: BatchScopeType }> = [
|
export const BATCH_SCOPE_OPTIONS: Array<{
|
||||||
|
label: string;
|
||||||
|
value: BatchScopeType;
|
||||||
|
}> = [
|
||||||
{ label: '全部商品', value: 'all' },
|
{ label: '全部商品', value: 'all' },
|
||||||
{ label: '按分类', value: 'category' },
|
{ label: '按分类', value: 'category' },
|
||||||
{ label: '手动选择', value: 'manual' },
|
{ label: '手动选择', value: 'manual' },
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
|
|
||||||
|
import type { BatchCategoryOption, BatchProductOption } from '../../types';
|
||||||
|
|
||||||
import type { ProductPickerItemDto } from '#/api/product';
|
import type { ProductPickerItemDto } from '#/api/product';
|
||||||
import type { StoreListItemDto } from '#/api/store';
|
import type { StoreListItemDto } from '#/api/store';
|
||||||
|
|
||||||
@@ -11,12 +13,7 @@ import {
|
|||||||
} from '#/api/product';
|
} from '#/api/product';
|
||||||
import { getStoreListApi } from '#/api/store';
|
import { getStoreListApi } from '#/api/store';
|
||||||
|
|
||||||
import {
|
import { toBatchCategoryOptions, toBatchProductOptions } from '../../types';
|
||||||
toBatchCategoryOptions,
|
|
||||||
toBatchProductOptions,
|
|
||||||
type BatchCategoryOption,
|
|
||||||
type BatchProductOption,
|
|
||||||
} from '../../types';
|
|
||||||
|
|
||||||
interface CreateBatchDataActionsOptions {
|
interface CreateBatchDataActionsOptions {
|
||||||
categoryOptions: Ref<BatchCategoryOption[]>;
|
categoryOptions: Ref<BatchCategoryOption[]>;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import type { Ref } from 'vue';
|
import type { Ref } from 'vue';
|
||||||
|
|
||||||
|
import type { BatchScopeType } from '../../types';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ProductBatchPricePreviewDto,
|
ProductBatchPricePreviewDto,
|
||||||
ProductBatchScopeDto,
|
ProductBatchScopeDto,
|
||||||
@@ -18,8 +20,6 @@ import {
|
|||||||
batchSyncProductStoreApi,
|
batchSyncProductStoreApi,
|
||||||
} from '#/api/product';
|
} from '#/api/product';
|
||||||
|
|
||||||
import type { BatchScopeType } from '../../types';
|
|
||||||
|
|
||||||
interface CreateBatchToolActionsOptions {
|
interface CreateBatchToolActionsOptions {
|
||||||
exportCategoryIds: Ref<string[]>;
|
exportCategoryIds: Ref<string[]>;
|
||||||
exportScopeType: Ref<'all' | 'category'>;
|
exportScopeType: Ref<'all' | 'category'>;
|
||||||
@@ -91,7 +91,7 @@ function decodeBase64ToBlob(base64: string) {
|
|||||||
const binary = window.atob(base64);
|
const binary = window.atob(base64);
|
||||||
const bytes = new Uint8Array(binary.length);
|
const bytes = new Uint8Array(binary.length);
|
||||||
for (let index = 0; index < binary.length; index++) {
|
for (let index = 0; index < binary.length; index++) {
|
||||||
bytes[index] = binary.charCodeAt(index);
|
bytes[index] = binary.codePointAt(index) ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Blob([bytes], {
|
return new Blob([bytes], {
|
||||||
@@ -241,7 +241,9 @@ export function createBatchToolActions(options: CreateBatchToolActionsOptions) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.moveSourceCategoryId.value === options.moveTargetCategoryId.value) {
|
if (
|
||||||
|
options.moveSourceCategoryId.value === options.moveTargetCategoryId.value
|
||||||
|
) {
|
||||||
message.warning('源分类和目标分类不能相同');
|
message.warning('源分类和目标分类不能相同');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,3 @@
|
|||||||
import { computed, onActivated, onMounted, ref, watch } from 'vue';
|
|
||||||
|
|
||||||
import type { StoreListItemDto } from '#/api/store';
|
|
||||||
|
|
||||||
import { BATCH_TOOL_CARDS } from './batch-page/constants';
|
|
||||||
import { createBatchDataActions } from './batch-page/data-actions';
|
|
||||||
import { createBatchToolActions } from './batch-page/tool-actions';
|
|
||||||
import type {
|
import type {
|
||||||
BatchCategoryOption,
|
BatchCategoryOption,
|
||||||
BatchScopeType,
|
BatchScopeType,
|
||||||
@@ -12,6 +5,14 @@ import type {
|
|||||||
BatchToolKey,
|
BatchToolKey,
|
||||||
} from '../types';
|
} from '../types';
|
||||||
|
|
||||||
|
import type { StoreListItemDto } from '#/api/store';
|
||||||
|
|
||||||
|
import { computed, onActivated, onMounted, ref, watch } from 'vue';
|
||||||
|
|
||||||
|
import { BATCH_TOOL_CARDS } from './batch-page/constants';
|
||||||
|
import { createBatchDataActions } from './batch-page/data-actions';
|
||||||
|
import { createBatchToolActions } from './batch-page/tool-actions';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 文件职责:批量工具页面状态编排。
|
* 文件职责:批量工具页面状态编排。
|
||||||
* 1. 管理门店、范围、卡片展开状态。
|
* 1. 管理门店、范围、卡片展开状态。
|
||||||
@@ -23,7 +24,9 @@ export function useProductBatchPage() {
|
|||||||
const isStoreLoading = ref(false);
|
const isStoreLoading = ref(false);
|
||||||
|
|
||||||
const categoryOptions = ref<BatchCategoryOption[]>([]);
|
const categoryOptions = ref<BatchCategoryOption[]>([]);
|
||||||
const productOptions = ref<Array<{ label: string; price: number; spuCode: string; value: string }>>([]);
|
const productOptions = ref<
|
||||||
|
Array<{ label: string; price: number; spuCode: string; value: string }>
|
||||||
|
>([]);
|
||||||
const isCategoryLoading = ref(false);
|
const isCategoryLoading = ref(false);
|
||||||
const isProductLoading = ref(false);
|
const isProductLoading = ref(false);
|
||||||
|
|
||||||
@@ -122,7 +125,9 @@ export function useProductBatchPage() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const selectedStoreLabel = computed(() => {
|
const selectedStoreLabel = computed(() => {
|
||||||
return stores.value.find((item) => item.id === selectedStoreId.value)?.name || '';
|
return (
|
||||||
|
stores.value.find((item) => item.id === selectedStoreId.value)?.name || ''
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const scopeEstimatedCount = computed(() => {
|
const scopeEstimatedCount = computed(() => {
|
||||||
@@ -143,8 +148,9 @@ export function useProductBatchPage() {
|
|||||||
const moveEstimatedCount = computed(() => {
|
const moveEstimatedCount = computed(() => {
|
||||||
if (moveSourceCategoryId.value) {
|
if (moveSourceCategoryId.value) {
|
||||||
return (
|
return (
|
||||||
categoryOptions.value.find((item) => item.value === moveSourceCategoryId.value)
|
categoryOptions.value.find(
|
||||||
?.productCount ?? 0
|
(item) => item.value === moveSourceCategoryId.value,
|
||||||
|
)?.productCount ?? 0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Page } from '@vben/common-ui';
|
import type { BatchToolKey } from './types';
|
||||||
|
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import { Page } from '@vben/common-ui';
|
||||||
|
|
||||||
import { Alert, Drawer, Empty, Spin } from 'ant-design-vue';
|
import { Alert, Drawer, Empty, Spin } from 'ant-design-vue';
|
||||||
|
|
||||||
|
import StoreScopeToolbar from '../../shared/components/StoreScopeToolbar.vue';
|
||||||
import BatchImportExportPanel from './components/BatchImportExportPanel.vue';
|
import BatchImportExportPanel from './components/BatchImportExportPanel.vue';
|
||||||
import BatchMoveCategoryPanel from './components/BatchMoveCategoryPanel.vue';
|
import BatchMoveCategoryPanel from './components/BatchMoveCategoryPanel.vue';
|
||||||
import BatchPriceAdjustPanel from './components/BatchPriceAdjustPanel.vue';
|
import BatchPriceAdjustPanel from './components/BatchPriceAdjustPanel.vue';
|
||||||
import BatchSaleSwitchPanel from './components/BatchSaleSwitchPanel.vue';
|
import BatchSaleSwitchPanel from './components/BatchSaleSwitchPanel.vue';
|
||||||
import BatchStoreSyncPanel from './components/BatchStoreSyncPanel.vue';
|
import BatchStoreSyncPanel from './components/BatchStoreSyncPanel.vue';
|
||||||
import StoreScopeToolbar from '../../shared/components/StoreScopeToolbar.vue';
|
|
||||||
import BatchToolCards from './components/BatchToolCards.vue';
|
import BatchToolCards from './components/BatchToolCards.vue';
|
||||||
import { useProductBatchPage } from './composables/useProductBatchPage';
|
import { useProductBatchPage } from './composables/useProductBatchPage';
|
||||||
import type { BatchToolKey } from './types';
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
activeTool,
|
activeTool,
|
||||||
@@ -150,7 +152,9 @@ const activeToolTitle = computed(() => {
|
|||||||
@update:selected-store-id="setSelectedStoreId"
|
@update:selected-store-id="setSelectedStoreId"
|
||||||
>
|
>
|
||||||
<template #actions>
|
<template #actions>
|
||||||
<div class="pbt-toolbar-tip">选择门店后,工具仅作用于当前门店商品</div>
|
<div class="pbt-toolbar-tip">
|
||||||
|
选择门店后,工具仅作用于当前门店商品
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</StoreScopeToolbar>
|
</StoreScopeToolbar>
|
||||||
|
|
||||||
|
|||||||
@@ -43,8 +43,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.pbt-card-desc {
|
.pbt-card-desc {
|
||||||
margin: 0;
|
|
||||||
min-height: 40px;
|
min-height: 40px;
|
||||||
|
margin: 0;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
color: #9ca3af;
|
color: #9ca3af;
|
||||||
|
|||||||
@@ -29,8 +29,8 @@
|
|||||||
|
|
||||||
.pbt-toolbar-tip {
|
.pbt-toolbar-tip {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: #9ca3af;
|
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
|
color: #9ca3af;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pbt-empty-wrap {
|
.pbt-empty-wrap {
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
.page-product-batch,
|
.page-product-batch,
|
||||||
.pbt-drawer {
|
.pbt-drawer {
|
||||||
|
|
||||||
.pbt-panel {
|
.pbt-panel {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ export function buildSkuCombinations(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const current = templates[depth];
|
const current = templates[depth];
|
||||||
|
if (!current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (const option of current.options) {
|
for (const option of current.options) {
|
||||||
walk(depth + 1, [
|
walk(depth + 1, [
|
||||||
...chain,
|
...chain,
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ interface CreateProductDetailSkuActionsOptions {
|
|||||||
specTemplateOptions: Ref<ProductSpecDto[]>;
|
specTemplateOptions: Ref<ProductSpecDto[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isDefined<T>(value: null | T | undefined): value is T {
|
||||||
|
return value !== null && value !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export function createProductDetailSkuActions(
|
export function createProductDetailSkuActions(
|
||||||
options: CreateProductDetailSkuActionsOptions,
|
options: CreateProductDetailSkuActionsOptions,
|
||||||
) {
|
) {
|
||||||
@@ -87,7 +91,7 @@ export function createProductDetailSkuActions(
|
|||||||
function buildSkuRows() {
|
function buildSkuRows() {
|
||||||
const selectedTemplates = form.specTemplateIds
|
const selectedTemplates = form.specTemplateIds
|
||||||
.map((id) => specTemplateOptions.value.find((item) => item.id === id))
|
.map((id) => specTemplateOptions.value.find((item) => item.id === id))
|
||||||
.filter(Boolean)
|
.filter((item): item is ProductSpecDto => isDefined(item))
|
||||||
.map((item) => ({
|
.map((item) => ({
|
||||||
id: item.id,
|
id: item.id,
|
||||||
name: item.name,
|
name: item.name,
|
||||||
@@ -169,19 +173,21 @@ export function createProductDetailSkuActions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setSkuPrice(index: number, value: number) {
|
function setSkuPrice(index: number, value: number) {
|
||||||
if (index < 0 || index >= form.skus.length) return;
|
const current = form.skus[index];
|
||||||
|
if (!current) return;
|
||||||
|
|
||||||
form.skus[index] = {
|
form.skus[index] = {
|
||||||
...form.skus[index],
|
...current,
|
||||||
price: Number.isFinite(value)
|
price: Number.isFinite(value) ? Math.max(0, value) : current.price,
|
||||||
? Math.max(0, value)
|
|
||||||
: form.skus[index].price,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSkuOriginalPrice(index: number, value: null | number) {
|
function setSkuOriginalPrice(index: number, value: null | number) {
|
||||||
if (index < 0 || index >= form.skus.length) return;
|
const current = form.skus[index];
|
||||||
|
if (!current) return;
|
||||||
|
|
||||||
form.skus[index] = {
|
form.skus[index] = {
|
||||||
...form.skus[index],
|
...current,
|
||||||
originalPrice:
|
originalPrice:
|
||||||
value !== null && value !== undefined && Number(value) > 0
|
value !== null && value !== undefined && Number(value) > 0
|
||||||
? Number(value)
|
? Number(value)
|
||||||
@@ -190,17 +196,21 @@ export function createProductDetailSkuActions(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setSkuStock(index: number, value: number) {
|
function setSkuStock(index: number, value: number) {
|
||||||
if (index < 0 || index >= form.skus.length) return;
|
const current = form.skus[index];
|
||||||
|
if (!current) return;
|
||||||
|
|
||||||
form.skus[index] = {
|
form.skus[index] = {
|
||||||
...form.skus[index],
|
...current,
|
||||||
stock: Math.max(0, Math.floor(Number(value || 0))),
|
stock: Math.max(0, Math.floor(Number(value || 0))),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSkuEnabled(index: number, checked: boolean) {
|
function setSkuEnabled(index: number, checked: boolean) {
|
||||||
if (index < 0 || index >= form.skus.length) return;
|
const current = form.skus[index];
|
||||||
|
if (!current) return;
|
||||||
|
|
||||||
form.skus[index] = {
|
form.skus[index] = {
|
||||||
...form.skus[index],
|
...current,
|
||||||
isEnabled: checked,
|
isEnabled: checked,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ import { DEFAULT_PRODUCT_DETAIL_FORM } from './product-detail-page/constants';
|
|||||||
import { createProductDetailDataActions } from './product-detail-page/data-actions';
|
import { createProductDetailDataActions } from './product-detail-page/data-actions';
|
||||||
import { createProductDetailSkuActions } from './product-detail-page/sku-actions';
|
import { createProductDetailSkuActions } from './product-detail-page/sku-actions';
|
||||||
|
|
||||||
|
function isDefined<T>(value: null | T | undefined): value is T {
|
||||||
|
return value !== null && value !== undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export function useProductDetailPage() {
|
export function useProductDetailPage() {
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@@ -71,10 +75,10 @@ export function useProductDetailPage() {
|
|||||||
return '#9ca3af';
|
return '#9ca3af';
|
||||||
});
|
});
|
||||||
|
|
||||||
const skuTemplateColumns = computed(() =>
|
const skuTemplateColumns = computed<ProductSpecDto[]>(() =>
|
||||||
form.specTemplateIds
|
form.specTemplateIds
|
||||||
.map((id) => specTemplateOptions.value.find((item) => item.id === id))
|
.map((id) => specTemplateOptions.value.find((item) => item.id === id))
|
||||||
.filter(Boolean),
|
.filter((item): item is ProductSpecDto => isDefined(item)),
|
||||||
);
|
);
|
||||||
|
|
||||||
const skuActions = createProductDetailSkuActions({
|
const skuActions = createProductDetailSkuActions({
|
||||||
|
|||||||
@@ -107,6 +107,36 @@ const sectionList = computed<ProductDetailSectionItem[]>(() => {
|
|||||||
const isOnSale = computed(() => form.status === 'on_sale');
|
const isOnSale = computed(() => form.status === 'on_sale');
|
||||||
const maxUploadReached = computed(() => form.imageUrls.length >= 5);
|
const maxUploadReached = computed(() => form.imageUrls.length >= 5);
|
||||||
const skuCountText = computed(() => `共 ${form.skus.length} 个 SKU`);
|
const skuCountText = computed(() => `共 ${form.skus.length} 个 SKU`);
|
||||||
|
const originalPriceValue = computed<number | undefined>({
|
||||||
|
get: () => form.originalPrice ?? undefined,
|
||||||
|
set: (value) => {
|
||||||
|
form.originalPrice = value ?? null;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const warningStockValue = computed<number | undefined>({
|
||||||
|
get: () => form.warningStock ?? undefined,
|
||||||
|
set: (value) => {
|
||||||
|
form.warningStock = value ?? null;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const packingFeeValue = computed<number | undefined>({
|
||||||
|
get: () => form.packingFee ?? undefined,
|
||||||
|
set: (value) => {
|
||||||
|
form.packingFee = value ?? null;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const skuBatchPriceValue = computed<number | undefined>({
|
||||||
|
get: () => skuBatch.price ?? undefined,
|
||||||
|
set: (value) => {
|
||||||
|
skuBatch.price = value ?? null;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const skuBatchStockValue = computed<number | undefined>({
|
||||||
|
get: () => skuBatch.stock ?? undefined,
|
||||||
|
set: (value) => {
|
||||||
|
skuBatch.stock = value ?? null;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const timedOnShelfValue = computed<Dayjs | undefined>({
|
const timedOnShelfValue = computed<Dayjs | undefined>({
|
||||||
get: () =>
|
get: () =>
|
||||||
@@ -386,7 +416,7 @@ watch(
|
|||||||
<div class="pd-pricing-inline">
|
<div class="pd-pricing-inline">
|
||||||
<span class="pd-pricing-unit">¥</span>
|
<span class="pd-pricing-unit">¥</span>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
v-model:value="form.originalPrice"
|
v-model:value="originalPriceValue"
|
||||||
:min="0"
|
:min="0"
|
||||||
:precision="2"
|
:precision="2"
|
||||||
:step="0.1"
|
:step="0.1"
|
||||||
@@ -418,7 +448,7 @@ watch(
|
|||||||
<div class="pd-pricing-inline">
|
<div class="pd-pricing-inline">
|
||||||
<span class="pd-pricing-unit is-empty"> ¥ </span>
|
<span class="pd-pricing-unit is-empty"> ¥ </span>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
v-model:value="form.warningStock"
|
v-model:value="warningStockValue"
|
||||||
:min="0"
|
:min="0"
|
||||||
:precision="0"
|
:precision="0"
|
||||||
:step="1"
|
:step="1"
|
||||||
@@ -434,7 +464,7 @@ watch(
|
|||||||
<div class="pd-pricing-inline">
|
<div class="pd-pricing-inline">
|
||||||
<span class="pd-pricing-unit">¥</span>
|
<span class="pd-pricing-unit">¥</span>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
v-model:value="form.packingFee"
|
v-model:value="packingFeeValue"
|
||||||
:min="0"
|
:min="0"
|
||||||
:precision="2"
|
:precision="2"
|
||||||
:step="0.1"
|
:step="0.1"
|
||||||
@@ -478,7 +508,7 @@ watch(
|
|||||||
<label>批量设价</label>
|
<label>批量设价</label>
|
||||||
<span class="pd-unit">¥</span>
|
<span class="pd-unit">¥</span>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
v-model:value="skuBatch.price"
|
v-model:value="skuBatchPriceValue"
|
||||||
:min="0"
|
:min="0"
|
||||||
:precision="2"
|
:precision="2"
|
||||||
:step="0.1"
|
:step="0.1"
|
||||||
@@ -489,7 +519,7 @@ watch(
|
|||||||
<span class="pd-sku-batch-gap"></span>
|
<span class="pd-sku-batch-gap"></span>
|
||||||
<label>批量设库存</label>
|
<label>批量设库存</label>
|
||||||
<InputNumber
|
<InputNumber
|
||||||
v-model:value="skuBatch.stock"
|
v-model:value="skuBatchStockValue"
|
||||||
:min="0"
|
:min="0"
|
||||||
:precision="0"
|
:precision="0"
|
||||||
:step="1"
|
:step="1"
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ export const SCHEDULE_COLOR_PALETTE = [
|
|||||||
'#2f54eb',
|
'#2f54eb',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
|
const DEFAULT_SCHEDULE_COLOR = '#1890ff';
|
||||||
|
|
||||||
/** 创建默认编辑表单。 */
|
/** 创建默认编辑表单。 */
|
||||||
export function createDefaultScheduleForm(): ScheduleEditorForm {
|
export function createDefaultScheduleForm(): ScheduleEditorForm {
|
||||||
return {
|
return {
|
||||||
@@ -63,7 +65,7 @@ export function normalizeWeekDays(weekDays: number[]) {
|
|||||||
/** 按规则 ID 生成稳定颜色。 */
|
/** 按规则 ID 生成稳定颜色。 */
|
||||||
export function resolveScheduleColor(scheduleId: string) {
|
export function resolveScheduleColor(scheduleId: string) {
|
||||||
if (!scheduleId) {
|
if (!scheduleId) {
|
||||||
return SCHEDULE_COLOR_PALETTE[0];
|
return DEFAULT_SCHEDULE_COLOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
let hash = 0;
|
let hash = 0;
|
||||||
@@ -71,5 +73,8 @@ export function resolveScheduleColor(scheduleId: string) {
|
|||||||
hash = (hash * 31 + (char.codePointAt(0) ?? 0)) >>> 0;
|
hash = (hash * 31 + (char.codePointAt(0) ?? 0)) >>> 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SCHEDULE_COLOR_PALETTE[hash % SCHEDULE_COLOR_PALETTE.length];
|
return (
|
||||||
|
SCHEDULE_COLOR_PALETTE[hash % SCHEDULE_COLOR_PALETTE.length] ??
|
||||||
|
DEFAULT_SCHEDULE_COLOR
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -99,8 +99,8 @@ export function useProductSchedulePage() {
|
|||||||
.map((item) => buildTimelineRow(item, getRuleColor(item.id)));
|
.map((item) => buildTimelineRow(item, getRuleColor(item.id)));
|
||||||
});
|
});
|
||||||
|
|
||||||
function getRuleColor(scheduleId: string) {
|
function getRuleColor(scheduleId: string | undefined) {
|
||||||
return resolveScheduleColor(scheduleId);
|
return resolveScheduleColor(scheduleId || '');
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolveProductName(productId: string) {
|
function resolveProductName(productId: string) {
|
||||||
|
|||||||
Reference in New Issue
Block a user