@shwfed/config 3.0.10 → 3.0.11
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/runtime/components/form/fields/2026-04-24/com.shwfed.form.field.combobox.single/config.d.vue.ts +16 -16
- package/dist/runtime/components/form/fields/2026-04-24/com.shwfed.form.field.combobox.single/config.vue.d.ts +16 -16
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.d.vue.ts +6 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue.d.ts +6 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.d.vue.ts +8 -8
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue.d.ts +8 -8
- 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.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.combobox.single.remote/config.d.vue.ts +16 -16
- package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.combobox.single.remote/config.vue.d.ts +16 -16
- package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.d.vue.ts +6 -6
- package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.vue.d.ts +6 -6
- package/dist/runtime/components/form/fields/2026-05-25/com.shwfed.form.field.combobox.multi/config.d.vue.ts +16 -16
- package/dist/runtime/components/form/fields/2026-05-25/com.shwfed.form.field.combobox.multi/config.vue.d.ts +16 -16
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/config.d.vue.ts +34 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/config.vue +109 -1
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/config.vue.d.ts +34 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/prompt.md +7 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/runtime.vue +66 -22
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/schema.d.ts +23 -0
- package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/schema.js +26 -0
- package/dist/runtime/components/table/columns/2026-07-16/com.shwfed.table.column.upload/config.d.vue.ts +10 -0
- package/dist/runtime/components/table/columns/2026-07-16/com.shwfed.table.column.upload/config.vue +1004 -0
- package/dist/runtime/components/table/columns/2026-07-16/com.shwfed.table.column.upload/config.vue.d.ts +10 -0
- package/dist/runtime/components/table/columns/2026-07-16/com.shwfed.table.column.upload/prompt.md +19 -0
- package/dist/runtime/components/table/columns/2026-07-16/com.shwfed.table.column.upload/runtime.d.vue.ts +9 -0
- package/dist/runtime/components/table/columns/2026-07-16/com.shwfed.table.column.upload/runtime.vue +503 -0
- package/dist/runtime/components/table/columns/2026-07-16/com.shwfed.table.column.upload/runtime.vue.d.ts +9 -0
- package/dist/runtime/components/table/columns/2026-07-16/com.shwfed.table.column.upload/schema.d.ts +138 -0
- package/dist/runtime/components/table/columns/2026-07-16/com.shwfed.table.column.upload/schema.js +181 -0
- package/dist/runtime/components/ui/date-picker/DatePickerInput.d.vue.ts +1 -1
- package/dist/runtime/components/ui/date-picker/DatePickerInput.vue.d.ts +1 -1
- package/dist/runtime/components/ui/date-picker/DatePickerTimeInput.d.vue.ts +1 -1
- package/dist/runtime/components/ui/date-picker/DatePickerTimeInput.vue.d.ts +1 -1
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerInput.d.vue.ts +1 -1
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerInput.vue.d.ts +1 -1
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerTimeInput.d.vue.ts +2 -2
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerTimeInput.vue.d.ts +2 -2
- package/package.json +1 -1
|
@@ -40,6 +40,14 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
40
40
|
readonly mode: "formula" | "prefill";
|
|
41
41
|
readonly expression: string;
|
|
42
42
|
} | undefined;
|
|
43
|
+
readonly optionValue: string;
|
|
44
|
+
readonly optionLabel: readonly [{
|
|
45
|
+
readonly locale: "zh";
|
|
46
|
+
readonly message: string;
|
|
47
|
+
}, ...{
|
|
48
|
+
readonly locale: "en" | "ja" | "ko";
|
|
49
|
+
readonly message: string;
|
|
50
|
+
}[]];
|
|
43
51
|
readonly validations?: readonly {
|
|
44
52
|
readonly message: readonly [{
|
|
45
53
|
readonly locale: "zh";
|
|
@@ -51,14 +59,6 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
51
59
|
readonly warning?: boolean | undefined;
|
|
52
60
|
readonly when: string;
|
|
53
61
|
}[] | undefined;
|
|
54
|
-
readonly optionValue: string;
|
|
55
|
-
readonly optionLabel: readonly [{
|
|
56
|
-
readonly locale: "zh";
|
|
57
|
-
readonly message: string;
|
|
58
|
-
}, ...{
|
|
59
|
-
readonly locale: "en" | "ja" | "ko";
|
|
60
|
-
readonly message: string;
|
|
61
|
-
}[]];
|
|
62
62
|
}) => any;
|
|
63
63
|
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
64
64
|
"onUpdate:modelValue"?: ((value: {
|
|
@@ -98,6 +98,14 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
98
98
|
readonly mode: "formula" | "prefill";
|
|
99
99
|
readonly expression: string;
|
|
100
100
|
} | undefined;
|
|
101
|
+
readonly optionValue: string;
|
|
102
|
+
readonly optionLabel: readonly [{
|
|
103
|
+
readonly locale: "zh";
|
|
104
|
+
readonly message: string;
|
|
105
|
+
}, ...{
|
|
106
|
+
readonly locale: "en" | "ja" | "ko";
|
|
107
|
+
readonly message: string;
|
|
108
|
+
}[]];
|
|
101
109
|
readonly validations?: readonly {
|
|
102
110
|
readonly message: readonly [{
|
|
103
111
|
readonly locale: "zh";
|
|
@@ -109,14 +117,6 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
109
117
|
readonly warning?: boolean | undefined;
|
|
110
118
|
readonly when: string;
|
|
111
119
|
}[] | undefined;
|
|
112
|
-
readonly optionValue: string;
|
|
113
|
-
readonly optionLabel: readonly [{
|
|
114
|
-
readonly locale: "zh";
|
|
115
|
-
readonly message: string;
|
|
116
|
-
}, ...{
|
|
117
|
-
readonly locale: "en" | "ja" | "ko";
|
|
118
|
-
readonly message: string;
|
|
119
|
-
}[]];
|
|
120
120
|
}) => any) | undefined;
|
|
121
121
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
122
122
|
declare const _default: typeof __VLS_export;
|
package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/config.d.vue.ts
CHANGED
|
@@ -32,6 +32,23 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
32
32
|
}[]] | undefined;
|
|
33
33
|
readonly required?: string | undefined;
|
|
34
34
|
readonly displayName?: string | undefined;
|
|
35
|
+
readonly download?: {
|
|
36
|
+
readonly label?: readonly [{
|
|
37
|
+
readonly locale: "zh";
|
|
38
|
+
readonly message: string;
|
|
39
|
+
}, ...{
|
|
40
|
+
readonly locale: "en" | "ja" | "ko";
|
|
41
|
+
readonly message: string;
|
|
42
|
+
}[]] | undefined;
|
|
43
|
+
readonly icon?: string | undefined;
|
|
44
|
+
readonly operations: readonly {
|
|
45
|
+
readonly id?: string | undefined;
|
|
46
|
+
readonly params?: unknown;
|
|
47
|
+
readonly compatibilityDate?: string | undefined;
|
|
48
|
+
readonly target: string;
|
|
49
|
+
readonly operation: string;
|
|
50
|
+
}[];
|
|
51
|
+
} | undefined;
|
|
35
52
|
readonly compatibilityDate: "2026-06-09";
|
|
36
53
|
readonly orientation?: "vertical" | "floating" | undefined;
|
|
37
54
|
readonly placeholder?: readonly [{
|
|
@@ -106,6 +123,23 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
106
123
|
}[]] | undefined;
|
|
107
124
|
readonly required?: string | undefined;
|
|
108
125
|
readonly displayName?: string | undefined;
|
|
126
|
+
readonly download?: {
|
|
127
|
+
readonly label?: readonly [{
|
|
128
|
+
readonly locale: "zh";
|
|
129
|
+
readonly message: string;
|
|
130
|
+
}, ...{
|
|
131
|
+
readonly locale: "en" | "ja" | "ko";
|
|
132
|
+
readonly message: string;
|
|
133
|
+
}[]] | undefined;
|
|
134
|
+
readonly icon?: string | undefined;
|
|
135
|
+
readonly operations: readonly {
|
|
136
|
+
readonly id?: string | undefined;
|
|
137
|
+
readonly params?: unknown;
|
|
138
|
+
readonly compatibilityDate?: string | undefined;
|
|
139
|
+
readonly target: string;
|
|
140
|
+
readonly operation: string;
|
|
141
|
+
}[];
|
|
142
|
+
} | undefined;
|
|
109
143
|
readonly compatibilityDate: "2026-06-09";
|
|
110
144
|
readonly orientation?: "vertical" | "floating" | undefined;
|
|
111
145
|
readonly placeholder?: readonly [{
|
package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/config.vue
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { Icon } from "@iconify/vue";
|
|
3
|
-
import { computed, ref, watch } from "vue";
|
|
3
|
+
import { computed, defineComponent, ref, watch } from "vue";
|
|
4
4
|
import {
|
|
5
5
|
useTreeDnd
|
|
6
6
|
} from "../../../../../composables/useTreeDnd";
|
|
7
|
+
import TriggersField from "../../../../actions/components/triggers-field.vue";
|
|
8
|
+
import { provideCELContext } from "../../../../../utils/cel-context";
|
|
7
9
|
import {
|
|
8
10
|
DropdownMenu,
|
|
9
11
|
DropdownMenuContent,
|
|
@@ -273,6 +275,52 @@ function setMultiple(v) {
|
|
|
273
275
|
value.value = { ...value.value, multiple: true };
|
|
274
276
|
}
|
|
275
277
|
}
|
|
278
|
+
const downloadEnabled = computed(() => value.value.download != null);
|
|
279
|
+
function setDownloadEnabled(on) {
|
|
280
|
+
if (on) {
|
|
281
|
+
if (value.value.download) return;
|
|
282
|
+
value.value = { ...value.value, download: { operations: [] } };
|
|
283
|
+
} else {
|
|
284
|
+
const { download: _omit, ...rest } = value.value;
|
|
285
|
+
value.value = rest;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const downloadOperations = computed(() => value.value.download?.operations ?? []);
|
|
289
|
+
function updateDownloadOperations(next) {
|
|
290
|
+
const current = value.value.download;
|
|
291
|
+
if (!current) return;
|
|
292
|
+
value.value = { ...value.value, download: { ...current, operations: next } };
|
|
293
|
+
}
|
|
294
|
+
function updateDownloadIcon(icon) {
|
|
295
|
+
const current = value.value.download;
|
|
296
|
+
if (!current) return;
|
|
297
|
+
const trimmed = icon.trim();
|
|
298
|
+
if (trimmed.length === 0) {
|
|
299
|
+
const { icon: _omit, ...rest } = current;
|
|
300
|
+
value.value = { ...value.value, download: rest };
|
|
301
|
+
} else {
|
|
302
|
+
value.value = { ...value.value, download: { ...current, icon: trimmed } };
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
function updateDownloadLabel(label) {
|
|
306
|
+
const current = value.value.download;
|
|
307
|
+
if (!current) return;
|
|
308
|
+
if (label == null || label.length === 0) {
|
|
309
|
+
const { label: _omit, ...rest } = current;
|
|
310
|
+
value.value = { ...value.value, download: rest };
|
|
311
|
+
} else {
|
|
312
|
+
value.value = { ...value.value, download: { ...current, label } };
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
const DownloadScope = defineComponent({
|
|
316
|
+
name: "ShwfedUploadDownloadScope",
|
|
317
|
+
setup(_, { slots }) {
|
|
318
|
+
provideCELContext({
|
|
319
|
+
file: { type: FILE_VAR.type, label: FILE_VAR.label, description: FILE_VAR.description, value: () => void 0 }
|
|
320
|
+
});
|
|
321
|
+
return () => slots.default?.();
|
|
322
|
+
}
|
|
323
|
+
});
|
|
276
324
|
</script>
|
|
277
325
|
|
|
278
326
|
<template>
|
|
@@ -693,6 +741,66 @@ function setMultiple(v) {
|
|
|
693
741
|
</Field>
|
|
694
742
|
</div>
|
|
695
743
|
|
|
744
|
+
<!-- Per-file download -->
|
|
745
|
+
<div class="flex items-center gap-2">
|
|
746
|
+
<h3 class="text-xs font-medium text-zinc-500">
|
|
747
|
+
{{ fieldTitle("download") }}
|
|
748
|
+
</h3>
|
|
749
|
+
<Switch
|
|
750
|
+
size="sm"
|
|
751
|
+
:model-value="downloadEnabled"
|
|
752
|
+
aria-label="启用文件下载"
|
|
753
|
+
@update:model-value="setDownloadEnabled"
|
|
754
|
+
/>
|
|
755
|
+
</div>
|
|
756
|
+
|
|
757
|
+
<div
|
|
758
|
+
v-if="downloadEnabled"
|
|
759
|
+
class="flex flex-col gap-3"
|
|
760
|
+
>
|
|
761
|
+
<div class="grid grid-cols-2 gap-3">
|
|
762
|
+
<Field orientation="vertical">
|
|
763
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
764
|
+
下载按钮图标
|
|
765
|
+
</FieldLabel>
|
|
766
|
+
<IconPicker
|
|
767
|
+
:model-value="value.download?.icon ?? ''"
|
|
768
|
+
@update:model-value="updateDownloadIcon"
|
|
769
|
+
/>
|
|
770
|
+
</Field>
|
|
771
|
+
|
|
772
|
+
<Field orientation="vertical">
|
|
773
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
774
|
+
下载按钮文本
|
|
775
|
+
</FieldLabel>
|
|
776
|
+
<LocaleField
|
|
777
|
+
translate-hint="file download button label"
|
|
778
|
+
:model-value="value.download?.label"
|
|
779
|
+
@update:model-value="updateDownloadLabel"
|
|
780
|
+
/>
|
|
781
|
+
</Field>
|
|
782
|
+
</div>
|
|
783
|
+
|
|
784
|
+
<Field orientation="vertical">
|
|
785
|
+
<FieldLabel class="text-xs text-zinc-500">
|
|
786
|
+
<template #tooltip>
|
|
787
|
+
<Markdown
|
|
788
|
+
source="点击文件项的下载按钮时按顺序执行的操作;可用 `file` 引用该文件项。尚未上传的本地文件会直接从内存下载,不经过此列表"
|
|
789
|
+
block
|
|
790
|
+
class="prose prose-sm prose-zinc"
|
|
791
|
+
/>
|
|
792
|
+
</template>
|
|
793
|
+
触发操作
|
|
794
|
+
</FieldLabel>
|
|
795
|
+
<DownloadScope>
|
|
796
|
+
<TriggersField
|
|
797
|
+
:triggers="downloadOperations"
|
|
798
|
+
@update:triggers="updateDownloadOperations"
|
|
799
|
+
/>
|
|
800
|
+
</DownloadScope>
|
|
801
|
+
</Field>
|
|
802
|
+
</div>
|
|
803
|
+
|
|
696
804
|
<!-- Download templates -->
|
|
697
805
|
<Field orientation="vertical">
|
|
698
806
|
<FieldLabel class="text-xs text-zinc-500">
|
package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/config.vue.d.ts
CHANGED
|
@@ -32,6 +32,23 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
32
32
|
}[]] | undefined;
|
|
33
33
|
readonly required?: string | undefined;
|
|
34
34
|
readonly displayName?: string | undefined;
|
|
35
|
+
readonly download?: {
|
|
36
|
+
readonly label?: readonly [{
|
|
37
|
+
readonly locale: "zh";
|
|
38
|
+
readonly message: string;
|
|
39
|
+
}, ...{
|
|
40
|
+
readonly locale: "en" | "ja" | "ko";
|
|
41
|
+
readonly message: string;
|
|
42
|
+
}[]] | undefined;
|
|
43
|
+
readonly icon?: string | undefined;
|
|
44
|
+
readonly operations: readonly {
|
|
45
|
+
readonly id?: string | undefined;
|
|
46
|
+
readonly params?: unknown;
|
|
47
|
+
readonly compatibilityDate?: string | undefined;
|
|
48
|
+
readonly target: string;
|
|
49
|
+
readonly operation: string;
|
|
50
|
+
}[];
|
|
51
|
+
} | undefined;
|
|
35
52
|
readonly compatibilityDate: "2026-06-09";
|
|
36
53
|
readonly orientation?: "vertical" | "floating" | undefined;
|
|
37
54
|
readonly placeholder?: readonly [{
|
|
@@ -106,6 +123,23 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {},
|
|
|
106
123
|
}[]] | undefined;
|
|
107
124
|
readonly required?: string | undefined;
|
|
108
125
|
readonly displayName?: string | undefined;
|
|
126
|
+
readonly download?: {
|
|
127
|
+
readonly label?: readonly [{
|
|
128
|
+
readonly locale: "zh";
|
|
129
|
+
readonly message: string;
|
|
130
|
+
}, ...{
|
|
131
|
+
readonly locale: "en" | "ja" | "ko";
|
|
132
|
+
readonly message: string;
|
|
133
|
+
}[]] | undefined;
|
|
134
|
+
readonly icon?: string | undefined;
|
|
135
|
+
readonly operations: readonly {
|
|
136
|
+
readonly id?: string | undefined;
|
|
137
|
+
readonly params?: unknown;
|
|
138
|
+
readonly compatibilityDate?: string | undefined;
|
|
139
|
+
readonly target: string;
|
|
140
|
+
readonly operation: string;
|
|
141
|
+
}[];
|
|
142
|
+
} | undefined;
|
|
109
143
|
readonly compatibilityDate: "2026-06-09";
|
|
110
144
|
readonly orientation?: "vertical" | "floating" | undefined;
|
|
111
145
|
readonly placeholder?: readonly [{
|
package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/prompt.md
CHANGED
|
@@ -9,4 +9,11 @@
|
|
|
9
9
|
|
|
10
10
|
`templates` 在上传区旁渲染「下载模板」按钮:只配 `request` 则直接下载其响应;再配 `download` 则是两步式——第二步经 `json` 引用第一步响应(如用 `json.data.key` 拼真正的下载地址)。
|
|
11
11
|
|
|
12
|
+
`download`(文件下载)给每个**文件项**渲染一个下载按钮,点击时执行一条「触发操作」列表(复用 actions 的操作子系统,与 state.write 同款),列表里的表达式可用 `file` 引用被点击的那一项。分两种情况:
|
|
13
|
+
|
|
14
|
+
- **已上传/回填的对象项**(即时上传结果,或编辑时服务端回填的记录):走操作列表,如放一个 `http.download` 操作、请求写 `http.get('/api/file').query('key', file.cacheKey)`;或两步式——先一个 `发送请求` 行取凭据、再一个 `下载文件` 行经 `steps[?"<步骤标识>"]` 引用其响应。凡下载要用到的字段,都必须已由 `upload.handle` 落进文件项(原始上传 `json` 在 `handle` 之后即失效,只有落进项里的字段才随保存/回填留存,从而让本会话上传的与编辑回填的文件项行为一致)。
|
|
15
|
+
- **尚未上传的本地文件**(延迟模式刚选中的原始 `File`):内存里没有服务端标识、也没有能表达“存这个本地 blob”的操作,故绕过列表、直接从 blob 下载。
|
|
16
|
+
|
|
17
|
+
下载按钮在只读表单里仍显示(查看已提交记录并下载附件是主要场景)。`download.icon` / `download.label` 定制按钮图标与无障碍文本。
|
|
18
|
+
|
|
12
19
|
约束类字段(`accept` / `maxFileSize` / `maxTotalSize` / `maxFiles` / `multiple`)按需设置即可。
|
package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/runtime.vue
CHANGED
|
@@ -6,7 +6,8 @@ import { computed, ref } from "vue";
|
|
|
6
6
|
import { useI18n } from "vue-i18n";
|
|
7
7
|
import { toast } from "vue-sonner";
|
|
8
8
|
import { cel as _rawCel } from "../../../../../utils/cel";
|
|
9
|
-
import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
|
|
9
|
+
import { celBindings, celScope, injectCELContext } from "../../../../../utils/cel-context";
|
|
10
|
+
import { dispatchTriggers, useEventChannel } from "../../../../../share/event-bus";
|
|
10
11
|
import { getLocalizedText } from "../../../../../share/locale";
|
|
11
12
|
import { interpolateMarkdown } from "../../../../table/utils/runtime";
|
|
12
13
|
import { Button } from "../../../../ui/button";
|
|
@@ -112,6 +113,7 @@ const { locale, t } = useI18n({
|
|
|
112
113
|
});
|
|
113
114
|
const { getAt, setAt } = useFormState();
|
|
114
115
|
const formScope = useFormScope();
|
|
116
|
+
const eventChannel = useEventChannel();
|
|
115
117
|
const inherited = injectCELContext();
|
|
116
118
|
const $cel = (expression, context) => _rawCel(expression, { ...celBindings(inherited), ...context });
|
|
117
119
|
const labelText = computed(
|
|
@@ -304,6 +306,16 @@ function onDelete(index) {
|
|
|
304
306
|
next.splice(index, 1);
|
|
305
307
|
entries.value = next;
|
|
306
308
|
}
|
|
309
|
+
function saveFile(file) {
|
|
310
|
+
const url = URL.createObjectURL(file);
|
|
311
|
+
const a = document.createElement("a");
|
|
312
|
+
a.href = url;
|
|
313
|
+
a.download = file.name;
|
|
314
|
+
document.body.appendChild(a);
|
|
315
|
+
a.click();
|
|
316
|
+
a.remove();
|
|
317
|
+
URL.revokeObjectURL(url);
|
|
318
|
+
}
|
|
307
319
|
const templates = computed(() => props.config.templates ?? []);
|
|
308
320
|
function templateIcon(template) {
|
|
309
321
|
return template.icon ?? "fluent:arrow-download-20-regular";
|
|
@@ -328,18 +340,36 @@ async function onDownloadTemplate(template) {
|
|
|
328
340
|
console.error(`[shwfed-form] template request for ${props.fieldId} did not produce a File`);
|
|
329
341
|
return;
|
|
330
342
|
}
|
|
331
|
-
|
|
332
|
-
const a = document.createElement("a");
|
|
333
|
-
a.href = url;
|
|
334
|
-
a.download = file.name;
|
|
335
|
-
document.body.appendChild(a);
|
|
336
|
-
a.click();
|
|
337
|
-
a.remove();
|
|
338
|
-
URL.revokeObjectURL(url);
|
|
343
|
+
saveFile(file);
|
|
339
344
|
} catch (err) {
|
|
340
345
|
console.error(`[shwfed-form] failed to download template for ${props.fieldId}:`, err);
|
|
341
346
|
}
|
|
342
347
|
}
|
|
348
|
+
const downloadEnabled = computed(() => props.config.download != null);
|
|
349
|
+
const downloadIcon = computed(() => props.config.download?.icon ?? "fluent:arrow-download-20-regular");
|
|
350
|
+
const downloadLabel = computed(
|
|
351
|
+
() => (props.config.download?.label ? getLocalizedText(props.config.download.label, locale.value) : void 0) ?? "\u4E0B\u8F7D"
|
|
352
|
+
);
|
|
353
|
+
function canDownload(entry) {
|
|
354
|
+
if (!downloadEnabled.value) return false;
|
|
355
|
+
if (entry instanceof File) return true;
|
|
356
|
+
return (props.config.download?.operations.length ?? 0) > 0;
|
|
357
|
+
}
|
|
358
|
+
async function onDownloadEntry(entry) {
|
|
359
|
+
if (!downloadEnabled.value) return;
|
|
360
|
+
if (entry instanceof File) {
|
|
361
|
+
saveFile(entry);
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
const download = props.config.download;
|
|
365
|
+
if (!download || download.operations.length === 0) return;
|
|
366
|
+
const triggerCel = (expression, context) => _rawCel(expression, celScope(inherited, { form: formScope.state.value ?? {}, file: entry, ...context }));
|
|
367
|
+
try {
|
|
368
|
+
await Effect.runPromise(dispatchTriggers(eventChannel, download.operations, triggerCel));
|
|
369
|
+
} catch (err) {
|
|
370
|
+
if (import.meta.dev) console.warn(`[shwfed-form] download operations halted for ${props.fieldId}:`, err);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
343
373
|
</script>
|
|
344
374
|
|
|
345
375
|
<template>
|
|
@@ -446,19 +476,33 @@ async function onDownloadTemplate(template) {
|
|
|
446
476
|
/>
|
|
447
477
|
<span class="truncate text-zinc-700">{{ entryName(entry) }}</span>
|
|
448
478
|
</span>
|
|
449
|
-
<
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
479
|
+
<span class="flex shrink-0 items-center gap-0.5">
|
|
480
|
+
<Button
|
|
481
|
+
v-if="canDownload(entry)"
|
|
482
|
+
type="button"
|
|
483
|
+
variant="ghost"
|
|
484
|
+
size="sm"
|
|
485
|
+
data-slot="upload-zone-download"
|
|
486
|
+
class="size-6 p-0 text-zinc-500 hover:bg-zinc-100 hover:text-zinc-700"
|
|
487
|
+
:aria-label="`${downloadLabel}\uFF1A${entryName(entry)}`"
|
|
488
|
+
@click="onDownloadEntry(entry)"
|
|
489
|
+
>
|
|
490
|
+
<Icon :icon="downloadIcon" />
|
|
491
|
+
</Button>
|
|
492
|
+
<Button
|
|
493
|
+
v-if="!isDisabled && !isReadonly"
|
|
494
|
+
type="button"
|
|
495
|
+
variant="ghost"
|
|
496
|
+
size="sm"
|
|
497
|
+
data-slot="upload-zone-delete"
|
|
498
|
+
class="size-6 p-0 text-zinc-500 hover:bg-red-50 hover:text-red-600"
|
|
499
|
+
:disabled="uploading"
|
|
500
|
+
:aria-label="`\u5220\u9664\uFF1A${entryName(entry)}`"
|
|
501
|
+
@click="onDelete(index)"
|
|
502
|
+
>
|
|
503
|
+
<Icon icon="fluent:delete-20-regular" />
|
|
504
|
+
</Button>
|
|
505
|
+
</span>
|
|
462
506
|
</li>
|
|
463
507
|
</ul>
|
|
464
508
|
|
package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/schema.d.ts
CHANGED
|
@@ -135,6 +135,29 @@ export declare function schema(configure: (env: Environment) => void): Schema.St
|
|
|
135
135
|
readonly message: string;
|
|
136
136
|
}[]], never>>;
|
|
137
137
|
}>>>;
|
|
138
|
+
download: Schema.optional<Schema.Struct<{
|
|
139
|
+
operations: Schema.Array$<Schema.Struct<{
|
|
140
|
+
id: Schema.optional<Schema.refine<string, typeof Schema.String>>;
|
|
141
|
+
target: Schema.refine<string, typeof Schema.String>;
|
|
142
|
+
operation: Schema.SchemaClass<string, string, never>;
|
|
143
|
+
compatibilityDate: Schema.optional<Schema.SchemaClass<string, string, never>>;
|
|
144
|
+
params: Schema.optional<Schema.SchemaClass<unknown, unknown, never>>;
|
|
145
|
+
}>>;
|
|
146
|
+
icon: Schema.optional<Schema.refine<string, typeof Schema.String>>;
|
|
147
|
+
label: Schema.optional<Schema.suspend<readonly [{
|
|
148
|
+
readonly locale: "zh";
|
|
149
|
+
readonly message: string;
|
|
150
|
+
}, ...{
|
|
151
|
+
readonly locale: "en" | "ja" | "ko";
|
|
152
|
+
readonly message: string;
|
|
153
|
+
}[]], string | readonly [{
|
|
154
|
+
readonly locale: "zh";
|
|
155
|
+
readonly message: string;
|
|
156
|
+
}, ...{
|
|
157
|
+
readonly locale: "en" | "ja" | "ko";
|
|
158
|
+
readonly message: string;
|
|
159
|
+
}[]], never>>;
|
|
160
|
+
}>>;
|
|
138
161
|
id: Schema.refine<string, typeof Schema.String>;
|
|
139
162
|
displayName: Schema.optional<Schema.SchemaClass<string, string, never>>;
|
|
140
163
|
hidden: Schema.optional<Schema.Schema<string, string, never>>;
|
package/dist/runtime/components/form/fields/2026-06-09/com.shwfed.form.field.upload/schema.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Effect, Schema } from "effect";
|
|
2
2
|
import { Expression, LocaleMarkdown } from "../../../../../share/expression.js";
|
|
3
|
+
import { Triggers } from "../../../../../share/event-bus.js";
|
|
3
4
|
import { Locale } from "../../../../../share/locale.js";
|
|
4
5
|
import { commonFieldFields, FieldOrientationSchema } from "../../../utils/common.js";
|
|
5
6
|
export const type = "com.shwfed.form.field.upload";
|
|
@@ -144,6 +145,31 @@ export function schema(configure) {
|
|
|
144
145
|
})).annotations({
|
|
145
146
|
title: "\u4E0B\u8F7D\u6A21\u677F",
|
|
146
147
|
description: "\u4E0B\u8F7D\u6A21\u677F\u5217\u8868\uFF1B\u6BCF\u4E00\u9879\u5728\u4E0A\u4F20\u533A\u57DF\u65C1\u6E32\u67D3\u4E00\u4E2A\u4E0B\u8F7D\u6309\u94AE"
|
|
148
|
+
})),
|
|
149
|
+
// Per-file download — a 触发操作 (trigger-operation) list run when the user
|
|
150
|
+
// clicks a file item's 下载 button, with the clicked stored item in scope as
|
|
151
|
+
// `file` (the same `FILE_VAR` as `upload.filename`). Object entries
|
|
152
|
+
// (immediate-upload results or server-backfilled records) download via these
|
|
153
|
+
// operations — e.g. an `http.download` op reading `file.cacheKey`, or a
|
|
154
|
+
// two-step `http.request` → `http.download` chain. A freshly-picked,
|
|
155
|
+
// not-yet-uploaded native `File` bypasses the list and downloads from its
|
|
156
|
+
// in-memory blob directly, since no operation can express "save this local
|
|
157
|
+
// blob". `params` on each row stay opaque here (validated by the target
|
|
158
|
+
// operation's own schema in the editor); `file` typing is advertised to the
|
|
159
|
+
// op editors at config time via `provideCELContext`, not by this schema.
|
|
160
|
+
download: Schema.optional(Schema.Struct({
|
|
161
|
+
operations: Triggers,
|
|
162
|
+
icon: Schema.optional(Schema.String.pipe(Schema.minLength(1)).annotations({
|
|
163
|
+
title: "\u4E0B\u8F7D\u6309\u94AE\u56FE\u6807",
|
|
164
|
+
description: "Iconify \u56FE\u6807\u6807\u8BC6\u7B26\uFF0C\u4F8B\u5982 `fluent:arrow-download-20-regular`\uFF1B\u7559\u7A7A\u65F6\u4F7F\u7528\u9ED8\u8BA4\u56FE\u6807"
|
|
165
|
+
})),
|
|
166
|
+
label: Schema.optional(Locale.annotations({
|
|
167
|
+
title: "\u4E0B\u8F7D\u6309\u94AE\u6587\u672C",
|
|
168
|
+
description: "\u6BCF\u4E2A\u6587\u4EF6\u9879\u4E0B\u8F7D\u6309\u94AE\u7684\u672C\u5730\u5316\u65E0\u969C\u788D\u6807\u7B7E\uFF1B\u7559\u7A7A\u65F6\u4F7F\u7528\u300C\u4E0B\u8F7D\u300D"
|
|
169
|
+
}))
|
|
170
|
+
}).annotations({
|
|
171
|
+
title: "\u6587\u4EF6\u4E0B\u8F7D",
|
|
172
|
+
description: "\u914D\u7F6E\u540E\u6BCF\u4E2A\u6587\u4EF6\u9879\u65C1\u6E32\u67D3\u4E0B\u8F7D\u6309\u94AE\uFF1A\u5DF2\u4E0A\u4F20/\u56DE\u586B\u7684\u5BF9\u8C61\u9879\u6309\u300C\u89E6\u53D1\u64CD\u4F5C\u300D\u5217\u8868\u4E0B\u8F7D\uFF08`file` \u4E3A\u8BE5\u6587\u4EF6\u9879\uFF09\uFF1B\u5C1A\u672A\u4E0A\u4F20\u7684\u672C\u5730\u6587\u4EF6\u76F4\u63A5\u4ECE\u5185\u5B58\u4E0B\u8F7D\uFF0C\u4E0D\u7ECF\u8FC7\u8BE5\u5217\u8868"
|
|
147
173
|
}))
|
|
148
174
|
}).annotations({
|
|
149
175
|
title: "UploadField",
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type __VLS_ModelProps = {
|
|
2
|
+
modelValue: Record<string, any>;
|
|
3
|
+
};
|
|
4
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_ModelProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
"update:modelValue": (value: Record<string, any>) => any;
|
|
6
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_ModelProps> & Readonly<{
|
|
7
|
+
"onUpdate:modelValue"?: ((value: Record<string, any>) => any) | undefined;
|
|
8
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
9
|
+
declare const _default: typeof __VLS_export;
|
|
10
|
+
export default _default;
|