123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- import React, { useContext, useState } from 'react';
- import style from '../../index.less';
- import { App, Button, Empty, Space, Upload } from 'antd';
- import useNewToken from '@/Hook/useNewToken';
- import SettingsUserInherit from './settingsUserlnherit';
- import dayjs from 'dayjs';
- import { getUserInDataData, headerJsMustStyle, headerJsStyle, TIME_TYPE } from '../../const';
- import ExcelJS from 'exceljs';
- import { saveAs } from 'file-saver';
- import FilterUserText from '@/pages/weComTask/components/filterUser/filterUserText';
- import { RcFile } from 'antd/es/upload';
- import { groupBy, readFileAsBuffer } from '@/utils/utils';
- import PreviewUserInherit from './previewUserlnherit';
- import { DispatchTaskCreate } from '../..';
- /**
- * 客户继承
- * @returns
- */
- const UserInherit: React.FC = () => {
- /***************************************************/
- const { token } = useNewToken()
- const { message } = App.useApp()
- const { setSettings, settings, bookPlatForm, bookList, onPreviewReset } = useContext(DispatchTaskCreate)!;
- const [newVisible, setNewVisible] = React.useState(false);
- const [downloadLoading, setDownloadLoading] = useState<boolean>(false)
- /***************************************************/
- // 导出Excel
- const exportExcel = async () => {
- setDownloadLoading(true)
- const workbook = new ExcelJS.Workbook(); // 创建空工作簿
- const worksheet = workbook.addWorksheet('Sheet1'); // 添加工作表
- const headerRowIndex = 1; // 表头行索引
- // 表头冻结
- worksheet.views = [
- {
- state: 'frozen',
- ySplit: 1, // 冻结行数
- topLeftCell: 'A2' // 冻结后可见区域的起始单元格
- }
- ];
- // 设置全局禁止
- worksheet.protect('yourPwd', {
- deleteColumns: false, // 禁止删除列
- sort: false, // 禁止排序
- autoFilter: false // 禁止自动筛选
- });
- worksheet.columns = [
- { key: 'A1', width: 30, header: '账号(原跟进企微号)' },
- { key: 'A2', width: 20, header: '继承标题' },
- { key: 'A3', width: 30, header: '策略信息' },
- { key: 'A4', width: 50, header: '继承对象' },
- { key: 'A5', width: 40, header: '继承后文本内容' },
- { key: 'A6', width: 30, header: '接替客户企微号' },
- { key: 'A7', width: 30, header: '接替客户企微号ID' },
- ];
- // 表头设置样式
- worksheet.getRow(headerRowIndex).height = 30;
- Array(7).fill(0).forEach((_, index) => {
- const col = index + 1; // 从第1列开始
- // 设置表头字体样式
- worksheet.getCell(headerRowIndex, col).style = index >= 5 ? headerJsMustStyle as any : headerJsStyle as any;
- })
- const userInData = getUserInDataData(settings?.userInherit?.schedulingStrategyDTO, settings?.userInherit?.taskName)
- const corpUserListLength = settings?.corpUsers?.length || 0;
- const dataLength = userInData.length || 0;
- // 解放填写限制区域
- const unLockArea = [];
- let dataRow = 1
- // 数据内容
- settings?.corpUsers?.forEach((item, i) => {
- userInData.forEach((dataItem, ii) => {
- unLockArea.push(`${dataRow}_6`)
- unLockArea.push(`${dataRow}_7`)
- dataRow++;
- worksheet.addRow([
- // 账号
- `${item.name}(ID:${item.corpUserId})`,
- // 继承标题
- `${dataItem?.taskName}`,
- // 策略信息
- {
- richText: [
- { text: `(策略${dataItem?.strategyIndex})\n`, font: { bold: true } },
- { text: `名称:${dataItem?.strategyData?.strategyName || '<空>'}\n` },
- {
- text: (`执行类型:${TIME_TYPE[dataItem?.strategyData?.timeRepeatType]}\n`) +
- (dataItem?.strategyData?.sendDay ? `执行时间:${dataItem?.strategyData?.sendDay}\n` : '') +
- (dataItem?.strategyData?.startTime ? `执行日期:${dataItem?.strategyData?.startTime}~${dataItem?.strategyData?.endTime ? dataItem?.strategyData?.endTime : '长期执行'}\n` : '') +
- (dataItem?.strategyData?.sendTime ? '执行时间:' + dataItem?.strategyData?.sendTime + '\n' : '') +
- (dataItem?.strategyData?.repeatArray ? `执行天数:${dataItem?.strategyData?.repeatArray.join('、')}\n` : '')
- }
- ]
- },
- // 转移对象
- {
- richText: [
- { text: `(转移对象${dataItem?.inheritIndex})\n`, font: { bold: true } },
- {
- text: `类型:${dataItem?.inheritData?.transferType === 'all' ? '全部' : '指定'}\n` +
- (dataItem?.inheritData?.transferType === 'specify' && dataItem?.inheritData?.transferUserDto ? FilterUserText({
- data: dataItem?.inheritData?.transferUserDto?.configContent,
- configName: dataItem?.inheritData?.transferUserDto?.configName,
- bookCityList: bookPlatForm?.map(item => ({ label: item.platformName, value: item.platformKey })),
- bookPlatForm,
- bookList
- }) : '')
- }
- ]
- },
- // 成功发送内容
- dataItem.inheritData?.transferSuccessMsg || '<空>',
- // 图文链接
- '请输入',
- // 小程序APPID
- '请输入'
- ])
- })
- })
- console.log('userInData', userInData)
- Array(corpUserListLength * dataLength).fill(0).forEach((_, index) => {
- worksheet.getRow(index + headerRowIndex + 1).height = 100; // 设置行高
- worksheet.getRow(index + headerRowIndex + 1).alignment = {
- vertical: 'middle',
- wrapText: true
- }
- // 分组设置背景色
- if (index % (dataLength * 2) < dataLength) {
- worksheet.getRow(index + headerRowIndex + 1).eachCell(function (cell, rowNumber) {
- if (rowNumber <= 8) {
- cell.border = {
- top: { style: 'thin', color: { argb: 'D4D4D4' } },
- bottom: { style: 'thin', color: { argb: 'D4D4D4' } },
- left: { style: 'thin', color: { argb: 'D4D4D4' } },
- right: { style: 'thin', color: { argb: 'D4D4D4' } }
- }
- cell.fill = {
- type: 'pattern',
- pattern: 'solid',
- fgColor: { argb: 'f0f0f0' }
- }
- }
- })
- } else {
- worksheet.getRow(index + headerRowIndex + 1).eachCell(function (cell, rowNumber) {
- if (rowNumber <= 8) {
- cell.border = {
- top: { style: 'thin', color: { argb: 'D4D4D4' } },
- bottom: { style: 'thin', color: { argb: 'D4D4D4' } },
- left: { style: 'thin', color: { argb: 'D4D4D4' } },
- right: { style: 'thin', color: { argb: 'D4D4D4' } }
- }
- }
- })
- }
- })
- // 设置可填写区域
- for (let rowNum = 1; rowNum <= corpUserListLength * dataLength; rowNum++) {
- for (let colNum = 1; colNum <= 3; colNum++) {
- if (unLockArea.includes(`${rowNum}_${colNum + 5}`)) {
- const cell = worksheet.getCell(rowNum + 1, colNum + 5);
- cell.protection = { locked: false };
- cell.fill = {
- type: 'pattern',
- pattern: 'solid',
- fgColor: { argb: 'ffadd2' }
- }
- }
- }
- }
- // 生成文件内容
- const buffer = await workbook.xlsx.writeBuffer();
- // 通过 Blob 下载
- const blob = new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
- saveAs(blob, `客户继承配置_${dayjs().format('YYYYMMDDHHmmss')}.xlsx`);
- setTimeout(() => setDownloadLoading(false), 100)
- }
- // 读取Excel
- const readExcelContent = async (file: RcFile) => {
- const buffer: any = await readFileAsBuffer(file);
- const workbook = new ExcelJS.Workbook();
- await workbook.xlsx.load(buffer); // 加载 Excel 内容
- const worksheet = workbook.worksheets[0]; // 获取第一个工作表
- const data = [];
- worksheet.eachRow((row) => {
- const rowData = {};
- row.eachCell((cell, colNumber) => {
- if (cell.isHyperlink) {
- rowData[`col${colNumber}`] = cell.text || '';
- } else {
- rowData[`col${colNumber}`] = cell.value || '';
- }
- });
- data.push(rowData);
- });
- data.shift(); // 删除表头
- const NULLDATA = ['请输入', '']
- if (data?.some(item => (NULLDATA.includes(item.col6) || !item?.col6 || NULLDATA.includes(item.col7) || !item?.col7))) {
- message.error('请正确填写Excel内容!')
- return
- }
- const msgData = getUserInDataData(settings?.userInherit?.schedulingStrategyDTO, settings?.userInherit?.taskName)
- console.log('读取的Excel数据', data, msgData)
- if (msgData.length * settings?.corpUsers?.length !== data?.length) {
- message.error('数量对不上,请正确填写Excel内容!')
- return
- }
- const groupData = groupBy(data, (item) => [item['col1']]).reduce((acc, cur) => {
- const id = cur[0]['col1'].split('ID:')[1].replace(/\)$/, '');
- acc[id] = cur
- return acc;
- }, {});
- const corpUsers = settings?.corpUsers?.map(item => {
- const externalUserTransferContent = []
- groupData[item.corpUserId]?.forEach((i: any) => {
- const strategyIndex = i.col3.richText[0].text.split('(策略')[1]?.split(')')[0]
- const sendDataIndex = i.col4.richText[0].text.split('(转移对象')[1]?.split(')')[0]
- const layer1 = strategyIndex - 1;
- if (!externalUserTransferContent[layer1]) externalUserTransferContent[layer1] = []; // 初始化第二层
- externalUserTransferContent[strategyIndex - 1][sendDataIndex - 1] = {
- corpUserName: i.col6 === '<空>' ? undefined : i.col6?.toString()?.trim(),
- corpUserId: i.col7 === '<空>' ? undefined : i.col7?.toString()?.trim()
- }
- })
- console.log('内容--->', externalUserTransferContent)
- return {
- ...item,
- externalUserTransferContent
- }
- })
- console.log('corpUsers', corpUsers)
- setSettings({
- ...settings,
- corpUsers
- })
- }
- return <>
- <div className={`${style.settingsBody_content_row}`}>
- <div className={`${style.settingsBody_content_col}`}>
- <div className={style.title}>
- <span>客户继承</span>
- {(settings?.userInherit && Object.keys(settings?.userInherit)?.length) && <Space>
- <Button
- type="link"
- style={{ padding: 0, fontSize: 12 }}
- loading={downloadLoading}
- onClick={() => { exportExcel() }}
- >下载</Button>
- <Upload
- accept={'.xlsx'}
- action="#"
- showUploadList={false}
- customRequest={() => { }}
- beforeUpload={async (file: RcFile): Promise<any> => {
- readExcelContent(file)
- onPreviewReset()
- }}
- >
- <Button
- type="link"
- style={{ padding: 0, fontSize: 12 }}
- >{settings?.corpUsers?.every(item => item?.externalUserTransferContent?.length) ? 'Excel内容已上传,重新上传' : '上传Excel'}</Button>
- </Upload>
- <Button
- type="link"
- danger
- style={{ padding: 0, fontSize: 12 }}
- onClick={() => {
- const corpUsers = settings?.corpUsers?.map(item => {
- delete item?.externalUserTransferContent
- return item
- })
- setSettings({
- ...settings,
- corpUsers,
- userInherit: undefined
- })
- onPreviewReset()
- }}
- >清空</Button>
- </Space>}
- </div>
- <div className={style.detail}>
- <div className={style.detail_title}>客户继承配置</div>
- <div className={style.detail_body}>
- {settings?.userInherit && Object.keys(settings?.userInherit).length > 0 ? <>
- <PreviewUserInherit userInherit={settings?.userInherit} />
- </> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
- </div>
- </div>
- <div className={style.detail_footer}>
- <Button type="link" style={{ padding: 0, fontSize: 12, color: token.colorPrimary }} onClick={() => setNewVisible(true)}>编辑</Button>
- </div>
- </div>
- </div>
- {/* 新增客户继承模板 */}
- {newVisible && <SettingsUserInherit
- visible={newVisible}
- value={settings?.userInherit}
- onChange={(values) => {
- setSettings({
- ...settings,
- userInherit: values
- })
- setNewVisible(false)
- onPreviewReset()
- }}
- onClose={() => {
- setNewVisible(false)
- }}
- />}
- </>
- };
- export default React.memo(UserInherit);
|