Files
iqudo-top1/codes/web/src/views/ScenariosView.vue
2026-08-06 21:48:42 +08:00

78 lines
5.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { useRouter } from 'vue-router'
import { PlusOutlined, SearchOutlined } from '@ant-design/icons-vue'
import { message } from 'ant-design-vue'
import { api, apiMessage } from '@/api/client'
import type { Scenario } from '@/types'
const router = useRouter()
const loading = ref(false)
const open = ref(false)
const keyword = ref('')
const items = ref<Scenario[]>([])
const form = reactive({ name: '', industry: '', role_name: '', goal: '', trigger_text: '', visibility: 'tenant' })
const columns = [
{ title: '场景名称', dataIndex: 'name', key: 'name' }, { title: '行业', dataIndex: 'industry', key: 'industry', width: 140 },
{ title: '适用角色', dataIndex: 'role_name', key: 'role_name', width: 160 }, { title: '状态', dataIndex: 'status', key: 'status', width: 110 },
{ title: '更新时间', dataIndex: 'updated_at', key: 'updated_at', width: 180 }, { title: '', key: 'action', width: 80 },
]
async function load() {
loading.value = true
try { items.value = (await api.get<{ items: Scenario[] }>('/scenarios', { params: { keyword: keyword.value } })).items } finally { loading.value = false }
}
async function create() {
try {
const item = await api.post<Scenario>('/scenarios', form)
message.success('场景已创建')
open.value = false
router.push(`/scenarios/${item.id}`)
} catch (error) { message.error(apiMessage(error)) }
}
function statusText(value: string) { return ({ draft: '草稿', active: '使用中', archived: '已归档' } as Record<string,string>)[value] || value }
onMounted(load)
</script>
<template>
<div class="page-shell">
<div class="page-heading">
<div><h1>场景与 SOP</h1><p>从业务触发点开始定义信息字段与可执行话术流程</p></div>
<a-button type="primary" @click="open = true"><PlusOutlined />新建场景</a-button>
</div>
<section class="surface">
<div class="toolbar">
<a-input v-model:value="keyword" allow-clear placeholder="搜索名称或行业" style="width: 280px" @press-enter="load"><template #prefix><SearchOutlined /></template></a-input>
<span class="muted"> {{ items.length }} 个场景</span>
</div>
<a-table :columns="columns" :data-source="items" :loading="loading" row-key="id" :pagination="false" :scroll="{ x: 800 }" :custom-row="(record: Scenario) => ({ onClick: () => router.push(`/scenarios/${record.id}`) })">
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'name'"><div class="scenario-name"><b>{{ record.name }}</b><small>{{ record.goal }}</small></div></template>
<template v-else-if="column.key === 'status'"><a-tag :color="record.status === 'active' ? 'green' : 'default'">{{ statusText(record.status) }}</a-tag></template>
<template v-else-if="column.key === 'updated_at'">{{ new Date(record.updated_at).toLocaleString('zh-CN') }}</template>
<template v-else-if="column.key === 'action'"><a-button type="link" size="small">配置</a-button></template>
</template>
<template #emptyText><div class="empty-copy">还没有业务场景。创建第一个场景后,就可以配置字段和 SOP。</div></template>
</a-table>
</section>
<a-drawer v-model:open="open" title="创建业务场景" width="520" :destroy-on-close="true">
<a-form layout="vertical" :model="form">
<a-form-item label="场景名称" name="name" :rules="[{ required: true, message: '请输入场景名称' }]"><a-input v-model:value="form.name" placeholder="例如宠物医生问诊问药" /></a-form-item>
<div class="form-grid"><a-form-item label="所属行业" name="industry" :rules="[{ required: true, message: '请输入行业' }]"><a-input v-model:value="form.industry" placeholder="宠物医疗" /></a-form-item><a-form-item label="适用角色" name="role_name" :rules="[{ required: true, message: '请输入角色' }]"><a-input v-model:value="form.role_name" placeholder="医生客服" /></a-form-item></div>
<a-form-item label="执行目标" name="goal" :rules="[{ required: true, message: '请输入执行目标' }]"><a-textarea v-model:value="form.goal" :rows="3" placeholder="这个场景最终要推动什么结果" /></a-form-item>
<a-form-item label="触发条件" name="trigger_text" :rules="[{ required: true, message: '请输入触发条件' }]"><a-textarea v-model:value="form.trigger_text" :rows="3" placeholder="什么时候进入这个场景" /></a-form-item>
<a-form-item label="可见范围"><a-radio-group v-model:value="form.visibility"><a-radio value="tenant">全企业</a-radio><a-radio value="team">团队</a-radio><a-radio value="private">仅自己</a-radio></a-radio-group></a-form-item>
<a-button type="primary" block @click="create">创建并继续配置</a-button>
</a-form>
</a-drawer>
</div>
</template>
<style scoped>
.scenario-name { max-width: 460px; display: flex; flex-direction: column; cursor: pointer; }.scenario-name b { font-size: 14px; }.scenario-name small { overflow: hidden; margin-top: 4px; color: var(--muted); text-overflow: ellipsis; white-space: nowrap; }
.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
:deep(.ant-table-row) { cursor: pointer; }
@media (max-width: 600px) { .form-grid { grid-template-columns: 1fr; gap: 0; } }
</style>