pyt
2025-04-29 28eb0ea7a3ec98877be93859f233f292a5f2857b
添加权限
14个文件已修改
1个文件已添加
1161 ■■■■■ 已修改文件
src/layouts/index.vue 466 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main.js 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/router.js 381 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/index.js 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/404.vue 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/car-manage/index.vue 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/company/index.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/complaint/index.vue 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/early-warning/index.vue 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/login/index.vue 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/order/index.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/systemManage/driver/index.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/systemManage/role/index.vue 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/view/systemManage/user/index.vue 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/layouts/index.vue
@@ -1,258 +1,326 @@
<template>
    <div class="sticky top0 layout">
        <div class="header relative" style="align-items: flex-end;">
            <div @click="$router.push('/home')" class="title">
                <img src="@/assets/logo.png" alt="">
                <span>
                    射洪两客一危监管平台
                </span>
  <div class="sticky top0 layout">
    <div class="header relative" style="align-items: flex-end">
      <div @click="$router.push('/home')" class="title">
        <img src="@/assets/logo.png" alt="" />
        <span> 射洪两客一危监管平台 </span>
      </div>
      <div></div>
      <div class="flex a-center pr--40">
        <div class="flex a-center mr--72">
          <img
            src="@/assets/header/photo.png"
            class="w--32 h--32 shrink0 mr--10"
            style="border-radius: 50%"
          />
          <div class="fs-- 18 lh--25 color2">
            {{ $store.state.userInfo.nickName }}
          </div>
        </div>
        <div
          class="dropdown"
          @mouseenter="toggleDropdown(true)"
          @mouseleave="toggleDropdown(false)"
        >
          <img src="@/assets/header/more.png" class="w--16 h--16" />
          <div v-if="isOpen" class="dropdown-menu">
            <div
              @click="clickItem(item)"
              class="dropdown-item"
              v-for="item in menuItems"
              :key="item.text"
            >
              <i :class="item.icon"></i> {{ item.text }}
            </div>
            <div></div>
            <div class="flex a-center pr--40">
                <div class="flex a-center mr--72">
                    <img src="@/assets/header/photo.png" class="w--32 h--32 shrink0 mr--10"
                        style="border-radius: 50%;" />
                    <div class="fs-- 18 lh--25 color2">{{ $store.state.userInfo.nickName }}</div>
                </div>
                <div class="dropdown" @mouseenter="toggleDropdown(true)" @mouseleave="toggleDropdown(false)">
                    <img src="@/assets/header/more.png" class="w--16 h--16" />
                    <div v-if="isOpen" class="dropdown-menu">
                        <div @click="clickItem(item)" class="dropdown-item" v-for="item in menuItems" :key="item.text">
                            <i :class="item.icon"></i> {{ item.text }}
                        </div>
                    </div>
                </div>
            </div>
          </div>
        </div>
        <div class="menu w100 bgColor1">
            <template v-for="(item, index) in routesList">
                <template v-if="!item.meta || !item.meta.title">
                    <template v-for="(item2, index2) in item.children">
                        <div v-if="!item2.meta.hide" :key="index2"
                            @click="pushPath(item2.path)"
                            class="flex a-center j-center h100 br--18 w--160 menuItemHover pointer"
                            :class="item2.path == $route.path && 'bgColor2'">
                            <img v-if="item2.meta.icon" :src="require(`@/assets/routerIcon/${item2.meta.icon}.png`)"
                                class="w--40 h--40 mr--12 shrink0" />
                            <div class="color1">
                                {{ item2.meta.title }}
                            </div>
                        </div>
                    </template>
                </template>
                <div v-else :key="index"
                    :class="$route.path.includes('systemManage') && 'bgColor2'"
                    class="h100 w--160 br--18 menuItemHover dropdown"
                    @mouseenter="routerDropdown(true)"
                    @mouseleave="routerDropdown(false)">
                    <div class="flex a-center j-center h100">
                        <img :src="require(`@/assets/routerIcon/${item.meta.icon}.png`)"
                            class="w--40 h--40 mr--12 shrink0" />
                        <div class="color1">
                            {{ item.meta.title }}
                        </div>
                    </div>
                    <div v-if="routerIsOpen" class="dropdown-menu positionTwo">
                        <template v-for="(item2, index2) in item.children">
                            <div v-if="!item2.meta.hide" :key="index2"
                                @click="pushPath(item.path + '/' + item2.path)"
                                class="dropdown-item flex a-center">
                                {{ item2.meta.title }}
                            </div>
                        </template>
                    </div>
                </div>
            </template>
        </div>
        <div class="main">
            <router-view></router-view>
        </div>
        <ResetPassword v-if="passwordVisible" :row="row" :dialogVisible="passwordVisible"
            @close="passwordVisible = false, row = {}" @confirm="passwordConfirm" />
      </div>
    </div>
    <div class="menu w100 bgColor1">
      <template v-for="(item, index) in routesList">
        <template v-if="!item.meta || !item.meta.title">
          <template v-for="(item2, index2) in item.children">
            <div
              v-if="!item2.meta.hide"
              :key="index2"
              @click="pushPath(item2.path)"
              class="flex a-center j-center h100 br--18 w--160 menuItemHover pointer"
              :class="item2.path == $route.path && 'bgColor2'"
            >
              <img
                v-if="item2.meta.icon"
                :src="require(`@/assets/routerIcon/${item2.meta.icon}.png`)"
                class="w--40 h--40 mr--12 shrink0"
              />
              <div class="color1">
                {{ item2.meta.title }}
              </div>
            </div>
          </template>
        </template>
        <div
          v-else
          :key="index"
          :class="$route.path.includes('systemManage') && 'bgColor2'"
          class="h100 w--160 br--18 menuItemHover dropdown"
          @mouseenter="routerDropdown(true)"
          @mouseleave="routerDropdown(false)"
        >
          <div class="flex a-center j-center h100">
            <img
              :src="require(`@/assets/routerIcon/${item.meta.icon}.png`)"
              class="w--40 h--40 mr--12 shrink0"
            />
            <div class="color1">
              {{ item.meta.title }}
            </div>
          </div>
          <div v-if="routerIsOpen" class="dropdown-menu positionTwo">
            <template v-for="(item2, index2) in item.children">
              <div
                v-if="!item2.meta.hide"
                :key="index2"
                @click="pushPath(item.path + '/' + item2.path)"
                class="dropdown-item flex a-center"
              >
                {{ item2.meta.title }}
              </div>
            </template>
          </div>
        </div>
      </template>
    </div>
    <div class="main">
      <router-view></router-view>
    </div>
    <ResetPassword
      v-if="passwordVisible"
      :row="row"
      :dialogVisible="passwordVisible"
      @close="(passwordVisible = false), (row = {})"
      @confirm="passwordConfirm"
    />
  </div>
