ERPTurbo_Admin/packages/app-operation/src/components/Material/MaterialList.tsx
shenyifei 1429319b01 refactor(components): 调整组件导入路径并新增验证码组件
- 将多个组件中的 @chageable/components 导入改为从 @/components 导入
- 在 BoxBrandList.tsx、CostList.tsx、ProductDataList.tsx 等文件中更新 ProFormBizSelect 相关组件导入
- 在 CaptchaModal/index.tsx 中将 Captcha 组件导入从 @chageable/components 改为 @/components
- 在 ChannelList.tsx、CompanyList.tsx、EmployeeList.tsx 等文件中更新 ProFormUploadMaterial 导入
- 在 MaterialList.tsx 中更新 ProFormBizTreeSelect 和 ProFormUploadOss 导入
- 在 MenuList.tsx、OrderCostList.tsx 中更新 ProFormBizSelect 相关组件导入
- 在 DealerModal.tsx、MaterialModal.tsx、OrderModal.tsx 等文件中更新 SelectModal 导入
- 在 app.tsx 中将 LeftMenu 导入从 @chageable/components 改为 @/components
- 新增 UploadMaterial 组件并添加到 components/index.ts 导出
- 在 Captcha 组件中添加滑动验证码功能,包含样式和交互逻辑
- 在 companyPaymentAccount 工具函数中添加 branchName 字段支持
2026-01-07 00:12:26 +08:00

