feat(模板管理): 新增模板管理功能模块

- 添加模板管理路由和页面组件
- 实现模板的增删改查接口
- 修改产品分类为品牌管理相关代码
- 更新字典管理接口路径
This commit is contained in:
tikkhun 2025-11-27 23:50:22 +08:00
parent 549b6615b7
commit f15c0224c3
6 changed files with 273 additions and 52 deletions

View File

@ -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',

View File

@ -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>

View File

@ -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: '请输入名称' }]}
/>

View File

@ -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"

View File

@ -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;

View File

@ -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 || {}),
});
}