perf: optimize custom components and scope

This commit is contained in:
sealday 2024-03-09 00:08:19 +08:00
parent dbcd884526
commit 47a5a504fe
5 changed files with 101 additions and 258 deletions

View File

@ -13,6 +13,7 @@
"antd": "5.*", "antd": "5.*",
"flatted": "^3.2.9", "flatted": "^3.2.9",
"qrcode": "^1.5.1", "qrcode": "^1.5.1",
"ahooks": "^3.7.2",
"dayjs": "^1.11.8", "dayjs": "^1.11.8",
"react-router-dom": "^6.11.2", "react-router-dom": "^6.11.2",
"qrcode.react": "^3.1.0" "qrcode.react": "^3.1.0"

View File

@ -1,4 +1,4 @@
import React, { useMemo } from 'react'; import React from 'react';
import { import {
CUSTOM_COMPONENT_TYPE_FIELD, CUSTOM_COMPONENT_TYPE_FIELD,
KEY_CUSTOM_COMPONENT_LABEL, KEY_CUSTOM_COMPONENT_LABEL,
@ -6,10 +6,9 @@ import {
} from '@hera/plugin-core/client'; } from '@hera/plugin-core/client';
import { observer, useField, useForm } from '@formily/react'; import { observer, useField, useForm } from '@formily/react';
import _ from 'lodash'; import _ from 'lodash';
import { useRequest } from '@nocobase/client';
import { formatQuantity } from '../../utils/currencyUtils'; import { formatQuantity } from '../../utils/currencyUtils';
import { Spin } from 'antd'; import { Spin } from 'antd';
import { stringify } from 'flatted'; import { useCachedRequest } from '../hooks';
export const RecordItemCount = observer((props) => { export const RecordItemCount = observer((props) => {
const param = { const param = {
@ -19,8 +18,7 @@ export const RecordItemCount = observer((props) => {
pageSize: 99999, pageSize: 99999,
}, },
}; };
const cacheKey = stringify(param); const { loading, data } = useCachedRequest<any>(param);
const { loading, data } = useRequest<any>(param, { cacheKey });
const form = useForm(); const form = useForm();
const field = useField(); const field = useField();

View File

@ -1,4 +1,4 @@
import React, { useEffect } from 'react'; import React from 'react';
import { import {
CUSTOM_COMPONENT_TYPE_FIELD, CUSTOM_COMPONENT_TYPE_FIELD,
KEY_CUSTOM_COMPONENT_LABEL, KEY_CUSTOM_COMPONENT_LABEL,
@ -6,42 +6,12 @@ import {
} from '@hera/plugin-core/client'; } from '@hera/plugin-core/client';
import { observer, useField, useForm } from '@formily/react'; import { observer, useField, useForm } from '@formily/react';
import _ from 'lodash'; import _ from 'lodash';
import { useRequest } from '@nocobase/client';
import { ConversionLogics, RecordCategory } from '../../utils/constants'; import { ConversionLogics, RecordCategory } from '../../utils/constants';
import { formatQuantity } from '../../utils/currencyUtils'; import { formatQuantity } from '../../utils/currencyUtils';
import { stringify } from 'flatted'; import { useCachedRequest, useLeaseItems } from '../hooks';
function useCachedRequest<P>(params: {}, options = {}) {
const cacheKey = stringify(params);
return useRequest<P>(params, { cacheKey, ...options });
}
const useLeaseItems = (planId) => {
const params = {
resource: 'contract_plan_lease_items',
action: 'list',
params: {
appends: ['products'],
filter: {
contract_plan_id: planId,
},
pageSize: 99999,
},
};
const { data, loading, run } = useCachedRequest<any>(params, {
manual: true,
});
useEffect(() => {
if (planId) {
run();
}
}, [planId]);
return { data, loading };
};
// 计价数量 // 计价数量
export const RecordItemValuationQuantity = observer((props) => { export const RecordItemValuationQuantity = observer((props) => {
console.count('计价数量');
const form = useForm(); const form = useForm();
const field = useField(); const field = useField();
const contractPlanId = form.getValuesIn('contract_plan')?.id; const contractPlanId = form.getValuesIn('contract_plan')?.id;
@ -87,7 +57,7 @@ export const RecordItemValuationQuantity = observer((props) => {
const count = subtotal(rule, item, productCategory, reqWeightRules); const count = subtotal(rule, item, productCategory, reqWeightRules);
count && result.push({ label: '合同', value: count }); count && result.push({ label: '合同', value: count });
} }
// 采购
if (form.values.category === RecordCategory.purchase && priceItems) { if (form.values.category === RecordCategory.purchase && priceItems) {
const rule = priceItems?.find( const rule = priceItems?.find(
(rule) => rule.product?.category_id === item.product?.category_id || rule.product?.id === item.product?.id, (rule) => rule.product?.category_id === item.product?.category_id || rule.product?.id === item.product?.id,
@ -98,10 +68,11 @@ export const RecordItemValuationQuantity = observer((props) => {
count && result.push({ label: '报价', value: count }); count && result.push({ label: '报价', value: count });
} }
} }
// 暂存或结存
if (form.values.category === RecordCategory.inventory || form.values.category === RecordCategory.staging) { if (form.values.category === RecordCategory.inventory || form.values.category === RecordCategory.staging) {
result.push([{ label: '', value: '-' }]); result.push([{ label: '', value: '-' }]);
} }
// 采购直发
if (form.values.category === RecordCategory.purchase2lease && priceItems && inLeaseItems) { if (form.values.category === RecordCategory.purchase2lease && priceItems && inLeaseItems) {
const rule = priceItems?.find( const rule = priceItems?.find(
(rule) => rule.product?.category_id === item.product?.category_id || rule.product?.id === item.product?.id, (rule) => rule.product?.category_id === item.product?.category_id || rule.product?.id === item.product?.id,
@ -119,7 +90,7 @@ export const RecordItemValuationQuantity = observer((props) => {
const count = subtotal(leaseRule, item, productCategory, reqWeightRules); const count = subtotal(leaseRule, item, productCategory, reqWeightRules);
count && result.push({ label: '入库合同', value: count }); count && result.push({ label: '入库合同', value: count });
} }
// 租赁直发
if (form.values.category === RecordCategory.lease2lease && inLeaseItems && outLeaseItems) { if (form.values.category === RecordCategory.lease2lease && inLeaseItems && outLeaseItems) {
const contractPlain_out = outLeaseItems.data.find((leaseItem) => const contractPlain_out = outLeaseItems.data.find((leaseItem) =>
leaseItem.products.find( leaseItem.products.find(

View File

@ -1,222 +1,78 @@
import _ from 'lodash'; import _ from 'lodash';
import { Spin } from 'antd'; import { Spin } from 'antd';
import React, { useEffect, useState } from 'react'; import React from 'react';
import { onFieldValueChange, onFieldInit } from '@formily/core'; import { observer, useForm } from '@formily/react';
import { useForm, useFormEffects } from '@formily/react';
import { useRequest } from '@nocobase/client';
import { RecordCategory } from '../../utils/constants'; import { RecordCategory } from '../../utils/constants';
import { import {
CUSTOM_COMPONENT_TYPE_ASSOCIATED_FIELD, CUSTOM_COMPONENT_TYPE_ASSOCIATED_FIELD,
KEY_CUSTOM_COMPONENT_LABEL, KEY_CUSTOM_COMPONENT_LABEL,
KEY_CUSTOM_COMPONENT_TYPE, KEY_CUSTOM_COMPONENT_TYPE,
} from '@hera/plugin-core/client'; } from '@hera/plugin-core/client';
import { useCachedRequest, useLeaseItems } from '../hooks';
import { useDeepCompareEffect } from 'ahooks';
export const RecordProductScope = () => { export const RecordProductScope = observer(() => {
const form = useForm(); const form = useForm();
const [priceProducts, setPriceProducts] = useState([]); const contractPlanId = form.getValuesIn('contract_plan')?.id;
const [contractPlanId, setContractPlanId] = useState(-1); const inContractPlanId = form.getValuesIn('in_contract_plan')?.id;
const [contractProducts, setContractProducts] = useState([]); const outContractPlanId = form.getValuesIn('out_contract_plan')?.id;
const [inContractPlanId, setInContractPlanId] = useState(-1);
const [outContractPlanId, setOutContractPlanId] = useState(-1); console.log('产品范围');
const [inContractProducts, setInContractProducts] = useState([]); let required = { price: false, contract: false, inContract: false, outContract: false };
const [outContractProducts, setOutContractProducts] = useState([]); const { data, loading } = useCachedRequest<any>({
const [required, setRequired] = useState({ price: false, contract: false, inContract: false, outContract: false });
const { data, loading } = useRequest<any>({
resource: 'product_category', resource: 'product_category',
action: 'list', action: 'list',
params: { params: {
pageSize: 9999, pageSize: 99999,
}, },
}); });
const { loading: loadingLeaseItems } = useRequest<any>( const { data: leaseItems, loading: leaseItemsLoading } = useLeaseItems(contractPlanId);
{ const { data: inLeaseItems, loading: inLeaseItemsLoading } = useLeaseItems(inContractPlanId);
resource: 'contract_plan_lease_items', const { data: outLeaseItems, loading: outLeaseItemsLoading } = useLeaseItems(outContractPlanId);
action: 'list',
params: {
appends: ['products'],
filter: {
contract_plan_id: contractPlanId,
},
pageSize: 9999,
},
},
{
refreshDeps: [contractPlanId],
onSuccess(data) {
if (data?.data?.length > 0) {
const items = data.data as { products: { category_id: string }[] }[];
const result = items.reduce((acc, current) => {
acc.push(...current.products.map((item) => ({ id: item.category_id })));
return acc;
}, []);
setContractProducts(result);
} else {
setContractProducts([]);
}
},
},
);
// 租赁直发,入库合同方案产品 const contractProducts =
const { loading: loadingInLeaseItems } = useRequest<any>( leaseItems?.data.reduce((acc, current) => {
{ acc.push(...current.products.map((item) => ({ id: item.category_id })));
resource: 'contract_plan_lease_items', return acc;
action: 'list', }, []) ?? [];
params: {
appends: ['products'],
filter: {
contract_plan_id: inContractPlanId,
},
pageSize: 9999,
},
},
{
refreshDeps: [inContractPlanId],
onSuccess(data) {
if (data?.data?.length > 0) {
const items = data.data as { products: { category_id: string }[] }[];
const result = items.reduce((acc, current) => {
acc.push(...current.products.map((item) => ({ id: item.category_id })));
return acc;
}, []);
setInContractProducts(result);
} else {
setInContractProducts([]);
}
},
},
);
// 租赁直发,出库合同方案产品
const { loading: loadingOutLeaseItems } = useRequest<any>(
{
resource: 'contract_plan_lease_items',
action: 'list',
params: {
appends: ['products'],
filter: {
contract_plan_id: outContractPlanId,
},
pageSize: 9999,
},
},
{
refreshDeps: [outContractPlanId],
onSuccess(data) {
if (data?.data?.length > 0) {
const items = data.data as { products: { category_id: string }[] }[];
const result = items.reduce((acc, current) => {
acc.push(...current.products.map((item) => ({ id: item.category_id })));
return acc;
}, []);
setOutContractProducts(result);
} else {
setOutContractProducts([]);
}
},
},
);
useFormEffects(() => { const inContractProducts =
onFieldValueChange('price_items.*.product', () => { inLeaseItems?.data.reduce((acc, current) => {
setPriceProducts(_.get(form.values, 'price_items', []).map((item) => ({ id: item.product.category_id }))); acc.push(...current.products.map((item) => ({ id: item.category_id })));
}); return acc;
}); }, []) ?? [];
useFormEffects(() => {
onFieldInit('contract_plan', () => {
if (form.values.contract_plan) {
setContractPlanId(form.values.contract_plan.id);
} else {
setContractPlanId(-1);
}
});
onFieldValueChange('contract_plan', () => {
if (form.values.contract_plan) {
setContractPlanId(form.values.contract_plan.id);
} else {
setContractPlanId(-1);
}
});
onFieldInit('in_contract_plan', () => {
if (form.values.in_contract_plan) {
setInContractPlanId(form.values.in_contract_plan.id);
} else {
setInContractPlanId(-1);
}
});
onFieldValueChange('in_contract_plan', () => {
if (form.values.in_contract_plan) {
setInContractPlanId(form.values.in_contract_plan.id);
} else {
setInContractPlanId(-1);
}
});
onFieldInit('out_contract_plan', () => { const outContractProducts =
if (form.values.out_contract_plan) { outLeaseItems?.data.reduce((acc, current) => {
setOutContractPlanId(form.values.out_contract_plan.id); acc.push(...current.products.map((item) => ({ id: item.category_id })));
} else { return acc;
setOutContractPlanId(-1); }, []) ?? [];
}
}); const priceProducts =
onFieldValueChange('out_contract_plan', () => { form.values.price_items?.filter((item) => item.product).map((item) => ({ id: item.product.category_id })) ?? [];
if (form.values.out_contract_plan) {
setOutContractPlanId(form.values.out_contract_plan.id); switch (form.values.category) {
} else { case RecordCategory.lease:
setOutContractPlanId(-1); required = { price: false, contract: true, inContract: false, outContract: false };
} break;
}); case RecordCategory.purchase:
}); required = { price: true, contract: false, inContract: false, outContract: false };
useFormEffects(() => { break;
onFieldInit('category', () => { case RecordCategory.lease2lease: // 出库合同,入库合同的产品范围交集
switch (form.values.category) { required = { price: false, contract: false, inContract: true, outContract: true };
case RecordCategory.lease: break;
setRequired({ price: false, contract: true, inContract: false, outContract: false }); case RecordCategory.purchase2lease: // 报价,入库合同的产品范围交集
break; required = { price: true, contract: false, inContract: true, outContract: false };
case RecordCategory.purchase: break;
setRequired({ price: true, contract: false, inContract: false, outContract: false }); case RecordCategory.inventory:
break; case RecordCategory.staging:
case RecordCategory.lease2lease: // 出库合同,入库合同的产品范围交集 required = { price: false, contract: false, inContract: false, outContract: false };
setRequired({ price: false, contract: false, inContract: true, outContract: true }); break;
break; default:
case RecordCategory.purchase2lease: // 报价,入库合同的产品范围交集 break;
setRequired({ price: true, contract: false, inContract: true, outContract: false }); }
break; useDeepCompareEffect(() => {
case RecordCategory.inventory: let result = data?.data ?? [];
case RecordCategory.staging:
setRequired({ price: false, contract: false, inContract: false, outContract: false });
break;
default:
break;
}
});
onFieldValueChange('category', () => {
switch (form.values.category) {
case RecordCategory.lease:
setRequired({ price: false, contract: true, inContract: false, outContract: false });
break;
case RecordCategory.purchase:
setRequired({ price: true, contract: false, inContract: false, outContract: false });
break;
case RecordCategory.lease2lease: // 出库合同,入库合同的产品范围交集
setRequired({ price: false, contract: false, inContract: true, outContract: true });
break;
case RecordCategory.purchase2lease: // 报价,入库合同的产品范围交集
setRequired({ price: true, contract: false, inContract: true, outContract: false });
break;
case RecordCategory.inventory:
case RecordCategory.staging:
setRequired({ price: false, contract: false, inContract: false, outContract: false });
break;
default:
break;
}
});
});
useEffect(() => {
if (loading || loadingLeaseItems || loadingInLeaseItems || loadingOutLeaseItems) {
return;
}
let result = data.data;
if (required.inContract && required.outContract) { if (required.inContract && required.outContract) {
// 租赁直发单 // 租赁直发单
const intersection = _.intersectionBy(inContractProducts, outContractProducts, 'id'); const intersection = _.intersectionBy(inContractProducts, outContractProducts, 'id');
@ -230,25 +86,11 @@ export const RecordProductScope = () => {
result = _.intersectionBy(result, contractProducts, 'id'); result = _.intersectionBy(result, contractProducts, 'id');
} }
form.setValues({ form.setValues({
// FIXME
product_scope: result, product_scope: result,
}); });
}, [ }, [required, data, priceProducts, contractProducts, inContractProducts, outContractProducts, form]);
required.price, return loading || leaseItemsLoading || inLeaseItemsLoading || outLeaseItemsLoading ? <Spin /> : <></>;
required.contract, });
data?.data,
priceProducts,
contractProducts,
inContractProducts,
outContractProducts,
form,
loading,
loadingLeaseItems,
loadingInLeaseItems,
loadingOutLeaseItems,
]);
return loading || loadingLeaseItems || loadingInLeaseItems || loadingOutLeaseItems ? <Spin /> : <></>;
};
RecordProductScope.displayName = 'RecordProductScope'; RecordProductScope.displayName = 'RecordProductScope';
RecordProductScope[KEY_CUSTOM_COMPONENT_TYPE] = CUSTOM_COMPONENT_TYPE_ASSOCIATED_FIELD; RecordProductScope[KEY_CUSTOM_COMPONENT_TYPE] = CUSTOM_COMPONENT_TYPE_ASSOCIATED_FIELD;

View File

@ -0,0 +1,31 @@
import { useRequest } from '@nocobase/client';
import { stringify } from 'flatted';
import { useEffect } from 'react';
export function useCachedRequest<P>(params: {}, options = {}) {
const cacheKey = stringify(params);
return useRequest<P>(params, { cacheKey, ...options });
}
export const useLeaseItems = (planId) => {
const params = {
resource: 'contract_plan_lease_items',
action: 'list',
params: {
appends: ['products'],
filter: {
contract_plan_id: planId,
},
pageSize: 99999,
},
};
const { data, loading, run } = useCachedRequest<any>(params, {
manual: true,
});
useEffect(() => {
if (planId) {
run();
}
}, [planId]);
return { data, loading };
};