356 lines
8.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import {
BizContainer,
BizValueType,
MaterialCategoryList,
ModeType,
ProFormBizTreeSelect,
ProFormBizTreeSelectHandles,
ProFormUploadOss,
Remark,
} from '@/components';
import { business } from '@/services';
import { useIntl } from '@@/exports';
import {
ProColumns,
ProFormDependency,
ProFormRadio,
} from '@ant-design/pro-components';
import { useModel } from '@umijs/max';
import { TreeSelect } from 'antd';
import moment from 'moment';
import React, { useRef, useState } from 'react';
import { v4 as uuidv4 } from 'uuid';
export interface IMaterialListProps {
ghost?: boolean;
search?: boolean;
mode?: ModeType;
trigger?: () => React.ReactNode;
onValueChange?: () => void;
}
export default function MaterialList(props: IMaterialListProps) {
const {
mode = 'page',
ghost = false,
search = true,
onValueChange,
trigger,
} = props;
const intl = useIntl();
const intlPrefix = 'material';
const actionBizRef = useRef<ProFormBizTreeSelectHandles>(null);
const { getOssToken } = useModel('useOssToken', (model) => ({
getOssToken: model.getOssToken,
}));
const [type, setType] = useState<BusinessAPI.MaterialVO['type']>();
const formContext = [
<ProFormDependency key={'categoryId'} name={['type']}>
{({ type: formType }, form) => {
if (formType !== type) {
setType(formType);
}
return (
<>
<ProFormRadio.Group
label={intl.formatMessage({
id: intlPrefix + '.form.type.label',
})}
name={'type'}
required={true}
fieldProps={{
onChange: () => {
form.setFieldValue('categoryId', undefined);
form.setFieldValue('path', undefined);
},
}}
options={[
{
label: intl.formatMessage({
id: intlPrefix + '.form.type.enum.image',
}),
value: 'FILE_IMAGE',
},
{
label: intl.formatMessage({
id: intlPrefix + '.form.type.enum.video',
}),
value: 'FILE_VIDEO',
},
]}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.type.required',
}),
},
]}
/>
</>
);
}}
</ProFormDependency>,
<ProFormBizTreeSelect
ref={actionBizRef}
key={'categoryId'}
label={intl.formatMessage({
id: intlPrefix + '.form.categoryId.label',
})}
required={true}
name={'categoryId'}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.categoryId.placeholder',
})}
params={{ type }}
fetchOptions={async (params) => {
const { data } = await business.materialCategory.treeMaterialCategory({
categoryTreeQry: {
...params,
},
});
return data || [];
}}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.categoryId.required',
}),
},
]}
fieldProps={{
suffixIcon: null,
showSearch: true,
allowClear: true,
autoClearSearchValue: true,
filterTreeNode: true,
multiple: false,
treeNodeFilterProp: 'name',
showCheckedStrategy: TreeSelect.SHOW_ALL,
fieldNames: {
label: 'name',
children: 'children',
value: 'categoryId',
},
}}
addonAfter={
<MaterialCategoryList
ghost={true}
type={type}
mode={'create'}
search={search}
onValueChange={() => actionBizRef.current?.reload()}
/>
}
/>,
<ProFormDependency key={'path'} name={['type']}>
{({ type }) => {
switch (type) {
case 'FILE_IMAGE':
case 'FILE_VIDEO':
return (
<ProFormUploadOss
//@ts-ignore
label={intl.formatMessage({
id: intlPrefix + '.form.path.label',
})}
required={true}
placeholder={intl.formatMessage({
id: intlPrefix + '.form.path.placeholder',
})}
rules={[
{
required: true,
message: intl.formatMessage({
id: intlPrefix + '.form.path.required',
}),
},
]}
key={'file'}
/>
);
}
}}
</ProFormDependency>,
];
const columns: ProColumns<BusinessAPI.MaterialVO, BizValueType>[] = [
{
title: intl.formatMessage({ id: intlPrefix + '.column.name' }),
dataIndex: 'name',
order: 3,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.url' }),
dataIndex: 'url',
search: false,
render: (_, record) => {
return record.type === 'FILE_IMAGE' || record.type === 'FILE_VIDEO' ? (
// 可预览
<a
href={record.url}
target="_blank"
rel="noopener noreferrer"
style={{
display: 'inline-block',
width: 22,
height: 22,
overflow: 'hidden',
}}
>
<img
src={record.url}
alt={record.name}
style={{ width: 22, height: 22 }}
/>
</a>
) : (
<Remark remark={record.path} />
);
},
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.type' }),
dataIndex: 'type',
valueType: 'select',
valueEnum: {
FILE_IMAGE: {
text: intl.formatMessage({
id: intlPrefix + '.column.type.enum.image',
}),
},
FILE_VIDEO: {
text: intl.formatMessage({
id: intlPrefix + '.column.type.enum.video',
}),
},
},
fieldProps: {
showSearch: true,
allowClear: true,
autoClearSearchValue: true,
},
order: 2,
},
{
title: intl.formatMessage({ id: intlPrefix + '.column.category' }),
dataIndex: 'categoryId',
valueType: 'treeSelect',
request: async (params) => {
const { data } = await business.materialCategory.treeMaterialCategory({
categoryTreeQry: {
...params,
},
});
return data || [];
},
dependencies: ['type'],
fieldProps: {
fieldNames: {
label: 'name',
children: 'children',
value: 'categoryId',
},
showSearch: true,
allowClear: true,
autoClearSearchValue: true,
filterTreeNode: true,
multiple: false,
treeNodeFilterProp: 'name',
},
order: 2,
},
];
return (
<BizContainer<
typeof business.material,
BusinessAPI.MaterialVO,
BusinessAPI.MaterialPageQry,
BusinessAPI.MaterialCreateCmd & { file: any },
BusinessAPI.MaterialUpdateCmd & { file: any }
>
rowKey={'materialId'}
permission={'operation-community'}
func={business.material}
method={'material'}
methodUpper={'Material'}
intlPrefix={intlPrefix}
onValueChange={onValueChange}
modeType={mode}
container={{ ghost }}
page={{
fieldProps: {
ghost,
//@ts-ignore
search,
},
columns,
}}
create={{
formType: 'drawer',
formContext,
trigger,
request: async (
formData: BusinessAPI.MaterialCreateCmd & {
file: any;
},
) => {
const OSS = require('ali-oss');
const ossToken = await getOssToken();
const client = new OSS({
// yourRegion填写Bucket所在地域。以华东1杭州为例yourRegion填写为oss-cn-hangzhou。
region: 'oss-' + ossToken?.region,
// 从STS服务获取的临时访问密钥AccessKey ID和AccessKey Secret
accessKeyId: ossToken?.accessKeyId,
accessKeySecret: ossToken?.accessKeySecret,
// 从STS服务获取的安全令牌SecurityToken
stsToken: ossToken?.securityToken,
// 填写Bucket名称。
bucket: ossToken?.bucket,
});
const path = moment(new Date()).format('YYMM/DD');
const materialCreateCmdList =
new Array<BusinessAPI.MaterialCreateCmd>();
for (const file of formData.file) {
const filename = uuidv4();
// @ts-ignore
const fileExtension = ((file.originFileObj?.name || '').match(
/\.([0-9a-z]+)(?:[\\?#]|$)/i,
) || ['.png'])[0];
// 目录存放 `/uploads/operations/${path}/${filename}${fileExtension}`
const result = await client.put(
`/uploads/operations/${path}/${filename}${fileExtension}`,
file.originFileObj,
);
materialCreateCmdList.push({
name: file.name,
categoryId: formData.categoryId,
path: result.name,
type: formData.type,
});
}
const { success } = await business.material.batchCreateMaterial({
materialCreateCmdList,
});
return success;
},
}}
destroy={{}}
update={{
formType: 'drawer',
formContext,
}}
/>
);
}