页面
<div class="app-container"> <!-- 查询表单 --> <div class="filter-container"> <el-date-picker v-model="dateRange" type="daterange" range-separator="至" start-placeholder="开始日期" end-placeholder="结束日期" value-format="yyyy-MM-dd" style="width: 280px; margin-right: 10px" /> <el-input v-model="queryParams.userName" placeholder="员工姓名/账号" clearable style="width: 180px; margin-right: 10px" /> <el-select v-model="queryParams.deptId" placeholder="所属部门" clearable style="width: 160px" > <el-option v-for="dept in deptOptions" :key="dept.deptId" :label="dept.deptName" :value="dept.deptId" /> </el-select> <el-button type="primary" icon="el-icon-search" @click="getList" >搜索</el-button > <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button> </div> <!-- 操作按钮 --> <el-row :gutter="10" class="mb8"> <el-col :span="1.5"> <el-button type="primary" plain icon="el-icon-plus" @click="openAddDialog" v-hasPermi="['system:schedule:add']" > 新增排班 </el-button> </el-col> <el-col :span="1.5"> <el-button type="danger" plain icon="el-icon-delete" :disabled="selectedSchedules.length === 0" @click="handleDelete(null)" v-hasPermi="['system:schedule:remove']" > 批量删除 </el-button> </el-col> </el-row> <!-- 排班列表 --> <el-table ref="scheduleTable" v-loading="loading" :data="list" @selection-change="handleSelectionChange" border > <el-table-column type="selection" width="50" align="center" /> <el-table-column label="员工" width="200"> <template slot-scope="scope"> <div style="display: flex; align-items: center"> <el-avatar size="small" :src="getAvatar(scope.row)" style="margin-right: 8px" fit="cover" ></el-avatar> <div> <div> <strong>{{ scope.row.nickName }}</strong> </div> <div style="font-size: 12px; color: #999"> {{ scope.row.userName }} </div> </div> </div> </template> </el-table-column> <el-table-column label="部门" prop="deptName" width="150" /> <el-table-column label="排班日期" width="120"> <template slot-scope="scope"> {{ parseTime(scope.row.scheduleDate, "{y}-{m}-{d}") }} </template> </el-table-column> <el-table-column label="班次" width="100"> <template slot-scope="scope"> <el-tag :type="getShiftType(scope.row.shiftType)"> {{ getShiftText(scope.row.shiftType) }} </el-tag> </template> </el-table-column> <el-table-column label="备注" prop="remark" min-width="120" show-overflow-tooltip /> <el-table-column label="操作" fixed="right" align="center" width="250px"> <template slot-scope="scope"> <el-button size="mini" type="text" icon="el-icon-edit" @click="handleEdit(scope.row)" v-hasPermi="['system:schedule:edit']" > 修改 </el-button> <el-button size="mini" type="text" icon="el-icon-view" @click="handleViewDetail(scope.row)" > 详情 </el-button> <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['system:schedule:remove']" > 删除 </el-button> </template> </el-table-column> </el-table> <!-- 分页 --> <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" /> <!-- 主表单:新增/编辑排班 --> <el-dialog :title="dialogTitle" :visible.sync="open" width="800px" append-to-body destroy-on-close @closed="resetDialogForm" > <el-form :model="tempSchedule" label-width="100px"> <!-- 员工选择 --> <el-form-item label="选择员工" required> <el-button type="primary" size="small" @click="openUserSelector"> + 选择员工 </el-button> <div v-if="selectedUsers.length > 0" style="margin-top: 10px; color: #666" > 已选 {{ selectedUsers.length }} 人: <el-tag v-for="user in selectedUsers" :key="user.userId" size="mini" closable @close="removeSelectedUser(user)" style="margin-right: 5px" > {{ user.nickName }} </el-tag> </div> </el-form-item> <!-- 排班时间 --> <el-form-item label="排班时间" required> <el-date-picker v-model="tempSchedule.dates" type="daterange" start-placeholder="开始日期" end-placeholder="结束日期" value-format="yyyy-MM-dd" style="width: 100%" /> </el-form-item> <!-- 班次类型 --> <el-form-item label="班次类型" required> <el-radio-group v-model="tempSchedule.shiftType"> <el-radio label="morning">早班 08:00-16:00</el-radio> <el-radio label="afternoon">晚班 16:00-24:00</el-radio> <el-radio label="night">夜班 00:00-08:00</el-radio> <el-radio label="off">休息</el-radio> </el-radio-group> </el-form-item> <!-- 备注 --> <el-form-item label="备注"> <el-input v-model="tempSchedule.remark" type="textarea" rows="2" /> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click="open = false">取 消</el-button> <el-button type="primary" :loading="submitLoading" @click="submitSchedule" > 确 定 </el-button> </div> </el-dialog> <!-- 用户选择弹窗 --> <el-dialog title="选择员工" :visible.sync="userSelectorVisible" width="800px" append-to-body destroy-on-close > <div class="filter-container" style="margin-bottom: 15px"> <el-input v-model="userQueryParams.userName" placeholder="姓名/账号" clearable style="width: 180px; margin-right: 10px" /> <el-select v-model="userQueryParams.deptId" placeholder="所属部门" clearable style="width: 160px" > <el-option v-for="dept in deptOptions" :key="dept.deptId" :label="dept.deptName" :value="dept.deptId" /> </el-select> <el-button type="primary" icon="el-icon-search" @click="getUserList" >查询</el-button > <el-button icon="el-icon-refresh" @click="resetUserQuery" >重置</el-button > </div> <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange" > <el-table-column type="selection" width="50" align="center" /> <el-table-column label="用户名称" align="center" key="userName" prop="userName" :show-overflow-tooltip="true" /> <el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" :show-overflow-tooltip="true" /> <el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" :show-overflow-tooltip="true" /> <el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" width="120" /> </el-table> <pagination v-show="userTotal > 0" :total="userTotal" :page.sync="userQueryParams.pageNum" :limit.sync="userQueryParams.pageSize" @pagination="getUserList" /> <div slot="footer" class="dialog-footer"> <el-button @click="userSelectorVisible = false">取 消</el-button> <el-button type="primary" @click="confirmSelectUsers">确 定</el-button> </div> </el-dialog> <!-- 详情弹窗 --> <el-dialog title="排班详情" :visible.sync="detailOpen" width="600px" append-to-body destroy-on-close > <div style="line-height: 2" v-if="currentRow"> <p> <b>员工:</b>{{ currentRow.nickName }} ({{ currentRow.userName }}) </p> <p><b>部门:</b>{{ currentRow.deptName }}</p> <p><b>排班日期:</b>{{ currentRow.scheduleDate }}</p> <p> <b>班次:</b> <el-tag :type="getShiftType(currentRow.shiftType)"> {{ getShiftText(currentRow.shiftType) }} </el-tag> </p> <p><b>备注:</b>{{ currentRow.remark || "-" }}</p> <p><b>创建人:</b>{{ currentRow.createBy }}</p> <p><b>创建时间:</b>{{ currentRow.createTime }}</p> </div> <div v-else> <el-empty description="暂无数据"></el-empty> </div> </el-dialog> </div> </template> <script> import { listUser } from "@/api/system/user"; import { listDept } from "@/api/system/dept"; import { listSchedule, addSchedule, updateSchedule, delSchedule, } from "@/api/system/schedule"; import { parseTime } from "@/utils"; export default { name: "ScheduleManagement", data() { return { loading: false, submitLoading: false, list: [], total: 0, queryParams: { pageNum: 1, pageSize: 10, userName: undefined, deptId: undefined, }, dateRange: [], selectedSchedules: [], currentRow: null, // 弹窗控制 open: false, detailOpen: false, dialogTitle: "", // 临时排班数据 tempSchedule: { userIds: [], dates: [], shiftType: "morning", remark: "", }, // 用户选择相关 userSelectorVisible: false, userList: [], userTotal: 0, userQueryParams: { pageNum: 1, pageSize: 10, userName: undefined, deptId: undefined, }, selectedUserIds: [], selectedUsers: [], allUserList: [], // 缓存所有用户信息 deptOptions: [], }; }, computed: { isSuperAdmin() { return this.$store.getters.roles.includes("admin"); }, }, created() { this.getDepts(); this.getAllUsers(); // ✅ 预加载所有用户 this.getList(); }, methods: { // ✅ 注册 parseTime 到 methods getDepts() { listDept().then((res) => { this.deptOptions = res.data || []; }); }, getAllUsers() { listUser({ pageSize: 1000 }).then((res) => { this.allUserList = res.rows || []; }); }, getList() { this.loading = true; const params = { ...this.queryParams, startTime: this.dateRange?.[0], endTime: this.dateRange?.[1], }; listSchedule(params) .then((res) => { this.list = res.rows || []; this.total = res.total || 0; }) .finally(() => { this.loading = false; }); }, resetQuery() { this.dateRange = []; this.queryParams = { pageNum: 1, pageSize: 10, userName: undefined, deptId: undefined, }; this.getList(); }, handleSelectionChange(selection) { this.selectedSchedules = selection; }, openAddDialog() { this.dialogTitle = "新增排班"; this.open = true; }, handleEdit(row) { this.dialogTitle = "修改排班"; this.tempSchedule = { userIds: [row.userId], dates: [row.scheduleDate, row.scheduleDate], shiftType: row.shiftType, remark: row.remark, }; const user = this.allUserList.find((u) => u.userId === row.userId); this.selectedUsers = user ? [user] : []; this.open = true; }, handleViewDetail(row) { this.currentRow = row; this.detailOpen = true; }, openUserSelector() { this.userSelectorVisible = true; this.getUserList(); }, getUserList() { const params = { ...this.userQueryParams }; listUser(params).then((res) => { this.userList = res.rows || []; this.userTotal = res.total || 0; }); }, resetUserQuery() { this.userQueryParams = { pageNum: 1, pageSize: 10, userName: undefined, deptId: undefined, }; this.getUserList(); }, handleUserSelectionChange(selection) { this.selectedUserIds = selection.map((u) => u.userId); }, confirmSelectUsers() { const selected = this.userList.filter((u) => this.selectedUserIds.includes(u.userId) ); const existIds = new Set(this.selectedUsers.map((u) => u.userId)); const newUsers = selected.filter((u) => !existIds.has(u.userId)); this.selectedUsers.push(...newUsers); this.tempSchedule.userIds = this.selectedUsers.map((u) => u.userId); this.userSelectorVisible = false; this.$message.success(`已选择 ${newUsers.length} 名员工`); }, removeSelectedUser(user) { this.selectedUsers = this.selectedUsers.filter( (u) => u.userId !== user.userId ); this.tempSchedule.userIds = this.selectedUsers.map((u) => u.userId); }, submitSchedule() { if (!this.tempSchedule.userIds.length) { this.$message.warning("请至少选择一名员工"); return; } if (!this.tempSchedule.dates || this.tempSchedule.dates.length !== 2) { this.$message.warning("请选择完整的日期范围"); return; } this.submitLoading = true; const [start, end] = this.tempSchedule.dates; const scheduleData = []; const currentDate = new Date(start); const endDate = new Date(end); while (currentDate <= endDate) { const dateStr = this.formatDate(currentDate); this.tempSchedule.userIds.forEach((userId) => { const userData = this.allUserList.find((u) => u.userId === userId); if (!userData) return; // ✅ 转换为下划线命名以匹配后端字段 scheduleData.push({ userId: userId, deptId: userData.deptId, scheduleDate: dateStr, shiftType: this.tempSchedule.shiftType, remark: this.tempSchedule.remark, }); }); currentDate.setDate(currentDate.getDate() + 1); } // ❌ 错误写法:scheduleData.deptId → 应为数组元素的属性 console.log("提交数据:", scheduleData); // ✅ 正确打印 addSchedule(scheduleData) .then(() => { this.$message.success("排班创建成功"); this.open = false; this.getList(); }) .catch((err) => { console.error("排班创建失败", err); this.$message.error("保存失败,请检查网络或数据"); }) .finally(() => { this.submitLoading = false; }); }, handleDelete(row) { const ids = row ? [row.id] : this.selectedSchedules.map((s) => s.id); this.$confirm(`确认删除 ${ids.length} 条排班记录?`, "警告", { type: "warning", }).then(() => { delSchedule(ids).then(() => { this.$message.success("删除成功"); this.getList(); }); }); }, formatDate(date) { const d = new Date(date); const year = d.getFullYear(); const month = String(d.getMonth() + 1).padStart(2, "0"); const day = String(d.getDate()).padStart(2, "0"); return `${year}-${month}-${day}`; }, getShiftText(type) { return ( { morning: "早班", afternoon: "晚班", night: "夜班", off: "休息" }[ type ] || "未知" ); }, getShiftType(type) { return ( { morning: "success", afternoon: "warning", night: "danger", off: "info", }[type] || "" ); }, getAvatar(user) { if (user.avatar) return user.avatar; return `https://ui-avatars.com/api/?name=${encodeURIComponent( user.nickName || "用户" )}&background=5f67e8&color=fff&size=32`; }, resetDialogForm() { this.tempSchedule = { userIds: [], dates: [], shiftType: "morning", remark: "", }; this.selectedUsers = []; this.selectedUserIds = []; }, }, }; </script> <style scoped> ::v-deep .el-table th { background-color: #f5f7fa; font-weight: bold; } .mb8 { margin-bottom: 15px; } .dialog-footer { text-align: right; } .custom-avatar { width: 32px; height: 32px; line-height: 32px; font-size: 14px; } </style>
接口package com.ruoyi.web.controller.system;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.system.domain.IncidentRecords;
import com.ruoyi.system.domain.ScheduleRecord;
import com.ruoyi.system.mapper.ScheduleRecordMapper;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.ScheduleRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
员工排班记录控制器
*/
@RestController
@RequestMapping(“/system/schedule”)
public class ScheduleRecordController extends BaseController {
@Autowired
private ScheduleRecordMapper scheduleRecordMapper;
@Autowired
private ScheduleRecordService scheduleRecordService;
@Autowired
SysUserMapper userMapper;
@Autowired
SysDeptMapper deptMapper;
/**
查询排班列表(分页)
*/
@GetMapping(“/list”)
public TableDataInfo list(ScheduleRecord record) {
QueryWrapper queryWrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(record.getUserName())) {
// 关联查询用户表字段需自行处理,此处仅支持数据库字段模糊匹配
List userIdList =userMapper.selectUserIdByName(record.getUserName());
queryWrapper.in(“user_id”, userIdList);
}
if (record.getUserId() != null) {
queryWrapper.eq(“user_id”, record.getUserId());
}
if (record.getDeptId() != null) {
queryWrapper.eq(“dept_id”, record.getDeptId());
}
if (record.getShiftType() != null && !“”.equals(record.getShiftType())) {
queryWrapper.eq(“shift_type”, record.getShiftType());
}
if (record.getScheduleDate() != null) {
// 精确到天的查询(可扩展为范围)
queryWrapper.ge(“schedule_date”, record.getScheduleDate());
}
Page page = new Page<>(record.getPageNum(), record.getPageSize());
Page resultPage = scheduleRecordMapper.selectPage(page, queryWrapper);
for (ScheduleRecord userRecord : resultPage.getRecords()) {
SysUser sysUser = userMapper.selectUserById(userRecord.getUserId());
userRecord.setUserName(sysUser.getNickName());
SysDept sysDept = deptMapper.selectDeptById(userRecord.getDeptId());
userRecord.setDeptName(sysDept.getDeptName());
}
TableDataInfo tableDataInfo = new TableDataInfo();
tableDataInfo.setRows(resultPage.getRecords());
tableDataInfo.setTotal(resultPage.getTotal());
return tableDataInfo;
}
/**
获取所有排班数据(用于导出或下拉框)
*/
@GetMapping(“/all”)
@PreAuthorize(“@ss.hasPermi(‘schedule:list’)”)
public AjaxResult getAll(ScheduleRecord record) {
QueryWrapper wrapper = new QueryWrapper<>(record);
List list = scheduleRecordMapper.selectList(wrapper);
return AjaxResult.success(list);
}
/**
根据ID获取排班详情
*/
@GetMapping(“/{id}”)
@PreAuthorize(“@ss.hasPermi(‘schedule:query’)”)
public AjaxResult getInfo(@PathVariable Long id) {
ScheduleRecord record = scheduleRecordMapper.selectById(id);
if (record == null) {
return AjaxResult.error(“排班记录不存在”);
}
return AjaxResult.success(record);
}
/**
新增排班
*/
@PostMapping
@PreAuthorize(“@ss.hasPermi(‘schedule:add’)”)
public AjaxResult add(@RequestBody List records) {
if (records == null || records.isEmpty()) {
return AjaxResult.error(“提交数据为空”);
}
records.forEach(r -> {
r.setCreateTime(new java.util.Date());
r.setCreateBy(getUsername());
r.setUpdateTime(null);
r.setUpdateBy(null);
});
boolean success = scheduleRecordService.saveBatch(records);
return success ? AjaxResult.success(“新增成功”) : AjaxResult.error(“新增失败”);
}
/**
修改排班
*/
@PutMapping
@PreAuthorize(“@ss.hasPermi(‘schedule:edit’)”)
public AjaxResult edit(@RequestBody ScheduleRecord record) {
if (record.getId() == null) {
return AjaxResult.error(“ID不能为空”);
}
ScheduleRecord old = scheduleRecordMapper.selectById(record.getId());
if (old == null) {
return AjaxResult.error(“记录不存在,无法修改”);
}
record.setUpdateBy(getUsername());
record.setUpdateTime(new java.util.Date());
int result = scheduleRecordMapper.updateById(record);
return result > 0 ? AjaxResult.success(“修改成功”) : AjaxResult.error(“修改失败”);
}
/**
删除排班记录
*/
@DeleteMapping(“/{ids}”)
@PreAuthorize(“@ss.hasPermi(‘schedule:remove’)”)
public AjaxResult remove(@PathVariable Long[] ids) {
if (ids == null || ids.length == 0) {
return AjaxResult.error(“请选择要删除的数据”);
}
int count = 0;
for (Long id : ids) {
int del = scheduleRecordMapper.deleteById(id);
if (del > 0) count++;
}
return count > 0 ?
AjaxResult.success(“删除成功,共删除 " + count + " 条记录”) :
AjaxResult.error(“删除失败”);
}
/**
导出排班数据
*/
@GetMapping(“/export”)
@PreAuthorize(“@ss.hasPermi(‘schedule:export’)”)
public AjaxResult export(ScheduleRecord record) {
QueryWrapper queryWrapper = new QueryWrapper<>(record);
List list = scheduleRecordMapper.selectList(queryWrapper);
ExcelUtil util = new ExcelUtil<>(ScheduleRecord.class);
return util.exportExcel(list, “排班数据”);
}
}
js文件import request from ‘@/utils/request’
export function listSchedule(params) {
return request({
url: ‘/system/schedule/list’,
method: ‘get’,
params
})
}
export function addSchedule(data) {
return request({
url: ‘/system/schedule’,
method: ‘post’,
data
})
}
export function updateSchedule(data) {
return request({
url: ‘/system/schedule’,
method: ‘put’,
data
})
}
export function delSchedule(id) {
return request({
url: /system/schedule/${id},
method: ‘delete’
})
}
路由import Vue from ‘vue’
import Router from ‘vue-router’
Vue.use(Router)
/* Layout */
import Layout from ‘@/layout’
/**
注意:路由配置说明
hidden: true // 设为 true 则不在侧边栏显示(如登录页、404)
alwaysShow: true // 子路由数量 >= 2 时默认嵌套展示;设为 true 强制显示根菜单
redirect: noRedirect // 面包屑不可点击
name: ‘router-name’ // 必须唯一,用于 缓存
meta: {
title: ‘标题’, // 菜单和面包屑显示的文字
icon: ‘svg-icon-name’, // 图标名(对应 src/assets/icons/svg 下的 SVG 文件)
noCache: true, // 设为 true 不会被 keep-alive 缓存
breadcrumb: false // 设为 false 不在面包屑中显示
activeMenu: ‘/path/to/menu’ // 当前页面高亮指定菜单
}
*/
// 公共路由
export const constantRoutes = [
{
path: ‘/redirect’,
component: Layout,
hidden: true,
children: [
{
path: ‘/redirect/:path(.*)’,
component: () => import(‘@/views/redirect’)
}
]
},
{
path: ‘/login’,
component: () => import(‘@/views/login’),
hidden: true
},
{
path: ‘/register’,
component: () => import(‘@/views/register’),
hidden: true
},
{
path: ‘/404’,
component: () => import(‘@/views/error/404’),
hidden: true
},
{
path: ‘/401’,
component: () => import(‘@/views/error/401’),
hidden: true
},
{
path: ‘’,
component: Layout,
redirect: ‘index’,
children: [
{
path: ‘index’,
component: () => import(‘@/views/index’),
name: ‘Index’,
meta: { title: ‘首页’, icon: ‘dashboard’, affix: true }
}
]
},
{
path: ‘/user’,
component: Layout,
hidden: true,
redirect: ‘noredirect’,
children: [
{
path: ‘profile’,
component: () => import(‘@/views/system/user/profile/index’),
name: ‘Profile’,
meta: { title: ‘个人中心’, icon: ‘user’ }
}
]
},
{
path: ‘/system/elderly’,
component: Layout,
hidden: true,
children: [
{
path: ‘index’,
component: () => import(‘@/views/system/elderly/index’),
name: ‘elderly’,
meta: { title: ‘收费管理’, activeMenu: ‘/system/elderly’ }
}
]
},
{
path: ‘/system/bed’,
component: Layout,
hidden: true,
children: [
{
path: ‘index’,
component: () => import(‘@/views/system/bed/index’),
name: ‘bed’,
meta: { title: ‘收费管理’, activeMenu: ‘/system/bed’ }
}
]
},
{
path: ‘/system/bill’,
component: Layout,
hidden: true,
children: [
{
path: ‘index’,
component: () => import(‘@/views/system/bill/index’),
name: ‘bill’,
meta: { title: ‘收费管理’, activeMenu: ‘/system/bill’ }
}
]
},
{
path: ‘/system/feeItem’,
component: Layout,
hidden: true,
children: [
{
path: ‘index’,
component: () => import(‘@/views/system/feeItem/index’),
name: ‘feeItem’,
meta: { title: ‘收费管理’, activeMenu: ‘/system/feeItem’ }
}
]
},
{
path: ‘/system/health’,
component: Layout,
hidden: true,
children: [
{
path: ‘index’,
component: () => import(‘@/views/system/health/index’),
name: ‘health’,
meta: { title: ‘健康记录管理’, activeMenu: ‘/system/health’ }
}
]
},
{
path: ‘/system/care’,
component: Layout,
hidden: true,
children: [
{
path: ‘index’,
component: () => import(‘@/views/system/care/index’),
name: ‘care’,
meta: { title: ‘事故记录管理’, activeMenu: ‘/system/care’ }
}
]
},
{
path: ‘/system/incident’,
component: Layout,
hidden: true,
children: [
{
path: ‘index’,
component: () => import(‘@/views/system/incident/index’),
name: ‘incident’,
meta: { title: ‘事故记录管理’, activeMenu: ‘/system/incident’ }
}
]
},
{
path: ‘/system/schedule’,
component: Layout,
hidden: true,
children: [
{
path: ‘index’,
component: () => import(‘@/views/system/schedule/index’),
name: ‘schedule’,
meta: { title: ‘排班管理’, activeMenu: ‘/system/schedule’ }
}
]
},
// 可继续添加其他模块…
]
// 动态路由(权限相关)
export const dynamicRoutes = [
{
path: ‘/system/user-auth’,
component: Layout,
hidden: true,
permissions: [‘system:user:edit’],
children: [
{
path: ‘role/:userId(\d+)’,
component: () => import(‘@/views/system/user/authRole’),
name: ‘AuthRole’,
meta: { title: ‘分配角色’, activeMenu: ‘/system/user’ }
}
]
},
{
path: ‘/system/role-auth’,
component: Layout,
hidden: true,
permissions: [‘system:role:edit’],
children: [
{
path: ‘user/:roleId(\d+)’,
component: () => import(‘@/views/system/role/authUser’),
name: ‘AuthUser’,
meta: { title: ‘分配用户’, activeMenu: ‘/system/role’ }
}
]
},
{
path: ‘/system/dict-data’,
component: Layout,
hidden: true,
permissions: [‘system:dict:list’],
children: [
{
path: ‘index/:dictId(\d+)’,
component: () => import(‘@/views/system/dict/data’),
name: ‘Data’,
meta: { title: ‘字典数据’, activeMenu: ‘/system/dict’ }
}
]
}
]
// 解决重复点击相同路由报错的问题
let routerPush = Router.prototype.push
let routerReplace = Router.prototype.replace
Router.prototype.push = function push(location) {
return routerPush.call(this, location).catch(err => err)
}
Router.prototype.replace = function replace(location) {
return routerReplace.call(this, location).catch(err => err)
}
export default new Router({
mode: ‘history’, // 去掉 URL 中的 #
scrollBehavior: () => ({ y: 0 }),
routes: constantRoutes
})
不设置权限字符,要求这个页面所有人可访问可操作,但提示无权限