</template>
<script>
import routes from '@/router/router'
import { mapMutations } from 'vuex';
import ResetPassword from '@/view/systemManage/user/components/resetPassWord.vue'
import { updatePwd } from '@/view/systemManage/user/service'
import routes from "@/router/router";
import { mapMutations } from "vuex";
import ResetPassword from "@/view/systemManage/user/components/resetPassWord.vue";
import { updatePwd } from "@/view/systemManage/user/service";
import { getRoleInfo } from "../view/systemManage/role/service";
export default {
    components: {
        ResetPassword,
    },
    data() {
        return {
            routesList: routes,
            isOpen: false,
            routerIsOpen: false,
            menuItems: [
                { text: '密码设置' },
                { text: '退出登录' },
            ],
            passwordVisible: false,
            row: {}
        };
    },
    created() {
        console.log(JSON.parse(localStorage.getItem('userInfo')).roles[0].roleId);
    },
    methods: {
        ...mapMutations(['clearToken']),
        passwordConfirm(form) {
            updatePwd(form).then(() => {
                this.row = {}
                this.passwordVisible = false
                this.msgsuccess('修改密码成功')
            })
        },
        clickItem(item) {
            switch (item.text) {
                case '密码设置':
                    this.row = this.$store.state.userInfo
                    this.passwordVisible = true
                    break;
                case '退出登录':
                    this.clearToken()
                    window.location.replace(`/`);
                    break;
                default:
                    break;
            }
        },
        pushPath(path) {
            this.$router.push(path)
            if (this.routerIsOpen) this.routerIsOpen = false
        },
        toggleDropdown(state) {
            this.isOpen = state;
        },
        routerDropdown(state) {
            this.routerIsOpen = state;
        }
  components: {
    ResetPassword,
  },
  data() {
    return {
      routesList: [],
      isOpen: false,
      routerIsOpen: false,
      menuItems: [{ text: "密码设置" }, { text: "退出登录" }],
      passwordVisible: false,
      row: {},
    };
  },
  created() {
    console.log(this.$store.state.permissions,this.$router.options.routes);
    if (localStorage.getItem("userInfo")) {
      this.routesList = this.filterRoutes(this.$router.options.routes)
    } else {
      this.routesList = routes;
    }
}
  },
  methods: {
    ...mapMutations(["clearToken"]),
    // 过滤路由函数
    filterRoutes(routes) {
      const permissions = this.$store.state.permissions || [];
      return routes.filter((route) => {
        // 如果路由有children,递归过滤
        if (route.children && route.children.length > 0) {
          const filteredChildren = this.filterRoutes(route.children);
          route.children = filteredChildren;
          // 如果过滤后children为空,且父路由有menuId需要权限,则过滤掉该路由
          if (
            filteredChildren.length === 0 &&
            route.meta &&
            route.meta.menuId &&
            !permissions.includes(route.meta.menuId)
          ) {
            return false;
          }
          // 如果过滤后children不为空,保留该父路由
          if (filteredChildren.length > 0) {
            return true;
          }
        }
        // 处理没有children的路由
        // 1. 如果路由没有menuId,保留
        if (!route.meta || !route.meta.menuId) {
          return true;
        }
        // 2. 如果路由有menuId,检查权限
        return permissions.includes(route.meta.menuId);
      });
    },
    passwordConfirm(form) {
      updatePwd(form).then(() => {
        this.row = {};
        this.passwordVisible = false;
        this.msgsuccess("修改密码成功");
      });
    },
    clickItem(item) {
      switch (item.text) {
        case "密码设置":
          this.row = this.$store.state.userInfo;
          this.passwordVisible = true;
          break;
        case "退出登录":
          this.clearToken();
          window.location.replace(`/`);
          break;
        default:
          break;
      }
    },
    pushPath(path) {
      this.$router.push(path);
      if (this.routerIsOpen) this.routerIsOpen = false;
    },
    toggleDropdown(state) {
      this.isOpen = state;
    },
    routerDropdown(state) {
      this.routerIsOpen = state;
    },
  },
};
</script>
<style lang="less" scoped>
.layout {
    display: flex;
    flex-direction: column;
    height: 100%;
  display: flex;
  flex-direction: column;
  height: 100%;
    .main {
        flex: 1;
        overflow: auto;
    }
  .main {
    flex: 1;
    overflow: auto;
  }
}
.bgColor1 {
    background-color: #3367ce;
  background-color: #3367ce;
}
.bgColor2 {
    background: #2b5ab6;
  background: #2b5ab6;
}
.color1 {
    color: #fff;
  color: #fff;
}
.color2 {
    // color: rgba(0, 0, 0, .6);
    color: #fff;
  // color: rgba(0, 0, 0, .6);
  color: #fff;
}
.header {
    height: 80px;
    background: #3367ce;
    background-image: url('../assets/title.png');
    background-size: 100% 100%;
  height: 80px;
  background: #3367ce;
  background-image: url("../assets/title.png");
  background-size: 100% 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  .title {
    display: flex;
    justify-content: center;
    font-weight: 600;
    font-size: 30px;
    align-items: center;
    justify-content: space-between;
    position: absolute;
    top: 38%;
    left: 48.5%;
    transform: translate(-50%, -50%);
    // color: rgba(0, 0, 0, .8);
    color: #fff;
    .title {
        display: flex;
        justify-content: center;
        font-weight: 600;
        font-size: 30px;
        align-items: center;
        position: absolute;
        top: 38%;
        left: 48.5%;
        transform: translate(-50%, -50%);
        // color: rgba(0, 0, 0, .8);
        color: #fff;
        img {
            width: 50px;
            height: 50px;
            margin-right: 25px;
        }
        span {
            letter-spacing: 4px;
            text-shadow: 2px 2px 8px rgba(0, 0, 0, 0.3); // 新增字体阴影
        }
    img {
      width: 50px;
      height: 50px;
      margin-right: 25px;
    }
    span {
      letter-spacing: 4px;
      text-shadow: 2px 2px 8px rgba(0, 0, 0, 0.3); // 新增字体阴影
    }
  }
}
.menu {
    height: 60px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 220px;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 220px;
}
.menuItemHover {
    flex: 1;
    max-width: 160px;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: all 0.3s;
  flex: 1;
  max-width: 160px;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: all 0.3s;
}
.menuItemHover:hover {
    border-radius: 18px;
    background: #2b5ab6;
  border-radius: 18px;
  background: #2b5ab6;
}
.dropdown {
    position: relative;
    display: inline-block;
    cursor: pointer;
  position: relative;
  display: inline-block;
  cursor: pointer;
}
.positionTwo {
    transform: unset !important;
    width: 160px !important;
  transform: unset !important;
  width: 160px !important;
}
.dropdown-menu {
    position: absolute;
    top: 100%;
    left: 0;
    transform: translateX(-50%);
    background: white;
    border: 1px solid #ccc;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
    z-index: 1000;
    border-radius: 8px;
  position: absolute;
  top: 100%;
  left: 0;
  transform: translateX(-50%);
  background: white;
  border: 1px solid #ccc;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
  z-index: 1000;
  border-radius: 8px;
}
.dropdown-item {
    padding: 8px 16px;
    white-space: nowrap;
    /* 防止文本换行 */
  padding: 8px 16px;
  white-space: nowrap;
  /* 防止文本换行 */
}
.dropdown-item:hover {
    background-color: #f0f0f0;
    /* 添加 hover 效果 */
  background-color: #f0f0f0;
  /* 添加 hover 效果 */
}
</style>
src/main.js
@@ -60,6 +60,32 @@
  });
}
Vue.prototype.$checkPermission = function(permissionId) {
  const permissions = store.state.permissions || [];
  if (!permissions.includes(permissionId)) {
    this.$router.push('/404');
    return false;
  }
  return true;
};
Vue.directive('permission', {
  inserted: function (el, binding) {
    const permissions = store.state.permissions || [];
    if (!permissions.includes(binding.value)) {
      el.style.display = 'none';
    }
  },
  update: function (el, binding) {
    const permissions = store.state.permissions || [];
    if (!permissions.includes(binding.value)) {
      el.style.display = 'none';
    } else {
      el.style.display = '';
    }
  }
});
new Vue({
  router,
  store,
src/router/index.js
@@ -16,12 +16,12 @@
  }),
  routes
})
const router = createRouter()
// 路由守卫
router.beforeEach((to, from, next) => {
  const token = store.state.token
  const permissions = store.state.permissions || []
  if (!token && to.path != '/') {
    // 如果没有 token 并且不是去登录页,重定向到登录页
    next('/')
@@ -29,9 +29,26 @@
    // 如果有 token 并且要去登录页,重定向到首页
    next('/home')
  } else {
    // 检查路由权限
    if (to.meta && to.meta.menuId) {
      // 如果路由有menuId,检查是否有权限访问
      if (permissions.length === 0) {
        // 如果权限数组为空,说明是刚登录,还未获取权限,允许访问
        next()
      } else if (permissions.includes(to.meta.menuId)) {
        // 有权限,允许访问
        next()
      } else {
        // 无权限,重定向到404或首页
        next('/404')
      }
    } else {
      // 路由没有menuId,直接放行
      next()
    }
    // 清理 localStorage
    localStorage.removeItem('registerForm')
    next()
  }
})
src/router/router.js
@@ -1,177 +1,204 @@
import Layout from '@/layouts'
/**
 * icon
 * home: 首页
 * alarm: 报警
 * car: 车辆
 * company: 公司
 * complaint: 投诉
 * sys: 系统
 * order: 订单
 *
 * hide: true, // 是否隐藏
 *
 */
