|
@@ -1,14 +1,8 @@
|
|
|
import React, { useContext, useState } from 'react';
|
|
import React, { useContext, useState } from 'react';
|
|
|
import style from '../../index.less';
|
|
import style from '../../index.less';
|
|
|
-import { App, Button, Empty, Space, Upload } from 'antd';
|
|
|
|
|
|
|
+import { Button, Empty, Space } from 'antd';
|
|
|
import SettingsWelcome from './settingsWelcome';
|
|
import SettingsWelcome from './settingsWelcome';
|
|
|
-import { businessPlanData, headerJsMustStyle, headerJsStyle, welcomeContentData } from '../../const';
|
|
|
|
|
import useNewToken from '@/Hook/useNewToken';
|
|
import useNewToken from '@/Hook/useNewToken';
|
|
|
-import { saveAs } from 'file-saver';
|
|
|
|
|
-import ExcelJS from 'exceljs';
|
|
|
|
|
-import dayjs from 'dayjs';
|
|
|
|
|
-import { RcFile } from 'antd/es/upload';
|
|
|
|
|
-import { groupBy, readFileAsBuffer } from '@/utils/utils';
|
|
|
|
|
import PreviewWelcome from './previewWelcome';
|
|
import PreviewWelcome from './previewWelcome';
|
|
|
import { DispatchTaskCreate } from '../..';
|
|
import { DispatchTaskCreate } from '../..';
|
|
|
|
|
|
|
@@ -19,276 +13,18 @@ import { DispatchTaskCreate } from '../..';
|
|
|
const Welcome: React.FC = () => {
|
|
const Welcome: React.FC = () => {
|
|
|
|
|
|
|
|
/***************************************************/
|
|
/***************************************************/
|
|
|
- const { message } = App.useApp()
|
|
|
|
|
const { token } = useNewToken()
|
|
const { token } = useNewToken()
|
|
|
- const { setSettings, settings, bookPlatForm, bookList, onPreviewReset } = useContext(DispatchTaskCreate)!;
|
|
|
|
|
- const { welcomeName, welcomeMsgTagDTO, sendMode, mediaContentList } = settings?.welcomeMsgTemplateDTO || {}
|
|
|
|
|
|
|
+ const { setSettings, settings, bookPlatForm, bookList, onPreviewReset, isEditSc } = useContext(DispatchTaskCreate)!;
|
|
|
const [newVisible, setNewVisible] = useState<boolean>(false);
|
|
const [newVisible, setNewVisible] = useState<boolean>(false);
|
|
|
- const [downloadLoading, setDownloadLoading] = useState<boolean>(false)
|
|
|
|
|
/***************************************************/
|
|
/***************************************************/
|
|
|
|
|
|
|
|
- const exportExcel = async () => {
|
|
|
|
|
- setDownloadLoading(true)
|
|
|
|
|
- const workbook = new ExcelJS.Workbook(); // 创建空工作簿:ml-citation{ref="1,7" data="citationList"}
|
|
|
|
|
- const worksheet = workbook.addWorksheet('Sheet1'); // 添加工作表:ml-citation{ref="1,8" data="citationList"}
|
|
|
|
|
- const headerRowIndex = 1; // 表头行索引
|
|
|
|
|
-
|
|
|
|
|
- // 表头冻结
|
|
|
|
|
- worksheet.views = [
|
|
|
|
|
- {
|
|
|
|
|
- state: 'frozen',
|
|
|
|
|
- ySplit: 1, // 冻结行数
|
|
|
|
|
- topLeftCell: 'A2' // 冻结后可见区域的起始单元格
|
|
|
|
|
- }
|
|
|
|
|
- ];
|
|
|
|
|
-
|
|
|
|
|
- // 设置全局禁止
|
|
|
|
|
- worksheet.protect('yourPwd', {
|
|
|
|
|
- deleteColumns: false, // 禁止删除列
|
|
|
|
|
- sort: false, // 禁止排序
|
|
|
|
|
- autoFilter: false // 禁止自动筛选:ml-citation{ref="5,7" data="citationList"}
|
|
|
|
|
- });
|
|
|
|
|
-
|
|
|
|
|
- worksheet.columns = [
|
|
|
|
|
- { key: 'A1', width: 20, header: '账号' },
|
|
|
|
|
- { key: 'A2', width: 20, header: '欢迎语标题' },
|
|
|
|
|
- { key: 'A3', width: 30, header: '智能标签' },
|
|
|
|
|
- { key: 'A4', width: 18, header: '内容组发送模式' },
|
|
|
|
|
- { key: 'A5', width: 70, header: '欢迎语内容' },
|
|
|
|
|
- { key: 'A6', width: 30, header: '图文链接' },
|
|
|
|
|
- { key: 'A7', width: 30, header: '小程序APPID' },
|
|
|
|
|
- { key: 'A8', width: 30, header: '小程序路径' },
|
|
|
|
|
- ];
|
|
|
|
|
-
|
|
|
|
|
- // 表头设置样式
|
|
|
|
|
- worksheet.getRow(headerRowIndex).height = 30;
|
|
|
|
|
- Array(8).fill(0).forEach((_, index) => {
|
|
|
|
|
- const col = index + 1; // 从第1列开始
|
|
|
|
|
- // 设置表头字体样式
|
|
|
|
|
- worksheet.getCell(headerRowIndex, col).style = index >= 5 ? headerJsMustStyle as any : headerJsStyle as any;
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- const corpUserListLength = settings?.corpUsers?.length || 0;
|
|
|
|
|
- const mediaContentLength = mediaContentList?.length || 0;
|
|
|
|
|
- // 合并单元集合
|
|
|
|
|
- const mergeCells = [];
|
|
|
|
|
- // 解放填写限制区域
|
|
|
|
|
- const unLockArea = [];
|
|
|
|
|
- let dataRow = 1
|
|
|
|
|
- // 数据内容
|
|
|
|
|
- settings?.corpUsers?.forEach((item, i) => {
|
|
|
|
|
- const startRow = 2 + (i * mediaContentLength)
|
|
|
|
|
- const endRow = startRow + mediaContentLength - 1
|
|
|
|
|
- mergeCells.push({
|
|
|
|
|
- startRow,
|
|
|
|
|
- startColumn: 1,
|
|
|
|
|
- endRow,
|
|
|
|
|
- endColumn: 1,
|
|
|
|
|
- })
|
|
|
|
|
- mergeCells.push({
|
|
|
|
|
- startRow,
|
|
|
|
|
- startColumn: 2,
|
|
|
|
|
- endRow,
|
|
|
|
|
- endColumn: 2,
|
|
|
|
|
- })
|
|
|
|
|
- mergeCells.push({
|
|
|
|
|
- startRow,
|
|
|
|
|
- startColumn: 3,
|
|
|
|
|
- endRow,
|
|
|
|
|
- endColumn: 3,
|
|
|
|
|
- })
|
|
|
|
|
- mergeCells.push({
|
|
|
|
|
- startRow,
|
|
|
|
|
- startColumn: 4,
|
|
|
|
|
- endRow,
|
|
|
|
|
- endColumn: 4,
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- mediaContentList?.forEach((mediaItem, index) => {
|
|
|
|
|
- let linkPlaceholder = '<空>'
|
|
|
|
|
- let miniprogramPlaceholder = '<空>'
|
|
|
|
|
-
|
|
|
|
|
- const contentRichText = mediaItem.map(item => {
|
|
|
|
|
- switch (item.mediaType) {
|
|
|
|
|
- case 'link':
|
|
|
|
|
- linkPlaceholder = '请输入'
|
|
|
|
|
- return { text: `链接:${item.linkTitle}_${item.linkDesc}\n`, font: { color: { argb: "FF0000" } } }
|
|
|
|
|
- case 'miniprogram':
|
|
|
|
|
- miniprogramPlaceholder = '请输入'
|
|
|
|
|
- return { text: `小程序:${item.miniprogramTitle}\n`, font: { color: { argb: "FF0000" } } }
|
|
|
|
|
- case 'file':
|
|
|
|
|
- return { text: `文件:${item.fileUrl}\n` }
|
|
|
|
|
- case 'video':
|
|
|
|
|
- return { text: `视频:${item.videoUrl}\n` }
|
|
|
|
|
- case 'image':
|
|
|
|
|
- return { text: `图片:${item.imageUrl}\n` }
|
|
|
|
|
- case 'text':
|
|
|
|
|
- return { text: `文本:${item.textContent}\n` }
|
|
|
|
|
- default:
|
|
|
|
|
- return { text: `该类型没有请联系管理员` }
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- const richText = {
|
|
|
|
|
- richText: [
|
|
|
|
|
- { text: `内容${index + 1}:\n` },
|
|
|
|
|
- ...contentRichText
|
|
|
|
|
- ]
|
|
|
|
|
- }
|
|
|
|
|
- if (linkPlaceholder !== '<空>') {
|
|
|
|
|
- unLockArea.push(`${dataRow}_6`)
|
|
|
|
|
- }
|
|
|
|
|
- if (miniprogramPlaceholder !== '<空>') {
|
|
|
|
|
- unLockArea.push(`${dataRow}_7`, `${dataRow}_8`)
|
|
|
|
|
- }
|
|
|
|
|
- console.log(dataRow)
|
|
|
|
|
- dataRow++;
|
|
|
|
|
- worksheet.addRow([
|
|
|
|
|
- // 账号
|
|
|
|
|
- `${item.name}(ID:${item.corpUserId})`,
|
|
|
|
|
- // 欢迎语标题
|
|
|
|
|
- `${welcomeName}`,
|
|
|
|
|
- // 智能标签
|
|
|
|
|
- `${welcomeMsgTagDTO?.business ? `业务:${businessPlanData.find(i => i.value === welcomeMsgTagDTO.business)?.label}` : '--'}\r\n${welcomeMsgTagDTO?.bookCity ? `书城;${bookPlatForm.find(i => i.id === welcomeMsgTagDTO.bookCity)?.platformName}` : '--'}\r\n${welcomeMsgTagDTO?.product ? `产品:${bookList.find(i => i.id === welcomeMsgTagDTO.product)?.bookName}` : '--'}`,
|
|
|
|
|
- // 内容组发送模式
|
|
|
|
|
- welcomeContentData.find(i => i.value === sendMode)?.label,
|
|
|
|
|
- // 欢迎语内容
|
|
|
|
|
- richText,
|
|
|
|
|
- // 图文链接
|
|
|
|
|
- linkPlaceholder,
|
|
|
|
|
- // 小程序APPID
|
|
|
|
|
- miniprogramPlaceholder,
|
|
|
|
|
- // 小程序路径
|
|
|
|
|
- miniprogramPlaceholder
|
|
|
|
|
- ])
|
|
|
|
|
- })
|
|
|
|
|
- })
|
|
|
|
|
- Array(corpUserListLength * mediaContentLength).fill(0).forEach((_, index) => {
|
|
|
|
|
- worksheet.getRow(index + headerRowIndex + 1).height = 100; // 设置行高
|
|
|
|
|
- worksheet.getRow(index + headerRowIndex + 1).alignment = {
|
|
|
|
|
- vertical: 'middle',
|
|
|
|
|
- wrapText: true
|
|
|
|
|
- }
|
|
|
|
|
- // 分组设置背景色
|
|
|
|
|
- if (index % (mediaContentLength * 2) < mediaContentLength) {
|
|
|
|
|
- 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' } }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- // 合并单元格
|
|
|
|
|
- mergeCells.forEach(({ startRow, startColumn, endRow, endColumn }) => {
|
|
|
|
|
- worksheet.mergeCells(startRow, startColumn, endRow, endColumn); // 合并单元格
|
|
|
|
|
- })
|
|
|
|
|
- // 设置可填写区域
|
|
|
|
|
- for (let rowNum = 1; rowNum <= corpUserListLength * mediaContentLength; 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) => {
|
|
|
|
|
- console.log(file)
|
|
|
|
|
- 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 || NULLDATA.includes(item.col8) || !item?.col8))) {
|
|
|
|
|
- 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 welcomeMsgContent = groupData[item.corpUserId]?.map((i: any) => {
|
|
|
|
|
- return {
|
|
|
|
|
- linkUrl: i.col6 === '<空>' ? undefined : i.col6?.toString()?.trim(),
|
|
|
|
|
- miniprogramAppid: i.col7 === '<空>' ? undefined : i.col7?.toString()?.trim(),
|
|
|
|
|
- miniprogramPage: i.col8 === '<空>' ? undefined : i.col8?.toString()?.trim(),
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
- return {
|
|
|
|
|
- ...item,
|
|
|
|
|
- welcomeMsgContent
|
|
|
|
|
- }
|
|
|
|
|
- })
|
|
|
|
|
-
|
|
|
|
|
- setSettings({
|
|
|
|
|
- ...settings,
|
|
|
|
|
- corpUsers
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
return <>
|
|
return <>
|
|
|
<div className={`${style.settingsBody_content_row}`}>
|
|
<div className={`${style.settingsBody_content_row}`}>
|
|
|
<div className={`${style.settingsBody_content_col}`} style={{ width: '100%' }}>
|
|
<div className={`${style.settingsBody_content_col}`} style={{ width: '100%' }}>
|
|
|
<div className={style.title}>
|
|
<div className={style.title}>
|
|
|
<span>欢迎语</span>
|
|
<span>欢迎语</span>
|
|
|
|
|
|
|
|
- {(settings?.welcomeMsgTemplateDTO && Object.keys(settings?.welcomeMsgTemplateDTO).length > 0) && <Space>
|
|
|
|
|
|
|
+ {(settings?.welcomeMsgTemplateDTO && Object.keys(settings?.welcomeMsgTemplateDTO).length > 0 && !isEditSc) && <Space>
|
|
|
<Button
|
|
<Button
|
|
|
type="link"
|
|
type="link"
|
|
|
danger
|
|
danger
|
|
@@ -320,7 +56,7 @@ const Welcome: React.FC = () => {
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
<div className={style.detail_footer}>
|
|
<div className={style.detail_footer}>
|
|
|
- <Button type="link" style={{ padding: 0, fontSize: 12, color: token.colorPrimary }} size="small" onClick={() => setNewVisible(true)}>编辑</Button>
|
|
|
|
|
|
|
+ <Button type="link" style={{ padding: 0, fontSize: 12 }} size="small" onClick={() => setNewVisible(true)}>编辑</Button>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
|
</div>
|
|
</div>
|
|
@@ -329,6 +65,7 @@ const Welcome: React.FC = () => {
|
|
|
{newVisible && <SettingsWelcome
|
|
{newVisible && <SettingsWelcome
|
|
|
visible={newVisible}
|
|
visible={newVisible}
|
|
|
value={settings?.welcomeMsgTemplateDTO}
|
|
value={settings?.welcomeMsgTemplateDTO}
|
|
|
|
|
+ isEditSc={isEditSc}
|
|
|
onClose={() => {
|
|
onClose={() => {
|
|
|
setNewVisible(false)
|
|
setNewVisible(false)
|
|
|
}}
|
|
}}
|