import moment from 'moment' type RTimeElement = HTMLElement & { _next_timer?: number } const parseInterval = (arg: string | undefined): number => { if (!arg) { return 60 * 1000 } const match = arg.match(/^(\d+)([smhd])$/) if (!match) { return 60 * 1000 } const [, numStr, unit] = match const num = parseInt(String(numStr), 10) switch (unit) { case 'd': return num * 24 * 3600 * 1000 case 'h': return num * 3600 * 1000 case 'm': return num * 60 * 1000 case 's': return num * 1000 default: return 60 * 1000 } } export default defineNuxtPlugin(nuxtApp => { nuxtApp.vueApp.directive('rtime', { mounted(el: RTimeElement, binding) { const intervalMs = parseInterval(binding.arg) const update = () => { const val = binding.value if (Number.isFinite(val)) { el.textContent = moment.unix(val as number).fromNow() return } el.textContent = moment(val).fromNow() } update() el._next_timer = window.setInterval(update, intervalMs) }, updated(el: RTimeElement, binding) { if (binding.oldValue !== binding.value) { if (null != el._next_timer) clearInterval(el._next_timer) const intervalMs = parseInterval(binding.arg) const update = () => { const val = binding.value if (Number.isFinite(val)) { el.textContent = moment.unix(val as number).fromNow() return } el.textContent = moment(val).fromNow() } update() el._next_timer = window.setInterval(update, intervalMs) } }, beforeUnmount(el: RTimeElement) { if (null != el._next_timer) clearInterval(el._next_timer) } }) return {} })