vome-core 0.0.66 → 0.0.68

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 (83) hide show
  1. package/dist/admin/config/plugin-dev.js +1 -1
  2. package/dist/admin/crud/components/vm-json-editor.vue +32 -3
  3. package/dist/admin/crud/components/vm-richtext.vue +5 -4
  4. package/dist/admin/crud/config.js +1 -1
  5. package/dist/admin/crud/confirm.js +1 -1
  6. package/dist/admin/crud/dict.js +1 -1
  7. package/dist/admin/crud/index.d.ts +1 -1
  8. package/dist/admin/crud/index.js +1 -1
  9. package/dist/admin/crud/key.js +1 -1
  10. package/dist/admin/crud/mitt.js +1 -1
  11. package/dist/admin/crud/plugins.js +1 -1
  12. package/dist/admin/crud/span.js +1 -1
  13. package/dist/admin/crud/style.d.ts +37 -0
  14. package/dist/admin/crud/style.js +1 -1
  15. package/dist/admin/crud/validate.js +1 -1
  16. package/dist/admin/crud/vm-add-btn.vue +2 -1
  17. package/dist/admin/crud/vm-adv-search.vue +5 -4
  18. package/dist/admin/crud/vm-crud.vue +14 -9
  19. package/dist/admin/crud/vm-export-btn.vue +2 -1
  20. package/dist/admin/crud/vm-import-btn.vue +2 -1
  21. package/dist/admin/crud/vm-multi-delete-btn.vue +2 -1
  22. package/dist/admin/crud/vm-pagination.vue +16 -7
  23. package/dist/admin/crud/vm-refresh-btn.vue +2 -1
  24. package/dist/admin/crud/vm-search-key.vue +3 -2
  25. package/dist/admin/crud/vm-search.vue +29 -20
  26. package/dist/admin/crud/vm-table.vue +65 -22
  27. package/dist/admin/crud/vm-toolbar.vue +12 -13
  28. package/dist/admin/crud/vm-upsert.vue +12 -6
  29. package/dist/admin/directives/perm.js +1 -1
  30. package/dist/admin/hooks/useUpload.js +1 -1
  31. package/dist/admin/index.d.ts +1 -1
  32. package/dist/admin/index.js +6 -1
  33. package/dist/admin/lib/browser.js +1 -1
  34. package/dist/admin/lib/cn.js +1 -1
  35. package/dist/admin/lib/dialog-float.js +1 -1
  36. package/dist/admin/lib/export-excel.js +1 -1
  37. package/dist/admin/lib/file-preview.js +1 -1
  38. package/dist/admin/lib/import-excel.js +1 -1
  39. package/dist/admin/lib/json.js +1 -1
  40. package/dist/admin/lib/menu.js +1 -1
  41. package/dist/admin/lib/tree.js +1 -1
  42. package/dist/admin/lib/upload.js +1 -1
  43. package/dist/admin/lib/video-frame.js +1 -1
  44. package/dist/admin/styles/base.css +33 -0
  45. package/dist/ai/index.js +28761 -0
  46. package/dist/ai.d.ts +1 -0
  47. package/dist/client/base.js +5 -1
  48. package/dist/client/index.d.ts +1 -0
  49. package/dist/client/index.js +3 -0
  50. package/dist/client/locale-store.d.ts +59 -0
  51. package/dist/client/locale-store.js +159 -0
  52. package/dist/index.js +1 -1
  53. package/dist/server/index.js +1 -1
  54. package/dist/shared/excel.js +1 -1
  55. package/dist/shared/index.js +1 -1
  56. package/dist/shared/locale-json.js +1 -0
  57. package/dist/shared/tree.js +1 -1
  58. package/dist/src/ai/adapters/anthropic-gemini.d.ts +5 -0
  59. package/dist/src/ai/adapters/auth-headers.d.ts +4 -0
  60. package/dist/src/ai/adapters/index.d.ts +3 -0
  61. package/dist/src/ai/adapters/openai-compatible.d.ts +4 -0
  62. package/dist/src/ai/call-log-helpers.d.ts +13 -0
  63. package/dist/src/ai/index.d.ts +10 -0
  64. package/dist/src/ai/normalize.d.ts +18 -0
  65. package/dist/src/ai/sse.d.ts +13 -0
  66. package/dist/src/ai/transport.d.ts +16 -0
  67. package/dist/src/ai/types.d.ts +194 -0
  68. package/dist/src/core/index.d.ts +1 -1
  69. package/dist/src/index.d.ts +1 -0
  70. package/dist/src/orm/index.d.ts +1 -1
  71. package/dist/src/server/index.d.ts +3 -1
  72. package/dist/src/shared/index.d.ts +1 -0
  73. package/dist/src/shared/locale-json.d.ts +7 -0
  74. package/dist/typings/routing/eps.d.ts +2 -0
  75. package/package.json +7 -2
  76. package/src/shared/index.ts +6 -0
  77. package/src/shared/locale-json.ts +79 -0
  78. package/typings/admin/comm/crud.d.ts +13 -0
  79. package/typings/admin/comm/crud.ts +13 -0
  80. package/typings/admin/comm/eps.d.ts +3 -0
  81. package/typings/admin/comm/eps.ts +3 -0
  82. package/typings/admin/comm/request.d.ts +1 -1
  83. package/typings/admin/comm/request.ts +1 -1
@@ -1 +1 @@
1
- (function(_0x4b4ca3,_0x203a90){const _0x3d9884=_0x3a4a,_0x2a5936=_0x4b4ca3();while(!![]){try{const _0x51fc01=parseInt(_0x3d9884(0x168))/0x1+-parseInt(_0x3d9884(0x169))/0x2+-parseInt(_0x3d9884(0x161))/0x3+parseInt(_0x3d9884(0x15c))/0x4+parseInt(_0x3d9884(0x156))/0x5+parseInt(_0x3d9884(0x150))/0x6+-parseInt(_0x3d9884(0x165))/0x7*(parseInt(_0x3d9884(0x154))/0x8);if(_0x51fc01===_0x203a90)break;else _0x2a5936['push'](_0x2a5936['shift']());}catch(_0x4e5a78){_0x2a5936['push'](_0x2a5936['shift']());}}}(_0x10de,0xb96ed));function _0x3a4a(_0x3784cb,_0x514d6e){_0x3784cb=_0x3784cb-0x14e;const _0x10de70=_0x10de();let _0x3a4ad5=_0x10de70[_0x3784cb];if(_0x3a4a['SuKFcK']===undefined){var _0x1871cc=function(_0x1a9c0e){const _0x3510bb='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x576af1='',_0x2f88e7='';for(let _0x15d45e=0x0,_0x18f5f8,_0x533638,_0x4c93ab=0x0;_0x533638=_0x1a9c0e['charAt'](_0x4c93ab++);~_0x533638&&(_0x18f5f8=_0x15d45e%0x4?_0x18f5f8*0x40+_0x533638:_0x533638,_0x15d45e++%0x4)?_0x576af1+=String['fromCharCode'](0xff&_0x18f5f8>>(-0x2*_0x15d45e&0x6)):0x0){_0x533638=_0x3510bb['indexOf'](_0x533638);}for(let _0x387b8d=0x0,_0x26aeff=_0x576af1['length'];_0x387b8d<_0x26aeff;_0x387b8d++){_0x2f88e7+='%'+('00'+_0x576af1['charCodeAt'](_0x387b8d)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x2f88e7);};_0x3a4a['jjsNoY']=_0x1871cc,_0x3a4a['UbuGDt']={},_0x3a4a['SuKFcK']=!![];}const _0x3e52dd=_0x10de70[0x0],_0x14a22d=_0x3784cb+_0x3e52dd,_0xbe1a87=_0x3a4a['UbuGDt'][_0x14a22d];return!_0xbe1a87?(_0x3a4ad5=_0x3a4a['jjsNoY'](_0x3a4ad5),_0x3a4a['UbuGDt'][_0x14a22d]=_0x3a4ad5):_0x3a4ad5=_0xbe1a87,_0x3a4ad5;}function isEmpty(_0x576af1){const _0x20d307=_0x3a4a;if(_0x576af1==null||_0x576af1==='')return!![];if(typeof _0x576af1===_0x20d307(0x152)&&_0x576af1[_0x20d307(0x155)]()==='')return!![];if(Array['isArray'](_0x576af1)&&_0x576af1[_0x20d307(0x16b)]===0x0)return!![];return![];}function normalizeRules(_0x2f88e7){const _0xb6b031=_0x3a4a,_0x15d45e=[];_0x2f88e7[_0xb6b031(0x158)]&&_0x15d45e['push']({'required':!![],'message':_0x2f88e7[_0xb6b031(0x16a)]+_0xb6b031(0x167)});const _0x18f5f8=_0x2f88e7[_0xb6b031(0x14f)];if(!_0x18f5f8)return _0x15d45e;if(Array[_0xb6b031(0x16c)](_0x18f5f8))for(const _0x533638 of _0x18f5f8){if(_0x533638&&typeof _0x533638===_0xb6b031(0x164))_0x15d45e[_0xb6b031(0x15d)](_0x533638);}else typeof _0x18f5f8==='object'&&_0x15d45e['push'](_0x18f5f8);return _0x15d45e;}function isItemHidden(_0x4c93ab,_0x387b8d){const _0x549e4f=_0x3a4a;if(typeof _0x4c93ab[_0x549e4f(0x162)]==='function')return _0x4c93ab[_0x549e4f(0x162)](_0x387b8d);return Boolean(_0x4c93ab['hidden']);}function _0x10de(){const _0x90fd8a=['BgfIzwW','BgvUz3rO','AxnbCNjHEq','BwLU','5Qc85BYp5lIn5Q2J56gU','CNvSzxm','nZu4mtK5mgjjB3zQCq','Cgf0DgvYBG','C3rYAw5N','DgvZDa','ntyYnti3mNLcu1zNsG','DhjPBq','odmYntyWBwXpuMj4','BwfW','CMvXDwLYzwq','Bwf4','6iEZ5Bcria','5QcH6AQm5AsX6lsL','mZyWmde2nejIt2jgzq','ChvZAa','DMfSAwrHDg9Y','ios4QUwTL+ESPG','ChjVCa','nta2mZqZv1zgugHg','AgLKzgvU','5PYa5AsAia','B2jQzwn0','n0DgtfPAAq','BwvZC2fNzq','5lIn6io95lI656M6','mJy0ote2reLlufjo','mtKYnZmYmKXtDuzmuG'];_0x10de=function(){return _0x90fd8a;};return _0x10de();}async function validateItem(_0x26aeff,_0x39dba8){const _0x525a8f=_0x3a4a,_0x3fcf33=_0x39dba8[_0x26aeff[_0x525a8f(0x160)]];for(const _0x27ed1a of normalizeRules(_0x26aeff)){if(_0x27ed1a[_0x525a8f(0x158)]&&isEmpty(_0x3fcf33))return _0x27ed1a[_0x525a8f(0x166)]||_0x26aeff[_0x525a8f(0x16a)]+_0x525a8f(0x167);if(isEmpty(_0x3fcf33))continue;const _0x15c34b=String(_0x3fcf33);if(_0x27ed1a['min']!=null&&_0x15c34b[_0x525a8f(0x16b)]<_0x27ed1a[_0x525a8f(0x16d)])return _0x27ed1a['message']||_0x26aeff[_0x525a8f(0x16a)]+_0x525a8f(0x15a)+_0x27ed1a['min']+'\x20个字符';if(_0x27ed1a['max']!=null&&_0x15c34b['length']>_0x27ed1a[_0x525a8f(0x159)])return _0x27ed1a[_0x525a8f(0x166)]||_0x26aeff['label']+_0x525a8f(0x163)+_0x27ed1a[_0x525a8f(0x159)]+_0x525a8f(0x15f);if(_0x27ed1a[_0x525a8f(0x151)]&&!_0x27ed1a['pattern'][_0x525a8f(0x153)](_0x15c34b))return _0x27ed1a[_0x525a8f(0x166)]||_0x26aeff[_0x525a8f(0x16a)]+_0x525a8f(0x14e);if(_0x27ed1a[_0x525a8f(0x15e)]){const _0x1f8ab3=await _0x27ed1a[_0x525a8f(0x15e)](_0x3fcf33,_0x39dba8);if(_0x1f8ab3!==!![])return _0x1f8ab3||_0x26aeff[_0x525a8f(0x16a)]+_0x525a8f(0x15b);}}return null;}export async function validateFormItems(_0x130b53,_0x3d7eee){for(const _0x31a0ac of _0x130b53){if(isItemHidden(_0x31a0ac,_0x3d7eee))continue;const _0x2a11f2=await validateItem(_0x31a0ac,_0x3d7eee);if(_0x2a11f2)return _0x2a11f2;}return null;}export async function validateFormFields(_0x11a7d2,_0x52d059){const _0x5831c8=_0x3a4a,_0x2f408e={};for(const _0xe871ed of _0x11a7d2){if(isItemHidden(_0xe871ed,_0x52d059))continue;const _0x5e40ae=await validateItem(_0xe871ed,_0x52d059);if(_0x5e40ae)_0x2f408e[_0xe871ed[_0x5831c8(0x160)]]=_0x5e40ae;}return _0x2f408e;}export function applySetRules(_0x4b18a3){const _0x26ca12=_0x3a4a;return _0x4b18a3[_0x26ca12(0x157)](_0x30a558=>{const _0x38c7d5=_0x26ca12;if(!_0x30a558[_0x38c7d5(0x158)]||_0x30a558[_0x38c7d5(0x14f)])return _0x30a558;return{..._0x30a558,'rules':[{'required':!![],'message':_0x30a558[_0x38c7d5(0x16a)]+_0x38c7d5(0x167)}]};});}
1
+ (function(_0x115a82,_0x2dd0d0){const _0x275540=_0x2df2,_0x5b478b=_0x115a82();while(!![]){try{const _0x16cfa4=-parseInt(_0x275540(0x169))/0x1+parseInt(_0x275540(0x165))/0x2*(parseInt(_0x275540(0x16f))/0x3)+-parseInt(_0x275540(0x167))/0x4*(-parseInt(_0x275540(0x157))/0x5)+parseInt(_0x275540(0x155))/0x6+-parseInt(_0x275540(0x170))/0x7*(parseInt(_0x275540(0x174))/0x8)+parseInt(_0x275540(0x156))/0x9+-parseInt(_0x275540(0x15c))/0xa;if(_0x16cfa4===_0x2dd0d0)break;else _0x5b478b['push'](_0x5b478b['shift']());}catch(_0x2d1df2){_0x5b478b['push'](_0x5b478b['shift']());}}}(_0x104d,0x3f447));function _0x104d(){const _0x1f914f=['odi0ntq4yM5Xze1i','BgfIzwW','nta5nJuYAfLhDer4','BgvUz3rO','DhjPBq','C3rYAw5N','zNvUy3rPB24','B2jQzwn0','mtm0otqWmeHmCu1OBG','n2zhs1zXzG','5PYa5AsAia','AgLKzgvU','DMfSAwrHDg9Y','mtC4nda4B0LyD0LQ','AxnbCNjHEq','5lIn6io95lI656M6','mtmYnJqYnK1Ns1D0BW','ndeWntuYmuPgCKjyrW','mtbMte1yr3y','Cgf0DgvYBG','ChvZAa','CMvXDwLYzwq','DgvZDa','nZq4mJe4mgn2zeHdwa','ios4QUwTL+ESPG','Bwf4','BwvZC2fNzq','6iEZ5Bcria','ChjVCa','CNvSzxm','5Qc85BYp5lIn5Q2J56gU','BwLU','mKfqzezNsq','5QcH6AQm5AsX6lsL'];_0x104d=function(){return _0x1f914f;};return _0x104d();}function _0x2df2(_0x3c0ad0,_0x3b7094){_0x3c0ad0=_0x3c0ad0-0x153;const _0x104d1e=_0x104d();let _0x2df22a=_0x104d1e[_0x3c0ad0];if(_0x2df2['QItQmv']===undefined){var _0x5b9646=function(_0x3e2f30){const _0x43ec02='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x20c5f3='',_0x29dc0b='';for(let _0xffb7a0=0x0,_0x43f6e8,_0x12aa85,_0x378634=0x0;_0x12aa85=_0x3e2f30['charAt'](_0x378634++);~_0x12aa85&&(_0x43f6e8=_0xffb7a0%0x4?_0x43f6e8*0x40+_0x12aa85:_0x12aa85,_0xffb7a0++%0x4)?_0x20c5f3+=String['fromCharCode'](0xff&_0x43f6e8>>(-0x2*_0xffb7a0&0x6)):0x0){_0x12aa85=_0x43ec02['indexOf'](_0x12aa85);}for(let _0x3182d7=0x0,_0x5e6c2c=_0x20c5f3['length'];_0x3182d7<_0x5e6c2c;_0x3182d7++){_0x29dc0b+='%'+('00'+_0x20c5f3['charCodeAt'](_0x3182d7)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x29dc0b);};_0x2df2['ZMAnXy']=_0x5b9646,_0x2df2['CBedgx']={},_0x2df2['QItQmv']=!![];}const _0x76144f=_0x104d1e[0x0],_0x55e8e8=_0x3c0ad0+_0x76144f,_0x312dc2=_0x2df2['CBedgx'][_0x55e8e8];return!_0x312dc2?(_0x2df22a=_0x2df2['ZMAnXy'](_0x2df22a),_0x2df2['CBedgx'][_0x55e8e8]=_0x2df22a):_0x2df22a=_0x312dc2,_0x2df22a;}function isEmpty(_0x20c5f3){const _0x5081e3=_0x2df2;if(_0x20c5f3==null||_0x20c5f3==='')return!![];if(typeof _0x20c5f3===_0x5081e3(0x16c)&&_0x20c5f3[_0x5081e3(0x16b)]()==='')return!![];if(Array[_0x5081e3(0x153)](_0x20c5f3)&&_0x20c5f3[_0x5081e3(0x16a)]===0x0)return!![];return![];}function normalizeRules(_0x29dc0b){const _0x2a1e6f=_0x2df2,_0xffb7a0=[];_0x29dc0b[_0x2a1e6f(0x15a)]&&_0xffb7a0[_0x2a1e6f(0x159)]({'required':!![],'message':_0x29dc0b[_0x2a1e6f(0x168)]+_0x2a1e6f(0x154)});const _0x43f6e8=_0x29dc0b[_0x2a1e6f(0x162)];if(!_0x43f6e8)return _0xffb7a0;if(Array[_0x2a1e6f(0x153)](_0x43f6e8))for(const _0x12aa85 of _0x43f6e8){if(_0x12aa85&&typeof _0x12aa85===_0x2a1e6f(0x16e))_0xffb7a0[_0x2a1e6f(0x159)](_0x12aa85);}else typeof _0x43f6e8==='object'&&_0xffb7a0[_0x2a1e6f(0x159)](_0x43f6e8);return _0xffb7a0;}function isItemHidden(_0x378634,_0x3182d7){const _0x4ba97c=_0x2df2;if(typeof _0x378634[_0x4ba97c(0x172)]===_0x4ba97c(0x16d))return _0x378634[_0x4ba97c(0x172)](_0x3182d7);return Boolean(_0x378634[_0x4ba97c(0x172)]);}async function validateItem(_0x5e6c2c,_0x4f5653){const _0x249a3c=_0x2df2,_0x194024=_0x4f5653[_0x5e6c2c[_0x249a3c(0x161)]];for(const _0x5e5aa8 of normalizeRules(_0x5e6c2c)){if(_0x5e5aa8[_0x249a3c(0x15a)]&&isEmpty(_0x194024))return _0x5e5aa8['message']||_0x5e6c2c[_0x249a3c(0x168)]+_0x249a3c(0x154);if(isEmpty(_0x194024))continue;const _0x1c14ce=String(_0x194024);if(_0x5e5aa8[_0x249a3c(0x164)]!=null&&_0x1c14ce[_0x249a3c(0x16a)]<_0x5e5aa8[_0x249a3c(0x164)])return _0x5e5aa8['message']||_0x5e6c2c[_0x249a3c(0x168)]+_0x249a3c(0x160)+_0x5e5aa8[_0x249a3c(0x164)]+_0x249a3c(0x15d);if(_0x5e5aa8[_0x249a3c(0x15e)]!=null&&_0x1c14ce[_0x249a3c(0x16a)]>_0x5e5aa8['max'])return _0x5e5aa8[_0x249a3c(0x15f)]||_0x5e6c2c[_0x249a3c(0x168)]+_0x249a3c(0x171)+_0x5e5aa8[_0x249a3c(0x15e)]+_0x249a3c(0x15d);if(_0x5e5aa8[_0x249a3c(0x158)]&&!_0x5e5aa8['pattern'][_0x249a3c(0x15b)](_0x1c14ce))return _0x5e5aa8[_0x249a3c(0x15f)]||_0x5e6c2c[_0x249a3c(0x168)]+_0x249a3c(0x163);if(_0x5e5aa8[_0x249a3c(0x173)]){const _0x5e7224=await _0x5e5aa8['validator'](_0x194024,_0x4f5653);if(_0x5e7224!==!![])return _0x5e7224||_0x5e6c2c[_0x249a3c(0x168)]+_0x249a3c(0x166);}}return null;}export async function validateFormItems(_0x5181c6,_0xbc4f9c){for(const _0x2ea4a7 of _0x5181c6){if(isItemHidden(_0x2ea4a7,_0xbc4f9c))continue;const _0x2eba56=await validateItem(_0x2ea4a7,_0xbc4f9c);if(_0x2eba56)return _0x2eba56;}return null;}export async function validateFormFields(_0x2b9e7e,_0x410e39){const _0x551a5a=_0x2df2,_0x658855={};for(const _0x2dc57a of _0x2b9e7e){if(isItemHidden(_0x2dc57a,_0x410e39))continue;const _0x16e557=await validateItem(_0x2dc57a,_0x410e39);if(_0x16e557)_0x658855[_0x2dc57a[_0x551a5a(0x161)]]=_0x16e557;}return _0x658855;}export function applySetRules(_0x40f479){return _0x40f479['map'](_0x16ea7a=>{const _0x4c2753=_0x2df2;if(!_0x16ea7a[_0x4c2753(0x15a)]||_0x16ea7a['rules'])return _0x16ea7a;return{..._0x16ea7a,'rules':[{'required':!![],'message':_0x16ea7a[_0x4c2753(0x168)]+_0x4c2753(0x154)}]};});}
@@ -6,13 +6,14 @@
6
6
  @click="onClick"
7
7
  >
8
8
  <i class="ri-add-line" />
9
- {{ crud.dict.label.add }}
9
+ {{ crudLabel('add', crud.dict.label) }}
10
10
  </button>
11
11
  </template>
12
12
 
13
13
  <script setup lang="ts">
14
14
  import { computed } from 'vue'
15
15
  import { useCrud } from './useCrud'
16
+ import { crudLabel } from './style'
16
17
 
17
18
  defineOptions({ name: 'vm-add-btn' })
18
19
 
@@ -2,7 +2,7 @@
2
2
  <div class="vm-adv-search">
3
3
  <Button size="sm" variant="outline" class="h-8" @click="open = true">
4
4
  <i class="ri-filter-3-line" />
5
- {{ crud.dict.label.advSearch }}
5
+ {{ crudLabel('advSearch', crud.dict.label) }}
6
6
  </Button>
7
7
  <Dialog :open="open" @update:open="onOpenChange">
8
8
  <DialogContent
@@ -14,7 +14,7 @@
14
14
  >
15
15
  <DialogHeader class="vm-crud-shell__head">
16
16
  <DialogTitle class="vm-crud-shell__title">
17
- {{ crud.dict.label.advSearch }}
17
+ {{ crudLabel('advSearch', crud.dict.label) }}
18
18
  </DialogTitle>
19
19
  </DialogHeader>
20
20
  <div class="vm-crud-shell__body">
@@ -26,14 +26,14 @@
26
26
  class="vm-crud-shell__btn is-ghost"
27
27
  @click="reset"
28
28
  >
29
- {{ crud.dict.label.reset }}
29
+ {{ crudLabel('reset', crud.dict.label) }}
30
30
  </button>
31
31
  <button
32
32
  type="button"
33
33
  class="vm-crud-shell__btn is-primary"
34
34
  @click="search"
35
35
  >
36
- {{ crud.dict.label.search }}
36
+ {{ crudLabel('search', crud.dict.label) }}
37
37
  </button>
38
38
  </DialogFooter>
39
39
  </DialogContent>
@@ -45,6 +45,7 @@
45
45
  import { ref } from 'vue'
46
46
  import { preventDialogOutsideClose } from '../lib/dialog-float'
47
47
  import { useCrud } from './useCrud'
48
+ import { crudLabel } from './style'
48
49
  defineOptions({ name: 'vm-adv-search' })
49
50
 
50
51
  const props = withDefaults(
@@ -12,6 +12,7 @@ import { mergeDict, mergePermission } from './config'
12
12
  import { vmConfirm } from './confirm'
13
13
  import { CRUD_KEY, CRUD_MITT_KEY, injectCrudOptions, injectTableOptions, injectUpsertOptions } from './key'
14
14
  import { createMitt } from './mitt'
15
+ import { crudLabel } from './style'
15
16
  defineOptions({ name: 'vm-crud' })
16
17
 
17
18
  const props = withDefaults(
@@ -283,7 +284,9 @@ async function doDelete(targets: Record<string, unknown>[], force = false) {
283
284
  .map((r) => r[dict.primaryId] as string | number)
284
285
  .filter((id) => id != null)
285
286
  await svc.delete({ ids, force })
286
- toast.success(force ? '已彻底删除' : dict.label.deleteSuccess || '已删除')
287
+ toast.success(
288
+ force ? crudLabel('forceDeleted', dict.label) : crudLabel('deleteSuccess', dict.label),
289
+ )
287
290
  await refresh()
288
291
  }
289
292
 
@@ -305,7 +308,9 @@ async function rowDelete(rows?: Record<string, unknown>[], force = false) {
305
308
  ...(payload as { ids: Array<string | number> }),
306
309
  force: hard,
307
310
  })
308
- toast.success(hard ? '已彻底删除' : dict.label.deleteSuccess || '已删除')
311
+ toast.success(
312
+ hard ? crudLabel('forceDeleted', dict.label) : crudLabel('deleteSuccess', dict.label),
313
+ )
309
314
  await refresh()
310
315
  return
311
316
  }
@@ -318,13 +323,13 @@ async function rowDelete(rows?: Record<string, unknown>[], force = false) {
318
323
  }
319
324
 
320
325
  const tip = hard
321
- ? dict.label.forceDeleteConfirm || '此操作将永久删除选中数据,是否继续?'
322
- : dict.label.deleteConfirm || '确定删除?'
326
+ ? crudLabel('forceDeleteConfirm', dict.label)
327
+ : crudLabel('deleteConfirm', dict.label)
323
328
  const ok = await vmConfirm({
324
- title: hard ? '彻底删除' : '删除确认',
329
+ title: hard ? crudLabel('forceDelete', dict.label) : crudLabel('tips', dict.label),
325
330
  message: tip,
326
- confirmText: '确定',
327
- cancelText: '取消',
331
+ confirmText: crudLabel('confirm', dict.label),
332
+ cancelText: crudLabel('close', dict.label),
328
333
  })
329
334
  if (!ok) return
330
335
  await next()
@@ -362,11 +367,11 @@ async function upsertSubmit() {
362
367
  if (upsertMode.value === 'add') {
363
368
  if (!svc.add) throw new Error('未配置 add')
364
369
  await svc.add(data)
365
- toast.success(dict.label.saveSuccess || '已新增')
370
+ toast.success(crudLabel('saveSuccess', dict.label))
366
371
  } else {
367
372
  if (!svc.update) throw new Error('未配置 update')
368
373
  await svc.update(data)
369
- toast.success(dict.label.saveSuccess || '已更新')
374
+ toast.success(crudLabel('saveSuccess', dict.label))
370
375
  }
371
376
  const after = async () => {
372
377
  upsertVisible.value = false
@@ -25,6 +25,7 @@ import {
25
25
  type TableApi,
26
26
  } from './key'
27
27
  import { useCrud } from './useCrud'
28
+ import { crudLabel } from './style'
28
29
 
29
30
  defineOptions({ name: 'vm-export-btn' })
30
31
 
@@ -59,7 +60,7 @@ const submitting = ref(false)
59
60
  const visible = computed(() => Boolean(crud.getPermission(props.permission)))
60
61
 
61
62
  const buttonText = computed(
62
- () => props.text || crud.dict.label.export || '导出',
63
+ () => props.text || crudLabel('export', crud.dict.label),
63
64
  )
64
65
 
65
66
  const exportColumns = computed(() => {
@@ -167,6 +167,7 @@ import {
167
167
  uploadImportExcel,
168
168
  } from '../lib/import-excel'
169
169
  import { useCrud } from './useCrud'
170
+ import { crudLabel } from './style'
170
171
 
171
172
  defineOptions({ name: 'vm-import-btn' })
172
173
 
@@ -215,7 +216,7 @@ const dragDepth = ref(0)
215
216
  const visible = computed(() => Boolean(crud.getPermission(props.permission)))
216
217
 
217
218
  const buttonText = computed(
218
- () => props.text || crud.dict.label.import || '导入',
219
+ () => props.text || crudLabel('import', crud.dict.label),
219
220
  )
220
221
 
221
222
  const totalPages = computed(() =>
@@ -7,12 +7,13 @@
7
7
  @click="crud.rowDelete()"
8
8
  >
9
9
  <i class="ri-delete-bin-line" />
10
- {{ crud.dict.label.multiDelete }}
10
+ {{ crudLabel('multiDelete', crud.dict.label) }}
11
11
  </button>
12
12
  </template>
13
13
 
14
14
  <script setup lang="ts">
15
15
  import { useCrud } from './useCrud'
16
+ import { crudLabel } from './style'
16
17
 
17
18
  defineOptions({ name: 'vm-multi-delete-btn' })
18
19
  const crud = useCrud()
@@ -1,6 +1,6 @@
1
1
  <template>
2
2
  <div class="vm-crud-pagination">
3
- <span class="vm-crud-pagination__total">共 {{ crud.pagination.value.total }} 条</span>
3
+ <span class="vm-crud-pagination__total">{{ totalText }}</span>
4
4
  <div class="vm-crud-pagination__actions">
5
5
  <Select
6
6
  :model-value="String(crud.pagination.value.size)"
@@ -10,10 +10,9 @@
10
10
  <SelectValue />
11
11
  </SelectTrigger>
12
12
  <SelectContent>
13
- <SelectItem value="10">10 / 页</SelectItem>
14
- <SelectItem value="20">20 / 页</SelectItem>
15
- <SelectItem value="50">50 / 页</SelectItem>
16
- <SelectItem value="100">100 / 页</SelectItem>
13
+ <SelectItem v-for="n in pageSizes" :key="n" :value="String(n)">
14
+ {{ pageSizeText(n) }}
15
+ </SelectItem>
17
16
  </SelectContent>
18
17
  </Select>
19
18
  <button
@@ -22,7 +21,7 @@
22
21
  :disabled="crud.pagination.value.page <= 1"
23
22
  @click="go(crud.pagination.value.page - 1)"
24
23
  >
25
- 上一页
24
+ {{ crudLabel('prevPage', crud.dict.label) }}
26
25
  </button>
27
26
  <span class="vm-crud-pagination__page">
28
27
  {{ crud.pagination.value.page }} / {{ totalPages }}
@@ -33,7 +32,7 @@
33
32
  :disabled="crud.pagination.value.page >= totalPages"
34
33
  @click="go(crud.pagination.value.page + 1)"
35
34
  >
36
- 下一页
35
+ {{ crudLabel('nextPage', crud.dict.label) }}
37
36
  </button>
38
37
  </div>
39
38
  </div>
@@ -42,15 +41,25 @@
42
41
  <script setup lang="ts">
43
42
  import { computed } from 'vue'
44
43
  import { useCrud } from './useCrud'
44
+ import { crudFormat, crudLabel } from './style'
45
45
 
46
46
  defineOptions({ name: 'vm-pagination' })
47
47
 
48
48
  const crud = useCrud()
49
+ const pageSizes = [10, 20, 50, 100]
49
50
 
50
51
  const totalPages = computed(() =>
51
52
  Math.max(1, Math.ceil(crud.pagination.value.total / crud.pagination.value.size) || 1),
52
53
  )
53
54
 
55
+ const totalText = computed(() =>
56
+ crudFormat(crudLabel('total', crud.dict.label), crud.pagination.value.total),
57
+ )
58
+
59
+ function pageSizeText(n: number) {
60
+ return crudFormat(crudLabel('pageSize', crud.dict.label), n)
61
+ }
62
+
54
63
  function go(page: number) {
55
64
  const next = Math.min(Math.max(1, page), totalPages.value)
56
65
  crud.pagination.value = { ...crud.pagination.value, page: next }
@@ -1,12 +1,13 @@
1
1
  <template>
2
2
  <button type="button" class="vm-crud-toolbar__btn is-ghost" @click="crud.refresh()">
3
3
  <i class="ri-refresh-line" />
4
- {{ crud.dict.label.refresh }}
4
+ {{ crudLabel('refresh', crud.dict.label) }}
5
5
  </button>
6
6
  </template>
7
7
 
8
8
  <script setup lang="ts">
9
9
  import { useCrud } from './useCrud'
10
+ import { crudLabel } from './style'
10
11
 
11
12
  defineOptions({ name: 'vm-refresh-btn' })
12
13
  const crud = useCrud()
@@ -3,12 +3,12 @@
3
3
  <Input
4
4
  class="vm-crud-search-key__input"
5
5
  :model-value="keyword"
6
- :placeholder="placeholder || crud.dict.label.searchKey"
6
+ :placeholder="placeholder || crudLabel('searchKey', crud.dict.label)"
7
7
  @update:model-value="onInput"
8
8
  @keydown.enter.prevent="search"
9
9
  />
10
10
  <button type="button" class="vm-crud-search-key__btn" @click="search">
11
- {{ crud.dict.label.search }}
11
+ {{ crudLabel('search', crud.dict.label) }}
12
12
  </button>
13
13
  </div>
14
14
  </template>
@@ -16,6 +16,7 @@
16
16
  <script setup lang="ts">
17
17
  import { ref } from 'vue'
18
18
  import { useCrud } from './useCrud'
19
+ import { crudLabel } from './style'
19
20
 
20
21
  defineOptions({ name: 'vm-search-key' })
21
22
 
@@ -17,7 +17,7 @@
17
17
  @update:model-value="(v) => (form[item.prop] = coerceSelect(item, v))"
18
18
  >
19
19
  <SelectTrigger class="vm-crud-search__control">
20
- <SelectValue :placeholder="item.placeholder || item.label" />
20
+ <SelectValue :placeholder="itemPlaceholder(item)" />
21
21
  </SelectTrigger>
22
22
  <SelectContent>
23
23
  <SelectItem
@@ -33,15 +33,19 @@
33
33
  v-else
34
34
  class="vm-crud-search__control"
35
35
  :model-value="String(form[item.prop] ?? '')"
36
- :placeholder="item.placeholder || item.label"
36
+ :placeholder="itemPlaceholder(item)"
37
37
  @update:model-value="(v) => (form[item.prop] = v)"
38
38
  @keydown.enter.prevent="search"
39
39
  />
40
40
  </template>
41
41
  </div>
42
42
  <div v-if="inlineActions" class="vm-crud-search__actions">
43
- <button type="button" class="vm-crud-search__btn is-primary" @click="search">搜索</button>
44
- <button type="button" class="vm-crud-search__btn is-ghost" @click="reset">重置</button>
43
+ <button type="button" class="vm-crud-search__btn is-primary" @click="search">
44
+ {{ crudLabel('search', crud.dict.label) }}
45
+ </button>
46
+ <button type="button" class="vm-crud-search__btn is-ghost" @click="reset">
47
+ {{ crudLabel('reset', crud.dict.label) }}
48
+ </button>
45
49
  <slot />
46
50
  </div>
47
51
  </div>
@@ -53,7 +57,13 @@ import { onBeforeUnmount } from 'vue'
53
57
  import { useCrud } from './useCrud'
54
58
  import { injectSearchOptions } from './key'
55
59
  import { buildAutoSearchItems } from './plugins'
56
- import { getCrudStyle } from './style'
60
+ import {
61
+ getCrudStyle,
62
+ crudLocaleRev,
63
+ crudLabel,
64
+ resolveSearchPlaceholder,
65
+ resolveRangePlaceholders,
66
+ } from './style'
57
67
  import { resolveCrudComponent } from './registry'
58
68
  import { service } from '../service'
59
69
  defineOptions({ name: 'vm-search' })
@@ -85,7 +95,14 @@ function mergeSearchItems(auto: CrudSearchItem[], manual: CrudSearchItem[]) {
85
95
  return merged
86
96
  }
87
97
 
88
- const items = computed(() => mergeSearchItems(autoItems.value, manualItems.value))
98
+ const items = computed(() => {
99
+ void crudLocaleRev.value
100
+ return mergeSearchItems(autoItems.value, manualItems.value)
101
+ })
102
+
103
+ function itemPlaceholder(item: CrudSearchItem) {
104
+ return resolveSearchPlaceholder(item)
105
+ }
89
106
 
90
107
  const form = reactive<Record<string, unknown>>({})
91
108
 
@@ -194,30 +211,22 @@ function resolveField(item: CrudSearchItem) {
194
211
  }
195
212
 
196
213
  function fieldProps(item: CrudSearchItem) {
197
- const name = String(item.placeholder || item.label || '').trim()
214
+ const ph = itemPlaceholder(item)
198
215
  const rangePlaceholders =
199
- item.type === 'number-range' && name
200
- ? {
201
- startPlaceholder: `${name}最小值`,
202
- endPlaceholder: `${name}最大值`,
203
- }
204
- : item.type === 'daterange' && name
205
- ? {
206
- startPlaceholder: `${name}开始`,
207
- endPlaceholder: `${name}结束`,
208
- }
209
- : {}
216
+ item.type === 'number-range' || item.type === 'daterange' || item.phMode === 'range'
217
+ ? resolveRangePlaceholders(item)
218
+ : {}
210
219
  return {
211
220
  options: resolveOptions(item.options),
212
- placeholder: item.placeholder || item.label,
213
221
  refreshOnChange: false,
214
222
  precision: item.range?.rangeType,
215
223
  mode:
216
224
  item.range?.rangeType === 'float' || item.range?.rangeType === 'int'
217
225
  ? item.range.rangeType
218
226
  : undefined,
219
- ...rangePlaceholders,
220
227
  ...(item.component?.props || {}),
228
+ placeholder: ph,
229
+ ...rangePlaceholders,
221
230
  }
222
231
  }
223
232
 
@@ -6,7 +6,9 @@
6
6
  'is-auto-height': autoHeight,
7
7
  }"
8
8
  >
9
- <div v-if="crud.loading.value" class="vm-crud-table__loading">加载中…</div>
9
+ <div v-if="crud.loading.value" class="vm-crud-table__loading">
10
+ {{ crudLabel('loading', crud.dict.label) }}
11
+ </div>
10
12
  <div ref="scrollRef" class="vm-crud-table__scroll vm-scroll">
11
13
  <Table>
12
14
  <TableHeader>
@@ -26,7 +28,7 @@
26
28
  @click="onSortClick(col)"
27
29
  >
28
30
  <span class="vm-crud-table__th-inner">
29
- {{ col.type === 'op' ? col.label || crud.dict.label.op : col.label }}
31
+ {{ columnLabel(col) }}
30
32
  <i
31
33
  v-if="isSortable(col) && col.prop"
32
34
  class="vm-crud-table__sort"
@@ -39,7 +41,7 @@
39
41
  class="vm-crud-table__th vm-crud-table__op"
40
42
  :style="{ width: `${opWidth}px`, minWidth: `${opWidth}px` }"
41
43
  >
42
- {{ crud.dict.label.op }}
44
+ {{ crudLabel('op', crud.dict.label) }}
43
45
  </TableHead>
44
46
  </TableRow>
45
47
  </TableHeader>
@@ -85,47 +87,52 @@
85
87
  class="vm-crud-table__ops"
86
88
  >
87
89
  <Button size="xs" variant="softPrimary" @click="crud.rowRestore([row])">
88
- 恢复
90
+ {{ crudLabel('restore', crud.dict.label) }}
89
91
  </Button>
90
92
  <Button
91
93
  size="xs"
92
94
  variant="softDestructive"
93
95
  @click="crud.rowDelete([row], true)"
94
96
  >
95
- 彻底删除
97
+ {{ crudLabel('forceDelete', crud.dict.label) }}
96
98
  </Button>
97
99
  </div>
98
100
  <div v-else class="vm-crud-table__ops">
99
101
  <template v-for="(btn, bi) in resolveButtons(col, row)" :key="bi">
100
102
  <Button
101
103
  v-if="btn === 'edit' && crud.getPermission('update')"
104
+ type="button"
102
105
  size="xs"
103
106
  variant="softPrimary"
104
- @click="crud.rowEdit(row)"
107
+ @click.stop="crud.rowEdit(row)"
105
108
  >
106
- {{ crud.dict.label.update }}
109
+ {{ crudLabel('update', crud.dict.label) }}
107
110
  </Button>
108
111
  <Button
109
112
  v-else-if="btn === 'delete' && crud.getPermission('delete')"
113
+ type="button"
110
114
  size="xs"
111
115
  variant="softDestructive"
112
- @click="crud.rowDelete([row])"
116
+ @click.stop="crud.rowDelete([row])"
113
117
  >
114
- {{ crud.dict.label.delete }}
118
+ {{ crudLabel('delete', crud.dict.label) }}
115
119
  </Button>
116
120
  <Button
117
121
  v-else-if="btn === 'info' && crud.getPermission('info')"
122
+ type="button"
118
123
  size="xs"
119
124
  variant="ghost"
120
- @click="crud.rowInfo(row)"
125
+ @click.stop="crud.rowInfo(row)"
121
126
  >
122
- {{ crud.dict.label.info }}
127
+ {{ crudLabel('info', crud.dict.label) }}
123
128
  </Button>
124
129
  <Button
125
130
  v-else-if="typeof btn === 'object' && !btn.hidden"
131
+ type="button"
126
132
  size="xs"
133
+ :disabled="btn.disabled"
127
134
  :variant="btn.variant || 'softSuccess'"
128
- @click="btn.onClick(row)"
135
+ @click.stop="btn.onClick(row)"
129
136
  >
130
137
  {{ btn.label }}
131
138
  </Button>
@@ -203,14 +210,14 @@
203
210
  class="vm-crud-table__ops"
204
211
  >
205
212
  <Button size="xs" variant="softPrimary" @click="crud.rowRestore([row])">
206
- 恢复
213
+ {{ crudLabel('restore', crud.dict.label) }}
207
214
  </Button>
208
215
  <Button
209
216
  size="xs"
210
217
  variant="softDestructive"
211
218
  @click="crud.rowDelete([row], true)"
212
219
  >
213
- 彻底删除
220
+ {{ crudLabel('forceDelete', crud.dict.label) }}
214
221
  </Button>
215
222
  </div>
216
223
  <slot v-else name="op" :row="row" />
@@ -229,7 +236,8 @@ import { useCrud } from './useCrud'
229
236
  import { injectTableOptions, TABLE_API_KEY } from './key'
230
237
  import { flattenTree } from '../lib/tree'
231
238
  import { resolveCrudComponent } from './registry'
232
- import { getCrudStyle } from './style'
239
+ import { getCrudStyle, crudLabel, crudT, crudLocaleRev } from './style'
240
+ import { findEpsEntity } from '../lib/eps'
233
241
  defineOptions({ name: 'vm-table' })
234
242
 
235
243
  const props = withDefaults(
@@ -284,6 +292,41 @@ const dataColumns = computed(() =>
284
292
  )
285
293
  const showSlotOp = computed(() => Boolean(slots.op) && !hasOpCol.value)
286
294
 
295
+ /** EPS 列 → field.{table}.{prop} */
296
+ function epsFieldKey(prop: string): string | undefined {
297
+ const ns = (crud.service as { namespace?: string } | undefined)?.namespace
298
+ if (!ns || !prop) return undefined
299
+ const entity = findEpsEntity(`/${ns}`)
300
+ if (!entity) return undefined
301
+ const cols = [
302
+ ...((entity as { columns?: Array<{ propertyName?: string; table?: string; source?: string }> }).columns || []),
303
+ ...((entity as { pageColumns?: Array<{ propertyName?: string; table?: string; source?: string }> }).pageColumns || []),
304
+ ]
305
+ const meta =
306
+ cols.find((c) => c.propertyName === prop) ||
307
+ cols.find((c) => c.source === `a.${prop}`) ||
308
+ cols.find((c) => c.source?.endsWith(`.${prop}`))
309
+ const table = meta?.table?.trim()
310
+ const name = (meta?.propertyName || prop).trim()
311
+ if (!table || !name) return undefined
312
+ return `${table}.${name}`
313
+ }
314
+
315
+ /** 表头文案:labelKey → field.* → label / op */
316
+ function columnLabel(col: CrudColumn): string {
317
+ void crudLocaleRev.value
318
+ if (col.type === 'op') {
319
+ return col.labelKey
320
+ ? crudT(col.labelKey, col.label || crudLabel('op', crud.dict.label))
321
+ : col.label || crudLabel('op', crud.dict.label)
322
+ }
323
+ const fb = col.label || col.prop || ''
324
+ if (col.labelKey) return crudT(col.labelKey, fb)
325
+ const fk = col.fieldKey || (col.prop ? epsFieldKey(col.prop) : undefined)
326
+ if (fk) return crudT(`field.${fk}`, fb)
327
+ return fb
328
+ }
329
+
287
330
  const colSpan = computed(
288
331
  () =>
289
332
  dataColumns.value.length +
@@ -352,7 +395,7 @@ function onSortClick(col: CrudColumn) {
352
395
  const prop = col.prop
353
396
  let next: 'asc' | 'desc' = 'asc'
354
397
  const current = sortState.value
355
- if (current?.prop === prop) {
398
+ if (current && current.prop === prop) {
356
399
  next = current.order === 'asc' ? 'desc' : 'asc'
357
400
  } else {
358
401
  const hint = normalizeSortDir(
@@ -403,12 +446,12 @@ const ctxItems = computed<CtxMenuItem[]>(() => {
403
446
  ? conf
404
447
  : ['refresh', 'check', 'edit', 'delete', 'order-asc', 'order-desc']
405
448
  const map: Record<string, string> = {
406
- refresh: crud.dict.label.refresh,
407
- check: crud.dict.label.select,
408
- edit: crud.dict.label.update,
409
- delete: crud.dict.label.delete,
410
- 'order-asc': crud.dict.label.asc,
411
- 'order-desc': crud.dict.label.desc,
449
+ refresh: crudLabel('refresh', crud.dict.label),
450
+ check: crudLabel('select', crud.dict.label),
451
+ edit: crudLabel('update', crud.dict.label),
452
+ delete: crudLabel('delete', crud.dict.label),
453
+ 'order-asc': crudLabel('asc', crud.dict.label),
454
+ 'order-desc': crudLabel('desc', crud.dict.label),
412
455
  }
413
456
  return keys.map((k) => ({
414
457
  key: k,