| | |
| | | VITE_ROUTE_LOAD_MODE = static |
| | | |
| | | # 设置登陆后跳转地址 |
| | | VITE_HOME_PATH = / |
| | | VITE_HOME_PATH = /dashboard |
| | | |
| | | # 本地存储前缀 |
| | | VITE_STORAGE_PREFIX = |
| | |
| | | // 如果是login路由,直接放行 |
| | | if (to.name === 'login') { |
| | | // login页面不需要任何认证检查,直接放行 |
| | | // 继续执行后面的逻辑 |
| | | // 如果已登录,则重定向到首页 |
| | | if (isLogin) { |
| | | next({ path: '/dashboard' }) |
| | | return |
| | | } |
| | | next() |
| | | return |
| | | } |
| | | // 如果路由明确设置了requiresAuth为false,直接放行 |
| | | else if (to.meta.requiresAuth === false) { |
| | | // 明确设置为false的路由直接放行 |
| | | // 继续执行后面的逻辑 |
| | | next() |
| | | return |
| | | } |
| | | // 如果路由设置了requiresAuth为true,且用户未登录,重定向到登录页 |
| | | else if (to.meta.requiresAuth === true && !isLogin) { |
| | | else if (to.meta.requiresAuth !== false && !isLogin) { |
| | | const redirect = to.name === 'not-found' ? undefined : to.fullPath |
| | | next({ path: '/login', query: { redirect } }) |
| | | next({ path: '/login', query: redirect ? { redirect } : undefined }) |
| | | return |
| | | } |
| | | |
| | |
| | | }) |
| | | return |
| | | } |
| | | // 如果不是404页面,继续导航 |
| | | next() |
| | | // 如果不是404页面,继续导航,并设置 replace: true 以确保路由正确替换 |
| | | next({ ...to, replace: true }) |
| | | return |
| | | } |
| | | catch { |
| | |
| | | } |
| | | |
| | | // 如果用户已登录且访问login页面,重定向到首页 |
| | | if (to.name === 'login' && isLogin) { |
| | | next({ path: '/' }) |
| | | return |
| | | } |
| | | |
| | | // 此逻辑已移至上方处理 |
| | | |
| | | next() |
| | | }) |
| | | router.beforeResolve((to) => { |
| | | // 设置菜单高亮 |
| | | routeStore.setActiveMenu(to.meta.activeMenu ?? to.fullPath) |
| | | // 设置菜单高亮,优先将 activeMenu 的路径转换为对应的菜单 key(路由 name) |
| | | let activeKey: string |
| | | if (to.meta.activeMenu) { |
| | | const target = routeStore.rowRoutes.find(r => r.path === to.meta.activeMenu) |
| | | activeKey = (target?.name as string) || (to.meta.activeMenu as string) |
| | | } |
| | | else if (to.name) { |
| | | activeKey = to.name as string |
| | | } |
| | | else { |
| | | activeKey = to.fullPath |
| | | } |
| | | routeStore.setActiveMenu(activeKey) |
| | | // 添加tabs |
| | | tabStore.addTab(to) |
| | | // 设置高亮标签; |
| | |
| | | id: 2021, |
| | | pid: 202, |
| | | }, |
| | | { |
| | | name: 'appVersionManage', |
| | | path: '/system/appVersion/appVersionManage', |
| | | title: 'APP版本管理', |
| | | requiresAuth: true, |
| | | icon: 'icon-park-outline:tool', |
| | | menuType: 'page', |
| | | componentPath: '/system/appVersion/appVersionManage/index.vue', |
| | | id: 2021, |
| | | pid: 202, |
| | | }, |
| | | { |
| | | name: 'systemConfig', |
| | | path: '/system/config', |
| | |
| | | id: 3022, |
| | | pid: 302, |
| | | }, |
| | | // 新增页面--活动 |
| | | { |
| | | name: 'businessOperations', |
| | | path: '/businessOperations', |
| | |
| | | menuType: 'page', |
| | | componentPath: '/businessOperations/cruise/parade-plan/add.vue', |
| | | id: 4073, |
| | | pid: 407, |
| | | pid: 4072, |
| | | hide: true, // 不在菜单中显示 |
| | | activeMenu: '/businessOperations/cruise/parade-plan', |
| | | }, |
| | |
| | | menuType: 'page', |
| | | componentPath: '/businessOperations/cruise/parade-plan/detail.vue', |
| | | id: 4074, |
| | | pid: 407, |
| | | pid: 4072, |
| | | hide: true, // 不在菜单中显示 |
| | | activeMenu: '/businessOperations/cruise/parade-plan', |
| | | }, |
| | |
| | | hide: true, // 不在菜单中显示 |
| | | activeMenu: '/assetManagement/fleetManagement', |
| | | }, |
| | | // 新增页面--运维规则配置 |
| | | { |
| | | name: 'ruleConfig', |
| | | path: '/assetManagement/ruleConfig', |
| | | title: '运维规则配置', |
| | | requiresAuth: true, |
| | | icon: 'icon-park-outline:list-view', |
| | | menuType: 'page', |
| | | componentPath: '/assetManagement/ruleConfig/index.vue', |
| | | id: 503, |
| | | pid: 5, |
| | | }, |
| | | { |
| | | name: 'transaction', |
| | | path: '/transaction', |
| | |
| | | icon: 'icon-park-outline:vip-1', |
| | | menuType: 'page', |
| | | componentPath: '/transaction/pricingManagement/detail.vue', |
| | | id: 603, |
| | | pid: 6, |
| | | id: 6021, |
| | | pid: 602, |
| | | hide: true, // 不在菜单中显示 |
| | | activeMenu: '/transaction/pricingManagement', |
| | | }, |
| | |
| | | icon: 'icon-park-outline:vip-1', |
| | | menuType: 'page', |
| | | componentPath: '/transaction/pricingManagement/detail.vue', |
| | | id: 604, |
| | | pid: 6, |
| | | id: 6024, |
| | | pid: 602, |
| | | hide: true, // 不在菜单中显示 |
| | | activeMenu: '/transaction/pricingManagement', |
| | | }, |
| | |
| | | icon: 'icon-park-outline:vip-1', |
| | | menuType: 'page', |
| | | componentPath: '/transaction/pricingManagement/rules.vue', |
| | | id: 605, |
| | | pid: 6, |
| | | id: 6022, |
| | | pid: 602, |
| | | hide: true, // 不在菜单中显示 |
| | | activeMenu: '/transaction/pricingManagement', |
| | | }, |
| | |
| | | icon: 'icon-park-outline:alarm', |
| | | menuType: 'page', |
| | | componentPath: '/transaction/transactionStrategy/index.vue', |
| | | id: 606, |
| | | id: 605, |
| | | pid: 6, |
| | | }, |
| | | { |
| | |
| | | icon: 'icon-park-outline:alarm', |
| | | menuType: 'page', |
| | | componentPath: '/transaction/navigationAndRoutePlanning/index.vue', |
| | | id: 607, |
| | | id: 606, |
| | | pid: 6, |
| | | }, |
| | | { |
| | |
| | | icon: 'icon-park-outline:list-view', |
| | | menuType: 'page', |
| | | componentPath: '/operations/personnel/personnelManagement/detail.vue', |
| | | id: 7012, |
| | | pid: 701, |
| | | id: 70111, |
| | | pid: 7011, |
| | | hide: true, |
| | | activeMenu: '/operations/personnel/personnelManagement', |
| | | }, |
| | |
| | | icon: 'icon-park-outline:list-view', |
| | | menuType: 'page', |
| | | componentPath: '/operations/attendance/statistics/detail.vue', |
| | | id: 7023, |
| | | pid: 702, |
| | | id: 70222, |
| | | pid: 7022, |
| | | hide: true, |
| | | activeMenu: '/operations/attendance/statistics', |
| | | }, |
| | |
| | | icon: 'icon-park-outline:list-view', |
| | | menuType: 'page', |
| | | componentPath: '/operations/attendance/plan/edit.vue', |
| | | id: 7026, |
| | | pid: 702, |
| | | id: 70251, |
| | | pid: 7025, |
| | | hide: true, |
| | | activeMenu: '/operations/attendance/plan', |
| | | },{ |
| | |
| | | icon: 'icon-park-outline:list-view', |
| | | menuType: 'page', |
| | | componentPath: '/operations/attendance/plan/copy.vue', |
| | | id: 7027, |
| | | pid: 702, |
| | | id: 70252, |
| | | pid: 7025, |
| | | hide: true, |
| | | activeMenu: '/operations/attendance/plan', |
| | | }, |
| | |
| | | id: 704, |
| | | pid: 7, |
| | | }, |
| | | // 新增页面--任务工单 |
| | | { |
| | | name: 'service', |
| | | path: '/service', |
| New file |
| | |
| | | <script setup lang="ts"> |
| | | import { ref } from 'vue' |
| | | import type { FormInst, FormRules } from 'naive-ui' |
| | | |
| | | interface FormModel { |
| | | maintenanceStatus: boolean |
| | | startTime: number | null |
| | | endTime: number | null |
| | | } |
| | | |
| | | const formRef = ref<FormInst | null>(null) |
| | | |
| | | const formModel = ref<FormModel>({ |
| | | maintenanceStatus: true, |
| | | startTime: null, |
| | | endTime: null |
| | | }) |
| | | |
| | | const rules: FormRules = { |
| | | startTime: [ |
| | | { required: true, type: 'number', message: '请选择开始维护时间', trigger: 'change' } |
| | | ], |
| | | endTime: [ |
| | | { required: true, type: 'number', message: '请选择预计结束时间', trigger: 'change' } |
| | | ] |
| | | } |
| | | |
| | | const handleSave = async () => { |
| | | try { |
| | | await formRef.value?.validate() |
| | | console.log('保存配置', formModel.value) |
| | | window.$message?.success('保存成功') |
| | | } catch (error) { |
| | | console.log('验证失败', error) |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <div class="h-full flex flex-col"> |
| | | <n-card content-style="padding: 12px"> |
| | | <n-form |
| | | ref="formRef" |
| | | :model="formModel" |
| | | :rules="rules" |
| | | label-placement="left" |
| | | inline |
| | | :show-feedback="false" |
| | | require-mark-placement="left" |
| | | > |
| | | <n-space vertical :size="16"> |
| | | <n-form-item label="维护状态" required> |
| | | <n-switch v-model:value="formModel.maintenanceStatus" /> |
| | | </n-form-item> |
| | | |
| | | <n-form-item label="开始维护时间" path="startTime" required> |
| | | <n-date-picker |
| | | v-model:value="formModel.startTime" |
| | | type="datetime" |
| | | placeholder="年/月/日 --:--" |
| | | style="width: 400px;" |
| | | clearable |
| | | /> |
| | | </n-form-item> |
| | | |
| | | <n-form-item label="预计结束时间" path="endTime" required> |
| | | <n-date-picker |
| | | v-model:value="formModel.endTime" |
| | | type="datetime" |
| | | placeholder="年/月/日 --:--" |
| | | style="width: 400px;" |
| | | clearable |
| | | /> |
| | | </n-form-item> |
| | | </n-space> |
| | | </n-form> |
| | | </n-card> |
| | | |
| | | <div class="absolute bottom-0 left-0 right-0 flex justify-end gap-3 bg-white px-6 py-4" style="box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1); z-index: 100"> |
| | | <n-button type="primary" style="width: 84px; height: 32px" @click="handleSave">保存</n-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <style scoped> |
| | | </style> |
| | |
| | | render: (row) => { |
| | | return ( |
| | | <NSpace justify="center"> |
| | | <NButton |
| | | {/* <NButton |
| | | text |
| | | type="primary" |
| | | onClick={() => handleView(row)} |
| | | > |
| | | 查看 |
| | | </NButton> |
| | | </NButton> */} |
| | | <NButton |
| | | text |
| | | type="primary" |
| | | v-permission="20112" |
| | | onClick={() => handleEdit(row)} |
| | | > |
| | | 编辑 |
| | |
| | | <NButton |
| | | text |
| | | type="warning" |
| | | v-permission="20113" |
| | | onClick={() => toggleAccountStatus(row.id!, '1')} |
| | | > |
| | | 禁用 |
| | |
| | | <NButton |
| | | text |
| | | type="success" |
| | | v-permission="20113" |
| | | onClick={() => toggleAccountStatus(row.id!, '0')} |
| | | > |
| | | 启用 |
| | |
| | | <NButton |
| | | text |
| | | type="primary" |
| | | v-permission="20114" |
| | | onClick={() => handleResetPassword(row)} |
| | | > |
| | | 重置密码 |
| | | </NButton> |
| | | <NButton text type="error" onClick={() => deleteAccount(row.id!)}>删除</NButton> |
| | | <NButton |
| | | text |
| | | type="error" |
| | | v-permission="20115" |
| | | onClick={() => deleteAccount(row.id!)} |
| | | > |
| | | 删除 |
| | | </NButton> |
| | | </NSpace> |
| | | ) |
| | | }, |
| | |
| | | |
| | | <n-card class="flex-1"> |
| | | <template #header> |
| | | <NButton type="primary" @click="handleAdd"> |
| | | <NButton type="primary" v-permission="20111" @click="handleAdd"> |
| | | 新增 |
| | | </NButton> |
| | | </template> |
| | |
| | | <NButton |
| | | text |
| | | type="primary" |
| | | v-permission="20132" |
| | | onClick={() => handleView(row)} |
| | | > |
| | | 详情 |
| | |
| | | <NButton |
| | | text |
| | | type="primary" |
| | | v-permission="20133" |
| | | onClick={() => handleEdit(row)} |
| | | > |
| | | 编辑 |
| | |
| | | <NButton |
| | | text |
| | | type="error" |
| | | v-permission="20134" |
| | | disabled={hasAccounts} |
| | | > |
| | | 删除 |
| | |
| | | |
| | | <n-card class="flex-1"> |
| | | <template #header> |
| | | <NButton type="primary" @click="handleAdd"> |
| | | <NButton type="primary" v-permission="20131" @click="handleAdd"> |
| | | 新增 |
| | | </NButton> |
| | | </template> |
| | |
| | | <NButton |
| | | text |
| | | type="primary" |
| | | v-permission="20152" |
| | | onClick={() => handleView(row)} |
| | | > |
| | | 详情 |
| | |
| | | <NButton |
| | | text |
| | | type="primary" |
| | | v-permission="20153" |
| | | onClick={() => handleEdit(row)} |
| | | > |
| | | 编辑 |
| | |
| | | <NButton |
| | | text |
| | | type="error" |
| | | v-permission="20154" |
| | | disabled={hasAccounts} |
| | | onClick={() => handleDelete(row.id!)} |
| | | > |
| | |
| | | |
| | | <n-card class="flex-1"> |
| | | <template #header> |
| | | <NButton type="primary" @click="handleAdd"> |
| | | <NButton type="primary" v-permission="20151" @click="handleAdd"> |
| | | 新增 |
| | | </NButton> |
| | | </template> |
| New file |
| | |
| | | <script setup lang="ts"> |
| | | import { ref } from 'vue' |
| | | import type { FormInst, FormRules } from 'naive-ui' |
| | | |
| | | interface FormModel { |
| | | maintenanceStatus: boolean |
| | | startTime: number | null |
| | | endTime: number | null |
| | | } |
| | | |
| | | const formRef = ref<FormInst | null>(null) |
| | | |
| | | const formModel = ref<FormModel>({ |
| | | maintenanceStatus: true, |
| | | startTime: null, |
| | | endTime: null |
| | | }) |
| | | |
| | | const rules: FormRules = { |
| | | startTime: [ |
| | | { required: true, type: 'number', message: '请选择开始维护时间', trigger: 'change' } |
| | | ], |
| | | endTime: [ |
| | | { required: true, type: 'number', message: '请选择预计结束时间', trigger: 'change' } |
| | | ] |
| | | } |
| | | |
| | | const handleSave = async () => { |
| | | try { |
| | | await formRef.value?.validate() |
| | | console.log('保存配置', formModel.value) |
| | | window.$message?.success('保存成功') |
| | | } catch (error) { |
| | | console.log('验证失败', error) |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <template> |
| | | <div class="h-full flex flex-col"> |
| | | <n-card content-style="padding: 12px"> |
| | | <n-form |
| | | ref="formRef" |
| | | :model="formModel" |
| | | :rules="rules" |
| | | label-placement="left" |
| | | inline |
| | | :show-feedback="false" |
| | | require-mark-placement="left" |
| | | > |
| | | <n-space vertical :size="16"> |
| | | <n-form-item label="维护状态" required> |
| | | <n-switch v-model:value="formModel.maintenanceStatus" /> |
| | | </n-form-item> |
| | | |
| | | <n-form-item label="开始维护时间" path="startTime" required> |
| | | <n-date-picker |
| | | v-model:value="formModel.startTime" |
| | | type="datetime" |
| | | placeholder="年/月/日 --:--" |
| | | style="width: 400px;" |
| | | clearable |
| | | /> |
| | | </n-form-item> |
| | | |
| | | <n-form-item label="预计结束时间" path="endTime" required> |
| | | <n-date-picker |
| | | v-model:value="formModel.endTime" |
| | | type="datetime" |
| | | placeholder="年/月/日 --:--" |
| | | style="width: 400px;" |
| | | clearable |
| | | /> |
| | | </n-form-item> |
| | | </n-space> |
| | | </n-form> |
| | | </n-card> |
| | | |
| | | <div class="absolute bottom-0 left-0 right-0 flex justify-end gap-3 bg-white px-6 py-4" style="box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1); z-index: 100"> |
| | | <n-button type="primary" style="width: 84px; height: 32px" @click="handleSave">保存</n-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | |
| | | <style scoped> |
| | | </style> |
| | |
| | | </n-card> |
| | | |
| | | <div class="absolute bottom-0 left-0 right-0 flex justify-end gap-3 bg-white px-6 py-4" style="box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1); z-index: 100"> |
| | | <n-button type="primary" style="width: 84px; height: 32px" @click="handleSave">保存</n-button> |
| | | <n-button type="primary" v-permission="201211" style="width: 84px; height: 32px" @click="handleSave">保存</n-button> |
| | | </div> |
| | | </div> |
| | | </template> |
| | |
| | | </n-card> |
| | | |
| | | <div class="absolute bottom-0 left-0 right-0 flex justify-end gap-3 bg-white px-6 py-4" style="box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1); z-index: 100"> |
| | | <n-button type="primary" style="width: 84px; height: 32px" @click="handleSave">保存</n-button> |
| | | <n-button type="primary" v-permission="2031" style="width: 84px; height: 32px" @click="handleSave">保存</n-button> |
| | | </div> |
| | | </div> |
| | | </template> |