|
|
@@ -0,0 +1,156 @@
|
|
|
+<template>
|
|
|
+ <div class="todo-list-bar">
|
|
|
+ <div class="todo-list-bar-header" @click="expanded = !expanded">
|
|
|
+ <div class="todo-list-bar-header-left">
|
|
|
+ <span class="todo-list-bar-title">任务进度</span>
|
|
|
+ <span class="todo-list-bar-summary">{{ completedCount }}/{{ todos.length }}</span>
|
|
|
+ </div>
|
|
|
+ <div :class="['todo-list-bar-arrow', { expanded }]">
|
|
|
+ <img :src="arrowIcon" width="12" height="12" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-show="expanded" class="todo-list-bar-body">
|
|
|
+ <div v-for="(todo, idx) in todos" :key="idx" :class="['todo-bar-item', todo.status]">
|
|
|
+ <span :class="['todo-bar-dot', todo.status]"></span>
|
|
|
+ <span :class="['todo-bar-text', todo.status]">{{ todo.content }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+ import { ref, computed, onMounted } from 'vue';
|
|
|
+
|
|
|
+ const props = defineProps<{
|
|
|
+ todos: Array<{ content: string; status: string }>;
|
|
|
+ }>();
|
|
|
+
|
|
|
+ const expanded = ref(true);
|
|
|
+
|
|
|
+ const completedCount = computed(() => props.todos.filter((t) => t.status === 'completed').length);
|
|
|
+
|
|
|
+ const getCssUrl = (varName: string) => {
|
|
|
+ const val = getComputedStyle(document.documentElement).getPropertyValue(varName).trim();
|
|
|
+ return val.replace(/^url\(["']?/, '').replace(/["']?\)$/, '');
|
|
|
+ };
|
|
|
+
|
|
|
+ const arrowIcon = ref('');
|
|
|
+ onMounted(() => {
|
|
|
+ arrowIcon.value = getCssUrl('--img-chat-arrow-icon');
|
|
|
+ });
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="less">
|
|
|
+ .todo-list-bar {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ margin: 0 16px;
|
|
|
+ background: #0a2a3f;
|
|
|
+ border: 1px solid #1a4a6f;
|
|
|
+ border-radius: 8px;
|
|
|
+ flex-shrink: 0;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ .todo-list-bar-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ padding: 10px 16px;
|
|
|
+ cursor: pointer;
|
|
|
+ user-select: none;
|
|
|
+ transition: background 0.2s;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: rgba(10, 132, 255, 0.08);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .todo-list-bar-header-left {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .todo-list-bar-title {
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #e0e6ed;
|
|
|
+ }
|
|
|
+
|
|
|
+ .todo-list-bar-summary {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #8b949e;
|
|
|
+ background: rgba(10, 132, 255, 0.12);
|
|
|
+ padding: 1px 8px;
|
|
|
+ border-radius: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .todo-list-bar-arrow {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ transition: transform 0.2s;
|
|
|
+
|
|
|
+ &.expanded {
|
|
|
+ transform: rotate(180deg);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .todo-list-bar-body {
|
|
|
+ padding: 0 16px 10px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 2px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .todo-bar-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ padding: 6px 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+ transition: background 0.2s;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: rgba(10, 132, 255, 0.06);
|
|
|
+ }
|
|
|
+
|
|
|
+ &.completed .todo-bar-text {
|
|
|
+ color: #5a6a7e;
|
|
|
+ text-decoration: line-through;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .todo-bar-dot {
|
|
|
+ width: 8px;
|
|
|
+ height: 8px;
|
|
|
+ border-radius: 50%;
|
|
|
+ flex-shrink: 0;
|
|
|
+
|
|
|
+ &.completed {
|
|
|
+ background: #3fb950;
|
|
|
+ }
|
|
|
+ &.in_progress {
|
|
|
+ background: #0a84ff;
|
|
|
+ box-shadow: 0 0 6px rgba(10, 132, 255, 0.5);
|
|
|
+ }
|
|
|
+ &.pending {
|
|
|
+ background: #484f5a;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .todo-bar-text {
|
|
|
+ font-size: 13px;
|
|
|
+ line-height: 1.4;
|
|
|
+
|
|
|
+ &.completed {
|
|
|
+ color: #5a6a7e;
|
|
|
+ }
|
|
|
+ &.in_progress {
|
|
|
+ color: #e0e6ed;
|
|
|
+ }
|
|
|
+ &.pending {
|
|
|
+ color: #8b949e;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|