增加配置格式化
parent
921c38cea2
commit
1613c0012b
|
|
@ -0,0 +1,15 @@
|
||||||
|
# http://editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
# 表示所有文件适用
|
||||||
|
[*]
|
||||||
|
charset = utf-8 # 设置文件字符集为 utf-8
|
||||||
|
end_of_line = lf # 控制换行类型(lf | cr | crlf)
|
||||||
|
indent_style = space # 缩进风格(tab | space)
|
||||||
|
indent_size = 2 # 缩进大小
|
||||||
|
insert_final_newline = true # 始终在文件末尾插入一个新行
|
||||||
|
|
||||||
|
# 表示仅 md 文件适用以下规则
|
||||||
|
[*.md]
|
||||||
|
max_line_length = off # 关闭最大行长度限制
|
||||||
|
trim_trailing_whitespace = false # 关闭末尾空格修剪
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
## 开发环境
|
||||||
|
NODE_ENV='development'
|
||||||
|
|
||||||
|
# 应用端口
|
||||||
|
VITE_APP_PORT = 3000
|
||||||
|
|
||||||
|
# 代理前缀
|
||||||
|
VITE_APP_BASE_API = '/dev-api'
|
||||||
|
|
||||||
|
# 线上接口地址
|
||||||
|
VITE_APP_API_URL = http://vapi.youlai.tech
|
||||||
|
# 开发接口地址
|
||||||
|
# VITE_APP_API_URL = http://localhost:8989
|
||||||
|
|
||||||
|
# 是否启用 Mock 服务
|
||||||
|
VITE_MOCK_DEV_SERVER = false
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
## 生产环境
|
||||||
|
NODE_ENV='production'
|
||||||
|
|
||||||
|
# 代理前缀
|
||||||
|
VITE_APP_BASE_API = '/prod-api'
|
||||||
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
dist
|
||||||
|
node_modules
|
||||||
|
public
|
||||||
|
.husky
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
*.sh
|
||||||
|
*.md
|
||||||
|
|
||||||
|
src/assets
|
||||||
|
|
||||||
|
.eslintrc.cjs
|
||||||
|
.prettierrc.cjs
|
||||||
|
.stylelintrc.cjs
|
||||||
|
|
@ -0,0 +1,284 @@
|
||||||
|
{
|
||||||
|
"globals": {
|
||||||
|
"Component": true,
|
||||||
|
"ComponentPublicInstance": true,
|
||||||
|
"ComputedRef": true,
|
||||||
|
"EffectScope": true,
|
||||||
|
"ElMessage": true,
|
||||||
|
"ElMessageBox": true,
|
||||||
|
"ElNotification": true,
|
||||||
|
"InjectionKey": true,
|
||||||
|
"PropType": true,
|
||||||
|
"Ref": true,
|
||||||
|
"VNode": true,
|
||||||
|
"asyncComputed": true,
|
||||||
|
"autoResetRef": true,
|
||||||
|
"computed": true,
|
||||||
|
"computedAsync": true,
|
||||||
|
"computedEager": true,
|
||||||
|
"computedInject": true,
|
||||||
|
"computedWithControl": true,
|
||||||
|
"controlledComputed": true,
|
||||||
|
"controlledRef": true,
|
||||||
|
"createApp": true,
|
||||||
|
"createEventHook": true,
|
||||||
|
"createGlobalState": true,
|
||||||
|
"createInjectionState": true,
|
||||||
|
"createReactiveFn": true,
|
||||||
|
"createReusableTemplate": true,
|
||||||
|
"createSharedComposable": true,
|
||||||
|
"createTemplatePromise": true,
|
||||||
|
"createUnrefFn": true,
|
||||||
|
"customRef": true,
|
||||||
|
"debouncedRef": true,
|
||||||
|
"debouncedWatch": true,
|
||||||
|
"defineAsyncComponent": true,
|
||||||
|
"defineComponent": true,
|
||||||
|
"eagerComputed": true,
|
||||||
|
"effectScope": true,
|
||||||
|
"extendRef": true,
|
||||||
|
"getCurrentInstance": true,
|
||||||
|
"getCurrentScope": true,
|
||||||
|
"h": true,
|
||||||
|
"ignorableWatch": true,
|
||||||
|
"inject": true,
|
||||||
|
"isDefined": true,
|
||||||
|
"isProxy": true,
|
||||||
|
"isReactive": true,
|
||||||
|
"isReadonly": true,
|
||||||
|
"isRef": true,
|
||||||
|
"makeDestructurable": true,
|
||||||
|
"markRaw": true,
|
||||||
|
"nextTick": true,
|
||||||
|
"onActivated": true,
|
||||||
|
"onBeforeMount": true,
|
||||||
|
"onBeforeUnmount": true,
|
||||||
|
"onBeforeUpdate": true,
|
||||||
|
"onClickOutside": true,
|
||||||
|
"onDeactivated": true,
|
||||||
|
"onErrorCaptured": true,
|
||||||
|
"onKeyStroke": true,
|
||||||
|
"onLongPress": true,
|
||||||
|
"onMounted": true,
|
||||||
|
"onRenderTracked": true,
|
||||||
|
"onRenderTriggered": true,
|
||||||
|
"onScopeDispose": true,
|
||||||
|
"onServerPrefetch": true,
|
||||||
|
"onStartTyping": true,
|
||||||
|
"onUnmounted": true,
|
||||||
|
"onUpdated": true,
|
||||||
|
"pausableWatch": true,
|
||||||
|
"provide": true,
|
||||||
|
"reactify": true,
|
||||||
|
"reactifyObject": true,
|
||||||
|
"reactive": true,
|
||||||
|
"reactiveComputed": true,
|
||||||
|
"reactiveOmit": true,
|
||||||
|
"reactivePick": true,
|
||||||
|
"readonly": true,
|
||||||
|
"ref": true,
|
||||||
|
"refAutoReset": true,
|
||||||
|
"refDebounced": true,
|
||||||
|
"refDefault": true,
|
||||||
|
"refThrottled": true,
|
||||||
|
"refWithControl": true,
|
||||||
|
"resolveComponent": true,
|
||||||
|
"resolveRef": true,
|
||||||
|
"resolveUnref": true,
|
||||||
|
"shallowReactive": true,
|
||||||
|
"shallowReadonly": true,
|
||||||
|
"shallowRef": true,
|
||||||
|
"syncRef": true,
|
||||||
|
"syncRefs": true,
|
||||||
|
"templateRef": true,
|
||||||
|
"throttledRef": true,
|
||||||
|
"throttledWatch": true,
|
||||||
|
"toRaw": true,
|
||||||
|
"toReactive": true,
|
||||||
|
"toRef": true,
|
||||||
|
"toRefs": true,
|
||||||
|
"toValue": true,
|
||||||
|
"triggerRef": true,
|
||||||
|
"tryOnBeforeMount": true,
|
||||||
|
"tryOnBeforeUnmount": true,
|
||||||
|
"tryOnMounted": true,
|
||||||
|
"tryOnScopeDispose": true,
|
||||||
|
"tryOnUnmounted": true,
|
||||||
|
"unref": true,
|
||||||
|
"unrefElement": true,
|
||||||
|
"until": true,
|
||||||
|
"useActiveElement": true,
|
||||||
|
"useAnimate": true,
|
||||||
|
"useArrayDifference": true,
|
||||||
|
"useArrayEvery": true,
|
||||||
|
"useArrayFilter": true,
|
||||||
|
"useArrayFind": true,
|
||||||
|
"useArrayFindIndex": true,
|
||||||
|
"useArrayFindLast": true,
|
||||||
|
"useArrayIncludes": true,
|
||||||
|
"useArrayJoin": true,
|
||||||
|
"useArrayMap": true,
|
||||||
|
"useArrayReduce": true,
|
||||||
|
"useArraySome": true,
|
||||||
|
"useArrayUnique": true,
|
||||||
|
"useAsyncQueue": true,
|
||||||
|
"useAsyncState": true,
|
||||||
|
"useAttrs": true,
|
||||||
|
"useBase64": true,
|
||||||
|
"useBattery": true,
|
||||||
|
"useBluetooth": true,
|
||||||
|
"useBreakpoints": true,
|
||||||
|
"useBroadcastChannel": true,
|
||||||
|
"useBrowserLocation": true,
|
||||||
|
"useCached": true,
|
||||||
|
"useClipboard": true,
|
||||||
|
"useCloned": true,
|
||||||
|
"useColorMode": true,
|
||||||
|
"useConfirmDialog": true,
|
||||||
|
"useCounter": true,
|
||||||
|
"useCssModule": true,
|
||||||
|
"useCssVar": true,
|
||||||
|
"useCssVars": true,
|
||||||
|
"useCurrentElement": true,
|
||||||
|
"useCycleList": true,
|
||||||
|
"useDark": true,
|
||||||
|
"useDateFormat": true,
|
||||||
|
"useDebounce": true,
|
||||||
|
"useDebounceFn": true,
|
||||||
|
"useDebouncedRefHistory": true,
|
||||||
|
"useDeviceMotion": true,
|
||||||
|
"useDeviceOrientation": true,
|
||||||
|
"useDevicePixelRatio": true,
|
||||||
|
"useDevicesList": true,
|
||||||
|
"useDisplayMedia": true,
|
||||||
|
"useDocumentVisibility": true,
|
||||||
|
"useDraggable": true,
|
||||||
|
"useDropZone": true,
|
||||||
|
"useElementBounding": true,
|
||||||
|
"useElementByPoint": true,
|
||||||
|
"useElementHover": true,
|
||||||
|
"useElementSize": true,
|
||||||
|
"useElementVisibility": true,
|
||||||
|
"useEventBus": true,
|
||||||
|
"useEventListener": true,
|
||||||
|
"useEventSource": true,
|
||||||
|
"useEyeDropper": true,
|
||||||
|
"useFavicon": true,
|
||||||
|
"useFetch": true,
|
||||||
|
"useFileDialog": true,
|
||||||
|
"useFileSystemAccess": true,
|
||||||
|
"useFocus": true,
|
||||||
|
"useFocusWithin": true,
|
||||||
|
"useFps": true,
|
||||||
|
"useFullscreen": true,
|
||||||
|
"useGamepad": true,
|
||||||
|
"useGeolocation": true,
|
||||||
|
"useIdle": true,
|
||||||
|
"useImage": true,
|
||||||
|
"useInfiniteScroll": true,
|
||||||
|
"useIntersectionObserver": true,
|
||||||
|
"useInterval": true,
|
||||||
|
"useIntervalFn": true,
|
||||||
|
"useKeyModifier": true,
|
||||||
|
"useLastChanged": true,
|
||||||
|
"useLocalStorage": true,
|
||||||
|
"useMagicKeys": true,
|
||||||
|
"useManualRefHistory": true,
|
||||||
|
"useMediaControls": true,
|
||||||
|
"useMediaQuery": true,
|
||||||
|
"useMemoize": true,
|
||||||
|
"useMemory": true,
|
||||||
|
"useMounted": true,
|
||||||
|
"useMouse": true,
|
||||||
|
"useMouseInElement": true,
|
||||||
|
"useMousePressed": true,
|
||||||
|
"useMutationObserver": true,
|
||||||
|
"useNavigatorLanguage": true,
|
||||||
|
"useNetwork": true,
|
||||||
|
"useNow": true,
|
||||||
|
"useObjectUrl": true,
|
||||||
|
"useOffsetPagination": true,
|
||||||
|
"useOnline": true,
|
||||||
|
"usePageLeave": true,
|
||||||
|
"useParallax": true,
|
||||||
|
"useParentElement": true,
|
||||||
|
"usePerformanceObserver": true,
|
||||||
|
"usePermission": true,
|
||||||
|
"usePointer": true,
|
||||||
|
"usePointerLock": true,
|
||||||
|
"usePointerSwipe": true,
|
||||||
|
"usePreferredColorScheme": true,
|
||||||
|
"usePreferredContrast": true,
|
||||||
|
"usePreferredDark": true,
|
||||||
|
"usePreferredLanguages": true,
|
||||||
|
"usePreferredReducedMotion": true,
|
||||||
|
"usePrevious": true,
|
||||||
|
"useRafFn": true,
|
||||||
|
"useRefHistory": true,
|
||||||
|
"useResizeObserver": true,
|
||||||
|
"useScreenOrientation": true,
|
||||||
|
"useScreenSafeArea": true,
|
||||||
|
"useScriptTag": true,
|
||||||
|
"useScroll": true,
|
||||||
|
"useScrollLock": true,
|
||||||
|
"useSessionStorage": true,
|
||||||
|
"useShare": true,
|
||||||
|
"useSlots": true,
|
||||||
|
"useSorted": true,
|
||||||
|
"useSpeechRecognition": true,
|
||||||
|
"useSpeechSynthesis": true,
|
||||||
|
"useStepper": true,
|
||||||
|
"useStorage": true,
|
||||||
|
"useStorageAsync": true,
|
||||||
|
"useStyleTag": true,
|
||||||
|
"useSupported": true,
|
||||||
|
"useSwipe": true,
|
||||||
|
"useTemplateRefsList": true,
|
||||||
|
"useTextDirection": true,
|
||||||
|
"useTextSelection": true,
|
||||||
|
"useTextareaAutosize": true,
|
||||||
|
"useThrottle": true,
|
||||||
|
"useThrottleFn": true,
|
||||||
|
"useThrottledRefHistory": true,
|
||||||
|
"useTimeAgo": true,
|
||||||
|
"useTimeout": true,
|
||||||
|
"useTimeoutFn": true,
|
||||||
|
"useTimeoutPoll": true,
|
||||||
|
"useTimestamp": true,
|
||||||
|
"useTitle": true,
|
||||||
|
"useToNumber": true,
|
||||||
|
"useToString": true,
|
||||||
|
"useToggle": true,
|
||||||
|
"useTransition": true,
|
||||||
|
"useUrlSearchParams": true,
|
||||||
|
"useUserMedia": true,
|
||||||
|
"useVModel": true,
|
||||||
|
"useVModels": true,
|
||||||
|
"useVibrate": true,
|
||||||
|
"useVirtualList": true,
|
||||||
|
"useWakeLock": true,
|
||||||
|
"useWebNotification": true,
|
||||||
|
"useWebSocket": true,
|
||||||
|
"useWebWorker": true,
|
||||||
|
"useWebWorkerFn": true,
|
||||||
|
"useWindowFocus": true,
|
||||||
|
"useWindowScroll": true,
|
||||||
|
"useWindowSize": true,
|
||||||
|
"watch": true,
|
||||||
|
"watchArray": true,
|
||||||
|
"watchAtMost": true,
|
||||||
|
"watchDebounced": true,
|
||||||
|
"watchDeep": true,
|
||||||
|
"watchEffect": true,
|
||||||
|
"watchIgnorable": true,
|
||||||
|
"watchImmediate": true,
|
||||||
|
"watchOnce": true,
|
||||||
|
"watchPausable": true,
|
||||||
|
"watchPostEffect": true,
|
||||||
|
"watchSyncEffect": true,
|
||||||
|
"watchThrottled": true,
|
||||||
|
"watchTriggerable": true,
|
||||||
|
"watchWithFilter": true,
|
||||||
|
"whenever": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
es2021: true,
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
parser: "vue-eslint-parser",
|
||||||
|
extends: [
|
||||||
|
// https://eslint.vuejs.org/user-guide/#usage
|
||||||
|
"plugin:vue/vue3-recommended",
|
||||||
|
"./.eslintrc-auto-import.json",
|
||||||
|
"prettier",
|
||||||
|
"plugin:@typescript-eslint/recommended",
|
||||||
|
"plugin:prettier/recommended",
|
||||||
|
],
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: "latest",
|
||||||
|
sourceType: "module",
|
||||||
|
parser: "@typescript-eslint/parser",
|
||||||
|
project: "./tsconfig.*?.json",
|
||||||
|
createDefaultProgram: false,
|
||||||
|
extraFileExtensions: [".vue"],
|
||||||
|
},
|
||||||
|
plugins: ["vue", "@typescript-eslint"],
|
||||||
|
rules: {
|
||||||
|
// https://eslint.vuejs.org/rules/#priority-a-essential-error-prevention
|
||||||
|
"vue/multi-word-component-names": "off",
|
||||||
|
"vue/no-v-model-argument": "off",
|
||||||
|
"vue/script-setup-uses-vars": "error",
|
||||||
|
"vue/no-reserved-component-names": "off",
|
||||||
|
"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/require-default-prop": "off",
|
||||||
|
"vue/require-explicit-emits": "off",
|
||||||
|
"vue/html-self-closing": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
html: {
|
||||||
|
void: "always",
|
||||||
|
normal: "never",
|
||||||
|
component: "always",
|
||||||
|
},
|
||||||
|
svg: "always",
|
||||||
|
math: "always",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
"@typescript-eslint/no-empty-function": "off", // 关闭空方法检查
|
||||||
|
"@typescript-eslint/no-explicit-any": "off", // 关闭any类型的警告
|
||||||
|
"@typescript-eslint/no-non-null-assertion": "off",
|
||||||
|
"@typescript-eslint/ban-ts-ignore": "off",
|
||||||
|
"@typescript-eslint/ban-ts-comment": "off",
|
||||||
|
"@typescript-eslint/ban-types": "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/no-non-null-assertion": "off",
|
||||||
|
"@typescript-eslint/explicit-module-boundary-types": "off",
|
||||||
|
"@typescript-eslint/no-unused-vars": "off",
|
||||||
|
|
||||||
|
"prettier/prettier": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
useTabs: false, // 不使用制表符
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// eslint不能对html文件生效
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ["*.html"],
|
||||||
|
processor: "vue/.vue",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
// https://eslint.org/docs/latest/use/configure/language-options#specifying-globals
|
||||||
|
globals: {
|
||||||
|
OptionType: "readonly",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
dist
|
||||||
|
node_modules
|
||||||
|
public
|
||||||
|
.husky
|
||||||
|
.vscode
|
||||||
|
.idea
|
||||||
|
*.sh
|
||||||
|
*.md
|
||||||
|
|
||||||
|
src/assets
|
||||||
|
stats.html
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
module.exports = {
|
||||||
|
// (x)=>{},单个参数箭头函数是否显示小括号。(always:始终显示;avoid:省略括号。默认:always)
|
||||||
|
arrowParens: "always",
|
||||||
|
// 开始标签的右尖括号是否跟随在最后一行属性末尾,默认false
|
||||||
|
bracketSameLine: false,
|
||||||
|
// 对象字面量的括号之间打印空格 (true - Example: { foo: bar } ; false - Example: {foo:bar})
|
||||||
|
bracketSpacing: true,
|
||||||
|
// 是否格式化一些文件中被嵌入的代码片段的风格(auto|off;默认auto)
|
||||||
|
embeddedLanguageFormatting: "auto",
|
||||||
|
// 指定 HTML 文件的空格敏感度 (css|strict|ignore;默认css)
|
||||||
|
htmlWhitespaceSensitivity: "css",
|
||||||
|
// 当文件已经被 Prettier 格式化之后,是否会在文件顶部插入一个特殊的 @format 标记,默认false
|
||||||
|
insertPragma: false,
|
||||||
|
// 在 JSX 中使用单引号替代双引号,默认false
|
||||||
|
jsxSingleQuote: false,
|
||||||
|
// 每行最多字符数量,超出换行(默认80)
|
||||||
|
printWidth: 80,
|
||||||
|
// 超出打印宽度 (always | never | preserve )
|
||||||
|
proseWrap: "preserve",
|
||||||
|
// 对象属性是否使用引号(as-needed | consistent | preserve;默认as-needed:对象的属性需要加引号才添加;)
|
||||||
|
quoteProps: "as-needed",
|
||||||
|
// 是否只格式化在文件顶部包含特定注释(@prettier| @format)的文件,默认false
|
||||||
|
requirePragma: false,
|
||||||
|
// 结尾添加分号
|
||||||
|
semi: true,
|
||||||
|
// 使用单引号 (true:单引号;false:双引号)
|
||||||
|
singleQuote: false,
|
||||||
|
// 缩进空格数,默认2个空格
|
||||||
|
tabWidth: 2,
|
||||||
|
// 元素末尾是否加逗号,默认es5: ES5中的 objects, arrays 等会添加逗号,TypeScript 中的 type 后不加逗号
|
||||||
|
trailingComma: "es5",
|
||||||
|
// 指定缩进方式,空格或tab,默认false,即使用空格
|
||||||
|
useTabs: false,
|
||||||
|
// vue 文件中是否缩进 <style> 和 <script> 标签,默认 false
|
||||||
|
vueIndentScriptAndStyle: false,
|
||||||
|
|
||||||
|
endOfLine: "auto",
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: "*.html",
|
||||||
|
options: {
|
||||||
|
parser: "html",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
// Generated by 'unplugin-auto-import'
|
// Generated by 'unplugin-auto-import'
|
||||||
export {}
|
export {};
|
||||||
declare global {
|
declare global {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -10,64 +10,27 @@ declare module '@vue/runtime-core' {
|
||||||
Countup: typeof import('./src/components/countup.vue')['default']
|
Countup: typeof import('./src/components/countup.vue')['default']
|
||||||
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
||||||
ElButton: typeof import('element-plus/es')['ElButton']
|
ElButton: typeof import('element-plus/es')['ElButton']
|
||||||
ElCalendar: typeof import('element-plus/es')['ElCalendar']
|
|
||||||
ElCard: typeof import('element-plus/es')['ElCard']
|
ElCard: typeof import('element-plus/es')['ElCard']
|
||||||
ElCarousel: typeof import('element-plus/es')['ElCarousel']
|
|
||||||
ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem']
|
|
||||||
ElCascader: typeof import('element-plus/es')['ElCascader']
|
|
||||||
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
|
||||||
ElCheckboxGroup: typeof import('element-plus/es')['ElCheckboxGroup']
|
|
||||||
ElCol: typeof import('element-plus/es')['ElCol']
|
ElCol: typeof import('element-plus/es')['ElCol']
|
||||||
ElColorPicker: typeof import('element-plus/es')['ElColorPicker']
|
|
||||||
ElCountdown: typeof import('element-plus/es')['ElCountdown']
|
|
||||||
ElDatePicker: typeof import('element-plus/es')['ElDatePicker']
|
|
||||||
ElDescriptions: typeof import('element-plus/es')['ElDescriptions']
|
|
||||||
ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem']
|
|
||||||
ElDialog: typeof import('element-plus/es')['ElDialog']
|
|
||||||
ElDivider: typeof import('element-plus/es')['ElDivider']
|
|
||||||
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
ElDropdown: typeof import('element-plus/es')['ElDropdown']
|
||||||
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
|
ElDropdownItem: typeof import('element-plus/es')['ElDropdownItem']
|
||||||
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
|
ElDropdownMenu: typeof import('element-plus/es')['ElDropdownMenu']
|
||||||
ElForm: typeof import('element-plus/es')['ElForm']
|
ElForm: typeof import('element-plus/es')['ElForm']
|
||||||
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
ElFormItem: typeof import('element-plus/es')['ElFormItem']
|
||||||
ElIcon: typeof import('element-plus/es')['ElIcon']
|
ElIcon: typeof import('element-plus/es')['ElIcon']
|
||||||
ElImage: typeof import('element-plus/es')['ElImage']
|
|
||||||
ElInput: typeof import('element-plus/es')['ElInput']
|
ElInput: typeof import('element-plus/es')['ElInput']
|
||||||
ElInputNumber: typeof import('element-plus/es')['ElInputNumber']
|
|
||||||
ElLink: typeof import('element-plus/es')['ElLink']
|
ElLink: typeof import('element-plus/es')['ElLink']
|
||||||
ElMenu: typeof import('element-plus/es')['ElMenu']
|
ElMenu: typeof import('element-plus/es')['ElMenu']
|
||||||
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
ElMenuItem: typeof import('element-plus/es')['ElMenuItem']
|
||||||
ElOption: typeof import('element-plus/es')['ElOption']
|
|
||||||
ElPagination: typeof import('element-plus/es')['ElPagination']
|
|
||||||
ElProgress: typeof import('element-plus/es')['ElProgress']
|
ElProgress: typeof import('element-plus/es')['ElProgress']
|
||||||
ElRadio: typeof import('element-plus/es')['ElRadio']
|
|
||||||
ElRadioButton: typeof import('element-plus/es')['ElRadioButton']
|
|
||||||
ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup']
|
|
||||||
ElRate: typeof import('element-plus/es')['ElRate']
|
|
||||||
ElResult: typeof import('element-plus/es')['ElResult']
|
|
||||||
ElRow: typeof import('element-plus/es')['ElRow']
|
ElRow: typeof import('element-plus/es')['ElRow']
|
||||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
|
||||||
ElSlider: typeof import('element-plus/es')['ElSlider']
|
|
||||||
ElSpace: typeof import('element-plus/es')['ElSpace']
|
|
||||||
ElStatistic: typeof import('element-plus/es')['ElStatistic']
|
|
||||||
ElStep: typeof import('element-plus/es')['ElStep']
|
|
||||||
ElSteps: typeof import('element-plus/es')['ElSteps']
|
|
||||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
||||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
|
||||||
ElTable: typeof import('element-plus/es')['ElTable']
|
|
||||||
ElTableColumn: typeof import('element-plus/es')['ElTableColumn']
|
|
||||||
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
ElTabPane: typeof import('element-plus/es')['ElTabPane']
|
||||||
ElTabs: typeof import('element-plus/es')['ElTabs']
|
ElTabs: typeof import('element-plus/es')['ElTabs']
|
||||||
ElTag: typeof import('element-plus/es')['ElTag']
|
|
||||||
ElTimeline: typeof import('element-plus/es')['ElTimeline']
|
ElTimeline: typeof import('element-plus/es')['ElTimeline']
|
||||||
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
|
ElTimelineItem: typeof import('element-plus/es')['ElTimelineItem']
|
||||||
ElTimePicker: typeof import('element-plus/es')['ElTimePicker']
|
|
||||||
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
ElTooltip: typeof import('element-plus/es')['ElTooltip']
|
||||||
ElTour: typeof import('element-plus/es')['ElTour']
|
|
||||||
ElTourStep: typeof import('element-plus/es')['ElTourStep']
|
|
||||||
ElTransfer: typeof import('element-plus/es')['ElTransfer']
|
|
||||||
ElUpload: typeof import('element-plus/es')['ElUpload']
|
|
||||||
ElWatermark: typeof import('element-plus/es')['ElWatermark']
|
|
||||||
Header: typeof import('./src/components/header.vue')['default']
|
Header: typeof import('./src/components/header.vue')['default']
|
||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
|
|
|
||||||
22
index.html
22
index.html
|
|
@ -1,22 +1,26 @@
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="">
|
<html lang="">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
|
||||||
<title>vue-manage-system后台管理系统</title>
|
<title>vue-manage-system后台管理系统</title>
|
||||||
<link rel="stylesheet" href="//at.alicdn.com/t/c/font_830376_92o68tc95je.css">
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="//at.alicdn.com/t/c/font_830376_92o68tc95je.css"
|
||||||
|
/>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
|
<strong
|
||||||
Please enable it to continue.</strong>
|
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
|
||||||
|
properly without JavaScript enabled. Please enable it to
|
||||||
|
continue.</strong
|
||||||
|
>
|
||||||
</noscript>
|
</noscript>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
<script type="module" src="/src/main.ts"></script>
|
<script type="module" src="/src/main.ts"></script>
|
||||||
<!-- built files will be auto injected -->
|
<!-- built files will be auto injected -->
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
File diff suppressed because it is too large
Load Diff
31
package.json
31
package.json
|
|
@ -5,7 +5,28 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vue-tsc --noEmit && vite build",
|
"build": "vue-tsc --noEmit && vite build",
|
||||||
"serve": "vite preview"
|
"serve": "vite preview",
|
||||||
|
"lint:prettier": "prettier --write \"**/*.{js,cjs,ts,json,tsx,css,less,scss,vue,html,md}\"",
|
||||||
|
"lint:eslint": "eslint --fix --ext .ts,.js,.vue ./src "
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*.{js,ts}": [
|
||||||
|
"eslint --fix",
|
||||||
|
"prettier --write"
|
||||||
|
],
|
||||||
|
"*.{cjs,json}": [
|
||||||
|
"prettier --write"
|
||||||
|
],
|
||||||
|
"*.{vue,html}": [
|
||||||
|
"eslint --fix",
|
||||||
|
"prettier --write"
|
||||||
|
],
|
||||||
|
"*.{scss,css}": [
|
||||||
|
"prettier --write"
|
||||||
|
],
|
||||||
|
"*.md": [
|
||||||
|
"prettier --write"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "*",
|
"@element-plus/icons-vue": "*",
|
||||||
|
|
@ -27,8 +48,16 @@
|
||||||
"xlsx": "^0.18.5"
|
"xlsx": "^0.18.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/node": "^20.12.11",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^7.8.0",
|
||||||
"@vitejs/plugin-vue": "^3.0.0",
|
"@vitejs/plugin-vue": "^3.0.0",
|
||||||
"@vue/compiler-sfc": "^3.1.2",
|
"@vue/compiler-sfc": "^3.1.2",
|
||||||
|
"eslint": "^8.57.0",
|
||||||
|
"eslint-config-prettier": "^9.1.0",
|
||||||
|
"eslint-plugin-import": "^2.29.1",
|
||||||
|
"eslint-plugin-prettier": "^5.1.3",
|
||||||
|
"eslint-plugin-vue": "^9.25.0",
|
||||||
|
"prettier": "^3.2.5",
|
||||||
"typescript": "^4.6.4",
|
"typescript": "^4.6.4",
|
||||||
"unplugin-auto-import": "^0.11.2",
|
"unplugin-auto-import": "^0.11.2",
|
||||||
"unplugin-vue-components": "^0.22.4",
|
"unplugin-vue-components": "^0.22.4",
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ElConfigProvider } from 'element-plus';
|
import { ElConfigProvider } from "element-plus";
|
||||||
import zhCn from 'element-plus/es/locale/lang/zh-cn';
|
import zhCn from "element-plus/es/locale/lang/zh-cn";
|
||||||
import { useThemeStore } from './store/theme';
|
import { useThemeStore } from "./store/theme";
|
||||||
|
|
||||||
const theme = useThemeStore();
|
const theme = useThemeStore();
|
||||||
theme.initTheme();
|
theme.initTheme();
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
@import './assets/css/main.css';
|
@import "./assets/css/main.css";
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
import request from '../utils/request';
|
import request from "../utils/request";
|
||||||
|
|
||||||
export const fetchData = () => {
|
export const fetchData = () => {
|
||||||
return request({
|
return request({
|
||||||
url: './mock/table.json',
|
url: "./mock/table.json",
|
||||||
method: 'get'
|
method: "get",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchUserData = () => {
|
export const fetchUserData = () => {
|
||||||
return request({
|
return request({
|
||||||
url: './mock/user.json',
|
url: "./mock/user.json",
|
||||||
method: 'get'
|
method: "get",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fetchRoleData = () => {
|
export const fetchRoleData = () => {
|
||||||
return request({
|
return request({
|
||||||
url: './mock/role.json',
|
url: "./mock/role.json",
|
||||||
method: 'get'
|
method: "get",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted, ref, watch } from 'vue';
|
import { onMounted, ref, watch } from "vue";
|
||||||
import { CountUp } from 'countup.js';
|
import { CountUp } from "countup.js";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
end: {
|
end: {
|
||||||
|
|
@ -29,11 +29,12 @@ onMounted(() => {
|
||||||
countUp.start();
|
countUp.start();
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(() => props.end, (newVal) => {
|
watch(
|
||||||
|
() => props.end,
|
||||||
|
(newVal) => {
|
||||||
if (countUp) {
|
if (countUp) {
|
||||||
countUp.update(newVal);
|
countUp.update(newVal);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -47,14 +47,22 @@
|
||||||
</span>
|
</span>
|
||||||
<template #dropdown>
|
<template #dropdown>
|
||||||
<el-dropdown-menu>
|
<el-dropdown-menu>
|
||||||
<a href="https://github.com/lin-xin/vue-manage-system" target="_blank">
|
<a
|
||||||
|
href="https://github.com/lin-xin/vue-manage-system"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
<el-dropdown-item>项目仓库</el-dropdown-item>
|
<el-dropdown-item>项目仓库</el-dropdown-item>
|
||||||
</a>
|
</a>
|
||||||
<a href="https://lin-xin.gitee.io/example/vuems-doc/" target="_blank">
|
<a
|
||||||
|
href="https://lin-xin.gitee.io/example/vuems-doc/"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
<el-dropdown-item>官方文档</el-dropdown-item>
|
<el-dropdown-item>官方文档</el-dropdown-item>
|
||||||
</a>
|
</a>
|
||||||
<el-dropdown-item command="user">个人中心</el-dropdown-item>
|
<el-dropdown-item command="user">个人中心</el-dropdown-item>
|
||||||
<el-dropdown-item divided command="loginout">退出登录</el-dropdown-item>
|
<el-dropdown-item divided command="loginout"
|
||||||
|
>退出登录</el-dropdown-item
|
||||||
|
>
|
||||||
</el-dropdown-menu>
|
</el-dropdown-menu>
|
||||||
</template>
|
</template>
|
||||||
</el-dropdown>
|
</el-dropdown>
|
||||||
|
|
@ -63,12 +71,12 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { onMounted } from 'vue';
|
import { onMounted } from "vue";
|
||||||
import { useSidebarStore } from '../store/sidebar';
|
import { useSidebarStore } from "../store/sidebar";
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from "vue-router";
|
||||||
import imgurl from '../assets/img/img.jpg';
|
import imgurl from "../assets/img/img.jpg";
|
||||||
|
|
||||||
const username: string | null = localStorage.getItem('vuems_name');
|
const username: string | null = localStorage.getItem("vuems_name");
|
||||||
const message: number = 2;
|
const message: number = 2;
|
||||||
|
|
||||||
const sidebar = useSidebarStore();
|
const sidebar = useSidebarStore();
|
||||||
|
|
@ -86,11 +94,11 @@ onMounted(() => {
|
||||||
// 用户名下拉菜单选择事件
|
// 用户名下拉菜单选择事件
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const handleCommand = (command: string) => {
|
const handleCommand = (command: string) => {
|
||||||
if (command == 'loginout') {
|
if (command == "loginout") {
|
||||||
localStorage.removeItem('vuems_name');
|
localStorage.removeItem("vuems_name");
|
||||||
router.push('/login');
|
router.push("/login");
|
||||||
} else if (command == 'user') {
|
} else if (command == "user") {
|
||||||
router.push('/ucenter');
|
router.push("/ucenter");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,220 +1,220 @@
|
||||||
import { Menus } from '@/types/menu';
|
import { Menus } from "@/types/menu";
|
||||||
|
|
||||||
export const menuData: Menus[] = [
|
export const menuData: Menus[] = [
|
||||||
{
|
{
|
||||||
id: '0',
|
id: "0",
|
||||||
title: '系统首页',
|
title: "系统首页",
|
||||||
index: '/dashboard',
|
index: "/dashboard",
|
||||||
icon: 'Odometer',
|
icon: "Odometer",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '1',
|
id: "1",
|
||||||
title: '系统管理',
|
title: "系统管理",
|
||||||
index: '1',
|
index: "1",
|
||||||
icon: 'HomeFilled',
|
icon: "HomeFilled",
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
id: '11',
|
id: "11",
|
||||||
pid: '1',
|
pid: "1",
|
||||||
index: '/system-user',
|
index: "/system-user",
|
||||||
title: '用户管理',
|
title: "用户管理",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '12',
|
id: "12",
|
||||||
pid: '1',
|
pid: "1",
|
||||||
index: '/system-role',
|
index: "/system-role",
|
||||||
title: '角色管理',
|
title: "角色管理",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '13',
|
id: "13",
|
||||||
pid: '1',
|
pid: "1",
|
||||||
index: '/system-menu',
|
index: "/system-menu",
|
||||||
title: '菜单管理',
|
title: "菜单管理",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '2',
|
id: "2",
|
||||||
title: '组件',
|
title: "组件",
|
||||||
index: '2-1',
|
index: "2-1",
|
||||||
icon: 'Calendar',
|
icon: "Calendar",
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
id: '21',
|
id: "21",
|
||||||
pid: '3',
|
pid: "3",
|
||||||
index: '/form',
|
index: "/form",
|
||||||
title: '表单',
|
title: "表单",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '22',
|
id: "22",
|
||||||
pid: '3',
|
pid: "3",
|
||||||
index: '/upload',
|
index: "/upload",
|
||||||
title: '上传',
|
title: "上传",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '23',
|
id: "23",
|
||||||
pid: '2',
|
pid: "2",
|
||||||
index: '/carousel',
|
index: "/carousel",
|
||||||
title: '走马灯',
|
title: "走马灯",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '24',
|
id: "24",
|
||||||
pid: '2',
|
pid: "2",
|
||||||
index: '/calendar',
|
index: "/calendar",
|
||||||
title: '日历',
|
title: "日历",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '25',
|
id: "25",
|
||||||
pid: '2',
|
pid: "2",
|
||||||
index: '/watermark',
|
index: "/watermark",
|
||||||
title: '水印',
|
title: "水印",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '26',
|
id: "26",
|
||||||
pid: '2',
|
pid: "2",
|
||||||
index: '/tour',
|
index: "/tour",
|
||||||
title: '分布引导',
|
title: "分布引导",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '27',
|
id: "27",
|
||||||
pid: '2',
|
pid: "2",
|
||||||
index: '/steps',
|
index: "/steps",
|
||||||
title: '步骤条',
|
title: "步骤条",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '28',
|
id: "28",
|
||||||
pid: '2',
|
pid: "2",
|
||||||
index: '/statistic',
|
index: "/statistic",
|
||||||
title: '统计',
|
title: "统计",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '29',
|
id: "29",
|
||||||
pid: '3',
|
pid: "3",
|
||||||
index: '29',
|
index: "29",
|
||||||
title: '三级菜单',
|
title: "三级菜单",
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
id: '291',
|
id: "291",
|
||||||
pid: '29',
|
pid: "29",
|
||||||
index: '/editor',
|
index: "/editor",
|
||||||
title: '富文本编辑器',
|
title: "富文本编辑器",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '292',
|
id: "292",
|
||||||
pid: '29',
|
pid: "29",
|
||||||
index: '/markdown',
|
index: "/markdown",
|
||||||
title: 'markdown编辑器',
|
title: "markdown编辑器",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '3',
|
id: "3",
|
||||||
title: '表格',
|
title: "表格",
|
||||||
index: '3',
|
index: "3",
|
||||||
icon: 'Calendar',
|
icon: "Calendar",
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
id: '31',
|
id: "31",
|
||||||
pid: '3',
|
pid: "3",
|
||||||
index: '/table',
|
index: "/table",
|
||||||
title: '基础表格',
|
title: "基础表格",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '32',
|
id: "32",
|
||||||
pid: '3',
|
pid: "3",
|
||||||
index: '/table-editor',
|
index: "/table-editor",
|
||||||
title: '可编辑表格',
|
title: "可编辑表格",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '33',
|
id: "33",
|
||||||
pid: '3',
|
pid: "3",
|
||||||
index: '/import',
|
index: "/import",
|
||||||
title: '导入Excel',
|
title: "导入Excel",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '34',
|
id: "34",
|
||||||
pid: '3',
|
pid: "3",
|
||||||
index: '/export',
|
index: "/export",
|
||||||
title: '导出Excel',
|
title: "导出Excel",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '4',
|
id: "4",
|
||||||
icon: 'PieChart',
|
icon: "PieChart",
|
||||||
index: '4',
|
index: "4",
|
||||||
title: '图表',
|
title: "图表",
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
id: '41',
|
id: "41",
|
||||||
pid: '4',
|
pid: "4",
|
||||||
index: '/schart',
|
index: "/schart",
|
||||||
title: 'schart图表',
|
title: "schart图表",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '42',
|
id: "42",
|
||||||
pid: '4',
|
pid: "4",
|
||||||
index: '/echarts',
|
index: "/echarts",
|
||||||
title: 'echarts图表',
|
title: "echarts图表",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '5',
|
id: "5",
|
||||||
icon: 'Guide',
|
icon: "Guide",
|
||||||
index: '/icon',
|
index: "/icon",
|
||||||
title: '图标',
|
title: "图标",
|
||||||
permiss: '5',
|
permiss: "5",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '7',
|
id: "7",
|
||||||
icon: 'Brush',
|
icon: "Brush",
|
||||||
index: '/theme',
|
index: "/theme",
|
||||||
title: '主题',
|
title: "主题",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '6',
|
id: "6",
|
||||||
icon: 'DocumentAdd',
|
icon: "DocumentAdd",
|
||||||
index: '6',
|
index: "6",
|
||||||
title: '附加页面',
|
title: "附加页面",
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
id: '61',
|
id: "61",
|
||||||
pid: '6',
|
pid: "6",
|
||||||
index: '/ucenter',
|
index: "/ucenter",
|
||||||
title: '个人中心',
|
title: "个人中心",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '62',
|
id: "62",
|
||||||
pid: '6',
|
pid: "6",
|
||||||
index: '/login',
|
index: "/login",
|
||||||
title: '登录',
|
title: "登录",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '63',
|
id: "63",
|
||||||
pid: '6',
|
pid: "6",
|
||||||
index: '/register',
|
index: "/register",
|
||||||
title: '注册',
|
title: "注册",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '64',
|
id: "64",
|
||||||
pid: '6',
|
pid: "6",
|
||||||
index: '/reset-pwd',
|
index: "/reset-pwd",
|
||||||
title: '重设密码',
|
title: "重设密码",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '65',
|
id: "65",
|
||||||
pid: '6',
|
pid: "6",
|
||||||
index: '/403',
|
index: "/403",
|
||||||
title: '403',
|
title: "403",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: '66',
|
id: "66",
|
||||||
pid: '6',
|
pid: "6",
|
||||||
index: '/404',
|
index: "/404",
|
||||||
title: '404',
|
title: "404",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,14 @@
|
||||||
>
|
>
|
||||||
<template v-for="item in menuData">
|
<template v-for="item in menuData">
|
||||||
<template v-if="item.children">
|
<template v-if="item.children">
|
||||||
<el-sub-menu :index="item.index" :key="item.index" v-permiss="item.id">
|
<el-sub-menu
|
||||||
|
:index="item.index"
|
||||||
|
:key="item.index"
|
||||||
|
v-permiss="item.id"
|
||||||
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<component :is="item.icon"></component>
|
<component :is="item.icon" />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<span>{{ item.title }}</span>
|
<span>{{ item.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -40,9 +44,13 @@
|
||||||
</el-sub-menu>
|
</el-sub-menu>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-menu-item :index="item.index" :key="item.index" v-permiss="item.id">
|
<el-menu-item
|
||||||
|
:index="item.index"
|
||||||
|
:key="item.index"
|
||||||
|
v-permiss="item.id"
|
||||||
|
>
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<component :is="item.icon"></component>
|
<component :is="item.icon" />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
<template #title>{{ item.title }}</template>
|
<template #title>{{ item.title }}</template>
|
||||||
</el-menu-item>
|
</el-menu-item>
|
||||||
|
|
@ -53,10 +61,10 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import { computed } from "vue";
|
||||||
import { useSidebarStore } from '../store/sidebar';
|
import { useSidebarStore } from "../store/sidebar";
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from "vue-router";
|
||||||
import { menuData } from '@/components/menu';
|
import { menuData } from "@/components/menu";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const onRoutes = computed(() => {
|
const onRoutes = computed(() => {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,10 @@
|
||||||
<div class="table-toolbar-right flex-center">
|
<div class="table-toolbar-right flex-center">
|
||||||
<template v-if="multipleSelection.length > 0">
|
<template v-if="multipleSelection.length > 0">
|
||||||
<el-tooltip effect="dark" content="删除选中" placement="top">
|
<el-tooltip effect="dark" content="删除选中" placement="top">
|
||||||
<el-icon class="columns-setting-icon" @click="delSelection(multipleSelection)">
|
<el-icon
|
||||||
|
class="columns-setting-icon"
|
||||||
|
@click="delSelection(multipleSelection)"
|
||||||
|
>
|
||||||
<Delete />
|
<Delete />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
|
|
@ -35,25 +38,55 @@
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-table class="mgb20" :style="{ width: '100%' }" border :data="tableData" :row-key="rowKey"
|
<el-table
|
||||||
@selection-change="handleSelectionChange" table-layout="auto">
|
class="mgb20"
|
||||||
|
:style="{ width: '100%' }"
|
||||||
|
border
|
||||||
|
:data="tableData"
|
||||||
|
:row-key="rowKey"
|
||||||
|
@selection-change="handleSelectionChange"
|
||||||
|
table-layout="auto"
|
||||||
|
>
|
||||||
<template v-for="item in columns" :key="item.prop">
|
<template v-for="item in columns" :key="item.prop">
|
||||||
<el-table-column v-if="item.visible" :prop="item.prop" :label="item.label" :width="item.width"
|
<el-table-column
|
||||||
:type="item.type" :align="item.align || 'center'">
|
v-if="item.visible"
|
||||||
|
:prop="item.prop"
|
||||||
<template #default="{ row, column, $index }" v-if="item.type === 'index'">
|
:label="item.label"
|
||||||
|
:width="item.width"
|
||||||
|
:type="item.type"
|
||||||
|
:align="item.align || 'center'"
|
||||||
|
>
|
||||||
|
<template
|
||||||
|
#default="{ row, column, $index }"
|
||||||
|
v-if="item.type === 'index'"
|
||||||
|
>
|
||||||
{{ getIndex($index) }}
|
{{ getIndex($index) }}
|
||||||
</template>
|
</template>
|
||||||
<template #default="{ row, column, $index }" v-if="!item.type">
|
<template #default="{ row, column, $index }" v-if="!item.type">
|
||||||
<slot :name="item.prop" :rows="row" :index="$index">
|
<slot :name="item.prop" :rows="row" :index="$index">
|
||||||
<template v-if="item.prop == 'operator'">
|
<template v-if="item.prop == 'operator'">
|
||||||
<el-button type="warning" size="small" :icon="View" @click="viewFunc(row)">
|
<el-button
|
||||||
|
type="warning"
|
||||||
|
size="small"
|
||||||
|
:icon="View"
|
||||||
|
@click="viewFunc(row)"
|
||||||
|
>
|
||||||
查看
|
查看
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" size="small" :icon="Edit" @click="editFunc(row)">
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
:icon="Edit"
|
||||||
|
@click="editFunc(row)"
|
||||||
|
>
|
||||||
编辑
|
编辑
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="danger" size="small" :icon="Delete" @click="handleDelete(row)">
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
size="small"
|
||||||
|
:icon="Delete"
|
||||||
|
@click="handleDelete(row)"
|
||||||
|
>
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -68,81 +101,88 @@
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</template>
|
</template>
|
||||||
</el-table>
|
</el-table>
|
||||||
<el-pagination v-if="hasPagination" :current-page="currentPage" :page-size="pageSize" :background="true"
|
<el-pagination
|
||||||
:layout="layout" :total="total" @current-change="handleCurrentChange" />
|
v-if="hasPagination"
|
||||||
|
:current-page="currentPage"
|
||||||
|
:page-size="pageSize"
|
||||||
|
:background="true"
|
||||||
|
:layout="layout"
|
||||||
|
:total="total"
|
||||||
|
@current-change="handleCurrentChange"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { toRefs, PropType, ref } from 'vue'
|
import { toRefs, PropType, ref } from "vue";
|
||||||
import { Delete, Edit, View, Refresh } from '@element-plus/icons-vue';
|
import { Delete, Edit, View, Refresh } from "@element-plus/icons-vue";
|
||||||
import { ElMessageBox } from 'element-plus';
|
import { ElMessageBox } from "element-plus";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
// 表格相关
|
// 表格相关
|
||||||
tableData: {
|
tableData: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default: []
|
default: [],
|
||||||
},
|
},
|
||||||
columns: {
|
columns: {
|
||||||
type: Array as PropType<any[]>,
|
type: Array as PropType<any[]>,
|
||||||
default: []
|
default: [],
|
||||||
},
|
},
|
||||||
rowKey: {
|
rowKey: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'id'
|
default: "id",
|
||||||
},
|
},
|
||||||
hasToolbar: {
|
hasToolbar: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
// 分页相关
|
// 分页相关
|
||||||
hasPagination: {
|
hasPagination: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true,
|
||||||
},
|
},
|
||||||
total: {
|
total: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 0
|
default: 0,
|
||||||
},
|
},
|
||||||
currentPage: {
|
currentPage: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 1
|
default: 1,
|
||||||
},
|
},
|
||||||
pageSize: {
|
pageSize: {
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 10
|
default: 10,
|
||||||
},
|
},
|
||||||
|
|
||||||
layout: {
|
layout: {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'total, prev, pager, next'
|
default: "total, prev, pager, next",
|
||||||
},
|
},
|
||||||
delFunc: {
|
delFunc: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: () => { }
|
default: () => {},
|
||||||
},
|
},
|
||||||
viewFunc: {
|
viewFunc: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: () => { }
|
default: () => {},
|
||||||
},
|
},
|
||||||
editFunc: {
|
editFunc: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: () => { }
|
default: () => {},
|
||||||
},
|
},
|
||||||
delSelection: {
|
delSelection: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: () => { }
|
default: () => {},
|
||||||
},
|
},
|
||||||
refresh: {
|
refresh: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: () => { }
|
default: () => {},
|
||||||
},
|
},
|
||||||
changePage: {
|
changePage: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: () => { }
|
default: () => {},
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
|
|
||||||
let {
|
let {
|
||||||
tableData,
|
tableData,
|
||||||
|
|
@ -154,28 +194,28 @@ let {
|
||||||
currentPage,
|
currentPage,
|
||||||
pageSize,
|
pageSize,
|
||||||
layout,
|
layout,
|
||||||
} = toRefs(props)
|
} = toRefs(props);
|
||||||
|
|
||||||
columns.value.forEach((item) => {
|
columns.value.forEach((item) => {
|
||||||
if (item.visible === undefined) {
|
if (item.visible === undefined) {
|
||||||
item.visible = true
|
item.visible = true;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
// 当选择项发生变化时会触发该事件
|
// 当选择项发生变化时会触发该事件
|
||||||
const multipleSelection = ref([])
|
const multipleSelection = ref([]);
|
||||||
const handleSelectionChange = (selection: any[]) => {
|
const handleSelectionChange = (selection: any[]) => {
|
||||||
multipleSelection.value = selection
|
multipleSelection.value = selection;
|
||||||
}
|
};
|
||||||
|
|
||||||
// 当前页码变化的事件
|
// 当前页码变化的事件
|
||||||
const handleCurrentChange = (val: number) => {
|
const handleCurrentChange = (val: number) => {
|
||||||
props.changePage(val)
|
props.changePage(val);
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleDelete = (row) => {
|
const handleDelete = (row) => {
|
||||||
ElMessageBox.confirm('确定要删除吗?', '提示', {
|
ElMessageBox.confirm("确定要删除吗?", "提示", {
|
||||||
type: 'warning'
|
type: "warning",
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
props.delFunc(row);
|
props.delFunc(row);
|
||||||
|
|
@ -184,9 +224,8 @@ const handleDelete = (row) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const getIndex = (index: number) => {
|
const getIndex = (index: number) => {
|
||||||
return index + 1 + (currentPage.value - 1) * pageSize.value
|
return index + 1 + (currentPage.value - 1) * pageSize.value;
|
||||||
}
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@ const props = defineProps({
|
||||||
data: {
|
data: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
const { row, title, column = 2, list } = props.data;
|
const { row, title, column = 2, list } = props.data;
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,67 @@
|
||||||
<template>
|
<template>
|
||||||
<el-form ref="formRef" :model="form" :rules="rules" :label-width="options.labelWidth">
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:model="form"
|
||||||
|
:rules="rules"
|
||||||
|
:label-width="options.labelWidth"
|
||||||
|
>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="options.span" v-for="item in options.list">
|
<el-col :span="options.span" v-for="item in options.list">
|
||||||
<el-form-item :label="item.label" :prop="item.prop">
|
<el-form-item :label="item.label" :prop="item.prop">
|
||||||
<!-- 文本框、数字框、下拉框、日期框、开关、上传 -->
|
<!-- 文本框、数字框、下拉框、日期框、开关、上传 -->
|
||||||
<el-input v-if="item.type === 'input'" v-model="form[item.prop]" :disabled="item.disabled"
|
<el-input
|
||||||
:placeholder="item.placeholder" clearable></el-input>
|
v-if="item.type === 'input'"
|
||||||
<el-input-number v-else-if="item.type === 'number'" v-model="form[item.prop]"
|
v-model="form[item.prop]"
|
||||||
:disabled="item.disabled" controls-position="right"></el-input-number>
|
:disabled="item.disabled"
|
||||||
<el-select v-else-if="item.type === 'select'" v-model="form[item.prop]" :disabled="item.disabled"
|
:placeholder="item.placeholder"
|
||||||
:placeholder="item.placeholder" clearable>
|
clearable
|
||||||
<el-option v-for="opt in item.opts" :label="opt.label" :value="opt.value"></el-option>
|
/>
|
||||||
|
<el-input-number
|
||||||
|
v-else-if="item.type === 'number'"
|
||||||
|
v-model="form[item.prop]"
|
||||||
|
:disabled="item.disabled"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
<el-select
|
||||||
|
v-else-if="item.type === 'select'"
|
||||||
|
v-model="form[item.prop]"
|
||||||
|
:disabled="item.disabled"
|
||||||
|
:placeholder="item.placeholder"
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="opt in item.opts"
|
||||||
|
:label="opt.label"
|
||||||
|
:value="opt.value"
|
||||||
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-date-picker v-else-if="item.type === 'date'" type="date" v-model="form[item.prop]"
|
<el-date-picker
|
||||||
:value-format="item.format"></el-date-picker>
|
v-else-if="item.type === 'date'"
|
||||||
<el-switch v-else-if="item.type === 'switch'" v-model="form[item.prop]"
|
type="date"
|
||||||
:active-value="item.activeValue" :inactive-value="item.inactiveValue"
|
v-model="form[item.prop]"
|
||||||
:active-text="item.activeText" :inactive-text="item.inactiveText"></el-switch>
|
:value-format="item.format"
|
||||||
<el-upload v-else-if="item.type === 'upload'" class="avatar-uploader" action="#"
|
/>
|
||||||
:show-file-list="false" :on-success="handleAvatarSuccess">
|
<el-switch
|
||||||
|
v-else-if="item.type === 'switch'"
|
||||||
|
v-model="form[item.prop]"
|
||||||
|
:active-value="item.activeValue"
|
||||||
|
:inactive-value="item.inactiveValue"
|
||||||
|
:active-text="item.activeText"
|
||||||
|
:inactive-text="item.inactiveText"
|
||||||
|
/>
|
||||||
|
<el-upload
|
||||||
|
v-else-if="item.type === 'upload'"
|
||||||
|
class="avatar-uploader"
|
||||||
|
action="#"
|
||||||
|
:show-file-list="false"
|
||||||
|
:on-success="handleAvatarSuccess"
|
||||||
|
>
|
||||||
<img v-if="form[item.prop]" :src="form[item.prop]" class="avatar" />
|
<img v-if="form[item.prop]" :src="form[item.prop]" class="avatar" />
|
||||||
<el-icon v-else class="avatar-uploader-icon">
|
<el-icon v-else class="avatar-uploader-icon">
|
||||||
<Plus />
|
<Plus />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
<slot :name="item.prop" v-else>
|
<slot :name="item.prop" v-else> </slot>
|
||||||
|
|
||||||
</slot>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
@ -38,53 +73,59 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { FormOption } from '@/types/form-option';
|
import { FormOption } from "@/types/form-option";
|
||||||
import { FormInstance, FormRules, UploadProps } from 'element-plus';
|
import { FormInstance, FormRules, UploadProps } from "element-plus";
|
||||||
import { PropType, ref } from 'vue';
|
import { PropType, ref } from "vue";
|
||||||
|
|
||||||
const { options, formData, edit, update } = defineProps({
|
const { options, formData, edit, update } = defineProps({
|
||||||
options: {
|
options: {
|
||||||
type: Object as PropType<FormOption>,
|
type: Object as PropType<FormOption>,
|
||||||
required: true
|
required: true,
|
||||||
},
|
},
|
||||||
formData: {
|
formData: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true,
|
||||||
},
|
},
|
||||||
edit: {
|
edit: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false
|
required: false,
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
type: Function,
|
type: Function,
|
||||||
required: true
|
required: true,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const form = ref({ ...(edit ? formData : {}) });
|
const form = ref({ ...(edit ? formData : {}) });
|
||||||
|
|
||||||
const rules: FormRules = options.list.map(item => {
|
const rules: FormRules = options.list
|
||||||
|
.map((item) => {
|
||||||
if (item.required) {
|
if (item.required) {
|
||||||
return { [item.prop]: [{ required: true, message: `${item.label}不能为空`, trigger: 'blur' }] };
|
return {
|
||||||
|
[item.prop]: [
|
||||||
|
{ required: true, message: `${item.label}不能为空`, trigger: "blur" },
|
||||||
|
],
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}).reduce((acc, cur) => ({ ...acc, ...cur }), {});
|
})
|
||||||
|
.reduce((acc, cur) => ({ ...acc, ...cur }), {});
|
||||||
|
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
const saveEdit = (formEl: FormInstance | undefined) => {
|
const saveEdit = (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.validate(valid => {
|
formEl.validate((valid) => {
|
||||||
if (!valid) return false;
|
if (!valid) return false;
|
||||||
update(form.value);
|
update(form.value);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAvatarSuccess: UploadProps['onSuccess'] = (response, uploadFile) => {
|
const handleAvatarSuccess: UploadProps["onSuccess"] = (
|
||||||
|
response,
|
||||||
|
uploadFile
|
||||||
|
) => {
|
||||||
form.value.thumb = URL.createObjectURL(uploadFile.raw!);
|
form.value.thumb = URL.createObjectURL(uploadFile.raw!);
|
||||||
};
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
|
||||||
|
|
@ -1,52 +1,78 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="search-container">
|
<div class="search-container">
|
||||||
<el-form ref="searchRef" :model="query" :inline="true">
|
<el-form ref="searchRef" :model="query" :inline="true">
|
||||||
<el-form-item :label="item.label" :prop="item.prop" v-for="item in options">
|
<el-form-item
|
||||||
|
:label="item.label"
|
||||||
|
:prop="item.prop"
|
||||||
|
v-for="item in options"
|
||||||
|
>
|
||||||
<!-- 文本框、下拉框、日期框 -->
|
<!-- 文本框、下拉框、日期框 -->
|
||||||
<el-input v-if="item.type === 'input'" v-model="query[item.prop]" :disabled="item.disabled"
|
<el-input
|
||||||
:placeholder="item.placeholder" clearable></el-input>
|
v-if="item.type === 'input'"
|
||||||
<el-select v-else-if="item.type === 'select'" v-model="query[item.prop]" :disabled="item.disabled"
|
v-model="query[item.prop]"
|
||||||
:placeholder="item.placeholder" clearable>
|
:disabled="item.disabled"
|
||||||
<el-option v-for="opt in item.opts" :label="opt.label" :value="opt.value"></el-option>
|
:placeholder="item.placeholder"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
<el-select
|
||||||
|
v-else-if="item.type === 'select'"
|
||||||
|
v-model="query[item.prop]"
|
||||||
|
:disabled="item.disabled"
|
||||||
|
:placeholder="item.placeholder"
|
||||||
|
clearable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="opt in item.opts"
|
||||||
|
:label="opt.label"
|
||||||
|
:value="opt.value"
|
||||||
|
/>
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-date-picker v-else-if="item.type === 'date'" type="date" v-model="query[item.prop]"
|
<el-date-picker
|
||||||
:value-format="item.format"></el-date-picker>
|
v-else-if="item.type === 'date'"
|
||||||
|
type="date"
|
||||||
|
v-model="query[item.prop]"
|
||||||
|
:value-format="item.format"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" :icon="Search" @click="search">搜索</el-button>
|
<el-button type="primary" :icon="Search" @click="search"
|
||||||
<el-button :icon="Refresh" @click="resetForm(searchRef)">重置</el-button>
|
>搜索</el-button
|
||||||
|
>
|
||||||
|
<el-button :icon="Refresh" @click="resetForm(searchRef)"
|
||||||
|
>重置</el-button
|
||||||
|
>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { FormInstance } from 'element-plus';
|
import { FormInstance } from "element-plus";
|
||||||
import { Search, Refresh } from '@element-plus/icons-vue';
|
import { Search, Refresh } from "@element-plus/icons-vue";
|
||||||
import { PropType, ref } from 'vue';
|
import { PropType, ref } from "vue";
|
||||||
import { FormOptionList } from '@/types/form-option';
|
import { FormOptionList } from "@/types/form-option";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
query: {
|
query: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true
|
required: true,
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
type: Array as PropType<Array<FormOptionList>>,
|
type: Array as PropType<Array<FormOptionList>>,
|
||||||
required: true
|
required: true,
|
||||||
},
|
},
|
||||||
search: {
|
search: {
|
||||||
type: Function,
|
type: Function,
|
||||||
default: () => { }
|
default: () => {},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const searchRef = ref<FormInstance>();
|
const searchRef = ref<FormInstance>();
|
||||||
const resetForm = (formEl: FormInstance | undefined) => {
|
const resetForm = (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return
|
if (!formEl) return;
|
||||||
formEl.resetFields()
|
formEl.resetFields();
|
||||||
props.search();
|
props.search();
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
@ -55,6 +81,6 @@ const resetForm = (formEl: FormInstance | undefined) => {
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 5px
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,20 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="tabs-container">
|
<div class="tabs-container">
|
||||||
<el-tabs v-model="activePath" class="tabs" type="card" closable @tab-click="clickTabls" @tab-remove="closeTabs">
|
<el-tabs
|
||||||
|
v-model="activePath"
|
||||||
|
class="tabs"
|
||||||
|
type="card"
|
||||||
|
closable
|
||||||
|
@tab-click="clickTabls"
|
||||||
|
@tab-remove="closeTabs"
|
||||||
|
>
|
||||||
<el-tab-pane
|
<el-tab-pane
|
||||||
v-for="item in tabs.list"
|
v-for="item in tabs.list"
|
||||||
:key="item.path"
|
:key="item.path"
|
||||||
:label="item.title"
|
:label="item.title"
|
||||||
:name="item.path"
|
:name="item.path"
|
||||||
@click="setTags(item)"
|
@click="setTags(item)"
|
||||||
></el-tab-pane>
|
/>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<div class="Tabs-close-box">
|
<div class="Tabs-close-box">
|
||||||
<el-dropdown @command="handleTags">
|
<el-dropdown @command="handleTags">
|
||||||
|
|
@ -30,9 +37,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, watch } from 'vue';
|
import { ref, watch } from "vue";
|
||||||
import { useTabsStore } from '../store/tabs';
|
import { useTabsStore } from "../store/tabs";
|
||||||
import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router';
|
import { onBeforeRouteUpdate, useRoute, useRouter } from "vue-router";
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -59,7 +66,7 @@ onBeforeRouteUpdate((to) => {
|
||||||
// 关闭全部标签
|
// 关闭全部标签
|
||||||
const closeAll = () => {
|
const closeAll = () => {
|
||||||
tabs.clearTabs();
|
tabs.clearTabs();
|
||||||
router.push('/');
|
router.push("/");
|
||||||
};
|
};
|
||||||
// 关闭其他标签
|
// 关闭其他标签
|
||||||
const closeOther = () => {
|
const closeOther = () => {
|
||||||
|
|
@ -70,18 +77,18 @@ const closeOther = () => {
|
||||||
};
|
};
|
||||||
const handleTags = (command: string) => {
|
const handleTags = (command: string) => {
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case 'current':
|
case "current":
|
||||||
// 关闭当前页面的标签页
|
// 关闭当前页面的标签页
|
||||||
tabs.closeCurrentTag({
|
tabs.closeCurrentTag({
|
||||||
$router: router,
|
$router: router,
|
||||||
$route: route,
|
$route: route,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'all':
|
case "all":
|
||||||
closeAll();
|
closeAll();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'other':
|
case "other":
|
||||||
closeOther();
|
closeOther();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -94,7 +101,7 @@ const closeTabs = (path: string) => {
|
||||||
const index = tabs.list.findIndex((item) => item.path === path);
|
const index = tabs.list.findIndex((item) => item.path === path);
|
||||||
tabs.delTabsItem(index);
|
tabs.delTabsItem(index);
|
||||||
const item = tabs.list[index] || tabs.list[index - 1];
|
const item = tabs.list[index] || tabs.list[index - 1];
|
||||||
router.push(item ? item.path : '/');
|
router.push(item ? item.path : "/");
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
|
|
||||||
22
src/main.ts
22
src/main.ts
|
|
@ -1,11 +1,11 @@
|
||||||
import { createApp } from 'vue';
|
import { createApp } from "vue";
|
||||||
import { createPinia } from 'pinia';
|
import { createPinia } from "pinia";
|
||||||
import * as ElementPlusIconsVue from '@element-plus/icons-vue';
|
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
|
||||||
import App from './App.vue';
|
import App from "./App.vue";
|
||||||
import router from './router';
|
import router from "./router";
|
||||||
import { usePermissStore } from './store/permiss';
|
import { usePermissStore } from "./store/permiss";
|
||||||
import 'element-plus/dist/index.css';
|
import "element-plus/dist/index.css";
|
||||||
import './assets/css/icon.css';
|
import "./assets/css/icon.css";
|
||||||
|
|
||||||
const app = createApp(App);
|
const app = createApp(App);
|
||||||
app.use(createPinia());
|
app.use(createPinia());
|
||||||
|
|
@ -17,12 +17,12 @@ for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
|
||||||
}
|
}
|
||||||
// 自定义权限指令
|
// 自定义权限指令
|
||||||
const permiss = usePermissStore();
|
const permiss = usePermissStore();
|
||||||
app.directive('permiss', {
|
app.directive("permiss", {
|
||||||
mounted(el, binding) {
|
mounted(el, binding) {
|
||||||
if (binding.value && !permiss.key.includes(String(binding.value))) {
|
if (binding.value && !permiss.key.includes(String(binding.value))) {
|
||||||
el['hidden'] = true;
|
el["hidden"] = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
app.mount('#app');
|
app.mount("#app");
|
||||||
|
|
|
||||||
|
|
@ -1,269 +1,325 @@
|
||||||
import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router';
|
import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
|
||||||
import { usePermissStore } from '../store/permiss';
|
import { usePermissStore } from "../store/permiss";
|
||||||
import Home from '../views/home.vue';
|
import Home from "../views/home.vue";
|
||||||
import NProgress from 'nprogress';
|
import NProgress from "nprogress";
|
||||||
import 'nprogress/nprogress.css';
|
import "nprogress/nprogress.css";
|
||||||
|
|
||||||
const routes: RouteRecordRaw[] = [
|
const routes: RouteRecordRaw[] = [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: "/",
|
||||||
redirect: '/dashboard',
|
redirect: "/dashboard",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/',
|
path: "/",
|
||||||
name: 'Home',
|
name: "Home",
|
||||||
component: Home,
|
component: Home,
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
path: '/dashboard',
|
path: "/dashboard",
|
||||||
name: 'dashboard',
|
name: "dashboard",
|
||||||
meta: {
|
meta: {
|
||||||
title: '系统首页',
|
title: "系统首页",
|
||||||
noAuth: true,
|
noAuth: true,
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "dashboard" */ '../views/dashboard.vue'),
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "dashboard" */ "../views/dashboard.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/system-user',
|
path: "/system-user",
|
||||||
name: 'system-user',
|
name: "system-user",
|
||||||
meta: {
|
meta: {
|
||||||
title: '用户管理',
|
title: "用户管理",
|
||||||
permiss: '11',
|
permiss: "11",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "system-user" */ '../views/system/user.vue'),
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "system-user" */ "../views/system/user.vue"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/system-role',
|
path: "/system-role",
|
||||||
name: 'system-role',
|
name: "system-role",
|
||||||
meta: {
|
meta: {
|
||||||
title: '角色管理',
|
title: "角色管理",
|
||||||
permiss: '12',
|
permiss: "12",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "system-role" */ '../views/system/role.vue'),
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "system-role" */ "../views/system/role.vue"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/system-menu',
|
path: "/system-menu",
|
||||||
name: 'system-menu',
|
name: "system-menu",
|
||||||
meta: {
|
meta: {
|
||||||
title: '菜单管理',
|
title: "菜单管理",
|
||||||
permiss: '13',
|
permiss: "13",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "system-menu" */ '../views/system/menu.vue'),
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "system-menu" */ "../views/system/menu.vue"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/table',
|
path: "/table",
|
||||||
name: 'basetable',
|
name: "basetable",
|
||||||
meta: {
|
meta: {
|
||||||
title: '基础表格',
|
title: "基础表格",
|
||||||
permiss: '31',
|
permiss: "31",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "table" */ '../views/table/basetable.vue'),
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "table" */ "../views/table/basetable.vue"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/table-editor',
|
path: "/table-editor",
|
||||||
name: 'table-editor',
|
name: "table-editor",
|
||||||
meta: {
|
meta: {
|
||||||
title: '可编辑表格',
|
title: "可编辑表格",
|
||||||
permiss: '32',
|
permiss: "32",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "table-editor" */ '../views/table/table-editor.vue'),
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "table-editor" */ "../views/table/table-editor.vue"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/schart',
|
path: "/schart",
|
||||||
name: 'schart',
|
name: "schart",
|
||||||
meta: {
|
meta: {
|
||||||
title: 'schart图表',
|
title: "schart图表",
|
||||||
permiss: '41',
|
permiss: "41",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "schart" */ '../views/chart/schart.vue'),
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "schart" */ "../views/chart/schart.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/echarts',
|
path: "/echarts",
|
||||||
name: 'echarts',
|
name: "echarts",
|
||||||
meta: {
|
meta: {
|
||||||
title: 'echarts图表',
|
title: "echarts图表",
|
||||||
permiss: '42',
|
permiss: "42",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "echarts" */ '../views/chart/echarts.vue'),
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "echarts" */ "../views/chart/echarts.vue"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/icon',
|
path: "/icon",
|
||||||
name: 'icon',
|
name: "icon",
|
||||||
meta: {
|
meta: {
|
||||||
title: '图标',
|
title: "图标",
|
||||||
permiss: '5',
|
permiss: "5",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "icon" */ '../views/pages/icon.vue'),
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "icon" */ "../views/pages/icon.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/ucenter',
|
path: "/ucenter",
|
||||||
name: 'ucenter',
|
name: "ucenter",
|
||||||
meta: {
|
meta: {
|
||||||
title: '个人中心',
|
title: "个人中心",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "ucenter" */ '../views/pages/ucenter.vue'),
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "ucenter" */ "../views/pages/ucenter.vue"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/editor',
|
path: "/editor",
|
||||||
name: 'editor',
|
name: "editor",
|
||||||
meta: {
|
meta: {
|
||||||
title: '富文本编辑器',
|
title: "富文本编辑器",
|
||||||
permiss: '291',
|
permiss: "291",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "editor" */ '../views/pages/editor.vue'),
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "editor" */ "../views/pages/editor.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/markdown',
|
path: "/markdown",
|
||||||
name: 'markdown',
|
name: "markdown",
|
||||||
meta: {
|
meta: {
|
||||||
title: 'markdown编辑器',
|
title: "markdown编辑器",
|
||||||
permiss: '292',
|
permiss: "292",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "markdown" */ '../views/pages/markdown.vue'),
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "markdown" */ "../views/pages/markdown.vue"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/export',
|
path: "/export",
|
||||||
name: 'export',
|
name: "export",
|
||||||
meta: {
|
meta: {
|
||||||
title: '导出Excel',
|
title: "导出Excel",
|
||||||
permiss: '34',
|
permiss: "34",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "export" */ '../views/table/export.vue'),
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "export" */ "../views/table/export.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/import',
|
path: "/import",
|
||||||
name: 'import',
|
name: "import",
|
||||||
meta: {
|
meta: {
|
||||||
title: '导入Excel',
|
title: "导入Excel",
|
||||||
permiss: '33',
|
permiss: "33",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "import" */ '../views/table/import.vue'),
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "import" */ "../views/table/import.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/theme',
|
path: "/theme",
|
||||||
name: 'theme',
|
name: "theme",
|
||||||
meta: {
|
meta: {
|
||||||
title: '主题设置',
|
title: "主题设置",
|
||||||
permiss: '7',
|
permiss: "7",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "theme" */ '../views/pages/theme.vue'),
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "theme" */ "../views/pages/theme.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/calendar',
|
path: "/calendar",
|
||||||
name: 'calendar',
|
name: "calendar",
|
||||||
meta: {
|
meta: {
|
||||||
title: '日历',
|
title: "日历",
|
||||||
permiss: '24',
|
permiss: "24",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "calendar" */ '../views/element/calendar.vue'),
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "calendar" */ "../views/element/calendar.vue"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/watermark',
|
path: "/watermark",
|
||||||
name: 'watermark',
|
name: "watermark",
|
||||||
meta: {
|
meta: {
|
||||||
title: '水印',
|
title: "水印",
|
||||||
permiss: '25',
|
permiss: "25",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "watermark" */ '../views/element/watermark.vue'),
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "watermark" */ "../views/element/watermark.vue"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/carousel',
|
path: "/carousel",
|
||||||
name: 'carousel',
|
name: "carousel",
|
||||||
meta: {
|
meta: {
|
||||||
title: '走马灯',
|
title: "走马灯",
|
||||||
permiss: '23',
|
permiss: "23",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "carousel" */ '../views/element/carousel.vue'),
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "carousel" */ "../views/element/carousel.vue"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/tour',
|
path: "/tour",
|
||||||
name: 'tour',
|
name: "tour",
|
||||||
meta: {
|
meta: {
|
||||||
title: '分步引导',
|
title: "分步引导",
|
||||||
permiss: '26',
|
permiss: "26",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "tour" */ '../views/element/tour.vue'),
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "tour" */ "../views/element/tour.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/steps',
|
path: "/steps",
|
||||||
name: 'steps',
|
name: "steps",
|
||||||
meta: {
|
meta: {
|
||||||
title: '步骤条',
|
title: "步骤条",
|
||||||
permiss: '27',
|
permiss: "27",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "steps" */ '../views/element/steps.vue'),
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "steps" */ "../views/element/steps.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/form',
|
path: "/form",
|
||||||
name: 'forms',
|
name: "forms",
|
||||||
meta: {
|
meta: {
|
||||||
title: '表单',
|
title: "表单",
|
||||||
permiss: '21',
|
permiss: "21",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "form" */ '../views/element/form.vue'),
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "form" */ "../views/element/form.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/upload',
|
path: "/upload",
|
||||||
name: 'upload',
|
name: "upload",
|
||||||
meta: {
|
meta: {
|
||||||
title: '上传',
|
title: "上传",
|
||||||
permiss: '22',
|
permiss: "22",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "upload" */ '../views/element/upload.vue'),
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "upload" */ "../views/element/upload.vue"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/statistic',
|
path: "/statistic",
|
||||||
name: 'statistic',
|
name: "statistic",
|
||||||
meta: {
|
meta: {
|
||||||
title: '统计',
|
title: "统计",
|
||||||
permiss: '28',
|
permiss: "28",
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "statistic" */ '../views/element/statistic.vue'),
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "statistic" */ "../views/element/statistic.vue"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/login',
|
path: "/login",
|
||||||
meta: {
|
meta: {
|
||||||
title: '登录',
|
title: "登录",
|
||||||
noAuth: true,
|
noAuth: true,
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "login" */ '../views/pages/login.vue'),
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "login" */ "../views/pages/login.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/register',
|
path: "/register",
|
||||||
meta: {
|
meta: {
|
||||||
title: '注册',
|
title: "注册",
|
||||||
noAuth: true,
|
noAuth: true,
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "register" */ '../views/pages/register.vue'),
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "register" */ "../views/pages/register.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/reset-pwd',
|
path: "/reset-pwd",
|
||||||
meta: {
|
meta: {
|
||||||
title: '重置密码',
|
title: "重置密码",
|
||||||
noAuth: true,
|
noAuth: true,
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "reset-pwd" */ '../views/pages/reset-pwd.vue'),
|
component: () =>
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "reset-pwd" */ "../views/pages/reset-pwd.vue"
|
||||||
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/403',
|
path: "/403",
|
||||||
meta: {
|
meta: {
|
||||||
title: '没有权限',
|
title: "没有权限",
|
||||||
noAuth: true,
|
noAuth: true,
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "403" */ '../views/pages/403.vue'),
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "403" */ "../views/pages/403.vue"),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/404',
|
path: "/404",
|
||||||
meta: {
|
meta: {
|
||||||
title: '找不到页面',
|
title: "找不到页面",
|
||||||
noAuth: true,
|
noAuth: true,
|
||||||
},
|
},
|
||||||
component: () => import(/* webpackChunkName: "404" */ '../views/pages/404.vue'),
|
component: () =>
|
||||||
|
import(/* webpackChunkName: "404" */ "../views/pages/404.vue"),
|
||||||
},
|
},
|
||||||
{ path: '/:path(.*)', redirect: '/404' },
|
{ path: "/:path(.*)", redirect: "/404" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const router = createRouter({
|
const router = createRouter({
|
||||||
|
|
@ -273,14 +329,17 @@ const router = createRouter({
|
||||||
|
|
||||||
router.beforeEach((to, from, next) => {
|
router.beforeEach((to, from, next) => {
|
||||||
NProgress.start();
|
NProgress.start();
|
||||||
const role = localStorage.getItem('vuems_name');
|
const role = localStorage.getItem("vuems_name");
|
||||||
const permiss = usePermissStore();
|
const permiss = usePermissStore();
|
||||||
|
|
||||||
if (!role && to.meta.noAuth !== true) {
|
if (!role && to.meta.noAuth !== true) {
|
||||||
next('/login');
|
next("/login");
|
||||||
} else if (typeof to.meta.permiss == 'string' && !permiss.key.includes(to.meta.permiss)) {
|
} else if (
|
||||||
|
typeof to.meta.permiss == "string" &&
|
||||||
|
!permiss.key.includes(to.meta.permiss)
|
||||||
|
) {
|
||||||
// 如果没有权限,则进入403
|
// 如果没有权限,则进入403
|
||||||
next('/403');
|
next("/403");
|
||||||
} else {
|
} else {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,54 +1,56 @@
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
interface ObjectList {
|
interface ObjectList {
|
||||||
[key: string]: string[];
|
[key: string]: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const usePermissStore = defineStore('permiss', {
|
export const usePermissStore = defineStore("permiss", {
|
||||||
state: () => {
|
state: () => {
|
||||||
const defaultList: ObjectList = {
|
const defaultList: ObjectList = {
|
||||||
admin: [
|
admin: [
|
||||||
'0',
|
"0",
|
||||||
'1',
|
"1",
|
||||||
'11',
|
"11",
|
||||||
'12',
|
"12",
|
||||||
'13',
|
"13",
|
||||||
'2',
|
"2",
|
||||||
'21',
|
"21",
|
||||||
'22',
|
"22",
|
||||||
'23',
|
"23",
|
||||||
'24',
|
"24",
|
||||||
'25',
|
"25",
|
||||||
'26',
|
"26",
|
||||||
'27',
|
"27",
|
||||||
'28',
|
"28",
|
||||||
'29',
|
"29",
|
||||||
'291',
|
"291",
|
||||||
'292',
|
"292",
|
||||||
'3',
|
"3",
|
||||||
'31',
|
"31",
|
||||||
'32',
|
"32",
|
||||||
'33',
|
"33",
|
||||||
'34',
|
"34",
|
||||||
'4',
|
"4",
|
||||||
'41',
|
"41",
|
||||||
'42',
|
"42",
|
||||||
'5',
|
"5",
|
||||||
'7',
|
"7",
|
||||||
'6',
|
"6",
|
||||||
'61',
|
"61",
|
||||||
'62',
|
"62",
|
||||||
'63',
|
"63",
|
||||||
'64',
|
"64",
|
||||||
'65',
|
"65",
|
||||||
'66',
|
"66",
|
||||||
],
|
],
|
||||||
user: ['0', '1', '11', '12', '13'],
|
user: ["0", "1", "11", "12", "13"],
|
||||||
};
|
};
|
||||||
const username = localStorage.getItem('vuems_name');
|
const username = localStorage.getItem("vuems_name");
|
||||||
console.log(username);
|
console.log(username);
|
||||||
return {
|
return {
|
||||||
key: (username == 'admin' ? defaultList.admin : defaultList.user) as string[],
|
key: (username == "admin"
|
||||||
|
? defaultList.admin
|
||||||
|
: defaultList.user) as string[],
|
||||||
defaultList,
|
defaultList,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
export const useSidebarStore = defineStore('sidebar', {
|
export const useSidebarStore = defineStore("sidebar", {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
collapse: false,
|
collapse: false,
|
||||||
bgColor: localStorage.getItem('sidebar-bg-color') || '#324157',
|
bgColor: localStorage.getItem("sidebar-bg-color") || "#324157",
|
||||||
textColor: localStorage.getItem('sidebar-text-color') || '#bfcbd9'
|
textColor: localStorage.getItem("sidebar-text-color") || "#bfcbd9",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getters: {},
|
getters: {},
|
||||||
|
|
@ -15,11 +15,11 @@ export const useSidebarStore = defineStore('sidebar', {
|
||||||
},
|
},
|
||||||
setBgColor(color: string) {
|
setBgColor(color: string) {
|
||||||
this.bgColor = color;
|
this.bgColor = color;
|
||||||
localStorage.setItem('sidebar-bg-color', color);
|
localStorage.setItem("sidebar-bg-color", color);
|
||||||
},
|
},
|
||||||
setTextColor(color: string) {
|
setTextColor(color: string) {
|
||||||
this.textColor = color;
|
this.textColor = color;
|
||||||
localStorage.setItem('sidebar-text-color', color);
|
localStorage.setItem("sidebar-text-color", color);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
interface ListItem {
|
interface ListItem {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
@ -6,19 +6,19 @@ interface ListItem {
|
||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useTabsStore = defineStore('tabs', {
|
export const useTabsStore = defineStore("tabs", {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
list: <ListItem[]>[]
|
list: <ListItem[]>[],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getters: {
|
getters: {
|
||||||
show: state => {
|
show: (state) => {
|
||||||
return state.list.length > 0;
|
return state.list.length > 0;
|
||||||
},
|
},
|
||||||
nameList: state => {
|
nameList: (state) => {
|
||||||
return state.list.map(item => item.name);
|
return state.list.map((item) => item.name);
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
delTabsItem(index: number) {
|
delTabsItem(index: number) {
|
||||||
|
|
@ -42,12 +42,12 @@ export const useTabsStore = defineStore('tabs', {
|
||||||
} else if (i > 0) {
|
} else if (i > 0) {
|
||||||
data.$router.push(this.list[i - 1].path);
|
data.$router.push(this.list[i - 1].path);
|
||||||
} else {
|
} else {
|
||||||
data.$router.push('/');
|
data.$router.push("/");
|
||||||
}
|
}
|
||||||
this.list.splice(i, 1);
|
this.list.splice(i, 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,58 +1,61 @@
|
||||||
import { mix, setProperty } from '@/utils';
|
import { mix, setProperty } from "@/utils";
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from "pinia";
|
||||||
|
|
||||||
export const useThemeStore = defineStore('theme', {
|
export const useThemeStore = defineStore("theme", {
|
||||||
state: () => {
|
state: () => {
|
||||||
return {
|
return {
|
||||||
primary: '',
|
primary: "",
|
||||||
success: '',
|
success: "",
|
||||||
warning: '',
|
warning: "",
|
||||||
danger: '',
|
danger: "",
|
||||||
info: '',
|
info: "",
|
||||||
headerBgColor: '#242f42',
|
headerBgColor: "#242f42",
|
||||||
headerTextColor: '#fff',
|
headerTextColor: "#fff",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getters: {},
|
getters: {},
|
||||||
actions: {
|
actions: {
|
||||||
initTheme() {
|
initTheme() {
|
||||||
['primary', 'success', 'warning', 'danger', 'info'].forEach((type) => {
|
["primary", "success", "warning", "danger", "info"].forEach((type) => {
|
||||||
const color = localStorage.getItem(`theme-${type}`) || '';
|
const color = localStorage.getItem(`theme-${type}`) || "";
|
||||||
if (color) {
|
if (color) {
|
||||||
this.setPropertyColor(color, type); // 设置主题色
|
this.setPropertyColor(color, type); // 设置主题色
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const headerBgColor = localStorage.getItem('header-bg-color');
|
const headerBgColor = localStorage.getItem("header-bg-color");
|
||||||
headerBgColor && this.setHeaderBgColor(headerBgColor);
|
headerBgColor && this.setHeaderBgColor(headerBgColor);
|
||||||
const headerTextColor = localStorage.getItem('header-text-color');
|
const headerTextColor = localStorage.getItem("header-text-color");
|
||||||
headerTextColor && this.setHeaderTextColor(headerTextColor);
|
headerTextColor && this.setHeaderTextColor(headerTextColor);
|
||||||
},
|
},
|
||||||
resetTheme() {
|
resetTheme() {
|
||||||
['primary', 'success', 'warning', 'danger', 'info'].forEach((type) => {
|
["primary", "success", "warning", "danger", "info"].forEach((type) => {
|
||||||
this.setPropertyColor('', type); // 重置主题色
|
this.setPropertyColor("", type); // 重置主题色
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
setPropertyColor(color: string, type: string = 'primary') {
|
setPropertyColor(color: string, type: string = "primary") {
|
||||||
this[type] = color;
|
this[type] = color;
|
||||||
setProperty(`--el-color-${type}`, color);
|
setProperty(`--el-color-${type}`, color);
|
||||||
localStorage.setItem(`theme-${type}`, color);
|
localStorage.setItem(`theme-${type}`, color);
|
||||||
this.setThemeLight(type);
|
this.setThemeLight(type);
|
||||||
},
|
},
|
||||||
setThemeLight(type: string = 'primary') {
|
setThemeLight(type: string = "primary") {
|
||||||
[3, 5, 7, 8, 9].forEach((v) => {
|
[3, 5, 7, 8, 9].forEach((v) => {
|
||||||
setProperty(`--el-color-${type}-light-${v}`, mix('#ffffff', this[type], v / 10));
|
setProperty(
|
||||||
|
`--el-color-${type}-light-${v}`,
|
||||||
|
mix("#ffffff", this[type], v / 10)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
setProperty(`--el-color-${type}-dark-2`, mix('#ffffff', this[type], 0.2));
|
setProperty(`--el-color-${type}-dark-2`, mix("#ffffff", this[type], 0.2));
|
||||||
},
|
},
|
||||||
setHeaderBgColor(color: string) {
|
setHeaderBgColor(color: string) {
|
||||||
this.headerBgColor = color;
|
this.headerBgColor = color;
|
||||||
setProperty('--header-bg-color', color);
|
setProperty("--header-bg-color", color);
|
||||||
localStorage.setItem(`header-bg-color`, color);
|
localStorage.setItem(`header-bg-color`, color);
|
||||||
},
|
},
|
||||||
setHeaderTextColor(color: string) {
|
setHeaderTextColor(color: string) {
|
||||||
this.headerTextColor = color;
|
this.headerTextColor = color;
|
||||||
setProperty('--header-text-color', color);
|
setProperty("--header-text-color", color);
|
||||||
localStorage.setItem(`header-text-color`, color);
|
localStorage.setItem(`header-text-color`, color);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -2,7 +2,6 @@ export interface FormOption {
|
||||||
list: FormOptionList[];
|
list: FormOptionList[];
|
||||||
labelWidth?: number | string;
|
labelWidth?: number | string;
|
||||||
span?: number;
|
span?: number;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FormOptionList {
|
export interface FormOptionList {
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
|
|
||||||
export interface Role {
|
export interface Role {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
key: string;
|
key: string;
|
||||||
status: boolean;
|
status: boolean;
|
||||||
permiss: string[]
|
permiss: string[];
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
export interface User {
|
export interface User {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -1,14 +1,22 @@
|
||||||
export const setProperty = (prop: string, val: any, dom = document.documentElement) => {
|
export const setProperty = (
|
||||||
|
prop: string,
|
||||||
|
val: any,
|
||||||
|
dom = document.documentElement
|
||||||
|
) => {
|
||||||
dom.style.setProperty(prop, val);
|
dom.style.setProperty(prop, val);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const mix = (color1: string, color2: string, weight: number = 0.5): string => {
|
export const mix = (
|
||||||
let color = '#';
|
color1: string,
|
||||||
|
color2: string,
|
||||||
|
weight: number = 0.5
|
||||||
|
): string => {
|
||||||
|
let color = "#";
|
||||||
for (let i = 0; i <= 2; i++) {
|
for (let i = 0; i <= 2; i++) {
|
||||||
const c1 = parseInt(color1.substring(1 + i * 2, 3 + i * 2), 16);
|
const c1 = parseInt(color1.substring(1 + i * 2, 3 + i * 2), 16);
|
||||||
const c2 = parseInt(color2.substring(1 + i * 2, 3 + i * 2), 16);
|
const c2 = parseInt(color2.substring(1 + i * 2, 3 + i * 2), 16);
|
||||||
const c = Math.round(c1 * weight + c2 * (1 - weight));
|
const c = Math.round(c1 * weight + c2 * (1 - weight));
|
||||||
color += c.toString(16).padStart(2, '0');
|
color += c.toString(16).padStart(2, "0");
|
||||||
}
|
}
|
||||||
return color;
|
return color;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
import axios, { AxiosInstance, AxiosError, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
|
import axios, {
|
||||||
|
AxiosInstance,
|
||||||
|
AxiosError,
|
||||||
|
AxiosResponse,
|
||||||
|
InternalAxiosRequestConfig,
|
||||||
|
} from "axios";
|
||||||
|
|
||||||
const service: AxiosInstance = axios.create({
|
const service: AxiosInstance = axios.create({
|
||||||
timeout: 5000
|
baseURL: import.meta.env.VITE_APP_BASE_API,
|
||||||
|
timeout: 5000,
|
||||||
});
|
});
|
||||||
|
|
||||||
service.interceptors.request.use(
|
service.interceptors.request.use(
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,9 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="plugins-tips">
|
<div class="plugins-tips">
|
||||||
vue-echarts:Apache ECharts™ 的 Vue.js 组件。 访问地址:
|
vue-echarts:Apache ECharts™ 的 Vue.js 组件。 访问地址:
|
||||||
<a href="https://github.com/ecomfe/vue-echarts" target="_blank">vue-echarts</a>
|
<a href="https://github.com/ecomfe/vue-echarts" target="_blank"
|
||||||
|
>vue-echarts</a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<el-card class="mgb20" shadow="hover">
|
<el-card class="mgb20" shadow="hover">
|
||||||
<template #header>
|
<template #header>
|
||||||
|
|
@ -44,20 +46,27 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="echarts">
|
<script setup lang="ts" name="echarts">
|
||||||
import { registerMap, use } from 'echarts/core';
|
import { registerMap, use } from "echarts/core";
|
||||||
import { BarChart, LineChart, PieChart, MapChart } from 'echarts/charts';
|
import { BarChart, LineChart, PieChart, MapChart } from "echarts/charts";
|
||||||
import {
|
import {
|
||||||
GridComponent,
|
GridComponent,
|
||||||
TooltipComponent,
|
TooltipComponent,
|
||||||
LegendComponent,
|
LegendComponent,
|
||||||
TitleComponent,
|
TitleComponent,
|
||||||
VisualMapComponent,
|
VisualMapComponent,
|
||||||
} from 'echarts/components';
|
} from "echarts/components";
|
||||||
import { CanvasRenderer } from 'echarts/renderers';
|
import { CanvasRenderer } from "echarts/renderers";
|
||||||
import VChart from 'vue-echarts';
|
import VChart from "vue-echarts";
|
||||||
import 'echarts-wordcloud';
|
import "echarts-wordcloud";
|
||||||
import { barOptions, lineOptions, pieOptions, ringOptions, wordOptions, mapOptions } from './options';
|
import {
|
||||||
import chinaMap from '@/utils/china';
|
barOptions,
|
||||||
|
lineOptions,
|
||||||
|
pieOptions,
|
||||||
|
ringOptions,
|
||||||
|
wordOptions,
|
||||||
|
mapOptions,
|
||||||
|
} from "./options";
|
||||||
|
import chinaMap from "@/utils/china";
|
||||||
use([
|
use([
|
||||||
CanvasRenderer,
|
CanvasRenderer,
|
||||||
BarChart,
|
BarChart,
|
||||||
|
|
@ -70,7 +79,7 @@ use([
|
||||||
TitleComponent,
|
TitleComponent,
|
||||||
VisualMapComponent,
|
VisualMapComponent,
|
||||||
]);
|
]);
|
||||||
registerMap('china', chinaMap);
|
registerMap("china", chinaMap);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
||||||
|
|
@ -1,63 +1,63 @@
|
||||||
import { graphic } from 'echarts/core';
|
import { graphic } from "echarts/core";
|
||||||
export const barOptions = {
|
export const barOptions = {
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: 'category',
|
type: "category",
|
||||||
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
|
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
type: 'value',
|
type: "value",
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: "axis",
|
||||||
axisPointer: {
|
axisPointer: {
|
||||||
type: 'shadow',
|
type: "shadow",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
color: ['#009688', '#f44336'],
|
color: ["#009688", "#f44336"],
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
data: [120, 200, 150, 80, 70, 110, 130],
|
data: [120, 200, 150, 80, 70, 110, 130],
|
||||||
type: 'bar',
|
type: "bar",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
data: [180, 230, 190, 120, 110, 230, 235],
|
data: [180, 230, 190, 120, 110, 230, 235],
|
||||||
type: 'bar',
|
type: "bar",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const lineOptions = {
|
export const lineOptions = {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: "axis",
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
left: '3%',
|
left: "3%",
|
||||||
right: '4%',
|
right: "4%",
|
||||||
bottom: '3%',
|
bottom: "3%",
|
||||||
containLabel: true,
|
containLabel: true,
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: 'category',
|
type: "category",
|
||||||
boundaryGap: false,
|
boundaryGap: false,
|
||||||
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
|
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
type: 'value',
|
type: "value",
|
||||||
},
|
},
|
||||||
color: ['#009688', '#f44336'],
|
color: ["#009688", "#f44336"],
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: 'Email',
|
name: "Email",
|
||||||
type: 'line',
|
type: "line",
|
||||||
stack: 'Total',
|
stack: "Total",
|
||||||
areaStyle: {},
|
areaStyle: {},
|
||||||
smooth: true,
|
smooth: true,
|
||||||
data: [120, 132, 101, 134, 90, 230, 210],
|
data: [120, 132, 101, 134, 90, 230, 210],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Union Ads',
|
name: "Union Ads",
|
||||||
type: 'line',
|
type: "line",
|
||||||
stack: 'Total',
|
stack: "Total",
|
||||||
areaStyle: {},
|
areaStyle: {},
|
||||||
smooth: true,
|
smooth: true,
|
||||||
data: [220, 182, 191, 234, 290, 330, 310],
|
data: [220, 182, 191, 234, 290, 330, 310],
|
||||||
|
|
@ -67,34 +67,34 @@ export const lineOptions = {
|
||||||
|
|
||||||
export const pieOptions = {
|
export const pieOptions = {
|
||||||
title: {
|
title: {
|
||||||
text: 'Referer of a Website',
|
text: "Referer of a Website",
|
||||||
subtext: 'Fake Data',
|
subtext: "Fake Data",
|
||||||
left: 'center',
|
left: "center",
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'item',
|
trigger: "item",
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
orient: 'vertical',
|
orient: "vertical",
|
||||||
left: 'left',
|
left: "left",
|
||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: 'Access From',
|
name: "Access From",
|
||||||
type: 'pie',
|
type: "pie",
|
||||||
radius: '50%',
|
radius: "50%",
|
||||||
data: [
|
data: [
|
||||||
{ value: 1048, name: 'Search Engine' },
|
{ value: 1048, name: "Search Engine" },
|
||||||
{ value: 735, name: 'Direct' },
|
{ value: 735, name: "Direct" },
|
||||||
{ value: 580, name: 'Email' },
|
{ value: 580, name: "Email" },
|
||||||
{ value: 484, name: 'Union Ads' },
|
{ value: 484, name: "Union Ads" },
|
||||||
{ value: 300, name: 'Video Ads' },
|
{ value: 300, name: "Video Ads" },
|
||||||
],
|
],
|
||||||
emphasis: {
|
emphasis: {
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
shadowBlur: 10,
|
shadowBlur: 10,
|
||||||
shadowOffsetX: 0,
|
shadowOffsetX: 0,
|
||||||
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
shadowColor: "rgba(0, 0, 0, 0.5)",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -104,73 +104,73 @@ export const pieOptions = {
|
||||||
export const wordOptions = {
|
export const wordOptions = {
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
type: 'wordCloud',
|
type: "wordCloud",
|
||||||
rotationRange: [0, 0],
|
rotationRange: [0, 0],
|
||||||
autoSize: {
|
autoSize: {
|
||||||
enable: true,
|
enable: true,
|
||||||
minSize: 14,
|
minSize: 14,
|
||||||
},
|
},
|
||||||
textStyle: {
|
textStyle: {
|
||||||
fontFamily: '微软雅黑,sans-serif',
|
fontFamily: "微软雅黑,sans-serif",
|
||||||
color: function () {
|
color: function () {
|
||||||
return (
|
return (
|
||||||
'rgb(' +
|
"rgb(" +
|
||||||
[
|
[
|
||||||
Math.round(Math.random() * 160),
|
Math.round(Math.random() * 160),
|
||||||
Math.round(Math.random() * 160),
|
Math.round(Math.random() * 160),
|
||||||
Math.round(Math.random() * 160),
|
Math.round(Math.random() * 160),
|
||||||
].join(',') +
|
].join(",") +
|
||||||
')'
|
")"
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
name: 'Vue',
|
name: "Vue",
|
||||||
value: 10000,
|
value: 10000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'React',
|
name: "React",
|
||||||
value: 9000,
|
value: 9000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '图表',
|
name: "图表",
|
||||||
value: 4000,
|
value: 4000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '产品',
|
name: "产品",
|
||||||
value: 7000,
|
value: 7000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'vue-manage-system',
|
name: "vue-manage-system",
|
||||||
value: 2000,
|
value: 2000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'element-plus',
|
name: "element-plus",
|
||||||
value: 6000,
|
value: 6000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '管理系统',
|
name: "管理系统",
|
||||||
value: 5000,
|
value: 5000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '前端',
|
name: "前端",
|
||||||
value: 4000,
|
value: 4000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '测试',
|
name: "测试",
|
||||||
value: 3000,
|
value: 3000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '后端',
|
name: "后端",
|
||||||
value: 8000,
|
value: 8000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '软件开发',
|
name: "软件开发",
|
||||||
value: 6000,
|
value: 6000,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '程序员',
|
name: "程序员",
|
||||||
value: 4000,
|
value: 4000,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
@ -180,44 +180,44 @@ export const wordOptions = {
|
||||||
|
|
||||||
export const ringOptions = {
|
export const ringOptions = {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'item',
|
trigger: "item",
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
top: '5%',
|
top: "5%",
|
||||||
left: 'center',
|
left: "center",
|
||||||
},
|
},
|
||||||
|
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
name: 'Access From',
|
name: "Access From",
|
||||||
type: 'pie',
|
type: "pie",
|
||||||
radius: ['40%', '70%'],
|
radius: ["40%", "70%"],
|
||||||
avoidLabelOverlap: false,
|
avoidLabelOverlap: false,
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
borderColor: '#fff',
|
borderColor: "#fff",
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
},
|
},
|
||||||
label: {
|
label: {
|
||||||
show: false,
|
show: false,
|
||||||
position: 'center',
|
position: "center",
|
||||||
},
|
},
|
||||||
emphasis: {
|
emphasis: {
|
||||||
label: {
|
label: {
|
||||||
show: true,
|
show: true,
|
||||||
fontSize: 40,
|
fontSize: 40,
|
||||||
fontWeight: 'bold',
|
fontWeight: "bold",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
labelLine: {
|
labelLine: {
|
||||||
show: false,
|
show: false,
|
||||||
},
|
},
|
||||||
data: [
|
data: [
|
||||||
{ value: 1048, name: 'Search Engine' },
|
{ value: 1048, name: "Search Engine" },
|
||||||
{ value: 735, name: 'Direct' },
|
{ value: 735, name: "Direct" },
|
||||||
{ value: 580, name: 'Email' },
|
{ value: 580, name: "Email" },
|
||||||
{ value: 484, name: 'Union Ads' },
|
{ value: 484, name: "Union Ads" },
|
||||||
{ value: 300, name: 'Video Ads' },
|
{ value: 300, name: "Video Ads" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
@ -225,33 +225,33 @@ export const ringOptions = {
|
||||||
|
|
||||||
export const dashOpt1 = {
|
export const dashOpt1 = {
|
||||||
xAxis: {
|
xAxis: {
|
||||||
type: 'category',
|
type: "category",
|
||||||
boundaryGap: false,
|
boundaryGap: false,
|
||||||
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
|
data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
|
||||||
},
|
},
|
||||||
yAxis: {
|
yAxis: {
|
||||||
type: 'value',
|
type: "value",
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
top: '2%',
|
top: "2%",
|
||||||
left: '2%',
|
left: "2%",
|
||||||
right: '3%',
|
right: "3%",
|
||||||
bottom: '2%',
|
bottom: "2%",
|
||||||
containLabel: true,
|
containLabel: true,
|
||||||
},
|
},
|
||||||
color: ['#009688', '#f44336'],
|
color: ["#009688", "#f44336"],
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
type: 'line',
|
type: "line",
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
color: new graphic.LinearGradient(0, 0, 0, 1, [
|
color: new graphic.LinearGradient(0, 0, 0, 1, [
|
||||||
{
|
{
|
||||||
offset: 0,
|
offset: 0,
|
||||||
color: 'rgba(0, 150, 136,0.8)',
|
color: "rgba(0, 150, 136,0.8)",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
offset: 1,
|
offset: 1,
|
||||||
color: 'rgba(0, 150, 136,0.2)',
|
color: "rgba(0, 150, 136,0.2)",
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
|
|
@ -259,7 +259,7 @@ export const dashOpt1 = {
|
||||||
data: [120, 132, 301, 134, 90, 230, 210],
|
data: [120, 132, 301, 134, 90, 230, 210],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'line',
|
type: "line",
|
||||||
smooth: true,
|
smooth: true,
|
||||||
data: [220, 122, 191, 234, 190, 130, 310],
|
data: [220, 122, 191, 234, 190, 130, 310],
|
||||||
},
|
},
|
||||||
|
|
@ -268,26 +268,26 @@ export const dashOpt1 = {
|
||||||
|
|
||||||
export const dashOpt2 = {
|
export const dashOpt2 = {
|
||||||
legend: {
|
legend: {
|
||||||
bottom: '1%',
|
bottom: "1%",
|
||||||
left: 'center',
|
left: "center",
|
||||||
},
|
},
|
||||||
color: ['#3f51b5', '#009688', '#f44336', '#00bcd4', '#1ABC9C'],
|
color: ["#3f51b5", "#009688", "#f44336", "#00bcd4", "#1ABC9C"],
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
type: 'pie',
|
type: "pie",
|
||||||
radius: ['40%', '70%'],
|
radius: ["40%", "70%"],
|
||||||
avoidLabelOverlap: false,
|
avoidLabelOverlap: false,
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
borderColor: '#fff',
|
borderColor: "#fff",
|
||||||
borderWidth: 2,
|
borderWidth: 2,
|
||||||
},
|
},
|
||||||
data: [
|
data: [
|
||||||
{ value: 1048, name: '数码' },
|
{ value: 1048, name: "数码" },
|
||||||
{ value: 735, name: '食品' },
|
{ value: 735, name: "食品" },
|
||||||
{ value: 580, name: '母婴' },
|
{ value: 580, name: "母婴" },
|
||||||
{ value: 484, name: '家电' },
|
{ value: 484, name: "家电" },
|
||||||
{ value: 300, name: '运动' },
|
{ value: 300, name: "运动" },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
@ -295,10 +295,10 @@ export const dashOpt2 = {
|
||||||
|
|
||||||
export const mapOptions = {
|
export const mapOptions = {
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'item',
|
trigger: "item",
|
||||||
},
|
},
|
||||||
geo: {
|
geo: {
|
||||||
map: 'china',
|
map: "china",
|
||||||
roam: false,
|
roam: false,
|
||||||
emphasis: {
|
emphasis: {
|
||||||
label: {
|
label: {
|
||||||
|
|
@ -313,32 +313,32 @@ export const mapOptions = {
|
||||||
realtime: false,
|
realtime: false,
|
||||||
calculable: false,
|
calculable: false,
|
||||||
inRange: {
|
inRange: {
|
||||||
color: ['#d2e0f5', '#71A9FF'],
|
color: ["#d2e0f5", "#71A9FF"],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
series: [
|
series: [
|
||||||
{
|
{
|
||||||
geoIndex: 0,
|
geoIndex: 0,
|
||||||
name: '地域分布',
|
name: "地域分布",
|
||||||
type: 'map',
|
type: "map",
|
||||||
coordinateSystem: 'geo',
|
coordinateSystem: "geo",
|
||||||
map: 'china',
|
map: "china",
|
||||||
data: [
|
data: [
|
||||||
{ name: '北京', value: 100 },
|
{ name: "北京", value: 100 },
|
||||||
{ name: '上海', value: 100 },
|
{ name: "上海", value: 100 },
|
||||||
{ name: '广东', value: 100 },
|
{ name: "广东", value: 100 },
|
||||||
{ name: '浙江', value: 90 },
|
{ name: "浙江", value: 90 },
|
||||||
{ name: '江西', value: 80 },
|
{ name: "江西", value: 80 },
|
||||||
{ name: '山东', value: 70 },
|
{ name: "山东", value: 70 },
|
||||||
{ name: '广西', value: 60 },
|
{ name: "广西", value: 60 },
|
||||||
{ name: '河南', value: 50 },
|
{ name: "河南", value: 50 },
|
||||||
{ name: '河南', value: 40 },
|
{ name: "河南", value: 40 },
|
||||||
{ name: '青海', value: 70 },
|
{ name: "青海", value: 70 },
|
||||||
{ name: '河南', value: 30 },
|
{ name: "河南", value: 30 },
|
||||||
{ name: '黑龙江', value: 20 },
|
{ name: "黑龙江", value: 20 },
|
||||||
{ name: '新疆', value: 20 },
|
{ name: "新疆", value: 20 },
|
||||||
{ name: '云南', value: 20 },
|
{ name: "云南", value: 20 },
|
||||||
{ name: '甘肃', value: 20 },
|
{ name: "甘肃", value: 20 },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -2,116 +2,126 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="plugins-tips">
|
<div class="plugins-tips">
|
||||||
vue-schart:vue.js封装sChart.js的图表组件。 访问地址:
|
vue-schart:vue.js封装sChart.js的图表组件。 访问地址:
|
||||||
<a href="https://github.com/lin-xin/vue-schart" target="_blank">vue-schart</a>
|
<a href="https://github.com/lin-xin/vue-schart" target="_blank"
|
||||||
|
>vue-schart</a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<el-card class="mgb20" shadow="hover">
|
<el-card class="mgb20" shadow="hover">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="content-title">柱状图</div>
|
<div class="content-title">柱状图</div>
|
||||||
</template>
|
</template>
|
||||||
<schart class="schart" canvasId="bar" :options="options1"></schart>
|
<schart class="schart" canvasId="bar" :options="options1" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-card class="mgb20" shadow="hover">
|
<el-card class="mgb20" shadow="hover">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="content-title">折线图</div>
|
<div class="content-title">折线图</div>
|
||||||
</template>
|
</template>
|
||||||
<schart class="schart" canvasId="line" :options="options2"></schart>
|
<schart class="schart" canvasId="line" :options="options2" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-card class="mgb20" shadow="hover">
|
<el-card class="mgb20" shadow="hover">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="content-title">饼状图</div>
|
<div class="content-title">饼状图</div>
|
||||||
</template>
|
</template>
|
||||||
<schart class="schart" canvasId="pie" :options="options3"></schart>
|
<schart class="schart" canvasId="pie" :options="options3" />
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-card class="mgb20" shadow="hover">
|
<el-card class="mgb20" shadow="hover">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="content-title">环形图</div>
|
<div class="content-title">环形图</div>
|
||||||
</template>
|
</template>
|
||||||
<schart class="schart" canvasId="ring" :options="options4"></schart>
|
<schart class="schart" canvasId="ring" :options="options4" />
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="schart">
|
<script setup lang="ts" name="schart">
|
||||||
import Schart from 'vue-schart';
|
import Schart from "vue-schart";
|
||||||
|
|
||||||
const options1 = {
|
const options1 = {
|
||||||
type: 'bar',
|
type: "bar",
|
||||||
title: {
|
title: {
|
||||||
text: '最近一周各品类销售图'
|
text: "最近一周各品类销售图",
|
||||||
},
|
},
|
||||||
colorList: ["#3f51b5", "#009688", "#f44336", "#00bcd4", "#1ABC9C"],
|
colorList: ["#3f51b5", "#009688", "#f44336", "#00bcd4", "#1ABC9C"],
|
||||||
labels: ['周一', '周二', '周三', '周四', '周五'],
|
labels: ["周一", "周二", "周三", "周四", "周五"],
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: '家电',
|
label: "家电",
|
||||||
// fillColor: 'rgba(241, 49, 74, 0.5)',
|
// fillColor: 'rgba(241, 49, 74, 0.5)',
|
||||||
data: [234, 278, 270, 190, 230]
|
data: [234, 278, 270, 190, 230],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '百货',
|
label: "百货",
|
||||||
data: [164, 178, 190, 135, 160]
|
data: [164, 178, 190, 135, 160],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '食品',
|
label: "食品",
|
||||||
data: [144, 198, 150, 235, 120]
|
data: [144, 198, 150, 235, 120],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
const options2 = {
|
const options2 = {
|
||||||
type: 'line',
|
type: "line",
|
||||||
title: {
|
title: {
|
||||||
text: '最近几个月各品类销售趋势图'
|
text: "最近几个月各品类销售趋势图",
|
||||||
},
|
},
|
||||||
colorList: ["#3f51b5", "#009688", "#f44336", "#00bcd4", "#1ABC9C"],
|
colorList: ["#3f51b5", "#009688", "#f44336", "#00bcd4", "#1ABC9C"],
|
||||||
labels: ['6月', '7月', '8月', '9月', '10月'],
|
labels: ["6月", "7月", "8月", "9月", "10月"],
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: '家电',
|
label: "家电",
|
||||||
data: [234, 278, 270, 190, 230]
|
data: [234, 278, 270, 190, 230],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '百货',
|
label: "百货",
|
||||||
data: [164, 178, 150, 135, 160]
|
data: [164, 178, 150, 135, 160],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '食品',
|
label: "食品",
|
||||||
data: [114, 138, 200, 235, 190]
|
data: [114, 138, 200, 235, 190],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
const options3 = {
|
const options3 = {
|
||||||
type: 'pie',
|
type: "pie",
|
||||||
title: {
|
title: {
|
||||||
text: '服装品类销售饼状图'
|
text: "服装品类销售饼状图",
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
position: 'left'
|
position: "left",
|
||||||
},
|
},
|
||||||
colorList: ["#2196f3", '#673ab7', "#009688", "#1ABC9C", "#3f51b5", "#f44336", "#00bcd4"],
|
colorList: [
|
||||||
labels: ['T恤', '牛仔裤', '连衣裙', '毛衣', '七分裤', '短裙', '羽绒服'],
|
"#2196f3",
|
||||||
|
"#673ab7",
|
||||||
|
"#009688",
|
||||||
|
"#1ABC9C",
|
||||||
|
"#3f51b5",
|
||||||
|
"#f44336",
|
||||||
|
"#00bcd4",
|
||||||
|
],
|
||||||
|
labels: ["T恤", "牛仔裤", "连衣裙", "毛衣", "七分裤", "短裙", "羽绒服"],
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
data: [334, 278, 190, 235, 260, 200, 141]
|
data: [334, 278, 190, 235, 260, 200, 141],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
const options4 = {
|
const options4 = {
|
||||||
type: 'ring',
|
type: "ring",
|
||||||
title: {
|
title: {
|
||||||
text: '环形三等分'
|
text: "环形三等分",
|
||||||
},
|
},
|
||||||
showValue: false,
|
showValue: false,
|
||||||
legend: {
|
legend: {
|
||||||
position: 'bottom',
|
position: "bottom",
|
||||||
bottom: 40
|
bottom: 40,
|
||||||
},
|
},
|
||||||
colorList: ["#3f51b5", "#009688", "#f44336", "#00bcd4", "#1ABC9C"],
|
colorList: ["#3f51b5", "#009688", "#f44336", "#00bcd4", "#1ABC9C"],
|
||||||
labels: ['vue', 'react', 'angular'],
|
labels: ["vue", "react", "angular"],
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
data: [500, 500, 500]
|
data: [500, 500, 500],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,9 @@
|
||||||
<el-card shadow="hover">
|
<el-card shadow="hover">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
<p class="card-header-title">订单动态</p>
|
<p class="card-header-title">订单动态</p>
|
||||||
<p class="card-header-desc">最近一周订单状态,包括订单成交量和订单退货量</p>
|
<p class="card-header-desc">
|
||||||
|
最近一周订单状态,包括订单成交量和订单退货量
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<v-chart class="chart" :option="dashOpt1" />
|
<v-chart class="chart" :option="dashOpt1" />
|
||||||
</el-card>
|
</el-card>
|
||||||
|
|
@ -75,7 +77,11 @@
|
||||||
<p class="card-header-desc">最新的销售动态和活动信息</p>
|
<p class="card-header-desc">最新的销售动态和活动信息</p>
|
||||||
</div>
|
</div>
|
||||||
<el-timeline>
|
<el-timeline>
|
||||||
<el-timeline-item v-for="(activity, index) in activities" :key="index" :color="activity.color">
|
<el-timeline-item
|
||||||
|
v-for="(activity, index) in activities"
|
||||||
|
:key="index"
|
||||||
|
:color="activity.color"
|
||||||
|
>
|
||||||
<div class="timeline-item">
|
<div class="timeline-item">
|
||||||
<div>
|
<div>
|
||||||
<p>{{ activity.content }}</p>
|
<p>{{ activity.content }}</p>
|
||||||
|
|
@ -127,20 +133,20 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="dashboard">
|
<script setup lang="ts" name="dashboard">
|
||||||
import countup from '@/components/countup.vue';
|
import countup from "@/components/countup.vue";
|
||||||
import { use, registerMap } from 'echarts/core';
|
import { use, registerMap } from "echarts/core";
|
||||||
import { BarChart, LineChart, PieChart, MapChart } from 'echarts/charts';
|
import { BarChart, LineChart, PieChart, MapChart } from "echarts/charts";
|
||||||
import {
|
import {
|
||||||
GridComponent,
|
GridComponent,
|
||||||
TooltipComponent,
|
TooltipComponent,
|
||||||
LegendComponent,
|
LegendComponent,
|
||||||
TitleComponent,
|
TitleComponent,
|
||||||
VisualMapComponent,
|
VisualMapComponent,
|
||||||
} from 'echarts/components';
|
} from "echarts/components";
|
||||||
import { CanvasRenderer } from 'echarts/renderers';
|
import { CanvasRenderer } from "echarts/renderers";
|
||||||
import VChart from 'vue-echarts';
|
import VChart from "vue-echarts";
|
||||||
import { dashOpt1, dashOpt2, mapOptions } from './chart/options';
|
import { dashOpt1, dashOpt2, mapOptions } from "./chart/options";
|
||||||
import chinaMap from '@/utils/china';
|
import chinaMap from "@/utils/china";
|
||||||
use([
|
use([
|
||||||
CanvasRenderer,
|
CanvasRenderer,
|
||||||
BarChart,
|
BarChart,
|
||||||
|
|
@ -153,70 +159,70 @@ use([
|
||||||
VisualMapComponent,
|
VisualMapComponent,
|
||||||
MapChart,
|
MapChart,
|
||||||
]);
|
]);
|
||||||
registerMap('china', chinaMap);
|
registerMap("china", chinaMap);
|
||||||
const activities = [
|
const activities = [
|
||||||
{
|
{
|
||||||
content: '收藏商品',
|
content: "收藏商品",
|
||||||
description: 'xxx收藏了你的商品,就是不买',
|
description: "xxx收藏了你的商品,就是不买",
|
||||||
timestamp: '30分钟前',
|
timestamp: "30分钟前",
|
||||||
color: '#00bcd4',
|
color: "#00bcd4",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
content: '用户评价',
|
content: "用户评价",
|
||||||
description: 'xxx给了某某商品一个差评,吐血啊',
|
description: "xxx给了某某商品一个差评,吐血啊",
|
||||||
timestamp: '55分钟前',
|
timestamp: "55分钟前",
|
||||||
color: '#1ABC9C',
|
color: "#1ABC9C",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
content: '订单提交',
|
content: "订单提交",
|
||||||
description: 'xxx提交了订单,快去收钱吧',
|
description: "xxx提交了订单,快去收钱吧",
|
||||||
timestamp: '1小时前',
|
timestamp: "1小时前",
|
||||||
color: '#3f51b5',
|
color: "#3f51b5",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
content: '退款申请',
|
content: "退款申请",
|
||||||
description: 'xxx申请了仅退款,又要亏钱了',
|
description: "xxx申请了仅退款,又要亏钱了",
|
||||||
timestamp: '15小时前',
|
timestamp: "15小时前",
|
||||||
color: '#f44336',
|
color: "#f44336",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
content: '商品上架',
|
content: "商品上架",
|
||||||
description: '运营专员瞒着你上架了一辆飞机',
|
description: "运营专员瞒着你上架了一辆飞机",
|
||||||
timestamp: '1天前',
|
timestamp: "1天前",
|
||||||
color: '#009688',
|
color: "#009688",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const ranks = [
|
const ranks = [
|
||||||
{
|
{
|
||||||
title: '手机',
|
title: "手机",
|
||||||
value: 10000,
|
value: 10000,
|
||||||
percent: 80,
|
percent: 80,
|
||||||
color: '#f25e43',
|
color: "#f25e43",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '电脑',
|
title: "电脑",
|
||||||
value: 8000,
|
value: 8000,
|
||||||
percent: 70,
|
percent: 70,
|
||||||
color: '#00bcd4',
|
color: "#00bcd4",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '相机',
|
title: "相机",
|
||||||
value: 6000,
|
value: 6000,
|
||||||
percent: 60,
|
percent: 60,
|
||||||
color: '#64d572',
|
color: "#64d572",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '衣服',
|
title: "衣服",
|
||||||
value: 5000,
|
value: 5000,
|
||||||
percent: 55,
|
percent: 55,
|
||||||
color: '#e9a745',
|
color: "#e9a745",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '书籍',
|
title: "书籍",
|
||||||
value: 4000,
|
value: 4000,
|
||||||
percent: 50,
|
percent: 50,
|
||||||
color: '#009688',
|
color: "#009688",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@
|
||||||
<div>{{ data.date.getDate() }}</div>
|
<div>{{ data.date.getDate() }}</div>
|
||||||
<div class="notes-container" v-if="notes[data.day.toString()]">
|
<div class="notes-container" v-if="notes[data.day.toString()]">
|
||||||
<div class="notes" v-for="note in notes[data.day.toString()]">
|
<div class="notes" v-for="note in notes[data.day.toString()]">
|
||||||
<span :class="note.status === 1 ? 'text-success' : 'text-danger'"></span>
|
<span
|
||||||
|
:class="note.status === 1 ? 'text-success' : 'text-danger'"
|
||||||
|
></span>
|
||||||
<div class="note-title">{{ note.title }}</div>
|
<div class="note-title">{{ note.title }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -15,7 +17,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from "vue";
|
||||||
|
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);
|
const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000);
|
||||||
|
|
@ -26,14 +28,14 @@ const yesterdayDate = yesterday.toISOString().slice(0, 10);
|
||||||
|
|
||||||
const notes: any = {
|
const notes: any = {
|
||||||
[todayDate]: [
|
[todayDate]: [
|
||||||
{ title: '吃饭', status: 1 },
|
{ title: "吃饭", status: 1 },
|
||||||
{ title: '睡觉', status: 0 },
|
{ title: "睡觉", status: 0 },
|
||||||
{ title: '吃饭', status: 1 },
|
{ title: "吃饭", status: 1 },
|
||||||
{ title: '睡觉', status: 0 },
|
{ title: "睡觉", status: 0 },
|
||||||
{ title: '吃饭', status: 1 },
|
{ title: "吃饭", status: 1 },
|
||||||
{ title: '睡觉', status: 0 },
|
{ title: "睡觉", status: 0 },
|
||||||
],
|
],
|
||||||
[yesterdayDate]: [{ title: '参加会议', status: 0 }],
|
[yesterdayDate]: [{ title: "参加会议", status: 0 }],
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,10 +36,10 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
const imgs = [
|
const imgs = [
|
||||||
'https://cdn.pixabay.com/photo/2017/08/07/08/23/sea-2601374_640.jpg',
|
"https://cdn.pixabay.com/photo/2017/08/07/08/23/sea-2601374_640.jpg",
|
||||||
'https://cdn.pixabay.com/photo/2020/02/11/10/24/lake-4839058_640.jpg',
|
"https://cdn.pixabay.com/photo/2020/02/11/10/24/lake-4839058_640.jpg",
|
||||||
'https://cdn.pixabay.com/photo/2024/02/21/08/06/coast-8587004_640.jpg',
|
"https://cdn.pixabay.com/photo/2024/02/21/08/06/coast-8587004_640.jpg",
|
||||||
'https://cdn.pixabay.com/photo/2023/07/29/10/21/grasshopper-8156626_640.jpg',
|
"https://cdn.pixabay.com/photo/2023/07/29/10/21/grasshopper-8156626_640.jpg",
|
||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,34 +5,43 @@
|
||||||
<el-radio-button value="right">Right</el-radio-button>
|
<el-radio-button value="right">Right</el-radio-button>
|
||||||
<el-radio-button value="top">Top</el-radio-button>
|
<el-radio-button value="top">Top</el-radio-button>
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
<el-form ref="formRef" :rules="rules" :model="form" label-width="120px" :label-position="labelPosition">
|
<el-form
|
||||||
|
ref="formRef"
|
||||||
|
:rules="rules"
|
||||||
|
:model="form"
|
||||||
|
label-width="120px"
|
||||||
|
:label-position="labelPosition"
|
||||||
|
>
|
||||||
<el-row :gutter="50">
|
<el-row :gutter="50">
|
||||||
<el-col :span="10">
|
<el-col :span="10">
|
||||||
<el-form-item label="文本框" prop="name">
|
<el-form-item label="文本框" prop="name">
|
||||||
<el-input v-model="form.name"></el-input>
|
<el-input v-model="form.name" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="数字框" prop="num">
|
<el-form-item label="数字框" prop="num">
|
||||||
<el-input-number v-model="form.num" :min="1" :max="10" />
|
<el-input-number v-model="form.num" :min="1" :max="10" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="日期选择" prop="date">
|
<el-form-item label="日期选择" prop="date">
|
||||||
<el-date-picker type="date" placeholder="选择日期" v-model="form.date"></el-date-picker>
|
<el-date-picker
|
||||||
|
type="date"
|
||||||
|
placeholder="选择日期"
|
||||||
|
v-model="form.date"
|
||||||
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="时间选择" prop="time">
|
<el-form-item label="时间选择" prop="time">
|
||||||
<el-time-picker placeholder="选择时间" v-model="form.time">
|
<el-time-picker placeholder="选择时间" v-model="form.time" />
|
||||||
</el-time-picker>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="选择器" prop="region">
|
<el-form-item label="选择器" prop="region">
|
||||||
<el-select v-model="form.region" placeholder="请选择">
|
<el-select v-model="form.region" placeholder="请选择">
|
||||||
<el-option key="小明" label="小明" value="小明"></el-option>
|
<el-option key="小明" label="小明" value="小明" />
|
||||||
<el-option key="小红" label="小红" value="小红"></el-option>
|
<el-option key="小红" label="小红" value="小红" />
|
||||||
<el-option key="小白" label="小白" value="小白"></el-option>
|
<el-option key="小白" label="小白" value="小白" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="城市级联" prop="options">
|
<el-form-item label="城市级联" prop="options">
|
||||||
<el-cascader :options="options" v-model="form.options"></el-cascader>
|
<el-cascader :options="options" v-model="form.options" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="文本框" prop="desc">
|
<el-form-item label="文本框" prop="desc">
|
||||||
<el-input type="textarea" rows="5" v-model="form.desc"></el-input>
|
<el-input type="textarea" rows="5" v-model="form.desc" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
|
|
@ -43,23 +52,23 @@
|
||||||
<el-slider v-model="form.num" :step="1" show-stops :max="10" />
|
<el-slider v-model="form.num" :step="1" show-stops :max="10" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="开关" prop="delivery">
|
<el-form-item label="开关" prop="delivery">
|
||||||
<el-switch v-model="form.delivery"></el-switch>
|
<el-switch v-model="form.delivery" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="颜色选择" prop="color">
|
<el-form-item label="颜色选择" prop="color">
|
||||||
<el-color-picker v-model="form.color" />
|
<el-color-picker v-model="form.color" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="多选框" prop="type">
|
<el-form-item label="多选框" prop="type">
|
||||||
<el-checkbox-group v-model="form.type">
|
<el-checkbox-group v-model="form.type">
|
||||||
<el-checkbox label="小明" value="小明" name="type"></el-checkbox>
|
<el-checkbox label="小明" value="小明" name="type" />
|
||||||
<el-checkbox label="小红" value="小红" name="type"></el-checkbox>
|
<el-checkbox label="小红" value="小红" name="type" />
|
||||||
<el-checkbox label="小白" value="小白" name="type"></el-checkbox>
|
<el-checkbox label="小白" value="小白" name="type" />
|
||||||
</el-checkbox-group>
|
</el-checkbox-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="单选框" prop="resource">
|
<el-form-item label="单选框" prop="resource">
|
||||||
<el-radio-group v-model="form.resource">
|
<el-radio-group v-model="form.resource">
|
||||||
<el-radio label="小明" value="小明"></el-radio>
|
<el-radio label="小明" value="小明" />
|
||||||
<el-radio label="小红" value="小红"></el-radio>
|
<el-radio label="小红" value="小红" />
|
||||||
<el-radio label="小白" value="小白"></el-radio>
|
<el-radio label="小白" value="小白" />
|
||||||
</el-radio-group>
|
</el-radio-group>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="穿梭框" prop="transfer">
|
<el-form-item label="穿梭框" prop="transfer">
|
||||||
|
|
@ -69,7 +78,9 @@
|
||||||
|
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="onSubmit(formRef)">表单提交</el-button>
|
<el-button type="primary" @click="onSubmit(formRef)"
|
||||||
|
>表单提交</el-button
|
||||||
|
>
|
||||||
<el-button @click="onReset(formRef)">重置表单</el-button>
|
<el-button @click="onReset(formRef)">重置表单</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
@ -79,56 +90,56 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="forms">
|
<script setup lang="ts" name="forms">
|
||||||
import { reactive, ref } from 'vue';
|
import { reactive, ref } from "vue";
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from "element-plus";
|
||||||
import type { FormInstance, FormProps, FormRules } from 'element-plus';
|
import type { FormInstance, FormProps, FormRules } from "element-plus";
|
||||||
const labelPosition = ref<FormProps['labelPosition']>('right')
|
const labelPosition = ref<FormProps["labelPosition"]>("right");
|
||||||
const options = [
|
const options = [
|
||||||
{
|
{
|
||||||
value: 'guangdong',
|
value: "guangdong",
|
||||||
label: '广东省',
|
label: "广东省",
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
value: 'guangzhou',
|
value: "guangzhou",
|
||||||
label: '广州市',
|
label: "广州市",
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
value: 'tianhe',
|
value: "tianhe",
|
||||||
label: '天河区',
|
label: "天河区",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'haizhu',
|
value: "haizhu",
|
||||||
label: '海珠区',
|
label: "海珠区",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'dongguan',
|
value: "dongguan",
|
||||||
label: '东莞市',
|
label: "东莞市",
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
value: 'changan',
|
value: "changan",
|
||||||
label: '长安镇',
|
label: "长安镇",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'humen',
|
value: "humen",
|
||||||
label: '虎门镇',
|
label: "虎门镇",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'hunan',
|
value: "hunan",
|
||||||
label: '湖南省',
|
label: "湖南省",
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
value: 'changsha',
|
value: "changsha",
|
||||||
label: '长沙市',
|
label: "长沙市",
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
value: 'yuelu',
|
value: "yuelu",
|
||||||
label: '岳麓区',
|
label: "岳麓区",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
@ -136,38 +147,37 @@ const options = [
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const rules: FormRules = {
|
const rules: FormRules = {
|
||||||
name: [{ required: true, message: '请输入表单名称', trigger: 'blur' }],
|
name: [{ required: true, message: "请输入表单名称", trigger: "blur" }],
|
||||||
};
|
};
|
||||||
const formRef = ref<FormInstance>();
|
const formRef = ref<FormInstance>();
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
name: '',
|
name: "",
|
||||||
region: '',
|
region: "",
|
||||||
date: '',
|
date: "",
|
||||||
time: '',
|
time: "",
|
||||||
delivery: true,
|
delivery: true,
|
||||||
type: ['小明'],
|
type: ["小明"],
|
||||||
resource: '小红',
|
resource: "小红",
|
||||||
desc: '',
|
desc: "",
|
||||||
options: [],
|
options: [],
|
||||||
color: '',
|
color: "",
|
||||||
num: 1,
|
num: 1,
|
||||||
rate: 0,
|
rate: 0,
|
||||||
transfer: [],
|
transfer: [],
|
||||||
|
|
||||||
});
|
});
|
||||||
const generateData = () => {
|
const generateData = () => {
|
||||||
const data = []
|
const data = [];
|
||||||
for (let i = 1; i <= 15; i++) {
|
for (let i = 1; i <= 15; i++) {
|
||||||
data.push({
|
data.push({
|
||||||
key: i,
|
key: i,
|
||||||
label: `Option ${i}`,
|
label: `Option ${i}`,
|
||||||
disabled: i % 4 === 0,
|
disabled: i % 4 === 0,
|
||||||
})
|
});
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
}
|
||||||
|
return data;
|
||||||
|
};
|
||||||
|
|
||||||
const transferData = ref(generateData())
|
const transferData = ref(generateData());
|
||||||
// 提交
|
// 提交
|
||||||
const onSubmit = (formEl: FormInstance | undefined) => {
|
const onSubmit = (formEl: FormInstance | undefined) => {
|
||||||
// 表单校验
|
// 表单校验
|
||||||
|
|
@ -175,7 +185,7 @@ const onSubmit = (formEl: FormInstance | undefined) => {
|
||||||
formEl.validate((valid) => {
|
formEl.validate((valid) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
console.log(form);
|
console.log(form);
|
||||||
ElMessage.success('提交成功!');
|
ElMessage.success("提交成功!");
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
|
|
||||||
<el-card class="mgb20" shadow="hover">
|
<el-card class="mgb20" shadow="hover">
|
||||||
<template #header>基础用法</template>
|
<template #header>基础用法</template>
|
||||||
<el-row>
|
<el-row>
|
||||||
|
|
@ -31,7 +29,9 @@
|
||||||
<template #header>CountUp.js</template>
|
<template #header>CountUp.js</template>
|
||||||
<div class="plugins-tips">
|
<div class="plugins-tips">
|
||||||
countup.js:用于快速创建以更有趣的方式显示数字数据的动画。 访问地址:
|
countup.js:用于快速创建以更有趣的方式显示数字数据的动画。 访问地址:
|
||||||
<a href="https://github.com/inorganik/countUp.js" target="_blank">countUp.js</a>
|
<a href="https://github.com/inorganik/countUp.js" target="_blank"
|
||||||
|
>countUp.js</a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="8" style="text-align: center">
|
<el-col :span="8" style="text-align: center">
|
||||||
|
|
@ -97,7 +97,11 @@
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-card shadow="hover" body-class="card-body">
|
<el-card shadow="hover" body-class="card-body">
|
||||||
<div class="card-content text-left">
|
<div class="card-content text-left">
|
||||||
<el-statistic :value-style="{ color: '#2d8cf0' }" title="日活跃用户量" :value="268500" />
|
<el-statistic
|
||||||
|
:value-style="{ color: '#2d8cf0' }"
|
||||||
|
title="日活跃用户量"
|
||||||
|
:value="268500"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<el-icon class="card-icon color1">
|
<el-icon class="card-icon color1">
|
||||||
<User />
|
<User />
|
||||||
|
|
@ -107,7 +111,11 @@
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-card shadow="hover" body-class="card-body">
|
<el-card shadow="hover" body-class="card-body">
|
||||||
<div class="card-content text-left">
|
<div class="card-content text-left">
|
||||||
<el-statistic :value-style="{ color: '#64d572' }" title="系统消息" :value="16800" />
|
<el-statistic
|
||||||
|
:value-style="{ color: '#64d572' }"
|
||||||
|
title="系统消息"
|
||||||
|
:value="16800"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<el-icon class="card-icon color2">
|
<el-icon class="card-icon color2">
|
||||||
<ChatDotRound />
|
<ChatDotRound />
|
||||||
|
|
@ -117,7 +125,11 @@
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-card shadow="hover" body-class="card-body">
|
<el-card shadow="hover" body-class="card-body">
|
||||||
<div class="card-content text-left">
|
<div class="card-content text-left">
|
||||||
<el-statistic :value-style="{ color: '#f25e43' }" title="商品数量" :value="8888" />
|
<el-statistic
|
||||||
|
:value-style="{ color: '#f25e43' }"
|
||||||
|
title="商品数量"
|
||||||
|
:value="8888"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<el-icon class="card-icon color3">
|
<el-icon class="card-icon color3">
|
||||||
<Goods />
|
<Goods />
|
||||||
|
|
@ -127,7 +139,11 @@
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-card shadow="hover" body-class="card-body">
|
<el-card shadow="hover" body-class="card-body">
|
||||||
<div class="card-content text-left">
|
<div class="card-content text-left">
|
||||||
<el-statistic :value-style="{ color: '#e9a745' }" title="今日订单量" :value="56888" />
|
<el-statistic
|
||||||
|
:value-style="{ color: '#e9a745' }"
|
||||||
|
title="今日订单量"
|
||||||
|
:value="56888"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<el-icon class="card-icon color4">
|
<el-icon class="card-icon color4">
|
||||||
<ShoppingCartFull />
|
<ShoppingCartFull />
|
||||||
|
|
@ -232,17 +248,17 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue'
|
import { ref } from "vue";
|
||||||
import { useTransition } from '@vueuse/core'
|
import { useTransition } from "@vueuse/core";
|
||||||
import countup from '@/components/countup.vue';
|
import countup from "@/components/countup.vue";
|
||||||
|
|
||||||
const source = ref(0)
|
const source = ref(0);
|
||||||
const outputValue = useTransition(source, {
|
const outputValue = useTransition(source, {
|
||||||
duration: 1500,
|
duration: 1500,
|
||||||
})
|
});
|
||||||
source.value = 172000
|
source.value = 172000;
|
||||||
|
|
||||||
const value = ref(Date.now() + 1000 * 60 * 60 * 7)
|
const value = ref(Date.now() + 1000 * 60 * 60 * 7);
|
||||||
const value1 = ref(1000);
|
const value1 = ref(1000);
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
value1.value = 8000;
|
value1.value = 8000;
|
||||||
|
|
@ -252,11 +268,11 @@ const options = {
|
||||||
decimalPlaces: 2,
|
decimalPlaces: 2,
|
||||||
duration: 5,
|
duration: 5,
|
||||||
useGrouping: false,
|
useGrouping: false,
|
||||||
prefix: '$',
|
prefix: "$",
|
||||||
separator: ',',
|
separator: ",",
|
||||||
decimal: '.',
|
decimal: ".",
|
||||||
suffix: '',
|
suffix: "",
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
|
@ -309,7 +325,6 @@ const options = {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.color0 {
|
.color0 {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,35 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="step-div" v-if="step === 0">
|
<div class="step-div" v-if="step === 0">
|
||||||
<p>输入注册时的邮箱,我们会发送验证码到您的邮箱</p>
|
<p>输入注册时的邮箱,我们会发送验证码到您的邮箱</p>
|
||||||
<el-input placeholder="请输入邮箱"></el-input>
|
<el-input placeholder="请输入邮箱" />
|
||||||
<el-button class="step-btn" type="primary" @click="step++">下一步</el-button>
|
<el-button class="step-btn" type="primary" @click="step++"
|
||||||
|
>下一步</el-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="step-div" v-else-if="step === 1">
|
<div class="step-div" v-else-if="step === 1">
|
||||||
<p>验证码已发送至您的邮箱,请输入验证码</p>
|
<p>验证码已发送至您的邮箱,请输入验证码</p>
|
||||||
<el-input placeholder="请输入验证码"></el-input>
|
<el-input placeholder="请输入验证码" />
|
||||||
<el-button class="step-btn" type="primary" @click="step++">下一步</el-button>
|
<el-button class="step-btn" type="primary" @click="step++"
|
||||||
|
>下一步</el-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="step-div" v-else-if="step === 2">
|
<div class="step-div" v-else-if="step === 2">
|
||||||
<p>请输入6位以上密码</p>
|
<p>请输入6位以上密码</p>
|
||||||
<el-input placeholder="请输入新密码"></el-input>
|
<el-input placeholder="请输入新密码" />
|
||||||
<el-button class="step-btn" type="primary" @click="step++">保存</el-button>
|
<el-button class="step-btn" type="primary" @click="step++"
|
||||||
|
>保存</el-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<el-result icon="success" title="保存成功" sub-title="请退出后重新登录"></el-result>
|
<el-result icon="success" title="保存成功" sub-title="请退出后重新登录" />
|
||||||
</div>
|
</div>
|
||||||
<el-steps class="step-style" :active="step" align-center finish-status="success">
|
<el-steps
|
||||||
|
class="step-style"
|
||||||
|
:active="step"
|
||||||
|
align-center
|
||||||
|
finish-status="success"
|
||||||
|
>
|
||||||
<el-step title="Step 1" description="填写邮箱" />
|
<el-step title="Step 1" description="填写邮箱" />
|
||||||
<el-step title="Step 2" description="填写验证码" />
|
<el-step title="Step 2" description="填写验证码" />
|
||||||
<el-step title="Step 3" description="修改密码" />
|
<el-step title="Step 3" description="修改密码" />
|
||||||
|
|
@ -33,8 +44,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref } from 'vue';
|
import { ref } from "vue";
|
||||||
const step = ref(0)
|
const step = ref(0);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,12 @@
|
||||||
<span class="message-title">{{ scope.row.title }}</span>
|
<span class="message-title">{{ scope.row.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="date" width="180"></el-table-column>
|
<el-table-column prop="date" width="180" />
|
||||||
<el-table-column width="120">
|
<el-table-column width="120">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button size="small" @click="handleRead(scope.$index)">标为已读</el-button>
|
<el-button size="small" @click="handleRead(scope.$index)"
|
||||||
|
>标为已读</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
@ -26,10 +28,15 @@
|
||||||
<span class="message-title">{{ scope.row.title }}</span>
|
<span class="message-title">{{ scope.row.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="date" width="180"></el-table-column>
|
<el-table-column prop="date" width="180" />
|
||||||
<el-table-column width="120">
|
<el-table-column width="120">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button type="danger" size="small" @click="handleDel(scope.$index)">删除</el-button>
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
size="small"
|
||||||
|
@click="handleDel(scope.$index)"
|
||||||
|
>删除</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
@ -40,16 +47,22 @@
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="`回收站(${state.recycle.length})`" name="third">
|
<el-tab-pane :label="`回收站(${state.recycle.length})`" name="third">
|
||||||
<template v-if="message === 'third'">
|
<template v-if="message === 'third'">
|
||||||
<el-table :data="state.recycle" :show-header="false" style="width: 100%">
|
<el-table
|
||||||
|
:data="state.recycle"
|
||||||
|
:show-header="false"
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
<el-table-column>
|
<el-table-column>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<span class="message-title">{{ scope.row.title }}</span>
|
<span class="message-title">{{ scope.row.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="date" width="180"></el-table-column>
|
<el-table-column prop="date" width="180" />
|
||||||
<el-table-column width="120">
|
<el-table-column width="120">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-button size="small" @click="handleRestore(scope.$index)">还原</el-button>
|
<el-button size="small" @click="handleRestore(scope.$index)"
|
||||||
|
>还原</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
@ -62,32 +75,32 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="tabs">
|
<script setup lang="ts" name="tabs">
|
||||||
import { ref, reactive } from 'vue';
|
import { ref, reactive } from "vue";
|
||||||
|
|
||||||
const message = ref('first');
|
const message = ref("first");
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
unread: [
|
unread: [
|
||||||
{
|
{
|
||||||
date: '2018-04-19 20:00:00',
|
date: "2018-04-19 20:00:00",
|
||||||
title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
|
title: "【系统通知】该系统将于今晚凌晨2点到5点进行升级维护",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
date: '2018-04-19 21:00:00',
|
date: "2018-04-19 21:00:00",
|
||||||
title: '今晚12点整发大红包,先到先得'
|
title: "今晚12点整发大红包,先到先得",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
read: [
|
read: [
|
||||||
{
|
{
|
||||||
date: '2018-04-19 20:00:00',
|
date: "2018-04-19 20:00:00",
|
||||||
title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
|
title: "【系统通知】该系统将于今晚凌晨2点到5点进行升级维护",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
recycle: [
|
recycle: [
|
||||||
{
|
{
|
||||||
date: '2018-04-19 20:00:00',
|
date: "2018-04-19 20:00:00",
|
||||||
title: '【系统通知】该系统将于今晚凌晨2点到5点进行升级维护'
|
title: "【系统通知】该系统将于今晚凌晨2点到5点进行升级维护",
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleRead = (index: number) => {
|
const handleRead = (index: number) => {
|
||||||
|
|
|
||||||
|
|
@ -12,22 +12,34 @@
|
||||||
|
|
||||||
<el-tour v-model="open">
|
<el-tour v-model="open">
|
||||||
<el-tour-step :target="ref1?.$el" title="上传文件">
|
<el-tour-step :target="ref1?.$el" title="上传文件">
|
||||||
<img style="width: 120px" src="../../assets/img/img.jpg" alt="tour.png" />
|
<img
|
||||||
|
style="width: 120px"
|
||||||
|
src="../../assets/img/img.jpg"
|
||||||
|
alt="tour.png"
|
||||||
|
/>
|
||||||
<div>点击这里选择文件</div>
|
<div>点击这里选择文件</div>
|
||||||
</el-tour-step>
|
</el-tour-step>
|
||||||
<el-tour-step :target="ref2?.$el" title="保存" description="点击进行上传" />
|
<el-tour-step
|
||||||
<el-tour-step :target="ref3?.$el" title="更多操作" description="点击查看更多操作" />
|
:target="ref2?.$el"
|
||||||
|
title="保存"
|
||||||
|
description="点击进行上传"
|
||||||
|
/>
|
||||||
|
<el-tour-step
|
||||||
|
:target="ref3?.$el"
|
||||||
|
title="更多操作"
|
||||||
|
description="点击查看更多操作"
|
||||||
|
/>
|
||||||
</el-tour>
|
</el-tour>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue'
|
import { ref } from "vue";
|
||||||
import { MoreFilled } from '@element-plus/icons-vue'
|
import { MoreFilled } from "@element-plus/icons-vue";
|
||||||
|
|
||||||
const ref1 = ref()
|
const ref1 = ref();
|
||||||
const ref2 = ref()
|
const ref2 = ref();
|
||||||
const ref3 = ref()
|
const ref3 = ref();
|
||||||
|
|
||||||
const open = ref(false)
|
const open = ref(false);
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -3,10 +3,19 @@
|
||||||
<div class="content-title">支持拖拽</div>
|
<div class="content-title">支持拖拽</div>
|
||||||
<div class="plugins-tips">
|
<div class="plugins-tips">
|
||||||
Element Plus自带上传组件。 访问地址:
|
Element Plus自带上传组件。 访问地址:
|
||||||
<a href="https://element-plus.org/zh-CN/component/upload.html" target="_blank">Element Plus Upload</a>
|
<a
|
||||||
|
href="https://element-plus.org/zh-CN/component/upload.html"
|
||||||
|
target="_blank"
|
||||||
|
>Element Plus Upload</a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<el-upload class="upload-demo" drag action="http://jsonplaceholder.typicode.com/api/posts/" multiple
|
<el-upload
|
||||||
:on-change="handle">
|
class="upload-demo"
|
||||||
|
drag
|
||||||
|
action="http://jsonplaceholder.typicode.com/api/posts/"
|
||||||
|
multiple
|
||||||
|
:on-change="handle"
|
||||||
|
>
|
||||||
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
<el-icon class="el-icon--upload"><upload-filled /></el-icon>
|
||||||
<div class="el-upload__text">
|
<div class="el-upload__text">
|
||||||
将文件拖到此处,或
|
将文件拖到此处,或
|
||||||
|
|
@ -17,7 +26,9 @@
|
||||||
<div class="content-title">支持裁剪</div>
|
<div class="content-title">支持裁剪</div>
|
||||||
<div class="plugins-tips">
|
<div class="plugins-tips">
|
||||||
vue-cropper:一个简单的vue图片裁剪插件。 访问地址:
|
vue-cropper:一个简单的vue图片裁剪插件。 访问地址:
|
||||||
<a href="https://github.com/xyxiao001/vue-cropper" target="_blank">vue-cropper</a>。 示例请查看
|
<a href="https://github.com/xyxiao001/vue-cropper" target="_blank"
|
||||||
|
>vue-cropper</a
|
||||||
|
>。 示例请查看
|
||||||
<router-link to="/ucenter">个人中心-我的头像</router-link>
|
<router-link to="/ucenter">个人中心-我的头像</router-link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,24 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="18">
|
<el-col :span="18">
|
||||||
<el-watermark :content="config.content" :font="config.font" :z-index="config.zIndex"
|
<el-watermark
|
||||||
:rotate="config.rotate" :gap="config.gap" :offset="config.offset">
|
:content="config.content"
|
||||||
<div style="height: 600px" />
|
:font="config.font"
|
||||||
|
:z-index="config.zIndex"
|
||||||
|
:rotate="config.rotate"
|
||||||
|
:gap="config.gap"
|
||||||
|
:offset="config.offset"
|
||||||
|
>
|
||||||
|
<div style="height: 600px"></div>
|
||||||
</el-watermark>
|
</el-watermark>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-form class="form" :model="config" label-position="top" label-width="50px">
|
<el-form
|
||||||
|
class="form"
|
||||||
|
:model="config"
|
||||||
|
label-position="top"
|
||||||
|
label-width="50px"
|
||||||
|
>
|
||||||
<el-form-item label="Content">
|
<el-form-item label="Content">
|
||||||
<el-input v-model="config.content" />
|
<el-input v-model="config.content" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
@ -26,37 +37,48 @@
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Gap">
|
<el-form-item label="Gap">
|
||||||
<el-space>
|
<el-space>
|
||||||
<el-input-number v-model="config.gap[0]" controls-position="right" />
|
<el-input-number
|
||||||
<el-input-number v-model="config.gap[1]" controls-position="right" />
|
v-model="config.gap[0]"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
<el-input-number
|
||||||
|
v-model="config.gap[1]"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
</el-space>
|
</el-space>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="Offset">
|
<el-form-item label="Offset">
|
||||||
<el-space>
|
<el-space>
|
||||||
<el-input-number v-model="config.offset[0]" placeholder="offsetLeft"
|
<el-input-number
|
||||||
controls-position="right" />
|
v-model="config.offset[0]"
|
||||||
<el-input-number v-model="config.offset[1]" placeholder="offsetTop"
|
placeholder="offsetLeft"
|
||||||
controls-position="right" />
|
controls-position="right"
|
||||||
|
/>
|
||||||
|
<el-input-number
|
||||||
|
v-model="config.offset[1]"
|
||||||
|
placeholder="offsetTop"
|
||||||
|
controls-position="right"
|
||||||
|
/>
|
||||||
</el-space>
|
</el-space>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive } from 'vue'
|
import { reactive } from "vue";
|
||||||
|
|
||||||
const config = reactive({
|
const config = reactive({
|
||||||
content: 'vue-manage-system',
|
content: "vue-manage-system",
|
||||||
font: {
|
font: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: 'rgba(0, 0, 0, 0.15)',
|
color: "rgba(0, 0, 0, 0.15)",
|
||||||
},
|
},
|
||||||
zIndex: -1,
|
zIndex: -1,
|
||||||
rotate: -22,
|
rotate: -22,
|
||||||
gap: [100, 100] as [number, number],
|
gap: [100, 100] as [number, number],
|
||||||
offset: [] as unknown as [number, number],
|
offset: [] as unknown as [number, number],
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -3,12 +3,12 @@
|
||||||
<v-header />
|
<v-header />
|
||||||
<v-sidebar />
|
<v-sidebar />
|
||||||
<div class="content-box" :class="{ 'content-collapse': sidebar.collapse }">
|
<div class="content-box" :class="{ 'content-collapse': sidebar.collapse }">
|
||||||
<v-tabs></v-tabs>
|
<v-tabs />
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<router-view v-slot="{ Component }">
|
<router-view v-slot="{ Component }">
|
||||||
<transition name="move" mode="out-in">
|
<transition name="move" mode="out-in">
|
||||||
<keep-alive :include="tabs.nameList">
|
<keep-alive :include="tabs.nameList">
|
||||||
<component :is="Component"></component>
|
<component :is="Component" />
|
||||||
</keep-alive>
|
</keep-alive>
|
||||||
</transition>
|
</transition>
|
||||||
</router-view>
|
</router-view>
|
||||||
|
|
@ -17,11 +17,11 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useSidebarStore } from '@/store/sidebar';
|
import { useSidebarStore } from "@/store/sidebar";
|
||||||
import { useTabsStore } from '@/store/tabs';
|
import { useTabsStore } from "@/store/tabs";
|
||||||
import vHeader from '@/components/header.vue';
|
import vHeader from "@/components/header.vue";
|
||||||
import vSidebar from '@/components/sidebar.vue';
|
import vSidebar from "@/components/sidebar.vue";
|
||||||
import vTabs from '@/components/tabs.vue';
|
import vTabs from "@/components/tabs.vue";
|
||||||
|
|
||||||
const sidebar = useSidebarStore();
|
const sidebar = useSidebarStore();
|
||||||
const tabs = useTabsStore();
|
const tabs = useTabsStore();
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,16 @@
|
||||||
<router-link to="/">
|
<router-link to="/">
|
||||||
<el-button type="primary" size="large">返回首页</el-button>
|
<el-button type="primary" size="large">返回首页</el-button>
|
||||||
</router-link>
|
</router-link>
|
||||||
<el-button class="error-btn" size="large" @click="goBack">返回上一页</el-button>
|
<el-button class="error-btn" size="large" @click="goBack"
|
||||||
|
>返回上一页</el-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="403">
|
<script setup lang="ts" name="403">
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const goBack = () => {
|
const goBack = () => {
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,16 @@
|
||||||
<router-link to="/">
|
<router-link to="/">
|
||||||
<el-button type="primary" size="large">返回首页</el-button>
|
<el-button type="primary" size="large">返回首页</el-button>
|
||||||
</router-link>
|
</router-link>
|
||||||
<el-button class="error-btn" size="large" @click="goBack">返回上一页</el-button>
|
<el-button class="error-btn" size="large" @click="goBack"
|
||||||
|
>返回上一页</el-button
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="404">
|
<script setup lang="ts" name="404">
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from "vue-router";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const goBack = () => {
|
const goBack = () => {
|
||||||
|
|
|
||||||
|
|
@ -5,12 +5,16 @@
|
||||||
<a href="https://www.wangeditor.com/doc/" target="_blank">wangEditor</a>
|
<a href="https://www.wangeditor.com/doc/" target="_blank">wangEditor</a>
|
||||||
</div>
|
</div>
|
||||||
<div style="border: 1px solid #ccc; margin-bottom: 10px">
|
<div style="border: 1px solid #ccc; margin-bottom: 10px">
|
||||||
<Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" />
|
<Toolbar
|
||||||
|
style="border-bottom: 1px solid #ccc"
|
||||||
|
:editor="editorRef"
|
||||||
|
:defaultConfig="toolbarConfig"
|
||||||
|
/>
|
||||||
<Editor
|
<Editor
|
||||||
style="height: 500px; overflow-y: hidden"
|
style="height: 500px; overflow-y: hidden"
|
||||||
v-model="valueHtml"
|
v-model="valueHtml"
|
||||||
:defaultConfig="editorConfig"
|
:defaultConfig="editorConfig"
|
||||||
@onCreated="handleCreated"
|
@on-created="handleCreated"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<el-button type="primary" @click="syncHTML">提交</el-button>
|
<el-button type="primary" @click="syncHTML">提交</el-button>
|
||||||
|
|
@ -18,24 +22,24 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="editor">
|
<script setup lang="ts" name="editor">
|
||||||
import '@wangeditor/editor/dist/css/style.css'; // 引入 css
|
import "@wangeditor/editor/dist/css/style.css"; // 引入 css
|
||||||
import { onBeforeUnmount, ref, reactive, shallowRef, onMounted } from 'vue';
|
import { onBeforeUnmount, ref, reactive, shallowRef, onMounted } from "vue";
|
||||||
import { Editor, Toolbar } from '@wangeditor/editor-for-vue';
|
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
|
||||||
// 编辑器实例,必须用 shallowRef
|
// 编辑器实例,必须用 shallowRef
|
||||||
const editorRef = shallowRef();
|
const editorRef = shallowRef();
|
||||||
|
|
||||||
// 内容 HTML
|
// 内容 HTML
|
||||||
const valueHtml = ref('<p>hello</p>');
|
const valueHtml = ref("<p>hello</p>");
|
||||||
|
|
||||||
// 模拟 ajax 异步获取内容
|
// 模拟 ajax 异步获取内容
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
valueHtml.value = '<p>模拟 Ajax 异步设置内容</p>';
|
valueHtml.value = "<p>模拟 Ajax 异步设置内容</p>";
|
||||||
}, 1500);
|
}, 1500);
|
||||||
});
|
});
|
||||||
|
|
||||||
const toolbarConfig = {};
|
const toolbarConfig = {};
|
||||||
const editorConfig = { placeholder: '请输入内容...' };
|
const editorConfig = { placeholder: "请输入内容..." };
|
||||||
|
|
||||||
// 组件销毁时,也及时销毁编辑器
|
// 组件销毁时,也及时销毁编辑器
|
||||||
onBeforeUnmount(() => {
|
onBeforeUnmount(() => {
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,42 @@
|
||||||
<template>
|
<template>
|
||||||
|
|
||||||
<el-tabs type="border-card">
|
<el-tabs type="border-card">
|
||||||
<el-tab-pane label="自定义图标">
|
<el-tab-pane label="自定义图标">
|
||||||
<h2>使用方法</h2>
|
<h2>使用方法</h2>
|
||||||
<p style="line-height: 50px">
|
<p style="line-height: 50px">
|
||||||
直接通过设置类名为 el-icon-lx-iconName 来使用即可。例如:(共{{ iconList.length }}个图标)
|
直接通过设置类名为 el-icon-lx-iconName 来使用即可。例如:(共{{
|
||||||
|
iconList.length
|
||||||
|
}}个图标)
|
||||||
</p>
|
</p>
|
||||||
<p class="example-p">
|
<p class="example-p">
|
||||||
<i class="el-icon-lx-redpacket_fill" style="font-size: 30px; color: #ff5900"></i>
|
<i
|
||||||
<span><i class="el-icon-lx-redpacket_fill"></i></span>
|
class="el-icon-lx-redpacket_fill"
|
||||||
|
style="font-size: 30px; color: #ff5900"
|
||||||
|
></i>
|
||||||
|
<span
|
||||||
|
><i class="el-icon-lx-redpacket_fill"></i></span
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
<p class="example-p">
|
<p class="example-p">
|
||||||
<i class="el-icon-lx-weibo" style="font-size: 30px; color: #fd5656"></i>
|
<i class="el-icon-lx-weibo" style="font-size: 30px; color: #fd5656"></i>
|
||||||
<span><i class="el-icon-lx-weibo"></i></span>
|
<span><i class="el-icon-lx-weibo"></i></span>
|
||||||
</p>
|
</p>
|
||||||
<p class="example-p">
|
<p class="example-p">
|
||||||
<i class="el-icon-lx-emojifill" style="font-size: 30px; color: #ffc300"></i>
|
<i
|
||||||
|
class="el-icon-lx-emojifill"
|
||||||
|
style="font-size: 30px; color: #ffc300"
|
||||||
|
></i>
|
||||||
<span><i class="el-icon-lx-emojifill"></i></span>
|
<span><i class="el-icon-lx-emojifill"></i></span>
|
||||||
</p>
|
</p>
|
||||||
<br />
|
<br />
|
||||||
<h2>图标</h2>
|
<h2>图标</h2>
|
||||||
<div class="search-box">
|
<div class="search-box">
|
||||||
<el-input class="search" size="large" v-model="keyword" clearable placeholder="请输入图标名称"></el-input>
|
<el-input
|
||||||
|
class="search"
|
||||||
|
size="large"
|
||||||
|
v-model="keyword"
|
||||||
|
clearable
|
||||||
|
placeholder="请输入图标名称"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li class="icon-li" v-for="(item, index) in list" :key="index">
|
<li class="icon-li" v-for="(item, index) in list" :key="index">
|
||||||
|
|
@ -33,171 +48,175 @@
|
||||||
</ul>
|
</ul>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="Element图标">
|
<el-tab-pane label="Element图标">
|
||||||
<el-link type="primary" href="https://element-plus.org/zh-CN/component/icon.html#icon-collection"
|
<el-link
|
||||||
target="_blank">前往官方文档查看</el-link>
|
type="primary"
|
||||||
|
href="https://element-plus.org/zh-CN/component/icon.html#icon-collection"
|
||||||
|
target="_blank"
|
||||||
|
>前往官方文档查看</el-link
|
||||||
|
>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="icon">
|
<script setup lang="ts" name="icon">
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from "vue";
|
||||||
|
|
||||||
const iconList: Array<string> = [
|
const iconList: Array<string> = [
|
||||||
'attentionforbid',
|
"attentionforbid",
|
||||||
'attentionforbidfill',
|
"attentionforbidfill",
|
||||||
'attention',
|
"attention",
|
||||||
'attentionfill',
|
"attentionfill",
|
||||||
'tag',
|
"tag",
|
||||||
'tagfill',
|
"tagfill",
|
||||||
'people',
|
"people",
|
||||||
'peoplefill',
|
"peoplefill",
|
||||||
'notice',
|
"notice",
|
||||||
'noticefill',
|
"noticefill",
|
||||||
'mobile',
|
"mobile",
|
||||||
'mobilefill',
|
"mobilefill",
|
||||||
'voice',
|
"voice",
|
||||||
'voicefill',
|
"voicefill",
|
||||||
'unlock',
|
"unlock",
|
||||||
'lock',
|
"lock",
|
||||||
'home',
|
"home",
|
||||||
'homefill',
|
"homefill",
|
||||||
'delete',
|
"delete",
|
||||||
'deletefill',
|
"deletefill",
|
||||||
'notification',
|
"notification",
|
||||||
'notificationfill',
|
"notificationfill",
|
||||||
'notificationforbidfill',
|
"notificationforbidfill",
|
||||||
'like',
|
"like",
|
||||||
'likefill',
|
"likefill",
|
||||||
'comment',
|
"comment",
|
||||||
'commentfill',
|
"commentfill",
|
||||||
'camera',
|
"camera",
|
||||||
'camerafill',
|
"camerafill",
|
||||||
'warn',
|
"warn",
|
||||||
'warnfill',
|
"warnfill",
|
||||||
'time',
|
"time",
|
||||||
'timefill',
|
"timefill",
|
||||||
'location',
|
"location",
|
||||||
'locationfill',
|
"locationfill",
|
||||||
'favor',
|
"favor",
|
||||||
'favorfill',
|
"favorfill",
|
||||||
'skin',
|
"skin",
|
||||||
'skinfill',
|
"skinfill",
|
||||||
'news',
|
"news",
|
||||||
'newsfill',
|
"newsfill",
|
||||||
'record',
|
"record",
|
||||||
'recordfill',
|
"recordfill",
|
||||||
'emoji',
|
"emoji",
|
||||||
'emojifill',
|
"emojifill",
|
||||||
'message',
|
"message",
|
||||||
'messagefill',
|
"messagefill",
|
||||||
'goods',
|
"goods",
|
||||||
'goodsfill',
|
"goodsfill",
|
||||||
'crown',
|
"crown",
|
||||||
'crownfill',
|
"crownfill",
|
||||||
'move',
|
"move",
|
||||||
'add',
|
"add",
|
||||||
'hot',
|
"hot",
|
||||||
'hotfill',
|
"hotfill",
|
||||||
'service',
|
"service",
|
||||||
'servicefill',
|
"servicefill",
|
||||||
'present',
|
"present",
|
||||||
'presentfill',
|
"presentfill",
|
||||||
'pic',
|
"pic",
|
||||||
'picfill',
|
"picfill",
|
||||||
'rank',
|
"rank",
|
||||||
'rankfill',
|
"rankfill",
|
||||||
'male',
|
"male",
|
||||||
'female',
|
"female",
|
||||||
'down',
|
"down",
|
||||||
'top',
|
"top",
|
||||||
'recharge',
|
"recharge",
|
||||||
'rechargefill',
|
"rechargefill",
|
||||||
'forward',
|
"forward",
|
||||||
'forwardfill',
|
"forwardfill",
|
||||||
'info',
|
"info",
|
||||||
'infofill',
|
"infofill",
|
||||||
'redpacket',
|
"redpacket",
|
||||||
'redpacket_fill',
|
"redpacket_fill",
|
||||||
'roundadd',
|
"roundadd",
|
||||||
'roundaddfill',
|
"roundaddfill",
|
||||||
'friendadd',
|
"friendadd",
|
||||||
'friendaddfill',
|
"friendaddfill",
|
||||||
'cart',
|
"cart",
|
||||||
'cartfill',
|
"cartfill",
|
||||||
'more',
|
"more",
|
||||||
'moreandroid',
|
"moreandroid",
|
||||||
'back',
|
"back",
|
||||||
'right',
|
"right",
|
||||||
'shop',
|
"shop",
|
||||||
'shopfill',
|
"shopfill",
|
||||||
'question',
|
"question",
|
||||||
'questionfill',
|
"questionfill",
|
||||||
'roundclose',
|
"roundclose",
|
||||||
'roundclosefill',
|
"roundclosefill",
|
||||||
'roundcheck',
|
"roundcheck",
|
||||||
'roundcheckfill',
|
"roundcheckfill",
|
||||||
'global',
|
"global",
|
||||||
'mail',
|
"mail",
|
||||||
'punch',
|
"punch",
|
||||||
'exit',
|
"exit",
|
||||||
'upload',
|
"upload",
|
||||||
'read',
|
"read",
|
||||||
'file',
|
"file",
|
||||||
'link',
|
"link",
|
||||||
'full',
|
"full",
|
||||||
'group',
|
"group",
|
||||||
'friend',
|
"friend",
|
||||||
'profile',
|
"profile",
|
||||||
'addressbook',
|
"addressbook",
|
||||||
'calendar',
|
"calendar",
|
||||||
'text',
|
"text",
|
||||||
'copy',
|
"copy",
|
||||||
'share',
|
"share",
|
||||||
'wifi',
|
"wifi",
|
||||||
'vipcard',
|
"vipcard",
|
||||||
'weibo',
|
"weibo",
|
||||||
'remind',
|
"remind",
|
||||||
'refresh',
|
"refresh",
|
||||||
'filter',
|
"filter",
|
||||||
'settings',
|
"settings",
|
||||||
'scan',
|
"scan",
|
||||||
'qrcode',
|
"qrcode",
|
||||||
'cascades',
|
"cascades",
|
||||||
'apps',
|
"apps",
|
||||||
'sort',
|
"sort",
|
||||||
'searchlist',
|
"searchlist",
|
||||||
'search',
|
"search",
|
||||||
'edit',
|
"edit",
|
||||||
'apple-line',
|
"apple-line",
|
||||||
'baidu-fill',
|
"baidu-fill",
|
||||||
'amazon-fill',
|
"amazon-fill",
|
||||||
'netease-cloud-music-fill',
|
"netease-cloud-music-fill",
|
||||||
'qq-line',
|
"qq-line",
|
||||||
'wechat-fill',
|
"wechat-fill",
|
||||||
'alipay-fill',
|
"alipay-fill",
|
||||||
'android-fill',
|
"android-fill",
|
||||||
'android-line',
|
"android-line",
|
||||||
'whatsapp-line',
|
"whatsapp-line",
|
||||||
'whatsapp-fill',
|
"whatsapp-fill",
|
||||||
'bilibili-fill',
|
"bilibili-fill",
|
||||||
'chrome-fill',
|
"chrome-fill",
|
||||||
'dingding-fill',
|
"dingding-fill",
|
||||||
'dingding-line',
|
"dingding-line",
|
||||||
'apple-fill',
|
"apple-fill",
|
||||||
'github-fill',
|
"github-fill",
|
||||||
'qq-fill',
|
"qq-fill",
|
||||||
'wechat-pay-fill',
|
"wechat-pay-fill",
|
||||||
'windows-line',
|
"windows-line",
|
||||||
'windows-fill',
|
"windows-fill",
|
||||||
'youtube-line',
|
"youtube-line",
|
||||||
'youtube-fill',
|
"youtube-fill",
|
||||||
'wechat-pay-line',
|
"wechat-pay-line",
|
||||||
'zhihu-line'
|
"zhihu-line",
|
||||||
];
|
];
|
||||||
|
|
||||||
const keyword = ref('');
|
const keyword = ref("");
|
||||||
const list = computed(() => {
|
const list = computed(() => {
|
||||||
return iconList.filter(item => {
|
return iconList.filter((item) => {
|
||||||
return item.indexOf(keyword.value) !== -1;
|
return item.indexOf(keyword.value) !== -1;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -30,13 +30,27 @@
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<div class="pwd-tips">
|
<div class="pwd-tips">
|
||||||
<el-checkbox class="pwd-checkbox" v-model="checked" label="记住密码" />
|
<el-checkbox
|
||||||
<el-link type="primary" @click="$router.push('/reset-pwd')">忘记密码</el-link>
|
class="pwd-checkbox"
|
||||||
|
v-model="checked"
|
||||||
|
label="记住密码"
|
||||||
|
/>
|
||||||
|
<el-link type="primary" @click="$router.push('/reset-pwd')"
|
||||||
|
>忘记密码</el-link
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<el-button class="login-btn" type="primary" size="large" @click="submitForm(login)">登录</el-button>
|
<el-button
|
||||||
|
class="login-btn"
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
@click="submitForm(login)"
|
||||||
|
>登录</el-button
|
||||||
|
>
|
||||||
<p class="login-tips">Tips : 用户名和密码随便填。</p>
|
<p class="login-tips">Tips : 用户名和密码随便填。</p>
|
||||||
<p class="login-text">
|
<p class="login-text">
|
||||||
没有账号?<el-link type="primary" @click="$router.push('/register')">立即注册</el-link>
|
没有账号?<el-link type="primary" @click="$router.push('/register')"
|
||||||
|
>立即注册</el-link
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -44,37 +58,37 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive } from 'vue';
|
import { ref, reactive } from "vue";
|
||||||
import { useTabsStore } from '@/store/tabs';
|
import { useTabsStore } from "@/store/tabs";
|
||||||
import { usePermissStore } from '@/store/permiss';
|
import { usePermissStore } from "@/store/permiss";
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from "vue-router";
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from "element-plus";
|
||||||
import type { FormInstance, FormRules } from 'element-plus';
|
import type { FormInstance, FormRules } from "element-plus";
|
||||||
|
|
||||||
interface LoginInfo {
|
interface LoginInfo {
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const lgStr = localStorage.getItem('login-param');
|
const lgStr = localStorage.getItem("login-param");
|
||||||
const defParam = lgStr ? JSON.parse(lgStr) : null;
|
const defParam = lgStr ? JSON.parse(lgStr) : null;
|
||||||
const checked = ref(lgStr ? true : false);
|
const checked = ref(lgStr ? true : false);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const param = reactive<LoginInfo>({
|
const param = reactive<LoginInfo>({
|
||||||
username: defParam ? defParam.username : '',
|
username: defParam ? defParam.username : "",
|
||||||
password: defParam ? defParam.password : '',
|
password: defParam ? defParam.password : "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const rules: FormRules = {
|
const rules: FormRules = {
|
||||||
username: [
|
username: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: '请输入用户名',
|
message: "请输入用户名",
|
||||||
trigger: 'blur',
|
trigger: "blur",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
|
||||||
};
|
};
|
||||||
const permiss = usePermissStore();
|
const permiss = usePermissStore();
|
||||||
const login = ref<FormInstance>();
|
const login = ref<FormInstance>();
|
||||||
|
|
@ -82,18 +96,19 @@ const submitForm = (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.validate((valid: boolean) => {
|
formEl.validate((valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
ElMessage.success('登录成功');
|
ElMessage.success("登录成功");
|
||||||
localStorage.setItem('vuems_name', param.username);
|
localStorage.setItem("vuems_name", param.username);
|
||||||
const keys = permiss.defaultList[param.username == 'admin' ? 'admin' : 'user'];
|
const keys =
|
||||||
|
permiss.defaultList[param.username == "admin" ? "admin" : "user"];
|
||||||
permiss.handleSet(keys);
|
permiss.handleSet(keys);
|
||||||
router.push('/');
|
router.push("/");
|
||||||
if (checked.value) {
|
if (checked.value) {
|
||||||
localStorage.setItem('login-param', JSON.stringify(param));
|
localStorage.setItem("login-param", JSON.stringify(param));
|
||||||
} else {
|
} else {
|
||||||
localStorage.removeItem('login-param');
|
localStorage.removeItem("login-param");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error('登录失败');
|
ElMessage.error("登录失败");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="plugins-tips">
|
<div class="plugins-tips">
|
||||||
md-editor-v3:vue3版本的 markdown 编辑器,配置丰富,请详看文档。 访问地址:
|
md-editor-v3:vue3版本的 markdown 编辑器,配置丰富,请详看文档。
|
||||||
<a href="https://imzbf.github.io/md-editor-v3/index" target="_blank">md-editor-v3</a>
|
访问地址:
|
||||||
|
<a href="https://imzbf.github.io/md-editor-v3/index" target="_blank"
|
||||||
|
>md-editor-v3</a
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<md-editor class="mgb20" v-model="text" @on-upload-img="onUploadImg" />
|
<md-editor class="mgb20" v-model="text" @on-upload-img="onUploadImg" />
|
||||||
<el-button type="primary">提交</el-button>
|
<el-button type="primary">提交</el-button>
|
||||||
|
|
@ -10,11 +13,11 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="md">
|
<script setup lang="ts" name="md">
|
||||||
import { ref } from 'vue';
|
import { ref } from "vue";
|
||||||
import MdEditor from 'md-editor-v3';
|
import MdEditor from "md-editor-v3";
|
||||||
import 'md-editor-v3/lib/style.css';
|
import "md-editor-v3/lib/style.css";
|
||||||
|
|
||||||
const text = ref('Hello Editor!');
|
const text = ref("Hello Editor!");
|
||||||
const onUploadImg = (files: any) => {
|
const onUploadImg = (files: any) => {
|
||||||
console.log(files);
|
console.log(files);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,17 @@
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-button class="login-btn" type="primary" size="large" @click="submitForm(register)">注册</el-button>
|
<el-button
|
||||||
|
class="login-btn"
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
@click="submitForm(register)"
|
||||||
|
>注册</el-button
|
||||||
|
>
|
||||||
<p class="login-text">
|
<p class="login-text">
|
||||||
已有账号,<el-link type="primary" @click="$router.push('/login')">立即登录</el-link>
|
已有账号,<el-link type="primary" @click="$router.push('/login')"
|
||||||
|
>立即登录</el-link
|
||||||
|
>
|
||||||
</p>
|
</p>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -48,36 +56,36 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, reactive } from 'vue';
|
import { ref, reactive } from "vue";
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from "vue-router";
|
||||||
import { ElMessage, type FormInstance, type FormRules } from 'element-plus';
|
import { ElMessage, type FormInstance, type FormRules } from "element-plus";
|
||||||
import { Register } from '@/types/user';
|
import { Register } from "@/types/user";
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const param = reactive<Register>({
|
const param = reactive<Register>({
|
||||||
username: '',
|
username: "",
|
||||||
password: '',
|
password: "",
|
||||||
email: '',
|
email: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const rules: FormRules = {
|
const rules: FormRules = {
|
||||||
username: [
|
username: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
message: '请输入用户名',
|
message: "请输入用户名",
|
||||||
trigger: 'blur',
|
trigger: "blur",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
password: [{ required: true, message: "请输入密码", trigger: "blur" }],
|
||||||
email: [{ required: true, message: '请输入邮箱', trigger: 'blur' }],
|
email: [{ required: true, message: "请输入邮箱", trigger: "blur" }],
|
||||||
};
|
};
|
||||||
const register = ref<FormInstance>();
|
const register = ref<FormInstance>();
|
||||||
const submitForm = (formEl: FormInstance | undefined) => {
|
const submitForm = (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.validate((valid: boolean) => {
|
formEl.validate((valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
ElMessage.success('注册成功,请登录');
|
ElMessage.success("注册成功,请登录");
|
||||||
router.push('/login');
|
router.push("/login");
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,30 +13,38 @@
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-button class="login-btn" type="primary" size="large" @click="submitForm(register)"
|
<el-button
|
||||||
|
class="login-btn"
|
||||||
|
type="primary"
|
||||||
|
size="large"
|
||||||
|
@click="submitForm(register)"
|
||||||
>发送邮件</el-button
|
>发送邮件</el-button
|
||||||
>
|
>
|
||||||
<p class="login-text"><el-link type="primary" @click="$router.push('/login')">返回登录</el-link></p>
|
<p class="login-text">
|
||||||
|
<el-link type="primary" @click="$router.push('/login')"
|
||||||
|
>返回登录</el-link
|
||||||
|
>
|
||||||
|
</p>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from "vue";
|
||||||
import { ElMessage, type FormInstance, type FormRules } from 'element-plus';
|
import { ElMessage, type FormInstance, type FormRules } from "element-plus";
|
||||||
|
|
||||||
const param = ref({
|
const param = ref({
|
||||||
email: '',
|
email: "",
|
||||||
});
|
});
|
||||||
|
|
||||||
const rules: FormRules = {
|
const rules: FormRules = {
|
||||||
email: [
|
email: [
|
||||||
{ required: true, message: '请输入邮箱', trigger: 'blur' },
|
{ required: true, message: "请输入邮箱", trigger: "blur" },
|
||||||
{
|
{
|
||||||
pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
|
pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/,
|
||||||
message: '请输入正确的邮箱格式',
|
message: "请输入正确的邮箱格式",
|
||||||
trigger: 'blur',
|
trigger: "blur",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
@ -45,7 +53,7 @@ const submitForm = (formEl: FormInstance | undefined) => {
|
||||||
if (!formEl) return;
|
if (!formEl) return;
|
||||||
formEl.validate((valid: boolean) => {
|
formEl.validate((valid: boolean) => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
ElMessage.success('邮件已发送,请注意查收');
|
ElMessage.success("邮件已发送,请注意查收");
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,13 @@
|
||||||
<div class="content-title">系统主题</div>
|
<div class="content-title">系统主题</div>
|
||||||
</template>
|
</template>
|
||||||
<div class="theme-list mgb20">
|
<div class="theme-list mgb20">
|
||||||
<div class="theme-item" @click="setSystemTheme(item)" v-for="item in system"
|
<div
|
||||||
:style="{ backgroundColor: item.color, color: '#fff' }">{{ item.name }}
|
class="theme-item"
|
||||||
|
@click="setSystemTheme(item)"
|
||||||
|
v-for="item in system"
|
||||||
|
:style="{ backgroundColor: item.color, color: '#fff' }"
|
||||||
|
>
|
||||||
|
{{ item.name }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-center">
|
<div class="flex-center">
|
||||||
|
|
@ -21,7 +26,10 @@
|
||||||
<div class="theme-item" v-for="theme in themes">
|
<div class="theme-item" v-for="theme in themes">
|
||||||
<el-button :type="theme.name">{{ theme.name }}</el-button>
|
<el-button :type="theme.name">{{ theme.name }}</el-button>
|
||||||
<div class="theme-color">{{ theme.color }}</div>
|
<div class="theme-color">{{ theme.color }}</div>
|
||||||
<el-color-picker v-model="color[theme.name]" @change="changeColor(theme.name)" />
|
<el-color-picker
|
||||||
|
v-model="color[theme.name]"
|
||||||
|
@change="changeColor(theme.name)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-center">
|
<div class="flex-center">
|
||||||
|
|
@ -39,14 +47,18 @@
|
||||||
<div class="theme-item">
|
<div class="theme-item">
|
||||||
<el-button :color="color.headerBgColor">背景颜色</el-button>
|
<el-button :color="color.headerBgColor">背景颜色</el-button>
|
||||||
<div class="theme-color">{{ color.headerBgColor }}</div>
|
<div class="theme-color">{{ color.headerBgColor }}</div>
|
||||||
<el-color-picker v-model="color.headerBgColor"
|
<el-color-picker
|
||||||
@change="themeStore.setHeaderBgColor(color.headerBgColor)" />
|
v-model="color.headerBgColor"
|
||||||
|
@change="themeStore.setHeaderBgColor(color.headerBgColor)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="theme-item">
|
<div class="theme-item">
|
||||||
<el-button :color="color.headerTextColor">文字颜色</el-button>
|
<el-button :color="color.headerTextColor">文字颜色</el-button>
|
||||||
<div class="theme-color">{{ color.headerTextColor }}</div>
|
<div class="theme-color">{{ color.headerTextColor }}</div>
|
||||||
<el-color-picker v-model="color.headerTextColor"
|
<el-color-picker
|
||||||
@change="themeStore.setHeaderTextColor(color.headerTextColor)" />
|
v-model="color.headerTextColor"
|
||||||
|
@change="themeStore.setHeaderTextColor(color.headerTextColor)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-center">
|
<div class="flex-center">
|
||||||
|
|
@ -64,14 +76,18 @@
|
||||||
<div class="theme-item">
|
<div class="theme-item">
|
||||||
<el-button :color="sidebar.bgColor">背景颜色</el-button>
|
<el-button :color="sidebar.bgColor">背景颜色</el-button>
|
||||||
<div class="theme-color">{{ sidebar.bgColor }}</div>
|
<div class="theme-color">{{ sidebar.bgColor }}</div>
|
||||||
<el-color-picker v-model="sidebarColor.bgColor"
|
<el-color-picker
|
||||||
@change="sidebar.setBgColor(sidebarColor.bgColor)" />
|
v-model="sidebarColor.bgColor"
|
||||||
|
@change="sidebar.setBgColor(sidebarColor.bgColor)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="theme-item">
|
<div class="theme-item">
|
||||||
<el-button :color="sidebar.textColor">文字颜色</el-button>
|
<el-button :color="sidebar.textColor">文字颜色</el-button>
|
||||||
<div class="theme-color">{{ sidebar.textColor }}</div>
|
<div class="theme-color">{{ sidebar.textColor }}</div>
|
||||||
<el-color-picker v-model="sidebarColor.textColor"
|
<el-color-picker
|
||||||
@change="sidebar.setTextColor(sidebarColor.textColor)" />
|
v-model="sidebarColor.textColor"
|
||||||
|
@change="sidebar.setTextColor(sidebarColor.textColor)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-center">
|
<div class="flex-center">
|
||||||
|
|
@ -80,108 +96,107 @@
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useSidebarStore } from '@/store/sidebar';
|
import { useSidebarStore } from "@/store/sidebar";
|
||||||
import { useThemeStore } from '@/store/theme'
|
import { useThemeStore } from "@/store/theme";
|
||||||
import { reactive } from 'vue';
|
import { reactive } from "vue";
|
||||||
const themeStore = useThemeStore();
|
const themeStore = useThemeStore();
|
||||||
const sidebar = useSidebarStore();
|
const sidebar = useSidebarStore();
|
||||||
|
|
||||||
const color = reactive({
|
const color = reactive({
|
||||||
primary: localStorage.getItem('theme-primary') || '#409eff',
|
primary: localStorage.getItem("theme-primary") || "#409eff",
|
||||||
success: localStorage.getItem('theme-success') || '#67c23a',
|
success: localStorage.getItem("theme-success") || "#67c23a",
|
||||||
warning: localStorage.getItem('theme-warning') || '#e6a23c',
|
warning: localStorage.getItem("theme-warning") || "#e6a23c",
|
||||||
danger: localStorage.getItem('theme-danger') || '#f56c6c',
|
danger: localStorage.getItem("theme-danger") || "#f56c6c",
|
||||||
info: localStorage.getItem('theme-info') || '#909399',
|
info: localStorage.getItem("theme-info") || "#909399",
|
||||||
headerBgColor: themeStore.headerBgColor,
|
headerBgColor: themeStore.headerBgColor,
|
||||||
headerTextColor: themeStore.headerTextColor,
|
headerTextColor: themeStore.headerTextColor,
|
||||||
})
|
});
|
||||||
const sidebarColor = reactive({
|
const sidebarColor = reactive({
|
||||||
bgColor: sidebar.bgColor,
|
bgColor: sidebar.bgColor,
|
||||||
textColor: sidebar.textColor
|
textColor: sidebar.textColor,
|
||||||
})
|
});
|
||||||
const themes = [
|
const themes = [
|
||||||
{
|
{
|
||||||
name: 'primary',
|
name: "primary",
|
||||||
color: themeStore.primary || color.primary
|
color: themeStore.primary || color.primary,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'success',
|
name: "success",
|
||||||
color: themeStore.success || color.success
|
color: themeStore.success || color.success,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'warning',
|
name: "warning",
|
||||||
color: themeStore.warning || color.warning
|
color: themeStore.warning || color.warning,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'danger',
|
name: "danger",
|
||||||
color: themeStore.danger || color.danger
|
color: themeStore.danger || color.danger,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'info',
|
name: "info",
|
||||||
color: themeStore.info || color.info
|
color: themeStore.info || color.info,
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
|
|
||||||
const changeColor = (name: string) => {
|
const changeColor = (name: string) => {
|
||||||
themeStore.setPropertyColor(color[name], name)
|
themeStore.setPropertyColor(color[name], name);
|
||||||
}
|
};
|
||||||
|
|
||||||
const resetTheme = () => {
|
const resetTheme = () => {
|
||||||
themeStore.resetTheme()
|
themeStore.resetTheme();
|
||||||
}
|
};
|
||||||
const resetHeader = () => {
|
const resetHeader = () => {
|
||||||
localStorage.removeItem('header-bg-color')
|
localStorage.removeItem("header-bg-color");
|
||||||
localStorage.removeItem('header-text-color')
|
localStorage.removeItem("header-text-color");
|
||||||
location.reload()
|
location.reload();
|
||||||
}
|
};
|
||||||
const resetSidebar = () => {
|
const resetSidebar = () => {
|
||||||
localStorage.removeItem('sidebar-bg-color')
|
localStorage.removeItem("sidebar-bg-color");
|
||||||
localStorage.removeItem('sidebar-text-color')
|
localStorage.removeItem("sidebar-text-color");
|
||||||
location.reload()
|
location.reload();
|
||||||
}
|
};
|
||||||
const system = [
|
const system = [
|
||||||
{
|
{
|
||||||
name: '默认',
|
name: "默认",
|
||||||
color: '#242f42'
|
color: "#242f42",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '健康',
|
name: "健康",
|
||||||
color: '#1ABC9C'
|
color: "#1ABC9C",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '优雅',
|
name: "优雅",
|
||||||
color: '#722ed1'
|
color: "#722ed1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '热情',
|
name: "热情",
|
||||||
color: '#f44336'
|
color: "#f44336",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '宁静',
|
name: "宁静",
|
||||||
color: '#00bcd4'
|
color: "#00bcd4",
|
||||||
}
|
},
|
||||||
]
|
];
|
||||||
const setSystemTheme = (data: any) => {
|
const setSystemTheme = (data: any) => {
|
||||||
if (data.name === '默认') {
|
if (data.name === "默认") {
|
||||||
resetSystemTheme()
|
resetSystemTheme();
|
||||||
} else {
|
} else {
|
||||||
themeStore.setHeaderBgColor(data.color)
|
themeStore.setHeaderBgColor(data.color);
|
||||||
themeStore.setHeaderTextColor('#fff')
|
themeStore.setHeaderTextColor("#fff");
|
||||||
sidebar.setBgColor('#fff')
|
sidebar.setBgColor("#fff");
|
||||||
sidebar.setTextColor('#5b6e88')
|
sidebar.setTextColor("#5b6e88");
|
||||||
themeStore.setPropertyColor(data.color, 'primary')
|
themeStore.setPropertyColor(data.color, "primary");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
const resetSystemTheme = () => {
|
const resetSystemTheme = () => {
|
||||||
resetTheme();
|
resetTheme();
|
||||||
resetHeader();
|
resetHeader();
|
||||||
resetSidebar();
|
resetSidebar();
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="user-container">
|
<div class="user-container">
|
||||||
<el-card class="user-profile" shadow="hover" :body-style="{ padding: '0px' }">
|
<el-card
|
||||||
|
class="user-profile"
|
||||||
|
shadow="hover"
|
||||||
|
:body-style="{ padding: '0px' }"
|
||||||
|
>
|
||||||
<div class="user-profile-bg"></div>
|
<div class="user-profile-bg"></div>
|
||||||
<div class="user-avatar-wrap">
|
<div class="user-avatar-wrap">
|
||||||
<el-avatar class="user-avatar" :size="120" :src="avatarImg" />
|
<el-avatar class="user-avatar" :size="120" :src="avatarImg" />
|
||||||
|
|
@ -11,11 +15,15 @@
|
||||||
<div class="info-desc">
|
<div class="info-desc">
|
||||||
<span>@lin-xin</span>
|
<span>@lin-xin</span>
|
||||||
<el-divider direction="vertical" />
|
<el-divider direction="vertical" />
|
||||||
<el-link href="https://lin-xin.gitee.io" target="_blank">lin-xin.gitee.io</el-link>
|
<el-link href="https://lin-xin.gitee.io" target="_blank"
|
||||||
|
>lin-xin.gitee.io</el-link
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-desc">FE Developer</div>
|
<div class="info-desc">FE Developer</div>
|
||||||
<div class="info-icon">
|
<div class="info-icon">
|
||||||
<a href="https://github.com/lin-xin" target="_blank"> <i class="el-icon-lx-github-fill"></i></a>
|
<a href="https://github.com/lin-xin" target="_blank">
|
||||||
|
<i class="el-icon-lx-github-fill"></i
|
||||||
|
></a>
|
||||||
<i class="el-icon-lx-qq-fill"></i>
|
<i class="el-icon-lx-qq-fill"></i>
|
||||||
<i class="el-icon-lx-facebook-fill"></i>
|
<i class="el-icon-lx-facebook-fill"></i>
|
||||||
<i class="el-icon-lx-twitter-fill"></i>
|
<i class="el-icon-lx-twitter-fill"></i>
|
||||||
|
|
@ -36,7 +44,11 @@
|
||||||
<el-card
|
<el-card
|
||||||
class="user-content"
|
class="user-content"
|
||||||
shadow="hover"
|
shadow="hover"
|
||||||
:body-style="{ padding: '20px 50px', height: '100%', boxSizing: 'border-box' }"
|
:body-style="{
|
||||||
|
padding: '20px 50px',
|
||||||
|
height: '100%',
|
||||||
|
boxSizing: 'border-box',
|
||||||
|
}"
|
||||||
>
|
>
|
||||||
<el-tabs tab-position="left" v-model="activeName">
|
<el-tabs tab-position="left" v-model="activeName">
|
||||||
<el-tab-pane name="label1" label="消息通知" class="user-tabpane">
|
<el-tab-pane name="label1" label="消息通知" class="user-tabpane">
|
||||||
|
|
@ -51,25 +63,30 @@
|
||||||
:centerBox="true"
|
:centerBox="true"
|
||||||
:full="true"
|
:full="true"
|
||||||
mode="contain"
|
mode="contain"
|
||||||
>
|
/>
|
||||||
</vueCropper>
|
|
||||||
</div>
|
</div>
|
||||||
<el-button class="crop-demo-btn" type="primary"
|
<el-button class="crop-demo-btn" type="primary"
|
||||||
>选择图片
|
>选择图片
|
||||||
<input class="crop-input" type="file" name="image" accept="image/*" @change="setImage" />
|
<input
|
||||||
|
class="crop-input"
|
||||||
|
type="file"
|
||||||
|
name="image"
|
||||||
|
accept="image/*"
|
||||||
|
@change="setImage"
|
||||||
|
/>
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="success" @click="saveAvatar">上传并保存</el-button>
|
<el-button type="success" @click="saveAvatar">上传并保存</el-button>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane name="label3" label="修改密码" class="user-tabpane">
|
<el-tab-pane name="label3" label="修改密码" class="user-tabpane">
|
||||||
<el-form class="w500" label-position="top">
|
<el-form class="w500" label-position="top">
|
||||||
<el-form-item label="旧密码:">
|
<el-form-item label="旧密码:">
|
||||||
<el-input type="password" v-model="form.old"></el-input>
|
<el-input type="password" v-model="form.old" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="新密码:">
|
<el-form-item label="新密码:">
|
||||||
<el-input type="password" v-model="form.new"></el-input>
|
<el-input type="password" v-model="form.new" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="确认新密码:">
|
<el-form-item label="确认新密码:">
|
||||||
<el-input type="password" v-model="form.new1"></el-input>
|
<el-input type="password" v-model="form.new1" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item>
|
<el-form-item>
|
||||||
<el-button type="primary" @click="onSubmit">保存</el-button>
|
<el-button type="primary" @click="onSubmit">保存</el-button>
|
||||||
|
|
@ -79,7 +96,9 @@
|
||||||
<el-tab-pane name="label4" label="赞赏作者" class="user-tabpane">
|
<el-tab-pane name="label4" label="赞赏作者" class="user-tabpane">
|
||||||
<div class="plugins-tips">
|
<div class="plugins-tips">
|
||||||
如果该框架
|
如果该框架
|
||||||
<el-link href="https://github.com/lin-xin/vue-manage-system" target="_blank"
|
<el-link
|
||||||
|
href="https://github.com/lin-xin/vue-manage-system"
|
||||||
|
target="_blank"
|
||||||
>vue-manage-system</el-link
|
>vue-manage-system</el-link
|
||||||
>
|
>
|
||||||
对你有帮助,那就请作者喝杯饮料吧!<el-icon>
|
对你有帮助,那就请作者喝杯饮料吧!<el-icon>
|
||||||
|
|
@ -98,30 +117,30 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="ucenter">
|
<script setup lang="ts" name="ucenter">
|
||||||
import { reactive, ref } from 'vue';
|
import { reactive, ref } from "vue";
|
||||||
import { VueCropper } from 'vue-cropper';
|
import { VueCropper } from "vue-cropper";
|
||||||
import 'vue-cropper/dist/index.css';
|
import "vue-cropper/dist/index.css";
|
||||||
import avatar from '@/assets/img/img.jpg';
|
import avatar from "@/assets/img/img.jpg";
|
||||||
import TabsComp from '../element/tabs.vue';
|
import TabsComp from "../element/tabs.vue";
|
||||||
|
|
||||||
const name = localStorage.getItem('vuems_name');
|
const name = localStorage.getItem("vuems_name");
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
new1: '',
|
new1: "",
|
||||||
new: '',
|
new: "",
|
||||||
old: '',
|
old: "",
|
||||||
});
|
});
|
||||||
const onSubmit = () => {};
|
const onSubmit = () => {};
|
||||||
|
|
||||||
const activeName = ref('label1');
|
const activeName = ref("label1");
|
||||||
|
|
||||||
const avatarImg = ref(avatar);
|
const avatarImg = ref(avatar);
|
||||||
const imgSrc = ref(avatar);
|
const imgSrc = ref(avatar);
|
||||||
const cropImg = ref('');
|
const cropImg = ref("");
|
||||||
const cropper: any = ref();
|
const cropper: any = ref();
|
||||||
|
|
||||||
const setImage = (e: any) => {
|
const setImage = (e: any) => {
|
||||||
const file = e.target.files[0];
|
const file = e.target.files[0];
|
||||||
if (!file.type.includes('image/')) {
|
if (!file.type.includes("image/")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
|
|
@ -153,7 +172,7 @@ const saveAvatar = () => {
|
||||||
.user-profile-bg {
|
.user-profile-bg {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 200px;
|
height: 200px;
|
||||||
background-image: url('../../assets/img/ucenter-bg.jpg');
|
background-image: url("../../assets/img/ucenter-bg.jpg");
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,64 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<TableCustom :columns="columns" :tableData="menuData" row-key="index" :has-pagination="false"
|
<TableCustom
|
||||||
:viewFunc="handleView" :delFunc="handleDelete" :editFunc="handleEdit">
|
:columns="columns"
|
||||||
|
:tableData="menuData"
|
||||||
|
row-key="index"
|
||||||
|
:has-pagination="false"
|
||||||
|
:viewFunc="handleView"
|
||||||
|
:delFunc="handleDelete"
|
||||||
|
:editFunc="handleEdit"
|
||||||
|
>
|
||||||
<template #toolbarBtn>
|
<template #toolbarBtn>
|
||||||
<el-button type="warning" :icon="CirclePlusFilled" @click="visible = true">新增</el-button>
|
<el-button
|
||||||
|
type="warning"
|
||||||
|
:icon="CirclePlusFilled"
|
||||||
|
@click="visible = true"
|
||||||
|
>新增</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
<template #icon="{ rows }">
|
<template #icon="{ rows }">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<component :is="rows.icon"></component>
|
<component :is="rows.icon" />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</template>
|
</template>
|
||||||
</TableCustom>
|
</TableCustom>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<el-dialog :title="isEdit ? '编辑' : '新增'" v-model="visible" width="700px" destroy-on-close
|
<el-dialog
|
||||||
:close-on-click-modal="false" @close="closeDialog">
|
:title="isEdit ? '编辑' : '新增'"
|
||||||
<TableEdit :form-data="rowData" :options="options" :edit="isEdit" :update="updateData">
|
v-model="visible"
|
||||||
|
width="700px"
|
||||||
|
destroy-on-close
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@close="closeDialog"
|
||||||
|
>
|
||||||
|
<TableEdit
|
||||||
|
:form-data="rowData"
|
||||||
|
:options="options"
|
||||||
|
:edit="isEdit"
|
||||||
|
:update="updateData"
|
||||||
|
>
|
||||||
<template #parent>
|
<template #parent>
|
||||||
<el-cascader v-model="rowData.pid" :options="cascaderOptions" :props="{ checkStrictly: true }"
|
<el-cascader
|
||||||
clearable />
|
v-model="rowData.pid"
|
||||||
|
:options="cascaderOptions"
|
||||||
|
:props="{ checkStrictly: true }"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</TableEdit>
|
</TableEdit>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog title="查看详情" v-model="visible1" width="700px" destroy-on-close>
|
<el-dialog
|
||||||
|
title="查看详情"
|
||||||
|
v-model="visible1"
|
||||||
|
width="700px"
|
||||||
|
destroy-on-close
|
||||||
|
>
|
||||||
<TableDetail :data="viewData">
|
<TableDetail :data="viewData">
|
||||||
<template #icon="{ rows }">
|
<template #icon="{ rows }">
|
||||||
<el-icon>
|
<el-icon>
|
||||||
<component :is="rows.icon"></component>
|
<component :is="rows.icon" />
|
||||||
</el-icon>
|
</el-icon>
|
||||||
</template>
|
</template>
|
||||||
</TableDetail>
|
</TableDetail>
|
||||||
|
|
@ -36,51 +67,50 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="system-menu">
|
<script setup lang="ts" name="system-menu">
|
||||||
import { ref } from 'vue';
|
import { ref } from "vue";
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from "element-plus";
|
||||||
import { CirclePlusFilled } from '@element-plus/icons-vue';
|
import { CirclePlusFilled } from "@element-plus/icons-vue";
|
||||||
import { Menus } from '@/types/menu';
|
import { Menus } from "@/types/menu";
|
||||||
import TableCustom from '@/components/table-custom.vue';
|
import TableCustom from "@/components/table-custom.vue";
|
||||||
import TableDetail from '@/components/table-detail.vue';
|
import TableDetail from "@/components/table-detail.vue";
|
||||||
import { FormOption } from '@/types/form-option';
|
import { FormOption } from "@/types/form-option";
|
||||||
import { menuData } from '@/components/menu';
|
import { menuData } from "@/components/menu";
|
||||||
|
|
||||||
// 表格相关
|
// 表格相关
|
||||||
let columns = ref([
|
let columns = ref([
|
||||||
{ prop: 'title', label: '菜单名称', align: 'left' },
|
{ prop: "title", label: "菜单名称", align: "left" },
|
||||||
{ prop: 'icon', label: '图标' },
|
{ prop: "icon", label: "图标" },
|
||||||
{ prop: 'index', label: '路由路径' },
|
{ prop: "index", label: "路由路径" },
|
||||||
{ prop: 'permiss', label: '权限标识' },
|
{ prop: "permiss", label: "权限标识" },
|
||||||
{ prop: 'operator', label: '操作', width: 250 },
|
{ prop: "operator", label: "操作", width: 250 },
|
||||||
])
|
]);
|
||||||
|
|
||||||
const getOptions = (data: any) => {
|
const getOptions = (data: any) => {
|
||||||
return data.map(item => {
|
return data.map((item) => {
|
||||||
const a: any = {
|
const a: any = {
|
||||||
label: item.title,
|
label: item.title,
|
||||||
value: item.id,
|
value: item.id,
|
||||||
}
|
};
|
||||||
if (item.children) {
|
if (item.children) {
|
||||||
a.children = getOptions(item.children)
|
a.children = getOptions(item.children);
|
||||||
}
|
|
||||||
return a
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
return a;
|
||||||
|
});
|
||||||
|
};
|
||||||
const cascaderOptions = ref(getOptions(menuData));
|
const cascaderOptions = ref(getOptions(menuData));
|
||||||
|
|
||||||
|
|
||||||
// 新增/编辑弹窗相关
|
// 新增/编辑弹窗相关
|
||||||
let options = ref<FormOption>({
|
let options = ref<FormOption>({
|
||||||
labelWidth: '100px',
|
labelWidth: "100px",
|
||||||
span: 12,
|
span: 12,
|
||||||
list: [
|
list: [
|
||||||
{ type: 'input', label: '菜单名称', prop: 'title', required: true },
|
{ type: "input", label: "菜单名称", prop: "title", required: true },
|
||||||
{ type: 'input', label: '路由路径', prop: 'index', required: true },
|
{ type: "input", label: "路由路径", prop: "index", required: true },
|
||||||
{ type: 'input', label: '图标', prop: 'icon' },
|
{ type: "input", label: "图标", prop: "icon" },
|
||||||
{ type: 'input', label: '权限标识', prop: 'permiss' },
|
{ type: "input", label: "权限标识", prop: "permiss" },
|
||||||
{ type: 'parent', label: '父菜单', prop: 'parent' },
|
{ type: "parent", label: "父菜单", prop: "parent" },
|
||||||
]
|
],
|
||||||
})
|
});
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const isEdit = ref(false);
|
const isEdit = ref(false);
|
||||||
const rowData = ref<any>({});
|
const rowData = ref<any>({});
|
||||||
|
|
@ -102,43 +132,43 @@ const closeDialog = () => {
|
||||||
const visible1 = ref(false);
|
const visible1 = ref(false);
|
||||||
const viewData = ref({
|
const viewData = ref({
|
||||||
row: {},
|
row: {},
|
||||||
list: []
|
list: [],
|
||||||
});
|
});
|
||||||
const handleView = (row: Menus) => {
|
const handleView = (row: Menus) => {
|
||||||
viewData.value.row = { ...row }
|
viewData.value.row = { ...row };
|
||||||
viewData.value.list = [
|
viewData.value.list = [
|
||||||
{
|
{
|
||||||
prop: 'id',
|
prop: "id",
|
||||||
label: '菜单ID',
|
label: "菜单ID",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'pid',
|
prop: "pid",
|
||||||
label: '父菜单ID',
|
label: "父菜单ID",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'title',
|
prop: "title",
|
||||||
label: '菜单名称',
|
label: "菜单名称",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'index',
|
prop: "index",
|
||||||
label: '路由路径',
|
label: "路由路径",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'permiss',
|
prop: "permiss",
|
||||||
label: '权限标识',
|
label: "权限标识",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'icon',
|
prop: "icon",
|
||||||
label: '图标',
|
label: "图标",
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
visible1.value = true;
|
visible1.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 删除相关
|
// 删除相关
|
||||||
const handleDelete = (row: Menus) => {
|
const handleDelete = (row: Menus) => {
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success("删除成功");
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|
@ -14,9 +14,9 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref } from 'vue';
|
import { ref } from "vue";
|
||||||
import { ElTree } from 'element-plus';
|
import { ElTree } from "element-plus";
|
||||||
import { menuData } from '@/components/menu';
|
import { menuData } from "@/components/menu";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
permissOptions: {
|
permissOptions: {
|
||||||
|
|
@ -58,7 +58,10 @@ const getTreeData = (data) => {
|
||||||
const data = getTreeData(menuData);
|
const data = getTreeData(menuData);
|
||||||
const checkData = (data: string[]) => {
|
const checkData = (data: string[]) => {
|
||||||
return data.filter((item) => {
|
return data.filter((item) => {
|
||||||
return !menuObj.value[item] || data.toString().includes(menuObj.value[item].toString());
|
return (
|
||||||
|
!menuObj.value[item] ||
|
||||||
|
data.toString().includes(menuObj.value[item].toString())
|
||||||
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// 获取当前权限
|
// 获取当前权限
|
||||||
|
|
@ -68,7 +71,10 @@ const checkedKeys = ref<string[]>(checkData(props.permissOptions.permiss));
|
||||||
const tree = ref<InstanceType<typeof ElTree>>();
|
const tree = ref<InstanceType<typeof ElTree>>();
|
||||||
const onSubmit = () => {
|
const onSubmit = () => {
|
||||||
// 获取选中的权限
|
// 获取选中的权限
|
||||||
const keys = [...tree.value!.getCheckedKeys(false), ...tree.value!.getHalfCheckedKeys()] as number[];
|
const keys = [
|
||||||
|
...tree.value!.getCheckedKeys(false),
|
||||||
|
...tree.value!.getHalfCheckedKeys(),
|
||||||
|
] as number[];
|
||||||
console.log(keys);
|
console.log(keys);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -2,26 +2,59 @@
|
||||||
<div>
|
<div>
|
||||||
<TableSearch :query="query" :options="searchOpt" :search="handleSearch" />
|
<TableSearch :query="query" :options="searchOpt" :search="handleSearch" />
|
||||||
<div class="container">
|
<div class="container">
|
||||||
|
<TableCustom
|
||||||
<TableCustom :columns="columns" :tableData="tableData" :total="page.total" :viewFunc="handleView"
|
:columns="columns"
|
||||||
:delFunc="handleDelete" :page-change="changePage" :editFunc="handleEdit">
|
:tableData="tableData"
|
||||||
|
:total="page.total"
|
||||||
|
:viewFunc="handleView"
|
||||||
|
:delFunc="handleDelete"
|
||||||
|
:page-change="changePage"
|
||||||
|
:editFunc="handleEdit"
|
||||||
|
>
|
||||||
<template #toolbarBtn>
|
<template #toolbarBtn>
|
||||||
<el-button type="warning" :icon="CirclePlusFilled" @click="visible = true">新增</el-button>
|
<el-button
|
||||||
|
type="warning"
|
||||||
|
:icon="CirclePlusFilled"
|
||||||
|
@click="visible = true"
|
||||||
|
>新增</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
<template #status="{ rows }">
|
<template #status="{ rows }">
|
||||||
<el-tag type="success" v-if="rows.status">启用</el-tag>
|
<el-tag type="success" v-if="rows.status">启用</el-tag>
|
||||||
<el-tag type="danger" v-else>禁用</el-tag>
|
<el-tag type="danger" v-else>禁用</el-tag>
|
||||||
</template>
|
</template>
|
||||||
<template #permissions="{ rows }">
|
<template #permissions="{ rows }">
|
||||||
<el-button type="primary" size="small" plain @click="handlePermission(rows)">管理</el-button>
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
plain
|
||||||
|
@click="handlePermission(rows)"
|
||||||
|
>管理</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</TableCustom>
|
</TableCustom>
|
||||||
</div>
|
</div>
|
||||||
<el-dialog :title="isEdit ? '编辑' : '新增'" v-model="visible" width="700px" destroy-on-close
|
<el-dialog
|
||||||
:close-on-click-modal="false" @close="closeDialog">
|
:title="isEdit ? '编辑' : '新增'"
|
||||||
<TableEdit :form-data="rowData" :options="options" :edit="isEdit" :update="updateData" />
|
v-model="visible"
|
||||||
|
width="700px"
|
||||||
|
destroy-on-close
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@close="closeDialog"
|
||||||
|
>
|
||||||
|
<TableEdit
|
||||||
|
:form-data="rowData"
|
||||||
|
:options="options"
|
||||||
|
:edit="isEdit"
|
||||||
|
:update="updateData"
|
||||||
|
/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog title="查看详情" v-model="visible1" width="700px" destroy-on-close>
|
<el-dialog
|
||||||
|
title="查看详情"
|
||||||
|
v-model="visible1"
|
||||||
|
width="700px"
|
||||||
|
destroy-on-close
|
||||||
|
>
|
||||||
<TableDetail :data="viewData">
|
<TableDetail :data="viewData">
|
||||||
<template #status="{ rows }">
|
<template #status="{ rows }">
|
||||||
<el-tag type="success" v-if="rows.status">启用</el-tag>
|
<el-tag type="success" v-if="rows.status">启用</el-tag>
|
||||||
|
|
@ -29,51 +62,56 @@
|
||||||
</template>
|
</template>
|
||||||
</TableDetail>
|
</TableDetail>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog title="权限管理" v-model="visible2" width="500px" destroy-on-close>
|
<el-dialog
|
||||||
|
title="权限管理"
|
||||||
|
v-model="visible2"
|
||||||
|
width="500px"
|
||||||
|
destroy-on-close
|
||||||
|
>
|
||||||
<RolePermission :permiss-options="permissOptions" />
|
<RolePermission :permiss-options="permissOptions" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="system-role">
|
<script setup lang="ts" name="system-role">
|
||||||
import { ref, reactive } from 'vue';
|
import { ref, reactive } from "vue";
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from "element-plus";
|
||||||
import { Role } from '@/types/role';
|
import { Role } from "@/types/role";
|
||||||
import { fetchRoleData } from '@/api';
|
import { fetchRoleData } from "@/api";
|
||||||
import TableCustom from '@/components/table-custom.vue';
|
import TableCustom from "@/components/table-custom.vue";
|
||||||
import TableDetail from '@/components/table-detail.vue';
|
import TableDetail from "@/components/table-detail.vue";
|
||||||
import RolePermission from './role-permission.vue'
|
import RolePermission from "./role-permission.vue";
|
||||||
import { CirclePlusFilled } from '@element-plus/icons-vue';
|
import { CirclePlusFilled } from "@element-plus/icons-vue";
|
||||||
import { FormOption, FormOptionList } from '@/types/form-option';
|
import { FormOption, FormOptionList } from "@/types/form-option";
|
||||||
|
|
||||||
// 查询相关
|
// 查询相关
|
||||||
const query = reactive({
|
const query = reactive({
|
||||||
name: '',
|
name: "",
|
||||||
});
|
});
|
||||||
const searchOpt = ref<FormOptionList[]>([
|
const searchOpt = ref<FormOptionList[]>([
|
||||||
{ type: 'input', label: '角色名称:', prop: 'name' }
|
{ type: "input", label: "角色名称:", prop: "name" },
|
||||||
])
|
]);
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
changePage(1);
|
changePage(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 表格相关
|
// 表格相关
|
||||||
let columns = ref([
|
let columns = ref([
|
||||||
{ type: 'index', label: '序号', width: 55, align: 'center' },
|
{ type: "index", label: "序号", width: 55, align: "center" },
|
||||||
{ prop: 'name', label: '角色名称' },
|
{ prop: "name", label: "角色名称" },
|
||||||
{ prop: 'key', label: '角色标识' },
|
{ prop: "key", label: "角色标识" },
|
||||||
{ prop: 'status', label: '状态' },
|
{ prop: "status", label: "状态" },
|
||||||
{ prop: 'permissions', label: '权限管理' },
|
{ prop: "permissions", label: "权限管理" },
|
||||||
{ prop: 'operator', label: '操作', width: 250 },
|
{ prop: "operator", label: "操作", width: 250 },
|
||||||
])
|
]);
|
||||||
const page = reactive({
|
const page = reactive({
|
||||||
index: 1,
|
index: 1,
|
||||||
size: 10,
|
size: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
})
|
});
|
||||||
const tableData = ref<Role[]>([]);
|
const tableData = ref<Role[]>([]);
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
const res = await fetchRoleData()
|
const res = await fetchRoleData();
|
||||||
tableData.value = res.data.list;
|
tableData.value = res.data.list;
|
||||||
page.total = res.data.pageTotal;
|
page.total = res.data.pageTotal;
|
||||||
};
|
};
|
||||||
|
|
@ -85,14 +123,21 @@ const changePage = (val: number) => {
|
||||||
|
|
||||||
// 新增/编辑弹窗相关
|
// 新增/编辑弹窗相关
|
||||||
const options = ref<FormOption>({
|
const options = ref<FormOption>({
|
||||||
labelWidth: '100px',
|
labelWidth: "100px",
|
||||||
span: 24,
|
span: 24,
|
||||||
list: [
|
list: [
|
||||||
{ type: 'input', label: '角色名称', prop: 'name', required: true },
|
{ type: "input", label: "角色名称", prop: "name", required: true },
|
||||||
{ type: 'input', label: '角色标识', prop: 'key', required: true },
|
{ type: "input", label: "角色标识", prop: "key", required: true },
|
||||||
{ type: 'switch', label: '状态', prop: 'status', required: false, activeText: '启用', inactiveText: '禁用' },
|
{
|
||||||
]
|
type: "switch",
|
||||||
})
|
label: "状态",
|
||||||
|
prop: "status",
|
||||||
|
required: false,
|
||||||
|
activeText: "启用",
|
||||||
|
inactiveText: "禁用",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const isEdit = ref(false);
|
const isEdit = ref(false);
|
||||||
const rowData = ref({});
|
const rowData = ref({});
|
||||||
|
|
@ -116,47 +161,46 @@ const visible1 = ref(false);
|
||||||
const viewData = ref({
|
const viewData = ref({
|
||||||
row: {},
|
row: {},
|
||||||
list: [],
|
list: [],
|
||||||
column: 1
|
column: 1,
|
||||||
});
|
});
|
||||||
const handleView = (row: Role) => {
|
const handleView = (row: Role) => {
|
||||||
viewData.value.row = { ...row }
|
viewData.value.row = { ...row };
|
||||||
viewData.value.list = [
|
viewData.value.list = [
|
||||||
{
|
{
|
||||||
prop: 'id',
|
prop: "id",
|
||||||
label: '角色ID',
|
label: "角色ID",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'name',
|
prop: "name",
|
||||||
label: '角色名称',
|
label: "角色名称",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'key',
|
prop: "key",
|
||||||
label: '角色标识',
|
label: "角色标识",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'status',
|
prop: "status",
|
||||||
label: '角色状态',
|
label: "角色状态",
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
visible1.value = true;
|
visible1.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 删除相关
|
// 删除相关
|
||||||
const handleDelete = (row: Role) => {
|
const handleDelete = (row: Role) => {
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success("删除成功");
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
// 权限管理弹窗相关
|
// 权限管理弹窗相关
|
||||||
const visible2 = ref(false);
|
const visible2 = ref(false);
|
||||||
const permissOptions = ref({})
|
const permissOptions = ref({});
|
||||||
const handlePermission = (row: Role) => {
|
const handlePermission = (row: Role) => {
|
||||||
visible2.value = true;
|
visible2.value = true;
|
||||||
permissOptions.value = {
|
permissOptions.value = {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
permiss: row.permiss
|
permiss: row.permiss,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|
@ -2,62 +2,89 @@
|
||||||
<div>
|
<div>
|
||||||
<TableSearch :query="query" :options="searchOpt" :search="handleSearch" />
|
<TableSearch :query="query" :options="searchOpt" :search="handleSearch" />
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<TableCustom :columns="columns" :tableData="tableData" :total="page.total" :viewFunc="handleView"
|
<TableCustom
|
||||||
:delFunc="handleDelete" :page-change="changePage" :editFunc="handleEdit">
|
:columns="columns"
|
||||||
|
:tableData="tableData"
|
||||||
|
:total="page.total"
|
||||||
|
:viewFunc="handleView"
|
||||||
|
:delFunc="handleDelete"
|
||||||
|
:page-change="changePage"
|
||||||
|
:editFunc="handleEdit"
|
||||||
|
>
|
||||||
<template #toolbarBtn>
|
<template #toolbarBtn>
|
||||||
<el-button type="warning" :icon="CirclePlusFilled" @click="visible = true">新增</el-button>
|
<el-button
|
||||||
|
type="warning"
|
||||||
|
:icon="CirclePlusFilled"
|
||||||
|
@click="visible = true"
|
||||||
|
>新增</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
</TableCustom>
|
</TableCustom>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<el-dialog :title="isEdit ? '编辑' : '新增'" v-model="visible" width="700px" destroy-on-close
|
<el-dialog
|
||||||
:close-on-click-modal="false" @close="closeDialog">
|
:title="isEdit ? '编辑' : '新增'"
|
||||||
<TableEdit :form-data="rowData" :options="options" :edit="isEdit" :update="updateData" />
|
v-model="visible"
|
||||||
|
width="700px"
|
||||||
|
destroy-on-close
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@close="closeDialog"
|
||||||
|
>
|
||||||
|
<TableEdit
|
||||||
|
:form-data="rowData"
|
||||||
|
:options="options"
|
||||||
|
:edit="isEdit"
|
||||||
|
:update="updateData"
|
||||||
|
/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog title="查看详情" v-model="visible1" width="700px" destroy-on-close>
|
<el-dialog
|
||||||
<TableDetail :data="viewData"></TableDetail>
|
title="查看详情"
|
||||||
|
v-model="visible1"
|
||||||
|
width="700px"
|
||||||
|
destroy-on-close
|
||||||
|
>
|
||||||
|
<TableDetail :data="viewData" />
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="system-user">
|
<script setup lang="ts" name="system-user">
|
||||||
import { ref, reactive } from 'vue';
|
import { ref, reactive } from "vue";
|
||||||
import { ElMessage } from 'element-plus';
|
import { ElMessage } from "element-plus";
|
||||||
import { CirclePlusFilled } from '@element-plus/icons-vue';
|
import { CirclePlusFilled } from "@element-plus/icons-vue";
|
||||||
import { User } from '@/types/user';
|
import { User } from "@/types/user";
|
||||||
import { fetchUserData } from '@/api';
|
import { fetchUserData } from "@/api";
|
||||||
import TableCustom from '@/components/table-custom.vue';
|
import TableCustom from "@/components/table-custom.vue";
|
||||||
import TableDetail from '@/components/table-detail.vue';
|
import TableDetail from "@/components/table-detail.vue";
|
||||||
import TableSearch from '@/components/table-search.vue';
|
import TableSearch from "@/components/table-search.vue";
|
||||||
import { FormOption, FormOptionList } from '@/types/form-option';
|
import { FormOption, FormOptionList } from "@/types/form-option";
|
||||||
|
|
||||||
// 查询相关
|
// 查询相关
|
||||||
const query = reactive({
|
const query = reactive({
|
||||||
name: '',
|
name: "",
|
||||||
});
|
});
|
||||||
const searchOpt = ref<FormOptionList[]>([
|
const searchOpt = ref<FormOptionList[]>([
|
||||||
{ type: 'input', label: '用户名:', prop: 'name' }
|
{ type: "input", label: "用户名:", prop: "name" },
|
||||||
])
|
]);
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
changePage(1);
|
changePage(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 表格相关
|
// 表格相关
|
||||||
let columns = ref([
|
let columns = ref([
|
||||||
{ type: 'index', label: '序号', width: 55, align: 'center' },
|
{ type: "index", label: "序号", width: 55, align: "center" },
|
||||||
{ prop: 'name', label: '用户名' },
|
{ prop: "name", label: "用户名" },
|
||||||
{ prop: 'phone', label: '手机号' },
|
{ prop: "phone", label: "手机号" },
|
||||||
{ prop: 'role', label: '角色' },
|
{ prop: "role", label: "角色" },
|
||||||
{ prop: 'operator', label: '操作', width: 250 },
|
{ prop: "operator", label: "操作", width: 250 },
|
||||||
])
|
]);
|
||||||
const page = reactive({
|
const page = reactive({
|
||||||
index: 1,
|
index: 1,
|
||||||
size: 10,
|
size: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
})
|
});
|
||||||
const tableData = ref<User[]>([]);
|
const tableData = ref<User[]>([]);
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
const res = await fetchUserData()
|
const res = await fetchUserData();
|
||||||
tableData.value = res.data.list;
|
tableData.value = res.data.list;
|
||||||
page.total = res.data.pageTotal;
|
page.total = res.data.pageTotal;
|
||||||
};
|
};
|
||||||
|
|
@ -70,16 +97,16 @@ const changePage = (val: number) => {
|
||||||
|
|
||||||
// 新增/编辑弹窗相关
|
// 新增/编辑弹窗相关
|
||||||
let options = ref<FormOption>({
|
let options = ref<FormOption>({
|
||||||
labelWidth: '100px',
|
labelWidth: "100px",
|
||||||
span: 12,
|
span: 12,
|
||||||
list: [
|
list: [
|
||||||
{ type: 'input', label: '用户名', prop: 'name', required: true },
|
{ type: "input", label: "用户名", prop: "name", required: true },
|
||||||
{ type: 'input', label: '手机号', prop: 'phone', required: true },
|
{ type: "input", label: "手机号", prop: "phone", required: true },
|
||||||
{ type: 'input', label: '密码', prop: 'password', required: true },
|
{ type: "input", label: "密码", prop: "password", required: true },
|
||||||
{ type: 'input', label: '邮箱', prop: 'email', required: true },
|
{ type: "input", label: "邮箱", prop: "email", required: true },
|
||||||
{ type: 'input', label: '角色', prop: 'role', required: true },
|
{ type: "input", label: "角色", prop: "role", required: true },
|
||||||
]
|
],
|
||||||
})
|
});
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const isEdit = ref(false);
|
const isEdit = ref(false);
|
||||||
const rowData = ref({});
|
const rowData = ref({});
|
||||||
|
|
@ -102,47 +129,47 @@ const closeDialog = () => {
|
||||||
const visible1 = ref(false);
|
const visible1 = ref(false);
|
||||||
const viewData = ref({
|
const viewData = ref({
|
||||||
row: {},
|
row: {},
|
||||||
list: []
|
list: [],
|
||||||
});
|
});
|
||||||
const handleView = (row: User) => {
|
const handleView = (row: User) => {
|
||||||
viewData.value.row = { ...row }
|
viewData.value.row = { ...row };
|
||||||
viewData.value.list = [
|
viewData.value.list = [
|
||||||
{
|
{
|
||||||
prop: 'id',
|
prop: "id",
|
||||||
label: '用户ID',
|
label: "用户ID",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'name',
|
prop: "name",
|
||||||
label: '用户名',
|
label: "用户名",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'password',
|
prop: "password",
|
||||||
label: '密码',
|
label: "密码",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'email',
|
prop: "email",
|
||||||
label: '邮箱',
|
label: "邮箱",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'phone',
|
prop: "phone",
|
||||||
label: '电话',
|
label: "电话",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'role',
|
prop: "role",
|
||||||
label: '角色',
|
label: "角色",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'date',
|
prop: "date",
|
||||||
label: '注册日期',
|
label: "注册日期",
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
visible1.value = true;
|
visible1.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 删除相关
|
// 删除相关
|
||||||
const handleDelete = (row: User) => {
|
const handleDelete = (row: User) => {
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success("删除成功");
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped></style>
|
||||||
|
|
@ -2,40 +2,70 @@
|
||||||
<div>
|
<div>
|
||||||
<TableSearch :query="query" :options="searchOpt" :search="handleSearch" />
|
<TableSearch :query="query" :options="searchOpt" :search="handleSearch" />
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<TableCustom :columns="columns" :tableData="tableData" :total="page.total" :viewFunc="handleView"
|
<TableCustom
|
||||||
:delFunc="handleDelete" :editFunc="handleEdit" :refresh="getData" :currentPage="page.index"
|
:columns="columns"
|
||||||
:changePage="changePage">
|
:tableData="tableData"
|
||||||
|
:total="page.total"
|
||||||
|
:viewFunc="handleView"
|
||||||
|
:delFunc="handleDelete"
|
||||||
|
:editFunc="handleEdit"
|
||||||
|
:refresh="getData"
|
||||||
|
:currentPage="page.index"
|
||||||
|
:changePage="changePage"
|
||||||
|
>
|
||||||
<template #toolbarBtn>
|
<template #toolbarBtn>
|
||||||
<el-button type="warning" :icon="CirclePlusFilled" @click="visible = true">新增</el-button>
|
<el-button
|
||||||
</template>
|
type="warning"
|
||||||
<template #money="{ rows }">
|
:icon="CirclePlusFilled"
|
||||||
¥{{ rows.money }}
|
@click="visible = true"
|
||||||
|
>新增</el-button
|
||||||
|
>
|
||||||
</template>
|
</template>
|
||||||
|
<template #money="{ rows }"> ¥{{ rows.money }} </template>
|
||||||
<template #thumb="{ rows }">
|
<template #thumb="{ rows }">
|
||||||
<el-image class="table-td-thumb" :src="rows.thumb" :z-index="10" :preview-src-list="[rows.thumb]"
|
<el-image
|
||||||
preview-teleported>
|
class="table-td-thumb"
|
||||||
</el-image>
|
:src="rows.thumb"
|
||||||
|
:z-index="10"
|
||||||
|
:preview-src-list="[rows.thumb]"
|
||||||
|
preview-teleported
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
<template #state="{ rows }">
|
<template #state="{ rows }">
|
||||||
<el-tag :type="rows.state ? 'success' : 'danger'">
|
<el-tag :type="rows.state ? 'success' : 'danger'">
|
||||||
{{ rows.state ? '正常' : '异常' }}
|
{{ rows.state ? "正常" : "异常" }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</TableCustom>
|
</TableCustom>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<el-dialog :title="isEdit ? '编辑' : '新增'" v-model="visible" width="700px" destroy-on-close
|
<el-dialog
|
||||||
:close-on-click-modal="false" @close="closeDialog">
|
:title="isEdit ? '编辑' : '新增'"
|
||||||
<TableEdit :form-data="rowData" :options="options" :edit="isEdit" :update="updateData">
|
v-model="visible"
|
||||||
|
width="700px"
|
||||||
|
destroy-on-close
|
||||||
|
:close-on-click-modal="false"
|
||||||
|
@close="closeDialog"
|
||||||
|
>
|
||||||
|
<TableEdit
|
||||||
|
:form-data="rowData"
|
||||||
|
:options="options"
|
||||||
|
:edit="isEdit"
|
||||||
|
:update="updateData"
|
||||||
|
>
|
||||||
<template #thumb="{ rows }">
|
<template #thumb="{ rows }">
|
||||||
<img class="table-td-thumb" :src="rows.thumb"></img>
|
<img class="table-td-thumb" :src="rows.thumb" />
|
||||||
</template>
|
</template>
|
||||||
</TableEdit>
|
</TableEdit>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
<el-dialog title="查看详情" v-model="visible1" width="700px" destroy-on-close>
|
<el-dialog
|
||||||
|
title="查看详情"
|
||||||
|
v-model="visible1"
|
||||||
|
width="700px"
|
||||||
|
destroy-on-close
|
||||||
|
>
|
||||||
<TableDetail :data="viewData">
|
<TableDetail :data="viewData">
|
||||||
<template #thumb="{ rows }">
|
<template #thumb="{ rows }">
|
||||||
<el-image :src="rows.thumb"></el-image>
|
<el-image :src="rows.thumb" />
|
||||||
</template>
|
</template>
|
||||||
</TableDetail>
|
</TableDetail>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
@ -43,45 +73,45 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="basetable">
|
<script setup lang="ts" name="basetable">
|
||||||
import { ref, reactive } from 'vue';
|
import { ref, reactive } from "vue";
|
||||||
import { ElMessage, } from 'element-plus';
|
import { ElMessage } from "element-plus";
|
||||||
import { CirclePlusFilled } from '@element-plus/icons-vue';
|
import { CirclePlusFilled } from "@element-plus/icons-vue";
|
||||||
import { fetchData } from '@/api/index';
|
import { fetchData } from "@/api/index";
|
||||||
import TableCustom from '@/components/table-custom.vue';
|
import TableCustom from "@/components/table-custom.vue";
|
||||||
import TableDetail from '@/components/table-detail.vue';
|
import TableDetail from "@/components/table-detail.vue";
|
||||||
import TableSearch from '@/components/table-search.vue';
|
import TableSearch from "@/components/table-search.vue";
|
||||||
import { TableItem } from '@/types/table';
|
import { TableItem } from "@/types/table";
|
||||||
import { FormOption, FormOptionList } from '@/types/form-option';
|
import { FormOption, FormOptionList } from "@/types/form-option";
|
||||||
|
|
||||||
// 查询相关
|
// 查询相关
|
||||||
const query = reactive({
|
const query = reactive({
|
||||||
name: '',
|
name: "",
|
||||||
});
|
});
|
||||||
const searchOpt = ref<FormOptionList[]>([
|
const searchOpt = ref<FormOptionList[]>([
|
||||||
{ type: 'input', label: '用户名:', prop: 'name' }
|
{ type: "input", label: "用户名:", prop: "name" },
|
||||||
])
|
]);
|
||||||
const handleSearch = () => {
|
const handleSearch = () => {
|
||||||
changePage(1);
|
changePage(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 表格相关
|
// 表格相关
|
||||||
let columns = ref([
|
let columns = ref([
|
||||||
{ type: 'selection' },
|
{ type: "selection" },
|
||||||
{ type: 'index', label: '序号', width: 55, align: 'center' },
|
{ type: "index", label: "序号", width: 55, align: "center" },
|
||||||
{ prop: 'name', label: '用户名' },
|
{ prop: "name", label: "用户名" },
|
||||||
{ prop: 'money', label: '账户余额' },
|
{ prop: "money", label: "账户余额" },
|
||||||
{ prop: 'thumb', label: '头像' },
|
{ prop: "thumb", label: "头像" },
|
||||||
{ prop: 'state', label: '账户状态' },
|
{ prop: "state", label: "账户状态" },
|
||||||
{ prop: 'operator', label: '操作', width: 250 },
|
{ prop: "operator", label: "操作", width: 250 },
|
||||||
])
|
]);
|
||||||
const page = reactive({
|
const page = reactive({
|
||||||
index: 1,
|
index: 1,
|
||||||
size: 10,
|
size: 10,
|
||||||
total: 200,
|
total: 200,
|
||||||
})
|
});
|
||||||
const tableData = ref<TableItem[]>([]);
|
const tableData = ref<TableItem[]>([]);
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
const res = await fetchData()
|
const res = await fetchData();
|
||||||
tableData.value = res.data.list;
|
tableData.value = res.data.list;
|
||||||
};
|
};
|
||||||
getData();
|
getData();
|
||||||
|
|
@ -93,15 +123,22 @@ const changePage = (val: number) => {
|
||||||
|
|
||||||
// 新增/编辑弹窗相关
|
// 新增/编辑弹窗相关
|
||||||
let options = ref<FormOption>({
|
let options = ref<FormOption>({
|
||||||
labelWidth: '100px',
|
labelWidth: "100px",
|
||||||
span: 24,
|
span: 24,
|
||||||
list: [
|
list: [
|
||||||
{ type: 'input', label: '用户名', prop: 'name', required: true },
|
{ type: "input", label: "用户名", prop: "name", required: true },
|
||||||
{ type: 'number', label: '账户余额', prop: 'money', required: true },
|
{ type: "number", label: "账户余额", prop: "money", required: true },
|
||||||
{ type: 'switch', activeText: '正常', inactiveText: '异常', label: '账户状态', prop: 'state', required: true },
|
{
|
||||||
{ type: 'upload', label: '头像', prop: 'thumb', required: true },
|
type: "switch",
|
||||||
]
|
activeText: "正常",
|
||||||
})
|
inactiveText: "异常",
|
||||||
|
label: "账户状态",
|
||||||
|
prop: "state",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
{ type: "upload", label: "头像", prop: "thumb", required: true },
|
||||||
|
],
|
||||||
|
});
|
||||||
const visible = ref(false);
|
const visible = ref(false);
|
||||||
const isEdit = ref(false);
|
const isEdit = ref(false);
|
||||||
const rowData = ref({});
|
const rowData = ref({});
|
||||||
|
|
@ -124,39 +161,39 @@ const closeDialog = () => {
|
||||||
const visible1 = ref(false);
|
const visible1 = ref(false);
|
||||||
const viewData = ref({
|
const viewData = ref({
|
||||||
row: {},
|
row: {},
|
||||||
list: []
|
list: [],
|
||||||
});
|
});
|
||||||
const handleView = (row: TableItem) => {
|
const handleView = (row: TableItem) => {
|
||||||
viewData.value.row = { ...row }
|
viewData.value.row = { ...row };
|
||||||
viewData.value.list = [
|
viewData.value.list = [
|
||||||
{
|
{
|
||||||
prop: 'id',
|
prop: "id",
|
||||||
label: '用户ID',
|
label: "用户ID",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'name',
|
prop: "name",
|
||||||
label: '用户名',
|
label: "用户名",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'money',
|
prop: "money",
|
||||||
label: '账户余额',
|
label: "账户余额",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'state',
|
prop: "state",
|
||||||
label: '账户状态',
|
label: "账户状态",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
prop: 'thumb',
|
prop: "thumb",
|
||||||
label: '头像',
|
label: "头像",
|
||||||
},
|
},
|
||||||
]
|
];
|
||||||
visible1.value = true;
|
visible1.value = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 删除相关
|
// 删除相关
|
||||||
const handleDelete = (row: TableItem) => {
|
const handleDelete = (row: TableItem) => {
|
||||||
ElMessage.success('删除成功');
|
ElMessage.success("删除成功");
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|
|
||||||
|
|
@ -4,21 +4,26 @@
|
||||||
<div class="handle-box">
|
<div class="handle-box">
|
||||||
<el-button type="primary" @click="exportXlsx">导出Excel</el-button>
|
<el-button type="primary" @click="exportXlsx">导出Excel</el-button>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="tableData" border class="table" header-cell-class-name="table-header">
|
<el-table
|
||||||
<el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
|
:data="tableData"
|
||||||
<el-table-column prop="name" label="姓名"></el-table-column>
|
border
|
||||||
<el-table-column prop="sno" label="学号"></el-table-column>
|
class="table"
|
||||||
<el-table-column prop="class" label="班级"></el-table-column>
|
header-cell-class-name="table-header"
|
||||||
<el-table-column prop="age" label="年龄"></el-table-column>
|
>
|
||||||
<el-table-column prop="sex" label="性别"></el-table-column>
|
<el-table-column prop="id" label="ID" width="55" align="center" />
|
||||||
|
<el-table-column prop="name" label="姓名" />
|
||||||
|
<el-table-column prop="sno" label="学号" />
|
||||||
|
<el-table-column prop="class" label="班级" />
|
||||||
|
<el-table-column prop="age" label="年龄" />
|
||||||
|
<el-table-column prop="sex" label="性别" />
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="export">
|
<script setup lang="ts" name="export">
|
||||||
import { ref } from 'vue';
|
import { ref } from "vue";
|
||||||
import * as XLSX from 'xlsx';
|
import * as XLSX from "xlsx";
|
||||||
|
|
||||||
interface TableItem {
|
interface TableItem {
|
||||||
id: number;
|
id: number;
|
||||||
|
|
@ -35,25 +40,25 @@ const getData = () => {
|
||||||
tableData.value = [
|
tableData.value = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: '小明',
|
name: "小明",
|
||||||
sno: 'S001',
|
sno: "S001",
|
||||||
class: '一班',
|
class: "一班",
|
||||||
age: '10',
|
age: "10",
|
||||||
sex: '男',
|
sex: "男",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
name: '小红',
|
name: "小红",
|
||||||
sno: 'S002',
|
sno: "S002",
|
||||||
class: '一班',
|
class: "一班",
|
||||||
age: '9',
|
age: "9",
|
||||||
sex: '女',
|
sex: "女",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
getData();
|
getData();
|
||||||
|
|
||||||
const list = [['序号', '姓名', '学号', '班级', '年龄', '性别']];
|
const list = [["序号", "姓名", "学号", "班级", "年龄", "性别"]];
|
||||||
const exportXlsx = () => {
|
const exportXlsx = () => {
|
||||||
tableData.value.map((item: any, i: number) => {
|
tableData.value.map((item: any, i: number) => {
|
||||||
const arr: any[] = [i + 1];
|
const arr: any[] = [i + 1];
|
||||||
|
|
@ -62,7 +67,7 @@ const exportXlsx = () => {
|
||||||
});
|
});
|
||||||
let WorkSheet = XLSX.utils.aoa_to_sheet(list);
|
let WorkSheet = XLSX.utils.aoa_to_sheet(list);
|
||||||
let new_workbook = XLSX.utils.book_new();
|
let new_workbook = XLSX.utils.book_new();
|
||||||
XLSX.utils.book_append_sheet(new_workbook, WorkSheet, '第一页');
|
XLSX.utils.book_append_sheet(new_workbook, WorkSheet, "第一页");
|
||||||
XLSX.writeFile(new_workbook, `表格.xlsx`);
|
XLSX.writeFile(new_workbook, `表格.xlsx`);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -2,28 +2,39 @@
|
||||||
<div>
|
<div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="handle-box">
|
<div class="handle-box">
|
||||||
<el-upload action="#" :limit="1" accept=".xlsx, .xls" :show-file-list="false"
|
<el-upload
|
||||||
:before-upload="beforeUpload" :http-request="handleMany">
|
action="#"
|
||||||
|
:limit="1"
|
||||||
|
accept=".xlsx, .xls"
|
||||||
|
:show-file-list="false"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
:http-request="handleMany"
|
||||||
|
>
|
||||||
<el-button class="mr10" type="success">批量导入</el-button>
|
<el-button class="mr10" type="success">批量导入</el-button>
|
||||||
</el-upload>
|
</el-upload>
|
||||||
<el-link href="/template.xlsx" target="_blank">下载模板</el-link>
|
<el-link href="/template.xlsx" target="_blank">下载模板</el-link>
|
||||||
</div>
|
</div>
|
||||||
<el-table :data="tableData" border class="table" header-cell-class-name="table-header">
|
<el-table
|
||||||
<el-table-column prop="id" label="ID" width="55" align="center"></el-table-column>
|
:data="tableData"
|
||||||
<el-table-column prop="name" label="姓名"></el-table-column>
|
border
|
||||||
<el-table-column prop="sno" label="学号"></el-table-column>
|
class="table"
|
||||||
<el-table-column prop="class" label="班级"></el-table-column>
|
header-cell-class-name="table-header"
|
||||||
<el-table-column prop="age" label="年龄"></el-table-column>
|
>
|
||||||
<el-table-column prop="sex" label="性别"></el-table-column>
|
<el-table-column prop="id" label="ID" width="55" align="center" />
|
||||||
|
<el-table-column prop="name" label="姓名" />
|
||||||
|
<el-table-column prop="sno" label="学号" />
|
||||||
|
<el-table-column prop="class" label="班级" />
|
||||||
|
<el-table-column prop="age" label="年龄" />
|
||||||
|
<el-table-column prop="sex" label="性别" />
|
||||||
</el-table>
|
</el-table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="import">
|
<script setup lang="ts" name="import">
|
||||||
import { UploadProps } from 'element-plus';
|
import { UploadProps } from "element-plus";
|
||||||
import { ref, reactive } from 'vue';
|
import { ref, reactive } from "vue";
|
||||||
import * as XLSX from 'xlsx';
|
import * as XLSX from "xlsx";
|
||||||
|
|
||||||
interface TableItem {
|
interface TableItem {
|
||||||
id: number;
|
id: number;
|
||||||
|
|
@ -40,26 +51,26 @@ const getData = () => {
|
||||||
tableData.value = [
|
tableData.value = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: '小明',
|
name: "小明",
|
||||||
sno: 'S001',
|
sno: "S001",
|
||||||
class: '一班',
|
class: "一班",
|
||||||
age: '10',
|
age: "10",
|
||||||
sex: '男',
|
sex: "男",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
name: '小红',
|
name: "小红",
|
||||||
sno: 'S002',
|
sno: "S002",
|
||||||
class: '一班',
|
class: "一班",
|
||||||
age: '9',
|
age: "9",
|
||||||
sex: '女',
|
sex: "女",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
getData();
|
getData();
|
||||||
|
|
||||||
const importList = ref<any>([]);
|
const importList = ref<any>([]);
|
||||||
const beforeUpload: UploadProps['beforeUpload'] = async (rawFile) => {
|
const beforeUpload: UploadProps["beforeUpload"] = async (rawFile) => {
|
||||||
importList.value = await analysisExcel(rawFile);
|
importList.value = await analysisExcel(rawFile);
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
@ -69,7 +80,7 @@ const analysisExcel = (file: any) => {
|
||||||
reader.onload = function (e: any) {
|
reader.onload = function (e: any) {
|
||||||
const data = e.target.result;
|
const data = e.target.result;
|
||||||
let datajson = XLSX.read(data, {
|
let datajson = XLSX.read(data, {
|
||||||
type: 'binary',
|
type: "binary",
|
||||||
});
|
});
|
||||||
|
|
||||||
const sheetName = datajson.SheetNames[0];
|
const sheetName = datajson.SheetNames[0];
|
||||||
|
|
@ -85,11 +96,11 @@ const handleMany = async () => {
|
||||||
const list = importList.value.map((item: any, index: number) => {
|
const list = importList.value.map((item: any, index: number) => {
|
||||||
return {
|
return {
|
||||||
id: index,
|
id: index,
|
||||||
name: item['姓名'],
|
name: item["姓名"],
|
||||||
sno: item['学号'],
|
sno: item["学号"],
|
||||||
class: item['班级'],
|
class: item["班级"],
|
||||||
age: item['年龄'],
|
age: item["年龄"],
|
||||||
sex: item['性别'],
|
sex: item["性别"],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
tableData.value.push(...list);
|
tableData.value.push(...list);
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,38 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<TableCustom :columns="columns" :tableData="tableData" :hasToolbar="false" :hasPagination="false">
|
<TableCustom
|
||||||
|
:columns="columns"
|
||||||
|
:tableData="tableData"
|
||||||
|
:hasToolbar="false"
|
||||||
|
:hasPagination="false"
|
||||||
|
>
|
||||||
<template #name="{ rows }">
|
<template #name="{ rows }">
|
||||||
<el-input v-if="rows.editing" v-model="rows.name"></el-input>
|
<el-input v-if="rows.editing" v-model="rows.name" />
|
||||||
<span v-else>{{ rows.name }}</span>
|
<span v-else>{{ rows.name }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #password="{ rows }">
|
<template #password="{ rows }">
|
||||||
<el-input v-if="rows.editing" v-model="rows.password"></el-input>
|
<el-input v-if="rows.editing" v-model="rows.password" />
|
||||||
<span v-else>{{ rows.password }}</span>
|
<span v-else>{{ rows.password }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #email="{ rows }">
|
<template #email="{ rows }">
|
||||||
<el-input v-if="rows.editing" v-model="rows.email"></el-input>
|
<el-input v-if="rows.editing" v-model="rows.email" />
|
||||||
<span v-else>{{ rows.email }}</span>
|
<span v-else>{{ rows.email }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #role="{ rows }">
|
<template #role="{ rows }">
|
||||||
<el-select v-if="rows.editing" v-model="rows.role">
|
<el-select v-if="rows.editing" v-model="rows.role">
|
||||||
<el-option label="管理员" value="管理员"></el-option>
|
<el-option label="管理员" value="管理员" />
|
||||||
<el-option label="普通用户" value="普通用户"></el-option>
|
<el-option label="普通用户" value="普通用户" />
|
||||||
</el-select>
|
</el-select>
|
||||||
<span v-else>{{ rows.role }}</span>
|
<span v-else>{{ rows.role }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template #operator="{ rows, index }">
|
<template #operator="{ rows, index }">
|
||||||
<template v-if="!rows.editing">
|
<template v-if="!rows.editing">
|
||||||
<el-button type="primary" size="small" :icon="Edit" @click="handleEdit(rows)">
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
:icon="Edit"
|
||||||
|
@click="handleEdit(rows)"
|
||||||
|
>
|
||||||
编辑
|
编辑
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="danger" size="small" :icon="Delete" @click="">
|
<el-button type="danger" size="small" :icon="Delete" @click="">
|
||||||
|
|
@ -30,10 +40,20 @@
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-button type="success" size="small" :icon="Select" @click="rows.editing = false">
|
<el-button
|
||||||
|
type="success"
|
||||||
|
size="small"
|
||||||
|
:icon="Select"
|
||||||
|
@click="rows.editing = false"
|
||||||
|
>
|
||||||
保存
|
保存
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="default" size="small" :icon="CloseBold" @click="handleCancel(rows, index)">
|
<el-button
|
||||||
|
type="default"
|
||||||
|
size="small"
|
||||||
|
:icon="CloseBold"
|
||||||
|
@click="handleCancel(rows, index)"
|
||||||
|
>
|
||||||
取消
|
取消
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -43,19 +63,19 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts" name="table-editor">
|
<script setup lang="ts" name="table-editor">
|
||||||
import { ref } from 'vue';
|
import { ref } from "vue";
|
||||||
import { Delete, Edit, CloseBold, Select } from '@element-plus/icons-vue';
|
import { Delete, Edit, CloseBold, Select } from "@element-plus/icons-vue";
|
||||||
import TableCustom from '@/components/table-custom.vue';
|
import TableCustom from "@/components/table-custom.vue";
|
||||||
import { fetchUserData } from '@/api/index';
|
import { fetchUserData } from "@/api/index";
|
||||||
|
|
||||||
let columns = ref([
|
let columns = ref([
|
||||||
{ type: 'index', label: '序号', width: 55, align: 'center' },
|
{ type: "index", label: "序号", width: 55, align: "center" },
|
||||||
{ prop: 'name', label: '用户名' },
|
{ prop: "name", label: "用户名" },
|
||||||
{ prop: 'password', label: '密码' },
|
{ prop: "password", label: "密码" },
|
||||||
{ prop: 'email', label: '邮箱' },
|
{ prop: "email", label: "邮箱" },
|
||||||
{ prop: 'role', label: '角色' },
|
{ prop: "role", label: "角色" },
|
||||||
{ prop: 'operator', label: '操作', width: 180 },
|
{ prop: "operator", label: "操作", width: 180 },
|
||||||
])
|
]);
|
||||||
const tableData = ref([]);
|
const tableData = ref([]);
|
||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
const res = await fetchUserData();
|
const res = await fetchUserData();
|
||||||
|
|
@ -63,7 +83,7 @@ const getData = async () => {
|
||||||
};
|
};
|
||||||
getData();
|
getData();
|
||||||
|
|
||||||
const rowData = ref({})
|
const rowData = ref({});
|
||||||
|
|
||||||
const handleEdit = (row) => {
|
const handleEdit = (row) => {
|
||||||
rowData.value = { ...row };
|
rowData.value = { ...row };
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
declare module '*.vue' {
|
declare module "*.vue" {
|
||||||
import type { DefineComponent } from 'vue'
|
import type { DefineComponent } from "vue";
|
||||||
const component: DefineComponent<{}, {}, any>
|
const component: DefineComponent<{}, {}, any>;
|
||||||
export default component
|
export default component;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare module 'vue-schart';
|
declare module "vue-schart";
|
||||||
declare module 'nprogress'
|
declare module "nprogress";
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,5 @@
|
||||||
"@/*": ["src/*"]
|
"@/*": ["src/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"include": ["src/**/*.ts", "src/**/*.d.ts","src/**/*.vue"],
|
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.vue"]
|
||||||
"references": [{ "path": "./tsconfig.node.json" }]
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"composite": true,
|
|
||||||
"module": "ESNext",
|
|
||||||
"moduleResolution": "Node",
|
|
||||||
"allowSyntheticDefaultImports": true
|
|
||||||
},
|
|
||||||
"include": ["vite.config.ts"]
|
|
||||||
}
|
|
||||||
|
|
@ -1,31 +1,53 @@
|
||||||
import { defineConfig } from 'vite';
|
import { UserConfig, ConfigEnv, loadEnv, defineConfig } from "vite";
|
||||||
import vue from '@vitejs/plugin-vue';
|
import vue from "@vitejs/plugin-vue";
|
||||||
import VueSetupExtend from 'vite-plugin-vue-setup-extend';
|
import VueSetupExtend from "vite-plugin-vue-setup-extend";
|
||||||
import AutoImport from 'unplugin-auto-import/vite';
|
import AutoImport from "unplugin-auto-import/vite";
|
||||||
import Components from 'unplugin-vue-components/vite';
|
import Components from "unplugin-vue-components/vite";
|
||||||
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
|
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
|
||||||
export default defineConfig({
|
|
||||||
base: './',
|
export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
|
||||||
|
const env = loadEnv(mode, process.cwd());
|
||||||
|
return {
|
||||||
|
base: "./",
|
||||||
plugins: [
|
plugins: [
|
||||||
vue(),
|
vue(),
|
||||||
VueSetupExtend(),
|
VueSetupExtend(),
|
||||||
AutoImport({
|
AutoImport({
|
||||||
resolvers: [ElementPlusResolver()]
|
resolvers: [ElementPlusResolver()],
|
||||||
}),
|
}),
|
||||||
Components({
|
Components({
|
||||||
resolvers: [ElementPlusResolver()]
|
resolvers: [ElementPlusResolver()],
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
include: ['schart.js']
|
include: ["schart.js"],
|
||||||
},
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': '/src',
|
"@": "/src",
|
||||||
'~': '/src/assets'
|
"~": "/src/assets",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
define: {
|
define: {
|
||||||
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: "true",
|
__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: "true",
|
||||||
},
|
},
|
||||||
|
server: {
|
||||||
|
// 允许IP访问
|
||||||
|
host: "0.0.0.0",
|
||||||
|
// 应用端口 (默认:3000)
|
||||||
|
port: Number(env.VITE_APP_PORT),
|
||||||
|
// 运行是否自动打开浏览器
|
||||||
|
open: true,
|
||||||
|
proxy: {
|
||||||
|
/** 代理前缀为 /dev-api 的请求 */
|
||||||
|
[env.VITE_APP_BASE_API]: {
|
||||||
|
changeOrigin: true,
|
||||||
|
// 接口地址
|
||||||
|
target: env.VITE_APP_API_URL,
|
||||||
|
rewrite: (path) =>
|
||||||
|
path.replace(new RegExp("^" + env.VITE_APP_BASE_API), ""),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue