- 将多个组件中的 @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 字段支持
356 lines
8.2 KiB
TypeScript
356 lines
8.2 KiB
TypeScript
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,
|
||
}}
|
||
/>
|
||
);
|
||
}
|