@core-pilot/client-vue 0.0.14 → 0.0.15
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/cjs/client-vue.css +1 -1
- package/dist/cjs/components/core-remote-select/index.js +2 -0
- package/dist/cjs/components/core-remote-select/index.js.map +1 -0
- package/dist/cjs/components/index.js +1 -1
- package/dist/cjs/components/x-markdown/composables/useConditionEvaluator.js +2 -0
- package/dist/cjs/components/x-markdown/composables/useConditionEvaluator.js.map +1 -0
- package/dist/cjs/components/x-markdown/composables/useRemoteData.js +2 -0
- package/dist/cjs/components/x-markdown/composables/useRemoteData.js.map +1 -0
- package/dist/cjs/components/x-markdown/renderers/hastRenderer.js +1 -1
- package/dist/cjs/components/x-markdown/renderers/hastRenderer.js.map +1 -1
- package/dist/cjs/components/x-markdown/utils/parseCorePilotSchema.js +1 -1
- package/dist/cjs/components/x-markdown/utils/parseCorePilotSchema.js.map +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/es/client-vue.css +1 -1
- package/dist/es/components/core-remote-select/index.js +97 -0
- package/dist/es/components/core-remote-select/index.js.map +1 -0
- package/dist/es/components/index.js +2 -0
- package/dist/es/components/index.js.map +1 -1
- package/dist/es/components/x-markdown/composables/useConditionEvaluator.js +70 -0
- package/dist/es/components/x-markdown/composables/useConditionEvaluator.js.map +1 -0
- package/dist/es/components/x-markdown/composables/useRemoteData.js +335 -0
- package/dist/es/components/x-markdown/composables/useRemoteData.js.map +1 -0
- package/dist/es/components/x-markdown/renderers/hastRenderer.js +76 -22
- package/dist/es/components/x-markdown/renderers/hastRenderer.js.map +1 -1
- package/dist/es/components/x-markdown/utils/parseCorePilotSchema.js +11 -0
- package/dist/es/components/x-markdown/utils/parseCorePilotSchema.js.map +1 -1
- package/dist/es/index.js +2 -0
- package/dist/es/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { defineComponent, ref, computed, h } from "vue";
|
|
2
|
+
import { ElOption, ElSelect } from "element-plus";
|
|
3
|
+
/* empty css */
|
|
4
|
+
/* empty css */
|
|
5
|
+
/* empty css */
|
|
6
|
+
/* empty css */
|
|
7
|
+
/* empty css */
|
|
8
|
+
/* empty css */
|
|
9
|
+
/* empty css */
|
|
10
|
+
import { useRemoteData } from "../x-markdown/composables/useRemoteData.js";
|
|
11
|
+
const CoreRemoteSelect = /* @__PURE__ */ defineComponent({
|
|
12
|
+
name: "CoreRemoteSelect",
|
|
13
|
+
props: {
|
|
14
|
+
modelValue: {
|
|
15
|
+
type: [String, Number, Array],
|
|
16
|
+
default: void 0
|
|
17
|
+
},
|
|
18
|
+
remote: {
|
|
19
|
+
type: Object,
|
|
20
|
+
default: void 0
|
|
21
|
+
},
|
|
22
|
+
formData: {
|
|
23
|
+
type: Object,
|
|
24
|
+
required: true
|
|
25
|
+
},
|
|
26
|
+
disabled: {
|
|
27
|
+
type: Boolean,
|
|
28
|
+
default: false
|
|
29
|
+
},
|
|
30
|
+
placeholder: {
|
|
31
|
+
type: String,
|
|
32
|
+
default: ""
|
|
33
|
+
},
|
|
34
|
+
filterable: {
|
|
35
|
+
type: Boolean,
|
|
36
|
+
default: false
|
|
37
|
+
},
|
|
38
|
+
clearable: {
|
|
39
|
+
type: Boolean,
|
|
40
|
+
default: false
|
|
41
|
+
},
|
|
42
|
+
multiple: {
|
|
43
|
+
type: Boolean,
|
|
44
|
+
default: false
|
|
45
|
+
},
|
|
46
|
+
formProp: {
|
|
47
|
+
type: String,
|
|
48
|
+
default: ""
|
|
49
|
+
}
|
|
50
|
+
// 其他 ElSelect 属性通过 attrs 传递
|
|
51
|
+
},
|
|
52
|
+
emits: ["update:modelValue"],
|
|
53
|
+
setup(props, {
|
|
54
|
+
emit,
|
|
55
|
+
attrs
|
|
56
|
+
}) {
|
|
57
|
+
const query = ref("");
|
|
58
|
+
const {
|
|
59
|
+
loading,
|
|
60
|
+
options,
|
|
61
|
+
loadData
|
|
62
|
+
} = useRemoteData(props.remote, computed(() => props.formData || {}), props.filterable ? query : void 0);
|
|
63
|
+
const remoteMethod = (searchQuery) => {
|
|
64
|
+
query.value = searchQuery || "";
|
|
65
|
+
};
|
|
66
|
+
return () => {
|
|
67
|
+
const selectProps = {
|
|
68
|
+
...attrs,
|
|
69
|
+
modelValue: props.modelValue,
|
|
70
|
+
"onUpdate:modelValue": (value) => {
|
|
71
|
+
emit("update:modelValue", value);
|
|
72
|
+
},
|
|
73
|
+
disabled: props.disabled,
|
|
74
|
+
placeholder: props.placeholder,
|
|
75
|
+
filterable: props.filterable,
|
|
76
|
+
clearable: props.clearable,
|
|
77
|
+
multiple: props.multiple,
|
|
78
|
+
loading: loading.value,
|
|
79
|
+
// Element Plus 的 remote 属性表示启用远程搜索
|
|
80
|
+
remote: !!props.remote && props.filterable,
|
|
81
|
+
// remoteMethod 仅在 filterable 时提供
|
|
82
|
+
remoteMethod: props.remote && props.filterable ? remoteMethod : void 0
|
|
83
|
+
};
|
|
84
|
+
const selectChildren = options.value.map((opt) => h(ElOption, {
|
|
85
|
+
key: String(opt.value),
|
|
86
|
+
label: opt.label,
|
|
87
|
+
value: opt.value,
|
|
88
|
+
disabled: opt.disabled || false
|
|
89
|
+
}));
|
|
90
|
+
return h(ElSelect, selectProps, selectChildren);
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
export {
|
|
95
|
+
CoreRemoteSelect as default
|
|
96
|
+
};
|
|
97
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../../src/components/core-remote-select/index.tsx"],"sourcesContent":["/**\n * 远程检索 Select 组件\n * 基于 Element Plus ElSelect 实现远程检索功能\n */\n\nimport { defineComponent, ref, computed, h, PropType } from 'vue';\nimport { ElSelect, ElOption } from 'element-plus';\nimport { useRemoteData } from '../x-markdown/composables/useRemoteData';\nimport { RemoteConfig } from '@/types/index';\n\nexport default defineComponent({\n name: 'CoreRemoteSelect',\n props: {\n modelValue: {\n type: [String, Number, Array] as PropType<string | number | Array<any>>,\n default: undefined,\n },\n remote: {\n type: Object as PropType<RemoteConfig>,\n default: undefined,\n },\n formData: {\n type: Object as PropType<Record<string, any>>,\n required: true,\n },\n disabled: {\n type: Boolean,\n default: false,\n },\n placeholder: {\n type: String,\n default: '',\n },\n filterable: {\n type: Boolean,\n default: false,\n },\n clearable: {\n type: Boolean,\n default: false,\n },\n multiple: {\n type: Boolean,\n default: false,\n },\n formProp: {\n type: String,\n default: '',\n },\n // 其他 ElSelect 属性通过 attrs 传递\n },\n emits: ['update:modelValue'],\n setup(props, { emit, attrs }) {\n // 搜索关键词(用于 filterable 时的搜索)\n const query = ref<string>('');\n \n // 使用远程数据加载\n const { loading, options, loadData } = useRemoteData(\n props.remote,\n computed(() => props.formData || {}),\n props.filterable ? query : undefined\n );\n\n // 远程搜索方法(仅在 filterable 时使用)\n const remoteMethod = (searchQuery: string) => {\n query.value = searchQuery || '';\n // useRemoteData 会自动处理 query 变化,这里不需要手动调用\n };\n\n // useRemoteData 会在初始化时自动加载一次,不需要手动调用\n\n return () => {\n const selectProps: any = {\n ...attrs,\n modelValue: props.modelValue,\n 'onUpdate:modelValue': (value: any) => {\n emit('update:modelValue', value);\n },\n disabled: props.disabled,\n placeholder: props.placeholder,\n filterable: props.filterable,\n clearable: props.clearable,\n multiple: props.multiple,\n loading: loading.value,\n // Element Plus 的 remote 属性表示启用远程搜索\n remote: !!props.remote && props.filterable,\n // remoteMethod 仅在 filterable 时提供\n remoteMethod: props.remote && props.filterable ? remoteMethod : undefined,\n };\n\n // 渲染选项\n const selectChildren = options.value.map((opt: any) =>\n h(ElOption, {\n key: String(opt.value),\n label: opt.label,\n value: opt.value,\n disabled: opt.disabled || false,\n })\n );\n\n return h(ElSelect, selectProps, selectChildren);\n };\n },\n});\n\n"],"names":["name","props","modelValue","type","String","Number","Array","default","undefined","remote","Object","formData","required","disabled","Boolean","placeholder","filterable","clearable","multiple","formProp","emits","setup","emit","attrs","query","ref","loading","options","loadData","useRemoteData","computed","remoteMethod","searchQuery","value","selectProps","selectChildren","map","opt","h","ElOption","key","label","ElSelect"],"mappings":";;;;;;;;;;AAUA,MAAA,mDAA+B;AAAA,EAC7BA,MAAM;AAAA,EACNC,OAAO;AAAA,IACLC,YAAY;AAAA,MACVC,MAAM,CAACC,QAAQC,QAAQC,KAAK;AAAA,MAC5BC,SAASC;AAAAA;IAEXC,QAAQ;AAAA,MACNN,MAAMO;AAAAA,MACNH,SAASC;AAAAA;IAEXG,UAAU;AAAA,MACRR,MAAMO;AAAAA,MACNE,UAAU;AAAA;IAEZC,UAAU;AAAA,MACRV,MAAMW;AAAAA,MACNP,SAAS;AAAA;IAEXQ,aAAa;AAAA,MACXZ,MAAMC;AAAAA,MACNG,SAAS;AAAA;IAEXS,YAAY;AAAA,MACVb,MAAMW;AAAAA,MACNP,SAAS;AAAA;IAEXU,WAAW;AAAA,MACTd,MAAMW;AAAAA,MACNP,SAAS;AAAA;IAEXW,UAAU;AAAA,MACRf,MAAMW;AAAAA,MACNP,SAAS;AAAA;IAEXY,UAAU;AAAA,MACRhB,MAAMC;AAAAA,MACNG,SAAS;AAAA,IACX;AAAA;AAAA;EAGFa,OAAO,CAAC,mBAAmB;AAAA,EAC3BC,MAAMpB,OAAO;AAAA,IAAEqB;AAAAA,IAAMC;AAAAA,EAAM,GAAG;AAE5B,UAAMC,QAAQC,IAAY,EAAE;AAG5B,UAAM;AAAA,MAAEC;AAAAA,MAASC;AAAAA,MAASC;AAAAA,QAAaC,cACrC5B,MAAMQ,QACNqB,SAAS,MAAM7B,MAAMU,YAAY,CAAA,CAAE,GACnCV,MAAMe,aAAaQ,QAAQhB,MAC7B;AAGA,UAAMuB,eAAgBC,iBAAwB;AAC5CR,YAAMS,QAAQD,eAAe;AAAA,IAE/B;AAIA,WAAO,MAAM;AACX,YAAME,cAAmB;AAAA,QACvB,GAAGX;AAAAA,QACHrB,YAAYD,MAAMC;AAAAA,QAClB,uBAAwB+B,WAAe;AACrCX,eAAK,qBAAqBW,KAAK;AAAA,QACjC;AAAA,QACApB,UAAUZ,MAAMY;AAAAA,QAChBE,aAAad,MAAMc;AAAAA,QACnBC,YAAYf,MAAMe;AAAAA,QAClBC,WAAWhB,MAAMgB;AAAAA,QACjBC,UAAUjB,MAAMiB;AAAAA,QAChBQ,SAASA,QAAQO;AAAAA;AAAAA,QAEjBxB,QAAQ,CAAC,CAACR,MAAMQ,UAAUR,MAAMe;AAAAA;AAAAA,QAEhCe,cAAc9B,MAAMQ,UAAUR,MAAMe,aAAae,eAAevB;AAAAA;AAIlE,YAAM2B,iBAAiBR,QAAQM,MAAMG,IAAKC,SACxCC,EAAEC,UAAU;AAAA,QACVC,KAAKpC,OAAOiC,IAAIJ,KAAK;AAAA,QACrBQ,OAAOJ,IAAII;AAAAA,QACXR,OAAOI,IAAIJ;AAAAA,QACXpB,UAAUwB,IAAIxB,YAAY;AAAA,MAC5B,CAAC,CACH;AAEA,aAAOyB,EAAEI,UAAUR,aAAaC,cAAc;AAAA,IAChD;AAAA,EACF;AACF,CAAC;"}
|
|
@@ -10,10 +10,12 @@ import { default as default10 } from "./core-table/index.js";
|
|
|
10
10
|
import { default as default11 } from "./core-chart/index.js";
|
|
11
11
|
import { default as default12 } from "./core-card/index.js";
|
|
12
12
|
import { default as default13 } from "./core-upload/index.js";
|
|
13
|
+
import { default as default14 } from "./core-remote-select/index.js";
|
|
13
14
|
export {
|
|
14
15
|
default2 as BubbleList,
|
|
15
16
|
default12 as CoreCard,
|
|
16
17
|
default11 as CoreChart,
|
|
18
|
+
default14 as CoreRemoteSelect,
|
|
17
19
|
default9 as CoreResult,
|
|
18
20
|
default10 as CoreTable,
|
|
19
21
|
default7 as CoreText,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
function getNestedValue(obj, path) {
|
|
2
|
+
if (!path) return void 0;
|
|
3
|
+
return path.split(".").reduce((current, key) => {
|
|
4
|
+
if (current == null) return void 0;
|
|
5
|
+
return current[key];
|
|
6
|
+
}, obj);
|
|
7
|
+
}
|
|
8
|
+
function compareValues(fieldValue, operator, compareValue) {
|
|
9
|
+
switch (operator) {
|
|
10
|
+
case "eq":
|
|
11
|
+
return fieldValue == compareValue;
|
|
12
|
+
case "ne":
|
|
13
|
+
return fieldValue != compareValue;
|
|
14
|
+
case "gt":
|
|
15
|
+
return Number(fieldValue) > Number(compareValue);
|
|
16
|
+
case "gte":
|
|
17
|
+
return Number(fieldValue) >= Number(compareValue);
|
|
18
|
+
case "lt":
|
|
19
|
+
return Number(fieldValue) < Number(compareValue);
|
|
20
|
+
case "lte":
|
|
21
|
+
return Number(fieldValue) <= Number(compareValue);
|
|
22
|
+
case "in":
|
|
23
|
+
return Array.isArray(compareValue) && compareValue.includes(fieldValue);
|
|
24
|
+
case "notIn":
|
|
25
|
+
return Array.isArray(compareValue) && !compareValue.includes(fieldValue);
|
|
26
|
+
case "contains":
|
|
27
|
+
return String(fieldValue).includes(String(compareValue));
|
|
28
|
+
case "startsWith":
|
|
29
|
+
return String(fieldValue).startsWith(String(compareValue));
|
|
30
|
+
case "endsWith":
|
|
31
|
+
return String(fieldValue).endsWith(String(compareValue));
|
|
32
|
+
case "regex":
|
|
33
|
+
try {
|
|
34
|
+
return new RegExp(compareValue).test(String(fieldValue));
|
|
35
|
+
} catch {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
case "isEmpty":
|
|
39
|
+
return fieldValue === null || fieldValue === void 0 || fieldValue === "" || Array.isArray(fieldValue) && fieldValue.length === 0;
|
|
40
|
+
case "isNotEmpty":
|
|
41
|
+
return !(fieldValue === null || fieldValue === void 0 || fieldValue === "" || Array.isArray(fieldValue) && fieldValue.length === 0);
|
|
42
|
+
default:
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function evaluateCondition(condition, formData) {
|
|
47
|
+
if ("field" in condition && "operator" in condition) {
|
|
48
|
+
const rule = condition;
|
|
49
|
+
const fieldValue = getNestedValue(formData, rule.field);
|
|
50
|
+
let compareValue = rule.value;
|
|
51
|
+
if (typeof compareValue === "object" && compareValue !== null && "field" in compareValue) {
|
|
52
|
+
compareValue = getNestedValue(formData, compareValue.field);
|
|
53
|
+
}
|
|
54
|
+
return compareValues(fieldValue, rule.operator, compareValue);
|
|
55
|
+
}
|
|
56
|
+
if ("rules" in condition) {
|
|
57
|
+
const group = condition;
|
|
58
|
+
const logic = group.logic || "and";
|
|
59
|
+
const results = group.rules.map(
|
|
60
|
+
(rule) => evaluateCondition(rule, formData)
|
|
61
|
+
);
|
|
62
|
+
return logic === "and" ? results.every((r) => r) : results.some((r) => r);
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
export {
|
|
67
|
+
evaluateCondition,
|
|
68
|
+
getNestedValue
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=useConditionEvaluator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useConditionEvaluator.js","sources":["../../../../../src/components/x-markdown/composables/useConditionEvaluator.ts"],"sourcesContent":["/**\n * 条件评估系统\n * 用于评估条件规则是否满足\n */\n\nimport { \n ConditionRule, \n ConditionGroup, \n ComparisonOperator \n} from '@/types/index';\n\n/**\n * 获取嵌套字段值\n */\nexport function getNestedValue(\n obj: Record<string, any>, \n path: string\n): any {\n if (!path) return undefined;\n return path.split('.').reduce((current, key) => {\n if (current == null) return undefined;\n return current[key];\n }, obj);\n}\n\n/**\n * 比较值\n */\nfunction compareValues(\n fieldValue: any,\n operator: ComparisonOperator,\n compareValue: any\n): boolean {\n switch (operator) {\n case 'eq':\n return fieldValue == compareValue;\n case 'ne':\n return fieldValue != compareValue;\n case 'gt':\n return Number(fieldValue) > Number(compareValue);\n case 'gte':\n return Number(fieldValue) >= Number(compareValue);\n case 'lt':\n return Number(fieldValue) < Number(compareValue);\n case 'lte':\n return Number(fieldValue) <= Number(compareValue);\n case 'in':\n return Array.isArray(compareValue) && compareValue.includes(fieldValue);\n case 'notIn':\n return Array.isArray(compareValue) && !compareValue.includes(fieldValue);\n case 'contains':\n return String(fieldValue).includes(String(compareValue));\n case 'startsWith':\n return String(fieldValue).startsWith(String(compareValue));\n case 'endsWith':\n return String(fieldValue).endsWith(String(compareValue));\n case 'regex':\n try {\n return new RegExp(compareValue).test(String(fieldValue));\n } catch {\n return false;\n }\n case 'isEmpty':\n return (\n fieldValue === null ||\n fieldValue === undefined ||\n fieldValue === '' ||\n (Array.isArray(fieldValue) && fieldValue.length === 0)\n );\n case 'isNotEmpty':\n return !(\n fieldValue === null ||\n fieldValue === undefined ||\n fieldValue === '' ||\n (Array.isArray(fieldValue) && fieldValue.length === 0)\n );\n default:\n return false;\n }\n}\n\n/**\n * 评估条件规则\n */\nexport function evaluateCondition(\n condition: ConditionRule | ConditionGroup,\n formData: Record<string, any>\n): boolean {\n // 单个条件规则\n if ('field' in condition && 'operator' in condition) {\n const rule = condition as ConditionRule;\n const fieldValue = getNestedValue(formData, rule.field);\n \n // 处理比较值:可能是静态值或引用其他字段\n let compareValue = rule.value;\n if (typeof compareValue === 'object' && compareValue !== null && 'field' in compareValue) {\n compareValue = getNestedValue(formData, compareValue.field);\n }\n \n return compareValues(fieldValue, rule.operator, compareValue);\n }\n \n // 条件组合\n if ('rules' in condition) {\n const group = condition as ConditionGroup;\n const logic = group.logic || 'and';\n const results = group.rules.map(rule => \n evaluateCondition(rule, formData)\n );\n \n return logic === 'and' \n ? results.every(r => r)\n : results.some(r => r);\n }\n \n return false;\n}\n\n/**\n * 使用条件评估的 composable\n */\nexport function useConditionEvaluator() {\n return {\n evaluateCondition,\n getNestedValue,\n };\n}\n\n"],"names":[],"mappings":"AAcO,SAAS,eACd,KACA,MACK;AACL,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,KAAK,MAAM,GAAG,EAAE,OAAO,CAAC,SAAS,QAAQ;AAC9C,QAAI,WAAW,KAAM,QAAO;AAC5B,WAAO,QAAQ,GAAG;AAAA,EACpB,GAAG,GAAG;AACR;AAKA,SAAS,cACP,YACA,UACA,cACS;AACT,UAAQ,UAAA;AAAA,IACN,KAAK;AACH,aAAO,cAAc;AAAA,IACvB,KAAK;AACH,aAAO,cAAc;AAAA,IACvB,KAAK;AACH,aAAO,OAAO,UAAU,IAAI,OAAO,YAAY;AAAA,IACjD,KAAK;AACH,aAAO,OAAO,UAAU,KAAK,OAAO,YAAY;AAAA,IAClD,KAAK;AACH,aAAO,OAAO,UAAU,IAAI,OAAO,YAAY;AAAA,IACjD,KAAK;AACH,aAAO,OAAO,UAAU,KAAK,OAAO,YAAY;AAAA,IAClD,KAAK;AACH,aAAO,MAAM,QAAQ,YAAY,KAAK,aAAa,SAAS,UAAU;AAAA,IACxE,KAAK;AACH,aAAO,MAAM,QAAQ,YAAY,KAAK,CAAC,aAAa,SAAS,UAAU;AAAA,IACzE,KAAK;AACH,aAAO,OAAO,UAAU,EAAE,SAAS,OAAO,YAAY,CAAC;AAAA,IACzD,KAAK;AACH,aAAO,OAAO,UAAU,EAAE,WAAW,OAAO,YAAY,CAAC;AAAA,IAC3D,KAAK;AACH,aAAO,OAAO,UAAU,EAAE,SAAS,OAAO,YAAY,CAAC;AAAA,IACzD,KAAK;AACH,UAAI;AACF,eAAO,IAAI,OAAO,YAAY,EAAE,KAAK,OAAO,UAAU,CAAC;AAAA,MACzD,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF,KAAK;AACH,aACE,eAAe,QACf,eAAe,UACf,eAAe,MACd,MAAM,QAAQ,UAAU,KAAK,WAAW,WAAW;AAAA,IAExD,KAAK;AACH,aAAO,EACL,eAAe,QACf,eAAe,UACf,eAAe,MACd,MAAM,QAAQ,UAAU,KAAK,WAAW,WAAW;AAAA,IAExD;AACE,aAAO;AAAA,EAAA;AAEb;AAKO,SAAS,kBACd,WACA,UACS;AAET,MAAI,WAAW,aAAa,cAAc,WAAW;AACnD,UAAM,OAAO;AACb,UAAM,aAAa,eAAe,UAAU,KAAK,KAAK;AAGtD,QAAI,eAAe,KAAK;AACxB,QAAI,OAAO,iBAAiB,YAAY,iBAAiB,QAAQ,WAAW,cAAc;AACxF,qBAAe,eAAe,UAAU,aAAa,KAAK;AAAA,IAC5D;AAEA,WAAO,cAAc,YAAY,KAAK,UAAU,YAAY;AAAA,EAC9D;AAGA,MAAI,WAAW,WAAW;AACxB,UAAM,QAAQ;AACd,UAAM,QAAQ,MAAM,SAAS;AAC7B,UAAM,UAAU,MAAM,MAAM;AAAA,MAAI,CAAA,SAC9B,kBAAkB,MAAM,QAAQ;AAAA,IAAA;AAGlC,WAAO,UAAU,QACb,QAAQ,MAAM,CAAA,MAAK,CAAC,IACpB,QAAQ,KAAK,CAAA,MAAK,CAAC;AAAA,EACzB;AAEA,SAAO;AACT;"}
|
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
import { ref, watch } from "vue";
|
|
2
|
+
import { getNestedValue } from "./useConditionEvaluator.js";
|
|
3
|
+
const cache = /* @__PURE__ */ new Map();
|
|
4
|
+
function getCachedData(key) {
|
|
5
|
+
const cached = cache.get(key);
|
|
6
|
+
if (cached && Date.now() < cached.expire) {
|
|
7
|
+
return cached.data;
|
|
8
|
+
}
|
|
9
|
+
if (cached) {
|
|
10
|
+
cache.delete(key);
|
|
11
|
+
}
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
function setCachedData(key, data, expire) {
|
|
15
|
+
cache.set(key, { data, expire: Date.now() + expire });
|
|
16
|
+
}
|
|
17
|
+
function buildRequestParams(remote, formData, query) {
|
|
18
|
+
const params = {};
|
|
19
|
+
if (remote.params) {
|
|
20
|
+
Object.entries(remote.params).forEach(([key, value]) => {
|
|
21
|
+
if (value === "query") {
|
|
22
|
+
params[key] = query || "";
|
|
23
|
+
} else if (typeof value === "object" && value !== null && "field" in value) {
|
|
24
|
+
params[key] = getNestedValue(formData, value.field) ?? value.default;
|
|
25
|
+
} else {
|
|
26
|
+
params[key] = value;
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return params;
|
|
31
|
+
}
|
|
32
|
+
function generateCacheKey(url, params) {
|
|
33
|
+
const sortedParams = Object.keys(params).sort().map((key) => `${key}=${JSON.stringify(params[key])}`).join("&");
|
|
34
|
+
return `${url}?${sortedParams}`;
|
|
35
|
+
}
|
|
36
|
+
function extractOptionsByPath(data, path) {
|
|
37
|
+
if (!path) {
|
|
38
|
+
if (Array.isArray(data)) {
|
|
39
|
+
return data;
|
|
40
|
+
}
|
|
41
|
+
if (data && typeof data === "object") {
|
|
42
|
+
const commonPaths = ["data", "list", "items", "results", "records"];
|
|
43
|
+
for (const commonPath of commonPaths) {
|
|
44
|
+
if (Array.isArray(data[commonPath])) {
|
|
45
|
+
return data[commonPath];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return [];
|
|
50
|
+
}
|
|
51
|
+
const value = getNestedValue(data, path);
|
|
52
|
+
return Array.isArray(value) ? value : [];
|
|
53
|
+
}
|
|
54
|
+
function evaluateExpression(expr, item) {
|
|
55
|
+
try {
|
|
56
|
+
const context = { item };
|
|
57
|
+
let safeExpr = expr.replace(/item\.(\w+)/g, (match, field) => {
|
|
58
|
+
return `context.item.${field}`;
|
|
59
|
+
});
|
|
60
|
+
if (!expr.includes("item.")) {
|
|
61
|
+
if (expr.startsWith('"') && expr.endsWith('"')) {
|
|
62
|
+
return expr.slice(1, -1);
|
|
63
|
+
}
|
|
64
|
+
if (expr.startsWith("'") && expr.endsWith("'")) {
|
|
65
|
+
return expr.slice(1, -1);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const func = new Function("context", `return ${safeExpr}`);
|
|
70
|
+
return func(context);
|
|
71
|
+
} catch (funcError) {
|
|
72
|
+
const simpleReplaced = expr.replace(/item\.(\w+)/g, (match, field) => {
|
|
73
|
+
const value = item[field];
|
|
74
|
+
if (value === null || value === void 0) {
|
|
75
|
+
return '""';
|
|
76
|
+
}
|
|
77
|
+
if (typeof value === "string") {
|
|
78
|
+
return `"${value.replace(/"/g, '\\"')}"`;
|
|
79
|
+
}
|
|
80
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
81
|
+
return String(value);
|
|
82
|
+
}
|
|
83
|
+
return `"${String(value).replace(/"/g, '\\"')}"`;
|
|
84
|
+
});
|
|
85
|
+
try {
|
|
86
|
+
return new Function("return " + simpleReplaced)();
|
|
87
|
+
} catch {
|
|
88
|
+
return "";
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.warn("Expression evaluation failed:", expr, error);
|
|
93
|
+
return "";
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function getFieldValue(config, item) {
|
|
97
|
+
if (typeof config === "string") {
|
|
98
|
+
return item[config];
|
|
99
|
+
}
|
|
100
|
+
if (config && typeof config === "object" && "expression" in config) {
|
|
101
|
+
return evaluateExpression(config.expression, item);
|
|
102
|
+
}
|
|
103
|
+
return void 0;
|
|
104
|
+
}
|
|
105
|
+
function transformChildren(children, transform) {
|
|
106
|
+
var _a;
|
|
107
|
+
return ((_a = children == null ? void 0 : children.map) == null ? void 0 : _a.call(children, (child) => {
|
|
108
|
+
const result = {
|
|
109
|
+
label: getFieldValue(transform.map.label, child) ?? "",
|
|
110
|
+
value: getFieldValue(transform.map.value, child) ?? child,
|
|
111
|
+
disabled: getFieldValue(transform.map.disabled, child) ?? false,
|
|
112
|
+
leaf: getFieldValue(transform.map.leaf, child) ?? false
|
|
113
|
+
};
|
|
114
|
+
if (transform.map.children !== void 0) {
|
|
115
|
+
result.children = transformChildren(child, transform);
|
|
116
|
+
}
|
|
117
|
+
return result;
|
|
118
|
+
})) ?? [];
|
|
119
|
+
}
|
|
120
|
+
function transformData(data, transform) {
|
|
121
|
+
const options = extractOptionsByPath(data, transform.optionsPath);
|
|
122
|
+
if (!Array.isArray(options) || options.length === 0) {
|
|
123
|
+
return [];
|
|
124
|
+
}
|
|
125
|
+
if (!transform.map) {
|
|
126
|
+
return options.map((item) => ({
|
|
127
|
+
label: item.label || item.name || String(item.value || item.id || item),
|
|
128
|
+
value: item.value || item.id || item,
|
|
129
|
+
disabled: item.disabled || false
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
return options.map((item) => {
|
|
133
|
+
const result = {
|
|
134
|
+
label: getFieldValue(transform.map.label, item) ?? "",
|
|
135
|
+
value: getFieldValue(transform.map.value, item) ?? item
|
|
136
|
+
};
|
|
137
|
+
if (transform.map.disabled !== void 0) {
|
|
138
|
+
result.disabled = Boolean(getFieldValue(transform.map.disabled, item));
|
|
139
|
+
}
|
|
140
|
+
if (transform.map.children !== void 0) {
|
|
141
|
+
const childrenValue = getFieldValue(transform.map.children, item);
|
|
142
|
+
if (childrenValue !== void 0 && childrenValue !== null) {
|
|
143
|
+
result.children = transformChildren(childrenValue, transform);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (transform.map.leaf !== void 0) {
|
|
147
|
+
const leafValue = getFieldValue(transform.map.leaf, item);
|
|
148
|
+
if (leafValue !== void 0 && leafValue !== null) {
|
|
149
|
+
result.leaf = Boolean(leafValue);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
async function loadRemoteData(remote, formData, query) {
|
|
156
|
+
const params = buildRequestParams(remote, formData, query);
|
|
157
|
+
const cacheKey = generateCacheKey(remote.url, params);
|
|
158
|
+
if (remote.cache) {
|
|
159
|
+
const cached = getCachedData(cacheKey);
|
|
160
|
+
if (cached !== null) {
|
|
161
|
+
return cached;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
let url = remote.url;
|
|
166
|
+
const requestOptions = {
|
|
167
|
+
method: remote.method || "GET",
|
|
168
|
+
headers: {
|
|
169
|
+
"Content-Type": "application/json",
|
|
170
|
+
...remote.headers
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
if (remote.method === "POST") {
|
|
174
|
+
requestOptions.body = JSON.stringify(remote.body || params);
|
|
175
|
+
} else {
|
|
176
|
+
const urlWithParams = new URL(remote.url, window.location.origin);
|
|
177
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
178
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
179
|
+
urlWithParams.searchParams.append(key, String(value));
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
url = urlWithParams.toString();
|
|
183
|
+
}
|
|
184
|
+
const response = await fetch(url, requestOptions);
|
|
185
|
+
if (!response.ok) {
|
|
186
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
187
|
+
}
|
|
188
|
+
let data = await response.json();
|
|
189
|
+
if (remote.transform) {
|
|
190
|
+
if (typeof remote.transform === "string") {
|
|
191
|
+
} else {
|
|
192
|
+
data = transformData(data, remote.transform);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (remote.cache) {
|
|
196
|
+
const expire = remote.cacheExpire || 3e5;
|
|
197
|
+
setCachedData(cacheKey, data, expire);
|
|
198
|
+
}
|
|
199
|
+
return Array.isArray(data) ? data : [];
|
|
200
|
+
} catch (error) {
|
|
201
|
+
console.error("Failed to load remote data:", error);
|
|
202
|
+
return [];
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
function debounce(func, wait) {
|
|
206
|
+
let timeout = null;
|
|
207
|
+
return function executedFunction(...args) {
|
|
208
|
+
const later = () => {
|
|
209
|
+
timeout = null;
|
|
210
|
+
func(...args);
|
|
211
|
+
};
|
|
212
|
+
if (timeout) {
|
|
213
|
+
clearTimeout(timeout);
|
|
214
|
+
}
|
|
215
|
+
timeout = setTimeout(later, wait);
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function useRemoteData(remote, formData, query) {
|
|
219
|
+
const loading = ref(false);
|
|
220
|
+
const options = ref([]);
|
|
221
|
+
const error = ref(null);
|
|
222
|
+
if (!remote) {
|
|
223
|
+
return {
|
|
224
|
+
loading,
|
|
225
|
+
options,
|
|
226
|
+
error,
|
|
227
|
+
loadData: async () => {
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
const debounceTime = remote.debounce || 300;
|
|
232
|
+
const debouncedLoad = debounce(async (searchQuery) => {
|
|
233
|
+
loading.value = true;
|
|
234
|
+
error.value = null;
|
|
235
|
+
try {
|
|
236
|
+
const data = await loadRemoteData(remote, formData.value, searchQuery);
|
|
237
|
+
options.value = data;
|
|
238
|
+
} catch (err) {
|
|
239
|
+
error.value = err;
|
|
240
|
+
options.value = [];
|
|
241
|
+
} finally {
|
|
242
|
+
loading.value = false;
|
|
243
|
+
}
|
|
244
|
+
}, debounceTime);
|
|
245
|
+
if (remote.params) {
|
|
246
|
+
const dependencyFields = Object.values(remote.params).filter(
|
|
247
|
+
(v) => typeof v === "object" && v !== null && "field" in v
|
|
248
|
+
).map((v) => v.field);
|
|
249
|
+
if (dependencyFields.length > 0) {
|
|
250
|
+
watch(
|
|
251
|
+
() => dependencyFields.map((path) => getNestedValue(formData.value, path)),
|
|
252
|
+
() => {
|
|
253
|
+
debouncedLoad(query == null ? void 0 : query.value);
|
|
254
|
+
},
|
|
255
|
+
{ deep: true }
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (query) {
|
|
260
|
+
watch(query, (newQuery) => {
|
|
261
|
+
debouncedLoad(newQuery);
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
const loadData = async (searchQuery) => {
|
|
265
|
+
await debouncedLoad(searchQuery);
|
|
266
|
+
};
|
|
267
|
+
loadData(query == null ? void 0 : query.value);
|
|
268
|
+
return {
|
|
269
|
+
loading,
|
|
270
|
+
options,
|
|
271
|
+
error,
|
|
272
|
+
loadData
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
function createCascaderLazyLoad(remote, formData) {
|
|
276
|
+
return async (node, resolve) => {
|
|
277
|
+
if (!remote.transform || typeof remote.transform === "string") {
|
|
278
|
+
resolve([]);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const transform = remote.transform;
|
|
282
|
+
try {
|
|
283
|
+
const params = {};
|
|
284
|
+
for (const [key, config] of Object.entries(remote.params)) {
|
|
285
|
+
if (typeof config === "string") {
|
|
286
|
+
if (config.startsWith("node.")) {
|
|
287
|
+
const nodePath = config.replace("node.", "");
|
|
288
|
+
const value = getNestedValue(node, nodePath);
|
|
289
|
+
if (value !== void 0 && value !== null) {
|
|
290
|
+
params[key] = value;
|
|
291
|
+
}
|
|
292
|
+
} else {
|
|
293
|
+
params[key] = config;
|
|
294
|
+
}
|
|
295
|
+
} else if (typeof config === "object" && "field" in config) {
|
|
296
|
+
const value = getNestedValue(formData.value, config.field);
|
|
297
|
+
params[key] = value !== void 0 && value !== null ? value : config.default ?? "";
|
|
298
|
+
} else if (typeof config === "object" && config && "expression" in config) {
|
|
299
|
+
params[key] = "";
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
const urlWithParams = new URL(remote.url, window.location.origin);
|
|
303
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
304
|
+
if (value !== void 0 && value !== null && value !== "") {
|
|
305
|
+
urlWithParams.searchParams.append(key, String(value));
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
const requestOptions = {
|
|
309
|
+
method: remote.method || "GET",
|
|
310
|
+
headers: {
|
|
311
|
+
"Content-Type": "application/json",
|
|
312
|
+
...remote.headers
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
if (remote.method === "POST") {
|
|
316
|
+
requestOptions.body = JSON.stringify(remote.body || params);
|
|
317
|
+
}
|
|
318
|
+
const response = await fetch(urlWithParams.toString(), requestOptions);
|
|
319
|
+
if (!response.ok) {
|
|
320
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
321
|
+
}
|
|
322
|
+
let data = await response.json();
|
|
323
|
+
const transformedData = transformData(data, transform);
|
|
324
|
+
resolve(transformedData);
|
|
325
|
+
} catch (error) {
|
|
326
|
+
console.error("Failed to load cascader children:", error);
|
|
327
|
+
resolve([]);
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
export {
|
|
332
|
+
createCascaderLazyLoad,
|
|
333
|
+
useRemoteData
|
|
334
|
+
};
|
|
335
|
+
//# sourceMappingURL=useRemoteData.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useRemoteData.js","sources":["../../../../../src/components/x-markdown/composables/useRemoteData.ts"],"sourcesContent":["/**\n * 远程数据加载\n * 处理远程检索和懒加载\n */\n\nimport { ref, Ref, watch } from 'vue';\nimport { RemoteConfig, TransformMap, ExpressionConfig } from '@/types/index';\nimport { getNestedValue } from './useConditionEvaluator';\n\n/**\n * 缓存项\n */\ninterface CacheItem {\n data: any;\n expire: number;\n}\n\n/**\n * 缓存存储\n */\nconst cache = new Map<string, CacheItem>();\n\n/**\n * 获取缓存数据\n */\nfunction getCachedData(key: string): any | null {\n const cached = cache.get(key);\n if (cached && Date.now() < cached.expire) {\n return cached.data;\n }\n if (cached) {\n cache.delete(key);\n }\n return null;\n}\n\n/**\n * 设置缓存数据\n */\nfunction setCachedData(key: string, data: any, expire: number) {\n cache.set(key, { data, expire: Date.now() + expire });\n}\n\n/**\n * 构建请求参数\n */\nfunction buildRequestParams(\n remote: RemoteConfig,\n formData: Record<string, any>,\n query?: string\n): Record<string, any> {\n const params: Record<string, any> = {};\n \n if (remote.params) {\n Object.entries(remote.params).forEach(([key, value]) => {\n // 如果值为query,则表示当前字段为搜索关键词\n if (value === 'query') {\n params[key] = query || '';\n } else if (typeof value === 'object' && value !== null && 'field' in value) {\n params[key] = getNestedValue(formData, value.field) ?? value.default;\n } else {\n params[key] = value;\n }\n });\n }\n \n return params;\n}\n\n/**\n * 生成缓存键\n */\nfunction generateCacheKey(\n url: string,\n params: Record<string, any>\n): string {\n const sortedParams = Object.keys(params)\n .sort()\n .map(key => `${key}=${JSON.stringify(params[key])}`)\n .join('&');\n return `${url}?${sortedParams}`;\n}\n\n/**\n * 从数据中提取选项列表(根据路径)\n */\nfunction extractOptionsByPath(data: any, path?: string): any[] {\n if (!path) {\n // 如果没有指定路径,尝试自动识别\n if (Array.isArray(data)) {\n return data;\n }\n if (data && typeof data === 'object') {\n // 尝试常见的字段名\n const commonPaths = ['data', 'list', 'items', 'results', 'records'];\n for (const commonPath of commonPaths) {\n if (Array.isArray(data[commonPath])) {\n return data[commonPath];\n }\n }\n }\n return [];\n }\n \n // 使用路径提取\n const value = getNestedValue(data, path);\n return Array.isArray(value) ? value : [];\n}\n\n/**\n * 计算表达式(简单实现,支持属性访问和字符串拼接)\n */\nfunction evaluateExpression(expr: string, item: any): any {\n try {\n // 简单的表达式解析\n // 支持:item.field, item.field1 + ' - ' + item.field2 等\n \n // 创建一个安全的上下文,只包含 item 对象\n const context = { item };\n \n // 替换表达式中的 item.xxx 为安全的访问方式\n // 将 item.field 转换为 context.item.field\n let safeExpr = expr.replace(/item\\.(\\w+)/g, (match, field) => {\n return `context.item.${field}`;\n });\n \n // 如果表达式不包含 item.,可能是简单的字符串字面量\n if (!expr.includes('item.')) {\n // 尝试作为字符串字面量处理\n if (expr.startsWith('\"') && expr.endsWith('\"')) {\n return expr.slice(1, -1);\n }\n if (expr.startsWith(\"'\") && expr.endsWith(\"'\")) {\n return expr.slice(1, -1);\n }\n }\n \n // 使用 Function 构造函数安全地执行表达式\n // 限制作用域,只允许访问 context\n try {\n const func = new Function('context', `return ${safeExpr}`);\n return func(context);\n } catch (funcError) {\n // 如果 Function 构造失败,尝试更简单的方式\n // 直接替换 item.xxx 为值\n const simpleReplaced = expr.replace(/item\\.(\\w+)/g, (match, field) => {\n const value = item[field];\n if (value === null || value === undefined) {\n return '\"\"';\n }\n if (typeof value === 'string') {\n return `\"${value.replace(/\"/g, '\\\\\"')}\"`;\n }\n if (typeof value === 'number' || typeof value === 'boolean') {\n return String(value);\n }\n return `\"${String(value).replace(/\"/g, '\\\\\"')}\"`;\n });\n \n // 尝试直接执行替换后的表达式\n try {\n return new Function('return ' + simpleReplaced)();\n } catch {\n // 如果还是失败,返回空字符串\n return '';\n }\n }\n } catch (error) {\n console.warn('Expression evaluation failed:', expr, error);\n return '';\n }\n}\n\n/**\n * 获取字段值或计算表达式\n */\nfunction getFieldValue(\n config: string | ExpressionConfig,\n item: any\n): any {\n if (typeof config === 'string') {\n // 简单字段名\n return item[config];\n }\n \n if (config && typeof config === 'object' && 'expression' in config) {\n // 表达式\n return evaluateExpression(config.expression, item);\n }\n \n return undefined;\n}\n\nfunction transformChildren(children: any, transform: TransformMap) {\n return children?.map?.(child => {\n const result: any = {\n label: getFieldValue(transform.map!.label, child) ?? '',\n value: getFieldValue(transform.map!.value, child) ?? child,\n disabled: getFieldValue(transform.map!.disabled, child) ?? false,\n leaf: getFieldValue(transform.map!.leaf, child) ?? false,\n };\n if (transform.map!.children !== undefined) {\n result.children = transformChildren(child, transform);\n }\n return result;\n }) ?? [];\n}\n\n/**\n * 转换数据为选项格式\n */\nfunction transformData(\n data: any,\n transform: TransformMap\n): Array<{ label: string; value: any; disabled?: boolean }> {\n // 1. 提取选项列表\n const options = extractOptionsByPath(data, transform.optionsPath);\n \n if (!Array.isArray(options) || options.length === 0) {\n return [];\n }\n \n // 2. 如果没有映射配置,直接返回(假设已经是正确格式)\n if (!transform.map) {\n return options.map(item => ({\n label: item.label || item.name || String(item.value || item.id || item),\n value: item.value || item.id || item,\n disabled: item.disabled || false,\n }));\n }\n \n // 3. 应用映射\n return options.map(item => {\n const result: any = {\n label: getFieldValue(transform.map!.label, item) ?? '',\n value: getFieldValue(transform.map!.value, item) ?? item,\n };\n \n if (transform.map!.disabled !== undefined) {\n result.disabled = Boolean(getFieldValue(transform.map!.disabled, item));\n }\n \n // 支持 children 字段(用于联级选择)\n // 基于 TransformMap中map 属性的 children 字段配置进行children数据格式化,需要深度遍历\n if (transform.map!.children !== undefined) {\n const childrenValue = getFieldValue(transform.map!.children, item);\n if (childrenValue !== undefined && childrenValue !== null) {\n result.children = transformChildren(childrenValue, transform);\n }\n }\n \n // 支持 leaf 字段(用于懒加载联级选择)\n if (transform.map!.leaf !== undefined) {\n const leafValue = getFieldValue(transform.map!.leaf, item);\n if (leafValue !== undefined && leafValue !== null) {\n result.leaf = Boolean(leafValue);\n }\n }\n \n return result;\n });\n}\n\n/**\n * 加载远程数据\n */\nasync function loadRemoteData(\n remote: RemoteConfig,\n formData: Record<string, any>,\n query?: string\n): Promise<any[]> {\n const params = buildRequestParams(remote, formData, query);\n const cacheKey = generateCacheKey(remote.url, params);\n \n // 检查缓存\n if (remote.cache) {\n const cached = getCachedData(cacheKey);\n if (cached !== null) {\n return cached;\n }\n }\n \n try {\n let url = remote.url;\n // 构建请求配置\n const requestOptions: RequestInit = {\n method: remote.method || 'GET',\n headers: {\n 'Content-Type': 'application/json',\n ...remote.headers,\n },\n };\n \n // 处理请求体\n if (remote.method === 'POST') {\n requestOptions.body = JSON.stringify(remote.body || params);\n } else {\n // GET 请求将参数拼接到 URL\n const urlWithParams = new URL(remote.url, window.location.origin);\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null && value !== '') {\n urlWithParams.searchParams.append(key, String(value));\n }\n });\n url = urlWithParams.toString();\n }\n \n // 发送请求\n const response = await fetch(url, requestOptions);\n \n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n \n let data = await response.json();\n \n // 数据转换(如果有)\n if (remote.transform) {\n if (typeof remote.transform === 'string') {\n // 向后兼容:函数名方式(暂未实现函数注册机制)\n // TODO: 调用转换函数\n // const transformFn = getRegisteredTransform(remote.transform);\n // data = transformFn(data);\n } else {\n // 新的对象配置方式\n data = transformData(data, remote.transform);\n }\n }\n \n // 缓存数据\n if (remote.cache) {\n const expire = remote.cacheExpire || 300000; // 默认5分钟\n setCachedData(cacheKey, data, expire);\n }\n \n return Array.isArray(data) ? data : [];\n } catch (error) {\n console.error('Failed to load remote data:', error);\n return [];\n }\n}\n\n/**\n * 防抖函数\n */\nfunction debounce<T extends (...args: any[]) => any>(\n func: T,\n wait: number\n): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n \n return function executedFunction(...args: Parameters<T>) {\n const later = () => {\n timeout = null;\n func(...args);\n };\n \n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(later, wait);\n };\n}\n\n/**\n * 使用远程数据的 composable\n */\nexport function useRemoteData(\n remote: RemoteConfig | undefined,\n formData: Ref<Record<string, any>>,\n query?: Ref<string>\n) {\n const loading = ref(false);\n const options = ref<any[]>([]);\n const error = ref<Error | null>(null);\n\n if (!remote) {\n return {\n loading,\n options,\n error,\n loadData: async () => {},\n };\n }\n\n // 创建防抖加载函数\n const debounceTime = remote.debounce || 300;\n const debouncedLoad = debounce(async (searchQuery?: string) => {\n loading.value = true;\n error.value = null;\n try {\n const data = await loadRemoteData(remote, formData.value, searchQuery);\n options.value = data;\n } catch (err) {\n error.value = err as Error;\n options.value = [];\n } finally {\n loading.value = false;\n }\n }, debounceTime);\n\n // 监听依赖字段变化\n if (remote.params) {\n const dependencyFields = Object.values(remote.params)\n .filter((v): v is { field: string } => \n typeof v === 'object' && v !== null && 'field' in v\n )\n .map(v => v.field);\n \n if (dependencyFields.length > 0) {\n watch(\n () => dependencyFields.map(path => getNestedValue(formData.value, path)),\n () => {\n debouncedLoad(query?.value);\n },\n { deep: true }\n );\n }\n }\n\n // 监听搜索关键词变化\n if (query) {\n watch(query, (newQuery) => {\n debouncedLoad(newQuery);\n });\n }\n\n // 初始加载\n const loadData = async (searchQuery?: string) => {\n await debouncedLoad(searchQuery);\n };\n\n // 立即加载一次\n loadData(query?.value);\n\n return {\n loading,\n options,\n error,\n loadData,\n };\n}\n\n\n/**\n * 构建 Cascader 懒加载函数\n * @param remote 远程配置\n * @param formData 表单数据\n * @returns Element Plus Cascader lazyLoad 函数\n */\nexport function createCascaderLazyLoad(\n remote: RemoteConfig,\n formData: Ref<Record<string, any>>\n): (node: any, resolve: (data: any[]) => void) => void {\n return async (node: any, resolve: (data: any[]) => void) => {\n if (!remote.transform || typeof remote.transform === 'string') {\n resolve([]);\n return;\n }\n\n const transform = remote.transform as TransformMap;\n\n try {\n // 构建懒加载请求参数\n const params: Record<string, any> = {};\n \n for (const [key, config] of Object.entries(remote.params)) {\n if (typeof config === 'string') {\n // 从 node 对象中获取(如 \"node.value\", \"node.level\")\n if (config.startsWith('node.')) {\n const nodePath = config.replace('node.', '');\n const value = getNestedValue(node, nodePath);\n if (value !== undefined && value !== null) {\n params[key] = value;\n }\n } else {\n // 直接作为字符串值\n params[key] = config;\n }\n } else if (typeof config === 'object' && 'field' in config) {\n // 从表单字段中获取\n const value = getNestedValue(formData.value, config.field);\n params[key] = value !== undefined && value !== null ? value : (config.default ?? '');\n } else if (typeof config === 'object' && config && 'expression' in config) {\n // 表达式计算(暂不支持,需要传入 node 和 formData)\n // TODO: 实现表达式计算\n params[key] = '';\n }\n }\n\n // 构建请求 URL\n const urlWithParams = new URL(remote.url, window.location.origin);\n Object.entries(params).forEach(([key, value]) => {\n if (value !== undefined && value !== null && value !== '') {\n urlWithParams.searchParams.append(key, String(value));\n }\n });\n\n // 发送请求\n const requestOptions: RequestInit = {\n method: remote.method || 'GET',\n headers: {\n 'Content-Type': 'application/json',\n ...remote.headers,\n },\n };\n\n if (remote.method === 'POST') {\n requestOptions.body = JSON.stringify(remote.body || params);\n }\n\n const response = await fetch(urlWithParams.toString(), requestOptions);\n \n if (!response.ok) {\n throw new Error(`HTTP error! status: ${response.status}`);\n }\n\n let data = await response.json();\n\n // 数据转换\n const transformedData = transformData(data, transform);\n resolve(transformedData);\n } catch (error) {\n console.error('Failed to load cascader children:', error);\n resolve([]);\n }\n };\n}\n\n"],"names":[],"mappings":"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"}
|