Commit 60a0a033 by 吴春元

设备地图调整,登录页面搭建,配置信息修改

parent 5ad3ceae
# 页面标题
VITE_APP_TITLE = 智慧隧道管理平台-集团版
# 开发环境配置
VITE_APP_ENV = 'development'
# 智慧隧道管理平台-集团版/开发环境
VITE_APP_BASE_API = '/dev-api'
# 页面标题
VITE_APP_TITLE = 智慧隧道管理平台-集团版
# 生产环境配置
VITE_APP_ENV = 'production'
# 智慧隧道管理平台-集团版/生产环境
VITE_APP_BASE_API = '/prod-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip
\ No newline at end of file
# 页面标题
VITE_APP_TITLE = 智慧隧道管理平台-集团版
# 生产环境配置
VITE_APP_ENV = 'staging'
# 智慧隧道管理平台-集团版/生产环境
VITE_APP_BASE_API = '/stage-api'
# 是否在打包时开启压缩,支持 gzip 和 brotli
VITE_BUILD_COMPRESS = gzip
\ No newline at end of file
{
"globals": {
"Component": true,
"ComponentPublicInstance": true,
"ComputedRef": true,
"DirectiveBinding": true,
"EffectScope": true,
"ExtractDefaultPropTypes": true,
"ExtractPropTypes": true,
"ExtractPublicPropTypes": true,
"InjectionKey": true,
"MaybeRef": true,
"MaybeRefOrGetter": true,
"PropType": true,
"Ref": true,
"ShallowRef": true,
"Slot": true,
"Slots": true,
"VNode": true,
"WritableComputedRef": true,
"computed": true,
"createApp": true,
"customRef": true,
"defineAsyncComponent": true,
"defineComponent": true,
"effectScope": true,
"getCurrentInstance": true,
"getCurrentScope": true,
"getCurrentWatcher": true,
"h": true,
"inject": true,
"isProxy": true,
"isReactive": true,
"isReadonly": true,
"isRef": true,
"isShallow": true,
"markRaw": true,
"nextTick": true,
"onActivated": true,
"onBeforeMount": true,
"onBeforeRouteLeave": true,
"onBeforeRouteUpdate": true,
"onBeforeUnmount": true,
"onBeforeUpdate": true,
"onDeactivated": true,
"onErrorCaptured": true,
"onMounted": true,
"onRenderTracked": true,
"onRenderTriggered": true,
"onScopeDispose": true,
"onServerPrefetch": true,
"onUnmounted": true,
"onUpdated": true,
"onWatcherCleanup": true,
"provide": true,
"reactive": true,
"readonly": true,
"ref": true,
"resolveComponent": true,
"shallowReactive": true,
"shallowReadonly": true,
"shallowRef": true,
"toRaw": true,
"toRef": true,
"toRefs": true,
"toValue": true,
"triggerRef": true,
"unref": true,
"useAttrs": true,
"useCssModule": true,
"useCssVars": true,
"useId": true,
"useLink": true,
"useModel": true,
"useRoute": true,
"useRouter": true,
"useSlots": true,
"useTemplateRef": true,
"watch": true,
"watchEffect": true,
"watchPostEffect": true,
"watchSyncEffect": true
}
}
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
dist
dist-ssr
*.local
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
......@@ -6,5 +6,73 @@
// biome-ignore lint: disable
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const effectScope: typeof import('vue')['effectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const getCurrentWatcher: typeof import('vue')['getCurrentWatcher']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const isShallow: typeof import('vue')['isShallow']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useId: typeof import('vue')['useId']
const useLink: typeof import('vue-router')['useLink']
const useModel: typeof import('vue')['useModel']
const useRoute: typeof import('vue-router')['useRoute']
const useRouter: typeof import('vue-router')['useRouter']
const useSlots: typeof import('vue')['useSlots']
const useTemplateRef: typeof import('vue')['useTemplateRef']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, Slot, Slots, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, ShallowRef, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
import('vue')
}
......@@ -11,13 +11,25 @@ declare module 'vue' {
ContainerWrap: typeof import('./src/components/ContainerWrap/index.vue')['default']
ElButton: typeof import('element-plus/es')['ElButton']
ElCascader: typeof import('element-plus/es')['ElCascader']
ElCheckbox: typeof import('element-plus/es')['ElCheckbox']
ElCol: typeof import('element-plus/es')['ElCol']
ElDialog: typeof import('element-plus/es')['ElDialog']
ElForm: typeof import('element-plus/es')['ElForm']
ElFormItem: typeof import('element-plus/es')['ElFormItem']
ElIcon: typeof import('element-plus/es')['ElIcon']
ElInput: typeof import('element-plus/es')['ElInput']
ElOption: typeof import('element-plus/es')['ElOption']
ElRow: typeof import('element-plus/es')['ElRow']
ElSelect: typeof import('element-plus/es')['ElSelect']
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
ItemWrap: typeof import('./src/components/ItemWrap/index.vue')['default']
ItemWrap2: typeof import('./src/components/ItemWrap2/index.vue')['default']
ProgressBar: typeof import('./src/components/ProgressBar/index.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SubTitleWrap: typeof import('./src/components/SubTitleWrap/index.vue')['default']
SvgIcon: typeof import('./src/components/SvgIcon/index.vue')['default']
TitleWrap: typeof import('./src/components/TitleWrap/index.vue')['default']
TunnelProgress: typeof import('./src/components/TunnelProgress/index.vue')['default']
}
}
......@@ -209,8 +209,12 @@ hoistedDependencies:
'@vue/compiler-ssr': private
'@vue/compiler-vue2@2.7.16':
'@vue/compiler-vue2': private
'@vue/devtools-api@6.6.4':
'@vue/devtools-api@7.7.7':
'@vue/devtools-api': private
'@vue/devtools-kit@7.7.7':
'@vue/devtools-kit': private
'@vue/devtools-shared@7.7.7':
'@vue/devtools-shared': private
'@vue/language-core@3.0.6(typescript@5.8.3)':
'@vue/language-core': private
'@vue/reactivity@3.5.21':
......@@ -239,8 +243,12 @@ hoistedDependencies:
argparse: private
async-validator@4.2.5:
async-validator: private
asynckit@0.4.0:
asynckit: private
binary-extensions@2.3.0:
binary-extensions: private
birpc@2.6.1:
birpc: private
bmaplib.curveline@1.0.0:
bmaplib.curveline: private
bmaplib.heatmap@1.0.4:
......@@ -253,12 +261,18 @@ hoistedDependencies:
bmaplib.texticonoverlay: private
braces@3.0.3:
braces: private
call-bind-apply-helpers@1.0.2:
call-bind-apply-helpers: private
chokidar@4.0.3:
chokidar: private
chownr@3.0.0:
chownr: private
combined-stream@1.0.8:
combined-stream: private
confbox@0.1.8:
confbox: private
copy-anything@3.0.5:
copy-anything: private
csstype@3.1.3:
csstype: private
dayjs@1.11.18:
......@@ -267,12 +281,24 @@ hoistedDependencies:
de-indent: private
debug@4.4.1:
debug: private
delayed-stream@1.0.0:
delayed-stream: private
detect-libc@1.0.3:
detect-libc: private
dunder-proto@1.0.1:
dunder-proto: private
enhanced-resolve@5.18.3:
enhanced-resolve: private
entities@1.1.2:
entities: private
es-define-property@1.0.1:
es-define-property: private
es-errors@1.3.0:
es-errors: private
es-object-atoms@1.1.1:
es-object-atoms: private
es-set-tostringtag@2.1.0:
es-set-tostringtag: private
esbuild@0.25.9:
esbuild: private
escape-html@1.0.3:
......@@ -287,14 +313,34 @@ hoistedDependencies:
fdir: private
fill-range@7.1.1:
fill-range: private
follow-redirects@1.15.11:
follow-redirects: private
form-data@4.0.4:
form-data: private
fsevents@2.3.3:
fsevents: private
function-bind@1.1.2:
function-bind: private
get-intrinsic@1.3.0:
get-intrinsic: private
get-proto@1.0.1:
get-proto: private
glob-parent@5.1.2:
glob-parent: private
gopd@1.2.0:
gopd: private
graceful-fs@4.2.11:
graceful-fs: private
has-symbols@1.1.0:
has-symbols: private
has-tostringtag@1.0.2:
has-tostringtag: private
hasown@2.0.2:
hasown: private
he@1.2.0:
he: private
hookable@5.5.3:
hookable: private
immutable@5.1.3:
immutable: private
is-binary-path@2.1.0:
......@@ -305,6 +351,8 @@ hoistedDependencies:
is-glob: private
is-number@7.0.0:
is-number: private
is-what@4.1.16:
is-what: private
jiti@2.5.1:
jiti: private
js-tokens@9.0.1:
......@@ -345,12 +393,18 @@ hoistedDependencies:
magic-string: private
markdown-it@8.4.2:
markdown-it: private
math-intrinsics@1.1.0:
math-intrinsics: private
mdurl@1.0.1:
mdurl: private
memoize-one@6.0.0:
memoize-one: private
micromatch@4.0.8:
micromatch: private
mime-db@1.52.0:
mime-db: private
mime-types@2.1.35:
mime-types: private
minipass@7.1.2:
minipass: private
minizlib@3.0.2:
......@@ -375,26 +429,36 @@ hoistedDependencies:
path-browserify: private
pathe@2.0.3:
pathe: private
perfect-debounce@1.0.0:
perfect-debounce: private
picocolors@1.1.1:
picocolors: private
picomatch@4.0.3:
picomatch: private
pkg-types@2.3.0:
pkg-types: private
proxy-from-env@1.1.0:
proxy-from-env: private
quansync@0.2.11:
quansync: private
readdirp@3.6.0:
readdirp: private
rfdc@1.4.1:
rfdc: private
rollup@4.50.1:
rollup: private
scule@1.3.0:
scule: private
source-map-js@1.2.1:
source-map-js: private
speakingurl@14.0.1:
speakingurl: private
sprintf-js@1.0.3:
sprintf-js: private
strip-literal@3.0.0:
strip-literal: private
superjson@2.2.2:
superjson: private
tapable@2.2.3:
tapable: private
tar@7.4.3:
......@@ -436,7 +500,7 @@ layoutVersion: 5
nodeLinker: isolated
packageManager: pnpm@9.4.0
pendingBuilds: []
prunedAt: Tue, 14 Oct 2025 06:16:23 GMT
prunedAt: Wed, 22 Oct 2025 04:39:09 GMT
publicHoistPattern:
- '*eslint*'
- '*prettier*'
......
../../@vue+devtools-api@6.6.4/node_modules/@vue/devtools-api
\ No newline at end of file
../../@vue+devtools-api@7.7.7/node_modules/@vue/devtools-api
\ No newline at end of file
{
"hash": "8e753367",
"configHash": "49fd5978",
"hash": "e671f9b4",
"configHash": "ca4ef806",
"lockfileHash": "0ea25b1a",
"browserHash": "df4a076a",
"browserHash": "d6d47013",
"optimized": {
"vue": {
"src": "../../.pnpm/vue@3.5.21_typescript@5.8.3/node_modules/vue/dist/vue.runtime.esm-bundler.js",
"file": "vue.js",
"fileHash": "2a349cde",
"needsInterop": false
},
"vue-router": {
"src": "../../.pnpm/vue-router@4.5.1_vue@3.5.21_typescript@5.8.3_/node_modules/vue-router/dist/vue-router.mjs",
"file": "vue-router.js",
"fileHash": "b1ecfe9b",
"needsInterop": false
},
"@bmapgl-plugin/cluster": {
"src": "../../.pnpm/@bmapgl-plugin+cluster@0.0.10/node_modules/@bmapgl-plugin/cluster/index.js",
"file": "@bmapgl-plugin_cluster.js",
"fileHash": "28dcf042",
"needsInterop": true
},
"@element-plus/icons-vue": {
"src": "../../.pnpm/@element-plus+icons-vue@2.3.2_vue@3.5.21_typescript@5.8.3_/node_modules/@element-plus/icons-vue/dist/index.js",
"file": "@element-plus_icons-vue.js",
"fileHash": "605ac4cc",
"fileHash": "58403fc9",
"needsInterop": false
},
"echarts": {
"src": "../../.pnpm/echarts@6.0.0/node_modules/echarts/index.js",
"file": "echarts.js",
"fileHash": "c3a769da",
"fileHash": "e5af48df",
"needsInterop": false
},
"element-plus": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/index.mjs",
"file": "element-plus.js",
"fileHash": "16379c51",
"fileHash": "250aa47a",
"needsInterop": false
},
"element-plus/es/locales.mjs": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/locales.mjs",
"file": "element-plus_es_locales__mjs.js",
"fileHash": "d9047404",
"needsInterop": false
},
"mitt": {
"src": "../../.pnpm/mitt@3.0.1/node_modules/mitt/dist/mitt.mjs",
"file": "mitt.js",
"fileHash": "00e242b5",
"needsInterop": false
},
"typescript": {
"src": "../../.pnpm/typescript@5.8.3/node_modules/typescript/lib/typescript.js",
"file": "typescript.js",
"fileHash": "9e9af5b7",
"fileHash": "156c0fc2",
"needsInterop": true
},
"vue": {
"src": "../../.pnpm/vue@3.5.21_typescript@5.8.3/node_modules/vue/dist/vue.runtime.esm-bundler.js",
"file": "vue.js",
"fileHash": "b6e5f295",
"element-plus/es": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/index.mjs",
"file": "element-plus_es.js",
"fileHash": "30a419b8",
"needsInterop": false
},
"vue-router": {
"src": "../../.pnpm/vue-router@4.5.1_vue@3.5.21_typescript@5.8.3_/node_modules/vue-router/dist/vue-router.mjs",
"file": "vue-router.js",
"fileHash": "ebd96e13",
"element-plus/es/components/base/style/index": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/components/base/style/index.mjs",
"file": "element-plus_es_components_base_style_index.js",
"fileHash": "4be03869",
"needsInterop": false
},
"mitt": {
"src": "../../.pnpm/mitt@3.0.1/node_modules/mitt/dist/mitt.mjs",
"file": "mitt.js",
"fileHash": "86dbed21",
"element-plus/es/components/select/style/index": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/components/select/style/index.mjs",
"file": "element-plus_es_components_select_style_index.js",
"fileHash": "cc768641",
"needsInterop": false
},
"echarts/extension/bmap/bmap": {
"src": "../../.pnpm/echarts@6.0.0/node_modules/echarts/extension/bmap/bmap.js",
"file": "echarts_extension_bmap_bmap.js",
"fileHash": "70a3fa90",
"element-plus/es/components/option/style/index": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/components/option/style/index.mjs",
"file": "element-plus_es_components_option_style_index.js",
"fileHash": "feb02448",
"needsInterop": false
},
"vue-baidu-map": {
"src": "../../.pnpm/vue-baidu-map@0.21.22_vue@3.5.21_typescript@5.8.3_/node_modules/vue-baidu-map/index.js",
"file": "vue-baidu-map.js",
"fileHash": "c3b50cd5",
"needsInterop": true
"element-plus/es/components/cascader/style/index": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/components/cascader/style/index.mjs",
"file": "element-plus_es_components_cascader_style_index.js",
"fileHash": "f2d3fa4d",
"needsInterop": false
},
"@bmapgl-plugin/cluster": {
"src": "../../.pnpm/@bmapgl-plugin+cluster@0.0.10/node_modules/@bmapgl-plugin/cluster/index.js",
"file": "@bmapgl-plugin_cluster.js",
"fileHash": "3c482662",
"element-plus/es/components/dialog/style/index": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/components/dialog/style/index.mjs",
"file": "element-plus_es_components_dialog_style_index.js",
"fileHash": "4b8bd945",
"needsInterop": false
},
"element-plus/es/components/icon/style/index": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/components/icon/style/index.mjs",
"file": "element-plus_es_components_icon_style_index.js",
"fileHash": "3b7a7934",
"needsInterop": false
},
"element-plus/es/components/row/style/index": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/components/row/style/index.mjs",
"file": "element-plus_es_components_row_style_index.js",
"fileHash": "7da42bf7",
"needsInterop": false
},
"element-plus/es/components/col/style/index": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/components/col/style/index.mjs",
"file": "element-plus_es_components_col_style_index.js",
"fileHash": "9defdb09",
"needsInterop": false
},
"pinia": {
"src": "../../.pnpm/pinia@3.0.3_typescript@5.8.3_vue@3.5.21_typescript@5.8.3_/node_modules/pinia/dist/pinia.mjs",
"file": "pinia.js",
"fileHash": "090b6e20",
"needsInterop": false
},
"js-cookie": {
"src": "../../.pnpm/js-cookie@3.0.5/node_modules/js-cookie/dist/js.cookie.mjs",
"file": "js-cookie.js",
"fileHash": "939ddd87",
"needsInterop": false
},
"nprogress": {
"src": "../../.pnpm/nprogress@0.2.0/node_modules/nprogress/nprogress.js",
"file": "nprogress.js",
"fileHash": "46ede6a6",
"needsInterop": true
},
"axios": {
"src": "../../.pnpm/axios@1.12.2/node_modules/axios/index.js",
"file": "axios.js",
"fileHash": "8ab60344",
"needsInterop": false
},
"element-plus/es/components/form/style/index": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/components/form/style/index.mjs",
"file": "element-plus_es_components_form_style_index.js",
"fileHash": "a38e69d2",
"needsInterop": false
},
"element-plus/es/components/button/style/index": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/components/button/style/index.mjs",
"file": "element-plus_es_components_button_style_index.js",
"fileHash": "a3e9aeb6",
"needsInterop": false
},
"element-plus/es/components/checkbox/style/index": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/components/checkbox/style/index.mjs",
"file": "element-plus_es_components_checkbox_style_index.js",
"fileHash": "136c8858",
"needsInterop": false
},
"element-plus/es/components/form-item/style/index": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/components/form-item/style/index.mjs",
"file": "element-plus_es_components_form-item_style_index.js",
"fileHash": "cd3db346",
"needsInterop": false
},
"element-plus/es/components/input/style/index": {
"src": "../../.pnpm/element-plus@2.11.2_vue@3.5.21_typescript@5.8.3_/node_modules/element-plus/es/components/input/style/index.mjs",
"file": "element-plus_es_components_input_style_index.js",
"fileHash": "2c8a3acc",
"needsInterop": false
},
"jsencrypt": {
"src": "../../.pnpm/jsencrypt@3.5.4/node_modules/jsencrypt/lib/index.js",
"file": "jsencrypt.js",
"fileHash": "b18f4b8b",
"needsInterop": false
}
},
"chunks": {
"chunk-AO2GUBMD": {
"file": "chunk-AO2GUBMD.js"
},
"chunk-XJ4FNH6G": {
"file": "chunk-XJ4FNH6G.js"
},
"chunk-H37PGX34": {
"file": "chunk-H37PGX34.js"
},
"chunk-WYGDTZ7H": {
"file": "chunk-WYGDTZ7H.js"
},
"chunk-5WDSIG6Y": {
"file": "chunk-5WDSIG6Y.js"
},
"chunk-QMPMWDA4": {
"file": "chunk-QMPMWDA4.js"
},
"chunk-U7ZX2BS5": {
"file": "chunk-U7ZX2BS5.js"
},
"chunk-HQ2UCEI6": {
"file": "chunk-HQ2UCEI6.js"
},
"chunk-P6TLTLJ2": {
"file": "chunk-P6TLTLJ2.js"
},
"chunk-24MKLYDO": {
"file": "chunk-24MKLYDO.js"
},
"chunk-PR4QN5HX": {
"file": "chunk-PR4QN5HX.js"
}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
.pnpm/vue-baidu-map@0.21.22_vue@3.5.21_typescript@5.8.3_/node_modules/vue-baidu-map
\ No newline at end of file
......@@ -13,9 +13,14 @@
"@bmapgl-plugin/cluster": "^0.0.10",
"@element-plus/icons-vue": "^2.3.2",
"@tailwindcss/postcss": "^4.1.13",
"axios": "^1.12.2",
"echarts": "^6.0.0",
"element-plus": "^2.11.2",
"js-cookie": "^3.0.5",
"jsencrypt": "^3.5.4",
"mitt": "^3.0.1",
"nprogress": "^0.2.0",
"pinia": "^3.0.3",
"postcss": "^8.5.6",
"tailwindcss": "^4.1.13",
"vue": "^3.5.18",
......@@ -24,6 +29,8 @@
},
"devDependencies": {
"@types/node": "^24.3.1",
"@types/js-cookie": "^3.0.6",
"@types/nprogress": "^0.2.3",
"@vitejs/plugin-vue": "^6.0.1",
"@vue/tsconfig": "^0.7.0",
"sass": "^1.92.1",
......
import request from "@/utils/request";
// 登录方法
export function login(
username: string,
password: string,
code: string,
uuid: string
) {
const data = {
username,
password,
code,
uuid,
};
return request({
url: "/login",
headers: {
isToken: false,
repeatSubmit: false,
},
method: "post",
data: data,
});
}
// 注册方法
export function register(data: any) {
return request({
url: "/register",
headers: {
isToken: false,
},
method: "post",
data: data,
});
}
// 获取用户详细信息
export function getInfo() {
return request({
url: "/getInfo",
method: "get",
});
}
// 退出方法
export function logout() {
return request({
url: "/auth/logout",
method: "post",
});
}
// 获取验证码
export function getCodeImg() {
return request({
url: "/code",
headers: {
isToken: false,
},
method: "get",
timeout: 20000,
});
}
import request from "@/utils/request";
import useUserStore from "@/store/modules/user";
// 获取机构信息,传用户id
export function officeInfo() {
const userStore = useUserStore();
return request({
url: "/getOfficeInfo?userId=" + userStore.id,
method: "get",
});
}
import request from "@/utils/request";
// 统计隧道数量(总数、进行中、已完工)
export function tunnelProjectNumCount(deptId: string) {
return request({
url: "/getInfo?deptId=" + deptId,
method: "get",
});
}
<?xml version="1.0" encoding="UTF-8"?>
<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
<rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
<filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
</defs>
<g id="配置面板" width="48" height="40" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="setting-copy-2" width="48" height="40" transform="translate(-1190.000000, -136.000000)">
<g id="Group-8" width="48" height="40" transform="translate(1167.000000, 0.000000)">
<g id="Group-5-Copy-5" filter="url(#filter-1)" transform="translate(25.000000, 137.000000)">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<g id="Rectangle-18">
<use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
<use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
</g>
<rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
<rect id="Rectangle-18" fill="#303648" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
<feMerge>
<feMergeNode in="shadowMatrixOuter1"></feMergeNode>
<feMergeNode in="SourceGraphic"></feMergeNode>
</feMerge>
</filter>
<rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
<filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
<feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
</defs>
<g id="配置面板" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="setting-copy-2" transform="translate(-1254.000000, -136.000000)">
<g id="Group-8" transform="translate(1167.000000, 0.000000)">
<g id="Group-5" filter="url(#filter-1)" transform="translate(89.000000, 137.000000)">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<g id="Rectangle-18">
<use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
<use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
</g>
<rect id="Rectangle-18" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
<rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
......@@ -9,7 +9,9 @@ import TitleWrap from "@components/TitleWrap/index.vue";
import ContainerWrap from "@components/ContainerWrap/index.vue";
import * as ElementPlusIconsVue from "@element-plus/icons-vue";
import "./assets/styles/element-plus.scss";
// import BaiduMap from "vue-baidu-map";
import store from "./store";
import "./permission.ts"; // permission control
import plugins from "./plugins"; // plugins
const app = createApp(App);
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
......@@ -18,7 +20,4 @@ for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component("TitleWrap", TitleWrap);
app.component("ContainerWrap", ContainerWrap);
app.use(router).use(ElementPlus).mount("#app");
// Vue.use(BaiduMap, {
// ak: "i8RgXE4a6vzGgbFs5s4ynlyUh6YnUQIB", //这个地方是官方提供的ak密钥
// });
app.use(router).use(ElementPlus).use(store).use(plugins).mount("#app");
import router from "./router";
import { ElMessage } from "element-plus";
import NProgress from "nprogress";
import "nprogress/nprogress.css";
import { getToken } from "@/utils/auth";
import { isRelogin } from "@/utils/request";
import useUserStore from "@/store/modules/user";
NProgress.configure({ showSpinner: false });
const whiteList = ["/login", "/register"];
router.beforeEach((to, from, next) => {
NProgress.start();
if (getToken()) {
/* has token*/
if (to.path === "/login") {
next({ path: "/" });
NProgress.done();
} else if (whiteList.indexOf(to.path) !== -1) {
next(); //
} else {
if (useUserStore().roles.length === 0) {
isRelogin.show = true;
// 判断当前用户是否已拉取完user_info信息
useUserStore()
.getInfo()
.then(() => {
isRelogin.show = false;
next({ ...to, replace: true });
})
.catch((err: any) => {
useUserStore()
.logOut()
.then(() => {
ElMessage.error(err);
next({ path: "/" });
});
});
} else {
next();
}
}
} else {
// 没有token
if (whiteList.indexOf(to.path) !== -1) {
// 在免登录白名单,直接进入
next();
} else {
next(`/login?redirect=${to.fullPath}`); // 否则全部重定向到登录页
NProgress.done();
}
}
});
router.afterEach(() => {
NProgress.done();
});
import useUserStore from '@/store/modules/user'
function authPermission(permission: string) {
const all_permission = "*:*:*";
const permissions = useUserStore().permissions
if (permission && permission.length > 0) {
return permissions.some((v: string) => {
return all_permission === v || v === permission
})
} else {
return false
}
}
function authRole(role: string) {
const super_admin = "admin";
const roles = useUserStore().roles
if (role && role.length > 0) {
return roles.some((v: string) => {
return super_admin === v || v === role
})
} else {
return false
}
}
export default {
// 验证用户是否具备某权限
hasPermi(permission: string) {
return authPermission(permission);
},
// 验证用户是否含有指定权限,只需包含其中一个
hasPermiOr(permissions: string[]) {
return permissions.some(item => {
return authPermission(item)
})
},
// 验证用户是否含有指定权限,必须全部拥有
hasPermiAnd(permissions: string[]) {
return permissions.every(item => {
return authPermission(item)
})
},
// 验证用户是否具备某角色
hasRole(role: string) {
return authRole(role);
},
// 验证用户是否含有指定角色,只需包含其中一个
hasRoleOr(roles: string[]) {
return roles.some(item => {
return authRole(item)
})
},
// 验证用户是否含有指定角色,必须全部拥有
hasRoleAnd(roles: string[]) {
return roles.every(item => {
return authRole(item)
})
}
}
const sessionCache = {
set (key: string, value: string) {
if (!sessionStorage) {
return
}
if (key != null && value != null) {
sessionStorage.setItem(key, value)
}
},
get (key: string) {
if (!sessionStorage) {
return null
}
if (key == null) {
return null
}
return sessionStorage.getItem(key)
},
setJSON (key: string, jsonValue: any) {
if (jsonValue != null) {
this.set(key, JSON.stringify(jsonValue))
}
},
getJSON (key: string) {
const value = this.get(key)
if (value != null) {
return JSON.parse(value)
}
},
remove (key: string) {
sessionStorage.removeItem(key);
}
}
const localCache = {
set (key: string, value: string) {
if (!localStorage) {
return
}
if (key != null && value != null) {
localStorage.setItem(key, value)
}
},
get (key: string) {
if (!localStorage) {
return null
}
if (key == null) {
return null
}
return localStorage.getItem(key)
},
setJSON (key: string, jsonValue: any) {
if (jsonValue != null) {
this.set(key, JSON.stringify(jsonValue))
}
},
getJSON (key: string) {
const value = this.get(key)
if (value != null) {
return JSON.parse(value)
}
},
remove (key: string) {
localStorage.removeItem(key);
}
}
export default {
/**
* 会话级缓存
*/
session: sessionCache,
/**
* 本地缓存
*/
local: localCache
}
import type { App } from 'vue'
import auth from './auth'
import cache from './cache'
export default function installPlugins(app: App){
// 认证对象
app.config.globalProperties.$auth = auth
// 缓存对象
app.config.globalProperties.$cache = cache
}
......@@ -2,14 +2,31 @@ import { createRouter, createWebHistory } from "vue-router";
// 引入页面组件
const Home = () => import("@/views/Home.vue");
const About = () => import("@/views/About.vue");
const Redirect = () => import("@/views/redirect/index.vue");
const Main = () => import("@/layout/main.vue");
const VideoList = () => import("@/views/VideoList.vue");
const Login = () => import("@/views/login.vue");
const AlarmList = () => import("@/views/AlarmList.vue");
// 定义路由配置
const routes = [
{
path: "/redirect",
component: Main,
hidden: true,
children: [
{
path: "/redirect/:path(.*)",
component: Redirect,
},
],
},
{
path: "/login",
component: Login,
hidden: true,
},
{
path: "/",
name: "Main",
component: Main,
......
import { createPinia } from 'pinia'
const store = createPinia()
export default store
\ No newline at end of file
import { defineStore } from 'pinia'
const useDictStore = defineStore(
'dict',
{
state: () => ({
dict: new Array()
}),
actions: {
// 获取字典
getDict(_key: string) {
if (_key == null && _key == "") {
return null;
}
try {
for (let i = 0; i < this.dict.length; i++) {
if (this.dict[i].key == _key) {
return this.dict[i].value;
}
}
} catch (e) {
return null;
}
},
// 设置字典
setDict(_key: string, value: any) {
if (_key !== null && _key !== "") {
this.dict.push({
key: _key,
value: value
});
}
},
// 删除字典
removeDict(_key: string) {
var bln = false;
try {
for (let i = 0; i < this.dict.length; i++) {
if (this.dict[i].key == _key) {
this.dict.splice(i, 1);
return true;
}
}
} catch (e) {
bln = false;
}
return bln;
},
// 清空字典
cleanDict() {
this.dict = new Array();
},
// 初始字典
initDict() {
}
}
})
export default useDictStore
import { login, logout, getInfo } from '@/api/login'
import { getToken, setToken, removeToken } from '@/utils/auth'
import { defineStore } from 'pinia'
const useUserStore = defineStore(
'user',
{
state: (): any => ({
token: getToken(),
id: '',
name: '',
avatar: '',
roles: [],
permissions: []
}),
actions: {
// 登录
login(userInfo: any) {
const username = userInfo.username.trim()
const password = userInfo.password
const code = userInfo.code
const uuid = userInfo.uuid
return new Promise((resolve, reject) => {
login(username, password, code, uuid).then((res: any) => {
setToken(res.token)
this.token = res.token
resolve(res)
}).catch(error => {
reject(error)
})
})
},
// 获取用户信息
getInfo() {
return new Promise((resolve, reject) => {
getInfo().then((res: any) => {
const user = res.user
const avatar = import.meta.env.VITE_APP_BASE_API + user.avatar;
if (res.roles && res.roles.length > 0) { // 验证返回的roles是否是一个非空数组
this.roles = res.roles
this.permissions = res.permissions
} else {
this.roles = ['ROLE_DEFAULT']
}
this.id = user.userId
this.name = user.userName
this.avatar = avatar
resolve(res)
}).catch(error => {
reject(error)
})
})
},
// 退出系统
logOut() {
return new Promise((resolve, reject)=> {
logout().then(() => {
this.token = ''
this.roles = []
this.permissions = []
removeToken()
resolve(true)
}).catch(error => {
reject(error)
})
})
}
}
})
export default useUserStore
import Cookies from 'js-cookie'
const TokenKey = 'Admin-Token'
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token: string) {
return Cookies.set(TokenKey, token)
}
export function removeToken() {
return Cookies.remove(TokenKey)
}
export default {
'401': '认证失败,无法访问系统资源',
'403': '当前操作没有权限',
'404': '访问资源不存在',
'default': '系统未知错误,请反馈给管理员'
}
import JSEncrypt from 'jsencrypt'
// 密钥对生成 http://web.chacuo.net/netrsakeypair
const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdH\n' +
'nzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
const privateKey = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY\n' +
'7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKN\n' +
'PuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gA\n' +
'kM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWow\n' +
'cSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99Ecv\n' +
'DQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthh\n' +
'YhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3\n' +
'UP8iWi1Qw0Y='
// 加密
export function encrypt(txt: string) {
const encryptor = new JSEncrypt()
encryptor.setPublicKey(publicKey) // 设置公钥
return encryptor.encrypt(txt) // 对数据进行加密
}
// 解密
export function decrypt(txt: string) {
const encryptor = new JSEncrypt()
encryptor.setPrivateKey(privateKey) // 设置私钥
return encryptor.decrypt(txt) // 对数据进行解密
}
import axios from 'axios'
import { ElNotification , ElMessageBox, ElMessage, ElLoading } from 'element-plus'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { tansParams, blobValidate } from '@/utils/ruoyi'
import cache from '@/plugins/cache'
import useUserStore from '@/store/modules/user'
let downloadLoadingInstance;
// 是否显示重新登录
export let isRelogin = { show: false };
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
// 创建axios实例
const service = axios.create({
// axios中请求配置有baseURL选项,表示请求URL公共部分
baseURL: import.meta.env.VITE_APP_BASE_API,
// 超时
timeout: 100000
})
// request拦截器
service.interceptors.request.use(config => {
// 是否需要设置 token
const isToken = (config.headers || {}).isToken === false
// 是否需要防止数据重复提交
const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
if (getToken() && !isToken) {
config.headers['Authorization'] = 'Bearer ' + getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
}
// get请求映射params参数
if (config.method === 'get' && config.params) {
let url = config.url + '?' + tansParams(config.params);
url = url.slice(0, -1);
config.params = {};
config.url = url;
}
if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
const requestObj = {
url: config.url,
data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
time: new Date().getTime()
}
const requestSize = Object.keys(JSON.stringify(requestObj)).length; // 请求数据大小
const limitSize = 5 * 1024 * 1024; // 限制存放数据5M
if (requestSize >= limitSize) {
console.warn(`[${config.url}]: ` + '请求数据大小超出允许的5M限制,无法进行防重复提交验证。')
return config;
}
const sessionObj = cache.session.getJSON('sessionObj')
if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
cache.session.setJSON('sessionObj', requestObj)
} else {
const s_url = sessionObj.url; // 请求地址
const s_data = sessionObj.data; // 请求数据
const s_time = sessionObj.time; // 请求时间
const interval = 1000; // 间隔时间(ms),小于此时间视为重复提交
if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
const message = '数据正在处理,请勿重复提交';
console.warn(`[${s_url}]: ` + message)
return Promise.reject(new Error(message))
} else {
cache.session.setJSON('sessionObj', requestObj)
}
}
}
return config
}, error => {
console.log(error)
Promise.reject(error)
})
// 响应拦截器
service.interceptors.response.use(res => {
// 未设置状态码则默认成功状态
const code = res.data.code || 200;
// 获取错误信息
const msg = (code in errorCode ? errorCode[code as keyof typeof errorCode] : undefined) || res.data.msg || errorCode['default']
// 二进制数据则直接返回
if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') {
return res.data
}
if (code === 401) {
if (!isRelogin.show) {
isRelogin.show = true;
ElMessageBox.confirm('登录状态已过期,您可以继续留在该页面,或者重新登录', '系统提示', { confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning' }).then(() => {
isRelogin.show = false;
useUserStore().logOut().then(() => {
location.href = '/index';
})
}).catch(() => {
isRelogin.show = false;
});
}
return Promise.reject('无效的会话,或者会话已过期,请重新登录。')
} else if (code === 500) {
ElMessage({ message: msg, type: 'error' })
return Promise.reject(new Error(msg))
} else if (code === 601) {
ElMessage({ message: msg, type: 'warning' })
return Promise.reject(new Error(msg))
} else if (code !== 200) {
ElNotification.error({ title: msg })
return Promise.reject('error')
} else {
return Promise.resolve(res.data)
}
},
error => {
console.log('err' + error)
let { message } = error;
if (message == "Network Error") {
message = "后端接口连接异常";
} else if (message.includes("timeout")) {
message = "系统接口请求超时";
} else if (message.includes("Request failed with status code")) {
message = "系统接口" + message.substr(message.length - 3) + "异常";
}
ElMessage({ message: message, type: 'error', duration: 5 * 1000 })
return Promise.reject(error)
}
)
export default service
/**
* 通用js方法封装处理
* Copyright (c) 2019 ruoyi
*/
// 回显数据字典
export function selectDictLabel(datas: any[], value: any) {
if (value === undefined) {
return "";
}
var actions: any[] = [];
Object.keys(datas).some((key) => {
if (datas[Number(key)].value == ('' + value)) {
actions.push(datas[Number(key)].label);
return true;
}
})
if (actions.length === 0) {
actions.push(value);
}
return actions.join('');
}
// 回显数据字典(字符串数组)
export function selectDictLabels(datas: any[], value: any, separator: string = ',') {
if (value === undefined || value.length ===0) {
return "";
}
if (Array.isArray(value)) {
value = value.join(",");
}
var actions: any[] = [];
var currentSeparator = undefined === separator ? "," : separator;
var temp = value.split(currentSeparator);
Object.keys(value.split(currentSeparator)).some((val) => {
var match = false;
Object.keys(datas).some((key) => {
if (datas[Number(key)].value == ('' + temp[Number(val)])) {
actions.push(datas[Number(key)].label + currentSeparator);
match = true;
}
})
if (!match) {
actions.push(temp[val] + currentSeparator);
}
})
return actions.join('').substring(0, actions.join('').length - 1);
}
// 字符串格式化(%s )
export function sprintf(str: string) {
var args = arguments, flag = true, i = 1;
str = str.replace(/%s/g, function () {
var arg = args[i++] as string;
if (typeof arg === 'undefined') {
flag = false;
return '';
}
return arg;
});
return flag ? str : '';
}
// 转换字符串,undefined,null等转化为""
export function parseStrEmpty(str: string) {
if (!str || str == "undefined" || str == "null") {
return "";
}
return str;
}
// 数据合并
export function mergeRecursive(source: any, target: any) {
for (var p in target) {
try {
if (target[p].constructor == Object) {
source[p] = mergeRecursive(source[p], target[p]);
} else {
source[p] = target[p];
}
} catch (e) {
source[p] = target[p];
}
}
return source;
};
/**
* 构造树型结构数据
* @param {*} data 数据源
* @param {*} id id字段 默认 'id'
* @param {*} parentId 父节点字段 默认 'parentId'
* @param {*} children 孩子节点字段 默认 'children'
*/
export function handleTree(data: any[], id: string = 'id', parentId: string = 'parentId', children: string = 'children') {
let config = {
id: id || 'id',
parentId: parentId || 'parentId',
childrenList: children || 'children'
};
var childrenListMap: any = {};
var nodeIds: any = {};
var tree = [];
for (let d of data) {
let parentId = d[config.parentId];
if (childrenListMap[parentId] == null) {
childrenListMap[parentId] = [];
}
nodeIds[d[config.id]] = d;
childrenListMap[parentId].push(d);
}
for (let d of data) {
let parentId = d[config.parentId];
if (nodeIds[parentId] == null) {
tree.push(d);
}
}
for (let t of tree) {
adaptToChildrenList(t);
}
function adaptToChildrenList(o: any) {
if (childrenListMap[o[config.id]] !== null) {
o[config.childrenList] = childrenListMap[o[config.id]];
}
if (o[config.childrenList]) {
for (let c of o[config.childrenList]) {
adaptToChildrenList(c);
}
}
}
return tree;
}
/**
* 参数处理
* @param {*} params 参数
*/
export function tansParams(params: any) {
let result = ''
for (const propName of Object.keys(params)) {
const value = params[propName];
var part = encodeURIComponent(propName) + "=";
if (value !== null && value !== "" && typeof (value) !== "undefined") {
if (typeof value === 'object') {
for (const key of Object.keys(value)) {
if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
let params = propName + '[' + key + ']';
var subPart = encodeURIComponent(params) + "=";
result += subPart + encodeURIComponent(value[key]) + "&";
}
}
} else {
result += part + encodeURIComponent(value) + "&";
}
}
}
return result
}
// 返回项目路径
export function getNormalPath(path: string) {
if (path.length === 0 || !path || path == 'undefined') {
return path
};
let res = path.replace('//', '/')
if (res[res.length - 1] === '/') {
return res.slice(0, res.length - 1)
}
return res;
}
// 验证是否为blob格式
export function blobValidate(data: any) {
return data.type !== 'application/json'
}
/**
* 路径匹配器
* @param {string} pattern
* @param {string} path
* @returns {Boolean}
*/
export function isPathMatch(pattern, path) {
const regexPattern = pattern
.replace(/\//g, "\\/")
.replace(/\*\*/g, ".*")
.replace(/\*/g, "[^\\/]*");
const regex = new RegExp(`^${regexPattern}$`);
return regex.test(path);
}
/**
* 判断value字符串是否为空
* @param {string} value
* @returns {Boolean}
*/
export function isEmpty(value) {
if (
value == null ||
value == "" ||
value == undefined ||
value == "undefined"
) {
return true;
}
return false;
}
/**
* 判断url是否是http或https
* @param {string} url
* @returns {Boolean}
*/
export function isHttp(url) {
return url.indexOf("http://") !== -1 || url.indexOf("https://") !== -1;
}
/**
* 判断path是否为外链
* @param {string} path
* @returns {Boolean}
*/
export function isExternal(path) {
return /^(https?:|mailto:|tel:)/.test(path);
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validUsername(str) {
const valid_map = ["admin", "editor"];
return valid_map.indexOf(str.trim()) >= 0;
}
/**
* @param {string} url
* @returns {Boolean}
*/
export function validURL(url) {
const reg =
/^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/;
return reg.test(url);
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validLowerCase(str) {
const reg = /^[a-z]+$/;
return reg.test(str);
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validUpperCase(str) {
const reg = /^[A-Z]+$/;
return reg.test(str);
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function validAlphabets(str) {
const reg = /^[A-Za-z]+$/;
return reg.test(str);
}
/**
* @param {string} email
* @returns {Boolean}
*/
export function validEmail(email) {
const reg =
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return reg.test(email);
}
/**
* @param {string} str
* @returns {Boolean}
*/
export function isString(str) {
return typeof str === "string" || str instanceof String;
}
/**
* @param {Array} arg
* @returns {Boolean}
*/
export function isArray(arg) {
if (typeof Array.isArray === "undefined") {
return Object.prototype.toString.call(arg) === "[object Array]";
}
return Array.isArray(arg);
}
<template>
<div class="login flex-col pb-10">
<h3 class="text-5xl font-bold text-center mb-15">
{{ AppSetting.projectName }}
</h3>
<el-form
ref="loginRef"
:model="loginForm"
:rules="loginRules"
class="login-form"
>
<h3 class="title">欢迎登录智慧物联网平台</h3>
<el-form-item prop="username">
<el-input
v-model="loginForm.username"
type="text"
size="large"
auto-complete="off"
placeholder="请输入账号"
>
<template #prefix>
<el-icon color="#fff"><Avatar /></el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
size="large"
auto-complete="off"
placeholder="请输入密码"
@keyup.enter="handleLogin"
>
<template #prefix
><el-icon color="#fff"><Lock /></el-icon
></template>
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input
v-model="loginForm.code"
size="large"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter="handleLogin"
>
<template #prefix
><el-icon color="#fff"><Opportunity /></el-icon
></template>
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img" />
</div>
</el-form-item>
<el-checkbox
v-model="loginForm.rememberMe"
style="margin: 0px 0px 10px 0px"
>记住密码</el-checkbox
>
<el-form-item style="width: 100%" class="pb-8">
<el-button
:loading="loading"
size="large"
type="primary"
style="width: 100%; height: 35px; border: 0px solid #4491fc"
color="#2261BA"
@click.prevent="handleLogin"
>
<span v-if="!loading">登 录</span>
<span v-else>登 录 中...</span>
</el-button>
<div style="float: right" v-if="register">
<router-link class="link-type" :to="'/register'"
>立即注册</router-link
>
</div>
</el-form-item>
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2018-2024 ruoyi.vip All Rights Reserved.</span>
</div>
</div>
</template>
<script setup>
import { getCodeImg } from "@/api/login";
import Cookies from "js-cookie";
import { encrypt, decrypt } from "@/utils/jsencrypt";
import useUserStore from "@/store/modules/user";
import { AppSetting } from "@/setting";
const userStore = useUserStore();
const route = useRoute();
const router = useRouter();
const { proxy } = getCurrentInstance();
const loginForm = ref({
username: "admin",
password: "admin123",
rememberMe: false,
code: "",
uuid: "",
});
const loginRules = {
username: [{ required: true, trigger: "blur", message: "请输入您的账号" }],
password: [{ required: true, trigger: "blur", message: "请输入您的密码" }],
code: [{ required: true, trigger: "change", message: "请输入验证码" }],
};
const codeUrl = ref("");
const loading = ref(false);
// 验证码开关
const captchaEnabled = ref(true);
// 注册开关
const register = ref(false);
const redirect = ref(undefined);
watch(
route,
(newRoute) => {
redirect.value = newRoute.query && newRoute.query.redirect;
},
{ immediate: true }
);
function handleLogin() {
proxy.$refs.loginRef.validate((valid) => {
if (valid) {
loading.value = true;
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
if (loginForm.value.rememberMe) {
Cookies.set("username", loginForm.value.username, { expires: 30 });
Cookies.set("password", encrypt(loginForm.value.password), {
expires: 30,
});
Cookies.set("rememberMe", loginForm.value.rememberMe, { expires: 30 });
} else {
// 否则移除
Cookies.remove("username");
Cookies.remove("password");
Cookies.remove("rememberMe");
}
// 调用action的登录方法
userStore
.login(loginForm.value)
.then(() => {
const query = route.query;
const otherQueryParams = Object.keys(query).reduce((acc, cur) => {
if (cur !== "redirect") {
acc[cur] = query[cur];
}
return acc;
}, {});
router.push({ path: redirect.value || "/", query: otherQueryParams });
})
.catch(() => {
loading.value = false;
// 重新获取验证码
if (captchaEnabled.value) {
getCode();
}
});
}
});
}
function getCode() {
getCodeImg().then((res) => {
captchaEnabled.value =
res.captchaEnabled === undefined ? true : res.captchaEnabled;
if (captchaEnabled.value) {
codeUrl.value = "data:image/gif;base64," + res.img;
loginForm.value.uuid = res.uuid;
}
});
}
function getCookie() {
const username = Cookies.get("username");
const password = Cookies.get("password");
const rememberMe = Cookies.get("rememberMe");
loginForm.value = {
username: username === undefined ? loginForm.value.username : username,
password:
password === undefined ? loginForm.value.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe),
};
}
getCode();
getCookie();
</script>
<style lang="scss" scoped>
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("@/assets/images/login-background.jpg");
background-size: 100% 100%;
}
.title {
margin: 30px auto 10px auto;
text-align: center;
font-weight: 500;
color: #fff;
}
.login-form {
border-radius: 6px;
// background: #ffffff;
background-image: url("@/assets/images/login-center-bg.png");
background-size: 100% 100%;
width: 700px;
padding: 20px 180px 5px 180px;
.el-input {
height: 35px;
input {
height: 35px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 0px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 40px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 40px;
padding-left: 12px;
}
// :deep(.el-form-item) {
// display: flex;
// // --font-size: 14px;
// margin-bottom: 13px;
// }
:deep(.el-input .el-input__inner) {
color: #fff;
// background: yellow !important;
// border: 0px solid rgba(255, 255, 255, 0.3);
}
:deep(.el-input--large .el-input__wrapper) {
// padding: 1px 15px;
background-color: #163054;
// box-shadow: 0 0 0 1px #2261ba inset !important; /* 可选:修改边框颜色 */
box-shadow: 0px 2px 4px rgba(79, 151, 214, 0.33);
// border: 0px solid rgba(255, 255, 255, 0.3);
}
:deep(.el-input__inner) {
// background-color: rgba(22, 48, 84, 0.6);
}
</style>
<template>
<div class="login flex-col pb-10">
<h3 class="text-5xl font-bold text-center mb-10">
{{ AppSetting.projectName }}
</h3>
<el-form
ref="loginRef"
:model="loginForm"
:rules="loginRules"
class="login-form"
>
<h3 class="title">用户登录</h3>
<el-form-item prop="username">
<el-input
v-model="loginForm.username"
type="text"
size="large"
auto-complete="off"
placeholder="请输入账号"
>
<template #prefix>
<el-icon color="#fff"><Avatar /></el-icon>
</template>
</el-input>
</el-form-item>
<el-form-item prop="password">
<el-input
v-model="loginForm.password"
type="password"
size="large"
auto-complete="off"
placeholder="请输入密码"
@keyup.enter="handleLogin"
>
<template #prefix
><el-icon color="#fff"><Lock /></el-icon
></template>
</el-input>
</el-form-item>
<el-form-item prop="code" v-if="captchaEnabled">
<el-input
v-model="loginForm.code"
size="large"
auto-complete="off"
placeholder="验证码"
style="width: 63%"
@keyup.enter="handleLogin"
>
<template #prefix
><el-icon color="#fff"><Opportunity /></el-icon
></template>
</el-input>
<div class="login-code">
<img :src="codeUrl" @click="getCode" class="login-code-img" />
</div>
</el-form-item>
<el-checkbox
v-model="loginForm.rememberMe"
style="margin: 0px 0px 10px 0px"
>记住密码</el-checkbox
>
<el-form-item style="width: 100%" class="pb-18">
<el-button
:loading="loading"
size="large"
type="primary"
style="width: 100%; height: 35px; border: 0px solid #4491fc"
color="#2261BA"
@click.prevent="handleLogin"
>
<span v-if="!loading">登 录</span>
<span v-else>登 录 中...</span>
</el-button>
<div style="float: right" v-if="register">
<router-link class="link-type" :to="'/register'"
>立即注册</router-link
>
</div>
</el-form-item>
</el-form>
<!-- 底部 -->
<div class="el-login-footer">
<span>Copyright © 2018-2024 ruoyi.vip All Rights Reserved.</span>
</div>
</div>
</template>
<script setup>
import { getCodeImg } from "@/api/login";
import Cookies from "js-cookie";
import { encrypt, decrypt } from "@/utils/jsencrypt";
import useUserStore from "@/store/modules/user";
import { AppSetting } from "@/setting";
const userStore = useUserStore();
const route = useRoute();
const router = useRouter();
const { proxy } = getCurrentInstance();
const loginForm = ref({
username: "admin",
password: "admin123",
rememberMe: false,
code: "",
uuid: "",
});
const loginRules = {
username: [{ required: true, trigger: "blur", message: "请输入您的账号" }],
password: [{ required: true, trigger: "blur", message: "请输入您的密码" }],
code: [{ required: true, trigger: "change", message: "请输入验证码" }],
};
const codeUrl = ref("");
const loading = ref(false);
// 验证码开关
const captchaEnabled = ref(true);
// 注册开关
const register = ref(false);
const redirect = ref(undefined);
watch(
route,
(newRoute) => {
redirect.value = newRoute.query && newRoute.query.redirect;
},
{ immediate: true }
);
function handleLogin() {
proxy.$refs.loginRef.validate((valid) => {
if (valid) {
loading.value = true;
// 勾选了需要记住密码设置在 cookie 中设置记住用户名和密码
if (loginForm.value.rememberMe) {
Cookies.set("username", loginForm.value.username, { expires: 30 });
Cookies.set("password", encrypt(loginForm.value.password), {
expires: 30,
});
Cookies.set("rememberMe", loginForm.value.rememberMe, { expires: 30 });
} else {
// 否则移除
Cookies.remove("username");
Cookies.remove("password");
Cookies.remove("rememberMe");
}
// 调用action的登录方法
userStore
.login(loginForm.value)
.then(() => {
const query = route.query;
const otherQueryParams = Object.keys(query).reduce((acc, cur) => {
if (cur !== "redirect") {
acc[cur] = query[cur];
}
return acc;
}, {});
router.push({ path: redirect.value || "/", query: otherQueryParams });
})
.catch(() => {
loading.value = false;
// 重新获取验证码
if (captchaEnabled.value) {
getCode();
}
});
}
});
}
function getCode() {
getCodeImg().then((res) => {
captchaEnabled.value =
res.captchaEnabled === undefined ? true : res.captchaEnabled;
if (captchaEnabled.value) {
codeUrl.value = "data:image/gif;base64," + res.img;
loginForm.value.uuid = res.uuid;
}
});
}
function getCookie() {
const username = Cookies.get("username");
const password = Cookies.get("password");
const rememberMe = Cookies.get("rememberMe");
loginForm.value = {
username: username === undefined ? loginForm.value.username : username,
password:
password === undefined ? loginForm.value.password : decrypt(password),
rememberMe: rememberMe === undefined ? false : Boolean(rememberMe),
};
}
getCode();
getCookie();
</script>
<style lang="scss" scoped>
.login {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
background-image: url("@/assets/images/login-background.jpg");
background-size: 100% 100%;
}
.title {
margin: 60px auto 10px auto;
text-align: center;
font-weight: 500;
color: #fff;
}
.login-form {
border-radius: 6px;
// background: #ffffff;
background-image: url("@/assets/images/login-center-bg1.png");
background-size: 100% 100%;
width: 700px;
padding: 20px 220px 5px 220px;
.el-input {
height: 35px;
input {
height: 35px;
}
}
.input-icon {
height: 39px;
width: 14px;
margin-left: 0px;
}
}
.login-tip {
font-size: 13px;
text-align: center;
color: #bfbfbf;
}
.login-code {
width: 33%;
height: 40px;
float: right;
img {
cursor: pointer;
vertical-align: middle;
}
}
.el-login-footer {
height: 40px;
line-height: 40px;
position: fixed;
bottom: 0;
width: 100%;
text-align: center;
color: #fff;
font-family: Arial;
font-size: 12px;
letter-spacing: 1px;
}
.login-code-img {
height: 40px;
padding-left: 12px;
}
:deep(.el-form-item) {
display: flex;
// --font-size: 14px;
margin-bottom: 13px;
}
:deep(.el-input .el-input__inner) {
color: #fff;
// background: yellow !important;
// border: 0px solid rgba(255, 255, 255, 0.3);
}
:deep(.el-input--large .el-input__wrapper) {
// padding: 1px 15px;
background-color: #163054;
// box-shadow: 0 0 0 0px #2261ba inset !important; /* 可选:修改边框颜色 */
box-shadow: 0px 2px 4px rgba(79, 151, 214, 0.33);
// border: 0px solid rgba(255, 255, 255, 0.3);
}
:deep(.el-input__inner) {
// background-color: rgba(22, 48, 84, 0.6);
}
</style>
<template>
<div></div>
</template>
<script setup>
import { useRoute, useRouter } from 'vue-router'
const route = useRoute();
const router = useRouter();
const { params, query } = route
const { path } = params
router.replace({ path: '/' + path, query })
</script>
\ No newline at end of file
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "path";
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue(),
// 添加 AutoImport 配置
AutoImport({
imports: [
"vue",
"vue-router",
// 可以添加其他需要自动导入的库
],
resolvers: [ElementPlusResolver()],
dts: "auto-imports.d.ts",
eslintrc: {
enabled: true,
},
}),
// 添加 Components 配置
Components({
resolvers: [
ElementPlusResolver({
// 使用自定义主题
importStyle: "sass",
}),
],
dts: "components.d.ts",
}),
],
css: {
preprocessorOptions: {
scss: {
additionalData: `@use "@/assets/styles/_variables.scss" as *;`
}
}
additionalData: `@use "@/assets/styles/_variables.scss" as *;`,
},
},
},
resolve: {
alias: {
'@': path.resolve(__dirname, './src'), // @指向src目录
'@components': path.resolve(__dirname, './src/components'),
'@api': path.resolve(__dirname, './src/api') // 接口请求目录
}
"@": path.resolve(__dirname, "./src"), // @指向src目录
"@components": path.resolve(__dirname, "./src/components"),
"@api": path.resolve(__dirname, "./src/api"), // 接口请求目录
},
},
server: {
open: true,
host: '0.0.0.0',
host: "0.0.0.0",
port: 8080,
proxy: {
'/api': {
target: 'http://localhost:3000',
"/api": {
target: "http://192.168.19.166:8081",
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
}
}
}
})
rewrite: (path) => path.replace(/^\/api/, ""),
},
},
},
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment