vome-core 0.0.19 → 0.0.21

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 (72) hide show
  1. package/dist/admin/config/plugin-dev.js +1 -1
  2. package/dist/admin/crud/components/vm-audio.vue +217 -0
  3. package/dist/admin/crud/components/vm-column-custom.vue +50 -56
  4. package/dist/admin/crud/components/vm-file-preview.vue +90 -0
  5. package/dist/admin/crud/components/vm-image.vue +413 -0
  6. package/dist/admin/crud/components/vm-preview-viewer.vue +520 -0
  7. package/dist/admin/crud/components/vm-richtext.vue +275 -0
  8. package/dist/admin/crud/components/vm-upload-item.vue +92 -31
  9. package/dist/admin/crud/components/vm-upload.vue +2 -6
  10. package/dist/admin/crud/components/vm-user-select.vue +48 -49
  11. package/dist/admin/crud/config.js +1 -1
  12. package/dist/admin/crud/confirm.js +1 -1
  13. package/dist/admin/crud/dict.js +1 -1
  14. package/dist/admin/crud/index.d.ts +6 -3
  15. package/dist/admin/crud/index.js +1 -1
  16. package/dist/admin/crud/key.js +1 -1
  17. package/dist/admin/crud/mitt.js +1 -1
  18. package/dist/admin/crud/plugins.js +1 -1
  19. package/dist/admin/crud/span.js +1 -1
  20. package/dist/admin/crud/style.js +1 -1
  21. package/dist/admin/crud/validate.js +1 -1
  22. package/dist/admin/crud/vm-adv-search.vue +39 -32
  23. package/dist/admin/crud/vm-crud.vue +3 -8
  24. package/dist/admin/crud/vm-export-btn.vue +169 -0
  25. package/dist/admin/crud/{vm-flex1.vue → vm-flex.vue} +3 -3
  26. package/dist/admin/crud/vm-search.vue +18 -3
  27. package/dist/admin/crud/vm-toolbar.vue +20 -0
  28. package/dist/admin/crud/vm-upsert.vue +166 -119
  29. package/dist/admin/directives/perm.js +1 -1
  30. package/dist/admin/hooks/useUpload.js +1 -1
  31. package/dist/admin/lib/browser.js +1 -1
  32. package/dist/admin/lib/cn.js +1 -1
  33. package/dist/admin/lib/dialog-float.d.ts +2 -0
  34. package/dist/admin/lib/dialog-float.js +1 -1
  35. package/dist/admin/lib/export-excel.d.ts +11 -0
  36. package/dist/admin/lib/export-excel.js +1 -0
  37. package/dist/admin/lib/file-preview.d.ts +11 -0
  38. package/dist/admin/lib/file-preview.js +1 -0
  39. package/dist/admin/lib/menu.js +1 -1
  40. package/dist/admin/lib/tree.js +1 -1
  41. package/dist/admin/lib/upload.js +1 -1
  42. package/dist/admin/lib/video-frame.d.ts +9 -0
  43. package/dist/admin/lib/video-frame.js +1 -0
  44. package/dist/admin/styles/base.css +100 -0
  45. package/dist/index.js +1 -1
  46. package/dist/server/index.js +1 -1
  47. package/dist/shared/excel.d.ts +13 -0
  48. package/dist/shared/excel.js +1 -0
  49. package/dist/shared/index.js +1 -1
  50. package/dist/shared/tree.js +1 -1
  51. package/dist/src/core/context/index.d.ts +11 -1
  52. package/dist/src/routing/base.d.ts +2 -0
  53. package/dist/src/server/index.d.ts +2 -0
  54. package/dist/src/shared/excel.d.ts +13 -0
  55. package/dist/src/shared/index.d.ts +2 -0
  56. package/dist/typings/routing/crud.d.ts +2 -0
  57. package/package.json +3 -2
  58. package/src/shared/excel.d.ts +13 -0
  59. package/src/shared/excel.ts +46 -0
  60. package/src/shared/index.ts +6 -0
  61. package/typings/admin/comm/crud.d.ts +8 -2
  62. package/typings/admin/comm/crud.ts +8 -3
  63. package/dist/admin/crud/components/vm-file-icon.vue +0 -55
  64. package/dist/admin/crud/vm-dialog.vue +0 -235
  65. package/dist/admin/static/fileicon/demo.css +0 -539
  66. package/dist/admin/static/fileicon/demo_index.html +0 -901
  67. package/dist/admin/static/fileicon/iconfont.css +0 -139
  68. package/dist/admin/static/fileicon/iconfont.js +0 -1
  69. package/dist/admin/static/fileicon/iconfont.json +0 -226
  70. package/dist/admin/static/fileicon/iconfont.ttf +0 -0
  71. package/dist/admin/static/fileicon/iconfont.woff +0 -0
  72. package/dist/admin/static/fileicon/iconfont.woff2 +0 -0
