├── .browserslistrc ├── .dockerignore ├── .editorconfig ├── .env ├── .env.development ├── .env.production ├── .env.staging ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── config.yml └── workflows │ ├── linter.yml │ └── pages.yml ├── .gitignore ├── .gitpod.yml ├── .husky ├── commit-msg ├── common.sh └── pre-commit ├── .lintstagedrc ├── .markdownlint.json ├── .npmrc ├── .nvmrc ├── .prettierignore ├── .prettierrc.js ├── .stylelintignore ├── .vscode ├── extensions.json ├── settings.json ├── vue3.0.code-snippets ├── vue3.2.code-snippets └── vue3.3.code-snippets ├── CHANGELOG.en_US.md ├── CHANGELOG.md ├── CHANGELOG.zh_CN.md ├── Dockerfile ├── LICENSE ├── README.en-US.md ├── README.md ├── build ├── cdn.ts ├── compress.ts ├── info.ts ├── optimize.ts ├── plugins.ts └── utils.ts ├── commitlint.config.js ├── eslint.config.js ├── index.html ├── locales ├── en.yaml └── zh-CN.yaml ├── mock ├── asyncRoutes.ts ├── list.ts ├── login.ts ├── map.ts ├── mine.ts ├── refreshToken.ts └── system.ts ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── public ├── audio │ └── 海阔天空.mp3 ├── favicon.ico ├── html │ └── button.html ├── logo.svg ├── platform-config.json └── wasm │ ├── capture.worker.js │ ├── capture.worker.wasm │ └── index.js ├── src ├── App.vue ├── api │ ├── list.ts │ ├── mock.ts │ ├── routes.ts │ ├── system.ts │ └── user.ts ├── assets │ ├── car.png │ ├── iconfont │ │ ├── iconfont.css │ │ ├── iconfont.js │ │ ├── iconfont.json │ │ ├── iconfont.ttf │ │ ├── iconfont.woff │ │ └── iconfont.woff2 │ ├── login │ │ ├── avatar.svg │ │ ├── bg.png │ │ └── illustration.svg │ ├── status │ │ ├── 403.svg │ │ ├── 404.svg │ │ └── 500.svg │ ├── svg │ │ ├── back.svg │ │ ├── back_top.svg │ │ ├── calendar.svg │ │ ├── dark.svg │ │ ├── day.svg │ │ ├── enter_outlined.svg │ │ ├── exit_screen.svg │ │ ├── full_screen.svg │ │ ├── globalization.svg │ │ ├── hot.svg │ │ ├── keyboard_esc.svg │ │ ├── laptop.svg │ │ ├── service.svg │ │ ├── shop.svg │ │ ├── system.svg │ │ └── user_avatar.svg │ ├── table-bar │ │ ├── collapse.svg │ │ ├── drag.svg │ │ ├── expand.svg │ │ ├── refresh.svg │ │ └── settings.svg │ └── user.jpg ├── components │ ├── ReAnimateSelector │ │ ├── index.ts │ │ └── src │ │ │ ├── animate.ts │ │ │ └── index.vue │ ├── ReAuth │ │ ├── index.ts │ │ └── src │ │ │ └── auth.tsx │ ├── ReBarcode │ │ ├── index.ts │ │ └── src │ │ │ └── index.vue │ ├── ReCol │ │ └── index.ts │ ├── ReCountTo │ │ ├── README.md │ │ ├── index.ts │ │ └── src │ │ │ ├── normal │ │ │ ├── index.tsx │ │ │ └── props.ts │ │ │ └── rebound │ │ │ ├── index.tsx │ │ │ ├── props.ts │ │ │ └── rebound.css │ ├── ReCropper │ │ ├── index.ts │ │ └── src │ │ │ ├── circled.css │ │ │ ├── index.tsx │ │ │ └── svg │ │ │ ├── arrow-down.svg │ │ │ ├── arrow-h.svg │ │ │ ├── arrow-left.svg │ │ │ ├── arrow-right.svg │ │ │ ├── arrow-up.svg │ │ │ ├── arrow-v.svg │ │ │ ├── change.svg │ │ │ ├── download.svg │ │ │ ├── index.ts │ │ │ ├── reload.svg │ │ │ ├── rotate-left.svg │ │ │ ├── rotate-right.svg │ │ │ ├── search-minus.svg │ │ │ ├── search-plus.svg │ │ │ └── upload.svg │ ├── ReCropperPreview │ │ ├── index.ts │ │ └── src │ │ │ └── index.vue │ ├── ReDialog │ │ ├── index.ts │ │ ├── index.vue │ │ └── type.ts │ ├── ReDrawer │ │ ├── index.ts │ │ ├── index.vue │ │ └── type.ts │ ├── ReFlicker │ │ ├── index.css │ │ └── index.ts │ ├── ReFlop │ │ ├── index.ts │ │ └── src │ │ │ ├── filpper.css │ │ │ ├── filpper.tsx │ │ │ └── index.vue │ ├── ReFlowChart │ │ ├── index.ts │ │ └── src │ │ │ ├── Control.vue │ │ │ ├── DataDialog.vue │ │ │ ├── NodePanel.vue │ │ │ ├── adpterForTurbo.ts │ │ │ ├── assets │ │ │ └── iconfont │ │ │ │ ├── iconfont.css │ │ │ │ ├── iconfont.eot │ │ │ │ ├── iconfont.js │ │ │ │ ├── iconfont.json │ │ │ │ ├── iconfont.svg │ │ │ │ ├── iconfont.ttf │ │ │ │ ├── iconfont.woff │ │ │ │ └── iconfont.woff2 │ │ │ └── config.ts │ ├── ReIcon │ │ ├── data.ts │ │ ├── index.ts │ │ └── src │ │ │ ├── Select.vue │ │ │ ├── hooks.ts │ │ │ ├── iconfont.ts │ │ │ ├── iconifyIconOffline.ts │ │ │ ├── iconifyIconOnline.ts │ │ │ ├── offlineIcon.ts │ │ │ └── types.ts │ ├── ReImageVerify │ │ ├── index.ts │ │ └── src │ │ │ ├── hooks.ts │ │ │ └── index.vue │ ├── ReMap │ │ ├── index.ts │ │ └── src │ │ │ └── Amap.vue │ ├── RePerms │ │ ├── index.ts │ │ └── src │ │ │ └── perms.tsx │ ├── RePureTableBar │ │ ├── index.ts │ │ └── src │ │ │ └── bar.tsx │ ├── ReQrcode │ │ ├── index.ts │ │ └── src │ │ │ ├── index.scss │ │ │ └── index.tsx │ ├── ReSeamlessScroll │ │ ├── index.ts │ │ └── src │ │ │ ├── index.vue │ │ │ └── utils.ts │ ├── ReSegmented │ │ ├── index.ts │ │ └── src │ │ │ ├── index.css │ │ │ ├── index.tsx │ │ │ └── type.ts │ ├── ReSelector │ │ ├── index.ts │ │ └── src │ │ │ ├── index.css │ │ │ └── index.tsx │ ├── ReSplitPane │ │ ├── iconfont │ │ │ ├── iconfont.css │ │ │ ├── iconfont.js │ │ │ ├── iconfont.json │ │ │ ├── iconfont.ttf │ │ │ ├── iconfont.woff │ │ │ └── iconfont.woff2 │ │ ├── index.css │ │ ├── index.tsx │ │ ├── resizer.css │ │ └── resizer.tsx │ ├── ReText │ │ ├── index.ts │ │ └── src │ │ │ └── index.vue │ ├── ReTreeLine │ │ ├── index.scss │ │ └── index.ts │ ├── ReTypeit │ │ ├── index.ts │ │ └── src │ │ │ └── index.tsx │ └── ReVxeTableBar │ │ ├── index.ts │ │ └── src │ │ └── bar.tsx ├── config │ └── index.ts ├── directives │ ├── auth │ │ └── index.ts │ ├── copy │ │ └── index.ts │ ├── index.ts │ ├── longpress │ │ └── index.ts │ ├── optimize │ │ └── index.ts │ ├── perms │ │ └── index.ts │ └── ripple │ │ ├── index.scss │ │ └── index.ts ├── layout │ ├── components │ │ ├── lay-content │ │ │ └── index.vue │ │ ├── lay-footer │ │ │ └── index.vue │ │ ├── lay-frame │ │ │ └── index.vue │ │ ├── lay-navbar │ │ │ └── index.vue │ │ ├── lay-notice │ │ │ ├── components │ │ │ │ ├── NoticeItem.vue │ │ │ │ └── NoticeList.vue │ │ │ ├── data.ts │ │ │ └── index.vue │ │ ├── lay-panel │ │ │ └── index.vue │ │ ├── lay-search │ │ │ ├── components │ │ │ │ ├── SearchFooter.vue │ │ │ │ ├── SearchHistory.vue │ │ │ │ ├── SearchHistoryItem.vue │ │ │ │ ├── SearchModal.vue │ │ │ │ └── SearchResult.vue │ │ │ ├── index.vue │ │ │ └── types.ts │ │ ├── lay-setting │ │ │ └── index.vue │ │ ├── lay-sidebar │ │ │ ├── NavHorizontal.vue │ │ │ ├── NavMix.vue │ │ │ ├── NavVertical.vue │ │ │ └── components │ │ │ │ ├── SidebarBreadCrumb.vue │ │ │ │ ├── SidebarCenterCollapse.vue │ │ │ │ ├── SidebarExtraIcon.vue │ │ │ │ ├── SidebarFullScreen.vue │ │ │ │ ├── SidebarItem.vue │ │ │ │ ├── SidebarLeftCollapse.vue │ │ │ │ ├── SidebarLinkItem.vue │ │ │ │ ├── SidebarLogo.vue │ │ │ │ └── SidebarTopCollapse.vue │ │ └── lay-tag │ │ │ ├── components │ │ │ └── TagChrome.vue │ │ │ ├── index.scss │ │ │ └── index.vue │ ├── frame.vue │ ├── hooks │ │ ├── useBoolean.ts │ │ ├── useDataThemeChange.ts │ │ ├── useLayout.ts │ │ ├── useMultiFrame.ts │ │ ├── useNav.ts │ │ ├── useTag.ts │ │ └── useTranslationLang.ts │ ├── index.vue │ ├── redirect.vue │ └── types.ts ├── main.ts ├── plugins │ ├── echarts.ts │ ├── elementPlus.ts │ ├── i18n.ts │ └── vxeTable.ts ├── router │ ├── enums.ts │ ├── index.ts │ ├── modules │ │ ├── able.ts │ │ ├── about.ts │ │ ├── board.ts │ │ ├── chatai.ts │ │ ├── codemirror.ts │ │ ├── components.ts │ │ ├── editor.ts │ │ ├── error.ts │ │ ├── flowchart.ts │ │ ├── form.ts │ │ ├── formdesign.ts │ │ ├── ganttastic.ts │ │ ├── guide.ts │ │ ├── home.ts │ │ ├── list.ts │ │ ├── markdown.ts │ │ ├── menuoverflow.ts │ │ ├── mind.ts │ │ ├── nested.ts │ │ ├── ppt.ts │ │ ├── remaining.ts │ │ ├── result.ts │ │ ├── table.ts │ │ └── vueflow.ts │ └── utils.ts ├── store │ ├── index.ts │ ├── modules │ │ ├── app.ts │ │ ├── epTheme.ts │ │ ├── multiTags.ts │ │ ├── permission.ts │ │ ├── settings.ts │ │ └── user.ts │ ├── types.ts │ └── utils.ts ├── style │ ├── dark.scss │ ├── element-plus.scss │ ├── index.scss │ ├── login.css │ ├── reset.scss │ ├── sidebar.scss │ ├── tailwind.css │ ├── theme.scss │ └── transition.scss ├── utils │ ├── README.md │ ├── auth.ts │ ├── chinaArea.ts │ ├── globalPolyfills.ts │ ├── http │ │ ├── index.ts │ │ └── types.d.ts │ ├── localforage │ │ ├── index.ts │ │ └── types.d.ts │ ├── message.ts │ ├── mitt.ts │ ├── preventDefault.ts │ ├── print.ts │ ├── progress │ │ └── index.ts │ ├── propTypes.ts │ ├── responsive.ts │ ├── sso.ts │ └── tree.ts └── views │ ├── able │ ├── barcode.vue │ ├── danmaku │ │ ├── danmu.ts │ │ └── index.vue │ ├── debounce.vue │ ├── directives.vue │ ├── download.vue │ ├── draggable.vue │ ├── excel.vue │ ├── infinite-scroll.vue │ ├── line-tree.vue │ ├── map.vue │ ├── menu-tree.vue │ ├── mqtt-client.vue │ ├── pdf.vue │ ├── pinyin.vue │ ├── print │ │ ├── index.vue │ │ └── pieChart.vue │ ├── qrcode.vue │ ├── ripple.vue │ ├── sensitive.vue │ ├── typeit.vue │ ├── verify.vue │ ├── video-frame │ │ ├── canvasRenderer.ts │ │ └── index.vue │ ├── video.vue │ ├── watermark.vue │ └── wavesurfer │ │ ├── index.vue │ │ └── svg │ │ ├── forward.svg │ │ ├── index.ts │ │ ├── pause.svg │ │ ├── play.svg │ │ └── rewind.svg │ ├── about │ ├── columns.tsx │ └── index.vue │ ├── account-settings │ ├── components │ │ ├── AccountManagement.vue │ │ ├── Preferences.vue │ │ ├── Profile.vue │ │ └── SecurityLog.vue │ └── index.vue │ ├── chatai │ ├── components │ │ ├── Bard.vue │ │ ├── Bing.vue │ │ ├── Blue.vue │ │ ├── ChatGPT.vue │ │ ├── Dark.vue │ │ ├── FullInput.vue │ │ ├── Group.vue │ │ ├── IntroPanel.vue │ │ ├── LoFi.vue │ │ ├── MessageCode.vue │ │ ├── Red.vue │ │ ├── Speech.vue │ │ ├── iMessage.vue │ │ └── index.ts │ └── index.vue │ ├── codemirror │ └── index.vue │ ├── components │ ├── animatecss.vue │ ├── button.vue │ ├── cascader.vue │ ├── check-button.vue │ ├── check-card.vue │ ├── collapse.vue │ ├── color-picker.vue │ ├── contextmenu │ │ ├── basic.vue │ │ ├── index.vue │ │ ├── menuDynamic.vue │ │ └── menuGroup.vue │ ├── count-to.vue │ ├── cropping │ │ ├── avatar.png │ │ └── index.vue │ ├── date-picker.vue │ ├── datetime-picker.vue │ ├── dialog │ │ ├── form.vue │ │ ├── formPrimitive.vue │ │ └── index.vue │ ├── drawer │ │ ├── form.vue │ │ ├── formPrimitive.vue │ │ └── index.vue │ ├── el-button.vue │ ├── icon-select.vue │ ├── json-editor.vue │ ├── message.vue │ ├── progress.vue │ ├── seamless-scroll.vue │ ├── segmented.vue │ ├── selector.vue │ ├── slider │ │ ├── components │ │ │ ├── Base.vue │ │ │ ├── Input.vue │ │ │ ├── Marks.vue │ │ │ ├── Placement.vue │ │ │ ├── Range.vue │ │ │ ├── Size.vue │ │ │ ├── Step.vue │ │ │ ├── Vertical.vue │ │ │ └── index.ts │ │ └── index.vue │ ├── split-pane.vue │ ├── statistic.vue │ ├── swiper.vue │ ├── tag.vue │ ├── text.vue │ ├── time-picker.vue │ ├── timeline.vue │ ├── upload │ │ ├── form.vue │ │ ├── imgs │ │ │ ├── 1.jpg │ │ │ ├── 2.jpg │ │ │ └── 3.jpg │ │ └── index.vue │ ├── virtual-list │ │ ├── horizontal.vue │ │ ├── index.vue │ │ └── vertical.vue │ └── waterfall │ │ ├── api.ts │ │ ├── error.png │ │ ├── index.vue │ │ └── loading.png │ ├── editor │ ├── components │ │ ├── EditorBase.vue │ │ ├── EditorMulti.vue │ │ ├── EditorUpload.vue │ │ └── index.ts │ └── index.vue │ ├── empty │ └── index.vue │ ├── error │ ├── 403.vue │ ├── 404.vue │ └── 500.vue │ ├── flow-chart │ ├── dataTurbo.json │ └── index.vue │ ├── ganttastic │ └── index.vue │ ├── guide │ └── index.vue │ ├── list │ └── card │ │ ├── components │ │ ├── ListCard.vue │ │ └── ListDialogForm.vue │ │ └── index.vue │ ├── login │ ├── components │ │ ├── LoginPhone.vue │ │ ├── LoginQrCode.vue │ │ ├── LoginRegist.vue │ │ └── LoginUpdate.vue │ ├── index.vue │ └── utils │ │ ├── enums.ts │ │ ├── motion.ts │ │ ├── rule.ts │ │ ├── static.ts │ │ └── verifyCode.ts │ ├── markdown │ ├── components │ │ └── Vditor.vue │ └── index.vue │ ├── menuoverflow │ └── index.vue │ ├── monitor │ ├── logs │ │ ├── login │ │ │ ├── hook.tsx │ │ │ └── index.vue │ │ ├── operation │ │ │ ├── hook.tsx │ │ │ └── index.vue │ │ └── system │ │ │ ├── detail.vue │ │ │ ├── hook.tsx │ │ │ └── index.vue │ ├── online │ │ ├── hook.tsx │ │ └── index.vue │ └── utils.ts │ ├── nested │ ├── menu1 │ │ ├── menu1-1 │ │ │ └── index.vue │ │ ├── menu1-2 │ │ │ ├── menu1-2-1 │ │ │ │ └── index.vue │ │ │ └── menu1-2-2 │ │ │ │ └── index.vue │ │ └── menu1-3 │ │ │ └── index.vue │ └── menu2 │ │ └── index.vue │ ├── permission │ ├── button │ │ ├── index.vue │ │ └── perms.vue │ └── page │ │ └── index.vue │ ├── result │ ├── columns.tsx │ ├── fail.vue │ └── success.vue │ ├── schema-form │ ├── form │ │ ├── base.vue │ │ ├── dialog.vue │ │ ├── drawer.vue │ │ ├── search.vue │ │ └── steps.vue │ ├── index.vue │ └── list.tsx │ ├── system │ ├── dept │ │ ├── form.vue │ │ ├── index.vue │ │ └── utils │ │ │ ├── hook.tsx │ │ │ ├── rule.ts │ │ │ └── types.ts │ ├── hooks.ts │ ├── menu │ │ ├── README.md │ │ ├── form.vue │ │ ├── index.vue │ │ └── utils │ │ │ ├── enums.ts │ │ │ ├── hook.tsx │ │ │ ├── rule.ts │ │ │ └── types.ts │ ├── role │ │ ├── form.vue │ │ ├── index.vue │ │ └── utils │ │ │ ├── hook.tsx │ │ │ ├── rule.ts │ │ │ └── types.ts │ └── user │ │ ├── form │ │ ├── index.vue │ │ └── role.vue │ │ ├── index.vue │ │ ├── svg │ │ ├── expand.svg │ │ └── unexpand.svg │ │ ├── tree.vue │ │ └── utils │ │ ├── hook.tsx │ │ ├── reset.css │ │ ├── rule.ts │ │ └── types.ts │ ├── table │ ├── base │ │ ├── base.vue │ │ ├── border.vue │ │ ├── column-template │ │ │ ├── columns.tsx │ │ │ └── index.vue │ │ ├── customIndex.vue │ │ ├── data.ts │ │ ├── expand.vue │ │ ├── filters.vue │ │ ├── fixColumn.vue │ │ ├── fixHeader.vue │ │ ├── fluidHeight.vue │ │ ├── groupHeader.vue │ │ ├── header-renderer │ │ │ ├── columns.tsx │ │ │ └── index.vue │ │ ├── imgPreview.vue │ │ ├── layout.vue │ │ ├── list.tsx │ │ ├── merge.vue │ │ ├── multipleChoice.vue │ │ ├── nestProp.vue │ │ ├── radio.vue │ │ ├── sortable.vue │ │ ├── status.vue │ │ ├── stripe.vue │ │ ├── totalRow.vue │ │ └── tree.vue │ ├── edit.vue │ ├── edit │ │ ├── data.ts │ │ ├── demo1 │ │ │ ├── columns.tsx │ │ │ └── index.vue │ │ ├── demo2 │ │ │ ├── columns.tsx │ │ │ └── index.vue │ │ ├── demo3 │ │ │ ├── columns.tsx │ │ │ └── index.vue │ │ ├── empty.svg │ │ └── list.tsx │ ├── high.vue │ ├── high │ │ ├── adaptive │ │ │ ├── columns.tsx │ │ │ └── index.vue │ │ ├── contextmenu │ │ │ ├── columns.tsx │ │ │ └── index.vue │ │ ├── data.ts │ │ ├── drag │ │ │ ├── column │ │ │ │ ├── columns.tsx │ │ │ │ └── index.vue │ │ │ └── row │ │ │ │ ├── columns.tsx │ │ │ │ └── index.vue │ │ ├── echarts │ │ │ ├── columns.tsx │ │ │ └── index.vue │ │ ├── excel │ │ │ ├── columns.tsx │ │ │ └── index.vue │ │ ├── header │ │ │ ├── columns.tsx │ │ │ └── index.vue │ │ ├── list.tsx │ │ ├── page │ │ │ ├── columns.tsx │ │ │ └── index.vue │ │ ├── prints │ │ │ ├── columns.tsx │ │ │ └── index.vue │ │ ├── table-select │ │ │ ├── index.vue │ │ │ ├── multiple │ │ │ │ ├── columns.tsx │ │ │ │ └── index.vue │ │ │ └── radio │ │ │ │ ├── columns.tsx │ │ │ │ └── index.vue │ │ └── watermark │ │ │ ├── columns.tsx │ │ │ └── index.vue │ ├── index.vue │ ├── virtual.vue │ └── virtual │ │ ├── list.tsx │ │ ├── list.vue │ │ ├── pageList.vue │ │ ├── tree.json │ │ └── treeList.vue │ ├── tabs │ ├── hooks.ts │ ├── index.vue │ ├── params-detail.vue │ └── query-detail.vue │ ├── vue-flow │ └── layouting │ │ ├── animationEdge.vue │ │ ├── icon.vue │ │ ├── index.vue │ │ ├── initialElements.ts │ │ ├── processNode.vue │ │ ├── useLayout.ts │ │ ├── useRunProcess.ts │ │ └── useShuffle.ts │ └── welcome │ ├── components │ ├── charts │ │ ├── ChartBar.vue │ │ ├── ChartLine.vue │ │ ├── ChartRound.vue │ │ └── index.ts │ └── table │ │ ├── columns.tsx │ │ ├── empty.svg │ │ └── index.vue │ ├── data.ts │ ├── index.vue │ └── utils.ts ├── stylelint.config.js ├── tsconfig.json ├── types ├── directives.d.ts ├── global-components.d.ts ├── global.d.ts ├── index.d.ts ├── router.d.ts ├── shims-tsx.d.ts └── shims-vue.d.ts └── vite.config.ts /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | not ie 11 -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | .eslintcache 7 | report.html 8 | 9 | yarn.lock 10 | npm-debug.log* 11 | .pnpm-error.log* 12 | .pnpm-debug.log 13 | tests/**/coverage/ 14 | 15 | # Editor directories and files 16 | .idea 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | tsconfig.tsbuildinfo 22 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | insert_final_newline = false 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | # 平台本地运行端口号 2 | VITE_PORT = 8848 3 | 4 | # 是否隐藏首页 隐藏 true 不隐藏 false (勿删除,VITE_HIDE_HOME只需在.env文件配置) 5 | VITE_HIDE_HOME = false 6 | -------------------------------------------------------------------------------- /.env.development: -------------------------------------------------------------------------------- 1 | # 平台本地运行端口号 2 | VITE_PORT = 8848 3 | 4 | # 开发环境读取配置文件路径 5 | VITE_PUBLIC_PATH = / 6 | 7 | # 开发环境路由历史模式(Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数") 8 | VITE_ROUTER_HISTORY = "hash" 9 | -------------------------------------------------------------------------------- /.env.production: -------------------------------------------------------------------------------- 1 | # 线上环境平台打包路径 2 | VITE_PUBLIC_PATH = / 3 | 4 | # 线上环境路由历史模式(Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数") 5 | VITE_ROUTER_HISTORY = "hash" 6 | 7 | # 是否在打包时使用cdn替换本地库 替换 true 不替换 false 8 | VITE_CDN = false 9 | 10 | # 是否启用gzip压缩或brotli压缩(分两种情况,删除原始文件和不删除原始文件) 11 | # 压缩时不删除原始文件的配置:gzip、brotli、both(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认) 12 | # 压缩时删除原始文件的配置:gzip-clear、brotli-clear、both-clear(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认) 13 | VITE_COMPRESSION = "none" -------------------------------------------------------------------------------- /.env.staging: -------------------------------------------------------------------------------- 1 | # 预发布也需要生产环境的行为 2 | # https://cn.vitejs.dev/guide/env-and-mode.html#modes 3 | # NODE_ENV = development 4 | 5 | VITE_PUBLIC_PATH = / 6 | 7 | # 预发布环境路由历史模式(Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数") 8 | VITE_ROUTER_HISTORY = "hash" 9 | 10 | # 是否在打包时使用cdn替换本地库 替换 true 不替换 false 11 | VITE_CDN = true 12 | 13 | # 是否启用gzip压缩或brotli压缩(分两种情况,删除原始文件和不删除原始文件) 14 | # 压缩时不删除原始文件的配置:gzip、brotli、both(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认) 15 | # 压缩时删除原始文件的配置:gzip-clear、brotli-clear、both-clear(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认) 16 | VITE_COMPRESSION = "none" 17 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | public/wasm/capture.worker.js linguist-language=Vue 2 | public/wasm/index.js linguist-language=Vue -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/workflows/pages.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy 2 | permissions: 3 | contents: write 4 | on: 5 | push: 6 | branches: 7 | - pages 8 | 9 | jobs: 10 | deploy: 11 | concurrency: ci-${{ github.ref }} 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout 🛎️ 15 | uses: actions/checkout@v4 16 | 17 | - name: Install Node.js 18 | uses: actions/setup-node@v4 19 | with: 20 | node-version: 20 21 | registry-url: https://registry.npmjs.com/ 22 | 23 | - uses: pnpm/action-setup@v3 24 | name: Install pnpm 25 | id: pnpm-install 26 | with: 27 | version: 9 28 | run_install: false 29 | 30 | - name: Deploy 🔧 31 | run: | 32 | pnpm install --no-frozen-lockfile 33 | sed -i "s#VITE_PUBLIC_PATH = /#VITE_PUBLIC_PATH = /vue-pure-admin/#g" $(pwd)/.env.production 34 | pnpm build 35 | cd dist 36 | touch README.md .nojekyll 37 | 38 | - name: Deploy 🚀 39 | uses: JamesIves/github-pages-deploy-action@v4 40 | with: 41 | folder: dist 42 | clean: true -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | .eslintcache 7 | report.html 8 | vite.config.*.timestamp* 9 | 10 | yarn.lock 11 | npm-debug.log* 12 | .pnpm-error.log* 13 | .pnpm-debug.log 14 | tests/**/coverage/ 15 | 16 | # Editor directories and files 17 | .idea 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | tsconfig.tsbuildinfo -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | ports: 2 | - port: 3344 3 | onOpen: open-preview 4 | tasks: 5 | - init: pnpm install && pnpm serve 6 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # shellcheck source=./_/husky.sh 4 | . "$(dirname "$0")/_/husky.sh" 5 | 6 | PATH="/usr/local/bin:$PATH" 7 | 8 | npx --no-install commitlint --edit "$1" -------------------------------------------------------------------------------- /.husky/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | command_exists () { 3 | command -v "$1" >/dev/null 2>&1 4 | } 5 | 6 | # Workaround for Windows 10, Git Bash and Pnpm 7 | if command_exists winpty && test -t 1; then 8 | exec < /dev/tty 9 | fi 10 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | . "$(dirname "$0")/common.sh" 4 | 5 | [ -n "$CI" ] && exit 0 6 | 7 | PATH="/usr/local/bin:$PATH" 8 | 9 | # Perform lint check on files in the staging area through .lintstagedrc configuration 10 | pnpm exec lint-staged -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "*.{js,jsx,ts,tsx}": [ 3 | "prettier --cache --ignore-unknown --write", 4 | "eslint --cache --fix" 5 | ], 6 | "{!(package)*.json,*.code-snippets,.!({browserslist,npm,nvm})*rc}": [ 7 | "prettier --cache --write--parser json" 8 | ], 9 | "package.json": ["prettier --cache --write"], 10 | "*.vue": [ 11 | "prettier --write", 12 | "eslint --cache --fix", 13 | "stylelint --fix --allow-empty-input" 14 | ], 15 | "*.{css,scss,html}": [ 16 | "prettier --cache --ignore-unknown --write", 17 | "stylelint --fix --allow-empty-input" 18 | ], 19 | "*.md": ["prettier --cache --ignore-unknown --write"] 20 | } 21 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "default": true, 3 | "MD003": false, 4 | "MD033": false, 5 | "MD013": false, 6 | "MD001": false, 7 | "MD025": false, 8 | "MD024": false, 9 | "MD007": { "indent": 4 }, 10 | "no-hard-tabs": false 11 | } 12 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shell-emulator=true 2 | shamefully-hoist=true 3 | enable-pre-post-scripts=false 4 | strict-peer-dependencies=false -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v22.15.1 -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | src/views/system/menu/README.md -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | /** @type {import("prettier").Config} */ 4 | export default { 5 | bracketSpacing: true, 6 | singleQuote: false, 7 | arrowParens: "avoid", 8 | trailingComma: "none" 9 | }; 10 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | /dist/* 2 | /public/* 3 | public/* 4 | src/style/reset.scss -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "christian-kohler.path-intellisense", 4 | "warmthsea.vscode-custom-code-color", 5 | "vscode-icons-team.vscode-icons", 6 | "davidanson.vscode-markdownlint", 7 | "ms-azuretools.vscode-docker", 8 | "stylelint.vscode-stylelint", 9 | "bradlc.vscode-tailwindcss", 10 | "dbaeumer.vscode-eslint", 11 | "esbenp.prettier-vscode", 12 | "lokalise.i18n-ally", 13 | "redhat.vscode-yaml", 14 | "csstools.postcss", 15 | "mikestead.dotenv", 16 | "eamodio.gitlens", 17 | "antfu.iconify", 18 | "Vue.volar" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/vue3.0.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "Vue3.0快速生成模板": { 3 | "scope": "vue", 4 | "prefix": "Vue3.0", 5 | "body": [ 6 | "\n", 9 | "\n", 16 | "", 18 | "$2" 19 | ], 20 | "description": "Vue3.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.vscode/vue3.2.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "Vue3.2+快速生成模板": { 3 | "scope": "vue", 4 | "prefix": "Vue3.2+", 5 | "body": [ 6 | "\n", 8 | "\n", 11 | "", 13 | "$2" 14 | ], 15 | "description": "Vue3.2+" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.vscode/vue3.3.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "Vue3.3+defineOptions快速生成模板": { 3 | "scope": "vue", 4 | "prefix": "Vue3.3+", 5 | "body": [ 6 | "\n", 11 | "\n", 14 | "", 16 | "$2" 17 | ], 18 | "description": "Vue3.3+defineOptions快速生成模板" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:20-alpine as build-stage 2 | 3 | WORKDIR /app 4 | RUN corepack enable 5 | RUN corepack prepare pnpm@latest --activate 6 | 7 | RUN npm config set registry https://registry.npmmirror.com 8 | 9 | COPY .npmrc package.json pnpm-lock.yaml ./ 10 | RUN pnpm install --frozen-lockfile 11 | 12 | COPY . . 13 | RUN pnpm build 14 | 15 | FROM nginx:stable-alpine as production-stage 16 | 17 | COPY --from=build-stage /app/dist /usr/share/nginx/html 18 | EXPOSE 80 19 | 20 | CMD ["nginx", "-g", "daemon off;"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-present, pure-admin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | /** @type {import("@commitlint/types").UserConfig} */ 4 | export default { 5 | ignores: [commit => commit.includes("init")], 6 | extends: ["@commitlint/config-conventional"], 7 | rules: { 8 | "body-leading-blank": [2, "always"], 9 | "footer-leading-blank": [1, "always"], 10 | "header-max-length": [2, "always", 108], 11 | "subject-empty": [2, "never"], 12 | "type-empty": [2, "never"], 13 | "type-enum": [ 14 | 2, 15 | "always", 16 | [ 17 | "feat", 18 | "fix", 19 | "perf", 20 | "style", 21 | "docs", 22 | "test", 23 | "refactor", 24 | "build", 25 | "ci", 26 | "chore", 27 | "revert", 28 | "wip", 29 | "workflow", 30 | "types", 31 | "release" 32 | ] 33 | ] 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /mock/login.ts: -------------------------------------------------------------------------------- 1 | // 根据角色动态生成路由 2 | import { defineFakeRoute } from "vite-plugin-fake-server/client"; 3 | 4 | export default defineFakeRoute([ 5 | { 6 | url: "/login", 7 | method: "post", 8 | response: ({ body }) => { 9 | if (body.username === "admin") { 10 | return { 11 | success: true, 12 | data: { 13 | avatar: "https://avatars.githubusercontent.com/u/44761321", 14 | username: "admin", 15 | nickname: "小铭", 16 | // 一个用户可能有多个角色 17 | roles: ["admin"], 18 | // 按钮级别权限 19 | permissions: ["*:*:*"], 20 | accessToken: "eyJhbGciOiJIUzUxMiJ9.admin", 21 | refreshToken: "eyJhbGciOiJIUzUxMiJ9.adminRefresh", 22 | expires: "2030/10/30 00:00:00" 23 | } 24 | }; 25 | } else { 26 | return { 27 | success: true, 28 | data: { 29 | avatar: "https://avatars.githubusercontent.com/u/52823142", 30 | username: "common", 31 | nickname: "小林", 32 | roles: ["common"], 33 | permissions: ["permission:btn:add", "permission:btn:edit"], 34 | accessToken: "eyJhbGciOiJIUzUxMiJ9.common", 35 | refreshToken: "eyJhbGciOiJIUzUxMiJ9.commonRefresh", 36 | expires: "2030/10/30 00:00:00" 37 | } 38 | }; 39 | } 40 | } 41 | } 42 | ]); 43 | -------------------------------------------------------------------------------- /mock/map.ts: -------------------------------------------------------------------------------- 1 | import { defineFakeRoute } from "vite-plugin-fake-server/client"; 2 | import { faker } from "@faker-js/faker/locale/zh_CN"; 3 | 4 | type mapType = { 5 | plateNumber: string; 6 | driver: string; 7 | orientation: number; 8 | lng: number; 9 | lat: number; 10 | }; 11 | 12 | const mapList = (): Array => { 13 | const result: Array = []; 14 | for (let index = 0; index < 200; index++) { 15 | result.push({ 16 | plateNumber: `豫A${faker.string.numeric({ 17 | length: 5 18 | })}${faker.string.alphanumeric({ 19 | casing: "upper" 20 | })}`, 21 | driver: faker.person.firstName(), 22 | orientation: faker.number.int({ min: 1, max: 360 }), 23 | lng: faker.location.latitude({ max: 114.1, min: 113 }), 24 | lat: faker.location.latitude({ max: 35.1, min: 34 }) 25 | }); 26 | } 27 | return result; 28 | }; 29 | 30 | export default defineFakeRoute([ 31 | { 32 | url: "/get-map-info", 33 | method: "get", 34 | response: () => { 35 | return { 36 | success: true, 37 | data: mapList() 38 | }; 39 | } 40 | } 41 | ]); 42 | -------------------------------------------------------------------------------- /mock/refreshToken.ts: -------------------------------------------------------------------------------- 1 | import { defineFakeRoute } from "vite-plugin-fake-server/client"; 2 | 3 | // 模拟刷新token接口 4 | export default defineFakeRoute([ 5 | { 6 | url: "/refresh-token", 7 | method: "post", 8 | response: ({ body }) => { 9 | if (body.refreshToken) { 10 | return { 11 | success: true, 12 | data: { 13 | accessToken: "eyJhbGciOiJIUzUxMiJ9.newAdmin", 14 | refreshToken: "eyJhbGciOiJIUzUxMiJ9.newAdminRefresh", 15 | // `expires`选择这种日期格式是为了方便调试,后端直接设置时间戳或许更方便(每次都应该递增)。如果后端返回的是时间戳格式,前端开发请来到这个目录`src/utils/auth.ts`,把第`38`行的代码换成expires = data.expires即可。 16 | expires: "2030/10/30 23:59:59" 17 | } 18 | }; 19 | } else { 20 | return { 21 | success: false, 22 | data: {} 23 | }; 24 | } 25 | } 26 | } 27 | ]); 28 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | /** @type {import('postcss-load-config').Config} */ 4 | export default { 5 | plugins: { 6 | ...(process.env.NODE_ENV === "production" ? { cssnano: {} } : {}) 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /public/audio/海阔天空.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/public/audio/海阔天空.mp3 -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/public/favicon.ico -------------------------------------------------------------------------------- /public/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/platform-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "6.0.0", 3 | "Title": "PureAdmin", 4 | "FixedHeader": true, 5 | "HiddenSideBar": false, 6 | "MultiTagsCache": false, 7 | "KeepAlive": true, 8 | "Locale": "zh", 9 | "Layout": "vertical", 10 | "Theme": "light", 11 | "DarkMode": false, 12 | "OverallStyle": "light", 13 | "Grey": false, 14 | "Weak": false, 15 | "HideTabs": false, 16 | "HideFooter": false, 17 | "Stretch": false, 18 | "SidebarStatus": true, 19 | "EpThemeColor": "#409EFF", 20 | "ShowLogo": true, 21 | "ShowModel": "smart", 22 | "MenuArrowIconNoTransition": false, 23 | "CachingAsyncRoutes": false, 24 | "TooltipEffect": "light", 25 | "ResponsiveStorageNameSpace": "responsive-", 26 | "MenuSearchHistory": 6, 27 | "MapConfigure": { 28 | "amapKey": "adc139d56406f3844c8f1cf1c6b65c41", 29 | "options": { 30 | "resizeEnable": true, 31 | "center": [113.6401, 34.72468], 32 | "zoom": 12 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /public/wasm/capture.worker.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/public/wasm/capture.worker.wasm -------------------------------------------------------------------------------- /src/api/list.ts: -------------------------------------------------------------------------------- 1 | import { http } from "@/utils/http"; 2 | 3 | type Result = { 4 | success: boolean; 5 | data?: { 6 | /** 列表数据 */ 7 | list: Array; 8 | }; 9 | }; 10 | 11 | /** 卡片列表 */ 12 | export const getCardList = (data?: object) => { 13 | return http.request("post", "/get-card-list", { data }); 14 | }; 15 | -------------------------------------------------------------------------------- /src/api/mock.ts: -------------------------------------------------------------------------------- 1 | import { http } from "@/utils/http"; 2 | 3 | type Result = { 4 | success: boolean; 5 | data: Array; 6 | }; 7 | 8 | /** 地图数据 */ 9 | export const mapJson = (params?: object) => { 10 | return http.request("get", "/get-map-info", { params }); 11 | }; 12 | 13 | /** 文件上传 */ 14 | export const formUpload = data => { 15 | return http.request( 16 | "post", 17 | "https://run.mocky.io/v3/3aa761d7-b0b3-4a03-96b3-6168d4f7467b", 18 | { data }, 19 | { 20 | headers: { 21 | "Content-Type": "multipart/form-data" 22 | } 23 | } 24 | ); 25 | }; 26 | -------------------------------------------------------------------------------- /src/api/routes.ts: -------------------------------------------------------------------------------- 1 | import { http } from "@/utils/http"; 2 | 3 | type Result = { 4 | success: boolean; 5 | data: Array; 6 | }; 7 | 8 | export const getAsyncRoutes = () => { 9 | return http.request("get", "/get-async-routes"); 10 | }; 11 | -------------------------------------------------------------------------------- /src/assets/car.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/src/assets/car.png -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "iconfont"; /* Project id 2208059 */ 3 | src: 4 | url("iconfont.woff2?t=1671895108120") format("woff2"), 5 | url("iconfont.woff?t=1671895108120") format("woff"), 6 | url("iconfont.ttf?t=1671895108120") format("truetype"); 7 | } 8 | 9 | .iconfont { 10 | font-family: "iconfont" !important; 11 | font-size: 16px; 12 | font-style: normal; 13 | -webkit-font-smoothing: antialiased; 14 | -moz-osx-font-smoothing: grayscale; 15 | } 16 | 17 | .pure-iconfont-tabs:before { 18 | content: "\e63e"; 19 | } 20 | 21 | .pure-iconfont-logo:before { 22 | content: "\e620"; 23 | } 24 | 25 | .pure-iconfont-new:before { 26 | content: "\e615"; 27 | } 28 | -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "2208059", 3 | "name": "pure-admin", 4 | "font_family": "iconfont", 5 | "css_prefix_text": "pure-iconfont-", 6 | "description": "pure-admin-iconfont", 7 | "glyphs": [ 8 | { 9 | "icon_id": "20594647", 10 | "name": "Tabs", 11 | "font_class": "tabs", 12 | "unicode": "e63e", 13 | "unicode_decimal": 58942 14 | }, 15 | { 16 | "icon_id": "22129506", 17 | "name": "PureLogo", 18 | "font_class": "logo", 19 | "unicode": "e620", 20 | "unicode_decimal": 58912 21 | }, 22 | { 23 | "icon_id": "7795615", 24 | "name": "New", 25 | "font_class": "new", 26 | "unicode": "e615", 27 | "unicode_decimal": 58901 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/src/assets/iconfont/iconfont.ttf -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/src/assets/iconfont/iconfont.woff -------------------------------------------------------------------------------- /src/assets/iconfont/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/src/assets/iconfont/iconfont.woff2 -------------------------------------------------------------------------------- /src/assets/login/avatar.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/login/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/src/assets/login/bg.png -------------------------------------------------------------------------------- /src/assets/svg/back.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/back_top.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/calendar.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/day.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/enter_outlined.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/exit_screen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/full_screen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/globalization.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/hot.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/keyboard_esc.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/laptop.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/service.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/shop.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/system.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/svg/user_avatar.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/table-bar/collapse.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/table-bar/drag.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/table-bar/expand.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/table-bar/refresh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/table-bar/settings.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/src/assets/user.jpg -------------------------------------------------------------------------------- /src/components/ReAnimateSelector/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@pureadmin/utils"; 2 | import reAnimateSelector from "./src/index.vue"; 3 | 4 | /** [animate.css](https://animate.style/) 选择器组件 */ 5 | export const ReAnimateSelector = withInstall(reAnimateSelector); 6 | 7 | export default ReAnimateSelector; 8 | -------------------------------------------------------------------------------- /src/components/ReAuth/index.ts: -------------------------------------------------------------------------------- 1 | import auth from "./src/auth"; 2 | 3 | const Auth = auth; 4 | 5 | export { Auth }; 6 | -------------------------------------------------------------------------------- /src/components/ReAuth/src/auth.tsx: -------------------------------------------------------------------------------- 1 | import { defineComponent, Fragment } from "vue"; 2 | import { hasAuth } from "@/router/utils"; 3 | 4 | export default defineComponent({ 5 | name: "Auth", 6 | props: { 7 | value: { 8 | type: undefined, 9 | default: [] 10 | } 11 | }, 12 | setup(props, { slots }) { 13 | return () => { 14 | if (!slots) return null; 15 | return hasAuth(props.value) ? ( 16 | {slots.default?.()} 17 | ) : null; 18 | }; 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /src/components/ReBarcode/index.ts: -------------------------------------------------------------------------------- 1 | import { withInstall } from "@pureadmin/utils"; 2 | import reBarcode from "./src/index.vue"; 3 | 4 | /** 条形码组件 */ 5 | export const ReBarcode = withInstall(reBarcode); 6 | 7 | export default ReBarcode; 8 | -------------------------------------------------------------------------------- /src/components/ReBarcode/src/index.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 43 | -------------------------------------------------------------------------------- /src/components/ReCol/index.ts: -------------------------------------------------------------------------------- 1 | import { ElCol } from "element-plus"; 2 | import { h, defineComponent } from "vue"; 3 | 4 | // 封装element-plus的el-col组件 5 | export default defineComponent({ 6 | name: "ReCol", 7 | props: { 8 | value: { 9 | type: Number, 10 | default: 24 11 | } 12 | }, 13 | render() { 14 | const attrs = this.$attrs; 15 | const val = this.value; 16 | return h( 17 | ElCol, 18 | { 19 | xs: val, 20 | sm: val, 21 | md: val, 22 | lg: val, 23 | xl: val, 24 | ...attrs 25 | }, 26 | { default: () => this.$slots.default() } 27 | ); 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /src/components/ReCountTo/README.md: -------------------------------------------------------------------------------- 1 | normal 普通数字动画组件 2 | rebound 回弹式数字动画组件 3 | -------------------------------------------------------------------------------- /src/components/ReCountTo/index.ts: -------------------------------------------------------------------------------- 1 | import reNormalCountTo from "./src/normal"; 2 | import reboundCountTo from "./src/rebound"; 3 | import { withInstall } from "@pureadmin/utils"; 4 | 5 | /** 普通数字动画组件 */ 6 | const ReNormalCountTo = withInstall(reNormalCountTo); 7 | 8 | /** 回弹式数字动画组件 */ 9 | const ReboundCountTo = withInstall(reboundCountTo); 10 | 11 | export { ReNormalCountTo, ReboundCountTo }; 12 | -------------------------------------------------------------------------------- /src/components/ReCountTo/src/normal/props.ts: -------------------------------------------------------------------------------- 1 | import type { PropType } from "vue"; 2 | import propTypes from "@/utils/propTypes"; 3 | 4 | export const countToProps = { 5 | startVal: propTypes.number.def(0), 6 | endVal: propTypes.number.def(2020), 7 | duration: propTypes.number.def(1300), 8 | autoplay: propTypes.bool.def(true), 9 | decimals: { 10 | type: Number as PropType, 11 | required: false, 12 | default: 0, 13 | validator(value: number) { 14 | return value >= 0; 15 | } 16 | }, 17 | color: propTypes.string.def(), 18 | fontSize: propTypes.string.def(), 19 | decimal: propTypes.string.def("."), 20 | separator: propTypes.string.def(","), 21 | prefix: propTypes.string.def(""), 22 | suffix: propTypes.string.def(""), 23 | useEasing: propTypes.bool.def(true), 24 | easingFn: { 25 | type: Function as PropType< 26 | (t: number, b: number, c: number, d: number) => number 27 | >, 28 | default(t: number, b: number, c: number, d: number) { 29 | return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b; 30 | } 31 | } 32 | }; 33 | -------------------------------------------------------------------------------- /src/components/ReCountTo/src/rebound/props.ts: -------------------------------------------------------------------------------- 1 | import type { PropType } from "vue"; 2 | import propTypes from "@/utils/propTypes"; 3 | 4 | export const reboundProps = { 5 | delay: propTypes.number.def(1), 6 | blur: propTypes.number.def(2), 7 | i: { 8 | type: Number as PropType, 9 | required: false, 10 | default: 0, 11 | validator(value: number) { 12 | return value < 10 && value >= 0 && Number.isInteger(value); 13 | } 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /src/components/ReCropper/index.ts: -------------------------------------------------------------------------------- 1 | import reCropper from "./src"; 2 | import { withInstall } from "@pureadmin/utils"; 3 | 4 | /** 图片裁剪组件 */ 5 | export const ReCropper = withInstall(reCropper); 6 | 7 | export default ReCropper; 8 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/circled.css: -------------------------------------------------------------------------------- 1 | @import "cropperjs/dist/cropper.css"; 2 | 3 | .re-circled { 4 | .cropper-view-box, 5 | .cropper-face { 6 | border-radius: 50%; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/svg/arrow-down.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/svg/arrow-h.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/svg/arrow-left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/svg/arrow-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/svg/arrow-up.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/svg/arrow-v.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/svg/change.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/svg/download.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/svg/index.ts: -------------------------------------------------------------------------------- 1 | import Reload from "./reload.svg?component"; 2 | import Upload from "./upload.svg?component"; 3 | import ArrowH from "./arrow-h.svg?component"; 4 | import ArrowV from "./arrow-v.svg?component"; 5 | import ArrowUp from "./arrow-up.svg?component"; 6 | import ChangeIcon from "./change.svg?component"; 7 | import ArrowDown from "./arrow-down.svg?component"; 8 | import ArrowLeft from "./arrow-left.svg?component"; 9 | import DownloadIcon from "./download.svg?component"; 10 | import ArrowRight from "./arrow-right.svg?component"; 11 | import RotateLeft from "./rotate-left.svg?component"; 12 | import SearchPlus from "./search-plus.svg?component"; 13 | import RotateRight from "./rotate-right.svg?component"; 14 | import SearchMinus from "./search-minus.svg?component"; 15 | 16 | export { 17 | Reload, 18 | Upload, 19 | ArrowH, 20 | ArrowV, 21 | ArrowUp, 22 | ArrowDown, 23 | ArrowLeft, 24 | ChangeIcon, 25 | ArrowRight, 26 | RotateLeft, 27 | SearchPlus, 28 | RotateRight, 29 | SearchMinus, 30 | DownloadIcon 31 | }; 32 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/svg/reload.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/svg/rotate-left.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/svg/rotate-right.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/svg/search-minus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/svg/search-plus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ReCropper/src/svg/upload.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/ReCropperPreview/index.ts: -------------------------------------------------------------------------------- 1 | import reCropperPreview from "./src/index.vue"; 2 | import { withInstall } from "@pureadmin/utils"; 3 | 4 | /** 图片裁剪预览组件 */ 5 | export const ReCropperPreview = withInstall(reCropperPreview); 6 | 7 | export default ReCropperPreview; 8 | -------------------------------------------------------------------------------- /src/components/ReFlicker/index.css: -------------------------------------------------------------------------------- 1 | .point { 2 | width: var(--point-width); 3 | height: var(--point-height); 4 | background: var(--point-background); 5 | position: relative; 6 | border-radius: var(--point-border-radius); 7 | } 8 | 9 | .point-flicker:after { 10 | background: var(--point-background); 11 | } 12 | 13 | .point-flicker:before, 14 | .point-flicker:after { 15 | content: ""; 16 | width: 100%; 17 | height: 100%; 18 | top: 0; 19 | left: 0; 20 | position: absolute; 21 | border-radius: var(--point-border-radius); 22 | animation: flicker 1.2s ease-out infinite; 23 | } 24 | 25 | @keyframes flicker { 26 | 0% { 27 | transform: scale(0.5); 28 | opacity: 1; 29 | } 30 | 31 | 30% { 32 | opacity: 1; 33 | } 34 | 35 | 100% { 36 | transform: scale(var(--point-scale)); 37 | opacity: 0; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/components/ReFlicker/index.ts: -------------------------------------------------------------------------------- 1 | import "./index.css"; 2 | import { type Component, h, defineComponent } from "vue"; 3 | 4 | export interface attrsType { 5 | width?: string; 6 | height?: string; 7 | borderRadius?: number | string; 8 | background?: string; 9 | scale?: number | string; 10 | } 11 | 12 | /** 13 | * 圆点、方形闪烁动画组件 14 | * @param width 可选 string 宽 15 | * @param height 可选 string 高 16 | * @param borderRadius 可选 number | string 传0为方形、传50%或者不传为圆形 17 | * @param background 可选 string 闪烁颜色 18 | * @param scale 可选 number | string 闪烁范围,默认2,值越大闪烁范围越大 19 | * @returns Component 20 | */ 21 | export function useRenderFlicker(attrs?: attrsType): Component { 22 | return defineComponent({ 23 | name: "ReFlicker", 24 | render() { 25 | return h( 26 | "div", 27 | { 28 | class: "point point-flicker", 29 | style: { 30 | "--point-width": attrs?.width ?? "12px", 31 | "--point-height": attrs?.height ?? "12px", 32 | "--point-background": 33 | attrs?.background ?? "var(--el-color-primary)", 34 | "--point-border-radius": attrs?.borderRadius ?? "50%", 35 | "--point-scale": attrs?.scale ?? "2" 36 | } 37 | }, 38 | { 39 | default: () => [] 40 | } 41 | ); 42 | } 43 | }); 44 | } 45 | -------------------------------------------------------------------------------- /src/components/ReFlop/index.ts: -------------------------------------------------------------------------------- 1 | import reFlop from "./src/index.vue"; 2 | import { withInstall } from "@pureadmin/utils"; 3 | 4 | /** 时间翻牌组件 */ 5 | export const ReFlop = withInstall(reFlop); 6 | 7 | export default ReFlop; 8 | -------------------------------------------------------------------------------- /src/components/ReFlowChart/index.ts: -------------------------------------------------------------------------------- 1 | import control from "./src/Control.vue"; 2 | import nodePanel from "./src/NodePanel.vue"; 3 | import dataDialog from "./src/DataDialog.vue"; 4 | import { withInstall } from "@pureadmin/utils"; 5 | 6 | /** LogicFlow流程图-控制面板 */ 7 | const Control = withInstall(control); 8 | 9 | /** LogicFlow流程图-拖拽面板 */ 10 | const NodePanel = withInstall(nodePanel); 11 | 12 | /** LogicFlow流程图-查看数据 */ 13 | const DataDialog = withInstall(dataDialog); 14 | 15 | export { Control, NodePanel, DataDialog }; 16 | 17 | // LogicFlow流程图文档:http://logic-flow.org/ 18 | -------------------------------------------------------------------------------- /src/components/ReFlowChart/src/DataDialog.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | -------------------------------------------------------------------------------- /src/components/ReFlowChart/src/assets/iconfont/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/src/components/ReFlowChart/src/assets/iconfont/iconfont.eot -------------------------------------------------------------------------------- /src/components/ReFlowChart/src/assets/iconfont/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/src/components/ReFlowChart/src/assets/iconfont/iconfont.ttf -------------------------------------------------------------------------------- /src/components/ReFlowChart/src/assets/iconfont/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/src/components/ReFlowChart/src/assets/iconfont/iconfont.woff -------------------------------------------------------------------------------- /src/components/ReFlowChart/src/assets/iconfont/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/src/components/ReFlowChart/src/assets/iconfont/iconfont.woff2 -------------------------------------------------------------------------------- /src/components/ReFlowChart/src/config.ts: -------------------------------------------------------------------------------- 1 | export const nodeList = [ 2 | { 3 | text: "开始", 4 | type: "start", 5 | class: "node-start" 6 | }, 7 | { 8 | text: "矩形", 9 | type: "rect", 10 | class: "node-rect" 11 | }, 12 | { 13 | type: "user", 14 | text: "用户", 15 | class: "node-user" 16 | }, 17 | { 18 | type: "push", 19 | text: "推送", 20 | class: "node-push" 21 | }, 22 | { 23 | type: "download", 24 | text: "位置", 25 | class: "node-download" 26 | }, 27 | { 28 | type: "end", 29 | text: "结束", 30 | class: "node-end" 31 | } 32 | ]; 33 | 34 | export const BpmnNode = [ 35 | { 36 | type: "bpmn:startEvent", 37 | text: "开始", 38 | class: "bpmn-start" 39 | }, 40 | { 41 | type: "bpmn:endEvent", 42 | text: "结束", 43 | class: "bpmn-end" 44 | }, 45 | { 46 | type: "bpmn:exclusiveGateway", 47 | text: "网关", 48 | class: "bpmn-exclusiveGateway" 49 | }, 50 | { 51 | type: "bpmn:userTask", 52 | text: "用户", 53 | class: "bpmn-user" 54 | } 55 | ]; 56 | -------------------------------------------------------------------------------- /src/components/ReIcon/index.ts: -------------------------------------------------------------------------------- 1 | import iconifyIconOffline from "./src/iconifyIconOffline"; 2 | import iconifyIconOnline from "./src/iconifyIconOnline"; 3 | import iconSelect from "./src/Select.vue"; 4 | import fontIcon from "./src/iconfont"; 5 | 6 | /** 本地图标组件 */ 7 | const IconifyIconOffline = iconifyIconOffline; 8 | /** 在线图标组件 */ 9 | const IconifyIconOnline = iconifyIconOnline; 10 | /** `IconSelect`图标选择器组件 */ 11 | const IconSelect = iconSelect; 12 | /** `iconfont`组件 */ 13 | const FontIcon = fontIcon; 14 | 15 | export { IconifyIconOffline, IconifyIconOnline, IconSelect, FontIcon }; 16 | -------------------------------------------------------------------------------- /src/components/ReIcon/src/iconfont.ts: -------------------------------------------------------------------------------- 1 | import { h, defineComponent } from "vue"; 2 | 3 | // 封装iconfont组件,默认`font-class`引用模式,支持`unicode`引用、`font-class`引用、`symbol`引用 (https://www.iconfont.cn/help/detail?spm=a313x.7781069.1998910419.20&helptype=code) 4 | export default defineComponent({ 5 | name: "FontIcon", 6 | props: { 7 | icon: { 8 | type: String, 9 | default: "" 10 | } 11 | }, 12 | render() { 13 | const attrs = this.$attrs; 14 | if (Object.keys(attrs).includes("uni") || attrs?.iconType === "uni") { 15 | return h( 16 | "i", 17 | { 18 | class: "iconfont", 19 | ...attrs 20 | }, 21 | this.icon 22 | ); 23 | } else if ( 24 | Object.keys(attrs).includes("svg") || 25 | attrs?.iconType === "svg" 26 | ) { 27 | return h( 28 | "svg", 29 | { 30 | class: "icon-svg" 31 | }, 32 | { 33 | default: () => [ 34 | h("use", { 35 | "xlink:href": `#${this.icon}` 36 | }) 37 | ] 38 | } 39 | ); 40 | } else { 41 | return h("i", { 42 | class: `iconfont ${this.icon}`, 43 | ...attrs 44 | }); 45 | } 46 | } 47 | }); 48 | -------------------------------------------------------------------------------- /src/components/ReIcon/src/iconifyIconOffline.ts: -------------------------------------------------------------------------------- 1 | import { h, defineComponent } from "vue"; 2 | import { Icon as IconifyIcon, addIcon } from "@iconify/vue/dist/offline"; 3 | 4 | // Iconify Icon在Vue里本地使用(用于内网环境) 5 | export default defineComponent({ 6 | name: "IconifyIconOffline", 7 | components: { IconifyIcon }, 8 | props: { 9 | icon: { 10 | default: null 11 | } 12 | }, 13 | render() { 14 | if (typeof this.icon === "object") addIcon(this.icon, this.icon); 15 | const attrs = this.$attrs; 16 | if (typeof this.icon === "string") { 17 | return h( 18 | IconifyIcon, 19 | { 20 | icon: this.icon, 21 | "aria-hidden": false, 22 | style: attrs?.style 23 | ? Object.assign(attrs.style, { outline: "none" }) 24 | : { outline: "none" }, 25 | ...attrs 26 | }, 27 | { 28 | default: () => [] 29 | } 30 | ); 31 | } else { 32 | return h( 33 | this.icon, 34 | { 35 | "aria-hidden": false, 36 | style: attrs?.style 37 | ? Object.assign(attrs.style, { outline: "none" }) 38 | : { outline: "none" }, 39 | ...attrs 40 | }, 41 | { 42 | default: () => [] 43 | } 44 | ); 45 | } 46 | } 47 | }); 48 | -------------------------------------------------------------------------------- /src/components/ReIcon/src/iconifyIconOnline.ts: -------------------------------------------------------------------------------- 1 | import { h, defineComponent } from "vue"; 2 | import { Icon as IconifyIcon } from "@iconify/vue"; 3 | 4 | // Iconify Icon在Vue里在线使用(用于外网环境) 5 | export default defineComponent({ 6 | name: "IconifyIconOnline", 7 | components: { IconifyIcon }, 8 | props: { 9 | icon: { 10 | type: String, 11 | default: "" 12 | } 13 | }, 14 | render() { 15 | const attrs = this.$attrs; 16 | return h( 17 | IconifyIcon, 18 | { 19 | icon: `${this.icon}`, 20 | "aria-hidden": false, 21 | style: attrs?.style 22 | ? Object.assign(attrs.style, { outline: "none" }) 23 | : { outline: "none" }, 24 | ...attrs 25 | }, 26 | { 27 | default: () => [] 28 | } 29 | ); 30 | } 31 | }); 32 | -------------------------------------------------------------------------------- /src/components/ReIcon/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface iconType { 2 | // iconify (https://docs.iconify.design/icon-components/vue/#properties) 3 | inline?: boolean; 4 | width?: string | number; 5 | height?: string | number; 6 | horizontalFlip?: boolean; 7 | verticalFlip?: boolean; 8 | flip?: string; 9 | rotate?: number | string; 10 | color?: string; 11 | horizontalAlign?: boolean; 12 | verticalAlign?: boolean; 13 | align?: string; 14 | onLoad?: Function; 15 | includes?: Function; 16 | // svg 需要什么SVG属性自行添加 17 | fill?: string; 18 | // all icon 19 | style?: object; 20 | } 21 | -------------------------------------------------------------------------------- /src/components/ReImageVerify/index.ts: -------------------------------------------------------------------------------- 1 | import reImageVerify from "./src/index.vue"; 2 | import { withInstall } from "@pureadmin/utils"; 3 | 4 | /** 图形验证码组件 */ 5 | export const ReImageVerify = withInstall(reImageVerify); 6 | 7 | export default ReImageVerify; 8 | -------------------------------------------------------------------------------- /src/components/ReImageVerify/src/index.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 47 | -------------------------------------------------------------------------------- /src/components/ReMap/index.ts: -------------------------------------------------------------------------------- 1 | import amap from "./src/Amap.vue"; 2 | import { withInstall } from "@pureadmin/utils"; 3 | 4 | /** 高德地图组件 */ 5 | export const Amap = withInstall(amap); 6 | 7 | export default Amap; 8 | -------------------------------------------------------------------------------- /src/components/RePerms/index.ts: -------------------------------------------------------------------------------- 1 | import perms from "./src/perms"; 2 | 3 | const Perms = perms; 4 | 5 | export { Perms }; 6 | -------------------------------------------------------------------------------- /src/components/RePerms/src/perms.tsx: -------------------------------------------------------------------------------- 1 | import { defineComponent, Fragment } from "vue"; 2 | import { hasPerms } from "@/utils/auth"; 3 | 4 | export default defineComponent({ 5 | name: "Perms", 6 | props: { 7 | value: { 8 | type: undefined, 9 | default: [] 10 | } 11 | }, 12 | setup(props, { slots }) { 13 | return () => { 14 | if (!slots) return null; 15 | return hasPerms(props.value) ? ( 16 | {slots.default?.()} 17 | ) : null; 18 | }; 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /src/components/RePureTableBar/index.ts: -------------------------------------------------------------------------------- 1 | import pureTableBar from "./src/bar"; 2 | import { withInstall } from "@pureadmin/utils"; 3 | 4 | /** 配合 `@pureadmin/table` 实现快速便捷的表格操作 https://github.com/pure-admin/pure-admin-table */ 5 | export const PureTableBar = withInstall(pureTableBar); 6 | -------------------------------------------------------------------------------- /src/components/ReQrcode/index.ts: -------------------------------------------------------------------------------- 1 | import reQrcode from "./src/index"; 2 | import { withInstall } from "@pureadmin/utils"; 3 | 4 | /** 二维码组件 */ 5 | export const ReQrcode = withInstall(reQrcode); 6 | 7 | export default ReQrcode; 8 | -------------------------------------------------------------------------------- /src/components/ReQrcode/src/index.scss: -------------------------------------------------------------------------------- 1 | .qrcode { 2 | &--disabled { 3 | background: rgb(255 255 255 / 95%); 4 | 5 | & > div { 6 | transform: translate(-50%, -50%); 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/components/ReSeamlessScroll/index.ts: -------------------------------------------------------------------------------- 1 | import reSeamlessScroll from "./src/index.vue"; 2 | import { withInstall } from "@pureadmin/utils"; 3 | 4 | /** 无缝滚动组件 */ 5 | export const ReSeamlessScroll = withInstall(reSeamlessScroll); 6 | 7 | export default ReSeamlessScroll; 8 | -------------------------------------------------------------------------------- /src/components/ReSegmented/index.ts: -------------------------------------------------------------------------------- 1 | import reSegmented from "./src/index"; 2 | import { withInstall } from "@pureadmin/utils"; 3 | 4 | /** 分段控制器组件 */ 5 | export const ReSegmented = withInstall(reSegmented); 6 | 7 | export default ReSegmented; 8 | export type { OptionsType } from "./src/type"; 9 | -------------------------------------------------------------------------------- /src/components/ReSegmented/src/type.ts: -------------------------------------------------------------------------------- 1 | import type { VNode, Component } from "vue"; 2 | import type { iconType } from "@/components/ReIcon/src/types.ts"; 3 | 4 | export interface OptionsType { 5 | /** 文字 */ 6 | label?: string | (() => VNode | Component); 7 | /** 8 | * @description 图标,采用平台内置的 `useRenderIcon` 函数渲染 9 | * @see {@link 用法参考 https://pure-admin.cn/pages/icon/#%E9%80%9A%E7%94%A8%E5%9B%BE%E6%A0%87-userendericon-hooks } 10 | */ 11 | icon?: string | Component; 12 | /** 图标属性、样式配置 */ 13 | iconAttrs?: iconType; 14 | /** 值 */ 15 | value?: any; 16 | /** 是否禁用 */ 17 | disabled?: boolean; 18 | /** `tooltip` 提示 */ 19 | tip?: string; 20 | } 21 | -------------------------------------------------------------------------------- /src/components/ReSelector/index.ts: -------------------------------------------------------------------------------- 1 | import reSelector from "./src"; 2 | import { withInstall } from "@pureadmin/utils"; 3 | 4 | /** 选择器组件 */ 5 | export const ReSelector = withInstall(reSelector); 6 | 7 | export default ReSelector; 8 | -------------------------------------------------------------------------------- /src/components/ReSelector/src/index.css: -------------------------------------------------------------------------------- 1 | .hs-rate__icon { 2 | font-size: 18px; 3 | transition: 0.3s; 4 | } 5 | 6 | .hs-item { 7 | width: 30px; 8 | height: 30px; 9 | box-sizing: border-box; 10 | line-height: 30px; 11 | } 12 | 13 | .hs-on { 14 | background-color: #409eff; 15 | border-radius: 50%; 16 | } 17 | 18 | .hs-range { 19 | background-color: #f2f6fc; 20 | } 21 | 22 | .both-left-sides { 23 | border-radius: 50% 0 0 50%; 24 | } 25 | 26 | .both-right-sides { 27 | border-radius: 0 50% 50% 0; 28 | } 29 | -------------------------------------------------------------------------------- /src/components/ReSplitPane/iconfont/iconfont.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "iconfont"; /* Project id 3268330 */ 3 | src: 4 | url("iconfont.woff2?t=1647939915215") format("woff2"), 5 | url("iconfont.woff?t=1647939915215") format("woff"), 6 | url("iconfont.ttf?t=1647939915215") format("truetype"); 7 | } 8 | 9 | .iconfont { 10 | font-family: "iconfont" !important; 11 | font-size: 16px; 12 | font-style: normal; 13 | -webkit-font-smoothing: antialiased; 14 | -moz-osx-font-smoothing: grayscale; 15 | } 16 | 17 | .icon-tuozhuai1:before { 18 | content: "\e647"; 19 | } 20 | 21 | .icon-tuozhuai1-copy:before { 22 | content: "\eda3"; 23 | } 24 | -------------------------------------------------------------------------------- /src/components/ReSplitPane/iconfont/iconfont.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "3268330", 3 | "name": "split", 4 | "font_family": "iconfont", 5 | "css_prefix_text": "icon-", 6 | "description": "", 7 | "glyphs": [ 8 | { 9 | "icon_id": "22378774", 10 | "name": "拖拽", 11 | "font_class": "tuozhuai1", 12 | "unicode": "e647", 13 | "unicode_decimal": 58951 14 | }, 15 | { 16 | "icon_id": "23570521", 17 | "name": "拖拽", 18 | "font_class": "tuozhuai1-copy", 19 | "unicode": "eda3", 20 | "unicode_decimal": 60835 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /src/components/ReSplitPane/iconfont/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/src/components/ReSplitPane/iconfont/iconfont.ttf -------------------------------------------------------------------------------- /src/components/ReSplitPane/iconfont/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/src/components/ReSplitPane/iconfont/iconfont.woff -------------------------------------------------------------------------------- /src/components/ReSplitPane/iconfont/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pure-admin/vue-pure-admin/d9a4ab8f86eec9a5839611eda2947d7a7692acff/src/components/ReSplitPane/iconfont/iconfont.woff2 -------------------------------------------------------------------------------- /src/components/ReSplitPane/index.css: -------------------------------------------------------------------------------- 1 | .clearfix::after { 2 | visibility: hidden; 3 | display: block; 4 | font-size: 0; 5 | content: " "; 6 | clear: both; 7 | height: 0; 8 | } 9 | 10 | .vue-splitter-container { 11 | height: 100%; 12 | position: relative; 13 | } 14 | 15 | .vue-splitter-container-mask { 16 | z-index: 9999; 17 | width: 100%; 18 | height: 100%; 19 | position: absolute; 20 | top: 0; 21 | left: 0; 22 | } 23 | 24 | .splitter-pane.vertical.splitter-paneL { 25 | position: absolute; 26 | left: 0; 27 | height: 100%; 28 | padding-right: 3px; 29 | } 30 | 31 | .splitter-pane.vertical.splitter-paneR { 32 | position: absolute; 33 | right: 0; 34 | height: 100%; 35 | padding-left: 3px; 36 | } 37 | 38 | .splitter-pane.horizontal.splitter-paneL { 39 | position: absolute; 40 | top: 0; 41 | width: 100%; 42 | } 43 | 44 | .splitter-pane.horizontal.splitter-paneR { 45 | position: absolute; 46 | bottom: 0; 47 | width: 100%; 48 | padding-top: 3px; 49 | } 50 | -------------------------------------------------------------------------------- /src/components/ReSplitPane/resizer.css: -------------------------------------------------------------------------------- 1 | @import "./iconfont/iconfont.css"; 2 | 3 | .splitter-pane-resizer { 4 | box-sizing: border-box; 5 | background: #000; 6 | position: absolute; 7 | opacity: 0.2; 8 | z-index: 1; 9 | background-clip: padding; 10 | background-clip: padding-box; 11 | } 12 | 13 | .splitter-pane-resizer.horizontal { 14 | height: 6px; 15 | width: 100%; 16 | background: #e5e6eb; 17 | cursor: row-resize; 18 | } 19 | 20 | .splitter-pane-resizer.horizontal:before { 21 | content: "\eda3"; 22 | font-family: "iconfont"; 23 | font-size: 13px; 24 | color: #000; 25 | position: absolute; 26 | top: 50%; 27 | left: 50%; 28 | transform: translate(-50%, -50%); 29 | } 30 | 31 | .splitter-pane-resizer.vertical { 32 | width: 6px; 33 | height: 100%; 34 | background: #e5e6eb; 35 | cursor: col-resize; 36 | } 37 | 38 | .splitter-pane-resizer.vertical:before { 39 | content: "\e647"; 40 | font-family: "iconfont"; 41 | font-size: 13px; 42 | color: #000; 43 | position: absolute; 44 | top: 50%; 45 | left: 50%; 46 | transform: translate(-50%, -50%); 47 | } 48 | -------------------------------------------------------------------------------- /src/components/ReSplitPane/resizer.tsx: -------------------------------------------------------------------------------- 1 | import "./resizer.css"; 2 | import { computed, unref, defineComponent } from "vue"; 3 | 4 | export default defineComponent({ 5 | name: "Resizer", 6 | props: { 7 | split: { 8 | type: String, 9 | required: true 10 | }, 11 | className: { 12 | type: String, 13 | default: "" 14 | } 15 | }, 16 | setup(props) { 17 | const classes = computed(() => { 18 | return ["splitter-pane-resizer", props.split, props.className].join(" "); 19 | }); 20 | 21 | return () =>
; 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /src/components/ReText/index.ts: -------------------------------------------------------------------------------- 1 | import reText from "./src/index.vue"; 2 | import { withInstall } from "@pureadmin/utils"; 3 | 4 | /** 支持`Tooltip`提示的文本省略组件 */ 5 | export const ReText = withInstall(reText); 6 | 7 | export default ReText; 8 | -------------------------------------------------------------------------------- /src/components/ReTreeLine/index.scss: -------------------------------------------------------------------------------- 1 | $--element-tree-line-color: #dcdfe6 !default; 2 | $--element-tree-line-style: dashed !default; 3 | $--element-tree-line-width: 1px !default; 4 | 5 | /* 添加 el-tree-node__conten 默认没有的 position */ 6 | .el-tree .el-tree-node__content { 7 | position: relative; 8 | } 9 | 10 | .element-tree-node-label-wrapper { 11 | display: flex; 12 | flex: 1; 13 | align-items: center; 14 | } 15 | 16 | .element-tree-node-label { 17 | font-size: 12px; 18 | } 19 | 20 | .element-tree-node-line-ver { 21 | position: absolute; 22 | top: 0; 23 | left: 0; 24 | display: block; 25 | height: 100%; 26 | border-left: $--element-tree-line-width $--element-tree-line-style 27 | $--element-tree-line-color; 28 | 29 | &.last-node-line { 30 | border-left: $--element-tree-line-width $--element-tree-line-style 31 | transparent; 32 | } 33 | 34 | &.last-node-isLeaf-line { 35 | height: 50%; 36 | } 37 | } 38 | 39 | .element-tree-node-line-hor { 40 | position: absolute; 41 | top: 50%; 42 | left: 0; 43 | display: block; 44 | height: 0; 45 | border-bottom: $--element-tree-line-width $--element-tree-line-style 46 | $--element-tree-line-color; 47 | } 48 | 49 | .element-tree-node-label-line { 50 | flex: 1; 51 | align-self: center; 52 | margin: 0 10px; 53 | border-top: $--element-tree-line-width $--element-tree-line-style 54 | $--element-tree-line-color; 55 | } 56 | -------------------------------------------------------------------------------- /src/components/ReTypeit/index.ts: -------------------------------------------------------------------------------- 1 | import typeIt from "./src/index"; 2 | import type { Options as TypeItOptions } from "typeit"; 3 | 4 | const TypeIt = typeIt; 5 | 6 | export { TypeIt, TypeItOptions }; 7 | 8 | export default TypeIt; 9 | -------------------------------------------------------------------------------- /src/components/ReVxeTableBar/index.ts: -------------------------------------------------------------------------------- 1 | import vxeTableBar from "./src/bar"; 2 | import { withInstall } from "@pureadmin/utils"; 3 | 4 | /** 配合 `vxe-table` 实现快速便捷的表格操作 */ 5 | export const VxeTableBar = withInstall(vxeTableBar); 6 | -------------------------------------------------------------------------------- /src/directives/auth/index.ts: -------------------------------------------------------------------------------- 1 | import { hasAuth } from "@/router/utils"; 2 | import type { Directive, DirectiveBinding } from "vue"; 3 | 4 | export const auth: Directive = { 5 | mounted(el: HTMLElement, binding: DirectiveBinding>) { 6 | const { value } = binding; 7 | if (value) { 8 | !hasAuth(value) && el.parentNode?.removeChild(el); 9 | } else { 10 | throw new Error( 11 | "[Directive: auth]: need auths! Like v-auth=\"['btn.add','btn.edit']\"" 12 | ); 13 | } 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /src/directives/copy/index.ts: -------------------------------------------------------------------------------- 1 | import { message } from "@/utils/message"; 2 | import { useEventListener } from "@vueuse/core"; 3 | import { copyTextToClipboard } from "@pureadmin/utils"; 4 | import type { Directive, DirectiveBinding } from "vue"; 5 | 6 | export interface CopyEl extends HTMLElement { 7 | copyValue: string; 8 | } 9 | 10 | /** 文本复制指令(默认双击复制) */ 11 | export const copy: Directive = { 12 | mounted(el: CopyEl, binding: DirectiveBinding) { 13 | const { value } = binding; 14 | if (value) { 15 | el.copyValue = value; 16 | const arg = binding.arg ?? "dblclick"; 17 | // Register using addEventListener on mounted, and removeEventListener automatically on unmounted 18 | useEventListener(el, arg, () => { 19 | const success = copyTextToClipboard(el.copyValue); 20 | success 21 | ? message("复制成功", { type: "success" }) 22 | : message("复制失败", { type: "error" }); 23 | }); 24 | } else { 25 | throw new Error( 26 | '[Directive: copy]: need value! Like v-copy="modelValue"' 27 | ); 28 | } 29 | }, 30 | updated(el: CopyEl, binding: DirectiveBinding) { 31 | el.copyValue = binding.value; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/directives/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./auth"; 2 | export * from "./copy"; 3 | export * from "./longpress"; 4 | export * from "./optimize"; 5 | export * from "./perms"; 6 | export * from "./ripple"; 7 | -------------------------------------------------------------------------------- /src/directives/perms/index.ts: -------------------------------------------------------------------------------- 1 | import { hasPerms } from "@/utils/auth"; 2 | import type { Directive, DirectiveBinding } from "vue"; 3 | 4 | export const perms: Directive = { 5 | mounted(el: HTMLElement, binding: DirectiveBinding>) { 6 | const { value } = binding; 7 | if (value) { 8 | !hasPerms(value) && el.parentNode?.removeChild(el); 9 | } else { 10 | throw new Error( 11 | "[Directive: perms]: need perms! Like v-perms=\"['btn.add','btn.edit']\"" 12 | ); 13 | } 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /src/directives/ripple/index.scss: -------------------------------------------------------------------------------- 1 | /* stylelint-disable-next-line scss/dollar-variable-colon-space-after */ 2 | $ripple-animation-transition-in: 3 | transform 0.4s cubic-bezier(0, 0, 0.2, 1), 4 | opacity 0.2s cubic-bezier(0, 0, 0.2, 1) !default; 5 | $ripple-animation-transition-out: opacity 0.5s cubic-bezier(0, 0, 0.2, 1) !default; 6 | $ripple-animation-visible-opacity: 0.25 !default; 7 | 8 | .v-ripple { 9 | &__container { 10 | position: absolute; 11 | top: 0; 12 | left: 0; 13 | z-index: 0; 14 | width: 100%; 15 | height: 100%; 16 | overflow: hidden; 17 | pointer-events: none; 18 | border-radius: inherit; 19 | contain: strict; 20 | } 21 | 22 | &__animation { 23 | position: absolute; 24 | top: 0; 25 | left: 0; 26 | overflow: hidden; 27 | pointer-events: none; 28 | background: currentcolor; 29 | border-radius: 50%; 30 | opacity: 0; 31 | will-change: transform, opacity; 32 | 33 | &--enter { 34 | opacity: 0; 35 | transition: none; 36 | } 37 | 38 | &--in { 39 | opacity: $ripple-animation-visible-opacity; 40 | transition: $ripple-animation-transition-in; 41 | } 42 | 43 | &--out { 44 | opacity: 0; 45 | transition: $ripple-animation-transition-out; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/layout/components/lay-footer/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 21 | 22 | 32 | -------------------------------------------------------------------------------- /src/layout/components/lay-notice/components/NoticeList.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 25 | -------------------------------------------------------------------------------- /src/layout/components/lay-search/index.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 22 | -------------------------------------------------------------------------------- /src/layout/components/lay-search/types.ts: -------------------------------------------------------------------------------- 1 | interface optionsItem { 2 | path: string; 3 | type: "history" | "collect"; 4 | meta: { 5 | icon?: string; 6 | title?: string; 7 | }; 8 | } 9 | 10 | interface dragItem { 11 | oldIndex: number; 12 | newIndex: number; 13 | } 14 | 15 | interface Props { 16 | value: string; 17 | options: Array; 18 | } 19 | 20 | export type { optionsItem, dragItem, Props }; 21 | -------------------------------------------------------------------------------- /src/layout/components/lay-sidebar/components/SidebarExtraIcon.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 21 | -------------------------------------------------------------------------------- /src/layout/components/lay-sidebar/components/SidebarFullScreen.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 31 | -------------------------------------------------------------------------------- /src/layout/components/lay-sidebar/components/SidebarLinkItem.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 33 | -------------------------------------------------------------------------------- /src/layout/components/lay-sidebar/components/SidebarTopCollapse.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 39 | -------------------------------------------------------------------------------- /src/layout/components/lay-tag/components/TagChrome.vue: -------------------------------------------------------------------------------- 1 | 34 | -------------------------------------------------------------------------------- /src/layout/hooks/useBoolean.ts: -------------------------------------------------------------------------------- 1 | import { ref } from "vue"; 2 | 3 | export function useBoolean(initValue = false) { 4 | const bool = ref(initValue); 5 | 6 | function setBool(value: boolean) { 7 | bool.value = value; 8 | } 9 | function setTrue() { 10 | setBool(true); 11 | } 12 | function setFalse() { 13 | setBool(false); 14 | } 15 | function toggle() { 16 | setBool(!bool.value); 17 | } 18 | 19 | return { 20 | bool, 21 | setBool, 22 | setTrue, 23 | setFalse, 24 | toggle 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /src/layout/hooks/useMultiFrame.ts: -------------------------------------------------------------------------------- 1 | const MAP = new Map(); 2 | 3 | export const useMultiFrame = () => { 4 | function setMap(path, Comp) { 5 | MAP.set(path, Comp); 6 | } 7 | 8 | function getMap(path?) { 9 | if (path) { 10 | return MAP.get(path); 11 | } 12 | return [...MAP.entries()]; 13 | } 14 | 15 | function delMap(path) { 16 | MAP.delete(path); 17 | } 18 | 19 | return { 20 | setMap, 21 | getMap, 22 | delMap, 23 | MAP 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /src/layout/hooks/useTranslationLang.ts: -------------------------------------------------------------------------------- 1 | import { useNav } from "./useNav"; 2 | import { useI18n } from "vue-i18n"; 3 | import { useRoute } from "vue-router"; 4 | import { watch, onBeforeMount, type Ref } from "vue"; 5 | 6 | export function useTranslationLang(ref?: Ref) { 7 | const { $storage, changeTitle, handleResize } = useNav(); 8 | const { locale, t } = useI18n(); 9 | const route = useRoute(); 10 | 11 | function translationCh() { 12 | $storage.locale = { locale: "zh" }; 13 | locale.value = "zh"; 14 | ref && handleResize(ref.value); 15 | } 16 | 17 | function translationEn() { 18 | $storage.locale = { locale: "en" }; 19 | locale.value = "en"; 20 | ref && handleResize(ref.value); 21 | } 22 | 23 | watch( 24 | () => locale.value, 25 | () => { 26 | changeTitle(route.meta); 27 | } 28 | ); 29 | 30 | onBeforeMount(() => { 31 | locale.value = $storage.locale?.locale ?? "zh"; 32 | }); 33 | 34 | return { 35 | t, 36 | route, 37 | locale, 38 | translationCh, 39 | translationEn 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /src/layout/redirect.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 25 | -------------------------------------------------------------------------------- /src/plugins/echarts.ts: -------------------------------------------------------------------------------- 1 | import type { App } from "vue"; 2 | import * as echarts from "echarts/core"; 3 | import { PieChart, BarChart, LineChart } from "echarts/charts"; 4 | import { CanvasRenderer, SVGRenderer } from "echarts/renderers"; 5 | import { 6 | GridComponent, 7 | TitleComponent, 8 | PolarComponent, 9 | LegendComponent, 10 | GraphicComponent, 11 | ToolboxComponent, 12 | TooltipComponent, 13 | DataZoomComponent, 14 | VisualMapComponent 15 | } from "echarts/components"; 16 | 17 | const { use } = echarts; 18 | 19 | use([ 20 | PieChart, 21 | BarChart, 22 | LineChart, 23 | CanvasRenderer, 24 | SVGRenderer, 25 | GridComponent, 26 | TitleComponent, 27 | PolarComponent, 28 | LegendComponent, 29 | GraphicComponent, 30 | ToolboxComponent, 31 | TooltipComponent, 32 | DataZoomComponent, 33 | VisualMapComponent 34 | ]); 35 | 36 | /** 37 | * @description 按需引入echarts,具体看 https://echarts.apache.org/handbook/zh/basics/import/#%E5%9C%A8-typescript-%E4%B8%AD%E6%8C%89%E9%9C%80%E5%BC%95%E5%85%A5 38 | * @see 温馨提示:必须将 `$echarts` 添加到全局 `globalProperties` ,具体看 https://pure-admin-utils.netlify.app/hooks/useECharts/useECharts#%E4%BD%BF%E7%94%A8%E5%89%8D%E6%8F%90 39 | */ 40 | export function useEcharts(app: App) { 41 | app.config.globalProperties.$echarts = echarts; 42 | } 43 | 44 | export default echarts; 45 | -------------------------------------------------------------------------------- /src/router/enums.ts: -------------------------------------------------------------------------------- 1 | // 完整版菜单比较多,将 rank 抽离出来,在此方便维护 2 | 3 | const home = 0, // 平台规定只有 home 路由的 rank 才能为 0 ,所以后端在返回 rank 的时候需要从非 0 开始 4 | chatai = 1, 5 | vueflow = 2, 6 | ganttastic = 3, 7 | components = 4, 8 | able = 5, 9 | table = 6, 10 | form = 7, 11 | list = 8, 12 | result = 9, 13 | error = 10, 14 | frame = 11, 15 | nested = 12, 16 | permission = 13, 17 | system = 14, 18 | monitor = 15, 19 | tabs = 16, 20 | about = 17, 21 | codemirror = 18, 22 | markdown = 19, 23 | editor = 20, 24 | flowchart = 21, 25 | formdesign = 22, 26 | board = 23, 27 | ppt = 24, 28 | mind = 25, 29 | guide = 26, 30 | menuoverflow = 27; 31 | 32 | export { 33 | home, 34 | chatai, 35 | vueflow, 36 | ganttastic, 37 | components, 38 | able, 39 | table, 40 | form, 41 | list, 42 | result, 43 | error, 44 | frame, 45 | nested, 46 | permission, 47 | system, 48 | monitor, 49 | tabs, 50 | about, 51 | codemirror, 52 | markdown, 53 | editor, 54 | flowchart, 55 | formdesign, 56 | board, 57 | ppt, 58 | mind, 59 | guide, 60 | menuoverflow 61 | }; 62 | -------------------------------------------------------------------------------- /src/router/modules/about.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { about } from "@/router/enums"; 3 | 4 | export default { 5 | path: "/about", 6 | redirect: "/about/index", 7 | meta: { 8 | icon: "ri/file-info-line", 9 | title: $t("menus.pureAbout"), 10 | rank: about 11 | }, 12 | children: [ 13 | { 14 | path: "/about/index", 15 | name: "About", 16 | component: () => import("@/views/about/index.vue"), 17 | meta: { 18 | title: $t("menus.pureAbout") 19 | } 20 | } 21 | ] 22 | } satisfies RouteConfigsTable; 23 | -------------------------------------------------------------------------------- /src/router/modules/board.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { board } from "@/router/enums"; 3 | const IFrame = () => import("@/layout/frame.vue"); 4 | 5 | export default { 6 | path: "/board", 7 | redirect: "/board/index", 8 | meta: { 9 | icon: "ri/artboard-line", 10 | title: $t("menus.pureBoard"), 11 | rank: board 12 | }, 13 | children: [ 14 | { 15 | path: "/board/index", 16 | name: "FrameBoard", 17 | component: IFrame, 18 | meta: { 19 | title: $t("menus.pureBoard"), 20 | keepAlive: true, 21 | frameSrc: "https://songlh.top/paint-board/" 22 | } 23 | } 24 | ] 25 | } satisfies RouteConfigsTable; 26 | -------------------------------------------------------------------------------- /src/router/modules/chatai.ts: -------------------------------------------------------------------------------- 1 | import { chatai } from "@/router/enums"; 2 | 3 | export default { 4 | path: "/chatai", 5 | redirect: "/chatai/index", 6 | meta: { 7 | icon: "ri/chat-search-line", 8 | title: "chat-ai", 9 | rank: chatai 10 | }, 11 | children: [ 12 | { 13 | path: "/chatai/index", 14 | name: "ChatAi", 15 | component: () => import("@/views/chatai/index.vue"), 16 | meta: { 17 | title: "chat-ai", 18 | extraIcon: "IF-pure-iconfont-new svg" 19 | } 20 | } 21 | ] 22 | } satisfies RouteConfigsTable; 23 | -------------------------------------------------------------------------------- /src/router/modules/codemirror.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { codemirror } from "@/router/enums"; 3 | 4 | export default { 5 | path: "/codemirror", 6 | redirect: "/codemirror/index", 7 | meta: { 8 | icon: "ri/code-box-line", 9 | title: $t("menus.pureCodeMirror"), 10 | rank: codemirror 11 | }, 12 | children: [ 13 | { 14 | path: "/codemirror/index", 15 | name: "CodeMirror", 16 | component: () => import("@/views/codemirror/index.vue"), 17 | meta: { 18 | title: $t("menus.pureCodeMirror"), 19 | extraIcon: "IF-pure-iconfont-new svg" 20 | } 21 | } 22 | ] 23 | } satisfies RouteConfigsTable; 24 | -------------------------------------------------------------------------------- /src/router/modules/editor.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { editor } from "@/router/enums"; 3 | 4 | export default { 5 | path: "/editor", 6 | redirect: "/editor/index", 7 | meta: { 8 | icon: "ep/edit", 9 | title: $t("menus.pureEditor"), 10 | rank: editor 11 | }, 12 | children: [ 13 | { 14 | path: "/editor/index", 15 | name: "Editor", 16 | component: () => import("@/views/editor/index.vue"), 17 | meta: { 18 | title: $t("menus.pureEditor"), 19 | keepAlive: true 20 | } 21 | } 22 | ] 23 | } satisfies RouteConfigsTable; 24 | -------------------------------------------------------------------------------- /src/router/modules/error.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { error } from "@/router/enums"; 3 | 4 | export default { 5 | path: "/error", 6 | redirect: "/error/403", 7 | meta: { 8 | icon: "ri/information-line", 9 | // showLink: false, 10 | title: $t("menus.pureAbnormal"), 11 | rank: error 12 | }, 13 | children: [ 14 | { 15 | path: "/error/403", 16 | name: "403", 17 | component: () => import("@/views/error/403.vue"), 18 | meta: { 19 | title: $t("menus.pureFourZeroOne") 20 | } 21 | }, 22 | { 23 | path: "/error/404", 24 | name: "404", 25 | component: () => import("@/views/error/404.vue"), 26 | meta: { 27 | title: $t("menus.pureFourZeroFour") 28 | } 29 | }, 30 | { 31 | path: "/error/500", 32 | name: "500", 33 | component: () => import("@/views/error/500.vue"), 34 | meta: { 35 | title: $t("menus.pureFive") 36 | } 37 | } 38 | ] 39 | } satisfies RouteConfigsTable; 40 | -------------------------------------------------------------------------------- /src/router/modules/flowchart.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { flowchart } from "@/router/enums"; 3 | 4 | export default { 5 | path: "/flow-chart", 6 | redirect: "/flow-chart/index", 7 | meta: { 8 | icon: "ep/set-up", 9 | title: $t("menus.pureFlowChart"), 10 | rank: flowchart 11 | }, 12 | children: [ 13 | { 14 | path: "/flow-chart/index", 15 | name: "FlowChart", 16 | component: () => import("@/views/flow-chart/index.vue"), 17 | meta: { 18 | title: $t("menus.pureFlowChart") 19 | } 20 | } 21 | ] 22 | } satisfies RouteConfigsTable; 23 | -------------------------------------------------------------------------------- /src/router/modules/form.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { form } from "@/router/enums"; 3 | 4 | export default { 5 | path: "/form", 6 | redirect: "/form/index", 7 | meta: { 8 | icon: "ri/edit-box-line", 9 | title: $t("menus.pureSchemaForm"), 10 | rank: form 11 | }, 12 | children: [ 13 | { 14 | path: "/form/index", 15 | name: "SchemaForm", 16 | component: () => import("@/views/schema-form/index.vue"), 17 | meta: { 18 | title: $t("menus.pureSchemaForm") 19 | } 20 | } 21 | ] 22 | } satisfies RouteConfigsTable; 23 | -------------------------------------------------------------------------------- /src/router/modules/formdesign.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { formdesign } from "@/router/enums"; 3 | const IFrame = () => import("@/layout/frame.vue"); 4 | 5 | export default { 6 | path: "/form-design", 7 | redirect: "/form-design/index", 8 | meta: { 9 | icon: "ri/terminal-window-line", 10 | title: $t("menus.pureFormDesign"), 11 | rank: formdesign 12 | }, 13 | children: [ 14 | { 15 | path: "/form-design/index", 16 | name: "FormDesign", 17 | component: IFrame, 18 | meta: { 19 | title: $t("menus.pureFormDesign"), 20 | keepAlive: true, 21 | frameSrc: 22 | "https://haixin-fang.github.io/vue-form-design/playground/index.html", 23 | frameLoading: false 24 | } 25 | } 26 | ] 27 | } satisfies RouteConfigsTable; 28 | -------------------------------------------------------------------------------- /src/router/modules/ganttastic.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { ganttastic } from "@/router/enums"; 3 | 4 | export default { 5 | path: "/ganttastic", 6 | redirect: "/ganttastic/index", 7 | meta: { 8 | icon: "ri/bar-chart-horizontal-line", 9 | title: $t("menus.pureGanttastic"), 10 | rank: ganttastic 11 | }, 12 | children: [ 13 | { 14 | path: "/ganttastic/index", 15 | name: "Ganttastic", 16 | component: () => import("@/views/ganttastic/index.vue"), 17 | meta: { 18 | title: $t("menus.pureGanttastic") 19 | } 20 | } 21 | ] 22 | } satisfies RouteConfigsTable; 23 | -------------------------------------------------------------------------------- /src/router/modules/guide.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { guide } from "@/router/enums"; 3 | 4 | export default { 5 | path: "/guide", 6 | redirect: "/guide/index", 7 | meta: { 8 | icon: "ep/guide", 9 | title: $t("menus.pureGuide"), 10 | rank: guide 11 | }, 12 | children: [ 13 | { 14 | path: "/guide/index", 15 | name: "Guide", 16 | component: () => import("@/views/guide/index.vue"), 17 | meta: { 18 | title: $t("menus.pureGuide") 19 | } 20 | } 21 | ] 22 | } satisfies RouteConfigsTable; 23 | -------------------------------------------------------------------------------- /src/router/modules/home.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { home } from "@/router/enums"; 3 | const { VITE_HIDE_HOME } = import.meta.env; 4 | const Layout = () => import("@/layout/index.vue"); 5 | 6 | export default { 7 | path: "/", 8 | name: "Home", 9 | component: Layout, 10 | redirect: "/welcome", 11 | meta: { 12 | icon: "ep/home-filled", 13 | title: $t("menus.pureHome"), 14 | rank: home 15 | }, 16 | children: [ 17 | { 18 | path: "/welcome", 19 | name: "Welcome", 20 | component: () => import("@/views/welcome/index.vue"), 21 | meta: { 22 | title: $t("menus.pureHome"), 23 | showLink: VITE_HIDE_HOME === "true" ? false : true 24 | } 25 | } 26 | ] 27 | } satisfies RouteConfigsTable; 28 | -------------------------------------------------------------------------------- /src/router/modules/list.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { list } from "@/router/enums"; 3 | 4 | export default { 5 | path: "/list", 6 | redirect: "/list/card", 7 | meta: { 8 | icon: "ri/list-check", 9 | title: $t("menus.pureList"), 10 | rank: list 11 | }, 12 | children: [ 13 | { 14 | path: "/list/card", 15 | name: "CardList", 16 | component: () => import("@/views/list/card/index.vue"), 17 | meta: { 18 | icon: "ri/bank-card-line", 19 | title: $t("menus.pureCardList"), 20 | showParent: true 21 | } 22 | } 23 | ] 24 | } satisfies RouteConfigsTable; 25 | -------------------------------------------------------------------------------- /src/router/modules/markdown.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { markdown } from "@/router/enums"; 3 | 4 | export default { 5 | path: "/markdown", 6 | redirect: "/markdown/index", 7 | meta: { 8 | icon: "ri/markdown-line", 9 | title: $t("menus.pureMarkdown"), 10 | rank: markdown 11 | }, 12 | children: [ 13 | { 14 | path: "/markdown/index", 15 | name: "Markdown", 16 | component: () => import("@/views/markdown/index.vue"), 17 | meta: { 18 | title: $t("menus.pureMarkdown"), 19 | extraIcon: "IF-pure-iconfont-new svg" 20 | } 21 | } 22 | ] 23 | } satisfies RouteConfigsTable; 24 | -------------------------------------------------------------------------------- /src/router/modules/menuoverflow.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { menuoverflow } from "@/router/enums"; 3 | 4 | export default { 5 | path: "/menuoverflow", 6 | redirect: "/menuoverflow/index", 7 | meta: { 8 | title: $t("menus.pureMenuOverflow"), 9 | rank: menuoverflow 10 | }, 11 | children: [ 12 | { 13 | path: "/menuoverflow/index", 14 | name: "MenuOverflow", 15 | component: () => import("@/views/menuoverflow/index.vue"), 16 | meta: { 17 | title: $t("menus.pureChildMenuOverflow"), 18 | showParent: true 19 | } 20 | } 21 | ] 22 | } satisfies RouteConfigsTable; 23 | -------------------------------------------------------------------------------- /src/router/modules/mind.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { mind } from "@/router/enums"; 3 | const IFrame = () => import("@/layout/frame.vue"); 4 | 5 | export default { 6 | path: "/mind-map", 7 | redirect: "/mind-map/index", 8 | meta: { 9 | icon: "ri/mind-map", 10 | title: $t("menus.pureMindMap"), 11 | rank: mind 12 | }, 13 | children: [ 14 | { 15 | path: "/mind-map/index", 16 | name: "FrameMindMap", 17 | component: IFrame, 18 | meta: { 19 | title: $t("menus.pureMindMap"), 20 | keepAlive: true, 21 | frameSrc: "https://wanglin2.github.io/mind-map/#/" 22 | } 23 | } 24 | ] 25 | } satisfies RouteConfigsTable; 26 | -------------------------------------------------------------------------------- /src/router/modules/ppt.ts: -------------------------------------------------------------------------------- 1 | import { ppt } from "@/router/enums"; 2 | const IFrame = () => import("@/layout/frame.vue"); 3 | 4 | export default { 5 | path: "/ppt", 6 | redirect: "/ppt/index", 7 | meta: { 8 | icon: "ri/file-ppt-2-line", 9 | title: "PPT", 10 | rank: ppt 11 | }, 12 | children: [ 13 | { 14 | path: "/ppt/index", 15 | name: "FramePpt", 16 | component: IFrame, 17 | meta: { 18 | title: "PPT", 19 | keepAlive: true, 20 | frameSrc: "https://pipipi-pikachu.github.io/PPTist/", 21 | frameLoading: false 22 | } 23 | } 24 | ] 25 | } satisfies RouteConfigsTable; 26 | -------------------------------------------------------------------------------- /src/router/modules/result.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { result } from "@/router/enums"; 3 | 4 | export default { 5 | path: "/result", 6 | redirect: "/result/success", 7 | meta: { 8 | icon: "ri/checkbox-circle-line", 9 | title: $t("menus.pureResult"), 10 | rank: result 11 | }, 12 | children: [ 13 | { 14 | path: "/result/success", 15 | name: "Success", 16 | component: () => import("@/views/result/success.vue"), 17 | meta: { 18 | title: $t("menus.pureSuccess") 19 | } 20 | }, 21 | { 22 | path: "/result/fail", 23 | name: "Fail", 24 | component: () => import("@/views/result/fail.vue"), 25 | meta: { 26 | title: $t("menus.pureFail") 27 | } 28 | } 29 | ] 30 | } satisfies RouteConfigsTable; 31 | -------------------------------------------------------------------------------- /src/router/modules/table.ts: -------------------------------------------------------------------------------- 1 | import { $t } from "@/plugins/i18n"; 2 | import { table } from "@/router/enums"; 3 | 4 | export default { 5 | path: "/table", 6 | redirect: "/table/index", 7 | meta: { 8 | icon: "ri/table-line", 9 | title: $t("menus.pureTable"), 10 | rank: table 11 | }, 12 | children: [ 13 | { 14 | path: "/table/index", 15 | name: "PureTable", 16 | component: () => import("@/views/table/index.vue"), 17 | meta: { 18 | title: $t("menus.pureTableBase") 19 | } 20 | }, 21 | { 22 | path: "/table/high", 23 | name: "PureTableHigh", 24 | component: () => import("@/views/table/high.vue"), 25 | meta: { 26 | title: $t("menus.pureTableHigh") 27 | } 28 | }, 29 | { 30 | path: "/table/edit", 31 | name: "PureTableEdit", 32 | component: () => import("@/views/table/edit.vue"), 33 | meta: { 34 | title: $t("menus.pureTableEdit") 35 | } 36 | }, 37 | { 38 | path: "/table/virtual", 39 | name: "VxeTable", 40 | component: () => import("@/views/table/virtual.vue"), 41 | meta: { 42 | title: $t("menus.pureVxeTable") 43 | } 44 | } 45 | ] 46 | } satisfies RouteConfigsTable; 47 | -------------------------------------------------------------------------------- /src/router/modules/vueflow.ts: -------------------------------------------------------------------------------- 1 | import { vueflow } from "@/router/enums"; 2 | 3 | export default { 4 | path: "/vue-flow", 5 | redirect: "/vue-flow/index", 6 | meta: { 7 | icon: "ep/set-up", 8 | title: "vue-flow", 9 | rank: vueflow 10 | }, 11 | children: [ 12 | { 13 | path: "/vue-flow/index", 14 | name: "VueFlow", 15 | component: () => import("@/views/vue-flow/layouting/index.vue"), 16 | meta: { 17 | title: "vue-flow" 18 | } 19 | } 20 | ] 21 | } satisfies RouteConfigsTable; 22 | -------------------------------------------------------------------------------- /src/store/index.ts: -------------------------------------------------------------------------------- 1 | import type { App } from "vue"; 2 | import { createPinia } from "pinia"; 3 | const store = createPinia(); 4 | 5 | export function setupStore(app: App) { 6 | app.use(store); 7 | } 8 | 9 | export { store }; 10 | -------------------------------------------------------------------------------- /src/store/modules/settings.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from "pinia"; 2 | import { type setType, store, getConfig } from "../utils"; 3 | 4 | export const useSettingStore = defineStore("pure-setting", { 5 | state: (): setType => ({ 6 | title: getConfig().Title, 7 | fixedHeader: getConfig().FixedHeader, 8 | hiddenSideBar: getConfig().HiddenSideBar 9 | }), 10 | getters: { 11 | getTitle(state) { 12 | return state.title; 13 | }, 14 | getFixedHeader(state) { 15 | return state.fixedHeader; 16 | }, 17 | getHiddenSideBar(state) { 18 | return state.hiddenSideBar; 19 | } 20 | }, 21 | actions: { 22 | CHANGE_SETTING({ key, value }) { 23 | if (Reflect.has(this, key)) { 24 | this[key] = value; 25 | } 26 | }, 27 | changeSetting(data) { 28 | this.CHANGE_SETTING(data); 29 | } 30 | } 31 | }); 32 | 33 | export function useSettingStoreHook() { 34 | return useSettingStore(store); 35 | } 36 | -------------------------------------------------------------------------------- /src/store/types.ts: -------------------------------------------------------------------------------- 1 | import type { RouteRecordName } from "vue-router"; 2 | 3 | export type cacheType = { 4 | mode: string; 5 | name?: RouteRecordName; 6 | }; 7 | 8 | export type positionType = { 9 | startIndex?: number; 10 | length?: number; 11 | }; 12 | 13 | export type appType = { 14 | sidebar: { 15 | opened: boolean; 16 | withoutAnimation: boolean; 17 | // 判断是否手动点击Collapse 18 | isClickCollapse: boolean; 19 | }; 20 | layout: string; 21 | device: string; 22 | viewportSize: { width: number; height: number }; 23 | sortSwap: boolean; 24 | }; 25 | 26 | export type multiType = { 27 | path: string; 28 | name: string; 29 | meta: any; 30 | query?: object; 31 | params?: object; 32 | }; 33 | 34 | export type setType = { 35 | title: string; 36 | fixedHeader: boolean; 37 | hiddenSideBar: boolean; 38 | }; 39 | 40 | export type userType = { 41 | avatar?: string; 42 | username?: string; 43 | nickname?: string; 44 | roles?: Array; 45 | permissions?: Array; 46 | verifyCode?: string; 47 | currentPage?: number; 48 | isRemembered?: boolean; 49 | loginDay?: number; 50 | }; 51 | -------------------------------------------------------------------------------- /src/store/utils.ts: -------------------------------------------------------------------------------- 1 | export { store } from "@/store"; 2 | export { routerArrays } from "@/layout/types"; 3 | export { router, resetRouter, constantMenus } from "@/router"; 4 | export { getConfig, responsiveStorageNameSpace } from "@/config"; 5 | export { 6 | ascending, 7 | filterTree, 8 | filterNoPermissionTree, 9 | formatFlatteningRoutes 10 | } from "@/router/utils"; 11 | export { 12 | isUrl, 13 | isEqual, 14 | isNumber, 15 | debounce, 16 | isBoolean, 17 | getKeyList, 18 | storageLocal, 19 | deviceDetection 20 | } from "@pureadmin/utils"; 21 | export type { 22 | setType, 23 | appType, 24 | userType, 25 | multiType, 26 | cacheType, 27 | positionType 28 | } from "./types"; 29 | -------------------------------------------------------------------------------- /src/style/index.scss: -------------------------------------------------------------------------------- 1 | @use "theme"; 2 | @use "transition"; 3 | @use "element-plus"; 4 | @use "sidebar"; 5 | @use "dark"; 6 | 7 | /* 自定义全局 CssVar */ 8 | :root { 9 | /* 左侧菜单展开、收起动画时长 */ 10 | --pure-transition-duration: 0.3s; 11 | 12 | /* 常用border-color 需要时可取用 */ 13 | --pure-border-color: rgb(5 5 5 / 6%); 14 | 15 | /* switch关闭状态下的color 需要时可取用 */ 16 | --pure-switch-off-color: #a6a6a6; 17 | 18 | /** 主题色 */ 19 | --pure-theme-sub-menu-active-text: initial; 20 | --pure-theme-menu-bg: none; 21 | --pure-theme-menu-hover: none; 22 | --pure-theme-sub-menu-bg: transparent; 23 | --pure-theme-menu-text: initial; 24 | --pure-theme-sidebar-logo: none; 25 | --pure-theme-menu-title-hover: initial; 26 | --pure-theme-menu-active-before: transparent; 27 | } 28 | 29 | /* 灰色模式 */ 30 | .html-grey { 31 | filter: grayscale(100%); 32 | } 33 | 34 | /* 色弱模式 */ 35 | .html-weakness { 36 | filter: invert(80%); 37 | } 38 | -------------------------------------------------------------------------------- /src/style/tailwind.css: -------------------------------------------------------------------------------- 1 | @layer theme, base, components, utilities; 2 | @import "tailwindcss/theme.css" layer(theme); 3 | @import "tailwindcss/utilities.css" layer(utilities); 4 | 5 | @custom-variant dark (&:is(.dark *)); 6 | 7 | @theme { 8 | --color-bg_color: var(--el-bg-color); 9 | --color-primary: var(--el-color-primary); 10 | --color-text_color_primary: var(--el-text-color-primary); 11 | --color-text_color_regular: var(--el-text-color-regular); 12 | } 13 | 14 | /* 15 | The default border color has changed to `currentColor` in Tailwind CSS v4, 16 | so we've added these compatibility styles to make sure everything still 17 | looks the same as it did with Tailwind CSS v3. 18 | 19 | If we ever want to remove these styles, we need to add an explicit border 20 | color utility to any element that depends on these defaults. 21 | */ 22 | @layer base { 23 | *, 24 | ::after, 25 | ::before, 26 | ::backdrop, 27 | ::file-selector-button { 28 | border-color: var(--color-gray-200, currentColor); 29 | } 30 | } 31 | 32 | @utility flex-c { 33 | @apply flex justify-center items-center; 34 | } 35 | 36 | @utility flex-ac { 37 | @apply flex justify-around items-center; 38 | } 39 | 40 | @utility flex-bc { 41 | @apply flex justify-between items-center; 42 | } 43 | 44 | @utility navbar-bg-hover { 45 | @apply dark:text-white dark:hover:bg-[#242424]!; 46 | } 47 | -------------------------------------------------------------------------------- /src/style/transition.scss: -------------------------------------------------------------------------------- 1 | /* fade */ 2 | .fade-enter-active, 3 | .fade-leave-active { 4 | transition: opacity 0.28s; 5 | } 6 | 7 | .fade-enter, 8 | .fade-leave-active { 9 | opacity: 0; 10 | } 11 | 12 | /* fade-transform */ 13 | .fade-transform-leave-active, 14 | .fade-transform-enter-active { 15 | transition: all 0.5s; 16 | } 17 | 18 | .fade-transform-enter-from { 19 | opacity: 0; 20 | transform: translateX(-30px); 21 | } 22 | 23 | .fade-transform-leave-to { 24 | opacity: 0; 25 | transform: translateX(30px); 26 | } 27 | 28 | /* breadcrumb transition */ 29 | .breadcrumb-enter-active { 30 | transition: all 0.4s; 31 | } 32 | 33 | .breadcrumb-leave-active { 34 | position: absolute; 35 | transition: all 0.3s; 36 | } 37 | 38 | .breadcrumb-enter-from, 39 | .breadcrumb-leave-active { 40 | opacity: 0; 41 | transform: translateX(20px); 42 | } 43 | 44 | /** 45 | * @description 重置el-menu的展开收起动画时长 46 | */ 47 | .outer-most .el-collapse-transition-leave-active, 48 | .outer-most .el-collapse-transition-enter-active { 49 | transition: 0.2s all ease-in-out !important; 50 | } 51 | 52 | .horizontal-collapse-transition { 53 | transition: var(--pure-transition-duration) all !important; 54 | } 55 | -------------------------------------------------------------------------------- /src/utils/README.md: -------------------------------------------------------------------------------- 1 | ### 注意 2 | 3 | - `vue-pure-admin` 从 `3.3.0` 版本之后(不包括 `3.3.0` 版本),大部分工具和 `hooks` 都集成到了 [@pureadmin/utils](https://pure-admin-utils.netlify.app/) 4 | - [npm](https://www.npmjs.com/package/@pureadmin/utils) 5 | - [文档代码地址](https://github.com/pure-admin/pure-admin-utils-docs) 6 | -------------------------------------------------------------------------------- /src/utils/globalPolyfills.ts: -------------------------------------------------------------------------------- 1 | // 如果项目出现 `global is not defined` 报错,可能是您引入某个库的问题,比如 aws-sdk-js https://github.com/aws/aws-sdk-js 2 | // 解决办法就是将该文件引入 src/main.ts 即可 import "@/utils/globalPolyfills"; 3 | if (typeof (window as any).global === "undefined") { 4 | (window as any).global = window; 5 | } 6 | 7 | export {}; 8 | -------------------------------------------------------------------------------- /src/utils/http/types.d.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | Method, 3 | AxiosError, 4 | AxiosResponse, 5 | AxiosRequestConfig 6 | } from "axios"; 7 | 8 | export type resultType = { 9 | accessToken?: string; 10 | }; 11 | 12 | export type RequestMethods = Extract< 13 | Method, 14 | "get" | "post" | "put" | "delete" | "patch" | "option" | "head" 15 | >; 16 | 17 | export interface PureHttpError extends AxiosError { 18 | isCancelRequest?: boolean; 19 | } 20 | 21 | export interface PureHttpResponse extends AxiosResponse { 22 | config: PureHttpRequestConfig; 23 | } 24 | 25 | export interface PureHttpRequestConfig extends AxiosRequestConfig { 26 | beforeRequestCallback?: (request: PureHttpRequestConfig) => void; 27 | beforeResponseCallback?: (response: PureHttpResponse) => void; 28 | } 29 | 30 | export default class PureHttp { 31 | request( 32 | method: RequestMethods, 33 | url: string, 34 | param?: AxiosRequestConfig, 35 | axiosConfig?: PureHttpRequestConfig 36 | ): Promise; 37 | post( 38 | url: string, 39 | params?: P, 40 | config?: PureHttpRequestConfig 41 | ): Promise; 42 | get( 43 | url: string, 44 | params?: P, 45 | config?: PureHttpRequestConfig 46 | ): Promise; 47 | } 48 | -------------------------------------------------------------------------------- /src/utils/mitt.ts: -------------------------------------------------------------------------------- 1 | import type { Emitter } from "mitt"; 2 | import mitt from "mitt"; 3 | 4 | /** 全局公共事件需要在此处添加类型 */ 5 | type Events = { 6 | openPanel: string; 7 | tagOnClick: string; 8 | logoChange: boolean; 9 | tagViewsChange: string; 10 | changLayoutRoute: string; 11 | tagViewsShowModel: string; 12 | imageInfo: { 13 | img: HTMLImageElement; 14 | height: number; 15 | width: number; 16 | x: number; 17 | y: number; 18 | }; 19 | }; 20 | 21 | export const emitter: Emitter = mitt(); 22 | -------------------------------------------------------------------------------- /src/utils/preventDefault.ts: -------------------------------------------------------------------------------- 1 | import { useEventListener } from "@vueuse/core"; 2 | 3 | /** 是否为`img`标签 */ 4 | function isImgElement(element) { 5 | return typeof HTMLImageElement !== "undefined" 6 | ? element instanceof HTMLImageElement 7 | : element.tagName.toLowerCase() === "img"; 8 | } 9 | 10 | // 在 src/main.ts 引入并调用即可 import { addPreventDefault } from "@/utils/preventDefault"; addPreventDefault(); 11 | export const addPreventDefault = () => { 12 | // 阻止通过键盘F12快捷键打开浏览器开发者工具面板 13 | useEventListener( 14 | window.document, 15 | "keydown", 16 | ev => ev.key === "F12" && ev.preventDefault() 17 | ); 18 | // 阻止浏览器默认的右键菜单弹出(不会影响自定义右键事件) 19 | useEventListener(window.document, "contextmenu", ev => ev.preventDefault()); 20 | // 阻止页面元素选中 21 | useEventListener(window.document, "selectstart", ev => ev.preventDefault()); 22 | // 浏览器中图片通常默认是可拖动的,并且可以在新标签页或窗口中打开,或者将其拖动到其他应用程序中,此处将其禁用,使其默认不可拖动 23 | useEventListener( 24 | window.document, 25 | "dragstart", 26 | ev => isImgElement(ev?.target) && ev.preventDefault() 27 | ); 28 | }; 29 | -------------------------------------------------------------------------------- /src/utils/progress/index.ts: -------------------------------------------------------------------------------- 1 | import NProgress from "nprogress"; 2 | import "nprogress/nprogress.css"; 3 | 4 | NProgress.configure({ 5 | // 动画方式 6 | easing: "ease", 7 | // 递增进度条的速度 8 | speed: 500, 9 | // 是否显示加载ico 10 | showSpinner: false, 11 | // 自动递增间隔 12 | trickleSpeed: 200, 13 | // 初始化时的最小百分比 14 | minimum: 0.3 15 | }); 16 | 17 | export default NProgress; 18 | -------------------------------------------------------------------------------- /src/utils/propTypes.ts: -------------------------------------------------------------------------------- 1 | import type { CSSProperties, VNodeChild } from "vue"; 2 | import { 3 | createTypes, 4 | toValidableType, 5 | type VueTypesInterface, 6 | type VueTypeValidableDef 7 | } from "vue-types"; 8 | 9 | export type VueNode = VNodeChild | JSX.Element; 10 | 11 | type PropTypes = VueTypesInterface & { 12 | readonly style: VueTypeValidableDef; 13 | readonly VNodeChild: VueTypeValidableDef; 14 | }; 15 | 16 | const newPropTypes = createTypes({ 17 | func: undefined, 18 | bool: undefined, 19 | string: undefined, 20 | number: undefined, 21 | object: undefined, 22 | integer: undefined 23 | }) as PropTypes; 24 | 25 | // 从 vue-types v5.0 开始,extend()方法已经废弃,当前已改为官方推荐的ES6+方法 https://dwightjack.github.io/vue-types/advanced/extending-vue-types.html#the-extend-method 26 | export default class propTypes extends newPropTypes { 27 | // a native-like validator that supports the `.validable` method 28 | static get style() { 29 | return toValidableType("style", { 30 | type: [String, Object] 31 | }); 32 | } 33 | 34 | static get VNodeChild() { 35 | return toValidableType("VNodeChild", { 36 | type: undefined 37 | }); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/views/able/map.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | 13 | 18 | -------------------------------------------------------------------------------- /src/views/able/pinyin.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 28 | 29 | 42 | -------------------------------------------------------------------------------- /src/views/able/print/pieChart.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 44 | -------------------------------------------------------------------------------- /src/views/able/sensitive.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 51 | -------------------------------------------------------------------------------- /src/views/able/typeit.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 30 | -------------------------------------------------------------------------------- /src/views/able/verify.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 41 | -------------------------------------------------------------------------------- /src/views/able/wavesurfer/svg/forward.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/able/wavesurfer/svg/index.ts: -------------------------------------------------------------------------------- 1 | import Play from "./play.svg?component"; 2 | import Pause from "./pause.svg?component"; 3 | import Forward from "./forward.svg?component"; 4 | import Rewind from "./rewind.svg?component"; 5 | 6 | export { 7 | /** 播放 */ 8 | Play, 9 | /** 暂停 */ 10 | Pause, 11 | /** 快进 */ 12 | Forward, 13 | /** 快退 */ 14 | Rewind 15 | }; 16 | -------------------------------------------------------------------------------- /src/views/able/wavesurfer/svg/pause.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/able/wavesurfer/svg/play.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/able/wavesurfer/svg/rewind.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/chatai/components/IntroPanel.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 49 | -------------------------------------------------------------------------------- /src/views/chatai/components/MessageCode.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 45 | -------------------------------------------------------------------------------- /src/views/chatai/components/Speech.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 36 | -------------------------------------------------------------------------------- /src/views/chatai/components/index.ts: -------------------------------------------------------------------------------- 1 | export { default as ChatGPT } from "./ChatGPT.vue"; 2 | export { default as Bard } from "./Bard.vue"; 3 | export { default as Bing } from "./Bing.vue"; 4 | export { default as iMessage } from "./iMessage.vue"; 5 | export { default as Blue } from "./Blue.vue"; 6 | export { default as LoFi } from "./LoFi.vue"; 7 | export { default as Red } from "./Red.vue"; 8 | export { default as Dark } from "./Dark.vue"; 9 | export { default as FullInput } from "./FullInput.vue"; 10 | export { default as Group } from "./Group.vue"; 11 | export { default as MessageCode } from "./MessageCode.vue"; 12 | export { default as Speech } from "./Speech.vue"; 13 | export { default as IntroPanel } from "./IntroPanel.vue"; 14 | -------------------------------------------------------------------------------- /src/views/components/animatecss.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 42 | -------------------------------------------------------------------------------- /src/views/components/button.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 |