diff --git a/src/components/Button/src/BasicButton.vue b/src/components/Button/src/BasicButton.vue index 9072c56a..17954e57 100644 --- a/src/components/Button/src/BasicButton.vue +++ b/src/components/Button/src/BasicButton.vue @@ -1,11 +1,12 @@ <script lang="ts" setup> import { Button, theme } from 'ant-design-vue' +import type { ComponentOptionsMixin } from 'vue' import { computed, unref } from 'vue' import { buttonProps } from './props' import { useAttrs } from '@/hooks/core/useAttrs' import { Icon } from '@/components/Icon' -defineOptions({ name: 'AButton', extends: Button, indeterminate: false }) +defineOptions({ name: 'AButton', extends: Button as ComponentOptionsMixin, indeterminate: false }) const props = defineProps(buttonProps) const { useToken } = theme const { token } = useToken() diff --git a/src/components/CardList/src/CardList.vue b/src/components/CardList/src/CardList.vue index 3d26a418..7c29f599 100644 --- a/src/components/CardList/src/CardList.vue +++ b/src/components/CardList/src/CardList.vue @@ -93,7 +93,7 @@ function sliderChange(n: number) { fetch() } -async function handleDelete(id) { +async function handleDelete(id: number) { emit('delete', id) } </script> diff --git a/src/components/Cropper/src/CropperAvatar.vue b/src/components/Cropper/src/CropperAvatar.vue index 38214f11..d9fd18c6 100644 --- a/src/components/Cropper/src/CropperAvatar.vue +++ b/src/components/Cropper/src/CropperAvatar.vue @@ -18,7 +18,9 @@ const props = defineProps({ showBtn: { type: Boolean, default: true }, btnProps: { type: Object as PropType<ButtonProps> }, btnText: { type: String, default: '' }, - uploadApi: { type: Function as PropType<({ file, name }) => Promise<void>> }, + uploadApi: { + type: Function as PropType<({ file, name }: { file: Blob; name: string }) => Promise<void>>, + }, size: { type: Number, default: 5 }, }) diff --git a/src/components/FormDesign/src/components/VFormDesign/components/FormItemProps.vue b/src/components/FormDesign/src/components/VFormDesign/components/FormItemProps.vue index 1d4a68d1..9c24cf68 100644 --- a/src/components/FormDesign/src/components/VFormDesign/components/FormItemProps.vue +++ b/src/components/FormDesign/src/components/VFormDesign/components/FormItemProps.vue @@ -3,15 +3,7 @@ --> <script lang="ts" setup> import { computed, watch } from 'vue' -import { - Checkbox, - Col, - Empty, - Form, - FormItem, - Input, - Switch, -} from 'ant-design-vue' +import { Checkbox, Col, Empty, Form, FormItem, Input, Switch } from 'ant-design-vue' import { isArray } from 'lodash-es' import { advanceFormItemColProps, @@ -23,6 +15,8 @@ import { import { useFormDesignState } from '../../../hooks/useFormDesignState' import RuleProps from './RuleProps.vue' +defineOptions({ name: 'FormItemProps' }) + const { formConfig } = useFormDesignState() watch( @@ -31,9 +25,9 @@ watch( if (formConfig.value.currentItem) { formConfig.value.currentItem.itemProps = formConfig.value.currentItem.itemProps || {} formConfig.value.currentItem.itemProps.labelCol - = formConfig.value.currentItem.itemProps.labelCol || {} + = formConfig.value.currentItem.itemProps.labelCol || {} formConfig.value.currentItem.itemProps.wrapperCol - = formConfig.value.currentItem.itemProps.wrapperCol || {} + = formConfig.value.currentItem.itemProps.wrapperCol || {} } }, { deep: true, immediate: true }, diff --git a/src/components/FormDesign/src/components/VFormDesign/components/FormProps.vue b/src/components/FormDesign/src/components/VFormDesign/components/FormProps.vue index 5b9fcb0d..97ce2b63 100644 --- a/src/components/FormDesign/src/components/VFormDesign/components/FormProps.vue +++ b/src/components/FormDesign/src/components/VFormDesign/components/FormProps.vue @@ -2,6 +2,7 @@ * @Description: 右侧属性面板控件 表单属性面板 --> <script lang="ts" setup> +import { computed } from 'vue' import type { RadioChangeEvent } from 'ant-design-vue' import { Checkbox, @@ -9,11 +10,12 @@ import { Form, FormItem, InputNumber, - Radio, Slider, } from 'ant-design-vue' import { useFormDesignState } from '../../../hooks/useFormDesignState' +defineOptions({ name: 'FormProps' }) + const { formConfig } = useFormDesignState() formConfig.value = formConfig.value || { @@ -21,10 +23,17 @@ formConfig.value = formConfig.value || { wrapperCol: { span: 24 }, } -function lableLayoutChange(e: RadioChangeEvent) { +function labelLayoutChange(e: RadioChangeEvent) { if (e.target.value === 'Grid') formConfig.value.layout = 'horizontal' } + +const sliderSpan = computed(() => { + if (formConfig.value.labelLayout) + return Number(formConfig.value.labelCol!.span) + + return 0 +}) </script> <template> @@ -33,33 +42,33 @@ function lableLayoutChange(e: RadioChangeEvent) { <!-- <e-upload v-model="fileList"></e-upload> --> <FormItem label="表单布局"> - <Radio.Group v-model:value="formConfig.layout" button-style="solid"> - <Radio.Button value="horizontal"> + <RadioGroup v-model:value="formConfig.layout" button-style="solid"> + <RadioButton value="horizontal"> 水平 - </Radio.Button> - <Radio.Button value="vertical" :disabled="formConfig.labelLayout === 'Grid'"> + </RadioButton> + <RadioButton value="vertical" :disabled="formConfig.labelLayout === 'Grid'"> 垂直 - </Radio.Button> - <Radio.Button value="inline" :disabled="formConfig.labelLayout === 'Grid'"> + </RadioButton> + <RadioButton value="inline" :disabled="formConfig.labelLayout === 'Grid'"> 行内 - </Radio.Button> - </Radio.Group> + </RadioButton> + </RadioGroup> </FormItem> <!-- <Row> --> <FormItem label="标签布局"> - <Radio.Group + <RadioGroup v-model:value="formConfig.labelLayout" button-style="solid" - @change="lableLayoutChange" + @change="labelLayoutChange" > - <Radio.Button value="flex"> + <RadioButton value="flex"> 固定 - </Radio.Button> - <Radio.Button value="Grid" :disabled="formConfig.layout !== 'horizontal'"> + </RadioButton> + <RadioButton value="Grid" :disabled="formConfig.layout !== 'horizontal'"> 栅格 - </Radio.Button> - </Radio.Group> + </RadioButton> + </RadioGroup> </FormItem> <!-- </Row> --> <FormItem v-show="formConfig.labelLayout === 'flex'" label="标签宽度(px)"> @@ -72,35 +81,35 @@ function lableLayoutChange(e: RadioChangeEvent) { </FormItem> <div v-if="formConfig.labelLayout === 'Grid'"> <FormItem label="labelCol"> - <Slider v-model:value="formConfig.labelCol!.span" :max="24" /> + <Slider v-model:value="sliderSpan" :max="24" /> </FormItem> <FormItem label="wrapperCol"> - <Slider v-model:value="formConfig.wrapperCol!.span" :max="24" /> + <Slider v-model:value="sliderSpan" :max="24" /> </FormItem> <FormItem label="标签对齐"> - <Radio.Group v-model:value="formConfig.labelAlign" button-style="solid"> - <Radio.Button value="left"> + <RadioGroup v-model:value="formConfig.labelAlign" button-style="solid"> + <RadioButton value="left"> 靠左 - </Radio.Button> - <Radio.Button value="right"> + </RadioButton> + <RadioButton value="right"> 靠右 - </Radio.Button> - </Radio.Group> + </RadioButton> + </RadioGroup> </FormItem> <FormItem label="控件大小"> - <Radio.Group v-model:value="formConfig.size" button-style="solid"> - <Radio.Button value="default"> + <RadioGroup v-model:value="formConfig.size" button-style="solid"> + <RadioButton value="default"> 默认 - </Radio.Button> - <Radio.Button value="small"> + </RadioButton> + <RadioButton value="small"> 小 - </Radio.Button> - <Radio.Button value="large"> + </RadioButton> + <RadioButton value="large"> 大 - </Radio.Button> - </Radio.Group> + </RadioButton> + </RadioGroup> </FormItem> </div> <FormItem label="表单属性"> diff --git a/src/components/FormDesign/src/components/VFormDesign/modules/CollapseItem.vue b/src/components/FormDesign/src/components/VFormDesign/modules/CollapseItem.vue index fe962397..144c43dd 100644 --- a/src/components/FormDesign/src/components/VFormDesign/modules/CollapseItem.vue +++ b/src/components/FormDesign/src/components/VFormDesign/modules/CollapseItem.vue @@ -7,7 +7,7 @@ import { useDesign } from '@/hooks/web/useDesign' const props = defineProps( { list: { - type: Array as unknown as any[], + type: Array as PropType<IVFormComponent[]>, default: () => [], }, handleListPush: { diff --git a/src/components/FormDesign/src/typings/v-form-component.ts b/src/components/FormDesign/src/typings/v-form-component.ts index 74c2a5a0..4b7a8218 100644 --- a/src/components/FormDesign/src/typings/v-form-component.ts +++ b/src/components/FormDesign/src/typings/v-form-component.ts @@ -4,12 +4,12 @@ import type { ComponentOptions } from 'vue' import type { SelectValue } from 'ant-design-vue/lib/select' import type { validateOptions } from 'ant-design-vue/lib/form/useForm' import type { RuleError } from 'ant-design-vue/lib/form/interface' +import type { FormLayout, FormProps } from 'ant-design-vue/lib/form/Form' import type { IVFormMethods } from '../hooks/useVFormMethods' import type { IAnyObject } from './base-type' import type { ColEx } from '@/components/Form/src/types' import type { FormItem } from '@/components/Form' -type LayoutType = 'horizontal' | 'vertical' | 'inline' type labelLayout = 'flex' | 'Grid' export type PropsTabKey = 1 | 2 | 3 type ColSpanType = number | string @@ -75,28 +75,25 @@ declare type namesType = string | string[] /** * 表单配置 */ -export interface IFormConfig { - // 表单项配置列表 - // schemas: IVFormComponent[]; - // 表单配置 - // config: { - layout?: LayoutType +export type PickAntFormConfig = Pick< + FormProps, + | 'layout' + | 'size' + | 'colon' + | 'labelAlign' + | 'disabled' + | 'labelCol' + | 'wrapperCol' + | 'hideRequiredMark' +> + +// 使用extends 而不使用 &联结 是为了避免 type:check指令类型重载错误 +export interface IFormConfig extends PickAntFormConfig { labelLayout?: labelLayout labelWidth?: number - labelCol?: Partial<IACol> - wrapperCol?: Partial<IACol> - hideRequiredMark?: boolean - // Whether to disable schemas: IVFormComponent[] - disabled?: boolean - labelAlign?: 'left' | 'right' - // Internal component size of the form - size?: 'default' | 'small' | 'large' - // }; - // 当前选中项 currentItem?: IVFormComponent activeKey?: PropsTabKey - colon?: boolean } export interface AForm { @@ -118,7 +115,7 @@ export interface AForm { * @default 'horizontal' * @type string */ - layout: 'horizontal' | 'inline' | 'vertical' + layout: FormLayout /** * The layout for input controls, same as labelCol diff --git a/src/components/Icon/src/IconPicker.vue b/src/components/Icon/src/IconPicker.vue index 6b5f791c..0f71accf 100644 --- a/src/components/Icon/src/IconPicker.vue +++ b/src/components/Icon/src/IconPicker.vue @@ -9,18 +9,26 @@ import SvgIcon from './SvgIcon.vue' import { useDesign } from '@/hooks/web/useDesign' import { ScrollContainer } from '@/components/Container' -import { propTypes } from '@/utils/propTypes' import { usePagination } from '@/hooks/web/usePagination' import { useI18n } from '@/hooks/web/useI18n' import { copyText } from '@/utils/copyTextToClipboard' -const props = defineProps({ - value: propTypes.string, - width: propTypes.string.def('100%'), - pageSize: propTypes.number.def(140), - copy: propTypes.bool.def(true), - mode: propTypes.oneOf(['svg', 'iconify']).def('iconify'), +export interface Props { + value?: string + width?: string + pageSize?: number + copy?: boolean + mode?: 'svg' | 'iconify' +} + +const props = withDefaults(defineProps<Props>(), { + value: '', + width: '100%', + pageSize: 140, + copy: false, + mode: 'iconify', }) + const emit = defineEmits(['change', 'update:value']) function getIcons() { @@ -36,7 +44,7 @@ function getIcons() { } function getSvgIcons() { - return svgIcons.map(icon => icon.replace('icon-', '')) + return svgIcons.map((icon: string) => icon.replace('icon-', '')) } const isSvgMode = props.mode === 'svg' @@ -87,7 +95,10 @@ function handleSearchChange(e: ChangeEvent) { </script> <template> - <Input v-model:value="currentSelect" disabled :style="{ width }" :placeholder="t('component.icon.placeholder')" :class="prefixCls"> + <Input + v-model:value="currentSelect" disabled :style="{ width }" :placeholder="t('component.icon.placeholder')" + :class="prefixCls" + > <template #addonAfter> <Popover v-model="open" placement="bottomLeft" trigger="click" :overlay-class-name="`${prefixCls}-popover`"> <template #title> @@ -101,12 +112,10 @@ function handleSearchChange(e: ChangeEvent) { <ScrollContainer class="border border-t-0 border-solid"> <ul class="flex flex-wrap px-2"> <li - v-for="icon in getPaginationList" - :key="icon" + v-for="icon in getPaginationList" :key="icon" :class="currentSelect === icon ? 'border border-primary' : ''" class="mr-1 mt-1 w-1/8 flex cursor-pointer items-center justify-center border border-solid p-2 hover:border-primary" - :title="icon" - @click="handleClick(icon)" + :title="icon" @click="handleClick(icon)" > <!-- <Icon :icon="icon" :prefix="prefix" /> --> <SvgIcon v-if="isSvgMode" :name="icon" /> diff --git a/src/directives/clickOutside.ts b/src/directives/clickOutside.ts index 783fb5a8..4265d152 100644 --- a/src/directives/clickOutside.ts +++ b/src/directives/clickOutside.ts @@ -17,10 +17,10 @@ const nodeList: FlushList = new Map() let startClick: MouseEvent if (!isServer) { - on(document, 'mousedown', (e: MouseEvent) => (startClick = e)) - on(document, 'mouseup', (e: MouseEvent) => { + on(document, 'mousedown', (e: Event) => (startClick = e as MouseEvent)) + on(document, 'mouseup', (e: Event) => { for (const { documentHandler } of nodeList.values()) - documentHandler(e, startClick) + documentHandler(e as MouseEvent, startClick) }) } diff --git a/src/directives/repeatClick.ts b/src/directives/repeatClick.ts index 9e9e9521..98824f55 100644 --- a/src/directives/repeatClick.ts +++ b/src/directives/repeatClick.ts @@ -18,8 +18,8 @@ const repeatDirective: Directive = { interval = null } - on(el, 'mousedown', (e: MouseEvent): void => { - if ((e as any).button !== 0) + on(el, 'mousedown', (e: Event): void => { + if ((e as MouseEvent).button !== 0) return startTime = Date.now() once(document as any, 'mouseup', clear) diff --git a/src/directives/ripple/index.ts b/src/directives/ripple/index.ts index 0a7deb37..8a5b8c75 100644 --- a/src/directives/ripple/index.ts +++ b/src/directives/ripple/index.ts @@ -29,9 +29,9 @@ const RippleDirective: Directive & RippleProto = { const background = bg || RippleDirective.background const zIndex = RippleDirective.zIndex - el.addEventListener(options.event, (event: EventType) => { + el.addEventListener(options.event, (event: Event) => { rippler({ - event, + event: event as EventType, el, background, zIndex, diff --git a/src/utils/propTypes.ts b/src/utils/propTypes.ts index 2ea6a6a7..a17209fa 100644 --- a/src/utils/propTypes.ts +++ b/src/utils/propTypes.ts @@ -1,6 +1,6 @@ import type { CSSProperties, VNodeChild } from 'vue' import type { VueTypeValidableDef, VueTypesInterface } from 'vue-types' -import { createTypes } from 'vue-types' +import { createTypes, toValidableType } from 'vue-types' export type VueNode = VNodeChild | JSX.Element @@ -10,7 +10,7 @@ type PropTypes = VueTypesInterface & { // readonly trueBool: VueTypeValidableDef<boolean>; } -const propTypes = createTypes({ +const newPropTypes = createTypes({ func: undefined, bool: undefined, string: undefined, @@ -19,17 +19,18 @@ const propTypes = createTypes({ integer: undefined, }) as PropTypes -// propTypes.extend([ -// { -// name: 'style', -// getter: true, -// type: [String, Object], -// default: undefined -// }, -// { -// name: 'VNodeChild', -// getter: true, -// type: undefined -// } -// ]) +class propTypes extends newPropTypes { + // a native-like validator that supports the `.validable` method + static override get style() { + return toValidableType('style', { + type: [String, Object], + }) + } + + static override get VNodeChild() { + return toValidableType('VNodeChild', { + type: undefined, + }) + } +} export { propTypes } diff --git a/src/utils/props.ts b/src/utils/props.ts index f30966d6..71df7be5 100644 --- a/src/utils/props.ts +++ b/src/utils/props.ts @@ -109,7 +109,7 @@ export function buildProp<T = never, D extends BuildPropType<T, V, C> = never, R : undefined return { - type: typeof type === 'object' && type && Object.getOwnPropertySymbols(type).includes(wrapperKey) ? type[wrapperKey] : type, + type: typeof type === 'object' && type && Object.getOwnPropertySymbols(type).includes(wrapperKey) && type ? type[wrapperKey] : type, required: !!required, default: defaultValue, validator: _validator, @@ -152,7 +152,8 @@ export function buildProps< export const definePropType = <T>(val: any) => ({ [wrapperKey]: val }) as PropWrapper<T> -export const keyOf = <T>(arr: T) => Object.keys(arr as any) as Array<keyof T> +export const keyOf = <T extends object>(arr: T) => Object.keys(arr) as Array<keyof T> + export const mutable = <T extends readonly any[] | Record<string, unknown>>(val: T) => val as Mutable<typeof val> export const componentSize = ['large', 'medium', 'small', 'mini'] as const diff --git a/src/views/base/login/useLogin.ts b/src/views/base/login/useLogin.ts index 200c3351..d4143d80 100644 --- a/src/views/base/login/useLogin.ts +++ b/src/views/base/login/useLogin.ts @@ -115,12 +115,12 @@ export function useFormRules(formData?: Recordable) { return { getFormRules } } -function createRule(message: string) { +function createRule(message: string): Rule[] { return [ { required: true, message, trigger: 'change', }, - ] as RuleObject[] + ] }