@shwfed/config 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/module.mjs +117 -23
- package/dist/runtime/components/config/footer.vue +0 -2
- package/dist/runtime/components/config/index.vue +13 -3
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.d.vue.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue +85 -10
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/runtime.vue +18 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/schema.d.ts +1 -1
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/schema.js +11 -4
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.d.vue.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue +85 -10
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/runtime.vue +18 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/schema.d.ts +1 -1
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/schema.js +11 -4
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.d.vue.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.vue +87 -11
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.vue.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/runtime.vue +18 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/schema.d.ts +1 -1
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/schema.js +11 -4
- package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/config.vue +3 -0
- package/dist/runtime/components/form/fields/2026-05-12/com.shwfed.form.field.upload/runtime.vue +8 -0
- package/dist/runtime/components/form/index.vue +2 -2
- package/dist/runtime/components/table/ai/columns-button.vue +91 -98
- package/dist/runtime/components/table/ai/data-source-button.vue +88 -95
- package/dist/runtime/components/table/index.vue +5 -7
- package/dist/runtime/plugins/ai/index.d.ts +1 -5
- package/dist/runtime/plugins/ai/index.js +185 -441
- package/dist/runtime/plugins/cel/index.js +7 -0
- package/dist/runtime/vendor/cel-js/PROMPT.md +8 -0
- package/package.json +4 -4
- package/dist/chunks/index.mjs +0 -212742
- package/dist/runtime/components/ai/byok-button.d.vue.ts +0 -3
- package/dist/runtime/components/ai/byok-button.vue +0 -48
- package/dist/runtime/components/ai/byok-button.vue.d.ts +0 -3
- package/dist/runtime/components/ai/byok-settings.d.vue.ts +0 -3
- package/dist/runtime/components/ai/byok-settings.vue +0 -282
- package/dist/runtime/components/ai/byok-settings.vue.d.ts +0 -3
- package/dist/runtime/plugins/ai/gate.d.ts +0 -1
- package/dist/runtime/plugins/ai/gate.js +0 -8
- package/dist/runtime/plugins/ai/settings-state.d.ts +0 -1
- package/dist/runtime/plugins/ai/settings-state.js +0 -2
- package/dist/runtime/plugins/ai/store.d.ts +0 -17
- package/dist/runtime/plugins/ai/store.js +0 -40
- package/dist/shared/config.DW2OtAXe.mjs +0 -86529
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,23 +1,117 @@
|
|
|
1
|
-
import '@nuxt/kit';
|
|
2
|
-
|
|
3
|
-
import '@tailwindcss/vite';
|
|
4
|
-
import 'defu';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
1
|
+
import { defineNuxtModule, createResolver, addVitePlugin, extendViteConfig, addPlugin, addRouteMiddleware, addComponent, addImports } from '@nuxt/kit';
|
|
2
|
+
import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite';
|
|
3
|
+
import TailwindCSS from '@tailwindcss/vite';
|
|
4
|
+
import { defu } from 'defu';
|
|
5
|
+
|
|
6
|
+
const module$1 = defineNuxtModule({
|
|
7
|
+
meta: {
|
|
8
|
+
name: "shwfed",
|
|
9
|
+
configKey: "shwfed"
|
|
10
|
+
},
|
|
11
|
+
moduleDependencies: {
|
|
12
|
+
"@nuxt/fonts": {
|
|
13
|
+
version: "^0.14.0",
|
|
14
|
+
defaults: {
|
|
15
|
+
providers: {
|
|
16
|
+
google: false,
|
|
17
|
+
googleicons: false
|
|
18
|
+
},
|
|
19
|
+
families: [
|
|
20
|
+
{ name: "Noto Sans", provider: "bunny" },
|
|
21
|
+
{ name: "Noto Sans SC", provider: "bunny" },
|
|
22
|
+
{ name: "Noto Sans JP", provider: "bunny" },
|
|
23
|
+
{ name: "Fira Mono", provider: "bunny" }
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
defaults: {},
|
|
29
|
+
setup(options, nuxt) {
|
|
30
|
+
const resolver = createResolver(import.meta.url);
|
|
31
|
+
const resolvedConfig = defu(options, {
|
|
32
|
+
git: {
|
|
33
|
+
commit: process.env.GIT_COMMIT,
|
|
34
|
+
branch: process.env.GIT_LOCAL_BRANCH
|
|
35
|
+
},
|
|
36
|
+
ci: {
|
|
37
|
+
job: process.env.JOB_NAME,
|
|
38
|
+
build: process.env.BUILD_NUMBER ? Number.parseInt(process.env.BUILD_NUMBER) : void 0
|
|
39
|
+
},
|
|
40
|
+
api: {
|
|
41
|
+
host: process.env.NUXT_PUBLIC_API_URI,
|
|
42
|
+
logout: process.env.NUXT_PUBLIC_SSO_LOGOUT_URI
|
|
43
|
+
},
|
|
44
|
+
headers: {
|
|
45
|
+
token: process.env.NUXT_PUBLIC_TOKEN_HEADER_NAME
|
|
46
|
+
},
|
|
47
|
+
config: options
|
|
48
|
+
});
|
|
49
|
+
nuxt.options.runtimeConfig.public.shwfed = resolvedConfig;
|
|
50
|
+
addVitePlugin(VueI18nPlugin({
|
|
51
|
+
ssr: true
|
|
52
|
+
}));
|
|
53
|
+
addVitePlugin(TailwindCSS());
|
|
54
|
+
nuxt.options.css.push(resolver.resolve("./runtime/style.css"));
|
|
55
|
+
nuxt.options.css.push("vue-sonner/style.css");
|
|
56
|
+
extendViteConfig((config) => {
|
|
57
|
+
config.optimizeDeps ||= {};
|
|
58
|
+
config.optimizeDeps.include ||= [];
|
|
59
|
+
config.optimizeDeps.include.push(
|
|
60
|
+
"reka-ui",
|
|
61
|
+
"reka-ui/namespaced",
|
|
62
|
+
"vue-sonner",
|
|
63
|
+
"@tanstack/vue-table",
|
|
64
|
+
"@tanstack/vue-virtual",
|
|
65
|
+
"effect",
|
|
66
|
+
"fx-fetch",
|
|
67
|
+
"@vueuse/core",
|
|
68
|
+
"date-fns",
|
|
69
|
+
"@date-fns/tz",
|
|
70
|
+
"class-variance-authority",
|
|
71
|
+
"vue-i18n",
|
|
72
|
+
"markdown-it",
|
|
73
|
+
"@iconify/vue",
|
|
74
|
+
"clsx",
|
|
75
|
+
"tailwind-merge",
|
|
76
|
+
"@atlaskit/pragmatic-drag-and-drop/combine",
|
|
77
|
+
"@atlaskit/pragmatic-drag-and-drop/element/adapter",
|
|
78
|
+
"@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item",
|
|
79
|
+
"vaul-vue",
|
|
80
|
+
"dot-prop",
|
|
81
|
+
"@internationalized/date",
|
|
82
|
+
"reka-ui/date"
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
addPlugin(resolver.resolve("./runtime/plugins/i18n"));
|
|
86
|
+
addPlugin(resolver.resolve("./runtime/plugins/http"));
|
|
87
|
+
addPlugin(resolver.resolve("./runtime/plugins/cel"));
|
|
88
|
+
addPlugin(resolver.resolve("./runtime/plugins/toast"));
|
|
89
|
+
addPlugin(resolver.resolve("./runtime/plugins/ai"));
|
|
90
|
+
addRouteMiddleware({
|
|
91
|
+
path: resolver.resolve("./runtime/middleware/token"),
|
|
92
|
+
name: "shwfed-token",
|
|
93
|
+
global: true
|
|
94
|
+
});
|
|
95
|
+
addComponent({
|
|
96
|
+
name: "ShwfedApp",
|
|
97
|
+
filePath: resolver.resolve("./runtime/components/app.vue")
|
|
98
|
+
});
|
|
99
|
+
addComponent({
|
|
100
|
+
name: "ShwfedModal",
|
|
101
|
+
filePath: resolver.resolve("./runtime/components/modal.vue")
|
|
102
|
+
});
|
|
103
|
+
addComponent({
|
|
104
|
+
name: "ShwfedConfig",
|
|
105
|
+
filePath: resolver.resolve("./runtime/components/config/index.vue")
|
|
106
|
+
});
|
|
107
|
+
addImports([
|
|
108
|
+
{ name: "provideCELContext", from: resolver.resolve("./runtime/plugins/cel/context") },
|
|
109
|
+
{ name: "openModal", from: resolver.resolve("./runtime/composables/useOverlay") },
|
|
110
|
+
{ name: "confirm", from: resolver.resolve("./runtime/composables/useOverlay") },
|
|
111
|
+
{ name: "reject", from: resolver.resolve("./runtime/composables/useOverlay") },
|
|
112
|
+
{ name: "useCel", from: resolver.resolve("./runtime/composables/useCel") }
|
|
113
|
+
]);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
export { module$1 as default };
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { Icon } from "@iconify/vue";
|
|
3
|
-
import AiByokButton from "../ai/byok-button.vue";
|
|
4
3
|
import { Button } from "../ui/button";
|
|
5
4
|
defineOptions({ name: "ShwfedConfigEditorFooter" });
|
|
6
5
|
const props = defineProps({
|
|
@@ -23,7 +22,6 @@ function onConfirm() {
|
|
|
23
22
|
|
|
24
23
|
<template>
|
|
25
24
|
<div class="flex w-full items-center justify-between gap-3">
|
|
26
|
-
<AiByokButton />
|
|
27
25
|
<div class="flex flex-1 flex-col gap-1 text-xs">
|
|
28
26
|
<span
|
|
29
27
|
v-if="props.state.validationError.value"
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { ref, watch } from "vue";
|
|
3
|
+
import { injectCELContext } from "../../plugins/cel/context";
|
|
3
4
|
import SlotRenderer from "../../share/slot-renderer.vue";
|
|
4
5
|
import ShwfedModal from "../modal.vue";
|
|
5
6
|
import EditorBody from "./config.vue";
|
|
@@ -13,11 +14,20 @@ const props = defineProps({
|
|
|
13
14
|
configure: { type: Function, required: false },
|
|
14
15
|
editable: { type: Boolean, required: false }
|
|
15
16
|
});
|
|
16
|
-
const
|
|
17
|
+
const inheritedCEL = injectCELContext();
|
|
18
|
+
const hostConfigure = props.configure ?? (() => {
|
|
17
19
|
});
|
|
20
|
+
const mergedConfigure = (env) => {
|
|
21
|
+
hostConfigure(env);
|
|
22
|
+
const existing = new Set(env.getDefinitions().variables.map((v) => v.name));
|
|
23
|
+
for (const [name, v] of Object.entries(inheritedCEL)) {
|
|
24
|
+
if (existing.has(name)) continue;
|
|
25
|
+
env.registerVariable(name, v.type, { description: v.description });
|
|
26
|
+
}
|
|
27
|
+
};
|
|
18
28
|
const editorOpen = ref(false);
|
|
19
29
|
const editorState = useConfigEditor(config, {
|
|
20
|
-
configure,
|
|
30
|
+
configure: mergedConfigure,
|
|
21
31
|
onClose: () => {
|
|
22
32
|
editorOpen.value = false;
|
|
23
33
|
}
|
|
@@ -45,7 +55,7 @@ function updateSlot(next) {
|
|
|
45
55
|
>
|
|
46
56
|
<SlotRenderer
|
|
47
57
|
:slot-value="config.slot"
|
|
48
|
-
:configure="
|
|
58
|
+
:configure="mergedConfigure"
|
|
49
59
|
:find-entry="findBlock"
|
|
50
60
|
@update:slot-value="updateSlot"
|
|
51
61
|
>
|
|
@@ -44,7 +44,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
44
44
|
readonly locale: "en" | "ja" | "ko";
|
|
45
45
|
readonly message: string;
|
|
46
46
|
}[]] | undefined;
|
|
47
|
-
readonly binding?: string | undefined;
|
|
47
|
+
readonly binding?: string | readonly [string, string] | undefined;
|
|
48
48
|
readonly presets?: readonly {
|
|
49
49
|
readonly label: readonly [{
|
|
50
50
|
readonly locale: "zh";
|
|
@@ -100,7 +100,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
100
100
|
readonly locale: "en" | "ja" | "ko";
|
|
101
101
|
readonly message: string;
|
|
102
102
|
}[]] | undefined;
|
|
103
|
-
readonly binding?: string | undefined;
|
|
103
|
+
readonly binding?: string | readonly [string, string] | undefined;
|
|
104
104
|
readonly presets?: readonly {
|
|
105
105
|
readonly label: readonly [{
|
|
106
106
|
readonly locale: "zh";
|
package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue
CHANGED
|
@@ -69,8 +69,11 @@ function setPresetStart(index, expr) {
|
|
|
69
69
|
function setPresetEnd(index, expr) {
|
|
70
70
|
patchPreset(index, { end: expr });
|
|
71
71
|
}
|
|
72
|
-
const
|
|
73
|
-
|
|
72
|
+
const bindingMode = computed(
|
|
73
|
+
() => Array.isArray(value.value.binding) ? "split" : "single"
|
|
74
|
+
);
|
|
75
|
+
const singlePathText = computed({
|
|
76
|
+
get: () => typeof value.value.binding === "string" ? value.value.binding : "",
|
|
74
77
|
set: (next) => {
|
|
75
78
|
const trimmed = next.trim();
|
|
76
79
|
if (trimmed.length === 0) {
|
|
@@ -81,6 +84,28 @@ const pathText = computed({
|
|
|
81
84
|
}
|
|
82
85
|
}
|
|
83
86
|
});
|
|
87
|
+
const splitStartText = computed(
|
|
88
|
+
() => Array.isArray(value.value.binding) ? value.value.binding[0] : ""
|
|
89
|
+
);
|
|
90
|
+
const splitEndText = computed(
|
|
91
|
+
() => Array.isArray(value.value.binding) ? value.value.binding[1] : ""
|
|
92
|
+
);
|
|
93
|
+
function setSplitStart(next) {
|
|
94
|
+
const cur = Array.isArray(value.value.binding) ? value.value.binding : ["", ""];
|
|
95
|
+
value.value = { ...value.value, binding: [next.trim(), cur[1]] };
|
|
96
|
+
}
|
|
97
|
+
function setSplitEnd(next) {
|
|
98
|
+
const cur = Array.isArray(value.value.binding) ? value.value.binding : ["", ""];
|
|
99
|
+
value.value = { ...value.value, binding: [cur[0], next.trim()] };
|
|
100
|
+
}
|
|
101
|
+
function toggleBindingMode() {
|
|
102
|
+
if (bindingMode.value === "single") {
|
|
103
|
+
value.value = { ...value.value, binding: ["", ""] };
|
|
104
|
+
} else {
|
|
105
|
+
const { binding: _omit, ...rest } = value.value;
|
|
106
|
+
value.value = rest;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
84
109
|
const formatText = computed({
|
|
85
110
|
get: () => value.value.format ?? "",
|
|
86
111
|
set: (next) => {
|
|
@@ -167,20 +192,70 @@ const valueFormatExample = computed(() => previewFormat(value.value.valueFormat
|
|
|
167
192
|
<FieldLabel class="text-xs text-zinc-500">
|
|
168
193
|
<template #tooltip>
|
|
169
194
|
<Markdown
|
|
170
|
-
source="写入表单状态的嵌套键路径,使用 `.`
|
|
195
|
+
source="写入表单状态的嵌套键路径,使用 `.` 分隔。单路径模式写入 `[start, end]` 字符串数组;拆分模式分别写入起始与结束两端"
|
|
171
196
|
block
|
|
172
197
|
class="prose prose-sm prose-zinc"
|
|
173
198
|
/>
|
|
174
199
|
</template>
|
|
175
200
|
{{ fieldTitle("binding") }}
|
|
176
201
|
</FieldLabel>
|
|
177
|
-
<
|
|
178
|
-
<
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
202
|
+
<template v-if="bindingMode === 'single'">
|
|
203
|
+
<InputGroup>
|
|
204
|
+
<InputGroupInput
|
|
205
|
+
v-model="singlePathText"
|
|
206
|
+
placeholder="例:event.range"
|
|
207
|
+
class="font-mono"
|
|
208
|
+
/>
|
|
209
|
+
<InputGroupAddon align="inline-end">
|
|
210
|
+
<InputGroupButton
|
|
211
|
+
size="icon-xs"
|
|
212
|
+
aria-label="拆分起止绑定路径"
|
|
213
|
+
@click="toggleBindingMode"
|
|
214
|
+
>
|
|
215
|
+
<Icon icon="fluent:split-horizontal-20-regular" />
|
|
216
|
+
</InputGroupButton>
|
|
217
|
+
</InputGroupAddon>
|
|
218
|
+
</InputGroup>
|
|
219
|
+
</template>
|
|
220
|
+
<template v-else>
|
|
221
|
+
<div class="grid grid-cols-2 gap-2">
|
|
222
|
+
<InputGroup>
|
|
223
|
+
<InputGroupAddon align="inline-start">
|
|
224
|
+
<InputGroupText class="text-xs text-zinc-400">
|
|
225
|
+
起
|
|
226
|
+
</InputGroupText>
|
|
227
|
+
</InputGroupAddon>
|
|
228
|
+
<InputGroupInput
|
|
229
|
+
:model-value="splitStartText"
|
|
230
|
+
placeholder="例:event.start"
|
|
231
|
+
class="font-mono"
|
|
232
|
+
@update:model-value="(v) => setSplitStart(String(v ?? ''))"
|
|
233
|
+
/>
|
|
234
|
+
</InputGroup>
|
|
235
|
+
<InputGroup>
|
|
236
|
+
<InputGroupAddon align="inline-start">
|
|
237
|
+
<InputGroupText class="text-xs text-zinc-400">
|
|
238
|
+
止
|
|
239
|
+
</InputGroupText>
|
|
240
|
+
</InputGroupAddon>
|
|
241
|
+
<InputGroupInput
|
|
242
|
+
:model-value="splitEndText"
|
|
243
|
+
placeholder="例:event.end"
|
|
244
|
+
class="font-mono"
|
|
245
|
+
@update:model-value="(v) => setSplitEnd(String(v ?? ''))"
|
|
246
|
+
/>
|
|
247
|
+
<InputGroupAddon align="inline-end">
|
|
248
|
+
<InputGroupButton
|
|
249
|
+
size="icon-xs"
|
|
250
|
+
aria-label="合并起止绑定路径"
|
|
251
|
+
@click="toggleBindingMode"
|
|
252
|
+
>
|
|
253
|
+
<Icon icon="fluent:merge-vertical-20-regular" />
|
|
254
|
+
</InputGroupButton>
|
|
255
|
+
</InputGroupAddon>
|
|
256
|
+
</InputGroup>
|
|
257
|
+
</div>
|
|
258
|
+
</template>
|
|
184
259
|
</Field>
|
|
185
260
|
</div>
|
|
186
261
|
|
|
@@ -44,7 +44,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
44
44
|
readonly locale: "en" | "ja" | "ko";
|
|
45
45
|
readonly message: string;
|
|
46
46
|
}[]] | undefined;
|
|
47
|
-
readonly binding?: string | undefined;
|
|
47
|
+
readonly binding?: string | readonly [string, string] | undefined;
|
|
48
48
|
readonly presets?: readonly {
|
|
49
49
|
readonly label: readonly [{
|
|
50
50
|
readonly locale: "zh";
|
|
@@ -100,7 +100,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
100
100
|
readonly locale: "en" | "ja" | "ko";
|
|
101
101
|
readonly message: string;
|
|
102
102
|
}[]] | undefined;
|
|
103
|
-
readonly binding?: string | undefined;
|
|
103
|
+
readonly binding?: string | readonly [string, string] | undefined;
|
|
104
104
|
readonly presets?: readonly {
|
|
105
105
|
readonly label: readonly [{
|
|
106
106
|
readonly locale: "zh";
|
package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/runtime.vue
CHANGED
|
@@ -71,20 +71,32 @@ function asRange(raw) {
|
|
|
71
71
|
if (a.length === 0 || b.length === 0) return void 0;
|
|
72
72
|
return [a, b];
|
|
73
73
|
}
|
|
74
|
+
function asString(raw) {
|
|
75
|
+
return typeof raw === "string" && raw.length > 0 ? raw : void 0;
|
|
76
|
+
}
|
|
74
77
|
const uncontrolled = ref(void 0);
|
|
75
78
|
const model = computed({
|
|
76
79
|
get: () => {
|
|
77
|
-
const
|
|
78
|
-
if (
|
|
79
|
-
return asRange(getAt(
|
|
80
|
+
const binding = props.config.binding;
|
|
81
|
+
if (binding == null) return uncontrolled.value;
|
|
82
|
+
if (typeof binding === "string") return asRange(getAt(binding));
|
|
83
|
+
const a = asString(getAt(binding[0]));
|
|
84
|
+
const b = asString(getAt(binding[1]));
|
|
85
|
+
if (a == null || b == null) return void 0;
|
|
86
|
+
return [a, b];
|
|
80
87
|
},
|
|
81
88
|
set: (next) => {
|
|
82
|
-
const
|
|
83
|
-
if (
|
|
89
|
+
const binding = props.config.binding;
|
|
90
|
+
if (binding == null) {
|
|
84
91
|
uncontrolled.value = next;
|
|
85
92
|
return;
|
|
86
93
|
}
|
|
87
|
-
|
|
94
|
+
if (typeof binding === "string") {
|
|
95
|
+
setAt(binding, next);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
setAt(binding[0], next?.[0]);
|
|
99
|
+
setAt(binding[1], next?.[1]);
|
|
88
100
|
}
|
|
89
101
|
});
|
|
90
102
|
const readonlyText = computed(() => {
|
package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/schema.d.ts
CHANGED
|
@@ -58,7 +58,7 @@ export declare function schema(configure: (env: Environment) => void): Schema.St
|
|
|
58
58
|
message: Schema.SchemaClass<string, string, never>;
|
|
59
59
|
}>]>>;
|
|
60
60
|
orientation: Schema.optional<Schema.Literal<["vertical", "floating"]>>;
|
|
61
|
-
binding: Schema.optional<Schema.
|
|
61
|
+
binding: Schema.optional<Schema.Union<[Schema.filter<typeof Schema.String>, Schema.filter<Schema.Tuple2<Schema.filter<typeof Schema.String>, Schema.filter<typeof Schema.String>>>]>>;
|
|
62
62
|
disabled: Schema.optional<Schema.Schema<string, string, never>>;
|
|
63
63
|
readonly: Schema.optional<Schema.Schema<string, string, never>>;
|
|
64
64
|
format: Schema.optional<Schema.refine<string, typeof Schema.String>>;
|
package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/schema.js
CHANGED
|
@@ -4,6 +4,16 @@ import { Locale } from "../../../../../share/locale.js";
|
|
|
4
4
|
import { commonFieldFields, FieldOrientationSchema } from "../../../utils/common.js";
|
|
5
5
|
export const type = "com.shwfed.form.field.daterange";
|
|
6
6
|
export const compatibilityDate = "2026-04-27";
|
|
7
|
+
const BindingPath = Schema.String.pipe(Schema.minLength(1));
|
|
8
|
+
const SplitBinding = Schema.Tuple(BindingPath, BindingPath).pipe(
|
|
9
|
+
Schema.filter(([a, b]) => a !== b, {
|
|
10
|
+
message: () => "\u8D77\u59CB\u4E0E\u7ED3\u675F\u7ED1\u5B9A\u8DEF\u5F84\u4E0D\u80FD\u76F8\u540C"
|
|
11
|
+
})
|
|
12
|
+
);
|
|
13
|
+
const bindingSchema = Schema.Union(BindingPath, SplitBinding).annotations({
|
|
14
|
+
title: "\u7ED1\u5B9A\u8DEF\u5F84",
|
|
15
|
+
description: "\u5199\u5165\u8868\u5355\u72B6\u6001\u7684 `dot-prop` \u8DEF\u5F84\uFF1B\u586B\u5199\u5355\u4E2A\u8DEF\u5F84\u65F6\u5199\u5165 `[start, end]` \u5B57\u7B26\u4E32\u6570\u7EC4\uFF0C\u4F8B\u5982 `event.range`\uFF1B\u586B\u5199 `[\u8D77\u59CB\u8DEF\u5F84, \u7ED3\u675F\u8DEF\u5F84]` \u5143\u7EC4\u65F6\u5206\u522B\u5199\u5165\u4E24\u7AEF\uFF1B\u7559\u7A7A\u5219\u4E3A\u975E\u53D7\u63A7\u5B57\u6BB5"
|
|
16
|
+
});
|
|
7
17
|
export const metadata = {
|
|
8
18
|
name: "\u65E5\u671F\u8303\u56F4",
|
|
9
19
|
icon: "fluent:calendar-arrow-right-20-regular",
|
|
@@ -54,10 +64,7 @@ export function schema(configure) {
|
|
|
54
64
|
description: "\u9F20\u6807\u60AC\u505C\u5728\u6807\u7B7E\u4E0A\u65F6\u5C55\u793A\u7684\u8BF4\u660E"
|
|
55
65
|
})),
|
|
56
66
|
orientation: Schema.optional(FieldOrientationSchema),
|
|
57
|
-
binding: Schema.optional(
|
|
58
|
-
title: "\u7ED1\u5B9A\u8DEF\u5F84",
|
|
59
|
-
description: "\u5199\u5165\u8868\u5355\u72B6\u6001\u7684 `dot-prop` \u8DEF\u5F84\uFF0C\u4F8B\u5982 `event.range`\uFF1B\u5199\u5165\u503C\u4E3A `[start, end]` \u5B57\u7B26\u4E32\u6570\u7EC4\uFF1B\u7559\u7A7A\u5219\u4E3A\u975E\u53D7\u63A7\u5B57\u6BB5"
|
|
60
|
-
})),
|
|
67
|
+
binding: Schema.optional(bindingSchema),
|
|
61
68
|
disabled: Schema.optional(CelBool.annotations({
|
|
62
69
|
title: "\u7981\u7528\u6761\u4EF6",
|
|
63
70
|
description: "\u8FD4\u56DE `true` \u65F6\u8F93\u5165\u6846\u4ECD\u7136\u6E32\u67D3\u4F46\u4E0D\u53EF\u7F16\u8F91"
|
|
@@ -46,7 +46,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
46
46
|
readonly locale: "en" | "ja" | "ko";
|
|
47
47
|
readonly message: string;
|
|
48
48
|
}[]] | undefined;
|
|
49
|
-
readonly binding?: string | undefined;
|
|
49
|
+
readonly binding?: string | readonly [string, string] | undefined;
|
|
50
50
|
readonly presets?: readonly {
|
|
51
51
|
readonly label: readonly [{
|
|
52
52
|
readonly locale: "zh";
|
|
@@ -104,7 +104,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
104
104
|
readonly locale: "en" | "ja" | "ko";
|
|
105
105
|
readonly message: string;
|
|
106
106
|
}[]] | undefined;
|
|
107
|
-
readonly binding?: string | undefined;
|
|
107
|
+
readonly binding?: string | readonly [string, string] | undefined;
|
|
108
108
|
readonly presets?: readonly {
|
|
109
109
|
readonly label: readonly [{
|
|
110
110
|
readonly locale: "zh";
|
|
@@ -69,8 +69,11 @@ function setPresetStart(index, expr) {
|
|
|
69
69
|
function setPresetEnd(index, expr) {
|
|
70
70
|
patchPreset(index, { end: expr });
|
|
71
71
|
}
|
|
72
|
-
const
|
|
73
|
-
|
|
72
|
+
const bindingMode = computed(
|
|
73
|
+
() => Array.isArray(value.value.binding) ? "split" : "single"
|
|
74
|
+
);
|
|
75
|
+
const singlePathText = computed({
|
|
76
|
+
get: () => typeof value.value.binding === "string" ? value.value.binding : "",
|
|
74
77
|
set: (next) => {
|
|
75
78
|
const trimmed = next.trim();
|
|
76
79
|
if (trimmed.length === 0) {
|
|
@@ -81,6 +84,28 @@ const pathText = computed({
|
|
|
81
84
|
}
|
|
82
85
|
}
|
|
83
86
|
});
|
|
87
|
+
const splitStartText = computed(
|
|
88
|
+
() => Array.isArray(value.value.binding) ? value.value.binding[0] : ""
|
|
89
|
+
);
|
|
90
|
+
const splitEndText = computed(
|
|
91
|
+
() => Array.isArray(value.value.binding) ? value.value.binding[1] : ""
|
|
92
|
+
);
|
|
93
|
+
function setSplitStart(next) {
|
|
94
|
+
const cur = Array.isArray(value.value.binding) ? value.value.binding : ["", ""];
|
|
95
|
+
value.value = { ...value.value, binding: [next.trim(), cur[1]] };
|
|
96
|
+
}
|
|
97
|
+
function setSplitEnd(next) {
|
|
98
|
+
const cur = Array.isArray(value.value.binding) ? value.value.binding : ["", ""];
|
|
99
|
+
value.value = { ...value.value, binding: [cur[0], next.trim()] };
|
|
100
|
+
}
|
|
101
|
+
function toggleBindingMode() {
|
|
102
|
+
if (bindingMode.value === "single") {
|
|
103
|
+
value.value = { ...value.value, binding: ["", ""] };
|
|
104
|
+
} else {
|
|
105
|
+
const { binding: _omit, ...rest } = value.value;
|
|
106
|
+
value.value = rest;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
84
109
|
const formatText = computed({
|
|
85
110
|
get: () => value.value.format ?? "",
|
|
86
111
|
set: (next) => {
|
|
@@ -189,20 +214,70 @@ const valueFormatExample = computed(() => previewFormat(value.value.valueFormat
|
|
|
189
214
|
<FieldLabel class="text-xs text-zinc-500">
|
|
190
215
|
<template #tooltip>
|
|
191
216
|
<Markdown
|
|
192
|
-
source="写入表单状态的嵌套键路径,使用 `.`
|
|
217
|
+
source="写入表单状态的嵌套键路径,使用 `.` 分隔。单路径模式写入 `[start, end]` 字符串数组;拆分模式分别写入起始与结束两端"
|
|
193
218
|
block
|
|
194
219
|
class="prose prose-sm prose-zinc"
|
|
195
220
|
/>
|
|
196
221
|
</template>
|
|
197
222
|
{{ fieldTitle("binding") }}
|
|
198
223
|
</FieldLabel>
|
|
199
|
-
<
|
|
200
|
-
<
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
224
|
+
<template v-if="bindingMode === 'single'">
|
|
225
|
+
<InputGroup>
|
|
226
|
+
<InputGroupInput
|
|
227
|
+
v-model="singlePathText"
|
|
228
|
+
placeholder="例:event.range"
|
|
229
|
+
class="font-mono"
|
|
230
|
+
/>
|
|
231
|
+
<InputGroupAddon align="inline-end">
|
|
232
|
+
<InputGroupButton
|
|
233
|
+
size="icon-xs"
|
|
234
|
+
aria-label="拆分起止绑定路径"
|
|
235
|
+
@click="toggleBindingMode"
|
|
236
|
+
>
|
|
237
|
+
<Icon icon="fluent:split-horizontal-20-regular" />
|
|
238
|
+
</InputGroupButton>
|
|
239
|
+
</InputGroupAddon>
|
|
240
|
+
</InputGroup>
|
|
241
|
+
</template>
|
|
242
|
+
<template v-else>
|
|
243
|
+
<div class="grid grid-cols-2 gap-2">
|
|
244
|
+
<InputGroup>
|
|
245
|
+
<InputGroupAddon align="inline-start">
|
|
246
|
+
<InputGroupText class="text-xs text-zinc-400">
|
|
247
|
+
起
|
|
248
|
+
</InputGroupText>
|
|
249
|
+
</InputGroupAddon>
|
|
250
|
+
<InputGroupInput
|
|
251
|
+
:model-value="splitStartText"
|
|
252
|
+
placeholder="例:event.start"
|
|
253
|
+
class="font-mono"
|
|
254
|
+
@update:model-value="(v) => setSplitStart(String(v ?? ''))"
|
|
255
|
+
/>
|
|
256
|
+
</InputGroup>
|
|
257
|
+
<InputGroup>
|
|
258
|
+
<InputGroupAddon align="inline-start">
|
|
259
|
+
<InputGroupText class="text-xs text-zinc-400">
|
|
260
|
+
止
|
|
261
|
+
</InputGroupText>
|
|
262
|
+
</InputGroupAddon>
|
|
263
|
+
<InputGroupInput
|
|
264
|
+
:model-value="splitEndText"
|
|
265
|
+
placeholder="例:event.end"
|
|
266
|
+
class="font-mono"
|
|
267
|
+
@update:model-value="(v) => setSplitEnd(String(v ?? ''))"
|
|
268
|
+
/>
|
|
269
|
+
<InputGroupAddon align="inline-end">
|
|
270
|
+
<InputGroupButton
|
|
271
|
+
size="icon-xs"
|
|
272
|
+
aria-label="合并起止绑定路径"
|
|
273
|
+
@click="toggleBindingMode"
|
|
274
|
+
>
|
|
275
|
+
<Icon icon="fluent:merge-vertical-20-regular" />
|
|
276
|
+
</InputGroupButton>
|
|
277
|
+
</InputGroupAddon>
|
|
278
|
+
</InputGroup>
|
|
279
|
+
</div>
|
|
280
|
+
</template>
|
|
206
281
|
</Field>
|
|
207
282
|
</div>
|
|
208
283
|
|
|
@@ -46,7 +46,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
46
46
|
readonly locale: "en" | "ja" | "ko";
|
|
47
47
|
readonly message: string;
|
|
48
48
|
}[]] | undefined;
|
|
49
|
-
readonly binding?: string | undefined;
|
|
49
|
+
readonly binding?: string | readonly [string, string] | undefined;
|
|
50
50
|
readonly presets?: readonly {
|
|
51
51
|
readonly label: readonly [{
|
|
52
52
|
readonly locale: "zh";
|
|
@@ -104,7 +104,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
104
104
|
readonly locale: "en" | "ja" | "ko";
|
|
105
105
|
readonly message: string;
|
|
106
106
|
}[]] | undefined;
|
|
107
|
-
readonly binding?: string | undefined;
|
|
107
|
+
readonly binding?: string | readonly [string, string] | undefined;
|
|
108
108
|
readonly presets?: readonly {
|
|
109
109
|
readonly label: readonly [{
|
|
110
110
|
readonly locale: "zh";
|
|
@@ -71,20 +71,32 @@ function asRange(raw) {
|
|
|
71
71
|
if (a.length === 0 || b.length === 0) return void 0;
|
|
72
72
|
return [a, b];
|
|
73
73
|
}
|
|
74
|
+
function asString(raw) {
|
|
75
|
+
return typeof raw === "string" && raw.length > 0 ? raw : void 0;
|
|
76
|
+
}
|
|
74
77
|
const uncontrolled = ref(void 0);
|
|
75
78
|
const model = computed({
|
|
76
79
|
get: () => {
|
|
77
|
-
const
|
|
78
|
-
if (
|
|
79
|
-
return asRange(getAt(
|
|
80
|
+
const binding = props.config.binding;
|
|
81
|
+
if (binding == null) return uncontrolled.value;
|
|
82
|
+
if (typeof binding === "string") return asRange(getAt(binding));
|
|
83
|
+
const a = asString(getAt(binding[0]));
|
|
84
|
+
const b = asString(getAt(binding[1]));
|
|
85
|
+
if (a == null || b == null) return void 0;
|
|
86
|
+
return [a, b];
|
|
80
87
|
},
|
|
81
88
|
set: (next) => {
|
|
82
|
-
const
|
|
83
|
-
if (
|
|
89
|
+
const binding = props.config.binding;
|
|
90
|
+
if (binding == null) {
|
|
84
91
|
uncontrolled.value = next;
|
|
85
92
|
return;
|
|
86
93
|
}
|
|
87
|
-
|
|
94
|
+
if (typeof binding === "string") {
|
|
95
|
+
setAt(binding, next);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
setAt(binding[0], next?.[0]);
|
|
99
|
+
setAt(binding[1], next?.[1]);
|
|
88
100
|
}
|
|
89
101
|
});
|
|
90
102
|
const readonlyText = computed(() => {
|
|
@@ -68,7 +68,7 @@ export declare function schema(configure: (env: Environment) => void): Schema.St
|
|
|
68
68
|
message: Schema.SchemaClass<string, string, never>;
|
|
69
69
|
}>]>>;
|
|
70
70
|
orientation: Schema.optional<Schema.Literal<["vertical", "floating"]>>;
|
|
71
|
-
binding: Schema.optional<Schema.
|
|
71
|
+
binding: Schema.optional<Schema.Union<[Schema.filter<typeof Schema.String>, Schema.filter<Schema.Tuple2<Schema.filter<typeof Schema.String>, Schema.filter<typeof Schema.String>>>]>>;
|
|
72
72
|
disabled: Schema.optional<Schema.Schema<string, string, never>>;
|
|
73
73
|
readonly: Schema.optional<Schema.Schema<string, string, never>>;
|
|
74
74
|
format: Schema.optional<Schema.refine<string, typeof Schema.String>>;
|