作者 202304001

聊天页面上传文件

... ... @@ -16,9 +16,8 @@ import {
} from "echarts/charts";
import { CanvasRenderer } from "echarts/renderers";
import { useRef, useEffect, useState } from "react";
import { ChartComponentProps, ChartData } from "./getChartData";
import { ChartComponentProps, ChartData, ValueItem } from "./getChartData";
// 注册必要的组件
echarts.use([
GridComponent,
TooltipComponent,
... ... @@ -40,15 +39,17 @@ const tabList = [
{ key: "line", label: "折线图" },
];
// 图表配置生成器
const getOption = (type: string, data: ChartData): EChartsOption => {
const commonOption = {
title: { text: `${tabList.find((t) => t.key === type)?.label}` },
tooltip: { trigger: "item" },
};
// 提取数值数组
const values = data.values.map((item) => item.value);
const getValue = (item: number | ValueItem): number =>
typeof item === "number" ? item : item.value;
const getItemStyle = (item: number | ValueItem) =>
typeof item === "object" ? item.itemStyle : undefined;
switch (type) {
case "bar":
... ... @@ -56,7 +57,22 @@ const getOption = (type: string, data: ChartData): EChartsOption => {
...commonOption,
xAxis: { type: "category", data: data.categories },
yAxis: { type: "value" },
series: [{ data: values, type: "bar" }],
series: [
{
data: data.values,
type: "bar",
itemStyle: {
color: (params) => {
const dataItem = params.data as ValueItem | number;
if (typeof dataItem === "object" && dataItem.itemStyle?.color) {
return dataItem.itemStyle.color;
}
// 返回一个默认颜色,比如 ECharts 默认色系中的颜色
return "#5470c6";
},
},
},
],
};
case "pie":
return {
... ... @@ -64,9 +80,10 @@ const getOption = (type: string, data: ChartData): EChartsOption => {
series: [
{
type: "pie",
data: data.categories.map((name, i) => ({
name,
value: values[i],
data: data.values.map((item, i) => ({
name: data.categories[i],
value: getValue(item),
itemStyle: getItemStyle(item),
})),
radius: "50%",
},
... ... @@ -79,15 +96,25 @@ const getOption = (type: string, data: ChartData): EChartsOption => {
yAxis: { type: "value" },
series: [
{
data: values,
data: data.values.map(getValue),
type: "line",
smooth: true,
areaStyle: {},
itemStyle: {
color: (params) => {
const dataItem = params.data as ValueItem | number;
if (typeof dataItem === "object" && dataItem.itemStyle?.color) {
return dataItem.itemStyle.color;
}
// 返回一个默认颜色,比如 ECharts 默认色系中的颜色
return "#5470c6";
},
},
},
],
};
default:
return {};
return commonOption;
}
};
... ... @@ -101,30 +128,31 @@ export function ChartComponent({
useEffect(() => {
if (!chartRef.current) return;
// 数据校验
if (
!data?.categories?.length ||
!data?.values?.length ||
data.values.some((item) => typeof item.value !== "number")
data.values.some(
(item) =>
typeof item !== "number" &&
(typeof (item as ValueItem).value !== "number" ||
((item as ValueItem).itemStyle &&
typeof (item as ValueItem).itemStyle?.color !== "string")),
)
) {
console.warn("Invalid chart data");
return;
}
// 销毁旧实例
if (chartInstance.current) {
chartInstance.current.dispose();
}
// 初始化新图表
chartInstance.current = echarts.init(chartRef.current);
chartInstance.current.setOption(getOption(activeTabKey, data));
// 窗口resize监听
const resizeHandler = () => chartInstance.current?.resize();
window.addEventListener("resize", resizeHandler);
// 清理函数
return () => {
window.removeEventListener("resize", resizeHandler);
chartInstance.current?.dispose();
... ... @@ -133,7 +161,7 @@ export function ChartComponent({
return (
<Card
style={{ width: "100%", minHeight: 400 }}
style={{ width: "auto", minHeight: 400 }}
tabList={tabList}
activeTabKey={activeTabKey}
onTabChange={setActiveTabKey}
... ... @@ -145,6 +173,7 @@ export function ChartComponent({
width: "100%",
height: 400,
minHeight: 400,
alignItems: "center",
}}
/>
</Card>
... ...
... ... @@ -7,21 +7,21 @@ export interface ValueItem {
export interface ChartData {
categories: string[];
values: ValueItem[];
values: Array<number | ValueItem>;
}
export interface ChartComponentProps {
data: {
categories: string[];
values: ValueItem[];
values: Array<number | ValueItem>;
};
}
export function extractDataFromText(text: string): ChartComponentProps | null {
const startMarkers = ["```javascript", "```json"];
const startMarkers = ["```javascript", "```json", "```typescript"];
let dataStartIndex = -1;
let markerLength = 0;
// 查找有效的数据块起始标记
for (const marker of startMarkers) {
const index = text.indexOf(marker);
if (index !== -1) {
... ... @@ -33,20 +33,16 @@ export function extractDataFromText(text: string): ChartComponentProps | null {
let parsedData: any = null;
// 如果找到有效数据块
if (dataStartIndex !== -1) {
// 查找数据块结束标记
const dataEndIndex = text.indexOf("```", dataStartIndex + markerLength);
if (dataEndIndex !== -1) {
// 提取并清理数据块内容
const dataBlock = text
.slice(dataStartIndex + markerLength, dataEndIndex)
.trim()
.replace(/'/g, '"') // 转换单引号为双引号
.replace(/(\w+)(?=\s*:)/g, '"$1"'); // 为键添加双引号
.replace(/'/g, '"')
.replace(/(\w+)(?=\s*:)/g, '"$1"');
try {
// 尝试安全解析数据块内容
parsedData = JSON.parse(dataBlock);
} catch (error) {
return null;
... ... @@ -54,11 +50,9 @@ export function extractDataFromText(text: string): ChartComponentProps | null {
}
}
// 如果没有找到数据块,尝试将整个文本解析为 ChartData
if (!parsedData) {
try {
const potentialData: any = JSON.parse(text);
// 验证解析后的数据是否符合 ChartData 结构
if (
potentialData &&
Array.isArray(potentialData.categories) &&
... ... @@ -66,32 +60,33 @@ export function extractDataFromText(text: string): ChartComponentProps | null {
Array.isArray(potentialData.values) &&
potentialData.values.every(
(v: any) =>
typeof v?.value === "number" &&
v?.itemStyle &&
typeof v.itemStyle?.color === "string",
typeof v === "number" ||
(typeof v?.value === "number" &&
(v.itemStyle === undefined ||
typeof v.itemStyle?.color === "string")),
)
) {
parsedData = potentialData;
}
} catch (error) {
return null; // 如果解析失败,返回 null
return null;
}
}
// 如果成功解析了数据并且符合 ChartData 类型,返回
if (
parsedData &&
Array.isArray(parsedData.categories) &&
Array.isArray(parsedData.values) &&
parsedData.values.every(
(v: any) =>
typeof v?.value === "number" &&
v?.itemStyle &&
typeof v.itemStyle?.color === "string",
typeof v === "number" ||
(typeof v?.value === "number" &&
(v.itemStyle === undefined ||
typeof v.itemStyle?.color === "string")),
)
) {
return { data: parsedData as ChartData };
}
return null; // 如果未满足条件,则返回 null
return null;
}
... ...
@import "../styles/animation.scss";
.disabled {
opacity: 0.5;
cursor: not-allowed !important;
pointer-events: none; /* 可选,禁用所有鼠标事件 */
}
.message-file{
align-items: center;
padding: 6px 12px;
background-color: var(--white);
border: 1px solid rgba(136, 136, 136, 0.2);
border-radius: 5px;
}
.attach-file {
position: absolute;
left: 30px;
bottom: 32px;
display: flex;
align-items: center;
padding: 6px 12px;
background-color: var(--white);
border: 1px solid rgba(136, 136, 136, 0.2);
border-radius: 5px;
cursor: default;
gap: 8px;
&:hover .delete-file {
opacity: 1;
}
}
.file-name {
max-width: 200px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.delete-file {
opacity: 0;
transition: opacity 0.2s ease;
cursor: pointer;
display: flex;
padding: 4px;
border-radius: 4px;
&:hover {
background-color: rgba(0, 0, 0, 0.1);
}
}
.attach-images {
position: absolute;
left: 30px;
... ... @@ -655,9 +709,6 @@
min-height: 68px;
}
.chat-input:focus {
}
.chat-input-send {
background-color: var(--primary);
color: white;
... ...
... ... @@ -54,6 +54,7 @@ import ExcelIcon from "../icons/excel.svg";
import WordIcon from "../icons/word.svg";
import MindIcon from "../icons/mind.svg";
import PptIcon from "../icons/ppt.svg";
import FileIcon from "../icons/file.svg";
import {
BOT_HELLO,
... ... @@ -135,9 +136,10 @@ import clsx from "clsx";
import { getAvailableClientsCount, isMcpEnabled } from "../mcp/actions";
//20250317新增
import { toExcel } from "../utils/excelAndWordUtils/export2Excel";
import { getExcelData, toExcel } from "../utils/excelAndWordUtils/export2Excel";
import { exportWord } from "../utils/excelAndWordUtils/word";
import { getMindPrompt } from "../utils/prompt";
import { message } from "antd";
const localStorage = safeLocalStorage();
const ttsPlayer = createTTSPlayer();
... ... @@ -436,6 +438,7 @@ export function ChatAction(props: {
text: string;
icon: JSX.Element;
onClick: () => void;
disabled?: boolean;
}) {
const iconRef = useRef<HTMLDivElement>(null);
const textRef = useRef<HTMLDivElement>(null);
... ... @@ -444,6 +447,8 @@ export function ChatAction(props: {
icon: 16,
});
const { disabled = false } = props;
function updateWidth() {
if (!iconRef.current || !textRef.current) return;
const getWidth = (dom: HTMLDivElement) => dom.getBoundingClientRect().width;
... ... @@ -457,8 +462,13 @@ export function ChatAction(props: {
return (
<div
className={clsx(styles["chat-input-action"], "clickable")}
className={clsx(
styles["chat-input-action"],
!disabled && "clickable",
disabled && styles["disabled"],
)}
onClick={() => {
if (disabled) return;
props.onClick();
setTimeout(updateWidth, 1);
}}
... ... @@ -523,6 +533,7 @@ function useScrollToBottom(
}
export function ChatActions(props: {
uploadFile: () => void;
uploadImage: () => void;
setAttachImages: (images: string[]) => void;
setUploading: (uploading: boolean) => void;
... ... @@ -660,6 +671,11 @@ export function ChatActions(props: {
/>
)}
<ChatAction
onClick={props.uploadFile}
text="上传文件"
icon={props.uploading ? <LoadingButtonIcon /> : <FileIcon />}
/>
<ChatAction
onClick={nextTheme}
text={Locale.Chat.InputActions.Theme[theme]}
icon={
... ... @@ -1135,10 +1151,15 @@ function _Chat() {
const doSubmit = (userInput: string) => {
if (userInput.trim() === "" && isEmpty(attachImages)) return;
if (fileData) {
userInput = fileData + userInput;
}
const matchCommand = chatCommands.match(userInput);
if (matchCommand.matched) {
setUserInput("");
setPromptHints([]);
setFileData("");
setFileName("");
matchCommand.invoke();
return;
}
... ... @@ -1148,7 +1169,10 @@ function _Chat() {
.then(() => setIsLoading(false));
setAttachImages([]);
chatStore.setLastInput(userInput);
setUserInput("");
setFileData("");
setFileName("");
setPromptHints([]);
if (!isMobileScreen) inputRef.current?.focus();
setAutoScroll(true);
... ... @@ -1584,6 +1608,7 @@ function _Chat() {
);
async function uploadImage() {
if (fileData) return;
const images: string[] = [];
images.push(...attachImages);
... ... @@ -1744,7 +1769,40 @@ function _Chat() {
function toPowerpoint(pptMessage: string) {
navigate("/powerpoint", { state: { msg: true, pptMessage: pptMessage } });
}
//20250402新增上传文件
const [fileData, setFileData] = useState("");
const [fileName, setFileName] = useState("");
async function uploadFile() {
// 创建一个隐藏的文件输入框
const fileInput = document.createElement("input");
fileInput.type = "file";
fileInput.accept = ".xlsx, .xls";
fileInput.multiple = false;
fileInput.onchange = (event: Event) => {
const target = event.target as HTMLInputElement;
const files = target.files;
if (files && files.length > 0) {
const file = files[0]; // 获取第一个文件
getExcelData(file)
.then((data) => {
const value = `'''filedata
${file.name}
${JSON.stringify(data)}
'''filedata
`;
setFileData(value);
setFileName(file.name);
console.log(value);
})
.catch((error) => {
message.error("上传失败");
});
}
fileInput.remove();
};
fileInput.click();
}
return (
<>
<div className={styles.chat} key={session.id}>
... ... @@ -1992,7 +2050,7 @@ function _Chat() {
</>
)} */}
<ChatAction
text={Locale.Chat.Actions.Excel}
text={Locale.Export.Excel}
icon={<ExcelIcon />}
onClick={() =>
toExcel(
... ... @@ -2005,7 +2063,7 @@ function _Chat() {
) && (
<>
<ChatAction
text={Locale.Chat.Actions.Word}
text={Locale.Export.Word}
icon={<WordIcon />}
onClick={() =>
exportWord(
... ... @@ -2014,7 +2072,7 @@ function _Chat() {
}
/>
<ChatAction
text={Locale.Chat.Actions.Mind}
text={Locale.Export.Mind.title}
icon={<MindIcon />}
onClick={() => {
toMind(
... ... @@ -2026,7 +2084,7 @@ function _Chat() {
</>
)}
<ChatAction
text={Locale.Chat.Actions.Ppt}
text={Locale.Export.Ppt}
icon={<PptIcon />}
onClick={() =>
toPowerpoint(
... ... @@ -2168,6 +2226,7 @@ function _Chat() {
/>
<ChatActions
uploadFile={uploadFile}
uploadImage={uploadImage}
setAttachImages={setAttachImages}
setUploading={setUploading}
... ... @@ -2193,7 +2252,7 @@ function _Chat() {
<label
className={clsx(styles["chat-input-panel-inner"], {
[styles["chat-input-panel-inner-attach"]]:
attachImages.length !== 0,
attachImages.length !== 0 || fileName,
})}
htmlFor="chat-input"
>
... ... @@ -2238,6 +2297,20 @@ function _Chat() {
})}
</div>
)}
{fileName && (
<div className={styles["attach-file"]}>
<span className={styles["file-name"]}>{fileName}</span>
<div
className={styles["delete-file"]}
onClick={() => {
setFileData("");
setFileName("");
}}
>
<DeleteIcon />
</div>
</div>
)}
<IconButton
icon={<SendWhiteIcon />}
text={Locale.Chat.Send}
... ...
... ... @@ -27,7 +27,7 @@ import clsx from "clsx";
import { ChartComponentProps, extractDataFromText } from "./chart/getChartData";
import { ChartComponent } from "./chart";
import styles from "./chat.module.scss";
export function Mermaid(props: { code: string }) {
const ref = useRef<HTMLDivElement>(null);
const [hasError, setHasError] = useState(false);
... ... @@ -110,16 +110,11 @@ export function PreCode(props: { children: any }) {
useEffect(() => {
if (ref.current) {
const textContent = ref.current.innerText;
if (textContent) {
console.log("有textContent");
console.log(textContent);
const data = extractDataFromText(textContent);
console.log(data);
if (data) {
console.log("data");
setChartData(data);
}
}
textContent &&
extractDataFromText(textContent) &&
setChartData(extractDataFromText(textContent));
const codeElements = ref.current.querySelectorAll(
"code",
) as NodeListOf<HTMLElement>;
... ... @@ -281,11 +276,138 @@ function tryWrapHtmlCode(text: string) {
},
);
}
// 首先定义完善的类型
type FileMatch = {
fullMatch: string;
fileName: string;
start: number;
end: number;
};
function _MarkDownContent(props: { content: string }) {
const escapedContent = useMemo(() => {
return tryWrapHtmlCode(escapeBrackets(props.content));
}, [props.content]);
type TextSegment = {
type: "text";
content: string;
start: number;
end: number;
};
type ElementSegment = {
type: "element";
node: React.ReactElement;
};
type Segment = TextSegment | ElementSegment;
// 将子节点转换为可分析的段落段
function parseChildrenToSegments(children: React.ReactNode): Segment[] {
const segments: Segment[] = [];
let textBuffer = "";
let globalIndex = 0;
React.Children.forEach(children, (child) => {
if (typeof child === "string") {
// 合并连续文本节点
textBuffer += child;
globalIndex += child.length;
} else {
// 遇到非文本节点时,先提交缓冲的文本
if (textBuffer) {
segments.push({
type: "text",
content: textBuffer,
start: globalIndex - textBuffer.length,
end: globalIndex,
});
textBuffer = "";
}
// 记录元素节点
segments.push({
type: "element",
node: child as React.ReactElement,
});
}
});
// 提交最后缓冲的文本
if (textBuffer) {
segments.push({
type: "text",
content: textBuffer,
start: globalIndex - textBuffer.length,
end: globalIndex,
});
}
return segments;
}
// 主处理函数
function CustomParagraph({ children }: { children: React.ReactNode }) {
const segments = parseChildrenToSegments(children);
const fullText = segments
.filter((s): s is TextSegment => s.type === "text")
.map((s) => s.content)
.join("");
const regex = /'''filedata\s+([^\n]+)[\s\S]*?'''filedata/g;
const matches: Array<{
fileName: string;
start: number;
end: number;
}> = [];
let match;
while ((match = regex.exec(fullText)) !== null) {
matches.push({
fileName: match[1].trim(),
start: match.index,
end: match.index + match[0].length,
});
}
const newChildren: React.ReactNode[] = [];
let lastPos = 0;
let currentSegmentIndex = 0;
matches.forEach((match) => {
while (currentSegmentIndex < segments.length) {
const segment = segments[currentSegmentIndex];
if (segment.type === "element") {
newChildren.push(segment.node);
currentSegmentIndex++;
continue;
}
const segmentEnd = segment.end;
if (segmentEnd <= match.start) {
newChildren.push(segment.content.slice(lastPos - segment.start));
lastPos = segmentEnd;
currentSegmentIndex++;
} else {
break;
}
}
newChildren.push(
<div key={`file-${match.start}`} className={styles["message-file"]}>
<span>{match.fileName}</span>
</div>,
);
lastPos = match.end;
});
while (currentSegmentIndex < segments.length) {
const segment = segments[currentSegmentIndex];
if (segment.type === "element") {
newChildren.push(segment.node);
} else {
newChildren.push(segment.content.slice(lastPos - segment.start));
}
currentSegmentIndex++;
}
return <p dir="auto">{newChildren}</p>;
}
return (
<ReactMarkdown
remarkPlugins={[RemarkMath, RemarkGfm, RemarkBreaks]}
... ... @@ -302,7 +424,7 @@ function _MarkDownContent(props: { content: string }) {
components={{
pre: PreCode,
code: CustomCode,
p: (pProps) => <p {...pProps} dir="auto" />,
p: CustomParagraph,
a: (aProps) => {
const href = aProps.href || "";
if (/\.(aac|mp3|opus|wav)$/.test(href)) {
... ...
... ... @@ -160,13 +160,13 @@ export function WritingPage() {
)}
<ChatAction
text={Locale.Chat.Actions.Pdf}
text={Locale.Export.Pdf}
icon={<PdfIcon />}
onClick={() => {}}
/>
{htmlCode && (
<ChatAction
text={Locale.Chat.Actions.Word}
text={Locale.Export.Word}
icon={<WordIcon />}
onClick={() => {
exportWord(htmlCode);
... ... @@ -174,17 +174,18 @@ export function WritingPage() {
/>
)}
<ChatAction
text={Locale.Chat.Actions.Excel}
text={Locale.Export.Excel}
icon={<ExcelIcon />}
onClick={() => {}}
disabled={true}
/>
<ChatAction
text={Locale.Chat.Actions.Ppt}
text={Locale.Export.Ppt}
icon={<PptIcon />}
onClick={() => {}}
/>
<ChatAction
text={Locale.Chat.Actions.Mind}
text={Locale.Export.Mind.title}
icon={<MindIcon />}
onClick={() => {}}
/>
... ...
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1743555941264" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4341" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M213.333333 853.333333a42.666667 42.666667 0 0 1-85.333333 0v-256a42.666667 42.666667 0 0 1 85.333333 0v256z m213.333334 0a42.666667 42.666667 0 0 1-85.333334 0v-384a42.666667 42.666667 0 0 1 85.333334 0v384z m213.333333 0a42.666667 42.666667 0 0 1-85.333333 0v-341.333333a42.666667 42.666667 0 0 1 85.333333 0v341.333333z m213.333333 0a42.666667 42.666667 0 0 1-85.333333 0V384a42.666667 42.666667 0 0 1 85.333333 0v469.333333zM197.333333 459.946667a42.666667 42.666667 0 1 1-53.333333-66.56l213.333333-170.666667a42.666667 42.666667 0 0 1 42.496-6.314667l192.512 76.970667 237.312-158.208a42.666667 42.666667 0 0 1 47.36 70.997333l-256 170.666667a42.666667 42.666667 0 0 1-39.509333 4.096l-190.293333-76.074667-193.877334 155.136z" p-id="4342"></path></svg>
\ No newline at end of file
... ...
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1743564801418" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2502" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16"><path d="M973.44 420.906667a42.666667 42.666667 0 0 0-32.853333-15.573334h-53.333334v-85.333333a85.333333 85.333333 0 0 0-85.333333-85.333333H533.333333l-93.866666-112.64A42.666667 42.666667 0 0 0 407.253333 106.666667h-277.333333a85.333333 85.333333 0 0 0-85.333333 85.333333v682.666667a37.333333 37.333333 0 0 0 0 8.533333v2.346667c0 2.133333 1.28 4.053333 2.133333 6.186666l1.28 2.56a27.306667 27.306667 0 0 0 3.2 5.333334v1.493333a47.573333 47.573333 0 0 0 5.546667 5.76 33.92 33.92 0 0 0 7.466666 4.693333h2.133334l5.973333 2.133334h782.933333a42.666667 42.666667 0 0 0 42.666667-34.346667l85.333333-426.666667a42.666667 42.666667 0 0 0-9.813333-31.786666zM387.2 192l93.866667 112.64a42.666667 42.666667 0 0 0 32.853333 15.36h288v85.333333H189.866667A42.666667 42.666667 0 0 0 149.333333 437.973333l-18.346666 77.013334V192z" fill="#363636" p-id="2503"></path></svg>
\ No newline at end of file
... ...
... ... @@ -59,13 +59,8 @@ const cn = {
Speech: "朗读",
StopSpeech: "停止",
//20250317新增
Word: "导出Word",
Excel: "下载Excel",
Pdf: "导出PDF",
Ppt: "导出PPT",
Mind: "生成思维导图",
Drag: "拖动模式",
ReWrite: "重写",
Chart: "查看图表",
},
Commands: {
new: "新建聊天",
... ... @@ -145,9 +140,14 @@ const cn = {
Error: "分享失败",
},
Mind: {
title: "生成思维导图",
ExportPng: "导出为PNG图片",
ExportSvg: "导出为SVG",
},
Word: "导出Word",
Excel: "下载Excel",
Pdf: "导出PDF",
Ppt: "导出PPT",
},
Select: {
Search: "搜索消息",
... ... @@ -884,7 +884,6 @@ const cn = {
generateBg: "生成背景",
promptTitle: "背景提示词",
},
Thinking: "AI思考中",
};
type DeepPartial<T> = T extends object
... ...
... ... @@ -10,13 +10,13 @@ const en: LocaleType = {
Error: {
Unauthorized: isApp
? `😆 Oops, there's an issue. No worries:
\\ 1️⃣ New here? [Click to start chatting now 🚀](${SAAS_CHAT_UTM_URL})
\\ 2️⃣ Want to use your own OpenAI resources? [Click here](/#/settings) to change settings ⚙️`
\\ 1️⃣ New here? [Click to start chatting now 🚀](${SAAS_CHAT_UTM_URL})
\\ 2️⃣ Want to use your own OpenAI resources? [Click here](/#/settings) to change settings ⚙️`
: `😆 Oops, there's an issue. Let's fix it:
\ 1️⃣ New here? [Click to start chatting now 🚀](${SAAS_CHAT_UTM_URL})
\ 2️⃣ Using a private setup? [Click here](/#/auth) to enter your key 🔑
\ 3️⃣ Want to use your own OpenAI resources? [Click here](/#/settings) to change settings ⚙️
`,
\ 1️⃣ New here? [Click to start chatting now 🚀](${SAAS_CHAT_UTM_URL})
\ 2️⃣ Using a private setup? [Click here](/#/auth) to enter your key 🔑
\ 3️⃣ Want to use your own OpenAI resources? [Click here](/#/settings) to change settings ⚙️
`,
},
Auth: {
Return: "Return",
... ... @@ -59,8 +59,8 @@ const en: LocaleType = {
RefreshToast: "Title refresh request sent",
Speech: "Play",
StopSpeech: "Stop",
Word: "ExportWord",
Excel: "ToExcel"
ReWrite: "ReWrite",
Chart: "Chart",
},
Commands: {
new: "Start a new chat",
... ... @@ -139,6 +139,15 @@ const en: LocaleType = {
Title: "Share Artifacts",
Error: "Share Error",
},
Mind: {
title: "Generate Mind Map",
ExportPng: "Export as PNG Image",
ExportSvg: "Export as SVG",
},
Word: "Export Word",
Excel: "Download Excel",
Pdf: "Export PDF",
Ppt: "Export PPT",
},
Select: {
Search: "Search",
... ... @@ -861,6 +870,28 @@ const en: LocaleType = {
GenerateParams: "Generate Params",
Detail: "Detail",
},
BgRemoval: {
Title: "Smart Background Removal",
subTitle: "AI Background Removal",
error: {
reqErr: "Request Failed",
selectImg: "Please Select an Image",
code: "Please Enter the Access Password First",
prompt: "Please Enter the Prompt",
resultErr: "Failed to Load Result Image",
downLoadErr: "Please Complete Image Processing First",
statuErr: "Status Query Failed",
timeoutErr: "Processing Timed Out, Please Try Again Later",
imgLoadingErr: "Image Loading Failed",
},
success:
"Image Processing Successful, Please Save the Image Within One Hour!",
generateImg: "Generate Image",
bgRemoveBtn: "One-Click Background Removal",
downloadImg: "Download Image",
generateBg: "Generate Background",
promptTitle: "Background Prompt",
},
};
export default en;
... ...
... ... @@ -55,9 +55,8 @@ const tw = {
Edit: "編輯",
RefreshTitle: "重新整理標題",
RefreshToast: "已傳送重新整理標題請求",
//20250317新增
Word: "導出Word",
Excel: "下載Excel"
ReWrite: "重寫",
Chart: "查看圖表",
},
Commands: {
new: "新建聊天",
... ... @@ -129,6 +128,15 @@ const tw = {
Toast: "正在產生截圖",
Modal: "長按或按右鍵儲存圖片",
},
Mind: {
title: "生成思維導圖",
ExportPng: "導出為PNG圖片",
ExportSvg: "導出為SVG",
},
Word: "導出Word",
Excel: "下載Excel",
Pdf: "導出PDF",
Ppt: "導出PPT",
},
Select: {
Search: "查詢訊息",
... ... @@ -536,6 +544,27 @@ const tw = {
Topic: "主題",
Time: "時間",
},
BgRemoval: {
Title: "智能扣圖",
subTitle: "AI扣圖",
error: {
reqErr: "請求失敗",
selectImg: "請選擇圖片",
code: "請先輸入訪問密碼",
prompt: "請輸入提示詞",
resultErr: "結果圖片加載失敗",
downLoadErr: "請先完成圖片處理",
statuErr: "狀態查詢失敗",
timeoutErr: "處理超時,請稍後重試",
imgLoadingErr: "圖片加載失敗",
},
success: "圖片處理成功,請在一小時內保存圖片!",
generateImg: "生成圖片",
bgRemoveBtn: "一鍵扣圖",
downloadImg: "下載圖片",
generateBg: "生成背景",
promptTitle: "背景提示詞",
},
};
type DeepPartial<T> = T extends object
... ...
/* eslint-disable */
import * as XLSX from 'xlsx';
import * as XLSX from "xlsx";
export function toExcel(content: string) {
let sheetName = 'result'; // 默认表名
let tableContent = '';
// 查找标题内容(以 ** 或 ## 或 ### 开头)
const titleMatch = content.match(/^(#{2,3}|\*\*)\s*(.*)/m);
if (titleMatch) {
sheetName = titleMatch[2].trim().replace(/\s+/g, '_'); // 使用标题作为表名
// 提取表格内容(跳过标题部分)
tableContent = content.substring(titleMatch[0].length).trim();
} else {
tableContent = content;
let sheetName = "result"; // 默认表名
let tableContent = "";
// 查找标题内容(以 ** 或 ## 或 ### 开头)
const titleMatch = content.match(/^(#{2,3}|\*\*)\s*(.*)/m);
if (titleMatch) {
sheetName = titleMatch[2].trim().replace(/\s+/g, "_"); // 使用标题作为表名
// 提取表格内容(跳过标题部分)
tableContent = content.substring(titleMatch[0].length).trim();
} else {
tableContent = content;
}
// 查找表格的起始位置(第一行以 | 开头且以 | 结尾)
let tableStartIndex = -1;
const lines = tableContent.split("\n");
for (let i = 0; i < lines.length; i++) {
if (lines[i].trim().startsWith("|") && lines[i].trim().endsWith("|")) {
tableStartIndex = i;
break;
}
}
// 查找表格的起始位置(第一行以 | 开头且以 | 结尾)
let tableStartIndex = -1;
const lines = tableContent.split('\n');
for (let i = 0; i < lines.length; i++) {
if (lines[i].trim().startsWith('|') && lines[i].trim().endsWith('|')) {
tableStartIndex = i;
break;
}
if (tableStartIndex === -1) {
console.error("表格内容未找到");
return;
}
// 查找表格的结束位置(遇到不以 | 开头或者不以 | 结尾的行)
let tableEndIndex = -1;
for (let i = tableStartIndex; i < lines.length; i++) {
if (!lines[i].trim().startsWith("|") || !lines[i].trim().endsWith("|")) {
tableEndIndex = i;
break;
}
}
if (tableEndIndex === -1) {
tableEndIndex = lines.length;
}
// 提取表格内容
const tableData = lines
.slice(tableStartIndex, tableEndIndex)
.join("\n")
.trim();
if (tableStartIndex === -1) {
console.error('表格内容未找到');
return;
// 解析表格内容
const rows = tableData.split("\n");
const data: any[] = [];
let headers: string[] = [];
rows.forEach((row, rowIndex) => {
// 去掉行首尾的 | 符号,并按 | 分割
const cells = row
.replace(/^\s*\|/g, "")
.replace(/\|\s*$/g, "")
.split(/\s*\|\s*/);
// 跳过分隔线(假设分隔线的每个单元格都是由短横线组成)
if (
rowIndex > 0 &&
cells.every(
(cell) => cell.trim().replace(/-/g, "").length === 0, // 检查单元格内容是否只包含短横线
)
) {
return;
}
// 查找表格的结束位置(遇到不以 | 开头或者不以 | 结尾的行)
let tableEndIndex = -1;
for (let i = tableStartIndex; i < lines.length; i++) {
if (!lines[i].trim().startsWith('|') || !lines[i].trim().endsWith('|')) {
tableEndIndex = i;
break;
if (rowIndex === 0) {
// 第一行是表头
headers = cells.map((cell) => cell.trim());
} else {
// 数据行
const rowData: any = {};
cells.forEach((cell, cellIndex) => {
if (cellIndex < headers.length) {
rowData[headers[cellIndex]] = cell.trim();
}
});
data.push(rowData);
}
});
if (tableEndIndex === -1) {
tableEndIndex = lines.length;
}
// 创建工作表
const ws = XLSX.utils.json_to_sheet(data);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, sheetName);
// 提取表格内容
const tableData = lines.slice(tableStartIndex, tableEndIndex).join('\n').trim();
// 解析表格内容
const rows = tableData.split('\n');
const data: any[] = [];
let headers: string[] = [];
rows.forEach((row, rowIndex) => {
// 去掉行首尾的 | 符号,并按 | 分割
const cells = row.replace(/^\s*\|/g, '').replace(/\|\s*$/g, '').split(/\s*\|\s*/);
// 跳过分隔线(假设分隔线的每个单元格都是由短横线组成)
if (
rowIndex > 0 &&
cells.every(cell =>
cell.trim().replace(/-/g, '').length === 0 // 检查单元格内容是否只包含短横线
)
) {
return;
}
// 生成文件并下载
XLSX.writeFile(wb, `${sheetName}.xlsx`);
}
export function getExcelData(file: File): Promise<any[][]> {
return new Promise((resolve, reject) => {
const reader = new FileReader();
if (rowIndex === 0) {
// 第一行是表头
headers = cells.map(cell => cell.trim());
} else {
// 数据行
const rowData: any = {};
cells.forEach((cell, cellIndex) => {
if (cellIndex < headers.length) {
rowData[headers[cellIndex]] = cell.trim();
}
});
data.push(rowData);
reader.onload = (e) => {
try {
const data = e.target?.result;
if (!data) {
reject(new Error("Failed to read file data"));
return;
}
});
// 创建工作表
const ws = XLSX.utils.json_to_sheet(data);
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, sheetName);
const workbook = XLSX.read(data, { type: "array" });
const firstSheetName = workbook.SheetNames[0];
const worksheet = workbook.Sheets[firstSheetName];
// 使用类型断言将 unknown[] 转换为 any[][]
const jsonData = XLSX.utils.sheet_to_json(worksheet, {
header: 1,
}) as any[][];
resolve(jsonData.slice(0, 100));
} catch (error) {
reject(error);
}
};
reader.onerror = (error) => {
reject(error);
};
// 生成文件并下载
XLSX.writeFile(wb, `${sheetName}.xlsx`);
}
\ No newline at end of file
reader.readAsArrayBuffer(file);
});
}
... ...
... ... @@ -33,7 +33,6 @@
"@xyflow/react": "^12.4.4",
"antd": "^5.24.4",
"axios": "^1.7.5",
"chart.js": "^4.4.8",
"cheerio": "^1.0.0",
"clsx": "^2.1.1",
"docx": "^9.3.0",
... ... @@ -43,8 +42,6 @@
"file-saver": "^2.0.5",
"fuse.js": "^7.0.0",
"heic2any": "^0.0.4",
"html-docx-js": "^0.3.1",
"html-docx-js-typescript": "^0.1.5",
"html-to-image": "^1.11.11",
"idb-keyval": "^6.2.1",
"lodash-es": "^4.17.21",
... ... @@ -58,7 +55,6 @@
"openapi-client-axios": "^7.5.5",
"rc-tooltip": "^6.4.0",
"react": "^18.2.0",
"react-chartjs-2": "^5.3.0",
"react-dom": "^18.2.0",
"react-markdown": "^8.0.7",
"react-quill": "^2.0.0",
... ... @@ -109,7 +105,6 @@
"ts-node": "^10.9.2",
"tsx": "^4.16.0",
"typescript": "5.2.2",
"vue-loader": "^17.3.1",
"watch": "^1.0.2",
"webpack": "^5.0.0-rc.6"
},
... ...
... ... @@ -1841,11 +1841,6 @@
"@jridgewell/resolve-uri" "^3.1.0"
"@jridgewell/sourcemap-codec" "^1.4.14"
"@kurkle/color@^0.3.0":
version "0.3.4"
resolved "https://registry.npmmirror.com/@kurkle/color/-/color-0.3.4.tgz"
integrity sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==
"@modelcontextprotocol/sdk@^1.0.4":
version "1.0.4"
resolved "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.0.4.tgz"
... ... @@ -3353,11 +3348,6 @@ braces@^3.0.2, braces@~3.0.2:
dependencies:
fill-range "^7.0.1"
browser-or-node@^1.2.1:
version "1.3.0"
resolved "https://registry.npmmirror.com/browser-or-node/-/browser-or-node-1.3.0.tgz"
integrity sha512-0F2z/VSnLbmEeBcUrSuDH5l0HxTXdQQzLjkmBR4cYfvg1zJrKSlmIZFqyFR8oX0NrwPhy3c3HQ6i3OxMbew4Tg==
browserslist@^4.14.3, browserslist@^4.21.3, browserslist@^4.21.5, browserslist@^4.23.1:
version "4.24.4"
resolved "https://registry.npmmirror.com/browserslist/-/browserslist-4.24.4.tgz"
... ... @@ -3507,13 +3497,6 @@ character-entities@^2.0.0:
resolved "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz"
integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==
chart.js@^4.4.8:
version "4.4.8"
resolved "https://registry.npmmirror.com/chart.js/-/chart.js-4.4.8.tgz#54645b638e9d585099bc16b892947b5e6cd2a552"
integrity sha512-IkGZlVpXP+83QpMm4uxEiGqSI7jFizwVtF3+n5Pc3k7sMO+tkd0qxh2OzLhenM0K80xtmAONWGBn082EiBQSDA==
dependencies:
"@kurkle/color" "^0.3.0"
cheerio-select@^2.1.0:
version "2.1.0"
resolved "https://registry.npmmirror.com/cheerio-select/-/cheerio-select-2.1.0.tgz"
... ... @@ -5506,11 +5489,6 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
hash-sum@^2.0.0:
version "2.0.0"
resolved "https://registry.npmmirror.com/hash-sum/-/hash-sum-2.0.0.tgz"
integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==
hash.js@^1.1.7:
version "1.1.7"
resolved "https://registry.npmmirror.com/hash.js/-/hash.js-1.1.7.tgz"
... ... @@ -5631,24 +5609,6 @@ hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
dependencies:
react-is "^16.7.0"
html-docx-js-typescript@^0.1.5:
version "0.1.5"
resolved "https://registry.npmmirror.com/html-docx-js-typescript/-/html-docx-js-typescript-0.1.5.tgz"
integrity sha512-GNojWFDYbpHSIgKml6/0oAom8mtHrHRTWKMyLRdeJQHO/CyeM6H39DYgzYvPp4OhBp2Ti8dxMKFq0/FkpYD4bg==
dependencies:
browser-or-node "^1.2.1"
jszip "^3.4.0"
tslib "^1.13.0"
html-docx-js@^0.3.1:
version "0.3.1"
resolved "https://registry.npmmirror.com/html-docx-js/-/html-docx-js-0.3.1.tgz"
integrity sha512-QSrMiRhxesqxYCa3f+2Z3ttIHPzSjDOL1tCOmIDIEET7HdabxXND6tAbsFMXAgRG4RADQ3wbl74ydMmjidaDPA==
dependencies:
jszip "^2.3.0"
lodash.escape "^3.0.0"
lodash.merge "^3.2.0"
html-encoding-sniffer@^3.0.0:
version "3.0.0"
resolved "https://registry.npmmirror.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz"
... ... @@ -6591,7 +6551,7 @@ json5@^2.2.2, json5@^2.2.3:
array-includes "^3.1.5"
object.assign "^4.1.3"
jszip@*, jszip@^3.10.1, jszip@^3.4.0:
jszip@*, jszip@^3.10.1:
version "3.10.1"
resolved "https://registry.npmmirror.com/jszip/-/jszip-3.10.1.tgz"
integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==
... ... @@ -6601,13 +6561,6 @@ jszip@*, jszip@^3.10.1, jszip@^3.4.0:
readable-stream "~2.3.6"
setimmediate "^1.0.5"
jszip@^2.3.0:
version "2.7.0"
resolved "https://registry.npmmirror.com/jszip/-/jszip-2.7.0.tgz"
integrity sha512-JIsRKRVC3gTRo2vM4Wy9WBC3TRcfnIZU8k65Phi3izkvPH975FowRYtKGT6PxevA0XnJ/yO8b0QwV0ydVyQwfw==
dependencies:
pako "~1.0.2"
katex@^0.13.0:
version "0.13.24"
resolved "https://registry.npmjs.org/katex/-/katex-0.13.24.tgz"
... ... @@ -6746,148 +6699,21 @@ lodash-es@^4.17.21:
resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
lodash._arraycopy@^3.0.0:
version "3.0.0"
resolved "https://registry.npmmirror.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz"
integrity sha512-RHShTDnPKP7aWxlvXKiDT6IX2jCs6YZLCtNhOru/OX2Q/tzX295vVBK5oX1ECtN+2r86S0Ogy8ykP1sgCZAN0A==
lodash._arrayeach@^3.0.0:
version "3.0.0"
resolved "https://registry.npmmirror.com/lodash._arrayeach/-/lodash._arrayeach-3.0.0.tgz"
integrity sha512-Mn7HidOVcl3mkQtbPsuKR0Fj0N6Q6DQB77CtYncZcJc0bx5qv2q4Gl6a0LC1AN+GSxpnBDNnK3CKEm9XNA4zqQ==
lodash._basecopy@^3.0.0:
version "3.0.1"
resolved "https://registry.npmmirror.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz"
integrity sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==
lodash._basefor@^3.0.0:
version "3.0.3"
resolved "https://registry.npmmirror.com/lodash._basefor/-/lodash._basefor-3.0.3.tgz"
integrity sha512-6bc3b8grkpMgDcVJv9JYZAk/mHgcqMljzm7OsbmcE2FGUMmmLQTPHlh/dFqR8LA0GQ7z4K67JSotVKu5058v1A==
lodash._bindcallback@^3.0.0:
version "3.0.1"
resolved "https://registry.npmmirror.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz"
integrity sha512-2wlI0JRAGX8WEf4Gm1p/mv/SZ+jLijpj0jyaE/AXeuQphzCgD8ZQW4oSpoN8JAopujOFGU3KMuq7qfHBWlGpjQ==
lodash._createassigner@^3.0.0:
version "3.1.1"
resolved "https://registry.npmmirror.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz"
integrity sha512-LziVL7IDnJjQeeV95Wvhw6G28Z8Q6da87LWKOPWmzBLv4u6FAT/x5v00pyGW0u38UoogNF2JnD3bGgZZDaNEBw==
dependencies:
lodash._bindcallback "^3.0.0"
lodash._isiterateecall "^3.0.0"
lodash.restparam "^3.0.0"
lodash._getnative@^3.0.0:
version "3.9.1"
resolved "https://registry.npmmirror.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz"
integrity sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==
lodash._isiterateecall@^3.0.0:
version "3.0.9"
resolved "https://registry.npmmirror.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz"
integrity sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==
lodash._root@^3.0.0:
version "3.0.1"
resolved "https://registry.npmmirror.com/lodash._root/-/lodash._root-3.0.1.tgz"
integrity sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ==
lodash.debounce@^4.0.8:
version "4.0.8"
resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz"
integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
lodash.escape@^3.0.0:
version "3.2.0"
resolved "https://registry.npmmirror.com/lodash.escape/-/lodash.escape-3.2.0.tgz"
integrity sha512-n1PZMXgaaDWZDSvuNZ/8XOcYO2hOKDqZel5adtR30VKQAtoWs/5AOeFA0vPV8moiPzlqe7F4cP2tzpFewQyelQ==
dependencies:
lodash._root "^3.0.0"
lodash.escape@^4.0.1:
version "4.0.1"
resolved "https://registry.npmjs.org/lodash.escape/-/lodash.escape-4.0.1.tgz"
integrity sha512-nXEOnb/jK9g0DYMr1/Xvq6l5xMD7GDG55+GSYIYmS0G4tBk/hURD4JR9WCavs04t33WmJx9kCyp9vJ+mr4BOUw==
lodash.isarguments@^3.0.0:
version "3.1.0"
resolved "https://registry.npmmirror.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz"
integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==
lodash.isarray@^3.0.0:
version "3.0.4"
resolved "https://registry.npmmirror.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz"
integrity sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==
lodash.isplainobject@^3.0.0:
version "3.2.0"
resolved "https://registry.npmmirror.com/lodash.isplainobject/-/lodash.isplainobject-3.2.0.tgz"
integrity sha512-P4wZnho5curNqeEq/x292Pb57e1v+woR7DJ84DURelKB46lby8aDEGVobSaYtzHdQBWQrJSdxcCwjlGOvvdIyg==
dependencies:
lodash._basefor "^3.0.0"
lodash.isarguments "^3.0.0"
lodash.keysin "^3.0.0"
lodash.istypedarray@^3.0.0:
version "3.0.6"
resolved "https://registry.npmmirror.com/lodash.istypedarray/-/lodash.istypedarray-3.0.6.tgz"
integrity sha512-lGWJ6N8AA3KSv+ZZxlTdn4f6A7kMfpJboeyvbFdE7IU9YAgweODqmOgdUHOA+c6lVWeVLysdaxciFXi+foVsWw==
lodash.keys@^3.0.0:
version "3.1.2"
resolved "https://registry.npmmirror.com/lodash.keys/-/lodash.keys-3.1.2.tgz"
integrity sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==
dependencies:
lodash._getnative "^3.0.0"
lodash.isarguments "^3.0.0"
lodash.isarray "^3.0.0"
lodash.keysin@^3.0.0:
version "3.0.8"
resolved "https://registry.npmmirror.com/lodash.keysin/-/lodash.keysin-3.0.8.tgz"
integrity sha512-YDB/5xkL3fBKFMDaC+cfGV00pbiJ6XoJIfRmBhv7aR6wWtbCW6IzkiWnTfkiHTF6ALD7ff83dAtB3OEaSoyQPg==
dependencies:
lodash.isarguments "^3.0.0"
lodash.isarray "^3.0.0"
lodash.merge@^3.2.0:
version "3.3.2"
resolved "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-3.3.2.tgz"
integrity sha512-ZgGZpRhWLjivGUbjtApZR4HyLv/UAyoYqESVYkK4aLBJVHRrbFpG+GNnE9JPijliME4LkKM0SFI/WyOiBiv1+w==
dependencies:
lodash._arraycopy "^3.0.0"
lodash._arrayeach "^3.0.0"
lodash._createassigner "^3.0.0"
lodash._getnative "^3.0.0"
lodash.isarguments "^3.0.0"
lodash.isarray "^3.0.0"
lodash.isplainobject "^3.0.0"
lodash.istypedarray "^3.0.0"
lodash.keys "^3.0.0"
lodash.keysin "^3.0.0"
lodash.toplainobject "^3.0.0"
lodash.merge@^4.6.2:
version "4.6.2"
resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
lodash.restparam@^3.0.0:
version "3.6.1"
resolved "https://registry.npmmirror.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz"
integrity sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==
lodash.toplainobject@^3.0.0:
version "3.0.0"
resolved "https://registry.npmmirror.com/lodash.toplainobject/-/lodash.toplainobject-3.0.0.tgz"
integrity sha512-wMI0Ju1bvSmnBS3EcRRH/3zDnZOPpDtMtNDzbbNMKuTrEpALsf+sPyMeogmv63Y11qZQO7H1xFzohIEGRMjPYA==
dependencies:
lodash._basecopy "^3.0.0"
lodash.keysin "^3.0.0"
lodash.unescape@^4.0.1:
version "4.0.1"
resolved "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz"
... ... @@ -8485,11 +8311,6 @@ rc-virtual-list@^3.14.2, rc-virtual-list@^3.5.1, rc-virtual-list@^3.5.2:
rc-resize-observer "^1.0.0"
rc-util "^5.36.0"
react-chartjs-2@^5.3.0:
version "5.3.0"
resolved "https://registry.npmmirror.com/react-chartjs-2/-/react-chartjs-2-5.3.0.tgz#2d3286339a742bc7f77b5829c33ebab215f714cc"
integrity sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw==
react-dom@^18.2.0:
version "18.2.0"
resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz"
... ... @@ -9557,11 +9378,6 @@ tslib@2.3.0:
resolved "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz#803b8cdab3e12ba581a4ca41c8839bbb0dacb09e"
integrity sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==
tslib@^1.13.0:
version "1.14.1"
resolved "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.1.0, tslib@^2.4.0:
version "2.5.0"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz"
... ... @@ -9860,15 +9676,6 @@ vfile@^5.0.0:
unist-util-stringify-position "^3.0.0"
vfile-message "^3.0.0"
vue-loader@^17.3.1:
version "17.3.1"
resolved "https://registry.npmmirror.com/vue-loader/-/vue-loader-17.3.1.tgz"
integrity sha512-nmVu7KU8geOyzsStyyaxID/uBGDMS8BkPXb6Lu2SNkMawriIbb+hYrNtgftHMKxOSkjjjTF5OSSwPo3KP59egg==
dependencies:
chalk "^4.1.0"
hash-sum "^2.0.0"
watchpack "^2.4.0"
w3c-xmlserializer@^4.0.0:
version "4.0.0"
resolved "https://registry.npmmirror.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz"
... ... @@ -9891,7 +9698,7 @@ watch@^1.0.2:
exec-sh "^0.2.0"
minimist "^1.2.0"
watchpack@^2.0.0, watchpack@^2.4.0:
watchpack@^2.0.0:
version "2.4.2"
resolved "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.2.tgz"
integrity sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==
... ...