diff --git a/.gitea/stat.html b/.gitea/stat.html deleted file mode 100644 index 0ed7872..0000000 --- a/.gitea/stat.html +++ /dev/null @@ -1,4842 +0,0 @@ - - - - - - - - 构建统计 | 绝弹管理中心 - - - -
- - - - - diff --git a/index.html b/index.html index 46ef5d1..1082204 100644 --- a/index.html +++ b/index.html @@ -9,13 +9,16 @@
-
-
-
-
-
-
-
+
+ loading +

欢迎访问%VITE_TITLE%

+
资源加载中, 请稍等...
diff --git a/package.json b/package.json index b170dc0..f63c3fa 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "@vitejs/plugin-vue": "^5.0.3", "@vitejs/plugin-vue-jsx": "^3.1.0", "@vueuse/core": "^10.7.1", + "arconify": "^0.0.2", "axios": "^1.6.5", "dayjs": "^1.11.10", "dplayer": "^1.27.1", diff --git a/scripts/vite/plugin-pages.ts b/scripts/vite/plugin-pages.ts new file mode 100644 index 0000000..5e3ba94 --- /dev/null +++ b/scripts/vite/plugin-pages.ts @@ -0,0 +1,20 @@ +import { RouteRecordRaw } from 'vue-router'; + +export function onRoutesGenerated(routes: RouteRecordRaw[], mode: string) { + const isProd = mode !== 'development'; + const result = []; + for (const route of routes) { + const { hide } = route.meta ?? {}; + if (!route.meta) { + continue; + } + if (hide === true) { + continue; + } + if (isProd && hide === 'prod') { + continue; + } + result.push(route); + } + return result; +} diff --git a/src/api/interceptors/auth.ts b/src/api/interceptors/auth.ts index f433c10..a48b640 100644 --- a/src/api/interceptors/auth.ts +++ b/src/api/interceptors/auth.ts @@ -12,7 +12,6 @@ export function addAuthInterceptor(axios: AxiosInstance) { if (userStore.accessToken) { config.headers.Authorization = `Bearer ${userStore.accessToken}`; } - // throw Error('dd'); return config; }); } diff --git a/src/components/AnBreadcrumb/bread-crumb.vue b/src/components/AnBreadcrumb.vue similarity index 100% rename from src/components/AnBreadcrumb/bread-crumb.vue rename to src/components/AnBreadcrumb.vue diff --git a/src/components/AnEmpty/AnEmpty.vue b/src/components/AnEmpty.vue similarity index 100% rename from src/components/AnEmpty/AnEmpty.vue rename to src/components/AnEmpty.vue diff --git a/src/components/AnForbidden/AnForbidden.vue b/src/components/AnForbidden.vue similarity index 100% rename from src/components/AnForbidden/AnForbidden.vue rename to src/components/AnForbidden.vue diff --git a/src/components/AnForm/components/Form.tsx b/src/components/AnForm/components/Form.tsx deleted file mode 100644 index fb45352..0000000 --- a/src/components/AnForm/components/Form.tsx +++ /dev/null @@ -1,155 +0,0 @@ -import { Form, FormInstance, Message } from '@arco-design/web-vue'; -import { useVModel } from '@vueuse/core'; -import { ComputedRef, InjectionKey, PropType, Ref } from 'vue'; -import { initFormItems } from '../utils/useFormItems'; -import { FormRef, useFormRef } from '../utils/useFormRef'; -import { AnFormItem, AnFormItemProps } from './FormItem'; -import { cloneDeep, isFunction, isObject, merge } from 'lodash-es'; -import { getModel } from '../utils/useFormModel'; - -const SUBMIT_ITEM = { - field: 'id', - setter: 'submit' as const, - itemProps: { - hideLabel: true, - }, -}; - -export type FormContextInterface = FormRef & { - model: Ref; - items: ComputedRef; - loading: Ref; - submitForm: any; - resetForm: any; -}; - -export const FormContextKey = Symbol('FormContextKey') as InjectionKey; - -/** - * 表单组件 - */ -export const AnForm = defineComponent({ - name: 'AnForm', - props: { - /** - * 表单数据 - * @example - * ```ts - * { - * id: undefined - * } - * ``` - */ - model: { - type: Object as PropType, - default: () => ({}), - }, - /** - * 表单项 - * @example - * ```ts - * [{ - * field: 'name', - * label: '昵称', - * setter: 'input' - * }] - * ``` - */ - items: { - type: Array as PropType, - default: () => [], - }, - /** - * 提交表单 - * @example - * ```ts - * (model) => api.user.addUser(model) - * ``` - */ - submit: { - type: [Function, Object] as PropType, - }, - /** - * 传给Form组件的参数 - * @exmaple - * ```ts - * { - * layout: 'vertical' - * } - * ``` - */ - formProps: { - type: Object as PropType>, - }, - }, - emits: ['update:model'], - setup(props, { slots, emit }) { - const model = useVModel(props, 'model', emit); - const items = computed(() => props.items); - const initModel = cloneDeep(model.value); - const loading = ref(false); - const { formRef, ...formMethods } = useFormRef(); - - const submitItem = () => { - if (!props.submit) { - return null; - } - if (isFunction(props.submit)) { - return SUBMIT_ITEM; - } - if (isObject(props.submit)) { - return merge({}, SUBMIT_ITEM, props.submit); - } - }; - - const resetForm = () => { - model.value = cloneDeep(initModel); - formRef.value?.clearValidate(); - }; - - const submitForm = async () => { - if (await formRef.value?.validate()) { - return; - } - const submit: any = typeof props.submit === 'object' ? props.submit.visible : props.submit; - try { - loading.value = true; - const data = getModel(model.value); - const res = await submit?.(data, props.items); - const msg = res?.data?.message; - msg && Message.success(`提示: ${msg}`); - } catch (e) { - console.log(e); - } finally { - loading.value = false; - } - }; - - const context = { slots, loading, resetForm, submitForm, submitItem, model, items, formRef, ...formMethods }; - provide(FormContextKey, context); - - onMounted(() => { - initFormItems(props.items, model.value); - }); - - return context; - }, - render() { - return ( -
- {this.items.map(item => ( - - ))} - {this.submitItem()} -
- ); - }, -}); - -export type AnFormInstance = InstanceType; - -export type AnFormProps = Pick; - -export type AnFormSubmitFn = (model: Recordable, items: AnFormItemProps[]) => any; - -export type AnFormSubmit = AnFormSubmitFn | AnFormItemProps; diff --git a/src/components/AnForm/components/FormItem.tsx b/src/components/AnForm/components/FormItem.tsx deleted file mode 100644 index 4570c97..0000000 --- a/src/components/AnForm/components/FormItem.tsx +++ /dev/null @@ -1,226 +0,0 @@ -import { FormItem, FieldRule, FormItemInstance, SelectOptionData, SelectOptionGroup } from '@arco-design/web-vue'; -import { InjectionKey, PropType, provide } from 'vue'; -import { SetterItem, SetterType, setterMap } from './FormSetter'; - -export const FormItemContextKey = Symbol('FormItemContextKey') as InjectionKey; - -/** - * 表单项 - */ -export const AnFormItem = defineComponent({ - name: 'AnFormItem', - props: { - /** - * 表单项 - */ - item: { - type: Object as PropType, - required: true, - }, - /** - * 表单项数组 - */ - items: { - type: Array as PropType, - required: true, - }, - /** - * 表单数据 - */ - model: { - type: Object as PropType, - required: true, - }, - }, - setup(props) { - const rules = computed(() => props.item.rules?.filter(i => !i.disable?.(props))); - const disabled = computed(() => Boolean(props.item.disable?.(props))); - - const setterSlots = (() => { - const slots = props.item.setterSlots; - if (!slots) { - return null; - } - const items: Recordable = {}; - for (const [name, Slot] of Object.entries(slots)) { - items[name] = (p: Recordable) => ; - } - return items; - })(); - - const itemSlots = (() => { - const Setter = setterMap[props.item.setter as SetterType]?.setter as any; - const slots = props.item.itemSlots; - if (!slots && !Setter) { - return null; - } - const SetterRender = () => ( - - {setterSlots} - - ); - if (!slots) { - return { - default: SetterRender, - }; - } - const items: Recordable = {}; - for (const [name, Slot] of Object.entries(slots)) { - items[name] = (p: Recordable) => ; - } - if (Setter) { - items.default = SetterRender; - } - return items; - })(); - - provide(FormItemContextKey, props); - - return () => { - if (props.item.visible && !props.item.visible(props)) { - return null; - } - return ( - - {itemSlots} - - ); - }; - }, -}); - -export type AnFormItemBoolFn = (args: AnFormItemFnProps) => boolean; - -export type AnFormItemElemFn = (args: AnFormItemFnProps) => any; - -export type AnFormItemFnProps = { model: Recordable; item: AnFormItemProps; items: AnFormItemProps[] }; - -export type AnFormItemRule = FieldRule & { disable?: AnFormItemBoolFn }; - -export type AnFormItemOption = string | number | boolean | SelectOptionData | SelectOptionGroup; - -export type AnFormItemSlot = (props: AnFormItemFnProps) => any; - -export type AnFormItemSlots = { - /** - * 默认插槽 - * @param props 参数 - */ - default?: AnFormItemSlot; - - /** - * 帮助插槽 - * @param props 参数 - */ - help?: AnFormItemSlot; - - /** - * 额外插槽 - * @param props 参数 - */ - extra?: AnFormItemSlot; - - /** - * 标签插槽 - * @param props 参数 - */ - label?: AnFormItemSlot; -}; - -export type AnFormItemPropsBase = { - /** - * 字段名 - * @description 字段名唯一,支持特殊语法 - * @example - * ```ts - * 'username' - * ``` - */ - field: string; - - /** - * 标签 - * @example - * ```ts - * '昵称' - * ``` - */ - label?: string; - - /** - * 校验规则 - * @example - * ```ts - * ['email'] - * ``` - */ - rules?: AnFormItemRule[]; - - /** - * 是否可见 - * @example - * ```ts - * (props) => Boolean(props.model.id) - * ``` - */ - visible?: AnFormItemBoolFn; - - /** - * 是否禁用 - * @example - * ```ts - * (props) => Boolean(props.model.id) - * ``` - */ - disable?: AnFormItemBoolFn; - - /** - * 选项 - * @description 适用于下拉框等组件 - * @example - * ```ts - * [{ - * label: '方式1', - * value: 1 - * }] - * ``` - */ - options?: AnFormItemOption[] | ((args: AnFormItemFnProps) => AnFormItemOption[] | Promise); - - /** - * 表单项参数 - * @example - * ```ts - * { - * hideLabel: true - * } - * ``` - */ - itemProps?: Partial>; - - /** - * 表单项插槽 - * @example - * ```tsx - * { - * help: () => 帮助提示 - * } - * ``` - */ - itemSlots?: AnFormItemSlots; - - /** - * 内置 - * @private - */ - $init?: () => void; -}; - -export type AnFormItemProps = AnFormItemPropsBase & SetterItem; diff --git a/src/components/AnForm/components/FormModal.tsx b/src/components/AnForm/components/FormModal.tsx deleted file mode 100644 index fa6c65c..0000000 --- a/src/components/AnForm/components/FormModal.tsx +++ /dev/null @@ -1,269 +0,0 @@ -import { Button, ButtonInstance, FormInstance, Message, Modal } from '@arco-design/web-vue'; -import { useVModel } from '@vueuse/core'; -import { InjectionKey, PropType, Ref } from 'vue'; -import { getModel, setModel } from '../utils/useFormModel'; -import { AnForm, AnFormInstance, AnFormSubmit } from './Form'; -import { AnFormItemProps } from './FormItem'; -import { cloneDeep } from 'lodash-es'; - -export interface AnFormModalContext { - visible: Ref; - loading: Ref; - anFormRef: Ref; - submitForm: () => any | Promise; - open: (data: Recordable) => void; - close: () => void; - modalTitle: () => any; - modalTrigger: () => any; - onClose: () => void; -} - -export const AnFormModalContextKey = Symbol('AnFormModalContextKey') as InjectionKey; - -/** - * 表单组件 - */ -export const AnFormModal = defineComponent({ - name: 'AnFormModal', - props: { - /** - * 弹窗标题 - * @default - * ```ts - * '新增' - * ``` - */ - title: { - type: [String, Function] as PropType, - default: '新增', - }, - /** - * 触发元素 - * @default - * ```ts - * '新增' - * ``` - */ - trigger: { - type: [Boolean, String, Function, Object] as PropType, - default: true, - }, - /** - * 传递给Modal的props - * @example - * ```ts - * { - * closable: true - * } - * ``` - */ - modalProps: { - type: Object as PropType['$props'], 'visible' | 'title'>>, - }, - /** - * 表单数据 - * @example - * ```ts - * { - * id: undefined - * } - * ``` - */ - model: { - type: Object as PropType, - required: true, - }, - /** - * 表单项 - * @example - * ```ts - * [{ - * field: 'name', - * label: '昵称', - * setter: 'input' - * }] - * ``` - */ - items: { - type: Array as PropType, - default: () => [], - }, - /** - * 提交表单 - * @example - * ```ts - * (model) => api.user.addUser(model) - * ``` - */ - submit: { - type: [Object, Function] as PropType, - }, - /** - * 传给Form组件的参数 - * @example - * ```ts - * { - * layout: 'vertical' - * } - * ``` - */ - formProps: { - type: Object as PropType>, - }, - }, - emits: ['update:model', 'submited'], - setup(props, { emit }) { - const model = useVModel(props, 'model', emit); - const originModel = cloneDeep(model.value); - const anFormRef = ref(null); - const visible = ref(false); - const loading = ref(false); - - const modalTitle = () => { - if (typeof props.title === 'string') { - return props.title; - } - return ; - }; - - const modalTrigger = () => { - if (!props.trigger) { - return null; - } - if (typeof props.trigger === 'function') { - return ; - } - const internal = { - text: '新增', - buttonProps: {}, - buttonSlots: {}, - }; - if (typeof props.trigger === 'string') { - internal.text = props.trigger; - } - if (typeof props.trigger === 'object') { - Object.assign(internal, props.trigger); - } - return ( - - ); - }; - - const submitForm = async () => { - if (await anFormRef.value?.validate()) { - return; - } - try { - loading.value = true; - const data = getModel(model.value); - const res = await (props as any).submit?.(data, props.items); - const msg = res?.data?.message; - msg && Message.success(msg); - visible.value = false; - emit('submited', res); - } catch { - // todo - } finally { - loading.value = false; - } - }; - - const open = async (data: Recordable = {}) => { - visible.value = true; - await nextTick(); - model.value = cloneDeep(originModel) - setModel(model.value, data); - }; - - const close = () => { - loading.value = false; - visible.value = false; - }; - - const onClose = () => {}; - - const context: AnFormModalContext = { - visible, - loading, - anFormRef, - open, - close, - onClose, - submitForm, - modalTitle, - modalTrigger, - }; - - provide(AnFormModalContextKey, context); - - return { - ...context - }; - }, - render() { - return ( - <> - - - {{ - title: this.modalTitle, - default: () => ( - this.$emit('update:model', v)} - items={this.items} - formProps={this.formProps} - > - ), - footer: () => ( -
-
-
- - -
-
- ), - }} -
- - ); - }, -}); - -export type AnFormModalTitle = string | ((model: Recordable, items: AnFormItemProps[]) => any); - -export type AnFormModalTrigger = - | boolean - | string - | ((model: Recordable, items: AnFormItemProps[]) => any) - | { - text?: string; - buttonProps?: ButtonInstance['$props']; - buttonSlots?: Recordable; - }; - -export type AnFormModalInstance = InstanceType; - -export type AnFormModalProps = Pick< - AnFormModalInstance['$props'], - 'title' | 'trigger' | 'modalProps' | 'model' | 'items' | 'submit' | 'formProps' ->; diff --git a/src/components/AnForm/components/FormSetter.tsx b/src/components/AnForm/components/FormSetter.tsx deleted file mode 100644 index 1762525..0000000 --- a/src/components/AnForm/components/FormSetter.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import setterMap from '../setters'; - -/** - * 键值对类型 - */ -export type SetterMap = typeof setterMap; - -/** - * 组件名联合类型 - */ -export type SetterType = keyof SetterMap; - -/** - * 重新映射 - */ -export type SetterItemMap = { - [key in SetterType]: { - /** - * 控件类型 - * @example - * ```ts - * 'input' - * ``` - */ - setter: key; - /** - * 控件参数 - * @example - * ```tsx - * { type: "password" } - * ``` - */ - setterProps?: SetterMap[key]['setterProps']; - /** - * 控件插槽 - * @example - * ```tsx - * label: (props) => {props.item.label} - * ``` - */ - setterSlots?: SetterMap[key]['setterSlots']; - }; -}; - -/** - * 控件类型 - */ -export type SetterItem = - | SetterItemMap[SetterType] - | { setter?: undefined; setterProps?: undefined; setterSlots?: undefined }; - -export { setterMap }; diff --git a/src/components/AnForm/hooks/useForm.tsx b/src/components/AnForm/hooks/useForm.tsx deleted file mode 100644 index 797655b..0000000 --- a/src/components/AnForm/hooks/useForm.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import { merge } from 'lodash-es'; -import { AnForm, AnFormInstance, AnFormProps } from '../components/Form'; -import { FormItem, useFormItems } from './useFormItems'; - -export type FormUseOptions = Partial> & { - /** - * 表单项 - * @example - * ```ts - * [{ - * field: 'name', - * label: '昵称', - * setter: 'input' - * }] - * ``` - */ - items?: FormItem[]; -}; - -export function useFormProps(options: FormUseOptions): Required { - const { model: _model = {}, items: _items = [], submit = () => null, formProps = {} } = options; - const model = merge({ id: undefined }, _model); - const items = useFormItems(_items ?? [], model); - return { - model, - items, - submit, - formProps, - }; -} - -/** - * 构建表单组件的参数 - */ -export const useForm = (options: FormUseOptions) => { - const props = reactive(useFormProps(options)); - const formRef = ref(null); - - const AnFormer = () => ( - (formRef.value = el)} - v-model:model={props.model} - items={props.items} - submit={props.submit} - formProps={props.formProps} - > - ); - - return { - component: AnFormer, - formRef, - props, - }; -}; diff --git a/src/components/AnForm/hooks/useFormItems.tsx b/src/components/AnForm/hooks/useFormItems.tsx deleted file mode 100644 index 99d92ba..0000000 --- a/src/components/AnForm/hooks/useFormItems.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { defaultsDeep, has, merge, omit } from 'lodash-es'; -import { AnFormItemProps, AnFormItemPropsBase } from '../components/FormItem'; -import { SetterItem, setterMap } from '../components/FormSetter'; -import { Rule, useFormRules } from './useFormRules'; - -/** - * 表单项数据 - */ -export type FormItem = Omit & - SetterItem & { - /** - * 默认值 - * @example - * ```ts - * '1' - * ``` - */ - value?: any; - - /** - * 是否必填 - * @default - * ```ts - * false - * ``` - */ - required?: boolean; - - /** - * 校验规则 - * @example - * ```ts - * ['email'] - * ``` - */ - rules?: Rule[]; - - /** - * 参数 `setterProps.placeholder` 的快捷语法 - * @example - * ```ts - * '请输入用户名称' - * ``` - */ - placeholder?: string | string[]; - }; - -const ITEM: Partial = { - setter: 'input', -}; - -export function useFormItems(items: FormItem[], model: Recordable) { - const data: AnFormItemProps[] = []; - - for (const item of items) { - let target: AnFormItemProps = defaultsDeep({}, ITEM); - - if (!item.setter || typeof item.setter === 'string') { - const setter = setterMap[item.setter ?? 'input']; - if (setter) { - defaultsDeep(target, { setterProps: setter.setterProps ?? {} }); - } - } - - target = merge(target, omit(item, ['required', 'rules', 'value', 'placeholder'])); - - if (item.required || item.rules) { - const rules = useFormRules(item)!; - target.rules = rules; - } - - if (target.setterProps && has(item, 'placeholder')) { - (target.setterProps as Recordable).placholder = item.placeholder; - } - - if (!has(model, item.field)) { - model[item.field] = item.value; - } - - data.push(target); - } - - return data; -} diff --git a/src/components/AnForm/hooks/useFormModal.tsx b/src/components/AnForm/hooks/useFormModal.tsx deleted file mode 100644 index 0794d24..0000000 --- a/src/components/AnForm/hooks/useFormModal.tsx +++ /dev/null @@ -1,95 +0,0 @@ -import { merge } from 'lodash-es'; -import { AnFormModal, AnFormModalProps } from '../components/FormModal'; -import { useFormProps } from './useForm'; -import { FormItem } from './useFormItems'; - -export type FormModalUseOptions = Partial> & { - /** - * 弹窗宽度 - * @description 参数 `modalProps.width` 的便捷语法 - * @example - * ```ts - * 580 - * ``` - */ - width?: number; - /** - * modal宽度 - * @example - * ```ts - * 1080 - * ``` - */ - modalWidth?: number; - /** - * 表单类名 - * @description 参数 `formProps.class` 的便捷语法 - * @example - * ```ts - * 'grid grid-cols-2' - * ``` - */ - formClass?: unknown; - /** - * 表单项 - * @example - * ```tsx - * [{ - * field: 'name', - * label: '昵称', - * setter: 'input' - * }] - * ``` - */ - items: FormItem[]; -}; - -export function useFormModalProps(options: FormModalUseOptions): AnFormModalProps { - if (options.width) { - merge(options, { modalProps: { width: options.width } }); - } - if (options.formClass) { - merge(options, { formProps: { class: options.formClass } }); - } - const { items, model, formProps } = useFormProps({ ...options, submit: undefined }); - const { trigger, title, submit, modalProps } = options; - return { - trigger, - model, - items, - title, - submit, - formProps, - modalProps, - }; -} - -export function useFormModal(options: FormModalUseOptions) { - const modalRef = ref | null>(null); - const formRef = computed(() => modalRef.value?.anFormRef); - const open = (data: Recordable = {}) => modalRef.value?.open(data); - const rawProps = useFormModalProps(options); - const props = reactive(rawProps); - - const component = () => ( - (modalRef.value = el)} - title={props.title} - trigger={props.trigger} - modalProps={props.modalProps as any} - model={props.model} - items={props.items} - formProps={props.formProps} - submit={props.submit} - onUpdate:model={model => ((props as any).model = model)} - > - ); - - return { - props, - component, - modalRef, - formRef, - open, - }; -} diff --git a/src/components/AnForm/hooks/useFormRules.tsx b/src/components/AnForm/hooks/useFormRules.tsx deleted file mode 100644 index fda9abe..0000000 --- a/src/components/AnForm/hooks/useFormRules.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { FieldRule } from "@arco-design/web-vue"; -import { has, isString } from "lodash-es"; -import { AnFormItemRule } from "../components/FormItem"; - -/** - * 内置规则 - */ -export const FieldRuleMap = defineRuleMap({ - required: { - required: true, - message: "该项不能为空", - }, - string: { - type: "string", - message: "请输入字符串", - }, - number: { - type: "number", - message: "请输入数字", - }, - email: { - type: "email", - message: "邮箱格式错误,示例: xx@abc.com", - }, - url: { - type: "url", - message: "URL格式错误, 示例: www.abc.com", - }, - ip: { - type: "ip", - message: "IP格式错误, 示例: 101.10.10.30", - }, - phone: { - match: /^(?:(?:\+|00)86)?1\d{10}$/, - message: "手机格式错误, 示例(11位): 15912345678", - }, - idcard: { - match: /^[1-9]\d{5}(?:18|19|20)\d{2}(?:0[1-9]|10|11|12)(?:0[1-9]|[1-2]\d|30|31)\d{3}[\dXx]$/, - message: "身份证格式错误, 长度为15或18位", - }, - alphabet: { - match: /^[a-zA-Z]\w{4,15}$/, - message: "请输入英文字母, 长度为4~15位", - }, - password: { - match: /^\S*(?=\S{6,})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/, - message: "至少包含大写字母、小写字母、数字和特殊字符", - }, -}); - -/** - * 字符串形式(枚举) - */ -export type FieldStringRule = keyof typeof FieldRuleMap; - -/** - * 完整类型 - */ -export type Rule = FieldStringRule | AnFormItemRule; - -/** - * 助手函数(获得TS提示) - */ -function defineRuleMap>(ruleMap: T) { - return ruleMap; -} - -/** - * 获取表单规则 - * @param item 表单项 - * @returns - */ -export const useFormRules = (item: T) => { - const data: AnFormItemRule[] = []; - const { required, rules } = item; - - if (!has(item, "required") && !has(item, "rules")) { - return null; - } - - if (required) { - data.push(FieldRuleMap.required); - } - - for (const rule of rules ?? []) { - if (isString(rule)) { - if (FieldRuleMap[rule]) { - data.push(FieldRuleMap[rule]); - } - } else { - data.push(rule); - } - } - - return data; -}; diff --git a/src/components/AnForm/index.ts b/src/components/AnForm/index.ts deleted file mode 100644 index f60fea7..0000000 --- a/src/components/AnForm/index.ts +++ /dev/null @@ -1,12 +0,0 @@ -export * from './components/Form'; -export * from './components/FormItem'; -export * from './components/FormModal'; -export * from './components/FormSetter'; -export * from './utils/useFormItems'; -export * from './utils/useFormModel'; -export * from './utils/useFormRef'; -export * from './hooks/useForm'; -export * from './hooks/useFormModal'; -export * from './hooks/useFormItems'; -export * from './hooks/useFormRules'; -export * from './setters'; diff --git a/src/components/AnForm/setters/Cascader.tsx b/src/components/AnForm/setters/Cascader.tsx deleted file mode 100644 index 2ff7c09..0000000 --- a/src/components/AnForm/setters/Cascader.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { Cascader, CascaderInstance } from '@arco-design/web-vue'; -import { defineSetter, initOptions } from './util'; - -type CascaderProps = CascaderInstance['$props']; - -type CascaderSlots = 'label' | 'prefix' | 'arrowIcon' | 'loadingIcon' | 'searchIcon' | 'empty' | 'option'; - -export default defineSetter({ - setter: Cascader, - setterProps: { - placeholder: '请选择', - allowClear: true, - expandTrigger: 'hover', - }, - onSetup: initOptions as any, -}); diff --git a/src/components/AnForm/setters/Date.tsx b/src/components/AnForm/setters/Date.tsx deleted file mode 100644 index 419b42f..0000000 --- a/src/components/AnForm/setters/Date.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { DatePicker, DatePickerInstance } from '@arco-design/web-vue'; -import { defineSetter } from './util'; -import { PickerProps } from '@arco-design/web-vue/es/date-picker/interface'; - -type DateProps = DatePickerInstance['$props'] & Partial; - -type DateSlots = - | 'prefix' - | 'suffixIcon' - | 'iconNextDouble' - | 'iconPrevDouble' - | 'iconNext' - | 'iconPrev' - | 'cell' - | 'extra'; - -export default defineSetter({ - setter: DatePicker, - setterProps: { - placeholder: '请选择', - allowClear: true, - }, -}); diff --git a/src/components/AnForm/setters/DateRange.tsx b/src/components/AnForm/setters/DateRange.tsx deleted file mode 100644 index f2d8963..0000000 --- a/src/components/AnForm/setters/DateRange.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { RangePicker, RangePickerInstance } from '@arco-design/web-vue'; -import { defineSetter } from './util'; - -type RangeProps = RangePickerInstance['$props']; - -type RangeSlots = "none"; - -export default defineSetter({ - setter: RangePicker, - setterProps: { - allowClear: true, - }, -}); diff --git a/src/components/AnForm/setters/Input.tsx b/src/components/AnForm/setters/Input.tsx deleted file mode 100644 index aa41360..0000000 --- a/src/components/AnForm/setters/Input.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Input, InputInstance } from '@arco-design/web-vue'; -import { defineSetter } from './util'; - -type InputProps = InputInstance['$props']; - -type InputSlots = 'prepend' | 'append' | 'suffix' | 'prefix'; - -export default defineSetter({ - setter: Input, - setterProps: { - placeholder: '请输入', - allowClear: true, - }, -}); diff --git a/src/components/AnForm/setters/Number.tsx b/src/components/AnForm/setters/Number.tsx deleted file mode 100644 index 4c5ecaf..0000000 --- a/src/components/AnForm/setters/Number.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { InputInstance, InputNumber, InputNumberInstance } from '@arco-design/web-vue'; -import { defineSetter } from './util'; - -type NumberProps = InputInstance['$props'] | InputNumberInstance['$props']; - -type NumberSlots = 'minus' | 'plus' | 'append' | 'prepend' | 'suffix' | 'prefix'; - -export default defineSetter({ - setter: InputNumber, - setterProps: { - placeholder: '请输入', - defaultValue: 0, - allowClear: true, - }, -}); diff --git a/src/components/AnForm/setters/Password.tsx b/src/components/AnForm/setters/Password.tsx deleted file mode 100644 index 2de9634..0000000 --- a/src/components/AnForm/setters/Password.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { InputInstance, InputPassword, InputPasswordInstance } from '@arco-design/web-vue'; -import { defineSetter } from './util'; - -type PasswordProps = InputInstance['$props'] & InputPasswordInstance['$props']; - -type PasswordSlots = 'none'; - -export default defineSetter({ - setter: InputPassword, - setterProps: { - placeholder: '请输入', - }, -}); diff --git a/src/components/AnForm/setters/Search.tsx b/src/components/AnForm/setters/Search.tsx deleted file mode 100644 index f544771..0000000 --- a/src/components/AnForm/setters/Search.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { InputInstance, InputSearch, InputSearchInstance } from '@arco-design/web-vue'; -import { defineSetter } from './util'; - -type SearchProps = InputInstance['$props'] & InputSearchInstance['$props']; - -type SearchSlots = "none"; - -export default defineSetter({ - setter: InputSearch, - setterProps: { - placeholder: '请输入', - allowClear: true, - }, -}); diff --git a/src/components/AnForm/setters/Select.tsx b/src/components/AnForm/setters/Select.tsx deleted file mode 100644 index 37a2195..0000000 --- a/src/components/AnForm/setters/Select.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { Select, SelectInstance } from '@arco-design/web-vue'; -import { defineSetter, initOptions } from './util'; - -type SelectProps = SelectInstance['$props']; - -type SelectSlots = - | 'trigger' - | 'prefix' - | 'searchIcon' - | 'loadingIcon' - | 'arrowIcon' - | 'footer' - | 'header' - | 'label' - | 'option' - | 'empty'; - -export default defineSetter({ - setter: Select, - onSetup: initOptions as any, - setterProps: { - placeholder: '请选择', - allowClear: true, - allowSearch: true, - options: [], - }, -}); diff --git a/src/components/AnForm/setters/Submit.tsx b/src/components/AnForm/setters/Submit.tsx deleted file mode 100644 index 6eaf335..0000000 --- a/src/components/AnForm/setters/Submit.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { Button } from '@arco-design/web-vue'; -import { FormContextKey } from '../components/Form'; -import { defineSetter } from './util'; - -export default defineSetter<{}, 'none'>({ - setter() { - const { submitForm, resetForm } = inject(FormContextKey)!; - return ( - <> - - - - ); - }, - setterProps: {}, -}); diff --git a/src/components/AnForm/setters/Textarea.tsx b/src/components/AnForm/setters/Textarea.tsx deleted file mode 100644 index ee77484..0000000 --- a/src/components/AnForm/setters/Textarea.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { InputInstance, Textarea, TextareaInstance } from '@arco-design/web-vue'; -import { defineSetter } from './util'; - -type TextareaProps = InputInstance['$props'] & TextareaInstance['$props']; - -type TextareaSlots = "none"; - -export default defineSetter({ - setter: Textarea, - setterProps: { - placeholder: '请输入', - allowClear: true, - }, -}); diff --git a/src/components/AnForm/setters/Time.tsx b/src/components/AnForm/setters/Time.tsx deleted file mode 100644 index 948b99f..0000000 --- a/src/components/AnForm/setters/Time.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { TimePicker, TimePickerInstance } from '@arco-design/web-vue'; -import { defineSetter } from './util'; - -type TimeProps = TimePickerInstance['$props']; - -type TimeSlots = 'prefix' | 'suffixIcon' | 'extra'; - -export default defineSetter({ - setter: TimePicker, - setterProps: { - allowClear: true, - }, -}); diff --git a/src/components/AnForm/setters/TreeSelect.tsx b/src/components/AnForm/setters/TreeSelect.tsx deleted file mode 100644 index 1c21160..0000000 --- a/src/components/AnForm/setters/TreeSelect.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { TreeSelect, TreeSelectInstance } from '@arco-design/web-vue'; -import { defineSetter, initOptions } from './util'; - -type TreeSelectProps = TreeSelectInstance['$props']; - -type TreeSelectSlots = - | 'trigger' - | 'prefix' - | 'label' - | 'header' - | 'loader' - | 'empty' - | 'footer' - | 'treeSlotExtra' - | 'treeSlotTitle' - | 'treeSlotIcon' - | 'treeSlotSwitcherIcon'; - -export default defineSetter({ - setter: TreeSelect, - onSetup: (arg: any) => initOptions(arg, 'data') as any, - setterProps: { - placeholder: '请选择', - allowClear: true, - allowSearch: true, - }, -}); diff --git a/src/components/AnForm/setters/index.ts b/src/components/AnForm/setters/index.ts deleted file mode 100644 index dbb460f..0000000 --- a/src/components/AnForm/setters/index.ts +++ /dev/null @@ -1,27 +0,0 @@ -import cascader from './Cascader'; -import date from './Date'; -import dateRange from './DateRange'; -import input from './Input'; -import number from './Number'; -import password from './Password'; -import search from './Search'; -import select from './Select'; -import submit from './Submit'; -import textarea from './Textarea'; -import time from './Time'; -import treeSelect from './TreeSelect'; - -export default { - input, - number, - search, - textarea, - select, - treeSelect, - time, - password, - cascader, - date, - submit, - dateRange, -}; diff --git a/src/components/AnForm/setters/util.ts b/src/components/AnForm/setters/util.ts deleted file mode 100644 index 9df7193..0000000 --- a/src/components/AnForm/setters/util.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Component } from 'vue'; -import { AnFormItemPropsBase, AnFormItemSlot, AnFormItemFnProps } from '../components/FormItem'; - -export interface ItemSetter

