权限: receive/reject校验assignee_id匹配 + 前端myActiveTask只显示本人任务 + 403处理
This commit is contained in:
@ -238,12 +238,16 @@ async def receive_task(
|
||||
"""
|
||||
task = await _get_task_or_404(db, task_id)
|
||||
|
||||
# 权限校验:只有负责人本人可接收
|
||||
if operator_id and task.assignee_id and operator_id != task.assignee_id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=f"您无权操作此任务,当前任务负责人为 {task.assignee_id}",
|
||||
)
|
||||
|
||||
# 校验:只有 PENDING 状态可接收
|
||||
if task.status != TASK_STATUS_PENDING:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"只有待接收(PENDING)状态的任务可接收,当前状态: {task.status}",
|
||||
)
|
||||
|
||||
now = get_beijing_time()
|
||||
task.status = TASK_STATUS_WIP
|
||||
@ -284,6 +288,13 @@ async def reject_task(
|
||||
"""
|
||||
task = await _get_task_or_404(db, task_id)
|
||||
|
||||
# 权限校验:只有负责人本人可驳回
|
||||
if operator_id and task.assignee_id and operator_id != task.assignee_id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail=f"您无权操作此任务,当前任务负责人为 {task.assignee_id}",
|
||||
)
|
||||
|
||||
# 校验:不能重复驳回已完成/已驳回的任务
|
||||
if task.status in (TASK_STATUS_COMPLETED, TASK_STATUS_REJECTED):
|
||||
raise HTTPException(
|
||||
|
||||
@ -90,21 +90,21 @@
|
||||
<!-- ================================================================ -->
|
||||
<!-- 底部操作栏(钉死,不随滚动) -->
|
||||
<!-- ================================================================ -->
|
||||
<view v-if="activeTask" class="footer-actions">
|
||||
<button v-if="activeTask.status === 'WIP'" class="footer-btn footer-transfer"
|
||||
@tap="handleTaskAction({ task: activeTask, type: 'transfer' })">
|
||||
<view v-if="myActiveTask" class="footer-actions">
|
||||
<button v-if="myActiveTask.status === 'WIP'" class="footer-btn footer-transfer"
|
||||
@tap="handleTaskAction({ task: myActiveTask, type: 'transfer' })">
|
||||
🔄 完工转交
|
||||
</button>
|
||||
<button v-if="activeTask.status === 'WIP'" class="footer-btn footer-record"
|
||||
@tap="handleTaskAction({ task: activeTask, type: 'record' })">
|
||||
<button v-if="myActiveTask.status === 'WIP'" class="footer-btn footer-record"
|
||||
@tap="handleTaskAction({ task: myActiveTask, type: 'record' })">
|
||||
📝 记录/拍照
|
||||
</button>
|
||||
<button v-if="activeTask.status === 'PENDING'" class="footer-btn footer-receive"
|
||||
@tap="handleTaskAction({ task: activeTask, type: 'receive' })">
|
||||
<button v-if="myActiveTask.status === 'PENDING'" class="footer-btn footer-receive"
|
||||
@tap="handleTaskAction({ task: myActiveTask, type: 'receive' })">
|
||||
✅ 接收任务
|
||||
</button>
|
||||
<button v-if="activeTask.status === 'PENDING'" class="footer-btn footer-reject"
|
||||
@tap="handleTaskAction({ task: activeTask, type: 'reject' })">
|
||||
<button v-if="myActiveTask.status === 'PENDING'" class="footer-btn footer-reject"
|
||||
@tap="handleTaskAction({ task: myActiveTask, type: 'reject' })">
|
||||
❌ 驳回任务
|
||||
</button>
|
||||
</view>
|
||||
@ -379,7 +379,7 @@ export default {
|
||||
});
|
||||
},
|
||||
activeTask() {
|
||||
// 查找树中第一个 WIP 或 PENDING 任务作为底部 Footer 的操作目标
|
||||
// 查找树中第一个 WIP 或 PENDING 任务(不限归属)
|
||||
const findActive = (tasks) => {
|
||||
if (!tasks) return null;
|
||||
for (const t of tasks) {
|
||||
@ -393,6 +393,24 @@ export default {
|
||||
};
|
||||
return this.product ? findActive(this.product.task_tree) : null;
|
||||
},
|
||||
myActiveTask() {
|
||||
// 只返回当前登录人自己的 WIP/PENDING 任务
|
||||
const findMine = (tasks) => {
|
||||
if (!tasks) return null;
|
||||
for (const t of tasks) {
|
||||
const isMine = t.status === 'WIP' || t.status === 'PENDING';
|
||||
const matchId = t.assignee_id == this.currentUserId;
|
||||
const matchName = t.assignee_id == this.currentUsername;
|
||||
if (isMine && (matchId || matchName)) return t;
|
||||
if (t.child_tasks && t.child_tasks.length) {
|
||||
const found = findMine(t.child_tasks);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
return this.product ? findMine(this.product.task_tree) : null;
|
||||
},
|
||||
},
|
||||
onLoad(options) {
|
||||
this.loadUsers();
|
||||
@ -516,7 +534,8 @@ export default {
|
||||
// 场景B: 立即接收
|
||||
if (this.firstForm.autoReceive) {
|
||||
try {
|
||||
await post(`/tasks/${task.id}/receive`);
|
||||
const opId = this.currentUsername || this.currentUserId;
|
||||
await post(`/tasks/${task.id}/receive?operator_id=${encodeURIComponent(opId)}`);
|
||||
} catch { /* receive 失败不影响流程 */ }
|
||||
}
|
||||
uni.showToast({
|
||||
@ -696,7 +715,8 @@ export default {
|
||||
this.actionLoading = true;
|
||||
try {
|
||||
const remark = this.receiveRemark.trim() || undefined;
|
||||
await post(`/tasks/${this.actionPopup.task.id}/receive`, { remark });
|
||||
const opId = this.currentUsername || this.currentUserId;
|
||||
await post(`/tasks/${this.actionPopup.task.id}/receive?operator_id=${encodeURIComponent(opId)}`, { remark });
|
||||
uni.showToast({ title: "已接收", icon: "success" });
|
||||
this.closeActionPopup();
|
||||
this.doQuery(this.product.serial_number);
|
||||
@ -705,7 +725,8 @@ export default {
|
||||
async doReject() {
|
||||
this.actionLoading = true;
|
||||
try {
|
||||
await post(`/tasks/${this.actionPopup.task.id}/reject`, { reason: this.rejectReason.trim() });
|
||||
const opId = this.currentUsername || this.currentUserId;
|
||||
await post(`/tasks/${this.actionPopup.task.id}/reject?operator_id=${encodeURIComponent(opId)}`, { reason: this.rejectReason.trim() });
|
||||
uni.showToast({ title: "已驳回,返工任务已创建", icon: "success" });
|
||||
this.closeActionPopup();
|
||||
this.doQuery(this.product.serial_number);
|
||||
|
||||
@ -30,6 +30,9 @@ export default function request(options) {
|
||||
uni.showToast({ title: "登录已过期,请重新登录", icon: "none" });
|
||||
setTimeout(() => uni.reLaunch({ url: "/pages/login/login" }), 1000);
|
||||
reject(res);
|
||||
} else if (code === 403) {
|
||||
uni.showToast({ title: res.data?.detail || "无权操作", icon: "none", duration: 3000 });
|
||||
reject(res);
|
||||
} else if (code === 400) {
|
||||
uni.showToast({ title: res.data?.detail || "请求参数有误", icon: "none", duration: 2500 });
|
||||
reject(res);
|
||||
|
||||
Reference in New Issue
Block a user