fix: export log dateend

This commit is contained in:
archer 2025-12-10 11:23:18 +08:00
parent c7fb948300
commit 4efd805961
No known key found for this signature in database
GPG Key ID: 4446499B846D4A9E
11 changed files with 43 additions and 32 deletions

View File

@ -57,6 +57,7 @@ curl --location --request POST 'https://{{host}}/api/admin/initv4144' \
10. 发布渠道文档链接定位错误。
11. Checkbox 在禁用状态时hover 样式错误。
12. 模型头像缺失情况下,默认 huggingface.svg 图标显示错误。
13. 日志导出时,结束时间会多出一天。
## 插件

View File

@ -119,7 +119,7 @@
"document/content/docs/upgrading/4-14/4141.mdx": "2025-11-19T10:15:27+08:00",
"document/content/docs/upgrading/4-14/4142.mdx": "2025-11-18T19:27:14+08:00",
"document/content/docs/upgrading/4-14/4143.mdx": "2025-11-26T20:52:05+08:00",
"document/content/docs/upgrading/4-14/4144.mdx": "2025-12-10T11:41:15+08:00",
"document/content/docs/upgrading/4-14/4144.mdx": "2025-12-09T23:33:32+08:00",
"document/content/docs/upgrading/4-8/40.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/41.mdx": "2025-08-02T19:38:37+08:00",
"document/content/docs/upgrading/4-8/42.mdx": "2025-08-02T19:38:37+08:00",
@ -201,4 +201,4 @@
"document/content/docs/use-cases/external-integration/openapi.mdx": "2025-09-29T11:34:11+08:00",
"document/content/docs/use-cases/external-integration/wecom.mdx": "2025-12-09T23:33:32+08:00",
"document/content/docs/use-cases/index.mdx": "2025-07-24T14:23:04+08:00"
}
}

View File

@ -16,3 +16,10 @@ export const parseI18nString = (str: I18nStringType | string = '', lang = 'en')
// 最后回退到英文
return str['en'] || '';
};
export const formatI18nLocationToZhEn = (locale: localeType = 'zh-CN'): 'zh' | 'en' => {
if (locale.toLocaleLowerCase().startsWith('zh')) {
return 'zh';
}
return 'en';
};

View File

