vome-core 0.0.28 → 0.0.32

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 (57) hide show
  1. package/dist/admin/components/vm-aside-list-item.vue +18 -6
  2. package/dist/admin/components/vm-card.vue +13 -7
  3. package/dist/admin/components/vm-page-tabs.vue +3 -2
  4. package/dist/admin/components/vm-split-layout.vue +4 -0
  5. package/dist/admin/config/plugin-dev.js +1 -1
  6. package/dist/admin/crud/components/vm-form-hint.vue +40 -22
  7. package/dist/admin/crud/config.js +1 -1
  8. package/dist/admin/crud/confirm.js +1 -1
  9. package/dist/admin/crud/dict.js +1 -1
  10. package/dist/admin/crud/index.d.ts +1 -1
  11. package/dist/admin/crud/index.js +1 -1
  12. package/dist/admin/crud/key.js +1 -1
  13. package/dist/admin/crud/mitt.js +1 -1
  14. package/dist/admin/crud/plugins.js +1 -1
  15. package/dist/admin/crud/span.js +1 -1
  16. package/dist/admin/crud/style.js +1 -1
  17. package/dist/admin/crud/validate.js +1 -1
  18. package/dist/admin/crud/vm-import-btn.vue +686 -0
  19. package/dist/admin/crud/vm-toolbar.vue +16 -0
  20. package/dist/admin/directives/perm.js +1 -1
  21. package/dist/admin/hooks/useUpload.js +1 -1
  22. package/dist/admin/lib/browser.js +1 -1
  23. package/dist/admin/lib/cn.js +1 -1
  24. package/dist/admin/lib/dialog-float.js +1 -1
  25. package/dist/admin/lib/export-excel.js +1 -1
  26. package/dist/admin/lib/file-preview.js +1 -1
  27. package/dist/admin/lib/import-excel.d.ts +18 -0
  28. package/dist/admin/lib/import-excel.js +1 -0
  29. package/dist/admin/lib/json.js +1 -1
  30. package/dist/admin/lib/menu.js +1 -1
  31. package/dist/admin/lib/tree.js +1 -1
  32. package/dist/admin/lib/upload.js +1 -1
  33. package/dist/admin/lib/video-frame.js +1 -1
  34. package/dist/admin/router/index.js +13 -3
  35. package/dist/client/vite-plugin-eps.d.ts +3 -3
  36. package/dist/client/vite-plugin-eps.js +6 -2
  37. package/dist/index.js +1 -1
  38. package/dist/server/index.js +1 -1
  39. package/dist/shared/excel.d.ts +10 -0
  40. package/dist/shared/excel.js +1 -1
  41. package/dist/shared/index.js +1 -1
  42. package/dist/shared/tree.js +1 -1
  43. package/dist/src/core/index.d.ts +2 -2
  44. package/dist/src/ext/index.d.ts +1 -1
  45. package/dist/src/ext/load-plugin.d.ts +16 -0
  46. package/dist/src/orm/import-excel.d.ts +31 -0
  47. package/dist/src/routing/index.d.ts +1 -0
  48. package/dist/src/routing/public-routes.d.ts +6 -0
  49. package/dist/src/server/index.d.ts +2 -2
  50. package/dist/src/shared/excel.d.ts +10 -0
  51. package/dist/src/shared/index.d.ts +1 -1
  52. package/dist/typings/routing/crud.d.ts +5 -0
  53. package/package.json +8 -3
  54. package/src/shared/excel.d.ts +10 -0
  55. package/src/shared/excel.ts +77 -0
  56. package/src/shared/index.ts +4 -0
  57. package/dist/admin/crud/components/vm-json-viewer.vue +0 -147
@@ -3,8 +3,18 @@ export type ExcelColumn = {
3
3
  label: string;
4
4
  };
5
5
  export type ExcelFormatCell = (prop: string, row: Record<string, unknown>) => string;
6
+ /** 导入模板排除的自动字段(实体公共列) */
7
+ export declare const IMPORT_SKIP_FIELDS: readonly ["id", "createTime", "updateTime", "deletedAt", "tenantId"];
8
+ export declare function isImportSkipField(name: string): boolean;
6
9
  /** 二维表 → xlsx 二进制 */
7
10
  export declare function buildExcelBuffer(columns: ExcelColumn[], rows: Record<string, unknown>[], formatCell?: ExcelFormatCell): Uint8Array;
11
+ /** 仅表头的导入模板 */
12
+ export declare function buildImportTemplateBuffer(columns: ExcelColumn[]): Uint8Array;
13
+ /**
14
+ * 解析 xlsx:首行表头 → 行对象。
15
+ * 表头可为字段名或中文 label(通过 columns 反查 prop)。
16
+ */
17
+ export declare function parseExcelBuffer(data: ArrayBuffer | Uint8Array, columns?: ExcelColumn[]): Record<string, unknown>[];
8
18
  export declare function excelFilename(name: string): string;
9
19
  /** Service 下载响应头 */
