dev-v2
Joe 10 months ago
parent 12f46100c1
commit 65f069956e

@ -176,25 +176,25 @@ export default [
access: 'trainingClassesCategoryQuery', access: 'trainingClassesCategoryQuery',
component: './TrainingClasses/category', component: './TrainingClasses/category',
}, },
// { {
// name: '商品管理', name: '课程维护',
// path: 'list', path: 'list',
// access: 'productQuery', access: 'trainingClassesQuery',
// component: './ProductList', component: './TrainingClasses',
// }, },
// { {
// name: '新增商品', name: '新增课程',
// path: 'add', path: 'add',
// hideInMenu: true, hideInMenu: true,
// component: './ProductList/add', component: './TrainingClasses/add',
// }, },
// { {
// name: '详情', name: '详情',
// path: 'detail/:id', path: 'detail/:id',
// access: 'productQuery', access: 'trainingClassesQuery',
// hideInMenu: true, hideInMenu: true,
// component: './ProductList/detail', component: './TrainingClasses/detail',
// }, },
] ]
}, },
{ {

@ -1,147 +1,48 @@
import Constants from '@/constants';
import { getPbcBusinessListUsingPost } from '@/services/pop-b2b2c/pbcBusinessController';
import { listAdminTreeUsingGet } from '@/services/pop-b2b2c/pbcCategoryController';
import { getRecordByL3CategoryIdUsingGet } from '@/services/pop-b2b2c/pbcCommonDataController';
import { addOrUpdateProductForAdminUsingPost } from '@/services/pop-b2b2c/pbcProductController';
import { getCities } from '@/utils/cities';
import { import {
ProCard, ProCard,
ProForm, ProForm,
ProFormCascader, ProFormDateTimeRangePicker,
ProFormDigit, ProFormDigit,
ProFormInstance, ProFormInstance,
ProFormList,
ProFormSelect, ProFormSelect,
ProFormText, ProFormText,
ProFormTextArea,
ProFormUploadButton, ProFormUploadButton,
} from '@ant-design/pro-components'; } from '@ant-design/pro-components';
import { PageContainer } from '@ant-design/pro-layout'; import { PageContainer } from '@ant-design/pro-layout';
import { DndContext, DragEndEvent, PointerSensor, useSensor } from '@dnd-kit/core';
import { arrayMove, SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable';
import { Button, Col, message, Row } from 'antd'; import { Button, Col, message, Row } from 'antd';
import Upload, { RcFile, UploadFile } from 'antd/es/upload'; import Upload, { RcFile } from 'antd/es/upload';
import React, { useRef, useState } from 'react'; import React, { useRef } from 'react';
import { CSS } from '@dnd-kit/utilities'; import { getClassesTypeListForAdminUsingPost } from '@/services/pop-b2b2c/pbcTrainingClassesTypeController';
import { addOrUpdateClassUsingPost } from '@/services/pop-b2b2c/pbcTrainingClassesController';
interface DraggableUploadListItemProps {
originNode: React.ReactElement<any, string | React.JSXElementConstructor<any>>;
file: UploadFile<any>;
}
const DraggableUploadListItem = ({ originNode, file }: DraggableUploadListItemProps) => {
let { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
id: file.uid,
});
const style: React.CSSProperties = {
transform: CSS.Translate.toString(transform),
transition,
cursor: 'move',
};
return (
<div
ref={setNodeRef}
style={style}
// prevent preview event when drag end
className={isDragging ? 'is-dragging' : ''}
{...attributes}
{...listeners}
>
{/* hide error tooltip when dragging */}
{file.status === 'error' && isDragging ? originNode.props.children : originNode}
</div>
);
};
const Detail: React.FC<any> = () => { const Detail: React.FC<any> = () => {
const [cities] = useState(() => getCities())
const [colorData, setColorData] = useState<API.PbcCommonData[]>()
const [commonDataList, setCommonDataList] = useState<API.PbcCommonData[]>()
const formRef = useRef<ProFormInstance>(); const formRef = useRef<ProFormInstance>();
const onSave = () => { const onSave = () => {
formRef.current?.submit() formRef.current?.submit()
const values = formRef.current?.getFieldsValue()
console.log(values.colorItems)
console.log(values.specItems)
}
const handleCategoryChange = (value: any[], items: API.PbcCategory[]) => {
const [c1, c2, c3] = items
formRef.current?.setFieldsValue({
pbcProductTopCategoryName: c1?.pbcCategoryName,
pbcProductParentCategoryName: c2?.pbcCategoryName,
pbcProductCategoryName: c3?.pbcCategoryName,
})
if (value.length === 3) {
getRecordByL3CategoryIdUsingGet({ l3CategoryId: value[2] }).then(res => {
if (res.retcode && res.data) {
setColorData(res.data.colorData)
setCommonDataList(res.data.commonDataList)
}
})
}
} }
const onSubmit = async (values: any) => { const onSubmit = async (values: any) => {
let pbcProductOriginalProvince = undefined, pbcProductOriginalCity = undefined;
if (values?.pbcZone?.length) { let pbcImages = ""
([pbcProductOriginalProvince, pbcProductOriginalCity] = values.pbcZone); if (values.pbcImages && values.pbcImages.length > 0) {
} if (
const [pbcProductTopCategoryId, pbcProductParentCategoryId, pbcProductCategoryId] = values.pbcProductCategoryIdList values.pbcImages[0].response &&
console.log(values.colorItems) values.pbcImages[0].response.retcode
console.log(values.specItems) ) {
const specItems: API.PbcProductCommonData[] = [] pbcImages = values.pbcImages[0].response.data;
if (colorData && values.colorItems && values.colorItems.length > 0) {
for (let i = 0; i < values.colorItems.length; i++) {
const element = values.colorItems[i];
specItems.push({
pbcCommonDataId: colorData.length > 0 ? colorData[0].pbcId : undefined,
pbcSystemName: '颜色',
pbcSystemInputType: 'text',
pbcCommonDataSystem: element.name,
pbcColorImageUrl: element.value.length > 0 ? element.value[0].response.data : ''
})
}
}
if (commonDataList) {
for (let i = 0; i < commonDataList.length; i++) {
const element = commonDataList[i];
console.log(values[`value${i}`])
let name = ''
if (element.pbcSystemInputType === 'select' && element.commonDataValueList) {
name = element.commonDataValueList.find(e => e.pbcId === values[`value${i}`])?.pbcSystemValue || ''
}
specItems.push({
pbcCommonDataId: element.pbcId,
pbcSystemName: element.pbcSystemName,
pbcSystemInputType: element.pbcSystemInputType,
pbcCommonDataValueId: element.pbcSystemInputType === 'select' ? values[`value${i}`] : undefined,
pbcCommonDataSystemValue: element.pbcSystemInputType === 'select' ? name : undefined,
pbcCommonDataSystem: element.pbcSystemInputType === 'select' ? undefined : values[`value${i}`]
})
} }
} }
const params: API.PbcProductDTO = {
const params: API.PbcTrainingClasses_ = {
...values, ...values,
pbcProductOriginalProvince, pbcImages,
pbcProductOriginalCity, pbcTrainingStartDatetime: values.pbcTrainingStartDatetime[0],
pbcProductTopCategoryId, pbcTrainingEndDatetime: values.pbcTrainingStartDatetime[1]
pbcProductParentCategoryId,
pbcProductCategoryId,
productCommonDataList: specItems,
pbcProductImages: values.pbcProductImages.filter((e: any) => e.response && e.response.data).map((e: any) => e.response.data).join(','),
pbcProductDetailImages: values.pbcProductDetailImages.filter((e: any) => e.response && e.response.data).map((e: any) => e.response.data).join(','),
pbcZone: undefined,
colorItems: undefined,
specItems: undefined,
pbcProductCategoryIdList: undefined,
} }
const msg = await addOrUpdateProductForAdminUsingPost(params) const msg = await addOrUpdateClassUsingPost(params)
if (msg.retcode) { if (msg.retcode) {
message.success("创建成功!") message.success("创建成功!")
history.back(); history.back();
@ -152,20 +53,6 @@ const Detail: React.FC<any> = () => {
} }
} }
const sensor = useSensor(PointerSensor, {
activationConstraint: { distance: 10 },
});
const onDragEnd = ({ active, over }: DragEndEvent, fieldName: string) => {
if (active.id !== over?.id) {
const arr = formRef.current?.getFieldValue(fieldName) || []
const activeIndex = arr.findIndex((i: any) => i.uid === active.id);
const overIndex = arr.findIndex((i: any) => i.uid === over?.id);
const newArr = arrayMove(arr, activeIndex, overIndex)
formRef.current?.setFieldValue(fieldName, newArr)
}
};
return ( return (
<PageContainer <PageContainer
header={{ header={{
@ -186,151 +73,52 @@ const Detail: React.FC<any> = () => {
]} ]}
> >
<ProForm layout="horizontal" labelAlign="left" requiredMark={false} formRef={formRef} onFinish={onSubmit} submitter={false}> <ProForm layout="horizontal" labelAlign="left" requiredMark={false} formRef={formRef} onFinish={onSubmit} submitter={false}>
<ProFormText name="pbcProductTopCategoryName" hidden /> <ProFormText name="pbcClassesTypeName" hidden />
<ProFormText name="pbcProductParentCategoryName" hidden />
<ProFormText name="pbcProductCategoryName" hidden />
<ProCard title="基本信息" style={{ marginBottom: 12 }}> <ProCard title="基本信息" style={{ marginBottom: 12 }}>
<Row gutter={20}> <Row gutter={20}>
<Col span={8}> <Col span={12}>
<ProFormText label="课程名称" name="pbcTitle" rules={[
{ required: true, message: '请输入课程名称' },
]} />
</Col>
<Col span={12}>
<ProFormSelect <ProFormSelect
label="所属商户" label="课程类型"
name="pbcBusinessId" name="pbcClassesTypeId"
rules={[ rules={[
{ required: true, message: '请选择所属商户' } { required: true, message: '请选择课程类型' }
]} ]}
request={ async () => { request={ async () => {
const msg = await getPbcBusinessListUsingPost(); const msg = await getClassesTypeListForAdminUsingPost();
if (msg.retcode && msg.data) { if (msg.retcode && msg.data) {
return msg.data; return msg.data;
} }
return []; return [];
}} }}
fieldProps={{ fieldProps={{
onChange(value, option: any) {
console.log(option)
formRef.current?.setFieldsValue({
pbcClassesTypeName: option.label
})
},
showSearch: true, showSearch: true,
fieldNames: { label: 'pbcBusinessName', value: 'pbcId' } fieldNames: { label: 'pbcType', value: 'pbcId' }
}} }}
/> />
</Col> </Col>
<Col span={8}>
<ProFormText label="编号" name="pbcProductCode" rules={[
{ required: true, message: '请输入商品编号' },
]} />
</Col>
<Col span={8}>
<ProFormText label="名称" name="pbcProductTitle" rules={[
{ required: true, message: '请输入商品名称' },
]} />
</Col>
</Row>
<Row gutter={20}>
<Col span={8}>
<ProFormCascader label="产地" name="pbcZone" fieldProps={{ options: cities }} />
</Col>
<Col span={8}>
<ProFormText label="价格" name="pbcProductPrice" rules={[
{ required: true, message: '请输入商品价格' },
]} fieldProps={{ prefix: '¥' }} />
</Col>
<Col span={8}>
<ProFormDigit label="库存" name="pbcProductStock" min={0} fieldProps={{ precision: 0 }} rules={[
{ required: true, message: '请输入商品库存' },
]} />
</Col>
</Row> </Row>
<Row gutter={20}> <Row gutter={20}>
<Col span={8}>
<ProFormText label="货架号" name="pbcProductShelfNumber" rules={[
{ required: true, message: '请输入货架号' }
]} />
</Col>
<Col span={8}>
<ProFormCascader label="类目" name="pbcProductCategoryIdList"
request={ async () => {
const msg = await listAdminTreeUsingGet({ type: 2 });
if (msg.retcode && msg.data) {
return msg.data;
}
return [];
}}
fieldProps={{fieldNames: { label: 'pbcCategoryName', value: 'pbcId', children: 'children' }, onChange: handleCategoryChange}}
rules={[
{ required: true, message: '请选择类目' },
]} />
</Col>
</Row>
{colorData ? <ProForm.Item isListField style={{ marginBlockEnd: 0 }} label="颜色" required>
<ProFormList
name="colorItems"
creatorButtonProps={{
creatorButtonText: '新增',
icon: false,
type: 'link',
style: { width: 'unset' },
}}
copyIconProps={false}
deleteIconProps={{ tooltipText: '删除' }}
itemRender={({ listDom, action }) => (
<div
style={{
display: 'inline-flex',
marginInlineEnd: 25,
}}
>
{listDom}
{action}
</div>
)}
>
<Row align="middle" gutter={20}>
<Col span={12}> <Col span={12}>
<ProFormText width="sm" name={['name']} placeholder="请输入颜色名" rules={[ <ProFormDigit label="总课次" name="pbcClassesSubCount" min={0} fieldProps={{ precision: 0 }} rules={[
{ required: true, message: '请输入颜色名' } { required: true, message: '请输入总课次' },
]} /> ]} />
</Col> </Col>
<Col span={12}> <Col span={12}>
<ProFormUploadButton <ProFormUploadButton
name={['value']} label="课程缩略图"
fieldProps={{ name="pbcImages"
name: 'file',
accept: 'image/*',
headers: {
authorization: localStorage.getItem('token') ?? '',
},
action: process.env.BASE_URL + '/oss/imgUpload',
beforeUpload(file: RcFile) {
const isLt2M = file.size / 1024 / 1024 < 10;
if (!isLt2M) {
message.error('图片大小不能超过10MB!');
}
return isLt2M || Upload.LIST_IGNORE;
},
onPreview: async (file) => {
if (file.uid === '-1') {
window.open(file.url);
}
if (file.response && file.response.retcode) {
window.open(file.response.data);
}
},
listType: 'picture-card',
}}
rules={[
{ required: true, message: '请上传颜色图片' },
]}
max={1} max={1}
/>
</Col>
</Row>
</ProFormList>
</ProForm.Item> : null}
<Row gutter={20}>
<Col span={24}>
<DndContext sensors={[sensor]} onDragEnd={(event) => onDragEnd(event, "pbcProductImages")}>
<SortableContext items={formRef.current?.getFieldValue("pbcProductImages") ? formRef.current?.getFieldValue("pbcProductImages").map((i: any) => i.uid) : []} strategy={verticalListSortingStrategy}>
<ProFormUploadButton
label="相册图"
name="pbcProductImages"
fieldProps={{ fieldProps={{
name: 'file', name: 'file',
accept: 'image/*', accept: 'image/*',
@ -338,59 +126,27 @@ const Detail: React.FC<any> = () => {
headers: { headers: {
authorization: localStorage.getItem('token') ?? '', authorization: localStorage.getItem('token') ?? '',
}, },
itemRender: (originNode, file) => <DraggableUploadListItem originNode={originNode} file={file} />, onChange: (info: any) => {
action: process.env.BASE_URL + '/oss/imgUpload', switch (info.file.status) {
beforeUpload(file: RcFile) { case 'done':
const isLt2M = file.size / 1024 / 1024 < 10; if (info.file.response.retcode === 0) {
if (!isLt2M) { message.error(info.file.response.retmsg);
message.error('图片大小不能超过10MB!'); formRef.current?.setFieldValue('pbcImages', [])
}
return isLt2M || Upload.LIST_IGNORE;
},
onPreview: async (file) => {
if (file.uid === '-1') {
window.open(file.url);
} }
if (file.response && file.response.retcode) { break;
window.open(file.response.data); default:
break;
} }
}, },
listType: 'picture-card',
}}
rules={[
{ required: true, message: '请上传相册图' },
]}
/>
</SortableContext>
</DndContext>
</Col>
</Row>
<Row gutter={20}>
<Col span={24}>
<DndContext sensors={[sensor]} onDragEnd={(event) => onDragEnd(event, "pbcProductDetailImages")}>
<SortableContext items={formRef.current?.getFieldValue("pbcProductDetailImages") ? formRef.current?.getFieldValue("pbcProductDetailImages").map((i: any) => i.uid) : []} strategy={verticalListSortingStrategy}>
<ProFormUploadButton
label="详情图"
name="pbcProductDetailImages"
fieldProps={{
name: 'file',
accept: 'image/*',
multiple: true,
headers: {
authorization: localStorage.getItem('token') ?? '',
},
itemRender: (originNode, file) => <DraggableUploadListItem originNode={originNode} file={file} />,
action: process.env.BASE_URL + '/oss/imgUpload', action: process.env.BASE_URL + '/oss/imgUpload',
beforeUpload(file: RcFile) { beforeUpload(file: RcFile) {
const isLt2M = file.size / 1024 / 1024 < 10; const isLt10M = file.size / 1024 / 1024 < 10;
if (!isLt2M) { if (!isLt10M) {
message.error('图片大小不能超过10MB!'); message.error('图片大小不能超过10MB!');
} }
return isLt2M || Upload.LIST_IGNORE; return isLt10M || Upload.LIST_IGNORE;
}, },
onPreview: async (file) => { onPreview: async (file) => {
if (file.uid === '-1') { if (file.uid === '-1') {
window.open(file.url); window.open(file.url);
} }
@ -401,43 +157,20 @@ const Detail: React.FC<any> = () => {
listType: 'picture-card', listType: 'picture-card',
}} }}
rules={[ rules={[
{ required: true, message: '请上传详情图' }, { required: true, message: '请上传课程缩略图' }
]} ]}
/> />
</SortableContext>
</DndContext>
</Col>
</Row>
{commonDataList ? commonDataList.map((e, index) => <Row key={e.pbcId} align="middle" gutter={20}>
<Col span={6}>
<ProFormText width="sm" disabled name={`name${index}`} initialValue={e.pbcSystemName} placeholder="请输入规格名称" rules={[
{ required: true, message: '请输入规格名称' }
]} />
</Col>
<Col span={6}>
{e.pbcSystemInputType === 'select' ? <ProFormSelect name={`value${index}`} options={e.commonDataValueList?.map(item => {
return {
label: item.pbcSystemValue || '',
value: item.pbcId
}
})} /> : <ProFormText width="sm" name={`value${index}`} placeholder="请输入规格描述" />
}
</Col>
</Row>) : null}
<Row gutter={20}>
<Col span={24}>
<ProFormTextArea label="详情描述" name="pbcProductDetail" />
</Col> </Col>
</Row> </Row>
<Row gutter={20}> <Row gutter={20}>
<Col span={8}> <Col span={12}>
<ProFormSelect label="可见范围" name="pbcProductType" valueEnum={Constants.pbcProductType} rules={[ <ProFormSelect label="教学方式" name="pbcTeachMethod" options={['线上', '线下']} rules={[
{ required: true, message: '请选择可见范围' }, { required: true, message: '请选择教学方式' },
]} /> ]} />
</Col> </Col>
<Col span={8}> <Col span={8}>
<ProFormSelect label="状态" name="pbcState" valueEnum={Constants.pbcState} rules={[ <ProFormDateTimeRangePicker label="培训时间" name="pbcTrainingStartDatetime" rules={[
{ required: true, message: '请选择上下架状态' }, { required: true, message: '请选择培训时间' },
]} /> ]} />
</Col> </Col>
</Row> </Row>

@ -1,8 +1,9 @@
import { getClassPageForAdminUsingPost } from '@/services/pop-b2b2c/pbcTrainingClassesController'; import Constants from '@/constants';
import { changeClassStateForAdminUsingGet, getClassPageForAdminUsingPost } from '@/services/pop-b2b2c/pbcTrainingClassesController';
import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components'; import { ActionType, ProColumns, ProTable } from '@ant-design/pro-components';
import { PageContainer } from '@ant-design/pro-layout'; import { PageContainer } from '@ant-design/pro-layout';
import { Access, Link, useAccess, history } from '@umijs/max'; import { Access, Link, useAccess, history } from '@umijs/max';
import { Button } from 'antd'; import { Button, message, Space, Switch, Image } from 'antd';
import React, { useRef } from 'react'; import React, { useRef } from 'react';
/** /**
@ -18,24 +19,24 @@ const fetchData = async (params: API.PbcTrainingClasses_) => {
} as any; } as any;
}; };
// const handleUpdateState = async (id: number, state: number) => { const handleUpdateState = async (id: number, state: number) => {
// const hide = message.loading('正在保存'); const hide = message.loading('正在保存');
// if (!id) return false; if (!id) return false;
// try { try {
// const msg = await updateCategoryRecordStateUsingGet({ pbcId: id, state: state }); const msg = await changeClassStateForAdminUsingGet({ id, state: state });
// hide(); hide();
// if (msg.retcode) { if (msg.retcode) {
// message.success(!id ? '新增成功!' : '保存成功!'); message.success(!id ? '新增成功!' : '保存成功!');
// return true; return true;
// } }
// message.error(msg.retmsg); message.error(msg.retmsg);
// return false; return false;
// } catch (error) { } catch (error) {
// hide(); hide();
// message.error(!id ? '新增失败,请重试!' : '保存失败,请重试!'); message.error(!id ? '新增失败,请重试!' : '保存失败,请重试!');
// return false; return false;
// } }
// }; };
// eslint-disable-next-line @typescript-eslint/ban-types // eslint-disable-next-line @typescript-eslint/ban-types
const TableList: React.FC<{}> = () => { const TableList: React.FC<{}> = () => {
@ -47,11 +48,15 @@ const TableList: React.FC<{}> = () => {
title: '课程缩略图', title: '课程缩略图',
dataIndex: 'pbcImages', dataIndex: 'pbcImages',
search: false, search: false,
width: 220,
render: (text) => {
const str = text?.toString()
return str && <Image style={{ objectFit: 'contain' }} src={str} width={200} height={200} />
}
}, },
{ {
title: '课程名称', title: '课程名称',
dataIndex: 'pbcTitle', dataIndex: 'pbcTitle',
search: false,
}, },
{ {
title: '课程类型', title: '课程类型',
@ -68,13 +73,19 @@ const TableList: React.FC<{}> = () => {
dataIndex: 'pbcCreateAt', dataIndex: 'pbcCreateAt',
search: false search: false
}, },
{
title: '课程状态',
dataIndex: 'pbcState',
hideInTable: true,
valueEnum: Constants.state
},
{ {
title: '操作', title: '操作',
fixed: 'right', fixed: 'right',
valueType: 'option', valueType: 'option',
render: (text, record) => ( render: (text, record) => (
<span> <Space>
{/* <Access key="switch" accessible={access.productCategoryUpdateState}> <Access key="switch" accessible={access.trainingClassesUpdateState}>
<Switch <Switch
checked={record.pbcState === 1} checked={record.pbcState === 1}
onChange={async (value) => { onChange={async (value) => {
@ -87,9 +98,12 @@ const TableList: React.FC<{}> = () => {
} }
}} }}
/> />
</Access> */} </Access>
<Link to={'/training-classes/save/' + record.pbcId}></Link> <Link to={'/training-classes/detail/' + record.pbcId}></Link>
</span> <Access key="switch" accessible={access.trainingClassesSave}>
<Link to={'/training-classes/detail/' + record.pbcId + "?isEdit=1"}></Link>
</Access>
</Space>
), ),
}, },
]; ];
@ -117,8 +131,8 @@ const TableList: React.FC<{}> = () => {
}} }}
toolbar={{ toolbar={{
actions: [ actions: [
<Access key="add" accessible={access.productAdd}> <Access key="add" accessible={access.trainingClassesSave}>
<Button type="primary" onClick={() => history.push('/product/add')}></Button> <Button type="primary" onClick={() => history.push('/training-classes/add')}></Button>
</Access> </Access>
] ]
}} }}

Loading…
Cancel
Save