feat: 管理员代工模式 — 前端权限放开 + 后端审计留痕

前端:
  - WorkspaceArea 新增 currentUserRole prop
  - isAssignee/canRecall: SUPER_ADMIN/SUPERVISOR 上帝视角直接放行
  - 管理员代操作时显示黄色提示条: 正在以管理员身份代[原负责人]操作
  - detail.vue: loadCurrentUser 提取并保存 user.role

后端:
  - _create_task_log 新增 task_assignee_id 参数
  - operator_id!=task_assignee_id 时自动拼接 [管理员xx代办操作]
  - 12处调用点全部传入 task_assignee_id
  - receive_task 位置赋值确认为 task.assignee_id(非 operator_id)
This commit is contained in:
2026-08-12 15:24:50 +08:00
parent 49cbf22854
commit 1fdc607c07
3 changed files with 47 additions and 9 deletions

View File

@ -78,6 +78,9 @@
<view class="fc-time">{{ formatTaskTime(lockedTask) }}</view>
</view>
<view v-if="isAdminProxy" class="admin-proxy-notice">
<text class="proxy-text"> 正在以管理员身份代 [{{ formatUserName(lockedTask.assignee_id) || lockedTask.assignee_id }}] 操作</text>
</view>
<view v-if="isAssignee" class="footer-actions">
<button v-if="lockedTask.status === 'WIP'" class="footer-btn footer-transfer"
@tap="$emit('action', { task: lockedTask, type: 'transfer' })"><text class="btn-icon">🔄</text><text class="btn-txt">完工转交</text></button>
@ -111,6 +114,7 @@ export default {
product: { type: Object, default: null },
currentUserId: { type: String, default: "" },
currentUsername: { type: String, default: "" },
currentUserRole: { type: String, default: "" },
initialLockTaskId: { type: String, default: "" },
},
emits: ["action", "viewRecords"],
@ -162,9 +166,22 @@ export default {
return result;
},
lockedTask() { return this.focusTasks.find(t => t.id === this.lockedTaskId) || null; },
isAssignee() { if (!this.lockedTask) return false; return this.lockedTask.assignee_id == this.currentUserId || this.lockedTask.assignee_id == this.currentUsername; },
isAdmin() { return this.currentUserRole === 'SUPER_ADMIN' || this.currentUserRole === 'SUPERVISOR'; },
isAssignee() {
if (!this.lockedTask) return false;
if (this.isAdmin) return true; // 管理员上帝视角
return this.lockedTask.assignee_id == this.currentUserId
|| this.lockedTask.assignee_id == this.currentUsername;
},
isAdminProxy() {
// 管理员正在代操作非本人任务
return this.isAdmin && this.lockedTask
&& this.lockedTask.assignee_id != this.currentUserId
&& this.lockedTask.assignee_id != this.currentUsername;
},
canRecall() {
if (!this.lockedTask || this.lockedTask.status !== 'PENDING') return false;
if (this.isAdmin) return true; // 管理员可撤回任何转交
if (this.isAssignee) return false;
if (!this.lockedTask.parent_task_id) return false;
const parent = this.taskMap[this.lockedTask.parent_task_id];
@ -281,6 +298,8 @@ export default {
.btn-icon { font-size: 36rpx; margin-bottom: 6rpx; }
.btn-txt { font-size: 24rpx; font-weight: 700; }
.footer-readonly { justify-content: center; background: #fef2f2; }
.admin-proxy-notice { padding: 10rpx 20rpx; background: #fef9e7; border-top: 2rpx solid #fde68a; flex-shrink: 0; }
.proxy-text { font-size: 22rpx; color: #b45309; font-weight: 600; }
.readonly-hint { font-size: 24rpx; color: #dc2626; font-weight: 600; }
.footer-transfer { background: #dcfce7; color: #16a34a; }
.footer-record { background: #eff6ff; color: #2563eb; }