chore: initial baseline with P0-safety .gitignore
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
<!-- =============================================================================
|
||||
// 企微IT智能服务台 — H5用户端 AI 助手面板容器
|
||||
// =============================================================================
|
||||
// 说明:AI 助手面板的容器组件,使用 Vant4 Tab 组件
|
||||
// 4个Tab:相似问题 | 审批流程 | 软件下载 | 搜索
|
||||
// 右上角展开/收起按钮(移动端)
|
||||
// ============================================================================= -->
|
||||
|
||||
<template>
|
||||
<div class="ai-helper-panel">
|
||||
<!-- 面板头部:标题 + 收起按钮 -->
|
||||
<div class="ai-helper-panel__header">
|
||||
<span class="ai-helper-panel__title">AI 助手</span>
|
||||
<!-- 移动端收起按钮 -->
|
||||
<van-icon
|
||||
name="cross"
|
||||
size="18"
|
||||
color="var(--text-tertiary)"
|
||||
class="ai-helper-panel__close"
|
||||
@click="handleClose"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Tab 切换区域 -->
|
||||
<van-tabs v-model:active="activeTab" sticky animated swipeable>
|
||||
<!-- Tab1: 相似问题(暂未实现,显示占位符) -->
|
||||
<van-tab title="相似问题">
|
||||
<ComingSoon title="相似问题与做法" />
|
||||
</van-tab>
|
||||
|
||||
<!-- Tab2: 审批流程 -->
|
||||
<van-tab title="审批流程">
|
||||
<ApprovalLinks />
|
||||
</van-tab>
|
||||
|
||||
<!-- Tab3: 软件下载 -->
|
||||
<van-tab title="软件下载">
|
||||
<SoftwareDownloads />
|
||||
</van-tab>
|
||||
|
||||
<!-- Tab4: 搜索(暂未实现,显示占位符) -->
|
||||
<van-tab title="搜索">
|
||||
<ComingSoon title="知识库搜索" />
|
||||
</van-tab>
|
||||
</van-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* AiHelperPanel AI 助手面板容器
|
||||
* 4个Tab模块:
|
||||
* - 相似问题:占位符"即将上线"
|
||||
* - 审批流程:真实功能(从 API 获取数据)
|
||||
* - 软件下载:真实功能(从 API 获取数据)
|
||||
* - 搜索:占位符"即将上线"
|
||||
* 移动端可通过右上角按钮收起面板
|
||||
*/
|
||||
|
||||
import { ref } from 'vue'
|
||||
import { useConversationStore } from '@/stores/conversation'
|
||||
import ComingSoon from './ComingSoon.vue'
|
||||
import ApprovalLinks from './ApprovalLinks.vue'
|
||||
import SoftwareDownloads from './SoftwareDownloads.vue'
|
||||
|
||||
const store = useConversationStore()
|
||||
|
||||
/** 当前激活的 Tab 索引(0=相似问题, 1=审批流程, 2=软件下载, 3=搜索) */
|
||||
const activeTab = ref<number>(1) // 默认显示审批流程
|
||||
|
||||
/**
|
||||
* 收起面板(移动端使用)
|
||||
* 通知 store 切换面板可见性
|
||||
*/
|
||||
function handleClose(): void {
|
||||
store.toggleAssistantPanel()
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* AI 助手面板容器 */
|
||||
.ai-helper-panel {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: var(--bg-secondary);
|
||||
}
|
||||
|
||||
/* 面板头部 */
|
||||
.ai-helper-panel__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px 16px;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 面板标题 */
|
||||
.ai-helper-panel__title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
/* 收起按钮 */
|
||||
.ai-helper-panel__close {
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
/* Tab 区域占满剩余空间 */
|
||||
.ai-helper-panel :deep(.van-tabs) {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ai-helper-panel :deep(.van-tabs__content) {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.ai-helper-panel :deep(.van-tab__panel) {
|
||||
min-height: 100%;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,111 @@
|
||||
<!-- =============================================================================
|
||||
// 企微IT智能服务台 — H5用户端审批流程链接组件
|
||||
// =============================================================================
|
||||
// 说明:展示所有审批流程链接,按分类分组
|
||||
// 使用 Vant4 CellGroup + Cell 组件
|
||||
// 点击链接在企微内置浏览器中打开
|
||||
// ============================================================================= -->
|
||||
|
||||
<template>
|
||||
<div class="approval-links">
|
||||
<!-- 加载中提示 -->
|
||||
<div v-if="loading" class="approval-links__loading">
|
||||
<van-loading size="24px" vertical>加载中...</van-loading>
|
||||
</div>
|
||||
|
||||
<!-- 无数据提示 -->
|
||||
<div v-else-if="Object.keys(groupedLinks).length === 0" class="approval-links__empty">
|
||||
<van-empty description="暂无审批流程" image="search" />
|
||||
</div>
|
||||
|
||||
<!-- 按分类展示审批链接 -->
|
||||
<template v-else>
|
||||
<div
|
||||
v-for="(links, category) in groupedLinks"
|
||||
:key="category"
|
||||
class="approval-links__group"
|
||||
>
|
||||
<!-- 分类标题 -->
|
||||
<div class="approval-links__category">{{ category }}</div>
|
||||
<!-- 该分类下的链接列表 -->
|
||||
<van-cell-group inset>
|
||||
<van-cell
|
||||
v-for="link in links"
|
||||
:key="link.id"
|
||||
:title="link.title"
|
||||
:icon="link.icon || 'link-o'"
|
||||
is-link
|
||||
@click="openLink(link.url)"
|
||||
>
|
||||
<!-- 右侧箭头 -->
|
||||
<template #right-icon>
|
||||
<van-icon name="arrow" />
|
||||
</template>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* ApprovalLinks 审批流程链接组件
|
||||
* 从 API 获取审批流程数据,按分类分组展示
|
||||
* 点击链接在企微内置浏览器中打开
|
||||
*/
|
||||
|
||||
import { computed } from 'vue'
|
||||
import { useConversationStore } from '@/stores/conversation'
|
||||
const store = useConversationStore()
|
||||
|
||||
/** 加载状态:当审批链接列表为空且未初始化时视为加载中 */
|
||||
const loading = computed(() => {
|
||||
return store.approvalLinks.length === 0 && !store.initialized
|
||||
})
|
||||
|
||||
/** 审批链接按分类分组(从 store 计算属性获取) */
|
||||
const groupedLinks = computed(() => store.approvalLinksByCategory)
|
||||
|
||||
/**
|
||||
* 打开审批流程链接
|
||||
* 在企微内置浏览器中打开目标链接
|
||||
* @param url 审批流程链接地址
|
||||
*/
|
||||
function openLink(url: string): void {
|
||||
// 在企微 WebView 中直接使用 window.open 即可在内置浏览器中打开
|
||||
window.open(url, '_blank')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 审批链接容器 */
|
||||
.approval-links {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
/* 加载中状态 */
|
||||
.approval-links__loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 40px 0;
|
||||
}
|
||||
|
||||
/* 空数据状态 */
|
||||
.approval-links__empty {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
/* 分类分组容器 */
|
||||
.approval-links__group {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
/* 分类标题 */
|
||||
.approval-links__category {
|
||||
font-size: 13px;
|
||||
color: var(--text-tertiary);
|
||||
padding: 8px 16px 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,63 @@
|
||||
<!-- =============================================================================
|
||||
// 企微IT智能服务台 — H5用户端"即将上线"占位组件
|
||||
// =============================================================================
|
||||
// 说明:通用占位组件,用于尚未实现的功能模块
|
||||
// 接收 title prop,显示灰色图标 + "{title} · 即将上线"
|
||||
// 用于"相似问题与做法"和"知识库搜索"两个模块
|
||||
// ============================================================================= -->
|
||||
|
||||
<template>
|
||||
<div class="coming-soon">
|
||||
<!-- 灰色占位图标 -->
|
||||
<div class="coming-soon__icon">
|
||||
<van-icon name="clock-o" size="48" color="var(--text-placeholder)" />
|
||||
</div>
|
||||
<!-- 模块名称 + 即将上线提示 -->
|
||||
<p class="coming-soon__text">{{ title }} · 即将上线</p>
|
||||
<p class="coming-soon__subtext">功能开发中,敬请期待</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* ComingSoon 占位组件
|
||||
* @prop title - 模块名称(如"相似问题与做法"、"知识库搜索")
|
||||
*/
|
||||
|
||||
defineProps<{
|
||||
/** 模块名称,显示在"即将上线"前 */
|
||||
title: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 占位容器:居中布局 */
|
||||
.coming-soon {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 60px 16px;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
/* 灰色图标 */
|
||||
.coming-soon__icon {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
/* 主提示文字:模块名 + 即将上线 */
|
||||
.coming-soon__text {
|
||||
font-size: 15px;
|
||||
color: var(--text-tertiary);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 副提示文字 */
|
||||
.coming-soon__subtext {
|
||||
font-size: 12px;
|
||||
color: var(--text-placeholder);
|
||||
margin-top: 8px;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,629 @@
|
||||
<!-- =============================================================================
|
||||
// 企微IT智能服务台 — H5用户端右侧面板
|
||||
// =============================================================================
|
||||
// 说明:桌面端右侧面板,三段式布局:
|
||||
// 1. 上方:AI推送区(根据排查步骤和会话内容动态推送)
|
||||
// 2. 中部:固定常用资源标签页(资源申请流程入口、常用必装软件)
|
||||
// 3. 下方:趣味问答(答对可提高用户积分和等级)
|
||||
// 注意:此面板仅在桌面端(≥500px)显示,手机端隐藏
|
||||
// ============================================================================= -->
|
||||
|
||||
<template>
|
||||
<div class="right-panel">
|
||||
<!-- ====== 上方:AI推送区 ====== -->
|
||||
<div class="right-panel__section right-panel__ai-push">
|
||||
<div class="right-panel__section-header">
|
||||
<span class="right-panel__section-icon">🤖</span>
|
||||
<span class="right-panel__section-title">AI 推荐</span>
|
||||
</div>
|
||||
<div class="right-panel__section-body">
|
||||
<!-- 推荐卡片列表(根据排查步骤和会话内容动态推送) -->
|
||||
<div
|
||||
v-for="item in aiPushItems"
|
||||
:key="item.id"
|
||||
class="ai-push-card"
|
||||
:class="`ai-push-card--${item.type}`"
|
||||
@click="handlePushClick(item)"
|
||||
>
|
||||
<div class="ai-push-card__header">
|
||||
<span class="ai-push-card__icon">{{ item.icon }}</span>
|
||||
<span class="ai-push-card__type-label">{{ item.typeLabel }}</span>
|
||||
</div>
|
||||
<div class="ai-push-card__title">{{ item.title }}</div>
|
||||
<div v-if="item.subtitle" class="ai-push-card__subtitle">{{ item.subtitle }}</div>
|
||||
</div>
|
||||
<!-- 暂无推荐 -->
|
||||
<div v-if="aiPushItems.length === 0" class="right-panel__empty">
|
||||
<span>💡 对话过程中会自动推送相关资源</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ====== 中部:常用资源标签页 ====== -->
|
||||
<div class="right-panel__section right-panel__resources">
|
||||
<div class="right-panel__section-header">
|
||||
<span class="right-panel__section-icon">📚</span>
|
||||
<span class="right-panel__section-title">常用资源</span>
|
||||
</div>
|
||||
<!-- 标签切换 -->
|
||||
<div class="right-panel__tabs">
|
||||
<button
|
||||
class="right-panel__tab"
|
||||
:class="{ 'right-panel__tab--active': activeResourceTab === 'process' }"
|
||||
@click="activeResourceTab = 'process'"
|
||||
>申请流程</button>
|
||||
<button
|
||||
class="right-panel__tab"
|
||||
:class="{ 'right-panel__tab--active': activeResourceTab === 'software' }"
|
||||
@click="activeResourceTab = 'software'"
|
||||
>必装软件</button>
|
||||
</div>
|
||||
<!-- 申请流程标签页内容 -->
|
||||
<div v-if="activeResourceTab === 'process'" class="right-panel__tab-content">
|
||||
<div
|
||||
v-for="item in processItems"
|
||||
:key="item.id"
|
||||
class="resource-item"
|
||||
@click="handleProcessClick(item)"
|
||||
>
|
||||
<span class="resource-item__icon">{{ item.icon }}</span>
|
||||
<div class="resource-item__info">
|
||||
<span class="resource-item__title">{{ item.title }}</span>
|
||||
<span v-if="item.desc" class="resource-item__desc">{{ item.desc }}</span>
|
||||
</div>
|
||||
<span class="resource-item__arrow">→</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 必装软件标签页内容 -->
|
||||
<div v-if="activeResourceTab === 'software'" class="right-panel__tab-content">
|
||||
<div
|
||||
v-for="item in softwareItems"
|
||||
:key="item.id"
|
||||
class="resource-item"
|
||||
@click="handleSoftwareClick(item)"
|
||||
>
|
||||
<span class="resource-item__icon">{{ item.icon }}</span>
|
||||
<div class="resource-item__info">
|
||||
<span class="resource-item__title">{{ item.title }}</span>
|
||||
<span v-if="item.desc" class="resource-item__desc">{{ item.desc }}</span>
|
||||
</div>
|
||||
<span class="resource-item__arrow">→</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ====== 下方:趣味问答 ====== -->
|
||||
<div class="right-panel__section right-panel__quiz">
|
||||
<div class="right-panel__section-header">
|
||||
<span class="right-panel__section-icon">🎯</span>
|
||||
<span class="right-panel__section-title">趣味问答</span>
|
||||
<span class="right-panel__quiz-score">🏆 {{ userScore }}分</span>
|
||||
</div>
|
||||
<div class="right-panel__section-body">
|
||||
<template v-if="currentQuiz">
|
||||
<div class="quiz-question">{{ currentQuiz.question }}</div>
|
||||
<div class="quiz-options">
|
||||
<button
|
||||
v-for="(option, idx) in currentQuiz.options"
|
||||
:key="idx"
|
||||
class="quiz-option"
|
||||
:class="{
|
||||
'quiz-option--correct': quizAnswered && idx === currentQuiz.correctIndex,
|
||||
'quiz-option--wrong': quizAnswered && quizSelectedIndex === idx && idx !== currentQuiz.correctIndex
|
||||
}"
|
||||
:disabled="quizAnswered"
|
||||
@click="handleQuizAnswer(idx)"
|
||||
>
|
||||
<span class="quiz-option__label">{{ optionLabels[idx] }}</span>
|
||||
<span class="quiz-option__text">{{ option }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- 答题结果 -->
|
||||
<div v-if="quizAnswered" class="quiz-result">
|
||||
<span v-if="quizSelectedIndex === currentQuiz.correctIndex" class="quiz-result--correct">
|
||||
✅ 答对啦!+10积分
|
||||
</span>
|
||||
<span v-else class="quiz-result--wrong">
|
||||
❌ 答错了!正确答案是 {{ optionLabels[currentQuiz.correctIndex] }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<div v-else class="right-panel__empty">
|
||||
<span>暂无问答题目</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* RightPanel 右侧面板组件
|
||||
* 三段式布局:AI推送区 / 常用资源标签页 / 趣味问答
|
||||
* 仅在桌面端(≥500px)显示
|
||||
*/
|
||||
import { ref, computed } from 'vue'
|
||||
// 阶段二接入 Dify 动态推送时启用:
|
||||
// import { useConversationStore } from '@/stores/conversation'
|
||||
|
||||
// const store = useConversationStore() // 阶段二接入 Dify 动态推送时启用
|
||||
|
||||
// ── AI推送区 ──
|
||||
|
||||
/** AI推送条目类型 */
|
||||
interface AiPushItem {
|
||||
id: string
|
||||
type: 'guide' | 'process' | 'download' // 处理指南/申请流程/软件下载
|
||||
icon: string
|
||||
typeLabel: string
|
||||
title: string
|
||||
subtitle?: string
|
||||
}
|
||||
|
||||
/** AI推送数据(阶段一使用静态数据,阶段二接入Dify动态推送) */
|
||||
const aiPushItems = computed<AiPushItem[]>(() => {
|
||||
// TODO: 阶段二根据排查步骤和会话内容动态生成推送
|
||||
// 当前使用示例数据
|
||||
return [
|
||||
{
|
||||
id: 'push-1',
|
||||
type: 'guide',
|
||||
icon: '📖',
|
||||
typeLabel: '处理指南',
|
||||
title: 'WiFi连接问题处理指南',
|
||||
subtitle: '已解决28次类似问题',
|
||||
},
|
||||
{
|
||||
id: 'push-2',
|
||||
type: 'process',
|
||||
icon: '📋',
|
||||
typeLabel: '申请流程',
|
||||
title: '网络连接申请流程',
|
||||
subtitle: '在线申请,1-3个工作日',
|
||||
},
|
||||
{
|
||||
id: 'push-3',
|
||||
type: 'download',
|
||||
icon: '💾',
|
||||
typeLabel: '软件下载',
|
||||
title: '无线网卡驱动下载',
|
||||
subtitle: '适用于 Windows 10/11',
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
/**
|
||||
* 点击AI推送卡片
|
||||
*/
|
||||
function handlePushClick(item: AiPushItem): void {
|
||||
// TODO: 阶段二实现推送跳转
|
||||
console.log('[RightPanel] AI推送点击:', item.title)
|
||||
}
|
||||
|
||||
// ── 常用资源标签页 ──
|
||||
|
||||
/** 当前激活的资源标签页 */
|
||||
const activeResourceTab = ref<'process' | 'software'>('process')
|
||||
|
||||
/** 申请流程列表 */
|
||||
const processItems = ref([
|
||||
{ id: 'p-1', icon: '💻', title: 'IT设备申请', desc: '电脑/显示器/外设' },
|
||||
{ id: 'p-2', icon: '🔐', title: '权限申请', desc: '系统/文件夹/VPN' },
|
||||
{ id: 'p-3', icon: '🌐', title: 'VPN申请', desc: '远程办公网络' },
|
||||
{ id: 'p-4', icon: '📧', title: '邮箱别名申请', desc: '别名/分发组' },
|
||||
])
|
||||
|
||||
/** 必装软件列表 */
|
||||
const softwareItems = ref([
|
||||
{ id: 's-1', icon: '📝', title: 'Office 365', desc: 'Word/Excel/PPT' },
|
||||
{ id: 's-2', icon: '📄', title: 'Adobe Acrobat', desc: 'PDF阅读/编辑' },
|
||||
{ id: 's-3', icon: '💬', title: '企业微信', desc: '即时通讯/协作' },
|
||||
{ id: 's-4', icon: '🛡️', title: '火绒安全', desc: '杀毒/终端防护' },
|
||||
])
|
||||
|
||||
/**
|
||||
* 点击申请流程项
|
||||
*/
|
||||
function handleProcessClick(item: { id: string; title: string }): void {
|
||||
// TODO: 阶段二实现流程跳转
|
||||
console.log('[RightPanel] 申请流程点击:', item.title)
|
||||
}
|
||||
|
||||
/**
|
||||
* 点击软件下载项
|
||||
*/
|
||||
function handleSoftwareClick(item: { id: string; title: string }): void {
|
||||
// TODO: 阶段二实现软件下载
|
||||
console.log('[RightPanel] 软件下载点击:', item.title)
|
||||
}
|
||||
|
||||
// ── 趣味问答 ──
|
||||
|
||||
/** 问答题目类型 */
|
||||
interface QuizQuestion {
|
||||
id: string
|
||||
question: string
|
||||
options: string[]
|
||||
correctIndex: number // 正确答案的索引
|
||||
}
|
||||
|
||||
/** 选项标签 */
|
||||
const optionLabels = ['A', 'B', 'C', 'D']
|
||||
|
||||
/** 用户积分 */
|
||||
const userScore = ref(0)
|
||||
|
||||
/** 是否已答题 */
|
||||
const quizAnswered = ref(false)
|
||||
|
||||
/** 用户选择的答案索引 */
|
||||
const quizSelectedIndex = ref(-1)
|
||||
|
||||
/** 问答题目列表(阶段一使用静态数据) */
|
||||
const quizQuestions = ref<QuizQuestion[]>([
|
||||
{
|
||||
id: 'q-1',
|
||||
question: 'IT服务台电话分机号是?',
|
||||
options: ['8001', '8002', '8003', '8004'],
|
||||
correctIndex: 0,
|
||||
},
|
||||
{
|
||||
id: 'q-2',
|
||||
question: '电脑无法连接WiFi时,首先应该检查什么?',
|
||||
options: ['重启路由器', 'WiFi适配器是否禁用', '联系网络管理员', '重新安装系统'],
|
||||
correctIndex: 1,
|
||||
},
|
||||
{
|
||||
id: 'q-3',
|
||||
question: 'VPN申请一般需要几个工作日?',
|
||||
options: ['1个工作日', '1-3个工作日', '3-5个工作日', '5个工作日以上'],
|
||||
correctIndex: 1,
|
||||
},
|
||||
])
|
||||
|
||||
/** 当前问答题目 */
|
||||
const currentQuiz = computed<QuizQuestion | null>(() => {
|
||||
return quizQuestions.value[0] || null
|
||||
})
|
||||
|
||||
/**
|
||||
* 用户回答问答
|
||||
* @param index - 用户选择的选项索引
|
||||
*/
|
||||
function handleQuizAnswer(index: number): void {
|
||||
if (quizAnswered.value) return
|
||||
quizAnswered.value = true
|
||||
quizSelectedIndex.value = index
|
||||
|
||||
// 答对加10分
|
||||
if (currentQuiz.value && index === currentQuiz.value.correctIndex) {
|
||||
userScore.value += 10
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* ====== 右侧面板容器 ====== */
|
||||
.right-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
background-color: var(--bg-secondary);
|
||||
border-left: 1px solid var(--border-color);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* ====== 面板区域通用样式 ====== */
|
||||
.right-panel__section {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.right-panel__section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 10px 14px;
|
||||
background-color: var(--bg-tertiary);
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.right-panel__section-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.right-panel__section-title {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.right-panel__section-body {
|
||||
padding: 10px 14px;
|
||||
}
|
||||
|
||||
.right-panel__empty {
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: var(--text-tertiary);
|
||||
padding: 16px 0;
|
||||
}
|
||||
|
||||
/* ====== AI推送区 ====== */
|
||||
.right-panel__ai-push {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.ai-push-card {
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--bg-primary);
|
||||
margin-bottom: 8px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.ai-push-card:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.ai-push-card:hover {
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 2px 8px rgba(59, 130, 246, 0.1);
|
||||
}
|
||||
|
||||
.ai-push-card:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.ai-push-card__header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.ai-push-card__icon {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.ai-push-card__type-label {
|
||||
font-size: 11px;
|
||||
padding: 1px 6px;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 处理指南类型 */
|
||||
.ai-push-card--guide .ai-push-card__type-label {
|
||||
background: rgba(34, 197, 94, 0.1);
|
||||
color: #22c55e;
|
||||
}
|
||||
|
||||
/* 申请流程类型 */
|
||||
.ai-push-card--process .ai-push-card__type-label {
|
||||
background: rgba(59, 130, 246, 0.1);
|
||||
color: #3b82f6;
|
||||
}
|
||||
|
||||
/* 软件下载类型 */
|
||||
.ai-push-card--download .ai-push-card__type-label {
|
||||
background: rgba(168, 85, 247, 0.1);
|
||||
color: #a855f7;
|
||||
}
|
||||
|
||||
.ai-push-card__title {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.ai-push-card__subtitle {
|
||||
font-size: 11px;
|
||||
color: var(--text-tertiary);
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
/* ====== 常用资源标签页 ====== */
|
||||
.right-panel__resources {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.right-panel__tabs {
|
||||
display: flex;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.right-panel__tab {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 13px;
|
||||
color: var(--text-tertiary);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
border-bottom: 2px solid transparent;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.right-panel__tab--active {
|
||||
color: var(--accent);
|
||||
border-bottom-color: var(--accent);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.right-panel__tab:hover:not(.right-panel__tab--active) {
|
||||
color: var(--text-secondary);
|
||||
background: var(--bg-tertiary);
|
||||
}
|
||||
|
||||
.right-panel__tab-content {
|
||||
padding: 8px 14px;
|
||||
}
|
||||
|
||||
.resource-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.resource-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.resource-item:hover {
|
||||
background: var(--bg-tertiary);
|
||||
}
|
||||
|
||||
.resource-item:active {
|
||||
background: var(--border-color);
|
||||
}
|
||||
|
||||
.resource-item__icon {
|
||||
font-size: 20px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.resource-item__info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.resource-item__title {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.resource-item__desc {
|
||||
font-size: 11px;
|
||||
color: var(--text-tertiary);
|
||||
display: block;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.resource-item__arrow {
|
||||
font-size: 14px;
|
||||
color: var(--text-tertiary);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ====== 趣味问答 ====== */
|
||||
.right-panel__quiz {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.right-panel__quiz-score {
|
||||
margin-left: auto;
|
||||
font-size: 12px;
|
||||
color: var(--color-warning);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.quiz-question {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
line-height: 1.5;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.quiz-options {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.quiz-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--border-color);
|
||||
background: var(--bg-primary);
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
font-family: inherit;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.quiz-option:hover:not(:disabled) {
|
||||
border-color: var(--accent);
|
||||
background: var(--accent-soft);
|
||||
}
|
||||
|
||||
.quiz-option:active:not(:disabled) {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.quiz-option:disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* 正确选项 */
|
||||
.quiz-option--correct {
|
||||
border-color: #22c55e;
|
||||
background: rgba(34, 197, 94, 0.1);
|
||||
}
|
||||
|
||||
/* 错误选项 */
|
||||
.quiz-option--wrong {
|
||||
border-color: #ef4444;
|
||||
background: rgba(239, 68, 68, 0.1);
|
||||
}
|
||||
|
||||
.quiz-option__label {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 50%;
|
||||
background: var(--bg-tertiary);
|
||||
color: var(--text-secondary);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.quiz-option--correct .quiz-option__label {
|
||||
background: #22c55e;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.quiz-option--wrong .quiz-option__label {
|
||||
background: #ef4444;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.quiz-option__text {
|
||||
font-size: 13px;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.quiz-result {
|
||||
margin-top: 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.quiz-result--correct {
|
||||
color: #22c55e;
|
||||
}
|
||||
|
||||
.quiz-result--wrong {
|
||||
color: #ef4444;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,148 @@
|
||||
<!-- =============================================================================
|
||||
// 企微IT智能服务台 — H5用户端软件下载入口组件
|
||||
// =============================================================================
|
||||
// 说明:展示所有可下载的软件,按分类分组
|
||||
// 显示名称 + 版本号 + 平台标签
|
||||
// 点击下载链接直接下载
|
||||
// ============================================================================= -->
|
||||
|
||||
<template>
|
||||
<div class="software-downloads">
|
||||
<!-- 加载中提示 -->
|
||||
<div v-if="loading" class="software-downloads__loading">
|
||||
<van-loading size="24px" vertical>加载中...</van-loading>
|
||||
</div>
|
||||
|
||||
<!-- 无数据提示 -->
|
||||
<div v-else-if="Object.keys(groupedDownloads).length === 0" class="software-downloads__empty">
|
||||
<van-empty description="暂无软件下载" image="search" />
|
||||
</div>
|
||||
|
||||
<!-- 按分类展示软件下载列表 -->
|
||||
<template v-else>
|
||||
<div
|
||||
v-for="(items, category) in groupedDownloads"
|
||||
:key="category"
|
||||
class="software-downloads__group"
|
||||
>
|
||||
<!-- 分类标题 -->
|
||||
<div class="software-downloads__category">{{ category }}</div>
|
||||
<!-- 该分类下的软件列表 -->
|
||||
<van-cell-group inset>
|
||||
<van-cell
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
:title="item.name"
|
||||
:label="versionLabel(item)"
|
||||
:icon="item.icon || 'down'"
|
||||
is-link
|
||||
@click="handleDownload(item)"
|
||||
>
|
||||
<!-- 右侧平台标签 -->
|
||||
<template #right-icon>
|
||||
<div class="software-downloads__platforms">
|
||||
<span
|
||||
v-for="platform in item.platforms"
|
||||
:key="platform"
|
||||
class="software-downloads__tag"
|
||||
>
|
||||
{{ platform }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</van-cell>
|
||||
</van-cell-group>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* SoftwareDownloads 软件下载入口组件
|
||||
* 从 API 获取软件下载数据,按分类分组展示
|
||||
* 显示名称、版本号、平台标签,点击下载
|
||||
*/
|
||||
|
||||
import { computed } from 'vue'
|
||||
import { useConversationStore } from '@/stores/conversation'
|
||||
import type { SoftwareDownload } from '@/api/conversation'
|
||||
|
||||
const store = useConversationStore()
|
||||
|
||||
/** 加载状态:当软件下载列表为空且未初始化时视为加载中 */
|
||||
const loading = computed(() => {
|
||||
return store.softwareDownloads.length === 0 && !store.initialized
|
||||
})
|
||||
|
||||
/** 软件下载按分类分组(从 store 计算属性获取) */
|
||||
const groupedDownloads = computed(() => store.softwareDownloadsByCategory)
|
||||
|
||||
/**
|
||||
* 生成版本号标签文字
|
||||
* @param item 软件下载项
|
||||
* @returns 版本号文字(如 "v2.1.0")
|
||||
*/
|
||||
function versionLabel(item: SoftwareDownload): string {
|
||||
return item.version ? `版本: ${item.version}` : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理下载点击
|
||||
* 在企微内置浏览器中打开下载链接
|
||||
* @param item 软件下载项
|
||||
*/
|
||||
function handleDownload(item: SoftwareDownload): void {
|
||||
window.open(item.download_url, '_blank')
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 软件下载容器 */
|
||||
.software-downloads {
|
||||
padding: 8px 0;
|
||||
}
|
||||
|
||||
/* 加载中状态 */
|
||||
.software-downloads__loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 40px 0;
|
||||
}
|
||||
|
||||
/* 空数据状态 */
|
||||
.software-downloads__empty {
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
/* 分类分组容器 */
|
||||
.software-downloads__group {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
/* 分类标题 */
|
||||
.software-downloads__category {
|
||||
font-size: 13px;
|
||||
color: var(--text-tertiary);
|
||||
padding: 8px 16px 4px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 平台标签容器 */
|
||||
.software-downloads__platforms {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* 单个平台标签 */
|
||||
.software-downloads__tag {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
padding: 1px 6px;
|
||||
border-radius: 3px;
|
||||
background-color: var(--accent-soft);
|
||||
color: var(--accent);
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user