@ -2,11 +2,13 @@ import fs from 'node:fs';
import type { ReaderModel } from '@maxmind/geoip2-node';
import { Reader } from '@maxmind/geoip2-node';
import { cleanupIntervalMs, dbPath, privateOrOtherLocationName } from './constants';
import type { I18nName, LocationName } from './type';
import type { LocationName } from './type';
import { extractLocationData } from './utils';
import type { NextApiRequest } from 'next';
import { getClientIp } from 'request-ip';
import { addLog } from '../system/log';
import type { localeType } from '@fastgpt/global/common/i18n/type';
import { formatI18nLocationToZhEn } from '@fastgpt/global/common/i18n/utils';
let reader: ReaderModel | null = null;
@ -25,21 +27,23 @@ export function getGeoReader() {
return reader;
}
export function getLocationFromIp(ip?: string, locale: keyof I18nName = 'zh') {
export function getLocationFromIp(ip?: string, locale: localeType = 'zh-CN') {
const formatedLocale = formatI18nLocationToZhEn(locale);
if (!ip) {
return privateOrOtherLocationName.country?.[locale];
return privateOrOtherLocationName.country?.[formatedLocale];
}
const reader = getGeoReader();
let locationName = locationIpMap.get(ip);
if (locationName) {
return [
locationName.country?.[locale],
locationName.province?.[locale],
locationName.city?.[locale]
locationName.country?.[formatedLocale],
locationName.province?.[formatedLocale],
locationName.city?.[formatedLocale]
]
.filter(Boolean)
.join(locale === 'zh' ? '' : ',');
.join(formatedLocale === 'zh' ? '' : ',');
}
try {
@ -62,15 +66,15 @@ export function getLocationFromIp(ip?: string, locale: keyof I18nName = 'zh') {
locationIpMap.set(ip, locationName);
return [
locationName.country?.[locale],
locationName.province?.[locale],
locationName.city?.[locale]
locationName.country?.[formatedLocale],
locationName.province?.[formatedLocale],
locationName.city?.[formatedLocale]
]
.filter(Boolean)
.join(locale === 'zh' ? '' : ', ');
.join(formatedLocale === 'zh' ? '' : ', ');
} catch (error) {
locationIpMap.set(ip, privateOrOtherLocationName);
return privateOrOtherLocationName.country?.[locale];
return privateOrOtherLocationName.country?.[formatedLocale];
}
}

View File

@ -145,6 +145,7 @@
"expand_tool_create": "Expand MCP/Http create",
"export_config_successful": "Configuration copied, some sensitive information automatically filtered. Please check for any remaining sensitive data.",
"export_configs": "Export",
"export_log_filename": "{{name}} chat logs.csv",
"fastgpt_marketplace": "FastGPT plug-in market",
"feedback_count": "User Feedback",
"file_quote_link": "Files",

View File

@ -149,6 +149,7 @@
"expand_tool_create": "展开MCP、Http创建",
"export_config_successful": "已复制配置,自动过滤部分敏感信息,请注意检查是否仍有敏感数据",
"export_configs": "导出配置",
"export_log_filename": "{{name}} 对话日志.csv",
"fastgpt_marketplace": "FastGPT 插件市场",
"feedback_count": "用户反馈",
"file_quote_link": "文件链接",

View File

@ -144,6 +144,7 @@
"expand_tool_create": "展開 MCP、Http 創建",
"export_config_successful": "已複製設定,自動過濾部分敏感資訊,請注意檢查是否仍有敏感資料",
"export_configs": "匯出設定",
"export_log_filename": "{{name}} 對話日誌.csv",
"fastgpt_marketplace": "FastGPT 插件市場",
"feedback_count": "使用者回饋",
"file_quote_link": "檔案連結",

View File

@ -10,7 +10,6 @@ export type GetAppChatLogsProps = {
sources?: ChatSourceEnum[];
tmbIds?: string[];
chatSearch?: string;
locale?: keyof I18nName;
};
export type GetAppChatLogsParams = PaginationProps<GetAppChatLogsProps>;

View File

@ -20,7 +20,6 @@ import MultipleSelect, {
import React, { useMemo, useState } from 'react';
import { useTranslation } from 'next-i18next';
import DateRangePicker from '@fastgpt/web/components/common/DateRangePicker';
import { addDays } from 'date-fns';
import { useScrollPagination } from '@fastgpt/web/hooks/useScrollPagination';
import { getTeamMembers } from '@/web/support/user/team/api';
import Avatar from '@fastgpt/web/components/common/Avatar';
@ -50,7 +49,8 @@ import dynamic from 'next/dynamic';
import type { HeaderControlProps } from './LogChart';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import MyBox from '@fastgpt/web/components/common/MyBox';
import type { I18nName } from '@fastgpt/service/common/geo/type';
import { useContextSelector } from 'use-context-selector';
import { AppContext } from '../context';
const DetailLogsModal = dynamic(() => import('./DetailLogsModal'));
@ -65,10 +65,11 @@ const LogTable = ({
showSourceSelector = true,
px = [4, 8]
}: HeaderControlProps) => {
const { t, i18n } = useTranslation();
const { t } = useTranslation();
const { feConfigs } = useSystemStore();
const [detailLogsId, setDetailLogsId] = useState<string>();
const appName = useContextSelector(AppContext, (v) => v.appDetail.name);
// source
const sourceList = useMemo(
@ -147,15 +148,14 @@ const LogTable = ({
const headerTitle = enabledKeys.map((k) => t(AppLogKeysEnumMap[k])).join(',');
await downloadFetch({
url: '/api/core/app/exportChatLogs',
filename: 'chat_logs.csv',
filename: t('app:export_log_filename', { name: appName }),
body: {
appId,
dateStart: dayjs(dateRange.from || new Date()).format(),
dateEnd: dayjs(addDays(dateRange.to || new Date(), 1)).format(),
dateEnd: dayjs(dateRange.to || new Date()).format(),
sources: isSelectAllSource ? undefined : chatSources,
tmbIds: isSelectAllTmb ? undefined : selectTmbIds,
chatSearch,
locale: i18n.language === 'zh-CN' ? 'zh' : 'en',
title: `${headerTitle},${t('app:logs_keys_chatDetails')}`,
logKeys: enabledKeys,
sourcesMap: Object.fromEntries(
@ -180,8 +180,7 @@ const LogTable = ({
dateEnd: dateRange.to!,
sources: isSelectAllSource ? undefined : chatSources,
tmbIds: isSelectAllTmb ? undefined : selectTmbIds,
chatSearch,
locale: (i18n.language === 'zh-CN' ? 'zh' : 'en') as keyof I18nName
chatSearch
}),
[
appId,
@ -191,8 +190,7 @@ const LogTable = ({
isSelectAllSource,
selectTmbIds,
isSelectAllTmb,
chatSearch,
i18n.language
chatSearch
]
);

View File

@ -26,7 +26,7 @@ import { getAppLatestVersion } from '@fastgpt/service/core/app/version/controlle
import { VariableInputEnum } from '@fastgpt/global/core/workflow/constants';
import { getTimezoneCodeFromStr } from '@fastgpt/global/common/time/timezone';
import { getLocationFromIp } from '@fastgpt/service/common/geo';
import type { I18nName } from '@fastgpt/service/common/geo/type';
import { getLocale } from '@fastgpt/service/common/middle/i18n';
const formatJsonString = (data: any) => {
if (data == null) return '';
@ -40,7 +40,6 @@ export type ExportChatLogsBody = GetAppChatLogsProps & {
title: string;
sourcesMap: Record<string, { label: string }>;
logKeys: AppLogKeysEnum[];
locale?: keyof I18nName;
};
async function handler(req: ApiRequestProps<ExportChatLogsBody, {}>, res: NextApiResponse) {
@ -51,7 +50,6 @@ async function handler(req: ApiRequestProps<ExportChatLogsBody, {}>, res: NextAp
sources,
tmbIds,
chatSearch,
locale = 'en',
title,
sourcesMap,
logKeys = []
@ -61,6 +59,7 @@ async function handler(req: ApiRequestProps<ExportChatLogsBody, {}>, res: NextAp
throw new Error('缺少参数');
}
const locale = getLocale(req);
const timezoneCode = getTimezoneCodeFromStr(dateStart);
const { teamId, tmbId, app } = await authApp({

View File

@ -1,8 +1,7 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import type { NextApiResponse } from 'next';
import { MongoChat } from '@fastgpt/service/core/chat/chatSchema';
import { type AppLogsListItemType } from '@/types/app';
import { Types } from '@fastgpt/service/common/mongo';
import { addDays } from 'date-fns';
import type { GetAppChatLogsParams } from '@/global/core/api/appReq.d';
import { authApp } from '@fastgpt/service/support/permission/app/auth';
import {
@ -19,12 +18,13 @@ import { getLocationFromIp } from '@fastgpt/service/common/geo';
import { AppReadChatLogPerVal } from '@fastgpt/global/support/permission/app/constant';
import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
import type { ApiRequestProps } from '@fastgpt/service/type/next';
import { getLocale } from '@fastgpt/service/common/middle/i18n';
async function handler(
req: ApiRequestProps<GetAppChatLogsParams>,
_res: NextApiResponse
): Promise<PaginationResponse<AppLogsListItemType>> {
const { appId, dateStart, dateEnd, sources, tmbIds, chatSearch, locale = 'en' } = req.body;
const { appId, dateStart, dateEnd, sources, tmbIds, chatSearch } = req.body;
const { pageSize = 20, offset } = parsePaginationRequest(req);
@ -294,7 +294,7 @@ async function handler(
const listWithRegion = list.map((item) => {
const ip = item.region;
const region = getLocationFromIp(ip, locale);
const region = getLocationFromIp(ip, getLocale(req));
return {
...item,