refactor(material): 重构素材库组件实现
- 移除旧的 MaterialList 组件相关配置和引用 - 删除 formatParam 工具函数的不必要导入 - 新增 MaterialLibraryModal 和 CategoryTree 组件 - 将 UploadMaterial 组件重构为使用新的素材库选择方式 - 实现素材分类树的菜单展示和选择功能 - 添加素材库弹窗的图片和列表两种视图模式 - 集成素材选择、预览和确认功能 - 移除各组件中对旧 MaterialList 的依赖配置
This commit is contained in:
parent
1429319b01
commit
7260b089e9
@ -2,20 +2,14 @@ import {
|
|||||||
BizContainer,
|
BizContainer,
|
||||||
BizValueType,
|
BizValueType,
|
||||||
BoxSpecList,
|
BoxSpecList,
|
||||||
MaterialList,
|
|
||||||
ModeType,
|
ModeType,
|
||||||
ProFormBizSelect,
|
ProFormBizSelect,
|
||||||
ProFormBizSelectHandles,
|
ProFormBizSelectHandles,
|
||||||
ProFormUploadMaterial,
|
ProFormUploadMaterial,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { business } from '@/services';
|
import { business } from '@/services';
|
||||||
import { formatParam } from '@/utils/formatParam';
|
|
||||||
import { useIntl } from '@@/exports';
|
import { useIntl } from '@@/exports';
|
||||||
import {
|
import { ProColumns, ProFormText } from '@ant-design/pro-components';
|
||||||
ActionType,
|
|
||||||
ProColumns,
|
|
||||||
ProFormText,
|
|
||||||
} from '@ant-design/pro-components';
|
|
||||||
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
|
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
|
||||||
import { ProListMetas } from '@ant-design/pro-list';
|
import { ProListMetas } from '@ant-design/pro-list';
|
||||||
import { Image } from 'antd';
|
import { Image } from 'antd';
|
||||||
@ -46,7 +40,6 @@ export default function BoxBrandList(props: IBoxBrandListProps) {
|
|||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const intlPrefix = 'boxBrand';
|
const intlPrefix = 'boxBrand';
|
||||||
const specRef = useRef<ProFormBizSelectHandles>(null);
|
const specRef = useRef<ProFormBizSelectHandles>(null);
|
||||||
const actionRef = useRef<ActionType>();
|
|
||||||
|
|
||||||
const columns: ProColumns<BusinessAPI.BoxBrandVO, BizValueType>[] = [
|
const columns: ProColumns<BusinessAPI.BoxBrandVO, BizValueType>[] = [
|
||||||
{
|
{
|
||||||
@ -132,32 +125,6 @@ export default function BoxBrandList(props: IBoxBrandListProps) {
|
|||||||
}}
|
}}
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
maxCount: 1,
|
maxCount: 1,
|
||||||
actionRef: actionRef,
|
|
||||||
toolBarRender: () => [
|
|
||||||
<MaterialList
|
|
||||||
key={'create'}
|
|
||||||
ghost={true}
|
|
||||||
mode={'create'}
|
|
||||||
search={false}
|
|
||||||
onValueChange={() => actionRef.current?.reload()}
|
|
||||||
/>,
|
|
||||||
],
|
|
||||||
request: async (params, sorter, filter) => {
|
|
||||||
const { data, success, totalCount } =
|
|
||||||
await business.material.pageMaterial({
|
|
||||||
materialPageQry: formatParam<typeof params>(
|
|
||||||
params,
|
|
||||||
sorter,
|
|
||||||
filter,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: data || [],
|
|
||||||
total: totalCount,
|
|
||||||
success,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
/>,
|
/>,
|
||||||
|
|
||||||
@ -254,14 +221,6 @@ export default function BoxBrandList(props: IBoxBrandListProps) {
|
|||||||
type: brandType,
|
type: brandType,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
columnsState: {
|
|
||||||
defaultValue: {
|
|
||||||
option: { show: true },
|
|
||||||
status: { show: true },
|
|
||||||
remark: { show: false },
|
|
||||||
createdAt: { show: false },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
columns,
|
columns,
|
||||||
}}
|
}}
|
||||||
@ -270,29 +229,11 @@ export default function BoxBrandList(props: IBoxBrandListProps) {
|
|||||||
bordered: true,
|
bordered: true,
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
search,
|
search,
|
||||||
pagination: false,
|
|
||||||
itemLayout: 'vertical',
|
|
||||||
showActions: 'hover',
|
|
||||||
params: {
|
params: {
|
||||||
...(brandType !== 'ALL' && {
|
...(brandType !== 'ALL' && {
|
||||||
type: brandType,
|
type: brandType,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
onItem: (record: any) => {
|
|
||||||
return {
|
|
||||||
onClick: async (e) => {
|
|
||||||
const { data } = await business.boxBrand.showBoxBrand({
|
|
||||||
boxBrandShowQry: {
|
|
||||||
brandId: record.brandId,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (data) {
|
|
||||||
onSelect?.(data);
|
|
||||||
}
|
|
||||||
e.stopPropagation();
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
metas,
|
metas,
|
||||||
columns,
|
columns,
|
||||||
|
|||||||
@ -1,25 +1,20 @@
|
|||||||
import {
|
import {
|
||||||
BizContainer,
|
BizContainer,
|
||||||
BizValueType,
|
BizValueType,
|
||||||
MaterialList,
|
|
||||||
ProFormUploadMaterial,
|
ProFormUploadMaterial,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { business } from '@/services';
|
import { business } from '@/services';
|
||||||
import { formatParam } from '@/utils/formatParam';
|
|
||||||
import { useIntl } from '@@/exports';
|
import { useIntl } from '@@/exports';
|
||||||
import {
|
import {
|
||||||
ActionType,
|
|
||||||
ProColumns,
|
ProColumns,
|
||||||
ProFormText,
|
ProFormText,
|
||||||
ProFormTextArea,
|
ProFormTextArea,
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
|
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
|
||||||
import { useRef } from 'react';
|
|
||||||
|
|
||||||
export default function ChannelList() {
|
export default function ChannelList() {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const intlPrefix = 'channel';
|
const intlPrefix = 'channel';
|
||||||
const actionRef = useRef<ActionType>();
|
|
||||||
|
|
||||||
const formContext = [
|
const formContext = [
|
||||||
<ProFormText
|
<ProFormText
|
||||||
@ -87,32 +82,6 @@ export default function ChannelList() {
|
|||||||
}}
|
}}
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
maxCount: 1,
|
maxCount: 1,
|
||||||
actionRef: actionRef,
|
|
||||||
toolBarRender: () => [
|
|
||||||
<MaterialList
|
|
||||||
key={'create'}
|
|
||||||
ghost={true}
|
|
||||||
mode={'create'}
|
|
||||||
search={false}
|
|
||||||
onValueChange={() => actionRef.current?.reload()}
|
|
||||||
/>,
|
|
||||||
],
|
|
||||||
request: async (params, sorter, filter) => {
|
|
||||||
const { data, success, totalCount } =
|
|
||||||
await business.material.pageMaterial({
|
|
||||||
materialPageQry: formatParam<typeof params>(
|
|
||||||
params,
|
|
||||||
sorter,
|
|
||||||
filter,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: data || [],
|
|
||||||
total: totalCount,
|
|
||||||
success,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
/>,
|
/>,
|
||||||
<ProFormUploadMaterial
|
<ProFormUploadMaterial
|
||||||
@ -129,32 +98,6 @@ export default function ChannelList() {
|
|||||||
}}
|
}}
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
maxCount: 1,
|
maxCount: 1,
|
||||||
actionRef: actionRef,
|
|
||||||
toolBarRender: () => [
|
|
||||||
<MaterialList
|
|
||||||
key={'create'}
|
|
||||||
ghost={true}
|
|
||||||
mode={'create'}
|
|
||||||
search={false}
|
|
||||||
onValueChange={() => actionRef.current?.reload()}
|
|
||||||
/>,
|
|
||||||
],
|
|
||||||
request: async (params, sorter, filter) => {
|
|
||||||
const { data, success, totalCount } =
|
|
||||||
await business.material.pageMaterial({
|
|
||||||
materialPageQry: formatParam<typeof params>(
|
|
||||||
params,
|
|
||||||
sorter,
|
|
||||||
filter,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: data || [],
|
|
||||||
total: totalCount,
|
|
||||||
success,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
/>,
|
/>,
|
||||||
<ProFormText
|
<ProFormText
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import {
|
|||||||
ProFormUploadMaterial,
|
ProFormUploadMaterial,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { business } from '@/services';
|
import { business } from '@/services';
|
||||||
import { formatParam } from '@/utils/formatParam';
|
|
||||||
import { useIntl } from '@@/exports';
|
import { useIntl } from '@@/exports';
|
||||||
import { ProColumns, ProFormText } from '@ant-design/pro-components';
|
import { ProColumns, ProFormText } from '@ant-design/pro-components';
|
||||||
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
|
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
|
||||||
@ -98,22 +97,6 @@ export default function CompanyList(props: ICompanyListProps) {
|
|||||||
}}
|
}}
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
maxCount: 1,
|
maxCount: 1,
|
||||||
request: async (params, sorter, filter) => {
|
|
||||||
const { data, success, totalCount } =
|
|
||||||
await business.material.pageMaterial({
|
|
||||||
materialPageQry: formatParam<typeof params>(
|
|
||||||
params,
|
|
||||||
sorter,
|
|
||||||
filter,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: data || [],
|
|
||||||
total: totalCount,
|
|
||||||
success,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
/>,
|
/>,
|
||||||
<ProFormText
|
<ProFormText
|
||||||
|
|||||||
@ -3,23 +3,20 @@ import {
|
|||||||
BizValueType,
|
BizValueType,
|
||||||
EmployeeDisable,
|
EmployeeDisable,
|
||||||
EmployeeRoleUpdate,
|
EmployeeRoleUpdate,
|
||||||
MaterialList,
|
|
||||||
ModeType,
|
ModeType,
|
||||||
ProFormUploadMaterial,
|
ProFormUploadMaterial,
|
||||||
RestPassword,
|
RestPassword,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { business } from '@/services';
|
import { business } from '@/services';
|
||||||
import { aesEncrypt } from '@/utils/aes';
|
import { aesEncrypt } from '@/utils/aes';
|
||||||
import { formatParam } from '@/utils/formatParam';
|
|
||||||
import { useIntl } from '@@/exports';
|
import { useIntl } from '@@/exports';
|
||||||
import {
|
import {
|
||||||
ActionType,
|
|
||||||
ProColumns,
|
ProColumns,
|
||||||
ProFormSelect,
|
ProFormSelect,
|
||||||
ProFormText,
|
ProFormText,
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
|
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
|
||||||
import React, { useRef } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
export interface IEmployeeListProps {
|
export interface IEmployeeListProps {
|
||||||
ghost?: boolean;
|
ghost?: boolean;
|
||||||
@ -33,7 +30,6 @@ const EmployeeList: React.FC = (props: IEmployeeListProps) => {
|
|||||||
const { ghost = false, search = true, mode = 'page', onValueChange } = props;
|
const { ghost = false, search = true, mode = 'page', onValueChange } = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const intlPrefix = 'employee';
|
const intlPrefix = 'employee';
|
||||||
const actionRef = useRef<ActionType>();
|
|
||||||
|
|
||||||
const columns: ProColumns<BusinessAPI.EmployeeVO, BizValueType>[] = [
|
const columns: ProColumns<BusinessAPI.EmployeeVO, BizValueType>[] = [
|
||||||
{
|
{
|
||||||
@ -187,22 +183,6 @@ const EmployeeList: React.FC = (props: IEmployeeListProps) => {
|
|||||||
}}
|
}}
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
maxCount: 1,
|
maxCount: 1,
|
||||||
request: async (params, sorter, filter) => {
|
|
||||||
const { data, success, totalCount } =
|
|
||||||
await business.material.pageMaterial({
|
|
||||||
materialPageQry: formatParam<typeof params>(
|
|
||||||
params,
|
|
||||||
sorter,
|
|
||||||
filter,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: data || [],
|
|
||||||
total: totalCount,
|
|
||||||
success,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
/>,
|
/>,
|
||||||
<ProFormText
|
<ProFormText
|
||||||
@ -408,32 +388,6 @@ const EmployeeList: React.FC = (props: IEmployeeListProps) => {
|
|||||||
}}
|
}}
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
maxCount: 1,
|
maxCount: 1,
|
||||||
actionRef: actionRef,
|
|
||||||
toolBarRender: () => [
|
|
||||||
<MaterialList
|
|
||||||
key={'create'}
|
|
||||||
ghost={true}
|
|
||||||
mode={'create'}
|
|
||||||
search={false}
|
|
||||||
onValueChange={() => actionRef.current?.reload()}
|
|
||||||
/>,
|
|
||||||
],
|
|
||||||
request: async (params, sorter, filter) => {
|
|
||||||
const { data, success, totalCount } =
|
|
||||||
await business.material.pageMaterial({
|
|
||||||
materialPageQry: formatParam<typeof params>(
|
|
||||||
params,
|
|
||||||
sorter,
|
|
||||||
filter,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: data || [],
|
|
||||||
total: totalCount,
|
|
||||||
success,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
/>,
|
/>,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -1,21 +1,16 @@
|
|||||||
|
import { UploadMaterial } from '@/components';
|
||||||
import {
|
import {
|
||||||
ActionType,
|
|
||||||
ProFormDependency,
|
ProFormDependency,
|
||||||
ProFormField,
|
ProFormField,
|
||||||
ProFormItemProps,
|
ProFormItemProps,
|
||||||
ProTableProps,
|
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { UploadMaterial } from '@/components';
|
import React from 'react';
|
||||||
import React, { MutableRefObject } from 'react';
|
|
||||||
|
|
||||||
interface ProFormUploadMaterialProps extends ProFormItemProps {
|
interface ProFormUploadMaterialProps extends ProFormItemProps {
|
||||||
fieldProps: {
|
fieldProps: {
|
||||||
maxCount: number;
|
maxCount: number;
|
||||||
onChange?: (fileList: any[]) => void;
|
onChange?: (fileList: any[]) => void;
|
||||||
fileList?: any[];
|
fileList?: any[];
|
||||||
request: ProTableProps<any, any>['request'];
|
|
||||||
toolBarRender?: ProTableProps<any, any>['toolBarRender'];
|
|
||||||
actionRef?: MutableRefObject<ActionType | undefined>;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -168,6 +168,7 @@ export default function MaterialCategoryList(
|
|||||||
}}
|
}}
|
||||||
tree={{
|
tree={{
|
||||||
fieldProps: {
|
fieldProps: {
|
||||||
|
bordered: true,
|
||||||
ghost,
|
ghost,
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
search,
|
search,
|
||||||
|
|||||||
@ -0,0 +1,130 @@
|
|||||||
|
import { business } from '@/services';
|
||||||
|
import { FolderOpenOutlined, FolderOutlined } from '@ant-design/icons';
|
||||||
|
import { ProCard } from '@ant-design/pro-components';
|
||||||
|
import type { MenuItemProps } from 'antd';
|
||||||
|
import { Empty, Menu, message } from 'antd';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import useStyle from './style.style';
|
||||||
|
|
||||||
|
interface CategoryTreeProps {
|
||||||
|
onCategorySelect: (categoryId?: string, categoryName?: string) => void;
|
||||||
|
selectedCategoryId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 素材分类树组件(使用 Menu 组件)
|
||||||
|
* 支持:展开/收起、显示素材数量
|
||||||
|
*/
|
||||||
|
const CategoryTree: React.FC<CategoryTreeProps> = ({
|
||||||
|
onCategorySelect,
|
||||||
|
selectedCategoryId,
|
||||||
|
}) => {
|
||||||
|
const { styles } = useStyle();
|
||||||
|
const [treeData, setTreeData] = useState<BusinessAPI.CategoryVO[]>([]);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
// 获取分类树数据
|
||||||
|
const fetchCategoryTree = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
try {
|
||||||
|
const { data } = await business.materialCategory.treeMaterialCategory({
|
||||||
|
categoryTreeQry: {},
|
||||||
|
});
|
||||||
|
if (data) {
|
||||||
|
setTreeData(data as BusinessAPI.CategoryVO[]);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取素材分类树失败:', error);
|
||||||
|
message.error('获取素材分类树失败');
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
fetchCategoryTree();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 转换数据为 Menu Item 格式
|
||||||
|
const convertToMenuItems = (nodes: BusinessAPI.CategoryVO[]): any[] => {
|
||||||
|
return nodes.map((node) => {
|
||||||
|
const menuItem: any = {
|
||||||
|
key: node.categoryId,
|
||||||
|
label: (
|
||||||
|
<div className={styles.menuItemLabel}>
|
||||||
|
<span className={styles.categoryName}>{node.name}</span>
|
||||||
|
<span className={styles.materialCount}>
|
||||||
|
{/* @ts-ignore */}({node.materialCount || 0})
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
icon:
|
||||||
|
node.children && node.children.length > 0 ? (
|
||||||
|
<FolderOpenOutlined />
|
||||||
|
) : (
|
||||||
|
<FolderOutlined />
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
// 递归处理子节点
|
||||||
|
if (node.children && node.children.length > 0) {
|
||||||
|
menuItem.children = convertToMenuItems(node.children);
|
||||||
|
}
|
||||||
|
|
||||||
|
return menuItem;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理菜单选择
|
||||||
|
const handleMenuSelect: MenuItemProps['onClick'] = ({ key }) => {
|
||||||
|
const categoryId = key as string;
|
||||||
|
// 从树数据中查找分类名称
|
||||||
|
const findCategoryName = (
|
||||||
|
nodes: BusinessAPI.CategoryVO[],
|
||||||
|
targetId: string,
|
||||||
|
): string | undefined => {
|
||||||
|
for (const node of nodes) {
|
||||||
|
if (node.categoryId === targetId) {
|
||||||
|
return node.name;
|
||||||
|
}
|
||||||
|
if (node.children) {
|
||||||
|
const found = findCategoryName(node.children, targetId);
|
||||||
|
if (found) return found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const categoryName = findCategoryName(treeData, categoryId);
|
||||||
|
onCategorySelect(categoryId, categoryName);
|
||||||
|
};
|
||||||
|
|
||||||
|
const menuItems = convertToMenuItems(treeData);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ProCard
|
||||||
|
title={
|
||||||
|
<div className={styles.cardHeader}>
|
||||||
|
<span>素材分类</span>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
size="small"
|
||||||
|
className={styles.categoryCard}
|
||||||
|
loading={loading}
|
||||||
|
>
|
||||||
|
{menuItems.length > 0 ? (
|
||||||
|
<Menu
|
||||||
|
mode="inline"
|
||||||
|
selectedKeys={selectedCategoryId ? [selectedCategoryId] : []}
|
||||||
|
onClick={handleMenuSelect}
|
||||||
|
items={menuItems}
|
||||||
|
className={styles.categoryMenu}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Empty description="暂无分类" image={Empty.PRESENTED_IMAGE_SIMPLE} />
|
||||||
|
)}
|
||||||
|
</ProCard>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CategoryTree;
|
||||||
@ -0,0 +1,336 @@
|
|||||||
|
import { CategoryTree, MaterialList } from '@/components';
|
||||||
|
import { business } from '@/services';
|
||||||
|
import { formatParam } from '@/utils/formatParam';
|
||||||
|
import { pagination } from '@/utils/pagination';
|
||||||
|
import {
|
||||||
|
ActionType,
|
||||||
|
ProColumns,
|
||||||
|
ProTable,
|
||||||
|
ProTableProps,
|
||||||
|
} from '@ant-design/pro-components';
|
||||||
|
import { Button, Image, message, Modal, ModalProps, Segmented } from 'antd';
|
||||||
|
import React, { useRef, useState } from 'react';
|
||||||
|
import useStyle from './style.style';
|
||||||
|
|
||||||
|
export interface MaterialLibraryModalProps extends ModalProps {
|
||||||
|
/** 最大选择数量,默认 1 */
|
||||||
|
maxCount?: number;
|
||||||
|
/** 选择模式: radio-单选, checkbox-多选 */
|
||||||
|
mode?: 'radio' | 'checkbox';
|
||||||
|
/** 确认选择回调 */
|
||||||
|
onFinish?: (materials: BusinessAPI.MaterialVO[]) => void;
|
||||||
|
/** 初始已选中的素材列表 */
|
||||||
|
initialSelectedMaterials?: BusinessAPI.MaterialVO[];
|
||||||
|
/** 素材类型筛选: FILE_IMAGE-图片, FILE_VIDEO-视频 */
|
||||||
|
materialType?: 'FILE_IMAGE' | 'FILE_VIDEO';
|
||||||
|
}
|
||||||
|
|
||||||
|
const MaterialLibraryModal: React.FC<MaterialLibraryModalProps> = ({
|
||||||
|
open,
|
||||||
|
onCancel,
|
||||||
|
maxCount = 1,
|
||||||
|
mode = 'radio',
|
||||||
|
onFinish,
|
||||||
|
initialSelectedMaterials = [],
|
||||||
|
materialType,
|
||||||
|
...rest
|
||||||
|
}) => {
|
||||||
|
const { styles } = useStyle();
|
||||||
|
const [selectedCategoryId, setSelectedCategoryId] = useState<
|
||||||
|
string | undefined
|
||||||
|
>();
|
||||||
|
const [selectedCategoryName, setSelectedCategoryName] = useState<
|
||||||
|
string | undefined
|
||||||
|
>();
|
||||||
|
const [selectedMaterials, setSelectedMaterials] = useState<
|
||||||
|
BusinessAPI.MaterialVO[]
|
||||||
|
>(initialSelectedMaterials);
|
||||||
|
const [viewMode, setViewMode] = useState<'list' | 'image'>('image');
|
||||||
|
const [materials, setMaterials] = useState<BusinessAPI.MaterialVO[]>([]);
|
||||||
|
const actionRef = useRef<ActionType>();
|
||||||
|
|
||||||
|
// 列表模式列配置
|
||||||
|
const columns: ProColumns<BusinessAPI.MaterialVO>[] = [
|
||||||
|
{
|
||||||
|
title: '素材名称',
|
||||||
|
dataIndex: 'name',
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '素材内容',
|
||||||
|
dataIndex: 'url',
|
||||||
|
render: (_, record) => {
|
||||||
|
if (record.type === 'FILE_IMAGE' || record.type === 'FILE_VIDEO') {
|
||||||
|
return (
|
||||||
|
<Image
|
||||||
|
width={40}
|
||||||
|
height={40}
|
||||||
|
src={record.url}
|
||||||
|
style={{ objectFit: 'cover', borderRadius: 4 }}
|
||||||
|
preview={{ src: record.url }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return '-';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '素材分类',
|
||||||
|
dataIndex: ['categoryVO', 'name'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '创建时间',
|
||||||
|
dataIndex: 'createdAt',
|
||||||
|
valueType: 'dateTime',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
// 处理分类选择
|
||||||
|
const handleCategorySelect = (categoryId?: string, categoryName?: string) => {
|
||||||
|
setSelectedCategoryId(categoryId);
|
||||||
|
setSelectedCategoryName(categoryName);
|
||||||
|
// 刷新素材列表
|
||||||
|
actionRef.current?.reload();
|
||||||
|
};
|
||||||
|
|
||||||
|
// 处理素材选择
|
||||||
|
const handleMaterialSelect = (material: BusinessAPI.MaterialVO) => {
|
||||||
|
const isSelected = selectedMaterials.some(
|
||||||
|
(m) => m.materialId === material.materialId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isSelected) {
|
||||||
|
// 取消选择
|
||||||
|
setSelectedMaterials((prev) =>
|
||||||
|
prev.filter((m) => m.materialId !== material.materialId),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 选择素材
|
||||||
|
if (mode === 'radio') {
|
||||||
|
// 单选模式直接替换
|
||||||
|
setSelectedMaterials([material]);
|
||||||
|
} else {
|
||||||
|
// 多选模式检查数量限制
|
||||||
|
if (maxCount > 0 && selectedMaterials.length >= maxCount) {
|
||||||
|
message.warning(`最多只能选择 ${maxCount} 个素材`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setSelectedMaterials((prev) => [...prev, material]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 确认选择
|
||||||
|
const handleOk = () => {
|
||||||
|
if (selectedMaterials.length === 0 && maxCount > 0) {
|
||||||
|
message.warning('请先选择素材');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
onFinish?.(selectedMaterials);
|
||||||
|
// 重置状态
|
||||||
|
setSelectedMaterials([]);
|
||||||
|
setSelectedCategoryId(undefined);
|
||||||
|
setSelectedCategoryName(undefined);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 关闭弹窗
|
||||||
|
const handleClose = () => {
|
||||||
|
setSelectedMaterials([]);
|
||||||
|
setSelectedCategoryId(undefined);
|
||||||
|
setSelectedCategoryName(undefined);
|
||||||
|
onCancel?.({} as any);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 图片预览渲染
|
||||||
|
const renderImagePreview = () => {
|
||||||
|
if (materials.length === 0) {
|
||||||
|
return (
|
||||||
|
<div className={styles.emptyTip}>
|
||||||
|
<span>暂无素材,请选择其他分类或添加素材</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.imagePreview}>
|
||||||
|
{materials.map((material) => {
|
||||||
|
const isSelected = selectedMaterials.some(
|
||||||
|
(m) => m.materialId === material.materialId,
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={material.materialId}
|
||||||
|
className={`${styles.imageItem} ${isSelected ? styles.imageItemSelected : ''}`}
|
||||||
|
onClick={() => handleMaterialSelect(material)}
|
||||||
|
>
|
||||||
|
<div className={styles.imageWrapper}>
|
||||||
|
<Image
|
||||||
|
src={material.url}
|
||||||
|
alt={material.name}
|
||||||
|
preview={{ src: material.url }}
|
||||||
|
placeholder={
|
||||||
|
<div className={styles.imagePlaceholder}>加载中...</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.imageInfo}>
|
||||||
|
<div className={styles.imageName}>{material.name}</div>
|
||||||
|
</div>
|
||||||
|
{isSelected && (
|
||||||
|
<div className={styles.imageSelectedCheck}>
|
||||||
|
{mode === 'radio'
|
||||||
|
? '✓'
|
||||||
|
: `${
|
||||||
|
selectedMaterials.findIndex(
|
||||||
|
(m) => m.materialId === material.materialId,
|
||||||
|
) + 1
|
||||||
|
}`}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 请求参数
|
||||||
|
const request: ProTableProps<
|
||||||
|
BusinessAPI.MaterialVO,
|
||||||
|
BusinessAPI.MaterialPageQry
|
||||||
|
>['request'] = async (params, sorter, filter) => {
|
||||||
|
const searchParams: BusinessAPI.MaterialPageQry = {
|
||||||
|
...formatParam<typeof params>(params, sorter, filter),
|
||||||
|
categoryId: selectedCategoryId,
|
||||||
|
type: materialType,
|
||||||
|
};
|
||||||
|
|
||||||
|
const { data, success, totalCount } = await business.material.pageMaterial({
|
||||||
|
materialPageQry: searchParams,
|
||||||
|
});
|
||||||
|
|
||||||
|
// 保存素材数据用于图片预览
|
||||||
|
if (data) {
|
||||||
|
setMaterials(data as BusinessAPI.MaterialVO[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: data || [],
|
||||||
|
total: totalCount,
|
||||||
|
success,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title="素材库"
|
||||||
|
open={open}
|
||||||
|
onOk={handleOk}
|
||||||
|
onCancel={handleClose}
|
||||||
|
width={1200}
|
||||||
|
destroyOnHidden
|
||||||
|
{...rest}
|
||||||
|
className={styles.materialModal}
|
||||||
|
>
|
||||||
|
<ProTable<BusinessAPI.MaterialVO, BusinessAPI.MaterialPageQry>
|
||||||
|
actionRef={actionRef}
|
||||||
|
rowKey="materialId"
|
||||||
|
bordered={true}
|
||||||
|
columns={columns}
|
||||||
|
request={request}
|
||||||
|
search={false}
|
||||||
|
pagination={pagination()}
|
||||||
|
size="small"
|
||||||
|
className={styles.materialTable}
|
||||||
|
rowClassName={(record) => {
|
||||||
|
const isSelected = selectedMaterials.some(
|
||||||
|
(m) => m.materialId === record.materialId,
|
||||||
|
);
|
||||||
|
return isSelected ? styles.rowSelected : '';
|
||||||
|
}}
|
||||||
|
onRow={(record) => ({
|
||||||
|
onClick: () => handleMaterialSelect(record),
|
||||||
|
style: { cursor: 'pointer' },
|
||||||
|
})}
|
||||||
|
toolBarRender={false}
|
||||||
|
tableRender={(props, defaultDom, domList) => {
|
||||||
|
return (
|
||||||
|
<div className={styles.modalContent}>
|
||||||
|
{/* 左侧分类树 */}
|
||||||
|
<div className={styles.leftPanel}>
|
||||||
|
<CategoryTree
|
||||||
|
onCategorySelect={handleCategorySelect}
|
||||||
|
selectedCategoryId={selectedCategoryId}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 右侧素材内容 */}
|
||||||
|
<div className={styles.rightPanel}>
|
||||||
|
{/* 顶部工具栏 */}
|
||||||
|
<div className={styles.toolbar}>
|
||||||
|
<div className={styles.toolbarLeft}>
|
||||||
|
<Segmented
|
||||||
|
value={viewMode}
|
||||||
|
onChange={(value) =>
|
||||||
|
setViewMode(value as 'list' | 'image')
|
||||||
|
}
|
||||||
|
options={[
|
||||||
|
{ label: '图片', value: 'image' },
|
||||||
|
{ label: '列表', value: 'list' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
{selectedCategoryName && (
|
||||||
|
<span className={styles.currentCategory}>
|
||||||
|
当前分类: <strong>{selectedCategoryName}</strong>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className={styles.toolbarRight}>
|
||||||
|
<MaterialList
|
||||||
|
formType={'modal'}
|
||||||
|
key={'create'}
|
||||||
|
ghost={true}
|
||||||
|
mode={'create'}
|
||||||
|
search={false}
|
||||||
|
onValueChange={() => actionRef.current?.reload()}
|
||||||
|
/>
|
||||||
|
{selectedMaterials.length > 0 && (
|
||||||
|
<span className={styles.selectedCount}>
|
||||||
|
已选择 {selectedMaterials.length}
|
||||||
|
{maxCount > 0 && `/${maxCount}`} 个
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{selectedMaterials.length > 0 && mode === 'checkbox' && (
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
onClick={() => setSelectedMaterials([])}
|
||||||
|
>
|
||||||
|
清空
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 素材展示区域 */}
|
||||||
|
<div className={styles.materialArea}>
|
||||||
|
{viewMode === 'list' ? (
|
||||||
|
defaultDom
|
||||||
|
) : (
|
||||||
|
<div className={styles.imageGridWrapper}>
|
||||||
|
{renderImagePreview()}
|
||||||
|
<div className={styles.paginationWrapper}>
|
||||||
|
{domList.table}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MaterialLibraryModal;
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
export { default as CategoryTree } from './CategoryTree';
|
||||||
|
export { default as MaterialLibraryModal } from './MaterialLibraryModal';
|
||||||
|
export type { MaterialLibraryModalProps } from './MaterialLibraryModal';
|
||||||
@ -0,0 +1,224 @@
|
|||||||
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
|
const useStyle = () => {
|
||||||
|
return createStyles(() => {
|
||||||
|
return {
|
||||||
|
// ==================== Modal 布局 ====================
|
||||||
|
materialModal: {
|
||||||
|
'.ant-modal-body': {
|
||||||
|
padding: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
modalContent: {
|
||||||
|
display: 'flex',
|
||||||
|
height: 600,
|
||||||
|
},
|
||||||
|
leftPanel: {
|
||||||
|
width: 280,
|
||||||
|
borderRight: '1px solid #f0f0f0',
|
||||||
|
padding: 16,
|
||||||
|
overflow: 'auto',
|
||||||
|
},
|
||||||
|
rightPanel: {
|
||||||
|
flex: 1,
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
overflow: 'hidden',
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==================== 工具栏 ====================
|
||||||
|
toolbar: {
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: '12px 16px',
|
||||||
|
borderBottom: '1px solid #f0f0f0',
|
||||||
|
},
|
||||||
|
toolbarLeft: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 16,
|
||||||
|
},
|
||||||
|
toolbarRight: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 12,
|
||||||
|
},
|
||||||
|
currentCategory: {
|
||||||
|
color: '#666',
|
||||||
|
fontSize: 13,
|
||||||
|
},
|
||||||
|
selectedCount: {
|
||||||
|
color: '#1890ff',
|
||||||
|
fontWeight: 500,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==================== 分类菜单 ====================
|
||||||
|
categoryCard: {
|
||||||
|
height: '100%',
|
||||||
|
},
|
||||||
|
cardHeader: {
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
categoryMenu: {
|
||||||
|
borderRight: 'none',
|
||||||
|
'.ant-menu-item': {
|
||||||
|
paddingLeft: '8px !important',
|
||||||
|
height: 'auto',
|
||||||
|
lineHeight: 'normal',
|
||||||
|
paddingTop: 8,
|
||||||
|
paddingBottom: 8,
|
||||||
|
margin: 0,
|
||||||
|
},
|
||||||
|
'.ant-menu-submenu': {
|
||||||
|
paddingLeft: '8px !important',
|
||||||
|
},
|
||||||
|
'.ant-menu-submenu-title': {
|
||||||
|
paddingLeft: '8px !important',
|
||||||
|
height: 'auto',
|
||||||
|
lineHeight: 'normal',
|
||||||
|
paddingTop: 8,
|
||||||
|
paddingBottom: 8,
|
||||||
|
margin: 0,
|
||||||
|
},
|
||||||
|
'.ant-menu-item-selected': {
|
||||||
|
backgroundColor: '#e6f7ff',
|
||||||
|
},
|
||||||
|
'.ant-menu-item:hover': {
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 4%)',
|
||||||
|
},
|
||||||
|
'.ant-menu-submenu-title:hover': {
|
||||||
|
backgroundColor: 'rgba(0, 0, 0, 4%)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
menuItemLabel: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
flex: 1,
|
||||||
|
marginLeft: 8,
|
||||||
|
},
|
||||||
|
categoryName: {
|
||||||
|
flex: 1,
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
},
|
||||||
|
materialCount: {
|
||||||
|
color: '#999',
|
||||||
|
fontSize: 12,
|
||||||
|
flexShrink: 0,
|
||||||
|
marginLeft: 8,
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==================== 素材列表 ====================
|
||||||
|
materialArea: {
|
||||||
|
flex: 1,
|
||||||
|
overflow: 'auto',
|
||||||
|
padding: 16,
|
||||||
|
},
|
||||||
|
materialTable: {
|
||||||
|
'.ant-table-row': {
|
||||||
|
cursor: 'pointer',
|
||||||
|
},
|
||||||
|
border: '1px solid #f0f0f0;',
|
||||||
|
borderRadius: 8,
|
||||||
|
},
|
||||||
|
rowSelected: {
|
||||||
|
backgroundColor: '#e6f7ff !important',
|
||||||
|
},
|
||||||
|
|
||||||
|
// ==================== 图片预览 ====================
|
||||||
|
imageGridWrapper: {
|
||||||
|
height: '100%',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
},
|
||||||
|
imagePreview: {
|
||||||
|
display: 'flex',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
gap: 12,
|
||||||
|
overflow: 'auto',
|
||||||
|
padding: '4px 0',
|
||||||
|
// flex: 1,
|
||||||
|
},
|
||||||
|
imageItem: {
|
||||||
|
width: 120,
|
||||||
|
border: '1px solid #f0f0f0',
|
||||||
|
borderRadius: 8,
|
||||||
|
overflow: 'hidden',
|
||||||
|
cursor: 'pointer',
|
||||||
|
transition: 'all 0.2s',
|
||||||
|
position: 'relative',
|
||||||
|
'&:hover': {
|
||||||
|
borderColor: '#1890ff',
|
||||||
|
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
imageItemSelected: {
|
||||||
|
borderColor: '#1890ff',
|
||||||
|
boxShadow: '0 0 0 2px rgba(24, 144, 255, 0.3)',
|
||||||
|
},
|
||||||
|
imageWrapper: {
|
||||||
|
width: '100%',
|
||||||
|
height: 100,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
backgroundColor: '#fafafa',
|
||||||
|
img: {
|
||||||
|
maxWidth: '100%',
|
||||||
|
maxHeight: '100%',
|
||||||
|
objectFit: 'contain',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
imagePlaceholder: {
|
||||||
|
color: '#999',
|
||||||
|
fontSize: 12,
|
||||||
|
},
|
||||||
|
imageInfo: {
|
||||||
|
padding: '8px 10px',
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
},
|
||||||
|
imageName: {
|
||||||
|
fontSize: 12,
|
||||||
|
overflow: 'hidden',
|
||||||
|
textOverflow: 'ellipsis',
|
||||||
|
whiteSpace: 'nowrap',
|
||||||
|
color: '#333',
|
||||||
|
},
|
||||||
|
imageSelectedCheck: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 4,
|
||||||
|
right: 4,
|
||||||
|
width: 20,
|
||||||
|
height: 20,
|
||||||
|
borderRadius: '50%',
|
||||||
|
backgroundColor: '#1890ff',
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 12,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
},
|
||||||
|
paginationWrapper: {
|
||||||
|
borderTop: '1px solid #f0f0f0',
|
||||||
|
marginTop: 8,
|
||||||
|
'.ant-table': {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emptyTip: {
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
height: '100%',
|
||||||
|
color: '#999',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useStyle;
|
||||||
@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
BizContainer,
|
BizContainer,
|
||||||
BizValueType,
|
BizValueType,
|
||||||
|
FormType,
|
||||||
MaterialCategoryList,
|
MaterialCategoryList,
|
||||||
ModeType,
|
ModeType,
|
||||||
ProFormBizTreeSelect,
|
ProFormBizTreeSelect,
|
||||||
@ -27,6 +28,7 @@ export interface IMaterialListProps {
|
|||||||
mode?: ModeType;
|
mode?: ModeType;
|
||||||
trigger?: () => React.ReactNode;
|
trigger?: () => React.ReactNode;
|
||||||
onValueChange?: () => void;
|
onValueChange?: () => void;
|
||||||
|
formType: FormType;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function MaterialList(props: IMaterialListProps) {
|
export default function MaterialList(props: IMaterialListProps) {
|
||||||
@ -36,6 +38,7 @@ export default function MaterialList(props: IMaterialListProps) {
|
|||||||
search = true,
|
search = true,
|
||||||
onValueChange,
|
onValueChange,
|
||||||
trigger,
|
trigger,
|
||||||
|
formType = 'drawer',
|
||||||
} = props;
|
} = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const intlPrefix = 'material';
|
const intlPrefix = 'material';
|
||||||
@ -291,7 +294,7 @@ export default function MaterialList(props: IMaterialListProps) {
|
|||||||
columns,
|
columns,
|
||||||
}}
|
}}
|
||||||
create={{
|
create={{
|
||||||
formType: 'drawer',
|
formType: formType,
|
||||||
formContext,
|
formContext,
|
||||||
trigger,
|
trigger,
|
||||||
request: async (
|
request: async (
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
export { default as MaterialCategoryList } from './MaterialCategoryList';
|
export { default as MaterialCategoryList } from './MaterialCategoryList';
|
||||||
|
export * from './MaterialLibrary';
|
||||||
export { default as MaterialList } from './MaterialList';
|
export { default as MaterialList } from './MaterialList';
|
||||||
export { default as MaterialModal } from './MaterialModal';
|
export { default as MaterialModal } from './MaterialModal';
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import {
|
|||||||
ButtonAccess,
|
ButtonAccess,
|
||||||
CompanyPaymentAccountSelect,
|
CompanyPaymentAccountSelect,
|
||||||
InsertPosition,
|
InsertPosition,
|
||||||
MaterialList,
|
|
||||||
OrderSupplierInvoiceList,
|
OrderSupplierInvoiceList,
|
||||||
ProFormUploadMaterial,
|
ProFormUploadMaterial,
|
||||||
SupplierFarmerList,
|
SupplierFarmerList,
|
||||||
@ -12,11 +11,9 @@ import {
|
|||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { business } from '@/services';
|
import { business } from '@/services';
|
||||||
import { formatCurrency } from '@/utils/format';
|
import { formatCurrency } from '@/utils/format';
|
||||||
import { formatParam } from '@/utils/formatParam';
|
|
||||||
import { formLayout } from '@/utils/formLayout';
|
import { formLayout } from '@/utils/formLayout';
|
||||||
import { useIntl } from '@@/exports';
|
import { useIntl } from '@@/exports';
|
||||||
import {
|
import {
|
||||||
ActionType,
|
|
||||||
DrawerForm,
|
DrawerForm,
|
||||||
ProCard,
|
ProCard,
|
||||||
ProFormDependency,
|
ProFormDependency,
|
||||||
@ -26,7 +23,6 @@ import {
|
|||||||
RouteContextType,
|
RouteContextType,
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { Col, Row, Space, Table } from 'antd';
|
import { Col, Row, Space, Table } from 'antd';
|
||||||
import { useRef } from 'react';
|
|
||||||
|
|
||||||
export interface IPaymentTaskPayProps {
|
export interface IPaymentTaskPayProps {
|
||||||
insertPosition?: InsertPosition;
|
insertPosition?: InsertPosition;
|
||||||
@ -43,8 +39,6 @@ export default function PaymentTaskPay(props: IPaymentTaskPayProps) {
|
|||||||
const unpaidAmount =
|
const unpaidAmount =
|
||||||
(paymentTaskVO.totalAmount || 0) - (paymentTaskVO.paidAmount || 0);
|
(paymentTaskVO.totalAmount || 0) - (paymentTaskVO.paidAmount || 0);
|
||||||
|
|
||||||
const actionRef = useRef<ActionType>();
|
|
||||||
|
|
||||||
const handleSubmit = async (formData: any) => {
|
const handleSubmit = async (formData: any) => {
|
||||||
console.log('付款数据:', formData);
|
console.log('付款数据:', formData);
|
||||||
// TODO: 调用付款接口
|
// TODO: 调用付款接口
|
||||||
@ -370,33 +364,7 @@ export default function PaymentTaskPay(props: IPaymentTaskPayProps) {
|
|||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
maxCount: 1,
|
maxCount: 9,
|
||||||
actionRef: actionRef,
|
|
||||||
toolBarRender: () => [
|
|
||||||
<MaterialList
|
|
||||||
key={'create'}
|
|
||||||
ghost={true}
|
|
||||||
mode={'create'}
|
|
||||||
search={false}
|
|
||||||
onValueChange={() => actionRef.current?.reload()}
|
|
||||||
/>,
|
|
||||||
],
|
|
||||||
request: async (params, sorter, filter) => {
|
|
||||||
const { data, success, totalCount } =
|
|
||||||
await business.material.pageMaterial({
|
|
||||||
materialPageQry: formatParam<typeof params>(
|
|
||||||
params,
|
|
||||||
sorter,
|
|
||||||
filter,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: data || [],
|
|
||||||
total: totalCount,
|
|
||||||
success,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,5 @@
|
|||||||
import {
|
import { BizEditor, ButtonAccess, ProFormUploadMaterial } from '@/components';
|
||||||
BizEditor,
|
|
||||||
ButtonAccess,
|
|
||||||
MaterialList,
|
|
||||||
ProFormUploadMaterial,
|
|
||||||
} from '@/components';
|
|
||||||
import { business } from '@/services';
|
import { business } from '@/services';
|
||||||
import { formatParam } from '@/utils/formatParam';
|
|
||||||
import { formLayout } from '@/utils/formLayout';
|
import { formLayout } from '@/utils/formLayout';
|
||||||
import {
|
import {
|
||||||
DrawerForm,
|
DrawerForm,
|
||||||
@ -150,30 +144,6 @@ export default function ChargingPilePurchaseConfig(
|
|||||||
}
|
}
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
maxCount: 1,
|
maxCount: 1,
|
||||||
toolBarRender: () => [
|
|
||||||
<MaterialList
|
|
||||||
key={'create'}
|
|
||||||
ghost={true}
|
|
||||||
mode={'create'}
|
|
||||||
search={false}
|
|
||||||
/>,
|
|
||||||
],
|
|
||||||
request: async (params, sorter, filter) => {
|
|
||||||
const { data, success, totalCount } =
|
|
||||||
await business.material.pageMaterial({
|
|
||||||
materialPageQry: formatParam<typeof params>(
|
|
||||||
params,
|
|
||||||
sorter,
|
|
||||||
filter,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: data || [],
|
|
||||||
total: totalCount,
|
|
||||||
success,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ProFormDependency key={'content'} name={['content']}>
|
<ProFormDependency key={'content'} name={['content']}>
|
||||||
|
|||||||
@ -1,18 +1,14 @@
|
|||||||
import { MaterialList, ProFormUploadMaterial } from '@/components';
|
import { ProFormUploadMaterial } from '@/components';
|
||||||
import { business } from '@/services';
|
import { business } from '@/services';
|
||||||
import { formatParam } from '@/utils/formatParam';
|
|
||||||
import { formLayout } from '@/utils/formLayout';
|
import { formLayout } from '@/utils/formLayout';
|
||||||
import {
|
import {
|
||||||
ActionType,
|
|
||||||
ProForm,
|
ProForm,
|
||||||
ProFormText,
|
ProFormText,
|
||||||
ProFormUploadDragger,
|
ProFormUploadDragger,
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { Col, message, Row, Space } from 'antd';
|
import { Col, message, Row, Space } from 'antd';
|
||||||
import { useRef } from 'react';
|
|
||||||
|
|
||||||
export default function WxMaConfig() {
|
export default function WxMaConfig() {
|
||||||
const actionRef = useRef<ActionType>();
|
|
||||||
return (
|
return (
|
||||||
<ProForm<BusinessAPI.WxMaConfigValue>
|
<ProForm<BusinessAPI.WxMaConfigValue>
|
||||||
{...formLayout()}
|
{...formLayout()}
|
||||||
@ -113,32 +109,6 @@ export default function WxMaConfig() {
|
|||||||
}}
|
}}
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
maxCount: 1,
|
maxCount: 1,
|
||||||
actionRef: actionRef,
|
|
||||||
toolBarRender: () => [
|
|
||||||
<MaterialList
|
|
||||||
key={'create'}
|
|
||||||
ghost={true}
|
|
||||||
mode={'create'}
|
|
||||||
search={false}
|
|
||||||
onValueChange={() => actionRef.current?.reload()}
|
|
||||||
/>,
|
|
||||||
],
|
|
||||||
request: async (params, sorter, filter) => {
|
|
||||||
const { data, success, totalCount } =
|
|
||||||
await business.material.pageMaterial({
|
|
||||||
materialPageQry: formatParam<typeof params>(
|
|
||||||
params,
|
|
||||||
sorter,
|
|
||||||
filter,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: data || [],
|
|
||||||
total: totalCount,
|
|
||||||
success,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ProFormUploadDragger
|
<ProFormUploadDragger
|
||||||
|
|||||||
@ -1,13 +1,10 @@
|
|||||||
import { MaterialList, ProFormUploadMaterial } from '@/components';
|
import { ProFormUploadMaterial } from '@/components';
|
||||||
import { business } from '@/services';
|
import { business } from '@/services';
|
||||||
import { formatParam } from '@/utils/formatParam';
|
|
||||||
import { formLayout } from '@/utils/formLayout';
|
import { formLayout } from '@/utils/formLayout';
|
||||||
import { ActionType, ProForm, ProFormText } from '@ant-design/pro-components';
|
import { ProForm, ProFormText } from '@ant-design/pro-components';
|
||||||
import { Col, message, Row, Space } from 'antd';
|
import { Col, message, Row, Space } from 'antd';
|
||||||
import { useRef } from 'react';
|
|
||||||
|
|
||||||
export default function WxMaConfig() {
|
export default function WxMaConfig() {
|
||||||
const actionRef = useRef<ActionType>();
|
|
||||||
return (
|
return (
|
||||||
<ProForm<BusinessAPI.WxMaConfigValue>
|
<ProForm<BusinessAPI.WxMaConfigValue>
|
||||||
{...formLayout()}
|
{...formLayout()}
|
||||||
@ -108,32 +105,6 @@ export default function WxMaConfig() {
|
|||||||
}}
|
}}
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
maxCount: 1,
|
maxCount: 1,
|
||||||
actionRef: actionRef,
|
|
||||||
toolBarRender: () => [
|
|
||||||
<MaterialList
|
|
||||||
key={'create'}
|
|
||||||
ghost={true}
|
|
||||||
mode={'create'}
|
|
||||||
search={false}
|
|
||||||
onValueChange={() => actionRef.current?.reload()}
|
|
||||||
/>,
|
|
||||||
],
|
|
||||||
request: async (params, sorter, filter) => {
|
|
||||||
const { data, success, totalCount } =
|
|
||||||
await business.material.pageMaterial({
|
|
||||||
materialPageQry: formatParam<typeof params>(
|
|
||||||
params,
|
|
||||||
sorter,
|
|
||||||
filter,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: data || [],
|
|
||||||
total: totalCount,
|
|
||||||
success,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</ProForm>
|
</ProForm>
|
||||||
|
|||||||
@ -1,22 +1,16 @@
|
|||||||
import {
|
import {
|
||||||
BizContainer,
|
BizContainer,
|
||||||
BizValueType,
|
BizValueType,
|
||||||
MaterialList,
|
|
||||||
ModeType,
|
ModeType,
|
||||||
ProFormUploadMaterial,
|
ProFormUploadMaterial,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { business } from '@/services';
|
import { business } from '@/services';
|
||||||
import { formatBankCard, formatIdCard, formatPhone } from '@/utils/format';
|
import { formatBankCard, formatIdCard, formatPhone } from '@/utils/format';
|
||||||
import { formatParam } from '@/utils/formatParam';
|
|
||||||
import { useIntl } from '@@/exports';
|
import { useIntl } from '@@/exports';
|
||||||
import { EyeInvisibleOutlined, EyeTwoTone } from '@ant-design/icons';
|
import { EyeInvisibleOutlined, EyeTwoTone } from '@ant-design/icons';
|
||||||
import {
|
import { ProColumns, ProFormText } from '@ant-design/pro-components';
|
||||||
ActionType,
|
|
||||||
ProColumns,
|
|
||||||
ProFormText,
|
|
||||||
} from '@ant-design/pro-components';
|
|
||||||
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
|
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
|
||||||
import React, { useRef, useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
interface ISupplierFarmerListProps {
|
interface ISupplierFarmerListProps {
|
||||||
ghost?: boolean;
|
ghost?: boolean;
|
||||||
@ -38,7 +32,6 @@ export default function SupplierFarmerList(props: ISupplierFarmerListProps) {
|
|||||||
} = props;
|
} = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const intlPrefix = 'supplierFarmer';
|
const intlPrefix = 'supplierFarmer';
|
||||||
const actionRef = useRef<ActionType>();
|
|
||||||
|
|
||||||
const [showIdCard, setShowIdCard] = useState<Record<string, boolean>>({});
|
const [showIdCard, setShowIdCard] = useState<Record<string, boolean>>({});
|
||||||
const [showBankCard, setShowBankCard] = useState<Record<string, boolean>>({});
|
const [showBankCard, setShowBankCard] = useState<Record<string, boolean>>({});
|
||||||
@ -255,32 +248,6 @@ export default function SupplierFarmerList(props: ISupplierFarmerListProps) {
|
|||||||
}}
|
}}
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
maxCount: 1,
|
maxCount: 1,
|
||||||
actionRef: actionRef,
|
|
||||||
toolBarRender: () => [
|
|
||||||
<MaterialList
|
|
||||||
key={'create'}
|
|
||||||
ghost={true}
|
|
||||||
mode={'create'}
|
|
||||||
search={false}
|
|
||||||
onValueChange={() => actionRef.current?.reload()}
|
|
||||||
/>,
|
|
||||||
],
|
|
||||||
request: async (params, sorter, filter) => {
|
|
||||||
const { data, success, totalCount } =
|
|
||||||
await business.material.pageMaterial({
|
|
||||||
materialPageQry: formatParam<typeof params>(
|
|
||||||
params,
|
|
||||||
sorter,
|
|
||||||
filter,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: data || [],
|
|
||||||
total: totalCount,
|
|
||||||
success,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
/>,
|
/>,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { SelectModal } from '@/components';
|
||||||
import { business } from '@/services';
|
import { business } from '@/services';
|
||||||
import { formatBankCard, formatIdCard, formatPhone } from '@/utils/format';
|
import { formatBankCard, formatIdCard, formatPhone } from '@/utils/format';
|
||||||
import { formatParam } from '@/utils/formatParam';
|
import { formatParam } from '@/utils/formatParam';
|
||||||
@ -10,7 +11,6 @@ import {
|
|||||||
ProColumns,
|
ProColumns,
|
||||||
ProFormText,
|
ProFormText,
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { SelectModal } from '@/components';
|
|
||||||
import { Alert, ModalProps, Row, Tag } from 'antd';
|
import { Alert, ModalProps, Row, Tag } from 'antd';
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
@ -159,13 +159,13 @@ export default function SupplierModal(props: ISupplierModalProps) {
|
|||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
// {
|
||||||
title: intl.formatMessage({ id: intlPrefix + '.column.wechatQr' }),
|
// title: intl.formatMessage({ id: intlPrefix + '.column.wechatQr' }),
|
||||||
dataIndex: 'wechatQr',
|
// dataIndex: 'wechatQr',
|
||||||
valueType: 'image',
|
// valueType: 'image',
|
||||||
key: 'wechatQr',
|
// key: 'wechatQr',
|
||||||
search: false,
|
// search: false,
|
||||||
},
|
// },
|
||||||
...(initExtraColumns || []),
|
...(initExtraColumns || []),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -1,22 +1,16 @@
|
|||||||
import {
|
import {
|
||||||
BizContainer,
|
BizContainer,
|
||||||
BizValueType,
|
BizValueType,
|
||||||
MaterialList,
|
|
||||||
ModeType,
|
ModeType,
|
||||||
ProFormUploadMaterial,
|
ProFormUploadMaterial,
|
||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { business } from '@/services';
|
import { business } from '@/services';
|
||||||
import { formatBankCard, formatPhone } from '@/utils/format';
|
import { formatBankCard, formatPhone } from '@/utils/format';
|
||||||
import { formatParam } from '@/utils/formatParam';
|
|
||||||
import { useIntl } from '@@/exports';
|
import { useIntl } from '@@/exports';
|
||||||
import { EyeInvisibleOutlined, EyeTwoTone } from '@ant-design/icons';
|
import { EyeInvisibleOutlined, EyeTwoTone } from '@ant-design/icons';
|
||||||
import {
|
import { ProColumns, ProFormText } from '@ant-design/pro-components';
|
||||||
ActionType,
|
|
||||||
ProColumns,
|
|
||||||
ProFormText,
|
|
||||||
} from '@ant-design/pro-components';
|
|
||||||
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
|
import { ProDescriptionsItemProps } from '@ant-design/pro-descriptions';
|
||||||
import React, { useRef, useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
interface ISupplierStallListProps {
|
interface ISupplierStallListProps {
|
||||||
ghost?: boolean;
|
ghost?: boolean;
|
||||||
@ -38,7 +32,6 @@ export default function SupplierStallList(props: ISupplierStallListProps) {
|
|||||||
} = props;
|
} = props;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const intlPrefix = 'supplierStall';
|
const intlPrefix = 'supplierStall';
|
||||||
const actionRef = useRef<ActionType>();
|
|
||||||
|
|
||||||
const [showBankCard, setShowBankCard] = useState<Record<string, boolean>>({});
|
const [showBankCard, setShowBankCard] = useState<Record<string, boolean>>({});
|
||||||
const [showPhone, setShowPhone] = useState<Record<string, boolean>>({});
|
const [showPhone, setShowPhone] = useState<Record<string, boolean>>({});
|
||||||
@ -214,32 +207,6 @@ export default function SupplierStallList(props: ISupplierStallListProps) {
|
|||||||
}}
|
}}
|
||||||
fieldProps={{
|
fieldProps={{
|
||||||
maxCount: 1,
|
maxCount: 1,
|
||||||
actionRef: actionRef,
|
|
||||||
toolBarRender: () => [
|
|
||||||
<MaterialList
|
|
||||||
key={'create'}
|
|
||||||
ghost={true}
|
|
||||||
mode={'create'}
|
|
||||||
search={false}
|
|
||||||
onValueChange={() => actionRef.current?.reload()}
|
|
||||||
/>,
|
|
||||||
],
|
|
||||||
request: async (params, sorter, filter) => {
|
|
||||||
const { data, success, totalCount } =
|
|
||||||
await business.material.pageMaterial({
|
|
||||||
materialPageQry: formatParam<typeof params>(
|
|
||||||
params,
|
|
||||||
sorter,
|
|
||||||
filter,
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
data: data || [],
|
|
||||||
total: totalCount,
|
|
||||||
success,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
/>,
|
/>,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -1,36 +1,41 @@
|
|||||||
|
import { MaterialLibraryModal } from '@/components';
|
||||||
import { UploadOutlined } from '@ant-design/icons';
|
import { UploadOutlined } from '@ant-design/icons';
|
||||||
import { ActionType, ProTableProps } from '@ant-design/pro-components';
|
|
||||||
import { SelectModal } from '@/components';
|
|
||||||
import { Upload } from 'antd';
|
import { Upload } from 'antd';
|
||||||
import React, { MutableRefObject, useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import useStyle from './style.style';
|
import useStyle from './style.style';
|
||||||
|
|
||||||
export interface UploadMaterialProps {
|
export interface UploadMaterialProps {
|
||||||
maxCount: number;
|
maxCount: number;
|
||||||
onChange: (fileList: any[]) => void;
|
onChange: (fileList: any[]) => void;
|
||||||
fileList?: any[];
|
fileList?: any[];
|
||||||
request: ProTableProps<any, any>['request'];
|
|
||||||
toolBarRender?: ProTableProps<any, any>['toolBarRender'];
|
|
||||||
actionRef?: MutableRefObject<ActionType | undefined>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const UploadMaterial: React.FC<UploadMaterialProps> = (props) => {
|
const UploadMaterial: React.FC<UploadMaterialProps> = (props) => {
|
||||||
const {
|
const { maxCount, onChange, fileList: initialFileList } = props;
|
||||||
maxCount,
|
|
||||||
fileList: initialFileList,
|
|
||||||
onChange,
|
|
||||||
request,
|
|
||||||
toolBarRender,
|
|
||||||
actionRef,
|
|
||||||
} = props;
|
|
||||||
const [fileList, setFileList] = useState<any[]>([]);
|
const [fileList, setFileList] = useState<any[]>([]);
|
||||||
const { styles } = useStyle();
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
const { styles } = useStyle();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setFileList(initialFileList || []);
|
setFileList(initialFileList || []);
|
||||||
}, [initialFileList]);
|
}, [initialFileList]);
|
||||||
|
|
||||||
|
// 处理素材选择完成
|
||||||
|
const handleMaterialSelect = (materials: BusinessAPI.MaterialVO[]) => {
|
||||||
|
const imageList = materials.map((materialVO) => ({
|
||||||
|
uid: materialVO?.materialId,
|
||||||
|
name: materialVO?.name,
|
||||||
|
// @ts-ignore
|
||||||
|
status: 'success',
|
||||||
|
thumbUrl: materialVO?.url,
|
||||||
|
url: materialVO?.url,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const newFileList = [...fileList, ...imageList];
|
||||||
|
setFileList(newFileList);
|
||||||
|
onChange(newFileList);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Upload
|
<Upload
|
||||||
@ -58,71 +63,20 @@ const UploadMaterial: React.FC<UploadMaterialProps> = (props) => {
|
|||||||
)}
|
)}
|
||||||
</Upload>
|
</Upload>
|
||||||
|
|
||||||
{/* 选择图片 */}
|
{/* 素材库选择弹窗 */}
|
||||||
<SelectModal
|
<MaterialLibraryModal
|
||||||
rowKey={'materialId'}
|
open={open}
|
||||||
modalProps={{
|
onCancel={() => setOpen(false)}
|
||||||
title: '选择图片',
|
maxCount={maxCount - fileList.length}
|
||||||
open: open,
|
mode="checkbox"
|
||||||
onOk: () => setOpen(false),
|
materialType="FILE_IMAGE"
|
||||||
onCancel: () => setOpen(false),
|
onFinish={(materials) => {
|
||||||
|
handleMaterialSelect(materials);
|
||||||
|
setOpen(false);
|
||||||
}}
|
}}
|
||||||
tableProps={{
|
|
||||||
actionRef: actionRef,
|
|
||||||
toolBarRender: toolBarRender,
|
|
||||||
rowKey: 'materialId',
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
title: '素材内容',
|
|
||||||
dataIndex: 'url',
|
|
||||||
valueType: 'image',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '素材名称',
|
|
||||||
dataIndex: 'name',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: '素材分类',
|
|
||||||
dataIndex: ['categoryVO', 'name'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
params: {
|
|
||||||
materialPageQry: {
|
|
||||||
type: 'FILE_IMAGE',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
request: request,
|
|
||||||
pagination: {
|
|
||||||
showSizeChanger: true,
|
|
||||||
showQuickJumper: true,
|
|
||||||
showTotal: (total: number) => `共 ${total} 条`,
|
|
||||||
pageSizeOptions: ['10', '20', '50', '100'],
|
|
||||||
defaultPageSize: 10,
|
|
||||||
hideOnSinglePage: true,
|
|
||||||
position: ['bottomRight'],
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
onFinish={(materialList) => {
|
|
||||||
const imageList = materialList.map((materialVO) => {
|
|
||||||
return {
|
|
||||||
uid: materialVO?.materialId,
|
|
||||||
name: materialVO?.name,
|
|
||||||
// @ts-ignore
|
|
||||||
status: 'success',
|
|
||||||
thumbUrl: materialVO?.url,
|
|
||||||
url: materialVO?.url,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
const newFileList = [...fileList, ...imageList];
|
|
||||||
setFileList(newFileList);
|
|
||||||
|
|
||||||
onChange(newFileList);
|
|
||||||
}}
|
|
||||||
num={(maxCount || 1) - fileList.length}
|
|
||||||
type={'checkbox'}
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UploadMaterial;
|
export default UploadMaterial;
|
||||||
|
|||||||
@ -1,30 +1,29 @@
|
|||||||
import { createStyles } from 'antd-style';
|
import { createStyles } from 'antd-style';
|
||||||
|
|
||||||
const useStyle = () => {
|
const useStyle = () => {
|
||||||
return createStyles(() => {
|
return createStyles(() => {
|
||||||
return {
|
return {
|
||||||
uploadImage: {
|
uploadImage: {
|
||||||
width: 102,
|
width: 102,
|
||||||
height: 102,
|
height: 102,
|
||||||
marginInlineEnd: 0,
|
marginInlineEnd: 0,
|
||||||
marginBottom: 0,
|
marginBottom: 0,
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
verticalAlign: 'top',
|
verticalAlign: 'top',
|
||||||
backgroundColor: "rgba(0, 0, 0, 2%)",
|
backgroundColor: 'rgba(0, 0, 0, 2%)',
|
||||||
//border: 1px dashed #d9d9d9,
|
borderRadius: 8,
|
||||||
borderRadius: 8,
|
cursor: 'pointer',
|
||||||
cursor: 'pointer',
|
transition: 'border-color 0.3s',
|
||||||
transition: 'border-color 0.3s',
|
},
|
||||||
},
|
uploadImageIcon: {
|
||||||
uploadImageIcon: {
|
display: 'flex',
|
||||||
display: 'flex',
|
alignItems: 'center',
|
||||||
alignItems: 'center',
|
justifyContent: 'center',
|
||||||
justifyContent: 'center',
|
height: '100%',
|
||||||
height: '100%',
|
textAlign: 'center',
|
||||||
textAlign: 'center',
|
},
|
||||||
},
|
};
|
||||||
};
|
})();
|
||||||
})();
|
};
|
||||||
}
|
|
||||||
|
|
||||||
export default useStyle;
|
export default useStyle;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user