export default [
    {
        path: '/',
        component: () => import('@/view/login'),
    },
    {
        path: '/home',
        component: Layout,
        children: [
            {
                path: '/home',
                component: () => import('@/view/home'),
                meta: {
                    title: '首页',
                    icon: 'home'
                }
            },
        ]
    },
    {
        path: '/company',
        component: Layout,
        children: [
            {
                path: '/company',
                component: () => import('@/view/company'),
                meta: {
                    title: '公司管理',
                    icon: 'company'
                }
            }
        ]
    },
    {
        path: '/car',
        component: Layout,
        children: [
            {
                path: '/car-manage',
                component: () => import('@/view/car-manage'),
                meta: {
                    title: '车辆管理',
                    icon: 'car'
                }
            },
            {
                path: '/car-detail',
                component: () => import('@/view/car-manage/detail'),
                meta: {
                    title: '车辆详情',
                    icon: 'car',
                    hide: true
                }
            },
            {
                path: '/car-playback',
                component: () => import('@/view/playback'),
                meta: {
                    title: '车辆回放',
                    hide: true
                }
            }
        ]
    },
    {
        path: '/early-warning',
        component: Layout,
        children: [
            {
                path: '/early-warning',
                component: () => import('@/view/early-warning'),
                meta: {
                    title: '报警记录',
                    icon: 'alarm'
                }
            }
        ]
    },
    {
        path: '/order',
        component: Layout,
        children: [
            {
                path: '/order',
                component: () => import('@/view/order'),
                meta: {
                    title: '订单记录',
                    icon: 'order'
                }
            }
        ]
    },
    {
        path: '/complaint',
        component: Layout,
        children: [
            {
                path: '/complaint',
                component: () => import('@/view/complaint/index'),
                meta: {
                    title: '投诉记录',
                    icon: 'complaint'
                }
            }
        ]
    },
    {
        path: '/systemManage',
        meta: {
            title: "系统管理",
            icon: 'sys',
        },
        component: Layout,
        children: [
            {
                path: 'driver',
                component: () => import('@/view/systemManage/driver'),
                meta: {
                    title: '驾驶员列表',
                }
            },
            {
                path: 'type',
                component: () => import('@/view/car-type'),
                meta: {
                    title: '车辆分类',
                }
            },
            {
                path: 'user',
                component: () => import('@/view/systemManage/user'),
                meta: {
                    title: '用户管理',
                }
            },
            {
                path: 'role',
                component: () => import('@/view/systemManage/role'),
                meta: {
                    title: '角色管理',
                }
            },
            {
                path: 'add-role',
                component: () => import('@/view/systemManage/role/addEdit.vue'),
                meta: {
                    title: '添加角色',
                    hide: true
                }
            },
            {
                path: 'role-detail',
                component: () => import('@/view/systemManage/role/detail'),
                meta: {
                    title: '角色详情',
                    hide: true
                }
            }
        ]
    }
]
import Layout from "@/layouts";
/**
 * icon
 * home: 首页
 * alarm: 报警
 * car: 车辆
 * company: 公司
 * complaint: 投诉
 * sys: 系统
 * order: 订单
 *
 * hide: true, // 是否隐藏
 *
 */