{ - /** - * 输入组件 - */ - setter: Component; - - /** - * 输入组件参数 - */ - setterProps?: P; - - /** - * 空间插槽 - */ - setterSlots?: { - /** - * 控件插槽 - * @example - * ```tsx - * (props) => { - * return {props.item.label} - * } - * ``` - */ - [key in S]?: AnFormItemSlot; - }; - - /** - * 初始化钩子 - */ - onSetup?: (args: { model: Recordable; item: AnFormItemPropsBase; items: AnFormItemPropsBase[] }) => void; -} - -export function defineSetter

(setter: ItemSetter) { - return setter; -} - -export function initOptions({ item, model }: AnFormItemFnProps, key: string = 'options') { - const setterProps: Recordable = item.setterProps!; - if (Array.isArray(item.options) && item.setterProps) { - setterProps[key] = item.options; - return; - } - if (typeof item.options === 'function') { - setterProps[key] = reactive([]); - item.$init = async () => { - const res = await (item as any).options({ item, model }); - if (Array.isArray(res)) { - setterProps[key].splice(0); - setterProps[key].push(...res); - return; - } - const data = res?.data?.data; - if (Array.isArray(data)) { - const maped = data.map((i: any) => ({ ...i, value: i.id, label: i.name })); - setterProps[key].splice(0); - setterProps[key].push(...maped); - return; - } - }; - item.$init(); - } -} diff --git a/src/components/AnForm/utils/context.ts b/src/components/AnForm/utils/context.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/components/AnForm/utils/useFormItems.tsx b/src/components/AnForm/utils/useFormItems.tsx deleted file mode 100644 index 9c461c3..0000000 --- a/src/components/AnForm/utils/useFormItems.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { AnFormItemProps } from '../components/FormItem'; -import { setterMap } from '../components/FormSetter'; - -export const getFormItem = (items: AnFormItemProps[], field: string) => { - return items.find(i => i.field === field); -}; - -export const initFormItems = (items: AnFormItemProps[], model: Recordable) => { - for (const item of items) { - const setter = setterMap[item.setter!]; - setter.onSetup?.({ item, items, model }); - } -}; \ No newline at end of file diff --git a/src/components/AnForm/utils/useFormModel.tsx b/src/components/AnForm/utils/useFormModel.tsx deleted file mode 100644 index 82d2f05..0000000 --- a/src/components/AnForm/utils/useFormModel.tsx +++ /dev/null @@ -1,89 +0,0 @@ -export function getModel(model: Recordable) { - const data: Recordable = {}; - - for (const [key, value] of Object.entries(model)) { - if (value === '') { - continue; - } - if (/^\[.+\]$/.test(key)) { - getModelArray(key, value, data); - continue; - } - if (/^\{.+\}$/.test(key)) { - getModelObject(key, value, data); - continue; - } - data[key] = value; - } - - return data; -} - -export function setModel(model: Recordable, data: Recordable) { - for (const [key, value] of Object.entries(model)) { - if (/^\[.+\]$/.test(key)) { - model[key] = setModelArray(data, key); - continue; - } - if (/^\{.+\}$/.test(key)) { - model[key] = setModelObject(data, key); - continue; - } - model[key] = data[key]; - } - console.log(model, data); - return model; -} - -function rmString(str: string) { - const field = str.replaceAll(/\s/g, ''); - return field.match(/^(\{|\[)(.+)(\}|\])$/)?.[1] ?? ''; -} - -function setModelArray(data: Recordable, key: string) { - const result: any[] = []; - const field = rmString(key); - for (const key of field.split(',')) { - result.push(data[key]); - } - return result; -} - -function setModelObject(data: Recordable, key: string) { - const result: Recordable = {}; - const field = rmString(key); - for (const key of field.split(',')) { - result[key] = data[key]; - } - return result; -} - -function getModelArray(key: string, value: any, data: Recordable) { - let field = rmString(key); - - if (!field) { - data[key] = value; - return; - } - - field.split(',').forEach((key, index) => { - data[key] = value?.[index]; - }); - - return data; -} - -function getModelObject(key: string, value: any, data: Recordable) { - const field = rmString(key); - - if (!field) { - data[key] = value; - return; - } - - for (const key of field.split(',')) { - data[key] = value?.[key]; - } - - return data; -} diff --git a/src/components/AnForm/utils/useFormRef.tsx b/src/components/AnForm/utils/useFormRef.tsx deleted file mode 100644 index 3aadc6c..0000000 --- a/src/components/AnForm/utils/useFormRef.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { FormInstance } from "@arco-design/web-vue"; - -export function useFormRef() { - /** - * 原始表单实例 - */ - const formRef = ref(null); - - type Validate = FormInstance["validate"]; - type ValidateField = FormInstance["validateField"]; - type ResetFields = FormInstance["resetFields"]; - type ClearValidate = FormInstance["clearValidate"]; - type SetFields = FormInstance["setFields"]; - type ScrollToField = FormInstance["scrollToField"]; - - const validate: Validate = async (...args) => formRef.value?.validate(...args); - const validateField: ValidateField = async (...args) => formRef.value?.validateField(...args); - const resetFields: ResetFields = (...args) => formRef.value?.resetFields(...args); - const clearValidate: ClearValidate = (...args) => formRef.value?.clearValidate(...args); - const setFields: SetFields = (...args) => formRef.value?.setFields(...args); - const scrollToField: ScrollToField = (...args) => formRef.value?.scrollToField(...args); - - return { - formRef, - validate, - validateField, - resetFields, - clearValidate, - setFields, - scrollToField, - }; -} - -export type FormRef = ReturnType; diff --git a/src/components/AnBreadcrumb/bread-page.vue b/src/components/AnPage.vue similarity index 94% rename from src/components/AnBreadcrumb/bread-page.vue rename to src/components/AnPage.vue index 153ccdf..45bd6fb 100644 --- a/src/components/AnBreadcrumb/bread-page.vue +++ b/src/components/AnPage.vue @@ -19,7 +19,7 @@ diff --git a/src/pages/setting/common/index.vue b/src/pages/setting/common/index.vue index 977d6b4..1d31128 100644 --- a/src/pages/setting/common/index.vue +++ b/src/pages/setting/common/index.vue @@ -1,13 +1,13 @@