fix: 修复批量工具门店选择器与组件渲染异常
All checks were successful
Build and Deploy TenantUI / build-and-deploy (push) Successful in 52s

This commit is contained in:
2026-02-26 13:09:45 +08:00
parent 5ec724188e
commit 38a296e8bc
7 changed files with 76 additions and 53 deletions

View File

@@ -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';
interface Props { interface Props {
categoryOptions: Array<{ label: string; value: string }>; categoryOptions: Array<{ label: string; value: string }>;
@@ -48,7 +49,7 @@ function setExportCategoryIds(value: unknown) {
<div class="pbt-sub-cards"> <div class="pbt-sub-cards">
<article class="pbt-sub-card"> <article class="pbt-sub-card">
<h4>导入商品</h4> <h4>导入商品</h4>
<a-upload-dragger <Upload.Dragger
:show-upload-list="false" :show-upload-list="false"
accept=".xlsx" accept=".xlsx"
:before-upload="beforeUpload" :before-upload="beforeUpload"
@@ -56,25 +57,25 @@ function setExportCategoryIds(value: unknown) {
<p class="pbt-upload-icon">XLSX</p> <p class="pbt-upload-icon">XLSX</p>
<p class="pbt-upload-title">点击或拖拽 Excel 文件到此处上传</p> <p class="pbt-upload-title">点击或拖拽 Excel 文件到此处上传</p>
<p class="pbt-upload-tip">仅支持 .xlsx建议不超过 10MB</p> <p class="pbt-upload-tip">仅支持 .xlsx建议不超过 10MB</p>
</a-upload-dragger> </Upload.Dragger>
<div class="pbt-upload-file" v-if="props.selectedFileName"> <div class="pbt-upload-file" v-if="props.selectedFileName">
已选择{{ props.selectedFileName }} 已选择{{ props.selectedFileName }}
</div> </div>
<a-space class="pbt-upload-actions"> <Space class="pbt-upload-actions">
<a-button <Button
:loading="props.submitting" :loading="props.submitting"
@click="emit('downloadTemplate')" @click="emit('downloadTemplate')"
> >
下载导入模板 下载导入模板
</a-button> </Button>
<a-button <Button
type="primary" type="primary"
:loading="props.submitting" :loading="props.submitting"
@click="emit('submitImport')" @click="emit('submitImport')"
> >
开始导入 开始导入
</a-button> </Button>
</a-space> </Space>
</article> </article>
<article class="pbt-sub-card"> <article class="pbt-sub-card">
@@ -99,7 +100,7 @@ function setExportCategoryIds(value: unknown) {
</button> </button>
</div> </div>
<a-select <Select
v-if="props.exportScopeType === 'category'" v-if="props.exportScopeType === 'category'"
mode="multiple" mode="multiple"
class="pbt-select-wide" class="pbt-select-wide"
@@ -110,18 +111,19 @@ function setExportCategoryIds(value: unknown) {
/> />
</div> </div>
<a-button <Button
type="primary" type="primary"
:loading="props.submitting" :loading="props.submitting"
@click="emit('submitExport')" @click="emit('submitExport')"
> >
导出 Excel 导出 Excel
</a-button> </Button>
</article> </article>
</div> </div>
<footer class="pbt-actions"> <footer class="pbt-actions">
<a-button @click="emit('close')">关闭</a-button> <Button @click="emit('close')">关闭</Button>
</footer> </footer>
</section> </section>
</template> </template>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { Button, Select } from 'ant-design-vue';
interface Props { interface Props {
categoryOptions: Array<{ label: string; value: string }>; categoryOptions: Array<{ label: string; value: string }>;
estimatedCount: number; estimatedCount: number;
@@ -38,7 +40,7 @@ function setTargetCategory(value: unknown) {
<div class="pbt-step-label"> <div class="pbt-step-label">
<span class="num">1</span> 源分类可选 <span class="num">1</span> 源分类可选
</div> </div>
<a-select <Select
:value="props.sourceCategoryId" :value="props.sourceCategoryId"
allow-clear allow-clear
class="pbt-select-narrow" class="pbt-select-narrow"
@@ -50,7 +52,7 @@ function setTargetCategory(value: unknown) {
<div class="pbt-step"> <div class="pbt-step">
<div class="pbt-step-label"><span class="num">2</span> 目标分类</div> <div class="pbt-step-label"><span class="num">2</span> 目标分类</div>
<a-select <Select
:value="props.targetCategoryId" :value="props.targetCategoryId"
class="pbt-select-narrow" class="pbt-select-narrow"
:options="props.categoryOptions" :options="props.categoryOptions"
@@ -64,14 +66,15 @@ function setTargetCategory(value: unknown) {
</div> </div>
<footer class="pbt-actions"> <footer class="pbt-actions">
<a-button <Button
type="primary" type="primary"
:loading="props.submitting" :loading="props.submitting"
@click="emit('submit')" @click="emit('submit')"
> >
确认移动 确认移动
</a-button> </Button>
<a-button @click="emit('close')">取消</a-button> <Button @click="emit('close')">取消</Button>
</footer> </footer>
</section> </section>
</template> </template>

View File

@@ -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';
interface Props { interface Props {
amount: number; amount: number;
@@ -85,8 +86,9 @@ function setScopeProductIds(value: unknown) {
emit('update:scopeProductIds', normalizeArray(value)); emit('update:scopeProductIds', normalizeArray(value));
} }
function setAmount(value: null | number) { function setAmount(value: null | number | string) {
emit('update:amount', Number(value ?? 0)); const parsed = Number(value ?? 0);
emit('update:amount', Number.isFinite(parsed) ? parsed : 0);
} }
</script> </script>
@@ -111,7 +113,7 @@ function setAmount(value: null | number) {
{{ item.label }} {{ item.label }}
</button> </button>
</div> </div>
<a-select <Select
v-if="props.scopeType === 'category'" v-if="props.scopeType === 'category'"
mode="multiple" mode="multiple"
:value="props.scopeCategoryIds" :value="props.scopeCategoryIds"
@@ -120,7 +122,7 @@ function setAmount(value: null | number) {
class="pbt-select-wide" class="pbt-select-wide"
@update:value="setScopeCategoryIds" @update:value="setScopeCategoryIds"
/> />
<a-select <Select
v-if="props.scopeType === 'manual'" v-if="props.scopeType === 'manual'"
mode="multiple" mode="multiple"
:value="props.scopeProductIds" :value="props.scopeProductIds"
@@ -158,16 +160,16 @@ function setAmount(value: null | number) {
{{ item.label }} {{ item.label }}
</button> </button>
</div> </div>
<a-input-number <InputNumber
:value="props.amount" :value="props.amount"
:min="0" :min="0"
:step="0.1" :step="0.1"
class="pbt-number" class="pbt-number"
@update:value="setAmount" @update:value="setAmount"
/> />
<a-button :loading="props.previewLoading" @click="emit('preview')"> <Button :loading="props.previewLoading" @click="emit('preview')">
更新预览 更新预览
</a-button> </Button>
</div> </div>
</div> </div>
@@ -176,7 +178,7 @@ function setAmount(value: null | number) {
<span class="num">3</span> <span class="num">3</span>
预览 {{ props.previewTotal }} 个商品展示前 50 预览 {{ props.previewTotal }} 个商品展示前 50
</div> </div>
<a-table <Table
class="pbt-table" class="pbt-table"
size="small" size="small"
:columns="columns" :columns="columns"
@@ -199,18 +201,19 @@ function setAmount(value: null | number) {
</span> </span>
</template> </template>
</template> </template>
</a-table> </Table>
</div> </div>
<footer class="pbt-actions"> <footer class="pbt-actions">
<a-button <Button
type="primary" type="primary"
:loading="props.submitting" :loading="props.submitting"
@click="emit('submit')" @click="emit('submit')"
> >
确认调价 确认调价
</a-button> </Button>
<a-button @click="emit('close')">取消</a-button> <Button @click="emit('close')">取消</Button>
</footer> </footer>
</section> </section>
</template> </template>

View File

@@ -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';
interface Props { interface Props {
action: 'off' | 'on'; action: 'off' | 'on';
@@ -74,7 +75,7 @@ function setScopeProductIds(value: unknown) {
</button> </button>
</div> </div>
<a-select <Select
v-if="props.scopeType === 'category'" v-if="props.scopeType === 'category'"
mode="multiple" mode="multiple"
:value="props.scopeCategoryIds" :value="props.scopeCategoryIds"
@@ -84,7 +85,7 @@ function setScopeProductIds(value: unknown) {
@update:value="setScopeCategoryIds" @update:value="setScopeCategoryIds"
/> />
<a-select <Select
v-if="props.scopeType === 'manual'" v-if="props.scopeType === 'manual'"
mode="multiple" mode="multiple"
:value="props.scopeProductIds" :value="props.scopeProductIds"
@@ -116,14 +117,15 @@ function setScopeProductIds(value: unknown) {
</div> </div>
<footer class="pbt-actions"> <footer class="pbt-actions">
<a-button <Button
type="primary" type="primary"
:loading="props.submitting" :loading="props.submitting"
@click="emit('submit')" @click="emit('submit')"
> >
确认执行 确认执行
</a-button> </Button>
<a-button @click="emit('close')">取消</a-button> <Button @click="emit('close')">取消</Button>
</footer> </footer>
</section> </section>
</template> </template>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { Button, Checkbox, Input, Select, Space } from 'ant-design-vue';
interface Props { interface Props {
open: boolean; open: boolean;
productIds: string[]; productIds: string[];
@@ -62,7 +64,7 @@ function setSyncStatus(value: boolean | string | undefined) {
<div class="pbt-step"> <div class="pbt-step">
<div class="pbt-step-label"><span class="num">1</span> 源门店</div> <div class="pbt-step-label"><span class="num">1</span> 源门店</div>
<a-input <Input
:value="props.sourceStoreName" :value="props.sourceStoreName"
disabled disabled
class="pbt-select-narrow" class="pbt-select-narrow"
@@ -71,7 +73,7 @@ function setSyncStatus(value: boolean | string | undefined) {
<div class="pbt-step"> <div class="pbt-step">
<div class="pbt-step-label"><span class="num">2</span> 目标门店</div> <div class="pbt-step-label"><span class="num">2</span> 目标门店</div>
<a-select <Select
mode="multiple" mode="multiple"
:value="props.targetStoreIds" :value="props.targetStoreIds"
:options="props.targetStoreOptions" :options="props.targetStoreOptions"
@@ -83,7 +85,7 @@ function setSyncStatus(value: boolean | string | undefined) {
<div class="pbt-step"> <div class="pbt-step">
<div class="pbt-step-label"><span class="num">3</span> 同步商品</div> <div class="pbt-step-label"><span class="num">3</span> 同步商品</div>
<a-select <Select
mode="multiple" mode="multiple"
:value="props.productIds" :value="props.productIds"
:options="props.productOptions" :options="props.productOptions"
@@ -95,28 +97,29 @@ function setSyncStatus(value: boolean | string | undefined) {
<div class="pbt-step"> <div class="pbt-step">
<div class="pbt-step-label"><span class="num">4</span> 同步选项</div> <div class="pbt-step-label"><span class="num">4</span> 同步选项</div>
<a-space> <Space>
<a-checkbox :checked="props.syncPrice" @update:checked="setSyncPrice"> <Checkbox :checked="props.syncPrice" @update:checked="setSyncPrice">
价格 价格
</a-checkbox> </Checkbox>
<a-checkbox :checked="props.syncStock" @update:checked="setSyncStock"> <Checkbox :checked="props.syncStock" @update:checked="setSyncStock">
库存 库存
</a-checkbox> </Checkbox>
<a-checkbox :checked="props.syncStatus" @update:checked="setSyncStatus"> <Checkbox :checked="props.syncStatus" @update:checked="setSyncStatus">
状态 状态
</a-checkbox> </Checkbox>
</a-space> </Space>
</div> </div>
<footer class="pbt-actions"> <footer class="pbt-actions">
<a-button <Button
type="primary" type="primary"
:loading="props.submitting" :loading="props.submitting"
@click="emit('submit')" @click="emit('submit')"
> >
确认同步 确认同步
</a-button> </Button>
<a-button @click="emit('close')">取消</a-button> <Button @click="emit('close')">取消</Button>
</footer> </footer>
</section> </section>
</template> </template>

View File

@@ -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';
interface Props { interface Props {
activeTool: BatchToolKey | null; activeTool: BatchToolKey | null;
@@ -29,9 +30,10 @@ const emit = defineEmits<Emits>();
</div> </div>
<h3 class="pbt-card-name">{{ card.title }}</h3> <h3 class="pbt-card-name">{{ card.title }}</h3>
<p class="pbt-card-desc">{{ card.description }}</p> <p class="pbt-card-desc">{{ card.description }}</p>
<a-button type="primary" size="small" @click="emit('toggle', card.key)"> <Button type="primary" size="small" @click="emit('toggle', card.key)">
{{ props.activeTool === card.key ? '收起' : '开始操作' }} {{ props.activeTool === card.key ? '收起' : '开始操作' }}
</a-button> </Button>
</article> </article>
</div> </div>
</template> </template>

View File

@@ -1,4 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { Select } from 'ant-design-vue';
interface Props { interface Props {
isStoreLoading: boolean; isStoreLoading: boolean;
selectedStoreId: string; selectedStoreId: string;
@@ -12,8 +14,13 @@ interface Emits {
const props = defineProps<Props>(); const props = defineProps<Props>();
const emit = defineEmits<Emits>(); const emit = defineEmits<Emits>();
function setStore(value: string | undefined) { function setStore(value: unknown) {
emit('update:selectedStoreId', value ?? ''); if (typeof value === 'string' || typeof value === 'number') {
emit('update:selectedStoreId', String(value));
return;
}
emit('update:selectedStoreId', '');
} }
</script> </script>
@@ -21,7 +28,7 @@ function setStore(value: string | undefined) {
<div class="pbt-toolbar"> <div class="pbt-toolbar">
<div class="pbt-toolbar-main"> <div class="pbt-toolbar-main">
<span class="pbt-toolbar-label">门店</span> <span class="pbt-toolbar-label">门店</span>
<a-select <Select
class="pbt-toolbar-store" class="pbt-toolbar-store"
:value="props.selectedStoreId" :value="props.selectedStoreId"
:options="props.storeOptions" :options="props.storeOptions"
@@ -33,3 +40,4 @@ function setStore(value: string | undefined) {
<div class="pbt-toolbar-tip">选择门店后工具仅作用于当前门店商品</div> <div class="pbt-toolbar-tip">选择门店后工具仅作用于当前门店商品</div>
</div> </div>
</template> </template>