normalize-lobster-dates.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. /**
  2. * Normalize lobster page date displays to use lobsterTimeFormatter / lobsterTime filter.
  3. * Run from repo root: node saas-companyui/scripts/normalize-lobster-dates.js
  4. */
  5. const fs = require('fs')
  6. const path = require('path')
  7. const ROOT = path.resolve(__dirname, '../..')
  8. const UI_DIRS = [
  9. path.join(ROOT, 'saas-companyui/src/views/lobster'),
  10. path.join(ROOT, 'saas-mgnui/src/views/lobster'),
  11. path.join(ROOT, 'adminui/src/views/lobster')
  12. ]
  13. const DATE_PROPS = [
  14. 'createTime', 'create_time', 'updateTime', 'update_time',
  15. 'sendTime', 'startTime', 'endTime', 'triggerTime', 'executeTime',
  16. 'lastConversationTime', 'lastEvolutionTime', 'lastMsgTime', 'last_msg_time'
  17. ]
  18. const DATE_PROP_PATTERN = DATE_PROPS.join('|')
  19. function walk(dir, files = []) {
  20. if (!fs.existsSync(dir)) return files
  21. for (const name of fs.readdirSync(dir)) {
  22. const full = path.join(dir, name)
  23. if (fs.statSync(full).isDirectory()) walk(full, files)
  24. else if (name.endsWith('.vue')) files.push(full)
  25. }
  26. return files
  27. }
  28. function addTableFormatters(content) {
  29. const re = new RegExp(
  30. `<el-table-column\\b((?![^>]*:formatter)(?![^>]*slot-scope)[^>]*\\bprop="(${DATE_PROP_PATTERN})"[^>]*?)(\\s*\\/?>)`,
  31. 'g'
  32. )
  33. return content.replace(re, (m, attrs, prop, end) => {
  34. if (attrs.includes('lobsterTimeFormatter')) return m
  35. const trimmedEnd = end.trim() === '/' ? ' />' : '>'
  36. return `<el-table-column${attrs} :formatter="lobsterTimeFormatter"${trimmedEnd}`
  37. })
  38. }
  39. function patchMustache(content) {
  40. let out = content
  41. const exprs = [
  42. 'detail.createTime', 'detail.updateTime', 'detail.create_time', 'detail.update_time',
  43. 'detail.triggerTime', 'logDetail.createTime', 'customer.createTime',
  44. 'gepaDetail.triggerTime'
  45. ]
  46. for (const expr of exprs) {
  47. const fallback = new RegExp(`\\{\\{\\s*${expr.replace(/\./g, '\\.')}\\s*\\|\\|\\s*'-'\\s*\\}\\}`, 'g')
  48. out = out.replace(fallback, `{{ ${expr} | lobsterTime }}`)
  49. const bare = new RegExp(`\\{\\{\\s*${expr.replace(/\./g, '\\.')}\\s*\\}\\}`, 'g')
  50. out = out.replace(bare, `{{ ${expr} | lobsterTime }}`)
  51. }
  52. out = out.replace(/\{\{\s*scope\.row\.createTime\s*\|\|\s*scope\.row\.create_time\s*\}\}/g,
  53. '{{ (scope.row.createTime || scope.row.create_time) | lobsterTime }}')
  54. return out.replace(/\{\{\s*([^|{}]+)\s*\|\s*lobsterTime\s*\|\s*lobsterTime\s*\}\}/g, '{{ $1 | lobsterTime }}')
  55. }
  56. function patchTimestamps(content) {
  57. return content.replace(/:timestamp="([a-zA-Z0-9_.]+)"/g, (m, expr) => {
  58. if (expr.includes('formatLobsterDateTime') || expr.includes('lobsterTime')) return m
  59. return `:timestamp="formatLobsterDateTime(${expr})"`
  60. })
  61. }
  62. function patchFmtTimeFilter(content) {
  63. if (!content.includes('fmtTime(v)')) return content
  64. return content.replace(
  65. /fmtTime\(v\)\s*\{\s*return v \? v\.replace\('T', ' '\)\.substring\(0, 19\) : '-'\s*\}/,
  66. 'fmtTime(v) { return this.formatLobsterDateTime(v) }'
  67. )
  68. }
  69. function patchChatTestFormatTime(content) {
  70. if (!content.includes('formatTime(date)')) return content
  71. return content.replace(
  72. /formatTime\(date\)\s*\{[\s\S]*?\n\s*\}/,
  73. `formatTime(date) {
  74. return this.formatLobsterDateTime(date)
  75. }`
  76. )
  77. }
  78. function patchWorkflowExecution(content) {
  79. if (!content.includes('formatDateTime(val)')) return content
  80. let out = content.replace(
  81. /formatDateTime\(val\)\s*\{\s*\n\s*return parseTime\(val\) \|\| '??'\s*\n\s*\}/,
  82. `formatDateTime(val) {
  83. return this.formatLobsterDateTime(val)
  84. }`
  85. )
  86. if (out.includes("import { parseTime } from '@/utils/common'") && !out.includes('parseTime(')) {
  87. out = out.replace(/import \{ parseTime \} from '@\/utils\/common'\n/, '')
  88. }
  89. return out
  90. }
  91. function processFile(file) {
  92. let content = fs.readFileSync(file, 'utf8')
  93. const original = content
  94. content = addTableFormatters(content)
  95. content = patchMustache(content)
  96. content = patchTimestamps(content)
  97. content = patchFmtTimeFilter(content)
  98. content = patchChatTestFormatTime(content)
  99. content = patchWorkflowExecution(content)
  100. if (content !== original) {
  101. fs.writeFileSync(file, content, 'utf8')
  102. return true
  103. }
  104. return false
  105. }
  106. let changed = 0
  107. for (const dir of UI_DIRS) {
  108. for (const file of walk(dir)) {
  109. if (processFile(file)) {
  110. changed++
  111. console.log('updated', path.relative(ROOT, file))
  112. }
  113. }
  114. }
  115. console.log('done, files changed:', changed)