@liujitcn/kratos-admin-core 0.0.1

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 (368) hide show
  1. package/README.md +168 -0
  2. package/build/getEnv.ts +46 -0
  3. package/build/plugins.ts +206 -0
  4. package/build/proxy.ts +29 -0
  5. package/dist/package/declarations/build/getEnv.d.ts +13 -0
  6. package/dist/package/declarations/build/plugins.d.ts +20 -0
  7. package/dist/package/declarations/build/proxy.d.ts +10 -0
  8. package/dist/package/declarations/index.d.ts +7 -0
  9. package/dist/package/declarations/src/App.vue.d.ts +3 -0
  10. package/dist/package/declarations/src/api/base/config.d.ts +7 -0
  11. package/dist/package/declarations/src/api/base/file.d.ts +11 -0
  12. package/dist/package/declarations/src/api/base/login.d.ts +18 -0
  13. package/dist/package/declarations/src/api/base/oauth.d.ts +12 -0
  14. package/dist/package/declarations/src/api/system/auth.d.ts +13 -0
  15. package/dist/package/declarations/src/api/system/base_dict.d.ts +8 -0
  16. package/dist/package/declarations/src/api/system/base_tenant.d.ts +9 -0
  17. package/dist/package/declarations/src/auth.d.ts +1 -0
  18. package/dist/package/declarations/src/bootstrap.d.ts +23 -0
  19. package/dist/package/declarations/src/components/Card/DataPanelCard.vue.d.ts +23 -0
  20. package/dist/package/declarations/src/components/CronExpression/index.vue.d.ts +15 -0
  21. package/dist/package/declarations/src/components/Dialog/FormDialog.vue.d.ts +74 -0
  22. package/dist/package/declarations/src/components/Dialog/ProDialog.vue.d.ts +58 -0
  23. package/dist/package/declarations/src/components/Dict/DictLabel.vue.d.ts +11 -0
  24. package/dist/package/declarations/src/components/Dict/index.vue.d.ts +30 -0
  25. package/dist/package/declarations/src/components/ECharts/config/index.d.ts +7 -0
  26. package/dist/package/declarations/src/components/ECharts/index.vue.d.ts +22 -0
  27. package/dist/package/declarations/src/components/ErrorMessage/index.vue.d.ts +12 -0
  28. package/dist/package/declarations/src/components/Grid/components/GridItem.vue.d.ts +34 -0
  29. package/dist/package/declarations/src/components/Grid/index.vue.d.ts +28 -0
  30. package/dist/package/declarations/src/components/Grid/interface/index.d.ts +7 -0
  31. package/dist/package/declarations/src/components/ImportExcel/index.vue.d.ts +26 -0
  32. package/dist/package/declarations/src/components/Loading/fullScreen.d.ts +5 -0
  33. package/dist/package/declarations/src/components/Loading/index.vue.d.ts +3 -0
  34. package/dist/package/declarations/src/components/PasswordStrength/index.vue.d.ts +13 -0
  35. package/dist/package/declarations/src/components/ProForm/components/DynamicList.vue.d.ts +15 -0
  36. package/dist/package/declarations/src/components/ProForm/components/KvList.vue.d.ts +26 -0
  37. package/dist/package/declarations/src/components/ProForm/components/ProFormItem.vue.d.ts +28 -0
  38. package/dist/package/declarations/src/components/ProForm/index.vue.d.ts +36 -0
  39. package/dist/package/declarations/src/components/ProForm/interface/index.d.ts +47 -0
  40. package/dist/package/declarations/src/components/ProTable/components/ColSetting.vue.d.ts +9 -0
  41. package/dist/package/declarations/src/components/ProTable/components/Pagination.vue.d.ts +15 -0
  42. package/dist/package/declarations/src/components/ProTable/components/TableColumn.vue.d.ts +9 -0
  43. package/dist/package/declarations/src/components/ProTable/interface/index.d.ts +187 -0
  44. package/dist/package/declarations/src/components/ProTable.d.ts +5 -0
  45. package/dist/package/declarations/src/components/SearchForm/components/SearchFormItem.vue.d.ts +21 -0
  46. package/dist/package/declarations/src/components/SearchForm/index.vue.d.ts +22 -0
  47. package/dist/package/declarations/src/components/SelectFilter/index.vue.d.ts +44 -0
  48. package/dist/package/declarations/src/components/SelectIcon/index.vue.d.ts +19 -0
  49. package/dist/package/declarations/src/components/SvgIcon/index.vue.d.ts +15 -0
  50. package/dist/package/declarations/src/components/SwitchDark/index.vue.d.ts +3 -0
  51. package/dist/package/declarations/src/components/TreeFilter/index.vue.d.ts +5866 -0
  52. package/dist/package/declarations/src/components/Upload/File.vue.d.ts +24 -0
  53. package/dist/package/declarations/src/components/Upload/Files.vue.d.ts +26 -0
  54. package/dist/package/declarations/src/components/Upload/Img.vue.d.ts +43 -0
  55. package/dist/package/declarations/src/components/Upload/Imgs.vue.d.ts +46 -0
  56. package/dist/package/declarations/src/components/WangEditor/index.vue.d.ts +29 -0
  57. package/dist/package/declarations/src/config/index.d.ts +6 -0
  58. package/dist/package/declarations/src/config/nprogress.d.ts +3 -0
  59. package/dist/package/declarations/src/directives/index.d.ts +5 -0
  60. package/dist/package/declarations/src/directives/modules/auth.d.ts +3 -0
  61. package/dist/package/declarations/src/directives/modules/copy.d.ts +8 -0
  62. package/dist/package/declarations/src/directives/modules/debounce.d.ts +8 -0
  63. package/dist/package/declarations/src/directives/modules/draggable.d.ts +3 -0
  64. package/dist/package/declarations/src/directives/modules/longpress.d.ts +7 -0
  65. package/dist/package/declarations/src/directives/modules/throttle.d.ts +3 -0
  66. package/dist/package/declarations/src/directives/modules/waterMarker.d.ts +5 -0
  67. package/dist/package/declarations/src/enums/httpEnum.d.ts +29 -0
  68. package/dist/package/declarations/src/format.d.ts +1 -0
  69. package/dist/package/declarations/src/hooks/interface/index.d.ts +36 -0
  70. package/dist/package/declarations/src/hooks/useAuthButtons.d.ts +8 -0
  71. package/dist/package/declarations/src/hooks/useDownload.d.ts +9 -0
  72. package/dist/package/declarations/src/hooks/useHandleData.d.ts +10 -0
  73. package/dist/package/declarations/src/hooks/useOnline.d.ts +6 -0
  74. package/dist/package/declarations/src/hooks/useSelection.d.ts +10 -0
  75. package/dist/package/declarations/src/hooks/useTable.d.ts +46 -0
  76. package/dist/package/declarations/src/hooks/useTheme.d.ts +12 -0
  77. package/dist/package/declarations/src/hooks/useTime.d.ts +13 -0
  78. package/dist/package/declarations/src/index.d.ts +3 -0
  79. package/dist/package/declarations/src/layouts/LayoutClassic/index.vue.d.ts +3 -0
  80. package/dist/package/declarations/src/layouts/LayoutColumns/index.vue.d.ts +3 -0
  81. package/dist/package/declarations/src/layouts/LayoutTransverse/index.vue.d.ts +3 -0
  82. package/dist/package/declarations/src/layouts/LayoutVertical/index.vue.d.ts +3 -0
  83. package/dist/package/declarations/src/layouts/components/Footer/index.vue.d.ts +3 -0
  84. package/dist/package/declarations/src/layouts/components/Header/ToolBarLeft.vue.d.ts +3 -0
  85. package/dist/package/declarations/src/layouts/components/Header/ToolBarRight.vue.d.ts +3 -0
  86. package/dist/package/declarations/src/layouts/components/Header/components/AssemblySize.vue.d.ts +3 -0
  87. package/dist/package/declarations/src/layouts/components/Header/components/Avatar.vue.d.ts +3 -0
  88. package/dist/package/declarations/src/layouts/components/Header/components/Breadcrumb.vue.d.ts +3 -0
  89. package/dist/package/declarations/src/layouts/components/Header/components/CollapseIcon.vue.d.ts +3 -0
  90. package/dist/package/declarations/src/layouts/components/Header/components/Fullscreen.vue.d.ts +3 -0
  91. package/dist/package/declarations/src/layouts/components/Header/components/InfoDialog.vue.d.ts +5 -0
  92. package/dist/package/declarations/src/layouts/components/Header/components/PasswordDialog.vue.d.ts +5 -0
  93. package/dist/package/declarations/src/layouts/components/Header/components/SearchMenu.vue.d.ts +3 -0
  94. package/dist/package/declarations/src/layouts/components/Header/components/ThemeSetting.vue.d.ts +3 -0
  95. package/dist/package/declarations/src/layouts/components/Main/components/Maximize.vue.d.ts +3 -0
  96. package/dist/package/declarations/src/layouts/components/Main/index.vue.d.ts +3 -0
  97. package/dist/package/declarations/src/layouts/components/Menu/SubMenu.vue.d.ts +7 -0
  98. package/dist/package/declarations/src/layouts/components/Tabs/components/MoreButton.vue.d.ts +3 -0
  99. package/dist/package/declarations/src/layouts/components/Tabs/index.vue.d.ts +3 -0
  100. package/dist/package/declarations/src/layouts/components/ThemeDrawer/index.vue.d.ts +3 -0
  101. package/dist/package/declarations/src/layouts/index.vue.d.ts +3 -0
  102. package/dist/package/declarations/src/layouts/indexAsync.vue.d.ts +3 -0
  103. package/dist/package/declarations/src/modules/index.d.ts +117 -0
  104. package/dist/package/declarations/src/modules/kratosAdmin.d.ts +4 -0
  105. package/dist/package/declarations/src/navigation.d.ts +2 -0
  106. package/dist/package/declarations/src/request.d.ts +2 -0
  107. package/dist/package/declarations/src/routers/index.d.ts +21 -0
  108. package/dist/package/declarations/src/routers/modules/dynamicRouter.d.ts +4 -0
  109. package/dist/package/declarations/src/routers/modules/staticRouter.d.ts +25 -0
  110. package/dist/package/declarations/src/rpc/base/v1/config.d.ts +23 -0
  111. package/dist/package/declarations/src/rpc/base/v1/file.d.ts +52 -0
  112. package/dist/package/declarations/src/rpc/base/v1/login.d.ts +107 -0
  113. package/dist/package/declarations/src/rpc/base/v1/oauth.d.ts +167 -0
  114. package/dist/package/declarations/src/rpc/common/v1/common.d.ts +57 -0
  115. package/dist/package/declarations/src/rpc/common/v1/enum.d.ts +58 -0
  116. package/dist/package/declarations/src/rpc/common/v1/types.d.ts +60 -0
  117. package/dist/package/declarations/src/rpc/google/protobuf/empty.d.ts +11 -0
  118. package/dist/package/declarations/src/rpc/google/protobuf/wrappers.d.ts +108 -0
  119. package/dist/package/declarations/src/rpc/system/admin/v1/auth.d.ts +156 -0
  120. package/dist/package/declarations/src/rpc/system/admin/v1/base_dict.d.ts +215 -0
  121. package/dist/package/declarations/src/rpc/system/admin/v1/base_tenant.d.ts +112 -0
  122. package/dist/package/declarations/src/rpc/system/common/v1/enum.d.ts +67 -0
  123. package/dist/package/declarations/src/security.d.ts +3 -0
  124. package/dist/package/declarations/src/stores/helper/persist.d.ts +9 -0
  125. package/dist/package/declarations/src/stores/index.d.ts +2 -0
  126. package/dist/package/declarations/src/stores/interface/index.d.ts +90 -0
  127. package/dist/package/declarations/src/stores/modules/auth.d.ts +168 -0
  128. package/dist/package/declarations/src/stores/modules/config.d.ts +26 -0
  129. package/dist/package/declarations/src/stores/modules/dict.d.ts +32 -0
  130. package/dist/package/declarations/src/stores/modules/global.d.ts +4 -0
  131. package/dist/package/declarations/src/stores/modules/keepAlive.d.ts +6 -0
  132. package/dist/package/declarations/src/stores/modules/tabs.d.ts +13 -0
  133. package/dist/package/declarations/src/stores/modules/user.d.ts +29 -0
  134. package/dist/package/declarations/src/stores/runtime.d.ts +4 -0
  135. package/dist/package/declarations/src/styles/theme/aside.d.ts +4 -0
  136. package/dist/package/declarations/src/styles/theme/header.d.ts +4 -0
  137. package/dist/package/declarations/src/styles/theme/menu.d.ts +4 -0
  138. package/dist/package/declarations/src/table.d.ts +1 -0
  139. package/dist/package/declarations/src/tenant.d.ts +1 -0
  140. package/dist/package/declarations/src/utils/color.d.ts +28 -0
  141. package/dist/package/declarations/src/utils/dict.d.ts +15 -0
  142. package/dist/package/declarations/src/utils/eleValidate.d.ts +4 -0
  143. package/dist/package/declarations/src/utils/errorHandler.d.ts +5 -0
  144. package/dist/package/declarations/src/utils/index.d.ts +192 -0
  145. package/dist/package/declarations/src/utils/is/index.d.ts +72 -0
  146. package/dist/package/declarations/src/utils/mittBus.d.ts +2 -0
  147. package/dist/package/declarations/src/utils/oauthProvider.d.ts +19 -0
  148. package/dist/package/declarations/src/utils/passwordCrypto.d.ts +6 -0
  149. package/dist/package/declarations/src/utils/passwordStrength.d.ts +36 -0
  150. package/dist/package/declarations/src/utils/proTable.d.ts +44 -0
  151. package/dist/package/declarations/src/utils/request.d.ts +11 -0
  152. package/dist/package/declarations/src/utils/router.d.ts +14 -0
  153. package/dist/package/declarations/src/utils/svg.d.ts +4 -0
  154. package/dist/package/declarations/src/utils/tenant.d.ts +6 -0
  155. package/dist/package/declarations/src/utils/utils.d.ts +12 -0
  156. package/dist/package/declarations/src/views/error/403.vue.d.ts +3 -0
  157. package/dist/package/declarations/src/views/error/404.vue.d.ts +3 -0
  158. package/dist/package/declarations/src/views/error/500.vue.d.ts +3 -0
  159. package/dist/package/declarations/src/views/error/pending.vue.d.ts +3 -0
  160. package/dist/package/declarations/src/views/login/components/LoginForm.vue.d.ts +4 -0
  161. package/dist/package/declarations/src/views/login/index.vue.d.ts +3 -0
  162. package/dist/package/declarations/vite.config.d.ts +13 -0
  163. package/dist/package/src/App.vue +25 -0
  164. package/dist/package/src/api/base/config.ts +19 -0
  165. package/dist/package/src/api/base/file.ts +75 -0
  166. package/dist/package/src/api/base/login.ts +81 -0
  167. package/dist/package/src/api/base/oauth.ts +50 -0
  168. package/dist/package/src/api/system/auth.ts +45 -0
  169. package/dist/package/src/api/system/base_dict.ts +19 -0
  170. package/dist/package/src/api/system/base_tenant.ts +20 -0
  171. package/dist/package/src/assets/fonts/DIN.otf +0 -0
  172. package/dist/package/src/assets/fonts/MetroDF.ttf +0 -0
  173. package/dist/package/src/assets/fonts/YouSheBiaoTiHei.ttf +0 -0
  174. package/dist/package/src/assets/fonts/font.scss +14 -0
  175. package/dist/package/src/assets/iconfont/iconfont.scss +47 -0
  176. package/dist/package/src/assets/iconfont/iconfont.ttf +0 -0
  177. package/dist/package/src/assets/images/403.png +0 -0
  178. package/dist/package/src/assets/images/404.png +0 -0
  179. package/dist/package/src/assets/images/500.png +0 -0
  180. package/dist/package/src/assets/images/avatar.png +0 -0
  181. package/dist/package/src/assets/images/login_bg.svg +33 -0
  182. package/dist/package/src/assets/images/login_left.png +0 -0
  183. package/dist/package/src/assets/images/logo.svg +1 -0
  184. package/dist/package/src/assets/images/notData.png +0 -0
  185. package/dist/package/src/assets/images/oauth/dingtalk.png +0 -0
  186. package/dist/package/src/assets/images/oauth/feishu.png +0 -0
  187. package/dist/package/src/assets/images/oauth/gitee.png +0 -0
  188. package/dist/package/src/assets/images/oauth/github.png +0 -0
  189. package/dist/package/src/assets/images/oauth/google.png +0 -0
  190. package/dist/package/src/assets/images/oauth/wechat.png +0 -0
  191. package/dist/package/src/assets/images/oauth/wechatwork.png +0 -0
  192. package/dist/package/src/auth.ts +1 -0
  193. package/dist/package/src/bootstrap.ts +69 -0
  194. package/dist/package/src/components/Card/DataPanelCard.vue +67 -0
  195. package/dist/package/src/components/CronExpression/index.vue +713 -0
  196. package/dist/package/src/components/Dialog/FormDialog.vue +160 -0
  197. package/dist/package/src/components/Dialog/ProDialog.vue +96 -0
  198. package/dist/package/src/components/Dict/DictLabel.vue +62 -0
  199. package/dist/package/src/components/Dict/index.vue +157 -0
  200. package/dist/package/src/components/ECharts/config/index.ts +45 -0
  201. package/dist/package/src/components/ECharts/index.vue +108 -0
  202. package/dist/package/src/components/ErrorMessage/index.vue +63 -0
  203. package/dist/package/src/components/Grid/components/GridItem.vue +69 -0
  204. package/dist/package/src/components/Grid/index.vue +169 -0
  205. package/dist/package/src/components/Grid/interface/index.ts +8 -0
  206. package/dist/package/src/components/ImportExcel/index.scss +3 -0
  207. package/dist/package/src/components/ImportExcel/index.vue +150 -0
  208. package/dist/package/src/components/Loading/fullScreen.ts +45 -0
  209. package/dist/package/src/components/Loading/index.scss +67 -0
  210. package/dist/package/src/components/Loading/index.vue +13 -0
  211. package/dist/package/src/components/PasswordStrength/index.vue +127 -0
  212. package/dist/package/src/components/ProForm/components/DynamicList.vue +59 -0
  213. package/dist/package/src/components/ProForm/components/KvList.vue +73 -0
  214. package/dist/package/src/components/ProForm/components/ProFormItem.vue +191 -0
  215. package/dist/package/src/components/ProForm/index.vue +120 -0
  216. package/dist/package/src/components/ProForm/interface/index.ts +74 -0
  217. package/dist/package/src/components/ProTable/components/ColSetting.vue +45 -0
  218. package/dist/package/src/components/ProTable/components/Pagination.vue +58 -0
  219. package/dist/package/src/components/ProTable/components/TableColumn.vue +234 -0
  220. package/dist/package/src/components/ProTable/index.vue +567 -0
  221. package/dist/package/src/components/ProTable/interface/index.ts +223 -0
  222. package/dist/package/src/components/ProTable.ts +8 -0
  223. package/dist/package/src/components/SearchForm/components/SearchFormItem.vue +168 -0
  224. package/dist/package/src/components/SearchForm/index.vue +105 -0
  225. package/dist/package/src/components/SelectFilter/index.scss +63 -0
  226. package/dist/package/src/components/SelectFilter/index.vue +113 -0
  227. package/dist/package/src/components/SelectIcon/index.scss +39 -0
  228. package/dist/package/src/components/SelectIcon/index.vue +105 -0
  229. package/dist/package/src/components/SvgIcon/index.vue +35 -0
  230. package/dist/package/src/components/SwitchDark/index.vue +12 -0
  231. package/dist/package/src/components/TreeFilter/index.scss +44 -0
  232. package/dist/package/src/components/TreeFilter/index.vue +207 -0
  233. package/dist/package/src/components/Upload/File.vue +201 -0
  234. package/dist/package/src/components/Upload/Files.vue +234 -0
  235. package/dist/package/src/components/Upload/Img.vue +306 -0
  236. package/dist/package/src/components/Upload/Imgs.vue +320 -0
  237. package/dist/package/src/components/WangEditor/index.scss +28 -0
  238. package/dist/package/src/components/WangEditor/index.vue +154 -0
  239. package/dist/package/src/config/index.ts +19 -0
  240. package/dist/package/src/config/nprogress.ts +12 -0
  241. package/dist/package/src/directives/index.ts +28 -0
  242. package/dist/package/src/directives/modules/auth.ts +25 -0
  243. package/dist/package/src/directives/modules/copy.ts +39 -0
  244. package/dist/package/src/directives/modules/debounce.ts +32 -0
  245. package/dist/package/src/directives/modules/draggable.ts +50 -0
  246. package/dist/package/src/directives/modules/longpress.ts +49 -0
  247. package/dist/package/src/directives/modules/throttle.ts +42 -0
  248. package/dist/package/src/directives/modules/waterMarker.ts +36 -0
  249. package/dist/package/src/enums/httpEnum.ts +35 -0
  250. package/dist/package/src/format.ts +1 -0
  251. package/dist/package/src/hooks/interface/index.ts +38 -0
  252. package/dist/package/src/hooks/useAuthButtons.ts +25 -0
  253. package/dist/package/src/hooks/useDownload.ts +44 -0
  254. package/dist/package/src/hooks/useHandleData.ts +38 -0
  255. package/dist/package/src/hooks/useOnline.ts +27 -0
  256. package/dist/package/src/hooks/useSelection.ts +34 -0
  257. package/dist/package/src/hooks/useTable.ts +151 -0
  258. package/dist/package/src/hooks/useTheme.ts +111 -0
  259. package/dist/package/src/hooks/useTime.ts +38 -0
  260. package/dist/package/src/index.ts +9 -0
  261. package/dist/package/src/layouts/LayoutClassic/index.scss +60 -0
  262. package/dist/package/src/layouts/LayoutClassic/index.vue +64 -0
  263. package/dist/package/src/layouts/LayoutColumns/index.scss +95 -0
  264. package/dist/package/src/layouts/LayoutColumns/index.vue +113 -0
  265. package/dist/package/src/layouts/LayoutTransverse/index.scss +60 -0
  266. package/dist/package/src/layouts/LayoutTransverse/index.vue +70 -0
  267. package/dist/package/src/layouts/LayoutVertical/index.scss +70 -0
  268. package/dist/package/src/layouts/LayoutVertical/index.vue +119 -0
  269. package/dist/package/src/layouts/components/Footer/index.scss +11 -0
  270. package/dist/package/src/layouts/components/Footer/index.vue +21 -0
  271. package/dist/package/src/layouts/components/Header/ToolBarLeft.vue +23 -0
  272. package/dist/package/src/layouts/components/Header/ToolBarRight.vue +44 -0
  273. package/dist/package/src/layouts/components/Header/components/AssemblySize.vue +39 -0
  274. package/dist/package/src/layouts/components/Header/components/Avatar.vue +226 -0
  275. package/dist/package/src/layouts/components/Header/components/Breadcrumb.vue +117 -0
  276. package/dist/package/src/layouts/components/Header/components/CollapseIcon.vue +21 -0
  277. package/dist/package/src/layouts/components/Header/components/Fullscreen.vue +28 -0
  278. package/dist/package/src/layouts/components/Header/components/InfoDialog.vue +22 -0
  279. package/dist/package/src/layouts/components/Header/components/PasswordDialog.vue +22 -0
  280. package/dist/package/src/layouts/components/Header/components/SearchMenu.vue +207 -0
  281. package/dist/package/src/layouts/components/Header/components/ThemeSetting.vue +14 -0
  282. package/dist/package/src/layouts/components/Main/components/Maximize.vue +39 -0
  283. package/dist/package/src/layouts/components/Main/index.scss +14 -0
  284. package/dist/package/src/layouts/components/Main/index.vue +90 -0
  285. package/dist/package/src/layouts/components/Menu/SubMenu.vue +132 -0
  286. package/dist/package/src/layouts/components/Tabs/components/MoreButton.vue +83 -0
  287. package/dist/package/src/layouts/components/Tabs/index.scss +69 -0
  288. package/dist/package/src/layouts/components/Tabs/index.vue +111 -0
  289. package/dist/package/src/layouts/components/ThemeDrawer/index.scss +137 -0
  290. package/dist/package/src/layouts/components/ThemeDrawer/index.vue +191 -0
  291. package/dist/package/src/layouts/index.vue +50 -0
  292. package/dist/package/src/layouts/indexAsync.vue +54 -0
  293. package/dist/package/src/modules/index.ts +233 -0
  294. package/dist/package/src/modules/kratosAdmin.ts +17 -0
  295. package/dist/package/src/navigation.ts +2 -0
  296. package/dist/package/src/request.ts +2 -0
  297. package/dist/package/src/routers/index.ts +143 -0
  298. package/dist/package/src/routers/modules/dynamicRouter.ts +160 -0
  299. package/dist/package/src/routers/modules/staticRouter.ts +73 -0
  300. package/dist/package/src/rpc/base/v1/config.ts +34 -0
  301. package/dist/package/src/rpc/base/v1/file.ts +66 -0
  302. package/dist/package/src/rpc/base/v1/login.ts +128 -0
  303. package/dist/package/src/rpc/base/v1/oauth.ts +199 -0
  304. package/dist/package/src/rpc/common/v1/common.ts +71 -0
  305. package/dist/package/src/rpc/common/v1/enum.ts +71 -0
  306. package/dist/package/src/rpc/common/v1/types.ts +77 -0
  307. package/dist/package/src/rpc/google/protobuf/empty.ts +19 -0
  308. package/dist/package/src/rpc/google/protobuf/wrappers.ts +124 -0
  309. package/dist/package/src/rpc/system/admin/v1/auth.ts +208 -0
  310. package/dist/package/src/rpc/system/admin/v1/base_dict.ts +249 -0
  311. package/dist/package/src/rpc/system/admin/v1/base_tenant.ts +134 -0
  312. package/dist/package/src/rpc/system/common/v1/enum.ts +80 -0
  313. package/dist/package/src/security.ts +3 -0
  314. package/dist/package/src/stores/helper/persist.ts +19 -0
  315. package/dist/package/src/stores/index.ts +8 -0
  316. package/dist/package/src/stores/interface/index.ts +102 -0
  317. package/dist/package/src/stores/modules/auth.ts +73 -0
  318. package/dist/package/src/stores/modules/config.ts +119 -0
  319. package/dist/package/src/stores/modules/dict.ts +65 -0
  320. package/dist/package/src/stores/modules/global.ts +54 -0
  321. package/dist/package/src/stores/modules/keepAlive.ts +22 -0
  322. package/dist/package/src/stores/modules/tabs.ts +77 -0
  323. package/dist/package/src/stores/modules/user.ts +109 -0
  324. package/dist/package/src/stores/runtime.ts +4 -0
  325. package/dist/package/src/styles/common.scss +144 -0
  326. package/dist/package/src/styles/element-dark.scss +46 -0
  327. package/dist/package/src/styles/element.scss +333 -0
  328. package/dist/package/src/styles/reset.scss +143 -0
  329. package/dist/package/src/styles/theme/aside.ts +16 -0
  330. package/dist/package/src/styles/theme/header.ts +25 -0
  331. package/dist/package/src/styles/theme/menu.ts +31 -0
  332. package/dist/package/src/styles/var.scss +2 -0
  333. package/dist/package/src/table.ts +1 -0
  334. package/dist/package/src/tenant.ts +1 -0
  335. package/dist/package/src/typings/global.d.ts +74 -0
  336. package/dist/package/src/typings/utils.d.ts +17 -0
  337. package/dist/package/src/typings/window.d.ts +8 -0
  338. package/dist/package/src/utils/color.ts +59 -0
  339. package/dist/package/src/utils/dict.ts +17 -0
  340. package/dist/package/src/utils/eleValidate.ts +14 -0
  341. package/dist/package/src/utils/errorHandler.ts +27 -0
  342. package/dist/package/src/utils/index.ts +403 -0
  343. package/dist/package/src/utils/is/index.ts +125 -0
  344. package/dist/package/src/utils/mittBus.ts +5 -0
  345. package/dist/package/src/utils/oauthProvider.ts +79 -0
  346. package/dist/package/src/utils/passwordCrypto.ts +71 -0
  347. package/dist/package/src/utils/passwordStrength.ts +86 -0
  348. package/dist/package/src/utils/proTable.ts +124 -0
  349. package/dist/package/src/utils/request.ts +296 -0
  350. package/dist/package/src/utils/router.ts +43 -0
  351. package/dist/package/src/utils/svg.ts +13 -0
  352. package/dist/package/src/utils/tenant.ts +10 -0
  353. package/dist/package/src/utils/utils.ts +40 -0
  354. package/dist/package/src/views/error/403.vue +8 -0
  355. package/dist/package/src/views/error/404.vue +8 -0
  356. package/dist/package/src/views/error/500.vue +8 -0
  357. package/dist/package/src/views/error/pending.vue +16 -0
  358. package/dist/package/src/views/login/components/LoginForm.vue +797 -0
  359. package/dist/package/src/views/login/index.scss +103 -0
  360. package/dist/package/src/views/login/index.vue +108 -0
  361. package/dist/package/src/vite-env.d.ts +3 -0
  362. package/dist/package/types/generated/auto-imports.d.ts +124 -0
  363. package/dist/package/types/generated/components.d.ts +151 -0
  364. package/package.json +199 -0
  365. package/tsconfig.json +21 -0
  366. package/types/generated/auto-imports.d.ts +124 -0
  367. package/types/generated/components.d.ts +151 -0
  368. package/vite.config.ts +239 -0
