mirror of
https://github.com/olcubo/obsidian-cubox.git
synced 2026-07-22 05:43:25 +00:00
filename/fontmatter process
This commit is contained in:
parent
cf5adc0511
commit
cb81eac092
7 changed files with 182 additions and 194 deletions
23
package-lock.json
generated
23
package-lock.json
generated
|
|
@ -8,13 +8,19 @@
|
|||
"name": "obsidian-cubox",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"luxon": "^3.1.1",
|
||||
"mustache": "^4.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mustache": "^4.2.0",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/mustache": "^4.2.5",
|
||||
"@types/node": "^16.11.6",
|
||||
"@typescript-eslint/eslint-plugin": "5.29.0",
|
||||
"@typescript-eslint/parser": "5.29.0",
|
||||
"builtin-modules": "3.3.0",
|
||||
"esbuild": "0.17.3",
|
||||
"luxon": "^3.1.1",
|
||||
"mustache": "^4.2.0",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.4.0",
|
||||
|
|
@ -559,6 +565,12 @@
|
|||
"integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/luxon": {
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.4.2.tgz",
|
||||
"integrity": "sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/mustache": {
|
||||
"version": "4.2.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/mustache/-/mustache-4.2.5.tgz",
|
||||
|
|
@ -1686,6 +1698,15 @@
|
|||
"dev": true,
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/luxon": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz",
|
||||
"integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
|
|
|
|||
10
package.json
10
package.json
|
|
@ -12,15 +12,21 @@
|
|||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/mustache": "^4.2.5",
|
||||
"@types/node": "^16.11.6",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@typescript-eslint/eslint-plugin": "5.29.0",
|
||||
"@typescript-eslint/parser": "5.29.0",
|
||||
"builtin-modules": "3.3.0",
|
||||
"esbuild": "0.17.3",
|
||||
"mustache": "^4.2.0",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.4.0",
|
||||
"typescript": "4.7.4",
|
||||
"@types/mustache": "^4.2.0",
|
||||
"mustache": "^4.2.0"
|
||||
"luxon": "^3.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"mustache": "^4.2.0",
|
||||
"luxon": "^3.1.1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,11 +31,6 @@ export interface CuboxHighlight {
|
|||
create_time: string;
|
||||
}
|
||||
|
||||
export interface CuboxApiOptions {
|
||||
domain: string;
|
||||
apiKey: string;
|
||||
}
|
||||
|
||||
export interface CuboxFolder {
|
||||
id: string;
|
||||
name: string;
|
||||
|
|
@ -78,17 +73,17 @@ export class CuboxApi {
|
|||
private endpoint: string;
|
||||
private apiKey: string;
|
||||
|
||||
constructor(options: CuboxApiOptions) {
|
||||
this.endpoint = 'https://test.cubox.pro'//`https://${options.domain}`;
|
||||
this.apiKey = options.apiKey;
|
||||
constructor(domain: string, apiKey: string) {
|
||||
this.endpoint = 'https://test.cubox.pro'//`https://${domain}`;
|
||||
this.apiKey = apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同时更新域名和 API Key
|
||||
*/
|
||||
updateConfig(options: CuboxApiOptions): void {
|
||||
this.endpoint = 'https://test.cubox.pro'// `https://${options.domain}`;
|
||||
this.apiKey = options.apiKey;
|
||||
updateConfig(domain: string, apiKey: string): void {
|
||||
this.endpoint = 'https://test.cubox.pro'// `https://${domain}`;
|
||||
this.apiKey = apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
54
src/main.ts
54
src/main.ts
|
|
@ -1,9 +1,9 @@
|
|||
import { addIcon, App, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting, TFolder } from 'obsidian';
|
||||
import { CuboxApi, CuboxApiOptions } from './cuboxApi';
|
||||
import { TemplateProcessor } from './templateProcessor';
|
||||
import { formatISODateTime, getCurrentFormattedTime } from './utils';
|
||||
import { CuboxApi } from './cuboxApi';
|
||||
import { TemplateProcessor, FRONT_MATTER_VARIABLES } from './templateProcessor';
|
||||
import { formatDateTime } from './utils';
|
||||
import { ALL_FOLDERS_ID, FolderSelectModal } from './modal/folderSelectModal';
|
||||
import { filenameTemplateInstructions, metadataTemplateInstructions, contentTemplateInstructions } from './templateInstructions';
|
||||
import { filenameTemplateInstructions, metadataVariablesInstructions, contentTemplateInstructions } from './templateInstructions';
|
||||
import { ALL_CONTENT_TYPES, TypeSelectModal } from './modal/typeSelectModal';
|
||||
import { StatusSelectModal } from './modal/statusSelectModal';
|
||||
import { ALL_TAGS_ID, TagSelectModal } from './modal/tagSelectModal';
|
||||
|
|
@ -22,7 +22,7 @@ interface CuboxSyncSettings {
|
|||
syncFrequency: number;
|
||||
targetFolder: string;
|
||||
filenameTemplate: string;
|
||||
frontMatterTemplate: string;
|
||||
frontMatterVariables: string[];
|
||||
contentTemplate: string;
|
||||
highlightInContent: boolean;
|
||||
dateFormat: string;
|
||||
|
|
@ -44,7 +44,7 @@ const DEFAULT_SETTINGS: CuboxSyncSettings = {
|
|||
syncFrequency: 30, // 分钟
|
||||
targetFolder: 'Cubox',
|
||||
filenameTemplate: '{{title}}-{{create_time}}',
|
||||
frontMatterTemplate: 'id: {{{id}}}',
|
||||
frontMatterVariables: ['id', 'cubox_url', 'url', 'tags'],
|
||||
contentTemplate: '# {{{title}}}\n\n{{{description}}}\n\n[Read in Cubox]({{{cubox_url}}})\n[Read Original]({{{url}}})\n\n{{#highlights.length}}\n## Annotations\n\n{{#highlights}}\n> {{{highlight_text}}}\n{{{highlight_note}}}\n[Link️]({{{highlight_url}}})\n\n{{/highlights}}\n{{/highlights.length}}',
|
||||
highlightInContent: true,
|
||||
dateFormat: 'YYYY-MM-dd',
|
||||
|
|
@ -63,10 +63,7 @@ export default class CuboxSyncPlugin extends Plugin {
|
|||
await this.loadSettings();
|
||||
|
||||
// 初始化 API 和模板处理器
|
||||
this.cuboxApi = new CuboxApi({
|
||||
domain: this.settings.domain,
|
||||
apiKey: this.settings.apiKey
|
||||
});
|
||||
this.cuboxApi = new CuboxApi(this.settings.domain, this.settings.apiKey);
|
||||
this.templateProcessor = new TemplateProcessor();
|
||||
// 设置模板处理器的日期格式
|
||||
this.templateProcessor.setDateFormat(this.settings.dateFormat);
|
||||
|
|
@ -126,16 +123,10 @@ export default class CuboxSyncPlugin extends Plugin {
|
|||
|
||||
// 更新 API 配置
|
||||
if (this.cuboxApi) {
|
||||
this.cuboxApi.updateConfig({
|
||||
domain: this.settings.domain,
|
||||
apiKey: this.settings.apiKey
|
||||
});
|
||||
this.cuboxApi.updateConfig(this.settings.domain, this.settings.apiKey);
|
||||
} else {
|
||||
// 如果实例不存在,创建新实例
|
||||
this.cuboxApi = new CuboxApi({
|
||||
domain: this.settings.domain,
|
||||
apiKey: this.settings.apiKey
|
||||
});
|
||||
this.cuboxApi = new CuboxApi(this.settings.domain, this.settings.apiKey);
|
||||
}
|
||||
|
||||
// 更新模板处理器的日期格式
|
||||
|
|
@ -224,8 +215,8 @@ export default class CuboxSyncPlugin extends Plugin {
|
|||
fullArticle
|
||||
);
|
||||
|
||||
const frontMatter = this.templateProcessor.processFrontMatterTemplate(
|
||||
this.settings.frontMatterTemplate,
|
||||
const frontMatter = this.templateProcessor.processFrontMatter(
|
||||
this.settings.frontMatterVariables,
|
||||
fullArticle
|
||||
);
|
||||
|
||||
|
|
@ -236,7 +227,7 @@ export default class CuboxSyncPlugin extends Plugin {
|
|||
|
||||
// 组合最终内容
|
||||
let finalContent = '';
|
||||
if (frontMatter) {
|
||||
if (frontMatter.length > 0) {
|
||||
finalContent = `---\n${frontMatter}\n---\n\n`;
|
||||
}
|
||||
finalContent += fullArticle.content;
|
||||
|
|
@ -308,7 +299,7 @@ export default class CuboxSyncPlugin extends Plugin {
|
|||
}
|
||||
|
||||
// 使用新的格式化方法
|
||||
return formatISODateTime(new Date(this.settings.lastSyncTime).toISOString(), 'yyyy-MM-dd HH:mm');
|
||||
return formatDateTime(new Date(this.settings.lastSyncTime).toISOString(), 'yyyy-MM-dd HH:mm');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -587,16 +578,23 @@ class CuboxSyncSettingTab extends PluginSettingTab {
|
|||
});
|
||||
|
||||
// 更新前置元数据模板设置
|
||||
const metadataInstructionsFragment = document.createRange().createContextualFragment(metadataTemplateInstructions);
|
||||
const metadataInstructionsFragment = document.createRange().createContextualFragment(metadataVariablesInstructions);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Metadata Template')
|
||||
.setName('Metadata Variables')
|
||||
.setDesc(metadataInstructionsFragment)
|
||||
.addTextArea(text => text
|
||||
.setPlaceholder('Enter front matter template')
|
||||
.setValue(this.plugin.settings.frontMatterTemplate)
|
||||
.setPlaceholder('Enter front matter variables')
|
||||
.setValue(this.plugin.settings.frontMatterVariables.join(','))
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.frontMatterTemplate = value;
|
||||
this.plugin.settings.frontMatterVariables = value
|
||||
.split(',')
|
||||
.map((v) => v.trim())
|
||||
.filter(
|
||||
(v, i, a) =>
|
||||
FRONT_MATTER_VARIABLES.includes(v.split('::')[0]) &&
|
||||
a.indexOf(v) === i,
|
||||
)
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
// 设置文本区域的大小
|
||||
|
|
@ -608,7 +606,7 @@ class CuboxSyncSettingTab extends PluginSettingTab {
|
|||
.setIcon('reset')
|
||||
.setTooltip('Reset to default')
|
||||
.onClick(async () => {
|
||||
this.plugin.settings.frontMatterTemplate = DEFAULT_SETTINGS.frontMatterTemplate;
|
||||
this.plugin.settings.frontMatterVariables = DEFAULT_SETTINGS.frontMatterVariables;
|
||||
await this.plugin.saveSettings();
|
||||
this.display(); // 刷新显示
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ Enter template for creating synced article file name.
|
|||
</div>
|
||||
`;
|
||||
|
||||
export const metadataTemplateInstructions = `
|
||||
export const metadataVariablesInstructions = `
|
||||
Enter the metadata separated by comma. you can also use custom aliases in the format of metadata::alias.
|
||||
|
||||
<div class="cubox-variables-container">
|
||||
|
|
|
|||
|
|
@ -1,8 +1,26 @@
|
|||
import { CuboxArticle, CuboxHighlight } from './cuboxApi';
|
||||
import { formatISODateTime, generateSafeFileArticleName } from './utils';
|
||||
import * as Mustache from 'mustache';
|
||||
import { formatDateTime, generateSafeFileArticleName } from './utils';
|
||||
//import * as Mustache from 'mustache';
|
||||
import Mustache from 'mustache';
|
||||
import { parseYaml, stringifyYaml } from 'obsidian';
|
||||
|
||||
export const FRONT_MATTER_VARIABLES = [
|
||||
'title',
|
||||
'article_title',
|
||||
'tags',
|
||||
'create_time',
|
||||
'update_time',
|
||||
'domain',
|
||||
'url',
|
||||
'cubox_url',
|
||||
'description',
|
||||
'description',
|
||||
'words_count',
|
||||
'type',
|
||||
'words_count',
|
||||
'id'
|
||||
]
|
||||
|
||||
export class TemplateProcessor {
|
||||
// 存储日期格式
|
||||
private dateFormat: string = 'yyyy-MM-dd';
|
||||
|
|
@ -25,106 +43,75 @@ export class TemplateProcessor {
|
|||
return article.title || 'Untitled';
|
||||
}
|
||||
|
||||
// 使用简单的字符串替换而不是 Mustache
|
||||
let filename = template;
|
||||
// 准备用于 Mustache 的视图对象
|
||||
const view = {
|
||||
title: article.title || '',
|
||||
article_title: article.article_title || '',
|
||||
create_time: article.create_time ? formatDateTime(article.create_time, this.dateFormat) : '',
|
||||
update_time: article.update_time ? formatDateTime(article.update_time, this.dateFormat) : '',
|
||||
domain: article.domain || '',
|
||||
type: article.type || '',
|
||||
id: article.id || '',
|
||||
// 可以根据需要添加更多字段
|
||||
};
|
||||
|
||||
// 替换所有支持的模板字段
|
||||
if (article.title) {
|
||||
filename = filename.replace(/{{{title}}}/g, article.title);
|
||||
}
|
||||
if (article.article_title) {
|
||||
filename = filename.replace(/{{{article_title}}}/g, article.article_title);
|
||||
}
|
||||
|
||||
const createDate = article.create_time ? formatISODateTime(article.create_time, this.dateFormat) : '';
|
||||
if (createDate) {
|
||||
filename = filename.replace(/{{{create_time}}}/g, createDate);
|
||||
let filename = '';
|
||||
try {
|
||||
filename = Mustache.render(template, view);
|
||||
} catch (error) {
|
||||
console.error('模板渲染失败:', error);
|
||||
// 使用备用方案
|
||||
filename = article.title || 'Untitled';
|
||||
}
|
||||
|
||||
const updateDate = article.update_time ? formatISODateTime(article.update_time, this.dateFormat) : '';
|
||||
if (updateDate) {
|
||||
filename = filename.replace(/{{{update_time}}}/g, updateDate);
|
||||
// 限制文件名长度不超过100个字符
|
||||
const MAX_LENGTH = 100;
|
||||
if (filename.length > MAX_LENGTH) {
|
||||
// 如果超过长度限制,截取前100个字符
|
||||
filename = filename.substring(0, MAX_LENGTH);
|
||||
}
|
||||
|
||||
if (article.domain) {
|
||||
filename = filename.replace(/{{{domain}}}/g, article.domain);
|
||||
}
|
||||
|
||||
if (article.type) {
|
||||
filename = filename.replace(/{{{type}}}/g, article.type);
|
||||
}
|
||||
|
||||
// 移除任何未被替换的模板标记 (如果某些字段不存在)
|
||||
filename = filename.replace(/{{{[^}]+}}}/g, '');
|
||||
|
||||
// 处理文件名安全性
|
||||
return generateSafeFileArticleName(filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理前置元数据模板
|
||||
* @param template 模板字符串
|
||||
* @param templateVariables 模板字符串
|
||||
* @param article 文章数据
|
||||
*/
|
||||
processFrontMatterTemplate(template: string, article: CuboxArticle): string {
|
||||
if (!template) {
|
||||
processFrontMatter(templateVariables: string[], article: CuboxArticle): string {
|
||||
if (templateVariables.length === 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
try {
|
||||
// 首先尝试将模板解析为 YAML 对象
|
||||
// 如果模板已经是 YAML 格式,则直接使用
|
||||
const yamlObj = parseYaml(template);
|
||||
|
||||
// 准备用于替换的数据
|
||||
const data = this.prepareTemplateData(article);
|
||||
|
||||
// 递归处理 YAML 对象中的所有字符串值
|
||||
const processedYaml = this.processYamlObject(yamlObj, data);
|
||||
|
||||
// 将处理后的对象转换回 YAML 字符串
|
||||
return stringifyYaml(processedYaml);
|
||||
} catch (e) {
|
||||
// 如果解析失败,则使用 Mustache 渲染模板
|
||||
// 这允许用户直接输入 YAML 格式的字符串
|
||||
const data = this.prepareTemplateData(article);
|
||||
const renderedTemplate = Mustache.render(template, data);
|
||||
|
||||
// 尝试将渲染后的模板解析为 YAML 并重新格式化
|
||||
try {
|
||||
const yamlObj = parseYaml(renderedTemplate);
|
||||
return stringifyYaml(yamlObj);
|
||||
} catch (e) {
|
||||
// 如果仍然无法解析,则返回原始渲染结果
|
||||
return renderedTemplate;
|
||||
}
|
||||
let frontMatter: { [id: string]: unknown } = {
|
||||
id: article.id, // id is required for deduplication
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归处理 YAML 对象中的所有字符串值
|
||||
* @param obj YAML 对象
|
||||
* @param data 替换数据
|
||||
*/
|
||||
private processYamlObject(obj: any, data: any): any {
|
||||
if (typeof obj === 'string') {
|
||||
// 如果是字符串,使用 Mustache 进行模板替换
|
||||
return Mustache.render(obj, data);
|
||||
} else if (Array.isArray(obj)) {
|
||||
// 如果是数组,递归处理每个元素
|
||||
return obj.map(item => this.processYamlObject(item, data));
|
||||
} else if (obj !== null && typeof obj === 'object') {
|
||||
// 如果是对象,递归处理每个属性
|
||||
const result: {[key: string]: any} = {};
|
||||
for (const key in obj) {
|
||||
// 处理键名中的模板变量
|
||||
const processedKey = Mustache.render(key, data);
|
||||
result[processedKey] = this.processYamlObject(obj[key], data);
|
||||
for (const item of templateVariables) {
|
||||
// split the item into variable and alias
|
||||
const aliasedVariables = item.split('::')
|
||||
const variable = aliasedVariables[0]
|
||||
if (
|
||||
variable === 'tags' &&
|
||||
article.tags &&
|
||||
article.tags.length > 0
|
||||
) {
|
||||
// tags are handled separately
|
||||
// use label names as tags
|
||||
frontMatter[variable] = article.tags
|
||||
continue
|
||||
}
|
||||
|
||||
const value = (article as any)[variable]
|
||||
if (value) {
|
||||
// if variable is in article, use it
|
||||
frontMatter[variable] = value
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// 其他类型(数字、布尔值等)直接返回
|
||||
return obj;
|
||||
|
||||
return stringifyYaml(frontMatter)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -164,7 +151,7 @@ export class TemplateProcessor {
|
|||
private prepareTemplateData(article: CuboxArticle): any {
|
||||
// 格式化日期
|
||||
const createDate = article.create_time || '';
|
||||
const formattedDate = createDate ? formatISODateTime(createDate, this.dateFormat) : '';
|
||||
const formattedDate = createDate ? formatDateTime(createDate, this.dateFormat) : '';
|
||||
|
||||
// 格式化高亮内容
|
||||
let highlightsText = '';
|
||||
|
|
@ -190,39 +177,4 @@ export class TemplateProcessor {
|
|||
tags: article.tags || []
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 将对象转换为 YAML 格式的 frontmatter
|
||||
* @param obj 要转换的对象
|
||||
*/
|
||||
objectToYamlFrontmatter(obj: any): string {
|
||||
try {
|
||||
return stringifyYaml(obj);
|
||||
} catch (e) {
|
||||
console.error('将对象转换为 YAML 失败:', e);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 YAML 格式的 frontmatter 为对象
|
||||
* @param yaml YAML 字符串
|
||||
*/
|
||||
yamlFrontmatterToObject(yaml: string): any {
|
||||
try {
|
||||
return parseYaml(yaml);
|
||||
} catch (e) {
|
||||
console.error('解析 YAML 失败:', e);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化日期 - 使用工具方法
|
||||
* @param dateStr 日期字符串
|
||||
* @param format 格式模板
|
||||
*/
|
||||
formatDate(dateStr: string, format: string): string {
|
||||
return formatISODateTime(dateStr, format);
|
||||
}
|
||||
}
|
||||
82
src/utils.ts
82
src/utils.ts
|
|
@ -1,3 +1,5 @@
|
|||
import { DateTime } from 'luxon';
|
||||
|
||||
// 文件名非法字符正则表达式
|
||||
export const ILLEGAL_CHAR_REGEX_FILE = /[<>:"/\\|?*\u0000-\u001F]/g;
|
||||
export const ILLEGAL_CHAR_REGEX_FOLDER = /[<>:"\\|?*\u0000-\u001F]/g;
|
||||
|
|
@ -32,46 +34,60 @@ export const generateSafeFileArticleName = (title: string): string => {
|
|||
};
|
||||
|
||||
/**
|
||||
* 格式化 ISO 时间字符串为可读格式
|
||||
* @param isoString ISO 格式的时间字符串
|
||||
* @param format 可选的格式化模式
|
||||
* 格式化时间字符串为指定格式
|
||||
* @param dateString 输入的时间字符串
|
||||
* @param format 输出格式,支持:YYYY(年), MM(月), DD(日), HH(时), mm(分), ss(秒)
|
||||
* @returns 格式化后的时间字符串
|
||||
*/
|
||||
export const formatISODateTime = (isoString: string, format: string = 'yyyy-MM-dd HH:mm'): string => {
|
||||
if (!isoString) return '';
|
||||
export const formatDateTime = (dateString: string, format: string = 'YYYY-MM-DD HH:mm:ss'): string => {
|
||||
if (!dateString) return '';
|
||||
|
||||
try {
|
||||
// 直接使用 Date 对象处理时间
|
||||
const date = new Date(isoString);
|
||||
// 预处理输入的时间字符串,处理非标准格式
|
||||
let normalizedString = dateString;
|
||||
|
||||
// 检查日期是否有效
|
||||
if (isNaN(date.getTime())) {
|
||||
return isoString;
|
||||
}
|
||||
// 处理类似 2024-04-23T14:30:42:780+08:00 格式(秒与毫秒之间用冒号)
|
||||
normalizedString = normalizedString.replace(/(\d{2}):(\d{2}):(\d{2}):(\d{3})/, '$1:$2:$3.$4');
|
||||
|
||||
// 根据不同格式返回不同的日期字符串
|
||||
if (format === 'yyyy-MM-dd HH:mm' || format === 'YYYY-MM-dd HH:mm') {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||
}
|
||||
else if (format === 'yyyy-MM-dd' || format === 'YYYY-MM-dd') {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
return DateTime.fromISO(normalizedString).toFormat('yyyy-MM-dd HH:mm');
|
||||
|
||||
// 默认返回原始字符串
|
||||
return isoString;
|
||||
// // 检查日期是否有效
|
||||
// if (isNaN(date.getTime())) {
|
||||
// console.warn(`Invalid date string: ${dateString}`);
|
||||
// return dateString;
|
||||
// }
|
||||
|
||||
// // 提取日期各部分
|
||||
// const year = date.getFullYear();
|
||||
// const month = date.getMonth() + 1;
|
||||
// const day = date.getDate();
|
||||
// const hours = date.getHours();
|
||||
// const minutes = date.getMinutes();
|
||||
// const seconds = date.getSeconds();
|
||||
|
||||
// // 格式化各部分,补零
|
||||
// const YYYY = String(year);
|
||||
// const YY = String(year).slice(-2);
|
||||
// const MM = String(month).padStart(2, '0');
|
||||
// const DD = String(day).padStart(2, '0');
|
||||
// const HH = String(hours).padStart(2, '0');
|
||||
// const mm = String(minutes).padStart(2, '0');
|
||||
// const ss = String(seconds).padStart(2, '0');
|
||||
|
||||
// // 使用正则表达式替换格式字符串中的占位符
|
||||
// let result = format
|
||||
// .replace(/YYYY/g, YYYY)
|
||||
// .replace(/YY/g, YY)
|
||||
// .replace(/MM/g, MM)
|
||||
// .replace(/DD/g, DD)
|
||||
// .replace(/HH/g, HH)
|
||||
// .replace(/mm/g, mm)
|
||||
// .replace(/ss/g, ss);
|
||||
|
||||
// return result;
|
||||
} catch (error) {
|
||||
console.error('Error formatting ISO date:', error);
|
||||
return isoString;
|
||||
console.error('Error formatting date:', error);
|
||||
return dateString;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -81,5 +97,5 @@ export const formatISODateTime = (isoString: string, format: string = 'yyyy-MM-d
|
|||
* @returns 格式化后的当前时间字符串
|
||||
*/
|
||||
export const getCurrentFormattedTime = (format: string = 'yyyy-MM-dd HH:mm'): string => {
|
||||
return formatISODateTime(new Date().toISOString(), format);
|
||||
return formatDateTime(new Date().toISOString(), format);
|
||||
};
|
||||
Loading…
Reference in a new issue