liyu-pc-base 1.0.554 → 1.0.560
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/{aiGenModel-CNwUTMNL.js → aiGenModel-C7SZpnoO.js} +506 -471
- package/dist/{aiGenModel-CNwUTMNL.js.map → aiGenModel-C7SZpnoO.js.map} +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/remotePages/index.js +1 -1
- package/dist/index.js +1 -1
- package/dist/liyu-pc-base.css +1 -1
- package/dist/{remotePages-CbLpjalw.js → remotePages-CFuf6Esl.js} +2 -2
- package/dist/remotePages-CFuf6Esl.js.map +1 -0
- package/dist/syncDataSourceConfig-BXAolK4f.js +443 -0
- package/dist/syncDataSourceConfig-BXAolK4f.js.map +1 -0
- package/dist/{syncExportRawData-dtLd_SL2.js → syncExportRawData-D1i3W5JO.js} +3 -12
- package/dist/syncExportRawData-D1i3W5JO.js.map +1 -0
- package/package.json +1 -1
- package/dist/remotePages-CbLpjalw.js.map +0 -1
- package/dist/syncDataSourceConfig-AlcjBERC.js +0 -465
- package/dist/syncDataSourceConfig-AlcjBERC.js.map +0 -1
- package/dist/syncExportRawData-dtLd_SL2.js.map +0 -1
|
@@ -1,465 +0,0 @@
|
|
|
1
|
-
import { N as e, o as t } from "./init-plugin-1SOa4xzt.js";
|
|
2
|
-
import { t as n } from "./_plugin-vue_export-helper-B3ysoDQm.js";
|
|
3
|
-
import { t as r } from "./lodash-CC0qDxjV.js";
|
|
4
|
-
import { getApiData as i } from "./api/api-model.js";
|
|
5
|
-
import { Fragment as a, createBlock as o, createCommentVNode as s, createElementBlock as c, createElementVNode as l, createTextVNode as u, createVNode as d, defineComponent as f, onMounted as p, openBlock as m, reactive as h, ref as g, renderList as _, resolveComponent as v, toDisplayString as y, withCtx as b } from "vue";
|
|
6
|
-
import { message as x } from "ant-design-vue";
|
|
7
|
-
//#region src/components/lysync/syncDataSourceConfig.vue?vue&type=script&setup=true&lang.ts
|
|
8
|
-
var S = r(), C = /*#__PURE__*/ n(/* @__PURE__ */ f({
|
|
9
|
-
__name: "syncDataSourceConfig",
|
|
10
|
-
props: {
|
|
11
|
-
title: {},
|
|
12
|
-
record: {}
|
|
13
|
-
},
|
|
14
|
-
emits: ["cancel", "ok"],
|
|
15
|
-
setup(n, { emit: r }) {
|
|
16
|
-
let f = n, C = r, w = g(null), T = g(!1), E = g(!0), D = g("create"), O = e().currentOrg, k = [{
|
|
17
|
-
value: "db",
|
|
18
|
-
label: "数据库"
|
|
19
|
-
}, {
|
|
20
|
-
value: "custom",
|
|
21
|
-
label: "自定义"
|
|
22
|
-
}], A = [{
|
|
23
|
-
value: "mysql",
|
|
24
|
-
label: "MySQL"
|
|
25
|
-
}, {
|
|
26
|
-
value: "tsql",
|
|
27
|
-
label: "SQL Server"
|
|
28
|
-
}], j = g([]), M = g(!1), N = async () => {
|
|
29
|
-
M.value = !0;
|
|
30
|
-
try {
|
|
31
|
-
j.value = await i({ org_id: O?.id }, `${f.record.model_app}/get_collect_funcs`) || [];
|
|
32
|
-
} catch {
|
|
33
|
-
j.value = [];
|
|
34
|
-
} finally {
|
|
35
|
-
M.value = !1;
|
|
36
|
-
}
|
|
37
|
-
}, P = g({
|
|
38
|
-
name: void 0,
|
|
39
|
-
source_type: "db",
|
|
40
|
-
db_type: "mysql",
|
|
41
|
-
db_host: void 0,
|
|
42
|
-
db_port: void 0,
|
|
43
|
-
db_user: void 0,
|
|
44
|
-
db_password: void 0,
|
|
45
|
-
db_name: void 0,
|
|
46
|
-
db_options_str: "",
|
|
47
|
-
custom_func: void 0,
|
|
48
|
-
custom_func_kwargs_str: ""
|
|
49
|
-
}), F = h({
|
|
50
|
-
name: [{
|
|
51
|
-
required: !0,
|
|
52
|
-
message: "请填写数据源名称"
|
|
53
|
-
}],
|
|
54
|
-
source_type: [{
|
|
55
|
-
required: !0,
|
|
56
|
-
message: "请选择数据源类型"
|
|
57
|
-
}],
|
|
58
|
-
db_type: [{
|
|
59
|
-
required: !0,
|
|
60
|
-
message: "请选择数据库类型"
|
|
61
|
-
}],
|
|
62
|
-
db_host: [{
|
|
63
|
-
required: !0,
|
|
64
|
-
message: "请填写数据库主机"
|
|
65
|
-
}],
|
|
66
|
-
db_port: [{
|
|
67
|
-
required: !0,
|
|
68
|
-
message: "请填写数据库端口"
|
|
69
|
-
}],
|
|
70
|
-
db_user: [{
|
|
71
|
-
required: !0,
|
|
72
|
-
message: "请填写数据库用户"
|
|
73
|
-
}],
|
|
74
|
-
db_name: [{
|
|
75
|
-
required: !0,
|
|
76
|
-
message: "请填写数据库名称"
|
|
77
|
-
}],
|
|
78
|
-
custom_func: [{
|
|
79
|
-
required: !0,
|
|
80
|
-
message: "请填写自定义采集函数名称"
|
|
81
|
-
}]
|
|
82
|
-
}), I = () => {
|
|
83
|
-
P.value.source_type === "db" ? (P.value.custom_func = void 0, P.value.custom_func_kwargs_str = "") : (P.value.db_host = void 0, P.value.db_port = void 0, P.value.db_user = void 0, P.value.db_password = void 0, P.value.db_name = void 0, P.value.db_options_str = "");
|
|
84
|
-
}, L = (e, t) => {
|
|
85
|
-
if (e == null || String(e).trim() === "") return {};
|
|
86
|
-
try {
|
|
87
|
-
return JSON.parse(e);
|
|
88
|
-
} catch (e) {
|
|
89
|
-
throw Error(`${t} 不是合法 JSON: ${e.message}`);
|
|
90
|
-
}
|
|
91
|
-
}, R = (e) => e && typeof e == "object" && !Array.isArray(e) && e.data !== void 0 ? e.data : e, z = async (e) => R(await i({
|
|
92
|
-
sync_data_source_id: e,
|
|
93
|
-
org_id: O?.id
|
|
94
|
-
}, `${f.record.model_app}/get_sync_data_source`)) || {}, B = () => {
|
|
95
|
-
let e = (0, S.cloneDeep)(P.value);
|
|
96
|
-
return e.update_field_list = [
|
|
97
|
-
"name",
|
|
98
|
-
"source_type",
|
|
99
|
-
"db_type",
|
|
100
|
-
"db_host",
|
|
101
|
-
"db_port",
|
|
102
|
-
"db_user",
|
|
103
|
-
"db_password",
|
|
104
|
-
"db_name",
|
|
105
|
-
"db_options",
|
|
106
|
-
"custom_func",
|
|
107
|
-
"custom_func_kwargs"
|
|
108
|
-
], e.source_type === "db" ? (delete e.custom_func, delete e.custom_func_kwargs_str, e.custom_func_kwargs = {}, e.db_options = L(e.db_options_str, "数据库选项"), delete e.db_options_str, e.db_password || (delete e.db_password, D.value === "edit" && (e.update_field_list = e.update_field_list.filter((e) => e !== "db_password")))) : ([
|
|
109
|
-
"db_type",
|
|
110
|
-
"db_host",
|
|
111
|
-
"db_port",
|
|
112
|
-
"db_user",
|
|
113
|
-
"db_password",
|
|
114
|
-
"db_name",
|
|
115
|
-
"db_options_str"
|
|
116
|
-
].forEach((t) => delete e[t]), e.db_options = {}, e.custom_func_kwargs = L(e.custom_func_kwargs_str, "自定义采集函数参数"), delete e.custom_func_kwargs_str), e;
|
|
117
|
-
}, V = async () => {
|
|
118
|
-
try {
|
|
119
|
-
if (await w.value.validate(), P.value.source_type === "db") {
|
|
120
|
-
if (!P.value.db_host) {
|
|
121
|
-
x.error("请填写数据库主机");
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if (P.value.db_port === void 0 || P.value.db_port === null) {
|
|
125
|
-
x.error("请填写数据库端口");
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
if (!P.value.db_user) {
|
|
129
|
-
x.error("请填写数据库用户");
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
if (!P.value.db_name) {
|
|
133
|
-
x.error("请填写数据库名称");
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
if (D.value === "create" && !P.value.db_password) {
|
|
137
|
-
x.error("请填写数据库密码");
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
if (P.value.db_options_str && P.value.db_options_str.trim() !== "") try {
|
|
141
|
-
JSON.parse(P.value.db_options_str);
|
|
142
|
-
} catch (e) {
|
|
143
|
-
x.error(`数据库选项不是合法 JSON: ${e.message}`);
|
|
144
|
-
return;
|
|
145
|
-
}
|
|
146
|
-
} else {
|
|
147
|
-
if (!P.value.custom_func) {
|
|
148
|
-
x.error("请填写自定义采集函数名称");
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
if (P.value.custom_func_kwargs_str && P.value.custom_func_kwargs_str.trim() !== "") try {
|
|
152
|
-
JSON.parse(P.value.custom_func_kwargs_str);
|
|
153
|
-
} catch (e) {
|
|
154
|
-
x.error(`自定义采集函数参数不是合法 JSON: ${e.message}`);
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
let e = B();
|
|
159
|
-
e.sync_data_source_id = f.record.id;
|
|
160
|
-
let n = D.value === "edit" ? `${f.record.model_app}/update_sync_data_source` : `${f.record.model_app}/create_sync_data_source`;
|
|
161
|
-
D.value === "edit" && (e.id = f.record.id), T.value = !0, await i({
|
|
162
|
-
...e,
|
|
163
|
-
org_id: O?.id
|
|
164
|
-
}, n), x.success("操作成功"), t()?.emit("refresh"), C("ok");
|
|
165
|
-
} catch {} finally {
|
|
166
|
-
T.value = !1;
|
|
167
|
-
}
|
|
168
|
-
}, H = () => C("cancel"), U = async () => {
|
|
169
|
-
let e = f.record?.id, t = (e == null ? f.record : await z(e)) || {}, n = t.db_options, r = t.custom_func_kwargs;
|
|
170
|
-
P.value = {
|
|
171
|
-
name: t.name || "",
|
|
172
|
-
source_type: t.source_type || "db",
|
|
173
|
-
db_type: t.db_type || "mysql",
|
|
174
|
-
db_host: t.db_host || void 0,
|
|
175
|
-
db_port: t.db_port ?? void 0,
|
|
176
|
-
db_user: t.db_user || void 0,
|
|
177
|
-
db_password: void 0,
|
|
178
|
-
db_name: t.db_name || void 0,
|
|
179
|
-
db_options_str: n && typeof n == "object" ? JSON.stringify(n, null, 2) : "",
|
|
180
|
-
custom_func: t.custom_func || void 0,
|
|
181
|
-
custom_func_kwargs_str: r && typeof r == "object" ? JSON.stringify(r, null, 2) : ""
|
|
182
|
-
};
|
|
183
|
-
let i = t.custom_func;
|
|
184
|
-
i && !j.value.some((e) => e.value === i) && (j.value = [{
|
|
185
|
-
value: i,
|
|
186
|
-
label: i
|
|
187
|
-
}, ...j.value]);
|
|
188
|
-
};
|
|
189
|
-
return p(async () => {
|
|
190
|
-
f.record?.form_type && (D.value = f.record.form_type), await N(), D.value === "edit" && await U();
|
|
191
|
-
}), (e, t) => {
|
|
192
|
-
let n = v("a-divider"), r = v("a-input"), i = v("a-form-item"), f = v("a-col"), p = v("a-select-option"), h = v("a-select"), g = v("a-row"), x = v("a-input-number"), S = v("a-input-password"), C = v("a-textarea"), D = v("a-form"), O = v("a-modal");
|
|
193
|
-
return m(), o(O, {
|
|
194
|
-
title: e.title,
|
|
195
|
-
width: "880px",
|
|
196
|
-
open: E.value,
|
|
197
|
-
bodyStyle: {
|
|
198
|
-
maxHeight: "78vh",
|
|
199
|
-
overflowY: "auto",
|
|
200
|
-
padding: "0 24px"
|
|
201
|
-
},
|
|
202
|
-
"confirm-loading": T.value,
|
|
203
|
-
"cancel-text": "取消",
|
|
204
|
-
"ok-text": "确定",
|
|
205
|
-
centered: "",
|
|
206
|
-
"destroy-on-close": "",
|
|
207
|
-
onCancel: H,
|
|
208
|
-
onOk: V
|
|
209
|
-
}, {
|
|
210
|
-
default: b(() => [d(D, {
|
|
211
|
-
ref_key: "formRef",
|
|
212
|
-
ref: w,
|
|
213
|
-
model: P.value,
|
|
214
|
-
layout: "vertical",
|
|
215
|
-
size: "small"
|
|
216
|
-
}, {
|
|
217
|
-
default: b(() => [
|
|
218
|
-
d(n, { orientation: "left" }, {
|
|
219
|
-
default: b(() => t[11] ||= [u("基本信息")]),
|
|
220
|
-
_: 1
|
|
221
|
-
}),
|
|
222
|
-
d(g, { gutter: 16 }, {
|
|
223
|
-
default: b(() => [
|
|
224
|
-
d(f, { span: 12 }, {
|
|
225
|
-
default: b(() => [d(i, {
|
|
226
|
-
label: "数据源名称",
|
|
227
|
-
name: "name",
|
|
228
|
-
rules: F.name
|
|
229
|
-
}, {
|
|
230
|
-
default: b(() => [d(r, {
|
|
231
|
-
value: P.value.name,
|
|
232
|
-
"onUpdate:value": t[0] ||= (e) => P.value.name = e,
|
|
233
|
-
placeholder: "请填写数据源名称",
|
|
234
|
-
"allow-clear": ""
|
|
235
|
-
}, null, 8, ["value"])]),
|
|
236
|
-
_: 1
|
|
237
|
-
}, 8, ["rules"])]),
|
|
238
|
-
_: 1
|
|
239
|
-
}),
|
|
240
|
-
d(f, { span: 12 }, {
|
|
241
|
-
default: b(() => [d(i, {
|
|
242
|
-
label: "数据源类型",
|
|
243
|
-
name: "source_type",
|
|
244
|
-
rules: F.source_type
|
|
245
|
-
}, {
|
|
246
|
-
default: b(() => [d(h, {
|
|
247
|
-
value: P.value.source_type,
|
|
248
|
-
"onUpdate:value": t[1] ||= (e) => P.value.source_type = e,
|
|
249
|
-
placeholder: "请选择",
|
|
250
|
-
onChange: I
|
|
251
|
-
}, {
|
|
252
|
-
default: b(() => [(m(), c(a, null, _(k, (e) => d(p, {
|
|
253
|
-
key: e.value,
|
|
254
|
-
value: e.value
|
|
255
|
-
}, {
|
|
256
|
-
default: b(() => [u(y(e.label), 1)]),
|
|
257
|
-
_: 2
|
|
258
|
-
}, 1032, ["value"])), 64))]),
|
|
259
|
-
_: 1
|
|
260
|
-
}, 8, ["value"])]),
|
|
261
|
-
_: 1
|
|
262
|
-
}, 8, ["rules"])]),
|
|
263
|
-
_: 1
|
|
264
|
-
}),
|
|
265
|
-
P.value.source_type === "db" ? (m(), o(f, {
|
|
266
|
-
key: 0,
|
|
267
|
-
span: 12
|
|
268
|
-
}, {
|
|
269
|
-
default: b(() => [d(i, {
|
|
270
|
-
label: "数据库类型",
|
|
271
|
-
name: "db_type",
|
|
272
|
-
rules: F.db_type
|
|
273
|
-
}, {
|
|
274
|
-
default: b(() => [d(h, {
|
|
275
|
-
value: P.value.db_type,
|
|
276
|
-
"onUpdate:value": t[2] ||= (e) => P.value.db_type = e,
|
|
277
|
-
placeholder: "请选择"
|
|
278
|
-
}, {
|
|
279
|
-
default: b(() => [(m(), c(a, null, _(A, (e) => d(p, {
|
|
280
|
-
key: e.value,
|
|
281
|
-
value: e.value
|
|
282
|
-
}, {
|
|
283
|
-
default: b(() => [u(y(e.label), 1)]),
|
|
284
|
-
_: 2
|
|
285
|
-
}, 1032, ["value"])), 64))]),
|
|
286
|
-
_: 1
|
|
287
|
-
}, 8, ["value"])]),
|
|
288
|
-
_: 1
|
|
289
|
-
}, 8, ["rules"])]),
|
|
290
|
-
_: 1
|
|
291
|
-
})) : s("", !0)
|
|
292
|
-
]),
|
|
293
|
-
_: 1
|
|
294
|
-
}),
|
|
295
|
-
P.value.source_type === "db" ? (m(), c(a, { key: 0 }, [
|
|
296
|
-
d(n, { orientation: "left" }, {
|
|
297
|
-
default: b(() => t[12] ||= [u("数据库连接信息")]),
|
|
298
|
-
_: 1
|
|
299
|
-
}),
|
|
300
|
-
d(g, { gutter: 16 }, {
|
|
301
|
-
default: b(() => [
|
|
302
|
-
d(f, { span: 12 }, {
|
|
303
|
-
default: b(() => [d(i, {
|
|
304
|
-
label: "数据库主机",
|
|
305
|
-
name: "db_host",
|
|
306
|
-
rules: F.db_host
|
|
307
|
-
}, {
|
|
308
|
-
default: b(() => [d(r, {
|
|
309
|
-
value: P.value.db_host,
|
|
310
|
-
"onUpdate:value": t[3] ||= (e) => P.value.db_host = e,
|
|
311
|
-
placeholder: "如 127.0.0.1",
|
|
312
|
-
"allow-clear": ""
|
|
313
|
-
}, null, 8, ["value"])]),
|
|
314
|
-
_: 1
|
|
315
|
-
}, 8, ["rules"])]),
|
|
316
|
-
_: 1
|
|
317
|
-
}),
|
|
318
|
-
d(f, { span: 12 }, {
|
|
319
|
-
default: b(() => [d(i, {
|
|
320
|
-
label: "数据库端口",
|
|
321
|
-
name: "db_port",
|
|
322
|
-
rules: F.db_port
|
|
323
|
-
}, {
|
|
324
|
-
default: b(() => [d(x, {
|
|
325
|
-
value: P.value.db_port,
|
|
326
|
-
"onUpdate:value": t[4] ||= (e) => P.value.db_port = e,
|
|
327
|
-
style: { width: "100%" },
|
|
328
|
-
min: 1,
|
|
329
|
-
max: 65535,
|
|
330
|
-
placeholder: "如 3306"
|
|
331
|
-
}, null, 8, ["value"])]),
|
|
332
|
-
_: 1
|
|
333
|
-
}, 8, ["rules"])]),
|
|
334
|
-
_: 1
|
|
335
|
-
}),
|
|
336
|
-
d(f, { span: 12 }, {
|
|
337
|
-
default: b(() => [d(i, {
|
|
338
|
-
label: "数据库用户",
|
|
339
|
-
name: "db_user",
|
|
340
|
-
rules: F.db_user
|
|
341
|
-
}, {
|
|
342
|
-
default: b(() => [d(r, {
|
|
343
|
-
value: P.value.db_user,
|
|
344
|
-
"onUpdate:value": t[5] ||= (e) => P.value.db_user = e,
|
|
345
|
-
placeholder: "如 root",
|
|
346
|
-
"allow-clear": ""
|
|
347
|
-
}, null, 8, ["value"])]),
|
|
348
|
-
_: 1
|
|
349
|
-
}, 8, ["rules"])]),
|
|
350
|
-
_: 1
|
|
351
|
-
}),
|
|
352
|
-
d(f, { span: 12 }, {
|
|
353
|
-
default: b(() => [d(i, {
|
|
354
|
-
label: "数据库密码",
|
|
355
|
-
name: "db_password"
|
|
356
|
-
}, {
|
|
357
|
-
default: b(() => [d(S, {
|
|
358
|
-
value: P.value.db_password,
|
|
359
|
-
"onUpdate:value": t[6] ||= (e) => P.value.db_password = e,
|
|
360
|
-
placeholder: "修改时留空则不修改密码",
|
|
361
|
-
"allow-clear": "",
|
|
362
|
-
autocomplete: "new-password"
|
|
363
|
-
}, null, 8, ["value"])]),
|
|
364
|
-
_: 1
|
|
365
|
-
})]),
|
|
366
|
-
_: 1
|
|
367
|
-
}),
|
|
368
|
-
d(f, { span: 12 }, {
|
|
369
|
-
default: b(() => [d(i, {
|
|
370
|
-
label: "数据库名称",
|
|
371
|
-
name: "db_name",
|
|
372
|
-
rules: F.db_name
|
|
373
|
-
}, {
|
|
374
|
-
default: b(() => [d(r, {
|
|
375
|
-
value: P.value.db_name,
|
|
376
|
-
"onUpdate:value": t[7] ||= (e) => P.value.db_name = e,
|
|
377
|
-
placeholder: "如 my_db",
|
|
378
|
-
"allow-clear": ""
|
|
379
|
-
}, null, 8, ["value"])]),
|
|
380
|
-
_: 1
|
|
381
|
-
}, 8, ["rules"])]),
|
|
382
|
-
_: 1
|
|
383
|
-
})
|
|
384
|
-
]),
|
|
385
|
-
_: 1
|
|
386
|
-
}),
|
|
387
|
-
d(i, {
|
|
388
|
-
label: "数据库选项(JSON)",
|
|
389
|
-
name: "db_options"
|
|
390
|
-
}, {
|
|
391
|
-
default: b(() => [d(C, {
|
|
392
|
-
value: P.value.db_options_str,
|
|
393
|
-
"onUpdate:value": t[8] ||= (e) => P.value.db_options_str = e,
|
|
394
|
-
placeholder: "可选,JSON 对象,如 {\"charset\":\"utf8mb4\"}",
|
|
395
|
-
"auto-size": {
|
|
396
|
-
minRows: 2,
|
|
397
|
-
maxRows: 6
|
|
398
|
-
},
|
|
399
|
-
"allow-clear": ""
|
|
400
|
-
}, null, 8, ["value"]), t[13] ||= l("div", { class: "field-extra" }, "该字段仅在保存时解析为 JSON,留空则使用 {}。", -1)]),
|
|
401
|
-
_: 1
|
|
402
|
-
})
|
|
403
|
-
], 64)) : P.value.source_type === "custom" ? (m(), c(a, { key: 1 }, [
|
|
404
|
-
d(n, { orientation: "left" }, {
|
|
405
|
-
default: b(() => t[14] ||= [u("自定义采集")]),
|
|
406
|
-
_: 1
|
|
407
|
-
}),
|
|
408
|
-
d(g, { gutter: 16 }, {
|
|
409
|
-
default: b(() => [d(f, { span: 12 }, {
|
|
410
|
-
default: b(() => [d(i, {
|
|
411
|
-
label: "自定义采集函数名称",
|
|
412
|
-
name: "custom_func",
|
|
413
|
-
rules: F.custom_func
|
|
414
|
-
}, {
|
|
415
|
-
default: b(() => [d(h, {
|
|
416
|
-
value: P.value.custom_func,
|
|
417
|
-
"onUpdate:value": t[9] ||= (e) => P.value.custom_func = e,
|
|
418
|
-
placeholder: "请选择采集函数",
|
|
419
|
-
options: j.value,
|
|
420
|
-
"option-filter-prop": "label",
|
|
421
|
-
"show-search": "",
|
|
422
|
-
"allow-clear": "",
|
|
423
|
-
loading: M.value
|
|
424
|
-
}, null, 8, [
|
|
425
|
-
"value",
|
|
426
|
-
"options",
|
|
427
|
-
"loading"
|
|
428
|
-
])]),
|
|
429
|
-
_: 1
|
|
430
|
-
}, 8, ["rules"])]),
|
|
431
|
-
_: 1
|
|
432
|
-
})]),
|
|
433
|
-
_: 1
|
|
434
|
-
}),
|
|
435
|
-
d(i, {
|
|
436
|
-
label: "自定义采集函数参数(JSON)",
|
|
437
|
-
name: "custom_func_kwargs"
|
|
438
|
-
}, {
|
|
439
|
-
default: b(() => [d(C, {
|
|
440
|
-
value: P.value.custom_func_kwargs_str,
|
|
441
|
-
"onUpdate:value": t[10] ||= (e) => P.value.custom_func_kwargs_str = e,
|
|
442
|
-
placeholder: "可选,JSON 对象,如 {\"token\":\"xxx\"}",
|
|
443
|
-
"auto-size": {
|
|
444
|
-
minRows: 2,
|
|
445
|
-
maxRows: 6
|
|
446
|
-
},
|
|
447
|
-
"allow-clear": ""
|
|
448
|
-
}, null, 8, ["value"]), t[15] ||= l("div", { class: "field-extra" }, "该字段仅在保存时解析为 JSON,留空则使用 {}。", -1)]),
|
|
449
|
-
_: 1
|
|
450
|
-
})
|
|
451
|
-
], 64)) : s("", !0)
|
|
452
|
-
]),
|
|
453
|
-
_: 1
|
|
454
|
-
}, 8, ["model"])]),
|
|
455
|
-
_: 1
|
|
456
|
-
}, 8, [
|
|
457
|
-
"title",
|
|
458
|
-
"open",
|
|
459
|
-
"confirm-loading"
|
|
460
|
-
]);
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
|
-
}), [["__scopeId", "data-v-571da14c"]]);
|
|
464
|
-
//#endregion
|
|
465
|
-
export { C as default };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"syncDataSourceConfig-AlcjBERC.js","names":[],"sources":["../src/components/lysync/syncDataSourceConfig.vue","../src/components/lysync/syncDataSourceConfig.vue"],"sourcesContent":["<template>\n <a-modal\n :title=\"title\"\n width=\"880px\"\n :open=\"open\"\n :bodyStyle=\"{ maxHeight: '78vh', overflowY: 'auto', padding: '0 24px' }\"\n :confirm-loading=\"loading\"\n cancel-text=\"取消\"\n ok-text=\"确定\"\n centered\n destroy-on-close\n @cancel=\"handleCancel\"\n @ok=\"handleOk\"\n >\n <a-form\n ref=\"formRef\"\n :model=\"model\"\n layout=\"vertical\"\n size=\"small\"\n >\n <a-divider orientation=\"left\">基本信息</a-divider>\n <a-row :gutter=\"16\">\n <a-col :span=\"12\">\n <a-form-item\n label=\"数据源名称\"\n name=\"name\"\n :rules=\"rules.name\"\n >\n <a-input\n v-model:value=\"model.name\"\n placeholder=\"请填写数据源名称\"\n allow-clear\n />\n </a-form-item>\n </a-col>\n <a-col :span=\"12\">\n <a-form-item\n label=\"数据源类型\"\n name=\"source_type\"\n :rules=\"rules.source_type\"\n >\n <a-select\n v-model:value=\"model.source_type\"\n placeholder=\"请选择\"\n @change=\"onSourceTypeChange\"\n >\n <a-select-option\n v-for=\"opt in sourceTypeOptions\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n >\n {{ opt.label }}\n </a-select-option>\n </a-select>\n </a-form-item>\n </a-col>\n <a-col\n v-if=\"model.source_type === 'db'\"\n :span=\"12\"\n >\n <a-form-item\n label=\"数据库类型\"\n name=\"db_type\"\n :rules=\"rules.db_type\"\n >\n <a-select\n v-model:value=\"model.db_type\"\n placeholder=\"请选择\"\n >\n <a-select-option\n v-for=\"opt in dbTypeOptions\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n >\n {{ opt.label }}\n </a-select-option>\n </a-select>\n </a-form-item>\n </a-col>\n </a-row>\n\n <!-- 数据库类型:连接信息 -->\n <template v-if=\"model.source_type === 'db'\">\n <a-divider orientation=\"left\">数据库连接信息</a-divider>\n <a-row :gutter=\"16\">\n <a-col :span=\"12\">\n <a-form-item\n label=\"数据库主机\"\n name=\"db_host\"\n :rules=\"rules.db_host\"\n >\n <a-input\n v-model:value=\"model.db_host\"\n placeholder=\"如 127.0.0.1\"\n allow-clear\n />\n </a-form-item>\n </a-col>\n <a-col :span=\"12\">\n <a-form-item\n label=\"数据库端口\"\n name=\"db_port\"\n :rules=\"rules.db_port\"\n >\n <a-input-number\n v-model:value=\"model.db_port\"\n style=\"width: 100%\"\n :min=\"1\"\n :max=\"65535\"\n placeholder=\"如 3306\"\n />\n </a-form-item>\n </a-col>\n <a-col :span=\"12\">\n <a-form-item\n label=\"数据库用户\"\n name=\"db_user\"\n :rules=\"rules.db_user\"\n >\n <a-input\n v-model:value=\"model.db_user\"\n placeholder=\"如 root\"\n allow-clear\n />\n </a-form-item>\n </a-col>\n <a-col :span=\"12\">\n <a-form-item\n label=\"数据库密码\"\n name=\"db_password\"\n >\n <a-input-password\n v-model:value=\"model.db_password\"\n placeholder=\"修改时留空则不修改密码\"\n allow-clear\n autocomplete=\"new-password\"\n />\n </a-form-item>\n </a-col>\n <a-col :span=\"12\">\n <a-form-item\n label=\"数据库名称\"\n name=\"db_name\"\n :rules=\"rules.db_name\"\n >\n <a-input\n v-model:value=\"model.db_name\"\n placeholder=\"如 my_db\"\n allow-clear\n />\n </a-form-item>\n </a-col>\n </a-row>\n <a-form-item\n label=\"数据库选项(JSON)\"\n name=\"db_options\"\n >\n <a-textarea\n v-model:value=\"model.db_options_str\"\n placeholder='可选,JSON 对象,如 {\"charset\":\"utf8mb4\"}'\n :auto-size=\"{ minRows: 2, maxRows: 6 }\"\n allow-clear\n />\n <div class=\"field-extra\">该字段仅在保存时解析为 JSON,留空则使用 {}。</div>\n </a-form-item>\n </template>\n\n <!-- 自定义类型:采集函数 -->\n <template v-else-if=\"model.source_type === 'custom'\">\n <a-divider orientation=\"left\">自定义采集</a-divider>\n <a-row :gutter=\"16\">\n <a-col :span=\"12\">\n <a-form-item\n label=\"自定义采集函数名称\"\n name=\"custom_func\"\n :rules=\"rules.custom_func\"\n >\n <a-select\n v-model:value=\"model.custom_func\"\n placeholder=\"请选择采集函数\"\n :options=\"customFuncOptions\"\n option-filter-prop=\"label\"\n show-search\n allow-clear\n :loading=\"funcOptionsLoading\"\n />\n </a-form-item>\n </a-col>\n </a-row>\n <a-form-item\n label=\"自定义采集函数参数(JSON)\"\n name=\"custom_func_kwargs\"\n >\n <a-textarea\n v-model:value=\"model.custom_func_kwargs_str\"\n placeholder='可选,JSON 对象,如 {\"token\":\"xxx\"}'\n :auto-size=\"{ minRows: 2, maxRows: 6 }\"\n allow-clear\n />\n <div class=\"field-extra\">该字段仅在保存时解析为 JSON,留空则使用 {}。</div>\n </a-form-item>\n </template>\n </a-form>\n </a-modal>\n</template>\n\n<script setup lang=\"ts\">\nimport { cloneDeep } from 'lodash';\nimport { message } from 'ant-design-vue';\nimport { onMounted, reactive, ref } from 'vue';\nimport { event_obj } from 'liyu-pc-base/init-plugin';\nimport { getApiData } from 'liyu-pc-base/api/api-model';\nimport { useUserStore } from 'liyu-pc-base/init-plugin';\ninterface Props {\n title: string;\n record: any;\n}\nconst props = defineProps<Props>();\nconst emit = defineEmits(['cancel', 'ok']);\n\nconst formRef = ref<any>(null);\nconst loading = ref(false);\nconst open = ref(true);\nconst form_type = ref('create');\nconst userStore = useUserStore();\nconst current_org = userStore.currentOrg;\n\nconst sourceTypeOptions = [\n { value: 'db', label: '数据库' },\n { value: 'custom', label: '自定义' },\n];\nconst dbTypeOptions = [\n { value: 'mysql', label: 'MySQL' },\n { value: 'tsql', label: 'SQL Server' },\n];\n\n/* 自定义采集函数下拉选项(来自后端 get_collect_funcs) */\nconst customFuncOptions = ref<any[]>([]);\nconst funcOptionsLoading = ref(false);\nconst loadCustomFuncOptions = async () => {\n funcOptionsLoading.value = true;\n try {\n const res = await getApiData(\n { org_id: current_org?.id },\n `${props.record.model_app}/get_collect_funcs`,\n );\n customFuncOptions.value = res || [];\n } catch (e) {\n customFuncOptions.value = [];\n } finally {\n funcOptionsLoading.value = false;\n }\n};\n\nconst model = ref<any>({\n name: undefined,\n source_type: 'db',\n db_type: 'mysql',\n db_host: undefined,\n db_port: undefined,\n db_user: undefined,\n db_password: undefined,\n db_name: undefined,\n db_options_str: '',\n custom_func: undefined,\n custom_func_kwargs_str: '',\n});\n\nconst rules = reactive<any>({\n name: [{ required: true, message: '请填写数据源名称' }],\n source_type: [{ required: true, message: '请选择数据源类型' }],\n db_type: [{ required: true, message: '请选择数据库类型' }],\n db_host: [{ required: true, message: '请填写数据库主机' }],\n db_port: [{ required: true, message: '请填写数据库端口' }],\n db_user: [{ required: true, message: '请填写数据库用户' }],\n db_name: [{ required: true, message: '请填写数据库名称' }],\n custom_func: [{ required: true, message: '请填写自定义采集函数名称' }],\n});\n\n/* 切换数据源类型时,清空与另一类型无关的不必要校验残留 */\nconst onSourceTypeChange = () => {\n if (model.value.source_type === 'db') {\n model.value.custom_func = undefined;\n model.value.custom_func_kwargs_str = '';\n } else {\n model.value.db_host = undefined;\n model.value.db_port = undefined;\n model.value.db_user = undefined;\n model.value.db_password = undefined;\n model.value.db_name = undefined;\n model.value.db_options_str = '';\n }\n};\n\n/* 将 JSON 字符串解析为对象;空字符串返回 {};解析失败抛出错误 */\nconst parseJsonField = (str: string, fieldName: string): any => {\n if (str === undefined || str === null || String(str).trim() === '') return {};\n try {\n return JSON.parse(str);\n } catch (e) {\n throw new Error(`${fieldName} 不是合法 JSON: ${(e as Error).message}`);\n }\n};\n\n/* 兼容 getApiData 可能的返回结构(直接对象 或 {data:{...}}) */\nconst extractData = (res: any) => {\n if (res && typeof res === 'object' && !Array.isArray(res) && res.data !== undefined)\n return res.data;\n return res;\n};\n\n/* 编辑:调用公共项目提供的详情接口(<app_flag>/get_<model_name>,即 get_basemodel)\n 获取完整的 SyncDataSource 记录。不依赖列表行数据 props.record,因为它可能缺失\n 部分字段。get_basemodel 返回单条 dict(非列表),按 id 查询(参数名\n 为 <model_name>_id,即 sync_data_source_id)。 */\nconst loadDetail = async (id: any) => {\n const res = await getApiData(\n { sync_data_source_id: id, org_id: current_org?.id },\n `${props.record.model_app}/get_sync_data_source`,\n );\n return extractData(res) || {};\n};\n\n/* 构建提交数据:始终 cloneDeep(model.value),兜底默认值 */\nconst buildPayload = () => {\n const payload: any = cloneDeep(model.value);\n payload.update_field_list = [\n 'name',\n 'source_type',\n 'db_type',\n 'db_host',\n 'db_port',\n 'db_user',\n 'db_password',\n 'db_name',\n 'db_options',\n 'custom_func',\n 'custom_func_kwargs',\n ];\n const isDb = payload.source_type === 'db';\n\n // 仅保留当前类型相关字段,避免把另一类型的空值带给后端\n if (isDb) {\n delete payload.custom_func;\n delete payload.custom_func_kwargs_str;\n payload.custom_func_kwargs = {};\n payload.db_options = parseJsonField(payload.db_options_str, '数据库选项');\n delete payload.db_options_str;\n // 编辑时密码留空则不修改:删除字段值,并从 update_field_list 中剔除,避免后端更新\n if (!payload.db_password) {\n delete payload.db_password;\n if (form_type.value === 'edit') {\n payload.update_field_list = payload.update_field_list.filter(\n (k: string) => k !== 'db_password',\n );\n }\n }\n } else {\n [\n 'db_type',\n 'db_host',\n 'db_port',\n 'db_user',\n 'db_password',\n 'db_name',\n 'db_options_str',\n ].forEach(k => delete payload[k]);\n payload.db_options = {};\n payload.custom_func_kwargs = parseJsonField(\n payload.custom_func_kwargs_str,\n '自定义采集函数参数',\n );\n delete payload.custom_func_kwargs_str;\n }\n\n return payload;\n};\n\n/* 提交:URL 遵循 /{app_flag}/create_{model} 与 /{app_flag}/update_{model} */\nconst handleOk = async () => {\n try {\n await formRef.value.validate();\n const isDb = model.value.source_type === 'db';\n if (isDb) {\n if (!model.value.db_host) {\n message.error('请填写数据库主机');\n return;\n }\n if (model.value.db_port === undefined || model.value.db_port === null) {\n message.error('请填写数据库端口');\n return;\n }\n if (!model.value.db_user) {\n message.error('请填写数据库用户');\n return;\n }\n if (!model.value.db_name) {\n message.error('请填写数据库名称');\n return;\n }\n if (form_type.value === 'create' && !model.value.db_password) {\n message.error('请填写数据库密码');\n return;\n }\n if (model.value.db_options_str && model.value.db_options_str.trim() !== '') {\n try {\n JSON.parse(model.value.db_options_str);\n } catch (e: any) {\n message.error(`数据库选项不是合法 JSON: ${e.message}`);\n return;\n }\n }\n } else {\n if (!model.value.custom_func) {\n message.error('请填写自定义采集函数名称');\n return;\n }\n if (model.value.custom_func_kwargs_str && model.value.custom_func_kwargs_str.trim() !== '') {\n try {\n JSON.parse(model.value.custom_func_kwargs_str);\n } catch (e: any) {\n message.error(`自定义采集函数参数不是合法 JSON: ${e.message}`);\n return;\n }\n }\n }\n\n const payload = buildPayload();\n payload.sync_data_source_id = props.record.id;\n const url =\n form_type.value === 'edit'\n ? `${props.record.model_app}/update_sync_data_source`\n : `${props.record.model_app}/create_sync_data_source`;\n if (form_type.value === 'edit') payload.id = props.record.id;\n loading.value = true;\n await getApiData({ ...payload, org_id: current_org?.id }, url);\n message.success('操作成功');\n event_obj()?.emit('refresh');\n emit('ok');\n } catch (error) {\n // 校验失败或接口异常:保持弹窗打开\n } finally {\n loading.value = false;\n }\n};\nconst handleCancel = () => emit('cancel');\n\n/* 初始化编辑:先调详情接口拿完整记录,再填充;并把 JSON 字段格式化为字符串 */\nconst initForEdit = async () => {\n const id = props.record?.id;\n // 编辑时依赖详情接口而非列表行数据(列表行可能缺失字段)\n const record = (id != null ? await loadDetail(id) : props.record) || {};\n const rawDbOptions = record.db_options;\n const rawCustomKwargs = record.custom_func_kwargs;\n model.value = {\n name: record.name || '',\n source_type: record.source_type || 'db',\n db_type: record.db_type || 'mysql',\n db_host: record.db_host || undefined,\n db_port: record.db_port ?? undefined,\n db_user: record.db_user || undefined,\n db_password: undefined, // 密码不回显,留空表示不修改\n db_name: record.db_name || undefined,\n db_options_str:\n rawDbOptions && typeof rawDbOptions === 'object' ? JSON.stringify(rawDbOptions, null, 2) : '',\n custom_func: record.custom_func || undefined,\n custom_func_kwargs_str:\n rawCustomKwargs && typeof rawCustomKwargs === 'object'\n ? JSON.stringify(rawCustomKwargs, null, 2)\n : '',\n };\n // 编辑时若已保存的采集函数不在当前选项列表中,补充进下拉避免丢失显示\n const rawCustomFunc = record.custom_func;\n if (rawCustomFunc && !customFuncOptions.value.some(o => o.value === rawCustomFunc)) {\n customFuncOptions.value = [\n { value: rawCustomFunc, label: rawCustomFunc },\n ...customFuncOptions.value,\n ];\n }\n};\n\nonMounted(async () => {\n if (props.record?.form_type) form_type.value = props.record.form_type;\n await loadCustomFuncOptions();\n if (form_type.value === 'edit') await initForEdit();\n});\n</script>\n\n<style scoped lang=\"less\">\n.field-extra {\n color: #999;\n font-size: 12px;\n line-height: 1.4;\n margin-top: 2px;\n}\n</style>\n","<template>\n <a-modal\n :title=\"title\"\n width=\"880px\"\n :open=\"open\"\n :bodyStyle=\"{ maxHeight: '78vh', overflowY: 'auto', padding: '0 24px' }\"\n :confirm-loading=\"loading\"\n cancel-text=\"取消\"\n ok-text=\"确定\"\n centered\n destroy-on-close\n @cancel=\"handleCancel\"\n @ok=\"handleOk\"\n >\n <a-form\n ref=\"formRef\"\n :model=\"model\"\n layout=\"vertical\"\n size=\"small\"\n >\n <a-divider orientation=\"left\">基本信息</a-divider>\n <a-row :gutter=\"16\">\n <a-col :span=\"12\">\n <a-form-item\n label=\"数据源名称\"\n name=\"name\"\n :rules=\"rules.name\"\n >\n <a-input\n v-model:value=\"model.name\"\n placeholder=\"请填写数据源名称\"\n allow-clear\n />\n </a-form-item>\n </a-col>\n <a-col :span=\"12\">\n <a-form-item\n label=\"数据源类型\"\n name=\"source_type\"\n :rules=\"rules.source_type\"\n >\n <a-select\n v-model:value=\"model.source_type\"\n placeholder=\"请选择\"\n @change=\"onSourceTypeChange\"\n >\n <a-select-option\n v-for=\"opt in sourceTypeOptions\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n >\n {{ opt.label }}\n </a-select-option>\n </a-select>\n </a-form-item>\n </a-col>\n <a-col\n v-if=\"model.source_type === 'db'\"\n :span=\"12\"\n >\n <a-form-item\n label=\"数据库类型\"\n name=\"db_type\"\n :rules=\"rules.db_type\"\n >\n <a-select\n v-model:value=\"model.db_type\"\n placeholder=\"请选择\"\n >\n <a-select-option\n v-for=\"opt in dbTypeOptions\"\n :key=\"opt.value\"\n :value=\"opt.value\"\n >\n {{ opt.label }}\n </a-select-option>\n </a-select>\n </a-form-item>\n </a-col>\n </a-row>\n\n <!-- 数据库类型:连接信息 -->\n <template v-if=\"model.source_type === 'db'\">\n <a-divider orientation=\"left\">数据库连接信息</a-divider>\n <a-row :gutter=\"16\">\n <a-col :span=\"12\">\n <a-form-item\n label=\"数据库主机\"\n name=\"db_host\"\n :rules=\"rules.db_host\"\n >\n <a-input\n v-model:value=\"model.db_host\"\n placeholder=\"如 127.0.0.1\"\n allow-clear\n />\n </a-form-item>\n </a-col>\n <a-col :span=\"12\">\n <a-form-item\n label=\"数据库端口\"\n name=\"db_port\"\n :rules=\"rules.db_port\"\n >\n <a-input-number\n v-model:value=\"model.db_port\"\n style=\"width: 100%\"\n :min=\"1\"\n :max=\"65535\"\n placeholder=\"如 3306\"\n />\n </a-form-item>\n </a-col>\n <a-col :span=\"12\">\n <a-form-item\n label=\"数据库用户\"\n name=\"db_user\"\n :rules=\"rules.db_user\"\n >\n <a-input\n v-model:value=\"model.db_user\"\n placeholder=\"如 root\"\n allow-clear\n />\n </a-form-item>\n </a-col>\n <a-col :span=\"12\">\n <a-form-item\n label=\"数据库密码\"\n name=\"db_password\"\n >\n <a-input-password\n v-model:value=\"model.db_password\"\n placeholder=\"修改时留空则不修改密码\"\n allow-clear\n autocomplete=\"new-password\"\n />\n </a-form-item>\n </a-col>\n <a-col :span=\"12\">\n <a-form-item\n label=\"数据库名称\"\n name=\"db_name\"\n :rules=\"rules.db_name\"\n >\n <a-input\n v-model:value=\"model.db_name\"\n placeholder=\"如 my_db\"\n allow-clear\n />\n </a-form-item>\n </a-col>\n </a-row>\n <a-form-item\n label=\"数据库选项(JSON)\"\n name=\"db_options\"\n >\n <a-textarea\n v-model:value=\"model.db_options_str\"\n placeholder='可选,JSON 对象,如 {\"charset\":\"utf8mb4\"}'\n :auto-size=\"{ minRows: 2, maxRows: 6 }\"\n allow-clear\n />\n <div class=\"field-extra\">该字段仅在保存时解析为 JSON,留空则使用 {}。</div>\n </a-form-item>\n </template>\n\n <!-- 自定义类型:采集函数 -->\n <template v-else-if=\"model.source_type === 'custom'\">\n <a-divider orientation=\"left\">自定义采集</a-divider>\n <a-row :gutter=\"16\">\n <a-col :span=\"12\">\n <a-form-item\n label=\"自定义采集函数名称\"\n name=\"custom_func\"\n :rules=\"rules.custom_func\"\n >\n <a-select\n v-model:value=\"model.custom_func\"\n placeholder=\"请选择采集函数\"\n :options=\"customFuncOptions\"\n option-filter-prop=\"label\"\n show-search\n allow-clear\n :loading=\"funcOptionsLoading\"\n />\n </a-form-item>\n </a-col>\n </a-row>\n <a-form-item\n label=\"自定义采集函数参数(JSON)\"\n name=\"custom_func_kwargs\"\n >\n <a-textarea\n v-model:value=\"model.custom_func_kwargs_str\"\n placeholder='可选,JSON 对象,如 {\"token\":\"xxx\"}'\n :auto-size=\"{ minRows: 2, maxRows: 6 }\"\n allow-clear\n />\n <div class=\"field-extra\">该字段仅在保存时解析为 JSON,留空则使用 {}。</div>\n </a-form-item>\n </template>\n </a-form>\n </a-modal>\n</template>\n\n<script setup lang=\"ts\">\nimport { cloneDeep } from 'lodash';\nimport { message } from 'ant-design-vue';\nimport { onMounted, reactive, ref } from 'vue';\nimport { event_obj } from 'liyu-pc-base/init-plugin';\nimport { getApiData } from 'liyu-pc-base/api/api-model';\nimport { useUserStore } from 'liyu-pc-base/init-plugin';\ninterface Props {\n title: string;\n record: any;\n}\nconst props = defineProps<Props>();\nconst emit = defineEmits(['cancel', 'ok']);\n\nconst formRef = ref<any>(null);\nconst loading = ref(false);\nconst open = ref(true);\nconst form_type = ref('create');\nconst userStore = useUserStore();\nconst current_org = userStore.currentOrg;\n\nconst sourceTypeOptions = [\n { value: 'db', label: '数据库' },\n { value: 'custom', label: '自定义' },\n];\nconst dbTypeOptions = [\n { value: 'mysql', label: 'MySQL' },\n { value: 'tsql', label: 'SQL Server' },\n];\n\n/* 自定义采集函数下拉选项(来自后端 get_collect_funcs) */\nconst customFuncOptions = ref<any[]>([]);\nconst funcOptionsLoading = ref(false);\nconst loadCustomFuncOptions = async () => {\n funcOptionsLoading.value = true;\n try {\n const res = await getApiData(\n { org_id: current_org?.id },\n `${props.record.model_app}/get_collect_funcs`,\n );\n customFuncOptions.value = res || [];\n } catch (e) {\n customFuncOptions.value = [];\n } finally {\n funcOptionsLoading.value = false;\n }\n};\n\nconst model = ref<any>({\n name: undefined,\n source_type: 'db',\n db_type: 'mysql',\n db_host: undefined,\n db_port: undefined,\n db_user: undefined,\n db_password: undefined,\n db_name: undefined,\n db_options_str: '',\n custom_func: undefined,\n custom_func_kwargs_str: '',\n});\n\nconst rules = reactive<any>({\n name: [{ required: true, message: '请填写数据源名称' }],\n source_type: [{ required: true, message: '请选择数据源类型' }],\n db_type: [{ required: true, message: '请选择数据库类型' }],\n db_host: [{ required: true, message: '请填写数据库主机' }],\n db_port: [{ required: true, message: '请填写数据库端口' }],\n db_user: [{ required: true, message: '请填写数据库用户' }],\n db_name: [{ required: true, message: '请填写数据库名称' }],\n custom_func: [{ required: true, message: '请填写自定义采集函数名称' }],\n});\n\n/* 切换数据源类型时,清空与另一类型无关的不必要校验残留 */\nconst onSourceTypeChange = () => {\n if (model.value.source_type === 'db') {\n model.value.custom_func = undefined;\n model.value.custom_func_kwargs_str = '';\n } else {\n model.value.db_host = undefined;\n model.value.db_port = undefined;\n model.value.db_user = undefined;\n model.value.db_password = undefined;\n model.value.db_name = undefined;\n model.value.db_options_str = '';\n }\n};\n\n/* 将 JSON 字符串解析为对象;空字符串返回 {};解析失败抛出错误 */\nconst parseJsonField = (str: string, fieldName: string): any => {\n if (str === undefined || str === null || String(str).trim() === '') return {};\n try {\n return JSON.parse(str);\n } catch (e) {\n throw new Error(`${fieldName} 不是合法 JSON: ${(e as Error).message}`);\n }\n};\n\n/* 兼容 getApiData 可能的返回结构(直接对象 或 {data:{...}}) */\nconst extractData = (res: any) => {\n if (res && typeof res === 'object' && !Array.isArray(res) && res.data !== undefined)\n return res.data;\n return res;\n};\n\n/* 编辑:调用公共项目提供的详情接口(<app_flag>/get_<model_name>,即 get_basemodel)\n 获取完整的 SyncDataSource 记录。不依赖列表行数据 props.record,因为它可能缺失\n 部分字段。get_basemodel 返回单条 dict(非列表),按 id 查询(参数名\n 为 <model_name>_id,即 sync_data_source_id)。 */\nconst loadDetail = async (id: any) => {\n const res = await getApiData(\n { sync_data_source_id: id, org_id: current_org?.id },\n `${props.record.model_app}/get_sync_data_source`,\n );\n return extractData(res) || {};\n};\n\n/* 构建提交数据:始终 cloneDeep(model.value),兜底默认值 */\nconst buildPayload = () => {\n const payload: any = cloneDeep(model.value);\n payload.update_field_list = [\n 'name',\n 'source_type',\n 'db_type',\n 'db_host',\n 'db_port',\n 'db_user',\n 'db_password',\n 'db_name',\n 'db_options',\n 'custom_func',\n 'custom_func_kwargs',\n ];\n const isDb = payload.source_type === 'db';\n\n // 仅保留当前类型相关字段,避免把另一类型的空值带给后端\n if (isDb) {\n delete payload.custom_func;\n delete payload.custom_func_kwargs_str;\n payload.custom_func_kwargs = {};\n payload.db_options = parseJsonField(payload.db_options_str, '数据库选项');\n delete payload.db_options_str;\n // 编辑时密码留空则不修改:删除字段值,并从 update_field_list 中剔除,避免后端更新\n if (!payload.db_password) {\n delete payload.db_password;\n if (form_type.value === 'edit') {\n payload.update_field_list = payload.update_field_list.filter(\n (k: string) => k !== 'db_password',\n );\n }\n }\n } else {\n [\n 'db_type',\n 'db_host',\n 'db_port',\n 'db_user',\n 'db_password',\n 'db_name',\n 'db_options_str',\n ].forEach(k => delete payload[k]);\n payload.db_options = {};\n payload.custom_func_kwargs = parseJsonField(\n payload.custom_func_kwargs_str,\n '自定义采集函数参数',\n );\n delete payload.custom_func_kwargs_str;\n }\n\n return payload;\n};\n\n/* 提交:URL 遵循 /{app_flag}/create_{model} 与 /{app_flag}/update_{model} */\nconst handleOk = async () => {\n try {\n await formRef.value.validate();\n const isDb = model.value.source_type === 'db';\n if (isDb) {\n if (!model.value.db_host) {\n message.error('请填写数据库主机');\n return;\n }\n if (model.value.db_port === undefined || model.value.db_port === null) {\n message.error('请填写数据库端口');\n return;\n }\n if (!model.value.db_user) {\n message.error('请填写数据库用户');\n return;\n }\n if (!model.value.db_name) {\n message.error('请填写数据库名称');\n return;\n }\n if (form_type.value === 'create' && !model.value.db_password) {\n message.error('请填写数据库密码');\n return;\n }\n if (model.value.db_options_str && model.value.db_options_str.trim() !== '') {\n try {\n JSON.parse(model.value.db_options_str);\n } catch (e: any) {\n message.error(`数据库选项不是合法 JSON: ${e.message}`);\n return;\n }\n }\n } else {\n if (!model.value.custom_func) {\n message.error('请填写自定义采集函数名称');\n return;\n }\n if (model.value.custom_func_kwargs_str && model.value.custom_func_kwargs_str.trim() !== '') {\n try {\n JSON.parse(model.value.custom_func_kwargs_str);\n } catch (e: any) {\n message.error(`自定义采集函数参数不是合法 JSON: ${e.message}`);\n return;\n }\n }\n }\n\n const payload = buildPayload();\n payload.sync_data_source_id = props.record.id;\n const url =\n form_type.value === 'edit'\n ? `${props.record.model_app}/update_sync_data_source`\n : `${props.record.model_app}/create_sync_data_source`;\n if (form_type.value === 'edit') payload.id = props.record.id;\n loading.value = true;\n await getApiData({ ...payload, org_id: current_org?.id }, url);\n message.success('操作成功');\n event_obj()?.emit('refresh');\n emit('ok');\n } catch (error) {\n // 校验失败或接口异常:保持弹窗打开\n } finally {\n loading.value = false;\n }\n};\nconst handleCancel = () => emit('cancel');\n\n/* 初始化编辑:先调详情接口拿完整记录,再填充;并把 JSON 字段格式化为字符串 */\nconst initForEdit = async () => {\n const id = props.record?.id;\n // 编辑时依赖详情接口而非列表行数据(列表行可能缺失字段)\n const record = (id != null ? await loadDetail(id) : props.record) || {};\n const rawDbOptions = record.db_options;\n const rawCustomKwargs = record.custom_func_kwargs;\n model.value = {\n name: record.name || '',\n source_type: record.source_type || 'db',\n db_type: record.db_type || 'mysql',\n db_host: record.db_host || undefined,\n db_port: record.db_port ?? undefined,\n db_user: record.db_user || undefined,\n db_password: undefined, // 密码不回显,留空表示不修改\n db_name: record.db_name || undefined,\n db_options_str:\n rawDbOptions && typeof rawDbOptions === 'object' ? JSON.stringify(rawDbOptions, null, 2) : '',\n custom_func: record.custom_func || undefined,\n custom_func_kwargs_str:\n rawCustomKwargs && typeof rawCustomKwargs === 'object'\n ? JSON.stringify(rawCustomKwargs, null, 2)\n : '',\n };\n // 编辑时若已保存的采集函数不在当前选项列表中,补充进下拉避免丢失显示\n const rawCustomFunc = record.custom_func;\n if (rawCustomFunc && !customFuncOptions.value.some(o => o.value === rawCustomFunc)) {\n customFuncOptions.value = [\n { value: rawCustomFunc, label: rawCustomFunc },\n ...customFuncOptions.value,\n ];\n }\n};\n\nonMounted(async () => {\n if (props.record?.form_type) form_type.value = props.record.form_type;\n await loadCustomFuncOptions();\n if (form_type.value === 'edit') await initForEdit();\n});\n</script>\n\n<style scoped lang=\"less\">\n.field-extra {\n color: #999;\n font-size: 12px;\n line-height: 1.4;\n margin-top: 2px;\n}\n</style>\n"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"syncExportRawData-dtLd_SL2.js","names":[],"sources":["../src/components/lysync/syncConditionGroup.vue","../src/components/lysync/syncConditionGroup.vue","../src/components/lysync/syncExportRawData.vue","../src/components/lysync/syncExportRawData.vue"],"sourcesContent":["<template>\n <div class=\"qb-group\">\n <div class=\"qb-group-head\">\n <a-select\n style=\"width: 110px\"\n :value=\"group.type || 'and'\"\n :options=\"[\n { label: '并且', value: 'and' },\n { label: '或者', value: 'or' },\n ]\"\n @update:value=\"(v:string) => (group.type = v)\"\n />\n <a-button\n size=\"small\"\n @click=\"addRule\"\n >\n 添加条件\n </a-button>\n <a-button\n size=\"small\"\n style=\"margin-left: 8px\"\n @click=\"addGroup\"\n >\n 添加分组\n </a-button>\n </div>\n\n <div class=\"qb-group-body\">\n <template\n v-for=\"(child, idx) in group.conditions\"\n :key=\"idx\"\n >\n <!-- 分组 -->\n <div\n v-if=\"child && typeof child === 'object' && 'type' in child\"\n class=\"qb-subgroup\"\n >\n <ConditionGroup\n :group=\"child\"\n :columns=\"columns\"\n />\n <a-button\n danger\n size=\"small\"\n style=\"margin: 4px 0\"\n @click=\"removeAt(idx)\"\n >\n 删除分组\n </a-button>\n </div>\n <!-- 规则 -->\n <div\n v-else\n class=\"qb-rule\"\n >\n <a-select\n :value=\"child.field\"\n style=\"min-width: 200px\"\n placeholder=\"选择字段\"\n :options=\"fieldOptions\"\n @update:value=\"(v:string)=> (child.field = v)\"\n />\n <a-select\n :value=\"child.op\"\n style=\"width: 200px\"\n :options=\"operators\"\n @update:value=\"(v:string)=> (child.op = v)\"\n />\n\n <!-- 值输入区域 -->\n <template v-if=\"child.op === 'in'\">\n <a-select\n mode=\"tags\"\n style=\"min-width: 220px\"\n :value=\"Array.isArray(child.value) ? child.value : []\"\n placeholder=\"输入多个值后回车\"\n @update:value=\"(v:any)=> (child.value = v)\"\n />\n </template>\n <template v-else-if=\"child.op === 'between'\">\n <a-space :size=\"4\">\n <a-input\n style=\"width: 120px\"\n :value=\"Array.isArray(child.value) ? child.value?.[0] : undefined\"\n placeholder=\"起始值\"\n @update:value=\"(v:any)=> updateBetween(child, 0, v)\"\n />\n <span style=\"padding: 0 4px; color: #999\">~</span>\n <a-input\n style=\"width: 120px\"\n :value=\"Array.isArray(child.value) ? child.value?.[1] : undefined\"\n placeholder=\"结束值\"\n @update:value=\"(v:any)=> updateBetween(child, 1, v)\"\n />\n </a-space>\n </template>\n <template v-else-if=\"child.op === 'is'\">\n <a-select\n style=\"min-width: 160px\"\n :value=\"child.value\"\n placeholder=\"选择 NULL/TRUE/FALSE\"\n @update:value=\"(v:any)=> (child.value = v)\"\n >\n <a-select-option :value=\"null\">NULL</a-select-option>\n <a-select-option :value=\"true\">TRUE</a-select-option>\n <a-select-option :value=\"false\">FALSE</a-select-option>\n </a-select>\n </template>\n <template v-else>\n <a-input\n style=\"min-width: 220px\"\n :value=\"child.value\"\n placeholder=\"输入值\"\n @update:value=\"(v:any)=> (child.value = v)\"\n />\n </template>\n\n <a-button\n danger\n size=\"small\"\n @click=\"removeAt(idx)\"\n >\n 删除\n </a-button>\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, computed } from 'vue';\n\nexport default defineComponent({\n name: 'ConditionGroup',\n props: {\n group: { type: Object as any, required: true },\n columns: { type: Array as any, required: true },\n isRoot: { type: Boolean, default: false },\n },\n setup(props) {\n const operators = [\n { label: '等于', value: '=' },\n { label: '不等于', value: '!=' },\n { label: '大于', value: '>' },\n { label: '大于或等于', value: '>=' },\n { label: '小于', value: '<' },\n { label: '小于或等于', value: '<=' },\n { label: '包含', value: 'in' },\n { label: '模糊匹配', value: 'like' },\n { label: '介于', value: 'between' },\n ];\n\n const fieldOptions = computed(() =>\n (props.columns as any[]).map((c: any) => ({ label: c.title, value: c.dataIndex })),\n );\n\n const addRule = () => {\n (props.group as any).conditions.push({ field: '', op: '=', value: '' });\n };\n const addGroup = () => {\n (props.group as any).conditions.push({ type: 'and', conditions: [] });\n };\n const removeAt = (idx: number) => {\n (props.group as any).conditions.splice(idx, 1);\n };\n const updateBetween = (rule: any, pos: number, v: any) => {\n const arr = Array.isArray(rule.value) ? rule.value : [undefined, undefined];\n arr[pos] = v;\n rule.value = arr;\n };\n\n return {\n operators,\n fieldOptions,\n addRule,\n addGroup,\n removeAt,\n updateBetween,\n };\n },\n});\n</script>\n\n<style lang=\"less\" scoped>\n.qb-group {\n border-left: 2px solid #f0f0f0;\n padding-left: 8px;\n}\n.qb-group-head {\n display: flex;\n gap: 8px;\n margin-bottom: 8px;\n}\n.qb-group-body {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.qb-rule {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.qb-subgroup {\n padding: 6px 0 6px 8px;\n border-left: 2px dashed #f0f0f0;\n}\n</style>\n","<template>\n <div class=\"qb-group\">\n <div class=\"qb-group-head\">\n <a-select\n style=\"width: 110px\"\n :value=\"group.type || 'and'\"\n :options=\"[\n { label: '并且', value: 'and' },\n { label: '或者', value: 'or' },\n ]\"\n @update:value=\"(v:string) => (group.type = v)\"\n />\n <a-button\n size=\"small\"\n @click=\"addRule\"\n >\n 添加条件\n </a-button>\n <a-button\n size=\"small\"\n style=\"margin-left: 8px\"\n @click=\"addGroup\"\n >\n 添加分组\n </a-button>\n </div>\n\n <div class=\"qb-group-body\">\n <template\n v-for=\"(child, idx) in group.conditions\"\n :key=\"idx\"\n >\n <!-- 分组 -->\n <div\n v-if=\"child && typeof child === 'object' && 'type' in child\"\n class=\"qb-subgroup\"\n >\n <ConditionGroup\n :group=\"child\"\n :columns=\"columns\"\n />\n <a-button\n danger\n size=\"small\"\n style=\"margin: 4px 0\"\n @click=\"removeAt(idx)\"\n >\n 删除分组\n </a-button>\n </div>\n <!-- 规则 -->\n <div\n v-else\n class=\"qb-rule\"\n >\n <a-select\n :value=\"child.field\"\n style=\"min-width: 200px\"\n placeholder=\"选择字段\"\n :options=\"fieldOptions\"\n @update:value=\"(v:string)=> (child.field = v)\"\n />\n <a-select\n :value=\"child.op\"\n style=\"width: 200px\"\n :options=\"operators\"\n @update:value=\"(v:string)=> (child.op = v)\"\n />\n\n <!-- 值输入区域 -->\n <template v-if=\"child.op === 'in'\">\n <a-select\n mode=\"tags\"\n style=\"min-width: 220px\"\n :value=\"Array.isArray(child.value) ? child.value : []\"\n placeholder=\"输入多个值后回车\"\n @update:value=\"(v:any)=> (child.value = v)\"\n />\n </template>\n <template v-else-if=\"child.op === 'between'\">\n <a-space :size=\"4\">\n <a-input\n style=\"width: 120px\"\n :value=\"Array.isArray(child.value) ? child.value?.[0] : undefined\"\n placeholder=\"起始值\"\n @update:value=\"(v:any)=> updateBetween(child, 0, v)\"\n />\n <span style=\"padding: 0 4px; color: #999\">~</span>\n <a-input\n style=\"width: 120px\"\n :value=\"Array.isArray(child.value) ? child.value?.[1] : undefined\"\n placeholder=\"结束值\"\n @update:value=\"(v:any)=> updateBetween(child, 1, v)\"\n />\n </a-space>\n </template>\n <template v-else-if=\"child.op === 'is'\">\n <a-select\n style=\"min-width: 160px\"\n :value=\"child.value\"\n placeholder=\"选择 NULL/TRUE/FALSE\"\n @update:value=\"(v:any)=> (child.value = v)\"\n >\n <a-select-option :value=\"null\">NULL</a-select-option>\n <a-select-option :value=\"true\">TRUE</a-select-option>\n <a-select-option :value=\"false\">FALSE</a-select-option>\n </a-select>\n </template>\n <template v-else>\n <a-input\n style=\"min-width: 220px\"\n :value=\"child.value\"\n placeholder=\"输入值\"\n @update:value=\"(v:any)=> (child.value = v)\"\n />\n </template>\n\n <a-button\n danger\n size=\"small\"\n @click=\"removeAt(idx)\"\n >\n 删除\n </a-button>\n </div>\n </template>\n </div>\n </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, computed } from 'vue';\n\nexport default defineComponent({\n name: 'ConditionGroup',\n props: {\n group: { type: Object as any, required: true },\n columns: { type: Array as any, required: true },\n isRoot: { type: Boolean, default: false },\n },\n setup(props) {\n const operators = [\n { label: '等于', value: '=' },\n { label: '不等于', value: '!=' },\n { label: '大于', value: '>' },\n { label: '大于或等于', value: '>=' },\n { label: '小于', value: '<' },\n { label: '小于或等于', value: '<=' },\n { label: '包含', value: 'in' },\n { label: '模糊匹配', value: 'like' },\n { label: '介于', value: 'between' },\n ];\n\n const fieldOptions = computed(() =>\n (props.columns as any[]).map((c: any) => ({ label: c.title, value: c.dataIndex })),\n );\n\n const addRule = () => {\n (props.group as any).conditions.push({ field: '', op: '=', value: '' });\n };\n const addGroup = () => {\n (props.group as any).conditions.push({ type: 'and', conditions: [] });\n };\n const removeAt = (idx: number) => {\n (props.group as any).conditions.splice(idx, 1);\n };\n const updateBetween = (rule: any, pos: number, v: any) => {\n const arr = Array.isArray(rule.value) ? rule.value : [undefined, undefined];\n arr[pos] = v;\n rule.value = arr;\n };\n\n return {\n operators,\n fieldOptions,\n addRule,\n addGroup,\n removeAt,\n updateBetween,\n };\n },\n});\n</script>\n\n<style lang=\"less\" scoped>\n.qb-group {\n border-left: 2px solid #f0f0f0;\n padding-left: 8px;\n}\n.qb-group-head {\n display: flex;\n gap: 8px;\n margin-bottom: 8px;\n}\n.qb-group-body {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.qb-rule {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.qb-subgroup {\n padding: 6px 0 6px 8px;\n border-left: 2px dashed #f0f0f0;\n}\n</style>\n","<template>\n <a-modal\n title=\"原始数据\"\n width=\"1300px\"\n v-model:open=\"open\"\n :maskClosable=\"false\"\n centered\n @cancel=\"handleCancel\"\n >\n <div>\n <a-card\n size=\"small\"\n :bordered=\"false\"\n style=\"margin-bottom: 12px\"\n >\n <a-space\n direction=\"vertical\"\n :size=\"8\"\n style=\"width: 100%\"\n >\n <div style=\"display: flex; justify-content: space-between; align-items: center\">\n <div style=\"font-weight: 600\">查询条件</div>\n <div>\n <a-button\n size=\"small\"\n @click=\"resetConditions\"\n >\n 重置\n </a-button>\n <a-button\n type=\"primary\"\n size=\"small\"\n style=\"margin-left: 8px\"\n @click=\"applySearch\"\n >\n 查询\n </a-button>\n </div>\n </div>\n <div class=\"conditions-scroll\">\n <ConditionGroup\n :group=\"conditionsRoot\"\n :columns=\"column\"\n :is-root=\"true\"\n />\n </div>\n <div class=\"time-range-row\">\n <span class=\"field-label\">时间范围:</span>\n <a-range-picker\n v-model:value=\"timeRange\"\n :show-time=\"{ format: 'HH:mm:ss' }\"\n format=\"YYYY-MM-DD HH:mm:ss\"\n value-format=\"YYYY-MM-DD HH:mm:ss\"\n :placeholder=\"['开始时间', '结束时间']\"\n style=\"width: 440px\"\n />\n </div>\n </a-space>\n </a-card>\n <a-spin :spinning=\"loading\">\n <a-table\n :columns=\"column\"\n :dataSource=\"datasource\"\n rowKey=\"id\"\n :pagination=\"{\n current: current,\n pageSize: pageSize,\n total: total,\n onChange: handlePageChange,\n showSizeChanger: true,\n showQuickJumper: true,\n pageSizeOptions: pageOptions,\n }\"\n :scroll=\"{ y: height, x: width }\"\n @change=\"handleTableChange\"\n ></a-table>\n </a-spin>\n </div>\n <template #footer>\n <a-button\n key=\"back\"\n @click=\"handleCancel\"\n >\n 关闭\n </a-button>\n <a-button\n key=\"ok\"\n type=\"primary\"\n @click=\"handleCancel\"\n >\n 确定\n </a-button>\n </template>\n </a-modal>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, onUnmounted, ref, onMounted, computed } from 'vue';\nimport { debounce } from 'lodash';\nimport ConditionGroup from './syncConditionGroup.vue';\nimport { getApiData } from 'liyu-pc-base/api/api-model';\nimport dayjs from 'dayjs';\n\nexport default defineComponent({\n name: 'ExportRawData',\n components: { ConditionGroup },\n props: {\n title: {\n type: String,\n required: false,\n default: () => '',\n },\n record: {\n type: Object,\n required: false,\n default: () => ({}),\n },\n },\n setup(props, { emit }) {\n const height = ref(window.innerHeight - 550);\n const onresize: any = debounce(() => {\n height.value = window.innerHeight - 550;\n }, 200);\n const loading = ref(false);\n\n const datasource = ref<any[]>([]);\n const open = ref(true);\n const titleMap = ref({});\n\n const column = computed(() => {\n const res = [];\n if (datasource.value?.length) {\n for (const key of Object.keys(datasource.value[0])) {\n const title = titleMap.value[key] || key;\n res.push({\n title: title,\n dataIndex: key,\n key: key,\n });\n }\n }\n return res;\n });\n\n const get_column_config = async () => {\n const res: any = await getApiData(\n {\n export_task_id: (props as any).record?.id,\n },\n `${props.record.model_app}/query_sync_model_field_list`,\n );\n if (res?.data?.length) {\n for (const item of res.data) {\n titleMap.value[item.field_name] = item.name;\n }\n }\n };\n const current = ref<number>(1);\n const pageSize = ref<number>(10);\n const total = ref<number>(0);\n const width = computed(() => {\n let w = column.value.length * 200;\n return w < 1000 ? 1000 : w;\n });\n const pageOptions = ref<string[]>([\n '10',\n '20',\n '50',\n '100',\n '500',\n '1000',\n '2000',\n '5000',\n '10000',\n ]);\n\n // 条件构建器根\n const conditionsRoot = ref<any>({ type: 'and', conditions: [] });\n\n // 时间范围([start, end] 字符串,格式 YYYY-MM-DD HH:mm:ss;用于后端 start_time/end_time)\n const timeRange = ref<any>(null);\n\n // 排序状态 - 支持多字段排序\n const sortFields = ref<Array<{ field: string; order: string }>>([]);\n\n const handleCancel = () => {\n emit('cancel');\n };\n\n const get_datasource = async () => {\n loading.value = true;\n try {\n const params: any = {\n export_task_id: (props as any).record?.id,\n current: current.value,\n pageSize: pageSize.value,\n conditions: conditionsRoot.value,\n sort_fields: sortFields.value.length > 0 ? sortFields.value : undefined,\n };\n // 时间范围:前端传则带上(供后端作为 start_time/end_time 渲染 SQL),不传则回退默认区间\n if (\n timeRange.value &&\n timeRange.value.length === 2 &&\n timeRange.value[0] &&\n timeRange.value[1]\n ) {\n params.time_range = timeRange.value;\n }\n const res: any = await getApiData(params, `${props.record.model_app}/query_raw_data`);\n datasource.value = res?.data || [];\n current.value = res?.current ?? current.value;\n pageSize.value = res?.pageSize ?? pageSize.value;\n total.value = res?.total ?? 0;\n } finally {\n loading.value = false;\n }\n };\n\n const handlePageChange = (page: number, size?: number) => {\n current.value = page;\n if (size && size !== pageSize.value) pageSize.value = size;\n get_datasource();\n };\n\n const handleTableChange = (pagination: any, filters: any, sorter: any, { action }: any) => {\n if (action === 'sort') {\n if (sorter?.field) {\n const field = sorter.field;\n const order = sorter.order === 'ascend' ? 'asc' : 'desc';\n sortFields.value = [{ field: field, order: order }];\n } else {\n // 清除所有排序\n sortFields.value = [];\n }\n\n // 重置到第一页并重新查询\n current.value = 1;\n get_datasource();\n }\n };\n\n const resetConditions = () => {\n conditionsRoot.value = { type: 'and', conditions: [] };\n timeRange.value = null;\n };\n const applySearch = () => {\n current.value = 1;\n get_datasource();\n };\n\n onMounted(() => {\n window.addEventListener('resize', onresize);\n onresize();\n get_column_config();\n let start_time = '';\n if (props.record?.data_start_date) {\n start_time = props.record?.data_start_date + ' 00:00:00';\n } else {\n start_time = dayjs().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss');\n }\n timeRange.value = [start_time, dayjs().format('YYYY-MM-DD HH:mm:ss')];\n });\n onUnmounted(() => {\n window.removeEventListener('resize', onresize);\n });\n return {\n height,\n handleCancel,\n open,\n column,\n width,\n datasource,\n current,\n pageSize,\n total,\n handlePageChange,\n pageOptions,\n // 条件\n conditionsRoot,\n resetConditions,\n applySearch,\n loading,\n handleTableChange,\n // 时间范围\n timeRange,\n };\n },\n});\n</script>\n<style lang=\"less\" scoped>\n.qb-group {\n border-left: 2px solid #f0f0f0;\n padding-left: 8px;\n}\n.qb-group-head {\n display: flex;\n gap: 8px;\n margin-bottom: 8px;\n}\n.qb-group-body {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.qb-rule {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.qb-subgroup {\n padding: 6px 0 6px 8px;\n border-left: 2px dashed #f0f0f0;\n}\n.conditions-scroll {\n max-height: 200px;\n overflow-y: auto;\n padding-right: 8px;\n}\n.time-range-row {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 8px;\n}\n.field-label {\n font-weight: 500;\n color: rgba(0, 0, 0, 0.85);\n}\n</style>\n","<template>\n <a-modal\n title=\"原始数据\"\n width=\"1300px\"\n v-model:open=\"open\"\n :maskClosable=\"false\"\n centered\n @cancel=\"handleCancel\"\n >\n <div>\n <a-card\n size=\"small\"\n :bordered=\"false\"\n style=\"margin-bottom: 12px\"\n >\n <a-space\n direction=\"vertical\"\n :size=\"8\"\n style=\"width: 100%\"\n >\n <div style=\"display: flex; justify-content: space-between; align-items: center\">\n <div style=\"font-weight: 600\">查询条件</div>\n <div>\n <a-button\n size=\"small\"\n @click=\"resetConditions\"\n >\n 重置\n </a-button>\n <a-button\n type=\"primary\"\n size=\"small\"\n style=\"margin-left: 8px\"\n @click=\"applySearch\"\n >\n 查询\n </a-button>\n </div>\n </div>\n <div class=\"conditions-scroll\">\n <ConditionGroup\n :group=\"conditionsRoot\"\n :columns=\"column\"\n :is-root=\"true\"\n />\n </div>\n <div class=\"time-range-row\">\n <span class=\"field-label\">时间范围:</span>\n <a-range-picker\n v-model:value=\"timeRange\"\n :show-time=\"{ format: 'HH:mm:ss' }\"\n format=\"YYYY-MM-DD HH:mm:ss\"\n value-format=\"YYYY-MM-DD HH:mm:ss\"\n :placeholder=\"['开始时间', '结束时间']\"\n style=\"width: 440px\"\n />\n </div>\n </a-space>\n </a-card>\n <a-spin :spinning=\"loading\">\n <a-table\n :columns=\"column\"\n :dataSource=\"datasource\"\n rowKey=\"id\"\n :pagination=\"{\n current: current,\n pageSize: pageSize,\n total: total,\n onChange: handlePageChange,\n showSizeChanger: true,\n showQuickJumper: true,\n pageSizeOptions: pageOptions,\n }\"\n :scroll=\"{ y: height, x: width }\"\n @change=\"handleTableChange\"\n ></a-table>\n </a-spin>\n </div>\n <template #footer>\n <a-button\n key=\"back\"\n @click=\"handleCancel\"\n >\n 关闭\n </a-button>\n <a-button\n key=\"ok\"\n type=\"primary\"\n @click=\"handleCancel\"\n >\n 确定\n </a-button>\n </template>\n </a-modal>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent, onUnmounted, ref, onMounted, computed } from 'vue';\nimport { debounce } from 'lodash';\nimport ConditionGroup from './syncConditionGroup.vue';\nimport { getApiData } from 'liyu-pc-base/api/api-model';\nimport dayjs from 'dayjs';\n\nexport default defineComponent({\n name: 'ExportRawData',\n components: { ConditionGroup },\n props: {\n title: {\n type: String,\n required: false,\n default: () => '',\n },\n record: {\n type: Object,\n required: false,\n default: () => ({}),\n },\n },\n setup(props, { emit }) {\n const height = ref(window.innerHeight - 550);\n const onresize: any = debounce(() => {\n height.value = window.innerHeight - 550;\n }, 200);\n const loading = ref(false);\n\n const datasource = ref<any[]>([]);\n const open = ref(true);\n const titleMap = ref({});\n\n const column = computed(() => {\n const res = [];\n if (datasource.value?.length) {\n for (const key of Object.keys(datasource.value[0])) {\n const title = titleMap.value[key] || key;\n res.push({\n title: title,\n dataIndex: key,\n key: key,\n });\n }\n }\n return res;\n });\n\n const get_column_config = async () => {\n const res: any = await getApiData(\n {\n export_task_id: (props as any).record?.id,\n },\n `${props.record.model_app}/query_sync_model_field_list`,\n );\n if (res?.data?.length) {\n for (const item of res.data) {\n titleMap.value[item.field_name] = item.name;\n }\n }\n };\n const current = ref<number>(1);\n const pageSize = ref<number>(10);\n const total = ref<number>(0);\n const width = computed(() => {\n let w = column.value.length * 200;\n return w < 1000 ? 1000 : w;\n });\n const pageOptions = ref<string[]>([\n '10',\n '20',\n '50',\n '100',\n '500',\n '1000',\n '2000',\n '5000',\n '10000',\n ]);\n\n // 条件构建器根\n const conditionsRoot = ref<any>({ type: 'and', conditions: [] });\n\n // 时间范围([start, end] 字符串,格式 YYYY-MM-DD HH:mm:ss;用于后端 start_time/end_time)\n const timeRange = ref<any>(null);\n\n // 排序状态 - 支持多字段排序\n const sortFields = ref<Array<{ field: string; order: string }>>([]);\n\n const handleCancel = () => {\n emit('cancel');\n };\n\n const get_datasource = async () => {\n loading.value = true;\n try {\n const params: any = {\n export_task_id: (props as any).record?.id,\n current: current.value,\n pageSize: pageSize.value,\n conditions: conditionsRoot.value,\n sort_fields: sortFields.value.length > 0 ? sortFields.value : undefined,\n };\n // 时间范围:前端传则带上(供后端作为 start_time/end_time 渲染 SQL),不传则回退默认区间\n if (\n timeRange.value &&\n timeRange.value.length === 2 &&\n timeRange.value[0] &&\n timeRange.value[1]\n ) {\n params.time_range = timeRange.value;\n }\n const res: any = await getApiData(params, `${props.record.model_app}/query_raw_data`);\n datasource.value = res?.data || [];\n current.value = res?.current ?? current.value;\n pageSize.value = res?.pageSize ?? pageSize.value;\n total.value = res?.total ?? 0;\n } finally {\n loading.value = false;\n }\n };\n\n const handlePageChange = (page: number, size?: number) => {\n current.value = page;\n if (size && size !== pageSize.value) pageSize.value = size;\n get_datasource();\n };\n\n const handleTableChange = (pagination: any, filters: any, sorter: any, { action }: any) => {\n if (action === 'sort') {\n if (sorter?.field) {\n const field = sorter.field;\n const order = sorter.order === 'ascend' ? 'asc' : 'desc';\n sortFields.value = [{ field: field, order: order }];\n } else {\n // 清除所有排序\n sortFields.value = [];\n }\n\n // 重置到第一页并重新查询\n current.value = 1;\n get_datasource();\n }\n };\n\n const resetConditions = () => {\n conditionsRoot.value = { type: 'and', conditions: [] };\n timeRange.value = null;\n };\n const applySearch = () => {\n current.value = 1;\n get_datasource();\n };\n\n onMounted(() => {\n window.addEventListener('resize', onresize);\n onresize();\n get_column_config();\n let start_time = '';\n if (props.record?.data_start_date) {\n start_time = props.record?.data_start_date + ' 00:00:00';\n } else {\n start_time = dayjs().subtract(1, 'day').format('YYYY-MM-DD HH:mm:ss');\n }\n timeRange.value = [start_time, dayjs().format('YYYY-MM-DD HH:mm:ss')];\n });\n onUnmounted(() => {\n window.removeEventListener('resize', onresize);\n });\n return {\n height,\n handleCancel,\n open,\n column,\n width,\n datasource,\n current,\n pageSize,\n total,\n handlePageChange,\n pageOptions,\n // 条件\n conditionsRoot,\n resetConditions,\n applySearch,\n loading,\n handleTableChange,\n // 时间范围\n timeRange,\n };\n },\n});\n</script>\n<style lang=\"less\" scoped>\n.qb-group {\n border-left: 2px solid #f0f0f0;\n padding-left: 8px;\n}\n.qb-group-head {\n display: flex;\n gap: 8px;\n margin-bottom: 8px;\n}\n.qb-group-body {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n.qb-rule {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.qb-subgroup {\n padding: 6px 0 6px 8px;\n border-left: 2px dashed #f0f0f0;\n}\n.conditions-scroll {\n max-height: 200px;\n overflow-y: auto;\n padding-right: 8px;\n}\n.time-range-row {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 8px;\n}\n.field-label {\n font-weight: 500;\n color: rgba(0, 0, 0, 0.85);\n}\n</style>\n"],"mappings":"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"}
|