@@ -0,0 +1,797 @@
1
+ <template>
2
+ <el-form ref="loginFormRef" :model="loginForm" :rules="loginRules" size="large">
3
+ <el-form-item prop="tenant_code">
4
+ <el-input v-model="loginForm.tenant_code" placeholder="请输入租户编码">
5
+ <template #prefix>
6
+ <el-icon class="el-input__icon">
7
+ <office-building />
8
+ </el-icon>
9
+ </template>
10
+ </el-input>
11
+ </el-form-item>
12
+ <el-form-item prop="user_name">
13
+ <el-input v-model="loginForm.user_name" placeholder="请输入用户名">
14
+ <template #prefix>
15
+ <el-icon class="el-input__icon">
16
+ <user />
17
+ </el-icon>
18
+ </template>
19
+ </el-input>
20
+ </el-form-item>
21
+ <el-form-item prop="password">
22
+ <el-input v-model="loginForm.password" type="password" placeholder="请输入密码" show-password autocomplete="new-password">
23
+ <template #prefix>
24
+ <el-icon class="el-input__icon">
25
+ <lock />
26
+ </el-icon>
27
+ </template>
28
+ </el-input>
29
+ </el-form-item>
30
+ <el-form-item v-if="!isBehaviorCaptcha" prop="captcha_code">
31
+ <div class="captcha-row">
32
+ <el-input v-model="loginForm.captcha_code" placeholder="请输入验证码" @keyup.enter="handleLogin(loginFormRef)">
33
+ <template #prefix>
34
+ <el-icon class="el-input__icon">
35
+ <Key />
36
+ </el-icon>
37
+ </template>
38
+ </el-input>
39
+ <img
40
+ v-if="captcha_base64"
41
+ class="captcha-image"
42
+ :style="{ width: captchaImageWidth }"
43
+ :src="captcha_base64"
44
+ alt="验证码"
45
+ @load="handleCaptchaImageLoad"
46
+ @click="getCaptcha"
47
+ />
48
+ </div>
49
+ </el-form-item>
50
+ </el-form>
51
+ <div class="login-btn">
52
+ <el-button :icon="CircleClose" round size="large" @click="resetForm(loginFormRef)"> 重置 </el-button>
53
+ <el-button :icon="UserFilled" round size="large" type="primary" :loading="loading || oauthTicketLoading" @click="handleLogin(loginFormRef)">
54
+ 登录
55
+ </el-button>
56
+ </div>
57
+ <div v-if="oauthProviders.length" class="oauth-login">
58
+ <div class="oauth-divider">
59
+ <span>其他登录方式</span>
60
+ </div>
61
+ <div class="oauth-provider-list">
62
+ <el-tooltip
63
+ v-for="provider in oauthProviders"
64
+ :key="provider.provider"
65
+ :content="provider.name"
66
+ placement="top"
67
+ :trigger="['hover', 'focus']"
68
+ >
69
+ <button
70
+ class="oauth-provider-button"
71
+ type="button"
72
+ :aria-label="provider.name"
73
+ :title="provider.name"
74
+ :disabled="oauthTicketLoading || oauthLoadingProvider === provider.provider"
75
+ @click="handleOauthLogin(provider)"
76
+ >
77
+ <component :is="getOauthProviderIcon(provider)" />
78
+ </button>
79
+ </el-tooltip>
80
+ </div>
81
+ </div>
82
+ <el-dialog
83
+ v-model="behaviorDialogVisible"
84
+ width="364px"
85
+ top="16vh"
86
+ :show-close="false"
87
+ append-to-body
88
+ class="behavior-captcha-dialog"
89
+ >
90
+ <div v-loading="behaviorLoading" class="behavior-captcha-body">
91
+ <GoCaptchaSlide
92
+ v-if="currentCaptchaType === 'slide'"
93
+ :config="slideCaptchaConfig"
94
+ :data="behaviorCaptchaData"
95
+ :events="slideCaptchaEvents"
96
+ />
97
+ <GoCaptchaClick
98
+ v-else-if="currentCaptchaType === 'click'"
99
+ :config="clickCaptchaConfig"
100
+ :data="behaviorCaptchaData"
101
+ :events="clickCaptchaEvents"
102
+ />
103
+ <GoCaptchaRotate
104
+ v-else-if="currentCaptchaType === 'rotate'"
105
+ :config="rotateCaptchaConfig"
106
+ :data="behaviorCaptchaData"
107
+ :events="rotateCaptchaEvents"
108
+ />
109
+ </div>
110
+ </el-dialog>
111
+ </template>
112
+
113
+ <script setup lang="ts">
114
+ import { computed, ref, reactive, onMounted, watch } from "vue";
115
+ import { useRoute, useRouter } from "vue-router";
116
+ import { HOME_URL } from "../../../config";
117
+ import { getTimeState } from "../../../utils";
118
+ import { defLoginService } from "../../../api/base/login";
119
+ import { defOauthService } from "../../../api/base/oauth";
120
+ import { ElMessage, ElNotification } from "element-plus";
121
+ import type { LoginRequest } from "../../../rpc/base/v1/login";
122
+ import type { OauthProvider } from "../../../rpc/base/v1/oauth";
123
+ import { getOauthProviderIcon, withOauthProviderDisplay, type OauthProviderDisplay } from "../../../utils/oauthProvider";
124
+ import { useUserStore } from "../../../stores/modules/user";
125
+ import { useDictStore } from "../../../stores/modules/dict";
126
+ import { useTabsStore } from "../../../stores/modules/tabs";
127
+ import { useKeepAliveStore } from "../../../stores/modules/keepAlive";
128
+ import { initDynamicRouter } from "../../../routers/modules/dynamicRouter";
129
+ import { isUnmatchedRoute, navigateTo, resolveFrontendRouteURL } from "../../../utils/router";
130
+ import { CircleClose, UserFilled } from "@element-plus/icons-vue";
131
+ import type { ElForm } from "element-plus";
132
+ import { PASSWORD_CRYPTO_SCENE, encryptPassword } from "../../../utils/passwordCrypto";
133
+ import { useConfigStore } from "../../../stores/modules/config";
134
+ import { Click as GoCaptchaClick, Rotate as GoCaptchaRotate, Slide as GoCaptchaSlide } from "go-captcha-vue";
135
+ import "go-captcha-vue/dist/style.css";
136
+
137
+ const router = useRouter();
138
+ const route = useRoute();
139
+ const userStore = useUserStore();
140
+ const configStore = useConfigStore();
141
+ const dictStore = useDictStore();
142
+ const tabsStore = useTabsStore();
143
+ const keepAliveStore = useKeepAliveStore();
144
+
145
+ /** 登录表单实例类型。 */
146
+ type FormInstance = InstanceType<typeof ElForm>;
147
+ const loginFormRef = ref<FormInstance>();
148
+ const captcha_base64 = ref("");
149
+ const defaultCaptchaImageWidth = 96;
150
+ const captchaImageWidth = ref(`${defaultCaptchaImageWidth}px`);
151
+ const behaviorDialogVisible = ref(false);
152
+ const behaviorLoading = ref(false);
153
+ const loginRules = reactive({
154
+ tenant_code: [{ required: true, message: "请输入租户编码", trigger: "blur" }],
155
+ user_name: [{ required: true, message: "请输入用户名", trigger: "blur" }],
156
+ password: [{ required: true, message: "请输入密码", trigger: "blur" }],
157
+ captcha_code: [{ required: true, message: "请输入验证码", trigger: "blur" }]
158
+ });
159
+
160
+ const loading = ref(false);
161
+ const oauthLoadingProvider = ref("");
162
+ const oauthTicketLoading = ref(false);
163
+
164
+ /** 登录页三方登录展示项。 */
165
+ type LoginOauthProvider = OauthProvider & OauthProviderDisplay;
166
+
167
+ const oauthProviders = ref<LoginOauthProvider[]>([]);
168
+
169
+ /** 登录表单状态。 */
170
+ interface LoginFormState {
171
+ /** 租户编码。 */
172
+ tenant_code: string;
173
+ /** 用户名。 */
174
+ user_name: string;
175
+ /** 密码。 */
176
+ password: string;
177
+ /** 验证码。 */
178
+ captcha_code: string;
179
+ /** 验证码 ID。 */
180
+ captcha_id: string;
181
+ }
182
+
183
+ const loginForm = reactive<LoginFormState>({
184
+ tenant_code: "",
185
+ user_name: "",
186
+ password: "",
187
+ captcha_code: "",
188
+ captcha_id: ""
189
+ });
190
+
191
+ /** 行为验证码类型集合。 */
192
+ const behaviorCaptchaTypeSet = new Set(["slide", "click", "rotate"]);
193
+
194
+ /** 行为验证码服务端返回的图片载荷。 */
195
+ interface BehaviorCaptchaPayload {
196
+ type?: string;
197
+ image: string;
198
+ thumb: string;
199
+ width?: number;
200
+ height?: number;
201
+ thumbX?: number;
202
+ thumbY?: number;
203
+ thumbWidth?: number;
204
+ thumbHeight?: number;
205
+ thumbSize?: number;
206
+ }
207
+
208
+ /** 行为验证码组件使用的坐标点。 */
209
+ interface CaptchaPoint {
210
+ x: number;
211
+ y: number;
212
+ }
213
+
214
+ /** 点击验证码组件提交的坐标点。 */
215
+ interface ClickCaptchaPoint extends CaptchaPoint {
216
+ key?: number;
217
+ index?: number;
218
+ }
219
+
220
+ /** 行为验证码组件数据。 */
221
+ interface BehaviorCaptchaData {
222
+ image: string;
223
+ thumb: string;
224
+ thumbX?: number;
225
+ thumbY?: number;
226
+ thumbWidth?: number;
227
+ thumbHeight?: number;
228
+ thumbSize?: number;
229
+ angle?: number;
230
+ }
231
+
232
+ const behaviorCaptchaData = reactive<BehaviorCaptchaData>({
233
+ image: "",
234
+ thumb: ""
235
+ });
236
+ const configuredCaptchaType = computed(() => configStore.captcha.type || "digit");
237
+ const currentCaptchaType = ref(configuredCaptchaType.value);
238
+ const isBehaviorCaptcha = computed(() => behaviorCaptchaTypeSet.has(currentCaptchaType.value));
239
+ const behaviorCaptchaDisplayWidth = 340;
240
+ const rotateCaptchaDisplaySize = 300;
241
+ const behaviorCaptchaSource = reactive({
242
+ width: 300,
243
+ height: 220,
244
+ thumbWidth: 60,
245
+ thumbHeight: 60,
246
+ thumbSize: 150
247
+ });
248
+ const behaviorCaptchaDisplayHeight = computed(() => Math.round((behaviorCaptchaSource.height * behaviorCaptchaDisplayWidth) / behaviorCaptchaSource.width));
249
+ const behaviorCaptchaScaleX = computed(() => behaviorCaptchaDisplayWidth / behaviorCaptchaSource.width);
250
+ const behaviorCaptchaScaleY = computed(() => behaviorCaptchaDisplayHeight.value / behaviorCaptchaSource.height);
251
+ const rotateCaptchaScale = computed(() => rotateCaptchaDisplaySize / behaviorCaptchaSource.width);
252
+
253
+ /** 将服务端原始 X 坐标换算为前端展示坐标。 */
254
+ const toDisplayCaptchaX = (value: number) => Math.round(value * behaviorCaptchaScaleX.value);
255
+
256
+ /** 将服务端原始 Y 坐标换算为前端展示坐标。 */
257
+ const toDisplayCaptchaY = (value: number) => Math.round(value * behaviorCaptchaScaleY.value);
258
+
259
+ /** 将服务端原始旋转内圈尺寸换算为前端展示尺寸。 */
260
+ const toDisplayRotateSize = (value: number) => Math.round(value * rotateCaptchaScale.value);
261
+
262
+ /** 将前端展示 X 坐标换算回服务端原始坐标。 */
263
+ const toOriginalCaptchaX = (value: number) => Math.min(behaviorCaptchaSource.width, Math.max(0, Math.round(value / behaviorCaptchaScaleX.value)));
264
+
265
+ /** 将前端展示 Y 坐标换算回服务端原始坐标。 */
266
+ const toOriginalCaptchaY = (value: number) => Math.min(behaviorCaptchaSource.height, Math.max(0, Math.round(value / behaviorCaptchaScaleY.value)));
267
+ const slideCaptchaConfig = computed(() => ({
268
+ width: behaviorCaptchaDisplayWidth,
269
+ height: behaviorCaptchaDisplayHeight.value,
270
+ thumbWidth: toDisplayCaptchaX(behaviorCaptchaSource.thumbWidth),
271
+ thumbHeight: toDisplayCaptchaY(behaviorCaptchaSource.thumbHeight),
272
+ showTheme: false,
273
+ verticalPadding: 0,
274
+ horizontalPadding: 0,
275
+ iconSize: 20,
276
+ title: "请拖动滑块完成拼图"
277
+ }));
278
+ const clickCaptchaConfig = computed(() => ({
279
+ width: behaviorCaptchaDisplayWidth,
280
+ height: behaviorCaptchaDisplayHeight.value,
281
+ thumbWidth: toDisplayCaptchaX(behaviorCaptchaSource.thumbWidth),
282
+ thumbHeight: toDisplayCaptchaY(behaviorCaptchaSource.thumbHeight),
283
+ showTheme: false,
284
+ verticalPadding: 0,
285
+ horizontalPadding: 0,
286
+ buttonText: "确认",
287
+ iconSize: 20,
288
+ dotSize: 20,
289
+ title: "请按顺序点击文字"
290
+ }));
291
+ const rotateCaptchaConfig = computed(() => ({
292
+ width: behaviorCaptchaDisplayWidth,
293
+ height: rotateCaptchaDisplaySize,
294
+ size: rotateCaptchaDisplaySize,
295
+ showTheme: false,
296
+ verticalPadding: 0,
297
+ horizontalPadding: 0,
298
+ iconSize: 20,
299
+ title: "拖动滑块,将内圈图片转正"
300
+ }));
301
+ const slideCaptchaEvents = {
302
+ refresh: () => getCaptcha(),
303
+ close: () => closeBehaviorCaptcha(),
304
+ confirm: (point: CaptchaPoint, reset: () => void) => verifyBehaviorCaptcha(String(toOriginalCaptchaX(point.x)), reset)
305
+ };
306
+ const clickCaptchaEvents = {
307
+ refresh: () => getCaptcha(),
308
+ close: () => closeBehaviorCaptcha(),
309
+ confirm: (dots: ClickCaptchaPoint[], reset: () => void) =>
310
+ verifyBehaviorCaptcha(JSON.stringify(dots.map(dot => ({ x: toOriginalCaptchaX(dot.x), y: toOriginalCaptchaY(dot.y) }))), reset)
311
+ };
312
+ const rotateCaptchaEvents = {
313
+ refresh: () => getCaptcha(),
314
+ close: () => closeBehaviorCaptcha(),
315
+ confirm: (angle: number, reset: () => void) => verifyBehaviorCaptcha(String(Math.round(angle)), reset)
316
+ };
317
+
318
+ /** 获取登录后的首个可访问路由 */
319
+ const getFirstAccessibleRoutePath = () => {
320
+ // 首页仅在真正完成动态路由注册后才视为可达,避免把全局 404 占位路由误判为首页已加载。
321
+ if (!isUnmatchedRoute(router, HOME_URL)) return HOME_URL;
322
+
323
+ const systemRouteSet = new Set(["/", "/layout", "/login", "/403", "/404", "/500"]);
324
+ const firstRoute = router.getRoutes().find(item => {
325
+ if (!item.path || systemRouteSet.has(item.path) || item.path.includes(":pathMatch")) return false;
326
+ return item.meta?.hidden !== true;
327
+ });
328
+ return firstRoute?.path ?? HOME_URL;
329
+ };
330
+
331
+ /** 获取登录成功后的回跳地址,优先使用登录前记录的完整页面地址。 */
332
+ const getLoginRedirectPath = () => {
333
+ const redirect = route.query.redirect;
334
+ if (typeof redirect === "string" && redirect && redirect !== HOME_URL) {
335
+ return normalizeFrontendRedirectPath(redirect);
336
+ }
337
+ return getFirstAccessibleRoutePath();
338
+ };
339
+
340
+ /** 将 OAuth 回调带回的同源绝对地址还原为 Vue Router 可识别的站内路径。 */
341
+ const normalizeFrontendRedirectPath = (redirect: string) => {
342
+ try {
343
+ const redirectURL = new URL(redirect, window.location.origin);
344
+ if (redirectURL.origin !== window.location.origin) return HOME_URL;
345
+ if (redirectURL.hash.startsWith("#/")) return redirectURL.hash.slice(1);
346
+ return `${redirectURL.pathname}${redirectURL.search}`;
347
+ } catch {
348
+ return HOME_URL;
349
+ }
350
+ };
351
+
352
+ /** 获取 OAuth 登录完成后的前端接收地址,并携带账号登录一致的业务回跳目标。 */
353
+ const getOauthLoginRedirectURL = () => {
354
+ const query = { ...route.query };
355
+ delete query.oauth_ticket;
356
+ delete query.oauth_error;
357
+ query.redirect = getLoginRedirectPath();
358
+ return resolveFrontendRouteURL(router, { path: route.path, query });
359
+ };
360
+
361
+ /** 查询配置启用的三方登录方式。 */
362
+ const loadOauthProviders = async () => {
363
+ const result = await defOauthService.ListOauthProvider({});
364
+ oauthProviders.value = result.providers.map(withOauthProviderDisplay);
365
+ };
366
+
367
+ /** 发起三方登录授权跳转。 */
368
+ const handleOauthLogin = async (provider: LoginOauthProvider) => {
369
+ // 授权地址创建期间锁定当前按钮,避免同一个 provider 重复创建 state。
370
+ if (oauthLoadingProvider.value) return;
371
+ oauthLoadingProvider.value = provider.provider;
372
+ try {
373
+ const result = await defOauthService.CreateOauthAuthorization({
374
+ provider: provider.provider,
375
+ redirect_url: getOauthLoginRedirectURL()
376
+ });
377
+ if (result.authorization_url) {
378
+ window.location.href = result.authorization_url;
379
+ }
380
+ } finally {
381
+ oauthLoadingProvider.value = "";
382
+ }
383
+ };
384
+
385
+ /** 完成登录后的用户信息、字典与动态路由初始化。 */
386
+ const finishLogin = async () => {
387
+ // 1.获取用户信息
388
+ await userStore.getUserInfo();
389
+
390
+ // 2.预加载字典缓存,避免页面首次渲染时字典值为空
391
+ await dictStore.loadDictionaries();
392
+
393
+ // 3.添加动态路由
394
+ await initDynamicRouter();
395
+
396
+ // 4.清空 tabs、keepAlive 数据
397
+ tabsStore.setTabs([]);
398
+ keepAliveStore.setKeepAliveName([]);
399
+
400
+ // 5.优先跳回登录失效前页面,没有记录时再进入首个可访问页面。
401
+ // 统一走动态路由感知跳转,避免首次登录后目标页面尚未完成挂载时直接进入 404。
402
+ await navigateTo(router, getLoginRedirectPath());
403
+ ElNotification({
404
+ title: getTimeState(),
405
+ message: "欢迎登录管理后台",
406
+ type: "success",
407
+ duration: 3000
408
+ });
409
+ };
410
+
411
+ /** 消费 OAuth 回调携带的一次性票据。 */
412
+ const consumeOauthTicket = async () => {
413
+ const oauthError = route.query.oauth_error;
414
+ if (typeof oauthError === "string" && oauthError) {
415
+ ElMessage.error(oauthError);
416
+ await router.replace({ path: route.path, query: { ...route.query, oauth_error: undefined, oauth_ticket: undefined } });
417
+ return;
418
+ }
419
+
420
+ const ticket = route.query.oauth_ticket;
421
+ if (typeof ticket !== "string" || !ticket) return;
422
+
423
+ oauthTicketLoading.value = true;
424
+ try {
425
+ const result = await defOauthService.ExchangeOauthTicket({ ticket });
426
+ userStore.updateTokenAuth(result.access_token, result.refresh_token ?? "", result.token_type ?? "", result.expires_in);
427
+ await finishLogin();
428
+ } finally {
429
+ oauthTicketLoading.value = false;
430
+ }
431
+ };
432
+
433
+ /** 获取验证码 */
434
+ const getCaptcha = async () => {
435
+ const requestedCaptchaType = configuredCaptchaType.value;
436
+ const data = await defLoginService.Captcha({ type: requestedCaptchaType });
437
+ currentCaptchaType.value = data.type || requestedCaptchaType;
438
+ if (!isBehaviorCaptcha.value) {
439
+ behaviorDialogVisible.value = false;
440
+ }
441
+ loginForm.captcha_id = data.captcha_id;
442
+ loginForm.captcha_code = "";
443
+ captchaImageWidth.value = `${defaultCaptchaImageWidth}px`;
444
+ captcha_base64.value = isBehaviorCaptcha.value ? "" : data.captcha_base64;
445
+ if (isBehaviorCaptcha.value) {
446
+ applyBehaviorCaptchaPayload(data.captcha_base64);
447
+ }
448
+ };
449
+
450
+ /** 页面加载或普通表单刷新验证码,行为验证码延迟到登录弹窗打开时再请求。 */
451
+ const loadPageCaptcha = async () => {
452
+ if (isBehaviorCaptcha.value) {
453
+ loginForm.captcha_id = "";
454
+ loginForm.captcha_code = "";
455
+ captcha_base64.value = "";
456
+ return;
457
+ }
458
+ await getCaptcha();
459
+ };
460
+
461
+ /** 解析行为验证码图片载荷并映射为官方组件数据。 */
462
+ const applyBehaviorCaptchaPayload = (payloadText: string) => {
463
+ const payload = JSON.parse(payloadText || "{}") as BehaviorCaptchaPayload;
464
+ const payloadType = payload.type || currentCaptchaType.value;
465
+ behaviorCaptchaSource.width = payload.width || 300;
466
+ behaviorCaptchaSource.height = payload.height || (payloadType === "rotate" ? 300 : 220);
467
+ behaviorCaptchaSource.thumbWidth = payload.thumbWidth || (payloadType === "click" ? 180 : 60);
468
+ behaviorCaptchaSource.thumbHeight = payload.thumbHeight || (payloadType === "click" ? 48 : 60);
469
+ behaviorCaptchaSource.thumbSize = payload.thumbSize || 150;
470
+ behaviorCaptchaData.image = payload.image || "";
471
+ behaviorCaptchaData.thumb = payload.thumb || "";
472
+ behaviorCaptchaData.thumbX = toDisplayCaptchaX(payload.thumbX ?? 0);
473
+ behaviorCaptchaData.thumbY = toDisplayCaptchaY(payload.thumbY ?? 0);
474
+ behaviorCaptchaData.thumbWidth = toDisplayCaptchaX(behaviorCaptchaSource.thumbWidth);
475
+ behaviorCaptchaData.thumbHeight = toDisplayCaptchaY(behaviorCaptchaSource.thumbHeight);
476
+ behaviorCaptchaData.thumbSize = toDisplayRotateSize(behaviorCaptchaSource.thumbSize);
477
+ behaviorCaptchaData.angle = 0;
478
+ };
479
+
480
+ /** 根据验证码图片原始比例更新展示宽度。 */
481
+ const handleCaptchaImageLoad = (event: Event) => {
482
+ const image = event.target as HTMLImageElement;
483
+ if (!image.naturalWidth || !image.naturalHeight) return;
484
+
485
+ // 验证码固定展示高度,宽度按图片比例自适应,避免算术验证码横向内容被裁剪。
486
+ const width = Math.round((40 * image.naturalWidth) / image.naturalHeight);
487
+ captchaImageWidth.value = `${Math.min(Math.max(width, defaultCaptchaImageWidth), 180)}px`;
488
+ };
489
+
490
+ /** 预校验验证码并返回可用于登录的一次性令牌。 */
491
+ const verifyCaptchaToken = async (captchaCode: string) => {
492
+ const result = await defLoginService.VerifyCaptcha({
493
+ captcha_id: loginForm.captcha_id,
494
+ captcha_code: captchaCode
495
+ });
496
+ return result.captcha_token;
497
+ };
498
+
499
+ /** 执行真正的账号登录流程。 */
500
+ const submitLogin = async (captchaToken: string) => {
501
+ loading.value = true;
502
+ try {
503
+ const password = await encryptPassword(loginForm.password, PASSWORD_CRYPTO_SCENE.LOGIN);
504
+ const loginRequest: LoginRequest = {
505
+ tenant_code: loginForm.tenant_code,
506
+ user_name: loginForm.user_name,
507
+ password,
508
+ captcha_code: captchaToken,
509
+ captcha_id: loginForm.captcha_id
510
+ };
511
+ // 1.执行登录接口
512
+ await userStore.login(loginRequest);
513
+
514
+ await finishLogin();
515
+ } catch (_error) {
516
+ await loadPageCaptcha();
517
+ } finally {
518
+ loading.value = false;
519
+ }
520
+ };
521
+
522
+ /** 验证行为验证码并继续登录。 */
523
+ const verifyBehaviorCaptcha = async (captchaCode: string, reset: () => void) => {
524
+ if (behaviorLoading.value) return;
525
+ behaviorLoading.value = true;
526
+ try {
527
+ const captchaToken = await verifyCaptchaToken(captchaCode);
528
+ behaviorDialogVisible.value = false;
529
+ await submitLogin(captchaToken);
530
+ } catch (_error) {
531
+ reset();
532
+ await getCaptcha();
533
+ } finally {
534
+ behaviorLoading.value = false;
535
+ }
536
+ };
537
+
538
+ /** 关闭行为验证码弹窗。 */
539
+ const closeBehaviorCaptcha = () => {
540
+ behaviorDialogVisible.value = false;
541
+ };
542
+
543
+ /** 打开行为验证码弹窗。 */
544
+ const openBehaviorCaptcha = async () => {
545
+ behaviorDialogVisible.value = true;
546
+ behaviorLoading.value = true;
547
+ try {
548
+ await getCaptcha();
549
+ } finally {
550
+ behaviorLoading.value = false;
551
+ }
552
+ };
553
+
554
+ /** 登录 */
555
+ const handleLogin = (formEl: FormInstance | undefined) => {
556
+ // 登录请求执行期间直接拦截重复提交,避免回车或连续点击导致重复登录。
557
+ if (!formEl || loading.value) return;
558
+ formEl.validate(async valid => {
559
+ if (!valid) return;
560
+ if (isBehaviorCaptcha.value) {
561
+ await openBehaviorCaptcha();
562
+ return;
563
+ }
564
+ try {
565
+ const captchaToken = await verifyCaptchaToken(loginForm.captcha_code);
566
+ await submitLogin(captchaToken);
567
+ } catch (_error) {
568
+ await loadPageCaptcha();
569
+ }
570
+ });
571
+ };
572
+
573
+ /** 重置表单 */
574
+ const resetForm = (formEl: FormInstance | undefined) => {
575
+ if (!formEl) return;
576
+ formEl.resetFields();
577
+ void loadPageCaptcha();
578
+ };
579
+
580
+ onMounted(() => {
581
+ void loadPageCaptcha();
582
+ void loadOauthProviders();
583
+ });
584
+
585
+ watch(
586
+ () => [route.query.oauth_ticket, route.query.oauth_error],
587
+ () => {
588
+ void consumeOauthTicket();
589
+ },
590
+ { immediate: true }
591
+ );
592
+ </script>
593
+
594
+ <style scoped lang="scss">
595
+ @use "../index.scss" as *;
596
+ .captcha-row {
597
+ display: flex;
598
+ align-items: center;
599
+ gap: 12px;
600
+ width: 100%;
601
+
602
+ .el-input {
603
+ flex: 1;
604
+ min-width: 0;
605
+ }
606
+ }
607
+ .captcha-image {
608
+ flex: 0 0 auto;
609
+ height: 40px;
610
+ cursor: pointer;
611
+ object-fit: contain;
612
+ border-radius: 6px;
613
+ }
614
+ .behavior-captcha-body {
615
+ min-height: 0;
616
+ display: flex;
617
+ align-items: center;
618
+ justify-content: center;
619
+ }
620
+
621
+ .oauth-login {
622
+ margin-top: 22px;
623
+ }
624
+
625
+ .oauth-divider {
626
+ display: flex;
627
+ align-items: center;
628
+ gap: 12px;
629
+ margin-bottom: 12px;
630
+ font-size: 14px;
631
+ font-weight: 700;
632
+ line-height: 1.2;
633
+ color: var(--el-text-color-primary);
634
+ white-space: nowrap;
635
+
636
+ &::before,
637
+ &::after {
638
+ flex: 1;
639
+ height: 1px;
640
+ content: "";
641
+ background-color: var(--el-border-color-lighter);
642
+ }
643
+ }
644
+
645
+ .oauth-provider-list {
646
+ display: flex;
647
+ flex-wrap: nowrap;
648
+ align-items: center;
649
+ justify-content: flex-start;
650
+ gap: 6px;
651
+ padding-bottom: 4px;
652
+ overflow-x: auto;
653
+ overflow-y: hidden;
654
+ scrollbar-width: thin;
655
+ }
656
+
657
+ .oauth-provider-button {
658
+ display: inline-flex;
659
+ flex: 0 0 36px;
660
+ align-items: center;
661
+ justify-content: center;
662
+ width: 36px;
663
+ height: 36px;
664
+ padding: 0;
665
+ cursor: pointer;
666
+ background: transparent;
667
+ border: 0;
668
+ border-radius: 50%;
669
+ transition:
670
+ color 0.2s ease,
671
+ transform 0.2s ease,
672
+ background-color 0.2s ease;
673
+
674
+ &:hover:not(:disabled) {
675
+ background-color: var(--el-fill-color-light);
676
+ transform: translateY(-1px);
677
+ }
678
+
679
+ &:disabled {
680
+ cursor: not-allowed;
681
+ opacity: 0.55;
682
+ }
683
+
684
+ svg,
685
+ img {
686
+ width: 26px;
687
+ height: 26px;
688
+ object-fit: contain;
689
+ }
690
+ }
691
+
692
+ .oauth-provider-fallback {
693
+ display: inline-flex;
694
+ align-items: center;
695
+ justify-content: center;
696
+ width: 26px;
697
+ height: 26px;
698
+ font-size: 14px;
699
+ font-weight: 700;
700
+ line-height: 1;
701
+ color: var(--el-color-primary);
702
+ }
703
+
704
+ :global(.behavior-captcha-dialog) {
705
+ --go-captcha-theme-text-color: var(--el-text-color-primary);
706
+ --go-captcha-theme-bg-color: var(--el-bg-color);
707
+ --go-captcha-theme-btn-bg-color: var(--el-color-primary);
708
+ --go-captcha-theme-btn-border-color: var(--el-color-primary);
709
+ --go-captcha-theme-btn-disabled-color: var(--el-color-primary-light-5);
710
+ --go-captcha-theme-active-color: var(--el-color-primary);
711
+ --go-captcha-theme-border-color: var(--el-border-color-light);
712
+ --go-captcha-theme-icon-color: var(--el-text-color-regular);
713
+ --go-captcha-theme-drag-bar-color: var(--el-fill-color);
714
+ --go-captcha-theme-drag-bg-color: var(--el-color-primary);
715
+ --go-captcha-theme-drag-icon-color: #ffffff;
716
+ --go-captcha-theme-round-color: var(--el-fill-color);
717
+ --go-captcha-theme-loading-icon-color: var(--el-color-primary);
718
+ --go-captcha-theme-body-bg-color: var(--el-fill-color-light);
719
+ --go-captcha-theme-dot-color-color: #ffffff;
720
+ --go-captcha-theme-dot-bg-color: color-mix(in srgb, var(--el-color-primary) 68%, transparent);
721
+ --go-captcha-theme-dot-border-color: var(--el-bg-color);
722
+ border-radius: 10px;
723
+ box-shadow: rgb(0 0 0 / 10%) 0 2px 10px 2px;
724
+ }
725
+
726
+ :global(.behavior-captcha-dialog .el-dialog__header) {
727
+ display: none;
728
+ }
729
+
730
+ :global(.behavior-captcha-dialog .el-dialog__body) {
731
+ padding: 10px 12px 12px;
732
+ }
733
+
734
+ :global(.behavior-captcha-dialog .go-captcha .gc-header) {
735
+ height: auto;
736
+ min-height: 24px;
737
+ margin-bottom: 6px;
738
+ }
739
+
740
+ :global(.behavior-captcha-dialog .go-captcha .gc-header span),
741
+ :global(.behavior-captcha-dialog .go-captcha .gc-header .gc-text) {
742
+ font-size: 14px;
743
+ line-height: 22px;
744
+ white-space: nowrap;
745
+ }
746
+
747
+ :global(.behavior-captcha-dialog .go-captcha .gc-body) {
748
+ margin-top: 0;
749
+ border-radius: 6px;
750
+ }
751
+
752
+ :global(.behavior-captcha-dialog .go-captcha .gc-footer) {
753
+ height: 38px;
754
+ padding-top: 8px;
755
+ }
756
+
757
+ :global(.behavior-captcha-dialog .go-captcha .gc-drag-line) {
758
+ height: 12px;
759
+ margin-top: -6px;
760
+ border-radius: 999px;
761
+ }
762
+
763
+ :global(.behavior-captcha-dialog .go-captcha .gc-drag-block) {
764
+ background: linear-gradient(135deg, var(--el-color-primary-light-3) 0%, var(--el-color-primary) 100%);
765
+ box-shadow: 0 8px 18px color-mix(in srgb, var(--el-color-primary) 28%, transparent);
766
+ }
767
+
768
+ :global(.behavior-captcha-dialog .go-captcha .gc-drag-block.disabled) {
769
+ background: var(--el-color-primary-light-5);
770
+ box-shadow: none;
771
+ }
772
+
773
+ :global(.behavior-captcha-dialog .go-captcha .gc-rotate-picture .gc-round) {
774
+ border-width: 4px;
775
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--el-bg-color) 80%, transparent);
776
+ }
777
+
778
+ :global(.behavior-captcha-dialog .go-captcha .gc-rotate-thumb-block) {
779
+ overflow: hidden;
780
+ border: 2px solid var(--el-bg-color);
781
+ border-radius: 50%;
782
+ box-shadow:
783
+ 0 8px 18px rgb(0 0 0 / 18%),
784
+ 0 0 0 1px color-mix(in srgb, var(--el-border-color) 80%, transparent);
785
+ }
786
+
787
+ :global(.behavior-captcha-dialog .go-captcha .gc-rotate-thumb-block img) {
788
+ border-radius: 50%;
789
+ }
790
+
791
+ :global(.behavior-captcha-dialog .go-captcha .gc-dots .gc-dot) {
792
+ font-size: 12px;
793
+ font-weight: 600;
794
+ border-width: 2px;
795
+ box-shadow: 0 3px 9px rgb(0 0 0 / 16%);
796
+ }
797
+ </style>