产品管理: 编辑权限

perf/export-docx
Lei OT 11 months ago
parent 53407fa57a
commit d83f39efe6

@ -116,6 +116,7 @@
"Weekdays": "Weekdays" "Weekdays": "Weekdays"
}, },
"sureSubmitAudit": "确认提交所有产品审核? 提交后,所有产品将进入待审核流程. ",
"FormTooltip": { "FormTooltip": {
"Type": "Product Type", "Type": "Product Type",
"Title": "Title", "Title": "Title",

@ -105,6 +105,7 @@
"Operation": "Operation" "Operation": "Operation"
}, },
"sureSubmitAudit": "确认提交所有产品审核? 提交后,所有产品将进入待审核流程. ",
"FormTooltip": { "FormTooltip": {
"Type": "Product Type", "Type": "Product Type",
"Title": "Title", "Title": "Title",

@ -181,10 +181,10 @@ const Header = ({ refresh, newActionable, ...props }) => {
</Button> </Button>
</RequireAuth> </RequireAuth>
)} )}
{activeAgencyState === 0 && ( {/* {activeAgencyState === 0 && ( */}
<> <>
<RequireAuth subject={PERM_PRODUCTS_OFFER_PUT}> <RequireAuth subject={PERM_PRODUCTS_OFFER_PUT}>
<Popconfirm title={t('sureSubmit')} onConfirm={handleSubmitForAudit} okText={t('Yes')} placement={'bottom'}> <Popconfirm title={t('products:sureSubmitAudit')} onConfirm={handleSubmitForAudit} okText={t('Yes')} placement={'bottomLeft'}>
<Button size='small' type={'primary'} > <Button size='small' type={'primary'} >
{t('Submit')} {t('Submit')}
{t('Audit')} {t('Audit')}
@ -192,7 +192,7 @@ const Header = ({ refresh, newActionable, ...props }) => {
</Popconfirm> </Popconfirm>
</RequireAuth> </RequireAuth>
</> </>
)} {/* )} */}
</div> </div>
); );
}; };

