mirror of
https://github.com/yangjian102621/geekai.git
synced 2026-04-23 11:34:27 +08:00
267 lines
7.3 KiB
Vue
267 lines
7.3 KiB
Vue
<template>
|
|
<div class="apps-page">
|
|
<div class="apps-filter mb-8 px-3">
|
|
<CustomTabs :model-value="activeTab" @update:model-value="activeTab = $event">
|
|
<CustomTabPane name="all" label="全部分类">
|
|
<div class="app-list">
|
|
<van-list v-model="loading" :finished="true" finished-text="" @load="fetchApps()">
|
|
<van-cell v-for="item in apps" :key="item.id" class="app-cell">
|
|
<div class="app-card">
|
|
<div class="app-info">
|
|
<div class="app-image">
|
|
<van-image :src="item.icon" round />
|
|
</div>
|
|
<div class="app-detail">
|
|
<div class="app-title">{{ item.name }}</div>
|
|
<div class="app-desc">{{ item.hello_msg }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="app-actions">
|
|
<van-button
|
|
size="small"
|
|
type="primary"
|
|
class="action-btn"
|
|
@click="useRole(item.id)"
|
|
>对话</van-button
|
|
>
|
|
<van-button
|
|
size="small"
|
|
:type="hasRole(item.key) ? 'danger' : 'success'"
|
|
class="action-btn"
|
|
@click="updateRole(item, hasRole(item.key) ? 'remove' : 'add')"
|
|
>
|
|
{{ hasRole(item.key) ? '移除' : '添加' }}
|
|
</van-button>
|
|
</div>
|
|
</div>
|
|
</van-cell>
|
|
</van-list>
|
|
</div>
|
|
</CustomTabPane>
|
|
<CustomTabPane v-for="type in appTypes" :key="type.id" :name="type.id" :label="type.name">
|
|
<div class="app-list">
|
|
<van-list
|
|
v-model="loading"
|
|
:finished="true"
|
|
finished-text=""
|
|
@load="fetchApps(type.id)"
|
|
>
|
|
<van-cell v-for="item in typeApps" :key="item.id" class="app-cell">
|
|
<div class="app-card">
|
|
<div class="app-info">
|
|
<div class="app-image">
|
|
<van-image :src="item.icon" round />
|
|
</div>
|
|
<div class="app-detail">
|
|
<div class="app-title">{{ item.name }}</div>
|
|
<div class="app-desc">{{ item.hello_msg }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="app-actions">
|
|
<van-button
|
|
size="small"
|
|
type="primary"
|
|
class="action-btn"
|
|
@click="useRole(item.id)"
|
|
>对话</van-button
|
|
>
|
|
<van-button
|
|
size="small"
|
|
:type="hasRole(item.key) ? 'danger' : 'success'"
|
|
class="action-btn"
|
|
@click="updateRole(item, hasRole(item.key) ? 'remove' : 'add')"
|
|
>
|
|
{{ hasRole(item.key) ? '移除' : '添加' }}
|
|
</van-button>
|
|
</div>
|
|
</div>
|
|
</van-cell>
|
|
</van-list>
|
|
</div>
|
|
</CustomTabPane>
|
|
</CustomTabs>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import CustomTabPane from '@/components/ui/CustomTabPane.vue'
|
|
import CustomTabs from '@/components/ui/CustomTabs.vue'
|
|
import { checkSession } from '@/store/cache'
|
|
import { httpGet, httpPost } from '@/utils/http'
|
|
import { arrayContains, removeArrayItem, showLoginDialog, substr } from '@/utils/libs'
|
|
import { showNotify } from 'vant'
|
|
import { onMounted, ref } from 'vue'
|
|
import { useRouter } from 'vue-router'
|
|
|
|
const router = useRouter()
|
|
const isLogin = ref(false)
|
|
const apps = ref([])
|
|
const typeApps = ref([])
|
|
const appTypes = ref([])
|
|
const loading = ref(false)
|
|
const roles = ref([])
|
|
const activeTab = ref(0)
|
|
|
|
onMounted(() => {
|
|
checkSession()
|
|
.then((user) => {
|
|
isLogin.value = true
|
|
roles.value = user.chat_roles
|
|
})
|
|
.catch(() => {})
|
|
fetchAppTypes()
|
|
fetchApps()
|
|
})
|
|
|
|
const fetchAppTypes = () => {
|
|
httpGet('/api/app/type/list')
|
|
.then((res) => {
|
|
appTypes.value = res.data
|
|
})
|
|
.catch((e) => {
|
|
showNotify({ type: 'danger', message: '获取应用分类失败:' + e.message })
|
|
})
|
|
}
|
|
|
|
const fetchApps = (typeId = '') => {
|
|
httpGet('/api/app/list', { tid: typeId })
|
|
.then((res) => {
|
|
const items = res.data
|
|
// 处理 hello message
|
|
for (let i = 0; i < items.length; i++) {
|
|
items[i].intro = substr(items[i].hello_msg, 80)
|
|
}
|
|
|
|
if (typeId) {
|
|
typeApps.value = items
|
|
} else {
|
|
apps.value = items
|
|
}
|
|
})
|
|
.catch((e) => {
|
|
showNotify({ type: 'danger', message: '获取应用失败:' + e.message })
|
|
})
|
|
}
|
|
|
|
const updateRole = (row, opt) => {
|
|
if (!isLogin.value) {
|
|
return showLoginDialog(router)
|
|
}
|
|
|
|
let actionTitle = ''
|
|
if (opt === 'add') {
|
|
actionTitle = '添加应用'
|
|
const exists = arrayContains(roles.value, row.key)
|
|
if (exists) {
|
|
return
|
|
}
|
|
roles.value.push(row.key)
|
|
} else {
|
|
actionTitle = '移除应用'
|
|
const exists = arrayContains(roles.value, row.key)
|
|
if (!exists) {
|
|
return
|
|
}
|
|
roles.value = removeArrayItem(roles.value, row.key)
|
|
}
|
|
httpPost('/api/app/update', { keys: roles.value })
|
|
.then(() => {
|
|
showNotify({ type: 'success', message: actionTitle + '成功!' })
|
|
})
|
|
.catch((e) => {
|
|
showNotify({ type: 'danger', message: actionTitle + '失败:' + e.message })
|
|
})
|
|
}
|
|
|
|
const hasRole = (roleKey) => {
|
|
return arrayContains(roles.value, roleKey, (v1, v2) => v1 === v2)
|
|
}
|
|
|
|
const useRole = (roleId) => {
|
|
if (!isLogin.value) {
|
|
return showLoginDialog(router)
|
|
}
|
|
router.push(`/mobile/chat/session?role_id=${roleId}`)
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.apps-page {
|
|
min-height: 100vh;
|
|
background-color: var(--van-background);
|
|
|
|
.apps-filter {
|
|
:deep(.van-tabs__nav) {
|
|
background: var(--van-background-2);
|
|
}
|
|
}
|
|
|
|
.app-list {
|
|
padding: 0;
|
|
|
|
.app-cell {
|
|
padding: 0;
|
|
margin-bottom: 15px;
|
|
|
|
.app-card {
|
|
background: var(--van-cell-background);
|
|
border-radius: 12px;
|
|
padding: 15px;
|
|
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
|
|
|
.app-info {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 15px;
|
|
|
|
.app-image {
|
|
width: 60px;
|
|
height: 60px;
|
|
margin-right: 15px;
|
|
|
|
:deep(.van-image) {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
}
|
|
|
|
.app-detail {
|
|
flex: 1;
|
|
|
|
.app-title {
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
margin-bottom: 5px;
|
|
color: var(--van-text-color);
|
|
}
|
|
|
|
.app-desc {
|
|
font-size: 13px;
|
|
color: var(--van-gray-6);
|
|
display: -webkit-box;
|
|
-webkit-box-orient: vertical;
|
|
-webkit-line-clamp: 2;
|
|
overflow: hidden;
|
|
}
|
|
}
|
|
}
|
|
|
|
.app-actions {
|
|
display: flex;
|
|
gap: 10px;
|
|
|
|
.action-btn {
|
|
flex: 1;
|
|
border-radius: 20px;
|
|
padding: 0 10px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|