fdb2 1.0.6 → 1.0.8

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 (193) hide show
  1. package/.vscodeignore +45 -0
  2. package/README.md +24 -85
  3. package/dist/package.json +115 -0
  4. package/dist/pnpm-lock.yaml +7447 -0
  5. package/dist/public/explorer.css +244 -111
  6. package/dist/public/explorer.js +523 -278
  7. package/dist/scripts/preinstall.js +112 -0
  8. package/dist/server/index.d.ts.map +1 -1
  9. package/dist/server/index.js +4 -9
  10. package/dist/server/index.js.map +1 -1
  11. package/dist/server/index.ts +5 -10
  12. package/dist/server/service/connection.service.d.ts.map +1 -1
  13. package/dist/server/service/connection.service.js +1 -0
  14. package/dist/server/service/connection.service.js.map +1 -1
  15. package/dist/server/service/connection.service.ts +1 -0
  16. package/dist/server/service/database/base.service.d.ts +4 -0
  17. package/dist/server/service/database/base.service.d.ts.map +1 -1
  18. package/dist/server/service/database/base.service.js +3 -3
  19. package/dist/server/service/database/base.service.js.map +1 -1
  20. package/dist/server/service/database/base.service.ts +8 -3
  21. package/dist/server/service/database/cockroachdb.service.d.ts +5 -0
  22. package/dist/server/service/database/cockroachdb.service.d.ts.map +1 -1
  23. package/dist/server/service/database/cockroachdb.service.js +112 -0
  24. package/dist/server/service/database/cockroachdb.service.js.map +1 -1
  25. package/dist/server/service/database/cockroachdb.service.ts +123 -0
  26. package/dist/server/service/database/database.service.d.ts +4 -0
  27. package/dist/server/service/database/database.service.d.ts.map +1 -1
  28. package/dist/server/service/database/database.service.js +8 -0
  29. package/dist/server/service/database/database.service.js.map +1 -1
  30. package/dist/server/service/database/database.service.ts +9 -0
  31. package/dist/server/service/database/mongodb.service.d.ts +6 -0
  32. package/dist/server/service/database/mongodb.service.d.ts.map +1 -1
  33. package/dist/server/service/database/mongodb.service.js +8 -0
  34. package/dist/server/service/database/mongodb.service.js.map +1 -1
  35. package/dist/server/service/database/mongodb.service.ts +9 -0
  36. package/dist/server/service/database/mssql.service.d.ts +4 -0
  37. package/dist/server/service/database/mssql.service.d.ts.map +1 -1
  38. package/dist/server/service/database/mssql.service.js +105 -0
  39. package/dist/server/service/database/mssql.service.js.map +1 -1
  40. package/dist/server/service/database/mssql.service.ts +118 -0
  41. package/dist/server/service/database/mysql.service.d.ts +4 -0
  42. package/dist/server/service/database/mysql.service.d.ts.map +1 -1
  43. package/dist/server/service/database/mysql.service.js +116 -0
  44. package/dist/server/service/database/mysql.service.js.map +1 -1
  45. package/dist/server/service/database/mysql.service.ts +130 -0
  46. package/dist/server/service/database/oracle.service.d.ts +4 -0
  47. package/dist/server/service/database/oracle.service.d.ts.map +1 -1
  48. package/dist/server/service/database/oracle.service.js +114 -0
  49. package/dist/server/service/database/oracle.service.js.map +1 -1
  50. package/dist/server/service/database/oracle.service.ts +128 -0
  51. package/dist/server/service/database/postgres.service.d.ts +4 -0
  52. package/dist/server/service/database/postgres.service.d.ts.map +1 -1
  53. package/dist/server/service/database/postgres.service.js +120 -0
  54. package/dist/server/service/database/postgres.service.js.map +1 -1
  55. package/dist/server/service/database/postgres.service.ts +131 -0
  56. package/dist/server/service/database/sap.service.d.ts +4 -0
  57. package/dist/server/service/database/sap.service.d.ts.map +1 -1
  58. package/dist/server/service/database/sap.service.js +107 -0
  59. package/dist/server/service/database/sap.service.js.map +1 -1
  60. package/dist/server/service/database/sap.service.ts +120 -0
  61. package/dist/server/service/database/sqlite.service.d.ts +5 -0
  62. package/dist/server/service/database/sqlite.service.d.ts.map +1 -1
  63. package/dist/server/service/database/sqlite.service.js +133 -0
  64. package/dist/server/service/database/sqlite.service.js.map +1 -1
  65. package/dist/server/service/database/sqlite.service.ts +150 -0
  66. package/fdb2.server.pid +1 -0
  67. package/package.json +18 -9
  68. package/packages/vscode/.vscodeignore +44 -0
  69. package/packages/vscode/README.md +62 -0
  70. package/packages/vscode/out/database-services/base.service.js +236 -0
  71. package/packages/vscode/out/database-services/base.service.js.map +1 -0
  72. package/packages/vscode/out/database-services/cockroachdb.service.js +634 -0
  73. package/packages/vscode/out/database-services/cockroachdb.service.js.map +1 -0
  74. package/packages/vscode/out/database-services/connection.service.js +346 -0
  75. package/packages/vscode/out/database-services/connection.service.js.map +1 -0
  76. package/packages/vscode/out/database-services/database.service.js +571 -0
  77. package/packages/vscode/out/database-services/database.service.js.map +1 -0
  78. package/packages/vscode/out/database-services/index.js +18 -0
  79. package/packages/vscode/out/database-services/index.js.map +1 -0
  80. package/packages/vscode/out/database-services/model/connection.entity.js +11 -0
  81. package/packages/vscode/out/database-services/model/connection.entity.js.map +1 -0
  82. package/packages/vscode/out/database-services/model/database.entity.js +35 -0
  83. package/packages/vscode/out/database-services/model/database.entity.js.map +1 -0
  84. package/packages/vscode/out/database-services/mongodb.service.js +458 -0
  85. package/packages/vscode/out/database-services/mongodb.service.js.map +1 -0
  86. package/packages/vscode/out/database-services/mssql.service.js +694 -0
  87. package/packages/vscode/out/database-services/mssql.service.js.map +1 -0
  88. package/packages/vscode/out/database-services/mysql.service.js +735 -0
  89. package/packages/vscode/out/database-services/mysql.service.js.map +1 -0
  90. package/packages/vscode/out/database-services/oracle.service.js +787 -0
  91. package/packages/vscode/out/database-services/oracle.service.js.map +1 -0
  92. package/packages/vscode/out/database-services/postgres.service.js +696 -0
  93. package/packages/vscode/out/database-services/postgres.service.js.map +1 -0
  94. package/packages/vscode/out/database-services/sap.service.js +695 -0
  95. package/packages/vscode/out/database-services/sap.service.js.map +1 -0
  96. package/packages/vscode/out/database-services/sqlite.service.js +532 -0
  97. package/packages/vscode/out/database-services/sqlite.service.js.map +1 -0
  98. package/packages/vscode/out/extension.js +93 -0
  99. package/packages/vscode/out/extension.js.map +1 -0
  100. package/packages/vscode/out/provider/DatabaseTreeProvider.js +159 -0
  101. package/packages/vscode/out/provider/DatabaseTreeProvider.js.map +1 -0
  102. package/packages/vscode/out/provider/WebViewProvider.js +259 -0
  103. package/packages/vscode/out/provider/WebViewProvider.js.map +1 -0
  104. package/packages/vscode/out/service/ConnectionManager.js +105 -0
  105. package/packages/vscode/out/service/ConnectionManager.js.map +1 -0
  106. package/packages/vscode/out/service/DatabaseServiceBridge.js +395 -0
  107. package/packages/vscode/out/service/DatabaseServiceBridge.js.map +1 -0
  108. package/packages/vscode/out/typings/connection.js +3 -0
  109. package/packages/vscode/out/typings/connection.js.map +1 -0
  110. package/packages/vscode/package.json +142 -0
  111. package/packages/vscode/resources/icon.svg +5 -0
  112. package/packages/vscode/resources/webview/_plugin-vue_export-helper.js +6529 -0
  113. package/packages/vscode/resources/webview/_plugin-vue_export-helper.js.map +1 -0
  114. package/packages/vscode/resources/webview/connection.css +69 -0
  115. package/packages/vscode/resources/webview/connection.js +228 -0
  116. package/packages/vscode/resources/webview/connection.js.map +1 -0
  117. package/packages/vscode/resources/webview/database.css +259 -0
  118. package/packages/vscode/resources/webview/database.js +275 -0
  119. package/packages/vscode/resources/webview/database.js.map +1 -0
  120. package/packages/vscode/resources/webview/favicon.ico +0 -0
  121. package/packages/vscode/resources/webview/index.html +9 -0
  122. package/packages/vscode/resources/webview/modules/header.tpl +14 -0
  123. package/packages/vscode/resources/webview/modules/initial_state.tpl +55 -0
  124. package/packages/vscode/resources/webview/query.css +162 -0
  125. package/packages/vscode/resources/webview/query.js +198 -0
  126. package/packages/vscode/resources/webview/query.js.map +1 -0
  127. package/packages/vscode/src/database-services/base.service.js.map +1 -0
  128. package/packages/vscode/src/database-services/base.service.ts +363 -0
  129. package/packages/vscode/src/database-services/cockroachdb.service.js.map +1 -0
  130. package/packages/vscode/src/database-services/cockroachdb.service.ts +659 -0
  131. package/packages/vscode/src/database-services/connection.service.ts +341 -0
  132. package/packages/vscode/src/database-services/database.service.ts +630 -0
  133. package/packages/vscode/src/database-services/index.ts +7 -0
  134. package/packages/vscode/src/database-services/model/connection.entity.js +11 -0
  135. package/packages/vscode/src/database-services/model/connection.entity.js.map +1 -0
  136. package/packages/vscode/src/database-services/model/connection.entity.ts +66 -0
  137. package/packages/vscode/src/database-services/model/database.entity.js +35 -0
  138. package/packages/vscode/src/database-services/model/database.entity.js.map +1 -0
  139. package/packages/vscode/src/database-services/model/database.entity.ts +246 -0
  140. package/packages/vscode/src/database-services/mongodb.service.js.map +1 -0
  141. package/packages/vscode/src/database-services/mongodb.service.ts +454 -0
  142. package/packages/vscode/src/database-services/mssql.service.js.map +1 -0
  143. package/packages/vscode/src/database-services/mssql.service.ts +723 -0
  144. package/packages/vscode/src/database-services/mysql.service.js.map +1 -0
  145. package/packages/vscode/src/database-services/mysql.service.ts +761 -0
  146. package/packages/vscode/src/database-services/oracle.service.js.map +1 -0
  147. package/packages/vscode/src/database-services/oracle.service.ts +832 -0
  148. package/packages/vscode/src/database-services/postgres.service.js.map +1 -0
  149. package/packages/vscode/src/database-services/postgres.service.ts +741 -0
  150. package/packages/vscode/src/database-services/sap.service.js.map +1 -0
  151. package/packages/vscode/src/database-services/sap.service.ts +713 -0
  152. package/packages/vscode/src/database-services/sqlite.service.js.map +1 -0
  153. package/packages/vscode/src/database-services/sqlite.service.ts +559 -0
  154. package/packages/vscode/src/extension.ts +76 -0
  155. package/packages/vscode/src/provider/DatabaseTreeProvider.ts +167 -0
  156. package/packages/vscode/src/provider/WebViewProvider.ts +277 -0
  157. package/packages/vscode/src/service/DatabaseServiceBridge.ts +414 -0
  158. package/packages/vscode/src/typings/connection.ts +90 -0
  159. package/packages/vscode/tsconfig.json +21 -0
  160. package/public/fdb2.png +0 -0
  161. package/server/backups/db_ai_breakout_2026-03-11T08-38-48-677Z.sql +0 -0
  162. package/server/index.ts +5 -10
  163. package/server/model/connection.entity.js +11 -0
  164. package/server/model/connection.entity.js.map +1 -0
  165. package/server/model/database.entity.js +35 -0
  166. package/server/model/database.entity.js.map +1 -0
  167. package/server/service/connection.service.ts +1 -0
  168. package/server/service/database/base.service.ts +8 -3
  169. package/server/service/database/cockroachdb.service.ts +123 -0
  170. package/server/service/database/database.service.ts +9 -0
  171. package/server/service/database/mongodb.service.ts +9 -0
  172. package/server/service/database/mssql.service.ts +118 -0
  173. package/server/service/database/mysql.service.ts +130 -0
  174. package/server/service/database/oracle.service.ts +128 -0
  175. package/server/service/database/postgres.service.ts +131 -0
  176. package/server/service/database/sap.service.ts +120 -0
  177. package/server/service/database/sqlite.service.ts +150 -0
  178. package/server/tsconfig.json +20 -0
  179. package/src/components/connection-editor/index.vue +0 -1
  180. package/src/platform/database/components/db-tools.vue +414 -174
  181. package/src/platform/database/components/table-detail.vue +3 -2
  182. package/src/platform/database/components/table-editor.vue +245 -18
  183. package/src/platform/vscode/bridge.ts +121 -0
  184. package/src/platform/vscode/components/ConnectionPanel.vue +272 -0
  185. package/src/platform/vscode/components/DatabasePanel.vue +532 -0
  186. package/src/platform/vscode/components/QueryPanel.vue +371 -0
  187. package/src/platform/vscode/entry/connection.ts +13 -0
  188. package/src/platform/vscode/entry/database.ts +13 -0
  189. package/src/platform/vscode/entry/query.ts +13 -0
  190. package/src/platform/vscode/index.ts +5 -0
  191. package/src/service/database.ts +2 -6
  192. package/vite.config.ts +46 -6
  193. package/vite.config.vscode.ts +47 -0
@@ -186,13 +186,11 @@ class DatabaseService {
186
186
  /**
187
187
  * 修改表结构
188
188
  */
189
- async alterTable(connectionId, database, tableName, columns, oldColumns) {
189
+ async alterTable(connectionId, database, tableDiff) {
190
190
  return request("/api/database/alterTable", {
191
191
  id: connectionId,
192
192
  database,
193
- tableName,
194
- columns,
195
- oldColumns
193
+ tableDiff
196
194
  });
197
195
  }
198
196
  /**
@@ -473,7 +471,6 @@ const _sfc_main$8 = /* @__PURE__ */ defineComponent({
473
471
  }
474
472
  async function saveConnection(closeModal = true) {
475
473
  try {
476
- debugger;
477
474
  const validation = validateConnection(connectionForm.value);
478
475
  if (!validation.isValid) {
479
476
  errorMessage.value = validation.message;
@@ -892,7 +889,7 @@ const _sfc_main$8 = /* @__PURE__ */ defineComponent({
892
889
  };
893
890
  }
894
891
  });
895
- const ConnectionEditor = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["__scopeId", "data-v-093594aa"]]);
892
+ const ConnectionEditor = /* @__PURE__ */ _export_sfc(_sfc_main$8, [["__scopeId", "data-v-144c6980"]]);
896
893
  class ModalHelper {
897
894
  /**
898
895
  * 获取全局modal实例
@@ -6837,7 +6834,7 @@ class TileBuilder {
6837
6834
  this.flushBuffer();
6838
6835
  let parent = this.ensureMarks(marks, openStart);
6839
6836
  let prev = parent.lastChild;
6840
- if (prev && prev.isText() && !(prev.flags & 8)) {
6837
+ if (prev && prev.isText() && !(prev.flags & 8) && prev.length + text.length < 512) {
6841
6838
  this.cache.reused.set(
6842
6839
  prev,
6843
6840
  2
@@ -7346,7 +7343,7 @@ class TileUpdate {
7346
7343
  pos++;
7347
7344
  } else {
7348
7345
  b.ensureLine(pendingLineAttrs);
7349
- b.addText(chars, active, openStart);
7346
+ b.addText(chars, active, pos == from2 ? openStart : active.length);
7350
7347
  pos += chars.length;
7351
7348
  }
7352
7349
  pendingLineAttrs = null;
@@ -8292,6 +8289,8 @@ function posAtCoords(view, coords, precise, scanY) {
8292
8289
  if (scanY == null)
8293
8290
  break;
8294
8291
  if (block.type == BlockType.Text) {
8292
+ if (scanY < 0 ? block.to < view.viewport.from : block.from > view.viewport.to)
8293
+ break;
8295
8294
  let rect = view.docView.coordsAt(scanY < 0 ? block.from : block.to, scanY);
8296
8295
  if (rect && (scanY < 0 ? rect.top <= yOffset + docTop : rect.bottom >= yOffset + docTop))
8297
8296
  break;
@@ -13051,7 +13050,7 @@ function rectanglesForRange(view, className, range) {
13051
13050
  return pieces(top2).concat(between).concat(pieces(bottom));
13052
13051
  }
13053
13052
  function piece(left, top2, right, bottom) {
13054
- return new RectangleMarker(className, left - base2.left, top2 - base2.top, right - left, bottom - top2);
13053
+ return new RectangleMarker(className, left - base2.left, top2 - base2.top, Math.max(0, right - left), bottom - top2);
13055
13054
  }
13056
13055
  function pieces({ top: top2, bottom, horizontal }) {
13057
13056
  let pieces2 = [];
@@ -14367,11 +14366,10 @@ class TreeNode extends BaseNode {
14367
14366
  return this.from + this._tree.length;
14368
14367
  }
14369
14368
  nextChild(i, dir, pos, side, mode = 0) {
14370
- var _a2;
14371
14369
  for (let parent = this; ; ) {
14372
14370
  for (let { children, positions } = parent._tree, e = dir > 0 ? children.length : -1; i != e; i += dir) {
14373
- let next = children[i], start = positions[i] + parent.from;
14374
- if (!(mode & IterMode.EnterBracketed && next instanceof Tree && ((_a2 = MountedTree.get(next)) === null || _a2 === void 0 ? void 0 : _a2.overlay) === null && (start >= pos || start + next.length <= pos)) && !checkSide(side, pos, start, start + next.length))
14371
+ let next = children[i], start = positions[i] + parent.from, mounted;
14372
+ if (!(mode & IterMode.EnterBracketed && next instanceof Tree && (mounted = MountedTree.get(next)) && !mounted.overlay && mounted.bracketed && pos >= start && pos <= start + next.length) && !checkSide(side, pos, start, start + next.length))
14375
14373
  continue;
14376
14374
  if (next instanceof TreeBuffer) {
14377
14375
  if (mode & IterMode.ExcludeBuffers)
@@ -14380,9 +14378,9 @@ class TreeNode extends BaseNode {
14380
14378
  if (index > -1)
14381
14379
  return new BufferNode(new BufferContext(parent, next, i, start), null, index);
14382
14380
  } else if (mode & IterMode.IncludeAnonymous || (!next.type.isAnonymous || hasChild(next))) {
14383
- let mounted;
14384
- if (!(mode & IterMode.IgnoreMounts) && (mounted = MountedTree.get(next)) && !mounted.overlay)
14385
- return new TreeNode(mounted.tree, start, i, parent);
14381
+ let mounted2;
14382
+ if (!(mode & IterMode.IgnoreMounts) && (mounted2 = MountedTree.get(next)) && !mounted2.overlay)
14383
+ return new TreeNode(mounted2.tree, start, i, parent);
14386
14384
  let inner = new TreeNode(next, start, i, parent);
14387
14385
  return mode & IterMode.IncludeAnonymous || !inner.type.isAnonymous ? inner : inner.nextChild(dir < 0 ? next.children.length - 1 : 0, dir, pos, side, mode);
14388
14386
  }
@@ -45151,6 +45149,69 @@ function getColumnTypesByName(databaseTypeName) {
45151
45149
  const type = Object.values(DatabaseType).find((t2) => t2 === databaseTypeName.toLowerCase());
45152
45150
  return type ? getColumnTypes(type) : [];
45153
45151
  }
45152
+ function isNumericType(type) {
45153
+ const numericTypes = [
45154
+ "int",
45155
+ "integer",
45156
+ "tinyint",
45157
+ "smallint",
45158
+ "mediumint",
45159
+ "bigint",
45160
+ "decimal",
45161
+ "numeric",
45162
+ "float",
45163
+ "double",
45164
+ "real",
45165
+ "number",
45166
+ "smallserial",
45167
+ "serial",
45168
+ "bigserial",
45169
+ "money",
45170
+ "smallmoney",
45171
+ "binary_float",
45172
+ "binary_double"
45173
+ ];
45174
+ return numericTypes.some((t2) => type.toLowerCase().includes(t2));
45175
+ }
45176
+ function isTextType(type) {
45177
+ const textTypes = [
45178
+ "text",
45179
+ "longtext",
45180
+ "mediumtext",
45181
+ "tinytext",
45182
+ "clob",
45183
+ "nclob",
45184
+ "ntext"
45185
+ ];
45186
+ return textTypes.some((t2) => type.toLowerCase().includes(t2));
45187
+ }
45188
+ function isDateTimeType(type) {
45189
+ const dateTimeTypes = [
45190
+ "date",
45191
+ "datetime",
45192
+ "timestamp",
45193
+ "time",
45194
+ "year",
45195
+ "time with time zone",
45196
+ "timestamp with time zone",
45197
+ "timestamp with local time zone",
45198
+ "interval",
45199
+ "datetimeoffset",
45200
+ "datetime2",
45201
+ "smalldatetime"
45202
+ ];
45203
+ return dateTimeTypes.some((t2) => type.toLowerCase().includes(t2));
45204
+ }
45205
+ function isBooleanType(type) {
45206
+ const booleanTypes = ["boolean", "bool", "bit", "tinyint(1)"];
45207
+ return booleanTypes.some((t2) => type.toLowerCase().includes(t2));
45208
+ }
45209
+ function isJsonType(type) {
45210
+ return ["json", "jsonb"].includes(type.toLowerCase());
45211
+ }
45212
+ function isArrayType(type) {
45213
+ return type.toLowerCase().endsWith("[]");
45214
+ }
45154
45215
  const _hoisted_1$5 = { class: "modal-content" };
45155
45216
  const _hoisted_2$5 = { class: "modal-header" };
45156
45217
  const _hoisted_3$5 = { class: "modal-title" };
@@ -45198,6 +45259,7 @@ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
45198
45259
  connection: {},
45199
45260
  database: {},
45200
45261
  table: {},
45262
+ columns: {},
45201
45263
  mode: {}
45202
45264
  },
45203
45265
  emits: ["close", "submit"],
@@ -45233,12 +45295,18 @@ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
45233
45295
  comment: ""
45234
45296
  }]
45235
45297
  });
45298
+ const originalTableData = ref({
45299
+ tableName: "",
45300
+ tableComment: "",
45301
+ columns: []
45302
+ });
45236
45303
  function initFormData() {
45237
45304
  if (props.mode === "edit" && props.table) {
45238
- formData.value = {
45305
+ const columns = props.columns || props.table.columns || [];
45306
+ const tableData = {
45239
45307
  tableName: props.table.name || "",
45240
45308
  tableComment: props.table.comment || "",
45241
- columns: props.table.columns?.map((col) => ({
45309
+ columns: columns.map((col) => ({
45242
45310
  name: col.name || "",
45243
45311
  type: col.type || "",
45244
45312
  length: col.length || "",
@@ -45251,6 +45319,8 @@ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
45251
45319
  comment: col.comment || ""
45252
45320
  })) || []
45253
45321
  };
45322
+ formData.value = { ...tableData };
45323
+ originalTableData.value = JSON.parse(JSON.stringify(tableData));
45254
45324
  } else {
45255
45325
  formData.value = {
45256
45326
  tableName: "",
@@ -45268,8 +45338,48 @@ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
45268
45338
  comment: ""
45269
45339
  }]
45270
45340
  };
45341
+ originalTableData.value = {
45342
+ tableName: "",
45343
+ tableComment: "",
45344
+ columns: []
45345
+ };
45271
45346
  }
45272
45347
  }
45348
+ function calculateTableDiff() {
45349
+ const diff = {
45350
+ tableName: formData.value.tableName,
45351
+ tableCommentChanged: formData.value.tableComment !== originalTableData.value.tableComment,
45352
+ tableComment: formData.value.tableComment,
45353
+ addedColumns: [],
45354
+ modifiedColumns: [],
45355
+ deletedColumns: []
45356
+ };
45357
+ const originalColumnsMap = /* @__PURE__ */ new Map();
45358
+ originalTableData.value.columns.forEach((col) => {
45359
+ originalColumnsMap.set(col.name, col);
45360
+ });
45361
+ formData.value.columns.forEach((newCol) => {
45362
+ const originalCol = originalColumnsMap.get(newCol.name);
45363
+ if (!originalCol) {
45364
+ diff.addedColumns.push(newCol);
45365
+ } else {
45366
+ const isModified = newCol.type !== originalCol.type || newCol.length !== originalCol.length || newCol.precision !== originalCol.precision || newCol.scale !== originalCol.scale || newCol.nullable !== originalCol.nullable || newCol.defaultValue !== originalCol.defaultValue || newCol.isPrimary !== originalCol.isPrimary || newCol.isAutoIncrement !== originalCol.isAutoIncrement || newCol.comment !== originalCol.comment;
45367
+ if (isModified) {
45368
+ diff.modifiedColumns.push({
45369
+ oldColumn: originalCol,
45370
+ newColumn: newCol
45371
+ });
45372
+ }
45373
+ }
45374
+ });
45375
+ originalTableData.value.columns.forEach((originalCol) => {
45376
+ const existsInNew = formData.value.columns.some((newCol) => newCol.name === originalCol.name);
45377
+ if (!existsInNew) {
45378
+ diff.deletedColumns.push(originalCol);
45379
+ }
45380
+ });
45381
+ return diff;
45382
+ }
45273
45383
  function addColumn() {
45274
45384
  formData.value.columns.push({
45275
45385
  name: "",
@@ -45324,9 +45434,9 @@ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
45324
45434
  const columnsSQL = formData.value.columns.map((col) => {
45325
45435
  if (!col.name || !col.type) return "";
45326
45436
  let sql22 = `${quoteIdentifier(col.name)} ${col.type}`;
45327
- if (col.length && (needsLength(col) || col.type.includes("CHAR"))) {
45437
+ if (!col.type.includes("(") && col.length && (needsLength(col) || col.type.includes("CHAR"))) {
45328
45438
  sql22 += `(${col.length})`;
45329
- } else if (col.precision) {
45439
+ } else if (!col.type.includes("(") && col.precision) {
45330
45440
  if (col.scale) {
45331
45441
  sql22 += `(${col.precision},${col.scale})`;
45332
45442
  } else {
@@ -45424,19 +45534,119 @@ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
45424
45534
  }
45425
45535
  return sql2;
45426
45536
  } else {
45427
- return `-- 表结构修改SQL(需要对比差异生成)
45428
- -- 当前表名: ${formData.value.tableName}`;
45537
+ const quoteIdentifier = (name2) => {
45538
+ if (!props.connection) return `"${name2}"`;
45539
+ switch (props.connection.type.toLowerCase()) {
45540
+ case "mysql":
45541
+ return `\`${name2}\``;
45542
+ case "postgres":
45543
+ return `"${name2}"`;
45544
+ case "sqlite":
45545
+ return `"${name2}"`;
45546
+ case "oracle":
45547
+ return `"${name2.toUpperCase()}"`;
45548
+ case "mssql":
45549
+ return `[${name2}]`;
45550
+ default:
45551
+ return `"${name2}"`;
45552
+ }
45553
+ };
45554
+ const sqlStatements = [];
45555
+ const tableName = formData.value.tableName;
45556
+ if (formData.value.tableComment) {
45557
+ switch (props.connection?.type.toLowerCase()) {
45558
+ case "mysql":
45559
+ sqlStatements.push(`ALTER TABLE ${quoteIdentifier(tableName)} COMMENT='${formData.value.tableComment}'`);
45560
+ break;
45561
+ case "postgres":
45562
+ sqlStatements.push(`COMMENT ON TABLE ${quoteIdentifier(tableName)} IS '${formData.value.tableComment}'`);
45563
+ break;
45564
+ case "oracle":
45565
+ sqlStatements.push(`COMMENT ON TABLE ${quoteIdentifier(tableName)} IS '${formData.value.tableComment}'`);
45566
+ break;
45567
+ case "mssql":
45568
+ sqlStatements.push(`EXEC sp_addextendedproperty 'MS_Description', '${formData.value.tableComment}', 'SCHEMA', 'dbo', 'TABLE', '${tableName}'`);
45569
+ break;
45570
+ }
45571
+ }
45572
+ formData.value.columns.forEach((col) => {
45573
+ if (!col.name || !col.type) return;
45574
+ let columnSQL = `${quoteIdentifier(col.name)} ${col.type}`;
45575
+ if (!col.type.includes("(") && col.length && (needsLength(col) || col.type.includes("CHAR"))) {
45576
+ columnSQL += `(${col.length})`;
45577
+ } else if (!col.type.includes("(") && col.precision) {
45578
+ if (col.scale) {
45579
+ columnSQL += `(${col.precision},${col.scale})`;
45580
+ } else {
45581
+ columnSQL += `(${col.precision})`;
45582
+ }
45583
+ }
45584
+ if (!col.nullable) {
45585
+ columnSQL += " NOT NULL";
45586
+ } else {
45587
+ columnSQL += " NULL";
45588
+ }
45589
+ if (col.defaultValue) {
45590
+ columnSQL += ` DEFAULT ${formatDefaultValue(col.defaultValue, col.type)}`;
45591
+ }
45592
+ let commentStatement = "";
45593
+ if (col.comment) {
45594
+ switch (props.connection?.type.toLowerCase()) {
45595
+ case "mysql":
45596
+ columnSQL += ` COMMENT '${col.comment}'`;
45597
+ break;
45598
+ case "postgres":
45599
+ commentStatement = `COMMENT ON COLUMN ${quoteIdentifier(tableName)}.${quoteIdentifier(col.name)} IS '${col.comment}'`;
45600
+ break;
45601
+ case "oracle":
45602
+ columnSQL += ` COMMENT '${col.comment}'`;
45603
+ break;
45604
+ case "mssql":
45605
+ commentStatement = `EXEC sp_addextendedproperty 'MS_Description', '${col.comment}', 'SCHEMA', 'dbo', 'TABLE', '${tableName}', 'COLUMN', '${col.name}'`;
45606
+ break;
45607
+ }
45608
+ }
45609
+ switch (props.connection?.type.toLowerCase()) {
45610
+ case "mysql":
45611
+ sqlStatements.push(`ALTER TABLE ${quoteIdentifier(tableName)} MODIFY COLUMN ${columnSQL}`);
45612
+ break;
45613
+ case "postgres":
45614
+ case "mssql":
45615
+ sqlStatements.push(`ALTER TABLE ${quoteIdentifier(tableName)} ALTER COLUMN ${columnSQL}`);
45616
+ break;
45617
+ case "oracle":
45618
+ sqlStatements.push(`ALTER TABLE ${quoteIdentifier(tableName)} MODIFY ${columnSQL}`);
45619
+ break;
45620
+ case "sqlite":
45621
+ sqlStatements.push(`-- SQLite 不支持直接修改列,需要重建表`);
45622
+ break;
45623
+ }
45624
+ if (commentStatement) {
45625
+ sqlStatements.push(commentStatement);
45626
+ }
45627
+ });
45628
+ const primaryKeys = formData.value.columns.filter((col) => col.isPrimary).map((col) => quoteIdentifier(col.name));
45629
+ if (primaryKeys.length > 0) {
45630
+ sqlStatements.push(`ALTER TABLE ${quoteIdentifier(tableName)} DROP PRIMARY KEY`);
45631
+ sqlStatements.push(`ALTER TABLE ${quoteIdentifier(tableName)} ADD PRIMARY KEY (${primaryKeys.join(", ")})`);
45632
+ }
45633
+ return sqlStatements.join(";\n") + ";";
45429
45634
  }
45430
45635
  }
45431
45636
  function formatDefaultValue(value, type) {
45432
45637
  if (value === null || value === void 0 || value === "") {
45433
45638
  return "NULL";
45434
45639
  }
45640
+ const lowerValue = String(value).toLowerCase();
45641
+ const specialKeywords = ["current_timestamp", "now()", "current_date", "current_time", "localtimestamp", "localtime"];
45642
+ if (specialKeywords.includes(lowerValue)) {
45643
+ return value;
45644
+ }
45435
45645
  const lowerType = type.toLowerCase();
45436
- if (isNumberInput(lowerType) && !isNaN(value)) {
45646
+ if (isNumericType(lowerType) && !isNaN(value)) {
45437
45647
  return String(value);
45438
45648
  }
45439
- if (isBooleanInput(lowerType)) {
45649
+ if (isBooleanType(lowerType)) {
45440
45650
  return value ? "TRUE" : "FALSE";
45441
45651
  }
45442
45652
  return `'${String(value).replace(/'/g, "''")}'`;
@@ -45451,16 +45661,30 @@ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
45451
45661
  await modal.warning("请完善所有字段信息");
45452
45662
  return;
45453
45663
  }
45454
- const sql2 = generateSQL();
45455
45664
  if (!props.connection?.id) {
45456
45665
  await modal.warning("请先选择数据库连接");
45457
45666
  return;
45458
45667
  }
45459
- const result = await databaseService2.executeQuery(
45460
- props.connection.id,
45461
- sql2,
45462
- props.database
45463
- );
45668
+ let result;
45669
+ if (props.mode === "create") {
45670
+ const sql2 = generateSQL();
45671
+ result = await databaseService2.executeQuery(
45672
+ props.connection.id,
45673
+ sql2,
45674
+ props.database
45675
+ );
45676
+ } else {
45677
+ const tableDiff = calculateTableDiff();
45678
+ if (tableDiff.addedColumns.length === 0 && tableDiff.modifiedColumns.length === 0 && tableDiff.deletedColumns.length === 0 && !tableDiff.tableCommentChanged) {
45679
+ await modal.info("没有检测到任何修改");
45680
+ return;
45681
+ }
45682
+ result = await databaseService2.alterTable(
45683
+ props.connection.id,
45684
+ props.database,
45685
+ tableDiff
45686
+ );
45687
+ }
45464
45688
  emit("submit", {
45465
45689
  success: result.ret === 0,
45466
45690
  message: result.ret === 0 ? "操作成功" : "操作失败",
@@ -45501,7 +45725,9 @@ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
45501
45725
  return labels[category] || category;
45502
45726
  }
45503
45727
  function getSelectedType(column) {
45504
- return columnTypes.value.find((t2) => t2.name === column.type);
45728
+ if (!column.type) return null;
45729
+ const typeName2 = column.type.match(/^[a-zA-Z]+/)?.[0] || column.type;
45730
+ return columnTypes.value.find((t2) => t2.name.toLowerCase() === typeName2.toLowerCase());
45505
45731
  }
45506
45732
  function needsLength(column) {
45507
45733
  const typeInfo = getSelectedType(column);
@@ -45768,34 +45994,37 @@ const _sfc_main$5 = /* @__PURE__ */ defineComponent({
45768
45994
  };
45769
45995
  }
45770
45996
  });
45771
- const TableEditor = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-081084ef"]]);
45997
+ const TableEditor = /* @__PURE__ */ _export_sfc(_sfc_main$5, [["__scopeId", "data-v-dcd325b0"]]);
45772
45998
  const _hoisted_1$4 = { class: "db-tools" };
45773
- const _hoisted_2$4 = { class: "modal-dialog" };
45774
- const _hoisted_3$4 = { class: "modal-content" };
45775
- const _hoisted_4$4 = { class: "modal-body" };
45776
- const _hoisted_5$4 = { class: "mb-3" };
45777
- const _hoisted_6$4 = {
45999
+ const _hoisted_2$4 = { class: "execution-results" };
46000
+ const _hoisted_3$4 = {
45778
46001
  key: 0,
45779
- class: "alert alert-info"
46002
+ class: "no-results"
45780
46003
  };
45781
- const _hoisted_7$4 = { class: "mb-3 form-check" };
45782
- const _hoisted_8$4 = { class: "modal-footer" };
45783
- const _hoisted_9$4 = ["disabled"];
45784
- const _hoisted_10$4 = {
46004
+ const _hoisted_4$4 = ["onClick"];
46005
+ const _hoisted_5$4 = { class: "result-title" };
46006
+ const _hoisted_6$4 = { class: "operation-name" };
46007
+ const _hoisted_7$4 = { class: "operation-time" };
46008
+ const _hoisted_8$4 = {
45785
46009
  key: 0,
45786
- class: "spinner-border spinner-border-sm me-2"
46010
+ class: "result-body"
45787
46011
  };
45788
- const _hoisted_11$4 = { class: "modal-dialog modal-lg" };
45789
- const _hoisted_12$4 = { class: "modal-content" };
45790
- const _hoisted_13$4 = { class: "modal-body" };
46012
+ const _hoisted_9$4 = ["innerHTML"];
46013
+ const _hoisted_10$4 = { class: "modal-dialog" };
46014
+ const _hoisted_11$4 = { class: "modal-content" };
46015
+ const _hoisted_12$4 = { class: "modal-body" };
46016
+ const _hoisted_13$4 = { class: "mb-3" };
45791
46017
  const _hoisted_14$4 = {
45792
46018
  key: 0,
45793
- class: "text-center py-4"
46019
+ class: "alert alert-info"
46020
+ };
46021
+ const _hoisted_15$4 = { class: "mb-3 form-check" };
46022
+ const _hoisted_16$4 = { class: "modal-footer" };
46023
+ const _hoisted_17$4 = ["disabled"];
46024
+ const _hoisted_18$4 = {
46025
+ key: 0,
46026
+ class: "spinner-border spinner-border-sm me-2"
45794
46027
  };
45795
- const _hoisted_15$4 = { key: 1 };
45796
- const _hoisted_16$4 = { class: "health-results" };
45797
- const _hoisted_17$4 = { class: "health-status" };
45798
- const _hoisted_18$4 = { class: "health-message text-wrap" };
45799
46028
  const _sfc_main$4 = /* @__PURE__ */ defineComponent({
45800
46029
  __name: "db-tools",
45801
46030
  props: {
@@ -45808,95 +46037,174 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
45808
46037
  const emit = __emit;
45809
46038
  const databaseService2 = new DatabaseService();
45810
46039
  const restoreModalVisible = ref(false);
45811
- const healthModalVisible = ref(false);
45812
46040
  const selectedFile = ref(null);
45813
46041
  const restoring = ref(false);
45814
- const healthChecking = ref(false);
45815
- const healthResults = ref([]);
46042
+ const resultsContentRef = ref(null);
46043
+ const executionResults = ref([]);
45816
46044
  const restoreOptions = ref({
45817
46045
  dropExisting: false
45818
46046
  });
46047
+ function addExecutionResult(operation, status, data) {
46048
+ const timestamp = (/* @__PURE__ */ new Date()).toLocaleString("zh-CN", {
46049
+ year: "numeric",
46050
+ month: "2-digit",
46051
+ day: "2-digit",
46052
+ hour: "2-digit",
46053
+ minute: "2-digit",
46054
+ second: "2-digit"
46055
+ });
46056
+ executionResults.value.unshift({
46057
+ operation,
46058
+ status,
46059
+ timestamp,
46060
+ data,
46061
+ expanded: false
46062
+ });
46063
+ if (executionResults.value.length > 50) {
46064
+ executionResults.value = executionResults.value.slice(0, 50);
46065
+ }
46066
+ setTimeout(() => {
46067
+ if (resultsContentRef.value) {
46068
+ resultsContentRef.value.scrollTop = 0;
46069
+ }
46070
+ }, 100);
46071
+ }
46072
+ function clearResults() {
46073
+ executionResults.value = [];
46074
+ }
46075
+ function toggleResult(index) {
46076
+ const result = executionResults.value[index];
46077
+ if (result) {
46078
+ result.expanded = !result.expanded;
46079
+ }
46080
+ }
46081
+ function formatError(error) {
46082
+ const formatted = {
46083
+ success: false,
46084
+ message: error.msg || error.message || "未知错误"
46085
+ };
46086
+ if (error.stack) {
46087
+ formatted.stack = error.stack;
46088
+ }
46089
+ return formatted;
46090
+ }
46091
+ function highlightJson(data) {
46092
+ if (data === null || data === void 0) return "";
46093
+ const jsonStr = JSON.stringify(data, null, 2);
46094
+ return jsonStr.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function(match) {
46095
+ let cls = "json-number";
46096
+ if (/^"/.test(match)) {
46097
+ if (/:$/.test(match)) {
46098
+ cls = "json-key";
46099
+ } else {
46100
+ cls = "json-string";
46101
+ }
46102
+ } else if (/true|false/.test(match)) {
46103
+ cls = "json-boolean";
46104
+ } else if (/null/.test(match)) {
46105
+ cls = "json-null";
46106
+ }
46107
+ return '<span class="' + cls + '">' + match + "</span>";
46108
+ });
46109
+ }
46110
+ function getResultIcon(status) {
46111
+ switch (status) {
46112
+ case "success":
46113
+ return "bi bi-check-circle-fill text-success";
46114
+ case "error":
46115
+ return "bi bi-x-circle-fill text-danger";
46116
+ case "info":
46117
+ return "bi bi-info-circle-fill text-info";
46118
+ default:
46119
+ return "bi bi-dash-circle-fill text-secondary";
46120
+ }
46121
+ }
45819
46122
  async function backupDatabase() {
46123
+ const operation = "备份数据库";
45820
46124
  try {
45821
- const res = await databaseService2.backupDatabase(props.connection?.id || "", props.database);
45822
- if (res.ret === 0) await modal.success("数据库备份成功");
45823
- else {
45824
- modal.error(res.msg || "备份失败", {
45825
- operation: "BACKUP",
45826
- database: props.database
45827
- });
46125
+ const res2 = await databaseService2.backupDatabase(props.connection?.id || "", props.database);
46126
+ if (res2.ret === 0) {
46127
+ addExecutionResult(operation, "success", res2);
46128
+ } else {
46129
+ modal.error(res2.msg || "备份失败");
46130
+ addExecutionResult(operation, "error", formatError(res2));
45828
46131
  }
45829
46132
  } catch (error) {
45830
46133
  console.error("备份失败:", error);
45831
- modal.error(error.msg || error.message || "备份失败", {
45832
- operation: "BACKUP",
45833
- database: props.database,
45834
- //options: backupOptions.value,
45835
- stack: error.stack
45836
- });
46134
+ modal.error(error.msg || error.message || "备份失败");
46135
+ addExecutionResult(operation, "error", formatError(error));
45837
46136
  }
45838
46137
  }
45839
46138
  function showUsersList() {
45840
- modal.info("用户列表功能开发中...");
46139
+ addExecutionResult("用户列表", "info", { message: "用户列表功能开发中..." });
45841
46140
  }
45842
46141
  function showCreateUserModal() {
45843
- modal.info("创建用户功能开发中...");
46142
+ addExecutionResult("创建用户", "info", { message: "创建用户功能开发中..." });
45844
46143
  }
45845
46144
  function showPermissionsModal() {
45846
- modal.info("权限管理功能开发中...");
46145
+ addExecutionResult("权限管理", "info", { message: "权限管理功能开发中..." });
45847
46146
  }
45848
46147
  function showProcessList() {
45849
46148
  const sql2 = "SHOW PROCESSLIST";
46149
+ addExecutionResult("进程列表", "info", { sql: sql2, message: "已发送 SQL 查询" });
45850
46150
  emit("execute-sql", sql2);
45851
46151
  }
45852
46152
  function showSlowQueries() {
45853
46153
  const sql2 = "SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 10";
46154
+ addExecutionResult("慢查询", "info", { sql: sql2, message: "已发送 SQL 查询" });
45854
46155
  emit("execute-sql", sql2);
45855
46156
  }
45856
46157
  function showConnectionsList() {
45857
46158
  const sql2 = 'SHOW STATUS LIKE "Threads_connected"';
46159
+ addExecutionResult("连接数", "info", { sql: sql2, message: "已发送 SQL 查询" });
45858
46160
  emit("execute-sql", sql2);
45859
46161
  }
45860
46162
  async function optimizeDatabase() {
46163
+ const operation = "优化数据库";
45861
46164
  try {
45862
- await databaseService2.optimizeDatabase(props.connection?.id || "", props.database);
45863
- await modal.success("数据库优化完成");
46165
+ const res2 = await databaseService2.optimizeDatabase(props.connection?.id || "", props.database);
46166
+ if (res2.ret === 0) {
46167
+ addExecutionResult(operation, "success", res2.data);
46168
+ } else {
46169
+ modal.error(res2.msg || "优化失败");
46170
+ addExecutionResult(operation, "error", formatError(res2));
46171
+ }
45864
46172
  } catch (error) {
45865
46173
  console.error("优化失败:", error);
45866
- modal.error(error.msg || error.message || "优化失败", {
45867
- operation: "OPTIMIZE",
45868
- database: props.database,
45869
- //options: optimizationOptions.value,
45870
- stack: error.stack
45871
- });
46174
+ modal.error(error.msg || error.message || "优化失败");
46175
+ addExecutionResult(operation, "error", formatError(error));
45872
46176
  }
45873
46177
  }
45874
46178
  async function analyzeTables() {
46179
+ const operation = "分析表";
45875
46180
  try {
45876
- await databaseService2.analyzeTables(props.connection?.id || "", props.database);
45877
- await modal.success("表分析完成");
46181
+ const res2 = await databaseService2.analyzeTables(props.connection?.id || "", props.database);
46182
+ if (res2.ret === 0) {
46183
+ addExecutionResult(operation, "success", res2.data);
46184
+ } else {
46185
+ modal.error(res2.msg || "分析失败");
46186
+ addExecutionResult(operation, "error", formatError(res2));
46187
+ }
45878
46188
  } catch (error) {
45879
46189
  console.error("分析失败:", error);
45880
- modal.error(error.msg || error.message || "分析失败", {
45881
- operation: "ANALYZE",
45882
- database: props.database,
45883
- //options: analysisOptions.value,
45884
- stack: error.stack
45885
- });
46190
+ modal.error(res.msg || error.message || "分析失败");
46191
+ addExecutionResult(operation, "error", formatError(error));
45886
46192
  }
45887
46193
  }
45888
46194
  async function repairTables() {
46195
+ const operation = "修复表";
45889
46196
  try {
45890
- await databaseService2.repairTables(props.connection?.id || "", props.database);
45891
- await modal.success("表修复完成");
46197
+ const res2 = await databaseService2.repairTables(props.connection?.id || "", props.database);
46198
+ if (res2.ret === 0) {
46199
+ addExecutionResult(operation, "success", res2.data);
46200
+ } else {
46201
+ modal.error(res2.msg || "修复失败");
46202
+ addExecutionResult(operation, "error", formatError(res2));
46203
+ }
45892
46204
  } catch (error) {
45893
46205
  console.error("修复失败:", error);
45894
- modal.error(error.msg || error.message || "修复失败", {
45895
- operation: "REPAIR",
45896
- database: props.database,
45897
- //options: repairOptions.value,
45898
- stack: error.stack
45899
- });
46206
+ modal.error(res.msg || error.message || "修复失败");
46207
+ addExecutionResult(operation, "error", formatError(error));
45900
46208
  }
45901
46209
  }
45902
46210
  async function clearLogs() {
@@ -45905,62 +46213,62 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
45905
46213
  "TRUNCATE TABLE mysql.general_log",
45906
46214
  "FLUSH LOGS"
45907
46215
  ];
45908
- logs.forEach((sql2) => emit("execute-sql", sql2));
45909
- await modal.success("日志清理完成");
46216
+ logs.forEach((sql2) => {
46217
+ addExecutionResult(`清理日志 - ${sql2.split(" ")[1]}`, "info", { sql: sql2, message: "已发送 SQL 查询" });
46218
+ emit("execute-sql", sql2);
46219
+ });
45910
46220
  }
45911
46221
  function showExportModal() {
45912
- modal.info("导出结构功能开发中...");
46222
+ addExecutionResult("导出结构", "info", { message: "导出结构功能开发中..." });
45913
46223
  }
45914
46224
  function showImportModal() {
45915
- modal.info("导入数据功能开发中...");
46225
+ addExecutionResult("导入数据", "info", { message: "导入数据功能开发中..." });
45916
46226
  }
45917
46227
  function showSyncModal() {
45918
- modal.info("数据同步功能开发中...");
46228
+ addExecutionResult("数据同步", "info", { message: "数据同步功能开发中..." });
45919
46229
  }
45920
46230
  async function runHealthCheck() {
45921
- healthChecking.value = true;
45922
- healthResults.value = [];
45923
- try {
45924
- const checks = [
45925
- { name: "连接状态", sql: "SELECT 1 as status" },
45926
- { name: "表完整性", sql: 'SELECT COUNT(*) as status FROM information_schema.tables WHERE table_schema = DATABASE() AND table_type = "BASE TABLE"' },
45927
- { name: "索引状态", sql: "SELECT COUNT(*) as status FROM information_schema.statistics WHERE table_schema = DATABASE()" },
45928
- { name: "磁盘空间", sql: "SELECT SUM(data_length + index_length) as status FROM information_schema.tables WHERE table_schema = DATABASE()" }
45929
- ];
45930
- for (const check of checks) {
45931
- try {
45932
- healthResults.value.push({
45933
- name: check.name,
45934
- status: "healthy",
45935
- message: "正常"
45936
- });
45937
- } catch (error) {
45938
- healthResults.value.push({
45939
- name: check.name,
45940
- status: "error",
45941
- message: error.message
45942
- });
45943
- }
46231
+ const operation = "健康检查";
46232
+ const checks = [
46233
+ { name: "连接状态", sql: "SELECT 1 as status" },
46234
+ { name: "表完整性", sql: 'SELECT COUNT(*) as status FROM information_schema.tables WHERE table_schema = DATABASE() AND table_type = "BASE TABLE"' },
46235
+ { name: "索引状态", sql: "SELECT COUNT(*) as status FROM information_schema.statistics WHERE table_schema = DATABASE()" },
46236
+ { name: "磁盘空间", sql: "SELECT SUM(data_length + index_length) as status FROM information_schema.tables WHERE table_schema = DATABASE()" }
46237
+ ];
46238
+ const results = [];
46239
+ for (const check of checks) {
46240
+ try {
46241
+ results.push({
46242
+ name: check.name,
46243
+ status: "healthy",
46244
+ message: "正常"
46245
+ });
46246
+ } catch (error) {
46247
+ results.push({
46248
+ name: check.name,
46249
+ status: "error",
46250
+ message: error.message
46251
+ });
45944
46252
  }
45945
- healthModalVisible.value = true;
45946
- } finally {
45947
- healthChecking.value = false;
45948
46253
  }
46254
+ addExecutionResult(operation, "success", { checks: results });
45949
46255
  }
45950
46256
  function showStatistics() {
45951
46257
  const sql2 = `
45952
- SELECT
46258
+ SELECT
45953
46259
  table_name as '表名',
45954
46260
  table_rows as '记录数',
45955
46261
  ROUND(((data_length + index_length) / 1024 / 1024), 2) as '大小(MB)'
45956
- FROM information_schema.tables
45957
- WHERE table_schema = DATABASE()
46262
+ FROM information_schema.tables
46263
+ WHERE table_schema = DATABASE()
45958
46264
  ORDER BY (data_length + index_length) DESC
45959
46265
  `;
46266
+ addExecutionResult("数据统计", "info", { sql: sql2, message: "已发送 SQL 查询" });
45960
46267
  emit("execute-sql", sql2);
45961
46268
  }
45962
46269
  function showAuditLog() {
45963
46270
  const sql2 = "SELECT * FROM mysql.general_log ORDER BY event_time DESC LIMIT 100";
46271
+ addExecutionResult("审计日志", "info", { sql: sql2, message: "已发送 SQL 查询" });
45964
46272
  emit("execute-sql", sql2);
45965
46273
  }
45966
46274
  function showRestoreModal() {
@@ -45972,39 +46280,32 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
45972
46280
  }
45973
46281
  async function performRestore() {
45974
46282
  if (!selectedFile.value) return;
46283
+ const operation = "恢复数据库";
45975
46284
  try {
45976
46285
  restoring.value = true;
45977
46286
  const filePath = selectedFile.value.name;
45978
- await databaseService2.restoreDatabase(
46287
+ const res2 = await databaseService2.restoreDatabase(
45979
46288
  props.connection?.id || "",
45980
46289
  props.database,
45981
46290
  filePath,
45982
46291
  { dropExisting: restoreOptions.value.dropExisting }
45983
46292
  );
45984
- await modal.success("数据库恢复成功");
46293
+ addExecutionResult(operation, "success", res2);
45985
46294
  closeRestoreModal();
45986
46295
  } catch (error) {
45987
46296
  console.error("恢复失败:", error);
45988
- modal.error(error.msg || error.message || "恢复失败", {
45989
- operation: "RESTORE",
45990
- database: props.database,
45991
- //file: restoreFile.value,
45992
- stack: error.stack
45993
- });
46297
+ modal.error(error.msg || error.message || "恢复失败");
46298
+ addExecutionResult(operation, "error", formatError(error));
45994
46299
  } finally {
45995
46300
  restoring.value = false;
45996
46301
  }
45997
46302
  }
45998
- function closeHealthModal() {
45999
- healthModalVisible.value = false;
46000
- healthResults.value = [];
46001
- }
46002
46303
  function showScheduleModal() {
46003
- modal.info("定时备份功能开发中...");
46304
+ addExecutionResult("定时备份", "info", { message: "定时备份功能开发中..." });
46004
46305
  }
46005
46306
  return (_ctx, _cache) => {
46006
46307
  return openBlock(), createElementBlock("div", _hoisted_1$4, [
46007
- _cache[33] || (_cache[33] = createBaseVNode("div", { class: "tools-header" }, [
46308
+ _cache[34] || (_cache[34] = createBaseVNode("div", { class: "tools-header" }, [
46008
46309
  createBaseVNode("h5", { class: "tools-title" }, [
46009
46310
  createBaseVNode("i", { class: "bi bi-tools" }),
46010
46311
  createTextVNode(" 数据库管理工具 ")
@@ -46193,23 +46494,77 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
46193
46494
  ])
46194
46495
  ])
46195
46496
  ]),
46497
+ createBaseVNode("div", _hoisted_2$4, [
46498
+ createBaseVNode("div", { class: "results-header" }, [
46499
+ _cache[28] || (_cache[28] = createBaseVNode("h6", { class: "results-title" }, [
46500
+ createBaseVNode("i", { class: "bi bi-terminal" }),
46501
+ createTextVNode(" 执行结果 ")
46502
+ ], -1)),
46503
+ createBaseVNode("button", {
46504
+ class: "btn btn-outline-secondary btn-sm",
46505
+ onClick: clearResults
46506
+ }, [..._cache[27] || (_cache[27] = [
46507
+ createBaseVNode("i", { class: "bi bi-trash" }, null, -1),
46508
+ createTextVNode(" 清空 ", -1)
46509
+ ])])
46510
+ ]),
46511
+ createBaseVNode("div", {
46512
+ class: "results-content",
46513
+ ref_key: "resultsContentRef",
46514
+ ref: resultsContentRef
46515
+ }, [
46516
+ executionResults.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_3$4, [..._cache[29] || (_cache[29] = [
46517
+ createBaseVNode("i", { class: "bi bi-inbox" }, null, -1),
46518
+ createBaseVNode("p", null, "暂无执行结果", -1)
46519
+ ])])) : createCommentVNode("", true),
46520
+ (openBlock(true), createElementBlock(Fragment, null, renderList(executionResults.value, (result, index) => {
46521
+ return openBlock(), createElementBlock("div", {
46522
+ key: index,
46523
+ class: normalizeClass(["result-item", `result-${result.status}`])
46524
+ }, [
46525
+ createBaseVNode("div", {
46526
+ class: "result-header",
46527
+ onClick: ($event) => toggleResult(index)
46528
+ }, [
46529
+ createBaseVNode("div", _hoisted_5$4, [
46530
+ createBaseVNode("i", {
46531
+ class: normalizeClass(getResultIcon(result.status))
46532
+ }, null, 2),
46533
+ createBaseVNode("span", _hoisted_6$4, toDisplayString(result.operation), 1),
46534
+ createBaseVNode("span", _hoisted_7$4, toDisplayString(result.timestamp), 1)
46535
+ ]),
46536
+ createBaseVNode("i", {
46537
+ class: normalizeClass(["bi bi-chevron-down toggle-icon", { "expanded": result.expanded }])
46538
+ }, null, 2)
46539
+ ], 8, _hoisted_4$4),
46540
+ result.expanded ? (openBlock(), createElementBlock("div", _hoisted_8$4, [
46541
+ createBaseVNode("pre", null, [
46542
+ createBaseVNode("code", {
46543
+ innerHTML: highlightJson(result.data)
46544
+ }, null, 8, _hoisted_9$4)
46545
+ ])
46546
+ ])) : createCommentVNode("", true)
46547
+ ], 2);
46548
+ }), 128))
46549
+ ], 512)
46550
+ ]),
46196
46551
  createBaseVNode("div", {
46197
46552
  class: normalizeClass(["modal fade", { show: restoreModalVisible.value }]),
46198
46553
  style: normalizeStyle({ display: restoreModalVisible.value ? "block" : "none", zIndex: 1055 })
46199
46554
  }, [
46200
- createBaseVNode("div", _hoisted_2$4, [
46201
- createBaseVNode("div", _hoisted_3$4, [
46555
+ createBaseVNode("div", _hoisted_10$4, [
46556
+ createBaseVNode("div", _hoisted_11$4, [
46202
46557
  createBaseVNode("div", { class: "modal-header" }, [
46203
- _cache[27] || (_cache[27] = createBaseVNode("h5", { class: "modal-title" }, "恢复数据库", -1)),
46558
+ _cache[30] || (_cache[30] = createBaseVNode("h5", { class: "modal-title" }, "恢复数据库", -1)),
46204
46559
  createBaseVNode("button", {
46205
46560
  type: "button",
46206
46561
  class: "btn-close",
46207
46562
  onClick: closeRestoreModal
46208
46563
  })
46209
46564
  ]),
46210
- createBaseVNode("div", _hoisted_4$4, [
46211
- _cache[29] || (_cache[29] = createBaseVNode("p", null, "请选择要恢复的备份文件:", -1)),
46212
- createBaseVNode("div", _hoisted_5$4, [
46565
+ createBaseVNode("div", _hoisted_12$4, [
46566
+ _cache[32] || (_cache[32] = createBaseVNode("p", null, "请选择要恢复的备份文件:", -1)),
46567
+ createBaseVNode("div", _hoisted_13$4, [
46213
46568
  createBaseVNode("input", {
46214
46569
  type: "file",
46215
46570
  class: "form-control",
@@ -46218,8 +46573,8 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
46218
46573
  accept: ".sql,.bak"
46219
46574
  }, null, 32)
46220
46575
  ]),
46221
- selectedFile.value ? (openBlock(), createElementBlock("div", _hoisted_6$4, " 已选择文件:" + toDisplayString(selectedFile.value.name), 1)) : createCommentVNode("", true),
46222
- createBaseVNode("div", _hoisted_7$4, [
46576
+ selectedFile.value ? (openBlock(), createElementBlock("div", _hoisted_14$4, " 已选择文件:" + toDisplayString(selectedFile.value.name), 1)) : createCommentVNode("", true),
46577
+ createBaseVNode("div", _hoisted_15$4, [
46223
46578
  withDirectives(createBaseVNode("input", {
46224
46579
  type: "checkbox",
46225
46580
  class: "form-check-input",
@@ -46228,13 +46583,13 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
46228
46583
  }, null, 512), [
46229
46584
  [vModelCheckbox, restoreOptions.value.dropExisting]
46230
46585
  ]),
46231
- _cache[28] || (_cache[28] = createBaseVNode("label", {
46586
+ _cache[31] || (_cache[31] = createBaseVNode("label", {
46232
46587
  class: "form-check-label",
46233
46588
  for: "dropExisting"
46234
46589
  }, "删除现有表", -1))
46235
46590
  ])
46236
46591
  ]),
46237
- createBaseVNode("div", _hoisted_8$4, [
46592
+ createBaseVNode("div", _hoisted_16$4, [
46238
46593
  createBaseVNode("button", {
46239
46594
  type: "button",
46240
46595
  class: "btn btn-secondary",
@@ -46246,59 +46601,9 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
46246
46601
  onClick: performRestore,
46247
46602
  disabled: !selectedFile.value
46248
46603
  }, [
46249
- restoring.value ? (openBlock(), createElementBlock("span", _hoisted_10$4)) : createCommentVNode("", true),
46250
- _cache[30] || (_cache[30] = createTextVNode(" 恢复 ", -1))
46251
- ], 8, _hoisted_9$4)
46252
- ])
46253
- ])
46254
- ])
46255
- ], 6),
46256
- createBaseVNode("div", {
46257
- class: normalizeClass(["modal fade", { show: healthModalVisible.value }]),
46258
- style: normalizeStyle({ display: healthModalVisible.value ? "block" : "none", zIndex: 1055 })
46259
- }, [
46260
- createBaseVNode("div", _hoisted_11$4, [
46261
- createBaseVNode("div", _hoisted_12$4, [
46262
- createBaseVNode("div", { class: "modal-header" }, [
46263
- _cache[31] || (_cache[31] = createBaseVNode("h5", { class: "modal-title" }, "数据库健康检查", -1)),
46264
- createBaseVNode("button", {
46265
- type: "button",
46266
- class: "btn-close",
46267
- onClick: closeHealthModal
46268
- })
46269
- ]),
46270
- createBaseVNode("div", _hoisted_13$4, [
46271
- healthChecking.value ? (openBlock(), createElementBlock("div", _hoisted_14$4, [..._cache[32] || (_cache[32] = [
46272
- createBaseVNode("div", {
46273
- class: "spinner-border text-primary",
46274
- role: "status"
46275
- }, null, -1),
46276
- createBaseVNode("div", { class: "mt-3" }, "正在检查数据库健康状况...", -1)
46277
- ])])) : (openBlock(), createElementBlock("div", _hoisted_15$4, [
46278
- createBaseVNode("div", _hoisted_16$4, [
46279
- (openBlock(true), createElementBlock(Fragment, null, renderList(healthResults.value, (check) => {
46280
- return openBlock(), createElementBlock("div", {
46281
- key: check.name,
46282
- class: "health-item"
46283
- }, [
46284
- createBaseVNode("div", _hoisted_17$4, [
46285
- createBaseVNode("i", {
46286
- class: normalizeClass(check.status === "healthy" ? "bi bi-check-circle-fill text-success" : check.status === "warning" ? "bi bi-exclamation-triangle-fill text-warning" : "bi bi-x-circle-fill text-danger")
46287
- }, null, 2),
46288
- createTextVNode(" " + toDisplayString(check.name), 1)
46289
- ]),
46290
- createBaseVNode("div", _hoisted_18$4, toDisplayString(check.message), 1)
46291
- ]);
46292
- }), 128))
46293
- ])
46294
- ]))
46295
- ]),
46296
- createBaseVNode("div", { class: "modal-footer" }, [
46297
- createBaseVNode("button", {
46298
- type: "button",
46299
- class: "btn btn-secondary",
46300
- onClick: closeHealthModal
46301
- }, "关闭")
46604
+ restoring.value ? (openBlock(), createElementBlock("span", _hoisted_18$4)) : createCommentVNode("", true),
46605
+ _cache[33] || (_cache[33] = createTextVNode(" 恢复 ", -1))
46606
+ ], 8, _hoisted_17$4)
46302
46607
  ])
46303
46608
  ])
46304
46609
  ])
@@ -46307,7 +46612,7 @@ const _sfc_main$4 = /* @__PURE__ */ defineComponent({
46307
46612
  };
46308
46613
  }
46309
46614
  });
46310
- const DbTools = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-94a9d8f2"]]);
46615
+ const DbTools = /* @__PURE__ */ _export_sfc(_sfc_main$4, [["__scopeId", "data-v-b1c1e4d6"]]);
46311
46616
  const _hoisted_1$3 = { class: "database-detail" };
46312
46617
  const _hoisted_2$3 = { class: "database-header" };
46313
46618
  const _hoisted_3$3 = { class: "database-header-content" };
@@ -47235,69 +47540,6 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
47235
47540
  }
47236
47541
  });
47237
47542
  const DatabaseDetail = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-fd20d470"]]);
47238
- function isNumericType(type) {
47239
- const numericTypes = [
47240
- "int",
47241
- "integer",
47242
- "tinyint",
47243
- "smallint",
47244
- "mediumint",
47245
- "bigint",
47246
- "decimal",
47247
- "numeric",
47248
- "float",
47249
- "double",
47250
- "real",
47251
- "number",
47252
- "smallserial",
47253
- "serial",
47254
- "bigserial",
47255
- "money",
47256
- "smallmoney",
47257
- "binary_float",
47258
- "binary_double"
47259
- ];
47260
- return numericTypes.some((t2) => type.toLowerCase().includes(t2));
47261
- }
47262
- function isTextType(type) {
47263
- const textTypes = [
47264
- "text",
47265
- "longtext",
47266
- "mediumtext",
47267
- "tinytext",
47268
- "clob",
47269
- "nclob",
47270
- "ntext"
47271
- ];
47272
- return textTypes.some((t2) => type.toLowerCase().includes(t2));
47273
- }
47274
- function isDateTimeType(type) {
47275
- const dateTimeTypes = [
47276
- "date",
47277
- "datetime",
47278
- "timestamp",
47279
- "time",
47280
- "year",
47281
- "time with time zone",
47282
- "timestamp with time zone",
47283
- "timestamp with local time zone",
47284
- "interval",
47285
- "datetimeoffset",
47286
- "datetime2",
47287
- "smalldatetime"
47288
- ];
47289
- return dateTimeTypes.some((t2) => type.toLowerCase().includes(t2));
47290
- }
47291
- function isBooleanType(type) {
47292
- const booleanTypes = ["boolean", "bool", "bit", "tinyint(1)"];
47293
- return booleanTypes.some((t2) => type.toLowerCase().includes(t2));
47294
- }
47295
- function isJsonType(type) {
47296
- return ["json", "jsonb"].includes(type.toLowerCase());
47297
- }
47298
- function isArrayType(type) {
47299
- return type.toLowerCase().endsWith("[]");
47300
- }
47301
47543
  const _hoisted_1$2 = { class: "modal-dialog modal-lg" };
47302
47544
  const _hoisted_2$2 = { class: "modal-content" };
47303
47545
  const _hoisted_3$2 = {
@@ -47396,7 +47638,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
47396
47638
  formData.value[column.name] = column.defaultValue;
47397
47639
  } else if (column.nullable) {
47398
47640
  formData.value[column.name] = null;
47399
- } else if (isBooleanInput2(column.type)) {
47641
+ } else if (isBooleanInput(column.type)) {
47400
47642
  formData.value[column.name] = false;
47401
47643
  } else if (isJsonInput(column.type) || isArrayInput(column.type)) {
47402
47644
  formData.value[column.name] = {};
@@ -47407,7 +47649,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
47407
47649
  }
47408
47650
  });
47409
47651
  }
47410
- function isNumberInput2(type) {
47652
+ function isNumberInput(type) {
47411
47653
  return isNumericType(type);
47412
47654
  }
47413
47655
  function isDecimalInput(type) {
@@ -47422,7 +47664,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
47422
47664
  function isEnumInput(type) {
47423
47665
  return type.toLowerCase().startsWith("enum");
47424
47666
  }
47425
- function isBooleanInput2(type) {
47667
+ function isBooleanInput(type) {
47426
47668
  return isBooleanType(type);
47427
47669
  }
47428
47670
  function isJsonInput(type, inputtype) {
@@ -47592,7 +47834,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
47592
47834
  value: __props.isEdit ? formData.value[column.name] : "自动生成",
47593
47835
  disabled: "",
47594
47836
  readonly: ""
47595
- }, null, 8, _hoisted_13$2)) : isNumberInput2(column.type) ? withDirectives((openBlock(), createElementBlock("input", {
47837
+ }, null, 8, _hoisted_13$2)) : isNumberInput(column.type) ? withDirectives((openBlock(), createElementBlock("input", {
47596
47838
  key: 1,
47597
47839
  type: "number",
47598
47840
  "data-type": "number",
@@ -47638,7 +47880,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
47638
47880
  }), 128))
47639
47881
  ], 8, _hoisted_17$2)), [
47640
47882
  [vModelSelect, formData.value[column.name]]
47641
- ]) : isBooleanInput2(column.type) ? withDirectives((openBlock(), createElementBlock("select", {
47883
+ ]) : isBooleanInput(column.type) ? withDirectives((openBlock(), createElementBlock("select", {
47642
47884
  key: 5,
47643
47885
  class: "form-select",
47644
47886
  "data-type": "boolean",
@@ -48474,9 +48716,11 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
48474
48716
  createBaseVNode("tbody", null, [
48475
48717
  (openBlock(true), createElementBlock(Fragment, null, renderList(paginatedData.value, (row, index) => {
48476
48718
  return openBlock(), createElementBlock("tr", { key: index }, [
48477
- (openBlock(true), createElementBlock(Fragment, null, renderList(row, (value, key) => {
48478
- return openBlock(), createElementBlock("td", { key }, [
48479
- createBaseVNode("div", _hoisted_41, toDisplayString(formatCellValue(value)), 1)
48719
+ (openBlock(true), createElementBlock(Fragment, null, renderList(safeTableColumns.value, (column) => {
48720
+ return openBlock(), createElementBlock("td", {
48721
+ key: column.name
48722
+ }, [
48723
+ createBaseVNode("div", _hoisted_41, toDisplayString(formatCellValue(row[column.name])), 1)
48480
48724
  ]);
48481
48725
  }), 128)),
48482
48726
  createBaseVNode("td", null, [
@@ -48887,15 +49131,16 @@ const _sfc_main$1 = /* @__PURE__ */ defineComponent({
48887
49131
  connection: __props.connection,
48888
49132
  database: __props.database,
48889
49133
  table: __props.table,
49134
+ columns: __props.tableStructure?.columns,
48890
49135
  mode: tableEditorMode.value,
48891
49136
  onClose: closeTableEditor,
48892
49137
  onSubmit: handleTableStructureChange
48893
- }, null, 8, ["visible", "connection", "database", "table", "mode"])
49138
+ }, null, 8, ["visible", "connection", "database", "table", "columns", "mode"])
48894
49139
  ]);
48895
49140
  };
48896
49141
  }
48897
49142
  });
48898
- const TableDetail = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-365fca24"]]);
49143
+ const TableDetail = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-131c5ea4"]]);
48899
49144
  const _hoisted_1 = { class: "database-explorer" };
48900
49145
  const _hoisted_2 = { class: "explorer-layout" };
48901
49146
  const _hoisted_3 = { class: "explorer-sidebar" };