权限隔离+2D蓝图修复: isAssignee按钮显隐+只读提示+分支标签(badge-main/sub)+并行同Y确认
This commit is contained in:
@ -24,7 +24,7 @@
|
|||||||
@tap="node.records && node.records.length && $emit('viewRecords', node)">
|
@tap="node.records && node.records.length && $emit('viewRecords', node)">
|
||||||
|
|
||||||
<view class="cn-header">
|
<view class="cn-header">
|
||||||
<text class="cn-name">{{ node.task_name }}</text>
|
<text :class="node.parent_task_id ? 'badge-sub' : 'badge-main'">{{ node.parent_task_id ? branchLabelMap[node.id] || '分支' : '主分支' }}</text>
|
||||||
<text :class="['cn-badge', statusColor(node.status)]">{{ statusLabel(node.status) }}</text>
|
<text :class="['cn-badge', statusColor(node.status)]">{{ statusLabel(node.status) }}</text>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
@ -106,6 +106,23 @@ export default {
|
|||||||
if (this.product) walk(this.product.task_tree);
|
if (this.product) walk(this.product.task_tree);
|
||||||
return map;
|
return map;
|
||||||
},
|
},
|
||||||
|
branchLabelMap() {
|
||||||
|
const map = {};
|
||||||
|
const traverse = (tasks, prefix) => {
|
||||||
|
if (!tasks) return;
|
||||||
|
tasks.forEach((t, i) => {
|
||||||
|
map[t.id] = prefix ? `分支 ${prefix}${i + 1}` : '分支 1';
|
||||||
|
traverse(t.child_tasks, prefix ? `${prefix}${i + 1}.` : `${i + 1}.`);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
if (this.product && this.product.task_tree) {
|
||||||
|
this.product.task_tree.forEach((t, i) => {
|
||||||
|
map[t.id] = '主分支';
|
||||||
|
traverse(t.child_tasks, `${i + 1}.`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
},
|
||||||
canvasWidth() { if (!this.treeNodes.length) return 400; return Math.max(800, Math.max(...this.treeNodes.map(n => n.x)) + 300); },
|
canvasWidth() { if (!this.treeNodes.length) return 400; return Math.max(800, Math.max(...this.treeNodes.map(n => n.x)) + 300); },
|
||||||
canvasHeight() { if (!this.treeNodes.length) return 400; return Math.max(800, Math.max(...this.treeNodes.map(n => n.y)) + 300); }
|
canvasHeight() { if (!this.treeNodes.length) return 400; return Math.max(800, Math.max(...this.treeNodes.map(n => n.y)) + 300); }
|
||||||
},
|
},
|
||||||
@ -145,6 +162,8 @@ export default {
|
|||||||
.canvas-node.s-green { border-left-color: #22c55e; }
|
.canvas-node.s-green { border-left-color: #22c55e; }
|
||||||
.canvas-node.s-red { border-left-color: #ef4444; }
|
.canvas-node.s-red { border-left-color: #ef4444; }
|
||||||
.cn-header { display: flex; align-items: center; justify-content: space-between; }
|
.cn-header { display: flex; align-items: center; justify-content: space-between; }
|
||||||
|
.badge-main { font-size: 10px; padding: 2px 8px; border-radius: 6px; background: #2563eb; color: #fff; font-weight: 700; }
|
||||||
|
.badge-sub { font-size: 10px; padding: 2px 8px; border-radius: 6px; background: #ede9fe; color: #7c3aed; font-weight: 700; }
|
||||||
.cn-name { font-size: 24px; font-weight: 800; color: #1f2937; }
|
.cn-name { font-size: 24px; font-weight: 800; color: #1f2937; }
|
||||||
.cn-badge { font-size: 14px; padding: 4px 12px; border-radius: 8px; font-weight: 700; }
|
.cn-badge { font-size: 14px; padding: 4px 12px; border-radius: 8px; font-weight: 700; }
|
||||||
.cn-badge.s-yellow { background: #fef3c7; color: #b45309; }
|
.cn-badge.s-yellow { background: #fef3c7; color: #b45309; }
|
||||||
|
|||||||
@ -78,7 +78,7 @@
|
|||||||
<view class="fc-time">{{ formatTaskTime(lockedTask) }}</view>
|
<view class="fc-time">{{ formatTaskTime(lockedTask) }}</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="footer-actions">
|
<view v-if="isAssignee" class="footer-actions">
|
||||||
<button v-if="lockedTask.status === 'WIP'" class="footer-btn footer-transfer"
|
<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>
|
@tap="$emit('action', { task: lockedTask, type: 'transfer' })"><text class="btn-icon">🔄</text><text class="btn-txt">完工转交</text></button>
|
||||||
<button v-if="lockedTask.status === 'WIP'" class="footer-btn footer-record"
|
<button v-if="lockedTask.status === 'WIP'" class="footer-btn footer-record"
|
||||||
@ -90,6 +90,9 @@
|
|||||||
<button v-if="lockedTask.status === 'PENDING'" class="footer-btn footer-reject"
|
<button v-if="lockedTask.status === 'PENDING'" class="footer-btn footer-reject"
|
||||||
@tap="$emit('action', { task: lockedTask, type: 'reject' })"><text class="btn-icon">❌</text><text class="btn-txt">驳回任务</text></button>
|
@tap="$emit('action', { task: lockedTask, type: 'reject' })"><text class="btn-icon">❌</text><text class="btn-txt">驳回任务</text></button>
|
||||||
</view>
|
</view>
|
||||||
|
<view v-else class="footer-actions footer-readonly">
|
||||||
|
<text class="readonly-hint">🔒 非当前任务指派人,仅可查看</text>
|
||||||
|
</view>
|
||||||
</template>
|
</template>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
@ -128,6 +131,7 @@ export default {
|
|||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
lockedTask() { return this.focusTasks.find(t => t.id === this.lockedTaskId) || null; },
|
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; },
|
||||||
branchLabelsMap() {
|
branchLabelsMap() {
|
||||||
const map = {};
|
const map = {};
|
||||||
if (!this.product || !this.product.task_tree) return map;
|
if (!this.product || !this.product.task_tree) return map;
|
||||||
@ -211,6 +215,8 @@ export default {
|
|||||||
.footer-btn::after { border: none; }
|
.footer-btn::after { border: none; }
|
||||||
.btn-icon { font-size: 36rpx; margin-bottom: 6rpx; }
|
.btn-icon { font-size: 36rpx; margin-bottom: 6rpx; }
|
||||||
.btn-txt { font-size: 24rpx; font-weight: 700; }
|
.btn-txt { font-size: 24rpx; font-weight: 700; }
|
||||||
|
.footer-readonly { justify-content: center; background: #fef2f2; }
|
||||||
|
.readonly-hint { font-size: 24rpx; color: #dc2626; font-weight: 600; }
|
||||||
.footer-transfer { background: #dcfce7; color: #16a34a; }
|
.footer-transfer { background: #dcfce7; color: #16a34a; }
|
||||||
.footer-record { background: #eff6ff; color: #2563eb; }
|
.footer-record { background: #eff6ff; color: #2563eb; }
|
||||||
.footer-receive { background: #dbeafe; color: #1d4ed8; }
|
.footer-receive { background: #dbeafe; color: #1d4ed8; }
|
||||||
|
|||||||
Reference in New Issue
Block a user