fdb2 1.0.11 → 1.0.12

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.
@@ -1062,10 +1062,38 @@ pre {
1062
1062
  }
1063
1063
  }
1064
1064
 
1065
- .datagrid-inner[data-v-9bff1755] {
1065
+ .datagrid-container[data-v-ae552d25] {
1066
+ display: flex;
1067
+ flex-direction: column;
1068
+ height: 100%;
1069
+ }
1070
+ .datagrid-inner[data-v-ae552d25] {
1071
+ flex: 1;
1066
1072
  overflow: auto;
1067
1073
  margin-bottom: 10px;
1068
1074
  }
1069
- .datagrid-th[data-v-9bff1755] {
1075
+ .datagrid-th[data-v-ae552d25] {
1070
1076
  min-width: 80px;
1077
+ white-space: nowrap;
1078
+ position: sticky;
1079
+ top: 0;
1080
+ z-index: 10;
1081
+ background-color: #f8f9fa;
1082
+ }
1083
+ .datagrid-th.sortable[data-v-ae552d25] {
1084
+ cursor: pointer;
1085
+ user-select: none;
1086
+ }
1087
+ .datagrid-th.sortable[data-v-ae552d25]:hover {
1088
+ background-color: #e9ecef;
1089
+ }
1090
+ .header-content[data-v-ae552d25] {
1091
+ display: flex;
1092
+ align-items: center;
1093
+ gap: 0.5rem;
1094
+ }
1095
+ .sort-icon[data-v-ae552d25] {
1096
+ display: flex;
1097
+ align-items: center;
1098
+ font-size: 0.75rem;
1071
1099
  }
@@ -12051,8 +12051,8 @@ const _hoisted_7$1 = {
12051
12051
  key: 0,
12052
12052
  class: "error-details-content mt-2"
12053
12053
  };
12054
- const _hoisted_8 = { class: "error-json" };
12055
- const _hoisted_9 = { class: "modal-footer" };
12054
+ const _hoisted_8$1 = { class: "error-json" };
12055
+ const _hoisted_9$1 = { class: "modal-footer" };
12056
12056
  const _sfc_main$2 = /* @__PURE__ */ defineComponent({
12057
12057
  __name: "index",
12058
12058
  props: {
@@ -12423,12 +12423,12 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
12423
12423
  _cache[0] || (_cache[0] = createBaseVNode("i", { class: "bi bi-chevron-{{detailsExpanded ? 'up' : 'down'}} ms-1" }, null, -1))
12424
12424
  ]),
12425
12425
  detailsExpanded.value ? (openBlock(), createElementBlock("div", _hoisted_7$1, [
12426
- createBaseVNode("pre", _hoisted_8, toDisplayString(formatErrorDetails()), 1)
12426
+ createBaseVNode("pre", _hoisted_8$1, toDisplayString(formatErrorDetails()), 1)
12427
12427
  ])) : createCommentVNode("", true)
12428
12428
  ])) : createCommentVNode("", true)
12429
12429
  ]))
12430
12430
  ])) : createCommentVNode("", true),
12431
- createBaseVNode("div", _hoisted_9, [
12431
+ createBaseVNode("div", _hoisted_9$1, [
12432
12432
  _ctx.$slots.footer ? renderSlot(_ctx.$slots, "footer", { key: 0 }, void 0) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
12433
12433
  dynamicShowCancel.value || props.closeButton.show ? (openBlock(), createElementBlock("button", {
12434
12434
  key: 0,
@@ -12563,9 +12563,27 @@ const _hoisted_1 = { class: "datagrid-container" };
12563
12563
  const _hoisted_2 = { class: "datagrid-inner" };
12564
12564
  const _hoisted_3 = { class: "table table-light table-striped table-hover" };
12565
12565
  const _hoisted_4 = { class: "table-light" };
12566
- const _hoisted_5 = { class: "table-group-divider" };
12567
- const _hoisted_6 = ["onClick"];
12568
- const _hoisted_7 = { key: 1 };
12566
+ const _hoisted_5 = ["onClick"];
12567
+ const _hoisted_6 = { class: "header-content" };
12568
+ const _hoisted_7 = {
12569
+ key: 0,
12570
+ class: "sort-icon"
12571
+ };
12572
+ const _hoisted_8 = {
12573
+ key: 0,
12574
+ class: "bi bi-caret-up-fill"
12575
+ };
12576
+ const _hoisted_9 = {
12577
+ key: 1,
12578
+ class: "bi bi-caret-down-fill"
12579
+ };
12580
+ const _hoisted_10 = {
12581
+ key: 2,
12582
+ class: "bi bi-caret-up text-muted opacity-50"
12583
+ };
12584
+ const _hoisted_11 = { class: "table-group-divider" };
12585
+ const _hoisted_12 = ["onClick"];
12586
+ const _hoisted_13 = { key: 1 };
12569
12587
  const _sfc_main = /* @__PURE__ */ defineComponent({
12570
12588
  __name: "index",
12571
12589
  props: {
@@ -12597,9 +12615,18 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
12597
12615
  columns: {
12598
12616
  type: Array,
12599
12617
  default: []
12618
+ },
12619
+ sortField: {
12620
+ type: String,
12621
+ default: ""
12622
+ },
12623
+ sortOrder: {
12624
+ type: String,
12625
+ default: ""
12626
+ // ASC, DESC, ''
12600
12627
  }
12601
12628
  },
12602
- emits: ["pageChanged", "rowClicked"],
12629
+ emits: ["pageChanged", "rowClicked", "sortChanged"],
12603
12630
  setup(__props, { emit: __emit }) {
12604
12631
  const props = __props;
12605
12632
  const emits = __emit;
@@ -12613,6 +12640,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
12613
12640
  function pageChanged(page) {
12614
12641
  emits("pageChanged", page);
12615
12642
  }
12643
+ function handleSort(field) {
12644
+ let order = "ASC";
12645
+ if (props.sortField === field) {
12646
+ if (props.sortOrder === "ASC") {
12647
+ order = "DESC";
12648
+ } else if (props.sortOrder === "DESC") {
12649
+ order = "";
12650
+ }
12651
+ }
12652
+ emits("sortChanged", { field: order ? field : "", order });
12653
+ }
12616
12654
  return (_ctx, _cache) => {
12617
12655
  return openBlock(), createElementBlock("div", _hoisted_1, [
12618
12656
  createBaseVNode("div", _hoisted_2, [
@@ -12623,17 +12661,23 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
12623
12661
  return openBlock(), createElementBlock("th", {
12624
12662
  key: column.name,
12625
12663
  scope: "col",
12626
- class: "datagrid-th",
12627
- style: normalizeStyle(column.headerStyle || "")
12664
+ class: normalizeClass(["datagrid-th", { "sortable": column.sortable !== false }]),
12665
+ style: normalizeStyle(column.headerStyle || ""),
12666
+ onClick: ($event) => column.sortable !== false && handleSort(column.name)
12628
12667
  }, [
12629
12668
  renderSlot(_ctx.$slots, column.name + "_header", { column }, () => [
12630
- createBaseVNode("span", null, toDisplayString(column.text || column.name || ""), 1)
12669
+ createBaseVNode("div", _hoisted_6, [
12670
+ createBaseVNode("span", null, toDisplayString(column.text || column.name || ""), 1),
12671
+ column.sortable !== false ? (openBlock(), createElementBlock("span", _hoisted_7, [
12672
+ props.sortField === column.name && props.sortOrder === "ASC" ? (openBlock(), createElementBlock("i", _hoisted_8)) : props.sortField === column.name && props.sortOrder === "DESC" ? (openBlock(), createElementBlock("i", _hoisted_9)) : (openBlock(), createElementBlock("i", _hoisted_10))
12673
+ ])) : createCommentVNode("", true)
12674
+ ])
12631
12675
  ])
12632
- ], 4);
12676
+ ], 14, _hoisted_5);
12633
12677
  }), 128))
12634
12678
  ])
12635
12679
  ]),
12636
- createBaseVNode("tbody", _hoisted_5, [
12680
+ createBaseVNode("tbody", _hoisted_11, [
12637
12681
  (openBlock(true), createElementBlock(Fragment, null, renderList(props.data, (row, index) => {
12638
12682
  return openBlock(), createElementBlock("tr", {
12639
12683
  key: index,
@@ -12648,11 +12692,11 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
12648
12692
  row,
12649
12693
  column
12650
12694
  }, () => [
12651
- column.component ? (openBlock(), createBlock(resolveDynamicComponent(column.component), { key: 0 })) : (openBlock(), createElementBlock("span", _hoisted_7, toDisplayString(renderDataItem(row, column)), 1))
12695
+ column.component ? (openBlock(), createBlock(resolveDynamicComponent(column.component), { key: 0 })) : (openBlock(), createElementBlock("span", _hoisted_13, toDisplayString(renderDataItem(row, column)), 1))
12652
12696
  ])
12653
12697
  ]);
12654
12698
  }), 128))
12655
- ], 8, _hoisted_6);
12699
+ ], 8, _hoisted_12);
12656
12700
  }), 128))
12657
12701
  ]),
12658
12702
  createBaseVNode("tfoot", null, [
@@ -12676,7 +12720,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
12676
12720
  };
12677
12721
  }
12678
12722
  });
12679
- const DataGrid = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-9bff1755"]]);
12723
+ const DataGrid = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-ae552d25"]]);
12680
12724
  let globalModalInstance = null;
12681
12725
  let modalInstance;
12682
12726
  const modalPlugin = {
@@ -12804,6 +12848,7 @@ app.component("Modal", Modal);
12804
12848
  app.component("DataGrid", DataGrid);
12805
12849
  app.mount("#app");
12806
12850
  export {
12851
+ DataGrid as D,
12807
12852
  Modal as M,
12808
12853
  Toast as T,
12809
12854
  _export_sfc as _,
@@ -2690,6 +2690,23 @@ function renderList(source, renderItem, cache, index) {
2690
2690
  }
2691
2691
  return ret;
2692
2692
  }
2693
+ function createSlots(slots, dynamicSlots) {
2694
+ for (let i2 = 0; i2 < dynamicSlots.length; i2++) {
2695
+ const slot = dynamicSlots[i2];
2696
+ if (isArray$1(slot)) {
2697
+ for (let j2 = 0; j2 < slot.length; j2++) {
2698
+ slots[slot[j2].name] = slot[j2].fn;
2699
+ }
2700
+ } else if (slot) {
2701
+ slots[slot.name] = slot.key ? (...args) => {
2702
+ const res = slot.fn(...args);
2703
+ if (res) res.key = slot.key;
2704
+ return res;
2705
+ } : slot.fn;
2706
+ }
2707
+ }
2708
+ return slots;
2709
+ }
2693
2710
  function renderSlot(slots, name, props = {}, fallback, noSlotted) {
2694
2711
  if (currentRenderingInstance.ce || currentRenderingInstance.parent && isAsyncWrapper(currentRenderingInstance.parent) && currentRenderingInstance.parent.ce) {
2695
2712
  const hasProps = Object.keys(props).length > 0;
@@ -6661,30 +6678,6 @@ const withModifiers = (fn, modifiers) => {
6661
6678
  return fn(event, ...args);
6662
6679
  }));
6663
6680
  };
6664
- const keyNames = {
6665
- esc: "escape",
6666
- space: " ",
6667
- up: "arrow-up",
6668
- left: "arrow-left",
6669
- right: "arrow-right",
6670
- down: "arrow-down",
6671
- delete: "backspace"
6672
- };
6673
- const withKeys = (fn, modifiers) => {
6674
- const cache = fn._withKeys || (fn._withKeys = {});
6675
- const cacheKey = modifiers.join(".");
6676
- return cache[cacheKey] || (cache[cacheKey] = ((event) => {
6677
- if (!("key" in event)) {
6678
- return;
6679
- }
6680
- const eventKey = hyphenate(event.key);
6681
- if (modifiers.some(
6682
- (k2) => k2 === eventKey || keyNames[k2] === eventKey
6683
- )) {
6684
- return fn(event);
6685
- }
6686
- }));
6687
- };
6688
6681
  const rendererOptions = /* @__PURE__ */ extend({ patchProp }, nodeOps);
6689
6682
  let renderer;
6690
6683
  function ensureRenderer() {
@@ -9086,7 +9079,7 @@ export {
9086
9079
  vShow as S,
9087
9080
  useRouter as T,
9088
9081
  createStaticVNode as U,
9089
- withKeys as V,
9082
+ createSlots as V,
9090
9083
  useRoute as W,
9091
9084
  ref as a,
9092
9085
  isRef as b,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fdb2",
3
- "version": "1.0.11",
3
+ "version": "1.0.12",
4
4
  "private": false,
5
5
  "type": "commonjs",
6
6
  "main": "view/index.html",
@@ -45,64 +45,64 @@
45
45
  },
46
46
  "dependencies": {
47
47
  "@fefeding/common": "^1.0.58",
48
- "axios": "^1.13.4",
49
- "dayjs": "^1.11.19",
48
+ "axios": "^1.13.6",
49
+ "better-sqlite3": "^11.10.0",
50
+ "dayjs": "^1.11.20",
50
51
  "express": "^5.2.1",
51
- "mysql2": "^3.16.3",
52
+ "mysql2": "^3.20.0",
52
53
  "oracledb": "^6.10.0",
53
- "pg": "^8.18.0",
54
+ "pg": "^8.20.0",
54
55
  "reflect-metadata": "^0.2.2",
55
- "better-sqlite3": "^11.0.0",
56
56
  "typeorm": "^0.3.28"
57
57
  },
58
58
  "devDependencies": {
59
- "@codemirror/commands": "^6.10.1",
59
+ "@codemirror/commands": "^6.10.3",
60
60
  "@codemirror/fold": "^0.19.4",
61
61
  "@codemirror/lang-json": "^6.0.2",
62
62
  "@codemirror/lang-sql": "^6.10.0",
63
- "@codemirror/language": "^6.12.1",
64
- "@codemirror/state": "^6.5.4",
63
+ "@codemirror/language": "^6.12.3",
64
+ "@codemirror/state": "^6.6.0",
65
65
  "@codemirror/theme-one-dark": "^6.1.3",
66
- "@codemirror/view": "^6.39.12",
66
+ "@codemirror/view": "^6.40.0",
67
67
  "@fefeding/eventemitter": "^1.0.5",
68
68
  "@fefeding/vite-nunjucks-plugin": "^1.0.2",
69
69
  "@popperjs/core": "^2.11.8",
70
70
  "@rollup/pluginutils": "^5.3.0",
71
71
  "@types/bootstrap": "^5.2.10",
72
72
  "@types/jsdom": "^21.1.7",
73
- "@types/node": "^24.10.10",
73
+ "@types/node": "^24.12.0",
74
74
  "@types/vue": "^2.0.0",
75
- "@vitejs/plugin-vue": "^6.0.4",
76
- "@vitejs/plugin-vue-jsx": "^5.1.4",
75
+ "@vitejs/plugin-vue": "^6.0.5",
76
+ "@vitejs/plugin-vue-jsx": "^5.1.5",
77
77
  "@vue/tsconfig": "^0.8.1",
78
78
  "@vueuse/core": "^13.9.0",
79
79
  "@zumer/snapdom": "^1.9.14",
80
- "autoprefixer": "^10.4.24",
80
+ "autoprefixer": "^10.4.27",
81
81
  "bootstrap": "^5.3.8",
82
82
  "bootstrap-icons": "^1.13.1",
83
83
  "codemirror": "^6.0.2",
84
- "dotenv": "^17.2.3",
84
+ "dotenv": "^17.3.1",
85
85
  "echarts": "^6.0.0",
86
86
  "exceljs": "^4.4.0",
87
87
  "js-cookie": "^3.0.5",
88
88
  "jsdom": "^26.1.0",
89
89
  "jszip": "^3.10.1",
90
90
  "nw": "^0.107.0",
91
- "nw-builder": "^4.17.2",
91
+ "nw-builder": "^4.17.5",
92
92
  "pinia": "^3.0.4",
93
93
  "pinia-plugin-persistedstate": "^4.7.1",
94
- "postcss": "^8.5.6",
95
- "sass": "^1.97.3",
94
+ "postcss": "^8.5.8",
95
+ "sass": "^1.98.0",
96
96
  "tailwindcss": "^3.4.19",
97
97
  "typescript": "^5.9.3",
98
98
  "vconsole": "^3.15.1",
99
99
  "vite": "latest",
100
100
  "vite-plugin-files-copy": "^3.8.0",
101
101
  "vitest": "^3.2.4",
102
- "vue": "^3.5.27",
102
+ "vue": "^3.5.31",
103
103
  "vue-json-pretty": "^2.6.0",
104
104
  "vue-router": "^4.6.4",
105
- "vue-tsc": "^3.2.4",
105
+ "vue-tsc": "^3.2.6",
106
106
  "vuex": "^4.1.0",
107
107
  "xlsx": "^0.18.5"
108
108
  },
@@ -4,9 +4,18 @@
4
4
  <table class="table table-light table-striped table-hover">
5
5
  <thead class="table-light">
6
6
  <tr>
7
- <th v-for="column in props.columns" :key="column.name" scope="col" class="datagrid-th" :style="column.headerStyle||''" >
7
+ <th v-for="column in props.columns" :key="column.name" scope="col" class="datagrid-th" :style="column.headerStyle||''"
8
+ @click="column.sortable !== false && handleSort(column.name)"
9
+ :class="{ 'sortable': column.sortable !== false }">
8
10
  <slot :name="column.name+'_header'" :column="column">
9
- <span>{{column.text||column.name||''}}</span>
11
+ <div class="header-content">
12
+ <span>{{column.text||column.name||''}}</span>
13
+ <span v-if="column.sortable !== false" class="sort-icon">
14
+ <i v-if="props.sortField === column.name && props.sortOrder === 'ASC'" class="bi bi-caret-up-fill"></i>
15
+ <i v-else-if="props.sortField === column.name && props.sortOrder === 'DESC'" class="bi bi-caret-down-fill"></i>
16
+ <i v-else class="bi bi-caret-up text-muted opacity-50"></i>
17
+ </span>
18
+ </div>
10
19
  </slot>
11
20
  </th>
12
21
  </tr>
@@ -43,7 +52,8 @@
43
52
  component?: Component;
44
53
  headerStyle?: string;
45
54
  style?: string;
46
- formatter?: (value: any) => string;
55
+ sortable?: boolean;
56
+ formatter?: (row: any, column: ColumnType) => string;
47
57
  };
48
58
 
49
59
  const props = defineProps({
@@ -75,10 +85,18 @@
75
85
  columns: {
76
86
  type: Array<ColumnType>,
77
87
  default: []
88
+ },
89
+ sortField: {
90
+ type: String,
91
+ default: ''
92
+ },
93
+ sortOrder: {
94
+ type: String,
95
+ default: '' // ASC, DESC, ''
78
96
  }
79
97
  });
80
98
 
81
- const emits = defineEmits(['pageChanged', 'rowClicked']);
99
+ const emits = defineEmits(['pageChanged', 'rowClicked', 'sortChanged']);
82
100
 
83
101
  function renderDataItem(row: any, column: any) {
84
102
  if(typeof column === 'string') return row[column];
@@ -92,14 +110,54 @@
92
110
  emits('pageChanged', page);
93
111
  }
94
112
 
113
+ function handleSort(field: string) {
114
+ let order: 'ASC' | 'DESC' | '' = 'ASC';
115
+ if (props.sortField === field) {
116
+ if (props.sortOrder === 'ASC') {
117
+ order = 'DESC';
118
+ } else if (props.sortOrder === 'DESC') {
119
+ order = ''; // 取消排序
120
+ }
121
+ }
122
+ emits('sortChanged', { field: order ? field : '', order });
123
+ }
124
+
95
125
  </script>
96
126
 
97
127
  <style scoped>
128
+ .datagrid-container {
129
+ display: flex;
130
+ flex-direction: column;
131
+ height: 100%;
132
+ }
98
133
  .datagrid-inner {
134
+ flex: 1;
99
135
  overflow: auto;
100
136
  margin-bottom: 10px;
101
137
  }
102
138
  .datagrid-th {
103
139
  min-width: 80px;
140
+ white-space: nowrap;
141
+ position: sticky;
142
+ top: 0;
143
+ z-index: 10;
144
+ background-color: #f8f9fa;
145
+ }
146
+ .datagrid-th.sortable {
147
+ cursor: pointer;
148
+ user-select: none;
149
+ }
150
+ .datagrid-th.sortable:hover {
151
+ background-color: #e9ecef;
152
+ }
153
+ .header-content {
154
+ display: flex;
155
+ align-items: center;
156
+ gap: 0.5rem;
157
+ }
158
+ .sort-icon {
159
+ display: flex;
160
+ align-items: center;
161
+ font-size: 0.75rem;
104
162
  }
105
163
  </style>
@@ -122,8 +122,13 @@
122
122
  <i class="bi bi-table"></i>
123
123
  </div>
124
124
  <div class="table-info">
125
- <div class="table-name">{{ table.name }}</div>
126
- <div class="table-engine">{{ table.engine || '-' }}</div>
125
+ <div class="table-name-wrapper">
126
+ <div class="table-name" :title="table.name">{{ table.name }}</div>
127
+ <div class="table-engine">{{ table.engine || '-' }}</div>
128
+ </div>
129
+ <div class="table-comment-header" v-if="table.comment" :title="table.comment">
130
+ {{ table.comment }}
131
+ </div>
127
132
  </div>
128
133
  </div>
129
134
  <div class="card-body">
@@ -137,9 +142,6 @@
137
142
  <span class="stat-value">{{ formatSize(table.dataSize) }}</span>
138
143
  </div>
139
144
  </div>
140
- <div class="table-comment" v-if="table.comment">
141
- {{ table.comment }}
142
- </div>
143
145
  <div class="table-actions">
144
146
  <button class="btn btn-sm btn-outline-primary" @click.stop="editTable(table)">
145
147
  <i class="bi bi-pencil"></i>
@@ -998,10 +1000,24 @@ function handleExecuteSQL(sql: string) {
998
1000
  color: white;
999
1001
  }
1000
1002
 
1003
+ .table-info {
1004
+ flex: 1;
1005
+ min-width: 0; /* 允许子元素截断 */
1006
+ }
1007
+
1008
+ .table-name-wrapper {
1009
+ display: flex;
1010
+ align-items: center;
1011
+ gap: 0.5rem;
1012
+ margin-bottom: 0.25rem;
1013
+ }
1014
+
1001
1015
  .table-name {
1002
1016
  font-weight: 600;
1003
1017
  color: #1e293b;
1004
- margin-bottom: 0.25rem;
1018
+ white-space: nowrap;
1019
+ overflow: hidden;
1020
+ text-overflow: ellipsis;
1005
1021
  }
1006
1022
 
1007
1023
  .table-engine {
@@ -1010,6 +1026,15 @@ function handleExecuteSQL(sql: string) {
1010
1026
  background: #f1f5f9;
1011
1027
  padding: 0.125rem 0.375rem;
1012
1028
  border-radius: 8px;
1029
+ flex-shrink: 0;
1030
+ }
1031
+
1032
+ .table-comment-header {
1033
+ font-size: 0.75rem;
1034
+ color: #64748b;
1035
+ white-space: nowrap;
1036
+ overflow: hidden;
1037
+ text-overflow: ellipsis;
1013
1038
  }
1014
1039
 
1015
1040
  .card-body {