feat(模板管理): 新增模板管理功能模块
- 添加模板管理路由和页面组件 - 实现模板的增删改查接口 - 修改产品分类为品牌管理相关代码 - 更新字典管理接口路径
This commit is contained in:
parent
549b6615b7
commit
f15c0224c3
14
.umirc.ts
14
.umirc.ts
|
|
@ -56,6 +56,20 @@ export default defineConfig({
|
|||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
// 模板管理
|
||||
name: '模板管理',
|
||||
path: '/template',
|
||||
access: 'canSeeDict', // 权限暂用 canSeeDict
|
||||
routes: [
|
||||
{
|
||||
// 模板列表
|
||||
name: '模板列表',
|
||||
path: '/template/list',
|
||||
component: './Template', // 对应 src/pages/Template/index.tsx
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: '站点管理',
|
||||
path: '/site',
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ const DictPage: React.FC = () => {
|
|||
const fetchDicts = async (title?: string) => {
|
||||
setLoadingDicts(true);
|
||||
try {
|
||||
const res = await request('/api/dicts', { params: { title } });
|
||||
const res = await request('/dict/list', { params: { title } });
|
||||
if (res) {
|
||||
setDicts(res);
|
||||
}
|
||||
|
|
@ -46,7 +46,7 @@ const DictPage: React.FC = () => {
|
|||
const fetchDictItems = async (dictId?: number) => {
|
||||
setLoadingDictItems(true);
|
||||
try {
|
||||
const res = await request('/api/dict-items', { params: { dictId } });
|
||||
const res = await request('/dict/items', { params: { dictId } });
|
||||
if (res) {
|
||||
setDictItems(res);
|
||||
}
|
||||
|
|
@ -80,13 +80,13 @@ const DictPage: React.FC = () => {
|
|||
}
|
||||
try {
|
||||
if (editingDict) {
|
||||
await request(`/api/dicts/${editingDict.id}`, {
|
||||
await request(`/dict/${editingDict.id}`, {
|
||||
method: 'PUT',
|
||||
data: { name: newDictName, title: newDictTitle },
|
||||
});
|
||||
message.success('更新成功');
|
||||
} else {
|
||||
await request('/api/dicts', {
|
||||
await request('/dict', {
|
||||
method: 'POST',
|
||||
data: { name: newDictName, title: newDictTitle },
|
||||
});
|
||||
|
|
@ -132,14 +132,14 @@ const DictPage: React.FC = () => {
|
|||
try {
|
||||
if (editingDictItem) {
|
||||
// 编辑
|
||||
await request(`/api/dict-items/${editingDictItem.id}`, {
|
||||
await request(`/dict/item/${editingDictItem.id}`, {
|
||||
method: 'PUT',
|
||||
data: dictItemForm,
|
||||
});
|
||||
message.success('更新成功');
|
||||
} else {
|
||||
// 添加
|
||||
await request('/api/dict-items', {
|
||||
await request('/dict/item', {
|
||||
method: 'POST',
|
||||
data: { ...dictItemForm, dictId: selectedDict.id },
|
||||
});
|
||||
|
|
@ -155,7 +155,7 @@ const DictPage: React.FC = () => {
|
|||
// 处理删除字典项
|
||||
const handleDeleteDictItem = async (itemId: number) => {
|
||||
try {
|
||||
await request(`/api/dict-items/${itemId}`, { method: 'DELETE' });
|
||||
await request(`/dict/item/${itemId}`, { method: 'DELETE' });
|
||||
message.success('删除成功');
|
||||
fetchDictItems(selectedDict.id);
|
||||
} catch (error) {
|
||||
|
|
@ -166,7 +166,7 @@ const DictPage: React.FC = () => {
|
|||
// 处理删除字典
|
||||
const handleDeleteDict = async (dictId: number) => {
|
||||
try {
|
||||
await request(`/api/dicts/${dictId}`, { method: 'DELETE' });
|
||||
await request(`/dict/${dictId}`, { method: 'DELETE' });
|
||||
message.success('删除成功');
|
||||
fetchDicts(); // 重新获取字典列表
|
||||
// 如果删除的是当前选中的字典,则清空右侧列表
|
||||
|
|
@ -244,7 +244,7 @@ const DictPage: React.FC = () => {
|
|||
<Space>
|
||||
<Upload
|
||||
name="file"
|
||||
action="/api/dicts/import"
|
||||
action="/dict/import"
|
||||
showUploadList={false}
|
||||
onChange={info => {
|
||||
if (info.file.status === 'done') {
|
||||
|
|
@ -257,7 +257,7 @@ const DictPage: React.FC = () => {
|
|||
>
|
||||
<Button icon={<UploadOutlined />}>导入字典</Button>
|
||||
</Upload>
|
||||
<Button onClick={() => window.open('/api/dicts/template')}>下载模板</Button>
|
||||
<Button onClick={() => window.open('/dict/template')}>下载模板</Button>
|
||||
</Space>
|
||||
<Table
|
||||
dataSource={dicts}
|
||||
|
|
@ -287,7 +287,7 @@ const DictPage: React.FC = () => {
|
|||
<Space>
|
||||
<Upload
|
||||
name="file"
|
||||
action={`/api/dict-items/import`}
|
||||
action={`/dict/item/import`}
|
||||
data={{ dictId: selectedDict?.id }}
|
||||
showUploadList={false}
|
||||
disabled={!selectedDict}
|
||||
|
|
@ -302,7 +302,7 @@ const DictPage: React.FC = () => {
|
|||
>
|
||||
<Button icon={<UploadOutlined />} disabled={!selectedDict}>导入字典项</Button>
|
||||
</Upload>
|
||||
<Button onClick={() => window.open('/api/dict-items/template')} disabled={!selectedDict}>下载模板</Button>
|
||||
<Button onClick={() => window.open('/dict/item/template')} disabled={!selectedDict}>下载模板</Button>
|
||||
</Space>
|
||||
<Table dataSource={dictItems} columns={dictItemColumns} rowKey="id" loading={loadingDictItems} />
|
||||
</Space>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import {
|
||||
productcontrollerCreatecategory,
|
||||
productcontrollerDeletecategory,
|
||||
productcontrollerGetcategories,
|
||||
productcontrollerUpdatecategory,
|
||||
productcontrollerCreatebrand,
|
||||
productcontrollerDeletebrand,
|
||||
productcontrollerGetbrands,
|
||||
productcontrollerUpdatebrand,
|
||||
} from '@/servers/api/product';
|
||||
import { EditOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
|
|
@ -20,7 +20,7 @@ import { useRef } from 'react';
|
|||
const List: React.FC = () => {
|
||||
const actionRef = useRef<ActionType>();
|
||||
const { message } = App.useApp();
|
||||
const columns: ProColumns<API.Category>[] = [
|
||||
const columns: ProColumns<API.Brand>[] = [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
|
|
@ -65,7 +65,7 @@ const List: React.FC = () => {
|
|||
onConfirm={async () => {
|
||||
try {
|
||||
const { success, message: errMsg } =
|
||||
await productcontrollerDeletecategory({ id: record.id });
|
||||
await productcontrollerDeletebrand({ id: record.id });
|
||||
if (!success) {
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
|
|
@ -85,14 +85,14 @@ const List: React.FC = () => {
|
|||
];
|
||||
|
||||
return (
|
||||
<PageContainer header={{ title: '分类列表' }}>
|
||||
<ProTable<API.Category>
|
||||
<PageContainer header={{ title: '品牌列表' }}>
|
||||
<ProTable<API.Brand>
|
||||
headerTitle="查询表格"
|
||||
actionRef={actionRef}
|
||||
rowKey="id"
|
||||
toolBarRender={() => [<CreateForm tableRef={actionRef} />]}
|
||||
request={async (params) => {
|
||||
const { data, success } = await productcontrollerGetcategories(
|
||||
const { data, success } = await productcontrollerGetbrands(
|
||||
params,
|
||||
);
|
||||
return {
|
||||
|
|
@ -112,7 +112,7 @@ const CreateForm: React.FC<{
|
|||
}> = ({ tableRef }) => {
|
||||
const { message } = App.useApp();
|
||||
return (
|
||||
<DrawerForm<API.CreateCategoryDTO>
|
||||
<DrawerForm<API.CreateBrandDTO>
|
||||
title="新建"
|
||||
trigger={
|
||||
<Button type="primary">
|
||||
|
|
@ -127,7 +127,7 @@ const CreateForm: React.FC<{
|
|||
onFinish={async (values) => {
|
||||
try {
|
||||
const { success, message: errMsg } =
|
||||
await productcontrollerCreatecategory(values);
|
||||
await productcontrollerCreatebrand(values);
|
||||
if (!success) {
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
|
|
@ -142,7 +142,7 @@ const CreateForm: React.FC<{
|
|||
<ProFormText
|
||||
name="name"
|
||||
width="md"
|
||||
label="分类名称"
|
||||
label="品牌名称"
|
||||
placeholder="请输入名称"
|
||||
rules={[{ required: true, message: '请输入名称' }]}
|
||||
/>
|
||||
|
|
@ -159,11 +159,11 @@ const CreateForm: React.FC<{
|
|||
|
||||
const UpdateForm: React.FC<{
|
||||
tableRef: React.MutableRefObject<ActionType | undefined>;
|
||||
values: API.Category;
|
||||
values: API.Brand;
|
||||
}> = ({ tableRef, values: initialValues }) => {
|
||||
const { message } = App.useApp();
|
||||
return (
|
||||
<DrawerForm<API.UpdateCategoryDTO>
|
||||
<DrawerForm<API.UpdateBrandDTO>
|
||||
title="编辑"
|
||||
initialValues={initialValues}
|
||||
trigger={
|
||||
|
|
@ -179,7 +179,7 @@ const UpdateForm: React.FC<{
|
|||
onFinish={async (values) => {
|
||||
try {
|
||||
const { success, message: errMsg } =
|
||||
await productcontrollerUpdatecategory(
|
||||
await productcontrollerUpdatebrand(
|
||||
{ id: initialValues.id },
|
||||
values,
|
||||
);
|
||||
|
|
@ -198,7 +198,7 @@ const UpdateForm: React.FC<{
|
|||
<ProFormText
|
||||
name="name"
|
||||
width="md"
|
||||
label="分类名称"
|
||||
label="品牌名称"
|
||||
placeholder="请输入名称"
|
||||
rules={[{ required: true, message: '请输入名称' }]}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import {
|
||||
productcontrollerCreateproduct,
|
||||
productcontrollerDeleteproduct,
|
||||
productcontrollerGetcategorieall,
|
||||
productcontrollerGetbrandall,
|
||||
productcontrollerGetflavorsall,
|
||||
productcontrollerGetproductlist,
|
||||
productcontrollerGetstrengthall,
|
||||
|
|
@ -24,13 +24,13 @@ import React, { useRef } from 'react';
|
|||
|
||||
const NameCn: React.FC<{
|
||||
id: number;
|
||||
value: string;
|
||||
value: string | undefined;
|
||||
tableRef: React.MutableRefObject<ActionType | undefined>;
|
||||
}> = ({value,tableRef, id}) => {
|
||||
const { message } = App.useApp();
|
||||
const [editable, setEditable] = React.useState<boolean>(false);
|
||||
if (!editable) return <div onClick={() => setEditable(true)}>{value||'-'}</div>;
|
||||
return <ProFormText fieldProps={{autoFocus:true}} initialValue={value} onBlur={async(e) => {
|
||||
return <ProFormText initialValue={value} fieldProps={{autoFocus:true, onBlur:async(e: React.FocusEvent<HTMLInputElement>) => {
|
||||
if(!e.target.value) return setEditable(false)
|
||||
const { success, message: errMsg } =
|
||||
await productcontrollerUpdateproductnamecn({
|
||||
|
|
@ -42,10 +42,12 @@ const NameCn: React.FC<{
|
|||
return message.error(errMsg)
|
||||
}
|
||||
tableRef?.current?.reload()
|
||||
}} />
|
||||
}}} />
|
||||
}
|
||||
const List: React.FC = () => {
|
||||
const actionRef = useRef<ActionType>();
|
||||
// 状态:存储当前选中的行
|
||||
const [selectedRows, setSelectedRows] = React.useState<API.Product[]>([]);
|
||||
|
||||
const { message } = App.useApp();
|
||||
const columns: ProColumns<API.Product>[] = [
|
||||
|
|
@ -68,8 +70,8 @@ const List: React.FC = () => {
|
|||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '产品分类',
|
||||
dataIndex: 'categoryName',
|
||||
title: '产品品牌',
|
||||
dataIndex: 'brandName',
|
||||
},
|
||||
{
|
||||
title: '强度',
|
||||
|
|
@ -86,7 +88,6 @@ const List: React.FC = () => {
|
|||
{
|
||||
title: 'sku',
|
||||
dataIndex: 'sku',
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
|
|
@ -210,18 +211,18 @@ const CreateForm: React.FC<{
|
|||
placeholder="请输入产品描述"
|
||||
/>
|
||||
<ProFormSelect
|
||||
name="categoryId"
|
||||
name="brandId"
|
||||
width="lg"
|
||||
label="产品分类"
|
||||
placeholder="请选择产品分类"
|
||||
label="产品品牌"
|
||||
placeholder="请选择产品品牌"
|
||||
request={async () => {
|
||||
const { data = [] } = await productcontrollerGetcategorieall();
|
||||
return data.map((item) => ({
|
||||
const { data = [] } = await productcontrollerGetbrandall();
|
||||
return data.map((item: API.Brand) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
}));
|
||||
}}
|
||||
rules={[{ required: true, message: '请选择产品分类' }]}
|
||||
rules={[{ required: true, message: '请选择产品品牌' }]}
|
||||
/>
|
||||
<ProFormSelect
|
||||
name="strengthId"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,206 @@
|
|||
import {
|
||||
templatecontrollerCreatetemplate,
|
||||
templatecontrollerDeletetemplate,
|
||||
templatecontrollerGettemplatelist,
|
||||
templatecontrollerUpdatetemplate,
|
||||
} from '@/servers/api/template';
|
||||
import { EditOutlined, PlusOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
ActionType,
|
||||
DrawerForm,
|
||||
PageContainer,
|
||||
ProColumns,
|
||||
ProForm,
|
||||
ProFormText,
|
||||
ProTable,
|
||||
} from '@ant-design/pro-components';
|
||||
import { App, Button, Popconfirm } from 'antd';
|
||||
import { useRef } from 'react';
|
||||
|
||||
const List: React.FC = () => {
|
||||
const actionRef = useRef<ActionType>();
|
||||
const { message } = App.useApp();
|
||||
const columns: ProColumns<API.Template>[] = [
|
||||
{
|
||||
title: '名称',
|
||||
dataIndex: 'name',
|
||||
tip: '名称是唯一的 key',
|
||||
formItemProps: {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '名称为必填项',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '值',
|
||||
dataIndex: 'value',
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
dataIndex: 'updatedAt',
|
||||
valueType: 'dateTime',
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
dataIndex: 'createdAt',
|
||||
valueType: 'dateTime',
|
||||
hideInSearch: true,
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'option',
|
||||
valueType: 'option',
|
||||
render: (_, record) => (
|
||||
<>
|
||||
<UpdateForm tableRef={actionRef} values={record} />
|
||||
<Popconfirm
|
||||
title="删除"
|
||||
description="确认删除?"
|
||||
onConfirm={async () => {
|
||||
if (!record.id) return;
|
||||
try {
|
||||
await templatecontrollerDeletetemplate({ id: record.id });
|
||||
actionRef.current?.reload();
|
||||
} catch (error: any) {
|
||||
message.error(error.message);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Button type="primary" danger>
|
||||
删除
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<PageContainer header={{ title: '模板列表' }}>
|
||||
<ProTable<API.Template>
|
||||
headerTitle="查询表格"
|
||||
actionRef={actionRef}
|
||||
rowKey="id"
|
||||
toolBarRender={() => [<CreateForm tableRef={actionRef} />]}
|
||||
request={async (params) => {
|
||||
const response = await templatecontrollerGettemplatelist(params as any) as any;
|
||||
return {
|
||||
data: response.items || [],
|
||||
total: response.total || 0,
|
||||
success: true,
|
||||
};
|
||||
}}
|
||||
columns={columns}
|
||||
/>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
||||
const CreateForm: React.FC<{
|
||||
tableRef: React.MutableRefObject<ActionType | undefined>;
|
||||
}> = ({ tableRef }) => {
|
||||
const { message } = App.useApp();
|
||||
return (
|
||||
<DrawerForm<API.CreateTemplateDTO>
|
||||
title="新建"
|
||||
trigger={
|
||||
<Button type="primary">
|
||||
<PlusOutlined />
|
||||
新建
|
||||
</Button>
|
||||
}
|
||||
autoFocusFirstInput
|
||||
drawerProps={{
|
||||
destroyOnHidden: true,
|
||||
}}
|
||||
onFinish={async (values) => {
|
||||
try {
|
||||
await templatecontrollerCreatetemplate(values);
|
||||
tableRef.current?.reload();
|
||||
message.success('提交成功');
|
||||
return true;
|
||||
} catch (error: any) {
|
||||
message.error(error.message);
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ProFormText
|
||||
name="name"
|
||||
width="md"
|
||||
label="模板名称"
|
||||
placeholder="请输入名称"
|
||||
rules={[{ required: true, message: '请输入名称' }]}
|
||||
/>
|
||||
<ProFormText
|
||||
name="value"
|
||||
width="md"
|
||||
label="值"
|
||||
placeholder="请输入值"
|
||||
rules={[{ required: true, message: '请输入值' }]}
|
||||
/>
|
||||
</DrawerForm>
|
||||
);
|
||||
};
|
||||
|
||||
const UpdateForm: React.FC<{
|
||||
tableRef: React.MutableRefObject<ActionType | undefined>;
|
||||
values: API.Template;
|
||||
}> = ({ tableRef, values: initialValues }) => {
|
||||
const { message } = App.useApp();
|
||||
return (
|
||||
<DrawerForm<API.UpdateTemplateDTO>
|
||||
title="编辑"
|
||||
initialValues={initialValues}
|
||||
trigger={
|
||||
<Button type="primary">
|
||||
<EditOutlined />
|
||||
编辑
|
||||
</Button>
|
||||
}
|
||||
autoFocusFirstInput
|
||||
drawerProps={{
|
||||
destroyOnHidden: true,
|
||||
}}
|
||||
onFinish={async (values) => {
|
||||
if (!initialValues.id) return false;
|
||||
try {
|
||||
await templatecontrollerUpdatetemplate(
|
||||
{ id: initialValues.id },
|
||||
values,
|
||||
);
|
||||
message.success('提交成功');
|
||||
tableRef.current?.reload();
|
||||
return true;
|
||||
} catch (error: any) {
|
||||
message.error(error.message);
|
||||
return false;
|
||||
}
|
||||
}}
|
||||
>
|
||||
<ProForm.Group>
|
||||
<ProFormText
|
||||
name="name"
|
||||
width="md"
|
||||
label="模板名称"
|
||||
placeholder="请输入名称"
|
||||
rules={[{ required: true, message: '请输入名称' }]}
|
||||
/>
|
||||
<ProFormText
|
||||
name="value"
|
||||
width="md"
|
||||
label="值"
|
||||
placeholder="请输入值"
|
||||
rules={[{ required: true, message: '请输入值' }]}
|
||||
/>
|
||||
</ProForm.Group>
|
||||
</DrawerForm>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default List;
|
||||
|
|
@ -2,16 +2,6 @@
|
|||
/* eslint-disable */
|
||||
import { request } from 'umi';
|
||||
|
||||
/** 此处后端没有提供注释 GET /template/ */
|
||||
export async function templatecontrollerGettemplatelist(options?: {
|
||||
[key: string]: any;
|
||||
}) {
|
||||
return request<API.Template[]>('/template/', {
|
||||
method: 'GET',
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 此处后端没有提供注释 POST /template/ */
|
||||
export async function templatecontrollerCreatetemplate(
|
||||
body: API.CreateTemplateDTO,
|
||||
|
|
@ -73,3 +63,13 @@ export async function templatecontrollerDeletetemplate(
|
|||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
||||
/** 此处后端没有提供注释 GET /template/list */
|
||||
export async function templatecontrollerGettemplatelist(options?: {
|
||||
[key: string]: any;
|
||||
}) {
|
||||
return request<API.Template[]>('/template/list', {
|
||||
method: 'GET',
|
||||
...(options || {}),
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue