From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目
---
src/components/Form/src/Form.vue | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 307 insertions(+), 0 deletions(-)
diff --git a/src/components/Form/src/Form.vue b/src/components/Form/src/Form.vue
new file mode 100644
index 0000000..3acc10a
--- /dev/null
+++ b/src/components/Form/src/Form.vue
@@ -0,0 +1,307 @@
+<script lang="tsx">
+import { computed, defineComponent, onMounted, PropType, ref, unref, watch } from 'vue'
+import { ElCol, ElForm, ElFormItem, ElRow, ElTooltip } from 'element-plus'
+import { componentMap } from './componentMap'
+import { propTypes } from '@/utils/propTypes'
+import { getSlot } from '@/utils/tsxHelper'
+import {
+ initModel,
+ setComponentProps,
+ setFormItemSlots,
+ setGridProp,
+ setItemComponentSlots,
+ setTextPlaceholder
+} from './helper'
+import { useRenderSelect } from './components/useRenderSelect'
+import { useRenderRadio } from './components/useRenderRadio'
+import { useRenderCheckbox } from './components/useRenderCheckbox'
+import { useDesign } from '@/hooks/web/useDesign'
+import { findIndex } from '@/utils'
+import { set } from 'lodash-es'
+import { FormProps } from './types'
+import { Icon } from '@/components/Icon'
+import { FormSchema, FormSetPropsType } from '@/types/form'
+
+const { getPrefixCls } = useDesign()
+
+const prefixCls = getPrefixCls('form')
+
+export default defineComponent({
+ // eslint-disable-next-line vue/no-reserved-component-names
+ name: 'Form',
+ props: {
+ // 鐢熸垚Form鐨勫竷灞�缁撴瀯鏁扮粍
+ schema: {
+ type: Array as PropType<FormSchema[]>,
+ default: () => []
+ },
+ // 鏄惁闇�瑕佹爡鏍煎竷灞�
+ // update by 鑺嬭壙锛氬皢 true 鏀规垚 false锛屽洜涓洪」鐩洿甯哥敤杩欑鏂瑰紡
+ isCol: propTypes.bool.def(false),
+ // 琛ㄥ崟鏁版嵁瀵硅薄
+ model: {
+ type: Object as PropType<Recordable>,
+ default: () => ({})
+ },
+ // 鏄惁鑷姩璁剧疆placeholder
+ autoSetPlaceholder: propTypes.bool.def(true),
+ // 鏄惁鑷畾涔夊唴瀹�
+ isCustom: propTypes.bool.def(false),
+ // 琛ㄥ崟label瀹藉害
+ labelWidth: propTypes.oneOfType([String, Number]).def('auto'),
+ // 鏄惁 loading 鏁版嵁涓� add by 鑺嬭壙
+ vLoading: propTypes.bool.def(false)
+ },
+ emits: ['register'],
+ setup(props, { slots, expose, emit }) {
+ // element form 瀹炰緥
+ const elFormRef = ref<ComponentRef<typeof ElForm>>()
+
+ // useForm浼犲叆鐨刾rops
+ const outsideProps = ref<FormProps>({})
+
+ const mergeProps = ref<FormProps>({})
+
+ const getProps = computed(() => {
+ const propsObj = { ...props }
+ Object.assign(propsObj, unref(mergeProps))
+ return propsObj
+ })
+
+ // 琛ㄥ崟鏁版嵁
+ const formModel = ref<Recordable>({})
+
+ onMounted(() => {
+ emit('register', unref(elFormRef)?.$parent, unref(elFormRef))
+ })
+
+ // 瀵硅〃鍗曡祴鍊�
+ const setValues = (data: Recordable = {}) => {
+ formModel.value = Object.assign(unref(formModel), data)
+ }
+
+ const setProps = (props: FormProps = {}) => {
+ mergeProps.value = Object.assign(unref(mergeProps), props)
+ outsideProps.value = props
+ }
+
+ const delSchema = (field: string) => {
+ const { schema } = unref(getProps)
+
+ const index = findIndex(schema, (v: FormSchema) => v.field === field)
+ if (index > -1) {
+ schema.splice(index, 1)
+ }
+ }
+
+ const addSchema = (formSchema: FormSchema, index?: number) => {
+ const { schema } = unref(getProps)
+ if (index !== void 0) {
+ schema.splice(index, 0, formSchema)
+ return
+ }
+ schema.push(formSchema)
+ }
+
+ const setSchema = (schemaProps: FormSetPropsType[]) => {
+ const { schema } = unref(getProps)
+ for (const v of schema) {
+ for (const item of schemaProps) {
+ if (v.field === item.field) {
+ set(v, item.path, item.value)
+ }
+ }
+ }
+ }
+
+ const getElFormRef = (): ComponentRef<typeof ElForm> => {
+ return unref(elFormRef) as ComponentRef<typeof ElForm>
+ }
+
+ expose({
+ setValues,
+ formModel,
+ setProps,
+ delSchema,
+ addSchema,
+ setSchema,
+ getElFormRef
+ })
+
+ // 鐩戝惉琛ㄥ崟缁撴瀯鍖栨暟缁勶紝閲嶆柊鐢熸垚formModel
+ watch(
+ () => unref(getProps).schema,
+ (schema = []) => {
+ formModel.value = initModel(schema, unref(formModel))
+ },
+ {
+ immediate: true,
+ deep: true
+ }
+ )
+
+ // 娓叉煋鍖呰9鏍囩锛屾槸鍚︿娇鐢ㄦ爡鏍煎竷灞�
+ const renderWrap = () => {
+ const { isCol } = unref(getProps)
+ const content = isCol ? (
+ <ElRow gutter={20}>{renderFormItemWrap()}</ElRow>
+ ) : (
+ renderFormItemWrap()
+ )
+ return content
+ }
+
+ // 鏄惁瑕佹覆鏌揺l-col
+ const renderFormItemWrap = () => {
+ // hidden灞炴�ц〃绀洪殣钘忥紝涓嶅仛娓叉煋
+ const { schema = [], isCol } = unref(getProps)
+
+ return schema
+ .filter((v) => !v.hidden)
+ .map((item) => {
+ // 濡傛灉鏄� Divider 缁勪欢锛岄渶瑕佽嚜宸卞崰鐢ㄤ竴琛�
+ const isDivider = item.component === 'Divider'
+ const Com = componentMap['Divider'] as ReturnType<typeof defineComponent>
+ return isDivider ? (
+ <Com {...{ contentPosition: 'left', ...item.componentProps }}>{item?.label}</Com>
+ ) : isCol ? (
+ // 濡傛灉闇�瑕佹爡鏍硷紝闇�瑕佸寘瑁� ElCol
+ <ElCol {...setGridProp(item.colProps)}>{renderFormItem(item)}</ElCol>
+ ) : (
+ renderFormItem(item)
+ )
+ })
+ }
+
+ // 娓叉煋formItem
+ const renderFormItem = (item: FormSchema) => {
+ // 鍗曠嫭缁欏彧鏈塷ptions灞炴�х殑缁勪欢鍋氬垽鏂�
+ const notRenderOptions = ['SelectV2', 'Cascader', 'Transfer']
+ const slotsMap: Recordable = {
+ ...setItemComponentSlots(slots, item?.componentProps?.slots, item.field)
+ }
+ if (
+ item?.component !== 'SelectV2' &&
+ item?.component !== 'Cascader' &&
+ item?.componentProps?.options
+ ) {
+ slotsMap.default = () => renderOptions(item)
+ }
+
+ const formItemSlots: Recordable = setFormItemSlots(slots, item.field)
+ // 濡傛灉鏈� labelMessage锛岃嚜鍔ㄤ娇鐢ㄦ彃妲芥覆鏌�
+ if (item?.labelMessage) {
+ formItemSlots.label = () => {
+ return (
+ <>
+ <span>{item.label}</span>
+ <ElTooltip placement="right" raw-content>
+ {{
+ content: () => <span v-dompurify-html={item.labelMessage}></span>,
+ default: () => (
+ <Icon
+ icon="ep:warning"
+ size={16}
+ color="var(--el-color-primary)"
+ class="relative top-1px ml-2px"
+ ></Icon>
+ )
+ }}
+ </ElTooltip>
+ </>
+ )
+ }
+ }
+ return (
+ <ElFormItem {...(item.formItemProps || {})} prop={item.field} label={item.label || ''}>
+ {{
+ ...formItemSlots,
+ default: () => {
+ const Com = componentMap[item.component as string] as ReturnType<
+ typeof defineComponent
+ >
+
+ const { autoSetPlaceholder } = unref(getProps)
+
+ return slots[item.field] ? (
+ getSlot(slots, item.field, formModel.value)
+ ) : (
+ <Com
+ vModel={formModel.value[item.field]}
+ {...(autoSetPlaceholder && setTextPlaceholder(item))}
+ {...setComponentProps(item)}
+ style={item.componentProps?.style}
+ {...(notRenderOptions.includes(item?.component as string) &&
+ item?.componentProps?.options
+ ? { options: item?.componentProps?.options || [] }
+ : {})}
+ >
+ {{ ...slotsMap }}
+ </Com>
+ )
+ }
+ }}
+ </ElFormItem>
+ )
+ }
+
+ // 娓叉煋options
+ const renderOptions = (item: FormSchema) => {
+ switch (item.component) {
+ case 'Select':
+ case 'SelectV2':
+ const { renderSelectOptions } = useRenderSelect(slots)
+ return renderSelectOptions(item)
+ case 'Radio':
+ case 'RadioButton':
+ const { renderRadioOptions } = useRenderRadio()
+ return renderRadioOptions(item)
+ case 'Checkbox':
+ case 'CheckboxButton':
+ const { renderCheckboxOptions } = useRenderCheckbox()
+ return renderCheckboxOptions(item)
+ default:
+ break
+ }
+ }
+
+ // 杩囨护浼犲叆Form缁勪欢鐨勫睘鎬�
+ const getFormBindValue = () => {
+ // 閬垮厤鍦ㄦ爣绛句笂鍑虹幇澶氫綑鐨勫睘鎬�
+ const delKeys = ['schema', 'isCol', 'autoSetPlaceholder', 'isCustom', 'model']
+ const props = { ...unref(getProps) }
+ for (const key in props) {
+ if (delKeys.indexOf(key) !== -1) {
+ delete props[key]
+ }
+ }
+ return props
+ }
+
+ return () => (
+ <ElForm
+ ref={elFormRef}
+ {...getFormBindValue()}
+ model={props.isCustom ? props.model : formModel}
+ class={prefixCls}
+ v-loading={props.vLoading}
+ >
+ {{
+ // 濡傛灉闇�瑕佽嚜瀹氫箟锛屽氨浠�涔堥兘涓嶆覆鏌擄紝鑰屾槸鎻愪緵榛樿鎻掓Ы
+ default: () => {
+ const { isCustom } = unref(getProps)
+ return isCustom ? getSlot(slots, 'default') : renderWrap()
+ }
+ }}
+ </ElForm>
+ )
+ }
+})
+</script>
+
+<style lang="scss" scoped>
+.#{$elNamespace}-form.#{$namespace}-form .#{$elNamespace}-row {
+ margin-right: 0 !important;
+ margin-left: 0 !important;
+}
+</style>
--
Gitblit v1.8.0