src/components/Form/src/components/FormItem.vue
<script lang="tsx">
import { NamePath, ValidateOptions } from 'ant-design-vue/lib/form/interface';
import type { PropType, Ref } from 'vue';
import type { FormActionType, FormProps } from '../types/form';
import type { FormSchema } from '../types/form';
import type { ValidationRule } from 'ant-design-vue/lib/form/Form';
import type { TableActionType } from '/@/components/Table';
import { defineComponent, computed, unref, toRefs } from 'vue';
import { Form, Col, Divider } from 'ant-design-vue';
import { componentMap } from '../componentMap';
import { BasicHelp } from '/@/components/Basic';
import { isBoolean, isFunction, isNull } from '/@/utils/is';
import { getSlot } from '/@/utils/helper/tsxHelper';
import { createPlaceholderMessage, setComponentRuleType } from '../helper';
import { upperFirst, cloneDeep } from 'lodash-es';
import { useItemLabelWidth } from '../hooks/useLabelWidth';
import { useI18n } from '/@/hooks/web/useI18n';
import { useAppInject } from '/@/hooks/web/useAppInject';
export default defineComponent({
name: 'BasicFormItem',
inheritAttrs: false,
props: {
schema: {
type: Object as PropType<FormSchema>,
default: () => ({}),
},
formProps: {
type: Object as PropType<FormProps>,
default: () => ({}),
},
allDefaultValues: {
type: Object as PropType<Recordable>,
default: () => ({}),
},
formModel: {
type: Object as PropType<Recordable>,
default: () => ({}),
},
setFormModel: {
type: Function as PropType<(key: string, value: any) => void>,
default: null,
},
validateFields: {
type: Function as PropType<(nameList?: NamePath[] | undefined, options?: ValidateOptions) => Promise<any>>,
default: null,
},
tableAction: {
type: Object as PropType<TableActionType>,
},
formActionType: {
type: Object as PropType<FormActionType>,
},
},
setup(props, { slots }) {
const { t } = useI18n();
const { schema, formProps } = toRefs(props) as {
schema: Ref<FormSchema>;
formProps: Ref<FormProps>;
};
const itemLabelWidthProp = useItemLabelWidth(schema, formProps);
const getValues = computed(() => {
const { allDefaultValues, formModel, schema } = props;
const { mergeDynamicData } = props.formProps;
return {
field: schema.field,
model: formModel,
values: {
...mergeDynamicData,
...allDefaultValues,
...formModel,
} as Recordable,
schema: schema,
};
});
const getComponentsProps = computed(() => {
const { schema, tableAction, formModel, formActionType } = props;
let { componentProps = {} } = schema;
if (isFunction(componentProps)) {
componentProps = componentProps({ schema, tableAction, formModel, formActionType }) ?? {};
}
if (schema.component === 'Divider') {
//update-begin---author:wangshuai---date:2023-09-22---for:【QQYUN-6603】分割线标题位置显示不正确---
componentProps = Object.assign({ type: 'horizontal',orientation:'left', plain: true, }, componentProps);
//update-end---author:wangshuai---date:2023-09-22---for:【QQYUN-6603】分割线标题位置显示不正确---
}
return componentProps as Recordable;
});
const getDisable = computed(() => {
const { disabled: globDisabled } = props.formProps;
const { dynamicDisabled } = props.schema;
const { disabled: itemDisabled = false } = unref(getComponentsProps);
let disabled = !!globDisabled || itemDisabled;
if (isBoolean(dynamicDisabled)) {
disabled = dynamicDisabled;
}
if (isFunction(dynamicDisabled)) {
disabled = dynamicDisabled(unref(getValues));
}
return disabled;
});
// update-begin--author:liaozhiyang---date:20240308---for:【QQYUN-8377】formSchema props支持动态修改
const getDynamicPropsValue = computed(() => {
const { dynamicPropsVal, dynamicPropskey } = props.schema;
if (dynamicPropskey == null) {
return null;
} else {
const { [dynamicPropskey]: itemValue } = unref(getComponentsProps);
let value = itemValue;
if (isFunction(dynamicPropsVal)) {
value = dynamicPropsVal(unref(getValues));
return value;
}
}
});
// update-end--author:liaozhiyang---date:20240308---for:【QQYUN-8377】formSchema props支持动态修改
function getShow(): { isShow: boolean; isIfShow: boolean } {
const { show, ifShow } = props.schema;
const { showAdvancedButton } = props.formProps;
const itemIsAdvanced = showAdvancedButton ? (isBoolean(props.schema.isAdvanced) ? props.schema.isAdvanced : true) : true;
let isShow = true;
let isIfShow = true;
if (isBoolean(show)) {
isShow = show;
}
if (isBoolean(ifShow)) {
isIfShow = ifShow;
}
if (isFunction(show)) {
isShow = show(unref(getValues));
}
if (isFunction(ifShow)) {
isIfShow = ifShow(unref(getValues));
}
isShow = isShow && itemIsAdvanced;
return { isShow, isIfShow };
}
function handleRules(): ValidationRule[] {
const { rules: defRules = [], component, rulesMessageJoinLabel, label, dynamicRules, required } = props.schema;
if (isFunction(dynamicRules)) {
return dynamicRules(unref(getValues)) as ValidationRule[];
}
let rules: ValidationRule[] = cloneDeep(defRules) as ValidationRule[];
const { rulesMessageJoinLabel: globalRulesMessageJoinLabel } = props.formProps;
const joinLabel = Reflect.has(props.schema, 'rulesMessageJoinLabel') ? rulesMessageJoinLabel : globalRulesMessageJoinLabel;
const defaultMsg = createPlaceholderMessage(component) + `${joinLabel ? label : ''}`;
function validator(rule: any, value: any) {
const msg = rule.message || defaultMsg;
if (value === undefined || isNull(value)) {
// 空值
return Promise.reject(msg);
} else if (Array.isArray(value) && value.length === 0) {
// 数组类型
return Promise.reject(msg);
} else if (typeof value === 'string' && value.trim() === '') {
// 空字符串
return Promise.reject(msg);
} else if (
typeof value === 'object' &&
Reflect.has(value, 'checked') &&
Reflect.has(value, 'halfChecked') &&
Array.isArray(value.checked) &&
Array.isArray(value.halfChecked) &&
value.checked.length === 0 &&
value.halfChecked.length === 0
) {
// 非关联选择的tree组件
return Promise.reject(msg);
}
return Promise.resolve();
}
const getRequired = isFunction(required) ? required(unref(getValues)) : required;
if ((!rules || rules.length === 0) && getRequired) {
rules = [{ required: getRequired, validator }];
}
const requiredRuleIndex: number = rules.findIndex((rule) => Reflect.has(rule, 'required') && !Reflect.has(rule, 'validator'));
if (requiredRuleIndex !== -1) {
const rule = rules[requiredRuleIndex];
const { isShow } = getShow();
if (!isShow) {
rule.required = false;
}
if (component) {
//update-begin---author:wangshuai---date:2024-02-01---for:【QQYUN-8176】编辑表单中,校验必填时,如果组件是ApiSelect,打开编辑页面时,即使该字段有值,也会提示请选择---
//https://github.com/vbenjs/vue-vben-admin/pull/3082 github修复原文
/*if (!Reflect.has(rule, 'type')) {
rule.type = component === 'InputNumber' ? 'number' : 'string';
}*/
//update-end---author:wangshuai---date:2024-02-01---for:【QQYUN-8176】编辑表单中,校验必填时,如果组件是ApiSelect,打开编辑页面时,即使该字段有值,也会提示请选择---
rule.message = rule.message || defaultMsg;
if (component.includes('Input') || component.includes('Textarea')) {
rule.whitespace = true;
}
const valueFormat = unref(getComponentsProps)?.valueFormat;
setComponentRuleType(rule, component, valueFormat);
}
}
// Maximum input length rule check
const characterInx = rules.findIndex((val) => val.max);
if (characterInx !== -1 && !rules[characterInx].validator) {
rules[characterInx].message = rules[characterInx].message || t('component.form.maxTip', [rules[characterInx].max] as Recordable);
}
// update-begin--author:liaozhiyang---date:20241226---for:【QQYUN-7495】pattern由字符串改成正则传递给antd(因使用InputNumber时发现正则无效)
rules.forEach((item) => {
if (typeof item.pattern === 'string') {
try {
const reg = new Function('item', `return ${item.pattern}`)(item);
if (Object.prototype.toString.call(reg) === '[object RegExp]') {
item.pattern = reg;
} else {
item.pattern = new RegExp(item.pattern);
}
} catch (error) {
item.pattern = new RegExp(item.pattern);
}
}
});
// update-end--author:liaozhiyang---date:20231226---for:【QQYUN-7495】pattern由字符串改成正则传递给antd(因使用InputNumber时发现正则无效)
return rules;
}
function renderComponent() {
const { renderComponentContent, component, field, changeEvent = 'change', valueField, componentProps } = props.schema;
const isCheck = component && ['Switch', 'Checkbox'].includes(component);
// update-begin--author:liaozhiyang---date:20231013---for:【QQYUN-6679】input去空格
let isTrim = false;
if (component === 'Input' && componentProps && componentProps.trim) {
isTrim = true;
}
// update-end--author:liaozhiyang---date:20231013---for:【QQYUN-6679】input去空格
const eventKey = `on${upperFirst(changeEvent)}`;
// update-begin--author:liaozhiyang---date:20230922---for:【issues/752】表单校验dynamicRules 无法 使用失去焦点后校验 trigger: 'blur'
const on = {
[eventKey]: (...args: Nullable<Recordable>[]) => {
const [e] = args;
if (propsData[eventKey]) {
propsData[eventKey](...args);
}
const target = e ? e.target : null;
// update-begin--author:liaozhiyang---date:20231013---for:【QQYUN-6679】input去空格
let value;
if (target) {
if (isCheck) {
value = target.checked;
} else {
value = isTrim ? target.value.trim() : target.value;
}
} else {
value = e;
}
// update-end--author:liaozhiyang---date:20231013---for:【QQYUN-6679】input去空格
props.setFormModel(field, value);
//props.validateFields([field], { triggerName: 'change' }).catch((_) => {});
},
// onBlur: () => {
// props.validateFields([field], { triggerName: 'blur' }).catch((_) => {});
// },
};
// update-end--author:liaozhiyang---date:20230922---for:【issues/752】表单校验dynamicRules 无法 使用失去焦点后校验 trigger: 'blur'
const Comp = componentMap.get(component) as ReturnType<typeof defineComponent>;
const { autoSetPlaceHolder, size } = props.formProps;
const propsData: Recordable = {
allowClear: true,
getPopupContainer: (trigger: Element) => {
return trigger?.parentNode;
},
size,
...unref(getComponentsProps),
disabled: unref(getDisable),
};
// update-begin--author:liaozhiyang---date:20240308---for:【QQYUN-8377】formSchema props支持动态修改
const dynamicPropskey = props.schema.dynamicPropskey;
if (dynamicPropskey) {
propsData[dynamicPropskey] = unref(getDynamicPropsValue);
}
// update-end--author:liaozhiyang---date:20240308---for:【QQYUN-8377】formSchema props支持动态修改
const isCreatePlaceholder = !propsData.disabled && autoSetPlaceHolder;
// RangePicker place是一个数组
if (isCreatePlaceholder && component !== 'RangePicker' && component) {
//自动设置placeholder
propsData.placeholder = unref(getComponentsProps)?.placeholder || createPlaceholderMessage(component) + props.schema.label;
}
propsData.codeField = field;
propsData.formValues = unref(getValues);
const bindValue: Recordable = {
[valueField || (isCheck ? 'checked' : 'value')]: props.formModel[field],
};
const compAttr: Recordable = {
...propsData,
...on,
...bindValue,
};
if (!renderComponentContent) {
return <Comp {...compAttr} />;
}
const compSlot = isFunction(renderComponentContent)
? { ...renderComponentContent(unref(getValues)) }
: {
default: () => renderComponentContent,
};
return <Comp {...compAttr}>{compSlot}</Comp>;
}
/**
*渲染Label
* @updateBy:zyf
*/
function renderLabelHelpMessage() {
//update-begin-author:taoyan date:2022-9-7 for: VUEN-2061【样式】online表单超出4个 .. 省略显示
//label宽度支持自定义
const { label, helpMessage, helpComponentProps, subLabel, labelLength } = props.schema;
let showLabel: string = label + '';
if (labelLength && showLabel.length > 4) {
showLabel = showLabel.substr(0, labelLength);
}
const titleObj = { title: label };
const renderLabel = subLabel ? (
<span>
{label} <span class="text-secondary">{subLabel}</span>
</span>
) : labelLength ? (
<label {...titleObj}>{showLabel}</label>
) : (
label
);
//update-end-author:taoyan date:2022-9-7 for: VUEN-2061【样式】online表单超出4个 .. 省略显示
const getHelpMessage = isFunction(helpMessage) ? helpMessage(unref(getValues)) : helpMessage;
if (!getHelpMessage || (Array.isArray(getHelpMessage) && getHelpMessage.length === 0)) {
return renderLabel;
}
return (
<span>
{renderLabel}
<BasicHelp placement="top" class="mx-1" text={getHelpMessage} {...helpComponentProps} />
</span>
);
}
function renderItem() {
const { itemProps, slot, render, field, suffix, component } = props.schema;
const { labelCol, wrapperCol } = unref(itemLabelWidthProp);
const { colon } = props.formProps;
if (component === 'Divider') {
return (
<Col span={24}>
<Divider {...unref(getComponentsProps)}>{renderLabelHelpMessage()}</Divider>
</Col>
);
} else {
const getContent = () => {
return slot ? getSlot(slots, slot, unref(getValues)) : render ? render(unref(getValues)) : renderComponent();
};
const showSuffix = !!suffix;
const getSuffix = isFunction(suffix) ? suffix(unref(getValues)) : suffix;
return (
<Form.Item
name={field}
colon={colon}
class={{ 'suffix-item': showSuffix }}
{...(itemProps as Recordable)}
label={renderLabelHelpMessage()}
rules={handleRules()}
labelCol={labelCol}
wrapperCol={wrapperCol}
>
<div style="display:flex">
{/* author: sunjianlei for: 【VUEN-744】此处加上 width: 100%; 因为要防止组件宽度超出 FormItem */}
<div style="flex:1; width: 100%;">{getContent()}</div>
{showSuffix && <span class="suffix">{getSuffix}</span>}
</div>
</Form.Item>
);
}
}
return () => {
const { colProps = {}, colSlot, renderColContent, component } = props.schema;
if (!componentMap.has(component)) {
return null;
}
const { baseColProps = {} } = props.formProps;
// update-begin--author:liaozhiyang---date:20230803---for:【issues-641】调整表格搜索表单的span配置无效
const { getIsMobile } = useAppInject();
let realColProps;
realColProps = { ...baseColProps, ...colProps };
if (colProps['span'] && !unref(getIsMobile)) {
['xs', 'sm', 'md', 'lg', 'xl', 'xxl'].forEach((name) => delete realColProps[name]);
}
// update-end--author:liaozhiyang---date:20230803---for:【issues-641】调整表格搜索表单的span配置无效
const { isIfShow, isShow } = getShow();
const values = unref(getValues);
const getContent = () => {
return colSlot ? getSlot(slots, colSlot, values) : renderColContent ? renderColContent(values) : renderItem();
};
return (
isIfShow && (
<Col {...realColProps} v-show={isShow}>
{getContent()}
</Col>
)
);
};
},
});
</script>
src/components/Form/src/types/form.ts
import type { NamePath, RuleObject, ValidateOptions } from 'ant-design-vue/lib/form/interface';
import type { VNode, ComputedRef } from 'vue';
import type { ButtonProps as AntdButtonProps } from '/@/components/Button';
import type { FormItem } from './formItem';
import type { ColEx, ComponentType } from './index';
import type { TableActionType } from '/@/components/Table/src/types/table';
import type { CSSProperties } from 'vue';
import type { RowProps } from 'ant-design-vue/lib/grid/Row';
export type FieldMapToTime = [string, [string, string], string?][];
export type FieldMapToNumber = [string, [string, string]][];
export type Rule = RuleObject & {
trigger?: 'blur' | 'change' | ['change', 'blur'];
};
export interface RenderCallbackParams {
schema: FormSchema;
values: Recordable;
model: Recordable;
field: string;
}
export interface ButtonProps extends AntdButtonProps {
text?: string;
}
export interface FormActionType {
submit: () => Promise<void>;
setFieldsValue: <T>(values: T) => Promise<void>;
resetFields: () => Promise<void>;
getFieldsValue: () => Recordable;
clearValidate: (name?: string | string[]) => Promise<void>;
updateSchema: (data: Partial<FormSchema> | Partial<FormSchema>[]) => Promise<void>;
resetSchema: (data: Partial<FormSchema> | Partial<FormSchema>[]) => Promise<void>;
setProps: (formProps: Partial<FormProps>) => Promise<void>;
getProps: ComputedRef<Partial<FormProps>>;
removeSchemaByFiled: (field: string | string[]) => Promise<void>;
appendSchemaByField: (schema: FormSchema, prefixField: string | undefined, first?: boolean | undefined) => Promise<void>;
validateFields: (nameList?: NamePath[], options?: ValidateOptions) => Promise<any>;
validate: (nameList?: NamePath[]) => Promise<any>;
scrollToField: (name: NamePath, options?: ScrollOptions) => Promise<void>;
}
export type RegisterFn = (formInstance: FormActionType) => void;
export type UseFormReturnType = [RegisterFn, FormActionType];
export interface FormProps {
layout?: 'vertical' | 'inline' | 'horizontal';
// Form value
model?: Recordable;
// The width of all items in the entire form
labelWidth?: number | string;
//alignment
labelAlign?: 'left' | 'right';
//Row configuration for the entire form
rowProps?: RowProps;
// Submit form on reset
submitOnReset?: boolean;
// Col configuration for the entire form
labelCol?: Partial<ColEx> | null;
// Col configuration for the entire form
wrapperCol?: Partial<ColEx> | null;
// General row style
baseRowStyle?: CSSProperties;
// General col configuration
baseColProps?: Partial<ColEx>;
// Form configuration rules
schemas?: FormSchema[];
// Function values used to merge into dynamic control form items
mergeDynamicData?: Recordable;
// Compact mode for search forms
compact?: boolean;
// Blank line span
emptySpan?: number | Partial<ColEx>;
// Internal component size of the form
size?: 'default' | 'small' | 'large';
// Whether to disable
disabled?: boolean;
// Time interval fields are mapped into multiple
fieldMapToTime?: FieldMapToTime;
// number interval fields are mapped into multiple
fieldMapToNumber?: FieldMapToNumber;
// Placeholder is set automatically
autoSetPlaceHolder?: boolean;
// Auto submit on press enter on input
autoSubmitOnEnter?: boolean;
// Check whether the information is added to the label
rulesMessageJoinLabel?: boolean;
// 是否显示展开收起按钮
showAdvancedButton?: boolean;
// Whether to focus on the first input box, only works when the first form item is input
autoFocusFirstItem?: boolean;
// 【jeecg】如果 showAdvancedButton 为 true,超过指定列数默认折叠,默认为3
autoAdvancedCol?: number;
// 如果 showAdvancedButton 为 true,超过指定行数行默认折叠
autoAdvancedLine?: number;
// 折叠时始终保持显示的行数
alwaysShowLines?: number;
// Whether to show the operation button
showActionButtonGroup?: boolean;
// Reset button configuration
resetButtonOptions?: Partial<ButtonProps>;
// Confirm button configuration
submitButtonOptions?: Partial<ButtonProps>;
// Operation column configuration
actionColOptions?: Partial<ColEx>;
// Show reset button
showResetButton?: boolean;
// Show confirmation button
showSubmitButton?: boolean;
resetFunc?: () => Promise<void>;
submitFunc?: () => Promise<void>;
transformDateFunc?: (date: any) => string;
colon?: boolean;
}
export interface FormSchema {
// Field name
field: string;
// Event name triggered by internal value change, default change
changeEvent?: string;
// Variable name bound to v-model Default value
valueField?: string;
// Label name
label: string | VNode;
// Auxiliary text
subLabel?: string;
// Help text on the right side of the text
helpMessage?: string | string[] | ((renderCallbackParams: RenderCallbackParams) => string | string[]);
// BaseHelp component props
helpComponentProps?: Partial<HelpComponentProps>;
// Label width, if it is passed, the labelCol and WrapperCol configured by itemProps will be invalid
labelWidth?: string | number;
// Disable the adjustment of labelWidth with global settings of formModel, and manually set labelCol and wrapperCol by yourself
disabledLabelWidth?: boolean;
// render component
component: ComponentType;
// Component parameters
componentProps?:
| ((opt: { schema: FormSchema; tableAction: TableActionType; formActionType: FormActionType; formModel: Recordable }) => Recordable)
| object;
// Required
required?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean);
suffix?: string | number | ((values: RenderCallbackParams) => string | number);
// Validation rules
rules?: Rule[];
// Check whether the information is added to the label
rulesMessageJoinLabel?: boolean;
// Reference formModelItem
itemProps?: Partial<FormItem>;
// col configuration outside formModelItem
colProps?: Partial<ColEx>;
// 默认值
defaultValue?: any;
isAdvanced?: boolean;
// Matching details components
span?: number;
ifShow?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean);
show?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean);
// Render the content in the form-item tag
render?: (renderCallbackParams: RenderCallbackParams) => VNode | VNode[] | string;
// Rendering col content requires outer wrapper form-item
renderColContent?: (renderCallbackParams: RenderCallbackParams) => VNode | VNode[] | string;
renderComponentContent?: ((renderCallbackParams: RenderCallbackParams) => any) | VNode | VNode[] | string;
// Custom slot, in from-item
slot?: string;
// Custom slot, similar to renderColContent
colSlot?: string;
dynamicDisabled?: boolean | ((renderCallbackParams: RenderCallbackParams) => boolean);
dynamicRules?: (renderCallbackParams: RenderCallbackParams) => Rule[];
// update-begin--author:liaozhiyang---date:20240308---for:【QQYUN-8377】formSchema props支持动态修改
// 设置组件props的key
dynamicPropskey?: string;
dynamicPropsVal?: ((renderCallbackParams: RenderCallbackParams) => any);
// update-end--author:liaozhiyang---date:20240308---for:【QQYUN-8377】formSchema props支持动态修改
// 这个属性自定义的 用于自定义的业务 比如在表单打开的时候修改表单的禁用状态,但是又不能重写componentProps,因为他的内容太多了,所以使用dynamicDisabled和buss实现
buss?: any;
//label字数控制(label宽度)
labelLength?: number
}
export interface HelpComponentProps {
maxWidth: string;
// Whether to display the serial number
showIndex: boolean;
// Text list
text: any;
// colour
color: string;
// font size
fontSize: string;
icon: string;
absolute: boolean;
// Positioning
position: any;
}
src/views/demo/jeecg/JeecgComponents.vue
<template>
<BasicForm
ref="formElRef"
:class="'jee-select-demo-form'"
:labelCol="{ span: 6 }"
:wrapperCol="{ span: 14 }"
:showResetButton="false"
:showSubmitButton="false"
:schemas="schemas"
:actionColOptions="{ span: 24 }"
@submit="handleSubmit"
@reset="handleReset"
style="height: 100%"
>
<template #jAreaLinkage="{ model, field }">
<JAreaLinkage v-model:value="model[field]" :showArea="true" :showAll="false" />
</template>
<template #jAreaLinkage1="{ model, field }">
<JAreaLinkage :disabled="isDisabledAuth(['demo.dbarray'])" v-model:value="model[field]" :showArea="true" :showAll="false" />
</template>
<template #JPopup="{ model, field }">
<JPopup v-model:value="model[field]" :formElRef="formElRef" code="report_user" :fieldConfig="[{ source: 'username', target: 'pop1' }]" />
</template>
<template #JAreaSelect="{ model, field }">
<JAreaSelect v-model:value="model[field]" />
</template>
<template #JCheckbox="{ model, field }">
<JCheckbox v-model:value="model[field]" dictCode="remindMode" />
</template>
<template #JInput="{ model, field }">
<JInput v-model:value="model[field]" :type="model['jinputtype']" />
</template>
<template #dargVerify="{ model, field }">
<BasicDragVerify v-model:value="model[field]" />
</template>
<template #superQuery="{ model, field }">
<super-query :config="superQueryConfig" @search="(value)=>handleSuperQuery(value, model, field)"/>
</template>
</BasicForm>
</template>
<script lang="ts">
import { computed, defineComponent, unref, ref } from 'vue';
import { BasicForm, ApiSelect, JAreaLinkage, JPopup, JAreaSelect, FormActionType, JCheckbox, JInput, JEllipsis } from '/@/components/Form';
import { useMessage } from '/@/hooks/web/useMessage';
import { optionsListApi } from '/@/api/demo/select';
import { useDebounceFn } from '@vueuse/core';
import { schemas } from './jeecgComponents.data';
import { usePermission } from '/@/hooks/web/usePermission';
import { BasicDragVerify } from '/@/components/Verify';
export default defineComponent({
components: {
BasicForm,
ApiSelect,
JAreaLinkage,
JPopup,
JAreaSelect,
JCheckbox,
JInput,
JEllipsis,
BasicDragVerify,
},
name: 'JeecgComponents',
setup() {
const { isDisabledAuth } = usePermission();
const check = ref(null);
const formElRef = ref<Nullable<FormActionType>>(null);
const { createMessage } = useMessage();
const keyword = ref<string>('');
const submitButtonOptions = ref({
text: '确定',
});
const searchParams = computed<Recordable>(() => {
return { keyword: unref(keyword) };
});
function onSearch(value: string) {
keyword.value = value;
}
const superQueryConfig = {
name:{ title: "名称", view: "text", type: "string", order: 1 },
birthday:{ title: "生日", view: "date", type: "string", order: 2 },
age:{ title: "年龄", view: "number", type: "number", order: 4 },
sex:{ title: "性别", view: "list", type: "string", dictCode: "sex", order: 5 },
bpmStatus:{ title: "流程状态", view: "list_multi", type: "string", dictCode: "bpm_status", order: 6 },
}
function handleSuperQuery(value, model, field){
if(value){
let str = decodeURI(value.superQueryParams)
console.log(str)
model[field] = str
}
}
return {
schemas,
formElRef,
isDisabledAuth,
optionsListApi,
submitButtonOptions,
onSearch: useDebounceFn(onSearch, 300),
searchParams,
superQueryConfig,
handleSuperQuery,
handleReset: () => {
keyword.value = '';
},
handleSubmit: (values: any) => {
console.log('values:', values);
createMessage.success('click search,values:' + JSON.stringify(values));
},
check,
};
},
});
</script>
<style lang="less" scoped>
/**update-begin-author:taoyan date:20220324 for: VUEN-351【vue3】展示不全*/
.jee-select-demo-form .ant-col-5 {
flex: 0 0 159px;
max-width: 159px;
}
/**update-end-author:taoyan date:20220324 for: VUEN-351【vue3】展示不全*/
</style>
src/views/demo/jeecg/jeecgComponents.data.ts
import { FormSchema, JCronValidator } from '/@/components/Form';
import { usePermission } from '/@/hooks/web/usePermission';
const { isDisabledAuth } = usePermission();
export const schemas: FormSchema[] = [
{
field: 'jdst',
component: 'JDictSelectTag',
label: '性别下拉',
helpMessage: ['component模式'],
componentProps: {
dictCode: 'sex',
},
colProps: {
span: 12,
},
},
{
field: 'jdst',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
{
field: 'jdst1',
component: 'JDictSelectTag',
label: '性别选择',
helpMessage: ['component模式'],
componentProps: {
dictCode: 'sex',
type: 'radioButton',
},
colProps: {
span: 12,
},
},
{
field: 'jdst1',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
{
field: 'jdst2',
component: 'JDictSelectTag',
label: '字典表下拉',
helpMessage: ['component模式'],
componentProps: {
dictCode: 'sys_user,realname,id',
},
colProps: {
span: 12,
},
},
{
field: 'jdst2',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
{
field: 'jdst3',
component: 'JDictSelectTag',
label: '字典表下拉(带条件)',
helpMessage: ['component模式'],
componentProps: {
dictCode: "sys_user,realname,id,username!='admin' order by create_time",
},
colProps: {
span: 12,
},
},
{
field: 'jdst3',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
{
field: 'jsst',
component: 'JSearchSelect',
label: '字典搜索(同步)',
colProps: { span: 12 },
componentProps: {
//dict: "sys_depart,depart_name,id",
dictOptions: [
{
text: '选项一',
value: '1',
},
{
text: '选项二',
value: '2',
},
{
text: '选项三',
value: '3',
},
],
},
},
{
field: 'jsst',
component: 'JEllipsis',
label: '选择值',
colProps: { span: 12 },
},
{
field: 'jsst2',
component: 'JSearchSelect',
label: '字典搜索(异步)',
colProps: { span: 12 },
componentProps: {
dict: 'sys_depart,depart_name,id',
pageSize: 6,
async: true,
},
},
{
field: 'jsst2',
component: 'JEllipsis',
label: '选择值',
colProps: { span: 12 },
},
{
field: 'xldx',
component: 'JDictSelectTag',
label: '字典下拉多选',
colProps: { span: 12 },
componentProps: {
dictCode: 'sex',
mode: 'multiple',
},
},
{
field: 'xldx',
component: 'JEllipsis',
label: '选择值',
colProps: { span: 12 },
},
{
field: 'xldx2',
component: 'JSelectMultiple',
label: '字典下拉多选2',
colProps: { span: 12 },
componentProps: {
dictCode: 'sex',
},
},
{
field: 'xldx2',
component: 'JEllipsis',
label: '选择值',
colProps: { span: 12 },
},
{
field: 'dxxlk',
component: 'JDictSelectTag',
label: '字典下拉单选',
colProps: { span: 12 },
componentProps: {
dictCode: 'sex',
},
},
{
field: 'dxxlk',
component: 'JEllipsis',
label: '选择值',
colProps: { span: 12 },
},
{
label: '可输入下拉',
field: 'selectInput',
component: 'JSelectInput',
componentProps: {
options: [
{ label: '选项一', value: '1' },
{ label: '选项二', value: '2' },
{ label: '选项三', value: '3' },
],
},
colProps: { span: 12 },
},
{
field: 'selectInput',
component: 'JEllipsis',
label: '选择值',
colProps: { span: 12 },
},
{
field: 'depart3',
component: 'JSelectDept',
label: '选择部门—自定义值',
helpMessage: ['component模式'],
componentProps: { showButton: false, rowKey: 'orgCode', primaryKey: 'orgCode' },
colProps: {
span: 12,
},
},
{
field: 'depart3',
component: 'JEllipsis',
label: '选中部门',
colProps: { span: 12 },
},
{
field: 'depart2',
component: 'JSelectDept',
label: '选择部门',
helpMessage: ['component模式'],
componentProps: { showButton: false },
colProps: {
span: 12,
},
},
{
field: 'depart2',
component: 'JEllipsis',
label: '选中部门',
colProps: { span: 12 },
},
{
field: 'user2',
component: 'JSelectUser',
label: '用户选择组件',
helpMessage: ['component模式'],
componentProps: {
labelKey: 'realname',
rowKey: 'id',
showSelected: true,
},
colProps: {
span: 12,
},
},
{
field: 'user2',
component: 'JEllipsis',
label: '选中用户',
colProps: { span: 12 },
},
{
field: 'user3',
component: 'JSelectUserByDept',
label: '部门选择用户',
helpMessage: ['component模式'],
componentProps: {
labelKey: 'realname',
rowKey: 'username',
},
colProps: {
span: 12,
},
},
{
field: 'user3',
component: 'JEllipsis',
label: '选中用户',
colProps: { span: 12 },
},
{
field: 'role2',
component: 'JSelectRole',
label: '角色选择组件',
helpMessage: ['component模式'],
colProps: {
span: 12,
},
},
{
field: 'role2',
component: 'JEllipsis',
label: '选中角色',
colProps: { span: 12 },
},
{
field: 'position2',
component: 'JSelectPosition',
label: '职务选择组件',
helpMessage: ['component模式'],
colProps: { span: 12 },
componentProps: { async: true, showSelectTable: true },
},
{
field: 'position2',
component: 'JEllipsis',
label: '选中职务',
colProps: { span: 12 },
},
{
field: 'checkbox1',
component: 'JCheckbox',
label: 'JCheckbox组件1',
helpMessage: ['component模式'],
defaultValue: '1,2',
componentProps: {
options: [
{ label: '男', value: '1' },
{ label: '女', value: '2' },
],
},
colProps: {
span: 12,
},
},
{
field: 'checkbox1',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
{
field: 'checkbox2',
component: 'Input',
label: 'JCheckbox组件2',
defaultValue: '1',
helpMessage: ['插槽模式'],
slot: 'JCheckbox',
colProps: {
span: 12,
},
},
{
field: 'checkbox2',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
{
field: 'data1',
label: '日期选择',
component: 'DatePicker',
componentProps: {
showTime: true,
valueFormat: 'YYYY-MM-DD HH:mm:ss',
},
colProps: {
span: 12,
},
},
{
field: 'data1',
component: 'JEllipsis',
label: '选中值',
colProps: {
span: 12,
},
},
{
field: 'data2',
label: '年份范围选择',
component: 'RangePicker',
componentProps: {
picker: 'year',
valueFormat: 'YYYY',
},
colProps: {
span: 12,
},
},
{
field: 'data2',
component: 'JEllipsis',
label: '选中值',
colProps: {
span: 12,
},
},
{
field: 'hk',
component: 'Input',
label: '滑块验证码',
helpMessage: ['插槽模式'],
slot: 'dargVerify',
colProps: {
span: 12,
},
},
{
field: 'hk',
component: 'JEllipsis',
label: '选中值',
colProps: {
span: 12,
},
},
{
field: 'JTreeDict',
component: 'JTreeDict',
label: '树字典',
helpMessage: ['component模式'],
colProps: { span: 12 },
},
{
field: 'JTreeDict',
component: 'JEllipsis',
label: '选中值',
colProps: {
span: 12,
},
},
{
field: 'ts',
component: 'JTreeSelect',
label: '下拉树选择',
helpMessage: ['component模式'],
componentProps: {
dict: 'sys_permission,name,id',
pidField: 'parent_id',
hasChildField: 'is_leaf',
converIsLeafVal: 0,
},
colProps: {
span: 12,
},
},
{
field: 'ts',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
{
field: 'ts1',
component: 'JTreeSelect',
label: '下拉树多选',
helpMessage: ['component模式'],
componentProps: {
dict: 'sys_permission,name,id',
pidField: 'parent_id',
hasChildField: 'is_leaf',
converIsLeafVal: 0,
multiple: true,
},
colProps: {
span: 12,
},
},
{
field: 'ts1',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
{
field: 'category',
component: 'JCategorySelect',
label: '分类字典树',
helpMessage: ['component模式'],
defaultValue: '',
componentProps: {
pcode: 'B01',
multiple: true,
},
colProps: {
span: 12,
},
},
{
field: 'category',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
{
field: 'JEasyCron',
component: 'JEasyCron',
label: 'JEasyCron',
helpMessage: ['component模式'],
colProps: { span: 12 },
defaultValue: '* * * * * ? *',
rules: [{ validator: JCronValidator }],
},
{
field: 'JEasyCron',
component: 'JEllipsis',
label: '选择值',
colProps: { span: 12 },
},
{
field: 'JInput',
component: 'JInput',
label: '特殊查询组件',
helpMessage: ['插槽模式'],
slot: 'JInput',
colProps: {
span: 12,
},
},
{
field: 'jinputtype',
component: 'Select',
label: '查询类型',
componentProps: {
options: [
{ value: 'like', label: '模糊(like)' },
{ value: 'ne', label: '不等于(ne)' },
{ value: 'ge', label: '大于等于(ge)' },
{ value: 'le', label: '小于等于(le)' },
],
},
colProps: {
span: 6,
},
},
{
field: 'JInput',
component: 'JEllipsis',
label: '输入值',
colProps: { span: 6 },
},
{
field: 'field1',
component: 'Select',
label: '省市区选择',
helpMessage: ['插槽模式'],
slot: 'jAreaLinkage',
colProps: {
span: 12,
},
defaultValue: ['130000', '130200'],
},
{
field: 'field1',
component: 'JEllipsis',
label: '选中值',
colProps: {
span: 12,
},
},
{
field: 'field0',
component: 'Select',
label: '禁用组件(方式一)',
helpMessage: ['插槽模式'],
slot: 'jAreaLinkage1',
colProps: {
span: 12,
},
defaultValue: ['130000', '130200'],
},
{
field: 'field0',
component: 'JEllipsis',
label: '选中值',
colProps: {
span: 12,
},
},
{
field: 'field2',
component: 'JAreaLinkage',
label: '禁用组件(方式二)',
helpMessage: ['component模式'],
colProps: {
span: 12,
},
dynamicDisabled: ({ values }) => {
console.log(values);
return isDisabledAuth(['demo.dbarray']);
},
defaultValue: ['140000', '140300', '140302'],
},
{
field: 'field2',
component: 'JEllipsis',
label: '选中值',
colProps: {
span: 12,
},
},
{
field: 'pca1',
component: 'JAreaSelect',
label: '省市区级联',
helpMessage: ['component模式'],
defaultValue: '140302',
colProps: {
span: 12,
},
},
{
field: 'pca1',
component: 'JEllipsis',
label: '选中值',
colProps: {
span: 12,
},
},
{
field: 'pop1',
component: 'Input',
label: 'JPopup示例',
helpMessage: ['插槽模式'],
slot: 'JPopup',
colProps: {
span: 12,
},
},
{
field: 'pop1',
component: 'JEllipsis',
label: '选中值',
colProps: {
span: 12,
},
},
{
field: 'JInputPop',
component: 'JInputPop',
label: 'JInputPop',
helpMessage: ['component模式'],
colProps: { span: 12 },
},
{
field: 'JInputPop',
component: 'JEllipsis',
label: '输入值',
colProps: { span: 12 },
},
{
field: 'JTreeDictAsync',
component: 'JTreeDict',
label: '异步JTreeDict',
helpMessage: ['component模式'],
colProps: { span: 12 },
componentProps: { async: true },
},
{
field: 'JTreeDictAsync',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
{
field: 'JSwitch',
component: 'JSwitch',
label: 'JSwitch',
helpMessage: ['component模式'],
colProps: { span: 12 },
},
{
field: 'JSwitch',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
{
field: 'JSwitchSelect',
component: 'JSwitch',
label: 'JSwitchSelect',
helpMessage: ['component模式'],
colProps: { span: 12 },
componentProps: { query: true },
},
{
field: 'JSwitchSelect',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
{
field: 'userSelect2',
component: 'UserSelect',
label: '高级用户选择',
helpMessage: ['component模式'],
colProps: { span: 12 },
},
{
field: 'userSelect2',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
{
field: 'superQuery',
component: 'Input',
label: '高级查询',
helpMessage: ['插槽模式'],
slot: 'superQuery',
colProps: { span: 12 },
},
{
field: 'superQuery',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
{
field: 'pop2',
component: 'JPopupDict',
label: 'JPopupDict示例',
colProps: {
span: 12,
},
componentProps:{
placeholder: '请选择',
dictCode: 'report_user,username,id',
multi: true,
},
},
{
field: 'pop2',
component: 'JEllipsis',
label: '选中值',
colProps: {
span: 12,
},
},
{
field: 'sex',
component: 'JDictSelectTag',
label: '性别(控制下方课程options)',
helpMessage: ['component模式','性别不同,下方课程展示选项不同'],
componentProps: {
dictCode: 'sex',
type: 'radioButton',
onChange: (value) => {
console.log(value);
},
},
colProps: {
span: 12,
},
},
{
field: 'sex',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
{
field: 'course',
component: 'Select',
label: '课程',
dynamicPropskey: 'options',
dynamicPropsVal: ({ model }) => {
let options;
if (model.sex == 1) {
return [
{ value: '0', label: 'java - 男' },
{ value: '1', label: 'vue - 男' },
];
} else if (model.sex == 2) {
return [
{ value: '2', label: '瑜伽 - 女' },
{ value: '3', label: '美甲 - 女' },
];
} else {
return [];
}
},
componentProps: {
disabled: false,
},
colProps: {
span: 12,
},
},
{
field: 'course',
component: 'JEllipsis',
label: '选中值',
colProps: { span: 12 },
},
];