export default [
  {
    path: "/",
    component: () => import("@/view/login"),
  },
  {
    path: "/home",
    component: Layout,
    children: [
      {
        path: "/home",
        component: () => import("@/view/home"),
        meta: {
          title: "首页",
          icon: "home",
          menuId: 1,
        },
      },
    ],
  },
  {
    path: "/404",
    component: Layout,
    children: [
      {
        path: "/404",
        component: () => import("@/view/404.vue"),
        meta: {
          title: "404",
          icon: "home",
          hide: true,
        },
      },
    ],
  },
  {
    path: "/company",
    component: Layout,
    children: [
      {
        path: "/company",
        component: () => import("@/view/company"),
        meta: {
          title: "公司管理",
          icon: "company",
          menuId: 2,
        },
      },
    ],
  },
  {
    path: "/car",
    component: Layout,
    children: [
      {
        path: "/car-manage",
        component: () => import("@/view/car-manage"),
        meta: {
          title: "车辆管理",
          icon: "car",
          menuId: 3,
        },
      },
      {
        path: "/car-detail",
        component: () => import("@/view/car-manage/detail"),
        meta: {
          title: "车辆详情",
          icon: "car",
          hide: true,
          menuId: 31,
        },
      },
      {
        path: "/car-playback",
        component: () => import("@/view/playback"),
        meta: {
          title: "车辆回放",
          hide: true,
        },
      },
    ],
  },
  {
    path: "/early-warning",
    component: Layout,
    children: [
      {
        path: "/early-warning",
        component: () => import("@/view/early-warning"),
        meta: {
          title: "报警记录",
          icon: "alarm",
          menuId: 9,
        },
      },
    ],
  },
  {
    path: "/order",
    component: Layout,
    children: [
      {
        path: "/order",
        component: () => import("@/view/order"),
        meta: {
          title: "订单记录",
          icon: "order",
          menuId: 6,
        },
      },
    ],
  },
  {
    path: "/complaint",
    component: Layout,
    children: [
      {
        path: "/complaint",
        component: () => import("@/view/complaint/index"),
        meta: {
          title: "投诉记录",
          icon: "complaint",
          menuId: 12,
        },
      },
    ],
  },
  {
    path: "/systemManage",
    meta: {
      title: "系统管理",
      icon: "sys",
    },
    component: Layout,
    children: [
      {
        path: "driver",
        component: () => import("@/view/systemManage/driver"),
        meta: {
          title: "驾驶员列表",
          menuId: 4,
        },
      },
      {
        path: "type",
        component: () => import("@/view/car-type"),
        meta: {
          title: "车辆分类",
          menuId: 5,
        },
      },
      {
        path: "user",
        component: () => import("@/view/systemManage/user"),
        meta: {
          title: "用户管理",
          menuId: 15,
        },
      },
      {
        path: "role",
        component: () => import("@/view/systemManage/role"),
        meta: {
          title: "角色管理",
          menuId: 22,
        },
      },
      {
        path: "add-role",
        component: () => import("@/view/systemManage/role/addEdit.vue"),
        meta: {
          title: "添加角色",
          hide: true,
          menuId: 24,
        },
      },
      {
        path: "role-detail",
        component: () => import("@/view/systemManage/role/detail"),
        meta: {
          title: "角色详情",
          hide: true,
          menuId: 27,
        },
      },
    ],
  },
];
src/store/index.js
@@ -1,29 +1,35 @@
import Vue from 'vue';
import Vuex from 'vuex';
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export default new Vuex.Store({
  state: {
    token: localStorage.getItem('token') || sessionStorage.getItem('token') || '',
    userInfo: JSON.parse(localStorage.getItem('userInfo')) || {}
    permissions: JSON.parse(localStorage.getItem("permissions")) || [],
    token:
      localStorage.getItem("token") || sessionStorage.getItem("token") || "",
    userInfo: JSON.parse(localStorage.getItem("userInfo")) || {},
  },
  mutations: {
    SET_PERMISSON(state, arr) {
      state.permissions = arr;
      localStorage.setItem("permissions", JSON.stringify(arr));
    },
    setToken(state, token) {
      state.token = token;
      localStorage.setItem('token', token);
      localStorage.setItem("token", token);
    },
    clearToken(state) {
      state.token = '';
      state.userInfo = {}
      state.token = "";
      state.userInfo = {};
      localStorage.clear();
      sessionStorage.clear();
    },
    setUserInfo(state, userInfo) {
      state.userInfo = userInfo;
      localStorage.setItem('userInfo', userInfo)
    }
      localStorage.setItem("userInfo", userInfo);
    },
  },
  actions: {},
  modules: {}
});
  modules: {},
});
src/view/404.vue
New file
@@ -0,0 +1,54 @@
<template>
  <div class="not-found">
    <div class="not-found-content">
      <!-- <img src="@/assets/404.png" alt="404" class="not-found-image"> -->
      <h1 class="not-found-title">404</h1>
      <p class="not-found-text">抱歉,您暂无该页面访问权限,请联系管理员开通</p>
    </div>
  </div>
</template>
<script>
export default {
  name: 'NotFound',
  methods: {
    goHome() {
      this.$router.push('/home');
    }
  }
}
</script>
<style lang="less" scoped>
.not-found {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  background-color: #f5f7fa;
  &-content {
    text-align: center;
    padding: 20px;
  }
  &-image {
    width: 300px;
    height: 300px;
    margin-bottom: 20px;
  }
  &-title {
    font-size: 72px;
    color: #409EFF;
    margin: 0;
    line-height: 1.2;
  }
  &-text {
    font-size: 20px;
    color: #606266;
    margin: 20px 0;
  }
}
</style>
src/view/car-manage/index.vue
@@ -76,7 +76,7 @@
                </el-table-column>
                <el-table-column label="操作" width="100">
                    <template slot-scope="scope">
                        <el-button type="text" @click="handle(scope.$index, scope.row)">详情</el-button>
                        <el-button type="text" v-permission="31" @click="handle(scope.$index, scope.row)">详情</el-button>
                    </template>
                </el-table-column>
            </el-table>
@@ -118,6 +118,8 @@
        };
    },
    created() {
        this.$checkPermission(30)
        getCarType().then(res => {
            this.options = res;
        });
src/view/company/index.vue
@@ -47,7 +47,7 @@
                <el-table-column prop="contactNumber" label="联系电话"></el-table-column>
                <el-table-column prop="name" label="操作">
                    <template slot-scope="scope">
                        <el-button @click="showDetail(scope.row)" size="small" type="primary">详情</el-button>
                        <el-button v-permission="29" @click="showDetail(scope.row)" size="small" type="primary">详情</el-button>
                    </template>
                </el-table-column>
            </el-table>
@@ -92,6 +92,7 @@
        },
    },
    created() {
        this.$checkPermission(28)
        this.getList()
    },
    methods: {
src/view/complaint/index.vue
@@ -32,7 +32,7 @@
        <div class="table-box-btn mt--23 ml--30">
            <el-button class="search-button h--40 w--90 fs--14" icon="el-icon-top" type="primary" size="small"
                @click="exportExcell">导出</el-button>
                @click="exportExcell" v-permission="14">导出</el-button>
        </div>
        <div class="table-box ml--30 mt--23 mr--30">
            <el-table :data="tableData" border stripe style="width: 100%" :element-loading-text="'正在加载...'">
@@ -87,6 +87,8 @@
        },
    },
    created() {
        this.$checkPermission(13)
        this.getTableList()
    },
    methods: {
src/view/early-warning/index.vue
@@ -55,7 +55,7 @@
        </div>
        <div class="table-box-btn mt--23 ml--30">
            <el-button class="search-button h--40 w--90 fs--14" icon="el-icon-top" type="primary" size="small"
            <el-button v-permission="11" class="search-button h--40 w--90 fs--14" icon="el-icon-top" type="primary" size="small"
                @click="exportExc">导出</el-button>
        </div>
        <div class="table-box ml--30 mt--23 mr--30">
@@ -66,8 +66,8 @@
                <el-table-column prop="vehicleNumber" label="车牌号码" fixed="left"></el-table-column>
                <!-- 其余列不固定,可滚动 -->
                <el-table-column prop="name" label="近15分钟情况">
                    <template #default="{ row }">
                        <img src="@/assets/homeImg/eye-fill.png" alt="" @click="viewDetail(row)"
                    <template #default="{ row }" >
                        <img v-permission="35" src="@/assets/homeImg/eye-fill.png" alt="" @click="viewDetail(row)"
                            style="width: 30px;cursor: pointer;">
                    </template>
                </el-table-column>
@@ -192,6 +192,7 @@
        };
    },
    created() {
        this.$checkPermission(10)
        this.fetchData()
    },
    methods: {
src/view/login/index.vue
@@ -2,51 +2,69 @@
  <div class="bgImg">
    <div class="login_box">
      <div class="logo">
        <img src="@/assets/logo.png" alt="">
        <div class="fs--25 fw-bold" style="letter-spacing: 4px;">射洪两客一危监管平台</div>
        <img src="@/assets/logo.png" alt="" />
        <div class="fs--25 fw-bold" style="letter-spacing: 4px">
          射洪两客一危监管平台
        </div>
      </div>
      <div class="txt-center pb--20 px--20">
        <div class="mt--20">
          <el-input class="w100" prefix-icon="el-icon-user" placeholder="账号" v-model="username" />
          <el-input
            class="w100"
            prefix-icon="el-icon-user"
            placeholder="账号"
            v-model="username"
          />
        </div>
        <div class="mt--20">
          <el-input prefix-icon="el-icon-lock" placeholder="密码" v-model="password" show-password />
          <el-input
            prefix-icon="el-icon-lock"
            placeholder="密码"
            v-model="password"
            show-password
          />
        </div>
        <div class="mt--20 flex a-center code_box">
          <div class="flex1">
            <el-input placeholder="请输入验证码" v-model="code" />
          </div>
          <div @click="resetCodeStr" class="fs--18 lh--40 border1 pointer">{{ codeStr }}</div>
          <div @click="resetCodeStr" class="fs--18 lh--40 border1 pointer">
            {{ codeStr }}
          </div>
        </div>
        <el-button :loading="loginLoading" @click="login"
          class="mt--40 w100 br--5 pointer bgcolor1 color1">登录</el-button>
        <el-button
          :loading="loginLoading"
          @click="login"
          class="mt--40 w100 br--5 pointer bgcolor1 color1"
          >登录</el-button
        >
      </div>
    </div>
  </div>
</template>
<script>
import { generateVerificationCode, generateRandomString } from '@/utils/utils';
import { mapMutations } from 'vuex';
import { loginPwd } from './service'
import CryptoJS from 'crypto-js';
import {
  Message
} from 'element-ui'
import { generateVerificationCode, generateRandomString } from "@/utils/utils";
import { mapMutations } from "vuex";
import { loginPwd } from "./service";
import CryptoJS from "crypto-js";
import { getRoleInfo } from "@/view/systemManage/role/service";
import { Message } from "element-ui";
export default {
  components: {},
  props: {},
  data() {
    return {
      loginLoading: false,//登录loading
      username: '',
      password: '',
      code: '',
      codeStr: ''
      loginLoading: false, //登录loading
      username: "",
      password: "",
      code: "",
      codeStr: "",
    };
  },
  created() {
    this.resetCodeStr()
    this.resetCodeStr();
  },
  mounted() {
    document.addEventListener("keydown", this.handleKeyDown);
@@ -55,48 +73,53 @@
    document.removeEventListener("keydown", this.handleKeyDown);
  },
  methods: {
    ...mapMutations(['setToken', 'setUserInfo']),
    ...mapMutations(["setToken", "setUserInfo"]),
    login() {
      if (!this.rulesLogin()) return
      if (!this.rulesLogin()) return;
      this.loginLoading = true;
      loginPwd({
        username: this.username,
        password: CryptoJS.MD5(this.password).toString()
      }).then(res => {
        localStorage.setItem('client', generateRandomString(16));
        this.loginLoading = false;
        this.setToken(res.token.access_token);
        this.setUserInfo(JSON.stringify(res.info.sysUser));
        this.$router.push('/home')
      }).catch(() => {
        this.resetCodeStr()
        this.loginLoading = false;
        password: CryptoJS.MD5(this.password).toString(),
      })
        .then((res) => {
          localStorage.setItem("client", generateRandomString(16));
          this.loginLoading = false;
          this.setToken(res.token.access_token);
          this.setUserInfo(JSON.stringify(res.info.sysUser));
          getRoleInfo({ id: res.info.sysUser.roles[0].roleId }).then((res) => {
            this.$store.commit("SET_PERMISSON", res.menus);
            this.$router.push("/home");
          });
        })
        .catch(() => {
          this.resetCodeStr();
          this.loginLoading = false;
        });
    },
    rulesLogin() {
      if (!this.username) {
        Message({
          message: '请输入账号',
          type: 'warning',
          duration: 2000
        })
        return false
          message: "请输入账号",
          type: "warning",
          duration: 2000,
        });
        return false;
      }
      if (!this.password) {
        Message({
          message: '请输入密码',
          type: 'warning',
          duration: 2000
        })
        return false
          message: "请输入密码",
          type: "warning",
          duration: 2000,
        });
        return false;
      }
      if (!this.code) {
        Message({
          message: '请输入验证码',
          type: 'warning',
          duration: 2000
        })
        return false
          message: "请输入验证码",
          type: "warning",
          duration: 2000,
        });
        return false;
      }
      if (!this.matchCaseInsensitive(this.codeStr, this.code)) {
        Message({
@@ -104,14 +127,14 @@
          type: "warning",
          duration: 1500,
        });
        this.resetCodeStr()
        return false
        this.resetCodeStr();
        return false;
      }
      return true
      return true;
    },
    handleKeyDown(event) {
      if (event.key === "Enter") {
        this.login()
        this.login();
      }
    },
    // 校验验证码
@@ -126,7 +149,7 @@
</script>
<style scoped lang="less">
.bgImg {
  background-image: url('../../assets/loginBG.png');
  background-image: url("../../assets/loginBG.png");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
@@ -156,12 +179,11 @@
      margin-right: 15px;
    }
  }
}
.code_box {
  border-radius: 4px;
  border: 1px solid #DCDFE6;
  border: 1px solid #dcdfe6;
  ::v-deep .el-input__inner {
    border: unset !important;
@@ -169,7 +191,7 @@
}
.bgcolor1 {
  background: #0E6EFD;
  background: #0e6efd;
}
.color1 {
@@ -177,7 +199,7 @@
}
.border1 {
  border-left: 1px solid #DCDFE6;
  border-left: 1px solid #dcdfe6;
  min-width: 100px;
}
</style>
src/view/order/index.vue
@@ -46,7 +46,7 @@
        </div>
        <div class="mt--23 ml--30">
            <el-button class="search-button h--40 w--90 fs--14" icon="el-icon-top" type="primary" size="small"
                @click="exportExcell">导出</el-button>
                @click="exportExcell" v-permission="8">导出</el-button>
        </div>
        <div class="table-box ml--30 mt--23 mr--30">
            <el-table :data="tableData" border stripe style="width: 100%" :element-loading-text="'正在加载...'">
@@ -68,7 +68,7 @@
                </el-table-column>
                <el-table-column label="操作">
                    <template #default="{ row }">
                        <el-button @click="showDetail(row)">详情</el-button>
                        <el-button v-permission="34" @click="showDetail(row)">详情</el-button>
                    </template>
                </el-table-column>
            </el-table>
@@ -110,6 +110,7 @@
        },
    },
    created() {
        this.$checkPermission(7)
        this.getTableList()
    },
    methods: {
src/view/systemManage/driver/index.vue
@@ -37,7 +37,7 @@
                <el-table-column prop="contractingCompany" label="驾驶员合同签订公司"></el-table-column>
                <el-table-column label="操作">
                    <template #default="{ row }">
                        <el-button @click="showDetail(row)">详情</el-button>
                        <el-button  v-permission="33" @click="showDetail(row)">详情</el-button>
                    </template>
                </el-table-column>
            </el-table>
@@ -76,6 +76,7 @@
        },
    },
    created() {
        this.$checkPermission(32)
        this.getTableList()
    },
    methods: {
src/view/systemManage/role/index.vue
@@ -13,7 +13,7 @@
    </el-card>
    <el-card style="margin-top: 20px;">
      <div class="add_btn">
        <el-button icon="el-icon-plus" @click="add" type="primary">添加角色</el-button>
        <el-button v-permission="24" icon="el-icon-plus" @click="add" type="primary">添加角色</el-button>
      </div>
      <el-table ref="tableSort" v-loading="listLoading" stripe :data="data"
        :element-loading-text="elementLoadingText">
@@ -24,10 +24,10 @@
        <el-table-column label="操作" width="300">
          <template slot-scope="{row}">
            <div>
              <el-button type="text"
              <el-button v-permission="27" type="text"
                @click="$router.push(`/systemManage/role-detail?roleId=${row.roleId}`)">详情</el-button>
              <el-button type="text" @click="$router.push(`/systemManage/add-role?roleId=${row.roleId}`)">编辑</el-button>
              <el-button type="text" @click="del(row)">删除</el-button>
              <el-button v-if="row.roleId != 1" v-permission="25" type="text" @click="$router.push(`/systemManage/add-role?roleId=${row.roleId}`)">编辑</el-button>
              <el-button v-if="row.roleId != 1" v-permission="26" type="text" @click="del(row)">删除</el-button>
            </div>
          </template>
        </el-table-column>
@@ -74,6 +74,7 @@
  },
  watch: {},
  created() {
    this.$checkPermission(23)
    this.getListData()
  },
  mounted() { },
