perf: 支持管理自己创建的标签

This commit is contained in:
kuaifan 2025-07-08 06:50:43 +08:00
parent 074ccc8aab
commit a15b29122e
7 changed files with 59 additions and 19 deletions

View File

@ -3032,11 +3032,14 @@ class ProjectController extends AbstractController
'color' => $color, 'color' => $color,
'userid' => $user->userid 'userid' => $user->userid
]; ];
$project = Project::userProject($projectId, true, $id > 0 ? true : null); $project = Project::userProject($projectId);
if ($id > 0) { if ($id > 0) {
$tag = ProjectTag::where('id', $id) $tag = ProjectTag::where('id', $id)
->where('project_id', $projectId) ->where('project_id', $projectId)
->first(); ->first();
if (!$project->owner && $tag->userid != $user->userid) {
return Base::retError('没有权限修改标签');
}
if (!$tag) { if (!$tag) {
return Base::retError('标签不存在或已被删除'); return Base::retError('标签不存在或已被删除');
} }

View File

@ -36,7 +36,6 @@ namespace App\Models;
class ProjectTag extends AbstractModel class ProjectTag extends AbstractModel
{ {
protected $hidden = [ protected $hidden = [
'created_at',
'updated_at', 'updated_at',
]; ];

View File

@ -66,7 +66,8 @@
<EDropdownItem command="delete" style="color:#f40">{{$L('删除项目')}}</EDropdownItem> <EDropdownItem command="delete" style="color:#f40">{{$L('删除项目')}}</EDropdownItem>
</EDropdownMenu> </EDropdownMenu>
<EDropdownMenu v-else slot="dropdown"> <EDropdownMenu v-else slot="dropdown">
<EDropdownItem command="log">{{$L('项目动态')}}</EDropdownItem> <EDropdownItem command="task_tag">{{$L('任务标签')}}</EDropdownItem>
<EDropdownItem command="log" divided>{{$L('项目动态')}}</EDropdownItem>
<EDropdownItem command="archived_task">{{$L('已归档任务')}}</EDropdownItem> <EDropdownItem command="archived_task">{{$L('已归档任务')}}</EDropdownItem>
<EDropdownItem command="deleted_task">{{$L('已删除任务')}}</EDropdownItem> <EDropdownItem command="deleted_task">{{$L('已删除任务')}}</EDropdownItem>
<EDropdownItem command="exit" divided style="color:#f40">{{$L('退出项目')}}</EDropdownItem> <EDropdownItem command="exit" divided style="color:#f40">{{$L('退出项目')}}</EDropdownItem>

View File

@ -72,6 +72,9 @@ export default {
formRules: { formRules: {
name: [ name: [
{ required: true, message: this.$L('请输入标签名称'), trigger: 'blur' } { required: true, message: this.$L('请输入标签名称'), trigger: 'blur' }
],
color: [
{ required: true, message: this.$L('请选择标签颜色'), trigger: 'blur' }
] ]
}, },

View File

@ -28,12 +28,18 @@
<div v-if="item.desc" class="tag-desc">{{ item.desc }}</div> <div v-if="item.desc" class="tag-desc">{{ item.desc }}</div>
</div> </div>
<div class="tag-actions"> <div class="tag-actions">
<Button @click="handleAdd(item)" type="primary"> <div v-if="item.userid === userId || projectData.owner_userid === userId" class="tag-actions-btns">
{{$L('编辑')}} <Button @click="handleAdd(item)" type="primary">
</Button> {{$L('编辑')}}
<Button @click="handleDelete(item)" type="error"> </Button>
{{$L('删除')}} <Button @click="handleDelete(item)" type="error">
</Button> {{$L('删除')}}
</Button>
</div>
<div class="tag-actions-owner">
<UserAvatar v-if="item.userid !== userId" :title="$L('创建人')" :userid="item.userid" show-name :show-icon="false" :size="16"/>
<span :title="$L('创建时间')">{{item.created_at}}</span>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -45,7 +51,7 @@
</template> </template>
<script> <script>
import {mapState} from 'vuex' import {mapState, mapGetters} from 'vuex'
import Tags from "./tags.vue"; import Tags from "./tags.vue";
import TaskTagAdd from "./add.vue"; import TaskTagAdd from "./add.vue";
@ -68,6 +74,7 @@ export default {
} }
}, },
computed: { computed: {
...mapGetters(['projectData']),
...mapState(['formOptions']) ...mapState(['formOptions'])
}, },
created() { created() {

View File

@ -559,6 +559,10 @@ body {
} }
} }
} }
.ivu-color-picker {
cursor: pointer;
}
} }
*[hidden="hidden"] { *[hidden="hidden"] {

View File

@ -108,13 +108,16 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
flex-wrap: wrap;
gap: 16px;
padding: 16px 0; padding: 16px 0;
border-top: 1px solid #F4F4F5; border-top: 1px solid #F4F4F5;
.tag-contents { .tag-contents {
flex-shrink: 0;
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
gap: 8px; gap: 8px;
margin-right: 8px; max-width: 100%;
.tag-title { .tag-title {
height: 22px; height: 22px;
display: flex; display: flex;
@ -124,20 +127,40 @@
.tag-desc { .tag-desc {
color: $primary-text-color; color: $primary-text-color;
font-size: 13px; font-size: 13px;
word-break: break-all;
} }
} }
.tag-actions { .tag-actions {
flex-shrink: 0; flex: 1;
> button { display: flex;
margin: 8px 0 8px 8px; flex-direction: column;
height: 28px; align-items: flex-end;
padding: 0 12px; gap: 8px;
font-size: 13px;
> i { .tag-actions-btns {
margin: 0 -2px; display: flex;
align-items: center;
gap: 8px;
> button {
margin: 0;
height: 28px;
padding: 0 12px;
font-size: 13px;
> i {
margin: 0 -2px;
}
} }
} }
.tag-actions-owner {
white-space: nowrap;
display: flex;
align-items: center;
gap: 4px;
font-size: 13px;
opacity: 0.5;
}
} }
} }
} }