Commit 9c934257 authored by 林洋洋's avatar 林洋洋

代码初始化

parent 8ef09df0
Pipeline #324 failed with stages
You are an expert in TypeScript, Vite, Vue3, Vue Router, Pinia, VueUse ,Daisy UI, Element Plus, and Tailwind, with a deep understanding of best practices and performance optimization techniques in these technologies.
Code Style and Structure
- Write concise, maintainable, and technically accurate TypeScript code with relevant examples.
- Use functional and declarative programming patterns; avoid classes.
- Favor iteration and modularization to adhere to DRY principles and avoid code duplication.
- Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
- Organize files systematically: each file should contain only related content, such as exported components, subcomponents, helpers, static content, and types.
Naming Conventions
- Use lowercase with dashes for directories (e.g., components/auth-wizard).
- Favor named exports for functions.
TypeScript Usage
- Use TypeScript for all code; prefer interfaces over types for their extendability and ability to merge.
- Avoid enums; use maps instead for better type safety and flexibility.
- Use functional components with TypeScript interfaces.
Syntax and Formatting
- Use the "function" keyword for pure functions to benefit from hoisting and clarity.
- Always use the Vue Composition API script setup style.
- The order is template , typescript , Sass
UI and Styling
- Use Element Plus,Daisyui, and Tailwind for components and styling.
- Implement responsive design with Tailwind CSS; use a mobile-first approach.
Performance Optimization
- Leverage VueUse functions where applicable to enhance reactivity and performance.
\ No newline at end of file
# 是否是微服务架构(重要)
VITE_IS_MICRO= true
# 前端访问前缀
VITE_PUBLIC_PATH = /
# 后端请求前缀
VITE_API_URL = /api
# OAUTH2 密码模式客户端信息
VITE_OAUTH2_PASSWORD_CLIENT='pig:pig'
# OAUTH2 短信客户端信息
VITE_OAUTH2_MOBILE_CLIENT='app:app'
# 是否开启前端验证码
VITE_VERIFY_ENABLE = true
# 前端加密密钥
VITE_PWD_ENC_KEY='thanks,pig4cloud'
# 是否开启websocket 消息接受,
VITE_WEBSOCKET_ENABLE = false
# 是否开启注册
VITE_REGISTER_ENABLE = true
# port 端口号
VITE_PORT = 8888
#浏览器自动打开
VITE_OPEN = true
# 本地环境
ENV = 'development'
# ADMIN 服务地址
VITE_ADMIN_PROXY_PATH = http://127.0.0.1:9999
*.sh
node_modules
lib
*.md
*.scss
*.woff
*.ttf
.vscode
.idea
dist
mock
public
bin
build
config
index.html
src/assets
\ No newline at end of file
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true,
},
parser: 'vue-eslint-parser',
parserOptions: {
ecmaVersion: 12,
parser: '@typescript-eslint/parser',
sourceType: 'module',
},
extends: ['plugin:vue/vue3-essential', 'plugin:vue/essential', 'eslint:recommended'],
plugins: ['vue', '@typescript-eslint'],
overrides: [
{
files: ['*.ts', '*.tsx', '*.vue'],
rules: {
'no-undef': 'off',
},
},
],
rules: {
// http://eslint.cn/docs/rules/
// https://eslint.vuejs.org/rules/
// https://typescript-eslint.io/rules/no-unused-vars/
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-redeclare': 'error',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
'@typescript-eslint/no-unused-vars': [2],
'vue/custom-event-name-casing': 'off',
'vue/attributes-order': 'off',
'vue/one-component-per-file': 'off',
'vue/html-closing-bracket-newline': 'off',
'vue/max-attributes-per-line': 'off',
'vue/multiline-html-element-content-newline': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/attribute-hyphenation': 'off',
'vue/html-self-closing': 'off',
'vue/no-multiple-template-root': 'off',
'vue/require-default-prop': 'off',
'vue/no-v-model-argument': 'off',
'vue/no-arrow-functions-in-watch': 'off',
'vue/no-template-key': 'off',
'vue/no-v-html': 'off',
'vue/comment-directive': 'off',
'vue/no-mutating-props': 'off',
'vue/no-parsing-error': 'off',
'vue/no-deprecated-v-on-native-modifier': 'off',
'vue/multi-word-component-names': 'off',
'no-useless-escape': 'off',
'no-sparse-arrays': 'off',
'no-prototype-builtins': 'off',
'no-constant-condition': 'off',
'no-use-before-define': 'off',
'no-restricted-globals': 'off',
'no-restricted-syntax': 'off',
'generator-star-spacing': 'off',
'no-unreachable': 'off',
'no-multiple-template-root': 'off',
'no-unused-vars': 'error',
'no-v-model-argument': 'off',
'no-case-declarations': 'off',
'no-console': 'error',
'no-redeclare': 'off',
'no-mixed-spaces-and-tabs': 'off',
},
};
.DS_Store
node_modules
dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
!.idea/icon.png
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
# lock files
yarn.lock
module.exports = {
// 一行最多多少个字符
printWidth: 150,
// 指定每个缩进级别的空格数
tabWidth: 2,
// 使用制表符而不是空格缩进行
useTabs: true,
// 在语句末尾打印分号
semi: true,
// 使用单引号而不是双引号
singleQuote: true,
// 更改引用对象属性的时间 可选值"<as-needed|consistent|preserve>"
quoteProps: 'as-needed',
// 在JSX中使用单引号而不是双引号
jsxSingleQuote: false,
// 多行时尽可能打印尾随逗号。(例如,单行数组永远不会出现逗号结尾。) 可选值"<none|es5|all>",默认none
trailingComma: 'es5',
// 在对象文字中的括号之间打印空格
bracketSpacing: true,
// jsx 标签的反尖括号需要换行
jsxBracketSameLine: false,
// 在单独的箭头函数参数周围包括括号 always:(x) => x \ avoid:x => x
arrowParens: 'always',
// 这两个选项可用于格式化以给定字符偏移量(分别包括和不包括)开始和结束的代码
rangeStart: 0,
rangeEnd: Infinity,
// 指定要使用的解析器,不需要写文件开头的 @prettier
requirePragma: false,
// 不需要自动在文件开头插入 @prettier
insertPragma: false,
// 使用默认的折行标准 always\never\preserve
proseWrap: 'preserve',
// 指定HTML文件的全局空格敏感度 css\strict\ignore
htmlWhitespaceSensitivity: 'css',
// Vue文件脚本和样式标签缩进
vueIndentScriptAndStyle: false,
// 换行符使用 lf 结尾是 可选值"<auto|lf|crlf|cr>"
endOfLine: 'lf',
};
This diff is collapsed.
1
\ No newline at end of file
<p align="center">
<img src="https://img.shields.io/badge/Pig-3.8-success.svg" alt="Build Status">
<img src="https://img.shields.io/badge/Spring%20Cloud-2024-blue.svg" alt="Coverage Status">
<img src="https://img.shields.io/badge/Spring%20Boot-3.4-blue.svg" alt="Downloads">
<img src="https://img.shields.io/badge/Vue-3.4-blue.svg" alt="Downloads">
<img src="https://img.shields.io/github/license/pig-mesh/pig"/>
<img src="https://gitcode.com/pig-mesh/pig/star/badge.svg"/>
</p>
## 概述
**pig-ui** 是一个为 PIGCLOUD 微服务开发平台开发的前端项目。它利用了现代 Web 技术,包括 Vue.js 3、Element Plus 和 Vite,提供了一个健壮且高效的开发环境。
## 功能特性
- **Vue 3**: 利用最新版本的 Vue.js 实现现代化的响应式体验。
- **Element Plus**: 集成了 Element Plus,提供丰富的 UI 组件。
- **Vite**: 使用 Vite 进行快速构建和模块热替换。
- **TypeScript**: 支持 TypeScript,提升代码质量和可维护性。
- **Tailwind CSS**: 使用 Tailwind CSS 进行样式设计。
## 快速开始
### 先决条件
- **Node.js**: 版本 18.0.0。
- **npm**: 版本 8.0.0 或更高。
### 使用文档
PIG 提供了详尽的部署文档 👉 [wiki.pig4cloud.com](https://wiki.pig4cloud.com),涵盖开发环境配置、服务端启动、前端运行等关键步骤。
重要的事情说三遍:
- 🔥 [ 配套文档 wiki.pig4cloud.com](https://wiki.pig4cloud.com)
- 🔥 [ 配套文档 wiki.pig4cloud.com](https://wiki.pig4cloud.com)
- 🔥 [ 配套文档 wiki.pig4cloud.com](https://wiki.pig4cloud.com)
## 浏览器支持
- 现代浏览器的最后两个版本。
- 不支持 IE 11 及更低版本。
## 贡献
欢迎贡献!在开始之前,请阅读[贡献指南](https://www.yuque.com/pig4cloud/pig/lceu0v)
## 许可证
本项目采用 Apache-2.0 许可证。
## 问题和反馈
如果遇到任何问题,请在 [PIGCLOUD 问题追踪](https://gitee.com/log4j/pig/issues)上报告。
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const acceptHMRUpdate: typeof import('pinia')['acceptHMRUpdate']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const createPinia: typeof import('pinia')['createPinia']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const defineStore: typeof import('pinia')['defineStore']
const effectScope: typeof import('vue')['effectScope']
const getActivePinia: typeof import('pinia')['getActivePinia']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const mapActions: typeof import('pinia')['mapActions']
const mapGetters: typeof import('pinia')['mapGetters']
const mapState: typeof import('pinia')['mapState']
const mapStores: typeof import('pinia')['mapStores']
const mapWritableState: typeof import('pinia')['mapWritableState']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const resolveDirective: typeof import('vue')['resolveDirective']
const setActivePinia: typeof import('pinia')['setActivePinia']
const setMapStoreSuffix: typeof import('pinia')['setMapStoreSuffix']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const storeToRefs: typeof import('pinia')['storeToRefs']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useId: typeof import('vue')['useId']
const useLink: typeof import('vue-router')['useLink']
const useModel: typeof import('vue')['useModel']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}
FROM registry.cn-hangzhou.aliyuncs.com/dockerhub_mirror/nginx
COPY ./dist /data
RUN rm /etc/nginx/conf.d/default.conf
ADD pig-ui.conf /etc/nginx/conf.d/default.conf
RUN /bin/bash -c 'echo init ok'
services:
pig-ui:
build:
context: .
restart: always
container_name: pig-ui
image: pig-ui
networks:
- spring_cloud_default
external_links:
- pig-gateway
ports:
- 80:80
# 加入到后端网络, 默认为 spring_cloud_default | docker network ls 查看
networks:
spring_cloud_default:
external: true
server {
listen 80;
server_name localhost;
gzip on;
gzip_static on; # 需要http_gzip_static_module 模块
gzip_min_length 1k;
gzip_comp_level 4;
gzip_proxied any;
gzip_types text/plain text/xml text/css;
gzip_vary on;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
# 前端打包好的dist目录文件
root /data/;
location ^~/api/ {
proxy_pass http://pig-gateway:9999/; #注意/后缀
proxy_connect_timeout 60s;
proxy_read_timeout 120s;
proxy_send_timeout 120s;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto http;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $http_host;
proxy_set_header from "";
}
# 屏蔽所有敏感路径,不用改代码
location ~* ^/(actuator|swagger-ui|v3/api-docs|swagger-resources|webjars|doc.html) {
return 403; # 禁止访问
}
}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
name="keywords"
content="
微服务,pig开发平台,oauth2,微服务框架,java微服务框架,微服务开发框架,微服务治理框架,开源微服务框架,微服务器框架,微服务框架图,微服务快速开发框架,微服务java框架,微服务开源框架,微服务开源框架,微服务架构框架,微服务基础框架,微服务常见框架,主流微服务框架,微服务框架搭建,java主流微服务框架,java微服务开发框架,微服务前端框架,Spring
Boot,Spring Cloud,Spring"
/>
<meta
name="description"
content="PIG应用微服务、容器、DevOps等云原生技术,封装了大量技术开发包、技术应用组件、技术场景实现能力,并支持SaaS模式应用,提供了一个可支持企业各业务系统或产品快速开发实现的微服务应用数字化融合平台,富含各类开箱即用的组件、微服务业务系统,助力企业跨越Cloud(IaaS/PaaS)与自身数字化的鸿沟,共享业务服务的组合重用,为企业服务化中台整合、数字化转型提供强力支撑,也为企业提供了最佳架构实践。"
/>
<!--避免微信管理防盗链机制-->
<meta name="referrer" content="no-referrer" />
<link rel="icon" href="/favicon.ico" />
<title>PIG 微服务快速开发平台</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
This diff is collapsed.
{
"name": "pig-ui",
"version": "3.9.0",
"description": "PIGCLOUD微服务开发平台",
"author": "pig4cloud",
"license": "Apache-2.0",
"type": "module",
"scripts": {
"dev": "vite --force",
"build": "cross-env NODE_OPTIONS=--max-old-space-size=4096 vite build",
"build:docker": "cross-env NODE_OPTIONS=--max-old-space-size=4096 vite build --outDir ./docker/dist/",
"lint:eslint": "eslint --fix --ext .js,.cjs,.mjs,.ts,.vue ./src",
"prettier": "prettier --write ."
},
"dependencies": {
"@element-plus/icons-vue": "2.3.1",
"@vueuse/core": "10.4.1",
"@wangeditor-next/editor": "5.6.34",
"@wangeditor-next/editor-for-vue": "5.1.14",
"autoprefixer": "10.4.20",
"axios": "1.7.9",
"china-area-data": "^5.0.1",
"codemirror": "5.65.18",
"crypto-js": "4.2.0",
"driver.js": "1.3.1",
"echarts": "5.5.1",
"element-plus": "2.8.7",
"js-cookie": "3.0.5",
"mitt": "3.0.1",
"nprogress": "0.2.0",
"pinia": "2.3.0",
"postcss": "8.4.49",
"qs": "6.13.1",
"screenfull": "6.0.2",
"sm-crypto": "0.3.13",
"sortablejs": "1.15.6",
"splitpanes": "3.1.8",
"tailwindcss": "3.4.17",
"vue": "3.5.13",
"vue-clipboard3": "2.0.0",
"vue-echarts": "7.0.3",
"vue-i18n": "9.14.2",
"vue-router": "4.4.5",
"vuedraggable": "4.1.0"
},
"devDependencies": {
"@swc/core": "1.6.13",
"@types/node": "20.0.0",
"@types/nprogress": "0.2.3",
"@types/sortablejs": "1.15.8",
"@typescript-eslint/eslint-plugin": "8.17.0",
"@typescript-eslint/parser": "8.17.0",
"@vitejs/plugin-vue": "5.2.1",
"@vue/compiler-sfc": "3.5.13",
"consola": "3.2.3",
"cross-env": "7.0.3",
"eslint": "9.14.0",
"eslint-plugin-vue": "9.32.0",
"glob": "9.3.5",
"pinia-plugin-persist": "1.0.0",
"prettier": "3.4.2",
"sass": "1.58.3",
"terser": "5.36.0",
"typescript": "5.6.3",
"unplugin-auto-import": "0.18.6",
"unplugin-vue-setup-extend": "^0.3.5",
"vite": "5.4.11",
"vite-plugin-compression": "0.5.1",
"vite-plugin-top-level-await": "1.4.4",
"vue-eslint-parser": "9.4.3"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
],
"bugs": {
"url": "https://pig4cloud.com"
},
"engines": {
"node": ">=18.0.0",
"npm": ">= 8.0.0"
},
"keywords": [
"vue",
"vue3",
"vuejs/vue-next",
"element-ui",
"element-plus"
],
"repository": {
"type": "git",
"url": "https://gitee.com/log4j/pig-ui"
}
}
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
};
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
<template>
<el-config-provider :size="getGlobalComponentSize" :locale="getGlobalI18n">
<router-view v-show="setLockScreen" />
<LockScreen v-if="themeConfig.isLockScreen" />
<Setings ref="settingRef" v-show="themeConfig.lockScreenTime > 1" />
<CloseFull v-if="!themeConfig.isLockScreen" />
</el-config-provider>
</template>
<script setup lang="ts" name="app">
import { useI18n } from 'vue-i18n';
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
import { useThemeConfig } from '/@/stores/themeConfig';
import other from '/@/utils/other';
import { Local, Session } from '/@/utils/storage';
import mittBus from '/@/utils/mitt';
import setIntroduction from '/@/utils/setIconfont';
// 引入组件
const LockScreen = defineAsyncComponent(() => import('/@/layout/lockScreen/index.vue'));
const Setings = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/setings.vue'));
const CloseFull = defineAsyncComponent(() => import('/@/layout/navBars/breadcrumb/closeFull.vue'));
// 定义变量内容
const { messages, locale } = useI18n();
const settingRef = ref();
const route = useRoute();
const stores = useTagsViewRoutes();
const storesThemeConfig = useThemeConfig();
const { themeConfig } = storeToRefs(storesThemeConfig);
// 设置锁屏时组件显示隐藏
const setLockScreen = computed(() => {
// 防止锁屏后,刷新出现不相关界面
// https://gitee.com/lyt-top/vue-next-admin/issues/I6AF8P
return themeConfig.value.isLockScreen ? themeConfig.value.lockScreenTime > 1 : themeConfig.value.lockScreenTime >= 0;
});
// 获取全局组件大小
const getGlobalComponentSize = computed(() => {
return other.globalComponentSize();
});
// 获取全局 i18n
const getGlobalI18n = computed(() => {
return messages.value[locale.value];
});
// 设置初始化,防止刷新时恢复默认
onBeforeMount(() => {
// 设置批量第三方 icon 图标
setIntroduction.cssCdn();
// 设置批量第三方 js
setIntroduction.jsCdn();
});
// 页面加载时
onMounted(() => {
nextTick(() => {
// 监听布局配'置弹窗点击打开
mittBus.on('openSetingsDrawer', () => {
settingRef.value.openDrawer();
});
// 获取缓存中的布局配置
if (Local.get('themeConfig')) {
storesThemeConfig.setThemeConfig({ themeConfig: Local.get('themeConfig') });
document.documentElement.style.cssText = Local.get('themeConfigStyle');
}
// 获取缓存中的全屏配置
if (Session.get('isTagsViewCurrenFull')) {
stores.setCurrenFullscreen(Session.get('isTagsViewCurrenFull'));
}
});
});
// 页面销毁时,关闭监听布局配置/i18n监听
onUnmounted(() => {
mittBus.off('openSetingsDrawer', () => {});
});
// 监听路由的变化,设置网站标题
watch(
() => route.path,
() => {
other.useTitle();
},
{
deep: true,
}
);
</script>
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/admin/client/page',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/admin/client',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/admin/client/' + id,
method: 'get',
});
}
export function delObj(ids?: object) {
return request({
url: '/admin/client',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/admin/client',
method: 'put',
data: obj,
});
}
export function refreshCache() {
return request({
url: '/admin/client/sync',
method: 'put',
});
}
export function getDetails(obj: Object) {
return request({
url: '/admin/client/getClientDetailsById/' + obj,
method: 'get',
});
}
export function validateclientId(rule: any, value: any, callback: any, isEdit: boolean) {
if (isEdit) {
return callback();
}
getDetails(value).then((res) => {
const result = res.data;
if (result !== null) {
callback(new Error('编号已经存在'));
} else {
callback();
}
});
}
import request from '/@/utils/request';
export const deptTree = (params?: Object) => {
return request({
url: '/admin/dept/tree',
method: 'get',
params,
});
};
export const addObj = (obj: Object) => {
return request({
url: '/admin/dept',
method: 'post',
data: obj,
});
};
export const getObj = (id: string) => {
return request({
url: '/admin/dept/' + id,
method: 'get',
});
};
export const delObj = (id: string) => {
return request({
url: '/admin/dept/' + id,
method: 'delete',
});
};
export const putObj = (obj: Object) => {
return request({
url: '/admin/dept',
method: 'put',
data: obj,
});
};
export const syncUser = () => {
return request({
url: '/admin/connect/sync/ding/user',
method: 'post',
});
};
export const syncDept = () => {
return request({
url: '/admin/connect/sync/ding/dept',
method: 'post',
});
};
export const syncCpUser = () => {
return request({
url: '/admin/connect/sync/cp/user',
method: 'post',
});
};
export const syncCpDept = () => {
return request({
url: '/admin/connect/sync/cp/dept',
method: 'post',
});
};
import request from '/@/utils/request';
export const getDicts = (type: String) => {
return request({
url: `/admin/dict/type/${type}`,
method: 'get',
});
};
export function fetchList(query: any) {
return request({
url: '/admin/dict/list',
method: 'get',
params: query,
});
}
export function fetchItemList(query: any) {
return request({
url: '/admin/dict/item/page',
method: 'get',
params: query,
});
}
export function addItemObj(obj: any) {
return request({
url: '/admin/dict/item',
method: 'post',
data: obj,
});
}
export function getItemObj(id: string) {
return request({
url: '/admin/dict/item/details/' + id,
method: 'get',
});
}
export function getItemDetails(obj: object) {
return request({
url: '/admin/dict/item/details',
method: 'get',
params: obj,
});
}
export function delItemObj(id: string) {
return request({
url: '/admin/dict/item/' + id,
method: 'delete',
});
}
export function putItemObj(obj: any) {
return request({
url: '/admin/dict/item',
method: 'put',
data: obj,
});
}
export function addObj(obj: any) {
return request({
url: '/admin/dict',
method: 'post',
data: obj,
});
}
export function getObj(id: string) {
return request({
url: '/admin/dict/details/' + id,
method: 'get',
});
}
export function getObjDetails(obj: object) {
return request({
url: '/admin/dict/details',
method: 'get',
params: obj,
});
}
export function delObj(ids: Object) {
return request({
url: '/admin/dict',
method: 'delete',
data: ids,
});
}
export function putObj(obj: any) {
return request({
url: '/admin/dict',
method: 'put',
data: obj,
});
}
export function refreshCache() {
return request({
url: '/admin/dict/sync',
method: 'put',
});
}
export function validateDictType(rule: any, value: any, callback: any, isEdit: boolean) {
if (isEdit) {
return callback();
}
getObjDetails({ dictType: value }).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('字典类型已经存在'));
} else {
callback();
}
});
}
export function validateDictItemLabel(rule: any, value: any, callback: any, type: string, isEdit: boolean) {
if (isEdit) {
return callback();
}
getItemDetails({ dictType: type, label: value }).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('标签已经存在'));
} else {
callback();
}
});
}
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/admin/sys-file/page',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/admin/sys-file',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/admin/sys-file/' + id,
method: 'get',
});
}
export function delObj(ids?: Object) {
return request({
url: '/admin/sys-file',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/admin/sys-file',
method: 'put',
data: obj,
});
}
import request from '/@/utils/request';
import axios from 'axios';
export function fetchList(query?: Object) {
return request({
url: '/admin/i18n/page',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/admin/i18n',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/admin/i18n/details/' + id,
method: 'get',
});
}
export function getObjDetails(obj?: object) {
return request({
url: '/admin/i18n/details',
method: 'get',
params: obj,
});
}
export function delObj(ids?: object) {
return request({
url: '/admin/i18n',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/admin/i18n',
method: 'put',
data: obj,
});
}
export function refreshCache() {
return request({
url: '/admin/i18n/sync',
method: 'put',
});
}
/**
* 注意这里使用原声axios对象进行操作,request 实例中依赖i18n 所以还没有初始化会报错
* @returns
*/
export function info() {
return axios.get(import.meta.env.VITE_API_URL + '/admin/i18n/info');
}
export function validateName(rule: any, value: any, callback: any, isEdit: boolean) {
if (isEdit) {
return callback();
}
getObjDetails({ name: value }).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('国际化编码已经存在'));
} else {
callback();
}
});
}
export function validateZhCn(rule: any, value: any, callback: any, isEdit: boolean) {
if (isEdit) {
return callback();
}
getObjDetails({ zhCn: value }).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('国际化中文已经存在'));
} else {
callback();
}
});
}
export function validateEn(rule: any, value: any, callback: any, isEdit: boolean) {
if (isEdit) {
return callback();
}
getObjDetails({ en: value }).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('国际化英文已经存在'));
} else {
callback();
}
});
}
import request from '/@/utils/request';
export const pageList = (params?: Object) => {
return request({
url: '/admin/log/page',
method: 'get',
params,
});
};
export const delObj = (ids: object) => {
return request({
url: '/admin/log',
method: 'delete',
data: ids,
});
};
import request from '/@/utils/request';
export const pageList = (params?: Object) => {
return request({
url: '/admin/menu/tree',
method: 'get',
params,
});
};
export const info = (id: String) => {
return request({
url: `/admin/menu/${id}`,
method: 'get',
});
};
export const save = (data: Object) => {
return request({
url: '/admin/menu',
method: 'post',
data: data,
});
};
export const putObj = (data: Object) => {
return request({
url: '/admin/menu',
method: 'put',
data: data,
});
};
export const addObj = (data: Object) => {
return request({
url: '/admin/menu',
method: 'post',
data: data,
});
};
export const delObj = (id: string) => {
return request({
url: '/admin/menu/' + id,
method: 'delete',
});
};
/**
* 后端控制路由,isRequestRoutes 为 true,则开启后端控制路由
* @method getAdminMenu 获取后端动态路由菜单(admin)
*/
export function useMenuApi() {
return {
getAdminMenu: (params?: object) => {
return request({
url: '/admin/menu',
method: 'get',
params,
});
},
};
}
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/admin/param/page',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/admin/param',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/admin/param/details/' + id,
method: 'get',
});
}
export function delObj(ids?: Object) {
return request({
url: '/admin/param',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/admin/param',
method: 'put',
data: obj,
});
}
export function refreshCache() {
return request({
url: '/admin/param/sync',
method: 'put',
});
}
export function getObjDetails(obj?: object) {
return request({
url: '/admin/param/details',
method: 'get',
params: obj,
});
}
export function validateParamsCode(rule: any, value: any, callback: any, isEdit: boolean) {
if (isEdit) {
return callback();
}
getObjDetails({ publicKey: value }).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('参数编码已经存在'));
} else {
callback();
}
});
}
export function validateParamsName(rule: any, value: any, callback: any, isEdit: boolean) {
if (isEdit) {
return callback();
}
getObjDetails({ publicName: value }).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('参数名称已经存在'));
} else {
callback();
}
});
}
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/admin/post/page',
method: 'get',
params: query,
});
}
export const list = (params?: Object) => {
return request({
url: '/admin/post/list',
method: 'get',
params,
});
};
export function addObj(obj?: Object) {
return request({
url: '/admin/post',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/admin/post/details/' + id,
method: 'get',
});
}
export function getObjDetails(obj?: object) {
return request({
url: '/admin/post/details',
method: 'get',
params: obj,
});
}
export function delObj(ids?: object) {
return request({
url: '/admin/post',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/admin/post',
method: 'put',
data: obj,
});
}
export function validatePostName(rule: any, value: any, callback: any, isEdit: boolean) {
if (isEdit) {
return callback();
}
getObjDetails({ postName: value }).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('岗位名称已经存在'));
} else {
callback();
}
});
}
export function validatePostCode(rule: any, value: any, callback: any, isEdit: boolean) {
if (isEdit) {
return callback();
}
getObjDetails({ postCode: value }).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('岗位编码已经存在'));
} else {
callback();
}
});
}
import request from '/@/utils/request';
export const list = (params?: Object) => {
return request({
url: '/admin/role/list',
method: 'get',
params,
});
};
export const pageList = (params?: Object) => {
return request({
url: '/admin/role/page',
method: 'get',
params,
});
};
export const deptRoleList = () => {
return request({
url: '/admin/role/list',
method: 'get',
});
};
export const getObj = (id: string) => {
return request({
url: '/admin/role/details/' + id,
method: 'get',
});
};
export const getObjDetails = (obj: object) => {
return request({
url: '/admin/role/details',
method: 'get',
params: obj,
});
};
export const addObj = (obj: Object) => {
return request({
url: '/admin/role',
method: 'post',
data: obj,
});
};
export const putObj = (obj: Object) => {
return request({
url: '/admin/role',
method: 'put',
data: obj,
});
};
export const delObj = (ids: Object) => {
return request({
url: '/admin/role',
method: 'delete',
data: ids,
});
};
export const permissionUpd = (roleId: string, menuIds: string) => {
return request({
url: '/admin/role/menu',
method: 'put',
data: {
roleId: roleId,
menuIds: menuIds,
},
});
};
export const fetchRoleTree = (roleId: string) => {
return request({
url: '/admin/menu/tree/' + roleId,
method: 'get',
});
};
export function validateRoleCode(rule: any, value: any, callback: any, isEdit: boolean) {
if (isEdit) {
return callback();
}
getObjDetails({ roleCode: value }).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('角色标识已经存在'));
} else {
callback();
}
});
}
export function validateRoleName(rule: any, value: any, callback: any, isEdit: boolean) {
if (isEdit) {
return callback();
}
getObjDetails({ roleName: value }).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('角色名称已经存在'));
} else {
callback();
}
});
}
import request from '/@/utils/request';
// 系统缓存监控
export function systemCache() {
return request({
url: '/admin/system/cache',
method: 'get',
});
}
import request from '/@/utils/request';
export function fetchList(query: object) {
return request({
url: '/admin/sys-token/page',
method: 'post',
data: query,
});
}
export function delObj(accessTokens: string[]) {
return request({
url: '/admin/sys-token/delete',
method: 'delete',
data: accessTokens,
});
}
import request from '/@/utils/request';
export const pageList = (params?: Object) => {
return request({
url: '/admin/user/page',
method: 'get',
params,
});
};
export const addObj = (obj: Object) => {
return request({
url: '/admin/user',
method: 'post',
data: obj,
});
};
export const getObj = (id: String) => {
return request({
url: '/admin/user/details/' + id,
method: 'get',
});
};
export const delObj = (ids: Object) => {
return request({
url: '/admin/user',
method: 'delete',
data: ids,
});
};
export const putObj = (obj: Object) => {
return request({
url: '/admin/user',
method: 'put',
data: obj,
});
};
export function getDetails(obj: Object) {
return request({
url: '/admin/user/details',
method: 'get',
params: obj,
});
}
// 更改个人信息
export function editInfo(obj: Object) {
return request({
url: '/admin/user/edit',
method: 'put',
data: obj,
});
}
export function password(obj: Object) {
return request({
url: '/admin/user/password',
method: 'put',
data: obj,
});
}
export function UnbindingUser(type) {
return request({
url: '/admin/user/unbinding',
method: 'post',
params: {
type,
},
});
}
export function checkPassword(password: string) {
return request({
url: '/admin/user/check',
method: 'post',
params: {
password,
},
});
}
/**
* 注册用户
*/
export const registerUser = (userInfo: object) => {
return request({
url: '/admin/register/user',
method: 'post',
data: userInfo,
});
};
export function validateUsername(rule: any, value: any, callback: any, isEdit: boolean) {
const flag = new RegExp(/^([a-z\d]+?)$/).test(value);
if (!flag) {
callback(new Error('用户名支持小写英文、数字'));
}
if (isEdit) {
return callback();
}
getDetails({ username: value }).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('用户名已经存在'));
} else {
callback();
}
});
}
export function validatePhone(rule: any, value: any, callback: any, isEdit: boolean) {
if (isEdit) {
return callback();
}
getDetails({ phone: value }).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('手机号已经存在'));
} else {
callback();
}
});
}
import request from '/@/utils/request';
export function fetchList(query: any) {
return request({
url: '/job/sys-job-log/page',
method: 'get',
params: query,
});
}
export function delObjs(ids: object) {
return request({
url: '/job/sys-job-log',
method: 'delete',
data: ids,
});
}
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/job/sys-job/page',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/job/sys-job',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/job/sys-job/' + id,
method: 'get',
});
}
export function delObj(id?: string) {
return request({
url: '/job/sys-job/' + id,
method: 'delete',
});
}
export function putObj(obj?: Object) {
return request({
url: '/job/sys-job',
method: 'put',
data: obj,
});
}
export function startJobRa(jobId: string) {
return request({
url: '/job/sys-job/start-job/' + jobId,
method: 'post',
});
}
export function runJobRa(jobId: string) {
return request({
url: '/job/sys-job/run-job/' + jobId,
method: 'post',
});
}
export function shutDownJobRa(jobId: string) {
return request({
url: '/job/sys-job/shutdown-job/' + jobId,
method: 'post',
});
}
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/gen/dsconf/page',
method: 'get',
params: query,
});
}
export function list(query?: Object) {
return request({
url: '/gen/dsconf/list',
method: 'get',
params: query,
});
}
export function listTable(query?: Object) {
return request({
url: '/gen/dsconf/table/list',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/gen/dsconf',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/gen/dsconf/' + id,
method: 'get',
});
}
export function delObj(ids?: Object) {
return request({
url: '/gen/dsconf',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/gen/dsconf',
method: 'put',
data: obj,
});
}
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/gen/fieldtype/page',
method: 'get',
params: query,
});
}
export function list(query?: Object) {
return request({
url: '/gen/fieldtype/list',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/gen/fieldtype',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/gen/fieldtype/details/' + id,
method: 'get',
});
}
export function getObjDetails(obj?: object) {
return request({
url: '/gen/fieldtype/details',
method: 'get',
params: obj,
});
}
export function delObj(ids?: object) {
return request({
url: '/gen/fieldtype',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/gen/fieldtype',
method: 'put',
data: obj,
});
}
export function validateColumnType(rule: any, value: any, callback: any, isEdit: boolean) {
if (isEdit) {
return callback();
}
getObjDetails({ columnType: value }).then((response) => {
const result = response.data;
if (result !== null) {
callback(new Error('类型已经存在'));
} else {
callback();
}
});
}
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/gen/group/page',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/gen/group',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/gen/group/' + id,
method: 'get',
});
}
export function delObjs(ids?: Object) {
return request({
url: '/gen/group',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/gen/group',
method: 'put',
data: obj,
});
}
export function list() {
return request({
url: '/gen/group/list',
method: 'get',
});
}
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/gen/table/page',
method: 'get',
params: query,
});
}
export function addObj(obj?: Object) {
return request({
url: '/gen/table',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/gen/table/' + id,
method: 'get',
});
}
export function delObj(id?: string) {
return request({
url: '/gen/table/' + id,
method: 'delete',
});
}
export function putObj(obj?: Object) {
return request({
url: '/gen/table',
method: 'put',
data: obj,
});
}
export const useSyncTableApi = (dsName: string, tableName: string) => {
return request.get('/gen/table/sync/' + dsName + '/' + tableName);
};
export const useTableApi = (dsName: string, tableName: string) => {
return request.get('/gen/table/' + dsName + '/' + tableName);
};
export const useListTableApi = (dsName: string) => {
return request.get('/gen/table/list/' + dsName);
};
export const useListTableColumnApi = (dsName: string, tableName: string) => {
return request.get('/gen/table/column/' + dsName + '/' + tableName);
};
export const useTableFieldSubmitApi = (dsName: string, tableName: string, fieldList: any) => {
return request.put('/gen/table/field/' + dsName + '/' + tableName, fieldList);
};
export const useGeneratorCodeApi = (tableIds: any) => {
return request({
url: '/gen/generator/code',
method: 'get',
params: { tableIds: tableIds },
});
};
export const useGeneratorVFormApi = (dsName: any, tableName: any) => {
return request({
url: '/gen/generator/vform',
method: 'get',
params: { dsName: dsName, tableName: tableName },
});
};
export const useGeneratorVFormSfcApi = (id: string) => {
return request({
url: '/gen/generator/vform/sfc',
method: 'get',
params: { formId: id },
});
};
export const useGeneratorPreviewApi = (tableId: any) => {
return request({
url: '/gen/generator/preview',
method: 'get',
params: { tableId: tableId },
});
};
export function fetchDictList() {
return request({
url: '/admin/dict/list',
method: 'get',
});
}
export function useFormConfSaveApi(obj?: Object) {
return request({
url: '/gen/form',
method: 'post',
data: obj,
});
}
export function fetchFormList(query?: Object) {
return request({
url: '/gen/form/page',
method: 'get',
params: query,
});
}
export function fetchFormById(id?: string) {
return request({
url: '/gen/form/' + id,
method: 'get',
});
}
export function delFormObj(id?: string) {
return request({
url: '/gen/form/' + id,
method: 'delete',
});
}
import request from '/@/utils/request';
export function fetchList(query?: Object) {
return request({
url: '/gen/template/page',
method: 'get',
params: query,
});
}
export function list() {
return request({
url: '/gen/template/list',
method: 'get',
});
}
export function online() {
return request({
url: '/gen/template/online',
method: 'get',
});
}
export function checkVersion() {
return request({
url: '/gen/template/checkVersion',
method: 'get',
});
}
export function addObj(obj?: Object) {
return request({
url: '/gen/template',
method: 'post',
data: obj,
});
}
export function getObj(id?: string) {
return request({
url: '/gen/template/' + id,
method: 'get',
});
}
export function delObjs(ids?: Object) {
return request({
url: '/gen/template',
method: 'delete',
data: ids,
});
}
export function putObj(obj?: Object) {
return request({
url: '/gen/template',
method: 'put',
data: obj,
});
}
import request from '/@/utils/request';
import {Session} from '/@/utils/storage';
import {validateNull} from '/@/utils/validate';
import {useUserInfo} from '/@/stores/userInfo';
import other from '/@/utils/other';
/**
* https://www.ietf.org/rfc/rfc6749.txt
* OAuth 协议 4.3.1 要求格式为 form 而不是 JSON 注意!
*/
const FORM_CONTENT_TYPE = 'application/x-www-form-urlencoded';
/**
* 登录
* @param data
*/
export const login = (data: any) => {
const basicAuth = 'Basic ' + window.btoa(import.meta.env.VITE_OAUTH2_PASSWORD_CLIENT);
Session.set('basicAuth', basicAuth);
let encPassword = data.password;
// 密码加密
if (import.meta.env.VITE_PWD_ENC_KEY) {
encPassword = other.encryption(data.password, import.meta.env.VITE_PWD_ENC_KEY);
}
return request({
url: '/auth/oauth2/token',
method: 'post',
data: {...data, password: encPassword},
headers: {
skipToken: true,
Authorization: basicAuth,
'Content-Type': FORM_CONTENT_TYPE,
},
});
};
export const loginByMobile = (mobile: any, code: any) => {
const grant_type = 'mobile';
const scope = 'server';
const basicAuth = 'Basic ' + window.btoa(import.meta.env.VITE_OAUTH2_MOBILE_CLIENT);
Session.set('basicAuth', basicAuth);
return request({
url: '/auth/oauth2/token',
headers: {
skipToken: true,
Authorization: basicAuth,
'Content-Type': FORM_CONTENT_TYPE,
},
method: 'post',
data: {mobile: mobile, code: code, grant_type, scope},
});
};
export const loginBySocial = (state: string, code: string) => {
const grant_type = 'mobile';
const scope = 'server';
const basicAuth = 'Basic ' + window.btoa(import.meta.env.VITE_OAUTH2_SOCIAL_CLIENT);
Session.set('basicAuth', basicAuth);
return request({
url: '/auth/oauth2/token',
headers: {
skipToken: true,
Authorization: basicAuth,
'Content-Type': FORM_CONTENT_TYPE,
},
method: 'post',
data: {mobile: state + '@' + code, code: code, grant_type, scope},
});
};
export const sendMobileCode = (mobile: any) => {
return request({
url: '/admin/mobile/' + mobile,
method: 'get',
});
};
export const refreshTokenApi = (refresh_token: string) => {
const grant_type = 'refresh_token';
const scope = 'server';
// 获取当前选中的 basic 认证信息
const basicAuth = Session.get('basicAuth');
return request({
url: '/auth/oauth2/token',
headers: {
skipToken: true,
Authorization: basicAuth,
'Content-Type': FORM_CONTENT_TYPE,
},
method: 'post',
data: {refresh_token, grant_type, scope},
});
};
/**
* 校验令牌,若有效期小于半小时自动续期
* @param refreshLock
*/
export const checkToken = (refreshTime: number, refreshLock: boolean) => {
const basicAuth = Session.get('basicAuth');
request({
url: '/auth/token/check_token',
headers: {
skipToken: true,
Authorization: basicAuth,
'Content-Type': FORM_CONTENT_TYPE,
},
method: 'get',
params: {token: Session.getToken()},
})
.then((response) => {
if (validateNull(response) || response.code === 1) {
clearInterval(refreshTime);
return;
}
const expire = Date.parse(response.data.expiresAt);
if (expire) {
const expiredPeriod = expire - new Date().getTime();
//小于半小时自动续约
if (expiredPeriod <= 30 * 60 * 1000) {
if (!refreshLock) {
refreshLock = true;
useUserInfo()
.refreshToken()
.catch(() => {
clearInterval(refreshTime);
});
refreshLock = false;
}
}
}
})
.catch(() => {
// 发生异常关闭定时器
clearInterval(refreshTime);
});
};
/**
* 获取用户信息
*/
export const getUserInfo = () => {
return request({
url: '/admin/user/info',
method: 'get',
});
};
export const logout = () => {
return request({
url: '/auth/token/logout',
method: 'delete',
});
};
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1680436859217" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="12985" xmlns:xlink="http://www.w3.org/1999/xlink" width="45" height="45"><path d="M784.66 462.13V336.37l-168.79 95.52v160.12l168.79 96.49V562.74H927v-100.6H784.66zM615.87 851.55h109.47l1.49-122.18-110.96-65.05v187.23z m116.35-558.98L734.61 97H479.13l80.97 13.55 55.54 9.21 0.23 238.82 116.35-66.01zM106.16 851.55L548.53 927V172.46L97 97l9.16 754.55z" fill="#8a8a8a" p-id="12986"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1680436627707" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4215" xmlns:xlink="http://www.w3.org/1999/xlink" width="45" height="45"><path d="M512 1024C230.4 1024 0 793.6 0 512S230.4 0 512 0s512 230.4 512 512-230.4 512-512 512z m259.2-569.6H480c-12.8 0-25.6 12.8-25.6 25.6v64c0 12.8 12.8 25.6 25.6 25.6h176c12.8 0 25.6 12.8 25.6 25.6v12.8c0 41.6-35.2 76.8-76.8 76.8h-240c-12.8 0-25.6-12.8-25.6-25.6V416c0-41.6 35.2-76.8 76.8-76.8h355.2c12.8 0 25.6-12.8 25.6-25.6v-64c0-12.8-12.8-25.6-25.6-25.6H416c-105.6 0-188.8 86.4-188.8 188.8V768c0 12.8 12.8 25.6 25.6 25.6h374.4c92.8 0 169.6-76.8 169.6-169.6v-144c0-12.8-12.8-25.6-25.6-25.6z" fill="#888888" p-id="4216"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1680436662087" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5326" xmlns:xlink="http://www.w3.org/1999/xlink" width="45" height="45"><path d="M518.4 691.2c-99.2 0-182.4-64-185.6-185.6-6.4-112 92.8-188.8 188.8-192 108.8-3.2 176 121.6 176 121.6l281.6-102.4S864 32 547.2 32C252.8 35.2 48 236.8 48 512c0 243.2 192 489.6 489.6 476.8C867.2 976 979.2 688 979.2 688L688 592c3.2 3.2-57.6 99.2-169.6 99.2" fill="#8a8a8a" p-id="5327"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1680436602191" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4038" xmlns:xlink="http://www.w3.org/1999/xlink" width="45" height="45"><path d="M824.8 613.2c-16-51.4-34.4-94.6-62.7-165.3C766.5 262.2 689.3 112 511.5 112 331.7 112 256.2 265.2 261 447.9c-28.4 70.8-46.7 113.7-62.7 165.3-34 109.5-23 154.8-14.6 155.8 18 2.2 70.1-82.4 70.1-82.4 0 49 25.2 112.9 79.8 159-26.4 8.1-85.7 29.9-71.6 53.8 11.4 19.3 196.2 12.3 249.5 6.3 53.3 6 238.1 13 249.5-6.3 14.1-23.8-45.3-45.7-71.6-53.8 54.6-46.2 79.8-110.1 79.8-159 0 0 52.1 84.6 70.1 82.4 8.5-1.1 19.5-46.4-14.5-155.8z" p-id="4039"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1680436062848" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2406" width="24" height="24" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M188.8704 576.192a187.712 187.712 0 0 1 188.928 189.12 189.184 189.184 0 0 1-188.928 190.912A189.184 189.184 0 0 1 0.0064 765.312a187.712 187.712 0 0 1 188.864-189.12z m359.68 250.176v81.472h-61.44a40.128 40.128 0 0 1-39.296-34.688l-0.448-6.016c0-20.48 14.72-37.376 33.92-40.32l5.888-0.384 61.44-0.064z m-359.68-169.664c-60.288 0-109.376 46.848-109.376 108.608 0 61.76 49.088 110.144 109.44 110.144 60.288 0 109.312-48.384 109.312-110.08 0-61.824-49.024-108.672-109.376-108.672z m359.68-59.392v81.408h-61.44a40.128 40.128 0 0 1-39.296-34.624L447.3664 638.08c0-20.48 14.72-37.376 33.92-40.32l5.888-0.448h61.44zM188.8704 64C293.1264 64 377.7984 149.568 377.7984 256.256A188.032 188.032 0 0 1 188.8064 445.76 188.032 188.032 0 0 1 0.0064 256.256C0.0064 149.568 84.7424 64 188.8704 64zM984.3264 342.784a40.32 40.32 0 0 1 39.744 40.704c0 20.48-14.72 37.376-33.92 40.32l-5.824 0.448H487.1744a40.32 40.32 0 0 1-39.808-40.768c0-20.416 14.72-37.376 33.92-40.256l5.888-0.448h497.088zM188.8064 147.584c-60.288 0-109.376 46.912-109.376 108.608 0 61.76 49.088 108.16 109.44 108.16 60.288 0 109.312-46.4 109.312-108.16 0-61.696-49.024-108.608-109.376-108.608z m795.392-33.92a40.32 40.32 0 0 1 39.744 40.768c0 20.416-14.72 37.312-33.92 40.256l-5.824 0.448H487.1744a40.32 40.32 0 0 1-39.808-40.704c0-20.48 14.72-37.376 33.92-40.32l5.888-0.448h497.088zM816.2624 918.528V847.36c0-10.56-16.192-15.872-30.08-15.872-13.824 0-33.152 3.84-33.152 15.872v71.168c0 9.088-6.144 15.104-15.36 15.104h-97.152c-23.104 0-40.064-16.64-40.064-37.824V752c0-9.088 12.8-15.104 22.08-15.104 9.216 0 21.76 6.016 21.76 15.104v133.12c0 4.48 3.072 7.552 9.216 7.552h59.392v-45.312c0-35.456 43.968-56.32 73.28-56.32 29.312 0 72 20.864 72 56.32v45.312h63.168c4.608 0 7.68 0 7.68-9.088V752c0-9.088 12.16-15.104 21.44-15.104 9.28 0 21.44 6.016 21.44 15.104v143.808c-1.536 22.656-16.96 37.824-40.064 37.824h-100.16c-9.28 0-15.424-6.016-15.424-15.104zM582.4064 712.256c-6.08-6.528-9.216-27.904-3.136-32.768l178.88-157.696c16.64-13.056 40.96-13.056 56.064 0l178.88 156.096c6.08 4.864 6.08 27.84 0 34.368-6.016 6.464-27.2 6.464-33.28 0l-163.776-142.72a18.24 18.24 0 0 0-18.176 0L615.0464 716.416c-3.008 3.264-6.016 3.264-9.088 3.264-4.48 0-20.544-2.56-23.616-7.424z" fill="#707070" p-id="2407"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1680436429435" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2757" width="45" height="45" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M405.333333 170.666667C228.693333 170.666667 85.333333 285.44 85.333333 426.666667c0 80.64 46.08 151.893333 118.613334 198.826666L170.666667 725.333333l106.666666-64c37.973333 13.226667 79.786667 21.333333 124.16 21.333334A222.72 222.72 0 0 1 384 597.333333c0-141.226667 133.546667-256 298.666667-256 8.106667 0 16.213333 0 23.893333 1.28C663.04 242.773333 545.28 170.666667 405.333333 170.666667m-128 106.666666c23.466667 0 42.666667 19.2 42.666667 42.666667s-19.2 42.666667-42.666667 42.666667-42.666667-19.2-42.666666-42.666667 19.2-42.666667 42.666666-42.666667m213.333334 0c23.466667 0 42.666667 19.2 42.666666 42.666667s-19.2 42.666667-42.666666 42.666667-42.666667-19.2-42.666667-42.666667 19.2-42.666667 42.666667-42.666667M682.666667 384c-141.226667 0-256 95.573333-256 213.333333s114.773333 213.333333 256 213.333334c28.586667 0 55.893333-3.413333 81.493333-10.666667L853.333333 853.333333l-26.453333-79.786666C893.866667 734.72 938.666667 670.293333 938.666667 597.333333c0-117.76-114.773333-213.333333-256-213.333333m-85.333334 106.666667c23.466667 0 42.666667 19.2 42.666667 42.666666s-19.2 42.666667-42.666667 42.666667-42.666667-19.2-42.666666-42.666667 19.2-42.666667 42.666666-42.666666m170.666667 0c23.466667 0 42.666667 19.2 42.666667 42.666666s-19.2 42.666667-42.666667 42.666667-42.666667-19.2-42.666667-42.666667 19.2-42.666667 42.666667-42.666666z" fill="#8a8a8a" p-id="2758"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1677809803390" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2360" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M891.2 326.4l-121.6 69.6v-144c0-33.6-27.2-60.8-60.8-60.8h-560c-33.6 0-60.8 27.2-60.8 60.8v545.6c0 33.6 27.2 60.8 60.8 60.8h560.8c33.6 0 60.8-27.2 60.8-60.8v-144l121.6 69.6c20 12 45.6-3.2 45.6-26.4v-344c-0.8-23.2-25.6-37.6-46.4-26.4z m-188.8 464H156V260h545.6v530.4z m166.4-157.6L770.4 576V475.2l98.4-56.8v214.4z" p-id="2361"></path><path d="M426.4 600c-0.8 0.8-1.6 1.6-1.6 2.4-5.6 8-10.4 16.8-16.8 24.8-7.2 10.4-16 20.8-25.6 29.6-8 7.2-16.8 13.6-27.2 17.6-6.4 2.4-13.6 3.2-20.8 2.4-6.4-0.8-12-4-16.8-8.8-6.4-5.6-11.2-12.8-15.2-20.8-3.2-6.4-7.2-13.6-9.6-20-3.2-8-7.2-16.8-9.6-25.6-3.2-10.4-6.4-20-9.6-30.4-3.2-10.4-5.6-21.6-8-32-2.4-8.8-4-17.6-5.6-26.4-1.6-8-2.4-16-4-24-0.8-6.4-1.6-13.6-2.4-20 0-2.4 0-4-0.8-6.4-0.8-12-0.8-24 0-35.2 0.8-9.6 2.4-18.4 6.4-27.2s9.6-16 18.4-20.8c7.2-4 14.4-4.8 21.6-3.2 8.8 1.6 16.8 5.6 24.8 11.2 8.8 6.4 16 13.6 23.2 20.8 8 8.8 15.2 17.6 22.4 27.2 8 10.4 15.2 21.6 22.4 32.8 9.6 15.2 18.4 30.4 28 45.6 2.4 3.2 4 6.4 5.6 10.4 0 0.8 0.8 0.8 0.8 1.6 2.4-4 4.8-7.2 7.2-11.2 10.4-17.6 21.6-35.2 33.6-52.8 10.4-15.2 20.8-30.4 32.8-44.8 8-9.6 16-18.4 25.6-25.6 7.2-5.6 14.4-10.4 23.2-12.8 12-4 23.2-2.4 33.6 6.4 5.6 4.8 9.6 10.4 12 16.8 3.2 8 4.8 16 6.4 24 1.6 12 0.8 23.2 0 35.2-0.8 7.2-0.8 13.6-2.4 20.8-1.6 12-3.2 23.2-5.6 35.2-1.6 8-3.2 16.8-5.6 24.8l-7.2 28.8c-2.4 8.8-5.6 18.4-8.8 27.2-4 12.8-9.6 25.6-15.2 37.6-4 8-8 16-12.8 23.2-4 5.6-8.8 10.4-14.4 14.4-6.4 4.8-14.4 5.6-22.4 4.8-12-1.6-21.6-7.2-31.2-14.4-11.2-8.8-20.8-20-29.6-32-6.4-8.8-12.8-18.4-18.4-28 0.8-1.6 0-2.4-0.8-3.2z m139.2-156.8c-0.8-5.6-0.8-11.2-1.6-16.8l-2.4-9.6c-0.8-3.2-3.2-4-6.4-2.4-1.6 0.8-2.4 1.6-4 2.4-7.2 4.8-12.8 11.2-18.4 16.8-12.8 13.6-23.2 28.8-33.6 44-9.6 14.4-18.4 28.8-27.2 43.2-7.2 12-14.4 24-21.6 35.2-3.2 4.8-3.2 4.8 0 10.4 4.8 9.6 10.4 19.2 16.8 28.8 8 12.8 16.8 24.8 28 35.2 2.4 2.4 5.6 4.8 8.8 7.2 4 2.4 8 1.6 10.4-2.4 0-0.8 0.8-0.8 0.8-1.6 6.4-9.6 10.4-20.8 15.2-31.2l9.6-26.4c2.4-6.4 4-12.8 5.6-19.2 3.2-12.8 6.4-24.8 9.6-37.6 2.4-9.6 4-20 5.6-29.6 1.6-8 2.4-15.2 3.2-23.2 0.8-8 1.6-16 1.6-23.2z m-160 117.6c-0.8-0.8-0.8-2.4-1.6-3.2-4-6.4-7.2-12.8-11.2-19.2-8.8-14.4-17.6-29.6-26.4-44-8.8-14.4-18.4-28.8-28.8-42.4-8-11.2-16.8-21.6-27.2-31.2-3.2-3.2-6.4-5.6-9.6-8-3.2-2.4-6.4-1.6-8 2.4-0.8 1.6-1.6 3.2-1.6 4.8-0.8 4.8-1.6 10.4-1.6 15.2-0.8 10.4 0.8 21.6 1.6 32 0.8 8.8 2.4 17.6 4 27.2 1.6 10.4 4 20.8 6.4 31.2 2.4 9.6 4.8 20 7.2 29.6 3.2 10.4 6.4 20.8 9.6 32 4 12 8 23.2 13.6 34.4 2.4 4 4.8 8.8 7.2 12.8 1.6 3.2 5.6 4.8 9.6 2.4 3.2-2.4 7.2-4.8 10.4-8 10.4-9.6 18.4-20 25.6-32 5.6-8 10.4-16 15.2-24.8 1.6-2.4 3.2-6.4 5.6-11.2z" p-id="2362"></path></svg>
\ No newline at end of file
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1677809829053" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3364" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M873.066667 533.333333h-39.466667c-4.202667 0-8.256 0.576-12.266667 1.237334V433.066667C821.333333 264.853333 682.56 128 512 128S202.666667 264.853333 202.666667 433.066667v101.504A75.434667 75.434667 0 0 0 190.378667 533.333333H150.954667A76.373333 76.373333 0 0 0 74.666667 609.6v210.133333A76.373333 76.373333 0 0 0 150.954667 896h39.445333a76.373333 76.373333 0 0 0 76.288-76.266667V433.066667C266.666667 300.138667 376.725333 192 512 192s245.333333 108.138667 245.333333 241.066667v386.666666A76.352 76.352 0 0 0 833.6 896h39.466667a76.352 76.352 0 0 0 76.266666-76.266667v-210.133333A76.373333 76.373333 0 0 0 873.066667 533.333333zM202.666667 714.666667v105.066666a12.288 12.288 0 0 1-12.288 12.266667H150.954667a12.288 12.288 0 0 1-12.288-12.266667v-210.133333c0-6.762667 5.504-12.266667 12.288-12.266667h39.445333c6.762667 0 12.266667 5.504 12.266667 12.266667V714.666667z m682.666666 105.066666a12.288 12.288 0 0 1-12.266666 12.266667h-39.466667a12.288 12.288 0 0 1-12.266667-12.266667v-210.133333c0-6.762667 5.504-12.266667 12.266667-12.266667h39.466667c6.762667 0 12.266667 5.504 12.266666 12.266667v210.133333z" fill="#232323" p-id="3365"></path><path d="M682.666667 578.666667h-85.333334c-12.394667 0-23.658667 7.168-28.949333 18.368l-9.472 20.138666-52.501333-125.546666c-5.056-12.074667-17.642667-19.477333-30.101334-19.648a32.021333 32.021333 0 0 0-29.376 20.736l-32.362666 85.930666H341.333333a32 32 0 1 0 0 64h95.381334a32 32 0 0 0 29.952-20.736l11.776-31.274666 49.216 117.696c4.885333 11.669333 16.170667 19.349333 28.821333 19.648h0.704a32 32 0 0 0 28.949333-18.368l31.530667-66.965334H682.666667a32 32 0 0 0 0-63.978666z" fill="#232323" p-id="3366"></path></svg>
\ No newline at end of file
<svg width="100" height="969"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" shape-rendering="auto" preserveAspectRatio="none" class="layout-footer-waves">
<g id="Layer_1">
<title>Layer 1</title>
<g transform="rotate(2.18686 -4.09974 506.2)" stroke="null" id="svg_5">
<defs stroke="null" transform="translate(0.00121616 0.0635973) translate(-0.844727 0.185777) translate(-4.69751 0.0674522) translate(4.80739 0.470252) translate(4.47211 0.0666505) translate(-47.1425 4.28569) translate(7.74305 4.90188) translate(-28.5712 -22.857) translate(-0.219291 4.06319) translate(-1.32311 -4.516) translate(22.5706 18.2109) translate(-49.4342 -5.96675) translate(-0.909089 0) translate(0.909089 0) translate(-0.909089 0) translate(-0.909089 0) translate(-0.909089 0) translate(-3.33335 0) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(0 -3.33335) translate(-7.34665 -0.396492) translate(-1.66666 0) translate(-1.66666 0) translate(-0.12551 2.32567) translate(-0.707827 0.218105) translate(-1.66666 0) translate(1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-2.15731 0.0264734) translate(1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(0 -1.66666) translate(0 -1.66666) translate(1.66666 0) translate(0 -1.66666) translate(1.66666 0) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(1.66666 0) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(0 -1.66666) translate(0 -1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(-1.66666 0) translate(0 1.66666) translate(-1.66666 0) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(0 -1.66666) translate(0 -1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(0 -1.66666) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.66666 0) translate(-1.56355 1.02885) translate(-7.50004 -25.0001) translate(-3.19245 0.846904) translate(5.00003 -97.5005) translate(-9.62431 -0.829817) translate(27.5002 -220.001) translate(-6.96615 1.62281) translate(1.10472 -2.23004) translate(-9.63847 0.899196) translate(7.04019 0.0560654) translate(-11.25 -16.25) translate(2.11523 2.02597) translate(-27.1193 -20.3394) translate(-10.8798 -0.397069) translate(-44.0688 -110.172) translate(-1.69495 5.08486) translate(-8.57191 2.416) translate(-67.7982 -69.4931) translate(-0.127168 3.4846) translate(-16.9495 -283.057) translate(-4.64027 -0.169348) translate(1 0) translate(71.5022 0) translate(0 127.337) translate(-78.8263 -168.947) scale(0.564803 0.937256) translate(78.8263 168.947) translate(-139.564 1126.64) scale(1 0.752632) translate(139.564 -1126.64) translate(-139.564 190.036) scale(1 0.902375) translate(139.564 -190.036) translate(-139.564 210.595) scale(1.30003 1) translate(139.564 -210.595) translate(-107.355 1517.49) scale(1 1.16096) translate(107.355 -1517.49) translate(-107.355 0.205247) scale(1 1.13183) translate(107.355 -0.205247) translate(-136.758 -338.436) scale(1.50148 1) translate(136.758 338.436) translate(-152.694 -417.354) scale(1.2612 1.21266) translate(152.694 417.354) translate(-160.148 -445.389) scale(1 1.22519) translate(160.148 445.389) translate(-187.477 -380.211) scale(1.1479 0.963065) translate(187.477 380.211) translate(-169.043 -406.673) scale(0.986706 0.876627) translate(169.043 406.673) translate(-166.85 -463.854) scale(1.08382 1.19196) translate(166.85 463.854) translate(-159.592 918.456) scale(0.859634 1.01716) translate(159.592 -918.456) translate(-184.899 -405.678) scale(1.135 1.11385) translate(184.899 405.678) translate(-150.577 -518.346) scale(0.986699 1.09676) translate(150.577 518.346) translate(-155.421 -535.896) scale(1.04426 1.02871) translate(155.421 535.896) translate(-155.064 -536.049) scale(1.0463 1.01338) translate(155.064 536.049) translate(-165.783 -521.136) scale(1.00568 1.01887) translate(165.783 521.136) translate(-170.657 -511.469) scale(1.01013 1.00598) translate(170.657 511.469) translate(-169.334 -508.298) scale(1.09126 1) translate(169.334 508.298) translate(-156.911 -506.897) scale(1 1.06292) translate(156.911 506.897) translate(-163.644 765.54) scale(0.881707 0.600266) translate(163.644 -765.54) translate(45.8836 -37.1657) scale(0.309 0.684766) translate(-45.8836 37.1657) translate(-69.5385 1277.7) scale(0.415094 0.969376) translate(69.5385 -1277.7) translate(-173.403 4.77105) scale(2.29193 1) translate(173.403 -4.77105) translate(-131.465 -21.955) scale(1.62026 0.838547) translate(131.465 21.955) translate(-128.274 -10.6013) scale(0.965372 1.26492) translate(128.274 10.6013) translate(-127.333 -8.29175) scale(0.874565 1.22473) translate(127.333 8.29175) translate(-138.784 -6.2554) scale(1.00883 0.82026) translate(138.784 6.2554) translate(-144.168 -7.53605) scale(1.05722 1.04501) translate(144.168 7.53605) translate(-137.487 -6.97423) scale(1.01704 0.999876) translate(137.487 6.97423)">
<path stroke="null" id="svg_3" d="m-160,44c30,0 58,-18 88,-18s58,18 88,18s58,-18 88,-18s58,18 88,18l0,44l-352,0l0,-44z"/>
</defs>
<g stroke="null" id="svg_6">
<title stroke="null">Layer 1</title>
<g stroke="null" transform="matrix(-0.0217456 0.782606 -0.765199 -0.0222404 584.591 1129.22)" class="layout-footer-waves-g" id="svg_1">
<use stroke="null" href="#svg_3" x="-328.61098" y="405.36815" fill="rgba(211, 239, 255, 1)" id="svg_4" transform="matrix(3.69628 0 0 3.42743 381.903 -787.25)"/>
<use stroke="null" href="#svg_3" x="-333.61098" y="401.76815" fill="rgba(211, 239, 255, 0.5)" id="svg_2" transform="matrix(3.69628 0 0 3.42743 381.903 -787.25)"/>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="64px" height="64px" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd" xmlns:xlink="http://www.w3.org/1999/xlink">
<g><path style="opacity:0.996" fill="#80bb58" d="M 63.5,35.5 C 63.5,37.8333 63.5,40.1667 63.5,42.5C 62.0168,46.1468 59.3501,48.6468 55.5,50C 43.1211,50.186 30.7877,50.686 18.5,51.5C 9.28752,51.7428 2.95418,47.7428 -0.5,39.5C -0.5,37.5 -0.5,35.5 -0.5,33.5C 1.21619,26.6281 5.71619,22.6281 13,21.5C 20.6091,11.8561 29.7758,10.0227 40.5,16C 44.3698,19.3546 46.7031,23.5212 47.5,28.5C 54.366,27.6047 59.6994,29.9381 63.5,35.5 Z M 25.5,17.5 C 36.8229,16.822 42.8229,22.1553 43.5,33.5C 47.5138,33.3345 51.5138,33.5012 55.5,34C 59.5,37.6667 59.5,41.3333 55.5,45C 44.4272,45.9308 33.4272,45.5975 22.5,44C 12.5525,33.8629 13.5525,25.0296 25.5,17.5 Z"/></g>
<g><path style="opacity:0.991" fill="#86be5f" d="M 39.5,33.5 C 43.0131,34.0282 44.0131,35.8615 42.5,39C 37.2894,39.5464 36.2894,37.713 39.5,33.5 Z"/></g>
</svg>
// base color
$blue: #324157;
$light-blue: #3a71a8;
$red: #c03639;
$pink: #e65d6e;
$green: #30b08f;
$tiffany: #4ab7bd;
$yellow: #fec171;
$panGreen: #30b08f;
// 默认菜单主题风格
$base-menu-color: #bfcbd9;
$base-menu-color-active: #f4f4f5;
$base-menu-background: #304156;
$base-logo-title-color: #ffffff;
$base-menu-light-color: rgba(0, 0, 0, 0.7);
$base-menu-light-background: #ffffff;
$base-logo-light-title-color: #001529;
$base-sub-menu-background: #1f2d3d;
$base-sub-menu-hover: #001528;
// 自定义暗色菜单风格
/**
$base-menu-color:hsla(0,0%,100%,.65);
$base-menu-color-active:#fff;
$base-menu-background:#001529;
$base-logo-title-color: #ffffff;
$base-menu-light-color:rgba(0,0,0,.70);
$base-menu-light-background:#ffffff;
$base-logo-light-title-color: #001529;
$base-sub-menu-background:#000c17;
$base-sub-menu-hover:#001528;
*/
$--color-primary: #409eff;
$--color-success: #67c23a;
$--color-warning: #e6a23c;
$--color-danger: #f56c6c;
$--color-info: #909399;
$base-sidebar-width: 200px;
// the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export {
menuColor: $base-menu-color;
menuLightColor: $base-menu-light-color;
menuColorActive: $base-menu-color-active;
menuBackground: $base-menu-background;
menuLightBackground: $base-menu-light-background;
subMenuBackground: $base-sub-menu-background;
subMenuHover: $base-sub-menu-hover;
sideBarWidth: $base-sidebar-width;
logoTitleColor: $base-logo-title-color;
logoLightTitleColor: $base-logo-light-title-color;
primaryColor: $--color-primary;
successColor: $--color-success;
dangerColor: $--color-danger;
infoColor: $--color-info;
warningColor: $--color-warning;
}
<template>
<div></div>
</template>
<script setup lang="ts" name="check-token">
import { checkToken } from '/@/api/login';
const refreshLock = ref(false);
const refreshTime = ref();
onMounted(() => {
refreshToken();
});
const refreshToken = () => {
refreshTime.value = setInterval(() => {
checkToken(refreshTime.value, refreshLock.value);
}, 60000);
};
</script>
<template>
<el-cascader :options="optionsData" :disabled="disabled" v-model="selectedOptions" @change="handleChange" />
</template>
<script setup lang="ts" name="china-area">
import { provinceAndCityData, provinceAndCityDataPlus, regionData, regionDataPlus } from '/@/utils/chinaArea';
const emit = defineEmits(['update:modelValue', 'change']);
const optionsData = ref();
const props = defineProps({
// 当前的值
modelValue: String,
// 类型 (二级联动,三级联动)
type: {
type: Number,
default: 3,
},
plus: {
type: Boolean,
default: false,
},
// 是否禁用
disabled: {
type: Boolean,
default: () => false,
},
});
const selectedOptions = computed({
get: () => {
return props.modelValue?.split(',');
},
set: (val) => {
emit('update:modelValue', val?.join(','));
},
});
const handleChange = (value: String[]) => {
emit('change', value.join(','));
};
onMounted(() => {
const { plus, type } = props;
if (plus) {
optionsData.value = type === 2 ? provinceAndCityDataPlus : regionDataPlus;
} else {
optionsData.value = type === 2 ? provinceAndCityData : regionData;
}
});
</script>
<!--
* @Descripttion: 代码编辑器
* @version: 1.0
* @Author: sakuya
* @Date: 2022年5月20日21:46:29
* @LastEditors:
* @LastEditTime:
-->
<template>
<div class="code-editor" :style="{ height: _height }">
<textarea ref="textarea" v-model="contentValue"></textarea>
</div>
</template>
<script>
import { markRaw } from 'vue';
//框架
import CodeMirror from 'codemirror';
import 'codemirror/lib/codemirror.css';
//主题
import 'codemirror/theme/idea.css';
import 'codemirror/theme/darcula.css';
//功能
import 'codemirror/addon/selection/active-line';
//语言
import 'codemirror/mode/velocity/velocity';
import 'codemirror/mode/go/go';
export default {
props: {
modelValue: {
type: String,
default: '',
},
mode: {
type: String,
default: 'go',
},
height: {
type: [String, Number],
default: 300,
},
options: {
type: Object,
default: () => {},
},
theme: {
type: String,
default: 'idea',
},
readOnly: {
type: Boolean,
default: false,
},
},
data() {
return {
contentValue: this.modelValue,
coder: null,
opt: {
theme: this.theme, //主题
styleActiveLine: true, //高亮当前行
lineNumbers: true, //行号
lineWrapping: false, //自动换行
tabSize: 4, //Tab缩进
indentUnit: 4, //缩进单位
indentWithTabs: true, //自动缩进
mode: this.mode, //语言
readOnly: this.readOnly, //只读
...this.options,
},
};
},
computed: {
_height() {
return Number(this.height) ? Number(this.height) + 'px' : this.height;
},
},
watch: {
modelValue(val) {
this.contentValue = val;
if (val !== this.coder.getValue()) {
this.coder.setValue(val);
}
},
},
mounted() {
this.init();
//获取挂载的所有modes
//console.log(CodeMirror.modes)
},
methods: {
init() {
this.coder = markRaw(CodeMirror.fromTextArea(this.$refs.textarea, this.opt));
this.coder.on('change', (coder) => {
this.contentValue = coder.getValue();
this.$emit('update:modelValue', this.contentValue);
});
},
formatStrInJson(strValue) {
return JSON.stringify(JSON.parse(strValue), null, 4);
},
},
};
</script>
<style scoped>
.code-editor {
font-size: 14px;
border: 1px solid #ddd;
line-height: 150%;
}
.code-editor:deep(.CodeMirror) {
height: 100%;
}
</style>
<template>
<div class="color-picker flex flex-1">
<el-color-picker v-model="color" :predefine="predefineColors" />
<el-input v-model="color" class="mx-[10px] flex-1" type="text" readonly />
<el-button type="text" @click="reset">重置</el-button>
</div>
</template>
<script lang="ts" setup>
const props = defineProps({
modelValue: {
type: String,
},
defaultColor: {
type: String,
},
});
const emit = defineEmits<{
(event: 'update:modelValue', value: any): void;
}>();
const color = computed({
get() {
return props.modelValue;
},
set(value) {
emit('update:modelValue', value);
},
});
const predefineColors = ['#409EFF', '#28C76F', '#EA5455', '#FF9F43', '#01CFE8', '#4A5DFF'];
const reset = () => {
color.value = props.defaultColor;
};
</script>
This diff is collapsed.
<template>
<div class="del-wrap">
<slot></slot>
<div v-if="showClose" class="icon-close" @click.stop="handleClose">
<el-icon><CloseBold /></el-icon>
</div>
</div>
</template>
<script lang="ts">
export default defineComponent({
props: {
showClose: {
type: Boolean,
default: true,
},
},
emits: ['close'],
setup(props, { emit }) {
const handleClose = () => {
emit('close');
};
return {
handleClose,
};
},
});
</script>
<style scoped lang="scss">
.del-wrap {
position: relative;
&:hover > .icon-close {
display: flex;
}
.icon-close {
display: none;
position: absolute;
top: -8px;
right: -8px;
width: 16px;
height: 16px;
background-color: rgba(0, 0, 0, 0.3);
justify-content: center;
align-items: center;
border-radius: 50%;
color: #fff;
cursor: pointer;
}
}
</style>
<template>
<div>
<template v-for="(item, index) in props.options">
<template v-if="values.includes(item.value || item)">
<span v-if="item.elTagType == 'default' || item.elTagType == ''" :key="index" :index="index" :class="item.elTagClass">{{
item.label || item
}}</span>
<el-tag
v-else
:disable-transitions="true"
:key="index * 2"
:index="index"
:type="item.elTagType === 'primary' ? '' : item.elTagType"
:class="item.elTagClass"
>{{ item.label || item }}</el-tag
>
</template>
</template>
</div>
</template>
<script setup lang="ts" name="dict-tag">
import { computed } from 'vue';
const props = defineProps({
// 数据
options: {
type: Array as any,
default: null,
},
// 当前的值
value: [Number, String, Array],
});
const values = computed(() => {
if (props.value !== null && typeof props.value !== 'undefined') {
return Array.isArray(props.value) ? props.value : [String(props.value)];
} else {
return [];
}
});
</script>
<style scoped>
.el-tag + .el-tag {
margin-left: 10px;
}
</style>
<template>
<div class="flex flex-col border border-br" :style="styles">
<Toolbar class="border-b border-br" :editor="editorRef" :mode="mode" />
<Editor
class="flex-1 overflow-y-auto"
:mode="mode"
:defaultConfig="state.editorConfig"
v-model="state.editorVal"
@onCreated="handleCreated"
@onChange="handleChange"
/>
</div>
</template>
<script setup lang="ts" name="wngEditor">
import '@wangeditor-next/editor/dist/css/style.css';
import { reactive, shallowRef, watch, onBeforeUnmount, CSSProperties } from 'vue';
// @ts-ignore
import { IDomEditor } from '@wangeditor-next/editor';
import { Toolbar, Editor } from '@wangeditor-next/editor-for-vue';
import { Session } from '/@/utils/storage';
import other from '/@/utils/other';
const { proxy } = getCurrentInstance();
// 定义父组件传过来的值
const props = defineProps({
// 是否禁用
disable: {
type: Boolean,
default: () => false,
},
// 内容框默认 placeholder
placeholder: {
type: String,
default: () => '请输入内容...',
},
// https://www.wangeditor.com/v5/getting-started.html#mode-%E6%A8%A1%E5%BC%8F
// 模式,可选 <default|simple>,默认 default
mode: {
type: String,
default: () => 'default',
},
// 高度
height: {
type: String,
default: () => '310',
},
// 宽度
width: {
type: String,
default: () => 'auto',
},
// 双向绑定,用于获取 editor.getHtml()
getHtml: String,
// 双向绑定,用于获取 editor.getText()
getText: String,
uploadFileUrl: {
type: String,
default: `/admin/sys-file/upload`,
},
});
// 定义子组件向父组件传值/事件
const emit = defineEmits(['update:getHtml', 'update:getText']);
// 定义上传需要的请求头信息
const headers = computed(() => {
return {
Authorization: 'Bearer ' + Session.get('token'),
'TENANT-ID': Session.getTenant(),
};
});
// 定义上传需要的字段信息
const uploadAttr = reactive({
fieldName: 'file',
server: proxy.baseURL + props.uploadFileUrl,
headers: headers,
customInsert(res, insertFn) {
insertFn(proxy.baseURL + res.data.url);
},
});
const editorRef = shallowRef();
const state = reactive({
editorConfig: {
placeholder: props.placeholder,
MENU_CONF: {
uploadImage: uploadAttr,
uploadVideo: uploadAttr,
},
},
editorVal: props.getHtml,
});
const styles = computed<CSSProperties>(() => ({
height: other.addUnit(props.height),
width: other.addUnit(props.width),
}));
// 编辑器回调函数
const handleCreated = (editor: IDomEditor) => {
editorRef.value = editor;
};
// 编辑器内容改变时
const handleChange = (editor: IDomEditor) => {
emit('update:getHtml', editor.getHtml());
emit('update:getText', editor.getText());
};
// 页面销毁时
onBeforeUnmount(() => {
const editor = editorRef.value;
if (editor == null) return;
editor.destroy();
});
// 监听是否禁用改变
watch(
() => props.disable,
(bool) => {
const editor = editorRef.value;
if (editor == null) return;
bool ? editor.disable() : editor.enable();
},
{
deep: true,
}
);
// 监听双向绑定值改变,用于回显
watch(
() => props.getHtml,
(val) => {
state.editorVal = val;
},
{
deep: true,
}
);
</script>
<template>
<div class="form-table" ref="scFormTable">
<el-table
:data="data"
ref="table"
border
stripe
:cell-style="{ textAlign: 'center' }"
:header-cell-style="{
textAlign: 'center',
background: 'var(--el-table-row-hover-bg-color)',
color: 'var(--el-text-color-primary)',
}"
>
<el-table-column type="index" width="50" fixed="left">
<template #header>
<el-button v-if="!hideAdd" type="primary" icon="el-icon-plus" size="small" circle @click="rowAdd"></el-button>
<el-tooltip v-else content="序号" placement="top"> # </el-tooltip>
</template>
<template #default="scope">
<div :class="['form-table-handle', { 'form-table-handle-delete': !hideDelete }]">
<span>{{ scope.$index + 1 }}</span>
<el-button
v-if="!hideDelete"
type="danger"
icon="el-icon-delete"
size="small"
plain
circle
@click="rowDel(scope.row, scope.$index)"
></el-button>
</div>
</template>
</el-table-column>
<el-table-column label="" width="50" v-if="dragSort">
<template #header>
<el-icon>
<el-tooltip content="拖动排序" placement="top">
<WarningFilled />
</el-tooltip>
</el-icon>
</template>
<template #default>
<div class="move" style="cursor: move">
<el-icon>
<Sort />
</el-icon>
</div>
</template>
</el-table-column>
<slot></slot>
<template #empty>
{{ placeholder }}
</template>
</el-table>
</div>
</template>
<script>
import Sortable from 'sortablejs';
export default {
props: {
/**
* 表格数据
*/
modelValue: { type: Array, default: () => [] },
/**
* 新增行模板
*/
addTemplate: { type: Object, default: () => {} },
/**
* 无数据时的提示语
*/
placeholder: { type: String, default: '暂无数据' },
/**
* 是否启用拖拽排序
*/
dragSort: { type: Boolean, default: false },
/**
* 是否隐藏新增按钮
*/
hideAdd: { type: Boolean, default: false },
/**
* 是否隐藏删除按钮
*/
hideDelete: { type: Boolean, default: false },
},
data() {
return {
/**
* 表格数据
*/
data: [],
};
},
mounted() {
this.data = this.modelValue;
if (this.dragSort) {
this.rowDrop();
}
},
watch: {
modelValue() {
this.data = this.modelValue;
},
data: {
handler() {
/**
* 更新表格数据
* @event update:modelValue
* @type {Array}
*/
this.$emit('update:modelValue', this.data);
},
deep: true,
},
},
methods: {
/**
* 启用表格行拖拽排序
*/
rowDrop() {
const _this = this;
const tbody = this.$refs.table.$el.querySelector('.el-table__body-wrapper tbody');
Sortable.create(tbody, {
handle: '.move',
animation: 300,
ghostClass: 'ghost',
onEnd({ newIndex, oldIndex }) {
_this.data.splice(newIndex, 0, _this.data.splice(oldIndex, 1)[0]);
const newArray = _this.data.slice(0);
const tmpHeight = _this.$refs.scFormTable.offsetHeight;
_this.$refs.scFormTable.style.setProperty('height', tmpHeight + 'px');
_this.data = [];
_this.$nextTick(() => {
_this.data = newArray;
_this.$nextTick(() => {
_this.$refs.scFormTable.style.removeProperty('height');
});
});
},
});
},
/**
* 新增一行
*/
rowAdd() {
const temp = JSON.parse(JSON.stringify(this.addTemplate));
this.data.push(temp);
},
/**
* 删除一行
* @param {Object} row - 要删除的行数据
* @param {number} index - 要删除的行的索引
*/
rowDel(row, index) {
this.data.splice(index, 1);
this.$emit('delete', row);
},
/**
* 插入一行
* @param {Object} row - 要插入的行数据,默认为新增行模板
*/
pushRow(row) {
const temp = row || JSON.parse(JSON.stringify(this.addTemplate));
this.data.push(temp);
},
/**
* 根据索引删除一行
* @param {number} index - 要删除的行的索引
*/
deleteRow(index) {
this.data.splice(index, 1);
},
},
};
</script>
<style scoped>
.form-table {
width: 100%;
}
.form-table .form-table-handle {
text-align: center;
}
.form-table .form-table-handle span {
display: inline-block;
}
.form-table .form-table-handle button {
display: none;
}
.form-table .hover-row .form-table-handle-delete span {
display: none;
}
.form-table .hover-row .form-table-handle-delete button {
display: inline-block;
}
.form-table .move {
text-align: center;
font-size: 14px;
margin-top: 3px;
}
</style>
import { readFileSync, readdirSync } from 'fs';
let idPerfix = '';
const iconNames: string[] = [];
const svgTitle = /<svg([^>+].*?)>/;
const clearHeightWidth = /(width|height)="([^>+].*?)"/g;
const hasViewBox = /(viewBox="[^>+].*?")/g;
const clearReturn = /(\r)|(\n)/g;
// 清理 svg 的 fill
const clearFill = /(fill="[^>+].*?")/g;
function findSvgFile(dir: string): string[] {
const svgRes = [] as any;
const dirents = readdirSync(dir, {
withFileTypes: true,
});
for (const dirent of dirents) {
iconNames.push(`${idPerfix}-${dirent.name.replace('.svg', '')}`);
if (dirent.isDirectory()) {
svgRes.push(...findSvgFile(dir + dirent.name + '/'));
} else {
const svg = readFileSync(dir + dirent.name)
.toString()
.replace(clearReturn, '')
.replace(clearFill, 'fill=""')
.replace(svgTitle, ($1, $2) => {
let width = 0;
let height = 0;
let content = $2.replace(clearHeightWidth, (s1: string, s2: string, s3: number) => {
if (s2 === 'width') {
width = s3;
} else if (s2 === 'height') {
height = s3;
}
return '';
});
if (!hasViewBox.test($2)) {
content += `viewBox="0 0 ${width} ${height}"`;
}
return `<symbol id="${idPerfix}-${dirent.name.replace('.svg', '')}" ${content}>`;
})
.replace('</svg>', '</symbol>');
svgRes.push(svg);
}
}
return svgRes;
}
export const svgBuilder = (path: string, perfix = 'local') => {
if (path === '') return;
idPerfix = perfix;
const res = findSvgFile(path);
return {
name: 'svg-transform',
transformIndexHtml(html: string) {
/* eslint-disable */
return html.replace(
'<body>',
`
<body>
<svg id="local-icon" data-icon-name="${iconNames.join(
','
)}" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute; width: 0; height: 0">
${res.join('')}
</svg>
`
);
/* eslint-enable */
},
};
};
<template>
<div class="icon-selector w100 h100">
<el-input
v-model="state.fontIconSearch"
:placeholder="state.fontIconPlaceholder"
:clearable="clearable"
:disabled="disabled"
:size="size"
ref="inputWidthRef"
@clear="onClearFontIcon"
@focus="onIconFocus"
@blur="onIconBlur"
>
<template #prepend>
<SvgIcon :name="state.fontIconPrefix === '' ? prepend : state.fontIconPrefix" class="font14" />
</template>
</el-input>
<el-popover
placement="bottom"
:width="state.fontIconWidth"
transition="el-zoom-in-top"
popper-class="icon-selector-popper"
trigger="click"
:virtual-ref="inputWidthRef"
virtual-triggering
>
<template #default>
<div class="icon-selector-warp">
<div class="icon-selector-warp-title">{{ title }}</div>
<el-tabs v-model="state.fontIconTabActive" @tab-click="onIconClick">
<el-tab-pane lazy label="ali" name="ali">
<IconList :list="fontIconSheetsFilterList" :empty="emptyDescription" :prefix="state.fontIconPrefix" @get-icon="onColClick" />
</el-tab-pane>
<el-tab-pane lazy label="ele" name="ele">
<IconList :list="fontIconSheetsFilterList" :empty="emptyDescription" :prefix="state.fontIconPrefix" @get-icon="onColClick" />
</el-tab-pane>
<el-tab-pane lazy label="awe" name="awe">
<IconList :list="fontIconSheetsFilterList" :empty="emptyDescription" :prefix="state.fontIconPrefix" @get-icon="onColClick" />
</el-tab-pane>
<el-tab-pane lazy label="local" name="local">
<IconList :list="fontIconSheetsFilterList" :empty="emptyDescription" :prefix="state.fontIconPrefix" @get-icon="onColClick" />
</el-tab-pane>
</el-tabs>
</div>
</template>
</el-popover>
</div>
</template>
<script setup lang="ts" name="iconSelector">
import { defineAsyncComponent, ref, reactive, onMounted, nextTick, computed, watch } from 'vue';
import type { TabsPaneContext } from 'element-plus';
import initIconfont from '/@/utils/getStyleSheets';
import '/@/theme/iconSelector.scss';
// 定义父组件传过来的值
const props = defineProps({
// 输入框前置内容
prepend: {
type: String,
default: () => 'ele-Pointer',
},
// 输入框占位文本
placeholder: {
type: String,
default: () => '请输入内容搜索图标或者选择图标',
},
// 输入框占位文本
size: {
type: String,
default: () => 'default',
},
// 弹窗标题
title: {
type: String,
default: () => '请选择图标',
},
// 禁用
disabled: {
type: Boolean,
default: () => false,
},
// 是否可清空
clearable: {
type: Boolean,
default: () => true,
},
// 自定义空状态描述文字
emptyDescription: {
type: String,
default: () => '无相关图标',
},
// 双向绑定值,默认为 modelValue,
// 参考:https://v3.cn.vuejs.org/guide/migration/v-model.html#%E8%BF%81%E7%A7%BB%E7%AD%96%E7%95%A5
// 参考:https://v3.cn.vuejs.org/guide/component-custom-events.html#%E5%A4%9A%E4%B8%AA-v-model-%E7%BB%91%E5%AE%9A
modelValue: String,
});
// 定义子组件向父组件传值/事件
const emit = defineEmits(['update:modelValue', 'get', 'clear']);
// 引入组件
const IconList = defineAsyncComponent(() => import('/@/components/IconSelector/list.vue'));
// 定义变量内容
const inputWidthRef = ref();
const state = reactive({
fontIconPrefix: '',
fontIconWidth: 0,
fontIconSearch: '',
fontIconPlaceholder: '',
fontIconTabActive: 'ali',
fontIconList: {
ali: [],
ele: [],
awe: [],
local: [],
},
});
// 处理 input 获取焦点时,modelValue 有值时,改变 input 的 placeholder 值
const onIconFocus = () => {
if (!props.modelValue) return false;
state.fontIconSearch = '';
state.fontIconPlaceholder = props.modelValue;
};
// 处理 input 失去焦点时,为空将清空 input 值,为点击选中图标时,将取原先值
const onIconBlur = () => {
const list = fontIconTabNameList();
setTimeout(() => {
const icon = list.filter((icon: string) => icon === state.fontIconSearch);
if (icon.length <= 0) state.fontIconSearch = '';
}, 300);
};
// 图标搜索及图标数据显示
const fontIconSheetsFilterList = computed(() => {
const list = fontIconTabNameList();
if (!state.fontIconSearch) return list;
let search = state.fontIconSearch.trim().toLowerCase();
return list.filter((item: string) => {
if (item.toLowerCase().indexOf(search) !== -1) return item;
});
});
// 根据 tab name 类型设置图标
const fontIconTabNameList = () => {
let iconList: any = [];
if (state.fontIconTabActive === 'ali') iconList = state.fontIconList.ali;
else if (state.fontIconTabActive === 'ele') iconList = state.fontIconList.ele;
else if (state.fontIconTabActive === 'awe') iconList = state.fontIconList.awe;
else if (state.fontIconTabActive === 'local') iconList = state.fontIconList.local;
return iconList;
};
// 处理 icon 双向绑定数值回显
const initModeValueEcho = () => {
if (props.modelValue === '') return ((<string | undefined>state.fontIconPlaceholder) = props.placeholder);
(<string | undefined>state.fontIconPlaceholder) = props.modelValue;
(<string | undefined>state.fontIconPrefix) = props.modelValue;
};
// 处理 icon 类型,用于回显时,tab 高亮与初始化数据
const initFontIconName = () => {
let name = 'ali';
if (!props.modelValue) {
return name;
}
if (props.modelValue!.indexOf('iconfont') > -1) name = 'ali';
else if (props.modelValue!.indexOf('ele-') > -1) name = 'ele';
else if (props.modelValue!.indexOf('fa') > -1) name = 'awe';
else if (props.modelValue!.indexOf('local') > -1) name = 'local';
// 初始化 tab 高亮回显
state.fontIconTabActive = name;
return name;
};
// 初始化数据
const initFontIconData = async (name: string) => {
if (name === 'ali') {
// 阿里字体图标使用 `iconfont xxx`
if (state.fontIconList.ali.length > 0) return;
await initIconfont.ali().then((res: any) => {
state.fontIconList.ali = res.map((i: string) => `iconfont ${i}`);
});
} else if (name === 'ele') {
// element plus 图标
if (state.fontIconList.ele.length > 0) return;
await initIconfont.ele().then((res: any) => {
state.fontIconList.ele = res;
});
} else if (name === 'awe') {
// fontawesome字体图标使用 `fa xxx`
if (state.fontIconList.awe.length > 0) return;
await initIconfont.awe().then((res: any) => {
state.fontIconList.awe = res.map((i: string) => `fa ${i}`);
});
} else if (name === 'local') {
if (state.fontIconList.local.length > 0) return;
await initIconfont.local().then((res: any) => {
state.fontIconList.local = res.map((i: string) => `${i}`);
});
}
// 初始化 input 的 placeholder
// 参考(单项数据流):https://cn.vuejs.org/v2/guide/components-props.html?#%E5%8D%95%E5%90%91%E6%95%B0%E6%8D%AE%E6%B5%81
state.fontIconPlaceholder = props.placeholder;
// 初始化双向绑定回显
initModeValueEcho();
};
// 图标点击切换
const onIconClick = (pane: TabsPaneContext) => {
initFontIconData(pane.paneName as string);
inputWidthRef.value.focus();
};
// 获取当前点击的 icon 图标
const onColClick = (v: string) => {
state.fontIconPlaceholder = v;
state.fontIconPrefix = v;
emit('get', state.fontIconPrefix);
emit('update:modelValue', state.fontIconPrefix);
inputWidthRef.value.focus();
};
// 清空当前点击的 icon 图标
const onClearFontIcon = () => {
state.fontIconPrefix = '';
emit('clear', state.fontIconPrefix);
emit('update:modelValue', state.fontIconPrefix);
};
// 获取 input 的宽度
const getInputWidth = () => {
nextTick(() => {
state.fontIconWidth = inputWidthRef.value.$el.offsetWidth;
});
};
// 监听页面宽度改变
const initResize = () => {
window.addEventListener('resize', () => {
getInputWidth();
});
};
// 页面加载时
onMounted(() => {
initFontIconData(initFontIconName());
initResize();
getInputWidth();
});
// 监听双向绑定 modelValue 的变化
watch(
() => props.modelValue,
() => {
initModeValueEcho();
initFontIconName();
}
);
</script>
<template>
<div class="icon-selector-warp-row">
<el-scrollbar ref="selectorScrollbarRef">
<el-row :gutter="10" v-if="props.list.length > 0">
<el-col :xs="6" :sm="4" :md="4" :lg="4" :xl="4" v-for="(v, k) in list" :key="k" @click="onColClick(v)">
<div class="icon-selector-warp-item" :class="{ 'icon-selector-active': prefix === v }">
<SvgIcon :name="v" />
</div>
</el-col>
</el-row>
<el-empty :image-size="100" v-if="list.length <= 0" :description="empty"></el-empty>
</el-scrollbar>
</div>
</template>
<script setup lang="ts" name="iconSelectorList">
// 定义父组件传过来的值
const props = defineProps({
// 图标列表数据
list: {
type: Array,
default: () => [],
},
// 自定义空状态描述文字
empty: {
type: String,
default: () => '无相关图标',
},
// 高亮当前选中图标
prefix: {
type: String,
default: () => '',
},
});
// 定义子组件向父组件传值/事件
const emit = defineEmits(['get-icon']);
// 当前 icon 图标点击时
const onColClick = (v: unknown | string) => {
emit('get-icon', v);
};
</script>
<style scoped lang="scss">
.icon-selector-warp-row {
height: 230px;
overflow: hidden;
.el-row {
padding: 15px;
}
.el-scrollbar__bar.is-horizontal {
display: none;
}
.icon-selector-warp-item {
display: flex;
justify-content: center;
align-items: center;
border: 1px solid var(--el-border-color);
border-radius: 5px;
margin-bottom: 10px;
height: 30px;
i {
font-size: 20px;
color: var(--el-text-color-regular);
}
&:hover {
cursor: pointer;
background-color: var(--el-color-primary-light-9);
border: 1px solid var(--el-color-primary-light-5);
i {
color: var(--el-color-primary);
}
}
}
.icon-selector-active {
background-color: var(--el-color-primary-light-9);
border: 1px solid var(--el-color-primary-light-5);
i {
color: var(--el-color-primary);
}
}
}
</style>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<template>
<el-pagination
@size-change="sizeChangeHandle"
@current-change="currentChangeHandle"
class="mt15"
:pager-count="5"
:page-sizes="props.pageSizes"
:current-page="props.current"
background
:page-size="props.size"
:layout="props.layout"
:total="props.total"
>
</el-pagination>
</template>
<script setup lang="ts" name="pagination">
const emit = defineEmits(['sizeChange', 'currentChange']);
const props = defineProps({
current: {
type: Number,
default: 1,
},
size: {
type: Number,
default: 10,
},
total: {
type: Number,
default: 0,
},
pageSizes: {
type: Array as () => number[],
default: () => {
return [1, 10, 20, 50, 100, 200];
},
},
layout: {
type: String,
default: 'total, sizes, prev, pager, next, jumper',
},
});
// 分页改变
const sizeChangeHandle = (val: number) => {
emit('sizeChange', val);
};
// 分页改变
const currentChangeHandle = (val: number) => {
emit('currentChange', val);
};
</script>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment