权限: receive/reject校验assignee_id匹配 + 前端myActiveTask只显示本人任务 + 403处理

This commit is contained in:
2026-08-05 16:21:27 +08:00
parent 62422e7558
commit 71e8eeb7e8
3 changed files with 51 additions and 16 deletions

View File

@ -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);

View File

@ -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);