@ -22,18 +22,25 @@ const ProductInfo = ({ ...props }) => {
const [activeAgency, editingProduct, setEditingProduct] = useProductsStore((state) => [state.activeAgency, state.editingProduct, state.setEditingProduct]); const [activeAgency, editingProduct, setEditingProduct] = useProductsStore((state) => [state.activeAgency, state.editingProduct, state.setEditingProduct]);
const [extrasVisible, setExtrasVisible] = useState(false); const [extrasVisible, setExtrasVisible] = useState(false);
const [editable, setEditable] = useState(false); const [editablePerm, setEditablePerm] = useState(false);
const [infoEditable, setInfoEditable] = useState(false);
const [priceEditable, setPriceEditable] = useState(false);
const topPerm = isPermitted(PERM_PRODUCTS_MANAGEMENT); // const topPerm = isPermitted(PERM_PRODUCTS_MANAGEMENT); //
useEffect(() => { useEffect(() => {
const hasHT = (editingProduct?.info?.htid || 0) > 0; const hasHT = (editingProduct?.info?.htid || 0) > 0;
// const hasAuditPer = isPermitted(PERM_PRODUCTS_OFFER_AUDIT); // const hasAuditPer = isPermitted(PERM_PRODUCTS_OFFER_AUDIT);
const hasEditPer = isPermitted(PERM_PRODUCTS_OFFER_PUT); const hasEditPer = isPermitted(PERM_PRODUCTS_OFFER_PUT);
setEditable(topPerm || (!hasHT && hasEditPer));
setEditablePerm(topPerm || hasEditPer);
// setEditable(topPerm || (hasAuditPer ? true : (!hasHT && hasEditPer))); // setEditable(topPerm || (hasAuditPer ? true : (!hasHT && hasEditPer)));
// setEditable(true); // debug: 0 // setEditable(true); // debug: 0
// console.log('editable', hasAuditPer, (notAudit && hasEditPer)); // console.log('editable', hasAuditPer, (notAudit && hasEditPer));
setInfoEditable(topPerm || (!hasHT && hasEditPer));
const _priceEditable = [-1, 3].includes(activeAgency?.audit_state_id);
setPriceEditable(topPerm || (_priceEditable && hasEditPer));
const showExtras = topPerm && !isEmpty(editingProduct) && hasHT; const showExtras = topPerm && hasHT; // !isEmpty(editingProduct) &&
setExtrasVisible(showExtras); setExtrasVisible(showExtras);
return () => {}; return () => {};
}, [activeAgency, editingProduct]); }, [activeAgency, editingProduct]);
@ -42,18 +49,19 @@ const ProductInfo = ({ ...props }) => {
values.travel_agency_id = activeAgency.travel_agency_id; values.travel_agency_id = activeAgency.travel_agency_id;
const copyNewProduct = structuredClone(newProductRecord); const copyNewProduct = structuredClone(newProductRecord);
const poster = { const poster = {
...(topPerm ? {} : {'audit_state': '-1',}), // : ...(topPerm ? {} : { 'audit_state': -1 }), // :
// "create_date": dayjs().format('YYYY-MM-DD HH:mm:ss'), // "create_date": dayjs().format('YYYY-MM-DD HH:mm:ss'),
// "created_by": userId, // "created_by": userId,
'travel_agency_id': activeAgency.travel_agency_id, 'travel_agency_id': activeAgency.travel_agency_id,
// "travel_agency_name": "", // "travel_agency_name": "",
// "lastedit_changed": "", // "lastedit_changed": "",
}; };
/** lgc_details */
const copyFields = pick(editingProduct.info, ['product_type_id']); // 'title', const copyFields = pick(editingProduct.info, ['product_type_id']); // 'title',
const readyToSubInfo = { ...copyNewProduct.info, ...editingProduct.info, ...values.info, ...copyFields, type: copyFields.product_type_id, ...poster }; const readyToSubInfo = { ...copyNewProduct.info, ...editingProduct.info, ...values.info, ...copyFields, type: copyFields.product_type_id, ...poster };
readyToSubInfo.dept = Number(readyToSubInfo.dept);
// console.log('onSave', editingProduct.info, readyToSubInfo); // console.log('onSave', editingProduct.info, readyToSubInfo);
const prevLgcDetailsMapped = editingProduct.lgc_details.reduce((r, c) => ({ ...r, [c.lgc]: { ...c, description: c.descriptions } }), {}); // todo: description /** lgc_details */
const prevLgcDetailsMapped = editingProduct.lgc_details.reduce((r, c) => ({ ...r, [c.lgc]: { ...c, description: c.descriptions } }), {});
const mergedLgc = { ...prevLgcDetailsMapped, ...values.lgc_details_mapped }; const mergedLgc = { ...prevLgcDetailsMapped, ...values.lgc_details_mapped };
// console.log(values); // console.log(values);
@ -64,15 +72,15 @@ const ProductInfo = ({ ...props }) => {
travel_agency_id: activeAgency.travel_agency_id, travel_agency_id: activeAgency.travel_agency_id,
info: readyToSubInfo, info: readyToSubInfo,
lgc_details: Object.values(mergedLgc), lgc_details: Object.values(mergedLgc),
quotation: values.quotation, // || editingProduct.quotation, // , quotation: values.quotation.map((q) => ({ ...q, unit: Number(q.unit || q.unit_id), unit_id: Number(q.unit_id) })), // || editingProduct.quotation, // ,
}).catch(ex => { }).catch((ex) => {
setLoading(false); setLoading(false);
notification.error({ notification.error({
message: 'Notification', message: 'Notification',
description: ex.message, description: ex.message,
placement: 'top', placement: 'top',
duration: 4, duration: 4,
}) });
}); });
setLoading(false); setLoading(false);
success ? message.success(t('Success')) : message.error(t('Failed')); success ? message.success(t('Success')) : message.error(t('Failed'));
@ -90,10 +98,14 @@ const ProductInfo = ({ ...props }) => {
]} ]}
/> />
<Divider className='my-1' /> <Divider className='my-1' />
<h2>{t('products:EditComponents.info')}</h2> {isEmpty(editingProduct) ? null : (
<ProductInfoForm editable={editable} initialValues={editingProduct?.info} onSubmit={onSave} /> <>
<Divider className='my-1' /> <h2>{t('products:EditComponents.info')}</h2>
{extrasVisible && <Extras productId={editingProduct?.info?.id} />} <ProductInfoForm {...{ editablePerm, infoEditable, priceEditable }} initialValues={editingProduct?.info} onSubmit={onSave} />
<Divider className='my-1' />
{extrasVisible && <Extras productId={editingProduct?.info?.id} />}
</>
)}
</> </>
); );
}; };

