feat(project): rebuild schedule supply module with split structure
This commit is contained in:
@@ -1,559 +1,176 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 文件职责:时段供应页面。
|
||||
* 1. 管理供应时段模板。
|
||||
* 2. 管理时段模板与商品关联关系。
|
||||
* 文件职责:时段供应页面主视图。
|
||||
* 1. 还原原型的工具栏、统计条、规则卡片、时间轴与抽屉。
|
||||
* 2. 通过真实 TenantAPI 管理时段规则及关联商品。
|
||||
*/
|
||||
import type { ProductSwitchStatus } from '#/api/product';
|
||||
import type { StoreListItemDto } from '#/api/store';
|
||||
|
||||
import { computed, onMounted, reactive, ref, watch } from 'vue';
|
||||
|
||||
import { Page } from '@vben/common-ui';
|
||||
import { IconifyIcon } from '@vben/icons';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Divider,
|
||||
Drawer,
|
||||
Empty,
|
||||
Form,
|
||||
Input,
|
||||
InputNumber,
|
||||
message,
|
||||
Modal,
|
||||
Select,
|
||||
Space,
|
||||
Switch,
|
||||
Table,
|
||||
Tag,
|
||||
} from 'ant-design-vue';
|
||||
import { Button, Empty, Input, Select, Spin } from 'ant-design-vue';
|
||||
|
||||
import {
|
||||
changeProductScheduleStatusApi,
|
||||
deleteProductScheduleApi,
|
||||
getProductScheduleListApi,
|
||||
saveProductScheduleApi,
|
||||
searchProductPickerApi,
|
||||
} from '#/api/product';
|
||||
import { getStoreListApi } from '#/api/store';
|
||||
import ScheduleEditorDrawer from './components/ScheduleEditorDrawer.vue';
|
||||
import ScheduleProductPickerModal from './components/ScheduleProductPickerModal.vue';
|
||||
import ScheduleRuleCard from './components/ScheduleRuleCard.vue';
|
||||
import ScheduleTimelineCard from './components/ScheduleTimelineCard.vue';
|
||||
import { useProductSchedulePage } from './composables/useProductSchedulePage';
|
||||
|
||||
type StatusFilter = '' | ProductSwitchStatus;
|
||||
|
||||
interface SlotForm {
|
||||
id: string;
|
||||
weekDays: number[];
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
}
|
||||
|
||||
interface ScheduleRow {
|
||||
description: string;
|
||||
id: string;
|
||||
name: string;
|
||||
productCount: number;
|
||||
productIds: string[];
|
||||
slots: SlotForm[];
|
||||
sort: number;
|
||||
status: ProductSwitchStatus;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
const stores = ref<StoreListItemDto[]>([]);
|
||||
const selectedStoreId = ref('');
|
||||
const isStoreLoading = ref(false);
|
||||
|
||||
const rows = ref<ScheduleRow[]>([]);
|
||||
const isLoading = ref(false);
|
||||
const keyword = ref('');
|
||||
const statusFilter = ref<StatusFilter>('');
|
||||
|
||||
const pickerOptions = ref<Array<{ label: string; value: string }>>([]);
|
||||
const isDrawerOpen = ref(false);
|
||||
const isDrawerSubmitting = ref(false);
|
||||
const editingScheduleId = ref('');
|
||||
|
||||
const form = reactive({
|
||||
name: '',
|
||||
description: '',
|
||||
status: 'enabled' as ProductSwitchStatus,
|
||||
sort: 1,
|
||||
productIds: [] as string[],
|
||||
slots: [] as SlotForm[],
|
||||
});
|
||||
|
||||
const weekDayOptions = [
|
||||
{ label: '周一', value: 1 },
|
||||
{ label: '周二', value: 2 },
|
||||
{ label: '周三', value: 3 },
|
||||
{ label: '周四', value: 4 },
|
||||
{ label: '周五', value: 5 },
|
||||
{ label: '周六', value: 6 },
|
||||
{ label: '周日', value: 7 },
|
||||
];
|
||||
|
||||
const storeOptions = computed(() =>
|
||||
stores.value.map((item) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
})),
|
||||
);
|
||||
|
||||
const statusOptions = [
|
||||
{ label: '全部状态', value: '' },
|
||||
{ label: '启用', value: 'enabled' },
|
||||
{ label: '停用', value: 'disabled' },
|
||||
];
|
||||
|
||||
const drawerTitle = computed(() =>
|
||||
editingScheduleId.value ? '编辑时段' : '新增时段',
|
||||
);
|
||||
|
||||
/** 控制抽屉开关。 */
|
||||
function setDrawerOpen(value: boolean) {
|
||||
isDrawerOpen.value = value;
|
||||
}
|
||||
|
||||
/** 加载门店列表。 */
|
||||
async function loadStores() {
|
||||
isStoreLoading.value = true;
|
||||
try {
|
||||
const result = await getStoreListApi({
|
||||
page: 1,
|
||||
pageSize: 200,
|
||||
});
|
||||
stores.value = result.items ?? [];
|
||||
if (stores.value.length === 0) {
|
||||
selectedStoreId.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
const hasSelected = stores.value.some(
|
||||
(item) => item.id === selectedStoreId.value,
|
||||
);
|
||||
if (!hasSelected) {
|
||||
selectedStoreId.value = stores.value[0]?.id ?? '';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
message.error('加载门店失败');
|
||||
} finally {
|
||||
isStoreLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** 加载时段列表。 */
|
||||
async function loadSchedules() {
|
||||
if (!selectedStoreId.value) {
|
||||
rows.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading.value = true;
|
||||
try {
|
||||
const result = await getProductScheduleListApi({
|
||||
storeId: selectedStoreId.value,
|
||||
keyword: keyword.value.trim() || undefined,
|
||||
status: (statusFilter.value || undefined) as
|
||||
| ProductSwitchStatus
|
||||
| undefined,
|
||||
});
|
||||
rows.value = result as ScheduleRow[];
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
rows.value = [];
|
||||
message.error('加载时段失败');
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** 加载商品选择器。 */
|
||||
async function loadPickerOptions() {
|
||||
if (!selectedStoreId.value) {
|
||||
pickerOptions.value = [];
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const list = await searchProductPickerApi({
|
||||
storeId: selectedStoreId.value,
|
||||
limit: 500,
|
||||
});
|
||||
pickerOptions.value = list.map((item) => ({
|
||||
label: `${item.name}(${item.spuCode})`,
|
||||
value: item.id,
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
pickerOptions.value = [];
|
||||
message.error('加载商品失败');
|
||||
}
|
||||
}
|
||||
|
||||
/** 重置表单。 */
|
||||
function resetForm() {
|
||||
editingScheduleId.value = '';
|
||||
form.name = '';
|
||||
form.description = '';
|
||||
form.status = 'enabled';
|
||||
form.sort = rows.value.length + 1;
|
||||
form.productIds = [];
|
||||
form.slots = [
|
||||
{
|
||||
id: '',
|
||||
weekDays: [1, 2, 3, 4, 5, 6, 7],
|
||||
startTime: '09:00',
|
||||
endTime: '21:00',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/** 打开新增抽屉。 */
|
||||
async function openCreateDrawer() {
|
||||
resetForm();
|
||||
await loadPickerOptions();
|
||||
isDrawerOpen.value = true;
|
||||
}
|
||||
|
||||
/** 打开编辑抽屉。 */
|
||||
async function openEditDrawer(row: ScheduleRow) {
|
||||
editingScheduleId.value = row.id;
|
||||
form.name = row.name;
|
||||
form.description = row.description;
|
||||
form.status = row.status;
|
||||
form.sort = row.sort;
|
||||
form.productIds = [...row.productIds];
|
||||
form.slots = row.slots.map((slot) => ({
|
||||
...slot,
|
||||
weekDays: [...slot.weekDays],
|
||||
}));
|
||||
if (form.slots.length === 0) {
|
||||
form.slots = [
|
||||
{
|
||||
id: '',
|
||||
weekDays: [1, 2, 3, 4, 5, 6, 7],
|
||||
startTime: '09:00',
|
||||
endTime: '21:00',
|
||||
},
|
||||
];
|
||||
}
|
||||
await loadPickerOptions();
|
||||
isDrawerOpen.value = true;
|
||||
}
|
||||
|
||||
/** 新增时段行。 */
|
||||
function addSlot() {
|
||||
form.slots.push({
|
||||
id: '',
|
||||
weekDays: [1, 2, 3, 4, 5, 6, 7],
|
||||
startTime: '09:00',
|
||||
endTime: '21:00',
|
||||
});
|
||||
}
|
||||
|
||||
/** 删除时段行。 */
|
||||
function removeSlot(index: number) {
|
||||
if (form.slots.length <= 1) {
|
||||
message.warning('至少保留一个时段');
|
||||
return;
|
||||
}
|
||||
form.slots.splice(index, 1);
|
||||
}
|
||||
|
||||
/** 保存时段。 */
|
||||
async function submitDrawer() {
|
||||
if (!selectedStoreId.value) return;
|
||||
if (!form.name.trim()) {
|
||||
message.warning('请输入时段名称');
|
||||
return;
|
||||
}
|
||||
if (
|
||||
form.slots.some(
|
||||
(slot) =>
|
||||
slot.weekDays.length === 0 ||
|
||||
!slot.startTime.trim() ||
|
||||
!slot.endTime.trim(),
|
||||
)
|
||||
) {
|
||||
message.warning('请完整填写时段信息');
|
||||
return;
|
||||
}
|
||||
|
||||
isDrawerSubmitting.value = true;
|
||||
try {
|
||||
await saveProductScheduleApi({
|
||||
storeId: selectedStoreId.value,
|
||||
id: editingScheduleId.value || undefined,
|
||||
name: form.name.trim(),
|
||||
description: form.description.trim(),
|
||||
status: form.status,
|
||||
sort: form.sort,
|
||||
productIds: [...form.productIds],
|
||||
slots: form.slots.map((slot) => ({
|
||||
id: slot.id || undefined,
|
||||
weekDays: [...slot.weekDays],
|
||||
startTime: slot.startTime.trim(),
|
||||
endTime: slot.endTime.trim(),
|
||||
})),
|
||||
});
|
||||
message.success(editingScheduleId.value ? '时段已更新' : '时段已创建');
|
||||
isDrawerOpen.value = false;
|
||||
await loadSchedules();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
} finally {
|
||||
isDrawerSubmitting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** 删除时段模板。 */
|
||||
function removeSchedule(row: ScheduleRow) {
|
||||
if (!selectedStoreId.value) return;
|
||||
Modal.confirm({
|
||||
title: `确认删除时段「${row.name}」吗?`,
|
||||
async onOk() {
|
||||
await deleteProductScheduleApi({
|
||||
storeId: selectedStoreId.value,
|
||||
scheduleId: row.id,
|
||||
});
|
||||
message.success('时段已删除');
|
||||
await loadSchedules();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/** 切换时段状态。 */
|
||||
async function toggleScheduleStatus(row: ScheduleRow, checked: boolean) {
|
||||
if (!selectedStoreId.value) return;
|
||||
await changeProductScheduleStatusApi({
|
||||
storeId: selectedStoreId.value,
|
||||
scheduleId: row.id,
|
||||
status: checked ? 'enabled' : 'disabled',
|
||||
});
|
||||
row.status = checked ? 'enabled' : 'disabled';
|
||||
message.success('状态已更新');
|
||||
}
|
||||
|
||||
/** 格式化星期展示文案。 */
|
||||
function formatWeekDays(weekDays: number[]) {
|
||||
const map: Record<number, string> = {
|
||||
1: '一',
|
||||
2: '二',
|
||||
3: '三',
|
||||
4: '四',
|
||||
5: '五',
|
||||
6: '六',
|
||||
7: '日',
|
||||
};
|
||||
return [...weekDays]
|
||||
.toSorted((a, b) => a - b)
|
||||
.map((day) => map[day] || day)
|
||||
.join('/');
|
||||
}
|
||||
|
||||
/** 重置筛选。 */
|
||||
function resetFilters() {
|
||||
keyword.value = '';
|
||||
statusFilter.value = '';
|
||||
loadSchedules();
|
||||
}
|
||||
|
||||
watch(selectedStoreId, loadSchedules);
|
||||
|
||||
onMounted(loadStores);
|
||||
const {
|
||||
coveredProductCount,
|
||||
drawerSubmitText,
|
||||
drawerTitle,
|
||||
enabledCount,
|
||||
filteredRows,
|
||||
form,
|
||||
getRuleColor,
|
||||
getScheduleProductNames,
|
||||
isDrawerOpen,
|
||||
isDrawerSubmitting,
|
||||
isLoading,
|
||||
isPickerLoading,
|
||||
isPickerOpen,
|
||||
isStoreLoading,
|
||||
keyword,
|
||||
loadPickerProducts,
|
||||
openCreateDrawer,
|
||||
openEditDrawer,
|
||||
openProductPicker,
|
||||
pickerKeyword,
|
||||
pickerProducts,
|
||||
pickerSelectedIds,
|
||||
removeFormProduct,
|
||||
removeRule,
|
||||
ruleCount,
|
||||
selectAllDays,
|
||||
selectedProducts,
|
||||
selectedStoreId,
|
||||
selectWeekdays,
|
||||
selectWeekend,
|
||||
setDrawerOpen,
|
||||
setFormEndTime,
|
||||
setFormName,
|
||||
setFormStartTime,
|
||||
setKeyword,
|
||||
setPickerKeyword,
|
||||
setPickerOpen,
|
||||
setSelectedStoreId,
|
||||
storeOptions,
|
||||
submitDrawer,
|
||||
submitPicker,
|
||||
timelineRows,
|
||||
toggleFormStatus,
|
||||
togglePickerProduct,
|
||||
toggleRuleStatus,
|
||||
toggleWeekDay,
|
||||
} = useProductSchedulePage();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Page title="时段供应" content-class="space-y-4 page-product-schedule">
|
||||
<Card :bordered="false">
|
||||
<Space wrap>
|
||||
<Page title="时段供应" content-class="page-product-schedule">
|
||||
<div class="ptm-page">
|
||||
<div class="ptm-toolbar">
|
||||
<Select
|
||||
v-model:value="selectedStoreId"
|
||||
class="ptm-store-select"
|
||||
:value="selectedStoreId"
|
||||
:options="storeOptions"
|
||||
:loading="isStoreLoading"
|
||||
style="width: 240px"
|
||||
placeholder="请选择门店"
|
||||
@update:value="(value) => setSelectedStoreId(String(value ?? ''))"
|
||||
/>
|
||||
|
||||
<Input
|
||||
v-model:value="keyword"
|
||||
style="width: 220px"
|
||||
placeholder="搜索时段名称"
|
||||
class="ptm-search"
|
||||
:value="keyword"
|
||||
placeholder="搜索规则名称…"
|
||||
@update:value="(value) => setKeyword(String(value ?? ''))"
|
||||
/>
|
||||
<Select
|
||||
v-model:value="statusFilter"
|
||||
:options="statusOptions"
|
||||
style="width: 140px"
|
||||
/>
|
||||
<Button type="primary" @click="loadSchedules">查询</Button>
|
||||
<Button @click="resetFilters">重置</Button>
|
||||
<Button type="primary" @click="openCreateDrawer">新增时段</Button>
|
||||
</Space>
|
||||
</Card>
|
||||
|
||||
<Card v-if="!selectedStoreId" :bordered="false">
|
||||
<Empty description="暂无门店,请先创建门店" />
|
||||
</Card>
|
||||
<span class="ptm-spacer"></span>
|
||||
|
||||
<Card v-else :bordered="false">
|
||||
<Table
|
||||
row-key="id"
|
||||
:data-source="rows"
|
||||
:loading="isLoading"
|
||||
:pagination="false"
|
||||
size="middle"
|
||||
>
|
||||
<Table.Column
|
||||
title="时段名称"
|
||||
data-index="name"
|
||||
key="name"
|
||||
:width="180"
|
||||
/>
|
||||
<Table.Column title="供应时段" key="slots">
|
||||
<template #default="{ record }">
|
||||
<Space direction="vertical" size="small">
|
||||
<Tag
|
||||
v-for="slot in record.slots"
|
||||
:key="slot.id || `${slot.startTime}-${slot.endTime}`"
|
||||
>
|
||||
周{{ formatWeekDays(slot.weekDays) }} {{ slot.startTime }}-{{
|
||||
slot.endTime
|
||||
}}
|
||||
</Tag>
|
||||
</Space>
|
||||
</template>
|
||||
</Table.Column>
|
||||
<Table.Column
|
||||
title="关联商品数"
|
||||
data-index="productCount"
|
||||
key="productCount"
|
||||
:width="100"
|
||||
/>
|
||||
<Table.Column title="状态" key="status" :width="90">
|
||||
<template #default="{ record }">
|
||||
<Switch
|
||||
:checked="record.status === 'enabled'"
|
||||
size="small"
|
||||
@change="
|
||||
(checked) => toggleScheduleStatus(record, checked === true)
|
||||
"
|
||||
/>
|
||||
</template>
|
||||
</Table.Column>
|
||||
<Table.Column
|
||||
title="更新时间"
|
||||
data-index="updatedAt"
|
||||
key="updatedAt"
|
||||
:width="170"
|
||||
/>
|
||||
<Table.Column title="操作" key="action" :width="170">
|
||||
<template #default="{ record }">
|
||||
<Space size="small">
|
||||
<Button size="small" @click="openEditDrawer(record)">编辑</Button>
|
||||
<Button danger size="small" @click="removeSchedule(record)">
|
||||
删除
|
||||
</Button>
|
||||
</Space>
|
||||
</template>
|
||||
</Table.Column>
|
||||
</Table>
|
||||
</Card>
|
||||
<Button type="primary" @click="openCreateDrawer">+ 添加时段规则</Button>
|
||||
</div>
|
||||
|
||||
<Drawer
|
||||
<div v-if="selectedStoreId" class="ptm-stats">
|
||||
<span>
|
||||
时段规则 <strong>{{ ruleCount }}</strong>
|
||||
</span>
|
||||
<span>
|
||||
启用 <strong>{{ enabledCount }}</strong>
|
||||
</span>
|
||||
<span>
|
||||
覆盖商品 <strong>{{ coveredProductCount }}</strong>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div v-if="selectedStoreId" class="ptm-banner">
|
||||
<span class="icon"><IconifyIcon icon="lucide:info" /></span>
|
||||
设置商品在特定时段内供应,未被任何规则覆盖的商品默认全天供应。
|
||||
</div>
|
||||
|
||||
<div v-if="!selectedStoreId" class="ptm-empty">
|
||||
暂无门店,请先创建门店
|
||||
</div>
|
||||
|
||||
<Spin v-else :spinning="isLoading">
|
||||
<template v-if="filteredRows.length > 0">
|
||||
<ScheduleRuleCard
|
||||
v-for="item in filteredRows"
|
||||
:key="item.id"
|
||||
:item="item"
|
||||
:color="getRuleColor(item.id)"
|
||||
:product-names="getScheduleProductNames(item)"
|
||||
@edit="openEditDrawer"
|
||||
@toggle-status="toggleRuleStatus"
|
||||
@remove="removeRule"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<div v-else class="ptm-empty">
|
||||
<Empty description="暂无时段规则" />
|
||||
</div>
|
||||
|
||||
<ScheduleTimelineCard :rows="timelineRows" />
|
||||
</Spin>
|
||||
</div>
|
||||
|
||||
<ScheduleEditorDrawer
|
||||
:open="isDrawerOpen"
|
||||
:title="drawerTitle"
|
||||
width="660"
|
||||
:destroy-on-close="true"
|
||||
@update:open="setDrawerOpen"
|
||||
>
|
||||
<Form layout="vertical">
|
||||
<Form.Item label="时段名称" required>
|
||||
<Input v-model:value="form.name" :maxlength="30" show-count />
|
||||
</Form.Item>
|
||||
<Form.Item label="时段描述">
|
||||
<Input v-model:value="form.description" :maxlength="100" show-count />
|
||||
</Form.Item>
|
||||
<Form.Item label="关联商品">
|
||||
<Select
|
||||
v-model:value="form.productIds"
|
||||
mode="multiple"
|
||||
:options="pickerOptions"
|
||||
placeholder="请选择商品"
|
||||
/>
|
||||
</Form.Item>
|
||||
:submit-text="drawerSubmitText"
|
||||
:submitting="isDrawerSubmitting"
|
||||
:form="form"
|
||||
:selected-products="selectedProducts"
|
||||
@close="setDrawerOpen(false)"
|
||||
@set-name="setFormName"
|
||||
@set-start-time="setFormStartTime"
|
||||
@set-end-time="setFormEndTime"
|
||||
@toggle-week-day="toggleWeekDay"
|
||||
@select-all-days="selectAllDays"
|
||||
@select-weekdays="selectWeekdays"
|
||||
@select-weekend="selectWeekend"
|
||||
@open-product-picker="openProductPicker"
|
||||
@remove-product="removeFormProduct"
|
||||
@toggle-status="toggleFormStatus"
|
||||
@submit="submitDrawer"
|
||||
/>
|
||||
|
||||
<Divider orientation="left">时段配置</Divider>
|
||||
<div v-for="(slot, index) in form.slots" :key="index" class="slot-row">
|
||||
<Select
|
||||
v-model:value="slot.weekDays"
|
||||
mode="multiple"
|
||||
:options="weekDayOptions"
|
||||
style="width: 220px"
|
||||
placeholder="选择星期"
|
||||
/>
|
||||
<Input
|
||||
v-model:value="slot.startTime"
|
||||
style="width: 110px"
|
||||
placeholder="开始 HH:mm"
|
||||
/>
|
||||
<Input
|
||||
v-model:value="slot.endTime"
|
||||
style="width: 110px"
|
||||
placeholder="结束 HH:mm"
|
||||
/>
|
||||
<Button danger @click="removeSlot(index)">删除</Button>
|
||||
</div>
|
||||
<Button @click="addSlot">新增时段</Button>
|
||||
|
||||
<Divider />
|
||||
<Space style="display: flex; width: 100%">
|
||||
<Form.Item label="排序" style="flex: 1">
|
||||
<InputNumber
|
||||
v-model:value="form.sort"
|
||||
:min="1"
|
||||
style="width: 100%"
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item label="状态" style="flex: 1">
|
||||
<Select
|
||||
v-model:value="form.status"
|
||||
:options="[
|
||||
{ label: '启用', value: 'enabled' },
|
||||
{ label: '停用', value: 'disabled' },
|
||||
]"
|
||||
/>
|
||||
</Form.Item>
|
||||
</Space>
|
||||
</Form>
|
||||
|
||||
<template #footer>
|
||||
<Space>
|
||||
<Button @click="setDrawerOpen(false)">取消</Button>
|
||||
<Button
|
||||
type="primary"
|
||||
:loading="isDrawerSubmitting"
|
||||
@click="submitDrawer"
|
||||
>
|
||||
保存
|
||||
</Button>
|
||||
</Space>
|
||||
</template>
|
||||
</Drawer>
|
||||
<ScheduleProductPickerModal
|
||||
:open="isPickerOpen"
|
||||
title="关联商品"
|
||||
:loading="isPickerLoading"
|
||||
:submitting="false"
|
||||
:keyword="pickerKeyword"
|
||||
:products="pickerProducts"
|
||||
:selected-ids="pickerSelectedIds"
|
||||
@close="setPickerOpen(false)"
|
||||
@set-keyword="setPickerKeyword"
|
||||
@search="loadPickerProducts"
|
||||
@toggle-product="togglePickerProduct"
|
||||
@submit="submitPicker"
|
||||
/>
|
||||
</Page>
|
||||
</template>
|
||||
|
||||
<style scoped lang="less">
|
||||
/* 文件职责:时段供应页面样式。 */
|
||||
.page-product-schedule {
|
||||
.slot-row {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
:deep(.ant-table-cell) {
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
<style lang="less">
|
||||
@import './styles/index.less';
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user