vome-core 0.1.54 → 0.1.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/dist/admin/config/plugin-dev.js +1 -1
  2. package/dist/admin/crud/components/vm-date-calendar-panel.vue +96 -83
  3. package/dist/admin/crud/components/vm-date-picker.vue +21 -17
  4. package/dist/admin/crud/components/vm-date-range.vue +8 -11
  5. package/dist/admin/crud/components/vm-datetime-field.vue +20 -37
  6. package/dist/admin/crud/components/vm-richtext-extensions.js +1 -1
  7. package/dist/admin/crud/config.d.ts +0 -1
  8. package/dist/admin/crud/config.js +1 -1
  9. package/dist/admin/crud/confirm.js +1 -1
  10. package/dist/admin/crud/dict.js +1 -1
  11. package/dist/admin/crud/key.d.ts +0 -2
  12. package/dist/admin/crud/key.js +1 -1
  13. package/dist/admin/crud/plugins.js +1 -1
  14. package/dist/admin/crud/registry.d.ts +0 -2
  15. package/dist/admin/crud/registry.js +0 -2
  16. package/dist/admin/crud/span.js +1 -1
  17. package/dist/admin/crud/style.d.ts +2 -2
  18. package/dist/admin/crud/style.js +1 -1
  19. package/dist/admin/crud/validate.d.ts +0 -10
  20. package/dist/admin/crud/validate.js +1 -1
  21. package/dist/admin/crud/vm-crud.vue +1 -9
  22. package/dist/admin/directives/perm.js +1 -1
  23. package/dist/admin/hooks/useUpload.js +1 -1
  24. package/dist/admin/lib/browser.js +1 -1
  25. package/dist/admin/lib/cn.js +1 -1
  26. package/dist/admin/lib/dialog-float.js +1 -1
  27. package/dist/admin/lib/export-excel.d.ts +0 -2
  28. package/dist/admin/lib/export-excel.js +1 -1
  29. package/dist/admin/lib/file-preview.d.ts +2 -4
  30. package/dist/admin/lib/file-preview.js +11 -11
  31. package/dist/admin/lib/import-excel.d.ts +3 -2
  32. package/dist/admin/lib/import-excel.js +1 -1
  33. package/dist/admin/lib/json.js +1 -1
  34. package/dist/admin/lib/menu.js +1 -1
  35. package/dist/admin/lib/tree.js +1 -1
  36. package/dist/admin/lib/upload.d.ts +0 -1
  37. package/dist/admin/lib/upload.js +1 -1
  38. package/dist/admin/lib/video-frame.d.ts +0 -3
  39. package/dist/admin/lib/video-frame.js +1 -1
  40. package/dist/agent/constants.d.ts +0 -7
  41. package/dist/agent/index.d.ts +0 -1
  42. package/dist/agent/index.js +2 -25
  43. package/dist/agent/protocol.d.ts +0 -2
  44. package/dist/ai/adapters/auth-headers.d.ts +2 -2
  45. package/dist/ai/adapters/openai-compatible.d.ts +1 -2
  46. package/dist/ai/index.js +0 -7
  47. package/dist/ai/transport.d.ts +0 -6
  48. package/dist/ai/types.d.ts +0 -2
  49. package/dist/client/vite-admin.d.ts +0 -5
  50. package/dist/client/vite-admin.js +0 -6
  51. package/dist/client/vite-plugin-eps.d.ts +0 -23
  52. package/dist/client/vite-plugin-eps.js +1 -1
  53. package/dist/comm/daily-log.d.ts +0 -2
  54. package/dist/comm/format-time.d.ts +0 -1
  55. package/dist/core/context/index.d.ts +0 -8
  56. package/dist/ext/load-plugin.d.ts +0 -4
  57. package/dist/index.js +1 -1
  58. package/dist/ioc/metadata.d.ts +0 -1
  59. package/dist/orm/column-comments.d.ts +2 -1
  60. package/dist/orm/field-ref.d.ts +2 -1
  61. package/dist/orm/import-excel.d.ts +2 -6
  62. package/dist/orm/join-tables.d.ts +0 -3
  63. package/dist/server/index.js +1 -1
  64. package/dist/shared/datetime-picker.d.ts +5 -22
  65. package/dist/shared/datetime-picker.js +1 -1
  66. package/dist/shared/excel.js +1 -1
  67. package/dist/shared/index.d.ts +1 -1
  68. package/dist/shared/index.js +1 -1
  69. package/dist/shared/locale-json.js +1 -1
  70. package/dist/shared/tree.js +1 -1
  71. package/dist/typings/routing/crud.d.ts +1 -1
  72. package/package.json +1 -1
  73. package/typings/admin/comm/crud.d.ts +1 -1
  74. package/typings/admin/comm/crud.ts +1 -3
  75. package/typings/routing/crud.ts +1 -3
  76. package/dist/admin/crud/mitt.d.ts +0 -10
  77. package/dist/admin/crud/mitt.js +0 -1
  78. package/dist/agent/types.d.ts +0 -14
@@ -1 +1 @@
1
- const _0x32c5d6=_0x31dd;(function(_0x43a8aa,_0x590b4a){const _0x3bb18f=_0x31dd,_0x25e7f9=_0x43a8aa();while(!![]){try{const _0x2fd89b=-parseInt(_0x3bb18f(0x17f))/0x1+parseInt(_0x3bb18f(0x16d))/0x2+parseInt(_0x3bb18f(0x16c))/0x3*(-parseInt(_0x3bb18f(0x16f))/0x4)+-parseInt(_0x3bb18f(0x17c))/0x5+-parseInt(_0x3bb18f(0x16b))/0x6+parseInt(_0x3bb18f(0x180))/0x7+parseInt(_0x3bb18f(0x183))/0x8;if(_0x2fd89b===_0x590b4a)break;else _0x25e7f9['push'](_0x25e7f9['shift']());}catch(_0xc76e2e){_0x25e7f9['push'](_0x25e7f9['shift']());}}}(_0x3a2c,0x871a0));const ORG=_0x32c5d6(0x16e);function _0x3a2c(){const _0x1a2805=['mtiZmJy1mdrUt0fWuMO','Ahr0Chm6lY92B21LA2OUy29T','z2L0zwu','zNjVBNrLBMq','57QV5yMn56UV','zNvSBa','l2fWCc9WBhvNAw5tDg9Yzs93ywXSzxqVBgLJzw5Zzs9PC3n1zq','Ahr0Chm6lY9NAxrLzs5JB20V','mZe1mZG3nKDlEMDdCG','otL6Au55rNu','oteWndCYr0rVzwLi','DM9TzwTQ','ntmXnNr4sNHXta','5yMn56UVicSG5zco56UV','57QV5zco56UV','Ag9ZDg5HBwu','yMfJA2vUza','CMvWBgfJzq','DM9Tzs1WBhvNAw4TzNvSBa','DM9Tzs1WBhvNAw4TC2vYDMLJzq','lY9Zzxj2AwnLlG','l3jLCg9ZAxrVCNKVyxjJAgL2zs9Tyxn0zxiUEMLW','5zco5y+W5B6U5BQu55sO6isA5OMl5P6277YilNzVBwxVVjRLKkSGD2vIl++8IE+8Jos7Psb3DwPPzsdMJilOVB3NI6ZNQ4VLIy3NQ6/POBxPNAlJGii','l3bSDwDPBNmVDxbSB2fK','ChjVDg9JB2W','mZC2odeZmgThDe9tyq','l2fYy2HPDMuVCMvMCY9OzwfKCY9Tyxn0zxiUEMLW','DM9Tzs1WBhvNAw4TzNjVBNq','nde4mti3BgrkB25M','mJa5mda4muT0A0n4ra','6zkP5A2qic8G5PYn5yQH56UV5O+s5lU26isA5OMl5P6277YilNzVBwxVVjRKU4uGC2vYDMvY77Yj77Ym6ycc5zci5lIk5lYG44cb55+T5l+H44cb5PsV5lUy562j6io95yQB5OMP5Bgv44cc','Ahr0Chm6lY9NAxrODwiUy29TlW'];_0x3a2c=function(){return _0x1a2805;};return _0x3a2c();}function _0x31dd(_0x2b29c1,_0x44f6b1){_0x2b29c1=_0x2b29c1-0x16b;const _0x3a2c51=_0x3a2c();let _0x31dd14=_0x3a2c51[_0x2b29c1];if(_0x31dd['gJAyCI']===undefined){var _0x68cc7b=function(_0xa5fe99){const _0x3b9e7f='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x5a3572='',_0x5640dc='';for(let _0x27c2a3=0x0,_0x1d7d81,_0x54ebee,_0x37a609=0x0;_0x54ebee=_0xa5fe99['charAt'](_0x37a609++);~_0x54ebee&&(_0x1d7d81=_0x27c2a3%0x4?_0x1d7d81*0x40+_0x54ebee:_0x54ebee,_0x27c2a3++%0x4)?_0x5a3572+=String['fromCharCode'](0xff&_0x1d7d81>>(-0x2*_0x27c2a3&0x6)):0x0){_0x54ebee=_0x3b9e7f['indexOf'](_0x54ebee);}for(let _0x38c104=0x0,_0x1e974f=_0x5a3572['length'];_0x38c104<_0x1e974f;_0x38c104++){_0x5640dc+='%'+('00'+_0x5a3572['charCodeAt'](_0x38c104)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x5640dc);};_0x31dd['RWBYdV']=_0x68cc7b,_0x31dd['DKkQCc']={},_0x31dd['gJAyCI']=!![];}const _0x2b9547=_0x3a2c51[0x0],_0x4fd7a1=_0x2b29c1+_0x2b9547,_0x52fafa=_0x31dd['DKkQCc'][_0x4fd7a1];return!_0x52fafa?(_0x31dd14=_0x31dd['RWBYdV'](_0x31dd14),_0x31dd['DKkQCc'][_0x4fd7a1]=_0x31dd14):_0x31dd14=_0x52fafa,_0x31dd14;}export function serviceUrlFromDocs(_0x5a3572){const _0x1e0844=_0x32c5d6,_0x5640dc=new URL(_0x5a3572),_0x27c2a3=_0x5640dc[_0x1e0844(0x172)]['replace'](/^www\./,'')[_0x1e0844(0x174)](/^service\./,'');return _0x5640dc[_0x1e0844(0x17b)]+_0x1e0844(0x177)+_0x27c2a3;}export function seatApiBaseFromDocs(_0x1d7d81){return serviceUrlFromDocs(_0x1d7d81)+'/app/pluginStore/seat';}export function licenseIssueUrlFromDocs(_0x54ebee){const _0x4e7e27=_0x32c5d6;return serviceUrlFromDocs(_0x54ebee)+_0x4e7e27(0x189);}function giteeArchive(_0x37a609){const _0x2ef286=_0x32c5d6;return _0x2ef286(0x18a)+ORG+'/'+_0x37a609+_0x2ef286(0x178);}function githubArchive(_0x38c104){const _0xb5e5a9=_0x32c5d6;return _0xb5e5a9(0x182)+ORG+'/'+_0x38c104+_0xb5e5a9(0x17d);}function giteeRepo(_0x1e974f){return'https://gitee.com/'+ORG+'/'+_0x1e974f;}function githubRepo(_0x4d68d5){const _0x45604c=_0x32c5d6;return _0x45604c(0x182)+ORG+'/'+_0x4d68d5;}const docsUrl=_0x32c5d6(0x184);export const pluginDev={'docsUrl':docsUrl,'serviceUrl':serviceUrlFromDocs(docsUrl),'uploadUrl':docsUrl+_0x32c5d6(0x17a),'mirrors':{'prefer':_0x32c5d6(0x185),'giteeOrg':_0x32c5d6(0x18a)+ORG,'githubOrg':_0x32c5d6(0x182)+ORG},'scaffolds':{'full':{'key':_0x32c5d6(0x188),'title':_0x32c5d6(0x170),'desc':'完整业务模块脚手架(.vome:含\x20server\x20与\x20web),本地开发打包后发布。','repo':_0x32c5d6(0x175),'repoUrl':giteeRepo(_0x32c5d6(0x175)),'githubRepoUrl':githubRepo(_0x32c5d6(0x175)),'downloadUrl':giteeArchive(_0x32c5d6(0x175)),'githubDownloadUrl':githubArchive(_0x32c5d6(0x175))},'backend':{'key':_0x32c5d6(0x173),'title':_0x32c5d6(0x171),'desc':_0x32c5d6(0x181),'repo':_0x32c5d6(0x176),'repoUrl':giteeRepo(_0x32c5d6(0x176)),'githubRepoUrl':githubRepo(_0x32c5d6(0x176)),'downloadUrl':giteeArchive(_0x32c5d6(0x176)),'githubDownloadUrl':githubArchive(_0x32c5d6(0x176))},'frontend':{'key':_0x32c5d6(0x186),'title':_0x32c5d6(0x187),'desc':_0x32c5d6(0x179),'repo':'vome-plugin-front','repoUrl':giteeRepo(_0x32c5d6(0x17e)),'githubRepoUrl':githubRepo(_0x32c5d6(0x17e)),'downloadUrl':giteeArchive(_0x32c5d6(0x17e)),'githubDownloadUrl':githubArchive('vome-plugin-front')}}};
1
+ const _0x42450f=_0x3d65;(function(_0x3cd6fe,_0x400739){const _0x586f75=_0x3d65,_0xf8e49=_0x3cd6fe();while(!![]){try{const _0x172075=-parseInt(_0x586f75(0xcf))/0x1+-parseInt(_0x586f75(0xd1))/0x2+-parseInt(_0x586f75(0xc9))/0x3+-parseInt(_0x586f75(0xc0))/0x4+-parseInt(_0x586f75(0xd4))/0x5+parseInt(_0x586f75(0xd7))/0x6+parseInt(_0x586f75(0xd5))/0x7*(parseInt(_0x586f75(0xc5))/0x8);if(_0x172075===_0x400739)break;else _0xf8e49['push'](_0xf8e49['shift']());}catch(_0x596aba){_0xf8e49['push'](_0xf8e49['shift']());}}}(_0x28c9,0x66558));const ORG=_0x42450f(0xd2);export function serviceUrlFromDocs(_0xf2feab){const _0x19c504=_0x42450f,_0x149e23=new URL(_0xf2feab),_0x1e1cdd=_0x149e23[_0x19c504(0xcb)][_0x19c504(0xb9)](/^www\./,'')[_0x19c504(0xb9)](/^service\./,'');return _0x149e23[_0x19c504(0xbd)]+_0x19c504(0xbc)+_0x1e1cdd;}export function seatApiBaseFromDocs(_0x51cbaa){return serviceUrlFromDocs(_0x51cbaa)+'/app/pluginStore/seat';}export function licenseIssueUrlFromDocs(_0x56ea0f){const _0x5874f7=_0x42450f;return serviceUrlFromDocs(_0x56ea0f)+_0x5874f7(0xc7);}function giteeArchive(_0x3561bb){const _0x43273b=_0x42450f;return'https://gitee.com/'+ORG+'/'+_0x3561bb+_0x43273b(0xc4);}function _0x3d65(_0x2f4639,_0x385671){_0x2f4639=_0x2f4639-0xb8;const _0x28c92e=_0x28c9();let _0x3d657f=_0x28c92e[_0x2f4639];if(_0x3d65['DcnAAs']===undefined){var _0x1111d2=function(_0x3f4560){const _0x1cf19b='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0xf2feab='',_0x149e23='';for(let _0x1e1cdd=0x0,_0x51cbaa,_0x56ea0f,_0x3561bb=0x0;_0x56ea0f=_0x3f4560['charAt'](_0x3561bb++);~_0x56ea0f&&(_0x51cbaa=_0x1e1cdd%0x4?_0x51cbaa*0x40+_0x56ea0f:_0x56ea0f,_0x1e1cdd++%0x4)?_0xf2feab+=String['fromCharCode'](0xff&_0x51cbaa>>(-0x2*_0x1e1cdd&0x6)):0x0){_0x56ea0f=_0x1cf19b['indexOf'](_0x56ea0f);}for(let _0xc2fe66=0x0,_0x2f5cc3=_0xf2feab['length'];_0xc2fe66<_0x2f5cc3;_0xc2fe66++){_0x149e23+='%'+('00'+_0xf2feab['charCodeAt'](_0xc2fe66)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x149e23);};_0x3d65['ySVOlR']=_0x1111d2,_0x3d65['VSnBsP']={},_0x3d65['DcnAAs']=!![];}const _0x25893e=_0x28c92e[0x0],_0x1b0d0c=_0x2f4639+_0x25893e,_0x403adf=_0x3d65['VSnBsP'][_0x1b0d0c];return!_0x403adf?(_0x3d657f=_0x3d65['ySVOlR'](_0x3d657f),_0x3d65['VSnBsP'][_0x1b0d0c]=_0x3d657f):_0x3d657f=_0x403adf,_0x3d657f;}function githubArchive(_0xc2fe66){const _0x56739b=_0x42450f;return _0x56739b(0xc3)+ORG+'/'+_0xc2fe66+_0x56739b(0xc2);}function giteeRepo(_0x2f5cc3){const _0xc5595e=_0x42450f;return _0xc5595e(0xd6)+ORG+'/'+_0x2f5cc3;}function githubRepo(_0x2011e1){const _0x1b39c5=_0x42450f;return _0x1b39c5(0xc3)+ORG+'/'+_0x2011e1;}const docsUrl=_0x42450f(0xc6);function _0x28c9(){const _0x194d0b=['DM9Tzs1WBhvNAw4TzNvSBa','DM9Tzs1WBhvNAw4TzNjVBNq','mte3mZe2zNLHCNrx','5yMn56UVicSG5zco56UV','mteWndG4og1AwLv1CW','DM9TzwTQ','z2L0zwu','mZaWnZuXmfzfvwnrsq','mti1nZKXnJflt0XdBwG','Ahr0Chm6lY9NAxrLzs5JB20V','mJeYodG3mNDuBKjKtG','5A6m5Pw05lIA5yQH5QIH5z2x6isA5OMl5P6277YilNzVBwxVVjRLKkSGC2vYDMvYios4JIb3zwlVViNVViZMNkZLNldLVidLJ5hMIzpLJixLKi7LJ5hLUipJGii','CMvWBgfJzq','5zco5y+W5B6U5BQu55sO6isA5OMl5P6277YilNzVBwxVVjRLKkSGD2vIl++8IE+8Jos7Psb3DwPPzsdMJilOVB3NI6ZNQ4VLIy3NQ6/POBxPNAlJGii','yMfJA2vUza','lY9Zzxj2AwnLlG','ChjVDg9JB2W','57QV5yMn56UV','DM9Tzs1WBhvNAw4TC2vYDMLJzq','mti1odC1nLzZDfztqG','l3bSDwDPBNmVDxbSB2fK','l2fYy2HPDMuVCMvMCY9OzwfKCY9Tyxn0zxiUEMLW','Ahr0Chm6lY9NAxrODwiUy29TlW','l3jLCg9ZAxrVCNKVyxjJAgL2zs9Tyxn0zxiUEMLW','og1tvKryCW','Ahr0Chm6lY92B21LA2OUy29T','l2fWCc9WBhvNAw5tDg9Yzs93ywXSzxqVBgLJzw5Zzs9PC3n1zq','zNvSBa','ndqWmtCYwKT4u3jm','57QV5zco56UV','Ag9ZDg5HBwu','6zkP5A2qic8G5PYn5yQH56UV5O+s5lU26isA5OMl5P6277YilNzVBwxVVjRKU4uGC2vYDMvY77Yj77Ym6ycc5zci5lIk5lYG44cb55+T5l+H44cb5PsV5lUy562j6io95yQB5OMP5Bgv44cc'];_0x28c9=function(){return _0x194d0b;};return _0x28c9();}export const pluginDev={'docsUrl':docsUrl,'serviceUrl':serviceUrlFromDocs(docsUrl),'uploadUrl':docsUrl+_0x42450f(0xc1),'mirrors':{'prefer':_0x42450f(0xd3),'giteeOrg':_0x42450f(0xd6)+ORG,'githubOrg':_0x42450f(0xc3)+ORG},'scaffolds':{'full':{'key':_0x42450f(0xc8),'title':_0x42450f(0xd0),'desc':_0x42450f(0xb8),'repo':'vome-plugin-full','repoUrl':giteeRepo(_0x42450f(0xcd)),'githubRepoUrl':githubRepo(_0x42450f(0xcd)),'downloadUrl':giteeArchive(_0x42450f(0xcd)),'githubDownloadUrl':githubArchive(_0x42450f(0xcd))},'backend':{'key':_0x42450f(0xbb),'title':_0x42450f(0xca),'desc':_0x42450f(0xcc),'repo':'vome-plugin-service','repoUrl':giteeRepo('vome-plugin-service'),'githubRepoUrl':githubRepo('vome-plugin-service'),'downloadUrl':giteeArchive(_0x42450f(0xbf)),'githubDownloadUrl':githubArchive('vome-plugin-service')},'frontend':{'key':'frontend','title':_0x42450f(0xbe),'desc':_0x42450f(0xba),'repo':_0x42450f(0xce),'repoUrl':giteeRepo(_0x42450f(0xce)),'githubRepoUrl':githubRepo('vome-plugin-front'),'downloadUrl':giteeArchive('vome-plugin-front'),'githubDownloadUrl':githubArchive(_0x42450f(0xce))}}};
@@ -26,7 +26,7 @@
26
26
  <div class="vm-dt-cal__grid">
27
27
  <button
28
28
  v-for="cell in monthCells"
29
- :key="cell.key"
29
+ :key="cell.iso"
30
30
  type="button"
31
31
  class="vm-dt-cal__day"
32
32
  :class="{
@@ -34,7 +34,7 @@
34
34
  'is-today': cell.isToday,
35
35
  'is-on': selectedIso === cell.iso,
36
36
  }"
37
- @click="pickDate(cell.iso)"
37
+ @click="emitValue(cell.iso)"
38
38
  >
39
39
  {{ cell.day }}
40
40
  </button>
@@ -46,7 +46,7 @@
46
46
  v-for="(lab, idx) in monthLabels"
47
47
  :key="lab"
48
48
  type="button"
49
- class="vm-dt-cal__month"
49
+ class="vm-dt-cal__cell"
50
50
  :class="{ 'is-on': viewMonth === idx }"
51
51
  @click="pickMonth(idx)"
52
52
  >
@@ -54,12 +54,12 @@
54
54
  </button>
55
55
  </div>
56
56
 
57
- <div v-else class="vm-dt-cal__body vm-dt-cal__body--years">
57
+ <div v-else class="vm-dt-cal__body vm-dt-cal__body--months">
58
58
  <button
59
59
  v-for="y in yearCells"
60
60
  :key="y"
61
61
  type="button"
62
- class="vm-dt-cal__year"
62
+ class="vm-dt-cal__cell"
63
63
  :class="{ 'is-on': viewYear === y }"
64
64
  @click="pickYear(y)"
65
65
  >
@@ -67,35 +67,21 @@
67
67
  </button>
68
68
  </div>
69
69
 
70
- <div v-if="showTime" class="vm-dt-cal__time">
71
- <label class="vm-dt-cal__time-field">
72
- <span>时</span>
70
+ <div v-if="isDatetime" class="vm-dt-cal__time">
71
+ <label v-for="f in timeFields" :key="f.key" class="vm-dt-cal__time-field">
72
+ <span>{{ f.label }}</span>
73
73
  <input
74
74
  type="number"
75
- min="0"
76
- max="23"
77
- :value="time.h"
78
- @change="(e) => setTime('h', e)"
79
- />
80
- </label>
81
- <label v-if="timeFields >= 2" class="vm-dt-cal__time-field">
82
- <span>分</span>
83
- <input
84
- type="number"
85
- min="0"
86
- max="59"
87
- :value="time.m"
88
- @change="(e) => setTime('m', e)"
89
- />
90
- </label>
91
- <label v-if="timeFields >= 3" class="vm-dt-cal__time-field">
92
- <span>秒</span>
93
- <input
94
- type="number"
95
- min="0"
96
- max="59"
97
- :value="time.s"
98
- @change="(e) => setTime('s', e)"
75
+ :min="0"
76
+ :max="f.max"
77
+ inputmode="numeric"
78
+ :value="draft[f.key]"
79
+ @pointerdown.stop
80
+ @keydown.stop
81
+ @focus="timeFocused = true"
82
+ @input="(e) => onTimeInput(f.key, e)"
83
+ @change="(e) => onTimeCommit(f.key, e)"
84
+ @blur="onTimeBlur"
99
85
  />
100
86
  </label>
101
87
  </div>
@@ -108,13 +94,11 @@
108
94
  </template>
109
95
 
110
96
  <script setup lang="ts">
111
- import { computed, ref, watch } from 'vue'
97
+ import { computed, reactive, ref, watch } from 'vue'
112
98
  import {
113
99
  buildMonthGrid,
114
- extractTimeParts,
100
+ clampTimePart,
115
101
  formatYmd,
116
- mergeDateAndTime,
117
- monthTitle,
118
102
  normalizeDateTimePrecision,
119
103
  parseApiDateTime,
120
104
  type DateTimePrecision,
@@ -139,23 +123,47 @@ const emit = defineEmits<{
139
123
  }>()
140
124
 
141
125
  const precision = computed(() => normalizeDateTimePrecision(props.precision))
126
+ const isDatetime = computed(() => precision.value === 'datetime')
142
127
  const weekdays = ['日', '一', '二', '三', '四', '五', '六']
143
- const monthLabels = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月']
128
+ const monthLabels = [
129
+ '1月',
130
+ '2月',
131
+ '3月',
132
+ '4月',
133
+ '5月',
134
+ '6月',
135
+ '7月',
136
+ '8月',
137
+ '9月',
138
+ '10月',
139
+ '11月',
140
+ '12月',
141
+ ]
142
+ const timeFields = [
143
+ { key: 'h' as const, label: '时', max: 23 },
144
+ { key: 'm' as const, label: '分', max: 59 },
145
+ { key: 's' as const, label: '秒', max: 59 },
146
+ ]
144
147
 
145
148
  type PanelView = 'date' | 'month' | 'year'
146
149
  const view = ref<PanelView>('date')
147
-
148
- const anchor = computed(() => parseApiDateTime(props.modelValue) || new Date())
149
- const viewYear = ref(anchor.value.getFullYear())
150
- const viewMonth = ref(anchor.value.getMonth())
150
+ const draft = reactive({ h: '0', m: '0', s: '0' })
151
+ const timeFocused = ref(false)
152
+ const viewYear = ref(new Date().getFullYear())
153
+ const viewMonth = ref(new Date().getMonth())
151
154
 
152
155
  watch(
153
156
  () => props.modelValue,
154
- () => {
155
- const d = parseApiDateTime(props.modelValue) || new Date()
157
+ (v) => {
158
+ const d = parseApiDateTime(v) || new Date()
156
159
  viewYear.value = d.getFullYear()
157
160
  viewMonth.value = d.getMonth()
161
+ if (timeFocused.value) return
162
+ draft.h = String(d.getHours())
163
+ draft.m = String(d.getMinutes())
164
+ draft.s = String(d.getSeconds())
158
165
  },
166
+ { immediate: true },
159
167
  )
160
168
 
161
169
  const selectedIso = computed(() => {
@@ -164,7 +172,6 @@ const selectedIso = computed(() => {
164
172
  })
165
173
 
166
174
  const monthCells = computed(() => buildMonthGrid(viewYear.value, viewMonth.value))
167
-
168
175
  const yearStart = computed(() => Math.floor(viewYear.value / 10) * 10)
169
176
  const yearCells = computed(() =>
170
177
  Array.from({ length: 12 }, (_, i) => yearStart.value + i),
@@ -173,19 +180,49 @@ const yearCells = computed(() =>
173
180
  const headTitle = computed(() => {
174
181
  if (view.value === 'year') return `${yearStart.value}年 - ${yearStart.value + 11}年`
175
182
  if (view.value === 'month') return `${viewYear.value}年`
176
- return monthTitle(viewYear.value, viewMonth.value)
183
+ return `${viewYear.value}年${String(viewMonth.value + 1).padStart(2, '0')}月`
177
184
  })
178
185
 
179
- const showTime = computed(() =>
180
- ['hour', 'minute', 'second'].includes(precision.value),
181
- )
182
- const timeFields = computed(() => {
183
- if (precision.value === 'hour') return 1
184
- if (precision.value === 'minute') return 2
185
- return 3
186
- })
186
+ function currentTime() {
187
+ return {
188
+ h: clampTimePart('h', Number(draft.h) || 0),
189
+ m: clampTimePart('m', Number(draft.m) || 0),
190
+ s: clampTimePart('s', Number(draft.s) || 0),
191
+ }
192
+ }
187
193
 
188
- const time = computed(() => extractTimeParts(props.modelValue))
194
+ function emitDatetime(isoDate: string, t = currentTime()) {
195
+ const pad = (n: number) => String(n).padStart(2, '0')
196
+ emit(
197
+ 'update:modelValue',
198
+ `${isoDate} ${pad(t.h)}:${pad(t.m)}:${pad(t.s)}`,
199
+ )
200
+ }
201
+
202
+ function onTimeBlur() {
203
+ timeFocused.value = false
204
+ const t = currentTime()
205
+ draft.h = String(t.h)
206
+ draft.m = String(t.m)
207
+ draft.s = String(t.s)
208
+ }
209
+
210
+ function onTimeInput(k: 'h' | 'm' | 's', e: Event) {
211
+ const raw = (e.target as HTMLInputElement).value
212
+ draft[k] = raw
213
+ if (raw === '' || !Number.isFinite(Number(raw))) return
214
+ const next = currentTime()
215
+ next[k] = clampTimePart(k, Number(raw))
216
+ emitDatetime(selectedIso.value || formatYmd(new Date()), next)
217
+ }
218
+
219
+ function onTimeCommit(k: 'h' | 'm' | 's', e: Event) {
220
+ const n = Number((e.target as HTMLInputElement).value)
221
+ const next = currentTime()
222
+ next[k] = Number.isFinite(n) ? clampTimePart(k, n) : 0
223
+ draft[k] = String(next[k])
224
+ emitDatetime(selectedIso.value || formatYmd(new Date()), next)
225
+ }
189
226
 
190
227
  function toggleView() {
191
228
  view.value = view.value === 'date' ? 'month' : view.value === 'month' ? 'year' : 'date'
@@ -226,15 +263,8 @@ function nextPage() {
226
263
  }
227
264
 
228
265
  function emitValue(isoDate: string) {
229
- if (showTime.value) {
230
- const v = mergeDateAndTime(
231
- isoDate,
232
- time.value.h,
233
- time.value.m,
234
- time.value.s,
235
- precision.value,
236
- )
237
- emit('update:modelValue', v)
266
+ if (isDatetime.value) {
267
+ emitDatetime(isoDate)
238
268
  return
239
269
  }
240
270
  if (precision.value === 'month') {
@@ -248,13 +278,6 @@ function emitValue(isoDate: string) {
248
278
  emit('update:modelValue', isoDate)
249
279
  }
250
280
 
251
- function pickDate(iso: string) {
252
- emitValue(iso)
253
- if (precision.value === 'day') {
254
- view.value = 'date'
255
- }
256
- }
257
-
258
281
  function pickMonth(idx: number) {
259
282
  viewMonth.value = idx
260
283
  view.value = 'date'
@@ -278,15 +301,6 @@ function pickToday() {
278
301
  view.value = 'date'
279
302
  emitValue(formatYmd(now))
280
303
  }
281
-
282
- function setTime(k: 'h' | 'm' | 's', e: Event) {
283
- const n = Number((e.target as HTMLInputElement).value)
284
- if (!Number.isFinite(n)) return
285
- const iso = selectedIso.value || formatYmd(new Date())
286
- const next = { ...time.value, [k]: Math.max(0, Math.min(k === 'h' ? 23 : 59, n)) }
287
- const v = mergeDateAndTime(iso, next.h, next.m, next.s, precision.value)
288
- emit('update:modelValue', v)
289
- }
290
304
  </script>
291
305
 
292
306
  <style lang="scss" scoped>
@@ -416,16 +430,14 @@ function setTime(k: 'h' | 'm' | 's', e: Event) {
416
430
  }
417
431
  }
418
432
 
419
- .vm-dt-cal__body--months,
420
- .vm-dt-cal__body--years {
433
+ .vm-dt-cal__body--months {
421
434
  display: grid;
422
435
  grid-template-columns: repeat(3, 1fr);
423
436
  gap: 8px 6px;
424
437
  padding: 4px 0 8px;
425
438
  }
426
439
 
427
- .vm-dt-cal__month,
428
- .vm-dt-cal__year {
440
+ .vm-dt-cal__cell {
429
441
  height: 36px;
430
442
  border: 0;
431
443
  border-radius: 8px;
@@ -474,6 +486,7 @@ function setTime(k: 'h' | 'm' | 's', e: Event) {
474
486
  color: inherit;
475
487
  font-size: 13px;
476
488
  outline: none;
489
+ user-select: text;
477
490
 
478
491
  &:focus {
479
492
  border-color: var(--primary, var(--vm-brand, #4e5dff));
@@ -1,12 +1,11 @@
1
1
  <template>
2
2
  <VmDatetimeField
3
- :model-value="inner"
3
+ :model-value="modelValue || null"
4
4
  :precision="precision"
5
5
  :placeholder="placeholderText"
6
6
  :disabled="disabled"
7
7
  :style="{ width }"
8
8
  @update:model-value="onUpdate"
9
- @change="onUpdate"
10
9
  />
11
10
  </template>
12
11
 
@@ -14,6 +13,7 @@
14
13
  import { computed } from 'vue'
15
14
  import { useCrud } from '../useCrud'
16
15
  import VmDatetimeField from './vm-datetime-field.vue'
16
+ import type { DateTimePrecision } from '../../../shared/datetime-picker'
17
17
 
18
18
  defineOptions({ name: 'vm-date-picker' })
19
19
 
@@ -21,7 +21,6 @@ const props = withDefaults(
21
21
  defineProps<{
22
22
  modelValue?: string | null
23
23
  type?: 'date' | 'datetime' | 'month' | 'year'
24
- valueFormat?: string
25
24
  prop?: string
26
25
  width?: string
27
26
  disabled?: boolean
@@ -42,22 +41,27 @@ const emit = defineEmits<{
42
41
 
43
42
  const crud = useCrud()
44
43
 
45
- const precision = computed(() => {
46
- if (props.type === 'datetime') return 'second'
47
- if (props.type === 'month') return 'month'
48
- if (props.type === 'year') return 'year'
49
- return 'day'
50
- })
44
+ const TYPE_PRECISION: Record<string, DateTimePrecision> = {
45
+ date: 'day',
46
+ datetime: 'datetime',
47
+ month: 'month',
48
+ year: 'year',
49
+ }
51
50
 
52
- const placeholderText = computed(() => {
53
- if (props.placeholder) return props.placeholder
54
- if (props.type === 'datetime') return '选择日期时间'
55
- if (props.type === 'month') return '选择月份'
56
- if (props.type === 'year') return '选择年份'
57
- return '选择日期'
58
- })
51
+ const TYPE_PLACEHOLDER: Record<string, string> = {
52
+ date: '选择日期',
53
+ datetime: '选择日期时间',
54
+ month: '选择月份',
55
+ year: '选择年份',
56
+ }
59
57
 
60
- const inner = computed(() => props.modelValue || null)
58
+ const precision = computed(
59
+ () => TYPE_PRECISION[props.type] ?? ('day' as DateTimePrecision),
60
+ )
61
+
62
+ const placeholderText = computed(
63
+ () => props.placeholder || TYPE_PLACEHOLDER[props.type] || '选择日期',
64
+ )
61
65
 
62
66
  function onUpdate(v: string | null) {
63
67
  const out = v || ''
@@ -2,36 +2,35 @@
2
2
  <div class="vm-date-range" :class="{ 'is-disabled': disabled }">
3
3
  <VmDatetimeField
4
4
  class="vm-date-range__field"
5
- :model-value="props.modelValue?.[0] ?? null"
5
+ :model-value="modelValue?.[0] ?? null"
6
6
  :precision="precision"
7
7
  :placeholder="startPlaceholder"
8
8
  :disabled="disabled"
9
9
  @update:model-value="(v) => set(0, v)"
10
- @change="(v) => set(0, v)"
11
10
  />
12
11
  <span class="vm-date-range__sep">-</span>
13
12
  <VmDatetimeField
14
13
  class="vm-date-range__field"
15
- :model-value="props.modelValue?.[1] ?? null"
14
+ :model-value="modelValue?.[1] ?? null"
16
15
  :precision="precision"
17
16
  :placeholder="endPlaceholder"
18
17
  :disabled="disabled"
19
18
  @update:model-value="(v) => set(1, v)"
20
- @change="(v) => set(1, v)"
21
19
  />
22
20
  </div>
23
21
  </template>
24
22
 
25
23
  <script setup lang="ts">
26
- defineOptions({ name: 'vm-date-range' })
27
-
28
24
  import VmDatetimeField from './vm-datetime-field.vue'
25
+ import type { DateTimePrecision } from '../../../shared/datetime-picker'
26
+
27
+ defineOptions({ name: 'vm-date-range' })
29
28
 
30
29
  const props = withDefaults(
31
30
  defineProps<{
32
31
  modelValue?: Array<string | null>
33
- /** 时间精度:year | month | day | hour | minute | second */
34
- precision?: 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second'
32
+ /** year | month | day | datetime */
33
+ precision?: DateTimePrecision
35
34
  startPlaceholder?: string
36
35
  endPlaceholder?: string
37
36
  disabled?: boolean
@@ -65,7 +64,6 @@ function set(idx: 0 | 1, v: string | null) {
65
64
  box-sizing: border-box;
66
65
  width: 100%;
67
66
  align-items: center;
68
- gap: 0;
69
67
 
70
68
  &.is-disabled {
71
69
  opacity: 0.55;
@@ -79,12 +77,11 @@ function set(idx: 0 | 1, v: string | null) {
79
77
  }
80
78
 
81
79
  .vm-date-range__sep {
82
- flex: 0 0 auto;
80
+ flex: none;
83
81
  padding: 0 8px;
84
82
  color: var(--muted-foreground, #94a3b8);
85
83
  font-size: 13px;
86
84
  font-weight: 600;
87
- line-height: 1;
88
85
  user-select: none;
89
86
  }
90
87
  </style>
@@ -2,25 +2,23 @@
2
2
  <div
3
3
  ref="rootRef"
4
4
  class="vm-dt-field"
5
- :class="{ 'is-disabled': disabled, 'is-open': open }"
5
+ :class="{ 'is-disabled': disabled }"
6
6
  @click="onRootClick"
7
7
  >
8
- <div class="vm-dt-field__side">
9
- <div class="vm-dt-field__box">
10
- <span v-if="!displayText && placeholder" class="vm-dt-field__ph">{{
11
- placeholder
12
- }}</span>
13
- <span class="vm-dt-field__val">{{ displayText }}</span>
14
- </div>
15
- <i class="ri-calendar-line vm-dt-field__icon" aria-hidden="true" />
8
+ <div class="vm-dt-field__box">
9
+ <span v-if="!displayText && placeholder" class="vm-dt-field__ph">{{
10
+ placeholder
11
+ }}</span>
12
+ <span class="vm-dt-field__val">{{ displayText }}</span>
16
13
  </div>
14
+ <i class="ri-calendar-line vm-dt-field__icon" aria-hidden="true" />
17
15
 
18
16
  <Teleport to="body">
19
- <!-- vm-dialog-float:Dialog modal body 为 pointer-events:none,且须被 preventDialogOutsideClose 识别 -->
17
+ <!-- vm-dialog-float:Dialog modal 下须被 preventDialogOutsideClose 识别 -->
20
18
  <div
21
19
  v-if="open"
22
20
  ref="panelWrapRef"
23
- class="vm-dt-field__panel-wrap vm-dialog-float"
21
+ class="vm-dialog-float"
24
22
  :style="panelStyle"
25
23
  @pointerdown.stop
26
24
  @mousedown.stop
@@ -37,7 +35,7 @@
37
35
  </template>
38
36
 
39
37
  <script setup lang="ts">
40
- import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
38
+ import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
41
39
  import VmDateCalendarPanel from './vm-date-calendar-panel.vue'
42
40
  import {
43
41
  dateTimeDisplayText,
@@ -73,7 +71,6 @@ const open = ref(false)
73
71
  const panelStyle = ref<Record<string, string>>({})
74
72
 
75
73
  const precision = computed(() => normalizeDateTimePrecision(props.precision))
76
-
77
74
  const displayText = computed(() =>
78
75
  dateTimeDisplayText(props.modelValue, precision.value),
79
76
  )
@@ -82,7 +79,6 @@ function syncPanelPos() {
82
79
  const el = rootRef.value
83
80
  if (!el) return
84
81
  const r = el.getBoundingClientRect()
85
- // 贴触发框左侧 + 底部
86
82
  panelStyle.value = {
87
83
  position: 'fixed',
88
84
  left: `${r.left}px`,
@@ -95,24 +91,20 @@ function close() {
95
91
  open.value = false
96
92
  }
97
93
 
98
- function openPanel() {
94
+ function onRootClick() {
99
95
  if (props.disabled) return
96
+ if (open.value) {
97
+ close()
98
+ return
99
+ }
100
100
  open.value = true
101
101
  syncPanelPos()
102
102
  }
103
103
 
104
- function onRootClick() {
105
- if (props.disabled) return
106
- if (open.value) close()
107
- else openPanel()
108
- }
109
-
110
104
  function onPick(v: string) {
111
105
  emit('update:modelValue', v)
112
106
  emit('change', v)
113
- if (precision.value === 'day' || precision.value === 'month' || precision.value === 'year') {
114
- close()
115
- }
107
+ if (precision.value !== 'datetime') close()
116
108
  }
117
109
 
118
110
  function onClear() {
@@ -132,10 +124,6 @@ function onViewportChange() {
132
124
  if (open.value) syncPanelPos()
133
125
  }
134
126
 
135
- watch(open, (v) => {
136
- if (v) syncPanelPos()
137
- })
138
-
139
127
  onMounted(() => {
140
128
  document.addEventListener('pointerdown', onDocPointer, true)
141
129
  window.addEventListener('resize', onViewportChange)
@@ -152,14 +140,17 @@ onBeforeUnmount(() => {
152
140
  <style lang="scss" scoped>
153
141
  .vm-dt-field {
154
142
  box-sizing: border-box;
143
+ display: flex;
155
144
  width: 100%;
156
145
  height: var(--vm-control-height, 38px);
146
+ align-items: center;
147
+ gap: 6px;
148
+ padding: 0 10px;
157
149
  border: 1px solid transparent;
158
150
  border-radius: 12px;
159
151
  background: var(--muted, #f4f6fb);
160
152
  cursor: pointer;
161
153
  outline: none;
162
- /* 弹层触发:不展示点击聚焦描边 */
163
154
 
164
155
  &.is-disabled {
165
156
  opacity: 0.55;
@@ -168,14 +159,6 @@ onBeforeUnmount(() => {
168
159
  }
169
160
  }
170
161
 
171
- .vm-dt-field__side {
172
- display: flex;
173
- height: 100%;
174
- align-items: center;
175
- gap: 6px;
176
- padding: 0 10px;
177
- }
178
-
179
162
  .vm-dt-field__box {
180
163
  position: relative;
181
164
  flex: 1 1 auto;