feat: add realtime attendance and monthly payroll menus

This commit is contained in:
焦龙言 2026-06-18 14:26:14 +08:00
parent a846ea5070
commit dc74a618f7
5 changed files with 136 additions and 1 deletions

View File

@ -12,6 +12,12 @@ PERMISSION_PAYROLL_EXCEL_CALCULATE = "payroll:excel:calculate"
PERMISSION_PAYROLL_DINGTALK_CALCULATE = "payroll:dingtalk:calculate" PERMISSION_PAYROLL_DINGTALK_CALCULATE = "payroll:dingtalk:calculate"
PERMISSION_PAYROLL_JOB_VIEW = "payroll:job:view" PERMISSION_PAYROLL_JOB_VIEW = "payroll:job:view"
PERMISSION_PAYROLL_FILE_DOWNLOAD = "payroll:file:download" PERMISSION_PAYROLL_FILE_DOWNLOAD = "payroll:file:download"
PERMISSION_ATTENDANCE_REALTIME_VIEW = "attendance:realtime:view"
PERMISSION_ATTENDANCE_REALTIME_SYNC = "attendance:realtime:sync"
PERMISSION_MONTHLY_PAYROLL_VIEW = "monthly_payroll:view"
PERMISSION_MONTHLY_PAYROLL_CALCULATE = "monthly_payroll:calculate"
PERMISSION_MONTHLY_PAYROLL_LOCK = "monthly_payroll:lock"
PERMISSION_MONTHLY_PAYROLL_EXPORT = "monthly_payroll:export"
PERMISSION_USER_CREATE = "user:create" PERMISSION_USER_CREATE = "user:create"
PERMISSION_USER_LIST = "user:list" PERMISSION_USER_LIST = "user:list"
PERMISSION_OPERATION_LOG_VIEW = "operation_log:view" PERMISSION_OPERATION_LOG_VIEW = "operation_log:view"
@ -38,6 +44,8 @@ class MenuPermission:
MENUS = { MENUS = {
"attendance_realtime": MenuPermission(code="attendance_realtime", name="实时考勤", path="/attendance/realtime"),
"monthly_payroll": MenuPermission(code="monthly_payroll", name="月度核算", path="/payroll/monthly"),
"payroll": MenuPermission(code="payroll", name="工资计算", path="/payroll"), "payroll": MenuPermission(code="payroll", name="工资计算", path="/payroll"),
"jobs": MenuPermission(code="jobs", name="计算记录", path="/payroll/jobs"), "jobs": MenuPermission(code="jobs", name="计算记录", path="/payroll/jobs"),
"employees": MenuPermission(code="employees", name="员工维护", path="/system/employees"), "employees": MenuPermission(code="employees", name="员工维护", path="/system/employees"),
@ -52,6 +60,8 @@ MENUS = {
ROLE_MENU_CODES = { ROLE_MENU_CODES = {
ROLE_SUPERUSER: ( ROLE_SUPERUSER: (
"attendance_realtime",
"monthly_payroll",
"payroll", "payroll",
"jobs", "jobs",
"employees", "employees",
@ -64,6 +74,8 @@ ROLE_MENU_CODES = {
"operation_logs", "operation_logs",
), ),
ROLE_MANAGER: ( ROLE_MANAGER: (
"attendance_realtime",
"monthly_payroll",
"payroll", "payroll",
"jobs", "jobs",
"employees", "employees",
@ -74,11 +86,17 @@ ROLE_MENU_CODES = {
"configs", "configs",
"operation_logs", "operation_logs",
), ),
ROLE_VIEWER: ("jobs", "reports"), ROLE_VIEWER: ("attendance_realtime", "jobs", "reports"),
} }
ROLE_OPERATION_PERMISSIONS = { ROLE_OPERATION_PERMISSIONS = {
ROLE_SUPERUSER: ( ROLE_SUPERUSER: (
PERMISSION_ATTENDANCE_REALTIME_VIEW,
PERMISSION_ATTENDANCE_REALTIME_SYNC,
PERMISSION_MONTHLY_PAYROLL_VIEW,
PERMISSION_MONTHLY_PAYROLL_CALCULATE,
PERMISSION_MONTHLY_PAYROLL_LOCK,
PERMISSION_MONTHLY_PAYROLL_EXPORT,
PERMISSION_PAYROLL_EXCEL_CALCULATE, PERMISSION_PAYROLL_EXCEL_CALCULATE,
PERMISSION_PAYROLL_DINGTALK_CALCULATE, PERMISSION_PAYROLL_DINGTALK_CALCULATE,
PERMISSION_PAYROLL_JOB_VIEW, PERMISSION_PAYROLL_JOB_VIEW,
@ -99,6 +117,12 @@ ROLE_OPERATION_PERMISSIONS = {
PERMISSION_REPORT_VIEW, PERMISSION_REPORT_VIEW,
), ),
ROLE_MANAGER: ( ROLE_MANAGER: (
PERMISSION_ATTENDANCE_REALTIME_VIEW,
PERMISSION_ATTENDANCE_REALTIME_SYNC,
PERMISSION_MONTHLY_PAYROLL_VIEW,
PERMISSION_MONTHLY_PAYROLL_CALCULATE,
PERMISSION_MONTHLY_PAYROLL_LOCK,
PERMISSION_MONTHLY_PAYROLL_EXPORT,
PERMISSION_PAYROLL_EXCEL_CALCULATE, PERMISSION_PAYROLL_EXCEL_CALCULATE,
PERMISSION_PAYROLL_DINGTALK_CALCULATE, PERMISSION_PAYROLL_DINGTALK_CALCULATE,
PERMISSION_PAYROLL_JOB_VIEW, PERMISSION_PAYROLL_JOB_VIEW,
@ -117,6 +141,7 @@ ROLE_OPERATION_PERMISSIONS = {
PERMISSION_REPORT_VIEW, PERMISSION_REPORT_VIEW,
), ),
ROLE_VIEWER: ( ROLE_VIEWER: (
PERMISSION_ATTENDANCE_REALTIME_VIEW,
PERMISSION_PAYROLL_JOB_VIEW, PERMISSION_PAYROLL_JOB_VIEW,
PERMISSION_PAYROLL_FILE_DOWNLOAD, PERMISSION_PAYROLL_FILE_DOWNLOAD,
PERMISSION_REPORT_VIEW, PERMISSION_REPORT_VIEW,

View File

@ -3,6 +3,8 @@ import {
Banknote, Banknote,
BadgeDollarSign, BadgeDollarSign,
Building2, Building2,
Calculator,
CalendarClock,
ClipboardList, ClipboardList,
FileChartColumn, FileChartColumn,
LayoutDashboard, LayoutDashboard,
@ -35,6 +37,8 @@ const auth = useAuthStore();
const router = useRouter(); const router = useRouter();
const backendIconMap = { const backendIconMap = {
attendance_realtime: CalendarClock,
monthly_payroll: Calculator,
payroll: Banknote, payroll: Banknote,
jobs: ClipboardList, jobs: ClipboardList,
employees: UserCog, employees: UserCog,

View File

@ -8,9 +8,11 @@ import DashboardView from "../views/DashboardView.vue";
import EmployeesView from "../views/EmployeesView.vue"; import EmployeesView from "../views/EmployeesView.vue";
import JobsView from "../views/JobsView.vue"; import JobsView from "../views/JobsView.vue";
import LoginView from "../views/LoginView.vue"; import LoginView from "../views/LoginView.vue";
import MonthlyPayrollView from "../views/MonthlyPayrollView.vue";
import OperationLogsView from "../views/OperationLogsView.vue"; import OperationLogsView from "../views/OperationLogsView.vue";
import OrganizationView from "../views/OrganizationView.vue"; import OrganizationView from "../views/OrganizationView.vue";
import PayrollView from "../views/PayrollView.vue"; import PayrollView from "../views/PayrollView.vue";
import RealtimeAttendanceView from "../views/RealtimeAttendanceView.vue";
import ReportsView from "../views/ReportsView.vue"; import ReportsView from "../views/ReportsView.vue";
import SalaryProfilesView from "../views/SalaryProfilesView.vue"; import SalaryProfilesView from "../views/SalaryProfilesView.vue";
import UsersView from "../views/UsersView.vue"; import UsersView from "../views/UsersView.vue";
@ -44,6 +46,18 @@ const router = createRouter({
name: "dashboard", name: "dashboard",
component: DashboardView, component: DashboardView,
}, },
{
path: "attendance/realtime",
name: "attendance-realtime",
component: RealtimeAttendanceView,
meta: { permission: "attendance:realtime:view" },
},
{
path: "payroll/monthly",
name: "monthly-payroll",
component: MonthlyPayrollView,
meta: { permission: "monthly_payroll:view" },
},
{ {
path: "payroll", path: "payroll",
name: "payroll", name: "payroll",
@ -137,6 +151,12 @@ router.beforeEach(async (to) => {
}); });
function firstAllowedPath(permissions: string[]): string { function firstAllowedPath(permissions: string[]): string {
if (permissions.includes("attendance:realtime:view")) {
return "/attendance/realtime";
}
if (permissions.includes("monthly_payroll:view")) {
return "/payroll/monthly";
}
if (permissions.includes("payroll:excel:calculate")) { if (permissions.includes("payroll:excel:calculate")) {
return "/payroll"; return "/payroll";
} }

View File

@ -0,0 +1,48 @@
<script setup lang="ts">
import { Calculator, FileSpreadsheet, LockKeyhole, Upload } from "@lucide/vue";
</script>
<template>
<div class="view-stack">
<header class="page-header">
<div>
<h1>月度核算</h1>
<p>按工资月份完成导入计算复核锁定和导出</p>
</div>
<div class="header-actions">
<button class="secondary-button" type="button" disabled>
<Upload :size="18" aria-hidden="true" />
<span>导入 Excel</span>
</button>
<button class="primary-button" type="button" disabled>
<Calculator :size="18" aria-hidden="true" />
<span>同步并计算</span>
</button>
</div>
</header>
<section class="panel">
<div class="panel-header">
<div>
<h2>核算流程</h2>
<p>数据导入 -> 考勤转换 -> 异常处理 -> 工资计算 -> 复核锁定</p>
</div>
<span class="status-chip neutral">草稿</span>
</div>
<div class="empty-state">
<FileSpreadsheet :size="38" aria-hidden="true" />
<p>月度核算中心已接入菜单下一阶段接入月度计算异常清单和锁定逻辑</p>
</div>
</section>
<section class="panel">
<div class="panel-header">
<div>
<h2>锁定规则</h2>
<p>锁定后本月工资不可重新计算仅允许导出</p>
</div>
<LockKeyhole :size="22" aria-hidden="true" />
</div>
</section>
</div>
</template>

View File

@ -0,0 +1,38 @@
<script setup lang="ts">
import { CalendarClock, CloudCog, RefreshCw } from "@lucide/vue";
</script>
<template>
<div class="view-stack">
<header class="page-header">
<div>
<h1>实时考勤</h1>
<p>查看今日打卡状态并预估本月薪资进度</p>
</div>
<div class="header-actions">
<button class="secondary-button" type="button" disabled>
<RefreshCw :size="18" aria-hidden="true" />
<span>刷新</span>
</button>
<button class="primary-button" type="button" disabled>
<CloudCog :size="18" aria-hidden="true" />
<span>同步钉钉</span>
</button>
</div>
</header>
<section class="panel">
<div class="panel-header">
<div>
<h2>今日考勤与薪资预估</h2>
<p>预估金额最终以月度核算锁定结果为准</p>
</div>
<span class="status-chip neutral">待接入</span>
</div>
<div class="empty-state">
<CalendarClock :size="38" aria-hidden="true" />
<p>实时考勤看板已接入菜单下一阶段接入钉钉同步和薪资预估数据</p>
</div>
</section>
</div>
</template>