@ -11,7 +11,7 @@ import ProductInfoLgc from './ProductInfoLgc';
import ProductInfoQuotation from './ProductInfoQuotation'; import ProductInfoQuotation from './ProductInfoQuotation';
import { useHTLanguageSetsMapVal } from '@/hooks/useHTLanguageSets'; import { useHTLanguageSetsMapVal } from '@/hooks/useHTLanguageSets';
const InfoForm = ({ onSubmit, onReset, onValuesChange, editable: _editable, showSubmit, confirmText, formName, ...props }) => { const InfoForm = ({ onSubmit, onReset, onValuesChange, editablePerm, infoEditable, priceEditable, showSubmit, confirmText, formName, ...props }) => {
const { notification } = App.useApp(); const { notification } = App.useApp();
const { t } = useTranslation('products'); const { t } = useTranslation('products');
const HTLanguageSetsMapVal = useHTLanguageSetsMapVal(); const HTLanguageSetsMapVal = useHTLanguageSetsMapVal();
@ -29,7 +29,9 @@ const InfoForm = ({ onSubmit, onReset, onValuesChange, editable: _editable, show
const filedsets = useProductsTypesFieldsets(editingProduct?.info?.product_type_id); const filedsets = useProductsTypesFieldsets(editingProduct?.info?.product_type_id);
const shows = filedsets[0]; const shows = filedsets[0];
const [editable, setEditable] = useState(true); // const [editable, setEditable] = useState(true);
const [formEditable, setFormEditable] = useState(true);
const [showSave, setShowSave] = useState(true);
useEffect(() => { useEffect(() => {
form.resetFields(); form.resetFields();
form.setFieldValue('city', editingProduct?.info?.city_id ? { value: editingProduct?.info?.city_id, label: editingProduct?.info?.city_name } : undefined); form.setFieldValue('city', editingProduct?.info?.city_id ? { value: editingProduct?.info?.city_id, label: editingProduct?.info?.city_name } : undefined);
@ -38,10 +40,13 @@ const InfoForm = ({ onSubmit, onReset, onValuesChange, editable: _editable, show
form.setFieldValue('lgc_details_mapped', lgc_details_mapped); form.setFieldValue('lgc_details_mapped', lgc_details_mapped);
form.setFieldValue('quotation', editingProduct?.quotation); form.setFieldValue('quotation', editingProduct?.quotation);
const editable0 = isEmpty(editingProduct) ? false : _editable; // setFormEditable(infoEditable || priceEditable);
setEditable(editable0);
const editable0 = isEmpty(editingProduct) ? false : editablePerm; //
setShowSave(infoEditable || priceEditable);
// setEditable(editable0);
return () => {}; return () => {};
}, [editingProduct?.info?.id, _editable]); }, [editingProduct?.info?.id, editablePerm, infoEditable, priceEditable]);
const onFinish = (values) => { const onFinish = (values) => {
console.log('Received values of form, origin form value: \n', values); console.log('Received values of form, origin form value: \n', values);
@ -84,7 +89,7 @@ const InfoForm = ({ onSubmit, onReset, onValuesChange, editable: _editable, show
<> <>
<Form <Form
form={form} form={form}
disabled={!editable} disabled={!formEditable}
name={formName || 'product_info'} name={formName || 'product_info'}
// preserve={false} // preserve={false}
onFinish={onFinish} onFinish={onFinish}
@ -93,7 +98,7 @@ const InfoForm = ({ onSubmit, onReset, onValuesChange, editable: _editable, show
initialValues={editingProduct?.info} initialValues={editingProduct?.info}
onFinishFailed={onFinishFailed} scrollToFirstError > onFinishFailed={onFinishFailed} scrollToFirstError >
<Row> <Row>
{getFields({ sort, initialValue: editingProduct?.info, hides, shows, fieldProps, fieldComProps, form, t, dataSets: { weekdays }, editable })} {getFields({ sort, initialValue: editingProduct?.info, hides, shows, fieldProps, fieldComProps, form, t, dataSets: { weekdays }, editable: infoEditable })}
{/* {showSubmit && ( {/* {showSubmit && (
<Col flex='1 0 90px' className='flex justify-end items-start'> <Col flex='1 0 90px' className='flex justify-end items-start'>
<Space align='center'> <Space align='center'>
@ -125,11 +130,11 @@ const InfoForm = ({ onSubmit, onReset, onValuesChange, editable: _editable, show
}, },
}), }),
]}> ]}>
<ProductInfoLgc editable={editable} formInstance={form} /> <ProductInfoLgc editable={infoEditable} formInstance={form} />
</Form.Item> </Form.Item>
<Form.Item name='quotation'> <Form.Item name='quotation'>
<ProductInfoQuotation editable={editable} /> <ProductInfoQuotation editable={priceEditable} />
</Form.Item> </Form.Item>
<Form.Item hidden name={'id'} label={'ID'}> <Form.Item hidden name={'id'} label={'ID'}>
@ -138,7 +143,7 @@ const InfoForm = ({ onSubmit, onReset, onValuesChange, editable: _editable, show
{/* <Form.Item hidden name={'title'} label={'title'}> {/* <Form.Item hidden name={'title'} label={'title'}>
<Input /> <Input />
</Form.Item> */} </Form.Item> */}
{editable && ( {showSave && (
<Form.Item> <Form.Item>
<div className='flex justify-around'> <div className='flex justify-around'>
<Button type='primary' htmlType='submit' loading={loading}> <Button type='primary' htmlType='submit' loading={loading}>

@ -333,10 +333,11 @@ const ProductInfoQuotation = ({ editable, ...props }) => {
dataIndex: 'operation', dataIndex: 'operation',
width: '3%', width: '3%',
render: (_, quotation) => { render: (_, quotation) => {
const _rowEditable = [-1,3].includes(quotation.audit_state_id);
return ( return (
<Space> <Space>
<Button type='link' onClick={() => onQuotationSeleted(quotation)}>{t('Edit')}</Button> <Button type='link' disabled={!_rowEditable} onClick={() => onQuotationSeleted(quotation)}>{t('Edit')}</Button>
<Button type='link' danger onClick={() => onDeleteQuotation(quotation.id)}>{t('Delete')}</Button> <Button type='link' danger disabled={!_rowEditable} onClick={() => onDeleteQuotation(quotation.id)}>{t('Delete')}</Button>
</Space> </Space>
) )
}, },

Loading…
Cancel
Save