提交 276d036c 作者: 龚洪江

功能:服务管理

上级 4cfad1de
import { InterFunction, InterListFunction } from '~/api/interface';
import { InterFunction, InterItemFunction, InterListFunction } from '~/api/interface';
// V1.0.1课程视频列表
export type queryCurriculumInfoListType = InterListFunction<
{
......@@ -106,8 +106,64 @@ export type addServiceType = InterFunction<
industryId: number;
serviceIntroduction?: string;
serviceName: string;
shareCard?: string;
video?: string;
},
any
>;
//服务-更新
export type editServiceType = InterFunction<
{
applicationId: number;
coverPlan: string;
displayState: number;
industryId: number;
serviceIntroduction?: string;
serviceName: string;
shareCard?: string;
video?: string;
id: number;
},
any
>;
//服务-列表
export type serviceType = InterItemFunction<
{ applicationId?: number; industryId?: number; serviceName?: string; displayState?: number },
{
applicationName: string;
serviceName: string;
industryName: string;
coverPlan: string;
shareCard: string;
video: string;
},
serviceIntroduction: string;
displayState: number;
applicationId: number;
industryId: number;
id: number;
}[]
>;
//服务-上下架-批量
export type batchUpAndDownWorkServiceType = InterFunction<
{ displayState: number; ids: number[] },
any
>;
//服务-删除-批量
export type deleteServiceType = InterFunction<number[], any>;
//服务-详情
export type serviceDetailType = InterFunction<
{ id: number },
{
applicationName: string;
serviceName: string;
industryName: string;
coverPlan: string;
shareCard: string;
video: string;
serviceIntroduction: string;
displayState: number;
applicationId: number;
industryId: number;
id: number;
}
>;
......@@ -5,8 +5,13 @@ import {
queryCategoryInfoByType,
queryCurriculumInfoListType,
removeCurriculumType,
serviceType,
treeCurriculumSkillType,
updateCurriculumType,
editServiceType,
batchUpAndDownWorkServiceType,
deleteServiceType,
serviceDetailType,
} from '~/api/interface/mallManageType';
export class MallManageAPI {
......@@ -32,4 +37,19 @@ export class MallManageAPI {
// 服务-新增
static addService: addServiceType = (data) =>
axios.post('/pms/backstage/work/addWorkService', data);
//服务-编辑
static editService: editServiceType = (data) =>
axios.post('/pms/backstage/work/updateWorkService', data);
// 服务-列表
static getServiceList: serviceType = (data) =>
axios.post('/pms/backstage/work/queryServiceManagerList', data);
// 服务-上下架
static batchUpAndDownWorkService: batchUpAndDownWorkServiceType = (data) =>
axios.post('/pms/backstage/work/batchUpAndDownWorkService', data);
// 服务-删除-批量
static deleteService: deleteServiceType = (data) =>
axios.post('/pms/backstage/work/deleteWorkService', data);
// 服务-详情
static getServiceDetail: serviceDetailType = (params) =>
axios.get('/pms/backstage/work/queryWorkService', { params });
}
......@@ -115,6 +115,8 @@ export const Uploader: React.FC<PropsType> = (props) => {
// 如果有默认文件列表
if (defaultFileList?.length) {
setFileList(defaultFileList);
} else {
setFileList([]);
}
}, [defaultFileList]);
return (
......
import { Button, Form } from 'antd';
import { useNavigate } from 'react-router-dom';
import { useNavigate, useSearchParams } from 'react-router-dom';
import './index.scss';
import { MallManageAPI } from '~/api';
import { useState } from 'react';
import { InterDataType } from '~/api/interface';
import { serviceDetailType } from '~/api/interface/mallManageType';
//服务详情-返回类型
type detailType = InterDataType<serviceDetailType>;
const ServiceDetail = () => {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const [serviceDetail, setServiceDetail] = useState<detailType>();
//服务详情
const getServiceDetail = (id: number) => {
MallManageAPI.getServiceDetail({ id }).then(({ result }) => {
setServiceDetail(result);
});
};
//返回
const backRoute = () => {
navigate(-1);
getServiceDetail(Number(searchParams.get('id')));
};
return (
<div className='service-detail'>
......
import { Button } from 'antd';
import { useNavigate } from 'react-router-dom';
import { useNavigate, useSearchParams } from 'react-router-dom';
import './index.scss';
import { useEffect, useState } from 'react';
import { MallManageAPI } from '~/api';
import RichText from '~/components/richText';
import { InterDataType } from '~/api/interface';
import { serviceDetailType } from '~/api/interface/mallManageType';
//服务详情-返回类型
type detailType = InterDataType<serviceDetailType>;
const ServiceIntroduce = () => {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const [serviceDetail, setServiceDetail] = useState<detailType>();
//服务详情
const getServiceDetail = (id: number) => {
MallManageAPI.getServiceDetail({ id }).then(({ result }) => {
setServiceDetail(result);
});
};
const richTextChange = (text?: string) => {};
//返回
const backRoute = () => {
navigate(-1);
};
useEffect(() => {
getServiceDetail(Number(searchParams.get('id')));
});
return (
<div className='service-introduce'>
<div className='service-introduce-operate'>
......@@ -18,7 +37,9 @@ const ServiceIntroduce = () => {
</Button>
</div>
<div className='service-introduce-title'></div>
<div className='service-introduce-rich-text'></div>
<div className='service-introduce-rich-text'>
<RichText value={serviceDetail.serviceIntroduction} onChange={richTextChange} />
</div>
</div>
);
};
......
import { FC, useState } from 'react';
import { Button, Col, Form, Input, Modal, Row, Select, Upload } from 'antd';
import { FC, useEffect, useState } from 'react';
import { Button, Form, Input, message, Modal, Select } from 'antd';
import { ModalProps } from 'antd';
import { UploadOutlined } from '@ant-design/icons';
import { Uploader } from '~/components/uploader';
import { InterDataType, InterReqType } from '~/api/interface';
import { categoryListType } from '~/api/interface/categoryManage';
import { addServiceType } from '~/api/interface/mallManageType';
import { addServiceType, serviceType } from '~/api/interface/mallManageType';
import { MallManageAPI } from '~/api';
//分类返回类型
type categoryType = InterDataType<categoryListType>['list'];
//服务返回类型
type serviceListType = InterDataType<serviceType>['list'];
interface selfProps {
industryCategoryList: categoryType;
applicationCategoryList: categoryType;
handleOk: () => void;
handleCancel: () => void;
currentServiceData: serviceListType[0] | undefined;
}
//新增服务参数类型
type addServiceParametersType = InterReqType<addServiceType>;
......@@ -19,9 +26,11 @@ type addServiceParametersType = InterReqType<addServiceType>;
const AddOrEditServiceModal: FC<ModalProps & selfProps> = ({
open,
title,
onCancel,
handleCancel,
handleOk,
industryCategoryList,
applicationCategoryList,
currentServiceData,
}) => {
const [form] = Form.useForm<addServiceParametersType>();
//封面图文件
......@@ -94,8 +103,72 @@ const AddOrEditServiceModal: FC<ModalProps & selfProps> = ({
});
setVideoFileList(fileList);
};
const onOk = () => {
form.validateFields().then((value: any) => {
MallManageAPI[currentServiceData ? 'editService' : 'addService']({
id: currentServiceData ? currentServiceData.id : undefined,
...value,
}).then(({ code }) => {
if (code === '200') {
message.success(currentServiceData ? '编辑服务成功' : '新增服务成功');
form.resetFields();
handleOk();
}
});
});
};
const onCancel = () => {
form.resetFields();
handleCancel();
};
useEffect(() => {
if (currentServiceData) {
form.setFieldsValue({
serviceName: currentServiceData.serviceName,
applicationId: currentServiceData.applicationId,
industryId: currentServiceData.industryId,
coverPlan: currentServiceData.coverPlan,
shareCard: currentServiceData.shareCard || undefined,
video: currentServiceData.video || undefined,
displayState: currentServiceData.displayState,
});
setCoverPlanFileList([
{
id: Math.random(),
uid: Math.random(),
url: currentServiceData.coverPlan,
name: 'coverPlan',
},
]);
if (currentServiceData.shareCard) {
setShareCardFileList([
{
id: Math.random(),
uid: Math.random(),
url: currentServiceData.shareCard,
name: 'shareCard',
},
]);
}
if (currentServiceData.video) {
setVideoFileList([
{
id: Math.random(),
uid: Math.random(),
url: currentServiceData.video,
name: 'shareCard',
},
]);
}
} else {
setCoverPlanFileList([]);
setVideoFileList([]);
setShareCardFileList([]);
}
}, [currentServiceData]);
return (
<Modal open={open} title={title} onCancel={onCancel}>
<Modal open={open} title={title} onCancel={onCancel} onOk={onOk}>
<Form
labelCol={{ span: 4 }}
wrapperCol={{ span: 16 }}
......@@ -140,31 +213,37 @@ const AddOrEditServiceModal: FC<ModalProps & selfProps> = ({
name='coverPlan'
rules={[{ required: true, message: '请上传封面图' }]}
>
<Uploader listType='picture-card' fileUpload onChange={coverPlanUploadSuccess}>
<Uploader
listType='picture-card'
fileUpload
onChange={coverPlanUploadSuccess}
defaultFileList={coverPlanFileList}
>
<UploadOutlined />
</Uploader>
</Form.Item>
<Form.Item label='分享卡片' name='shareCard'>
<Uploader listType='picture-card' fileUpload onChange={shareCardUploadSuccess}>
<Uploader
listType='picture-card'
fileUpload
onChange={shareCardUploadSuccess}
defaultFileList={shareCardFileList}
>
<UploadOutlined />
</Uploader>
</Form.Item>
<Form.Item label='视频' name='video'>
<Row>
<Col></Col>
<Col>
<Uploader
listType='text'
fileUpload
onChange={videoUploadSuccess}
fileType={['video/mp4', 'video/avi', 'video/wmv', 'video/rmvb']}
defaultFileList={videoFileList}
>
<Button icon={<UploadOutlined />} size='small' type='primary'>
上传
</Button>
</Uploader>
</Col>
</Row>
</Form.Item>
<Form.Item label='展示状态' name='displayState'>
<Select placeholder='请选择展示状态'>
......
import { FC, useEffect, useState } from 'react';
import React, { FC, useEffect, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { searchColumns } from '~/components/search-box';
import SearchBox from '~/components/search-box';
import AddOrEditServiceModal from './components/addOrEditServiceModal';
import { Button, Card, Table } from 'antd';
import { Button, Card, Image, message, Modal, Table } from 'antd';
import {
PlusOutlined,
ArrowUpOutlined,
......@@ -11,12 +11,17 @@ import {
DeleteOutlined,
} from '@ant-design/icons';
import { ColumnsType } from 'antd/es/table';
import { CategoryManageAPI } from '~/api';
import { InterDataType } from '~/api/interface';
import { CategoryManageAPI, MallManageAPI } from '~/api';
import { InterDataType, InterReqType, PaginationProps } from '~/api/interface';
import { categoryListType } from '~/api/interface/categoryManage';
import { serviceType } from '~/api/interface/mallManageType';
//分类返回类型
type categoryType = InterDataType<categoryListType>['list'];
//服务返回类型
type serviceListType = InterDataType<serviceType>['list'];
//服务列表请求类型
type serviceParametersType = Omit<InterReqType<serviceType>, 'pageSize' | 'pageNo'>;
const ServiceList: FC<any> = () => {
const navigate = useNavigate();
......@@ -40,54 +45,99 @@ const ServiceList: FC<any> = () => {
type: 'input',
placeholder: '请输入服务名称',
label: '服务名称',
name: '',
name: 'serviceName',
},
{
type: 'select',
placeholder: '请选择应用类型',
label: '应用类型',
name: '',
name: 'applicationId',
options: [],
},
{
type: 'select',
placeholder: '请选择对应行业',
label: '对应行业',
name: '',
name: 'industryId',
options: [],
},
]);
const tableColumns: ColumnsType<any> = [
{ title: '序号', align: 'center' },
{ title: '服务名称', align: 'center' },
{ title: '应用', align: 'center' },
{ title: '对应行业', align: 'center' },
{ title: '封面图', align: 'center' },
{ title: '分享卡片', align: 'center' },
{ title: '视频', align: 'center' },
const tableColumns: ColumnsType<serviceListType[0]> = [
{
title: '序号',
align: 'center',
render: (_text: any, _record: any, index: number) =>
(pagination.pageNo - 1) * pagination.pageSize + index + 1,
},
{ title: '服务名称', align: 'center', dataIndex: 'serviceName' },
{ title: '应用', align: 'center', dataIndex: 'applicationName' },
{ title: '对应行业', align: 'center', dataIndex: 'industryName' },
{
title: '封面图',
align: 'center',
dataIndex: 'coverPlan',
render: (text: string) => <Image src={text} width={50} height={50} />,
},
{
title: '分享卡片',
align: 'center',
dataIndex: 'shareCard',
render: (text: string) => (text ? <Image src={text} width={50} height={50} /> : '暂无'),
},
{
title: '视频',
align: 'center',
dataIndex: 'video',
render: (text: string) => (text ? '--' : '暂无'),
},
{
title: '服务介绍',
align: 'center',
render: () => (
<Button type='link' onClick={toServiceIntroduce}>
--
dataIndex: 'serviceIntroduction',
render: (text: string, record) =>
text ? (
'--'
) : (
<Button type='link' onClick={() => toServiceIntroduce(record)}>
查看
</Button>
),
},
{ title: '状态', align: 'center' },
{
title: '状态',
align: 'center',
dataIndex: 'displayState',
render: (text: number) => (text === 0 ? '上架' : '下架'),
},
{
title: '操作',
align: 'center',
render: () => (
render: (_text: any, record) => (
<>
<Button type='link' onClick={toServiceDetail}>
<Button type='link' onClick={() => addOrEditServiceModalShow(record)}>
编辑
</Button>
<Button type='link' onClick={() => toServiceDetail(record)}>
详情
</Button>
</>
),
},
];
const [tableData] = useState<{ id: number }[]>([{ id: 1 }]);
const [loading, setLoading] = useState<boolean>(false);
const [tableData, setTableData] = useState<serviceListType>([]);
const [currentServiceData, setCurrentServiceData] = useState<serviceListType[0]>();
// 表格多选
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [pagination, setPagination] = useState<PaginationProps & { totalCount: number }>({
pageNo: 1,
pageSize: 10,
totalCount: 0,
});
//筛选
const [query, setQuery] = useState<serviceParametersType>({
displayState: undefined,
});
//行业分类列表
const [industryCategoryList, setIndustryCategoryList] = useState<categoryType>([]);
//应用分类列表
......@@ -97,17 +147,39 @@ const ServiceList: FC<any> = () => {
const [addOrEditServiceModalTitle, setAddOrEditServiceModalTitle] = useState<string>('新增服务');
const onTabChange = (key: string) => {
pagination.pageNo = 1;
setQuery({ ...query, displayState: key === '1' ? undefined : key === '2' ? 0 : 1 });
setActiveTabKey(key);
getServiceList({ ...query, displayState: key === '1' ? undefined : key === '2' ? 0 : 1 });
};
//新增服务
const addServiceModalShow = () => {
setAddOrEditServiceModalTitle('新增服务');
const addOrEditServiceModalShow = (record?: serviceListType[0]) => {
setAddOrEditServiceModalTitle(record ? '编辑服务' : '新增服务');
setAddOrEditServiceModalOpen(true);
setCurrentServiceData(record && { ...record });
};
const addOrEditServiceModalCancel = () => {
setAddOrEditServiceModalOpen(false);
};
const addOrEditServiceModalOk = () => {
setAddOrEditServiceModalOpen(false);
getServiceList(query);
};
//服务-列表
const getServiceList = (query?: serviceParametersType) => {
setLoading(true);
MallManageAPI.getServiceList({
pageNo: pagination.pageNo,
pageSize: pagination.pageSize,
...query,
}).then(({ result }) => {
setLoading(false);
setTableData(result.list || []);
pagination.totalCount = result.totalCount;
setPagination(pagination);
});
};
//行业分类列表
const getIndustryCategoryList = () => {
CategoryManageAPI.getCategoryList({ directoryId: 2, pageSize: 99999, pageNo: 1 }).then(
......@@ -137,14 +209,62 @@ const ServiceList: FC<any> = () => {
);
};
//服务详情
const toServiceDetail = () => {
navigate({ pathname: '/mallManage/serviceDetail' });
const toServiceDetail = (record: serviceListType[0]) => {
navigate({ pathname: '/mallManage/serviceDetail', search: `id=${record.id}` });
};
//服务介绍
const toServiceIntroduce = () => {
navigate({ pathname: '/mallManage/serviceIntroduce' });
const toServiceIntroduce = (record: serviceListType[0]) => {
navigate({ pathname: '/mallManage/serviceIntroduce', search: `id=${record.id}` });
};
//上下架
const groundingOrOffService = (status: number) => {
MallManageAPI.batchUpAndDownWorkService({
displayState: status,
ids: selectedRowKeys as number[],
}).then(({ code }) => {
if (code === '200') {
message.success(status ? '下架成功' : '上架成功');
getServiceList(query);
setSelectedRowKeys([]);
}
});
};
//服务删除
const deleteService = () => {
Modal.confirm({
title: '提示',
content: '删除后此数据将会丢失,确定删除吗?',
onOk() {
MallManageAPI.deleteService(selectedRowKeys as number[]).then(({ code }) => {
if (code === '200') {
if (pagination.pageNo !== 1 && tableData.length === 1) {
pagination.pageNo -= 1;
}
message.success('删除成功');
getServiceList(query);
}
});
},
});
};
//分页事件
const paginationChange = (pageNo: number, pageSize: number) => {
pagination.pageNo = pageNo;
pagination.pageSize = pageSize;
getServiceList(query);
};
// 表格多选事件
const onSelectChange = (newSelectedRowKeys: React.Key[]) => {
setSelectedRowKeys(newSelectedRowKeys);
};
//筛选
const searchSuccess = (data: any) => {
pagination.pageNo = 1;
setQuery(data);
getServiceList(data);
};
useEffect(() => {
getServiceList();
getIndustryCategoryList();
getApplicationCategoryList();
}, []);
......@@ -154,32 +274,77 @@ const ServiceList: FC<any> = () => {
<SearchBox
search={searchColumnsData}
child={
<Button type='primary' icon={<PlusOutlined />} onClick={addServiceModalShow}>
<Button
type='primary'
icon={<PlusOutlined />}
onClick={() => addOrEditServiceModalShow()}
>
新增服务
</Button>
}
searchData={searchSuccess}
/>
<Card tabList={tabList} activeTabKey={activeTabKey} onTabChange={onTabChange}>
<div className='header-operate' style={{ marginBottom: '10px' }}>
<Button type='primary' style={{ marginRight: '10px' }} icon={<ArrowUpOutlined />}>
{activeTabKey !== '2' ? (
<Button
type='primary'
style={{ marginRight: '10px' }}
icon={<ArrowUpOutlined />}
onClick={() => groundingOrOffService(0)}
>
上架
</Button>
<Button type='primary' style={{ marginRight: '10px' }} icon={<ArrowDownOutlined />}>
) : (
''
)}
{activeTabKey !== '3' ? (
<Button
type='primary'
style={{ marginRight: '10px' }}
icon={<ArrowDownOutlined />}
onClick={() => groundingOrOffService(1)}
>
下架
</Button>
<Button danger icon={<DeleteOutlined />}>
) : (
''
)}
<Button danger icon={<DeleteOutlined />} onClick={deleteService}>
删除
</Button>
</div>
<Table columns={tableColumns} bordered dataSource={tableData} />
<Table
columns={tableColumns}
loading={loading}
bordered
rowKey='id'
dataSource={tableData}
pagination={{
total: pagination.totalCount,
pageSize: pagination.pageSize,
current: pagination.pageNo,
showSizeChanger: true,
showQuickJumper: true,
onChange: (page: number, pageSize: number) => paginationChange(page, pageSize),
showTotal: (total, range) => `当前 ${range[0]}-${range[1]} 条记录 / 共 ${total} 条数据`,
}}
rowSelection={{
selectedRowKeys,
onChange: onSelectChange,
}}
/>
</Card>
{/*新增/编辑服务弹窗*/}
<AddOrEditServiceModal
open={addOrEditServiceModalOpen}
title={addOrEditServiceModalTitle}
onCancel={addOrEditServiceModalCancel}
handleCancel={addOrEditServiceModalCancel}
industryCategoryList={industryCategoryList}
applicationCategoryList={applicationCategoryList}
handleOk={addOrEditServiceModalOk}
currentServiceData={currentServiceData}
/>
</div>
);
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论