@scorpioz/suna-components 0.0.2
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/README.md +52 -0
- package/button/index.ts +3 -0
- package/button/src/Button.vue +42 -0
- package/button/src/props.ts +24 -0
- package/button/src/types.ts +26 -0
- package/confirm-button/index.ts +2 -0
- package/confirm-button/src/ConfirmButton.vue +52 -0
- package/confirm-button/src/props.ts +50 -0
- package/debounce-button/index.ts +2 -0
- package/debounce-button/src/DebounceButton.vue +65 -0
- package/debounce-button/src/props.ts +15 -0
- package/drawer/index.ts +3 -0
- package/drawer/src/Drawer.vue +120 -0
- package/drawer/src/props.ts +76 -0
- package/drawer/src/types.ts +8 -0
- package/drawer-form/index.ts +2 -0
- package/drawer-form/src/DrawerForm.vue +164 -0
- package/drawer-form/src/props.ts +74 -0
- package/form/index.ts +3 -0
- package/form/src/Form.vue +183 -0
- package/form/src/form-items/FCascader.vue +25 -0
- package/form/src/form-items/FCheckboxGroup.vue +33 -0
- package/form/src/form-items/FDatePicker.vue +24 -0
- package/form/src/form-items/FInput.vue +26 -0
- package/form/src/form-items/FInputNumber.vue +26 -0
- package/form/src/form-items/FRadioGroup.vue +33 -0
- package/form/src/form-items/FRate.vue +24 -0
- package/form/src/form-items/FSelect.vue +34 -0
- package/form/src/form-items/FSwitch.vue +24 -0
- package/form/src/form-items/FText.vue +16 -0
- package/form/src/form-items/FTextarea.vue +27 -0
- package/form/src/path.ts +39 -0
- package/form/src/props.ts +73 -0
- package/form/src/types.ts +168 -0
- package/form/src/useFormField.ts +137 -0
- package/form/src/useFormItems.ts +85 -0
- package/index.ts +82 -0
- package/package.json +50 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, watch } from "vue";
|
|
3
|
+
import SDrawer from "../../drawer/src/Drawer.vue";
|
|
4
|
+
import SForm from "../../form/src/Form.vue";
|
|
5
|
+
import SunaButton from "../../button/src/Button.vue";
|
|
6
|
+
import SunaDebounceButton from "../../debounce-button/src/DebounceButton.vue";
|
|
7
|
+
import { drawerFormProps } from "./props";
|
|
8
|
+
|
|
9
|
+
defineOptions({ name: "SunaDrawerForm" });
|
|
10
|
+
|
|
11
|
+
// ---- v-model:visible(抽屉显隐) + 数据(表单默认值 / 确认后同步) ----
|
|
12
|
+
const visible = defineModel<boolean>("visible", { default: false });
|
|
13
|
+
const formData = defineModel<Record<string, any>>({ default: () => ({}) });
|
|
14
|
+
|
|
15
|
+
// ---- 其余 props ----
|
|
16
|
+
const props = defineProps(drawerFormProps);
|
|
17
|
+
const emit = defineEmits<{
|
|
18
|
+
/** 提交且校验通过时触发 */
|
|
19
|
+
confirm: [data: Record<string, any>];
|
|
20
|
+
cancel: [];
|
|
21
|
+
open: [];
|
|
22
|
+
opened: [];
|
|
23
|
+
close: [];
|
|
24
|
+
closed: [];
|
|
25
|
+
}>();
|
|
26
|
+
|
|
27
|
+
// ---- 内部表单数据(支持「取消即撤销」) ----
|
|
28
|
+
const internalData = ref<Record<string, any>>({});
|
|
29
|
+
|
|
30
|
+
watch(visible, (opening) => {
|
|
31
|
+
if (opening) {
|
|
32
|
+
if (props.cloneOnOpen) {
|
|
33
|
+
// 深层克隆:cancel 不会污染外部数据
|
|
34
|
+
internalData.value = JSON.parse(JSON.stringify(formData.value));
|
|
35
|
+
} else {
|
|
36
|
+
internalData.value = formData.value;
|
|
37
|
+
}
|
|
38
|
+
emit("open");
|
|
39
|
+
} else {
|
|
40
|
+
emit("close");
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
function onOpened() {
|
|
45
|
+
emit("opened");
|
|
46
|
+
}
|
|
47
|
+
function onClosed() {
|
|
48
|
+
emit("closed");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ---- 表单 ref ----
|
|
52
|
+
const formRef = ref<InstanceType<typeof SForm> | null>(null);
|
|
53
|
+
|
|
54
|
+
function onReset() {
|
|
55
|
+
formRef.value?.resetFields();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function onCancel() {
|
|
59
|
+
visible.value = false;
|
|
60
|
+
emit("cancel");
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function onSubmit() {
|
|
64
|
+
try {
|
|
65
|
+
await formRef.value?.validate();
|
|
66
|
+
// 确认时同步数据到父组件
|
|
67
|
+
if (props.cloneOnOpen) {
|
|
68
|
+
formData.value = JSON.parse(JSON.stringify(internalData.value));
|
|
69
|
+
}
|
|
70
|
+
visible.value = false;
|
|
71
|
+
emit("confirm", formData.value);
|
|
72
|
+
emit("closed");
|
|
73
|
+
} catch {
|
|
74
|
+
/* 校验未通过,el-form 会显示错误,无需额外处理 */
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
defineExpose({
|
|
79
|
+
formRef,
|
|
80
|
+
validate: () => formRef.value?.validate(),
|
|
81
|
+
resetFields: () => formRef.value?.resetFields(),
|
|
82
|
+
open: () => { visible.value = true; },
|
|
83
|
+
close: () => { visible.value = false; },
|
|
84
|
+
});
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<template>
|
|
88
|
+
<SDrawer
|
|
89
|
+
:model-value="visible"
|
|
90
|
+
:title="title"
|
|
91
|
+
:direction="direction"
|
|
92
|
+
:size="size"
|
|
93
|
+
:with-footer="false"
|
|
94
|
+
v-bind="drawerConfig"
|
|
95
|
+
@update:model-value="visible = $event"
|
|
96
|
+
@opened="onOpened"
|
|
97
|
+
@closed="onClosed"
|
|
98
|
+
>
|
|
99
|
+
<SForm
|
|
100
|
+
ref="formRef"
|
|
101
|
+
v-model="internalData"
|
|
102
|
+
:form-items="formItems"
|
|
103
|
+
:label-width="labelWidth"
|
|
104
|
+
:label-position="labelPosition"
|
|
105
|
+
:gutter="gutter"
|
|
106
|
+
:default-span="defaultSpan"
|
|
107
|
+
:show-type="showType"
|
|
108
|
+
:with-actions="false"
|
|
109
|
+
v-bind="formConfig"
|
|
110
|
+
>
|
|
111
|
+
<template v-for="(_, name) in $slots" #[name]="scope">
|
|
112
|
+
<slot :name="name" v-bind="scope" />
|
|
113
|
+
</template>
|
|
114
|
+
</SForm>
|
|
115
|
+
|
|
116
|
+
<!-- 内置底部操作栏(位于 Drawer footer 区域) -->
|
|
117
|
+
<template #footer>
|
|
118
|
+
<slot name="footer">
|
|
119
|
+
<div
|
|
120
|
+
v-if="withActions"
|
|
121
|
+
class="suna-drawer-form__actions"
|
|
122
|
+
:class="`is-${actionAlign}`"
|
|
123
|
+
>
|
|
124
|
+
<SunaButton
|
|
125
|
+
v-if="showReset"
|
|
126
|
+
:type="resetButtonType"
|
|
127
|
+
@click="onReset"
|
|
128
|
+
>{{ resetText }}</SunaButton>
|
|
129
|
+
<SunaButton
|
|
130
|
+
v-if="showCancel"
|
|
131
|
+
:type="cancelButtonType"
|
|
132
|
+
@click="onCancel"
|
|
133
|
+
>{{ cancelText }}</SunaButton>
|
|
134
|
+
<SunaDebounceButton
|
|
135
|
+
v-if="showSubmit"
|
|
136
|
+
:type="submitButtonType"
|
|
137
|
+
:loading="submitLoading"
|
|
138
|
+
:wait="submitWait"
|
|
139
|
+
:leading="submitLeading"
|
|
140
|
+
@click="onSubmit"
|
|
141
|
+
>{{ submitText }}</SunaDebounceButton>
|
|
142
|
+
</div>
|
|
143
|
+
</slot>
|
|
144
|
+
</template>
|
|
145
|
+
</SDrawer>
|
|
146
|
+
</template>
|
|
147
|
+
|
|
148
|
+
<style scoped>
|
|
149
|
+
.suna-drawer-form__actions {
|
|
150
|
+
display: flex;
|
|
151
|
+
align-items: center;
|
|
152
|
+
gap: 12px;
|
|
153
|
+
width: 100%;
|
|
154
|
+
}
|
|
155
|
+
.suna-drawer-form__actions.is-left {
|
|
156
|
+
justify-content: flex-start;
|
|
157
|
+
}
|
|
158
|
+
.suna-drawer-form__actions.is-center {
|
|
159
|
+
justify-content: center;
|
|
160
|
+
}
|
|
161
|
+
.suna-drawer-form__actions.is-right {
|
|
162
|
+
justify-content: flex-end;
|
|
163
|
+
}
|
|
164
|
+
</style>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { PropType } from "vue";
|
|
2
|
+
import type { ButtonType } from "../../button/src/types";
|
|
3
|
+
import type { DrawerDirection, DrawerSize } from "../../drawer/src/types";
|
|
4
|
+
import type { FormItem } from "../../form/src/types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* DrawerForm 的运行时 props:汇集 SunaDrawer 和 SunaForm 最常用的属性,
|
|
8
|
+
* 其余高级配置通过 drawerConfig / formConfig 传入。
|
|
9
|
+
*/
|
|
10
|
+
export const drawerFormProps = {
|
|
11
|
+
// ---- 抽屉控制 ----
|
|
12
|
+
/** 抽屉标题 */
|
|
13
|
+
title: { type: String, default: "" },
|
|
14
|
+
/** 滑出方向 */
|
|
15
|
+
direction: { type: String as PropType<DrawerDirection>, default: "rtl" },
|
|
16
|
+
/** 抽屉尺寸 */
|
|
17
|
+
size: { type: [String, Number] as PropType<DrawerSize>, default: "30%" },
|
|
18
|
+
/** 其余 ElDrawer 属性透传(before-close / z-index / append-to 等) */
|
|
19
|
+
drawerConfig: { type: Object, default: () => ({}) },
|
|
20
|
+
|
|
21
|
+
// ---- 表单控制 ----
|
|
22
|
+
/** 字段配置数组 */
|
|
23
|
+
formItems: {
|
|
24
|
+
type: Array as PropType<FormItem[]>,
|
|
25
|
+
required: true as const,
|
|
26
|
+
},
|
|
27
|
+
/** 标签宽度 */
|
|
28
|
+
labelWidth: { type: [String, Number], default: "100px" },
|
|
29
|
+
/** 标签对齐方式 */
|
|
30
|
+
labelPosition: {
|
|
31
|
+
type: String as PropType<"left" | "right" | "top">,
|
|
32
|
+
default: "right",
|
|
33
|
+
},
|
|
34
|
+
/** 栅格间隔(px) */
|
|
35
|
+
gutter: { type: Number, default: 12 },
|
|
36
|
+
/** 未指定 span 时的默认栅格占比 */
|
|
37
|
+
defaultSpan: { type: Number, default: 12 },
|
|
38
|
+
/** 渲染模式:normal(可编辑)/ text(只读) */
|
|
39
|
+
showType: {
|
|
40
|
+
type: String as PropType<"normal" | "text">,
|
|
41
|
+
default: "normal",
|
|
42
|
+
},
|
|
43
|
+
/** 其余 ElForm 属性透传(inline / disabled 等) */
|
|
44
|
+
formConfig: { type: Object, default: () => ({}) },
|
|
45
|
+
|
|
46
|
+
// ---- 底部操作栏 ----
|
|
47
|
+
/** 是否显示操作栏 */
|
|
48
|
+
withActions: { type: Boolean, default: true },
|
|
49
|
+
/** 按钮对齐方式 */
|
|
50
|
+
actionAlign: {
|
|
51
|
+
type: String as PropType<"left" | "center" | "right">,
|
|
52
|
+
default: "right",
|
|
53
|
+
},
|
|
54
|
+
showSubmit: { type: Boolean, default: true },
|
|
55
|
+
showReset: { type: Boolean, default: true },
|
|
56
|
+
showCancel: { type: Boolean, default: true },
|
|
57
|
+
submitText: { type: String, default: "提交" },
|
|
58
|
+
resetText: { type: String, default: "重置" },
|
|
59
|
+
cancelText: { type: String, default: "取消" },
|
|
60
|
+
submitButtonType: { type: String as PropType<ButtonType>, default: "primary" },
|
|
61
|
+
resetButtonType: { type: String as PropType<ButtonType>, default: "default" },
|
|
62
|
+
cancelButtonType: { type: String as PropType<ButtonType>, default: "default" },
|
|
63
|
+
submitLoading: { type: Boolean, default: false },
|
|
64
|
+
submitWait: { type: Number, default: 300 },
|
|
65
|
+
submitLeading: { type: Boolean, default: true },
|
|
66
|
+
|
|
67
|
+
// ---- DrawerForm 特有 ----
|
|
68
|
+
/**
|
|
69
|
+
* 每次打开抽屉时是否深层克隆 v-model 数据。
|
|
70
|
+
* true(默认)→ 编辑在内部副本上进行,「取消」不会污染外部数据;
|
|
71
|
+
* false → 直接绑定外部数据,编辑实时同步。
|
|
72
|
+
*/
|
|
73
|
+
cloneOnOpen: { type: Boolean, default: true },
|
|
74
|
+
};
|
package/form/index.ts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref, computed, provide } from "vue";
|
|
3
|
+
import type { FormInstance } from "element-plus";
|
|
4
|
+
import { ElForm, ElRow, ElCol, ElFormItem } from "element-plus";
|
|
5
|
+
import SunaButton from "../../button/src/Button.vue";
|
|
6
|
+
import SunaDebounceButton from "../../debounce-button/src/DebounceButton.vue";
|
|
7
|
+
import { formProps } from "./props";
|
|
8
|
+
import { useFormItems } from "./useFormItems";
|
|
9
|
+
import { getPath, setPath } from "./path";
|
|
10
|
+
|
|
11
|
+
defineOptions({ name: "SunaForm" });
|
|
12
|
+
|
|
13
|
+
// ---- v-model:整个表单数据对象(omit from formProps 以避免冲突) ----
|
|
14
|
+
const model = defineModel<Record<string, any>>({ default: () => ({}) });
|
|
15
|
+
|
|
16
|
+
// ---- 其余 props ----
|
|
17
|
+
const props = defineProps(formProps);
|
|
18
|
+
const emit = defineEmits(["update:modelValue", "submit", "reset", "cancel"]);
|
|
19
|
+
|
|
20
|
+
// ---- 注入详情模式到后代字段组件 ----
|
|
21
|
+
provide("suna:showType", computed(() => props.showType));
|
|
22
|
+
|
|
23
|
+
// ---- 字段映射 / 校验 / 版式 ----
|
|
24
|
+
const { getType, getRules, getSpan } = useFormItems(props.defaultSpan);
|
|
25
|
+
|
|
26
|
+
// ---- el-form 暴露 ----
|
|
27
|
+
const elFormRef = ref<FormInstance | null>(null);
|
|
28
|
+
defineExpose({
|
|
29
|
+
validate: () => elFormRef.value?.validate(),
|
|
30
|
+
resetFields: () => elFormRef.value?.resetFields(),
|
|
31
|
+
clearValidate: () => elFormRef.value?.clearValidate(),
|
|
32
|
+
scrollToField: (prop: string) => elFormRef.value?.scrollToField(prop),
|
|
33
|
+
elForm: elFormRef,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// ---- 值读写辅助(支持嵌套 prop 路径) ----
|
|
37
|
+
function getVal(prop: string | undefined): any {
|
|
38
|
+
return prop ? getPath(model.value, prop) : undefined;
|
|
39
|
+
}
|
|
40
|
+
function onFieldUpdate(item: any, val: any) {
|
|
41
|
+
if (item.prop) setPath(model.value, item.prop, val);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ---- 操作栏事件 ----
|
|
45
|
+
async function onSubmit() {
|
|
46
|
+
try {
|
|
47
|
+
await elFormRef.value?.validate();
|
|
48
|
+
emit("submit");
|
|
49
|
+
} catch {
|
|
50
|
+
/* 校验失败由 EP 显示错误 */
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function onReset() {
|
|
54
|
+
elFormRef.value?.resetFields();
|
|
55
|
+
emit("reset");
|
|
56
|
+
}
|
|
57
|
+
function onCancel() {
|
|
58
|
+
emit("cancel");
|
|
59
|
+
}
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<template>
|
|
63
|
+
<el-form
|
|
64
|
+
ref="elFormRef"
|
|
65
|
+
class="suna-form"
|
|
66
|
+
:model="model"
|
|
67
|
+
:label-width="labelWidth"
|
|
68
|
+
:label-position="labelPosition"
|
|
69
|
+
:size="size"
|
|
70
|
+
v-bind="$attrs"
|
|
71
|
+
>
|
|
72
|
+
<el-row :gutter="gutter">
|
|
73
|
+
<template v-for="(item, i) in formItems" :key="(item as any).prop || (item as any).slot || i">
|
|
74
|
+
<el-col
|
|
75
|
+
v-if="(item as any).showItem !== false"
|
|
76
|
+
:span="getSpan(item)"
|
|
77
|
+
:offset="(item as any).offset || 0"
|
|
78
|
+
>
|
|
79
|
+
<!-- 纯插槽项:由调用方通过具名 slot 完全掌控渲染 -->
|
|
80
|
+
<slot
|
|
81
|
+
v-if="(item as any).slot"
|
|
82
|
+
:name="(item as any).slot"
|
|
83
|
+
:form="model"
|
|
84
|
+
:item="item"
|
|
85
|
+
/>
|
|
86
|
+
<!-- 字段项 -->
|
|
87
|
+
<el-form-item
|
|
88
|
+
v-else
|
|
89
|
+
:prop="(item as any).prop"
|
|
90
|
+
:label="(item as any).label"
|
|
91
|
+
:label-width="(item as any).labelWidth"
|
|
92
|
+
:rules="getRules(item)"
|
|
93
|
+
>
|
|
94
|
+
<template #label>
|
|
95
|
+
<span>{{ (item as any).label }}</span>
|
|
96
|
+
<span
|
|
97
|
+
v-if="(item as any).tooltip"
|
|
98
|
+
class="suna-form__tooltip-icon"
|
|
99
|
+
:title="(item as any).tooltip"
|
|
100
|
+
>ⓘ</span>
|
|
101
|
+
</template>
|
|
102
|
+
<component
|
|
103
|
+
:is="getType((item as any).type)"
|
|
104
|
+
:model-value="getVal((item as any).prop)"
|
|
105
|
+
:item="item"
|
|
106
|
+
:form="model"
|
|
107
|
+
@update:model-value="(v: any) => onFieldUpdate(item, v)"
|
|
108
|
+
/>
|
|
109
|
+
</el-form-item>
|
|
110
|
+
</el-col>
|
|
111
|
+
</template>
|
|
112
|
+
</el-row>
|
|
113
|
+
|
|
114
|
+
<!-- 内置操作栏(按钮对齐、显隐、文字、防抖等语义同 Drawer footer) -->
|
|
115
|
+
<div
|
|
116
|
+
v-if="withActions"
|
|
117
|
+
class="suna-form__actions"
|
|
118
|
+
:class="`is-${actionAlign}`"
|
|
119
|
+
>
|
|
120
|
+
<SunaButton
|
|
121
|
+
v-if="showReset"
|
|
122
|
+
:type="resetButtonType"
|
|
123
|
+
@click="onReset"
|
|
124
|
+
>{{ resetText }}</SunaButton>
|
|
125
|
+
<SunaButton
|
|
126
|
+
v-if="showCancel"
|
|
127
|
+
:type="cancelButtonType"
|
|
128
|
+
@click="onCancel"
|
|
129
|
+
>{{ cancelText }}</SunaButton>
|
|
130
|
+
<SunaDebounceButton
|
|
131
|
+
v-if="showSubmit"
|
|
132
|
+
:type="submitButtonType"
|
|
133
|
+
:loading="submitLoading"
|
|
134
|
+
:wait="submitWait"
|
|
135
|
+
:leading="submitLeading"
|
|
136
|
+
@click="onSubmit"
|
|
137
|
+
>{{ submitText }}</SunaDebounceButton>
|
|
138
|
+
</div>
|
|
139
|
+
</el-form>
|
|
140
|
+
</template>
|
|
141
|
+
|
|
142
|
+
<style scoped>
|
|
143
|
+
/* 操作栏:flex 布局,对齐方式由 .is-* 控制 */
|
|
144
|
+
.suna-form__actions {
|
|
145
|
+
display: flex;
|
|
146
|
+
align-items: center;
|
|
147
|
+
gap: 12px;
|
|
148
|
+
width: 100%;
|
|
149
|
+
margin-top: 16px;
|
|
150
|
+
padding-top: 16px;
|
|
151
|
+
border-top: 1px solid var(--el-border-color-light, #e5e7eb);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.suna-form__actions.is-left {
|
|
155
|
+
justify-content: flex-start;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.suna-form__actions.is-center {
|
|
159
|
+
justify-content: center;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.suna-form__actions.is-right {
|
|
163
|
+
justify-content: flex-end;
|
|
164
|
+
}
|
|
165
|
+
</style>
|
|
166
|
+
|
|
167
|
+
<!-- 子组件(F*.vue)共用的文本 / 工具提示类 -->
|
|
168
|
+
<style>
|
|
169
|
+
.suna-form__text {
|
|
170
|
+
font-size: 14px;
|
|
171
|
+
color: var(--el-text-color-regular, #303133);
|
|
172
|
+
word-break: break-all;
|
|
173
|
+
line-height: 1.6;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
.suna-form__tooltip-icon {
|
|
177
|
+
cursor: help;
|
|
178
|
+
font-size: 14px;
|
|
179
|
+
color: var(--el-text-color-secondary, #909399);
|
|
180
|
+
margin-left: 4px;
|
|
181
|
+
vertical-align: middle;
|
|
182
|
+
}
|
|
183
|
+
</style>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ElCascader } from "element-plus";
|
|
3
|
+
import { useFormField } from "../useFormField";
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
modelValue: { default: undefined },
|
|
7
|
+
item: { type: Object, default: () => ({}) },
|
|
8
|
+
form: { type: Object, default: () => ({}) },
|
|
9
|
+
});
|
|
10
|
+
const emit = defineEmits(["update:modelValue", "change"]);
|
|
11
|
+
|
|
12
|
+
const { valueTmp, showText, formatTextVal, handleChange } =
|
|
13
|
+
useFormField(props, emit);
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<ElCascader
|
|
18
|
+
v-if="!showText"
|
|
19
|
+
:model-value="valueTmp"
|
|
20
|
+
:options="item.options"
|
|
21
|
+
v-bind="item.attrs"
|
|
22
|
+
@update:model-value="handleChange"
|
|
23
|
+
/>
|
|
24
|
+
<span v-else class="suna-form__text">{{ formatTextVal }}</span>
|
|
25
|
+
</template>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ElCheckboxGroup, ElCheckbox } from "element-plus";
|
|
3
|
+
import { useFormField } from "../useFormField";
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
modelValue: { default: undefined },
|
|
7
|
+
item: { type: Object, default: () => ({}) },
|
|
8
|
+
form: { type: Object, default: () => ({}) },
|
|
9
|
+
});
|
|
10
|
+
const emit = defineEmits(["update:modelValue", "change"]);
|
|
11
|
+
|
|
12
|
+
const { valueTmp, showText, formatTextVal, handleChange } =
|
|
13
|
+
useFormField(props, emit);
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<ElCheckboxGroup
|
|
18
|
+
v-if="!showText"
|
|
19
|
+
:model-value="valueTmp"
|
|
20
|
+
v-bind="item.attrs"
|
|
21
|
+
@update:model-value="handleChange"
|
|
22
|
+
>
|
|
23
|
+
<ElCheckbox
|
|
24
|
+
v-for="opt in (item.options || [])"
|
|
25
|
+
:key="opt[item.optionProps?.value || 'value']"
|
|
26
|
+
:value="opt[item.optionProps?.value || 'value']"
|
|
27
|
+
:disabled="opt.disabled"
|
|
28
|
+
>
|
|
29
|
+
{{ opt[item.optionProps?.label || 'label'] }}
|
|
30
|
+
</ElCheckbox>
|
|
31
|
+
</ElCheckboxGroup>
|
|
32
|
+
<span v-else class="suna-form__text">{{ formatTextVal }}</span>
|
|
33
|
+
</template>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ElDatePicker } from "element-plus";
|
|
3
|
+
import { useFormField } from "../useFormField";
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
modelValue: { default: undefined },
|
|
7
|
+
item: { type: Object, default: () => ({}) },
|
|
8
|
+
form: { type: Object, default: () => ({}) },
|
|
9
|
+
});
|
|
10
|
+
const emit = defineEmits(["update:modelValue", "change"]);
|
|
11
|
+
|
|
12
|
+
const { valueTmp, showText, formatTextVal, handleChange } =
|
|
13
|
+
useFormField(props, emit);
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<ElDatePicker
|
|
18
|
+
v-if="!showText"
|
|
19
|
+
:model-value="valueTmp"
|
|
20
|
+
v-bind="item.attrs"
|
|
21
|
+
@update:model-value="handleChange"
|
|
22
|
+
/>
|
|
23
|
+
<span v-else class="suna-form__text">{{ formatTextVal }}</span>
|
|
24
|
+
</template>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ElInput } from "element-plus";
|
|
3
|
+
import { useFormField } from "../useFormField";
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
modelValue: { default: undefined },
|
|
7
|
+
item: { type: Object, default: () => ({}) },
|
|
8
|
+
form: { type: Object, default: () => ({}) },
|
|
9
|
+
});
|
|
10
|
+
const emit = defineEmits(["update:modelValue", "change"]);
|
|
11
|
+
|
|
12
|
+
const { valueTmp, showText, formatTextVal, handleChange, blur, focus } =
|
|
13
|
+
useFormField(props, emit);
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<ElInput
|
|
18
|
+
v-if="!showText"
|
|
19
|
+
:model-value="valueTmp"
|
|
20
|
+
v-bind="item.attrs"
|
|
21
|
+
@update:model-value="handleChange"
|
|
22
|
+
@blur="blur"
|
|
23
|
+
@focus="focus"
|
|
24
|
+
/>
|
|
25
|
+
<span v-else class="suna-form__text">{{ formatTextVal }}</span>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ElInputNumber } from "element-plus";
|
|
3
|
+
import { useFormField } from "../useFormField";
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
modelValue: { default: undefined },
|
|
7
|
+
item: { type: Object, default: () => ({}) },
|
|
8
|
+
form: { type: Object, default: () => ({}) },
|
|
9
|
+
});
|
|
10
|
+
const emit = defineEmits(["update:modelValue", "change"]);
|
|
11
|
+
|
|
12
|
+
const { valueTmp, showText, formatTextVal, handleChange, blur, focus } =
|
|
13
|
+
useFormField(props, emit);
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<ElInputNumber
|
|
18
|
+
v-if="!showText"
|
|
19
|
+
:model-value="valueTmp"
|
|
20
|
+
v-bind="item.attrs"
|
|
21
|
+
@update:model-value="handleChange"
|
|
22
|
+
@blur="blur"
|
|
23
|
+
@focus="focus"
|
|
24
|
+
/>
|
|
25
|
+
<span v-else class="suna-form__text">{{ formatTextVal }}</span>
|
|
26
|
+
</template>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ElRadioGroup, ElRadio } from "element-plus";
|
|
3
|
+
import { useFormField } from "../useFormField";
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
modelValue: { default: undefined },
|
|
7
|
+
item: { type: Object, default: () => ({}) },
|
|
8
|
+
form: { type: Object, default: () => ({}) },
|
|
9
|
+
});
|
|
10
|
+
const emit = defineEmits(["update:modelValue", "change"]);
|
|
11
|
+
|
|
12
|
+
const { valueTmp, showText, formatTextVal, handleChange } =
|
|
13
|
+
useFormField(props, emit);
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<ElRadioGroup
|
|
18
|
+
v-if="!showText"
|
|
19
|
+
:model-value="valueTmp"
|
|
20
|
+
v-bind="item.attrs"
|
|
21
|
+
@update:model-value="handleChange"
|
|
22
|
+
>
|
|
23
|
+
<ElRadio
|
|
24
|
+
v-for="opt in (item.options || [])"
|
|
25
|
+
:key="opt[item.optionProps?.value || 'value']"
|
|
26
|
+
:label="opt[item.optionProps?.value || 'value']"
|
|
27
|
+
:disabled="opt.disabled"
|
|
28
|
+
>
|
|
29
|
+
{{ opt[item.optionProps?.label || 'label'] }}
|
|
30
|
+
</ElRadio>
|
|
31
|
+
</ElRadioGroup>
|
|
32
|
+
<span v-else class="suna-form__text">{{ formatTextVal }}</span>
|
|
33
|
+
</template>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ElRate } from "element-plus";
|
|
3
|
+
import { useFormField } from "../useFormField";
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
modelValue: { default: undefined },
|
|
7
|
+
item: { type: Object, default: () => ({}) },
|
|
8
|
+
form: { type: Object, default: () => ({}) },
|
|
9
|
+
});
|
|
10
|
+
const emit = defineEmits(["update:modelValue", "change"]);
|
|
11
|
+
|
|
12
|
+
const { valueTmp, showText, formatTextVal, handleChange } =
|
|
13
|
+
useFormField(props, emit);
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<ElRate
|
|
18
|
+
v-if="!showText"
|
|
19
|
+
:model-value="valueTmp"
|
|
20
|
+
v-bind="item.attrs"
|
|
21
|
+
@update:model-value="handleChange"
|
|
22
|
+
/>
|
|
23
|
+
<span v-else class="suna-form__text">{{ formatTextVal }}</span>
|
|
24
|
+
</template>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ElSelect, ElOption } from "element-plus";
|
|
3
|
+
import { useFormField } from "../useFormField";
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
modelValue: { default: undefined },
|
|
7
|
+
item: { type: Object, default: () => ({}) },
|
|
8
|
+
form: { type: Object, default: () => ({}) },
|
|
9
|
+
});
|
|
10
|
+
const emit = defineEmits(["update:modelValue", "change"]);
|
|
11
|
+
|
|
12
|
+
const { valueTmp, showText, formatTextVal, handleChange, blur, focus } =
|
|
13
|
+
useFormField(props, emit);
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<ElSelect
|
|
18
|
+
v-if="!showText"
|
|
19
|
+
:model-value="valueTmp"
|
|
20
|
+
v-bind="item.attrs"
|
|
21
|
+
@update:model-value="handleChange"
|
|
22
|
+
@blur="blur"
|
|
23
|
+
@focus="focus"
|
|
24
|
+
>
|
|
25
|
+
<ElOption
|
|
26
|
+
v-for="(opt, i) in (item.options || [])"
|
|
27
|
+
:key="opt[item.optionProps?.value || 'value'] ?? i"
|
|
28
|
+
:label="opt[item.optionProps?.label || 'label']"
|
|
29
|
+
:value="opt[item.optionProps?.value || 'value']"
|
|
30
|
+
:disabled="opt.disabled"
|
|
31
|
+
/>
|
|
32
|
+
</ElSelect>
|
|
33
|
+
<span v-else class="suna-form__text">{{ formatTextVal }}</span>
|
|
34
|
+
</template>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ElSwitch } from "element-plus";
|
|
3
|
+
import { useFormField } from "../useFormField";
|
|
4
|
+
|
|
5
|
+
const props = defineProps({
|
|
6
|
+
modelValue: { default: undefined },
|
|
7
|
+
item: { type: Object, default: () => ({}) },
|
|
8
|
+
form: { type: Object, default: () => ({}) },
|
|
9
|
+
});
|
|
10
|
+
const emit = defineEmits(["update:modelValue", "change"]);
|
|
11
|
+
|
|
12
|
+
const { valueTmp, showText, formatTextVal, handleChange } =
|
|
13
|
+
useFormField(props, emit);
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<ElSwitch
|
|
18
|
+
v-if="!showText"
|
|
19
|
+
:model-value="valueTmp"
|
|
20
|
+
v-bind="item.attrs"
|
|
21
|
+
@update:model-value="handleChange"
|
|
22
|
+
/>
|
|
23
|
+
<span v-else class="suna-form__text">{{ formatTextVal }}</span>
|
|
24
|
+
</template>
|