feat:【antd】mall 商品列表的优化代码
This commit is contained in:
@@ -2,11 +2,17 @@ import type { VbenFormSchema } from '#/adapter/form';
|
||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||
import type { MallSpuApi } from '#/api/mall/product/spu';
|
||||
|
||||
import { handleTree } from '@vben/utils';
|
||||
import { fenToYuan, handleTree, treeToString } from '@vben/utils';
|
||||
|
||||
import { getCategoryList } from '#/api/mall/product/category';
|
||||
import { getRangePickerDefaultProps } from '#/utils';
|
||||
|
||||
/** 关联数据 */
|
||||
let categoryList: any[] = [];
|
||||
getCategoryList({}).then((data) => {
|
||||
categoryList = handleTree(data, 'id', 'parentId', 'children');
|
||||
});
|
||||
|
||||
/** 列表的搜索表单 */
|
||||
export function useGridFormSchema(): VbenFormSchema[] {
|
||||
return [
|
||||
@@ -14,16 +20,19 @@ export function useGridFormSchema(): VbenFormSchema[] {
|
||||
fieldName: 'name',
|
||||
label: '商品名称',
|
||||
component: 'Input',
|
||||
componentProps: {
|
||||
placeholder: '请输入商品名称',
|
||||
allowClear: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
fieldName: 'categoryId',
|
||||
label: '商品分类',
|
||||
component: 'ApiTreeSelect',
|
||||
componentProps: {
|
||||
api: async () => {
|
||||
const res = await getCategoryList({});
|
||||
return handleTree(res, 'id', 'parentId', 'children');
|
||||
},
|
||||
placeholder: '请选择商品分类',
|
||||
allowClear: true,
|
||||
options: categoryList,
|
||||
fieldNames: { label: 'name', value: 'id', children: 'children' },
|
||||
},
|
||||
},
|
||||
@@ -47,16 +56,11 @@ export function useGridColumns(
|
||||
) => PromiseLike<boolean | undefined>,
|
||||
): VxeTableGridOptions['columns'] {
|
||||
return [
|
||||
{
|
||||
type: 'expand',
|
||||
width: 80,
|
||||
slots: { content: 'expand_content' },
|
||||
fixed: 'left',
|
||||
},
|
||||
{
|
||||
field: 'id',
|
||||
title: '商品编号',
|
||||
fixed: 'left',
|
||||
minWidth: 100,
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
@@ -67,30 +71,23 @@ export function useGridColumns(
|
||||
{
|
||||
field: 'picUrl',
|
||||
title: '商品图片',
|
||||
minWidth: 100,
|
||||
cellRender: {
|
||||
name: 'CellImage',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'price',
|
||||
title: '价格',
|
||||
formatter: 'formatAmount2',
|
||||
},
|
||||
{
|
||||
field: 'salesCount',
|
||||
title: '销量',
|
||||
},
|
||||
{
|
||||
field: 'stock',
|
||||
title: '库存',
|
||||
},
|
||||
{
|
||||
field: 'sort',
|
||||
title: '排序',
|
||||
field: 'categoryId',
|
||||
title: '商品分类',
|
||||
minWidth: 150,
|
||||
formatter: ({ row }) => {
|
||||
return treeToString(categoryList, row.categoryId);
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
title: '销售状态',
|
||||
minWidth: 100,
|
||||
cellRender: {
|
||||
attrs: { beforeChange: onStatusChange },
|
||||
name: 'CellSwitch',
|
||||
@@ -102,9 +99,57 @@ export function useGridColumns(
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'price',
|
||||
title: '价格',
|
||||
minWidth: 100,
|
||||
formatter: 'formatAmount2',
|
||||
},
|
||||
{
|
||||
field: 'marketPrice',
|
||||
title: '市场价',
|
||||
minWidth: 100,
|
||||
formatter: ({ row }) => {
|
||||
return `${fenToYuan(row.marketPrice)} 元`;
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'costPrice',
|
||||
title: '成本价',
|
||||
minWidth: 100,
|
||||
formatter: ({ row }) => {
|
||||
return `${fenToYuan(row.costPrice)} 元`;
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'salesCount',
|
||||
title: '销量',
|
||||
minWidth: 80,
|
||||
},
|
||||
{
|
||||
field: 'virtualSalesCount',
|
||||
title: '虚拟销量',
|
||||
minWidth: 100,
|
||||
},
|
||||
{
|
||||
field: 'stock',
|
||||
title: '库存',
|
||||
minWidth: 80,
|
||||
},
|
||||
{
|
||||
field: 'browseCount',
|
||||
title: '浏览量',
|
||||
minWidth: 100,
|
||||
},
|
||||
{
|
||||
field: 'sort',
|
||||
title: '排序',
|
||||
minWidth: 80,
|
||||
},
|
||||
{
|
||||
field: 'createTime',
|
||||
title: '创建时间',
|
||||
minWidth: 160,
|
||||
formatter: 'formatDateTime',
|
||||
},
|
||||
{
|
||||
|
||||
@@ -7,17 +7,11 @@ import { useRoute, useRouter } from 'vue-router';
|
||||
|
||||
import { confirm, DocAlert, Page } from '@vben/common-ui';
|
||||
import { ProductSpuStatusEnum } from '@vben/constants';
|
||||
import {
|
||||
downloadFileFromBlobPart,
|
||||
fenToYuan,
|
||||
handleTree,
|
||||
treeToString,
|
||||
} from '@vben/utils';
|
||||
import { downloadFileFromBlobPart } from '@vben/utils';
|
||||
|
||||
import { Descriptions, message, Tabs } from 'ant-design-vue';
|
||||
import { message, Tabs } from 'ant-design-vue';
|
||||
|
||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||
import { getCategoryList } from '#/api/mall/product/category';
|
||||
import {
|
||||
deleteSpu,
|
||||
exportSpu,
|
||||
@@ -32,10 +26,6 @@ import { useGridColumns, useGridFormSchema } from './data';
|
||||
const { push } = useRouter();
|
||||
const route = useRoute();
|
||||
const tabType = ref(0);
|
||||
|
||||
// TODO @AI:放到 data.ts 里;
|
||||
const categoryList = ref();
|
||||
|
||||
const tabsData = ref([
|
||||
{
|
||||
name: '出售中',
|
||||
@@ -62,7 +52,7 @@ const tabsData = ref([
|
||||
type: 4,
|
||||
count: 0,
|
||||
},
|
||||
]); // tabs 数据
|
||||
]);
|
||||
|
||||
/** 刷新表格 */
|
||||
async function handleRefresh() {
|
||||
@@ -70,13 +60,19 @@ async function handleRefresh() {
|
||||
await getTabCount();
|
||||
}
|
||||
|
||||
/** 导出表格 */
|
||||
async function handleExport() {
|
||||
const data = await exportSpu(await gridApi.formApi.getValues());
|
||||
downloadFileFromBlobPart({ fileName: '商品.xls', source: data });
|
||||
}
|
||||
|
||||
/** 获得每个 Tab 的数量 */
|
||||
async function getTabCount() {
|
||||
const res = await getTabsCount();
|
||||
for (const objName in res) {
|
||||
const index = Number(objName);
|
||||
if (tabsData.value[index]) {
|
||||
tabsData.value[index].count = res[objName] as number;
|
||||
tabsData.value[index].count = res[objName]!;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -86,12 +82,6 @@ function handleCreate() {
|
||||
push({ name: 'ProductSpuAdd' });
|
||||
}
|
||||
|
||||
/** 导出表格 */
|
||||
async function handleExport() {
|
||||
const data = await exportSpu(await gridApi.formApi.getValues());
|
||||
downloadFileFromBlobPart({ fileName: '商品.xls', source: data });
|
||||
}
|
||||
|
||||
/** 编辑商品 */
|
||||
function handleEdit(row: MallSpuApi.Spu) {
|
||||
push({ name: 'ProductSpuEdit', params: { id: row.id } });
|
||||
@@ -104,34 +94,14 @@ async function handleDelete(row: MallSpuApi.Spu) {
|
||||
duration: 0,
|
||||
});
|
||||
try {
|
||||
await deleteSpu(row.id as number);
|
||||
message.success({
|
||||
content: $t('ui.actionMessage.deleteSuccess', [row.name]),
|
||||
});
|
||||
handleRefresh();
|
||||
await deleteSpu(row.id!);
|
||||
message.success($t('ui.actionMessage.deleteSuccess', [row.name]));
|
||||
await handleRefresh();
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
/** 添加到仓库 / 回收站的状态 */
|
||||
async function handleStatus02Change(row: MallSpuApi.Spu, newStatus: number) {
|
||||
// 二次确认
|
||||
const text =
|
||||
newStatus === ProductSpuStatusEnum.RECYCLE.status
|
||||
? '加入到回收站'
|
||||
: '恢复到仓库';
|
||||
confirm(`确认要"${row.name}"${text}吗?`)
|
||||
.then(async () => {
|
||||
await updateStatus({ id: row.id as number, status: newStatus });
|
||||
message.success(`${text}成功`);
|
||||
await handleRefresh();
|
||||
})
|
||||
.catch(() => {
|
||||
message.error(`${text}失败`);
|
||||
});
|
||||
}
|
||||
|
||||
/** 更新状态 */
|
||||
async function handleStatusChange(
|
||||
newStatus: number,
|
||||
@@ -139,14 +109,14 @@ async function handleStatusChange(
|
||||
): Promise<boolean | undefined> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 二次确认
|
||||
const text = row.status ? '上架' : '下架';
|
||||
const text = newStatus ? '上架' : '下架';
|
||||
confirm({
|
||||
content: `确认要${text + row.name}吗?`,
|
||||
})
|
||||
.then(async () => {
|
||||
// 更新状态
|
||||
const res = await updateStatus({
|
||||
id: row.id as number,
|
||||
id: row.id!,
|
||||
status: newStatus,
|
||||
});
|
||||
if (res) {
|
||||
@@ -163,6 +133,28 @@ async function handleStatusChange(
|
||||
});
|
||||
}
|
||||
|
||||
/** 添加到仓库 / 回收站的状态 */
|
||||
async function handleStatus02Change(row: MallSpuApi.Spu, newStatus: number) {
|
||||
const text =
|
||||
newStatus === ProductSpuStatusEnum.RECYCLE.status
|
||||
? '加入到回收站'
|
||||
: '恢复到仓库';
|
||||
await confirm({
|
||||
content: `确认要"${row.name}"${text}吗?`,
|
||||
});
|
||||
const hideLoading = message.loading({
|
||||
content: `正在${text}中...`,
|
||||
duration: 0,
|
||||
});
|
||||
try {
|
||||
await updateStatus({ id: row.id!, status: newStatus });
|
||||
message.success(`${text}成功`);
|
||||
await handleRefresh();
|
||||
} finally {
|
||||
hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
/** 查看商品详情 */
|
||||
function handleDetail(row: MallSpuApi.Spu) {
|
||||
push({ name: 'ProductSpuDetail', params: { id: row.id } });
|
||||
@@ -175,12 +167,6 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
gridOptions: {
|
||||
columns: useGridColumns(handleStatusChange),
|
||||
height: 'auto',
|
||||
cellConfig: {
|
||||
height: 80,
|
||||
},
|
||||
expandConfig: {
|
||||
height: 100,
|
||||
},
|
||||
keepSource: true,
|
||||
proxyConfig: {
|
||||
ajax: {
|
||||
@@ -196,7 +182,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||
},
|
||||
rowConfig: {
|
||||
keyField: 'id',
|
||||
resizable: true,
|
||||
isHover: true,
|
||||
},
|
||||
toolbarConfig: {
|
||||
refresh: true,
|
||||
@@ -217,9 +203,8 @@ onMounted(async () => {
|
||||
categoryId: Number(route.query.categoryId),
|
||||
});
|
||||
}
|
||||
// 获得每个 Tab 的数量
|
||||
await getTabCount();
|
||||
const categoryRes = await getCategoryList({});
|
||||
categoryList.value = handleTree(categoryRes, 'id', 'parentId', 'children');
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -262,39 +247,6 @@ onMounted(async () => {
|
||||
]"
|
||||
/>
|
||||
</template>
|
||||
<template #expand_content="{ row }">
|
||||
<Descriptions
|
||||
:column="4"
|
||||
class="mx-32 my-4 w-1/2"
|
||||
:label-style="{
|
||||
width: '100px',
|
||||
fontWeight: 'bold',
|
||||
fontSize: '14px',
|
||||
color: '#99a9bf',
|
||||
}"
|
||||
:content-style="{ width: '100px', fontSize: '14px' }"
|
||||
>
|
||||
<Descriptions.Item label="商品分类">
|
||||
{{ treeToString(categoryList, row.categoryId!) }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="商品名称">
|
||||
{{ row.name }}
|
||||
</Descriptions.Item>
|
||||
|
||||
<Descriptions.Item label="市场价">
|
||||
{{ fenToYuan(row.marketPrice as number) }} 元
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="成本价">
|
||||
{{ fenToYuan(row.costPrice as number) }} 元
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="浏览量">
|
||||
{{ row.browseCount }}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="虚拟销量">
|
||||
{{ row.virtualSalesCount }}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</template>
|
||||
<template #actions="{ row }">
|
||||
<TableAction
|
||||
:actions="[
|
||||
|
||||
Reference in New Issue
Block a user