src/view/systemManage/user/index.vue
@@ -30,7 +30,7 @@
      </div>
    </div>
    <div class="table-box-btn mt--23 ml--30">
      <el-button class="search-button h--40 w--90 fs--14" icon="el-icon-plus" type="primary" size="small"
      <el-button v-permission="17" class="search-button h--40 w--90 fs--14" icon="el-icon-plus" type="primary" size="small"
        @click="dialogVisible = true">添加</el-button>
      <!-- <el-button class="search-button h--40 w--90 fs--14" icon="el-icon-delete" type="danger" size="small"
        @click="dialogVisible = true">删除</el-button> -->
@@ -66,11 +66,11 @@
        <el-table-column label="操作" width="300">
          <template #default="{ row }">
            <div v-if="row.userId != 1">
              <el-button type="text" @click="edit(row)">编辑</el-button>
              <el-button v-if="row.status != 0" type="text" @click="updateStatus(row, true)">启用</el-button>
              <el-button v-if="row.status == 0" type="text" @click="updateStatus(row, false)">禁用</el-button>
              <el-button type="text" @click="detail(row)">重置密码</el-button>
              <el-button type="text" @click="del(row)">删除</el-button>
              <el-button v-permission="19" type="text" @click="edit(row)">编辑</el-button>
              <el-button v-permission="20" v-if="row.status != 0" type="text" @click="updateStatus(row, true)">启用</el-button>
              <el-button v-permission="20" v-if="row.status == 0" type="text" @click="updateStatus(row, false)">禁用</el-button>
              <el-button v-permission="21" type="text" @click="detail(row)">重置密码</el-button>
              <el-button v-permission="18" type="text" @click="del(row)">删除</el-button>
            </div>
          </template>
        </el-table-column>
@@ -137,6 +137,8 @@
  },
  watch: {},
  created() {
    this.$checkPermission(16)
    this.getRoleList()
    this.getListData()
  },