fdb2 1.0.12 → 1.0.14

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 (313) hide show
  1. package/README.md +9 -2
  2. package/bin/docker/.env +4 -0
  3. package/package.json +19 -9
  4. package/public/favicon.ico +0 -0
  5. package/public/favicon.png +0 -0
  6. package/view/modules/header.tpl +1 -1
  7. package/.dockerignore +0 -21
  8. package/.editorconfig +0 -11
  9. package/.eslintrc.cjs +0 -14
  10. package/.eslintrc.json +0 -7
  11. package/.prettierrc.js +0 -3
  12. package/.tpl.env +0 -22
  13. package/.vscodeignore +0 -45
  14. package/dist/package.json +0 -115
  15. package/dist/pnpm-lock.yaml +0 -8135
  16. package/dist/public/.vite/manifest.json +0 -82
  17. package/dist/public/bootstrap-icons.woff +0 -0
  18. package/dist/public/bootstrap-icons.woff2 +0 -0
  19. package/dist/public/bootstrap.css +0 -14152
  20. package/dist/public/bootstrap.js +0 -5038
  21. package/dist/public/explorer.css +0 -2379
  22. package/dist/public/explorer.js +0 -50586
  23. package/dist/public/index.css +0 -1099
  24. package/dist/public/index.js +0 -12862
  25. package/dist/public/layout.css +0 -318
  26. package/dist/public/layout.js +0 -25
  27. package/dist/public/vue.css +0 -1
  28. package/dist/public/vue.js +0 -9110
  29. package/dist/scripts/preinstall.js +0 -112
  30. package/dist/server/index.d.ts +0 -2
  31. package/dist/server/index.d.ts.map +0 -1
  32. package/dist/server/index.js +0 -601
  33. package/dist/server/index.js.map +0 -1
  34. package/dist/server/index.ts +0 -681
  35. package/dist/server/model/connection.entity.d.ts +0 -55
  36. package/dist/server/model/connection.entity.d.ts.map +0 -1
  37. package/dist/server/model/connection.entity.js +0 -59
  38. package/dist/server/model/connection.entity.js.map +0 -1
  39. package/dist/server/model/connection.entity.ts +0 -66
  40. package/dist/server/model/database.entity.d.ts +0 -203
  41. package/dist/server/model/database.entity.d.ts.map +0 -1
  42. package/dist/server/model/database.entity.js +0 -211
  43. package/dist/server/model/database.entity.js.map +0 -1
  44. package/dist/server/model/database.entity.ts +0 -246
  45. package/dist/server/service/connection.service.d.ts +0 -84
  46. package/dist/server/service/connection.service.d.ts.map +0 -1
  47. package/dist/server/service/connection.service.js +0 -369
  48. package/dist/server/service/connection.service.js.map +0 -1
  49. package/dist/server/service/connection.service.ts +0 -359
  50. package/dist/server/service/database/base.service.d.ts +0 -183
  51. package/dist/server/service/database/base.service.d.ts.map +0 -1
  52. package/dist/server/service/database/base.service.js +0 -253
  53. package/dist/server/service/database/base.service.js.map +0 -1
  54. package/dist/server/service/database/base.service.ts +0 -407
  55. package/dist/server/service/database/cockroachdb.service.d.ts +0 -116
  56. package/dist/server/service/database/cockroachdb.service.d.ts.map +0 -1
  57. package/dist/server/service/database/cockroachdb.service.js +0 -812
  58. package/dist/server/service/database/cockroachdb.service.js.map +0 -1
  59. package/dist/server/service/database/cockroachdb.service.ts +0 -871
  60. package/dist/server/service/database/database.service.d.ts +0 -495
  61. package/dist/server/service/database/database.service.d.ts.map +0 -1
  62. package/dist/server/service/database/database.service.js +0 -711
  63. package/dist/server/service/database/database.service.js.map +0 -1
  64. package/dist/server/service/database/database.service.ts +0 -776
  65. package/dist/server/service/database/index.d.ts +0 -8
  66. package/dist/server/service/database/index.d.ts.map +0 -1
  67. package/dist/server/service/database/index.js +0 -18
  68. package/dist/server/service/database/index.js.map +0 -1
  69. package/dist/server/service/database/index.ts +0 -7
  70. package/dist/server/service/database/mongodb.service.d.ts +0 -121
  71. package/dist/server/service/database/mongodb.service.d.ts.map +0 -1
  72. package/dist/server/service/database/mongodb.service.js +0 -502
  73. package/dist/server/service/database/mongodb.service.js.map +0 -1
  74. package/dist/server/service/database/mongodb.service.ts +0 -501
  75. package/dist/server/service/database/mssql.service.d.ts +0 -118
  76. package/dist/server/service/database/mssql.service.d.ts.map +0 -1
  77. package/dist/server/service/database/mssql.service.js +0 -871
  78. package/dist/server/service/database/mssql.service.js.map +0 -1
  79. package/dist/server/service/database/mssql.service.ts +0 -932
  80. package/dist/server/service/database/mysql.service.d.ts +0 -114
  81. package/dist/server/service/database/mysql.service.d.ts.map +0 -1
  82. package/dist/server/service/database/mysql.service.js +0 -960
  83. package/dist/server/service/database/mysql.service.js.map +0 -1
  84. package/dist/server/service/database/mysql.service.ts +0 -1026
  85. package/dist/server/service/database/oracle.service.d.ts +0 -126
  86. package/dist/server/service/database/oracle.service.d.ts.map +0 -1
  87. package/dist/server/service/database/oracle.service.js +0 -963
  88. package/dist/server/service/database/oracle.service.js.map +0 -1
  89. package/dist/server/service/database/oracle.service.ts +0 -1036
  90. package/dist/server/service/database/postgres.service.d.ts +0 -122
  91. package/dist/server/service/database/postgres.service.d.ts.map +0 -1
  92. package/dist/server/service/database/postgres.service.js +0 -882
  93. package/dist/server/service/database/postgres.service.js.map +0 -1
  94. package/dist/server/service/database/postgres.service.ts +0 -961
  95. package/dist/server/service/database/sap.service.d.ts +0 -115
  96. package/dist/server/service/database/sap.service.d.ts.map +0 -1
  97. package/dist/server/service/database/sap.service.js +0 -868
  98. package/dist/server/service/database/sap.service.js.map +0 -1
  99. package/dist/server/service/database/sap.service.ts +0 -922
  100. package/dist/server/service/database/sqlite.service.d.ts +0 -113
  101. package/dist/server/service/database/sqlite.service.d.ts.map +0 -1
  102. package/dist/server/service/database/sqlite.service.js +0 -724
  103. package/dist/server/service/database/sqlite.service.js.map +0 -1
  104. package/dist/server/service/database/sqlite.service.ts +0 -788
  105. package/dist/server/service/session.service.ts +0 -158
  106. package/dist/view/index.html +0 -45
  107. package/env.d.ts +0 -1
  108. package/packages/vscode/.vscodeignore +0 -44
  109. package/packages/vscode/README.md +0 -62
  110. package/packages/vscode/out/database-services/base.service.js +0 -236
  111. package/packages/vscode/out/database-services/base.service.js.map +0 -1
  112. package/packages/vscode/out/database-services/cockroachdb.service.js +0 -634
  113. package/packages/vscode/out/database-services/cockroachdb.service.js.map +0 -1
  114. package/packages/vscode/out/database-services/connection.service.js +0 -346
  115. package/packages/vscode/out/database-services/connection.service.js.map +0 -1
  116. package/packages/vscode/out/database-services/database.service.js +0 -571
  117. package/packages/vscode/out/database-services/database.service.js.map +0 -1
  118. package/packages/vscode/out/database-services/index.js +0 -18
  119. package/packages/vscode/out/database-services/index.js.map +0 -1
  120. package/packages/vscode/out/database-services/model/connection.entity.js +0 -11
  121. package/packages/vscode/out/database-services/model/connection.entity.js.map +0 -1
  122. package/packages/vscode/out/database-services/model/database.entity.js +0 -35
  123. package/packages/vscode/out/database-services/model/database.entity.js.map +0 -1
  124. package/packages/vscode/out/database-services/mongodb.service.js +0 -458
  125. package/packages/vscode/out/database-services/mongodb.service.js.map +0 -1
  126. package/packages/vscode/out/database-services/mssql.service.js +0 -694
  127. package/packages/vscode/out/database-services/mssql.service.js.map +0 -1
  128. package/packages/vscode/out/database-services/mysql.service.js +0 -735
  129. package/packages/vscode/out/database-services/mysql.service.js.map +0 -1
  130. package/packages/vscode/out/database-services/oracle.service.js +0 -787
  131. package/packages/vscode/out/database-services/oracle.service.js.map +0 -1
  132. package/packages/vscode/out/database-services/postgres.service.js +0 -696
  133. package/packages/vscode/out/database-services/postgres.service.js.map +0 -1
  134. package/packages/vscode/out/database-services/sap.service.js +0 -695
  135. package/packages/vscode/out/database-services/sap.service.js.map +0 -1
  136. package/packages/vscode/out/database-services/sqlite.service.js +0 -532
  137. package/packages/vscode/out/database-services/sqlite.service.js.map +0 -1
  138. package/packages/vscode/out/extension.js +0 -93
  139. package/packages/vscode/out/extension.js.map +0 -1
  140. package/packages/vscode/out/provider/DatabaseTreeProvider.js +0 -159
  141. package/packages/vscode/out/provider/DatabaseTreeProvider.js.map +0 -1
  142. package/packages/vscode/out/provider/WebViewProvider.js +0 -259
  143. package/packages/vscode/out/provider/WebViewProvider.js.map +0 -1
  144. package/packages/vscode/out/service/ConnectionManager.js +0 -105
  145. package/packages/vscode/out/service/ConnectionManager.js.map +0 -1
  146. package/packages/vscode/out/service/DatabaseServiceBridge.js +0 -395
  147. package/packages/vscode/out/service/DatabaseServiceBridge.js.map +0 -1
  148. package/packages/vscode/out/typings/connection.js +0 -3
  149. package/packages/vscode/out/typings/connection.js.map +0 -1
  150. package/packages/vscode/package.json +0 -142
  151. package/packages/vscode/resources/icon.svg +0 -5
  152. package/packages/vscode/resources/webview/_plugin-vue_export-helper.js +0 -6529
  153. package/packages/vscode/resources/webview/_plugin-vue_export-helper.js.map +0 -1
  154. package/packages/vscode/resources/webview/connection.css +0 -69
  155. package/packages/vscode/resources/webview/connection.js +0 -228
  156. package/packages/vscode/resources/webview/connection.js.map +0 -1
  157. package/packages/vscode/resources/webview/database.css +0 -259
  158. package/packages/vscode/resources/webview/database.js +0 -275
  159. package/packages/vscode/resources/webview/database.js.map +0 -1
  160. package/packages/vscode/resources/webview/favicon.ico +0 -0
  161. package/packages/vscode/resources/webview/index.html +0 -9
  162. package/packages/vscode/resources/webview/modules/header.tpl +0 -14
  163. package/packages/vscode/resources/webview/modules/initial_state.tpl +0 -55
  164. package/packages/vscode/resources/webview/query.css +0 -162
  165. package/packages/vscode/resources/webview/query.js +0 -198
  166. package/packages/vscode/resources/webview/query.js.map +0 -1
  167. package/packages/vscode/src/database-services/base.service.js.map +0 -1
  168. package/packages/vscode/src/database-services/base.service.ts +0 -363
  169. package/packages/vscode/src/database-services/cockroachdb.service.js.map +0 -1
  170. package/packages/vscode/src/database-services/cockroachdb.service.ts +0 -659
  171. package/packages/vscode/src/database-services/connection.service.ts +0 -341
  172. package/packages/vscode/src/database-services/database.service.ts +0 -630
  173. package/packages/vscode/src/database-services/index.ts +0 -7
  174. package/packages/vscode/src/database-services/model/connection.entity.js +0 -11
  175. package/packages/vscode/src/database-services/model/connection.entity.js.map +0 -1
  176. package/packages/vscode/src/database-services/model/connection.entity.ts +0 -66
  177. package/packages/vscode/src/database-services/model/database.entity.js +0 -35
  178. package/packages/vscode/src/database-services/model/database.entity.js.map +0 -1
  179. package/packages/vscode/src/database-services/model/database.entity.ts +0 -246
  180. package/packages/vscode/src/database-services/mongodb.service.js.map +0 -1
  181. package/packages/vscode/src/database-services/mongodb.service.ts +0 -454
  182. package/packages/vscode/src/database-services/mssql.service.js.map +0 -1
  183. package/packages/vscode/src/database-services/mssql.service.ts +0 -723
  184. package/packages/vscode/src/database-services/mysql.service.js.map +0 -1
  185. package/packages/vscode/src/database-services/mysql.service.ts +0 -761
  186. package/packages/vscode/src/database-services/oracle.service.js.map +0 -1
  187. package/packages/vscode/src/database-services/oracle.service.ts +0 -832
  188. package/packages/vscode/src/database-services/postgres.service.js.map +0 -1
  189. package/packages/vscode/src/database-services/postgres.service.ts +0 -741
  190. package/packages/vscode/src/database-services/sap.service.js.map +0 -1
  191. package/packages/vscode/src/database-services/sap.service.ts +0 -713
  192. package/packages/vscode/src/database-services/sqlite.service.js.map +0 -1
  193. package/packages/vscode/src/database-services/sqlite.service.ts +0 -559
  194. package/packages/vscode/src/extension.ts +0 -76
  195. package/packages/vscode/src/provider/DatabaseTreeProvider.ts +0 -167
  196. package/packages/vscode/src/provider/WebViewProvider.ts +0 -277
  197. package/packages/vscode/src/service/DatabaseServiceBridge.ts +0 -414
  198. package/packages/vscode/src/typings/connection.ts +0 -90
  199. package/packages/vscode/tsconfig.json +0 -21
  200. package/scripts/preinstall.js +0 -112
  201. package/server/index.ts +0 -681
  202. package/server/model/connection.entity.js +0 -11
  203. package/server/model/connection.entity.js.map +0 -1
  204. package/server/model/connection.entity.ts +0 -66
  205. package/server/model/database.entity.js +0 -35
  206. package/server/model/database.entity.js.map +0 -1
  207. package/server/model/database.entity.ts +0 -246
  208. package/server/service/connection.service.ts +0 -359
  209. package/server/service/database/base.service.ts +0 -407
  210. package/server/service/database/cockroachdb.service.ts +0 -871
  211. package/server/service/database/database.service.ts +0 -776
  212. package/server/service/database/index.ts +0 -7
  213. package/server/service/database/mongodb.service.ts +0 -501
  214. package/server/service/database/mssql.service.ts +0 -932
  215. package/server/service/database/mysql.service.ts +0 -1026
  216. package/server/service/database/oracle.service.ts +0 -1036
  217. package/server/service/database/postgres.service.ts +0 -961
  218. package/server/service/database/sap.service.ts +0 -922
  219. package/server/service/database/sqlite.service.ts +0 -788
  220. package/server/service/session.service.ts +0 -158
  221. package/server/tsconfig.json +0 -20
  222. package/src/adapter/ajax.ts +0 -135
  223. package/src/assets/base.css +0 -1
  224. package/src/assets/database.css +0 -950
  225. package/src/assets/images/collapse.png +0 -0
  226. package/src/assets/images/no-login.png +0 -0
  227. package/src/assets/images/svg/illustrations/illustration-1.svg +0 -1
  228. package/src/assets/images/svg/illustrations/illustration-2.svg +0 -2
  229. package/src/assets/images/svg/illustrations/illustration-3.svg +0 -50
  230. package/src/assets/images/svg/illustrations/illustration-4.svg +0 -1
  231. package/src/assets/images/svg/illustrations/illustration-5.svg +0 -73
  232. package/src/assets/images/svg/illustrations/illustration-6.svg +0 -89
  233. package/src/assets/images/svg/illustrations/illustration-7.svg +0 -39
  234. package/src/assets/images/svg/illustrations/illustration-8.svg +0 -1
  235. package/src/assets/images/svg/separators/curve-2.svg +0 -3
  236. package/src/assets/images/svg/separators/curve.svg +0 -3
  237. package/src/assets/images/svg/separators/line.svg +0 -3
  238. package/src/assets/images/theme/light/screen-1-1000x800.jpg +0 -0
  239. package/src/assets/images/theme/light/screen-2-1000x800.jpg +0 -0
  240. package/src/assets/login/bg.jpg +0 -0
  241. package/src/assets/login/bg.png +0 -0
  242. package/src/assets/login/left.jpg +0 -0
  243. package/src/assets/logo.svg +0 -73
  244. package/src/assets/logo.webp +0 -0
  245. package/src/assets/main.css +0 -1
  246. package/src/base/config.ts +0 -20
  247. package/src/base/detect.ts +0 -134
  248. package/src/base/entity.ts +0 -92
  249. package/src/base/eventBus.ts +0 -37
  250. package/src/components/connection-editor/index.vue +0 -589
  251. package/src/components/dataGrid/index.vue +0 -163
  252. package/src/components/dataGrid/pagination.vue +0 -106
  253. package/src/components/loading/index.vue +0 -43
  254. package/src/components/modal/index.ts +0 -181
  255. package/src/components/modal/index.vue +0 -560
  256. package/src/components/toast/index.ts +0 -44
  257. package/src/components/toast/toast.vue +0 -58
  258. package/src/components/user/name.vue +0 -104
  259. package/src/components/user/selector.vue +0 -416
  260. package/src/domain/SysConfig.ts +0 -74
  261. package/src/platform/App.vue +0 -8
  262. package/src/platform/database/components/connection-detail.vue +0 -1153
  263. package/src/platform/database/components/data-editor.vue +0 -478
  264. package/src/platform/database/components/data-import-export.vue +0 -1602
  265. package/src/platform/database/components/database-detail.vue +0 -1199
  266. package/src/platform/database/components/database-monitor.vue +0 -1086
  267. package/src/platform/database/components/db-tools.vue +0 -1265
  268. package/src/platform/database/components/query-history.vue +0 -1349
  269. package/src/platform/database/components/sql-executor.vue +0 -738
  270. package/src/platform/database/components/sql-query-editor.vue +0 -1046
  271. package/src/platform/database/components/table-data-grid.vue +0 -273
  272. package/src/platform/database/components/table-detail.vue +0 -1173
  273. package/src/platform/database/components/table-editor.vue +0 -917
  274. package/src/platform/database/explorer.vue +0 -1840
  275. package/src/platform/database/index.vue +0 -1193
  276. package/src/platform/database/layout.vue +0 -367
  277. package/src/platform/database/router.ts +0 -37
  278. package/src/platform/database/styles/common.scss +0 -602
  279. package/src/platform/database/types/common.ts +0 -445
  280. package/src/platform/database/utils/export.ts +0 -232
  281. package/src/platform/database/utils/helpers.ts +0 -437
  282. package/src/platform/index.ts +0 -33
  283. package/src/platform/router.ts +0 -41
  284. package/src/platform/vscode/bridge.ts +0 -121
  285. package/src/platform/vscode/components/ConnectionPanel.vue +0 -272
  286. package/src/platform/vscode/components/DatabasePanel.vue +0 -532
  287. package/src/platform/vscode/components/QueryPanel.vue +0 -371
  288. package/src/platform/vscode/entry/connection.ts +0 -13
  289. package/src/platform/vscode/entry/database.ts +0 -13
  290. package/src/platform/vscode/entry/query.ts +0 -13
  291. package/src/platform/vscode/index.ts +0 -5
  292. package/src/service/base.ts +0 -134
  293. package/src/service/database.ts +0 -506
  294. package/src/service/login.ts +0 -121
  295. package/src/shims-vue.d.ts +0 -7
  296. package/src/stores/connection.ts +0 -266
  297. package/src/stores/session.ts +0 -87
  298. package/src/typings/database-types.ts +0 -413
  299. package/src/typings/database.ts +0 -364
  300. package/src/typings/global.d.ts +0 -58
  301. package/src/typings/pinia.d.ts +0 -8
  302. package/src/utils/clipboard.ts +0 -30
  303. package/src/utils/database-types.ts +0 -243
  304. package/src/utils/modal.ts +0 -124
  305. package/src/utils/request.ts +0 -55
  306. package/src/utils/sleep.ts +0 -4
  307. package/src/utils/toast.ts +0 -73
  308. package/src/utils/util.ts +0 -171
  309. package/src/utils/xlsx.ts +0 -228
  310. package/tsconfig.json +0 -33
  311. package/tsconfig.server.json +0 -19
  312. package/vite.config.ts +0 -424
  313. package/vite.config.vscode.ts +0 -47
@@ -1,1173 +0,0 @@
1
- <template>
2
- <div class="table-detail">
3
- <!-- 表头部信息 -->
4
- <div class="table-header">
5
- <div class="table-header-content">
6
- <div class="table-info">
7
- <div class="table-icon">
8
- <i class="bi bi-table"></i>
9
- </div>
10
- <div class="table-meta">
11
- <h4 class="table-name">{{ table?.name }}</h4>
12
- <div class="table-breadcrumb">
13
- <span class="connection">{{ connection?.name }}</span>
14
- <i class="bi bi-chevron-right"></i>
15
- <span class="database">{{ database }}</span>
16
- <i class="bi bi-chevron-right"></i>
17
- <span class="table">{{ table?.name }}</span>
18
- </div>
19
- </div>
20
- </div>
21
- <div class="table-stats">
22
- <div class="stat-item" v-if="table?.rowCount !== undefined">
23
- <div class="stat-value">{{ formatNumber(table?.rowCount) }}</div>
24
- <div class="stat-label">行数据</div>
25
- </div>
26
- <div class="stat-item">
27
- <div class="stat-value">{{ tableStructure?.columns?.length || 0 }}</div>
28
- <div class="stat-label">列</div>
29
- </div>
30
- <div class="stat-item">
31
- <div class="stat-value">{{ tableStructure?.indexes?.length || 0 }}</div>
32
- <div class="stat-label">索引</div>
33
- </div>
34
- <div class="stat-item" v-if="table?.dataSize !== undefined">
35
- <div class="stat-value">{{ formatSize(table?.dataSize) }}</div>
36
- <div class="stat-label">大小</div>
37
- </div>
38
- </div>
39
- </div>
40
- </div>
41
-
42
- <!-- 操作工具栏 -->
43
- <div class="table-toolbar">
44
- <div class="toolbar-left">
45
- <button class="btn btn-primary btn-sm" @click="refreshData">
46
- <i class="bi bi-arrow-clockwise"></i> 刷新数据
47
- </button>
48
- <button class="btn btn-info btn-sm" @click="editTableStructure">
49
- <i class="bi bi-pencil-square"></i> 修改表结构
50
- </button>
51
- <button class="btn btn-success btn-sm" @click="()=>insertData()">
52
- <i class="bi bi-plus-lg"></i> 插入数据
53
- </button>
54
- <div class="btn-group">
55
- <button class="btn btn-info btn-sm dropdown-toggle" data-bs-toggle="dropdown">
56
- <i class="bi bi-download"></i> 导出
57
- </button>
58
- <ul class="dropdown-menu">
59
- <li><button class="dropdown-item" @click="exportTableData('csv')">
60
- <i class="bi bi-file-earmark-spreadsheet me-2"></i>导出 CSV
61
- </button></li>
62
- <li><button class="dropdown-item" @click="exportTableData('json')">
63
- <i class="bi bi-file-earmark-code me-2"></i>导出 JSON
64
- </button></li>
65
- <li><button class="dropdown-item" @click="exportTableData('excel')">
66
- <i class="bi bi-file-earmark-excel me-2"></i>导出 Excel
67
- </button></li>
68
- <li><hr class="dropdown-divider"></li>
69
- <li><button class="dropdown-item" @click="exportTableStructure()">
70
- <i class="bi bi-file-earmark-text me-2"></i>导出表结构
71
- </button></li>
72
- <li><button class="dropdown-item" @click="exportTableDataSQL()">
73
- <i class="bi bi-file-earmark-code me-2"></i>导出表数据(SQL)
74
- </button></li>
75
- </ul>
76
- </div>
77
- </div>
78
- <div class="toolbar-right">
79
- <button class="btn btn-outline-warning btn-sm" @click="truncateTable" v-if="table?.rowCount">
80
- <i class="bi bi-trash"></i> 清空表
81
- </button>
82
- <button class="btn btn-outline-danger btn-sm" @click="dropTable">
83
- <i class="bi bi-x-circle"></i> 删除表
84
- </button>
85
- </div>
86
- </div>
87
-
88
- <!-- 标签页 -->
89
- <div class="table-tabs">
90
- <ul class="nav nav-tabs">
91
- <li class="nav-item">
92
- <button
93
- class="nav-link"
94
- :class="{ active: activeTab === 'data' }"
95
- @click="activeTab = 'data'"
96
- >
97
- <i class="bi bi-grid"></i> 数据
98
- <span class="badge bg-secondary ms-2" v-if="table?.rowCount">{{ formatNumber(table?.rowCount) }}</span>
99
- </button>
100
- </li>
101
- <li class="nav-item">
102
- <button
103
- class="nav-link"
104
- :class="{ active: activeTab === 'structure' }"
105
- @click="activeTab = 'structure'"
106
- >
107
- <i class="bi bi-diagram-3"></i> 结构
108
- </button>
109
- </li>
110
- <li class="nav-item">
111
- <button
112
- class="nav-link"
113
- :class="{ active: activeTab === 'indexes' }"
114
- @click="activeTab = 'indexes'"
115
- >
116
- <i class="bi bi-key"></i> 索引
117
- </button>
118
- </li>
119
- <li class="nav-item">
120
- <button
121
- class="nav-link"
122
- :class="{ active: activeTab === 'relations' }"
123
- @click="activeTab = 'relations'"
124
- >
125
- <i class="bi bi-link-45deg"></i> 关系
126
- </button>
127
- </li>
128
- <li class="nav-item">
129
- <button
130
- class="nav-link"
131
- :class="{ active: activeTab === 'sql' }"
132
- @click="activeTab = 'sql'"
133
- >
134
- <i class="bi bi-code-slash"></i> SQL
135
- </button>
136
- </li>
137
- </ul>
138
-
139
- <div class="tab-content">
140
- <!-- 数据标签页 -->
141
- <div v-show="activeTab === 'data'" class="tab-panel">
142
- <TableDataGrid
143
- ref="tableDataGridRef"
144
- :connection="connection"
145
- :database="database"
146
- :table="table"
147
- :columns="tableStructure?.columns || []"
148
- @edit-row="editRow"
149
- @delete-row="deleteRow"
150
- />
151
- </div>
152
-
153
- <!-- 结构标签页 -->
154
- <div v-show="activeTab === 'structure'" class="tab-panel">
155
- <div class="structure-actions mb-3">
156
- <button class="btn btn-success btn-sm" @click="addColumn">
157
- <i class="bi bi-plus-lg"></i> 新增字段
158
- </button>
159
- <button class="btn btn-info btn-sm" @click="editTableStructure">
160
- <i class="bi bi-pencil-square"></i> 修改表结构
161
- </button>
162
- </div>
163
-
164
- <div class="structure-content">
165
- <div class="structure-table">
166
- <table class="table table-bordered">
167
- <thead class="table-dark">
168
- <tr>
169
- <th>列名</th>
170
- <th>数据类型</th>
171
- <th>可空</th>
172
- <th>默认值</th>
173
- <th>主键</th>
174
- <th>自增</th>
175
- <th>注释</th>
176
- <th width="100">操作</th>
177
- </tr>
178
- </thead>
179
- <tbody>
180
- <tr v-for="column in tableStructure?.columns || []" :key="column.name">
181
- <td><strong>{{ column.name }}</strong></td>
182
- <td><code>{{ column.type }}</code></td>
183
- <td>
184
- <span :class="column.nullable ? 'text-warning' : 'text-success'">
185
- <i :class="column.nullable ? 'bi bi-unlock' : 'bi bi-lock-fill'"></i>
186
- {{ column.nullable ? 'YES' : 'NO' }}
187
- </span>
188
- </td>
189
- <td>{{ column.defaultValue || '-' }}</td>
190
- <td>
191
- <span v-if="column.isPrimary" class="badge bg-primary">
192
- <i class="bi bi-key-fill"></i> 主键
193
- </span>
194
- <span v-else>-</span>
195
- </td>
196
- <td>
197
- <span v-if="column.isAutoIncrement" class="badge bg-success">
198
- <i class="bi bi-arrow-up-circle"></i> 自增
199
- </span>
200
- <span v-else>-</span>
201
- </td>
202
- <td>{{ column.comment || '-' }}</td>
203
- <td>
204
- <div class="btn-group btn-group-sm">
205
- <button class="btn btn-outline-primary btn-sm" @click="editColumn(column)">
206
- <i class="bi bi-pencil"></i>
207
- </button>
208
- <button class="btn btn-outline-danger btn-sm" @click="deleteColumn(column)">
209
- <i class="bi bi-trash"></i>
210
- </button>
211
- </div>
212
- </td>
213
- </tr>
214
- </tbody>
215
- </table>
216
- </div>
217
- </div>
218
- </div>
219
-
220
- <!-- 索引标签页 -->
221
- <div v-show="activeTab === 'indexes'" class="tab-panel">
222
- <div class="indexes-content">
223
- <div class="indexes-table">
224
- <table class="table table-bordered">
225
- <thead class="table-dark">
226
- <tr>
227
- <th>索引名</th>
228
- <th>类型</th>
229
- <th>唯一</th>
230
- <th>列</th>
231
- <th width="100">操作</th>
232
- </tr>
233
- </thead>
234
- <tbody>
235
- <tr v-for="index in tableStructure?.indexes || []" :key="index.name">
236
- <td><strong>{{ index.name }}</strong></td>
237
- <td><span class="badge bg-info">{{ index.type }}</span></td>
238
- <td>
239
- <span :class="index.unique ? 'text-success' : 'text-secondary'">
240
- <i :class="index.unique ? 'bi bi-check-circle-fill' : 'bi bi-circle'"></i>
241
- {{ index.unique ? '是' : '否' }}
242
- </span>
243
- </td>
244
- <td><code>{{ index.columns.join(', ') }}</code></td>
245
- <td>
246
- <div class="btn-group btn-group-sm">
247
- <button class="btn btn-outline-primary btn-sm" @click="editIndex(index)">
248
- <i class="bi bi-pencil"></i>
249
- </button>
250
- <button class="btn btn-outline-danger btn-sm" @click="deleteIndex(index)">
251
- <i class="bi bi-trash"></i>
252
- </button>
253
- </div>
254
- </td>
255
- </tr>
256
- </tbody>
257
- </table>
258
- </div>
259
- </div>
260
- </div>
261
-
262
- <!-- 关系标签页 -->
263
- <div v-show="activeTab === 'relations'" class="tab-panel">
264
- <div class="relations-content">
265
- <div class="relations-table">
266
- <table class="table table-bordered">
267
- <thead class="table-dark">
268
- <tr>
269
- <th>约束名</th>
270
- <th>本表列</th>
271
- <th>目标表</th>
272
- <th>目标列</th>
273
- <th>删除规则</th>
274
- <th>更新规则</th>
275
- <th width="100">操作</th>
276
- </tr>
277
- </thead>
278
- <tbody>
279
- <tr v-for="fk in tableStructure?.foreignKeys || []" :key="fk.name">
280
- <td><strong>{{ fk.name }}</strong></td>
281
- <td><code>{{ fk.column }}</code></td>
282
- <td><code>{{ fk.referencedTable }}</code></td>
283
- <td><code>{{ fk.referencedColumn }}</code></td>
284
- <td>{{ fk.onDelete || '-' }}</td>
285
- <td>{{ fk.onUpdate || '-' }}</td>
286
- <td>
287
- <div class="btn-group btn-group-sm">
288
- <button class="btn btn-outline-danger btn-sm" @click="deleteForeignKey(fk)">
289
- <i class="bi bi-trash"></i>
290
- </button>
291
- </div>
292
- </td>
293
- </tr>
294
- </tbody>
295
- </table>
296
- </div>
297
- </div>
298
- </div>
299
-
300
- <!-- SQL标签页 -->
301
- <div v-show="activeTab === 'sql'" class="tab-panel">
302
- <div class="sql-section">
303
- <SqlExecutor
304
- :connection="connection"
305
- :database="database"
306
- />
307
- </div>
308
- </div>
309
- </div>
310
- </div>
311
-
312
- <!-- 数据编辑器 -->
313
- <DataEditor
314
- :visible="showDataEditor"
315
- :is-edit="isEditMode"
316
- :data="editingRow"
317
- :columns="safeTableColumns"
318
- :connection="connection"
319
- :database="database"
320
- :table-name="table?.name"
321
- @close="closeDataEditor"
322
- @submit="handleDataSubmit"
323
- />
324
-
325
- <!-- 表格编辑器 -->
326
- <TableEditor
327
- :visible="showTableEditor"
328
- :connection="connection"
329
- :database="database"
330
- :table="table"
331
- :columns="tableStructure?.columns"
332
- :mode="tableEditorMode"
333
- @close="closeTableEditor"
334
- @submit="handleTableStructureChange"
335
- />
336
- </div>
337
- </template>
338
-
339
- <script lang="ts" setup>
340
- import { ref, computed, watch, onMounted } from 'vue';
341
- import type { ConnectionEntity, TableEntity } from '@/typings/database';
342
- import { DatabaseService } from '@/service/database';
343
- import DataEditor from './data-editor.vue';
344
-
345
- import TableDataGrid from './table-data-grid.vue';
346
- import TableEditor from './table-editor.vue';
347
- import SqlExecutor from './sql-executor.vue';
348
- import { exportDataToCSV, exportDataToJSON, exportDataToExcel, formatFileName } from '../utils/export';
349
- import { modal } from '@/utils/modal';
350
- import { isNumericType, isBooleanType } from '@/utils/database-types';
351
-
352
-
353
- // Props
354
- const props = defineProps<{
355
- connection: ConnectionEntity | null;
356
- database: string;
357
- table: TableEntity | null;
358
- tableData: any[];
359
- tableStructure: any;
360
- loading: boolean;
361
- total: number;
362
- sqlExecuting?: boolean;
363
- sqlResult?: {
364
- success: boolean;
365
- message?: string;
366
- data?: any[];
367
- columns?: string[];
368
- affectedRows?: number;
369
- insertId?: any;
370
- error?: string;
371
- };
372
- }>();
373
-
374
- // Emits
375
- const emit = defineEmits<{
376
- 'refresh-data': [page: number, pageSize: number, searchQuery?: string];
377
- 'refresh-database': [];
378
- 'refresh-structure': [];
379
- 'truncate-table': [];
380
- 'drop-table': [];
381
- 'delete-row': [row: any];
382
- 'insert-data': [];
383
- 'export-table': [];
384
- 'edit-row': [row: any];
385
- 'execute-sql': [sql: string];
386
- }>();
387
-
388
- const databaseService = new DatabaseService();
389
-
390
- // 引用
391
- const tableDataGridRef = ref();
392
-
393
- // 响应式数据
394
- const activeTab = ref('data');
395
- const sqlQuery = ref('');
396
-
397
- // 数据编辑相关
398
- const showDataEditor = ref(false);
399
- const isEditMode = ref(false);
400
- const editingRow = ref<any>(null);
401
-
402
- // 表格编辑器相关
403
- const showTableEditor = ref(false);
404
- const tableEditorMode = ref<'create' | 'edit'>('edit');
405
-
406
- // 计算属性
407
- // 类型安全的表列数据
408
- const safeTableColumns = computed(() => {
409
- const columns = props.tableStructure?.columns || [];
410
- return columns.map(col => ({
411
- ...col,
412
- name: col.name || '',
413
- type: col.type || '',
414
- nullable: !!col.nullable,
415
- isPrimary: !!col.isPrimary,
416
- isAutoIncrement: !!col.isAutoIncrement,
417
- comment: col.comment || ''
418
- }));
419
- });
420
-
421
- // 监听变化
422
- watch(() => props.table, () => {
423
- activeTab.value = 'data';
424
- });
425
-
426
- // 方法
427
- function formatSize(bytes: number): string {
428
- if (bytes === 0) return '0 B';
429
- const k = 1024;
430
- const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
431
- const i = Math.floor(Math.log(bytes) / Math.log(k));
432
- return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
433
- }
434
-
435
- function formatNumber(num: number): string {
436
- return num?.toLocaleString?.() || num?.toString() || '';
437
- }
438
-
439
- function refreshData() {
440
- if (tableDataGridRef.value) {
441
- tableDataGridRef.value.refresh();
442
- }
443
- }
444
-
445
- function insertData(newData?: any) {
446
- if (newData) {
447
- // 从编辑器来的新增数据
448
- performInsert(newData);
449
- } else {
450
- // 新增按钮点击,打开编辑器
451
- editingRow.value = null;
452
- isEditMode.value = false;
453
- showDataEditor.value = true;
454
- }
455
- }
456
-
457
- async function performInsert(data: any) {
458
- try {
459
- // 构建INSERT语句
460
- const columns = [];
461
- const values = [];
462
-
463
- safeTableColumns.value.forEach((column: any) => {
464
- if (!column.isPrimary || !column.isAutoIncrement) {
465
- columns.push(column.name);
466
- values.push(formatValueForSQL(data[column.name], column.type));
467
- }
468
- });
469
-
470
- if (columns.length === 0) {
471
- await modal.error('没有可插入的字段');
472
- return;
473
- }
474
-
475
- const sql = `INSERT INTO ${props.table?.name} (${columns.join(', ')}) VALUES (${values.join(', ')})`;
476
-
477
- // 执行SQL
478
- emit('execute-sql', sql);
479
- } catch (error) {
480
- console.error('插入数据失败:', error);
481
- modal.error('插入数据失败: ' + (error as any).message);
482
- }
483
- }
484
-
485
- async function editRow(row: any) {
486
- editingRow.value = row;
487
- isEditMode.value = true;
488
- showDataEditor.value = true;
489
- }
490
-
491
- async function deleteRow(row: any) {
492
- try {
493
- const result = await modal.confirm('确定要删除这条记录吗?', {
494
- confirmButtonText: '删除',
495
- cancelButtonText: '取消',
496
- type: 'danger'
497
- });
498
-
499
- if (result) {
500
- // 获取主键条件
501
- const primaryKeys = props.tableStructure?.columns?.filter((col: any) => col.isPrimary) || [];
502
- if (primaryKeys.length === 0) {
503
- await modal.warning('该表没有主键,无法删除单行。');
504
- return;
505
- }
506
-
507
- const where: any = {};
508
- primaryKeys.forEach((pk: any) => {
509
- where[pk.name] = row[pk.name];
510
- });
511
-
512
- const response = await databaseService.deleteData(
513
- props.connection?.id || '',
514
- props.database,
515
- props.table?.name || '',
516
- where
517
- );
518
-
519
- if (response.ret === 0) {
520
- await modal.success('删除成功');
521
- refreshData();
522
- } else {
523
- await modal.error('删除失败: ' + (response.msg || '未知错误'));
524
- }
525
- }
526
- } catch (error) {
527
- console.error('删除行失败:', error);
528
- modal.error('删除行失败: ' + (error as any).message);
529
- }
530
- }
531
-
532
- async function truncateTable() {
533
- try {
534
- const result = await modal.confirm('确定要清空表中的所有数据吗?此操作不可恢复!', {
535
- confirmButtonText: '确定清空',
536
- cancelButtonText: '取消',
537
- type: 'danger'
538
- });
539
-
540
- if (result) {
541
- const response = await databaseService.truncateTable(
542
- props.connection?.id || '',
543
- props.database,
544
- props.table?.name || ''
545
- );
546
- if (response.ret === 0) {
547
- await modal.success('表清空成功');
548
- refreshData();
549
- } else {
550
- await modal.error('清空表失败');
551
- }
552
- }
553
- } catch (error) {
554
- console.error('清空表失败:', error);
555
- }
556
- }
557
-
558
- async function dropTable() {
559
- try {
560
- const result = await modal.confirm('确定要删除此表吗?此操作不可恢复!', {
561
- confirmButtonText: '删除',
562
- cancelButtonText: '取消',
563
- type: 'danger'
564
- });
565
-
566
- if (result) {
567
- try {
568
- const response = await databaseService.dropTable(
569
- props.connection?.id || '',
570
- props.database,
571
- props.table?.name || ''
572
- );
573
-
574
- if (response.ret === 0 && response.data?.success) {
575
- await modal.success('表删除成功');
576
- // 表删除后需要返回到数据库视图,这里通过事件通知父组件
577
- emit('refresh-database');
578
- } else {
579
- await modal.error('表删除失败');
580
- }
581
- } catch (error) {
582
- console.error('删除表失败:', error);
583
- modal.error(error.msg || error.message || '删除表失败', {
584
- operation: 'DROP_TABLE',
585
- table: props.table?.name,
586
- stack: error.stack
587
- });
588
- }
589
- }
590
- } catch (error) {
591
- console.error('删除表失败:', error);
592
- }
593
- }
594
-
595
- function handleDataSubmit(result: any) {
596
- try {
597
-
598
- if (result.ret === 0) {
599
- // 操作成功,刷新数据
600
- refreshData();
601
- closeDataEditor();
602
- } else {
603
- modal.error('操作失败');
604
- }
605
- } catch (error) {
606
- console.error('处理数据提交失败:', error);
607
-
608
- modal.error(error.msg || error.message || '操作失败', {
609
- //operation: operation,
610
- table: props.table?.name,
611
- stack: error.stack
612
- });
613
- }
614
- }
615
-
616
- function closeDataEditor() {
617
- showDataEditor.value = false;
618
- editingRow.value = null;
619
- isEditMode.value = false;
620
- }
621
-
622
- // 表格编辑相关方法
623
- function editTableStructure() {
624
- tableEditorMode.value = 'edit';
625
- showTableEditor.value = true;
626
- }
627
-
628
- function addColumn() {
629
- // 这里可以打开列编辑器或直接调用表格编辑器
630
- tableEditorMode.value = 'edit';
631
- showTableEditor.value = true;
632
- }
633
-
634
- function closeTableEditor() {
635
- showTableEditor.value = false;
636
- }
637
-
638
- async function handleTableStructureChange(result: any) {
639
- try {
640
-
641
- if (result.success) {
642
- // 表结构修改成功,刷新结构
643
- emit('refresh-structure');
644
- emit('refresh-database');
645
- closeTableEditor();
646
- await modal.success('表结构修改成功');
647
- } else {
648
- await modal.error('表结构修改失败');
649
- }
650
- } catch (error) {
651
- console.error('处理表结构修改失败:', error);
652
-
653
- modal.error(error.msg || error.message || '表结构修改失败', {
654
- operation: 'MODIFY_TABLE',
655
- table: props.table?.name,
656
- stack: error.stack
657
- });
658
- }
659
- }
660
-
661
- // 其他方法
662
- function editColumn(column: any) {
663
- // 打开列编辑器
664
- tableEditorMode.value = 'edit';
665
- showTableEditor.value = true;
666
- }
667
-
668
- function deleteColumn(column: any) {
669
- // 删除列
670
- modal.confirm(`确定要删除列 ${column.name} 吗?`, {
671
- confirmButtonText: '删除',
672
- cancelButtonText: '取消',
673
- type: 'danger'
674
- }).then(result => {
675
- if (result) {
676
- // 这里可以调用API删除列
677
- emit('refresh-structure');
678
- }
679
- });
680
- }
681
-
682
- function editIndex(index: any) {
683
- // 编辑索引
684
- console.log('编辑索引:', index);
685
- }
686
-
687
- function deleteIndex(index: any) {
688
- // 删除索引
689
- modal.confirm(`确定要删除索引 ${index.name} 吗?`, {
690
- confirmButtonText: '删除',
691
- cancelButtonText: '取消',
692
- type: 'danger'
693
- }).then(result => {
694
- if (result) {
695
- // 这里可以调用API删除索引
696
- emit('refresh-structure');
697
- }
698
- });
699
- }
700
-
701
- function deleteForeignKey(fk: any) {
702
- // 删除外键
703
- modal.confirm(`确定要删除外键 ${fk.name} 吗?`, {
704
- confirmButtonText: '删除',
705
- cancelButtonText: '取消',
706
- type: 'danger'
707
- }).then(result => {
708
- if (result) {
709
- // 这里可以调用API删除外键
710
- emit('refresh-structure');
711
- }
712
- });
713
- }
714
-
715
- function formatValueForSQL(value: any, type: string): string {
716
- if (value === null || value === undefined) {
717
- return 'NULL';
718
- }
719
-
720
- if (typeof value === 'string') {
721
- // 转义单引号
722
- const escaped = value.replace(/'/g, "''");
723
- return `'${escaped}'`;
724
- }
725
-
726
- if (typeof value === 'boolean') {
727
- return value ? '1' : '0';
728
- }
729
-
730
- return String(value);
731
- }
732
-
733
-
734
-
735
- async function exportTableData(format: 'csv' | 'json' | 'excel') {
736
- try {
737
- if (!props.connection || !props.database || !props.table?.name) {
738
- await modal.warning('缺少必要的连接信息');
739
- return;
740
- }
741
-
742
- // 调用后端API导出表数据
743
- let response;
744
- switch (format) {
745
- case 'csv':
746
- response = await databaseService.exportTableDataToCSV(
747
- props.connection.id,
748
- props.database,
749
- props.table.name
750
- );
751
- break;
752
- case 'json':
753
- response = await databaseService.exportTableDataToJSON(
754
- props.connection.id,
755
- props.database,
756
- props.table.name
757
- );
758
- break;
759
- case 'excel':
760
- response = await databaseService.exportTableDataToExcel(
761
- props.connection.id,
762
- props.database,
763
- props.table.name
764
- );
765
- break;
766
- default:
767
- throw new Error('不支持的导出格式');
768
- }
769
-
770
- if (response.ret === 0) {
771
- await modal.success(`表数据导出成功,文件路径:${response.data}`);
772
- } else {
773
- await modal.error('导出表数据失败: ' + response.msg);
774
- }
775
- } catch (error) {
776
- console.error('导出表数据失败:', error);
777
- modal.error('导出表数据失败: ' + (error as any).message);
778
- }
779
- }
780
-
781
- async function exportTableStructure() {
782
- try {
783
- // 构建CREATE TABLE语句
784
- let createTableSQL = `CREATE TABLE ${props.table?.name} (
785
- `;
786
-
787
- const columns = [];
788
- safeTableColumns.value.forEach((column: any, index: number) => {
789
- let columnDef = ` ${column.name} ${column.type}`;
790
-
791
- if (!column.nullable) {
792
- columnDef += ' NOT NULL';
793
- }
794
-
795
- if (column.defaultValue !== undefined && column.defaultValue !== null) {
796
- if (typeof column.defaultValue === 'string') {
797
- columnDef += ` DEFAULT '${column.defaultValue.replace(/'/g, "''")}'`;
798
- } else {
799
- columnDef += ` DEFAULT ${column.defaultValue}`;
800
- }
801
- }
802
-
803
- if (column.isPrimary) {
804
- columnDef += ' PRIMARY KEY';
805
- }
806
-
807
- if (column.isAutoIncrement) {
808
- columnDef += ' AUTO_INCREMENT';
809
- }
810
-
811
- if (column.comment) {
812
- columnDef += ` COMMENT '${column.comment.replace(/'/g, "''")}'`;
813
- }
814
-
815
- columns.push(columnDef);
816
- });
817
-
818
- createTableSQL += columns.join(',\n');
819
- createTableSQL += '\n);\n';
820
-
821
- // 添加索引
822
- if (props.tableStructure?.indexes) {
823
- props.tableStructure.indexes.forEach((index: any) => {
824
- if (!index.isPrimary) {
825
- createTableSQL += `CREATE ${index.unique ? 'UNIQUE ' : ''}INDEX ${index.name} ON ${props.table?.name} (${index.columns.join(', ')})\n`;
826
- }
827
- });
828
- }
829
-
830
- // 添加外键
831
- if (props.tableStructure?.foreignKeys) {
832
- props.tableStructure.foreignKeys.forEach((fk: any) => {
833
- createTableSQL += `ALTER TABLE ${props.table?.name} ADD CONSTRAINT ${fk.name} FOREIGN KEY (${fk.column}) REFERENCES ${fk.referencedTable} (${fk.referencedColumn})${fk.onDelete ? ` ON DELETE ${fk.onDelete}` : ''}${fk.onUpdate ? ` ON UPDATE ${fk.onUpdate}` : ''}\n`;
834
- });
835
- }
836
-
837
- // 下载SQL文件
838
- downloadSQLFile(createTableSQL, `${props.table?.name}_structure.sql`);
839
- } catch (error) {
840
- console.error('导出表结构失败:', error);
841
- modal.error('导出表结构失败: ' + (error as any).message);
842
- }
843
- }
844
-
845
- async function exportTableDataSQL() {
846
- try {
847
- if (!props.connection || !props.database || !props.table?.name) {
848
- await modal.warning('缺少必要的连接信息');
849
- return;
850
- }
851
-
852
- // 调用后端API导出表数据
853
- const response = await databaseService.exportTableDataToSQL(
854
- props.connection.id,
855
- props.database,
856
- props.table.name
857
- );
858
-
859
- if (response.ret === 0) {
860
- await modal.success(`表数据导出成功,文件路径:${response.data}`);
861
- } else {
862
- await modal.error('导出表数据失败: ' + response.msg);
863
- }
864
- } catch (error) {
865
- console.error('导出表数据失败:', error);
866
- modal.error('导出表数据失败: ' + (error as any).message);
867
- }
868
- }
869
-
870
- function downloadSQLFile(content: string, filename: string) {
871
- const blob = new Blob([content], { type: 'text/sql;charset=utf-8;' });
872
- const link = document.createElement('a');
873
-
874
- if (link.download !== undefined) {
875
- const url = URL.createObjectURL(blob);
876
- link.setAttribute('href', url);
877
- link.setAttribute('download', filename);
878
- link.style.visibility = 'hidden';
879
- document.body.appendChild(link);
880
- link.click();
881
- document.body.removeChild(link);
882
- }
883
- }
884
- </script>
885
-
886
- <style scoped>
887
- .table-detail {
888
- width: 100%;
889
- height: 100%;
890
- display: flex;
891
- flex-direction: column;
892
- }
893
-
894
- .table-header {
895
- background-color: #f8f9fa;
896
- border-bottom: 1px solid #dee2e6;
897
- padding: 15px 20px;
898
- }
899
-
900
- .table-header-content {
901
- display: flex;
902
- justify-content: space-between;
903
- align-items: center;
904
- }
905
-
906
- .table-info {
907
- display: flex;
908
- align-items: center;
909
- gap: 15px;
910
- }
911
-
912
- .table-icon {
913
- font-size: 32px;
914
- color: #495057;
915
- }
916
-
917
- .table-meta {
918
- display: flex;
919
- flex-direction: column;
920
- gap: 5px;
921
- }
922
-
923
- .table-name {
924
- margin: 0;
925
- font-size: 1.25rem;
926
- font-weight: 600;
927
- }
928
-
929
- .table-breadcrumb {
930
- display: flex;
931
- align-items: center;
932
- gap: 8px;
933
- font-size: 0.875rem;
934
- color: #6c757d;
935
- }
936
-
937
- .table-stats {
938
- display: flex;
939
- gap: 20px;
940
- }
941
-
942
- .stat-item {
943
- display: flex;
944
- flex-direction: column;
945
- align-items: center;
946
- gap: 2px;
947
- }
948
-
949
- .stat-value {
950
- font-size: 1.125rem;
951
- font-weight: 600;
952
- color: #495057;
953
- }
954
-
955
- .stat-label {
956
- font-size: 0.75rem;
957
- color: #6c757d;
958
- }
959
-
960
- .table-toolbar {
961
- display: flex;
962
- justify-content: space-between;
963
- align-items: center;
964
- padding: 10px 20px;
965
- background-color: #f8f9fa;
966
- border-bottom: 1px solid #dee2e6;
967
- }
968
-
969
- .toolbar-left {
970
- display: flex;
971
- gap: 10px;
972
- align-items: center;
973
- }
974
-
975
- .toolbar-right {
976
- display: flex;
977
- gap: 10px;
978
- align-items: center;
979
- }
980
-
981
- .table-tabs {
982
- flex: 1;
983
- display: flex;
984
- flex-direction: column;
985
- overflow: hidden;
986
- }
987
-
988
- .nav-tabs {
989
- border-bottom: 1px solid #dee2e6;
990
- background-color: #f8f9fa;
991
- flex-shrink: 0;
992
- }
993
-
994
- .nav-tabs .nav-link {
995
- color: #495057;
996
- border: none;
997
- border-bottom: 3px solid transparent;
998
- border-radius: 0;
999
- padding: 10px 15px;
1000
- font-weight: 500;
1001
- }
1002
-
1003
- .nav-tabs .nav-link:hover {
1004
- background-color: #e9ecef;
1005
- border-bottom-color: #adb5bd;
1006
- }
1007
-
1008
- .nav-tabs .nav-link.active {
1009
- background-color: #fff;
1010
- border-bottom-color: #0d6efd;
1011
- color: #0d6efd;
1012
- }
1013
-
1014
- .tab-content {
1015
- flex: 1;
1016
- overflow: auto;
1017
- padding: 20px;
1018
- background-color: #fff;
1019
- display: flex;
1020
- flex-direction: column;
1021
- }
1022
-
1023
- .tab-panel {
1024
- flex: 1;
1025
- display: flex;
1026
- flex-direction: column;
1027
- height: 100%;
1028
- overflow: auto;
1029
- }
1030
-
1031
- .data-content {
1032
- height: 100%;
1033
- display: flex;
1034
- flex-direction: column;
1035
- }
1036
-
1037
- .data-content.loading {
1038
- opacity: 0.7;
1039
- pointer-events: none;
1040
- }
1041
-
1042
- .table-responsive {
1043
- flex: 1;
1044
- overflow: auto;
1045
- }
1046
-
1047
- .column-header {
1048
- position: relative;
1049
- }
1050
-
1051
- .column-key {
1052
- position: absolute;
1053
- top: -5px;
1054
- right: -15px;
1055
- color: #0d6efd;
1056
- font-size: 0.75rem;
1057
- }
1058
-
1059
- .cell-value {
1060
- max-width: 200px;
1061
- overflow: hidden;
1062
- text-overflow: ellipsis;
1063
- white-space: nowrap;
1064
- }
1065
-
1066
- .loading-state {
1067
- display: flex;
1068
- flex-direction: column;
1069
- align-items: center;
1070
- justify-content: center;
1071
- height: 300px;
1072
- gap: 15px;
1073
- }
1074
-
1075
- .empty-state {
1076
- display: flex;
1077
- flex-direction: column;
1078
- align-items: center;
1079
- justify-content: center;
1080
- height: 300px;
1081
- gap: 15px;
1082
- color: #6c757d;
1083
- }
1084
-
1085
- .empty-state i {
1086
- font-size: 48px;
1087
- opacity: 0.5;
1088
- }
1089
-
1090
- .pagination-nav {
1091
- margin-top: 20px;
1092
- border-top: 1px solid #dee2e6;
1093
- padding-top: 15px;
1094
- }
1095
-
1096
- .pagination-container {
1097
- display: flex;
1098
- align-items: center;
1099
- justify-content: space-between;
1100
- flex-wrap: wrap;
1101
- gap: 10px;
1102
- }
1103
-
1104
- .pagination-info {
1105
- font-size: 0.875rem;
1106
- color: #6c757d;
1107
- }
1108
-
1109
- .page-size-selector {
1110
- display: flex;
1111
- align-items: center;
1112
- gap: 5px;
1113
- }
1114
-
1115
- .page-jump {
1116
- display: flex;
1117
- align-items: center;
1118
- gap: 5px;
1119
- }
1120
-
1121
- .structure-actions {
1122
- display: flex;
1123
- gap: 10px;
1124
- margin-bottom: 15px;
1125
- }
1126
-
1127
- .structure-table, .indexes-table, .relations-table {
1128
- overflow: auto;
1129
- }
1130
-
1131
- .structure-table table, .indexes-table table, .relations-table table {
1132
- width: 100%;
1133
- }
1134
-
1135
- .sql-section {
1136
- height: 100%;
1137
- }
1138
-
1139
- /* 响应式设计 */
1140
- @media (max-width: 768px) {
1141
- .table-header-content {
1142
- flex-direction: column;
1143
- align-items: flex-start;
1144
- gap: 15px;
1145
- }
1146
-
1147
- .table-stats {
1148
- width: 100%;
1149
- justify-content: space-around;
1150
- }
1151
-
1152
- .table-toolbar {
1153
- flex-direction: column;
1154
- align-items: stretch;
1155
- gap: 10px;
1156
- }
1157
-
1158
- .toolbar-left, .toolbar-right {
1159
- justify-content: center;
1160
- }
1161
-
1162
- .pagination-container {
1163
- flex-direction: column;
1164
- align-items: flex-start;
1165
- gap: 15px;
1166
- }
1167
-
1168
- .pagination {
1169
- width: 100%;
1170
- justify-content: center;
1171
- }
1172
- }
1173
- </style>