472 lines
19 KiB
TypeScript
472 lines
19 KiB
TypeScript
/*
|
||
* @Author: cclue
|
||
* @Date: 2021-12-13 11:01:23
|
||
* @LastEditTime: 2024-12-16 11:03:30
|
||
* @LastEditors: cclu 1106109051@qq.com
|
||
* @Description: 经营项目列表页面
|
||
* @FilePath: \cloud-platform\src\pages\BussinessProject\list.tsx
|
||
*/
|
||
|
||
// 经营项目管理
|
||
import React from "react";
|
||
import Draggable from "react-draggable";
|
||
import SubMenu from "antd/lib/menu/SubMenu";
|
||
import ProTable from "@ant-design/pro-table";
|
||
import useRequest from "@ahooksjs/use-request";
|
||
|
||
import { useRef, useState } from "react";
|
||
import { PlusOutlined } from "@ant-design/icons";
|
||
import { PageContainer } from "@ant-design/pro-layout";
|
||
import { Button, Col, Drawer, Menu, message, Modal, Popconfirm, Row, Spin, Typography } from "antd";
|
||
import type { ActionType, ProColumns } from "@ant-design/pro-table";
|
||
import type { FormInstance } from 'antd';
|
||
import type { BusinessProjectModel } from "./data";
|
||
import type { ProFormInstance } from "@ant-design/pro-form";
|
||
import type { ServerpartTree } from "@/services/options";
|
||
import type { ContractListModel } from "../contract/data";
|
||
import type { ServerpartShopModel } from "../basicManage/ServerpartShop/data";
|
||
|
||
import { delProject, getProjectDetail, getProjectList, updateProject } from "./service";
|
||
import { getFieldEnum, getServerpartTree } from "@/services/options";
|
||
import { getList as getContractList } from "@/pages/contract/service";
|
||
import { getList as getServerpartShopList } from "@/pages/basicManage/ServerpartShop/service"
|
||
import { contractType } from "../contract/emun";
|
||
|
||
import ProjectEditor from './editor'
|
||
import ProjectDetail from './detail'
|
||
import './style.less'
|
||
import session from "@/utils/session";
|
||
import moment from "moment";
|
||
import PageTitleBox from "@/components/PageTitleBox";
|
||
import { CurrentUser } from "umi";
|
||
// 经营项目管理列表
|
||
|
||
// 列表数据删除功能;函数返回值为布尔型,表示成功或失败
|
||
const handelDelete = async (registerCompactId: number): Promise<boolean> => {
|
||
// 提示正在执行删除消息
|
||
const hide = message.loading('正在删除...');
|
||
try {
|
||
// 同步请求删除数据,等待返回值
|
||
const result = await delProject(registerCompactId);
|
||
// 关闭 提示正在执行删除的消息
|
||
hide();
|
||
// 根据返回值提示用户是否删除成功 并返回对应的布尔值
|
||
if (result.Result_Code !== 100) {
|
||
message.error(`${result.Result_Desc}`);
|
||
return false;
|
||
}
|
||
message.success('删除成功!');
|
||
return true;
|
||
} catch (error) { // 捕获请求异常,若执行则返回失败
|
||
hide();
|
||
message.error('删除失败');
|
||
return false;
|
||
}
|
||
};
|
||
|
||
// 提交新增或编辑的项目数据;函数返回值为布尔型,表示成功或失败
|
||
|
||
/**
|
||
* @description: 生成服务区左侧菜单
|
||
* @param {ServerpartTree[]} data 菜单数据源
|
||
* @param {Function} callback 点击菜单回调函数
|
||
* @return {JSX.Element[]} 返回jsx数据节点集
|
||
*/
|
||
function getMenuDom(data: ServerpartTree[], callback?: Function) {
|
||
// 遍历菜单数据源并返回相应的菜单子父级节点
|
||
return (
|
||
data.map((element: any) => {
|
||
// 判断数据是否为父级菜单 是则返回父级菜单容器并生成包含的子菜单
|
||
if (element.type === 0) {
|
||
|
||
return (
|
||
<SubMenu // 父级菜单andt组件
|
||
title={element.label}
|
||
key={`${element.value}`}
|
||
onTitleClick={(item) => { // 点击父级菜单标题方法 执行传入的回调方法
|
||
callback?.call(callback, item);
|
||
item.domEvent.stopPropagation();
|
||
}}
|
||
>
|
||
{/* 父级菜单有子级存在,则遍历子级数据生成子菜单 */}
|
||
{element.children && element.children.length > 0 && getMenuDom(element.children, callback)}
|
||
</SubMenu>
|
||
);
|
||
}
|
||
// 返回子菜单
|
||
return (
|
||
<Menu.Item key={`${element.value}`}>{element.label}</Menu.Item>); // 子级菜单andt组件
|
||
})
|
||
);
|
||
}
|
||
|
||
// 项目页面主体
|
||
// const ProjecetTable: React.FC = () => {
|
||
const ProjecetTable: React.FC<{ currentUser?: CurrentUser }> = (props) => {
|
||
const serverpartObj = session.get('serverpartObj')
|
||
const { currentUser } = props
|
||
// props
|
||
// useState 为umi封装的hooks方法
|
||
const [currentRow, setCurrentRow] = useState<BusinessProjectModel | any>(undefined) // 选中的当前行
|
||
|
||
const [showDetail, setShowDetail] = useState<boolean>(false) // 是否显示详情
|
||
const [modalVisible, handleModalVisible] = useState<boolean>(false) // 是否显示编辑
|
||
// 经营模式
|
||
const [businessType, setBusinessType] = useState<any>()
|
||
const actionRef = useRef<ActionType>() // 项目列表对象
|
||
const formRef = useRef<FormInstance>() // 项目列表查询对象
|
||
const SETTLEMENTMODESOBJ = session.get('SETTLEMENT_MODESObj')
|
||
const [showLoading, setShowLoading] = useState<boolean>(false)
|
||
// 项目列表 列数据配置
|
||
const columns: ProColumns<BusinessProjectModel>[] = [
|
||
{
|
||
title: '查询项目',
|
||
dataIndex: 'searchKey',
|
||
hideInTable: true,
|
||
hideInDescriptions: true,
|
||
fieldProps: {
|
||
placeholder: "请输入项目/备注/商户名称/门店"
|
||
}
|
||
|
||
},
|
||
{
|
||
title: '项目名称',
|
||
dataIndex: 'BUSINESSPROJECT_NAME',
|
||
ellipsis: true,
|
||
hideInDescriptions: true,
|
||
width: '24%',
|
||
render: (_, record) => {
|
||
return <a onClick={() => { // 点击项目名称时 打开抽屉 展示项目详情
|
||
setCurrentRow(record)
|
||
setShowDetail(true)
|
||
}}>{record.BUSINESSPROJECT_NAME}</a>
|
||
},
|
||
hideInSearch: true,
|
||
sorter: true,
|
||
},
|
||
{
|
||
title: '经营模式',
|
||
dataIndex: 'BUSINESS_TYPE',
|
||
valueType: 'select',
|
||
valueEnum: contractType,
|
||
width: 110,
|
||
align: "center",
|
||
// hideInSearch: true,
|
||
},
|
||
{
|
||
dataIndex: 'SETTLEMENT_MODES',
|
||
title: '结算模式',
|
||
valueType: 'select',
|
||
align: 'center',
|
||
width: 160,
|
||
request: async () => {
|
||
return await getFieldEnum({ FieldExplainField: 'SETTLEMENT_MODES' });
|
||
},
|
||
render: (_, record) => {
|
||
return record?.SWITCH_MODES ? `${SETTLEMENTMODESOBJ[record?.SETTLEMENT_MODES]}-->${SETTLEMENTMODESOBJ[record?.SWITCH_MODES]}` : SETTLEMENTMODESOBJ[record?.SETTLEMENT_MODES]
|
||
}
|
||
},
|
||
{
|
||
dataIndex: 'Period_Count',
|
||
hideInSearch: true,
|
||
title: '项目期数',
|
||
width: 100,
|
||
align: 'right',
|
||
},
|
||
{
|
||
dataIndex: 'Period_AvgAmount',
|
||
hideInSearch: true,
|
||
align: 'right',
|
||
title: '单期均值',
|
||
width: 100,
|
||
},
|
||
{
|
||
title: '项目金额',
|
||
dataIndex: 'GUARANTEE_PRICE',
|
||
valueType: "digit",
|
||
align: 'right',
|
||
sorter: true,
|
||
width: 130,
|
||
hideInSearch: true,
|
||
render: (_) => {
|
||
return <span style={{ paddingRight: 20 }}>{_}</span>
|
||
},
|
||
},
|
||
{
|
||
title: '经营商户',
|
||
dataIndex: 'MERCHANTS_NAME',
|
||
ellipsis: true,
|
||
width: '22%',
|
||
hideInSearch: true,
|
||
sorter: true,
|
||
},
|
||
{
|
||
title: '经营门店',
|
||
dataIndex: 'SERVERPARTSHOP_NAME',
|
||
width: 200,
|
||
hideInSearch: true,
|
||
ellipsis: true,
|
||
},
|
||
{
|
||
title: '开始日期',
|
||
hideInSearch: true,
|
||
dataIndex: 'PROJECT_STARTDATE',
|
||
valueType: 'date',
|
||
align: 'center',
|
||
width: 120,
|
||
sorter: true,
|
||
// defaultSortOrder: 'descend',
|
||
},
|
||
{
|
||
title: '结束日期',
|
||
hideInSearch: true,
|
||
dataIndex: 'PROJECT_ENDDATE',
|
||
valueType: 'date',
|
||
align: 'center',
|
||
width: 120,
|
||
sorter: true,
|
||
},
|
||
{
|
||
title: '项目周期(天)',
|
||
dataIndex: 'PROJECT_DAYS',
|
||
ellipsis: true,
|
||
hideInSearch: true,
|
||
width: '10%',
|
||
hideInTable: true
|
||
},
|
||
{
|
||
dataIndex: 'BUSINESSPROJECT_DESC',
|
||
title: '项目备注',
|
||
width: '20%',
|
||
ellipsis: true,
|
||
hideInSearch: true,
|
||
hideInDescriptions: true
|
||
},
|
||
{
|
||
title: '项目状态',
|
||
dataIndex: 'PROJECT_VALID',
|
||
valueType: 'select',
|
||
initialValue: "1",
|
||
// hideInSearch: true,
|
||
hideInTable: true,
|
||
valueEnum: {
|
||
'0': { text: '无效', status: 'error' },
|
||
'1': { text: '有效', status: 'success' },
|
||
'-1': { text: '待补充', status: 'process' }
|
||
},
|
||
},
|
||
{
|
||
title: '项目到期',
|
||
dataIndex: 'ProjectStateSearch',
|
||
hideInTable: true,
|
||
valueType: 'select',
|
||
valueEnum: {
|
||
"0": "已过期项目",
|
||
"1": "在营项目",
|
||
"2": "三个月到期",
|
||
"3": "半年到期",
|
||
}
|
||
},
|
||
{
|
||
title: '项目类型',
|
||
dataIndex: 'ProjectTypeSearch',
|
||
hideInTable: true,
|
||
valueType: 'select',
|
||
valueEnum: {
|
||
"1": "商铺租赁(有门店)",
|
||
"2": "经营资产(无门店)",
|
||
},
|
||
initialValue: '1'
|
||
},
|
||
{
|
||
title: '服务区',
|
||
dataIndex: "SERVERPART_IDS",
|
||
hideInTable: true,
|
||
valueType: 'select',
|
||
valueEnum: serverpartObj,
|
||
fieldProps: {
|
||
showSearch: true, // 支持输入文字搜索
|
||
filterOption: (input, option) => (option?.label ?? '').toLowerCase().includes(input.toLowerCase()),
|
||
}
|
||
},
|
||
{
|
||
title: '操作人',
|
||
dataIndex: 'STAFF_NAME',
|
||
hideInSearch: true,
|
||
hideInTable: true
|
||
},
|
||
{
|
||
dataIndex: 'OPERATE_DATE',
|
||
title: '更新时间',
|
||
hideInSearch: true,
|
||
hideInTable: true
|
||
},
|
||
{
|
||
title: '操作',
|
||
dataIndex: 'option',
|
||
valueType: 'option',
|
||
hideInDescriptions: true,
|
||
hideInSearch: true,
|
||
width: 90,
|
||
render: (_, record) => {
|
||
return [
|
||
<a onClick={async () => { // 点击编辑 存储当前行数据 并打开编辑弹出框
|
||
// 存在选中行且选中行数据有项目id 则 请求项目详情接口 并赋值给表单
|
||
setShowLoading(true)
|
||
if (record && record.BUSINESSPROJECT_ID) {
|
||
const data = await getProjectDetail(record?.BUSINESSPROJECT_ID)
|
||
/**
|
||
* serverpartId:选择门店弹出框中查询服务区的参数
|
||
* SERVERPART_IDS:服务区内码数组,用在编辑页面显示服务区
|
||
* serverpartShopIds:门店内码数组
|
||
*/
|
||
const current = {
|
||
...data,
|
||
serverpartId: data?.SERVERPART_IDS,
|
||
SERVERPART_IDS: data?.SERVERPART_IDS ? data?.SERVERPART_IDS.split(',').map(Number) : [],
|
||
serverpartShopIds: data?.SERVERPARTSHOP_ID ? data?.SERVERPARTSHOP_ID.split(',').map(Number) : [],
|
||
projectRangeDate: [record?.PROJECT_STARTDATE, record?.PROJECT_ENDDATE]
|
||
}
|
||
formRef.current?.setFieldsValue(current)
|
||
setCurrentRow(current)
|
||
}
|
||
else {
|
||
setCurrentRow(record)
|
||
// 否则 给表单数据赋初始值
|
||
formRef.current?.setFieldsValue({ PROJECT_VALID: 1, MULTIPROJECT_STATE: 0, SEGMENTED_MODE: 1 })
|
||
}
|
||
handleModalVisible(true)
|
||
setShowLoading(false)
|
||
}}>编辑</a>,
|
||
<Popconfirm // 删除按钮功能
|
||
title="确认删除该项目记录吗?"
|
||
onConfirm={async () => {
|
||
const sucesse = await handelDelete(record.BUSINESSPROJECT_ID); // 调用删除数据的方法
|
||
// 判断返回值 返回值若为true 则刷新项目数据
|
||
if (sucesse && actionRef.current) {
|
||
actionRef.current.reload();
|
||
}
|
||
}}
|
||
>
|
||
<a>删除</a>
|
||
</Popconfirm>
|
||
]
|
||
}
|
||
}
|
||
];
|
||
|
||
return (
|
||
<PageContainer
|
||
header={{
|
||
title: '',
|
||
breadcrumb: {},
|
||
}}>
|
||
{
|
||
showLoading ?
|
||
<div
|
||
style={{
|
||
width: '100%',
|
||
height: '100%',
|
||
background: 'rgba(0,0,0,0.1)',
|
||
position: 'fixed',
|
||
zIndex: 2,
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center'
|
||
}}
|
||
>
|
||
<div style={{
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
padding: '15px 20px 10px',
|
||
background: '#fff',
|
||
borderRadius: '8px',
|
||
width: '150px'
|
||
}}>
|
||
<Spin />
|
||
<span style={{ marginLeft: '5px' }}>加载中...</span>
|
||
</div>
|
||
</div> : ''
|
||
}
|
||
{/* 项目页面 表格主体 */}
|
||
<ProTable<BusinessProjectModel>
|
||
headerTitle={<PageTitleBox props={props} />}
|
||
rowKey="BUSINESSPROJECT_ID"
|
||
request={async (params, sorter) => { // 请求项目表格数据 params 查询对象键值对;sorter 排序对象键值对
|
||
if (params.BUSINESS_TYPE) {
|
||
setBusinessType(params.BUSINESS_TYPE)
|
||
} else {
|
||
setBusinessType('')
|
||
}
|
||
// 排序对象键值对 有值 则调整成后台接口需要的数据格式
|
||
const sortstr = Object.keys(sorter).map(n => {
|
||
const value = sorter[n]
|
||
return value ? `${n} ${value.replace('end', '')}` : ''
|
||
})
|
||
console.log('params', params)
|
||
// 发起请求,return 请求返回的数据
|
||
const list = await getProjectList({
|
||
...params,
|
||
SERVERPART_IDS: params?.SERVERPART_IDS || "",
|
||
sortstr: sortstr.length ? sortstr.toString() : params?.sortstr,
|
||
keyWord: params.searchKey ? { key: "BUSINESSPROJECT_NAME,BUSINESSPROJECT_DESC,MERCHANTS_NAME,SERVERPARTSHOP_NAME", value: params.searchKey } : null, // 关键词查询
|
||
pagesize: params.pageSize,
|
||
ProjectStateSearch: params.ProjectStateSearch === "0" || params.ProjectStateSearch === "1" ? params.ProjectStateSearch : '',
|
||
DueDate_End: params.ProjectStateSearch === "2" ? moment().add(3, 'month').format('YYYY-MM-DD') : params.ProjectStateSearch === "3" ? moment().add(6, 'month').format('YYYY-MM-DD') : ''
|
||
})
|
||
console.log('list', list)
|
||
return list
|
||
}}
|
||
actionRef={actionRef} // 表格操作对象
|
||
search={{ span: 6 }} // 查询栏布局配置按照24/6=4份来分割
|
||
columns={columns} // 表格列数据配置
|
||
toolbar={{
|
||
actions: [ // 表格右上角工具栏配置
|
||
<Typography.Text type="secondary">单位:万元</Typography.Text>,
|
||
<Button
|
||
key="new"
|
||
icon={<PlusOutlined />}
|
||
type="primary"
|
||
onClick={() => {
|
||
handleModalVisible(true)
|
||
const current = {
|
||
PROJECT_VALID: 1,
|
||
MULTIPROJECT_STATE: 0,
|
||
SEGMENTED_MODE: 1
|
||
}
|
||
formRef.current?.setFieldsValue(current)
|
||
setCurrentRow(current)
|
||
}}
|
||
>
|
||
项目
|
||
</Button>,
|
||
],
|
||
}}
|
||
pagination={{ defaultPageSize: 10 }} // 翻页默认10条分页
|
||
/>
|
||
|
||
{/* 项目数据编辑弹出框 */}
|
||
<ProjectEditor parentTableRef={actionRef} currentRecord={currentRow} modalVisible={modalVisible} handleModalVisible={handleModalVisible} />
|
||
|
||
{/* 查看项目详情 右侧弹出的抽屉 */}
|
||
<Drawer
|
||
width="80%"
|
||
className="project-drawer"
|
||
visible={showDetail} // 抽屉弹框是否显示状态
|
||
onClose={() => { // 关闭抽屉 则在清空选中行数据 并 设置抽屉状态为关闭
|
||
setCurrentRow(undefined);
|
||
setShowDetail(false);
|
||
}}
|
||
bodyStyle={{ backgroundColor: "#f9f9f9", padding: 0 }}
|
||
closable={false}
|
||
>
|
||
{/* 抽屉打开时 加载项目详情组件 */}
|
||
{showDetail && <ProjectDetail id={currentRow?.BUSINESSPROJECT_ID} businessType={businessType} showType={'edit'}></ProjectDetail>}
|
||
</Drawer>
|
||
</PageContainer>
|
||
);
|
||
}
|
||
|
||
export default ProjecetTable;
|