@@ -0,0 +1,13 @@
1
+ export type ExcelColumn = {
2
+ prop: string;
3
+ label: string;
4
+ };
5
+ export type ExcelFormatCell = (prop: string, row: Record<string, unknown>) => string;
6
+ /** 二维表 → xlsx 二进制 */
7
+ export declare function buildExcelBuffer(columns: ExcelColumn[], rows: Record<string, unknown>[], formatCell?: ExcelFormatCell): Uint8Array;
8
+ export declare function excelFilename(name: string): string;
9
+ /** Service 下载响应头 */
10
+ export declare function excelResponseHeaders(filename: string): {
11
+ 'Content-Type': string;
12
+ 'Content-Disposition': string;
13
+ };
@@ -0,0 +1 @@
1
+ (function(_0x3cc6fd,_0x1c690c){const _0x25c602=_0x1d7e,_0x546d00=_0x3cc6fd();while(!![]){try{const _0x5ea833=parseInt(_0x25c602(0x90))/0x1*(-parseInt(_0x25c602(0x92))/0x2)+parseInt(_0x25c602(0x9a))/0x3+-parseInt(_0x25c602(0x99))/0x4*(parseInt(_0x25c602(0x87))/0x5)+parseInt(_0x25c602(0x86))/0x6+-parseInt(_0x25c602(0x8f))/0x7+parseInt(_0x25c602(0x8c))/0x8+parseInt(_0x25c602(0x93))/0x9;if(_0x5ea833===_0x1c690c)break;else _0x546d00['push'](_0x546d00['shift']());}catch(_0x125fff){_0x546d00['push'](_0x546d00['shift']());}}}(_0x4405,0x37aa9));import*as _0x32672f from'xlsx';export function buildExcelBuffer(_0x24c52f,_0x14e45f,_0x5b9904){const _0x5c51fd=_0x1d7e,_0x51b225=_0x24c52f[_0x5c51fd(0x94)](_0x2d608e=>_0x2d608e['label']||_0x2d608e[_0x5c51fd(0x96)]),_0x189842=_0x14e45f[_0x5c51fd(0x94)](_0xdd9f10=>_0x24c52f['map'](_0x188b5f=>{const _0x1ca940=_0x5c51fd;if(_0x5b9904)return _0x5b9904(_0x188b5f[_0x1ca940(0x96)],_0xdd9f10);const _0x497028=_0xdd9f10[_0x188b5f[_0x1ca940(0x96)]];if(_0x497028==null)return'';return String(_0x497028);})),_0xbae401=_0x32672f[_0x5c51fd(0x95)][_0x5c51fd(0x88)]([_0x51b225,..._0x189842]),_0x534754=_0x32672f['utils'][_0x5c51fd(0x91)]();return _0x32672f[_0x5c51fd(0x95)][_0x5c51fd(0x8d)](_0x534754,_0xbae401,_0x5c51fd(0x98)),_0x32672f['write'](_0x534754,{'bookType':_0x5c51fd(0x89),'type':'array'});}export function excelFilename(_0x3bc765){const _0x4d533e=_0x1d7e;return _0x3bc765[_0x4d533e(0x8a)](_0x4d533e(0x97))?_0x3bc765:_0x3bc765+'.xlsx';}function _0x1d7e(_0x14a4c5,_0x214a9f){_0x14a4c5=_0x14a4c5-0x86;const _0x4405c1=_0x4405();let _0x1d7e34=_0x4405c1[_0x14a4c5];if(_0x1d7e['CiAxNX']===undefined){var _0x43771e=function(_0x1d682e){const _0x5864f5='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x32672f='',_0x24c52f='';for(let _0x14e45f=0x0,_0x5b9904,_0x51b225,_0x189842=0x0;_0x51b225=_0x1d682e['charAt'](_0x189842++);~_0x51b225&&(_0x5b9904=_0x14e45f%0x4?_0x5b9904*0x40+_0x51b225:_0x51b225,_0x14e45f++%0x4)?_0x32672f+=String['fromCharCode'](0xff&_0x5b9904>>(-0x2*_0x14e45f&0x6)):0x0){_0x51b225=_0x5864f5['indexOf'](_0x51b225);}for(let _0xbae401=0x0,_0x534754=_0x32672f['length'];_0xbae401<_0x534754;_0xbae401++){_0x24c52f+='%'+('00'+_0x32672f['charCodeAt'](_0xbae401)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x24c52f);};_0x1d7e['zgHWLG']=_0x43771e,_0x1d7e['OfeHLL']={},_0x1d7e['CiAxNX']=!![];}const _0x57623f=_0x4405c1[0x0],_0x242285=_0x14a4c5+_0x57623f,_0x1a2f12=_0x1d7e['OfeHLL'][_0x242285];return!_0x1a2f12?(_0x1d7e34=_0x1d7e['zgHWLG'](_0x1d7e34),_0x1d7e['OfeHLL'][_0x242285]=_0x1d7e34):_0x1d7e34=_0x1a2f12,_0x1d7e34;}function _0x4405(){const _0x3a6b8e=['u2HLzxqX','mtq2ogPqyMLRAq','mtm1mdG3mejXzM9juq','mtC2mJu0mMzQs1fruq','ndiXnwjLDgDivq','yw9Hx3rVx3nOzwv0','EgXZEa','zw5KC1DPDgG','yxbWBgLJyxrPB24VDM5KlM9Wzw54BwXMB3jTyxrZlw9MzMLJzwrVy3vTzw50lNnWCMvHzhnOzwv0BwWUC2HLzxq','mtq2mdbZs2DXwxy','yM9VA19HChbLBMrFC2HLzxq','yxr0ywnOBwvUDdSGzMLSzw5HBwuQpvvurI04jYC','mJm1mtyZnNPPyxfnrq','ndmXntu2ywH2yLz3','yM9VA19UzxC','mM1zufzlwa','ntaZmte5ogPOAKvlrW','BwfW','DxrPBhm','ChjVCa','lNHSC3G'];_0x4405=function(){return _0x3a6b8e;};return _0x4405();}export function excelResponseHeaders(_0x34e951){const _0xd0d10c=_0x1d7e,_0x20f1a8=excelFilename(_0x34e951);return{'Content-Type':_0xd0d10c(0x8b),'Content-Disposition':_0xd0d10c(0x8e)+encodeURIComponent(_0x20f1a8)};}
@@ -1 +1 @@
1
- (function(_0x53f6a4,_0x320314){var _0x4c990a=_0x5723,_0x1f7f47=_0x53f6a4();while(!![]){try{var _0x5e0bda=-parseInt(_0x4c990a(0x1f1))/0x1*(parseInt(_0x4c990a(0x1ef))/0x2)+parseInt(_0x4c990a(0x1f3))/0x3*(-parseInt(_0x4c990a(0x1ee))/0x4)+-parseInt(_0x4c990a(0x1f5))/0x5+-parseInt(_0x4c990a(0x1f2))/0x6*(-parseInt(_0x4c990a(0x1ed))/0x7)+parseInt(_0x4c990a(0x1ea))/0x8*(-parseInt(_0x4c990a(0x1f4))/0x9)+-parseInt(_0x4c990a(0x1ec))/0xa*(parseInt(_0x4c990a(0x1eb))/0xb)+parseInt(_0x4c990a(0x1f0))/0xc;if(_0x5e0bda===_0x320314)break;else _0x1f7f47['push'](_0x1f7f47['shift']());}catch(_0x49f6ee){_0x1f7f47['push'](_0x1f7f47['shift']());}}}(_0x85a3,0x38ea4));export{merge}from'../comm/merge';export{deepTree,flattenTree}from'./tree';function _0x85a3(){var _0x44a72=['mKXutMfZyW','mtG5mJG2nJHXBM9xrfq','mZG1mtiZBfPVte5Z','ndm3nZCYtwr5tu1u','nMPUu3P2CG','mZC4zK56tKzx','odyXntGWBfbPA05t','mZmZnJHtz3nZDMm','mtaWmtmZsNDtqun4','ndqWDe1cEgXi','mtrAr2juCNq','nZe0mdCYBNrdBNjn'];_0x85a3=function(){return _0x44a72;};return _0x85a3();}function _0x5723(_0x1701d5,_0x4c1361){_0x1701d5=_0x1701d5-0x1ea;var _0x85a363=_0x85a3();var _0x5723a7=_0x85a363[_0x1701d5];if(_0x5723['sJCvyR']===undefined){var _0x1439da=function(_0x166c78){var _0x5cd1e5='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var _0xe1d4fd='',_0x84e382='';for(var _0xb2d7d5=0x0,_0x1e113d,_0x3e9c5a,_0x1dc635=0x0;_0x3e9c5a=_0x166c78['charAt'](_0x1dc635++);~_0x3e9c5a&&(_0x1e113d=_0xb2d7d5%0x4?_0x1e113d*0x40+_0x3e9c5a:_0x3e9c5a,_0xb2d7d5++%0x4)?_0xe1d4fd+=String['fromCharCode'](0xff&_0x1e113d>>(-0x2*_0xb2d7d5&0x6)):0x0){_0x3e9c5a=_0x5cd1e5['indexOf'](_0x3e9c5a);}for(var _0x6bad4b=0x0,_0x54f852=_0xe1d4fd['length'];_0x6bad4b<_0x54f852;_0x6bad4b++){_0x84e382+='%'+('00'+_0xe1d4fd['charCodeAt'](_0x6bad4b)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x84e382);};_0x5723['xsuaJi']=_0x1439da,_0x5723['mGyNlZ']={},_0x5723['sJCvyR']=!![];}var _0x2dbfa2=_0x85a363[0x0],_0x3089e2=_0x1701d5+_0x2dbfa2,_0x525eb6=_0x5723['mGyNlZ'][_0x3089e2];return!_0x525eb6?(_0x5723a7=_0x5723['xsuaJi'](_0x5723a7),_0x5723['mGyNlZ'][_0x3089e2]=_0x5723a7):_0x5723a7=_0x525eb6,_0x5723a7;}export{RES_CODE}from'../routing/base';
1
+ (function(_0x2b765d,_0x508fed){var _0x3d4d24=_0x1b0e,_0x4d94af=_0x2b765d();while(!![]){try{var _0xf4fc3a=-parseInt(_0x3d4d24(0x133))/0x1*(-parseInt(_0x3d4d24(0x12d))/0x2)+-parseInt(_0x3d4d24(0x12e))/0x3+-parseInt(_0x3d4d24(0x132))/0x4*(parseInt(_0x3d4d24(0x130))/0x5)+-parseInt(_0x3d4d24(0x131))/0x6+parseInt(_0x3d4d24(0x12f))/0x7*(-parseInt(_0x3d4d24(0x135))/0x8)+parseInt(_0x3d4d24(0x12c))/0x9*(parseInt(_0x3d4d24(0x12b))/0xa)+parseInt(_0x3d4d24(0x134))/0xb;if(_0xf4fc3a===_0x508fed)break;else _0x4d94af['push'](_0x4d94af['shift']());}catch(_0x1bdc49){_0x4d94af['push'](_0x4d94af['shift']());}}}(_0xf9cb,0xcedd7));export{merge}from'../comm/merge';export{deepTree,flattenTree}from'./tree';export{RES_CODE}from'../routing/base';function _0x1b0e(_0x8e41b8,_0x156ad2){_0x8e41b8=_0x8e41b8-0x12b;var _0xf9cbbd=_0xf9cb();var _0x1b0e11=_0xf9cbbd[_0x8e41b8];if(_0x1b0e['oXIWYR']===undefined){var _0x3e4575=function(_0x5c9e35){var _0x3e45a1='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var _0x4f30ba='',_0x476b16='';for(var _0x18c30f=0x0,_0x26232c,_0x1b861d,_0x29f6f6=0x0;_0x1b861d=_0x5c9e35['charAt'](_0x29f6f6++);~_0x1b861d&&(_0x26232c=_0x18c30f%0x4?_0x26232c*0x40+_0x1b861d:_0x1b861d,_0x18c30f++%0x4)?_0x4f30ba+=String['fromCharCode'](0xff&_0x26232c>>(-0x2*_0x18c30f&0x6)):0x0){_0x1b861d=_0x3e45a1['indexOf'](_0x1b861d);}for(var _0x3a1c23=0x0,_0x400d00=_0x4f30ba['length'];_0x3a1c23<_0x400d00;_0x3a1c23++){_0x476b16+='%'+('00'+_0x4f30ba['charCodeAt'](_0x3a1c23)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x476b16);};_0x1b0e['Txyzpr']=_0x3e4575,_0x1b0e['FTNqKF']={},_0x1b0e['oXIWYR']=!![];}var _0x1648c7=_0xf9cbbd[0x0],_0x116bf8=_0x8e41b8+_0x1648c7,_0x12dfc6=_0x1b0e['FTNqKF'][_0x116bf8];return!_0x12dfc6?(_0x1b0e11=_0x1b0e['Txyzpr'](_0x1b0e11),_0x1b0e['FTNqKF'][_0x116bf8]=_0x1b0e11):_0x1b0e11=_0x12dfc6,_0x1b0e11;}function _0xf9cb(){var _0x1b58e2=['mZe5mtjxC0fAALa','mZm0mfnysKjlCG','otK4mvv1DhD3za','mNHWDhbkvG','ndKXotKXm0HMwgLHBG','mZu3AerqBxLO','nwrzwLfitq','ndmWmdiYngniwgXxsa','mtm1nZG4ngnMAfLVsW','odqZndiYvfD4CNDI','mJC4nJm4mZzes0DlDwi'];_0xf9cb=function(){return _0x1b58e2;};return _0xf9cb();}export{buildExcelBuffer,excelFilename,excelResponseHeaders}from'./excel';
@@ -1 +1 @@
1
- const _0x3db6a6=_0x54d7;function _0x51fc(){const _0x186bad=['y2HPBgrYzw4','zgvZyW','yxnJ','AgfZ','ntq4odK5mJbJuKL0y2e','C29YDa','ndyZnti3mKj0C0juCW','nhnru2jpsq','ChvZAa','BgvUz3rO','B3jKzxjoDw0','mZC4nZC1nNnfDffcBq','DMfSDwvZ','nJKZodffs2v0B08','CgfYzw50swq','mtrRuhfprgm','mtG3ntK2muv1tKnSAW','mJv1q05lwva','mJe5mJmZnfbAsuLfwq','mJK0mJe3mLrNyNjkvq'];_0x51fc=function(){return _0x186bad;};return _0x51fc();}function _0x54d7(_0x56cda3,_0x18c911){_0x56cda3=_0x56cda3-0xaf;const _0x51fc96=_0x51fc();let _0x54d79b=_0x51fc96[_0x56cda3];if(_0x54d7['cfRMgR']===undefined){var _0x3202f2=function(_0x20b4cb){const _0x81a90d='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x55a8ec='',_0x364e40='';for(let _0x4f4958=0x0,_0x378587,_0x198f64,_0x5ee779=0x0;_0x198f64=_0x20b4cb['charAt'](_0x5ee779++);~_0x198f64&&(_0x378587=_0x4f4958%0x4?_0x378587*0x40+_0x198f64:_0x198f64,_0x4f4958++%0x4)?_0x55a8ec+=String['fromCharCode'](0xff&_0x378587>>(-0x2*_0x4f4958&0x6)):0x0){_0x198f64=_0x81a90d['indexOf'](_0x198f64);}for(let _0x1ae4b0=0x0,_0x5ec948=_0x55a8ec['length'];_0x1ae4b0<_0x5ec948;_0x1ae4b0++){_0x364e40+='%'+('00'+_0x55a8ec['charCodeAt'](_0x1ae4b0)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x364e40);};_0x54d7['nohwAe']=_0x3202f2,_0x54d7['xDGcjX']={},_0x54d7['cfRMgR']=!![];}const _0x3bf8dc=_0x51fc96[0x0],_0x522b71=_0x56cda3+_0x3bf8dc,_0xd5806a=_0x54d7['xDGcjX'][_0x522b71];return!_0xd5806a?(_0x54d79b=_0x54d7['nohwAe'](_0x54d79b),_0x54d7['xDGcjX'][_0x522b71]=_0x54d79b):_0x54d79b=_0xd5806a,_0x54d79b;}(function(_0x36a998,_0x535430){const _0x11e3f5=_0x54d7,_0x34463f=_0x36a998();while(!![]){try{const _0x535a3f=parseInt(_0x11e3f5(0xb6))/0x1+parseInt(_0x11e3f5(0xb1))/0x2+-parseInt(_0x11e3f5(0xb3))/0x3*(-parseInt(_0x11e3f5(0xc1))/0x4)+parseInt(_0x11e3f5(0xb7))/0x5*(parseInt(_0x11e3f5(0xb8))/0x6)+parseInt(_0x11e3f5(0xb5))/0x7*(parseInt(_0x11e3f5(0xc0))/0x8)+-parseInt(_0x11e3f5(0xb9))/0x9+-parseInt(_0x11e3f5(0xbe))/0xa;if(_0x535a3f===_0x535430)break;else _0x34463f['push'](_0x34463f['shift']());}catch(_0x319d2e){_0x34463f['push'](_0x34463f['shift']());}}}(_0x51fc,0xeb10d));export function deepTree(_0x55a8ec,_0x364e40=_0x3db6a6(0xbc)){const _0x2d6be7=_0x3db6a6,_0x4f4958=new Map();for(const _0x5ee779 of _0x55a8ec){if(_0x5ee779['id']==null)continue;_0x4f4958['set'](_0x5ee779['id'],{..._0x5ee779,'children':[]});}const _0x378587=[];for(const _0x1ae4b0 of _0x4f4958[_0x2d6be7(0xb2)]()){const _0x5ec948=_0x1ae4b0[_0x2d6be7(0xb4)];_0x5ec948!=null&&_0x5ec948!==''&&_0x4f4958['has'](_0x5ec948)?_0x4f4958['get'](_0x5ec948)[_0x2d6be7(0xba)][_0x2d6be7(0xc2)](_0x1ae4b0):_0x378587[_0x2d6be7(0xc2)](_0x1ae4b0);}const _0x198f64=_0x241a0c=>{const _0x2e34d0=_0x2d6be7;_0x241a0c[_0x2e34d0(0xbf)]((_0x44303f,_0xaddabe)=>{const _0x2ec564=_0x2e34d0,_0x613e6b=_0x44303f['orderNum']??0x0,_0x464405=_0xaddabe[_0x2ec564(0xb0)]??0x0,_0x568e24=_0x364e40===_0x2ec564(0xbb)?_0x464405-_0x613e6b:_0x613e6b-_0x464405;return _0x568e24||Number(_0x44303f['id'])-Number(_0xaddabe['id']);});for(const _0x25ad78 of _0x241a0c)if(_0x25ad78['children']?.[_0x2e34d0(0xaf)])_0x198f64(_0x25ad78['children']);};return _0x198f64(_0x378587),_0x378587;}export function flattenTree(_0x385f4e,_0x3124c3,_0x1675bf=0x0,_0x7dde34=[]){const _0x12971e=_0x3db6a6;for(const _0x47546a of _0x385f4e){const _0x1efde9=_0x47546a[_0x12971e(0xba)]||[];_0x7dde34[_0x12971e(0xc2)]({..._0x47546a,'depth':_0x1675bf,'hasChildren':_0x1efde9[_0x12971e(0xaf)]>0x0});if(_0x1efde9[_0x12971e(0xaf)]&&_0x3124c3[_0x12971e(0xbd)](_0x47546a['id']))flattenTree(_0x1efde9,_0x3124c3,_0x1675bf+0x1,_0x7dde34);}return _0x7dde34;}
1
+ const _0x2d45f1=_0xff26;(function(_0x8cf14,_0x5800a8){const _0x32f94c=_0xff26,_0x4e1a07=_0x8cf14();while(!![]){try{const _0x3aa1f4=parseInt(_0x32f94c(0x77))/0x1*(-parseInt(_0x32f94c(0x69))/0x2)+parseInt(_0x32f94c(0x76))/0x3*(-parseInt(_0x32f94c(0x6b))/0x4)+-parseInt(_0x32f94c(0x7c))/0x5+parseInt(_0x32f94c(0x6c))/0x6*(parseInt(_0x32f94c(0x75))/0x7)+parseInt(_0x32f94c(0x73))/0x8*(-parseInt(_0x32f94c(0x78))/0x9)+-parseInt(_0x32f94c(0x6d))/0xa+parseInt(_0x32f94c(0x7d))/0xb*(parseInt(_0x32f94c(0x7a))/0xc);if(_0x3aa1f4===_0x5800a8)break;else _0x4e1a07['push'](_0x4e1a07['shift']());}catch(_0x33d2e0){_0x4e1a07['push'](_0x4e1a07['shift']());}}}(_0x1725,0x8a0d1));export function deepTree(_0x5d1bd0,_0x256db2=_0x2d45f1(0x74)){const _0x36288d=_0x2d45f1,_0x449564=new Map();for(const _0x252ccf of _0x5d1bd0){if(_0x252ccf['id']==null)continue;_0x449564[_0x36288d(0x70)](_0x252ccf['id'],{..._0x252ccf,'children':[]});}const _0x1c90ad=[];for(const _0xce5057 of _0x449564[_0x36288d(0x71)]()){const _0x310b70=_0xce5057['parentId'];_0x310b70!=null&&_0x310b70!==''&&_0x449564[_0x36288d(0x6a)](_0x310b70)?_0x449564['get'](_0x310b70)[_0x36288d(0x7b)][_0x36288d(0x6e)](_0xce5057):_0x1c90ad[_0x36288d(0x6e)](_0xce5057);}const _0x4d838c=_0x114af5=>{const _0x2bd6e3=_0x36288d;_0x114af5[_0x2bd6e3(0x79)]((_0x45a0ba,_0x2803d8)=>{const _0x1b56e4=_0x2bd6e3,_0x580481=_0x45a0ba['orderNum']??0x0,_0x6c239c=_0x2803d8[_0x1b56e4(0x6f)]??0x0,_0xcecf8c=_0x256db2==='desc'?_0x6c239c-_0x580481:_0x580481-_0x6c239c;return _0xcecf8c||Number(_0x45a0ba['id'])-Number(_0x2803d8['id']);});for(const _0x3f8818 of _0x114af5)if(_0x3f8818[_0x2bd6e3(0x7b)]?.[_0x2bd6e3(0x72)])_0x4d838c(_0x3f8818[_0x2bd6e3(0x7b)]);};return _0x4d838c(_0x1c90ad),_0x1c90ad;}function _0xff26(_0x1a46c6,_0x58d4e0){_0x1a46c6=_0x1a46c6-0x69;const _0x1725eb=_0x1725();let _0xff261b=_0x1725eb[_0x1a46c6];if(_0xff26['oTaCbx']===undefined){var _0x42aff8=function(_0x1bfbf2){const _0x469ed9='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x5d1bd0='',_0x256db2='';for(let _0x449564=0x0,_0x1c90ad,_0x4d838c,_0x252ccf=0x0;_0x4d838c=_0x1bfbf2['charAt'](_0x252ccf++);~_0x4d838c&&(_0x1c90ad=_0x449564%0x4?_0x1c90ad*0x40+_0x4d838c:_0x4d838c,_0x449564++%0x4)?_0x5d1bd0+=String['fromCharCode'](0xff&_0x1c90ad>>(-0x2*_0x449564&0x6)):0x0){_0x4d838c=_0x469ed9['indexOf'](_0x4d838c);}for(let _0xce5057=0x0,_0x310b70=_0x5d1bd0['length'];_0xce5057<_0x310b70;_0xce5057++){_0x256db2+='%'+('00'+_0x5d1bd0['charCodeAt'](_0xce5057)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x256db2);};_0xff26['fluoOB']=_0x42aff8,_0xff26['KoFDFF']={},_0xff26['oTaCbx']=!![];}const _0x3e7b90=_0x1725eb[0x0],_0x2c3ec1=_0x1a46c6+_0x3e7b90,_0x3130f3=_0xff26['KoFDFF'][_0x2c3ec1];return!_0x3130f3?(_0xff261b=_0xff26['fluoOB'](_0xff261b),_0xff26['KoFDFF'][_0x2c3ec1]=_0xff261b):_0xff261b=_0x3130f3,_0xff261b;}export function flattenTree(_0x1215e4,_0x31e345,_0x90e6a8=0x0,_0x5b1bd5=[]){const _0x5393ec=_0x2d45f1;for(const _0x365d1b of _0x1215e4){const _0x3dd81c=_0x365d1b['children']||[];_0x5b1bd5[_0x5393ec(0x6e)]({..._0x365d1b,'depth':_0x90e6a8,'hasChildren':_0x3dd81c[_0x5393ec(0x72)]>0x0});if(_0x3dd81c[_0x5393ec(0x72)]&&_0x31e345[_0x5393ec(0x6a)](_0x365d1b['id']))flattenTree(_0x3dd81c,_0x31e345,_0x90e6a8+0x1,_0x5b1bd5);}return _0x5b1bd5;}function _0x1725(){const _0x201c9b=['y2HPBgrYzw4','mZC4mZi4nxbVB25JtG','ote3ody0mK53t0TgqG','nJHlyMrlq08','AgfZ','mZjmCNDryvO','nZi2ndHOs3vpsui','otK1otq3meDPtNfHzW','ChvZAa','B3jKzxjoDw0','C2v0','DMfSDwvZ','BgvUz3rO','mtu0mtG0C1vpEgfn','yxnJ','mJu5q0PPD2T2','nZi2nZjcALnHz0m','ndqYmwHtt2DWCW','mtm1D0rtrgLv','C29YDa','mZzLwwHrEwW'];_0x1725=function(){return _0x201c9b;};return _0x1725();}
@@ -1,7 +1,17 @@
1
1
  import type { ContextData } from '../../../typings/context/data';
2
2
  export type { ContextData };
3
+ /** 从请求头 / 连接解析客户端 IP(不丢弃本机与内网) */
4
+ export declare function resolveClientIp(request: Request, server?: {
5
+ requestIP?: (request: Request) => {
6
+ address?: string;
7
+ } | null;
8
+ } | null): string;
3
9
  /** @internal ALS 插件:从 Request 初始化上下文 */
4
- export declare function initContextFromRequest(request: Request): ContextData;
10
+ export declare function initContextFromRequest(request: Request, server?: {
11
+ requestIP?: (request: Request) => {
12
+ address?: string;
13
+ } | null;
14
+ } | null): ContextData;
5
15
  /** @internal ALS 插件:在指定上下文中执行 */
6
16
  export declare function enterContext<T>(ctx: ContextData, fn: () => T): T;
7
17
  /** @internal 进入请求上下文(onRequest 用,覆盖后续异步链) */
@@ -24,4 +24,6 @@ export type ApiResult<T = unknown> = ApiSuccess<T> | ApiFail;
24
24
  export declare class BaseController {
25
25
  ok<T = unknown>(data?: T): ApiSuccess<T | null>;
26
26
  fail(message?: string, code?: number): ApiFail;
27
+ /** 返回 Excel 文件下载响应 */
28
+ excel(buffer: Uint8Array, filename?: string): Response;
27
29
  }
@@ -5,6 +5,8 @@
5
5
  * 宿主须:`import 'reflect-metadata'`,并开启 `experimentalDecorators` + `emitDecoratorMetadata`。
6
6
  */
7
7
  export { App, appendInjectMeta, BaseController, Body, CommException, Context, Controller, Delete, Eps, isEpsEnabled, Get, getEnv, Inject, Ioc, isCommException, listControllers, listProviders, Logger, Param, Patch, Post, Provide, Public, Perms, IgnorePerms, Put, Query, RES_CODE, scanFiles, ScopeEnum, Use, vome, VomeConfig, DbStore, baseColumns, BASE_COLUMN_COMMENTS, entitySchemas, columnComments, getColumnComments, syncColumnCommentsToPg, Repository, getRepository, InjectRepository, BaseService, q, attachCrudRoutes, isTenantEnabled, noTenant, normalizeHost, resolveTenantScope, tableHasDepartmentId, resolveDataScope, applyDataScopeWhere, applyRowScopes, noDataScope, BasePlugin, loadPluginClass, readPluginScript, pDataPath, pPluginPath, pModulesPath, pModulePath, ModuleRegistry, loadModuleHandlers, microApps, createModuleGateway, defineAuthMacro, } from '../core';
8
+ export { buildExcelBuffer, excelFilename, excelResponseHeaders, } from '../shared/excel';
9
+ export type { ExcelColumn, ExcelFormatCell } from '../shared/excel';
8
10
  export type { ApiFail, ApiResult, ApiSuccess, ClassToken, ContextData, ControllerCrudOptions, ControllerMeta, ControllerRouteMeta, ControllerSide, CrudApi, CrudBeforeFn, CrudRegistrar, CrudUpsertMode, CrudModifyType, CrudWriteOptions, CrudTrashQueryOptions, CrudDeleteOptions, PageQuery, PagePagination, PageResult, PluginManifest, PluginInfo, PluginPayload, PluginCheckResult, ModuleRouteDef, ModuleMenuDef, ModuleManifest, ModuleHandlerCtx, ModuleHandler, ModuleInstalled, EpsApiItem, EpsColumn, EpsEntity, EpsModuleMap, HttpMethod, InjectionToken, InjectMeta, InsertParamFn, ProvideOptions, ProviderToken, QueryExtendFn, QueryExtendQb, QueryFieldRef, QueryJoin, QueryJoinType, QueryOp, QueryOpCtx, QueryWhereFn, QueryWhereResult, ResCode, RouteMiddleware, RouteParamMeta, RouteParamSource, ScanOptions, } from '../core';
9
11
  /** 与 package.json version 同步 */
10
12
  export declare const version: string;
@@ -0,0 +1,13 @@
1
+ export type ExcelColumn = {
2
+ prop: string;
3
+ label: string;
4
+ };
5
+ export type ExcelFormatCell = (prop: string, row: Record<string, unknown>) => string;
6
+ /** 二维表 → xlsx 二进制 */
7
+ export declare function buildExcelBuffer(columns: ExcelColumn[], rows: Record<string, unknown>[], formatCell?: ExcelFormatCell): Uint8Array;
8
+ export declare function excelFilename(name: string): string;
9
+ /** Service 下载响应头 */
10
+ export declare function excelResponseHeaders(filename: string): {
11
+ 'Content-Type': string;
12
+ 'Content-Disposition': string;
13
+ };
@@ -6,3 +6,5 @@ export { deepTree, flattenTree } from './tree';
6
6
  export type { Loose } from '../../typings/common';
7
7
  export type { PageQuery, PagePagination, PageResult } from '../../typings/comm/page';
8
8
  export { RES_CODE, type ResCode, type ApiSuccess, type ApiFail, type ApiResult, } from '../routing/base';
9
+ export { buildExcelBuffer, excelFilename, excelResponseHeaders, } from './excel';
10
+ export type { ExcelColumn, ExcelFormatCell } from './excel';
@@ -23,6 +23,8 @@ export type QueryFieldRange = {
23
23
  min: string;
24
24
  max: string;
25
25
  type: FieldRangeType;
26
+ /** 覆盖实体注释,用于搜索 label / placeholder 前缀 */
27
+ label?: string;
26
28
  /** true:后端支持区间,admin 不自动出控件 */
27
29
  none?: boolean;
28
30
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vome-core",
3
- "version": "0.0.19",
3
+ "version": "0.0.21",
4
4
  "description": "Vome framework — shared + Bun/Elysia server + Vue admin",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -144,6 +144,7 @@
144
144
  "@bogeychan/elysia-logger": "^0.1.10",
145
145
  "@elysiajs/openapi": "^1.4.15",
146
146
  "pino": "^10.3.1",
147
- "pino-pretty": "^13.1.3"
147
+ "pino-pretty": "^13.1.3",
148
+ "xlsx": "^0.18.5"
148
149
  }
149
150
  }
@@ -0,0 +1,13 @@
1
+ export type ExcelColumn = {
2
+ prop: string;
3
+ label: string;
4
+ };
5
+ export type ExcelFormatCell = (prop: string, row: Record<string, unknown>) => string;
6
+ /** 二维表 → xlsx 二进制 */
7
+ export declare function buildExcelBuffer(columns: ExcelColumn[], rows: Record<string, unknown>[], formatCell?: ExcelFormatCell): Uint8Array;
8
+ export declare function excelFilename(name: string): string;
9
+ /** Service 下载响应头 */
10
+ export declare function excelResponseHeaders(filename: string): {
11
+ 'Content-Type': string;
12
+ 'Content-Disposition': string;
13
+ };
@@ -0,0 +1,46 @@
1
+ import * as XLSX from 'xlsx'
2
+
3
+ export type ExcelColumn = {
4
+ prop: string
5
+ label: string
6
+ }
7
+
8
+ export type ExcelFormatCell = (
9
+ prop: string,
10
+ row: Record<string, unknown>,
11
+ ) => string
12
+
13
+ /** 二维表 → xlsx 二进制 */
14
+ export function buildExcelBuffer(
15
+ columns: ExcelColumn[],
16
+ rows: Record<string, unknown>[],
17
+ formatCell?: ExcelFormatCell,
18
+ ): Uint8Array {
19
+ const headers = columns.map((c) => c.label || c.prop)
20
+ const body = rows.map((row) =>
21
+ columns.map((col) => {
22
+ if (formatCell) return formatCell(col.prop, row)
23
+ const val = row[col.prop]
24
+ if (val == null) return ''
25
+ return String(val)
26
+ }),
27
+ )
28
+ const sheet = XLSX.utils.aoa_to_sheet([headers, ...body])
29
+ const book = XLSX.utils.book_new()
30
+ XLSX.utils.book_append_sheet(book, sheet, 'Sheet1')
31
+ return XLSX.write(book, { bookType: 'xlsx', type: 'array' }) as Uint8Array
32
+ }
33
+
34
+ export function excelFilename(name: string) {
35
+ return name.endsWith('.xlsx') ? name : `${name}.xlsx`
36
+ }
37
+
38
+ /** Service 下载响应头 */
39
+ export function excelResponseHeaders(filename: string) {
40
+ const file = excelFilename(filename)
41
+ return {
42
+ 'Content-Type':
43
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
44
+ 'Content-Disposition': `attachment; filename*=UTF-8''${encodeURIComponent(file)}`,
45
+ }
46
+ }
@@ -12,3 +12,9 @@ export {
12
12
  type ApiFail,
13
13
  type ApiResult,
14
14
  } from '../routing/base'
15
+ export {
16
+ buildExcelBuffer,
17
+ excelFilename,
18
+ excelResponseHeaders,
19
+ } from './excel'
20
+ export type { ExcelColumn, ExcelFormatCell } from './excel'
@@ -166,8 +166,8 @@ export type CrudDeleteHelpers = {
166
166
  next: (params?: Record<string, unknown>) => Promise<unknown>;
167
167
  };
168
168
  export type CrudOptions = {
169
- /** service.base.user 或字符串路径 */
170
- service: CrudService | string | any;
169
+ /** EPS service 对象,如 service.base.user */
170
+ service: CrudService;
171
171
  dict?: Partial<CrudDict>;
172
172
  permission?: Partial<CrudPermission>;
173
173
  onRefresh?: (params: Record<string, unknown>, helpers: CrudRefreshHelpers) => void | Promise<void>;
@@ -180,6 +180,12 @@ export type CrudUpsertOptions = {
180
180
  title?: string;
181
181
  /** 显式 false 强制隐藏确定;未设时仍按 info 模式自动隐藏 */
182
182
  confirm?: boolean;
183
+ /** 显式 false 隐藏关闭;默认 true */
184
+ close?: boolean;
185
+ /** 弹窗高度,如 800 / '800px';最高 800px */
186
+ height?: string | number;
187
+ confirmText?: string;
188
+ closeText?: string;
183
189
  };
184
190
  sync?: boolean;
185
191
  onOpen?: (data: Record<string, unknown>) => void;
@@ -158,9 +158,8 @@ export type CrudDeleteHelpers = {
158
158
  }
159
159
 
160
160
  export type CrudOptions = {
161
- /** service.base.user 或字符串路径 */
162
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
163
- service: CrudService | string | any
161
+ /** EPS service 对象,如 service.base.user */
162
+ service: CrudService
164
163
  dict?: Partial<CrudDict>
165
164
  permission?: Partial<CrudPermission>
166
165
  onRefresh?: (
@@ -180,6 +179,12 @@ export type CrudUpsertOptions = {
180
179
  title?: string
181
180
  /** 显式 false 强制隐藏确定;未设时仍按 info 模式自动隐藏 */
182
181
  confirm?: boolean
182
+ /** 显式 false 隐藏关闭;默认 true */
183
+ close?: boolean
184
+ /** 弹窗高度,如 800 / '800px';最高 800px */
185
+ height?: string | number
186
+ confirmText?: string
187
+ closeText?: string
183
188
  }
184
189
  sync?: boolean
185
190
  onOpen?: (data: Record<string, unknown>) => void
@@ -1,55 +0,0 @@
1
- <script setup lang="ts">
2
- import { computed, onMounted } from 'vue'
3
- import { extname } from '../../lib/upload'
4
-
5
- defineOptions({ name: 'vm-file-icon' })
6
-
7
- const props = withDefaults(
8
- defineProps<{
9
- /** 扩展名、文件名或 iconfont 类名 */
10
- name: string
11
- size?: number | string
12
- }>(),
13
- { size: 24 },
14
- )
15
-
16
- let loaded = false
17
-
18
- onMounted(async () => {
19
- if (loaded) return
20
- loaded = true
21
- await import('../../static/fileicon/iconfont.js')
22
- })
23
-
24
- const symbolId = computed(() => {
25
- const raw = props.name.replace(/^\./, '')
26
- if (raw.startsWith('icon-')) return `#${raw}`
27
- const ext = extname(raw) || raw
28
- const key = ext.toUpperCase()
29
- if (key === '3GP') return '#icon-a-3GP'
30
- return `#icon-${key}`
31
- })
32
-
33
- const px = computed(() =>
34
- typeof props.size === 'number' ? `${props.size}px` : props.size,
35
- )
36
- </script>
37
-
38
- <template>
39
- <svg
40
- class="vm-file-icon"
41
- aria-hidden="true"
42
- :style="{ width: px, height: px }"
43
- >
44
- <use :xlink:href="symbolId" />
45
- </svg>
46
- </template>
47
-
48
- <style lang="scss" scoped>
49
- .vm-file-icon {
50
- display: inline-block;
51
- vertical-align: middle;
52
- fill: currentColor;
53
- flex-shrink: 0;
54
- }
55
- </style>
@@ -1,235 +0,0 @@
1
- <template>
2
- <Dialog :open="open" @update:open="onOpenChange">
3
- <DialogContent
4
- shell="crud"
5
- class="vm-dialog"
6
- :class="{ 'is-empty': !hasBody, 'is-fill': fill }"
7
- @pointer-down-outside="onPointerDownOutside"
8
- @focus-outside="onFocusOutside"
9
- @interact-outside="onInteractOutside"
10
- >
11
- <DialogHeader class="vm-dialog__head">
12
- <DialogTitle class="vm-dialog__title">{{ title }}</DialogTitle>
13
- </DialogHeader>
14
- <div class="vm-dialog__body">
15
- <slot v-if="hasBody" />
16
- <div v-else class="vm-dialog__empty">
17
- <vm-empty kind="暂无内容" />
18
- </div>
19
- </div>
20
- <DialogFooter class="vm-dialog__foot">
21
- <slot v-if="$slots.footer" name="footer" />
22
- <template v-else>
23
- <button
24
- type="button"
25
- class="vm-dialog__btn is-ghost"
26
- :disabled="confirmLoading"
27
- @click="onCloseClick"
28
- >
29
- {{ closeText }}
30
- </button>
31
- <button
32
- v-if="confirm"
33
- type="button"
34
- class="vm-dialog__btn is-primary"
35
- :disabled="confirmLoading"
36
- @click="onConfirmClick"
37
- >
38
- {{ confirmLoading ? '提交中…' : confirmText }}
39
- </button>
40
- </template>
41
- </DialogFooter>
42
- </DialogContent>
43
- </Dialog>
44
- </template>
45
-
46
- <script setup lang="ts">
47
- import { computed, getCurrentInstance, useSlots } from 'vue'
48
- import { isDialogFloatTarget } from '../lib/dialog-float'
49
-
50
- defineOptions({ name: 'vm-dialog' })
51
-
52
- const props = withDefaults(
53
- defineProps<{
54
- open?: boolean
55
- title?: string
56
- /** 宽度:桌面 50vw,移动端全屏 */
57
- width?: string
58
- /** 是否显示确定按钮,默认 true;说明类弹窗传 false */
59
- confirm?: boolean
60
- confirmLoading?: boolean
61
- confirmText?: string
62
- closeText?: string
63
- /** 拉满 CRUD 壳层最高高度(700px),列表类弹窗用 */
64
- fill?: boolean
65
- }>(),
66
- {
67
- open: false,
68
- title: '',
69
- width: '50vw',
70
- confirm: true,
71
- confirmLoading: false,
72
- confirmText: '确定',
73
- closeText: '关闭',
74
- fill: false,
75
- },
76
- )
77
-
78
- const emit = defineEmits<{
79
- 'update:open': [v: boolean]
80
- /** 关闭动作;监听时可拦截(不调 done 则不关) */
81
- close: [done: () => void]
82
- /** 确定动作;监听时可拦截(不调 done 则不关) */
83
- confirm: [done: () => void]
84
- }>()
85
-
86
- const slots = useSlots()
87
- const hasBody = computed(() => Boolean(slots.default))
88
- const instance = getCurrentInstance()
89
-
90
- function finishClose() {
91
- emit('update:open', false)
92
- }
93
-
94
- /** 声明式 emit 不在 attrs 里,从 vnode.props 判断是否有监听 */
95
- function hasListener(event: 'close' | 'confirm') {
96
- const p = instance?.vnode.props
97
- if (!p) return false
98
- const key = `on${event[0]!.toUpperCase()}${event.slice(1)}`
99
- return typeof p[key] === 'function' || Array.isArray(p[key])
100
- }
101
-
102
- function onOpenChange(v: boolean) {
103
- if (v) {
104
- emit('update:open', true)
105
- return
106
- }
107
- onCloseClick()
108
- }
109
-
110
- function onCloseClick() {
111
- if (hasListener('close')) {
112
- emit('close', finishClose)
113
- return
114
- }
115
- finishClose()
116
- }
117
-
118
- function onConfirmClick() {
119
- if (props.confirmLoading) return
120
- if (hasListener('confirm')) {
121
- emit('confirm', finishClose)
122
- return
123
- }
124
- finishClose()
125
- }
126
-
127
- function onPointerDownOutside(event: Event) {
128
- if (isDialogFloatTarget(event)) event.preventDefault()
129
- }
130
-
131
- function onFocusOutside(event: Event) {
132
- if (isDialogFloatTarget(event)) event.preventDefault()
133
- }
134
-
135
- function onInteractOutside(event: Event) {
136
- if (isDialogFloatTarget(event)) event.preventDefault()
137
- }
138
- </script>
139
-
140
- <style lang="scss" scoped>
141
- .vm-dialog__head {
142
- flex-shrink: 0;
143
- padding: 12px 22px;
144
- border-bottom: 1px solid var(--border);
145
-
146
- @media (max-width: 768px) {
147
- padding: 8px 12px;
148
- }
149
- }
150
-
151
- .vm-dialog__title {
152
- font-size: 15px;
153
- font-weight: 650;
154
- letter-spacing: -0.01em;
155
- line-height: 1.3;
156
- color: var(--foreground);
157
- }
158
-
159
- .vm-dialog__body {
160
- display: flex;
161
- flex: 1 1 auto;
162
- flex-direction: column;
163
- min-height: 0;
164
- overflow: auto;
165
- overscroll-behavior: contain;
166
- padding: 18px 22px 16px;
167
-
168
- @media (max-width: 768px) {
169
- flex: 1;
170
- padding: 12px;
171
- }
172
- }
173
-
174
- .vm-dialog__empty {
175
- display: flex;
176
- min-height: 160px;
177
- align-items: center;
178
- justify-content: center;
179
- }
180
-
181
- .vm-dialog__foot {
182
- display: flex;
183
- flex-shrink: 0;
184
- justify-content: flex-end;
185
- gap: 8px;
186
- padding: 10px 22px;
187
- border-top: 1px solid var(--border);
188
-
189
- @media (max-width: 768px) {
190
- flex-direction: column-reverse;
191
- gap: 8px;
192
- padding: 8px 12px calc(8px + env(safe-area-inset-bottom, 0px));
193
-
194
- .vm-dialog__btn {
195
- width: 100%;
196
- }
197
- }
198
- }
199
-
200
- .vm-dialog__btn {
201
- height: 36px;
202
- padding: 0 16px;
203
- border: none;
204
- border-radius: 12px;
205
- font-size: 13px;
206
- font-weight: 600;
207
- cursor: pointer;
208
- transition:
209
- background 0.15s ease,
210
- color 0.15s ease;
211
-
212
- &.is-primary {
213
- background: var(--brand);
214
- color: #fff;
215
-
216
- &:hover:not(:disabled) {
217
- background: var(--brand-deep);
218
- }
219
- }
220
-
221
- &.is-ghost {
222
- background: var(--muted);
223
- color: var(--foreground);
224
-
225
- &:hover:not(:disabled) {
226
- background: color-mix(in srgb, var(--muted) 70%, var(--foreground) 8%);
227
- }
228
- }
229
-
230
- &:disabled {
231
- cursor: wait;
232
- opacity: 0.65;
233
- }
234
- }
235
- </style>