612 lines
26 KiB
TypeScript
612 lines
26 KiB
TypeScript
// 经营品牌管理
|
||
import { connect } from "umi";
|
||
import type { CurrentUser } from "umi";
|
||
import type { ConnectState } from "@/models/connect";
|
||
import React, { useEffect, useRef, useState } from "react";
|
||
import ProCard from "@ant-design/pro-card";
|
||
import { MenuFoldOutlined } from "@ant-design/icons";
|
||
import type { FormInstance } from "antd";
|
||
import { Avatar, Button, Col, Form, message, Popconfirm, Row, Space, Spin, Tree, TreeSelect } from "antd";
|
||
import useRequest from "@ahooksjs/use-request";
|
||
import { getServerpartTree } from "@/services/options";
|
||
import type { ActionType } from "@ant-design/pro-table";
|
||
import ProTable from "@ant-design/pro-table";
|
||
import ReactHTMLTableToExcel from "react-html-table-to-excel";
|
||
import LeftSelectTree from "@/pages/reports/settlementAccount/component/leftSelectTree";
|
||
import PageTitleBox from "@/components/PageTitleBox";
|
||
import { getBusniessBrandTree } from "../service";
|
||
import { initial } from "lodash";
|
||
import { ModalForm, ProFormDigit, ProFormSelect, ProFormText, ProFormTextArea } from "@ant-design/pro-form";
|
||
import { getList } from "../BusinessTrade/service";
|
||
import { handleAddUpdate, handleDelete, handleGetBrandList } from "./service";
|
||
import { getList as handleGetTradeList } from '../BusinessTrade/service'
|
||
import { exportXlsxFromProColumnsExcelJS } from "@/utils/exportExcelFun";
|
||
import { formatTreeData } from "@/utils/format";
|
||
import moment from 'moment'
|
||
|
||
const operatingBrand: React.FC<{ currentUser: CurrentUser }> = (props) => {
|
||
const { currentUser } = props
|
||
const downloadBtnRef = useRef<any>()
|
||
const actionRef = useRef<ActionType>();
|
||
const formRef = useRef<FormInstance>();
|
||
const [reqDetailList, setReqDetailList] = useState<any>(); // 合计项数据源
|
||
const [printOut, setPrintOut] = useState<any>(); // 打印数据的内容
|
||
const [collapsible, setCollapsible] = useState<boolean>(false)
|
||
const [treeView, setTreeView] = useState<any>()
|
||
const [printIndex, setPrintIndex] = useState<number>(new Date().getTime())
|
||
|
||
const [currentRow, setCurrentRow] = useState<any>();// 当前选中行数据
|
||
// 树相关的属性和方法
|
||
const [selectedId, setSelectedId] = useState<string>()
|
||
// 导出的加载效果
|
||
const [showLoading, setShowLoading] = useState<boolean>(false)
|
||
// 是否显示打印的表格
|
||
const [showExportTable, setShowExportTable] = useState<boolean>(false)
|
||
// 查询的条件
|
||
const [searchParams, setSearchParams] = useState<any>()
|
||
// 导出数据
|
||
const [exportData, setExportData] = useState<any>()
|
||
const [createModalVisible, handleModalVisible] = useState<boolean>(false); // 新建窗口的弹窗
|
||
const [treeSelectOption, setTreeSelectOption] = useState<any[]>(); // 可选择项
|
||
// 业态品牌
|
||
const [businessBrand, setBusinessBrand] = useState<any[]>(); // 业态品牌
|
||
// 所有业态最里层的数据
|
||
const [extractLeafIdsList, setExtractLeafIdsList] = useState<any[]>([]);
|
||
|
||
|
||
const columns: any = [
|
||
{
|
||
title: "品牌图标",
|
||
dataIndex: 'BRAND_INTRO',
|
||
width: 120,
|
||
align: 'center',
|
||
hideInSearch: true,
|
||
hideInDescriptions: true,
|
||
render: (_, record) => {
|
||
return record?.BRAND_INTRO ? <img style={{ width: "90px", height: "90px", borderRadius: '50%' }} src={record?.BRAND_INTRO} /> :
|
||
<Avatar src={_} size={16} shape="square">{record.BRAND_NAME ? record.BRAND_NAME.substring(0, 1) : ''}</Avatar>
|
||
}
|
||
},
|
||
{
|
||
title: "品牌索引",
|
||
dataIndex: "BRAND_INDEX",
|
||
width: 120,
|
||
align: 'center',
|
||
hideInSearch: true,
|
||
ellipisis: true,
|
||
},
|
||
{
|
||
title: "品牌名称",
|
||
dataIndex: "BRAND_NAME",
|
||
width: 120,
|
||
align: 'center',
|
||
hideInSearch: true,
|
||
ellipisis: true,
|
||
},
|
||
{
|
||
title: "经营业态名称",
|
||
dataIndex: "BUSINESSTRADE_NAME",
|
||
width: 120,
|
||
align: 'center',
|
||
hideInSearch: true,
|
||
ellipisis: true,
|
||
},
|
||
{
|
||
title: "有效状态",
|
||
width: 120,
|
||
align: 'center',
|
||
dataIndex: "BRAND_STATE",
|
||
valueType: "select",
|
||
fieldProps: {
|
||
options: [{ label: "有效", value: 1 }, { label: "无效", value: 0 }]
|
||
},
|
||
initialValue: 1,
|
||
},
|
||
|
||
{
|
||
title: '操作',
|
||
width: 120,
|
||
dataIndex: 'option',
|
||
valueType: 'option',
|
||
align: 'center',
|
||
hideInDescriptions: true,
|
||
render: (_, record) => record?.BRAND_ID ? [
|
||
<a
|
||
key="edit"
|
||
onClick={() => {
|
||
setCurrentRow(record);
|
||
handleModalVisible(true);
|
||
}}
|
||
>
|
||
编辑
|
||
</a>,
|
||
<Popconfirm title="确认删除该品牌?" onConfirm={async () => {
|
||
|
||
const sucesse = await handleDelete({ BrandId: record.BRAND_ID })
|
||
if (sucesse && actionRef.current) {
|
||
actionRef.current.reload()
|
||
}
|
||
}}>
|
||
<a>删除</a>
|
||
</Popconfirm>
|
||
] : ""
|
||
}
|
||
]
|
||
|
||
const exportColumns: any = [
|
||
{
|
||
title: <div style={{ textAlign: 'center' }}>经营业态</div>,
|
||
dataIndex: 'Business_Format',
|
||
align: 'center',
|
||
hideInSearch: true,
|
||
},
|
||
{
|
||
title: <div style={{ textAlign: 'center' }}>品牌名称</div>,
|
||
dataIndex: 'BusinessTrade_Name',
|
||
align: 'center',
|
||
hideInSearch: true,
|
||
},
|
||
]
|
||
|
||
const exportTable = (e) => {
|
||
e.stopPropagation(); // 防止Collapse组件收起
|
||
const main = document.getElementsByClassName(`saleReportHideBox${printIndex}`)[0]
|
||
const thead = main.querySelector('thead').cloneNode(true); // 深克隆DOM节点
|
||
const tbody = main.querySelector('tbody').cloneNode(true); // 深克隆DOM节点
|
||
const container = document.querySelector('#hiddenBox');
|
||
|
||
const tempTable = document.createElement('table');
|
||
tempTable.appendChild(thead);
|
||
tempTable.appendChild(tbody);
|
||
|
||
tempTable.setAttribute('id', 'table-to-xls-operatingBrand'); // 给table添加id,值与按钮上的table字段对应
|
||
|
||
container.appendChild(tempTable); // 把创建的节点添加到页面容器中
|
||
|
||
setShowLoading(false)
|
||
|
||
downloadBtnRef.current.handleDownload();
|
||
setShowExportTable(false)
|
||
tempTable.remove() // 防止重复打印一个内容
|
||
}
|
||
|
||
useEffect(async () => {
|
||
// 拿到经营品牌数据
|
||
await handleGetBusinessTrade();
|
||
|
||
|
||
}, [])
|
||
|
||
const normalizeTreeChildren = (list: any[]): any[] => {
|
||
return list.map((node: any) => {
|
||
// 复制节点,防止修改原始数据
|
||
const newNode = { ...node };
|
||
|
||
// 可能存在两种字段:BrandTreeList / children
|
||
const subList = newNode.children || newNode.BrandTreeList;
|
||
|
||
if (Array.isArray(subList) && subList.length > 0) {
|
||
// 递归处理子节点
|
||
newNode.children = normalizeTreeChildren(subList);
|
||
} else {
|
||
// ✅ 空数组改为 null
|
||
newNode.children = null;
|
||
}
|
||
|
||
// 删除旧字段
|
||
delete newNode.BrandTreeList;
|
||
|
||
return newNode;
|
||
});
|
||
};
|
||
|
||
// 拿到经营业态的数据
|
||
const handleGetBusinessTrade = async () => {
|
||
const data: any = await handleGetTradeList({ BusinessTradeModelPID: -1, BusinessTradeState: 1 })
|
||
console.log('handleGetBusinessTradehandleGetBusinessTrade', data);
|
||
setBusinessBrand(data.data)
|
||
setExtractLeafIdsList(extractLeafIds(data.data))
|
||
setTreeSelectOption(markNonLeafDisabled([{ AUTOSTATISTICS_NAME: '默认', AUTOSTATISTICS_ID: -1, children: [...data.data] }]))
|
||
}
|
||
|
||
// 拿到全部最里层的 业态值
|
||
const extractLeafIds = (data: any) => {
|
||
const result: any = [];
|
||
|
||
const traverse = (list: any) => {
|
||
list.forEach((item: any) => {
|
||
if (!item.children || item.children.length === 0) {
|
||
// 没有 children,就是最里层节点
|
||
result.push(item.AUTOSTATISTICS_ID);
|
||
} else {
|
||
// 有 children,继续递归
|
||
traverse(item.children);
|
||
}
|
||
});
|
||
}
|
||
|
||
traverse(data);
|
||
return result;
|
||
}
|
||
|
||
// 不是没有children 都禁用
|
||
const markNonLeafDisabled = (list: any) => {
|
||
return list.map((node: any) => {
|
||
const hasChildren = Array.isArray(node.children) && node.children.length > 0;
|
||
// 复制原节点,添加 disabled 字段(只有非叶子节点 disabled)
|
||
const newNode = {
|
||
...node,
|
||
// 如果你更喜欢使用 selectable 而不是 disabled,可用: selectable: !hasChildren
|
||
disabled: hasChildren ? true : undefined,
|
||
};
|
||
if (hasChildren) {
|
||
newNode.children = markNonLeafDisabled(node.children);
|
||
}
|
||
return newNode;
|
||
});
|
||
}
|
||
|
||
|
||
return (
|
||
<div ref={(el) => {
|
||
// 打印报表
|
||
if (!reqDetailList || reqDetailList.length === 0) return;
|
||
setPrintOut(el);
|
||
}} >
|
||
|
||
{
|
||
showLoading ?
|
||
<div
|
||
style={{
|
||
width: '100%',
|
||
height: '100%',
|
||
background: 'rgba(0,0,0,0.1)',
|
||
position: 'fixed',
|
||
zIndex: 5,
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center'
|
||
}}
|
||
>
|
||
<div style={{
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
padding: '15px 20px 10px',
|
||
background: '#fff',
|
||
borderRadius: '8px',
|
||
width: '200px'
|
||
}}>
|
||
<Spin />
|
||
<span style={{ marginLeft: '5px' }}>数据导出中...</span>
|
||
</div>
|
||
</div> : ''
|
||
}
|
||
|
||
<div className={`saleReportHideBox${printIndex}`} style={{ position: 'fixed', zIndex: -1, top: 0, left: 0 }}>
|
||
{
|
||
showExportTable && exportData && exportData.length > 0 ?
|
||
<ProTable
|
||
columns={exportColumns}
|
||
dataSource={exportData}
|
||
pagination={false}
|
||
expandable={{
|
||
defaultExpandAllRows: true
|
||
}}
|
||
/> : ''
|
||
}
|
||
</div>
|
||
<div id='hiddenBox' style={{ position: 'fixed', zIndex: -1, top: 0, left: 0 }} />
|
||
|
||
<div style={{ backgroundColor: '#fff', display: 'flex' }}>
|
||
<ProCard
|
||
style={{ width: !collapsible ? "300px" : "60px" }}
|
||
className="pageTable-leftnav"
|
||
bodyStyle={{ padding: 0, paddingTop: 20, paddingLeft: 20, width: !collapsible ? "300px" : "60px" }}
|
||
extra={<MenuFoldOutlined onClick={() => {
|
||
setCollapsible(!collapsible);
|
||
}} />}
|
||
colSpan={!collapsible ? "300px" : "60px"}
|
||
title={!collapsible ? "请选择业态" : ""}
|
||
headerBordered
|
||
collapsed={collapsible}
|
||
>
|
||
{businessBrand && businessBrand.length > 0 ? <Tree
|
||
checkable
|
||
treeData={[{
|
||
AUTOSTATISTICS_NAME: '全部',
|
||
value: 0,
|
||
AUTOSTATISTICS_ID: '0-0',
|
||
children: businessBrand
|
||
}]}
|
||
blockNode
|
||
defaultExpandAll={true}
|
||
defaultExpandedKeys={['0-0']}
|
||
onCheck={(checkedKeys: React.Key[] | any, info) => {
|
||
let res: any = []
|
||
if (checkedKeys && checkedKeys.length > 0) {
|
||
if (extractLeafIdsList && extractLeafIdsList.length > 0) {
|
||
checkedKeys.forEach((item: any) => {
|
||
if (extractLeafIdsList.indexOf(item) > -1) {
|
||
res.push(item);
|
||
}
|
||
})
|
||
}
|
||
}
|
||
setSelectedId(res)
|
||
}}
|
||
fieldNames={{
|
||
title: "AUTOSTATISTICS_NAME",
|
||
key: "AUTOSTATISTICS_ID"
|
||
}}
|
||
/> : ''}
|
||
</ProCard>
|
||
|
||
|
||
<div style={{
|
||
width: !collapsible ? 'calc(100% - 300px)' : 'calc(100% - 60px)',
|
||
paddingTop: 0,
|
||
paddingBottom: 0,
|
||
paddingRight: 0
|
||
}}>
|
||
<ProTable
|
||
actionRef={actionRef}
|
||
formRef={formRef}
|
||
columns={columns}
|
||
rowKey={(record) => {
|
||
return `${record?.BusinessTrade_Id}`
|
||
}}
|
||
bordered
|
||
expandable={{
|
||
expandRowByClick: true
|
||
}}
|
||
scroll={{ x: "100%", y: "calc(100vh - 410px)" }}
|
||
headerTitle={<PageTitleBox props={props} />} // 列表表头
|
||
search={{ span: 6 }}
|
||
request={async (params) => {
|
||
if (!selectedId) {
|
||
return { data: [], success: true }
|
||
}
|
||
const req: any = {
|
||
SearchParameter: {
|
||
BRAND_CATEGORY: 1000,
|
||
BRAND_INDUSTRYS: selectedId && selectedId.length > 0 ? selectedId.toString() : '',
|
||
BRAND_STATE: params.BRAND_STATE || "",
|
||
},
|
||
PageIndex: 1,
|
||
PageSize: 999999
|
||
}
|
||
const data = await handleGetBrandList(req)
|
||
console.log('handleGetBrandListhandleGetBrandList', data);
|
||
if (data && data.length > 0) {
|
||
|
||
|
||
let fieldData: any = []
|
||
|
||
let enumList: any = ["BRAND_STATE",]
|
||
let newPrintData: any = formatTreeData(JSON.parse(JSON.stringify(data)), fieldData, enumList, [[{ label: "有效", value: 1 }, { label: "无效", value: 0 }]], [])
|
||
|
||
setReqDetailList(newPrintData)
|
||
return { data: data, success: true }
|
||
}
|
||
|
||
// const req: any = {
|
||
// ProvinceCode: currentUser?.ProvinceCode,
|
||
// BrandState: 1
|
||
// }
|
||
// setSearchParams(params)
|
||
// const data = await getBusniessBrandTree(req)
|
||
// if (data && data.length > 0) {
|
||
// let exportData: any = []
|
||
|
||
// data.forEach((item: any) => {
|
||
// exportData.push({
|
||
// Business_Format: item.BusinessTrade_Name,
|
||
// BusinessTrade_Name: ""
|
||
// })
|
||
// if (item.children && item.children.length > 0) {
|
||
// item.children.forEach((subItem: any) => {
|
||
// exportData.push({
|
||
// Business_Format: item.BusinessTrade_Name,
|
||
// BusinessTrade_Name: subItem.BusinessTrade_Name,
|
||
// })
|
||
// })
|
||
// }
|
||
// })
|
||
// setExportData(exportData)
|
||
// console.log('datadatadata', data);
|
||
|
||
// let res: any = normalizeTreeChildren(data)
|
||
// console.log(res, 'res');
|
||
|
||
// return { data: res, success: true }
|
||
// }
|
||
setReqDetailList([])
|
||
return { data: [], success: true }
|
||
}}
|
||
toolbar={{
|
||
actions: [
|
||
// <span style={{ visibility: 'hidden' }}>
|
||
// <ReactHTMLTableToExcel
|
||
// buttonText={'导出excel'}
|
||
// ref={downloadBtnRef}
|
||
// table="table-to-xls-operatingBrand"
|
||
// filename={`经营品牌列表`}
|
||
// sheet="sheet1"
|
||
// />
|
||
// </span>,
|
||
<Button
|
||
key="new"
|
||
type="primary"
|
||
onClick={(e) => {
|
||
if (reqDetailList && reqDetailList.length > 0) {
|
||
// 尝试一下 导出新方法
|
||
exportXlsxFromProColumnsExcelJS(columns.slice(0, columns.length - 1),
|
||
reqDetailList,
|
||
`经营品牌列表`,
|
||
{
|
||
footerMaker: currentUser?.Name,
|
||
footerMakerTime: moment().format('YYYY-MM-DD HH:mm:ss'),
|
||
footerStatsTime: ""
|
||
}
|
||
)
|
||
} else {
|
||
message.error('暂无数据可导出!')
|
||
}
|
||
|
||
// if (exportData && exportData.length > 0) {
|
||
// setShowLoading(true)
|
||
// setTimeout(() => {
|
||
// setShowExportTable(true)
|
||
// setTimeout(() => {
|
||
// exportTable(e)
|
||
// }, 100)
|
||
// }, 100)
|
||
// } else {
|
||
// message.error('暂无数据可导出!')
|
||
// }
|
||
}}
|
||
>
|
||
导出excel
|
||
</Button>,
|
||
<Button
|
||
key="new"
|
||
type="primary"
|
||
onClick={(e) => {
|
||
handleModalVisible(true)
|
||
}}
|
||
>
|
||
新增品牌
|
||
</Button>
|
||
]
|
||
}}
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
{ /* 更新 信息弹出框 */}
|
||
<ModalForm
|
||
layout={'horizontal'}
|
||
wrapperCol={{ span: 16 }}
|
||
labelCol={{ span: 6 }}
|
||
width={600}
|
||
title={currentRow ? '更新经营业态' : '新建经营业态'}
|
||
visible={createModalVisible}
|
||
formRef={formRef}
|
||
onVisibleChange={(value) => {
|
||
handleModalVisible(value)
|
||
if (!value) {
|
||
formRef.current?.resetFields();
|
||
setCurrentRow(undefined);
|
||
} else {
|
||
formRef.current?.setFieldsValue(currentRow || { AUTOSTATISTICS_TYPE: 2000 })
|
||
|
||
}
|
||
}}
|
||
onFinish={async (values) => {
|
||
let newValue: any = { ...values }
|
||
|
||
if (currentRow) { // 编辑数据
|
||
newValue = { ...currentRow, ...newValue }
|
||
}
|
||
newValue.AUTOSTATISTICS_STATE = values.AUTOSTATISTICS_STATE ? 1 : 0
|
||
newValue.AUTOSTATISTICS_TYPE = currentRow?.AUTOSTATISTICS_TYPE || 2000
|
||
const success = await handleAddUpdate(newValue);
|
||
|
||
if (success) {
|
||
if (actionRef.current) {
|
||
actionRef.current.reload();
|
||
}
|
||
return true
|
||
|
||
}
|
||
return false
|
||
}}
|
||
>
|
||
<Row>
|
||
<Col span={24}>
|
||
<Form.Item
|
||
name="BRAND_INDUSTRY"
|
||
label="上级业态"
|
||
rules={[{ required: true, message: '请选择上级业态' }]}
|
||
>
|
||
<TreeSelect
|
||
placeholder="请选择上级业态"
|
||
dropdownStyle={{ maxHeight: 300, overflow: 'auto' }}
|
||
treeDefaultExpandAll
|
||
showArrow={false}
|
||
showSearch
|
||
treeData={treeSelectOption}
|
||
fieldNames={{
|
||
label: 'AUTOSTATISTICS_NAME',
|
||
value: 'AUTOSTATISTICS_ID',
|
||
}}
|
||
filterTreeNode={(input, node) =>
|
||
String(node.AUTOSTATISTICS_NAME)
|
||
.toLowerCase()
|
||
.includes(String(input).toLowerCase())
|
||
}
|
||
/>
|
||
</Form.Item>
|
||
<ProFormText
|
||
name="BRAND_NAME"
|
||
label="品牌名称"
|
||
placeholder="请输入品牌名称"
|
||
rules={[
|
||
{
|
||
required: true,
|
||
message: '请输入品牌名称',
|
||
},
|
||
]} />
|
||
|
||
<ProFormDigit
|
||
name="BRAND_INDEX"
|
||
label="品牌索引"
|
||
placeholder="请输入品牌索引"
|
||
min={0}
|
||
max={9999}
|
||
rules={[
|
||
{
|
||
required: true,
|
||
message: '请输入品牌索引',
|
||
},
|
||
]}
|
||
fieldProps={{ precision: 0 }}
|
||
/>
|
||
|
||
<ProFormSelect
|
||
name="BRAND_CATEGORY"
|
||
label="品牌类型"
|
||
rules={[
|
||
{
|
||
required: true,
|
||
message: '请选择品牌类型',
|
||
},
|
||
]}
|
||
options={[{ label: '经营品牌', value: 1000 }]}
|
||
initialValue={1000}
|
||
// , { label: '商城品牌', value: 2000 }
|
||
/>
|
||
|
||
<ProFormSelect
|
||
name="BRAND_STATE"
|
||
label="是否有效"
|
||
options={[{ label: '有效', value: 1 }, { label: '无效', value: 0 }]}
|
||
initialValue={1}
|
||
/>
|
||
<ProFormTextArea
|
||
name="BRAND_DESC"
|
||
label="品牌介绍"
|
||
placeholder="请输入介绍" />
|
||
</Col>
|
||
</Row>
|
||
</ModalForm>
|
||
</div>
|
||
)
|
||
}
|
||
|
||
export default connect(({ user }: ConnectState) => ({
|
||
currentUser: user.currentUser
|
||
}))(operatingBrand);
|