Ver código fonte

add product list page

dev
powersir 1 ano atrás
pai
commit
087f896594
7 arquivos alterados com 386 adições e 71 exclusões
  1. +2
    -1
      src/models/index.ts
  2. +49
    -13
      src/models/product.data.ts
  3. +0
    -0
      src/models/user.data.ts
  4. +192
    -4
      src/pages/custom/product/finished/index.tsx
  5. +38
    -23
      src/pages/custom/product/material/index.tsx
  6. +39
    -2
      src/pages/custom/product/sample/index.tsx
  7. +66
    -28
      src/pages/custom/product/shape/index.tsx

+ 2
- 1
src/models/index.ts Ver arquivo

@@ -1,4 +1,5 @@
export * from './user.ts'
export * from './user.data.ts'
export * from './product.data.ts'

export interface ResponseDTO<T>{
code: number;


src/pages/custom/product/shape/shape.data.ts → src/models/product.data.ts Ver arquivo

@@ -24,11 +24,14 @@ export interface Shape {


export interface ProductBase {
id?: number;
productName: string;
productNameEn?:string;
}

export interface ProductClassify {
id: number;
name?: string;
}

export interface ProductImage {
@@ -36,23 +39,14 @@ export interface ProductImage {
imgUrl:string;
}

export interface Product {
export interface ProductCategory {
id: number;
spuCode: string;
classifyId: number;
sourceType: number;
productStatus: number;
creatorId: number;
createTime: string;
base: ProductBase;
classify: ProductClassify;
attrs: string[];
productImgs: ProductImage[];
productSkus: string[];
creatorName: string;
categoryName: string;
categoryNameEn: string;
}



export interface SdParamEmplate {
id: number;
createTime: string;
@@ -73,3 +67,45 @@ export interface SdParamEmplate {
isDelete: number;
niter: number;
}

export interface SkuAttr {
attrName: string;
attrValName: string;
}

export interface ProductSku {
id: number;
spuCode: string;
skuCode: string;
skuImgId: number;
weight: number;
costPrice: number;
homeFreight: number;
packCost: number;
minRetailPrice: number;
length: number;
width: number;
height: number;
rawSku: string;
skuStatus: number;
attrs: SkuAttr[];
skuImgUrl: string;
}

export interface Product {
id: number;
spuCode: string;
categoryId?: number;
classifyId: number;
sourceType: number;
productStatus: number;
creatorId: number;
createTime: string;
base: ProductBase;
category?: ProductCategory;
classify: ProductClassify;
attrs: string[];
productImgs: ProductImage[];
productSkus: ProductSku[];
creatorName: string;
}

src/models/user.ts → src/models/user.data.ts Ver arquivo


+ 192
- 4
src/pages/custom/product/finished/index.tsx Ver arquivo

@@ -1,9 +1,197 @@
import { Empty } from 'antd';
import { Space, Table, Button, Image, Divider, Badge, Modal, notification, message } from 'antd';
import type { TableColumnsType } from 'antd';
import { t } from '@/utils/i18n';
import React, { useState } from 'react';
import mData from '../../../../../mock/productListPage.json'
import { PlusOutlined, ExclamationCircleFilled } from '@ant-design/icons';
import type { Product, ProductBase, ProductImage, ProductSku } from '@/models'

const { confirm } = Modal;
type NotificationType = 'success' | 'info' | 'warning' | 'error';
//成品
const FinishedProductPage: React.FC = () => {

const [notificationApi, notificationContextHolder] = notification.useNotification();
const [messageApi, messageContextHolder] = message.useMessage();

const openNotificationWithIcon = (type: NotificationType) => {
notificationApi[type]({
message: '删除成功',
description:
'商品信息已删除',
});
};

const showDeleteConfirm = () => {
confirm({
title: '确认要将该商品删除吗?',
icon: <ExclamationCircleFilled />,
content: '请注意删除以后不可恢复!',
okText: '删除',
okType: 'danger',
cancelText: '取消',
onOk() {
return new Promise((resolve, reject) => {
setTimeout(() => {
messageApi.open({
type: 'success',
content: '删除成功',
});
resolve(null)
}, 1000);
// openNotificationWithIcon('success')

}).catch(() => messageApi.open({
type: 'error',
content: '操作失败',
}));
},
onCancel() {
},
});
};

const columns: TableColumnsType<Product> = [
{
title: '商品主图',
dataIndex: 'productImgs',
key: 'productImgs',
render: (value: ProductImage[]) => (
value.length > 0 && <Image className='bg-[gold]' src={value[0].imgUrl} />
),
align: 'center',
width: 100,
},
{
title: 'SPU编码',
dataIndex: 'spuCode',
key: 'spuCode',
width: 100,
},
{
title: '数据源',
dataIndex: 'sourceType',
key: 'sourceType',
width: 100,
render: (value: number) => (value == 4 ? 'diy导入' : '未知')
},
{
title: '商品标题',
key: 'base',
dataIndex: 'base',
render: (value: ProductBase) => (
<>
<div>{value.productName}</div>
<div>{value.productNameEn}</div>
</>
)
},
{
title: '类目',
key: 'category',
dataIndex: ['category', 'categoryName'],
width: 100,
},
{
title: '商品状态',
key: 'productStatus',
dataIndex: 'productStatus',
width: 100,
render: (value: number) => {
return (value === 1 ? <Badge status="error" text="未审核" /> : <Badge status="success" text="已审核" />)
}
},
{
title: '总销售额',
key: 'specimenNumber',
dataIndex: 'specimenNumber',
width: 100,
render: (value: number) => ('-')
},
{
title: '创建人',
dataIndex: 'creatorName',
key: 'creatorName',
width: 150,
},
{
title: '创建时间',
key: 'createTime',
dataIndex: 'createTime',
width: 200,
},
{
title: t("QkOmYwne" /* 操作 */),
key: 'action',
render: (_, record) => (
<Space size="small" split={(
<Divider type='vertical' />
)}>
<a
onClick={() => {

}}>
编辑
</a>
<a
onClick={() => {
showDeleteConfirm()
}}>
删除
</a>
<a
onClick={() => {

}}>
认领商品
</a>
</Space>
),
width: 250,
},
];

const expandedColumnsRender = (item: Product) => {
const expandedColumns: TableColumnsType<ProductSku> = [
{ title: '序号', key: 'index', align: 'center', render: (data, _, index) => (<>{index}</>) },
{
title: '缩略图', dataIndex: 'skuImgUrl', key: 'productImgs', width: 80, render: (value: string) => (
<Image className='bg-[gold] align-middle flex items-center justify-center w-[40px] h-[40px]' src={value} />
)
},
{ title: 'SKU编码', dataIndex: 'skuCode', key: 'spuCode' },
{ title: '建议零售价', dataIndex: 'costPrice', key: 'costPrice' },
{ title: '重量', dataIndex: 'weight', key: 'weight' },
{ title: '销售额', dataIndex: 'packCost', key: 'packCost' },
{ title: '长', dataIndex: 'length', key: 'length' },
{ title: '宽', dataIndex: 'width', key: 'width' },
{ title: '高', dataIndex: 'height', key: 'height' }
];
const data: Array<ProductSku> = item.productSkus;
return <Table columns={expandedColumns} dataSource={data} pagination={false} size='small' />;
}

const data: Array<Product> = mData as Array<Product>;

const CustomMade = () => {
return (
<Empty />
<>
{notificationContextHolder}
{messageContextHolder}
<div className='mt-[4px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]'>
<div className="py-[8px]">
<Button className="ml-5" type='primary' size='large' icon={<PlusOutlined />}> 批量操作 </Button>
</div>
<Table rowKey="id"
scroll={{ x: true }}
columns={columns}
expandable={{ expandedRowRender: expandedColumnsRender, defaultExpandedRowKeys: ['0'] }}
dataSource={data}
className='bg-transparent'
pagination={{ position: ['bottomRight'] }} />
</div>
</>

);
};

export default CustomMade;
export default FinishedProductPage;

+ 38
- 23
src/pages/custom/product/material/index.tsx Ver arquivo

@@ -1,30 +1,13 @@
import { Space, Tag, Table, Form, Row, Col, Input, InputNumber, Button, Avatar, Divider } from 'antd';
import { Space, Tag, Table, Modal, message, Col, Input, InputNumber, Button, Avatar, Divider } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { t } from '@/utils/i18n';
import { IconBuguang } from '@/assets/icons/buguang';
import React, { useState } from 'react';
import type { TableRowSelection } from 'antd/es/table/interface';
import mData from '../../../../../mock/findMaterialPage.json'
import { PlusOutlined } from '@ant-design/icons';
import { PlusOutlined, ExclamationCircleFilled } from '@ant-design/icons';


// {
// "id": 1465,
// "createTime": "2023-06-06 10:47:21",
// "classifyId": 52,
// "materialImgId": 1875217,
// "materialName": "HDC-11010015-P",
// "materialRemark": "multiple boys, brown hair, striped, hat, baseball cap, dark skin, backpack, jacket, dark-skinned male, pink dress, bag, white background, headband, camera, pants, shirt, striped shirt, backwards hat, dress, 1girl, parody, bandana, black hair, simple background, vest, holding, english text, 3boys, standing, blue jacket, white skin, short hair, shoes",
// "materialWidth": 885.0000,
// "materialHeight": 711.0000,
// "materialSize": 617393,
// "createId": 1,
// "classify": {
// "id": 52,
// "classifyName": "其他"
// },
// "materialImgUrl": "https://test.vogocm.com:9010/eshop/eshop_img/2023/6/06/20230606104721A806.png"
// },
const { confirm } = Modal;

interface Classify {
id: number;
@@ -48,6 +31,35 @@ interface DataType {
}

const TablePage: React.FC = () => {
const [messageApi, messageContextHolder] = message.useMessage();

const showDeleteConfirm = (item: DataType) => {
confirm({
title: `确认删除标题为: ${item.materialName} 的素材吗?`,
icon: <ExclamationCircleFilled />,
content: '请注意删除以后不可恢复!',
okText: '删除',
okType: 'danger',
cancelText: '取消',
onOk() {
return new Promise((resolve, reject) => {
setTimeout(() => {
messageApi.open({
type: 'success',
content: '删除成功',
});
resolve(null)
}, 1000);

}).catch(() => messageApi.open({
type: 'error',
content: '操作失败',
}));
},
onCancel() {
},
});
};

const columns: ColumnsType<DataType> = [
{
@@ -172,8 +184,7 @@ const TablePage: React.FC = () => {
</a>
<a
onClick={() => {
// setEditData(record);
// setCreateVisible(true);
showDeleteConfirm(record)
}}>
删除
</a>
@@ -232,7 +243,9 @@ const TablePage: React.FC = () => {


return (
<div className='mt-[4px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]'>
<>
{messageContextHolder}
<div className='mt-[4px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]'>
<div className="py-[8px]">
<Button className="ml-5" type='primary' size='large' icon={<PlusOutlined/>}> 新增素材 </Button>
</div>
@@ -240,6 +253,8 @@ const TablePage: React.FC = () => {
pagination={{ position: ['bottomRight'] }}
/>
</div>
</>

);
};



+ 39
- 2
src/pages/custom/product/sample/index.tsx Ver arquivo

@@ -1,4 +1,4 @@
import { Space, Tag, Table, Form, Row, Col, Input, InputNumber, Button, Avatar } from 'antd';
import { Space, Modal, Table, Form, message, Col, Input, InputNumber, Button, Avatar } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { t } from '@/utils/i18n';
import { IconBuguang } from '@/assets/icons/buguang';
@@ -9,6 +9,9 @@ import MaskPictureEditor from './components/mask-picture-editor';
import type { SampleAttribute } from './components/attr-editor'
import type { MaskPicture } from './components/mask-picture-editor';
import { useNavigate } from 'react-router-dom';
import { ExclamationCircleFilled } from '@ant-design/icons';

const { confirm } = Modal;

interface DataType {
id: number;
@@ -25,6 +28,36 @@ interface DataType {

const TablePage: React.FC = () => {

const [messageApi, messageContextHolder] = message.useMessage();

const showDeleteConfirm = (item: DataType) => {
confirm({
title: `确认删除标题为: ${item.prototypeName} 的样机吗?`,
icon: <ExclamationCircleFilled />,
content: `请注意删除以后不可恢复!`,
okText: '删除',
okType: 'danger',
cancelText: '取消',
onOk() {
return new Promise((resolve, reject) => {
setTimeout(() => {
messageApi.open({
type: 'success',
content: '删除成功',
});
resolve(null)
}, 1000);

}).catch(() => messageApi.open({
type: 'error',
content: '操作失败',
}));
},
onCancel() {
},
});
};

const columns: ColumnsType<DataType> = [
{
title: '示例图',
@@ -84,7 +117,10 @@ const TablePage: React.FC = () => {
onClick={() => {
navigate('/custom/product/sample/editor')
}}>编辑</a>
<a>删除</a>
<a
onClick={() => {
showDeleteConfirm(record)
}}>删除</a>
</Space>
),
},
@@ -269,6 +305,7 @@ const TablePage: React.FC = () => {

return (
<div>
{messageContextHolder}
<div className="dark:bg-[rgb(33,41,70)] rounded-md">
<Table rowKey="id" rowSelection={rowSelection} scroll={{ x: true }} columns={columns} dataSource={data} className='bg-transparent'
pagination={{ position: ['bottomRight'] }}


+ 66
- 28
src/pages/custom/product/shape/index.tsx Ver arquivo

@@ -1,23 +1,54 @@
import { Space, Table, Button, Image, Divider } from 'antd';
import { Space, Table, Button, Image, Divider, message, Modal } from 'antd';
import type { TableColumnsType } from 'antd';
import { t } from '@/utils/i18n';
import { IconBuguang } from '@/assets/icons/buguang';
import React, { useState } from 'react';
import mData from '../../../../../mock/findDiySpecimenPage.json'
import shapeData from '../../../../../mock/findSpecimensByPrototypeId.json'
import { PlusOutlined } from '@ant-design/icons';
import type { ShapeProperty, Shape, ProductImage } from './shape.data'
import { PlusOutlined, ExclamationCircleFilled } from '@ant-design/icons';
import type { ShapeProperty, Shape, ProductImage } from '@/models'

const { confirm } = Modal;

const ShapePage: React.FC = () => {

const [messageApi, messageContextHolder] = message.useMessage();

const showDeleteConfirm = (item: Shape) => {
confirm({
title: `确认删除标题为: ${item.sdParamEmplate.chinaName} 的素材吗?`,
icon: <ExclamationCircleFilled />,
content: '请注意删除以后不可恢复!',
okText: '删除',
okType: 'danger',
cancelText: '取消',
onOk() {
return new Promise((resolve, reject) => {
setTimeout(() => {
messageApi.open({
type: 'success',
content: '删除成功',
});
resolve(null)
}, 1000);

}).catch(() => messageApi.open({
type: 'error',
content: '操作失败',
}));
},
onCancel() {
},
});
};

const columns: TableColumnsType<ShapeProperty> = [
{
title: '示例图',
dataIndex: 'oneImgUrl',
key: 'oneImgUrl',
render: (value: string) => (
<div className='flex justify-center'>
<Image className='bg-[gold] align-middle flex items-center justify-center w-[40px] h-[40px]' src={value}/>
</div>
<Image className='bg-[gold] w-[40px] h-[40px]' src={value} />
),
align: 'center',
width: 130,
@@ -35,7 +66,7 @@ const ShapePage: React.FC = () => {
width: 150,
},
{
title:'类目',
title: '类目',
key: 'categoryName',
dataIndex: 'categoryName'
},
@@ -44,7 +75,7 @@ const ShapePage: React.FC = () => {
key: 'specimenNumber',
dataIndex: 'specimenNumber',
width: 100,
render:(value: number) => (<>{value}</>)
render: (value: number) => (<>{value}</>)
},
{
title: '创建人',
@@ -53,7 +84,7 @@ const ShapePage: React.FC = () => {
width: 150,
},
{
title:'创建时间',
title: '创建时间',
key: 'createTime',
dataIndex: 'createTime',
width: 200,
@@ -79,24 +110,27 @@ const ShapePage: React.FC = () => {

const expandedColumnsRender = (item: ShapeProperty) => {
const expandedColumns: TableColumnsType<Shape> = [
{ title: '序号', key: 'index', align: 'center', render:(data, _ ,index)=>(<>{index}</>)},
{ title: '主图', dataIndex: ['product', 'productImgs'], key: 'productImgs', width: 100, render: (value: ProductImage[]) => (
value.length > 0 && <Image className='bg-[gold] align-middle flex items-center justify-center w-[40px] h-[40px]' src={value[0].imgUrl}/>
)},
{ title: '序号', key: 'index', align: 'center', render: (data, _, index) => (<>{index}</>) },
{
title: '主图', dataIndex: ['product', 'productImgs'], key: 'productImgs', width: 100, render: (value: ProductImage[]) => (
value.length > 0 && <Image className='bg-[gold] align-middle flex items-center justify-center w-[40px] h-[40px]' src={value[0].imgUrl} />
)
},
{ title: 'SPU', dataIndex: ['product', 'spuCode'], key: 'spuCode' },
{ title: '商品标题', dataIndex: ['product', 'base', 'productName'], key: 'productName' },
{ title: '背景词', dataIndex: ['sdParamEmplate','chinaName'], key: 'chinaName' },
{ title: '背景词', dataIndex: ['sdParamEmplate', 'chinaName'], key: 'chinaName' },
{ title: '商品状态', dataIndex: 'upgradeNum', key: 'status' },
{ title: '数据来源', dataIndex: ['product', 'sourceType'], key: 'sourceType', render: (value: number) => (<>diy导入</>)},
{ title: '数据来源', dataIndex: ['product', 'sourceType'], key: 'sourceType', render: (value: number) => (<>diy导入</>) },
{ title: '创建人', dataIndex: ['product', 'creatorName'], key: 'creatorName' },
{
title: t("QkOmYwne" /* 操作 */),
key: 'operation',
render: () => (
render: (_, record) => (
<Space size="middle">
<a>审核</a>
<a>编辑</a>
<a>删除</a>
<a
onClick={() => {showDeleteConfirm(record)}}>删除</a>
</Space>
),
},
@@ -118,18 +152,22 @@ const ShapePage: React.FC = () => {


return (
<div className='mt-[4px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]'>
<div className="py-[8px]">
<Button className="ml-5" type='primary' size='large' icon={<PlusOutlined/>}> 新增款式 </Button>
<>
{messageContextHolder}
<div className='mt-[4px] dark:bg-[rgb(33,41,70)] bg-white roundle-lg px[12px]'>
<div className="py-[8px]">
<Button className="ml-5" type='primary' size='large' icon={<PlusOutlined />}> 新增款式 </Button>
</div>
<Table rowKey="id"
scroll={{ x: true }}
columns={columns}
expandable={{ expandedRowRender: expandedColumnsRender, defaultExpandedRowKeys: ['0'] }}
dataSource={data}
className='bg-transparent'
pagination={{ position: ['bottomRight'] }} />
</div>
<Table rowKey="id"
scroll={{ x: true }}
columns={columns}
expandable={{ expandedRowRender: expandedColumnsRender, defaultExpandedRowKeys: ['0'] }}
dataSource={data}
className='bg-transparent'
pagination={{ position: ['bottomRight'] }}/>
</div>
</>

);
};



Carregando…
Cancelar
Salvar