Commit dbaa0fee by qinjianhui

feat: 共享库存表格、新增页面

parent 0b8a1459
import { BasePaginationData } from '@/types/api'
import axios from '../axios'
import { SearchForm, WarehouseRuleSettingData } from '@/types/api/warehouse/warehouseRuleSetting'
export function getWarehouseRuleSettingListApi(
data: SearchForm,
page: number,
pageSize: number,
) {
return axios.post<never, BasePaginationData<WarehouseRuleSettingData>>(
'warehouseRuleSetting/list_page',
{ ...data, page, pageSize },
)
}
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
align="center" align="center"
:class="isMore ? 'is-more-active' : ''" :class="isMore ? 'is-more-active' : ''"
></ElTableColumn> ></ElTableColumn>
<template v-for="column in columns" :key="column.key"> <template v-for="column in columns" :key="column.prop">
<ElTableColumn <ElTableColumn
v-if="column.type === 'expand'" v-if="column.type === 'expand'"
v-bind="column" v-bind="column"
......
export interface SearchForm {
startTime: string
endTime: string
warehouseSku: string
warehouseGroupName: string
status: number
}
export interface WarehouseRuleSettingData {
id?: number
createTime?: string
warehouseSku?: string
warehouseGroupName?: string
status?: number
}
export interface WarehouseRuleSpuItem {
warehouseSpu: string
productName: string
spuImage?: string
sortNo: number
}
export interface EditForm {
id?: number
warehouseGroupName?: string
status?: number
spuList?: WarehouseRuleSpuItem[]
}
import type { Column as ElColumn } from 'element-plus/lib/components/index.js' import type { Column as ElColumn } from 'element-plus/lib/components/index.js'
import type { VNode } from 'vue'
interface Column<D> extends Omit<ElColumn, 'width'> { interface Column<D> extends Omit<ElColumn, 'width'> {
/** 为 false 时隐藏该列;未设置时默认显示 */ /** 为 false 时隐藏该列;未设置时默认显示 */
showColumn?: boolean showColumn?: boolean
width?: number | string width?: number | string
minWidth?: number | string minWidth?: number | string
key?: string
slot?: string slot?: string
headerSlot?: string headerSlot?: string
headerRender?: (scope: { column: never; index: number }) => JSX.Element headerRender?: (scope: { column: never; index: number }) => JSX.Element
render?: (scope: { row: D; index: number }) => JSX.Element render?: (row: D, index: number) => VNode | JSX.Element
formatDate?: (row: D) => string formatDate?: (row: D) => string
children?: Column<D>[] children?: Column<D>[]
subs?: Column<D>[] subs?: Column<D>[]
......
<template>
<ElDialog
v-model="dialogVisible"
:title="editForm.id ? '编辑共享库存组' : '新增共享库存组'"
width="800px"
:close-on-click-modal="false"
destroy-on-close
>
<ElForm ref="editFormRef" :model="editForm" label-width="100px">
<div class="section-title">分组基础信息</div>
<ElFormItem
label="库存组名称"
prop="warehouseGroupName"
:rules="[
{ required: true, message: '请输入库存组名称', trigger: 'blur' },
]"
>
<ElInput
v-model="editForm.warehouseGroupName"
clearable
placeholder="请输入库存组名称"
style="width: 100%"
/>
</ElFormItem>
<ElFormItem
label="状态"
prop="status"
:rules="[{ required: true, message: '请选择状态', trigger: 'blur' }]"
>
<ElSwitch
v-model="editForm.status"
:active-value="1"
:inactive-value="0"
style="--el-switch-on-color: #42b983"
/>
</ElFormItem>
<div class="section-title">组内SPU清单</div>
<div class="spu-search-bar">
<ElInput
v-model="spuSearchKeyword"
clearable
placeholder="请输入库存SPU"
style="width: 200px"
@keyup.enter="handleSearchSpu"
/>
<ElButton type="primary" @click="handleSearchSpu">查询</ElButton>
</div>
<div class="spu-drag-tip">
<el-icon style="color: #409eff; font-size: 16px"><Warning /></el-icon
><span>拖动SPU调整扣减顺序</span>
</div>
<div class="spu-table-wrapper">
<TableView
:paginated-data="editForm.spuList ?? []"
:columns="spuTableColumns"
row-key="warehouseSpu"
size="small"
>
<template #sortNo="{ row, index }">
<span
class="drag-handle"
draggable="true"
@dragstart="handleDragStart(index)"
@dragover.prevent
@drop="handleDrop(index)"
>
{{ row.sortNo }}
</span>
</template>
<template #spuImage="{ row }">
<ImageView :src="row.spuImage" width="40px" height="40px" />
</template>
<template #operation="{ index }">
<ElButton link type="danger" @click="handleRemoveSpu(index)">
删除
</ElButton>
</template>
</TableView>
</div>
</ElForm>
<template #footer>
<div class="dialog-footer">
<ElButton @click="handleCancel">取消</ElButton>
<ElButton type="primary" :loading="saving" @click="handleSave">
保存
</ElButton>
</div>
</template>
</ElDialog>
</template>
<script setup lang="ts">
import ImageView from '@/components/ImageView.vue'
import TableView from '@/components/TableView.vue'
import {
EditForm,
WarehouseRuleSpuItem,
} from '@/types/api/warehouse/warehouseRuleSetting'
import { Warning } from '@element-plus/icons-vue'
import { useWarehouseRuleSettingTableColumns } from '../hooks/useWarehouseRuleSettingTableColumns'
const emit = defineEmits<{
(e: 'update:visible', value: boolean): void
(e: 'saved'): void
}>()
const props = defineProps<{
visible: boolean
}>()
const dialogVisible = computed({
get() {
return props.visible
},
set(value: boolean) {
emit('update:visible', value)
},
})
const createDefaultForm = (): EditForm => ({
id: undefined,
warehouseGroupName: '',
status: 1,
spuList: [],
})
const editForm = ref<EditForm>(createDefaultForm())
const editFormRef = ref()
const spuSearchKeyword = ref('')
const saving = ref(false)
const dragIndex = ref<number | null>(null)
const { spuTableColumns } = useWarehouseRuleSettingTableColumns()
const resetFields = () => {
editForm.value = createDefaultForm()
spuSearchKeyword.value = ''
dragIndex.value = null
nextTick(() => {
editFormRef.value?.clearValidate()
})
}
const updateSortNo = (list: WarehouseRuleSpuItem[]) => {
return list.map((item, index) => ({
...item,
sortNo: index + 1,
}))
}
const handleDragStart = (index: number) => {
dragIndex.value = index
}
const handleDrop = (index: number) => {
if (dragIndex.value === null || dragIndex.value === index) {
return
}
const list = [...(editForm.value.spuList ?? [])]
const [movedItem] = list.splice(dragIndex.value, 1)
list.splice(index, 0, movedItem)
editForm.value.spuList = updateSortNo(list)
dragIndex.value = null
}
const handleSearchSpu = () => {
// TODO: 调用接口查询库存SPU并添加到列表
}
const handleRemoveSpu = (index: number) => {
const list = [...(editForm.value.spuList ?? [])]
list.splice(index, 1)
editForm.value.spuList = updateSortNo(list)
}
const handleCancel = () => {
dialogVisible.value = false
}
const handleSave = async () => {
const valid = await editFormRef.value?.validate().catch(() => false)
if (!valid) {
return
}
saving.value = true
try {
// TODO: 调用保存接口
emit('saved')
dialogVisible.value = false
} finally {
saving.value = false
}
}
defineExpose({
resetFields,
})
</script>
<style scoped lang="scss">
.section-title {
font-size: 14px;
font-weight: 600;
color: #303133;
margin-bottom: 12px;
padding-left: 8px;
border-left: 3px solid #409eff;
& + .el-form-item {
margin-top: 0;
}
&:not(:first-child) {
margin-top: 8px;
}
}
.spu-search-bar {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 8px;
}
.spu-drag-tip {
font-size: 12px;
color: #909399;
margin-bottom: 8px;
display: flex;
align-items: center;
gap: 4px;
}
.spu-table-wrapper {
height: 280px;
}
.drag-handle {
display: inline-block;
width: 100%;
cursor: move;
user-select: none;
}
.dialog-footer {
display: flex;
justify-content: center;
gap: 10px;
}
</style>
import { ElButton, ElTag } from 'element-plus'
import type { WarehouseRuleSettingData } from '@/types/api/warehouse/warehouseRuleSetting'
const statusMap: Record<number, { label: string; type: 'success' | 'info' }> = {
1: { label: '启用', type: 'success' },
0: { label: '禁用', type: 'info' },
}
export interface UseWarehouseRuleSettingTableColumnsOptions {
onEdit?: (row: WarehouseRuleSettingData) => void
}
export function useWarehouseRuleSettingTableColumns(
options: UseWarehouseRuleSettingTableColumnsOptions = {},
) {
const columns = computed(() => [
{
label: '库存组名称',
prop: '',
align: 'left',
},
{
label: '共享库存SPU',
prop: '',
align: 'left',
},
{
label: '创建时间',
prop: 'createTime',
width: 180,
align: 'center',
},
{
label: '状态',
prop: 'status',
width: 100,
align: 'center',
render: (row: WarehouseRuleSettingData) => {
const status = statusMap[row.status ?? -1]
return status ? (
<ElTag type={status.type}>{status.label}</ElTag>
) : (
<span>-</span>
)
},
},
{
label: '操作',
width: 100,
align: 'center',
render: (row: WarehouseRuleSettingData) => {
return (
<div>
<ElButton
link
type="primary"
onClick={() => options?.onEdit?.(row)}
>
编辑
</ElButton>
</div>
)
},
},
])
const spuTableColumns = computed(() => [
{
label: '扣减顺序',
width: 90,
align: 'center',
slot: 'sortNo',
},
{
label: '图片',
width: 80,
align: 'center',
slot: 'spuImage',
},
{
label: '库存SPU',
prop: 'warehouseSpu',
minWidth: 120,
align: 'left',
},
{
label: '商品名称',
prop: 'productName',
minWidth: 160,
align: 'left',
},
{
label: '操作',
width: 80,
align: 'center',
slot: 'operation',
},
])
return { columns, spuTableColumns }
}
...@@ -11,15 +11,152 @@ ...@@ -11,15 +11,152 @@
</div> </div>
<div class="content-container flex-1 flex-column overflow-hidden"> <div class="content-container flex-1 flex-column overflow-hidden">
主要内容 <div class="search-form">
<ElForm ref="searchFormRef" :model="searchForm" inline>
<ElFormItem label="创建时间">
<ElDatePicker
v-model="dateRange"
:default-time="[
new Date(0, 0, 0, 0, 0, 0),
new Date(0, 0, 0, 23, 59, 59),
]"
type="datetimerange"
start-placeholder="开始时间"
end-placeholder="结束时间"
clearable
style="width: 260px"
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
/>
</ElFormItem>
<ElFormItem label="库存SKU">
<ElInput
v-model="searchForm.warehouseSku"
clearable
placeholder="库存SKU"
style="width: 140px"
/>
</ElFormItem>
<ElFormItem label="库存组名称">
<ElInput
v-model="searchForm.warehouseGroupName"
clearable
placeholder="库存组名称"
style="width: 140px"
/>
</ElFormItem>
<ElFormItem label="状态"
><ElSelect
v-model="searchForm.status"
placeholder="请选择"
style="width: 140px"
>
<ElOption label="启用" :value="1" />
<ElOption label="禁用" :value="0" />
</ElSelect>
</ElFormItem>
<ElFormItem>
<ElButton @click="resetSearchForm">重置</ElButton>
</ElFormItem>
<ElFormItem>
<ElButton type="primary" @click="search">查询</ElButton>
</ElFormItem>
<ElFormItem>
<ElButton type="success" @click="() => handleEdit()">新增</ElButton>
</ElFormItem>
<ElFormItem>
<ElButton type="danger">删除</ElButton>
</ElFormItem>
</ElForm>
</div>
<div class="table-wrapper">
<TableView
serial-numberable
:selectionable="true"
:paginated-data="tableData"
:columns="tableColumns"
@selection-change="handleSelectionChange"
/>
</div>
<div class="table-pagination-bar">
<div class="selected-count-text">
已选择
<strong style="color: red">{{ selectedRows.length }}</strong>
条数据
</div>
<ElPagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:page-sizes="[100, 200, 300, 400, 500]"
background
layout="total, sizes, prev, pager, next, jumper"
:total="total"
style="margin: 0 auto"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
/>
</div>
</div> </div>
</div> </div>
<EditFormDialog ref="editFormRef" v-model:visible="editDialogVisible" />
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { getWarehouseRuleSettingListApi } from '@/api/warehouse/warehouseRuleSetting'
import {
SearchForm,
WarehouseRuleSettingData,
} from '@/types/api/warehouse/warehouseRuleSetting'
import usePageList from '@/utils/hooks/usePageList'
import { useValue } from '@/utils/hooks/useValue'
import { ElDatePicker, ElFormItem } from 'element-plus'
import { useWarehouseRuleSettingTableColumns } from './hooks/useWarehouseRuleSettingTableColumns'
import EditFormDialog from './components/EditDialog.vue'
const [searchForm, resetSearchForm] = useValue<SearchForm>({
startTime: '',
endTime: '',
warehouseSku: '',
warehouseGroupName: '',
status: 1,
})
const dateRange = ref([])
const currentStatus = ref('sharedInventory') const currentStatus = ref('sharedInventory')
const editDialogVisible = ref(false)
const editFormRef = ref()
const handleStatusClick = (status: string) => { const handleStatusClick = (status: string) => {
currentStatus.value = status currentStatus.value = status
} }
const {
currentPage,
pageSize,
total,
data: tableData,
refresh: search,
onCurrentPageChange: handleCurrentChange,
onPageSizeChange: handleSizeChange,
} = usePageList<WarehouseRuleSettingData>({
query: (page, pageSize) =>
getWarehouseRuleSettingListApi(searchForm.value, page, pageSize).then(
(res) => res.data,
),
})
const selectedRows = ref<WarehouseRuleSettingData[]>([])
const handleSelectionChange = (selection: WarehouseRuleSettingData[]) => {
selectedRows.value = selection
}
const handleEdit = async (row?: WarehouseRuleSettingData) => {
if (row) {
// 调用接口,获取数据
} else {
await editFormRef.value.resetFields()
}
editDialogVisible.value = true
}
const { columns: tableColumns } = useWarehouseRuleSettingTableColumns({
onEdit: handleEdit,
})
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.status-container { .status-container {
...@@ -40,4 +177,18 @@ const handleStatusClick = (status: string) => { ...@@ -40,4 +177,18 @@ const handleStatusClick = (status: string) => {
} }
} }
} }
.table-wrapper {
flex: 1;
overflow: hidden;
}
.table-pagination-bar {
margin-top: 10px;
display: flex;
align-items: center;
}
.selected-count-text {
font-size: 14px;
color: #606266;
white-space: nowrap;
}
</style> </style>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment