style: 更新多个组件以使用分段控件替代按钮组
This commit is contained in:
parent
edc4caaf9c
commit
be40799af9
@ -350,9 +350,7 @@ def check_and_migrate(db_path: str):
|
|||||||
logger.warning(f" - {issue}")
|
logger.warning(f" - {issue}")
|
||||||
|
|
||||||
if os.path.exists(db_path):
|
if os.path.exists(db_path):
|
||||||
logger.info(
|
logger.info("建议运行迁移脚本: docker exec api-dev python /app/scripts/migrate_user_soft_delete.py")
|
||||||
"建议运行迁移脚本: docker exec api-dev python /app/scripts/migrate_user_soft_delete.py"
|
|
||||||
)
|
|
||||||
|
|
||||||
migrator = DatabaseMigrator(db_path)
|
migrator = DatabaseMigrator(db_path)
|
||||||
|
|
||||||
|
|||||||
@ -234,7 +234,7 @@
|
|||||||
<a-modal
|
<a-modal
|
||||||
v-model:open="toolsModalOpen"
|
v-model:open="toolsModalOpen"
|
||||||
title="选择工具"
|
title="选择工具"
|
||||||
:width="600"
|
:width="800"
|
||||||
:footer="null"
|
:footer="null"
|
||||||
:maskClosable="false"
|
:maskClosable="false"
|
||||||
class="tools-modal"
|
class="tools-modal"
|
||||||
@ -569,7 +569,7 @@ watch(() => props.isOpen, (newVal) => {
|
|||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
||||||
@padding-bottom: 40px;
|
@padding-bottom: 0px;
|
||||||
.agent-config-sidebar {
|
.agent-config-sidebar {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 0;
|
width: 0;
|
||||||
@ -642,7 +642,7 @@ watch(() => props.isOpen, (newVal) => {
|
|||||||
|
|
||||||
.sidebar-footer {
|
.sidebar-footer {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
bottom: 16px;
|
bottom: 0px;
|
||||||
padding: 12px 0;
|
padding: 12px 0;
|
||||||
border-top: 1px solid var(--gray-100);
|
border-top: 1px solid var(--gray-100);
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
|||||||
@ -9,36 +9,10 @@
|
|||||||
<div class="task-center">
|
<div class="task-center">
|
||||||
<div class="task-toolbar">
|
<div class="task-toolbar">
|
||||||
<div class="task-filter-group">
|
<div class="task-filter-group">
|
||||||
<a-button-group>
|
<a-segmented
|
||||||
<a-button
|
v-model:value="statusFilter"
|
||||||
:type="isActiveFilter('all') ? 'primary' : 'default'"
|
:options="taskFilterOptions"
|
||||||
@click="setFilter('all')"
|
/>
|
||||||
>
|
|
||||||
全部
|
|
||||||
<span class="filter-count">{{ totalCount }}</span>
|
|
||||||
</a-button>
|
|
||||||
<a-button
|
|
||||||
:type="isActiveFilter('active') ? 'primary' : 'default'"
|
|
||||||
@click="setFilter('active')"
|
|
||||||
>
|
|
||||||
进行中
|
|
||||||
<span class="filter-count">{{ inProgressCount }}</span>
|
|
||||||
</a-button>
|
|
||||||
<a-button
|
|
||||||
:type="isActiveFilter('success') ? 'primary' : 'default'"
|
|
||||||
@click="setFilter('success')"
|
|
||||||
>
|
|
||||||
已完成
|
|
||||||
<span class="filter-count">{{ completedCount }}</span>
|
|
||||||
</a-button>
|
|
||||||
<a-button
|
|
||||||
:type="isActiveFilter('failed') ? 'primary' : 'default'"
|
|
||||||
@click="setFilter('failed')"
|
|
||||||
>
|
|
||||||
失败
|
|
||||||
<span class="filter-count">{{ failedCount }}</span>
|
|
||||||
</a-button>
|
|
||||||
</a-button-group>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="task-toolbar-actions">
|
<div class="task-toolbar-actions">
|
||||||
<a-button
|
<a-button
|
||||||
@ -135,7 +109,6 @@ import { computed, h, onBeforeUnmount, watch, ref } from 'vue'
|
|||||||
import { Modal } from 'ant-design-vue'
|
import { Modal } from 'ant-design-vue'
|
||||||
import { useTaskerStore } from '@/stores/tasker'
|
import { useTaskerStore } from '@/stores/tasker'
|
||||||
import { storeToRefs } from 'pinia'
|
import { storeToRefs } from 'pinia'
|
||||||
import { ReloadOutlined } from '@ant-design/icons-vue'
|
|
||||||
import { formatFullDateTime, formatRelative, parseToShanghai } from '@/utils/time'
|
import { formatFullDateTime, formatRelative, parseToShanghai } from '@/utils/time'
|
||||||
|
|
||||||
const taskerStore = useTaskerStore()
|
const taskerStore = useTaskerStore()
|
||||||
@ -146,6 +119,48 @@ const tasks = computed(() => sortedTasks.value)
|
|||||||
const loadingState = computed(() => Boolean(loading.value))
|
const loadingState = computed(() => Boolean(loading.value))
|
||||||
const lastErrorState = computed(() => lastError.value)
|
const lastErrorState = computed(() => lastError.value)
|
||||||
const statusFilter = ref('all')
|
const statusFilter = ref('all')
|
||||||
|
const inProgressCount = computed(
|
||||||
|
() => tasks.value.filter((task) => ACTIVE_CLASS_STATUSES.has(task.status)).length
|
||||||
|
)
|
||||||
|
const completedCount = computed(() => tasks.value.filter((task) => task.status === 'success').length)
|
||||||
|
const failedCount = computed(
|
||||||
|
() => tasks.value.filter((task) => FAILED_STATUSES.has(task.status)).length
|
||||||
|
)
|
||||||
|
const totalCount = computed(() => tasks.value.length)
|
||||||
|
const taskFilterOptions = computed(() => [
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h('span', { class: 'task-filter-option' }, [
|
||||||
|
'全部',
|
||||||
|
h('span', { class: 'filter-count' }, totalCount.value)
|
||||||
|
]),
|
||||||
|
value: 'all'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h('span', { class: 'task-filter-option' }, [
|
||||||
|
'进行中',
|
||||||
|
h('span', { class: 'filter-count' }, inProgressCount.value)
|
||||||
|
]),
|
||||||
|
value: 'active'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h('span', { class: 'task-filter-option' }, [
|
||||||
|
'已完成',
|
||||||
|
h('span', { class: 'filter-count' }, completedCount.value)
|
||||||
|
]),
|
||||||
|
value: 'success'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: () =>
|
||||||
|
h('span', { class: 'task-filter-option' }, [
|
||||||
|
'失败',
|
||||||
|
h('span', { class: 'filter-count' }, failedCount.value)
|
||||||
|
]),
|
||||||
|
value: 'failed'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
const filteredTasks = computed(() => {
|
const filteredTasks = computed(() => {
|
||||||
const list = tasks.value
|
const list = tasks.value
|
||||||
@ -321,22 +336,6 @@ function canCancel(task) {
|
|||||||
return ['pending', 'running', 'queued'].includes(task.status) && !task.cancel_requested
|
return ['pending', 'running', 'queued'].includes(task.status) && !task.cancel_requested
|
||||||
}
|
}
|
||||||
|
|
||||||
const inProgressCount = computed(
|
|
||||||
() => tasks.value.filter((task) => ACTIVE_CLASS_STATUSES.has(task.status)).length
|
|
||||||
)
|
|
||||||
const completedCount = computed(() => tasks.value.filter((task) => task.status === 'success').length)
|
|
||||||
const failedCount = computed(
|
|
||||||
() => tasks.value.filter((task) => FAILED_STATUSES.has(task.status)).length
|
|
||||||
)
|
|
||||||
const totalCount = computed(() => tasks.value.length)
|
|
||||||
|
|
||||||
function setFilter(value) {
|
|
||||||
statusFilter.value = value
|
|
||||||
}
|
|
||||||
|
|
||||||
function isActiveFilter(value) {
|
|
||||||
return statusFilter.value === value
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
<style scoped lang="less">
|
<style scoped lang="less">
|
||||||
.task-center {
|
.task-center {
|
||||||
@ -365,13 +364,7 @@ function isActiveFilter(value) {
|
|||||||
gap: 4px;
|
gap: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-filter-group :deep(.ant-btn) {
|
:deep(.filter-count) {
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-count {
|
|
||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #94a3b8;
|
color: #94a3b8;
|
||||||
|
|||||||
@ -7,11 +7,11 @@
|
|||||||
:footer="null"
|
:footer="null"
|
||||||
>
|
>
|
||||||
<a-space style="margin-bottom: 16px">
|
<a-space style="margin-bottom: 16px">
|
||||||
<a-radio-group v-model:value="feedbackFilter" @change="loadFeedbacks">
|
<a-segmented
|
||||||
<a-radio-button value="all">全部</a-radio-button>
|
v-model:value="feedbackFilter"
|
||||||
<a-radio-button value="like">点赞</a-radio-button>
|
:options="feedbackOptions"
|
||||||
<a-radio-button value="dislike">点踩</a-radio-button>
|
@change="loadFeedbacks"
|
||||||
</a-radio-group>
|
/>
|
||||||
</a-space>
|
</a-space>
|
||||||
|
|
||||||
<!-- 卡片列表 -->
|
<!-- 卡片列表 -->
|
||||||
@ -92,7 +92,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, watch } from 'vue'
|
import { ref, watch } from 'vue'
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
import { LikeOutlined, DislikeOutlined, ClockCircleOutlined } from '@ant-design/icons-vue'
|
import { LikeOutlined, DislikeOutlined, ClockCircleOutlined } from '@ant-design/icons-vue'
|
||||||
import { dashboardApi } from '@/apis/dashboard_api'
|
import { dashboardApi } from '@/apis/dashboard_api'
|
||||||
@ -113,6 +113,11 @@ const modalVisible = ref(false)
|
|||||||
const feedbacks = ref([])
|
const feedbacks = ref([])
|
||||||
const loadingFeedbacks = ref(false)
|
const loadingFeedbacks = ref(false)
|
||||||
const feedbackFilter = ref('all')
|
const feedbackFilter = ref('all')
|
||||||
|
const feedbackOptions = [
|
||||||
|
{ label: '全部', value: 'all' },
|
||||||
|
{ label: '点赞', value: 'like' },
|
||||||
|
{ label: '点踩', value: 'dislike' }
|
||||||
|
]
|
||||||
|
|
||||||
// 显示模态框
|
// 显示模态框
|
||||||
const show = () => {
|
const show = () => {
|
||||||
|
|||||||
@ -18,19 +18,19 @@
|
|||||||
<h3>检索配置</h3>
|
<h3>检索配置</h3>
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<div class="card card-select">
|
<div class="card card-select">
|
||||||
<span class="label">对话模型</span>
|
<span class="label">{{ items?.default_model?.des || '默认对话模型' }}</span>
|
||||||
<ModelSelectorComponent
|
<ModelSelectorComponent
|
||||||
@select-model="handleChatModelSelect"
|
@select-model="handleChatModelSelect"
|
||||||
:model_name="configStore.config?.model_name"
|
:model_spec="configStore.config?.default_model"
|
||||||
:model_provider="configStore.config?.model_provider"
|
placeholder="请选择默认模型"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="card card-select">
|
<div class="card card-select">
|
||||||
<span class="label">{{ items?.fast_model.des }}</span>
|
<span class="label">{{ items?.fast_model.des }}</span>
|
||||||
<ModelSelectorComponent
|
<ModelSelectorComponent
|
||||||
@select-model="handleFastModelSelect"
|
@select-model="handleFastModelSelect"
|
||||||
:model_name="fastModelName"
|
:model_spec="configStore.config?.fast_model"
|
||||||
:model_provider="fastModelProvider"
|
placeholder="请选择模型"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="card card-select">
|
<div class="card card-select">
|
||||||
@ -109,8 +109,8 @@
|
|||||||
<span class="label">{{ items?.content_guard_llm_model.des }}</span>
|
<span class="label">{{ items?.content_guard_llm_model.des }}</span>
|
||||||
<ModelSelectorComponent
|
<ModelSelectorComponent
|
||||||
@select-model="handleContentGuardModelSelect"
|
@select-model="handleContentGuardModelSelect"
|
||||||
:model_name="contentGuardModelName"
|
:model_spec="configStore.config?.content_guard_llm_model"
|
||||||
:model_provider="contentGuardModelProvider"
|
placeholder="请选择模型"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -251,45 +251,22 @@ const updateWindowWidth = () => {
|
|||||||
state.windowWidth = window?.innerWidth || 0
|
state.windowWidth = window?.innerWidth || 0
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleChatModelSelect = ({ provider, name }) => {
|
const handleChatModelSelect = (spec) => {
|
||||||
configStore.setConfigValues({
|
if (typeof spec === 'string' && spec) {
|
||||||
model_provider: provider,
|
configStore.setConfigValue('default_model', spec)
|
||||||
model_name: name,
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const fastModelProvider = computed(() => {
|
const handleFastModelSelect = (spec) => {
|
||||||
const fastModel = configStore.config?.fast_model
|
if (typeof spec === 'string' && spec) {
|
||||||
if (!fastModel) return ''
|
configStore.setConfigValue('fast_model', spec)
|
||||||
return fastModel.split('/')[0]
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const fastModelName = computed(() => {
|
|
||||||
const fastModel = configStore.config?.fast_model
|
|
||||||
if (!fastModel) return ''
|
|
||||||
const parts = fastModel.split('/')
|
|
||||||
return parts.slice(1).join('/')
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleFastModelSelect = ({ provider, name }) => {
|
|
||||||
configStore.setConfigValue('fast_model', `${provider}/${name}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const contentGuardModelProvider = computed(() => {
|
const handleContentGuardModelSelect = (spec) => {
|
||||||
const contentGuardModel = configStore.config?.content_guard_llm_model
|
if (typeof spec === 'string' && spec) {
|
||||||
if (!contentGuardModel) return ''
|
configStore.setConfigValue('content_guard_llm_model', spec)
|
||||||
return contentGuardModel.split('/')[0]
|
}
|
||||||
})
|
|
||||||
|
|
||||||
const contentGuardModelName = computed(() => {
|
|
||||||
const contentGuardModel = configStore.config?.content_guard_llm_model
|
|
||||||
if (!contentGuardModel) return ''
|
|
||||||
const parts = contentGuardModel.split('/')
|
|
||||||
return parts.slice(1).join('/')
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleContentGuardModelSelect = ({ provider, name }) => {
|
|
||||||
configStore.setConfigValue('content_guard_llm_model', `${provider}/${name}`)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@ -381,7 +358,7 @@ const openLink = (url) => {
|
|||||||
|
|
||||||
.setting-container {
|
.setting-container {
|
||||||
--setting-header-height: 55px;
|
--setting-header-height: 55px;
|
||||||
max-width: 870px;
|
max-width: 1054px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.setting-header {
|
.setting-header {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user