/** * Normalize lobster page date displays to use lobsterTimeFormatter / lobsterTime filter. * Run from repo root: node saas-companyui/scripts/normalize-lobster-dates.js */ const fs = require('fs') const path = require('path') const ROOT = path.resolve(__dirname, '../..') const UI_DIRS = [ path.join(ROOT, 'saas-companyui/src/views/lobster'), path.join(ROOT, 'saas-mgnui/src/views/lobster'), path.join(ROOT, 'adminui/src/views/lobster') ] const DATE_PROPS = [ 'createTime', 'create_time', 'updateTime', 'update_time', 'sendTime', 'startTime', 'endTime', 'triggerTime', 'executeTime', 'lastConversationTime', 'lastEvolutionTime', 'lastMsgTime', 'last_msg_time' ] const DATE_PROP_PATTERN = DATE_PROPS.join('|') function walk(dir, files = []) { if (!fs.existsSync(dir)) return files for (const name of fs.readdirSync(dir)) { const full = path.join(dir, name) if (fs.statSync(full).isDirectory()) walk(full, files) else if (name.endsWith('.vue')) files.push(full) } return files } function addTableFormatters(content) { const re = new RegExp( `]*:formatter)(?![^>]*slot-scope)[^>]*\\bprop="(${DATE_PROP_PATTERN})"[^>]*?)(\\s*\\/?>)`, 'g' ) return content.replace(re, (m, attrs, prop, end) => { if (attrs.includes('lobsterTimeFormatter')) return m const trimmedEnd = end.trim() === '/' ? ' />' : '>' return ` { if (expr.includes('formatLobsterDateTime') || expr.includes('lobsterTime')) return m return `:timestamp="formatLobsterDateTime(${expr})"` }) } function patchFmtTimeFilter(content) { if (!content.includes('fmtTime(v)')) return content return content.replace( /fmtTime\(v\)\s*\{\s*return v \? v\.replace\('T', ' '\)\.substring\(0, 19\) : '-'\s*\}/, 'fmtTime(v) { return this.formatLobsterDateTime(v) }' ) } function patchChatTestFormatTime(content) { if (!content.includes('formatTime(date)')) return content return content.replace( /formatTime\(date\)\s*\{[\s\S]*?\n\s*\}/, `formatTime(date) { return this.formatLobsterDateTime(date) }` ) } function patchWorkflowExecution(content) { if (!content.includes('formatDateTime(val)')) return content let out = content.replace( /formatDateTime\(val\)\s*\{\s*\n\s*return parseTime\(val\) \|\| '??'\s*\n\s*\}/, `formatDateTime(val) { return this.formatLobsterDateTime(val) }` ) if (out.includes("import { parseTime } from '@/utils/common'") && !out.includes('parseTime(')) { out = out.replace(/import \{ parseTime \} from '@\/utils\/common'\n/, '') } return out } function processFile(file) { let content = fs.readFileSync(file, 'utf8') const original = content content = addTableFormatters(content) content = patchMustache(content) content = patchTimestamps(content) content = patchFmtTimeFilter(content) content = patchChatTestFormatTime(content) content = patchWorkflowExecution(content) if (content !== original) { fs.writeFileSync(file, content, 'utf8') return true } return false } let changed = 0 for (const dir of UI_DIRS) { for (const file of walk(dir)) { if (processFile(file)) { changed++ console.log('updated', path.relative(ROOT, file)) } } } console.log('done, files changed:', changed)