10
20
  export declare function excelResponseHeaders(filename: string): {
@@ -1 +1 @@
1
- (function(_0xc2335c,_0xac2132){const _0x5895e6=_0x1561,_0x2f9440=_0xc2335c();while(!![]){try{const _0x1560e1=parseInt(_0x5895e6(0xe9))/0x1+-parseInt(_0x5895e6(0xf1))/0x2*(-parseInt(_0x5895e6(0xfc))/0x3)+-parseInt(_0x5895e6(0xea))/0x4*(-parseInt(_0x5895e6(0xf5))/0x5)+-parseInt(_0x5895e6(0xeb))/0x6*(parseInt(_0x5895e6(0xe7))/0x7)+-parseInt(_0x5895e6(0xfd))/0x8*(parseInt(_0x5895e6(0xec))/0x9)+-parseInt(_0x5895e6(0xef))/0xa*(parseInt(_0x5895e6(0xed))/0xb)+-parseInt(_0x5895e6(0xee))/0xc*(-parseInt(_0x5895e6(0xf8))/0xd);if(_0x1560e1===_0xac2132)break;else _0x2f9440['push'](_0x2f9440['shift']());}catch(_0x15a2c6){_0x2f9440['push'](_0x2f9440['shift']());}}}(_0x98fc,0x829e1));import*as _0x2dc47e from'xlsx';export function buildExcelBuffer(_0x3af7cc,_0x137fa4,_0xd2b300){const _0x29b38a=_0x1561,_0x2238a9=_0x3af7cc[_0x29b38a(0xf2)](_0x3a6aae=>_0x3a6aae[_0x29b38a(0xf6)]||_0x3a6aae[_0x29b38a(0xf0)]),_0x378763=_0x137fa4[_0x29b38a(0xf2)](_0x46513e=>_0x3af7cc['map'](_0x356220=>{const _0x3c3fec=_0x29b38a;if(_0xd2b300)return _0xd2b300(_0x356220[_0x3c3fec(0xf0)],_0x46513e);const _0x18ca46=_0x46513e[_0x356220['prop']];if(_0x18ca46==null)return'';return String(_0x18ca46);})),_0x5036cf=_0x2dc47e[_0x29b38a(0xf3)][_0x29b38a(0xf9)]([_0x2238a9,..._0x378763]),_0x2fd1f4=_0x2dc47e['utils']['book_new']();return _0x2dc47e[_0x29b38a(0xf3)]['book_append_sheet'](_0x2fd1f4,_0x5036cf,_0x29b38a(0xfb)),_0x2dc47e['write'](_0x2fd1f4,{'bookType':'xlsx','type':_0x29b38a(0xe6)});}export function excelFilename(_0x479643){const _0xd7585a=_0x1561;return _0x479643[_0xd7585a(0xf4)](_0xd7585a(0xe8))?_0x479643:_0x479643+_0xd7585a(0xe8);}export function excelResponseHeaders(_0x4e6032){const _0x474210=_0x1561,_0x24433c=excelFilename(_0x4e6032);return{'Content-Type':_0x474210(0xf7),'Content-Disposition':_0x474210(0xfa)+encodeURIComponent(_0x24433c)};}function _0x1561(_0x26ddff,_0xff68b6){_0x26ddff=_0x26ddff-0xe6;const _0x98fcb1=_0x98fc();let _0x1561cb=_0x98fcb1[_0x26ddff];if(_0x1561['fctWtl']===undefined){var _0x403dfe=function(_0x279400){const _0x34dcff='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x2dc47e='',_0x3af7cc='';for(let _0x137fa4=0x0,_0xd2b300,_0x2238a9,_0x378763=0x0;_0x2238a9=_0x279400['charAt'](_0x378763++);~_0x2238a9&&(_0xd2b300=_0x137fa4%0x4?_0xd2b300*0x40+_0x2238a9:_0x2238a9,_0x137fa4++%0x4)?_0x2dc47e+=String['fromCharCode'](0xff&_0xd2b300>>(-0x2*_0x137fa4&0x6)):0x0){_0x2238a9=_0x34dcff['indexOf'](_0x2238a9);}for(let _0x5036cf=0x0,_0x2fd1f4=_0x2dc47e['length'];_0x5036cf<_0x2fd1f4;_0x5036cf++){_0x3af7cc+='%'+('00'+_0x2dc47e['charCodeAt'](_0x5036cf)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x3af7cc);};_0x1561['rrlpzQ']=_0x403dfe,_0x1561['hEElJJ']={},_0x1561['fctWtl']=!![];}const _0xda6f2a=_0x98fcb1[0x0],_0x4c48f0=_0x26ddff+_0xda6f2a,_0x456ea8=_0x1561['hEElJJ'][_0x4c48f0];return!_0x456ea8?(_0x1561cb=_0x1561['rrlpzQ'](_0x1561cb),_0x1561['hEElJJ'][_0x4c48f0]=_0x1561cb):_0x1561cb=_0x456ea8,_0x1561cb;}function _0x98fc(){const _0x4504a5=['mtjKu1zerNG','BwfW','DxrPBhm','zw5KC1DPDgG','ndiXmhb6zw5zDW','BgfIzwW','yxbWBgLJyxrPB24VDM5KlM9Wzw54BwXMB3jTyxrZlw9MzMLJzwrVy3vTzw50lNnWCMvHzhnOzwv0BwWUC2HLzxq','mJztuwv2vuG','yw9Hx3rVx3nOzwv0','yxr0ywnOBwvUDdSGzMLSzw5HBwuQpvvurI04jYC','u2HLzxqX','ndy2mtuYy3fuD2nI','ogvqBuvRzW','yxjYyxK','nJnrD0rsB0G','lNHSC3G','ntK5ode2s1DYsg9w','mZG4r0joD3nn','ntiXntyYBNHPAg9l','otuZotu2ogj6qNHbyG','ndrSEg9bBfu','otCXnZq0nhvXAwjhCa','mJe0mde2me9ctLvuza','ChjVCa'];_0x98fc=function(){return _0x4504a5;};return _0x98fc();}
1
+ const _0x1921d2=_0x3dc7;(function(_0x159f93,_0x443a33){const _0x570d0c=_0x3dc7,_0x155501=_0x159f93();while(!![]){try{const _0x33c4d1=-parseInt(_0x570d0c(0xf6))/0x1*(parseInt(_0x570d0c(0xf3))/0x2)+-parseInt(_0x570d0c(0xeb))/0x3+-parseInt(_0x570d0c(0xe7))/0x4*(parseInt(_0x570d0c(0xf5))/0x5)+parseInt(_0x570d0c(0xfb))/0x6*(-parseInt(_0x570d0c(0xe9))/0x7)+parseInt(_0x570d0c(0xea))/0x8*(parseInt(_0x570d0c(0xde))/0x9)+-parseInt(_0x570d0c(0xe3))/0xa+-parseInt(_0x570d0c(0xe4))/0xb*(-parseInt(_0x570d0c(0xf9))/0xc);if(_0x33c4d1===_0x443a33)break;else _0x155501['push'](_0x155501['shift']());}catch(_0x5e4413){_0x155501['push'](_0x155501['shift']());}}}(_0x4bb4,0xe8333));function _0x3dc7(_0x4c8a58,_0x29f3a1){_0x4c8a58=_0x4c8a58-0xdb;const _0x4bb411=_0x4bb4();let _0x3dc7fa=_0x4bb411[_0x4c8a58];if(_0x3dc7['bMaXFZ']===undefined){var _0x44cbfa=function(_0x5c67c9){const _0x4fd771='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x41a123='',_0x5ad8cd='';for(let _0x3ac08d=0x0,_0x44e5e1,_0x463106,_0x4b44d7=0x0;_0x463106=_0x5c67c9['charAt'](_0x4b44d7++);~_0x463106&&(_0x44e5e1=_0x3ac08d%0x4?_0x44e5e1*0x40+_0x463106:_0x463106,_0x3ac08d++%0x4)?_0x41a123+=String['fromCharCode'](0xff&_0x44e5e1>>(-0x2*_0x3ac08d&0x6)):0x0){_0x463106=_0x4fd771['indexOf'](_0x463106);}for(let _0x146bfd=0x0,_0x13950a=_0x41a123['length'];_0x146bfd<_0x13950a;_0x146bfd++){_0x5ad8cd+='%'+('00'+_0x41a123['charCodeAt'](_0x146bfd)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x5ad8cd);};_0x3dc7['tWRTzm']=_0x44cbfa,_0x3dc7['IPHoZR']={},_0x3dc7['bMaXFZ']=!![];}const _0x324acb=_0x4bb411[0x0],_0x3f60fd=_0x4c8a58+_0x324acb,_0x2106d7=_0x3dc7['IPHoZR'][_0x3f60fd];return!_0x2106d7?(_0x3dc7fa=_0x3dc7['tWRTzm'](_0x3dc7fa),_0x3dc7['IPHoZR'][_0x3f60fd]=_0x3dc7fa):_0x3dc7fa=_0x2106d7,_0x3dc7fa;}import*as _0x41a123 from'xlsx';export const IMPORT_SKIP_FIELDS=['id',_0x1921d2(0xf8),_0x1921d2(0xf4),_0x1921d2(0xdc),'tenantId'];export function isImportSkipField(_0x5ad8cd){return IMPORT_SKIP_FIELDS['includes'](_0x5ad8cd);}export function buildExcelBuffer(_0x3ac08d,_0x44e5e1,_0x463106){const _0x20deb9=_0x1921d2,_0x4b44d7=_0x3ac08d[_0x20deb9(0xdf)](_0x2b91cc=>_0x2b91cc[_0x20deb9(0xf0)]||_0x2b91cc[_0x20deb9(0xe2)]),_0x146bfd=_0x44e5e1[_0x20deb9(0xdf)](_0x460d04=>_0x3ac08d['map'](_0x3fba6f=>{const _0x4b7260=_0x20deb9;if(_0x463106)return _0x463106(_0x3fba6f[_0x4b7260(0xe2)],_0x460d04);const _0x453007=_0x460d04[_0x3fba6f[_0x4b7260(0xe2)]];if(_0x453007==null)return'';return String(_0x453007);})),_0x13950a=_0x41a123[_0x20deb9(0xef)][_0x20deb9(0xfa)]([_0x4b44d7,..._0x146bfd]),_0x598068=_0x41a123['utils'][_0x20deb9(0xdb)]();return _0x41a123[_0x20deb9(0xef)]['book_append_sheet'](_0x598068,_0x13950a,_0x20deb9(0xf2)),_0x41a123[_0x20deb9(0xec)](_0x598068,{'bookType':_0x20deb9(0xee),'type':_0x20deb9(0xe6)});}export function buildImportTemplateBuffer(_0x5b2e68){return buildExcelBuffer(_0x5b2e68,[]);}export function parseExcelBuffer(_0x31d9b9,_0x37266f){const _0x9210db=_0x1921d2,_0x185146=_0x41a123[_0x9210db(0xe5)](_0x31d9b9,{'type':_0x9210db(0xe6),'cellDates':!![]}),_0x274ae9=_0x185146['SheetNames'][0x0];if(!_0x274ae9)return[];const _0x571171=_0x185146['Sheets'][_0x274ae9];if(!_0x571171)return[];const _0xefc132=_0x41a123[_0x9210db(0xef)][_0x9210db(0xf7)](_0x571171,{'header':0x1,'defval':'','raw':![]});if(!_0xefc132[_0x9210db(0xfd)])return[];const _0x2f1735=(_0xefc132[0x0]||[])[_0x9210db(0xdf)](_0x4c1514=>String(_0x4c1514??'')['trim']()),_0x34bd5b=new Map();if(_0x37266f?.[_0x9210db(0xfd)])for(const _0x162d73 of _0x37266f){_0x34bd5b[_0x9210db(0xed)](_0x162d73['label'][_0x9210db(0xe8)](),_0x162d73[_0x9210db(0xe2)]),_0x34bd5b['set'](_0x162d73[_0x9210db(0xe2)],_0x162d73[_0x9210db(0xe2)]);}const _0x5de197=_0x2f1735[_0x9210db(0xdf)](_0x2d287e=>{if(!_0x2d287e)return'';return _0x34bd5b['get'](_0x2d287e)||_0x2d287e;}),_0x310f30=[];for(let _0x302e41=0x1;_0x302e41<_0xefc132['length'];_0x302e41++){const _0x365ef0=_0xefc132[_0x302e41]||[],_0x4b1b7e={};let _0x47e0bf=!![];for(let _0x419ddf=0x0;_0x419ddf<_0x5de197['length'];_0x419ddf++){const _0x26dee6=_0x5de197[_0x419ddf];if(!_0x26dee6)continue;let _0x4bf471=_0x365ef0[_0x419ddf];if(_0x4bf471==null||_0x4bf471===''){_0x4b1b7e[_0x26dee6]=_0x4bf471==null?null:'';continue;}_0x47e0bf=![],typeof _0x4bf471==='string'?_0x4b1b7e[_0x26dee6]=_0x4bf471['trim']():_0x4b1b7e[_0x26dee6]=_0x4bf471;}if(!_0x47e0bf)_0x310f30[_0x9210db(0xf1)](_0x4b1b7e);}return _0x310f30;}function _0x4bb4(){const _0x55f835=['zw5KC1DPDgG','BgvUz3rO','yM9VA19UzxC','zgvSzxrLzef0','lNHSC3G','ovHksunsvG','BwfW','yxr0ywnOBwvUDdSGzMLSzw5HBwuQpvvurI04jYC','yxbWBgLJyxrPB24VDM5KlM9Wzw54BwXMB3jTyxrZlw9MzMLJzwrVy3vTzw50lNnWCMvHzhnOzwv0BwWUC2HLzxq','ChjVCa','mtiYnte0ndbqrwXqzK8','mti2nZKXnuPrrhnpBa','CMvHza','yxjYyxK','ne9jrxPTEq','DhjPBq','mJfgs3HgrNq','oti0nZC2oezLC09iqW','nda2nZa0nMzPEhDZzW','D3jPDgu','C2v0','EgXZEa','DxrPBhm','BgfIzwW','ChvZAa','u2HLzxqX','mLn3AfbyuG','DxbKyxrLvgLTzq','nZaXnJm3nxftD0rpyW','odm4mtjpt0zfywy','C2HLzxrFDg9FANnVBG','y3jLyxrLvgLTzq','nte2wwL6BxrZ','yw9Hx3rVx3nOzwv0','mJe4nJCYngPrvhLcyq'];_0x4bb4=function(){return _0x55f835;};return _0x4bb4();}export function excelFilename(_0x291f19){const _0x5d88c0=_0x1921d2;return _0x291f19[_0x5d88c0(0xfc)](_0x5d88c0(0xdd))?_0x291f19:_0x291f19+_0x5d88c0(0xdd);}export function excelResponseHeaders(_0x485471){const _0x4d2945=_0x1921d2,_0x53c6a9=excelFilename(_0x485471);return{'Content-Type':_0x4d2945(0xe1),'Content-Disposition':_0x4d2945(0xe0)+encodeURIComponent(_0x53c6a9)};}
@@ -1 +1 @@
1
- function _0x5324(){var _0x17eb51=['m0jTBePxua','mtaZndaXnfvlCwvfza','ndG3mtiZANLmwef4','mtm0nZu5nuPvrvLRwG','mtG4mtaYohviD1PMva','mJyYndG5mMXks1jQuq','mtu4mZu5otjdDNjLuMO','mJe1mdi3ng5rzhHeDG'];_0x5324=function(){return _0x17eb51;};return _0x5324();}(function(_0x242d6b,_0x298377){var _0x522302=_0x5bfd,_0x19ba95=_0x242d6b();while(!![]){try{var _0x3192c2=-parseInt(_0x522302(0x97))/0x1+-parseInt(_0x522302(0x96))/0x2+parseInt(_0x522302(0x95))/0x3*(-parseInt(_0x522302(0x99))/0x4)+-parseInt(_0x522302(0x98))/0x5+parseInt(_0x522302(0x9a))/0x6+-parseInt(_0x522302(0x9c))/0x7+parseInt(_0x522302(0x9b))/0x8;if(_0x3192c2===_0x298377)break;else _0x19ba95['push'](_0x19ba95['shift']());}catch(_0x67924){_0x19ba95['push'](_0x19ba95['shift']());}}}(_0x5324,0x59545));export{merge}from'../comm/merge';function _0x5bfd(_0x5bc5bc,_0x2c5925){_0x5bc5bc=_0x5bc5bc-0x95;var _0x5324f9=_0x5324();var _0x5bfddd=_0x5324f9[_0x5bc5bc];if(_0x5bfd['KeUQRy']===undefined){var _0x56449b=function(_0x5a47c3){var _0x226f5e='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var _0x1c2e88='',_0xff34c8='';for(var _0xe00d91=0x0,_0x110c9e,_0x1e20d2,_0x4c3136=0x0;_0x1e20d2=_0x5a47c3['charAt'](_0x4c3136++);~_0x1e20d2&&(_0x110c9e=_0xe00d91%0x4?_0x110c9e*0x40+_0x1e20d2:_0x1e20d2,_0xe00d91++%0x4)?_0x1c2e88+=String['fromCharCode'](0xff&_0x110c9e>>(-0x2*_0xe00d91&0x6)):0x0){_0x1e20d2=_0x226f5e['indexOf'](_0x1e20d2);}for(var _0x1bac9d=0x0,_0x67f8dc=_0x1c2e88['length'];_0x1bac9d<_0x67f8dc;_0x1bac9d++){_0xff34c8+='%'+('00'+_0x1c2e88['charCodeAt'](_0x1bac9d)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0xff34c8);};_0x5bfd['RgyMfL']=_0x56449b,_0x5bfd['YbyItQ']={},_0x5bfd['KeUQRy']=!![];}var _0x41f032=_0x5324f9[0x0],_0x25ff3a=_0x5bc5bc+_0x41f032,_0x45e4b8=_0x5bfd['YbyItQ'][_0x25ff3a];return!_0x45e4b8?(_0x5bfddd=_0x5bfd['RgyMfL'](_0x5bfddd),_0x5bfd['YbyItQ'][_0x25ff3a]=_0x5bfddd):_0x5bfddd=_0x45e4b8,_0x5bfddd;}export{deepTree,flattenTree}from'./tree';export{RES_CODE}from'../routing/base';export{buildExcelBuffer,excelFilename,excelResponseHeaders}from'./excel';
1
+ function _0x2bce(_0x1ab677,_0x41755b){_0x1ab677=_0x1ab677-0x1ba;var _0x54da7f=_0x54da();var _0x2bce3b=_0x54da7f[_0x1ab677];if(_0x2bce['IVhhXX']===undefined){var _0x1d4e3e=function(_0x3759e4){var _0x56d554='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var _0x45766c='',_0x411bd1='';for(var _0x45a517=0x0,_0x5d0d70,_0x1c8bf6,_0xb6ecb2=0x0;_0x1c8bf6=_0x3759e4['charAt'](_0xb6ecb2++);~_0x1c8bf6&&(_0x5d0d70=_0x45a517%0x4?_0x5d0d70*0x40+_0x1c8bf6:_0x1c8bf6,_0x45a517++%0x4)?_0x45766c+=String['fromCharCode'](0xff&_0x5d0d70>>(-0x2*_0x45a517&0x6)):0x0){_0x1c8bf6=_0x56d554['indexOf'](_0x1c8bf6);}for(var _0x3c1dfa=0x0,_0x3a55fe=_0x45766c['length'];_0x3c1dfa<_0x3a55fe;_0x3c1dfa++){_0x411bd1+='%'+('00'+_0x45766c['charCodeAt'](_0x3c1dfa)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x411bd1);};_0x2bce['aUMinv']=_0x1d4e3e,_0x2bce['RIVwDk']={},_0x2bce['IVhhXX']=!![];}var _0x49afae=_0x54da7f[0x0],_0x2f96e9=_0x1ab677+_0x49afae,_0x4131c7=_0x2bce['RIVwDk'][_0x2f96e9];return!_0x4131c7?(_0x2bce3b=_0x2bce['aUMinv'](_0x2bce3b),_0x2bce['RIVwDk'][_0x2f96e9]=_0x2bce3b):_0x2bce3b=_0x4131c7,_0x2bce3b;}function _0x54da(){var _0x5c9436=['odmXmeDvDwXSrW','nJm4otu2BLnMCvDd','mZa3mg9frKzLBq','nJi1mtmXmxLsqwTIAa','mte1ndDIzu5dv3i','mZa2nMLcuwHltq','mJa4nZq5me9PAxfezq','mtnHtuTywKK','ndvlzgviDhO','ote5mtK2mhrvAfHmqW','mtjhrMTjAMe','odq5mZrjuhfQueS'];_0x54da=function(){return _0x5c9436;};return _0x54da();}(function(_0x5c1b1e,_0x34099f){var _0x25e05b=_0x2bce,_0x11afed=_0x5c1b1e();while(!![]){try{var _0x3540e9=-parseInt(_0x25e05b(0x1ba))/0x1*(-parseInt(_0x25e05b(0x1be))/0x2)+parseInt(_0x25e05b(0x1c5))/0x3+parseInt(_0x25e05b(0x1c0))/0x4*(parseInt(_0x25e05b(0x1bb))/0x5)+-parseInt(_0x25e05b(0x1bf))/0x6*(parseInt(_0x25e05b(0x1c4))/0x7)+-parseInt(_0x25e05b(0x1bc))/0x8+parseInt(_0x25e05b(0x1c3))/0x9*(parseInt(_0x25e05b(0x1c1))/0xa)+-parseInt(_0x25e05b(0x1c2))/0xb*(parseInt(_0x25e05b(0x1bd))/0xc);if(_0x3540e9===_0x34099f)break;else _0x11afed['push'](_0x11afed['shift']());}catch(_0x50bf5b){_0x11afed['push'](_0x11afed['shift']());}}}(_0x54da,0xb8733));export{merge}from'../comm/merge';export{deepTree,flattenTree}from'./tree';export{RES_CODE}from'../routing/base';export{buildExcelBuffer,buildImportTemplateBuffer,parseExcelBuffer,excelFilename,excelResponseHeaders,IMPORT_SKIP_FIELDS,isImportSkipField}from'./excel';
@@ -1 +1 @@
1
- const _0x2d0e33=_0x8f46;function _0x1ffd(){const _0x2c3d7c=['mtiWndG3oez1D3DVtq','z2v0','y2HPBgrYzw4','BgvUz3rO','DMfSDwvZ','C2v0','mtzzDMLMAuK','zgvZyW','otC0odaWqvzqAwf5','mZuWntm2ohfPy0fYyW','mtyZmZe4nw9sy2HJCW','yxnJ','mtu4otu0nKTprufWEa','mJq2mJuXnZLZEuzdz2m','B3jKzxjoDw0','ChvZAa','mtbUDMHKzNC','C29YDa','AgfZ','mZm4mti0nMHACgTbCq','CgfYzw50swq'];_0x1ffd=function(){return _0x2c3d7c;};return _0x1ffd();}function _0x8f46(_0x38ff29,_0x3a4cf6){_0x38ff29=_0x38ff29-0xa1;const _0x1ffd1f=_0x1ffd();let _0x8f466d=_0x1ffd1f[_0x38ff29];if(_0x8f46['vhWtnb']===undefined){var _0x556d41=function(_0x1fc6af){const _0x5ae8e4='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x1cb2ca='',_0x11b6a1='';for(let _0x1b22c4=0x0,_0x569240,_0x1e8651,_0x497c65=0x0;_0x1e8651=_0x1fc6af['charAt'](_0x497c65++);~_0x1e8651&&(_0x569240=_0x1b22c4%0x4?_0x569240*0x40+_0x1e8651:_0x1e8651,_0x1b22c4++%0x4)?_0x1cb2ca+=String['fromCharCode'](0xff&_0x569240>>(-0x2*_0x1b22c4&0x6)):0x0){_0x1e8651=_0x5ae8e4['indexOf'](_0x1e8651);}for(let _0x3a88c9=0x0,_0x5a33a2=_0x1cb2ca['length'];_0x3a88c9<_0x5a33a2;_0x3a88c9++){_0x11b6a1+='%'+('00'+_0x1cb2ca['charCodeAt'](_0x3a88c9)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x11b6a1);};_0x8f46['BXaRTo']=_0x556d41,_0x8f46['DnoRgy']={},_0x8f46['vhWtnb']=!![];}const _0x319301=_0x1ffd1f[0x0],_0x4099bd=_0x38ff29+_0x319301,_0x4c03c0=_0x8f46['DnoRgy'][_0x4099bd];return!_0x4c03c0?(_0x8f466d=_0x8f46['BXaRTo'](_0x8f466d),_0x8f46['DnoRgy'][_0x4099bd]=_0x8f466d):_0x8f466d=_0x4c03c0,_0x8f466d;}(function(_0x195710,_0x39258b){const _0x48a3b2=_0x8f46,_0x4ce2b5=_0x195710();while(!![]){try{const _0x460a6a=-parseInt(_0x48a3b2(0xa5))/0x1+-parseInt(_0x48a3b2(0xb2))/0x2+parseInt(_0x48a3b2(0xa7))/0x3+parseInt(_0x48a3b2(0xa6))/0x4+-parseInt(_0x48a3b2(0xad))/0x5*(parseInt(_0x48a3b2(0xb0))/0x6)+parseInt(_0x48a3b2(0xa9))/0x7*(-parseInt(_0x48a3b2(0xa3))/0x8)+parseInt(_0x48a3b2(0xaa))/0x9;if(_0x460a6a===_0x39258b)break;else _0x4ce2b5['push'](_0x4ce2b5['shift']());}catch(_0xc8bd7f){_0x4ce2b5['push'](_0x4ce2b5['shift']());}}}(_0x1ffd,0xf3bf7));export function deepTree(_0x1cb2ca,_0x11b6a1=_0x2d0e33(0xa8)){const _0x495587=_0x2d0e33,_0x1b22c4=new Map();for(const _0x497c65 of _0x1cb2ca){if(_0x497c65['id']==null)continue;_0x1b22c4[_0x495587(0xa2)](_0x497c65['id'],{..._0x497c65,'children':[]});}const _0x569240=[];for(const _0x3a88c9 of _0x1b22c4[_0x495587(0xa1)]()){const _0x5a33a2=_0x3a88c9[_0x495587(0xb1)];_0x5a33a2!=null&&_0x5a33a2!==''&&_0x1b22c4[_0x495587(0xaf)](_0x5a33a2)?_0x1b22c4[_0x495587(0xb3)](_0x5a33a2)[_0x495587(0xb4)][_0x495587(0xac)](_0x3a88c9):_0x569240['push'](_0x3a88c9);}const _0x1e8651=_0x486892=>{const _0x5efb73=_0x495587;_0x486892[_0x5efb73(0xae)]((_0x223f19,_0x47d7de)=>{const _0x5d6dbd=_0x5efb73,_0x377819=_0x223f19[_0x5d6dbd(0xab)]??0x0,_0x1f2e3e=_0x47d7de['orderNum']??0x0,_0x58e54b=_0x11b6a1===_0x5d6dbd(0xa4)?_0x1f2e3e-_0x377819:_0x377819-_0x1f2e3e;return _0x58e54b||Number(_0x223f19['id'])-Number(_0x47d7de['id']);});for(const _0xaf4431 of _0x486892)if(_0xaf4431[_0x5efb73(0xb4)]?.[_0x5efb73(0xb5)])_0x1e8651(_0xaf4431[_0x5efb73(0xb4)]);};return _0x1e8651(_0x569240),_0x569240;}export function flattenTree(_0x434b50,_0x4a24be,_0x4624f8=0x0,_0x325095=[]){const _0x4404a5=_0x2d0e33;for(const _0x55d604 of _0x434b50){const _0x5e0981=_0x55d604['children']||[];_0x325095[_0x4404a5(0xac)]({..._0x55d604,'depth':_0x4624f8,'hasChildren':_0x5e0981[_0x4404a5(0xb5)]>0x0});if(_0x5e0981['length']&&_0x4a24be[_0x4404a5(0xaf)](_0x55d604['id']))flattenTree(_0x5e0981,_0x4a24be,_0x4624f8+0x1,_0x325095);}return _0x325095;}
1
+ (function(_0x5e1678,_0x41aa0c){const _0x1738ad=_0x4979,_0x3ff0d1=_0x5e1678();while(!![]){try{const _0x58aa90=parseInt(_0x1738ad(0x88))/0x1*(parseInt(_0x1738ad(0x8f))/0x2)+-parseInt(_0x1738ad(0x84))/0x3+parseInt(_0x1738ad(0x81))/0x4+parseInt(_0x1738ad(0x8a))/0x5*(-parseInt(_0x1738ad(0x85))/0x6)+-parseInt(_0x1738ad(0x93))/0x7*(parseInt(_0x1738ad(0x90))/0x8)+-parseInt(_0x1738ad(0x83))/0x9*(-parseInt(_0x1738ad(0x92))/0xa)+-parseInt(_0x1738ad(0x86))/0xb*(-parseInt(_0x1738ad(0x87))/0xc);if(_0x58aa90===_0x41aa0c)break;else _0x3ff0d1['push'](_0x3ff0d1['shift']());}catch(_0x390e4d){_0x3ff0d1['push'](_0x3ff0d1['shift']());}}}(_0x103a,0x59022));function _0x4979(_0x13eb76,_0x53c557){_0x13eb76=_0x13eb76-0x80;const _0x103a99=_0x103a();let _0x497904=_0x103a99[_0x13eb76];if(_0x4979['laRQGX']===undefined){var _0x2e43c8=function(_0x547811){const _0x16edf4='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x16706b='',_0x3a4526='';for(let _0x38e863=0x0,_0x2ea730,_0x2eded2,_0x469b85=0x0;_0x2eded2=_0x547811['charAt'](_0x469b85++);~_0x2eded2&&(_0x2ea730=_0x38e863%0x4?_0x2ea730*0x40+_0x2eded2:_0x2eded2,_0x38e863++%0x4)?_0x16706b+=String['fromCharCode'](0xff&_0x2ea730>>(-0x2*_0x38e863&0x6)):0x0){_0x2eded2=_0x16edf4['indexOf'](_0x2eded2);}for(let _0x5ce427=0x0,_0xe3cf7=_0x16706b['length'];_0x5ce427<_0xe3cf7;_0x5ce427++){_0x3a4526+='%'+('00'+_0x16706b['charCodeAt'](_0x5ce427)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x3a4526);};_0x4979['eEZseC']=_0x2e43c8,_0x4979['LVOlbq']={},_0x4979['laRQGX']=!![];}const _0x3d3de9=_0x103a99[0x0],_0x147a19=_0x13eb76+_0x3d3de9,_0xe273=_0x4979['LVOlbq'][_0x147a19];return!_0xe273?(_0x497904=_0x4979['eEZseC'](_0x497904),_0x4979['LVOlbq'][_0x147a19]=_0x497904):_0x497904=_0xe273,_0x497904;}function _0x103a(){const _0x4aea65=['ChvZAa','oxvAz2rdra','mtq3otu3m1ftBvbSza','mti2BKXZvKDi','nZCWntK3m2PPwKXHta','mJr2EuPiCfi','mtm4ote3qLD5wvz5','CgfYzw50swq','mtuWmJy1B21oywvs','DMfSDwvZ','BgvUz3rO','zgvZyW','C29YDa','mMP5qunKva','oejiz052uW','C2v0','nta0ndKZmhbNDMDOsa','ndq2mJKWnKHUs1vJtq','B3jKzxjoDw0','y2HPBgrYzw4','mZi3nZC2CwjHrgHN'];_0x103a=function(){return _0x4aea65;};return _0x103a();}export function deepTree(_0x16706b,_0x3a4526='asc'){const _0x3e34f2=_0x4979,_0x38e863=new Map();for(const _0x469b85 of _0x16706b){if(_0x469b85['id']==null)continue;_0x38e863[_0x3e34f2(0x91)](_0x469b85['id'],{..._0x469b85,'children':[]});}const _0x2ea730=[];for(const _0x5ce427 of _0x38e863[_0x3e34f2(0x8b)]()){const _0xe3cf7=_0x5ce427[_0x3e34f2(0x89)];_0xe3cf7!=null&&_0xe3cf7!==''&&_0x38e863['has'](_0xe3cf7)?_0x38e863['get'](_0xe3cf7)['children'][_0x3e34f2(0x82)](_0x5ce427):_0x2ea730[_0x3e34f2(0x82)](_0x5ce427);}const _0x2eded2=_0xf8a680=>{const _0x13c63d=_0x3e34f2;_0xf8a680[_0x13c63d(0x8e)]((_0x442e26,_0x3dee8b)=>{const _0x332a3d=_0x13c63d,_0x3fbe12=_0x442e26[_0x332a3d(0x94)]??0x0,_0x5cc6d7=_0x3dee8b[_0x332a3d(0x94)]??0x0,_0x688c65=_0x3a4526===_0x332a3d(0x8d)?_0x5cc6d7-_0x3fbe12:_0x3fbe12-_0x5cc6d7;return _0x688c65||Number(_0x442e26['id'])-Number(_0x3dee8b['id']);});for(const _0x4fdb37 of _0xf8a680)if(_0x4fdb37[_0x13c63d(0x80)]?.['length'])_0x2eded2(_0x4fdb37[_0x13c63d(0x80)]);};return _0x2eded2(_0x2ea730),_0x2ea730;}export function flattenTree(_0x4d60d5,_0x4d2304,_0x1fdb24=0x0,_0x571b9b=[]){const _0x5f0e42=_0x4979;for(const _0x5419be of _0x4d60d5){const _0x3cb994=_0x5419be[_0x5f0e42(0x80)]||[];_0x571b9b[_0x5f0e42(0x82)]({..._0x5419be,'depth':_0x1fdb24,'hasChildren':_0x3cb994[_0x5f0e42(0x8c)]>0x0});if(_0x3cb994['length']&&_0x4d2304['has'](_0x5419be['id']))flattenTree(_0x3cb994,_0x4d2304,_0x1fdb24+0x1,_0x571b9b);}return _0x571b9b;}
@@ -11,10 +11,10 @@ export { scanFiles } from '../comm/scan';
11
11
  export type { ScanOptions } from '../comm/scan';
12
12
  export { getEnv } from '../comm/env';
13
13
  export { Logger, CommException, isCommException } from '../logger';
14
- export { Eps, isEpsEnabled, BaseController, RES_CODE, Controller, Get, Post, Put, Delete, Patch, Body, Query, Param, Public, Perms, IgnorePerms, Use, listControllers, } from '../routing';
14
+ export { Eps, isEpsEnabled, BaseController, RES_CODE, Controller, Get, Post, Put, Delete, Patch, Body, Query, Param, Public, Perms, IgnorePerms, Use, listControllers, isPublicHttpRoute, clearPublicRouteCache, collectPublicRouteKeys, } from '../routing';
15
15
  export type { ApiFail, ApiResult, ApiSuccess, ControllerCrudOptions, ControllerMeta, ControllerRouteMeta, ControllerSide, CrudApi, CrudBeforeFn, CrudRegistrar, EpsApiItem, EpsColumn, EpsEntity, EpsModuleMap, HttpMethod, InsertParamFn, QueryExtendFn, QueryExtendQb, QueryFieldRef, QueryJoin, QueryJoinType, QueryOp, QueryOpCtx, QueryWhereFn, QueryWhereResult, ResCode, RouteMiddleware, RouteParamMeta, RouteParamSource, } from '../routing';
16
16
  export { DbStore, baseColumns, BASE_COLUMN_COMMENTS, entitySchemas, columnComments, getColumnComments, syncColumnCommentsToPg, readCrudConfig, resolveSoftDelete, resolveUpsert, Repository, getRepository, InjectRepository, BaseService, q, compactWhere, needsAdvancedQuery, buildQueryOp, queryWithOp, attachCrudRoutes, isTenantEnabled, noTenant, normalizeHost, resolveTenantScope, tableHasDepartmentId, resolveDataScope, applyDataScopeWhere, applyRowScopes, noDataScope, } from '../orm';
17
17
  export type { CrudUpsertMode, CrudModifyType, CrudWriteOptions, CrudTrashQueryOptions, CrudDeleteOptions, PageQuery, PagePagination, PageResult, } from '../orm';
18
- export { BasePlugin, loadPluginClass, readPluginScript, pDataPath, pPluginPath, pModulesPath, pModulePath, ModuleRegistry, loadModuleHandlers, microApps, createModuleGateway, } from '../ext';
18
+ export { BasePlugin, loadPluginClass, loadPluginClassFromPath, readPluginScript, resolvePluginServerPath, pDataPath, pPluginPath, pModulesPath, pModulePath, ModuleRegistry, loadModuleHandlers, microApps, createModuleGateway, } from '../ext';
19
19
  export type { PluginManifest, PluginInfo, PluginPayload, PluginCheckResult, ModuleRouteDef, ModuleMenuDef, ModuleManifest, ModuleHandlerCtx, ModuleHandler, ModuleInstalled, } from '../ext';
20
20
  export { defineAuthMacro } from '../auth';
@@ -6,7 +6,7 @@
6
6
  * - microApps / createModuleGateway:静态与网关
7
7
  */
8
8
  export { BasePlugin } from './base-plugin';
9
- export { loadPluginClass, readPluginScript } from './load-plugin';
9
+ export { loadPluginClass, loadPluginClassFromPath, readPluginScript, resolvePluginServerPath, } from './load-plugin';
10
10
  export { pDataPath, pPluginPath, pModulesPath, pModulePath, } from './path';
11
11
  export { ModuleRegistry, loadModuleHandlers, } from './module-registry';
12
12
  export { microApps } from './micro-apps';
@@ -2,11 +2,27 @@ import type { PluginInfo } from '../../typings/ext/plugin';
2
2
  type PluginCtor = new () => {
3
3
  init: (info: PluginInfo, ctx?: unknown, app?: unknown, services?: Record<string, unknown>) => Promise<void>;
4
4
  };
5
+ /** 混淆后 `vome-plugin-runtime` 可能进字符串数组,字面量替换失效;运行时拦截 require */
6
+ export declare function pluginRequire(id: string): any;
7
+ /** 剥 ESM、替换 CJS external,供 Plugin / handlers 共用 */
8
+ export declare function normalizePluginScript(content: string): string;
9
+ /**
10
+ * 落临时 .cjs + Module._compile,避免 new Function 加载数 MB 混淆包时压垮进程。
11
+ * footer 决定导出(Plugin ctor 或 handlers)。
12
+ *
13
+ * BasePlugin 经 globalThis 注入(Bun 下覆盖 Module.require 不可靠);
14
+ * 规范化脚本里的 require('vome-plugin-runtime') 已替换为 ({ BasePlugin })。
15
+ */
16
+ export declare function compilePluginCjs(normalized: string, footer: string): unknown;
5
17
  /**
6
18
  * 注入宿主 BasePlugin 与 require。
7
19
  * 支持 ESM 剥离 import、CJS 打包(ali-oss 等)及 external `vome-plugin-runtime`。
8
20
  */
9
21
  export declare function loadPluginClass(content: string): PluginCtor;
22
+ /** 从落盘 server/index.js 加载(安装/热启优先路径) */
23
+ export declare function loadPluginClassFromPath(filePath: string): PluginCtor;
24
+ /** modules/{key}/server/index.js(若存在) */
25
+ export declare function resolvePluginServerPath(keyName: string): string | undefined;
10
26
  /** 优先 modules/{key}/server/index.js,回退旧 plugin/{key} JSON */
11
27
  export declare function readPluginScript(keyName: string): string | undefined;
12
28
  export {};
@@ -0,0 +1,31 @@
1
+ import { type PgTable } from 'drizzle-orm/pg-core';
2
+ import { type ExcelColumn } from '../shared/excel';
3
+ import type { BaseService } from './service';
4
+ /** 从表唯一索引 / unique 约束提取键集合(用于导入 upsert) */
5
+ export declare function listUniqueKeySets(table: PgTable): string[][];
6
+ /** 导入模板列:实体业务字段,排除自动生成列 */
7
+ export declare function buildImportExcelColumns(table: PgTable, ignoreProperty?: string[]): ExcelColumn[];
8
+ export declare function buildEntityImportTemplate(table: PgTable, ignoreProperty?: string[]): Uint8Array;
9
+ export type ImportRowResult = {
10
+ inserted: number;
11
+ updated: number;
12
+ failed: Array<{
13
+ row: number;
14
+ message: string;
15
+ }>;
16
+ };
17
+ /**
18
+ * 按唯一键 upsert 导入行:
19
+ * 1. 有 id 且存在 → 更新
20
+ * 2. 否则按 unique 索引匹配 → 更新
21
+ * 3. 否则新增
22
+ */
23
+ export declare function importEntityRows(svc: BaseService, table: PgTable, rows: Record<string, unknown>[], options?: {
24
+ uniqueKeys?: string[];
25
+ ignoreProperty?: string[];
26
+ }): Promise<ImportRowResult>;
27
+ /** 从上传文件解析并导入 */
28
+ export declare function importEntityExcel(svc: BaseService, table: PgTable, fileData: ArrayBuffer | Uint8Array, options?: {
29
+ uniqueKeys?: string[];
30
+ ignoreProperty?: string[];
31
+ }): Promise<ImportRowResult>;
@@ -4,5 +4,6 @@ export { BaseController, RES_CODE } from './base';
4
4
  export type { ApiFail, ApiResult, ApiSuccess, ResCode } from './base';
5
5
  export { Controller, Get, Post, Put, Delete, Patch, Body, Query, Param, Public, Perms, IgnorePerms, Use, } from './decorators';
6
6
  export { listControllers, type ControllerMeta, type ControllerRouteMeta, type ControllerSide, type HttpMethod, type RouteParamMeta, type RouteParamSource, } from './metadata';
7
+ export { clearPublicRouteCache, collectPublicRouteKeys, isPublicHttpRoute, } from './public-routes';
7
8
  export type { ControllerCrudOptions, CrudApi, CrudBeforeFn, InsertParamFn, QueryExtendFn, QueryExtendQb, QueryFieldRef, QueryJoin, QueryJoinType, QueryOp, QueryOpCtx, QueryWhereFn, QueryWhereResult, RouteMiddleware, } from '../../typings/routing/crud';
8
9
  export type { CrudRegistrar } from './register';
@@ -0,0 +1,6 @@
1
+ /** 收集所有 @Public() 路由(METHOD + 全路径) */
2
+ export declare function collectPublicRouteKeys(): Set<string>;
3
+ /** 是否为 @Public() 开放接口(懒加载缓存;路由注册完成后调用) */
4
+ export declare function isPublicHttpRoute(method: string, path: string): boolean;
5
+ /** 测试或热重载后清空缓存 */
6
+ export declare function clearPublicRouteCache(): void;
@@ -4,8 +4,8 @@
4
4
  * 导入时加载宿主 `src/config`;扫描 / IoC / 路由注册在 `App.start()` 中执行。
5
5
  * 宿主须:`import 'reflect-metadata'`,并开启 `experimentalDecorators` + `emitDecoratorMetadata`。
6
6
  */
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';
7
+ export { App, appendInjectMeta, BaseController, Body, CommException, Context, Controller, Delete, Eps, isEpsEnabled, Get, getEnv, Inject, Ioc, isCommException, listControllers, isPublicHttpRoute, 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, loadPluginClassFromPath, readPluginScript, resolvePluginServerPath, pDataPath, pPluginPath, pModulesPath, pModulePath, ModuleRegistry, loadModuleHandlers, microApps, createModuleGateway, defineAuthMacro, } from '../core';
8
+ export { buildExcelBuffer, buildImportTemplateBuffer, parseExcelBuffer, excelFilename, excelResponseHeaders, IMPORT_SKIP_FIELDS, isImportSkipField, } from '../shared/excel';
9
9
  export type { ExcelColumn, ExcelFormatCell } from '../shared/excel';
10
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';
11
11
  /** 与 package.json version 同步 */
@@ -3,8 +3,18 @@ export type ExcelColumn = {
3
3
  label: string;
4
4
  };
5
5
  export type ExcelFormatCell = (prop: string, row: Record<string, unknown>) => string;
6
+ /** 导入模板排除的自动字段(实体公共列) */
7
+ export declare const IMPORT_SKIP_FIELDS: readonly ["id", "createTime", "updateTime", "deletedAt", "tenantId"];
8
+ export declare function isImportSkipField(name: string): boolean;
6
9
  /** 二维表 → xlsx 二进制 */
7
10
  export declare function buildExcelBuffer(columns: ExcelColumn[], rows: Record<string, unknown>[], formatCell?: ExcelFormatCell): Uint8Array;
11
+ /** 仅表头的导入模板 */
12
+ export declare function buildImportTemplateBuffer(columns: ExcelColumn[]): Uint8Array;
13
+ /**
14
+ * 解析 xlsx:首行表头 → 行对象。
15
+ * 表头可为字段名或中文 label(通过 columns 反查 prop)。
16
+ */
17
+ export declare function parseExcelBuffer(data: ArrayBuffer | Uint8Array, columns?: ExcelColumn[]): Record<string, unknown>[];
8
18
  export declare function excelFilename(name: string): string;
9
19
  /** Service 下载响应头 */
10
20
  export declare function excelResponseHeaders(filename: string): {
@@ -6,5 +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';
9
+ export { buildExcelBuffer, buildImportTemplateBuffer, parseExcelBuffer, excelFilename, excelResponseHeaders, IMPORT_SKIP_FIELDS, isImportSkipField, } from './excel';
10
10
  export type { ExcelColumn, ExcelFormatCell } from './excel';
@@ -98,4 +98,9 @@ export type ControllerCrudOptions = {
98
98
  listQueryOp?: QueryOp;
99
99
  insertParam?: InsertParamFn;
100
100
  infoIgnoreProperty?: string[];
101
+ /**
102
+ * 导入 upsert 唯一键(字段名数组)。
103
+ * 未配置时自动取实体 uniqueIndex / unique 约束。
104
+ */
105
+ importUniqueKeys?: string[];
101
106
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vome-core",
3
- "version": "0.0.28",
3
+ "version": "0.0.32",
4
4
  "description": "Vome framework — shared + Bun/Elysia server + Vue admin",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -94,7 +94,8 @@
94
94
  "clsx": ">=2.0.0",
95
95
  "tailwind-merge": ">=2.0.0",
96
96
  "dompurify": ">=3.0.0",
97
- "marked": ">=9.0.0"
97
+ "marked": ">=9.0.0",
98
+ "vite": ">=5.0.0"
98
99
  },
99
100
  "peerDependenciesMeta": {
100
101
  "drizzle-orm": {
@@ -129,6 +130,9 @@
129
130
  },
130
131
  "marked": {
131
132
  "optional": true
133
+ },
134
+ "vite": {
135
+ "optional": true
132
136
  }
133
137
  },
134
138
  "devDependencies": {
@@ -138,7 +142,8 @@
138
142
  "elysia": "latest",
139
143
  "javascript-obfuscator": "^5.4.7",
140
144
  "reflect-metadata": "^0.2.2",
141
- "typescript": "latest"
145
+ "typescript": "latest",
146
+ "vite": "^6.0.7"
142
147
  },
143
148
  "dependencies": {
144
149
  "@bogeychan/elysia-logger": "^0.1.10",
@@ -3,8 +3,18 @@ export type ExcelColumn = {
3
3
  label: string;
4
4
  };
5
5
  export type ExcelFormatCell = (prop: string, row: Record<string, unknown>) => string;
6
+ /** 导入模板排除的自动字段(实体公共列) */
7
+ export declare const IMPORT_SKIP_FIELDS: readonly ["id", "createTime", "updateTime", "deletedAt", "tenantId"];
8
+ export declare function isImportSkipField(name: string): boolean;
6
9
  /** 二维表 → xlsx 二进制 */
7
10
  export declare function buildExcelBuffer(columns: ExcelColumn[], rows: Record<string, unknown>[], formatCell?: ExcelFormatCell): Uint8Array;
11
+ /** 仅表头的导入模板 */
12
+ export declare function buildImportTemplateBuffer(columns: ExcelColumn[]): Uint8Array;
13
+ /**
14
+ * 解析 xlsx:首行表头 → 行对象。
15
+ * 表头可为字段名或中文 label(通过 columns 反查 prop)。
16
+ */
17
+ export declare function parseExcelBuffer(data: ArrayBuffer | Uint8Array, columns?: ExcelColumn[]): Record<string, unknown>[];
8
18
  export declare function excelFilename(name: string): string;
9
19
  /** Service 下载响应头 */
10
20
  export declare function excelResponseHeaders(filename: string): {
@@ -10,6 +10,19 @@ export type ExcelFormatCell = (
10
10
  row: Record<string, unknown>,
11
11
  ) => string
12
12
 
13
+ /** 导入模板排除的自动字段(实体公共列) */
14
+ export const IMPORT_SKIP_FIELDS = [
15
+ 'id',
16
+ 'createTime',
17
+ 'updateTime',
18
+ 'deletedAt',
19
+ 'tenantId',
20
+ ] as const
21
+
22
+ export function isImportSkipField(name: string) {
23
+ return (IMPORT_SKIP_FIELDS as readonly string[]).includes(name)
24
+ }
25
+
13
26
  /** 二维表 → xlsx 二进制 */
14
27
  export function buildExcelBuffer(
15
28
  columns: ExcelColumn[],
@@ -31,6 +44,70 @@ export function buildExcelBuffer(
31
44
  return XLSX.write(book, { bookType: 'xlsx', type: 'array' }) as Uint8Array
32
45
  }
33
46
 
47
+ /** 仅表头的导入模板 */
48
+ export function buildImportTemplateBuffer(columns: ExcelColumn[]): Uint8Array {
49
+ return buildExcelBuffer(columns, [])
50
+ }
51
+
52
+ /**
53
+ * 解析 xlsx:首行表头 → 行对象。
54
+ * 表头可为字段名或中文 label(通过 columns 反查 prop)。
55
+ */
56
+ export function parseExcelBuffer(
57
+ data: ArrayBuffer | Uint8Array,
58
+ columns?: ExcelColumn[],
59
+ ): Record<string, unknown>[] {
60
+ const book = XLSX.read(data, { type: 'array', cellDates: true })
61
+ const name = book.SheetNames[0]
62
+ if (!name) return []
63
+ const sheet = book.Sheets[name]
64
+ if (!sheet) return []
65
+ const aoa = XLSX.utils.sheet_to_json(sheet, {
66
+ header: 1,
67
+ defval: '',
68
+ raw: false,
69
+ }) as unknown[][]
70
+ if (!aoa.length) return []
71
+
72
+ const headerRow = (aoa[0] || []).map((h) => String(h ?? '').trim())
73
+ const labelToProp = new Map<string, string>()
74
+ if (columns?.length) {
75
+ for (const c of columns) {
76
+ labelToProp.set(c.label.trim(), c.prop)
77
+ labelToProp.set(c.prop, c.prop)
78
+ }
79
+ }
80
+
81
+ const props = headerRow.map((h) => {
82
+ if (!h) return ''
83
+ return labelToProp.get(h) || h
84
+ })
85
+
86
+ const rows: Record<string, unknown>[] = []
87
+ for (let i = 1; i < aoa.length; i++) {
88
+ const line = aoa[i] || []
89
+ const row: Record<string, unknown> = {}
90
+ let empty = true
91
+ for (let c = 0; c < props.length; c++) {
92
+ const prop = props[c]
93
+ if (!prop) continue
94
+ let val: unknown = line[c]
95
+ if (val == null || val === '') {
96
+ row[prop] = val == null ? null : ''
97
+ continue
98
+ }
99
+ empty = false
100
+ if (typeof val === 'string') {
101
+ row[prop] = val.trim()
102
+ } else {
103
+ row[prop] = val
104
+ }
105
+ }
106
+ if (!empty) rows.push(row)
107
+ }
108
+ return rows
109
+ }
110
+
34
111
  export function excelFilename(name: string) {
35
112
  return name.endsWith('.xlsx') ? name : `${name}.xlsx`
36
113
  }
@@ -14,7 +14,11 @@ export {
14
14
  } from '../routing/base'
15
15
  export {
16
16
  buildExcelBuffer,
17
+ buildImportTemplateBuffer,
18
+ parseExcelBuffer,
17
19
  excelFilename,
18
20
  excelResponseHeaders,
21
+ IMPORT_SKIP_FIELDS,
22
+ isImportSkipField,
19
23
  } from './excel'
20
24
  export type { ExcelColumn, ExcelFormatCell } from './excel'
@@ -1,147 +0,0 @@
1
- <template>
2
- <template v-if="mode === 'code'">
3
- <vm-json-code :model-value="modelValue" :empty="empty" />
4
- </template>
5
- <template v-else>
6
- <vm-text-link
7
- v-if="hasContent"
8
- :label="label"
9
- @click="open = true"
10
- />
11
- <span v-else class="vm-json-viewer is-empty">—</span>
12
- </template>
13
-
14
- <Teleport to="body">
15
- <div
16
- v-if="open"
17
- class="vm-json-viewer__dialog"
18
- role="dialog"
19
- aria-modal="true"
20
- @click.self="open = false"
21
- >
22
- <header class="vm-json-viewer__head">
23
- <span class="vm-json-viewer__title">{{ title }}</span>
24
- <div class="vm-json-viewer__actions">
25
- <vm-copy-btn :text="body" size="sm" label="复制" />
26
- <button type="button" class="vm-json-viewer__close" title="关闭" @click="open = false">
27
- <i class="ri-close-line" />
28
- </button>
29
- </div>
30
- </header>
31
- <div class="vm-json-viewer__body vm-scroll">
32
- <vm-json-code :model-value="modelValue" :empty="empty" />
33
- </div>
34
- </div>
35
- </Teleport>
36
- </template>
37
-
38
- <script setup lang="ts">
39
- import { computed, ref } from 'vue'
40
- import { hasJsonContent, prettyJson } from '../../lib/json'
41
- import VmJsonCode from './vm-json-code.vue'
42
- import VmTextLink from './vm-text-link.vue'
43
- import VmCopyBtn from './vm-copy-btn.vue'
44
-
45
- defineOptions({ name: 'vm-json-viewer' })
46
-
47
- const props = withDefaults(
48
- defineProps<{
49
- modelValue?: unknown
50
- title?: string
51
- label?: string
52
- /** button 打开浮层;code 仅渲染代码块(upsert fill) */
53
- mode?: 'button' | 'code'
54
- empty?: string
55
- }>(),
56
- {
57
- title: 'JSON',
58
- label: '查看',
59
- mode: 'button',
60
- empty: '(空)',
61
- },
62
- )
63
-
64
- const open = ref(false)
65
- const hasContent = computed(() => hasJsonContent(props.modelValue))
66
- const body = computed(() => prettyJson(props.modelValue, props.empty))
67
- </script>
68
-
69
- <style lang="scss" scoped>
70
- .vm-json-viewer.is-empty {
71
- color: var(--muted-foreground);
72
- }
73
-
74
- .vm-json-viewer__dialog {
75
- position: fixed;
76
- inset: 0;
77
- z-index: 5200;
78
- display: flex;
79
- flex-direction: column;
80
- padding: 24px;
81
- background: color-mix(in srgb, var(--foreground) 42%, transparent);
82
- }
83
-
84
- .vm-json-viewer__head {
85
- display: flex;
86
- flex-shrink: 0;
87
- align-items: center;
88
- justify-content: space-between;
89
- gap: 12px;
90
- margin: 0 auto;
91
- width: min(960px, 100%);
92
- padding: 12px 16px;
93
- border-radius: 14px 14px 0 0;
94
- background: var(--card);
95
- border: 1px solid color-mix(in srgb, var(--foreground) 8%, transparent);
96
- border-bottom: none;
97
- }
98
-
99
- .vm-json-viewer__title {
100
- font-size: 14px;
101
- font-weight: 700;
102
- color: var(--foreground);
103
- }
104
-
105
- .vm-json-viewer__actions {
106
- display: inline-flex;
107
- align-items: center;
108
- gap: 8px;
109
- }
110
-
111
- .vm-json-viewer__close {
112
- display: inline-flex;
113
- width: 32px;
114
- height: 32px;
115
- align-items: center;
116
- justify-content: center;
117
- border: none;
118
- border-radius: 8px;
119
- background: transparent;
120
- color: var(--muted-foreground);
121
- cursor: pointer;
122
-
123
- &:hover {
124
- background: var(--muted);
125
- color: var(--foreground);
126
- }
127
- }
128
-
129
- .vm-json-viewer__body {
130
- flex: 1;
131
- min-height: 0;
132
- margin: 0 auto;
133
- width: min(960px, 100%);
134
- display: flex;
135
- flex-direction: column;
136
- border-radius: 0 0 14px 14px;
137
- background: var(--card);
138
- border: 1px solid color-mix(in srgb, var(--foreground) 8%, transparent);
139
- border-top: none;
140
- overflow: hidden;
141
-
142
- :deep(.vm-json-code) {
143
- border-radius: 0;
144
- background: var(--muted);
145
- }
146
- }
147
- </style>