| | |
| | | "url": "http://localhost:3100", |
| | | "webRoot": "${workspaceFolder}/src", |
| | | "sourceMaps": true |
| | | }, |
| | | } |
| | | ] |
| | | } |
| | |
| | | ## 后台整合示例 |
| | | |
| | | - [lamp-cloud](https://github.com/zuihou/lamp-cloud) - 基于 SpringCloud Alibaba 的微服务中后台快速开发平台 |
| | | - [matecloud](https://github.com/matevip/matecloud) - MateCloud微服务脚手架,基于Spring Cloud 2020.0.3、SpringBoot 2.5.3的全开源平台 |
| | | - [matecloud](https://github.com/matevip/matecloud) - MateCloud 微服务脚手架,基于 Spring Cloud 2020.0.3、SpringBoot 2.5.3 的全开源平台 |
| | | |
| | | ## 维护者 |
| | | |
| | |
| | | const { prefix } = data; |
| | | const isLocal = useType === 'local'; |
| | | const icons = Object.keys(data.icons).map( |
| | | (item) => `${isLocal ? prefix + ':' : ''}${item}` |
| | | (item) => `${isLocal ? prefix + ':' : ''}${item}`, |
| | | ); |
| | | |
| | | await fs.writeFileSync( |
| | | path.join(output, `icons.data.ts`), |
| | | `export default ${isLocal ? JSON.stringify(icons) : JSON.stringify({ prefix, icons })}` |
| | | `export default ${isLocal ? JSON.stringify(icons) : JSON.stringify({ prefix, icons })}`, |
| | | ); |
| | | prefixSet.push(prefix); |
| | | } |
| | | } |
| | | fs.emptyDir(path.join(process.cwd(), 'node_modules/.vite')); |
| | | console.log( |
| | | `✨ ${chalk.cyan(`[${pkg.name}]`)}` + ' - Icon generated successfully:' + `[${prefixSet}]` |
| | | `✨ ${chalk.cyan(`[${pkg.name}]`)}` + ' - Icon generated successfully:' + `[${prefixSet}]`, |
| | | ); |
| | | }); |
| | | } |
| | |
| | | configName, |
| | | config, |
| | | configFileName = GLOB_CONFIG_FILE_NAME, |
| | | }: { configName: string; config: any; configFileName?: string } = { configName: '', config: {} } |
| | | }: { configName: string; config: any; configFileName?: string } = { configName: '', config: {} }, |
| | | ) { |
| | | try { |
| | | const windowConf = `window.${configName}`; |
| | |
| | | |
| | | export function configCompressPlugin( |
| | | compress: 'gzip' | 'brotli' | 'none', |
| | | deleteOriginFile = false |
| | | deleteOriginFile = false, |
| | | ): Plugin | Plugin[] { |
| | | const compressList = compress.split(','); |
| | | |
| | |
| | | compressPlugin({ |
| | | ext: '.gz', |
| | | deleteOriginFile, |
| | | }) |
| | | }), |
| | | ); |
| | | } |
| | | |
| | |
| | | ext: '.br', |
| | | algorithm: 'brotliCompress', |
| | | deleteOriginFile, |
| | | }) |
| | | }), |
| | | ); |
| | | } |
| | | return plugins; |
| | |
| | | |
| | | // rollup-plugin-gzip |
| | | vitePlugins.push( |
| | | configCompressPlugin(VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE) |
| | | configCompressPlugin(VITE_BUILD_COMPRESS, VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE), |
| | | ); |
| | | |
| | | // vite-plugin-pwa |
| | |
| | | page: number, |
| | | pageSize: number, |
| | | list: T[], |
| | | { message = 'ok' } = {} |
| | | { message = 'ok' } = {}, |
| | | ) { |
| | | const pageData = pagination(page, pageSize, list); |
| | | |
| | |
| | | response: ({ body }) => { |
| | | const { username, password } = body; |
| | | const checkUser = createFakeUserList().find( |
| | | (item) => item.username === username && password === item.password |
| | | (item) => item.username === username && password === item.password, |
| | | ); |
| | | if (!checkUser) { |
| | | return resultError('Incorrect account or password!'); |
| | |
| | | singleQuote: true, |
| | | quoteProps: 'as-needed', |
| | | bracketSpacing: true, |
| | | trailingComma: 'es5', |
| | | trailingComma: 'all', |
| | | jsxBracketSameLine: false, |
| | | jsxSingleQuote: false, |
| | | arrowParens: 'always', |
| | |
| | | proseWrap: 'never', |
| | | htmlWhitespaceSensitivity: 'strict', |
| | | endOfLine: 'auto', |
| | | rangeStart: 0, |
| | | }; |
| | |
| | | // support Multi-language |
| | | const { getAntdLocale } = useLocale(); |
| | | |
| | | // Listening to page changes and dynamically changing site titles |
| | | useTitle(); |
| | | </script> |
| | |
| | | */ |
| | | export function uploadApi( |
| | | params: UploadFileParams, |
| | | onUploadProgress: (progressEvent: ProgressEvent) => void |
| | | onUploadProgress: (progressEvent: ProgressEvent) => void, |
| | | ) { |
| | | return defHttp.uploadFile<UploadApiResult>( |
| | | { |
| | | url: uploadUrl, |
| | | onUploadProgress, |
| | | }, |
| | | params |
| | | params, |
| | | ); |
| | | } |
| | |
| | | }, |
| | | { |
| | | errorMessageMode: mode, |
| | | } |
| | | }, |
| | | ); |
| | | } |
| | | |
| | |
| | | <template> |
| | | <div v-if="getShowDarkModeToggle" :class="getClass" @click="toggleDarkMode"> |
| | | <div :class="`${prefixCls}-inner`"> </div> |
| | | <div :class="`${prefixCls}-inner`"></div> |
| | | <SvgIcon size="14" name="sun" /> |
| | | <SvgIcon size="14" name="moon" /> |
| | | </div> |
| | |
| | | nextTick(() => { |
| | | unref(inputRef)?.focus(); |
| | | }); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | function handleClose() { |
| | |
| | | const { prefixCls } = useDesign('basic-help'); |
| | | |
| | | const getTooltipStyle = computed( |
| | | (): CSSProperties => ({ color: props.color, fontSize: props.fontSize }) |
| | | (): CSSProperties => ({ color: props.color, fontSize: props.fontSize }), |
| | | ); |
| | | |
| | | const getOverlayStyle = computed((): CSSProperties => ({ maxWidth: props.maxWidth })); |
| | |
| | | okText: t('common.okText'), |
| | | cancelText: t('common.cancelText'), |
| | | }, |
| | | { ...props, ...unref(attrs) } |
| | | { ...props, ...unref(attrs) }, |
| | | ); |
| | | }); |
| | | |
| | |
| | | <template> |
| | | <div class="relative !h-full w-full overflow-hidden" ref="el"> </div> |
| | | <div class="relative !h-full w-full overflow-hidden" ref="el"></div> |
| | | </template> |
| | | |
| | | <script lang="ts" setup> |
| | |
| | | editor?.setValue(value ? value : ''); |
| | | } |
| | | }, |
| | | { flush: 'post' } |
| | | { flush: 'post' }, |
| | | ); |
| | | |
| | | watchEffect(() => { |
| | |
| | | }, |
| | | { |
| | | immediate: true, |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | function setTheme() { |
| | | unref(editor)?.setOption( |
| | | 'theme', |
| | | appStore.getDarkMode === 'light' ? 'idea' : 'material-palenight' |
| | | appStore.getDarkMode === 'light' ? 'idea' : 'material-palenight', |
| | | ); |
| | | } |
| | | |
| | |
| | | const getStyle = computed((): CSSProperties => ({ width: unref(getWidth) })); |
| | | |
| | | const getImageWrapperStyle = computed( |
| | | (): CSSProperties => ({ width: unref(getWidth), height: unref(getWidth) }) |
| | | (): CSSProperties => ({ width: unref(getWidth), height: unref(getWidth) }), |
| | | ); |
| | | |
| | | watchEffect(() => { |
| | |
| | | () => sourceValue.value, |
| | | (v: string) => { |
| | | emit('update:value', v); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | function handleUploadSuccess({ source }) { |
| | |
| | | // render |
| | | render?: ( |
| | | val: any, |
| | | data: Recordable |
| | | data: Recordable, |
| | | ) => VNode | undefined | JSX.Element | Element | string | number; |
| | | } |
| | | |
| | |
| | | (newVal, oldVal) => { |
| | | if (newVal !== oldVal) visibleRef.value = newVal; |
| | | }, |
| | | { deep: true } |
| | | { deep: true }, |
| | | ); |
| | | |
| | | watch( |
| | |
| | | emit('visible-change', visible); |
| | | instance && drawerInstance.emitVisible?.(visible, instance.uid); |
| | | }); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | // Cancel event |
| | |
| | | () => props.data, |
| | | () => { |
| | | onRender(); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | // TODO |
| | |
| | | () => unref(getFlowOptions), |
| | | (options) => { |
| | | unref(lfInstance)?.updateEditConfig(options); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | // init logicFlow |
| | |
| | | }); |
| | | |
| | | const getBindValue = computed( |
| | | () => ({ ...attrs, ...props, ...unref(getProps) } as Recordable) |
| | | () => ({ ...attrs, ...props, ...unref(getProps) } as Recordable), |
| | | ); |
| | | |
| | | const getSchema = computed((): FormSchema[] => { |
| | |
| | | }, |
| | | { |
| | | immediate: true, |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | watch( |
| | | () => unref(getProps).schemas, |
| | | (schemas) => { |
| | | resetSchema(schemas ?? []); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | watch( |
| | |
| | | initDefault(); |
| | | isInitedDefaultRef.value = true; |
| | | } |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | async function setProps(formProps: Partial<FormProps>): Promise<void> { |
| | |
| | | setFormModel, |
| | | getFormClass, |
| | | getFormActionBindProps: computed( |
| | | (): Recordable => ({ ...getProps.value, ...advanceState }) |
| | | (): Recordable => ({ ...getProps.value, ...advanceState }), |
| | | ), |
| | | ...formActionType, |
| | | }; |
| | |
| | | () => { |
| | | !unref(isFirstLoad) && fetch(); |
| | | }, |
| | | { deep: true } |
| | | { deep: true }, |
| | | ); |
| | | |
| | | async function fetch() { |
| | |
| | | () => { |
| | | isFirstLoaded.value && fetch(); |
| | | }, |
| | | { deep: true } |
| | | { deep: true }, |
| | | ); |
| | | |
| | | watch( |
| | | () => props.immediate, |
| | | (v) => { |
| | | v && !isFirstLoaded.value && fetch(); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | onMounted(() => { |
| | |
| | | { |
| | | text: t('common.resetText'), |
| | | }, |
| | | props.resetButtonOptions |
| | | props.resetButtonOptions, |
| | | ); |
| | | }); |
| | | |
| | |
| | | { |
| | | text: t('common.queryText'), |
| | | }, |
| | | props.submitButtonOptions |
| | | props.submitButtonOptions, |
| | | ); |
| | | }); |
| | | |
| | |
| | | } |
| | | |
| | | const requiredRuleIndex: number = rules.findIndex( |
| | | (rule) => Reflect.has(rule, 'required') && !Reflect.has(rule, 'validator') |
| | | (rule) => Reflect.has(rule, 'required') && !Reflect.has(rule, 'validator'), |
| | | ); |
| | | |
| | | if (requiredRuleIndex !== -1) { |
| | |
| | | export function setComponentRuleType( |
| | | rule: ValidationRule, |
| | | component: ComponentType, |
| | | valueFormat: string |
| | | valueFormat: string, |
| | | ) { |
| | | if (['DatePicker', 'MonthPicker', 'WeekPicker', 'TimePicker'].includes(component)) { |
| | | rule.type = valueFormat ? 'string' : 'object'; |
| | |
| | | debounceUpdateAdvanced(); |
| | | } |
| | | }, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | function getAdvanced(itemCol: Partial<ColEx>, itemColSum = 0, isLastAction = false) { |
| | |
| | | if (isShow && (colProps || baseColProps)) { |
| | | const { itemColSum: sum, isAdvanced } = getAdvanced( |
| | | { ...baseColProps, ...colProps }, |
| | | itemColSum |
| | | itemColSum, |
| | | ); |
| | | |
| | | itemColSum = sum || 0; |
| | |
| | | const form = unref(formRef); |
| | | if (!form) { |
| | | error( |
| | | 'The form instance has not been obtained, please make sure that the form has been rendered when performing the form operation!' |
| | | 'The form instance has not been obtained, please make sure that the form has been rendered when performing the form operation!', |
| | | ); |
| | | } |
| | | await nextTick(); |
| | |
| | | { |
| | | immediate: true, |
| | | deep: true, |
| | | } |
| | | }, |
| | | ); |
| | | } |
| | | |
| | |
| | | appendSchemaByField: async ( |
| | | schema: FormSchema, |
| | | prefixField: string | undefined, |
| | | first: boolean |
| | | first: boolean, |
| | | ) => { |
| | | const form = await getForm(); |
| | | form.appendSchemaByField(schema, prefixField, first); |
| | |
| | | } |
| | | |
| | | const hasField = updateData.every( |
| | | (item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field) |
| | | (item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field), |
| | | ); |
| | | |
| | | if (!hasField) { |
| | | error( |
| | | 'All children of the form Schema array that need to be updated must contain the `field` field' |
| | | 'All children of the form Schema array that need to be updated must contain the `field` field', |
| | | ); |
| | | return; |
| | | } |
| | |
| | | } |
| | | |
| | | const hasField = updateData.every( |
| | | (item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field) |
| | | (item) => item.component === 'Divider' || (Reflect.has(item, 'field') && item.field), |
| | | ); |
| | | |
| | | if (!hasField) { |
| | | error( |
| | | 'All children of the form Schema array that need to be updated must contain the `field` field' |
| | | 'All children of the form Schema array that need to be updated must contain the `field` field', |
| | | ); |
| | | return; |
| | | } |
| | |
| | | appendSchemaByField: ( |
| | | schema: FormSchema, |
| | | prefixField: string | undefined, |
| | | first?: boolean | undefined |
| | | first?: boolean | undefined, |
| | | ) => Promise<void>; |
| | | validateFields: (nameList?: NamePath[]) => Promise<any>; |
| | | validate: (nameList?: NamePath[]) => Promise<any>; |
| | |
| | | </div> |
| | | </div> |
| | | <template v-else |
| | | ><div class="p-5"> <Empty /></div> |
| | | ><div class="p-5"><Empty /></div> |
| | | </template> |
| | | </template> |
| | | |
| | |
| | | |
| | | const { getPaginationList, getTotal, setCurrentPage } = usePagination( |
| | | currentList, |
| | | props.pageSize |
| | | props.pageSize, |
| | | ); |
| | | |
| | | watchEffect(() => { |
| | |
| | | (v) => { |
| | | emit('update:value', v); |
| | | return emit('change', v); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | function handlePageChange(page: number) { |
| | |
| | | export function useLoading(opt: Partial<UseLoadingOptions>): [Fn, Fn, (string) => void]; |
| | | |
| | | export function useLoading( |
| | | opt: Partial<LoadingProps> | Partial<UseLoadingOptions> |
| | | opt: Partial<LoadingProps> | Partial<UseLoadingOptions>, |
| | | ): [Fn, Fn, (string) => void] { |
| | | let props: Partial<LoadingProps>; |
| | | let target: HTMLElement | Ref<ElRef> = document.body; |
| | |
| | | { |
| | | immediate: true, |
| | | flush: 'post', |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | watch( |
| | |
| | | instance.getVditor()?.setValue(v); |
| | | } |
| | | valueRef.value = v; |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | const getCurrentLang = computed((): 'zh_CN' | 'en_US' | 'ja_JP' | 'ko_KR' => { |
| | |
| | | menuState, |
| | | items, |
| | | mode as any, |
| | | accordion |
| | | accordion, |
| | | ); |
| | | |
| | | const getIsTopMenu = computed(() => { |
| | |
| | | () => props.items, |
| | | () => { |
| | | handleMenuChange(); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | async function handleMenuClick({ key }: { key: string; keyPath: string[] }) { |
| | |
| | | menuState: MenuState, |
| | | menus: Ref<MenuType[]>, |
| | | mode: Ref<MenuModeEnum>, |
| | | accordion: Ref<boolean> |
| | | accordion: Ref<boolean>, |
| | | ) { |
| | | const { getCollapsed, getIsMixSidebar } = useMenuSetting(); |
| | | |
| | |
| | | } |
| | | }, |
| | | 16, |
| | | !native |
| | | !native, |
| | | ); |
| | | } |
| | | |
| | |
| | | }, |
| | | { |
| | | immediate: false, |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | // 取消事件 |
| | |
| | | { |
| | | attributes: true, |
| | | subtree: true, |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | createModalContext({ |
| | |
| | | } else { |
| | | minRealHeightRef.value = realHeightRef.value; |
| | | } |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | onMounted(() => { |
| | |
| | | |
| | | provide( |
| | | PageWrapperFixedHeightKey, |
| | | computed(() => props.fixedHeight) |
| | | computed(() => props.fixedHeight), |
| | | ); |
| | | |
| | | const getIsContentFullHeight = computed(() => { |
| | |
| | | getIsContentFullHeight, |
| | | wrapperRef, |
| | | [headerRef, footerRef], |
| | | [contentRef] |
| | | [contentRef], |
| | | ); |
| | | setCompensation({ useLayoutFooter: true, elements: [footerRef] }); |
| | | |
| | |
| | | { |
| | | flush: 'post', |
| | | immediate: true, |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | return { |
| | |
| | | }, |
| | | { |
| | | deep: true, |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | return { wrapRef, download }; |
| | |
| | | canvas, |
| | | content, |
| | | width = 0, |
| | | options: params = {} |
| | | options: params = {}, |
| | | }: RenderQrCodeParams) => { |
| | | const options = cloneDeep(params) |
| | | const options = cloneDeep(params); |
| | | // 容错率,默认对内容少的二维码采用高容错率,内容多的二维码采用低容错率 |
| | | options.errorCorrectionLevel = options.errorCorrectionLevel || getErrorCorrectionLevel(content); |
| | | |
| | |
| | | |
| | | const clickTrackHandler = (e: any) => { |
| | | const offset = Math.abs( |
| | | e.target.getBoundingClientRect()[bar.value.direction] - e[bar.value.client] |
| | | e.target.getBoundingClientRect()[bar.value.direction] - e[bar.value.client], |
| | | ); |
| | | const thumbHalf = thumb.value[bar.value.offset] / 2; |
| | | const thumbPositionPercentage = |
| | |
| | | move: props.move, |
| | | bar: bar.value, |
| | | }), |
| | | }) |
| | | }), |
| | | ); |
| | | }, |
| | | }); |
| | |
| | | items, |
| | | accordion, |
| | | mixSider, |
| | | collapse |
| | | collapse, |
| | | ); |
| | | |
| | | const getBindValues = computed(() => ({ ...attrs, ...props })); |
| | |
| | | setOpenKeys(currentRoute.value.path); |
| | | } |
| | | }, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | watch( |
| | |
| | | } |
| | | setOpenKeys(currentRoute.value.path); |
| | | }, |
| | | { flush: 'post' } |
| | | { flush: 'post' }, |
| | | ); |
| | | |
| | | listenerRouteChange((route) => { |
| | |
| | | nextTick(() => { |
| | | updateOpened(); |
| | | }); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | function updateOpened() { |
| | |
| | | active.value = false; |
| | | } |
| | | }, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | return { getClass, prefixCls, getItemStyle, getCollapse, handleClickItem, showTooptip }; |
| | |
| | | if (props.name && Array.isArray(data)) { |
| | | state.opened = (data as (string | number)[]).includes(props.name); |
| | | } |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | rootMenuEmitter.on('on-update-active-name:submenu', (data: number[]) => { |
| | |
| | | menus: Ref<MenuType[]>, |
| | | accordion: Ref<boolean>, |
| | | mixSider: Ref<boolean>, |
| | | collapse: Ref<boolean> |
| | | collapse: Ref<boolean>, |
| | | ) { |
| | | const debounceSetOpenKeys = useDebounceFn(setOpenKeys, 50); |
| | | async function setOpenKeys(path: string) { |
| | |
| | | menuState.activeSubMenuNames = menuState.openNames; |
| | | }, |
| | | 30, |
| | | native |
| | | native, |
| | | ); |
| | | } |
| | | |
| | |
| | | () => unref(innerValueRef), |
| | | (val) => { |
| | | emit('change', val); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | return { |
| | |
| | | unref(isFixedHeightPage) && |
| | | props.canResize && |
| | | warn( |
| | | "'canResize' of BasicTable may not work in PageWrapper with 'fixedHeight' (especially in hot updates)" |
| | | "'canResize' of BasicTable may not work in PageWrapper with 'fixedHeight' (especially in hot updates)", |
| | | ); |
| | | }); |
| | | |
| | |
| | | getFieldsValue: formActions.getFieldsValue, |
| | | clearSelectedRowKeys, |
| | | }, |
| | | emit |
| | | emit, |
| | | ); |
| | | |
| | | function handleTableChange(...args) { |
| | |
| | | tableElRef, |
| | | getColumnsRef, |
| | | getRowSelectionRef, |
| | | getDataSourceRef |
| | | getDataSourceRef, |
| | | ); |
| | | |
| | | const { customRow } = useCustomRow(getProps, { |
| | |
| | | getProps, |
| | | getScrollRef, |
| | | tableElRef, |
| | | getDataSourceRef |
| | | getDataSourceRef, |
| | | ); |
| | | |
| | | const { getFormProps, replaceFormSlotKey, getFormSlotKeys, handleSearchInfoChange } = |
| | |
| | | popoverVisible, |
| | | getPopupContainer, |
| | | }: ComponentProps, |
| | | { attrs } |
| | | { attrs }, |
| | | ) => { |
| | | const Comp = componentMap.get(component) as typeof defineComponent; |
| | | |
| | |
| | | { |
| | | default: () => DefaultComp, |
| | | content: () => ruleMessage, |
| | | } |
| | | }, |
| | | ); |
| | | }; |
| | |
| | | :class="{ [`${prefixCls}__normal`]: true, 'ellipsis-cell': column.ellipsis }" |
| | | @click="handleEdit" |
| | | > |
| | | <div class="cell-content" :title="column.ellipsis ? getValues ?? '' : ''">{{ |
| | | getValues ? getValues : ' ' |
| | | }}</div> |
| | | <div class="cell-content" :title="column.ellipsis ? getValues ?? '' : ''"> |
| | | {{ getValues ? getValues : ' ' }} |
| | | </div> |
| | | <FormOutlined :class="`${prefixCls}__normal-icon`" v-if="!column.editRow" /> |
| | | </div> |
| | | |
| | |
| | | const visible = |
| | | columns.findIndex( |
| | | (c: BasicColumn | string) => |
| | | c === col.value || (typeof c !== 'string' && c.dataIndex === col.value) |
| | | c === col.value || (typeof c !== 'string' && c.dataIndex === col.value), |
| | | ) !== -1; |
| | | return { dataIndex: col.value, fixed: col.fixed, visible }; |
| | | }); |
| | |
| | | function handleIndexColumn( |
| | | propsRef: ComputedRef<BasicTableProps>, |
| | | getPaginationRef: ComputedRef<boolean | PaginationProps>, |
| | | columns: BasicColumn[] |
| | | columns: BasicColumn[], |
| | | ) { |
| | | const { t } = useI18n(); |
| | | |
| | |
| | | |
| | | export function useColumns( |
| | | propsRef: ComputedRef<BasicTableProps>, |
| | | getPaginationRef: ComputedRef<boolean | PaginationProps> |
| | | getPaginationRef: ComputedRef<boolean | PaginationProps>, |
| | | ) { |
| | | const columnsRef = ref(unref(propsRef).columns) as unknown as Ref<BasicColumn[]>; |
| | | let cacheColumns = unref(propsRef).columns; |
| | |
| | | |
| | | handleItem( |
| | | item, |
| | | Reflect.has(item, 'ellipsis') ? !!item.ellipsis : !!ellipsis && !customRender && !slots |
| | | Reflect.has(item, 'ellipsis') ? !!item.ellipsis : !!ellipsis && !customRender && !slots, |
| | | ); |
| | | }); |
| | | return columns; |
| | |
| | | (columns) => { |
| | | columnsRef.value = columns; |
| | | cacheColumns = columns?.filter((item) => !item.flag) ?? []; |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | function setCacheColumnsByField(dataIndex: string | undefined, value: Partial<BasicColumn>) { |
| | |
| | | defColumns.push(column); |
| | | } |
| | | return [...fixedLeftColumns, ...defColumns, ...fixedRightColumns].filter( |
| | | (item) => !item.defaultHidden |
| | | (item) => !item.defaultHidden, |
| | | ); |
| | | } |
| | | |
| | |
| | | function getKey( |
| | | record: Recordable, |
| | | rowKey: string | ((record: Record<string, any>) => string) | undefined, |
| | | autoCreateKey?: boolean |
| | | autoCreateKey?: boolean, |
| | | ) { |
| | | if (!rowKey || autoCreateKey) { |
| | | return record[ROW_KEY]; |
| | |
| | | |
| | | export function useCustomRow( |
| | | propsRef: ComputedRef<BasicTableProps>, |
| | | { setSelectedRowKeys, getSelectRowKeys, getAutoCreateKey, clearSelectedRowKeys, emit }: Options |
| | | { setSelectedRowKeys, getSelectRowKeys, getAutoCreateKey, clearSelectedRowKeys, emit }: Options, |
| | | ) { |
| | | const customRow = (record: Recordable, index: number) => { |
| | | return { |
| | |
| | | clearSelectedRowKeys, |
| | | tableData, |
| | | }: ActionType, |
| | | emit: EmitType |
| | | emit: EmitType, |
| | | ) { |
| | | const searchState = reactive<SearchState>({ |
| | | sortInfo: {}, |
| | |
| | | }, |
| | | { |
| | | immediate: true, |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | function handleTableChange( |
| | | pagination: PaginationProps, |
| | | filters: Partial<Recordable<string[]>>, |
| | | sorter: SorterResult |
| | | sorter: SorterResult, |
| | | ) { |
| | | const { clearSelectOnPageChange, sortFn, filterFn } = unref(propsRef); |
| | | if (clearSelectOnPageChange) { |
| | |
| | | |
| | | function updateTableDataRecord( |
| | | rowKey: string | number, |
| | | record: Recordable |
| | | record: Recordable, |
| | | ): Recordable | undefined { |
| | | const row = findTableDataRecord(rowKey); |
| | | |
| | |
| | | const { pageField, sizeField, listField, totalField } = Object.assign( |
| | | {}, |
| | | FETCH_SETTING, |
| | | fetchSetting |
| | | fetchSetting, |
| | | ); |
| | | let pageParams: Recordable = {}; |
| | | |
| | |
| | | () => unref(props).loading, |
| | | (loading) => { |
| | | loadingRef.value = loading; |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | const getLoading = computed(() => unref(loadingRef)); |
| | |
| | | export function useRowSelection( |
| | | propsRef: ComputedRef<BasicTableProps>, |
| | | tableData: Ref<Recordable[]>, |
| | | emit: EmitType |
| | | emit: EmitType, |
| | | ) { |
| | | const selectedRowKeysRef = ref<string[]>([]); |
| | | const selectedRowRef = ref<Recordable[]>([]); |
| | |
| | | () => unref(propsRef).rowSelection?.selectedRowKeys, |
| | | (v: string[]) => { |
| | | setSelectedRowKeys(v); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | watch( |
| | |
| | | }); |
| | | }); |
| | | }, |
| | | { deep: true } |
| | | { deep: true }, |
| | | ); |
| | | |
| | | const getAutoCreateKey = computed(() => { |
| | |
| | | (item) => rowKeys.includes(item[unref(getRowKey) as string]), |
| | | { |
| | | children: propsRef.value.childrenColumnName ?? 'children', |
| | | } |
| | | }, |
| | | ); |
| | | const trueSelectedRows: any[] = []; |
| | | rowKeys.forEach((key: string) => { |
| | |
| | | (instance: TableActionType, formInstance: UseTableMethod) => void, |
| | | TableActionType & { |
| | | getForm: () => FormActionType; |
| | | } |
| | | }, |
| | | ] { |
| | | const tableRef = ref<Nullable<TableActionType>>(null); |
| | | const loadedRef = ref<Nullable<boolean>>(false); |
| | |
| | | { |
| | | immediate: true, |
| | | deep: true, |
| | | } |
| | | }, |
| | | ); |
| | | } |
| | | |
| | |
| | | const table = unref(tableRef); |
| | | if (!table) { |
| | | error( |
| | | 'The table instance has not been obtained yet, please make sure the table is presented when performing the table operation!' |
| | | 'The table instance has not been obtained yet, please make sure the table is presented when performing the table operation!', |
| | | ); |
| | | } |
| | | return table as TableActionType; |
| | |
| | | export function useTableExpand( |
| | | propsRef: ComputedRef<BasicTableProps>, |
| | | tableData: Ref<Recordable[]>, |
| | | emit: EmitType |
| | | emit: EmitType, |
| | | ) { |
| | | const expandedRowKeys = ref<string[]>([]); |
| | | |
| | |
| | | scrollToFirstRowOnChange: boolean; |
| | | }>, |
| | | tableElRef: Ref<ComponentRef>, |
| | | getDataSourceRef: ComputedRef<Recordable> |
| | | getDataSourceRef: ComputedRef<Recordable>, |
| | | ) { |
| | | const getIsEmptyData = computed(() => { |
| | | return (unref(getDataSourceRef) || []).length === 0; |
| | |
| | | name: 'scroll', |
| | | listener: () => { |
| | | const footerBodyDom = tableEl.$el.querySelector( |
| | | '.ant-table-footer .ant-table-body' |
| | | '.ant-table-footer .ant-table-body', |
| | | ) as HTMLDivElement; |
| | | if (!footerBodyDom || !bodyDom) return; |
| | | footerBodyDom.scrollLeft = bodyDom.scrollLeft; |
| | |
| | | propsRef: ComputedRef<BasicTableProps>, |
| | | slots: Slots, |
| | | fetch: (opt?: FetchParams | undefined) => Promise<void>, |
| | | getLoading: ComputedRef<boolean | undefined> |
| | | getLoading: ComputedRef<boolean | undefined>, |
| | | ) { |
| | | const getFormProps = computed((): Partial<FormProps> => { |
| | | const { formConfig } = unref(propsRef); |
| | |
| | | export function useTableHeader( |
| | | propsRef: ComputedRef<BasicTableProps>, |
| | | slots: Slots, |
| | | handlers: InnerHandlers |
| | | handlers: InnerHandlers, |
| | | ) { |
| | | const getHeaderProps = computed((): Recordable => { |
| | | const { title, showTableSetting, titleHelpMessage, tableSetting } = unref(propsRef); |
| | |
| | | headerTop: () => getSlot(slots, 'headerTop'), |
| | | } |
| | | : {}), |
| | | } |
| | | }, |
| | | ), |
| | | }; |
| | | }); |
| | |
| | | tableElRef: Ref<ComponentRef>, |
| | | columnsRef: ComputedRef<BasicColumn[]>, |
| | | rowSelectionRef: ComputedRef<TableRowSelection<any> | null>, |
| | | getDataSourceRef: ComputedRef<Recordable[]> |
| | | getDataSourceRef: ComputedRef<Recordable[]>, |
| | | ) { |
| | | const tableHeightRef: Ref<Nullable<number>> = ref(null); |
| | | |
| | |
| | | }, |
| | | { |
| | | flush: 'post', |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | function redoHeight() { |
| | |
| | | () => { |
| | | setTime(); |
| | | }, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | function getTime() { |
| | |
| | | return; |
| | | } |
| | | editor.setMode(attrs.disabled ? 'readonly' : 'design'); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | onMountedOrActivated(() => { |
| | |
| | | () => props.modelValue, |
| | | (val: string, prevVal: string) => { |
| | | setValue(editor, val, prevVal); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | watch( |
| | |
| | | }, |
| | | { |
| | | immediate: true, |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | editor.on(normalizedEvents ? normalizedEvents : 'change keyup undo redo', () => { |
| | |
| | | |
| | | export const ExpandXTransition = createJavascriptTransition( |
| | | 'expand-x-transition', |
| | | ExpandTransitionGenerator('', true) |
| | | ExpandTransitionGenerator('', true), |
| | | ); |
| | | |
| | | export const ExpandTransition = createJavascriptTransition( |
| | | 'expand-transition', |
| | | ExpandTransitionGenerator('') |
| | | ExpandTransitionGenerator(''), |
| | | ); |
| | |
| | | export function createJavascriptTransition( |
| | | name: string, |
| | | functions: Recordable, |
| | | mode: Mode = 'in-out' |
| | | mode: Mode = 'in-out', |
| | | ) { |
| | | return defineComponent({ |
| | | name, |
| | |
| | | }); |
| | | |
| | | const getTreeData = computed((): TreeItem[] => |
| | | searchState.startSearch ? searchState.searchData : unref(treeDataRef) |
| | | searchState.startSearch ? searchState.searchData : unref(treeDataRef), |
| | | ); |
| | | |
| | | const getNotFound = computed((): boolean => { |
| | |
| | | (node) => { |
| | | return node[titleField]?.includes(searchValue) ?? false; |
| | | }, |
| | | unref(getReplaceFields) |
| | | unref(getReplaceFields), |
| | | ); |
| | | } |
| | | |
| | |
| | | () => props.value, |
| | | () => { |
| | | state.checkedKeys = toRaw(props.value || []); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | watch( |
| | |
| | | const v = toRaw(state.checkedKeys); |
| | | emit('update:value', v); |
| | | emit('change', v); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | // watchEffect(() => { |
| | |
| | | () => searchValue.value, |
| | | (v) => { |
| | | debounceEmitChange(v); |
| | | } |
| | | }, |
| | | ); |
| | | watch( |
| | | () => props.searchText, |
| | |
| | | if (v !== searchValue.value) { |
| | | searchValue.value = v; |
| | | } |
| | | } |
| | | }, |
| | | ); |
| | | // function handleSearch(e: ChangeEvent): void { |
| | | // debounceEmitChange(e.target.value); |
| | |
| | | |
| | | export function useTree( |
| | | treeDataRef: Ref<TreeDataItem[]>, |
| | | getReplaceFields: ComputedRef<ReplaceFields> |
| | | getReplaceFields: ComputedRef<ReplaceFields>, |
| | | ) { |
| | | function getAllKeys(list?: TreeDataItem[]) { |
| | | const keys: string[] = []; |
| | |
| | | (value = []) => { |
| | | fileList.value = isArray(value) ? value : []; |
| | | }, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | // 上传modal保存操作 |
| | |
| | | nextTick(() => { |
| | | modalFn?.redoModalHeight?.(); |
| | | }); |
| | | } |
| | | }, |
| | | ); |
| | | return () => { |
| | | const { columns, actionColumn, dataSource } = props; |
| | |
| | | |
| | | const getOkButtonProps = computed(() => { |
| | | const someSuccess = fileListRef.value.some( |
| | | (item) => item.status === UploadResultStatus.SUCCESS |
| | | (item) => item.status === UploadResultStatus.SUCCESS, |
| | | ); |
| | | return { |
| | | disabled: isUploadingRef.value || fileListRef.value.length === 0 || !someSuccess, |
| | |
| | | |
| | | const getUploadBtnText = computed(() => { |
| | | const someError = fileListRef.value.some( |
| | | (item) => item.status === UploadResultStatus.ERROR |
| | | (item) => item.status === UploadResultStatus.ERROR, |
| | | ); |
| | | return isUploadingRef.value |
| | | ? t('component.upload.uploading') |
| | |
| | | function onUploadProgress(progressEvent: ProgressEvent) { |
| | | const complete = ((progressEvent.loaded / progressEvent.total) * 100) | 0; |
| | | item.percent = complete; |
| | | } |
| | | }, |
| | | ); |
| | | item.status = UploadResultStatus.SUCCESS; |
| | | item.responseData = data; |
| | |
| | | const data = await Promise.all( |
| | | uploadFileList.map((item) => { |
| | | return uploadApiByItem(item); |
| | | }) |
| | | }), |
| | | ); |
| | | isUploadingRef.value = false; |
| | | // 生产环境:抛出错误 |
| | |
| | | }; |
| | | }); |
| | | }, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | // 删除 |
| | |
| | | emit('delete', removed[0].url); |
| | | emit( |
| | | 'list-change', |
| | | fileListRef.value.map((item) => item.url) |
| | | fileListRef.value.map((item) => item.url), |
| | | ); |
| | | } |
| | | } |
| | |
| | | emit('update:value', isPassing); |
| | | emit('change', isPassing); |
| | | } |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | watchEffect(() => { |
| | |
| | | emit('change', isPassing); |
| | | emit('update:value', isPassing); |
| | | } |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | const getImgWrapStyleRef = computed(() => { |
| | |
| | | const { imgWidth, height, maxDegree } = props; |
| | | const { moveX } = data; |
| | | const currentRotate = Math.ceil( |
| | | (moveX / (imgWidth! - parseInt(height as string))) * maxDegree! * unref(getFactorRef) |
| | | (moveX / (imgWidth! - parseInt(height as string))) * maxDegree! * unref(getFactorRef), |
| | | ); |
| | | state.currentRotate = currentRotate; |
| | | state.imgStyle = hackCss('transform', `rotateZ(${state.randomRotate - currentRotate}deg)`); |
| | |
| | | loading: !!binding.value, |
| | | absolute: !fullscreen, |
| | | }, |
| | | fullscreen ? document.body : el |
| | | fullscreen ? document.body : el, |
| | | ); |
| | | el.instance = instance; |
| | | }, |
| | |
| | | props: T, |
| | | key: keyof T = 'value', |
| | | changeEvent = 'change', |
| | | emitData?: Ref<any[]> |
| | | emitData?: Ref<any[]>, |
| | | ) { |
| | | const instance = getCurrentInstance(); |
| | | const emit = instance?.emit; |
| | |
| | | export function createContext<T>( |
| | | context: any, |
| | | key: InjectionKey<T> = Symbol(), |
| | | options: CreateContextOptions = {} |
| | | options: CreateContextOptions = {}, |
| | | ) { |
| | | const { readonly = true, createProvider = false, native = false } = options; |
| | | |
| | |
| | | |
| | | export function useContext<T>( |
| | | key: InjectionKey<T> = Symbol(), |
| | | defaultValue?: any |
| | | defaultValue?: any, |
| | | ): ShallowUnwrap<T> { |
| | | return inject(key, defaultValue || {}); |
| | | } |
| | |
| | | import { ref, unref } from 'vue'; |
| | | |
| | | export function useLockFn<P extends any[] = any[], V extends any = any>( |
| | | fn: (...args: P) => Promise<V> |
| | | fn: (...args: P) => Promise<V>, |
| | | ) { |
| | | const lockRef = ref(false); |
| | | return async function (...args: P) { |
| | |
| | | (maturity) => { |
| | | maturity && handle(); |
| | | }, |
| | | { immediate: false } |
| | | { immediate: false }, |
| | | ); |
| | | } |
| | | return { readyRef, stop, start }; |
| | |
| | | }); |
| | | } |
| | | }, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | remove = () => { |
| | |
| | | wait?: number; |
| | | leading?: boolean; |
| | | trailing?: boolean; |
| | | } |
| | | }, |
| | | ) { |
| | | const refX = ref(0); |
| | | const refY = ref(0); |
| | |
| | | el && el.removeEventListener('scroll', handler); |
| | | }); |
| | | }, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | }); |
| | | |
| | |
| | | |
| | | if (!/[a-zA-Z\_]*/.test(VITE_GLOB_APP_SHORT_NAME)) { |
| | | warn( |
| | | `VITE_GLOB_APP_SHORT_NAME Variables can only be characters/underscores, please modify in the environment variables and re-running.` |
| | | `VITE_GLOB_APP_SHORT_NAME Variables can only be characters/underscores, please modify in the environment variables and re-running.`, |
| | | ); |
| | | } |
| | | |
| | |
| | | const getTopMenuAlign = computed(() => appStore.getMenuSetting.topMenuAlign); |
| | | |
| | | const getCloseMixSidebarOnChange = computed( |
| | | () => appStore.getMenuSetting.closeMixSidebarOnChange |
| | | () => appStore.getMenuSetting.closeMixSidebarOnChange, |
| | | ); |
| | | |
| | | const getIsSidebarType = computed(() => unref(getMenuType) === MenuTypeEnum.SIDEBAR); |
| | |
| | | const getLayoutContentMode = computed(() => |
| | | appStore.getProjectConfig.contentMode === ContentEnum.FULL |
| | | ? ContentEnum.FULL |
| | | : ContentEnum.FIXED |
| | | : ContentEnum.FIXED, |
| | | ); |
| | | |
| | | function setRootSetting(setting: Partial<RootSetting>) { |
| | |
| | | anchorRef: Ref, |
| | | subtractHeightRefs: Ref[], |
| | | substractSpaceRefs: Ref[], |
| | | offsetHeightRef: Ref<number> = ref(0) |
| | | offsetHeightRef: Ref<number> = ref(0), |
| | | ) { |
| | | const contentHeight: Ref<Nullable<number>> = ref(null); |
| | | const { footerHeightRef: layoutFooterHeightRef } = useLayoutHeight(); |
| | |
| | | calcContentHeight(); |
| | | }, |
| | | 50, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | watch( |
| | | () => [layoutFooterHeightRef.value], |
| | |
| | | { |
| | | flush: 'post', |
| | | immediate: true, |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | return { redoHeight, setCompensation, contentHeight }; |
| | |
| | | isSuccessRef.value = copyTextToClipboard(str); |
| | | } |
| | | }, |
| | | { immediate: !!initial, flush: 'sync' } |
| | | { immediate: !!initial, flush: 'sync' }, |
| | | ); |
| | | |
| | | return { clipboardRef, isSuccessRef, copiedRef }; |
| | |
| | | |
| | | export function useECharts( |
| | | elRef: Ref<HTMLDivElement>, |
| | | theme: 'light' | 'dark' | 'default' = 'default' |
| | | theme: 'light' | 'dark' | 'default' = 'default', |
| | | ) { |
| | | const { getDarkMode: getSysDarkMode } = useRootSetting(); |
| | | |
| | |
| | | initCharts(theme as 'default'); |
| | | setOptions(cacheOptions.value); |
| | | } |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | tryOnUnmounted(() => { |
| | |
| | | async function changeRole(roles: RoleEnum | RoleEnum[]): Promise<void> { |
| | | if (projectSetting.permissionMode !== PermissionModeEnum.ROUTE_MAPPING) { |
| | | throw new Error( |
| | | 'Please switch PermissionModeEnum to ROUTE_MAPPING mode in the configuration to operate!' |
| | | 'Please switch PermissionModeEnum to ROUTE_MAPPING mode in the configuration to operate!', |
| | | ); |
| | | } |
| | | |
| | |
| | | |
| | | import { REDIRECT_NAME } from '/@/router/constant'; |
| | | |
| | | /** |
| | | * Listening to page changes and dynamically changing site titles |
| | | */ |
| | | export function useTitle() { |
| | | const { title } = useGlobSetting(); |
| | | const { t } = useI18n(); |
| | |
| | | () => currentRoute.value.path, |
| | | () => { |
| | | const route = unref(currentRoute); |
| | | |
| | | if (route.name === REDIRECT_NAME) { |
| | | return; |
| | | } |
| | |
| | | const tTitle = t(route?.meta?.title as string); |
| | | pageTitle.value = tTitle ? ` ${tTitle} - ${title} ` : `${title}`; |
| | | }, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | } |
| | |
| | | const domSymbol = Symbol('watermark-dom'); |
| | | |
| | | export function useWatermark( |
| | | appendEl: Ref<HTMLElement | null> = ref(document.body) as Ref<HTMLElement> |
| | | appendEl: Ref<HTMLElement | null> = ref(document.body) as Ref<HTMLElement>, |
| | | ) { |
| | | const func = useRafThrottle(function () { |
| | | const el = unref(appendEl); |
| | |
| | | width?: number; |
| | | height?: number; |
| | | str?: string; |
| | | } = {} |
| | | } = {}, |
| | | ) { |
| | | const el = unref(watermarkEl); |
| | | if (!el) return; |
| | |
| | | contentHeight.value = window.innerHeight; |
| | | }, |
| | | 100, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | |
| | | async function setPageHeight(height: number) { |
| | |
| | | () => props.currentPage, |
| | | (v) => { |
| | | current.value = v; |
| | | } |
| | | }, |
| | | ); |
| | | const isTitleClickable = computed(() => !!props.onTitleClick); |
| | | const getPagination = computed(() => { |
| | |
| | | const { getIsMobile } = useAppInject(); |
| | | |
| | | const getComputedMenuMode = computed(() => |
| | | unref(getIsMobile) ? MenuModeEnum.INLINE : props.menuMode || unref(getMenuMode) |
| | | unref(getIsMobile) ? MenuModeEnum.INLINE : props.menuMode || unref(getMenuMode), |
| | | ); |
| | | |
| | | const getComputedMenuTheme = computed(() => props.theme || unref(getMenuTheme)); |
| | |
| | | const throttleHandleSplitLeftMenu = useThrottleFn(handleSplitLeftMenu, 50); |
| | | |
| | | const splitNotLeft = computed( |
| | | () => unref(splitType) !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontal) |
| | | () => unref(splitType) !== MenuSplitTyeEnum.LEFT && !unref(getIsHorizontal), |
| | | ); |
| | | |
| | | const getSplitLeft = computed( |
| | | () => !unref(getSplit) || unref(splitType) !== MenuSplitTyeEnum.LEFT |
| | | () => !unref(getSplit) || unref(splitType) !== MenuSplitTyeEnum.LEFT, |
| | | ); |
| | | |
| | | const getSpiltTop = computed(() => unref(splitType) === MenuSplitTyeEnum.TOP); |
| | |
| | | }, |
| | | { |
| | | immediate: true, |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | // Menu changes |
| | |
| | | }, |
| | | { |
| | | immediate: true, |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | // split Menu changes |
| | |
| | | () => { |
| | | if (unref(splitNotLeft)) return; |
| | | genMenus(); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | // Handle left menu split |
| | |
| | | |
| | | function handleCopy() { |
| | | const { isSuccessRef } = useCopyToClipboard( |
| | | JSON.stringify(unref(appStore.getProjectConfig), null, 2) |
| | | JSON.stringify(unref(appStore.getProjectConfig), null, 2), |
| | | ); |
| | | unref(isSuccessRef) && |
| | | createSuccessModal({ |
| | |
| | | const getIsUnFold = computed(() => !unref(getShowMenu) && !unref(getShowHeader)); |
| | | |
| | | const getIcon = computed(() => |
| | | unref(getIsUnFold) ? 'codicon:screen-normal' : 'codicon:screen-full' |
| | | unref(getIsUnFold) ? 'codicon:screen-normal' : 'codicon:screen-full', |
| | | ); |
| | | |
| | | function handleFold() { |
| | |
| | | const getIsTabs = computed(() => !props.isExtra); |
| | | |
| | | const getTrigger = computed((): ('contextmenu' | 'click' | 'hover')[] => |
| | | unref(getIsTabs) ? ['contextmenu'] : ['click'] |
| | | unref(getIsTabs) ? ['contextmenu'] : ['click'], |
| | | ); |
| | | |
| | | const { getDropMenuList, handleMenuEvent, handleContextMenu } = useTabDropdown( |
| | | props as TabContentProps, |
| | | getIsTabs |
| | | getIsTabs, |
| | | ); |
| | | |
| | | function handleContext(e) { |
| | |
| | | source?: string, |
| | | lineno?: number, |
| | | colno?: number, |
| | | error?: Error |
| | | error?: Error, |
| | | ) { |
| | | if (event === 'Script error.' && !source) { |
| | | return false; |
| | |
| | | message: event.reason, |
| | | }); |
| | | }, |
| | | true |
| | | true, |
| | | ); |
| | | } |
| | | |
| | |
| | | message: (e.target || ({} as any)).localName + ' is load error', |
| | | }); |
| | | }, |
| | | true |
| | | true, |
| | | ); |
| | | } |
| | | |
| | |
| | | |
| | | export function listenerRouteChange( |
| | | callback: (route: RouteLocationNormalized) => void, |
| | | immediate = true |
| | | immediate = true, |
| | | ) { |
| | | emitter.on(key, callback); |
| | | immediate && lastChangeTab && callback(lastChangeTab); |
| | |
| | | import 'virtual:windi-base.css'; |
| | | import 'virtual:windi-components.css'; |
| | | import 'virtual:windi-utilities.css'; |
| | | import 'virtual:windi-devtools'; |
| | | // Register icon sprite |
| | | import 'virtual:svg-icons-register'; |
| | | import App from './App.vue'; |
| | |
| | | // https://next.router.vuejs.org/api/#isready |
| | | // await router.isReady(); |
| | | |
| | | app.mount('#app', true); |
| | | app.mount('#app'); |
| | | } |
| | | |
| | | bootstrap(); |
| | |
| | | |
| | | function dynamicImport( |
| | | dynamicViewsModules: Record<string, () => Promise<Recordable>>, |
| | | component: string |
| | | component: string, |
| | | ) { |
| | | const keys = Object.keys(dynamicViewsModules); |
| | | const matchKeys = keys.filter((key) => { |
| | |
| | | } |
| | | if (matchKeys?.length > 1) { |
| | | warn( |
| | | 'Please do not create `.vue` and `.TSX` files with the same file name in the same hierarchical directory under the views folder. This will cause dynamic introduction failure' |
| | | 'Please do not create `.vue` and `.TSX` files with the same file name in the same hierarchical directory under the views folder. This will cause dynamic introduction failure', |
| | | ); |
| | | return; |
| | | } |
| | |
| | | function addToChildren( |
| | | routes: RouteRecordNormalized[], |
| | | children: AppRouteRecordRaw[], |
| | | routeModule: AppRouteModule |
| | | routeModule: AppRouteModule, |
| | | ) { |
| | | for (let index = 0; index < children.length; index++) { |
| | | const child = children[index]; |
| | |
| | | params: LoginParams & { |
| | | goHome?: boolean; |
| | | mode?: ErrorMessageMode; |
| | | } |
| | | }, |
| | | ): Promise<GetUserInfoModel | null> { |
| | | try { |
| | | const { goHome = true, mode, ...loginParams } = params; |
| | |
| | | () => { |
| | | this.remove(key); |
| | | }, |
| | | expires > now ? expires - now : expires |
| | | expires > now ? expires - now : expires, |
| | | ); |
| | | |
| | | return value; |
| | |
| | | amount = Math.trunc((255 * amount) / 100); |
| | | return `#${subtractLight(color.substring(0, 2), amount)}${subtractLight( |
| | | color.substring(2, 4), |
| | | amount |
| | | amount, |
| | | )}${subtractLight(color.substring(4, 6), amount)}`; |
| | | } |
| | | |
| | |
| | | amount = Math.trunc((255 * amount) / 100); |
| | | return `#${addLight(color.substring(0, 2), amount)}${addLight( |
| | | color.substring(2, 4), |
| | | amount |
| | | amount, |
| | | )}${addLight(color.substring(4, 6), amount)}`; |
| | | } |
| | | |
| | |
| | | |
| | | export function formatToDateTime( |
| | | date: moment.MomentInput = undefined, |
| | | format = DATE_TIME_FORMAT |
| | | format = DATE_TIME_FORMAT, |
| | | ): string { |
| | | return moment(date).format(format); |
| | | } |
| | |
| | | export function on( |
| | | element: Element | HTMLElement | Document | Window, |
| | | event: string, |
| | | handler: EventListenerOrEventListenerObject |
| | | handler: EventListenerOrEventListenerObject, |
| | | ): void { |
| | | if (element && event && handler) { |
| | | element.addEventListener(event, handler, false); |
| | |
| | | export function off( |
| | | element: Element | HTMLElement | Document | Window, |
| | | event: string, |
| | | handler: Fn |
| | | handler: Fn, |
| | | ): void { |
| | | if (element && event && handler) { |
| | | element.removeEventListener(event, handler, false); |
| | |
| | | |
| | | if (!/^[a-zA-Z\_]*$/.test(VITE_GLOB_APP_SHORT_NAME)) { |
| | | warn( |
| | | `VITE_GLOB_APP_SHORT_NAME Variables can only be characters/underscores, please modify in the environment variables and re-running.` |
| | | `VITE_GLOB_APP_SHORT_NAME Variables can only be characters/underscores, please modify in the environment variables and re-running.`, |
| | | ); |
| | | } |
| | | |
| | |
| | | export function findNode<T = any>( |
| | | tree: any, |
| | | func: Fn, |
| | | config: Partial<TreeHelperConfig> = {} |
| | | config: Partial<TreeHelperConfig> = {}, |
| | | ): T | null { |
| | | config = getConfig(config); |
| | | const { children } = config; |
| | |
| | | export function findNodeAll<T = any>( |
| | | tree: any, |
| | | func: Fn, |
| | | config: Partial<TreeHelperConfig> = {} |
| | | config: Partial<TreeHelperConfig> = {}, |
| | | ): T[] { |
| | | config = getConfig(config); |
| | | const { children } = config; |
| | |
| | | export function findPath<T = any>( |
| | | tree: any, |
| | | func: Fn, |
| | | config: Partial<TreeHelperConfig> = {} |
| | | config: Partial<TreeHelperConfig> = {}, |
| | | ): T | T[] | null { |
| | | config = getConfig(config); |
| | | const path: T[] = []; |
| | |
| | | export function filter<T = any>( |
| | | tree: T[], |
| | | func: (n: T) => boolean, |
| | | config: Partial<TreeHelperConfig> = {} |
| | | config: Partial<TreeHelperConfig> = {}, |
| | | ): T[] { |
| | | config = getConfig(config); |
| | | const children = config.children as string; |
| | |
| | | export function forEach<T = any>( |
| | | tree: T[], |
| | | func: (n: T) => any, |
| | | config: Partial<TreeHelperConfig> = {} |
| | | config: Partial<TreeHelperConfig> = {}, |
| | | ): void { |
| | | config = getConfig(config); |
| | | const list: any[] = [...tree]; |
| | |
| | | */ |
| | | export function treeMapEach( |
| | | data: any, |
| | | { children = 'children', conversion }: { children?: string; conversion: Fn } |
| | | { children = 'children', conversion }: { children?: string; conversion: Fn }, |
| | | ) { |
| | | const haveChildren = Array.isArray(data[children]) && data[children].length > 0; |
| | | const conversionData = conversion(data) || {}; |
| | |
| | | treeMapEach(i, { |
| | | children, |
| | | conversion, |
| | | }) |
| | | }), |
| | | ), |
| | | }; |
| | | } else { |
| | |
| | | */ |
| | | requestInterceptors?: ( |
| | | config: AxiosRequestConfig, |
| | | options: CreateAxiosOptions |
| | | options: CreateAxiosOptions, |
| | | ) => AxiosRequestConfig; |
| | | |
| | | /** |
| | |
| | | export function checkStatus( |
| | | status: number, |
| | | msg: string, |
| | | errorMessageMode: ErrorMessageMode = 'message' |
| | | errorMessageMode: ErrorMessageMode = 'message', |
| | | ): void { |
| | | const { t } = useI18n(); |
| | | const userStore = useUserStoreWithOut(); |
| | |
| | | |
| | | export function joinTimestamp<T extends boolean>( |
| | | join: boolean, |
| | | restful: T |
| | | restful: T, |
| | | ): T extends true ? string : object; |
| | | |
| | | export function joinTimestamp(join: boolean, restful = false): string | object { |
| | |
| | | if (joinParamsToUrl) { |
| | | config.url = setObjToUrlParams( |
| | | config.url as string, |
| | | Object.assign({}, config.params, config.data) |
| | | Object.assign({}, config.params, config.data), |
| | | ); |
| | | } |
| | | } else { |
| | |
| | | withToken: true, |
| | | }, |
| | | }, |
| | | opt || {} |
| | | ) |
| | | opt || {}, |
| | | ), |
| | | ); |
| | | } |
| | | export const defHttp = createAxios(); |
| | |
| | | |
| | | export function openWindow( |
| | | url: string, |
| | | opt?: { target?: TargetContext | string; noopener?: boolean; noreferrer?: boolean } |
| | | opt?: { target?: TargetContext | string; noopener?: boolean; noreferrer?: boolean }, |
| | | ) { |
| | | const { target = '__blank', noopener = true, noreferrer = true } = opt || {}; |
| | | const feature: string[] = []; |
| | |
| | | ], |
| | | }); |
| | | }, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | </script> |
| | |
| | | ], |
| | | }); |
| | | }, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | </script> |
| | |
| | | ], |
| | | }); |
| | | }, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | </script> |
| | |
| | | <Icon :icon="item.icon" :color="item.color" size="30" /> |
| | | <span class="text-lg ml-4">{{ item.title }}</span> |
| | | </span> |
| | | <div class="flex mt-2 h-10 text-secondary"> {{ item.desc }} </div> |
| | | <div class="flex mt-2 h-10 text-secondary">{{ item.desc }}</div> |
| | | <div class="flex justify-between text-secondary"> |
| | | <span>{{ item.group }}</span> |
| | | <span>{{ item.date }}</span> |
| | |
| | | ], |
| | | }); |
| | | }, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | </script> |
| | |
| | | ], |
| | | }); |
| | | }, |
| | | { immediate: true } |
| | | { immediate: true }, |
| | | ); |
| | | return { chartRef }; |
| | | }, |
| | |
| | | <template> |
| | | <BasicDrawer v-bind="$attrs" title="Modal Title" width="50%" showFooter @ok="handleOk"> |
| | | <p class="h-20" v-for="index in 40" :key="index"> 根据屏幕高度自适应 </p> |
| | | <p class="h-20" v-for="index in 40" :key="index">根据屏幕高度自适应</p> |
| | | <template #insertFooter> |
| | | <a-button> btn</a-button> |
| | | </template> |
| | |
| | | <template> |
| | | <BasicDrawer v-bind="$attrs" :isDetail="true" title="Drawer Title5"> |
| | | <p class="h-20"> Content Message </p> |
| | | <p class="h-20">Content Message</p> |
| | | <template #titleToolbar> toolbar </template> |
| | | </BasicDrawer> |
| | | </template> |
| | |
| | | <a-button type="primary" danger @click="setLines" :disabled="loading">点我更新内容</a-button> |
| | | </template> |
| | | <template v-if="loading"> |
| | | <div class="empty-tips"> 加载中,稍等3秒…… </div> |
| | | <div class="empty-tips">加载中,稍等3秒……</div> |
| | | </template> |
| | | <template v-if="!loading"> |
| | | <ul> |
| | |
| | | () => lines.value, |
| | | () => { |
| | | redoModalHeight(); |
| | | } |
| | | }, |
| | | ); |
| | | |
| | | function handleShow(visible: boolean) { |
| | |
| | | <template> |
| | | <BasicModal v-bind="$attrs" title="Modal Title" :helpMessage="['提示1', '提示2']" width="700px"> |
| | | <p class="h-20" v-for="index in 20" :key="index"> 根据屏幕高度自适应 </p> |
| | | <p class="h-20" v-for="index in 20" :key="index">根据屏幕高度自适应</p> |
| | | </BasicModal> |
| | | </template> |
| | | <script lang="ts"> |
| | |
| | | <CollapseContainer title="下载示例" class="text-center qrcode-demo-item"> |
| | | <QrCode :value="qrCodeUrl" ref="qrRef" :logo="LogoImg" /> |
| | | <a-button class="mb-2" type="primary" @click="download"> 下载 </a-button> |
| | | <div class="msg"> (在线logo会导致图片跨域,需要下载图片需要自行解决跨域问题) </div> |
| | | <div class="msg">(在线logo会导致图片跨域,需要下载图片需要自行解决跨域问题)</div> |
| | | </CollapseContainer> |
| | | |
| | | <CollapseContainer title="配置大小示例" class="text-center qrcode-demo-item"> |
| | |
| | | @done="onQrcodeDone" |
| | | /> |
| | | <a-button class="mb-2" type="primary" @click="downloadDiy"> 下载 </a-button> |
| | | <div class="msg"> 要进行扩展绘制则不能将tag设为img </div> |
| | | <div class="msg">要进行扩展绘制则不能将tag设为img</div> |
| | | </CollapseContainer> |
| | | </div> |
| | | </PageWrapper> |
| | |
| | | <template> |
| | | <PageWrapper title="子级详情页"> |
| | | <div> 子级详情页内容在此 </div> |
| | | <div>子级详情页内容在此</div> |
| | | </PageWrapper> |
| | | </template> |
| | | <script lang="ts"> |
| | |
| | | <template> |
| | | <div> 平级详情页 </div> |
| | | <div>平级详情页</div> |
| | | </template> |
| | | <script lang="ts"> |
| | | import { defineComponent } from 'vue'; |
| | |
| | | function handleDownloadByOnlineUrl() { |
| | | downloadByOnlineUrl( |
| | | 'https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5944817f47b8408e9f1442ece49d68ca~tplv-k3u1fbpfcp-watermark.image', |
| | | 'logo.png' |
| | | 'logo.png', |
| | | ); |
| | | } |
| | | return { |
| | |
| | | <template> |
| | | <PageWrapper title="Ripple示例"> |
| | | <div class="demo-box" v-ripple> content </div> |
| | | <div class="demo-box" v-ripple>content</div> |
| | | </PageWrapper> |
| | | </template> |
| | | <script lang="ts"> |
| | |
| | | }, |
| | | required: true, |
| | | }, |
| | | '' |
| | | '', |
| | | ); |
| | | appendSchemaByField( |
| | | { |
| | |
| | | }, |
| | | required: true, |
| | | }, |
| | | '' |
| | | '', |
| | | ); |
| | | |
| | | appendSchemaByField( |
| | |
| | | }, |
| | | slot: 'add', |
| | | }, |
| | | '' |
| | | '', |
| | | ); |
| | | n.value++; |
| | | } |
| | |
| | | span: 8, |
| | | }, |
| | | }, |
| | | 'field3' |
| | | 'field3', |
| | | ); |
| | | } |
| | | function deleteField() { |
| | |
| | | <template> |
| | | <div class="fixed h-full w-full flex flex-col justify-center items-center text-4xl"> |
| | | <div class=""> 位于主框架外的页面 </div> |
| | | <div class="">位于主框架外的页面</div> |
| | | <a-button @click="$router.go(-1)" class="mt-10" type="primary">Back</a-button> |
| | | </div> |
| | | </template> |
| | |
| | | </a-button> |
| | | </template> |
| | | <template #description> |
| | | <div>{{ item.description }} </div> |
| | | <div>{{ item.description }}</div> |
| | | </template> |
| | | </ListItemMeta> |
| | | </ListItem> |
| | |
| | | </a-col> |
| | | <a-col :span="10"> |
| | | <div class="change-avatar"> |
| | | <div class="mb-2"> 头像 </div> |
| | | <div class="mb-2">头像</div> |
| | | <CropperAvatar |
| | | :uploadApi="uploadApi" |
| | | :value="avatar" |
| | |
| | | /> |
| | | </template> |
| | | <template #description> |
| | | <div>{{ item.description }} </div> |
| | | <div>{{ item.description }}</div> |
| | | </template> |
| | | </ListItemMeta> |
| | | </ListItem> |
| | |
| | | </div> |
| | | </template> |
| | | <template #description> |
| | | <div>{{ item.description }} </div> |
| | | <div>{{ item.description }}</div> |
| | | </template> |
| | | </ListItemMeta> |
| | | </ListItem> |
| | |
| | | <a-card title="流程进度" :bordered="false"> |
| | | <a-steps :current="1" progress-dot size="small"> |
| | | <a-step title="创建项目"> |
| | | <template #description> <div>Vben</div> <p>2016-12-12 12:32</p> </template> |
| | | <template #description> |
| | | <div>Vben</div> |
| | | <p>2016-12-12 12:32</p> |
| | | </template> |
| | | </a-step> |
| | | <a-step title="部门初审"> |
| | | <template #description> |
| | |
| | | </template> |
| | | </Result> |
| | | <div class="result-error__content"> |
| | | <div class="result-error__content-title"> 您提交的内容有如下错误: </div> |
| | | <div class="result-error__content-title">您提交的内容有如下错误:</div> |
| | | <div class="mb-4"> |
| | | <CloseCircleOutlined class="mr-2 result-error__content-icon" /> |
| | | 您的账户已被冻结 |
| | |
| | | </Descriptions> |
| | | <Steps :current="1" progress-dot size="small"> |
| | | <Step title="创建项目"> |
| | | <template #description> <div>Vben</div> <p>2016-12-12 12:32</p> </template> |
| | | <template #description> |
| | | <div>Vben</div> |
| | | <p>2016-12-12 12:32</p> |
| | | </template> |
| | | </Step> |
| | | <Step title="部门初审"> |
| | | <template #description> |
| | |
| | | const userStore = useUserStore(); |
| | | |
| | | const isBackPremissionMode = computed( |
| | | () => appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK |
| | | () => appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK, |
| | | ); |
| | | |
| | | async function switchToken(userId: number) { |
| | |
| | | const appStore = useAppStore(); |
| | | |
| | | const isBackPremissionMode = computed( |
| | | () => appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK |
| | | () => appStore.getProjectConfig.permissionMode === PermissionModeEnum.BACK, |
| | | ); |
| | | |
| | | async function switchToken(userId: number) { |
| | |
| | | <template> |
| | | <div class="m-10 auth-page"> Super 角色可见 </div> |
| | | <div class="m-10 auth-page">Super 角色可见</div> |
| | | </template> |
| | | <script lang="ts"> |
| | | import { defineComponent } from 'vue'; |
| | |
| | | <template> |
| | | <div class="m-10 auth-page"> Test 角色可见 </div> |
| | | <div class="m-10 auth-page">Test 角色可见</div> |
| | | </template> |
| | | <script lang="ts"> |
| | | import { defineComponent } from 'vue'; |
| | |
| | | }, |
| | | { |
| | | immediate: true, |
| | | } |
| | | }, |
| | | ); |
| | | const { createMessage } = useMessage(); |
| | | if (import.meta.env.DEV) { |
| | |
| | | <div class="text-5xl mb-4 enter-x" v-show="!showDate"> |
| | | {{ hour }}:{{ minute }} <span class="text-3xl">{{ meridiem }}</span> |
| | | </div> |
| | | <div class="text-2xl"> {{ year }}/{{ month }}/{{ day }} {{ week }} </div> |
| | | <div class="text-2xl">{{ year }}/{{ month }}/{{ day }} {{ week }}</div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | |
| | | password: data.password, |
| | | username: data.account, |
| | | mode: 'none', //不要默认的错误提示 |
| | | }) |
| | | }), |
| | | ); |
| | | if (userInfo) { |
| | | notification.success({ |
| | |
| | | } |
| | | console.log(message); |
| | | }); |
| | | }) |
| | | }), |
| | | ); |
| | | |
| | | const router = new Router(); |
| | |
| | | keepExtensions: true, |
| | | maxFieldsSize: 20 * 1024 * 1024, |
| | | }, |
| | | }) |
| | | }), |
| | | ); |
| | | app.use(router.routes()); |
| | | app.use(router.allowedMethods()); |