@hostlink/nuxt-light 1.57.1 → 1.58.0

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.
package/dist/module.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "light",
3
3
  "configKey": "light",
4
- "version": "1.57.1",
4
+ "version": "1.58.0",
5
5
  "builder": {
6
6
  "@nuxt/module-builder": "1.0.2",
7
7
  "unbuild": "3.6.1"
package/dist/module.mjs CHANGED
@@ -136,6 +136,11 @@ const routes = [
136
136
  path: "/System/database/check",
137
137
  file: "runtime/pages/System/database/check.vue"
138
138
  },
139
+ {
140
+ name: "System-database-migrate",
141
+ path: "/System/database/migrate",
142
+ file: "runtime/pages/System/database/migrate.vue"
143
+ },
139
144
  {
140
145
  name: "System-database-process",
141
146
  path: "/System/database/process",
@@ -19,7 +19,7 @@ if (props.context.state.required) {
19
19
 
20
20
  <template>
21
21
  <l-select v-model="value" :label="context.label" v-bind="context.attrs" :error="error" :error-message="errorMessage"
22
- :clearable="clearable" :required="context.state.required" :disable="context.disabled">
22
+ :clearable="clearable" :disable="context.disabled">
23
23
  <template v-for="(s, name) in $slots" v-slot:[name]="props" :key="name">
24
24
  <slot :name="name" v-bind="props ?? {}"></slot>
25
25
  </template>
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
@@ -0,0 +1,179 @@
1
+ <script setup>
2
+ import { q, m } from "#imports";
3
+ import { ref } from "vue";
4
+ import { Loading, Notify } from "quasar";
5
+ const isExporting = ref(false);
6
+ const onExportSchema = async () => {
7
+ isExporting.value = true;
8
+ Loading.show({ message: "\u6B63\u5728\u532F\u51FA Schema..." });
9
+ try {
10
+ const data = await q({
11
+ system: {
12
+ database: {
13
+ exportSchema: true
14
+ }
15
+ }
16
+ });
17
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().slice(0, 19).replace(/:/g, "-");
18
+ const filename = `schema-${timestamp}.json`;
19
+ const blob = new Blob(
20
+ [data.system.database.exportSchema],
21
+ { type: "application/json;charset=utf-8" }
22
+ );
23
+ const url = URL.createObjectURL(blob);
24
+ const a = document.createElement("a");
25
+ a.download = filename;
26
+ a.href = url;
27
+ a.click();
28
+ setTimeout(() => URL.revokeObjectURL(url), 1e3);
29
+ Notify.create({
30
+ type: "positive",
31
+ message: "Schema \u532F\u51FA\u6210\u529F\uFF01",
32
+ position: "top"
33
+ });
34
+ } catch (e) {
35
+ Notify.create({
36
+ type: "negative",
37
+ message: "\u532F\u51FA\u5931\u6557\uFF1A" + e.message,
38
+ position: "top"
39
+ });
40
+ } finally {
41
+ Loading.hide();
42
+ isExporting.value = false;
43
+ }
44
+ };
45
+ const selectedFile = ref(null);
46
+ const dryRun = ref(true);
47
+ const isImporting = ref(false);
48
+ const importResult = ref(null);
49
+ const onFileChange = () => {
50
+ importResult.value = null;
51
+ };
52
+ const clearFile = () => {
53
+ selectedFile.value = null;
54
+ importResult.value = null;
55
+ };
56
+ const onImportSchema = async () => {
57
+ if (!selectedFile.value) return;
58
+ isImporting.value = true;
59
+ Loading.show({
60
+ message: dryRun.value ? "\u6B63\u5728\u9810\u89BD\u8B8A\u66F4..." : "\u6B63\u5728\u532F\u5165 Schema..."
61
+ });
62
+ try {
63
+ if (dryRun.value) {
64
+ const data = await q({
65
+ system: {
66
+ database: {
67
+ importSchema: {
68
+ __args: { schema: selectedFile.value }
69
+ }
70
+ }
71
+ }
72
+ });
73
+ importResult.value = data.system.database.importSchema;
74
+ Notify.create({
75
+ type: "info",
76
+ message: "\u9810\u89BD\u5B8C\u6210\uFF0C\u8ACB\u6AA2\u8996\u8B8A\u66F4\u5167\u5BB9",
77
+ position: "top"
78
+ });
79
+ } else {
80
+ await m("importDatabaseSchema", { schema: selectedFile.value });
81
+ Notify.create({
82
+ type: "positive",
83
+ message: "Schema \u532F\u5165\u6210\u529F\uFF01",
84
+ position: "top"
85
+ });
86
+ importResult.value = null;
87
+ clearFile();
88
+ }
89
+ } catch (e) {
90
+ Notify.create({
91
+ type: "negative",
92
+ message: "\u64CD\u4F5C\u5931\u6557\uFF1A" + e.message,
93
+ position: "top"
94
+ });
95
+ } finally {
96
+ Loading.hide();
97
+ isImporting.value = false;
98
+ }
99
+ };
100
+ </script>
101
+
102
+ <template>
103
+ <l-page title="資料庫 Schema 遷移">
104
+ <div class="row q-col-gutter-md">
105
+ <!-- EXPORT 區塊 -->
106
+ <div class="col-12 col-md-6">
107
+ <l-card>
108
+ <q-card-section>
109
+ <div class="text-h6">
110
+ <q-icon name="sym_o_download" class="q-mr-sm" />
111
+ 匯出 Schema
112
+ </div>
113
+ </q-card-section>
114
+ <q-card-section>
115
+ <p class="text-grey-7">
116
+ 匯出目前的資料庫 Schema 為 JSON 檔案,可用於備份或遷移至其他環境。
117
+ </p>
118
+ <l-btn label="匯出 Schema" icon="sym_o_download" color="primary" :loading="isExporting"
119
+ :disable="isExporting" @click="onExportSchema" />
120
+ </q-card-section>
121
+ </l-card>
122
+ </div>
123
+
124
+ <!-- IMPORT 區塊 -->
125
+ <div class="col-12 col-md-6">
126
+ <l-card>
127
+ <q-card-section>
128
+ <div class="text-h6">
129
+ <q-icon name="sym_o_upload" class="q-mr-sm" />
130
+ 匯入 Schema
131
+ </div>
132
+ </q-card-section>
133
+ <q-card-section>
134
+ <p class="text-grey-7">
135
+ 選擇 Schema JSON 檔案進行匯入,建議先使用 Dry Run 預覽變更。
136
+ </p>
137
+
138
+ <q-file v-model="selectedFile" label="選擇 Schema 檔案 (.json)" accept=".json,application/json"
139
+ clearable outlined class="q-mb-md" @update:model-value="onFileChange">
140
+ <template #prepend>
141
+ <q-icon name="sym_o_attach_file" />
142
+ </template>
143
+ </q-file>
144
+
145
+ <l-checkbox v-model="dryRun" label="Dry Run (僅預覽變更,不實際執行)" class="q-mb-md" />
146
+
147
+ <div class="row q-gutter-sm">
148
+ <l-btn v-if="dryRun" label="預覽變更" icon="sym_o_preview" color="primary"
149
+ :loading="isImporting" :disable="isImporting || !selectedFile"
150
+ @click="onImportSchema" />
151
+ <l-btn v-else label="執行匯入" icon="sym_o_upload" color="negative" :loading="isImporting"
152
+ :disable="isImporting || !selectedFile" confirm-message="確定要執行 Schema 匯入嗎?此操作將修改資料庫結構。"
153
+ @click="onImportSchema" />
154
+ </div>
155
+ </q-card-section>
156
+ </l-card>
157
+ </div>
158
+
159
+ <!-- 結果顯示區塊 -->
160
+ <div v-if="importResult" class="col-12">
161
+ <l-card>
162
+ <q-card-section>
163
+ <div class="text-h6">
164
+ <q-icon name="sym_o_list_alt" class="q-mr-sm" />
165
+ 變更預覽結果
166
+ </div>
167
+ </q-card-section>
168
+ <q-card-section>
169
+ <pre class="import-result">{{ importResult }}</pre>
170
+ </q-card-section>
171
+ </l-card>
172
+ </div>
173
+ </div>
174
+ </l-page>
175
+ </template>
176
+
177
+ <style scoped>
178
+ .import-result{background-color:#f5f5f5;border-radius:8px;font-size:13px;line-height:1.5;max-height:500px;overflow-x:auto;overflow-y:auto;padding:16px}
179
+ </style>
@@ -0,0 +1,3 @@
1
+ declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
2
+ declare const _default: typeof __VLS_export;
3
+ export default _default;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hostlink/nuxt-light",
3
- "version": "1.57.1",
3
+ "version": "1.58.0",
4
4
  "description": "HostLink Nuxt Light Framework",
5
5
  "repository": {
6
6
  "type": "git",