From 1c1ce2c508aa108d06b248937646a6877a212c69 Mon Sep 17 00:00:00 2001 From: zhangxiao <898441624@qq.com> Date: 星期二, 06 八月 2024 10:13:12 +0800 Subject: [PATCH] Merge branch 'master' of http://192.168.5.5:10010/r/web/flow_web --- src/views/dmx/IntelligentAgent/components/editAgent.vue | 147 +- src/views/dmx/knowledgeLib/tool.vue | 15 src/views/dmx/knowledgeLib/index.vue | 26 src/hooks/permission.ts | 44 src/views/dmx/agent/components/sessionAction.vue | 265 +++++ src/views/dmx/knowledgeLib/test.vue | 8 src/views/dmx/IntelligentAgent/components/sessionAction.vue | 265 +++++ src/views/dmx/agent/components/custom-settings.vue | 244 +++++ src/views/dmx/agent/components/rules-preset.vue | 51 + src/views/dmx/agent/components/card-wrap.vue | 204 ++++ src/views/dmx/agent/components/quality-inspection.vue | 115 ++ src/router/guard/permission.ts | 1 src/store/modules/user/types.ts | 1 src/views/dmx/agent/components/addAgent.vue | 149 +++ src/views/dmx/agent/mock.ts | 186 ++++ .idea/codeStyles/Project.xml | 4 src/views/dmx/agent/locale/zh-CN.ts | 20 src/views/login/components/login-form.vue | 8 src/views/dmx/agent/locale/en-US.ts | 20 src/store/modules/user/index.ts | 6 src/views/dmx/agent/components/editAgent.vue | 332 +++++++ src/views/dmx/agent/components/the-service.vue | 57 + src/utils/auth.ts | 15 src/views/dmx/IntelligentAgent/components/agent.vue | 149 +++ src/api/authority.ts | 4 src/views/dmx/IntelligentAgent/components/addAgent.vue | 2 src/views/dmx/agent/index.vue | 350 +++++++ src/views/dmx/knowledgeLib/config.vue | 10 28 files changed, 2,582 insertions(+), 116 deletions(-) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 70dac63..3e22f4b 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -3,7 +3,7 @@ <HTMLCodeStyleSettings> <option name="HTML_SPACE_INSIDE_EMPTY_TAG" value="true" /> </HTMLCodeStyleSettings> - <JSCodeStyleSettings> + <JSCodeStyleSettings version="0"> <option name="FORCE_SEMICOLON_STYLE" value="true" /> <option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" /> <option name="FORCE_QUOTE_STYlE" value="true" /> @@ -11,7 +11,7 @@ <option name="SPACES_WITHIN_OBJECT_LITERAL_BRACES" value="true" /> <option name="SPACES_WITHIN_IMPORTS" value="true" /> </JSCodeStyleSettings> - <TypeScriptCodeStyleSettings> + <TypeScriptCodeStyleSettings version="0"> <option name="FORCE_SEMICOLON_STYLE" value="true" /> <option name="SPACE_BEFORE_FUNCTION_LEFT_PARENTH" value="false" /> <option name="FORCE_QUOTE_STYlE" value="true" /> diff --git a/src/api/authority.ts b/src/api/authority.ts index 76e14c9..64cb6ca 100644 --- a/src/api/authority.ts +++ b/src/api/authority.ts @@ -85,8 +85,8 @@ return axios.post('/base/system/user', { user }); } -export function UserDelete(userId) { - return axios.delete('/base/system/user/' + userId); +export function UserDelete(id) { + return axios.delete('/base/system/user/' + id); } export function OrganizationList(key: string) { diff --git a/src/hooks/permission.ts b/src/hooks/permission.ts index de8cdc4..7930d0e 100644 --- a/src/hooks/permission.ts +++ b/src/hooks/permission.ts @@ -1,24 +1,46 @@ -import { RouteLocationNormalized, RouteRecordRaw } from 'vue-router'; -import { useUserStore } from '@/store'; +import { RouteLocationNormalized, RouteRecordRaw } from "vue-router"; +import { useUserStore } from "@/store"; +import { getUserInfo, getUserResources } from "@/utils/auth"; export default function usePermission() { const userStore = useUserStore(); return { accessRouter(route: RouteLocationNormalized | RouteRecordRaw) { - return ( - !route.meta?.requiresAuth || - !route.meta?.roles || - route.meta?.roles?.includes('*') || - route.meta?.roles?.includes(userStore.role) - ); + //閬嶅巻userStore.resource + let isok = false; + let user = getUserResources(); + let resurces: any; + if (userStore.resources) { + resurces = userStore.resources; + } else { + if (user) { + resurces = JSON.parse(user); + } + } + if (resurces) { + resurces.forEach(r => { + if ((r.menuType == 0 || r.menuType == 3) && (route.name == r.component || route.path == r.component)) { + isok = true; + } + }); + return isok; + } else { + return ( + !route.meta?.requiresAuth || + !route.meta?.roles || + route.meta?.roles?.includes("*") || + route.meta?.roles?.includes(userStore.role) + ); + } + }, - findFirstPermissionRoute(_routers: any, role = 'admin') { + findFirstPermissionRoute(_routers: any, role = "admin") { const cloneRouters = [..._routers]; while (cloneRouters.length) { const firstElement = cloneRouters.shift(); if ( firstElement?.meta?.roles?.find((el: string[]) => { - return el.includes('*') || el.includes(role); + return el.includes("*") || el.includes(role); }) ) return { name: firstElement.name }; @@ -27,7 +49,7 @@ } } return null; - }, + } // You can add any rules you want }; } diff --git a/src/router/guard/permission.ts b/src/router/guard/permission.ts index ad3724e..c3e2efb 100644 --- a/src/router/guard/permission.ts +++ b/src/router/guard/permission.ts @@ -5,6 +5,7 @@ import { useUserStore, useAppStore } from '@/store'; import { appRoutes } from '../routes'; import { WHITE_LIST, NOT_FOUND } from '../constants'; +import { defineStore } from "pinia"; export default function setupPermissionGuard(router: Router) { router.beforeEach(async (to, from, next) => { diff --git a/src/store/modules/user/index.ts b/src/store/modules/user/index.ts index c77c21a..0849edf 100644 --- a/src/store/modules/user/index.ts +++ b/src/store/modules/user/index.ts @@ -5,7 +5,7 @@ getUserInfo, LoginData, } from '@/api/user'; -import { setToken, clearToken,setUserInfo } from '@/utils/auth'; +import { setToken, clearToken, setUserInfo, setUserResources, clearUserResources } from "@/utils/auth"; import { removeRouteListener } from '@/utils/route-listener'; import { UserState } from './types'; import useAppStore from '../app'; @@ -28,6 +28,7 @@ accountId: undefined, certification: undefined, role: '', + resources:undefined, }), getters: { @@ -50,6 +51,7 @@ // Reset user's information resetInfo() { + clearUserResources() this.$reset(); }, @@ -70,7 +72,9 @@ name: res.data.nickname, email: res.data.email, }; + this.resources=res.data.resources; setUserInfo(JSON.stringify(userInfo)); + setUserResources(JSON.stringify(this.resources)) } catch (err) { clearToken(); throw err; diff --git a/src/store/modules/user/types.ts b/src/store/modules/user/types.ts index 75fd784..71fae3f 100644 --- a/src/store/modules/user/types.ts +++ b/src/store/modules/user/types.ts @@ -16,4 +16,5 @@ accountId?: string; certification?: number; role: RoleType; + resources:any; } diff --git a/src/utils/auth.ts b/src/utils/auth.ts index d3f72d2..0caf5e8 100644 --- a/src/utils/auth.ts +++ b/src/utils/auth.ts @@ -1,6 +1,7 @@ const TOKEN_KEY = 'token'; const Authorization = 'Authorization'; const UserInfo = 'userInfo'; +const UserResources='userResources' const isLogin = () => { return !!localStorage.getItem(TOKEN_KEY); @@ -35,4 +36,16 @@ localStorage.setItem(UserInfo, info); }; -export { isLogin, getToken, setToken, clearToken,getAuthorization, setAuthorization, getUserInfo, setUserInfo}; +const getUserResources = () => { + return localStorage.getItem(UserResources); +}; + +const setUserResources = (info: string) => { + localStorage.setItem(UserResources, info); +}; + +const clearUserResources = () => { + localStorage.removeItem(UserResources); +}; + +export { isLogin, getToken, setToken, clearToken,getAuthorization, setAuthorization, getUserInfo, setUserInfo,setUserResources,getUserResources,clearUserResources}; diff --git a/src/views/dmx/IntelligentAgent/components/addAgent.vue b/src/views/dmx/IntelligentAgent/components/addAgent.vue index e8562b7..ee4a9bb 100644 --- a/src/views/dmx/IntelligentAgent/components/addAgent.vue +++ b/src/views/dmx/IntelligentAgent/components/addAgent.vue @@ -79,7 +79,7 @@ }, ], }, - kb_ids: ['985eda244efc11ef9a7a0242ac120006'], + kb_ids: [], llm_id: 'qwen-plus', llm_setting: { temperature: 0.1, diff --git a/src/views/dmx/IntelligentAgent/components/agent.vue b/src/views/dmx/IntelligentAgent/components/agent.vue new file mode 100644 index 0000000..ee4a9bb --- /dev/null +++ b/src/views/dmx/IntelligentAgent/components/agent.vue @@ -0,0 +1,149 @@ +<template> + <!-- <a-button type="primary" @click="handleClick" style="margin-left: 10px">--> + <!-- <template #icon>--> + <!-- <icon-plus />--> + <!-- </template>--> + <!-- </a-button>--> + <a-modal + v-model:visible="visible" + title="鍒涘缓鏅鸿兘浣�" + @before-open="handleOpened" + @cancel="handleCancel" + :footer="false" + title-align="start" + width="600px" + > + <a-form + ref="formRef" + :rules="rules" + :model="form" + @submit="handleSubmit" + :style="{ width: '90%', margin: '0 auto' }" + layout="vertical" + > + <a-form-item field="name" label="鏅鸿兘浣撳悕绉�"> + <a-input v-model="form.name" placeholder="璇疯緭鍏ュ悕绉�" /> + </a-form-item> + <a-form-item label="浣犲笇鏈涙櫤鑳戒綋鐨勮鑹叉槸浠�涔堬紝鍏蜂綋瀹屾垚浠�涔堜换鍔★紵"> + <a-textarea + v-model="form.prompt_config.system" + placeholder="" + style="height: 180px" + /> + </a-form-item> + <a-form-item> + <div style="width: 100%; text-align: right"> + <a-button @click="visible = false">鍙栨秷</a-button> + <a-button style="margin-left: 10px" type="primary" html-type="submit" + >纭畾</a-button + > + <editAgent + ref="editAgentKuai" + typeAngint="add" + :formData="form" + @cancelModal="handleCancel" + ></editAgent> + </div> + </a-form-item> + </a-form> + </a-modal> +</template> + +<script lang="ts" setup> + import { onMounted, onBeforeMount, reactive, ref } from 'vue'; + import editAgent from '@/views/dmx/IntelligentAgent/components/editAgent.vue'; + + const visible = ref(false); + const loading = ref(false); + const editAgentKuai = ref(); + const form = reactive({ + name: '', + icon: '', + language: 'English', + prompt_config: { + empty_response: '', + prologue: '浣犲ソ锛� 鎴戞槸浣犵殑鍔╃悊锛屾湁浠�涔堝彲浠ュ府鍒颁綘鐨勫悧锛�', + quote: true, + self_rag: true, + system: + '绀轰緥锛歕n' + + '浣犳槸 XX锛屽叿鏈� XX 缁忛獙锛屾搮闀� XX锛屸�n' + + '浣犵殑浠诲姟鏄� XX 锛岄渶瑕佹寜鐓т互涓嬫楠ゆ墽琛岋細\n' + + '1. XX\n' + + '2. XX\n' + + '3. 鈥n', + parameters: [ + { + key: 'knowledge', + optional: false, + }, + ], + }, + kb_ids: [], + llm_id: 'qwen-plus', + llm_setting: { + temperature: 0.1, + top_p: 0.3, + presence_penalty: 0.4, + frequency_penalty: 0.7, + max_tokens: 512, + }, + similarity_threshold: 0.2, + vector_similarity_weight: 0.30000000000000004, + top_n: 8, + }); + const formRef = ref(null); + + const rules = { + name: [ + { + required: true, + message: '鍚嶇О涓嶅厑璁镐负绌�', + }, + ], + }; + + const handleSubmit = ({ values, errors }) => { + console.log('values:', values, '\nerrors:', errors); + if (!errors) { + editAgentKuai.value.handleClick(form); + } + }; + + const handleClick = () => { + visible.value = true; + }; + defineExpose({ + handleClick, + }); + + const handleCancel = () => { + visible.value = false; + formRef.value.resetFields(); + form.name = ''; + }; + + const handleOpened = (el) => { + // Object.assign(form,{ + // name: '',// 鐢ㄦ埛鍚� + // nameJoin: '',// 鏄电О + // post: '',// 宀椾綅 + // txt: '',// 澶囨敞 + // }); + formRef.value.resetFields(); + form.name = ''; + form.prompt_config.system = + '绀轰緥锛歕n' + + '浣犳槸 XX锛屽叿鏈� XX 缁忛獙锛屾搮闀� XX锛屸�n' + + '浣犵殑浠诲姟鏄� XX 锛岄渶瑕佹寜鐓т互涓嬫楠ゆ墽琛岋細\n' + + '1. XX\n' + + '2. XX\n' + + '3. 鈥n'+ + '{knowledge}'; + }; + + const file = ref(); + + onBeforeMount(() => {}); + onMounted(() => {}); +</script> diff --git a/src/views/dmx/IntelligentAgent/components/editAgent.vue b/src/views/dmx/IntelligentAgent/components/editAgent.vue index d1d6d6c..f10b761 100644 --- a/src/views/dmx/IntelligentAgent/components/editAgent.vue +++ b/src/views/dmx/IntelligentAgent/components/editAgent.vue @@ -37,41 +37,45 @@ <a-input v-model="form.name" placeholder="璇疯緭鍏ユ櫤鑳戒綋鍚嶇О" style="width:200px;margin-top: 10px" /> </a-collapse-item> <a-collapse-item header="AI妯″瀷閰嶇疆" key="1"> - <a-space direction="vertical" size="large"> - <a-select :size="'large'" v-model="form.llm_id" :style="{width:'25rem'}" placeholder="璇烽�夋嫨 ..."> - <a-optgroup - :label="index" - v-for="(item, index) in modelList" - :key="index" - > - <a-option - v-for="obj in item" - :key="obj.fid" - :disabled="!obj.available" - :value="obj.llm_id" + <a-form-item field="llm_id" label="妯″瀷"> + <a-space direction="vertical" size="large"> + <a-select :size="'large'" field="llm_id" v-model="form.llm_id" :style="{width:'25rem'}" placeholder="璇烽�夋嫨 ..."> + <a-optgroup + :label="index" + v-for="(item, index) in modelList" + :key="index" > - {{ obj.llm_name }} - </a-option> - </a-optgroup> + <a-option + v-for="obj in item" + :key="obj.fid" + :disabled="!obj.available" + :value="obj.llm_id" + > + {{ obj.llm_name }} + </a-option> + </a-optgroup> </a-select> </a-space> + </a-form-item> </a-collapse-item> <a-collapse-item header="寮�鍦哄紩瀵�" :key="'2'" disabled> </a-collapse-item> - <a-collapse-item header="鐭ヨ瘑搴�" key="3"> - <a-select - v-model="form.kb_ids" - :style="{ width: '25rem' }" - placeholder="璇烽�夋嫨 ..." - multiple - > - <a-option - v-for="item in tabs" - :key="item.id" - :value="item.id" - >{{ item.name }}</a-option + <a-collapse-item header="鐭ヨ瘑搴�" key="3"> + <a-form-item field="kb_ids" label="鐭ヨ瘑搴�"> + <a-select + v-model="form.kb_ids" + :style="{ width: '25rem' }" + placeholder="璇烽�夋嫨 ..." + multiple > - </a-select> + <a-option + v-for="item in tabs" + :key="item.id" + :value="item.id" + >{{ item.name }}</a-option + > + </a-select> + </a-form-item> </a-collapse-item> <a-collapse-item header="宸ュ叿" key="4" disabled> </a-collapse-item> @@ -102,29 +106,7 @@ </div> </div> <div class="main-container-rt"> - <div :style="{ height: heightrg }"> - <div style="padding: 10px"> - <a-avatar :style="{ backgroundColor: '#3370ff' }"> - <img - :style="{ width: '100%' }" - alt="dessert" - src="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a20012a2d4d5b9db43dfc6a01fe508c0.png~tplv-uwbnlip3yd-webp.webp" - /> - </a-avatar> - 璋冭瘯棰勮 - </div> - <a-divider style="margin: 0; margin-left: 10px" /> - - <div class="bottom"> - <div class="input"> - <a-input placeholder="杈撳叆鎮ㄦ兂浜嗚В鐨勫唴瀹癸紝鎸塃nter鍙戦��"> - <template #suffix> - <icon-send style="cursor: pointer" /> - </template> </a-input - ></div> - <div class="text">鍐呭鐢盇I鐢熸垚锛屼粎渚涘弬鑰�</div> - </div> - </div> + <sessionAction></sessionAction> </div> </div> </a-modal> @@ -138,6 +120,7 @@ import { dialogSet } from '@/api/Agent'; import { Message } from '@arco-design/web-vue'; import EventBus from "@/utils/EventBus"; + import sessionAction from "@/views/dmx/IntelligentAgent/components/sessionAction.vue"; const { setLoading } = useLoading(true); const props = defineProps(['typeAngint', 'formData']); const visible = ref(false); @@ -157,7 +140,8 @@ '浣犵殑浠诲姟鏄� XX 锛岄渶瑕佹寜鐓т互涓嬫楠ゆ墽琛岋細\n' + '1. XX\n' + '2. XX\n' + - '3. 鈥n', + '3. 鈥n' + + '{knowlege}', parameters: [ { key: 'knowledge', @@ -165,7 +149,7 @@ }, ], }, - kb_ids: ['985eda244efc11ef9a7a0242ac120006'], + kb_ids: [], llm_id: 'qwen-plus', llm_setting: { temperature: 0.1, @@ -185,7 +169,6 @@ const formRef = ref(null); let tabs = ref([]); const height = ref('calc(100vh - 150px)'); - const heightrg = ref('calc(100vh - 100px)'); const emit = defineEmits(['cancelModal']); const rules = { name: [ @@ -194,24 +177,37 @@ message: '鍚嶇О涓嶅厑璁镐负绌�', }, ], + llm_id: [ + { + required: true, + message: '妯″瀷涓嶈兘涓虹┖', + }, + ], + kb_ids: [ + { + required: true, + message: '鐭ヨ瘑搴撲笉鑳戒负绌�', + }, + ], }; const handleSubmit = async ({ values, errors }) => { // console.log('values:', values, '\nerrors:', errors) - let title = '鍒涘缓鎴愬姛'; - let formNew = { ...form }; - if (props.typeAngint == 'edit') { - formNew.dialog_id = form.id; - delete formNew.id; - delete formNew.off; - title = '淇敼鎴愬姛'; - } - - const data = await dialogSet(formNew); - if (data.code == 0) { - Message.success(title); - handleCancel(); - EventBus.emit('queryList'); + if(!errors){ + let title = '鍒涘缓鎴愬姛'; + let formNew = { ...form }; + if (props.typeAngint == 'edit') { + formNew.dialog_id = form.id; + delete formNew.id; + delete formNew.off; + title = '淇敼鎴愬姛'; + } + const data = await dialogSet(formNew); + if (data.code == 0) { + Message.success(title); + handleCancel(); + EventBus.emit('queryList'); + } } }; @@ -228,8 +224,11 @@ visible.value = true; nextTick(() => { Object.assign(form, data); - console.log(form); + console.log(form,'浼犲��'); system.value = form.prompt_config.system; + if(tabs.value && tabs.value.length>0){ + form.kb_ids = [tabs.value[0].id]; + } }); }; defineExpose({ @@ -280,8 +279,10 @@ try { const { data } = await queryKbList(params); console.log(data, 'data'); - tabs.value = data; - console.log(tabs.value, 'tabs'); + nextTick(() => { + tabs.value = data; + console.log(tabs.value, 'tabs'); + }); } catch (err) { // you can report use errorHandler or other } finally { @@ -324,4 +325,8 @@ line-height: 40px; } } + :deep(.arco-textarea-wrapper.arco-textarea-disabled){ + background: var(--color-bg-2); + color: var(--color-text-1); + } </style> diff --git a/src/views/dmx/IntelligentAgent/components/sessionAction.vue b/src/views/dmx/IntelligentAgent/components/sessionAction.vue new file mode 100644 index 0000000..e084802 --- /dev/null +++ b/src/views/dmx/IntelligentAgent/components/sessionAction.vue @@ -0,0 +1,265 @@ +<template> + <div :style="{ height: heightrg }"> + <div style="padding: 10px"> + <a-avatar :style="{ backgroundColor: '#3370ff' }"> + <img + :style="{ width: '100%' }" + alt="dessert" + src="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a20012a2d4d5b9db43dfc6a01fe508c0.png~tplv-uwbnlip3yd-webp.webp" + /> + </a-avatar> + 璋冭瘯棰勮 + </div> + <a-divider style="margin: 0; margin-left: 10px" /> + <a-scrollbar + ref="scrollbar" + id="home" + class="chat-list" + style="width: 90%; overflow: auto; height: 70vh; margin: 0px auto;" + > + <div class="chat-item" v-for="sessionDetail in sessionDetailList"> + <a-comment + v-if="sessionDetail.role === 'user'" + avatar="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp" + > + <template #content> + <div :class="{ light: theme === 'light' }" style="background-color: var(--color-bg-2);color: var(--color-text-3);border: none;padding: 16px;">{{ + sessionDetail.content + }}</div> + </template> + </a-comment> + <a-comment + v-else-if="sessionDetail.role === 'assistant'" + avatar="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/9eeb1800d9b78349b24682c3518ac4a3.png~tplv-uwbnlip3yd-webp.webp" + > + <template #content> + <a-card + class="chat-item-answer" + style="background-color: var(--color-bg-2);color: var(--color-text-3);border: none" + > + <div :class="{ light: theme === 'light' }">{{ + sessionDetail.content + }}</div> + </a-card> + </template> + </a-comment> + <a-comment + v-else-if="sessionDetail.role === 'last'" + avatar="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/9eeb1800d9b78349b24682c3518ac4a3.png~tplv-uwbnlip3yd-webp.webp" + > + <template #content> + <a-textarea + readonly + auto-size + v-model="displayedText" + class="chat-item-answer" + style="background-color: var(--color-bg-2);color: var(--color-text-3);border: none" + > + </a-textarea> + </template> + </a-comment> + </div> + </a-scrollbar> + <div class="bottom"> + <div class="input"> + <a-input + v-model="inputMsg" + @keydown.enter="sendMessage" + placeholder="杈撳叆鎮ㄦ兂浜嗚В鐨勫唴瀹癸紝鎸塃nter鍙戦��" + > + <template #suffix> + <icon-send style="cursor: pointer" @click="sendMessage" /> + </template> </a-input + ></div> + <div class="text">鍐呭鐢盇I鐢熸垚锛屼粎渚涘弬鑰�</div> + </div> + </div> +</template> + +<script setup lang="ts"> +import { + IconMoreVertical, + IconQuestionCircleFill, + IconPoweroff, + IconCommon, + IconSend, +} from '@arco-design/web-vue/es/icon'; +import img1 from '@/assets/images/u64.png'; +import img2 from '@/assets/images/u69.png'; +import img3 from '@/assets/images/u74.png'; +import { ref, onMounted, computed, reactive, nextTick, watch } from 'vue'; +import { useUserStore, useAppStore } from '@/store'; +import { + sessionListApi, + deleteSessionApi, + getSessionDetailsApi, + chatApi, +} from '@/api/session'; +import { Message } from '@arco-design/web-vue'; +const userStore = useUserStore(); +const appStore = useAppStore(); +const theme = computed(() => { + return appStore.theme; +}); +const heightrg = ref('calc(100vh - 100px)'); +const sessionList = ref([]); //浼氳瘽鍒楄〃 +const sessionDetailList = ref([]); //鏍规嵁浼氳瘽id鍑烘潵鐨勪細璇濊鎯� +const activeSessionId = ref(''); +const inputMsg = ref(''); +const scrollbar = ref(null); + +const currIndex = ref(0); +const displayedText = ref(''); // 姝e湪鏄剧ず鐨勬枃瀛� +let timer: number | null = null; +const streamStr = ref(''); +const modalObj = reactive({ add: false }); +//鏌ヨ浼氳瘽鍒楄〃 +const querySessionList = async () => { + const { code, data } = await sessionListApi(); + if (code === 200) { + sessionList.value = data; + if (Array.isArray(data) && data.length > 0) { + activeSessionId.value = data[1].id; + const res = await getSessionDetailsApi(data[0].id); + if (res.code === 200) { + sessionDetailList.value = res.data.message; + refreshScroll(); + } + } + } else { + Message.warning('鏌ヨ澶辫触'); + } +}; +//鏍规嵁浼氳瘽id鍒犻櫎浼氳瘽 +const deleteSession = async (session) => { + const { code } = await deleteSessionApi([session.id]); + if (code === 200) { + Message.success('鍒犻櫎鎴愬姛'); + querySessionList(); + } +}; +// eslint-disable-next-line prettier/prettier +// 鏂板浼氳瘽涔嬪悗鍒锋柊浼氳瘽鍒楄〃 +const addSession = () => { + querySessionList(); +}; +// 鍒濆鍖栨暟鎹� +const initData = () => { + querySessionList(); +}; +// 鑾峰彇鐧诲綍淇℃伅 +const userName = computed(() => { + return userStore.name; +}); +const avatar = computed(() => { + return userStore.avatar; +}); +const refreshScroll = () => { + nextTick(() => { + const container = document.getElementById('home'); + scrollbar.value.scrollTop(container.scrollHeight); + }); +}; +// 鏍规嵁浼氳瘽id 鏌ヨ浼氳瘽璇︽儏 +const querySessionDetail = async (session) => { + activeSessionId.value = session.id; + const { code, data } = await getSessionDetailsApi(session.id); + if (code === 200) { + sessionDetailList.value = data.message; + refreshScroll(); //鍒锋柊婊氬姩鏉′綅缃� + } +}; +const sendMessage = async () => { + if (inputMsg.value) { + const { code, data } = await chatApi({ + conversation_id: activeSessionId.value, + messages: inputMsg.value, + }); + const res = await getSessionDetailsApi(activeSessionId.value); + if (res.code === 200) { + sessionDetailList.value = res.data.message.map((item, index) => { + if (index === res.data.message.length - 1) { + item.role = 'last'; + displayedText.value = ''; + currIndex.value = 0; + streamStr.value = item.content; + startDisplayStr(); + } + return item; + }); + refreshScroll(); + } + inputMsg.value = ''; + } else { + Message.warning('娑堟伅涓嶈兘涓虹┖'); + } +}; +onMounted(() => { + initData(); +}); +//鏂囧瓧鍔ㄦ�佽緭鍑� +const startDisplayStr = () => { + if (timer) { + clearTimeout(timer!); + } + const res = streamStr.value; + // 灏嗘暟缁勪腑鐨勫瓧绗︿覆鎷兼帴璧锋潵 + if (currIndex.value < res.length) { + displayedText.value += res[currIndex.value]; + currIndex.value++; + setTimeout(startDisplayStr, 100); + } else { + clearTimeout(timer!); + timer = null; + } +}; +watch( + () => scrollbar.value, + (newScroll, oldScroll) => { + if (newScroll) { + // 鑾峰彇a-scroll鐨勯珮搴� + const height = newScroll.$el.offsetHeight; + console.log('a-scroll height changed to:', height); + } + }, + { deep: true } +); +</script> + +<style scoped lang="less"> +.container { + width: 100%; + display: flex; +} +//.light { +// color: white !important; +//} +.bottom { + width: 100%; + position: absolute; + bottom: 40px; + left: 0; + + .input { + margin-left: 20%; + width: 60%; + } + + .text { + margin-left: 40%; + font-size: 12px; + color: lightgrey; + line-height: 40px; + } +} +.chat-list { + width: 90%; + margin: 0px auto; + .chat-item { + margin-top: 20px; + .chat-item-answer { + color: white; + } + } +} +</style> diff --git a/src/views/dmx/agent/components/addAgent.vue b/src/views/dmx/agent/components/addAgent.vue new file mode 100644 index 0000000..ee4a9bb --- /dev/null +++ b/src/views/dmx/agent/components/addAgent.vue @@ -0,0 +1,149 @@ +<template> + <!-- <a-button type="primary" @click="handleClick" style="margin-left: 10px">--> + <!-- <template #icon>--> + <!-- <icon-plus />--> + <!-- </template>--> + <!-- </a-button>--> + <a-modal + v-model:visible="visible" + title="鍒涘缓鏅鸿兘浣�" + @before-open="handleOpened" + @cancel="handleCancel" + :footer="false" + title-align="start" + width="600px" + > + <a-form + ref="formRef" + :rules="rules" + :model="form" + @submit="handleSubmit" + :style="{ width: '90%', margin: '0 auto' }" + layout="vertical" + > + <a-form-item field="name" label="鏅鸿兘浣撳悕绉�"> + <a-input v-model="form.name" placeholder="璇疯緭鍏ュ悕绉�" /> + </a-form-item> + <a-form-item label="浣犲笇鏈涙櫤鑳戒綋鐨勮鑹叉槸浠�涔堬紝鍏蜂綋瀹屾垚浠�涔堜换鍔★紵"> + <a-textarea + v-model="form.prompt_config.system" + placeholder="" + style="height: 180px" + /> + </a-form-item> + <a-form-item> + <div style="width: 100%; text-align: right"> + <a-button @click="visible = false">鍙栨秷</a-button> + <a-button style="margin-left: 10px" type="primary" html-type="submit" + >纭畾</a-button + > + <editAgent + ref="editAgentKuai" + typeAngint="add" + :formData="form" + @cancelModal="handleCancel" + ></editAgent> + </div> + </a-form-item> + </a-form> + </a-modal> +</template> + +<script lang="ts" setup> + import { onMounted, onBeforeMount, reactive, ref } from 'vue'; + import editAgent from '@/views/dmx/IntelligentAgent/components/editAgent.vue'; + + const visible = ref(false); + const loading = ref(false); + const editAgentKuai = ref(); + const form = reactive({ + name: '', + icon: '', + language: 'English', + prompt_config: { + empty_response: '', + prologue: '浣犲ソ锛� 鎴戞槸浣犵殑鍔╃悊锛屾湁浠�涔堝彲浠ュ府鍒颁綘鐨勫悧锛�', + quote: true, + self_rag: true, + system: + '绀轰緥锛歕n' + + '浣犳槸 XX锛屽叿鏈� XX 缁忛獙锛屾搮闀� XX锛屸�n' + + '浣犵殑浠诲姟鏄� XX 锛岄渶瑕佹寜鐓т互涓嬫楠ゆ墽琛岋細\n' + + '1. XX\n' + + '2. XX\n' + + '3. 鈥n', + parameters: [ + { + key: 'knowledge', + optional: false, + }, + ], + }, + kb_ids: [], + llm_id: 'qwen-plus', + llm_setting: { + temperature: 0.1, + top_p: 0.3, + presence_penalty: 0.4, + frequency_penalty: 0.7, + max_tokens: 512, + }, + similarity_threshold: 0.2, + vector_similarity_weight: 0.30000000000000004, + top_n: 8, + }); + const formRef = ref(null); + + const rules = { + name: [ + { + required: true, + message: '鍚嶇О涓嶅厑璁镐负绌�', + }, + ], + }; + + const handleSubmit = ({ values, errors }) => { + console.log('values:', values, '\nerrors:', errors); + if (!errors) { + editAgentKuai.value.handleClick(form); + } + }; + + const handleClick = () => { + visible.value = true; + }; + defineExpose({ + handleClick, + }); + + const handleCancel = () => { + visible.value = false; + formRef.value.resetFields(); + form.name = ''; + }; + + const handleOpened = (el) => { + // Object.assign(form,{ + // name: '',// 鐢ㄦ埛鍚� + // nameJoin: '',// 鏄电О + // post: '',// 宀椾綅 + // txt: '',// 澶囨敞 + // }); + formRef.value.resetFields(); + form.name = ''; + form.prompt_config.system = + '绀轰緥锛歕n' + + '浣犳槸 XX锛屽叿鏈� XX 缁忛獙锛屾搮闀� XX锛屸�n' + + '浣犵殑浠诲姟鏄� XX 锛岄渶瑕佹寜鐓т互涓嬫楠ゆ墽琛岋細\n' + + '1. XX\n' + + '2. XX\n' + + '3. 鈥n'+ + '{knowledge}'; + }; + + const file = ref(); + + onBeforeMount(() => {}); + onMounted(() => {}); +</script> diff --git a/src/views/dmx/agent/components/card-wrap.vue b/src/views/dmx/agent/components/card-wrap.vue new file mode 100644 index 0000000..9b876d8 --- /dev/null +++ b/src/views/dmx/agent/components/card-wrap.vue @@ -0,0 +1,204 @@ +<template> + <div class="card-wrap"> + <a-card v-if="loading" :bordered="false" hoverable> + <slot name="skeleton"></slot> + </a-card> + <a-card v-else :bordered="false" hoverable> + <a-space align="start"> + <a-avatar + v-if="icon" + :size="24" + style="margin-right: 8px; background-color: #626aea" + > + <icon-filter /> + </a-avatar> + <a-card-meta> + <template #title> + <a-typography-text style="margin-right: 10px"> + {{ title }} + </a-typography-text> + <template v-if="showTag"> + <a-tag + v-if="open && isExpires === false" + size="small" + color="green" + > + <template #icon> + <icon-check-circle-fill /> + </template> + <span>{{ tagText }}</span> + </a-tag> + <a-tag v-else-if="isExpires" size="small" color="red"> + <template #icon> + <icon-check-circle-fill /> + </template> + <span>{{ expiresTagText }}</span> + </a-tag> + </template> + </template> + <template #description> + {{ description }} + <slot></slot> + </template> + </a-card-meta> + </a-space> + <template #actions> + <a-switch v-if="actionType === 'switch'" v-model="open" /> + <a-space v-else-if="actionType === 'button'"> + <template v-if="isExpires"> + <a-button type="outline" @click="renew"> + {{ expiresText }} + </a-button> + </template> + <template v-else> + <a-button v-if="open" @click="handleToggle"> + {{ closeTxt }} + </a-button> + <a-button v-else-if="!open" type="outline" @click="handleToggle"> + {{ openTxt }} + </a-button> + </template> + </a-space> + <div v-else> + <a-space> + <a-button @click="toggle(false)"> + {{ closeTxt }} + </a-button> + <a-button type="primary" @click="toggle(true)"> + {{ openTxt }} + </a-button> + </a-space> + </div> + </template> + </a-card> + </div> +</template> + +<script lang="ts" setup> + import { ref } from 'vue'; + import { useToggle } from '@vueuse/core'; + + const props = defineProps({ + loading: { + type: Boolean, + default: false, + }, + title: { + type: String, + default: '', + }, + description: { + type: String, + default: '', + }, + actionType: { + type: String, + default: '', + }, + defaultValue: { + type: Boolean, + default: false, + }, + openTxt: { + type: String, + default: '', + }, + closeTxt: { + type: String, + default: '', + }, + expiresText: { + type: String, + default: '', + }, + icon: { + type: String, + default: '', + }, + showTag: { + type: Boolean, + default: true, + }, + tagText: { + type: String, + default: '', + }, + expires: { + type: Boolean, + default: false, + }, + expiresTagText: { + type: String, + default: '', + }, + }); + const [open, toggle] = useToggle(props.defaultValue); + const handleToggle = () => { + toggle(); + }; + const isExpires = ref(props.expires); + const renew = () => { + isExpires.value = false; + }; +</script> + +<style scoped lang="less"> + .card-wrap { + height: 100%; + transition: all 0.3s; + border: 1px solid var(--color-neutral-3); + border-radius: 4px; + &:hover { + transform: translateY(-4px); + // box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.1); + } + :deep(.arco-card) { + height: 100%; + border-radius: 4px; + .arco-card-body { + height: 100%; + .arco-space { + width: 100%; + height: 100%; + .arco-space-item { + height: 100%; + &:last-child { + flex: 1; + } + .arco-card-meta { + height: 100%; + display: flex; + flex-flow: column; + .arco-card-meta-content { + flex: 1; + .arco-card-meta-description { + margin-top: 8px; + color: rgb(var(--gray-6)); + line-height: 20px; + font-size: 12px; + } + } + .arco-card-meta-footer { + margin-top: 0; + } + } + } + } + } + } + :deep(.arco-card-meta-title) { + display: flex; + align-items: center; + + // To prevent the shaking + line-height: 28px; + } + :deep(.arco-skeleton-line) { + &:last-child { + display: flex; + justify-content: flex-end; + margin-top: 20px; + } + } + } +</style> diff --git a/src/views/dmx/agent/components/custom-settings.vue b/src/views/dmx/agent/components/custom-settings.vue new file mode 100644 index 0000000..808f80f --- /dev/null +++ b/src/views/dmx/agent/components/custom-settings.vue @@ -0,0 +1,244 @@ +<template> + <div class="list-wrap"> + <a-typography-title class="block-title" :heading="6"> + {{ $t('cardList.tab.title.content') }} + </a-typography-title> + <a-button class="add-button" type="primary" @click="addCard">娣诲姞</a-button> + + <a-row class="list-row" :gutter="24"> + <a-col + :xs="12" + :sm="12" + :md="12" + :lg="6" + :xl="6" + :xxl="6" + class="list-col" + > + <div class="card-wrap empty-wrap"> + <a-card :bordered="false" hoverable> + <a-result :status="null" title="Xinference妯″瀷鏄釜寰堝帀瀹崇殑妯″瀷"> + <template #icon> + <icon-plus style="font-size: 20px" /> + </template> + </a-result> + </a-card> + </div> + </a-col> + <a-col + v-for="item in renderData" + :key="item.id" + class="list-col" + :xs="12" + :sm="12" + :md="12" + :lg="6" + :xl="6" + :xxl="6" + > + <CardWrap + :loading="loading" + :title="item.title" + :description="item.description" + :default-value="item.enable" + :action-type="item.actionType" + :icon="item.icon" + :open-txt="$t('cardList.content.inspection')" + :close-txt="$t('cardList.content.delete')" + :show-tag="false" + > + <a-descriptions + style="margin-top: 16px" + :data="item.data" + layout="inline-horizontal" + :column="2" + /> + <template #skeleton> + <a-skeleton :animation="true"> + <a-skeleton-line + :widths="['50%', '50%', '100%', '40%']" + :rows="4" + /> + <a-skeleton-line :widths="['40%']" :rows="1" /> + </a-skeleton> + </template> + </CardWrap> + </a-col> + </a-row> + + <a-modal v-model:visible="visible" @Ok="handleOk" @cancel="handleCancel"> + <template #title> 娣诲姞LLM </template> + <a-form + ref="formRef" + :size="form.size" + :model="form" + auto-label-width + @submit="handleSubmit" + > + <a-form-item + field="type" + label="妯″瀷绫诲瀷" + :rules="[{ required: true, message: '涓嶈兘涓虹┖' }]" + :validate-trigger="['change', 'input']" + > + <a-select + v-model="form.type" + placeholder="璇烽�夋嫨妯″瀷绫诲瀷" + allow-clear + > + <a-option>chartGpt 4</a-option> + <a-option>chartGpt o</a-option> + <a-option>LLM</a-option> + </a-select> + </a-form-item> + + <a-form-item + field="UID" + label="妯″瀷UID" + :rules="[ + { required: true, message: '涓嶈兘涓虹┖' }, + { minLength: 1, message: '鑷冲皯涓�涓瓧绗�' }, + ]" + :validate-trigger="['change', 'input']" + > + <a-input v-model="form.UID" placeholder="璇疯緭鍏ユā鍨婾ID" /> + </a-form-item> + + <a-form-item + field="Url" + label="鍩虹Url" + :rules="[ + { required: true, message: '涓嶈兘涓虹┖' }, + { minLength: 1, message: '鑷冲皯涓�涓瓧绗�' }, + ]" + :validate-trigger="['change', 'input']" + > + <a-input v-model="form.Url" placeholder="璇疯緭鍏ュ熀纭�Url" /> + </a-form-item> + + <a-form-item + field="vision" + label="鏄惁鏀寔 vision" + :validate-trigger="['change', 'input']" + > + <a-switch v-model="form.vision" /> + </a-form-item> + </a-form> + </a-modal> + </div> +</template> + +<script lang="ts" setup> + import { nextTick, reactive, ref } from 'vue'; + import { queryInspectionList, ServiceRecord } from '@/api/list'; + import useRequest from '@/hooks/request'; + import CardWrap from './card-wrap.vue'; + + const defaultValue: ServiceRecord[] = new Array(3).fill({}); + const { loading, response: renderData } = useRequest<ServiceRecord[]>( + queryInspectionList, + defaultValue + ); + const visible = ref(false); + const addCard = () => { + visible.value = true; + }; + + const formRef = ref(null); + const form = reactive({ + size: 'medium', + type: '', + UID: '', + Url: '', + vision: false, + }); + const handleOk = () => { + formRef.value.validate().then((res) => { + if (res) { + return; + } + renderData.value = renderData.value.concat({ + id: renderData.value.length + 1, + title: form.type, + description: form.Url, + icon: 'icon-setting', + actionType: 'inspection', + enable: true, + data: [ + { + label: '寰呰川妫�鏁�', + value: '120', + }, + { + label: '绉帇鏃堕暱', + value: '60s', + }, + { + label: '寰呮娊妫�鏁�', + value: '0', + }, + ], + }); + visible.value = false; + }); + nextTick(() => { + visible.value = true; + }); + return false; + }; + const handleCancel = () => { + formRef.value.resetFields(); + visible.value = false; + }; +</script> + +<style scoped lang="less"> + .card-wrap { + height: 100%; + transition: all 0.3s; + border: 1px solid var(--color-neutral-3); + &:hover { + transform: translateY(-4px); + } + :deep(.arco-card-meta-description) { + color: rgb(var(--gray-6)); + .arco-descriptions-item-label-inline { + font-weight: normal; + font-size: 12px; + color: rgb(var(--gray-6)); + } + .arco-descriptions-item-value-inline { + color: rgb(var(--gray-8)); + } + } + } + .empty-wrap { + height: 200px; + border-radius: 4px; + :deep(.arco-card) { + height: 100%; + display: flex; + align-items: center; + justify-content: center; + border-radius: 4px; + .arco-result-title { + color: rgb(var(--gray-6)); + } + } + } + + .list-wrap { + position: relative; + + ::v-deep .block-title { + height: 36px; + lin-height: 36px; + } + + .add-button { + position: absolute; + right: 20px; + top: 0; + } + } +</style> diff --git a/src/views/dmx/agent/components/editAgent.vue b/src/views/dmx/agent/components/editAgent.vue new file mode 100644 index 0000000..f10b761 --- /dev/null +++ b/src/views/dmx/agent/components/editAgent.vue @@ -0,0 +1,332 @@ +<template> + <a-button + v-if="typeAngint == 'edit'" + type="text" + size="small" + @click="editClick" + > + <template #icon> + <icon-tool /> + </template> + </a-button> + <!-- <a-button v-if="typeAngint=='add'" style="margin-left: 10px" type="primary" @click="handleClick">纭畾</a-button>--> + <a-modal + v-model:visible="visible" + title="" + @before-open="handleOpened" + @cancel="handleCancel" + :footer="false" + title-align="start" + fullscreen + > + <div class="main-container"> + <div class="main-container-lf"> + <div style="padding: 10px;font-size: 16px;background: var(--color-neutral-3);">鏅鸿兘浣撻厤缃�</div> + <div style="display: flex;width: 100%;" :style="{height:height}"> + <div style="width: 50%;height: 100%"> + <div style="padding: 10px;font-size: 12px;color: #2a2a2b;">鏅鸿兘浣撶敾鍍�</div> + <div> + <a-textarea v-model="system" placeholder="" disabled style="height: 400px;" /> + </div> + + </div> + <div style="width: 50%;border: 1px solid var(--color-neutral-3);background: var(--color-neutral-3)"> + <a-form ref="formRef" :rules="rules" :model="form" @submit="handleSubmit" layout="vertical" > + <a-collapse :default-active-key="['1']"> + <a-collapse-item header="鍩虹淇℃伅" key="0" v-if="typeAngint == 'edit'"> + <a-input v-model="form.name" placeholder="璇疯緭鍏ユ櫤鑳戒綋鍚嶇О" style="width:200px;margin-top: 10px" /> + </a-collapse-item> + <a-collapse-item header="AI妯″瀷閰嶇疆" key="1"> + <a-form-item field="llm_id" label="妯″瀷"> + <a-space direction="vertical" size="large"> + <a-select :size="'large'" field="llm_id" v-model="form.llm_id" :style="{width:'25rem'}" placeholder="璇烽�夋嫨 ..."> + <a-optgroup + :label="index" + v-for="(item, index) in modelList" + :key="index" + > + <a-option + v-for="obj in item" + :key="obj.fid" + :disabled="!obj.available" + :value="obj.llm_id" + > + {{ obj.llm_name }} + </a-option> + </a-optgroup> + </a-select> + </a-space> + </a-form-item> + </a-collapse-item> + <a-collapse-item header="寮�鍦哄紩瀵�" :key="'2'" disabled> + </a-collapse-item> + <a-collapse-item header="鐭ヨ瘑搴�" key="3"> + <a-form-item field="kb_ids" label="鐭ヨ瘑搴�"> + <a-select + v-model="form.kb_ids" + :style="{ width: '25rem' }" + placeholder="璇烽�夋嫨 ..." + multiple + > + <a-option + v-for="item in tabs" + :key="item.id" + :value="item.id" + >{{ item.name }}</a-option + > + </a-select> + </a-form-item> + </a-collapse-item> + <a-collapse-item header="宸ュ叿" key="4" disabled> + </a-collapse-item> + <a-collapse-item header="宸ヤ綔娴�" key="5" disabled> + </a-collapse-item> + </a-collapse> + + <a-form-item> + <div + style=" + position: absolute; + right: 10px; + top: 0px; + z-index: 99999; + " + > + <!-- <a-button @click="visible = false">鍙栨秷</a-button>--> + <a-button + style="margin-left: 10px" + type="primary" + html-type="submit" + >淇濆瓨</a-button + > + </div> + </a-form-item> + </a-form> + </div> + </div> + </div> + <div class="main-container-rt"> + <sessionAction></sessionAction> + </div> + </div> + </a-modal> +</template> + +<script lang="ts" setup> + import { onMounted, onBeforeMount, reactive, ref, nextTick } from 'vue'; + import { IconSend } from '@arco-design/web-vue/es/icon'; + import { queryKbList, queryModelList } from '@/api/kbList'; + import useLoading from '@/hooks/loading'; + import { dialogSet } from '@/api/Agent'; + import { Message } from '@arco-design/web-vue'; + import EventBus from "@/utils/EventBus"; + import sessionAction from "@/views/dmx/IntelligentAgent/components/sessionAction.vue"; + const { setLoading } = useLoading(true); + const props = defineProps(['typeAngint', 'formData']); + const visible = ref(false); + const loading = ref(false); + const form = reactive({ + name: '', + icon: '', + language: 'English', + prompt_config: { + empty_response: '', + prologue: '浣犲ソ锛� 鎴戞槸浣犵殑鍔╃悊锛屾湁浠�涔堝彲浠ュ府鍒颁綘鐨勫悧锛�', + quote: true, + self_rag: true, + system: + '绀轰緥锛歕n' + + '浣犳槸 XX锛屽叿鏈� XX 缁忛獙锛屾搮闀� XX锛屸�n' + + '浣犵殑浠诲姟鏄� XX 锛岄渶瑕佹寜鐓т互涓嬫楠ゆ墽琛岋細\n' + + '1. XX\n' + + '2. XX\n' + + '3. 鈥n' + + '{knowlege}', + parameters: [ + { + key: 'knowledge', + optional: false, + }, + ], + }, + kb_ids: [], + llm_id: 'qwen-plus', + llm_setting: { + temperature: 0.1, + top_p: 0.3, + presence_penalty: 0.4, + frequency_penalty: 0.7, + max_tokens: 512, + }, + similarity_threshold: 0.2, + vector_similarity_weight: 0.30000000000000004, + top_n: 8, + }); + const system = ref(''); + const embdId = ref(''); + const modelList = ref({}); + const renderData = ref([]); + const formRef = ref(null); + let tabs = ref([]); + const height = ref('calc(100vh - 150px)'); + const emit = defineEmits(['cancelModal']); + const rules = { + name: [ + { + required: true, + message: '鍚嶇О涓嶅厑璁镐负绌�', + }, + ], + llm_id: [ + { + required: true, + message: '妯″瀷涓嶈兘涓虹┖', + }, + ], + kb_ids: [ + { + required: true, + message: '鐭ヨ瘑搴撲笉鑳戒负绌�', + }, + ], + }; + + const handleSubmit = async ({ values, errors }) => { + // console.log('values:', values, '\nerrors:', errors) + if(!errors){ + let title = '鍒涘缓鎴愬姛'; + let formNew = { ...form }; + if (props.typeAngint == 'edit') { + formNew.dialog_id = form.id; + delete formNew.id; + delete formNew.off; + title = '淇敼鎴愬姛'; + } + const data = await dialogSet(formNew); + if (data.code == 0) { + Message.success(title); + handleCancel(); + EventBus.emit('queryList'); + } + } + }; + + const editClick = (data) => { + visible.value = true; + + console.log(props.formData); + Object.assign(form, props.formData); + console.log(form); + system.value = form.prompt_config.system; + }; + + const handleClick = (data) => { + visible.value = true; + nextTick(() => { + Object.assign(form, data); + console.log(form,'浼犲��'); + system.value = form.prompt_config.system; + if(tabs.value && tabs.value.length>0){ + form.kb_ids = [tabs.value[0].id]; + } + }); + }; + defineExpose({ + handleClick, + }); + const handleBeforeOk = (done) => { + formRef.value.validate().then((res) => { + console.log('form:', form); + if (!form.name) { + done(false); + } else { + console.log('璇锋眰鏁版嵁'); + } + }); + }; + const handleCancel = () => { + visible.value = false; + emit('cancelModal'); + }; + + const handleOpened = (el) => { + // formRef.value.resetFields(); + }; + const queryModel = async (params) => { + try { + const data = await queryModelList(params); + console.log(data.data, '澶фā鍨嬪垪琛�'); + modelList.value = data.data; + } catch (err) { + // you can report use errorHandler or other + } finally { + } + }; + const file = ref(); + + const onChange = (_, currentFile) => { + file.value = { + ...currentFile, + // url: URL.createObjectURL(currentFile.file), + }; + }; + const onProgress = (currentFile) => { + file.value = currentFile; + }; + + const knowledgeData = async (params = { page: 1, page_size: 20 }) => { + setLoading(true); + try { + const { data } = await queryKbList(params); + console.log(data, 'data'); + nextTick(() => { + tabs.value = data; + console.log(tabs.value, 'tabs'); + }); + } catch (err) { + // you can report use errorHandler or other + } finally { + setLoading(false); + } + }; + + onBeforeMount(() => { + queryModel({}); + knowledgeData(); + }); + onMounted(() => {}); +</script> + +<style scoped lang="less"> + .main-container { + width: 100%; + display: flex; + .main-container-lf { + width: 60%; + } + .main-container-rt { + position: relative; + width: 40%; + } + } + .bottom { + width: 100%; + position: absolute; + bottom: 40px; + left: 0; + .input { + margin-left: 20%; + width: 60%; + } + .text { + margin-left: 40%; + font-size: 12px; + color: lightgrey; + line-height: 40px; + } + } + :deep(.arco-textarea-wrapper.arco-textarea-disabled){ + background: var(--color-bg-2); + color: var(--color-text-1); + } +</style> diff --git a/src/views/dmx/agent/components/quality-inspection.vue b/src/views/dmx/agent/components/quality-inspection.vue new file mode 100644 index 0000000..88167b6 --- /dev/null +++ b/src/views/dmx/agent/components/quality-inspection.vue @@ -0,0 +1,115 @@ +<template> + <div class="list-wrap"> + <a-typography-title class="block-title" :heading="6"> + {{ $t('cardList.tab.title.content') }} + </a-typography-title> + <a-row class="list-row" :gutter="24"> + <a-col + :xs="12" + :sm="12" + :md="12" + :lg="6" + :xl="6" + :xxl="6" + class="list-col" + > + <div class="card-wrap empty-wrap"> + <a-card :bordered="false" hoverable> + <a-result :status="null" :title="$t('cardList.content.action')"> + <template #icon> + <icon-plus style="font-size: 20px" /> + </template> + </a-result> + </a-card> + </div> + </a-col> + <a-col + v-for="item in renderData" + :key="item.id" + class="list-col" + :xs="12" + :sm="12" + :md="12" + :lg="6" + :xl="6" + :xxl="6" + > + <CardWrap + :loading="loading" + :title="item.title" + :description="item.description" + :default-value="item.enable" + :action-type="item.actionType" + :icon="item.icon" + :open-txt="$t('cardList.content.inspection')" + :close-txt="$t('cardList.content.delete')" + :show-tag="false" + > + <a-descriptions + style="margin-top: 16px" + :data="item.data" + layout="inline-horizontal" + :column="2" + /> + <template #skeleton> + <a-skeleton :animation="true"> + <a-skeleton-line + :widths="['50%', '50%', '100%', '40%']" + :rows="4" + /> + <a-skeleton-line :widths="['40%']" :rows="1" /> + </a-skeleton> + </template> + </CardWrap> + </a-col> + </a-row> + </div> +</template> + +<script lang="ts" setup> + import { queryInspectionList, ServiceRecord } from '@/api/list'; + import useRequest from '@/hooks/request'; + import CardWrap from './card-wrap.vue'; + + const defaultValue: ServiceRecord[] = new Array(3).fill({}); + const { loading, response: renderData } = useRequest<ServiceRecord[]>( + queryInspectionList, + defaultValue + ); +</script> + +<style scoped lang="less"> + .card-wrap { + height: 100%; + transition: all 0.3s; + border: 1px solid var(--color-neutral-3); + &:hover { + transform: translateY(-4px); + } + :deep(.arco-card-meta-description) { + color: rgb(var(--gray-6)); + .arco-descriptions-item-label-inline { + font-weight: normal; + font-size: 12px; + color: rgb(var(--gray-6)); + } + .arco-descriptions-item-value-inline { + color: rgb(var(--gray-8)); + } + } + } + .empty-wrap { + height: 200px; + border-radius: 4px; + :deep(.arco-card) { + height: 100%; + display: flex; + align-items: center; + justify-content: center; + border-radius: 4px; + .arco-result-title { + color: rgb(var(--gray-6)); + } + } + } +</style> diff --git a/src/views/dmx/agent/components/rules-preset.vue b/src/views/dmx/agent/components/rules-preset.vue new file mode 100644 index 0000000..e5a2878 --- /dev/null +++ b/src/views/dmx/agent/components/rules-preset.vue @@ -0,0 +1,51 @@ +<template> + <div class="list-wrap"> + <a-typography-title class="block-title" :heading="6"> + {{ $t('cardList.tab.title.preset') }} + </a-typography-title> + <a-row class="list-row" :gutter="24"> + <a-col + v-for="item in renderData" + :key="item.id" + :xs="12" + :sm="12" + :md="12" + :lg="6" + :xl="6" + :xxl="6" + class="list-col" + style="min-height: 140px" + > + <CardWrap + :loading="loading" + :title="item.title" + :description="item.description" + :default-value="item.enable" + :action-type="item.actionType" + :tag-text="$t('cardList.preset.tag')" + > + <template #skeleton> + <a-skeleton :animation="true"> + <a-skeleton-line :widths="['100%', '40%']" :rows="2" /> + <a-skeleton-line :widths="['40%']" :rows="1" /> + </a-skeleton> + </template> + </CardWrap> + </a-col> + </a-row> + </div> +</template> + +<script lang="ts" setup> + import { queryRulesPresetList, ServiceRecord } from '@/api/list'; + import useRequest from '@/hooks/request'; + import CardWrap from './card-wrap.vue'; + + const defaultValue: ServiceRecord[] = new Array(6).fill({}); + const { loading, response: renderData } = useRequest<ServiceRecord[]>( + queryRulesPresetList, + defaultValue + ); +</script> + +<style scoped lang="less"></style> diff --git a/src/views/dmx/agent/components/sessionAction.vue b/src/views/dmx/agent/components/sessionAction.vue new file mode 100644 index 0000000..e084802 --- /dev/null +++ b/src/views/dmx/agent/components/sessionAction.vue @@ -0,0 +1,265 @@ +<template> + <div :style="{ height: heightrg }"> + <div style="padding: 10px"> + <a-avatar :style="{ backgroundColor: '#3370ff' }"> + <img + :style="{ width: '100%' }" + alt="dessert" + src="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a20012a2d4d5b9db43dfc6a01fe508c0.png~tplv-uwbnlip3yd-webp.webp" + /> + </a-avatar> + 璋冭瘯棰勮 + </div> + <a-divider style="margin: 0; margin-left: 10px" /> + <a-scrollbar + ref="scrollbar" + id="home" + class="chat-list" + style="width: 90%; overflow: auto; height: 70vh; margin: 0px auto;" + > + <div class="chat-item" v-for="sessionDetail in sessionDetailList"> + <a-comment + v-if="sessionDetail.role === 'user'" + avatar="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/3ee5f13fb09879ecb5185e440cef6eb9.png~tplv-uwbnlip3yd-webp.webp" + > + <template #content> + <div :class="{ light: theme === 'light' }" style="background-color: var(--color-bg-2);color: var(--color-text-3);border: none;padding: 16px;">{{ + sessionDetail.content + }}</div> + </template> + </a-comment> + <a-comment + v-else-if="sessionDetail.role === 'assistant'" + avatar="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/9eeb1800d9b78349b24682c3518ac4a3.png~tplv-uwbnlip3yd-webp.webp" + > + <template #content> + <a-card + class="chat-item-answer" + style="background-color: var(--color-bg-2);color: var(--color-text-3);border: none" + > + <div :class="{ light: theme === 'light' }">{{ + sessionDetail.content + }}</div> + </a-card> + </template> + </a-comment> + <a-comment + v-else-if="sessionDetail.role === 'last'" + avatar="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/9eeb1800d9b78349b24682c3518ac4a3.png~tplv-uwbnlip3yd-webp.webp" + > + <template #content> + <a-textarea + readonly + auto-size + v-model="displayedText" + class="chat-item-answer" + style="background-color: var(--color-bg-2);color: var(--color-text-3);border: none" + > + </a-textarea> + </template> + </a-comment> + </div> + </a-scrollbar> + <div class="bottom"> + <div class="input"> + <a-input + v-model="inputMsg" + @keydown.enter="sendMessage" + placeholder="杈撳叆鎮ㄦ兂浜嗚В鐨勫唴瀹癸紝鎸塃nter鍙戦��" + > + <template #suffix> + <icon-send style="cursor: pointer" @click="sendMessage" /> + </template> </a-input + ></div> + <div class="text">鍐呭鐢盇I鐢熸垚锛屼粎渚涘弬鑰�</div> + </div> + </div> +</template> + +<script setup lang="ts"> +import { + IconMoreVertical, + IconQuestionCircleFill, + IconPoweroff, + IconCommon, + IconSend, +} from '@arco-design/web-vue/es/icon'; +import img1 from '@/assets/images/u64.png'; +import img2 from '@/assets/images/u69.png'; +import img3 from '@/assets/images/u74.png'; +import { ref, onMounted, computed, reactive, nextTick, watch } from 'vue'; +import { useUserStore, useAppStore } from '@/store'; +import { + sessionListApi, + deleteSessionApi, + getSessionDetailsApi, + chatApi, +} from '@/api/session'; +import { Message } from '@arco-design/web-vue'; +const userStore = useUserStore(); +const appStore = useAppStore(); +const theme = computed(() => { + return appStore.theme; +}); +const heightrg = ref('calc(100vh - 100px)'); +const sessionList = ref([]); //浼氳瘽鍒楄〃 +const sessionDetailList = ref([]); //鏍规嵁浼氳瘽id鍑烘潵鐨勪細璇濊鎯� +const activeSessionId = ref(''); +const inputMsg = ref(''); +const scrollbar = ref(null); + +const currIndex = ref(0); +const displayedText = ref(''); // 姝e湪鏄剧ず鐨勬枃瀛� +let timer: number | null = null; +const streamStr = ref(''); +const modalObj = reactive({ add: false }); +//鏌ヨ浼氳瘽鍒楄〃 +const querySessionList = async () => { + const { code, data } = await sessionListApi(); + if (code === 200) { + sessionList.value = data; + if (Array.isArray(data) && data.length > 0) { + activeSessionId.value = data[1].id; + const res = await getSessionDetailsApi(data[0].id); + if (res.code === 200) { + sessionDetailList.value = res.data.message; + refreshScroll(); + } + } + } else { + Message.warning('鏌ヨ澶辫触'); + } +}; +//鏍规嵁浼氳瘽id鍒犻櫎浼氳瘽 +const deleteSession = async (session) => { + const { code } = await deleteSessionApi([session.id]); + if (code === 200) { + Message.success('鍒犻櫎鎴愬姛'); + querySessionList(); + } +}; +// eslint-disable-next-line prettier/prettier +// 鏂板浼氳瘽涔嬪悗鍒锋柊浼氳瘽鍒楄〃 +const addSession = () => { + querySessionList(); +}; +// 鍒濆鍖栨暟鎹� +const initData = () => { + querySessionList(); +}; +// 鑾峰彇鐧诲綍淇℃伅 +const userName = computed(() => { + return userStore.name; +}); +const avatar = computed(() => { + return userStore.avatar; +}); +const refreshScroll = () => { + nextTick(() => { + const container = document.getElementById('home'); + scrollbar.value.scrollTop(container.scrollHeight); + }); +}; +// 鏍规嵁浼氳瘽id 鏌ヨ浼氳瘽璇︽儏 +const querySessionDetail = async (session) => { + activeSessionId.value = session.id; + const { code, data } = await getSessionDetailsApi(session.id); + if (code === 200) { + sessionDetailList.value = data.message; + refreshScroll(); //鍒锋柊婊氬姩鏉′綅缃� + } +}; +const sendMessage = async () => { + if (inputMsg.value) { + const { code, data } = await chatApi({ + conversation_id: activeSessionId.value, + messages: inputMsg.value, + }); + const res = await getSessionDetailsApi(activeSessionId.value); + if (res.code === 200) { + sessionDetailList.value = res.data.message.map((item, index) => { + if (index === res.data.message.length - 1) { + item.role = 'last'; + displayedText.value = ''; + currIndex.value = 0; + streamStr.value = item.content; + startDisplayStr(); + } + return item; + }); + refreshScroll(); + } + inputMsg.value = ''; + } else { + Message.warning('娑堟伅涓嶈兘涓虹┖'); + } +}; +onMounted(() => { + initData(); +}); +//鏂囧瓧鍔ㄦ�佽緭鍑� +const startDisplayStr = () => { + if (timer) { + clearTimeout(timer!); + } + const res = streamStr.value; + // 灏嗘暟缁勪腑鐨勫瓧绗︿覆鎷兼帴璧锋潵 + if (currIndex.value < res.length) { + displayedText.value += res[currIndex.value]; + currIndex.value++; + setTimeout(startDisplayStr, 100); + } else { + clearTimeout(timer!); + timer = null; + } +}; +watch( + () => scrollbar.value, + (newScroll, oldScroll) => { + if (newScroll) { + // 鑾峰彇a-scroll鐨勯珮搴� + const height = newScroll.$el.offsetHeight; + console.log('a-scroll height changed to:', height); + } + }, + { deep: true } +); +</script> + +<style scoped lang="less"> +.container { + width: 100%; + display: flex; +} +//.light { +// color: white !important; +//} +.bottom { + width: 100%; + position: absolute; + bottom: 40px; + left: 0; + + .input { + margin-left: 20%; + width: 60%; + } + + .text { + margin-left: 40%; + font-size: 12px; + color: lightgrey; + line-height: 40px; + } +} +.chat-list { + width: 90%; + margin: 0px auto; + .chat-item { + margin-top: 20px; + .chat-item-answer { + color: white; + } + } +} +</style> diff --git a/src/views/dmx/agent/components/the-service.vue b/src/views/dmx/agent/components/the-service.vue new file mode 100644 index 0000000..2f4748e --- /dev/null +++ b/src/views/dmx/agent/components/the-service.vue @@ -0,0 +1,57 @@ +<template> + <div class="list-wrap"> + <a-typography-title class="block-title" :heading="6"> + {{ $t('cardList.tab.title.service') }} + </a-typography-title> + <a-row class="list-row" :gutter="24"> + <a-col + v-for="item in renderData" + :key="item.id" + :xs="12" + :sm="12" + :md="12" + :lg="6" + :xl="6" + :xxl="6" + class="list-col" + style="min-height: 162px" + > + <CardWrap + :loading="loading" + :title="item.title" + :description="item.description" + :default-value="item.enable" + :action-type="item.actionType" + :expires="item.expires" + :open-txt="$t('cardList.service.open')" + :close-txt="$t('cardList.service.cancel')" + :expires-text="$t('cardList.service.renew')" + :tag-text="$t('cardList.service.tag')" + :expires-tag-text="$t('cardList.service.expiresTag')" + :icon="item.icon" + > + <template #skeleton> + <a-skeleton :animation="true"> + <a-skeleton-line :widths="['100%', '40%', '100%']" :rows="3" /> + <a-skeleton-line :widths="['40%']" :rows="1" /> + </a-skeleton> + </template> + </CardWrap> + </a-col> + </a-row> + </div> +</template> + +<script lang="ts" setup> + import { queryTheServiceList, ServiceRecord } from '@/api/list'; + import useRequest from '@/hooks/request'; + import CardWrap from './card-wrap.vue'; + + const defaultValue: ServiceRecord[] = new Array(4).fill({}); + const { loading, response: renderData } = useRequest<ServiceRecord[]>( + queryTheServiceList, + defaultValue + ); +</script> + +<style scoped lang="less"></style> diff --git a/src/views/dmx/agent/index.vue b/src/views/dmx/agent/index.vue new file mode 100644 index 0000000..0ddb08a --- /dev/null +++ b/src/views/dmx/agent/index.vue @@ -0,0 +1,350 @@ +<template> + <div class="container"> + <Breadcrumb :items="['澶фā鍨�', '鏅鸿兘浣撶鐞�']" /> + <a-row :gutter="20" align="stretch"> + <a-col :span="24"> + <a-card class="general-card" :title="$t('鏅鸿兘浣撶鐞�')"> + <div style="display: flex; justify-content: right"> + <a-input-search + :placeholder="$t('cardList.searchInput.placeholder')" + style="width: 240px" + @change="queryList" + /> + </div> + <a-divider style="margin: 10px 0" /> + <a-row justify="space-between"> + <a-col :span="24"> + <div style="display: flex; flex-wrap: wrap"> + <div + class="card-wrap" + style="cursor: pointer" + @click="handleAdd" + > + <a-card :bordered="false" hoverable> + <div style="margin-top: 30px; text-align: center"> + <a-avatar style="background: #3370ff"> + <icon-plus /> + </a-avatar> + </div> + <div class="arco-card-body-content"> + <div style="text-align: center; margin-top: 10px"> + 鏂板缓鏅鸿兘浣� + </div> + <div + style=" + text-align: center; + margin-top: 10px; + font-size: 12px; + color: #999999; + " + > + 閫氳繃鎻忚堪瑙掕壊鍜屼换鍔℃潵鍒涘缓浣犵殑鏅鸿兘浣�<br /> + 鏅鸿兘浣撳彲浠ヨ皟鐢ㄥ涓伐浣滄祦鍜屽伐鍏� + </div> + </div> + <add-agent ref="addAgents"></add-agent> + <!-- <div style="position: absolute; bottom: 1rem; right: 1rem;">--> + <!-- <a-space>--> + <!-- </a-space>--> + <!-- </div>--> + </a-card> + </div> + <div + class="card-wrap" + v-for="(item, index) of agentList" + :key="item.id" + > + <a-card :bordered="false" hoverable> + <a-avatar :style="{ backgroundColor: '#3370ff' }"> + <img + :style="{ width: '100%' }" + alt="dessert" + src="https://p1-arco.byteimg.com/tos-cn-i-uwbnlip3yd/a20012a2d4d5b9db43dfc6a01fe508c0.png~tplv-uwbnlip3yd-webp.webp" + /> + </a-avatar> + <a-switch + v-model="item.off" + style="position: absolute; top: 10px; right: 10px" + size="medium" + @change="handleChange(item)" + > + <template #checked> 涓婄嚎 </template> + <template #unchecked> 涓嬬嚎 </template> + </a-switch> + <div class="arco-card-body-content"> + <div class="arco-card-body-content-top"> + <span style="font-size: 18px; font-weight: 900"> + {{ item.name }} + </span> + </div> + <div class="arco-card-body-content-down"> + {{ item.prompt_config.prologue }} + </div> + </div> + <div style="position: absolute; bottom: 1.4rem; left: 1rem"> + <icon-user /> + <span style="font-size: 12px"> + <!-- {{ item.name }}--> + </span> + </div> + <div style="position: absolute; bottom: 1rem; right: 1rem"> + <a-space> + <span v-show="!item.off"> + <editAgent + ref="editAgentKuai" + typeAngint="edit" + :formData="form" + @cancelModal="handleCancel" + ></editAgent> + </span> + <a-popconfirm + :content="'纭畾鍒犻櫎鍚�'" + type="warning" + @ok="deleteItem(item)" + > + <a-button type="text" size="small"> + <template #icon> + <icon-delete /> + </template> + </a-button> + </a-popconfirm> + </a-space> + </div> + </a-card> + </div> + </div> + </a-col> + </a-row> + </a-card> + </a-col> + </a-row> + </div> +</template> + +<script lang="ts" setup> +import { ref, reactive, nextTick, onBeforeMount, onMounted, onBeforeUnmount } from "vue"; + import addAgent from '@/views/dmx/IntelligentAgent/components/addAgent.vue'; + import editAgent from '@/views/dmx/IntelligentAgent/components/editAgent.vue'; + import { kbdocumentrm, queryKbList } from '@/api/kbList'; + import { Message } from '@arco-design/web-vue'; + import { deletedialog, querydialogList } from '@/api/Agent'; + import useLoading from '@/hooks/loading'; + const { loading, setLoading } = useLoading(true); + import EventBus from '@/utils/EventBus'; + + let count = 5; + const activeKey = ref(1); + const addAgents = ref(); + const editAgentKuai = ref(); + const agentList = ref([ + // { + // key: 2, + // title: '鍐呭璐ㄦ', + // content: 'Content of Tab Panel 2', + // }, + // { + // key: 3, + // title: '寮�閫氭湇鍔�', + // content: 'Content of Tab Panel 3', + // }, + // { + // key: 4, + // title: '瑙勫垯棰勭疆', + // content: 'Content of Tab Panel 4', + // }, + ]); + const changeTabs = (val) => { + activeKey.value = val; + }; + const handleAdd = () => { + addAgents.value.handleClick(); + }; + const handleDelete = (key: any) => { + data.value = data.value.filter((item) => item.key !== key); + }; + + const visible = ref(false); + const formRef = ref(null); + const form = reactive({ + // size: 'medium', + // name: '', + }); + + const queryList = async (params = {}) => { + setLoading(true); + try { + const { data } = await querydialogList(params); + console.log(data, 'data'); + agentList.value = data.map((item) => { + return { + ...item, + off: true, + }; + }); + } catch (err) { + // you can report use errorHandler or other + } finally { + setLoading(false); + } + }; + + const deleteItem = async (row) => { + console.log(row); + let data = await deletedialog({ dialog_ids: [row.id] }); + if (data.code == 0) { + Message.success('鍒犻櫎鎴愬姛'); + queryList(); + } + }; + const handleChange = async (item) => { + if (item) { + Object.assign(form, item); + } + }; + const handleCancel = () => { + queryList(); + }; + const handleSubmit = ({ values, errors }) => { + this.$refs.formRef.validate().then((res, a, b) => { + debugger; + console.log('values', values); + }); + }; + onBeforeMount(() => { + queryList(); + }); + onMounted(()=>{ + EventBus.on('queryList',()=>{ + queryList(); + }) + }) + onBeforeUnmount(()=>{ + EventBus.off('queryList') + }) +</script> + +<script lang="ts"> + export default { + name: 'Card', + }; +</script> + +<style scoped lang="less"> + .container { + padding: 0 20px 20px 20px; + :deep(.arco-list-content) { + overflow-x: hidden; + } + + :deep(.arco-card-meta-title) { + font-size: 14px; + } + } + :deep(.arco-list-col) { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; + } + + :deep(.arco-list-item) { + width: 33%; + } + + :deep(.block-title) { + margin: 0 0 12px 0; + font-size: 14px; + } + :deep(.list-wrap) { + // min-height: 140px; + .list-row { + align-items: stretch; + .list-col { + margin-bottom: 16px; + } + } + :deep(.arco-space) { + width: 100%; + .arco-space-item { + &:last-child { + flex: 1; + } + } + } + } + .card-wrap { + width: 23%; + height: 200px; + margin: 1%; + transition: all 0.3s; + border: 1px solid var(--color-neutral-3); + border-radius: 4px; + position: relative; + &:hover { + transform: translateY(-4px); + // box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.1); + } + :deep(.arco-card) { + height: 100%; + border-radius: 4px; + .arco-card-body { + height: 100%; + .arco-space { + width: 100%; + height: 100%; + .arco-space-item { + height: 100%; + &:last-child { + flex: 1; + } + .arco-card-meta { + height: 100%; + display: flex; + flex-flow: column; + .arco-card-meta-content { + flex: 1; + .arco-card-meta-description { + margin-top: 8px; + color: rgb(var(--gray-6)); + line-height: 20px; + font-size: 12px; + } + } + .arco-card-meta-footer { + margin-top: 0; + } + } + } + } + } + } + :deep(.arco-card-meta-title) { + display: flex; + align-items: center; + + // To prevent the shaking + line-height: 28px; + } + :deep(.arco-skeleton-line) { + &:last-child { + display: flex; + justify-content: flex-end; + margin-top: 20px; + } + } + } + .arco-card-body-content { + .arco-card-body-content-top { + margin-top: 10px; + text-align: center; + } + .arco-card-body-content-down { + text-align: center; + margin-top: 10px; + font-size: 12px; + color: #999999; + width: 100%; + height: 60px; + } + } +</style> diff --git a/src/views/dmx/agent/locale/en-US.ts b/src/views/dmx/agent/locale/en-US.ts new file mode 100644 index 0000000..04cddd0 --- /dev/null +++ b/src/views/dmx/agent/locale/en-US.ts @@ -0,0 +1,20 @@ +export default { + // 'menu.list.cardList': 'Card List', + 'menu.dmx.setting': 'GPT Setting', + 'cardList.tab.title.all': 'All', + 'cardList.tab.title.content': 'Quality Inspection', + 'cardList.tab.title.service': 'The service', + 'cardList.tab.title.preset': 'Rules Preset', + 'cardList.searchInput.placeholder': 'Search', + 'cardList.enable': 'Enable', + 'cardList.disable': 'Disable', + 'cardList.content.delete': 'Delete', + 'cardList.content.inspection': 'Inspection', + 'cardList.content.action': 'Click Create Qc Content queue', + 'cardList.service.open': 'Open', + 'cardList.service.cancel': 'Cancel', + 'cardList.service.renew': 'Contract of service', + 'cardList.service.tag': 'Opened', + 'cardList.service.expiresTag': 'Expired', + 'cardList.preset.tag': 'Enable', +}; diff --git a/src/views/dmx/agent/locale/zh-CN.ts b/src/views/dmx/agent/locale/zh-CN.ts new file mode 100644 index 0000000..49a4478 --- /dev/null +++ b/src/views/dmx/agent/locale/zh-CN.ts @@ -0,0 +1,20 @@ +export default { + // 'menu.list.cardList': '鍗$墖鍒楄〃', + 'menu.dmx.setting': '澶фā鍨嬭缃�', + 'cardList.tab.title.all': '鍏ㄩ儴', + 'cardList.tab.title.content': '鍐呭璐ㄦ', + 'cardList.tab.title.service': '寮�閫氭湇鍔�', + 'cardList.tab.title.preset': '瑙勫垯棰勭疆', + 'cardList.searchInput.placeholder': '鎼滅储', + // 'cardList.statistic.enable': '宸插惎鐢�', + // 'cardList.statistic.disable': '鏈惎鐢�', + 'cardList.content.delete': '鍒犻櫎', + 'cardList.content.inspection': '璐ㄦ', + 'cardList.content.action': '鐐瑰嚮鍒涘缓璐ㄦ鍐呭闃熷垪', + 'cardList.service.open': '寮�閫氭湇鍔�', + 'cardList.service.cancel': '鍙栨秷鏈嶅姟', + 'cardList.service.renew': '缁害鏈嶅姟', + 'cardList.service.tag': '宸插紑閫�', + 'cardList.service.expiresTag': '宸茶繃鏈�', + 'cardList.preset.tag': '宸插惎鐢�', +}; diff --git a/src/views/dmx/agent/mock.ts b/src/views/dmx/agent/mock.ts new file mode 100644 index 0000000..68cf096 --- /dev/null +++ b/src/views/dmx/agent/mock.ts @@ -0,0 +1,186 @@ +import Mock from 'mockjs'; +import setupMock, { successResponseWrap } from '@/utils/setup-mock'; +import { ServiceRecord } from '@/api/list'; + +const qualityInspectionList: ServiceRecord[] = [ + { + id: 1, + name: 'quality', + title: '瑙嗛绫�-鍘嗗彶瀵煎叆', + description: '2021-10-12 00:00:00', + data: [ + { + label: '寰呰川妫�鏁�', + value: '120', + }, + { + label: '绉帇鏃堕暱', + value: '60s', + }, + { + label: '寰呮娊妫�鏁�', + value: '0', + }, + ], + }, + { + id: 2, + name: 'quality', + title: '鍥炬枃绫�-鍥剧墖鐗堟潈', + description: '2021-12-11 18:30:00', + data: [ + { + label: '寰呰川妫�鏁�', + value: '120', + }, + { + label: '绉帇鏃堕暱', + value: '60s', + }, + { + label: '寰呮娊妫�鏁�', + value: '0', + }, + ], + }, + { + id: 3, + name: 'quality', + title: '鍥炬枃绫�-楂樻竻鍥剧墖', + description: '2021-10-15 08:10:00', + data: [ + { + label: '寰呰川妫�鏁�', + value: '120', + }, + { + label: '绉帇鏃堕暱', + value: '60s', + }, + { + label: '寰呮娊妫�鏁�', + value: '0', + }, + ], + }, +]; +const theServiceList: ServiceRecord[] = [ + { + id: 1, + icon: 'code', + title: '婕忔枟鍒嗘瀽', + description: + '鐢ㄦ埛琛屼负鍒嗘瀽涔嬫紡鏂楀垎鏋愭ā鍨嬫槸浼佷笟瀹炵幇绮剧粏鍖栬繍钀ャ�佽繘琛岀敤鎴疯涓哄垎鏋愮殑閲嶈鏁版嵁鍒嗘瀽妯″瀷銆�', + enable: true, + actionType: 'button', + }, + { + id: 2, + icon: 'edit', + title: '鐢ㄦ埛鍒嗗竷', + description: + '蹇�熻瘖鏂敤鎴蜂汉缇わ紝鍦板煙缁嗗垎鎯呭喌锛屼簡瑙f暟鎹垎甯冪殑闆嗕腑搴︼紝浠ュ強涓昏鐨勬暟鎹垎甯冪殑鍖洪棿娈垫槸浠�涔堛��', + enable: true, + actionType: 'button', + expires: true, + }, + { + id: 3, + icon: 'user', + title: '璧勬簮鍒嗗彂', + description: + '绉诲姩绔姩鎬佸寲璧勬簮鍒嗗彂瑙e喅鏂规銆傛彁渚涚ǔ瀹氬ぇ娴侀噺鏈嶅姟鏀寔銆佺伒娲诲畾鍒剁殑鍒嗗彂鍦堥�夎鍒欙紝閫氳繃绂荤嚎鍖栭鍔犺浇銆�', + enable: false, + actionType: 'button', + }, + { + id: 4, + icon: 'user', + title: '鐢ㄦ埛鐢诲儚鍒嗘瀽', + description: + '鐢ㄦ埛鐢诲儚灏辨槸灏嗗吀鍨嬬敤鎴蜂俊鎭爣绛惧寲锛屾牴鎹敤鎴风壒寰併�佷笟鍔″満鏅拰鐢ㄦ埛琛屼负绛変俊鎭紝鏋勫缓涓�涓爣绛惧寲鐨勭敤鎴锋ā鍨嬨��', + enable: true, + actionType: 'button', + }, +]; +const rulesPresetList: ServiceRecord[] = [ + { + id: 1, + title: '鍐呭灞忚斀瑙勫垯', + description: + '鐢ㄦ埛鍦ㄦ墽琛岀壒瀹氱殑鍐呭鍒嗗彂浠诲姟鏃讹紝鍙娇鐢ㄥ唴瀹瑰睆钄借鍒欐牴鎹壒瀹氭爣绛撅紝杩囨护鍐呭闆嗗悎銆�', + enable: true, + actionType: 'switch', + }, + { + id: 2, + title: '鍐呭缃《瑙勫垯', + description: + '璇ヨ鍒欐敮鎸佺敤鎴峰湪鎵ц鐗瑰畾鍐呭鍒嗗彂浠诲姟鏃讹紝瀵瑰浐瀹氱殑鍑犳潯鍐呭缃《銆�', + enable: true, + actionType: 'switch', + }, + { + id: 3, + title: '鍐呭鍔犳潈瑙勫垯', + description: '閫夊畾鍐呭鍔犳潈瑙勫垯鍚庡彲鑷畾涔変粠涓嶅悓鍐呭闆嗗悎鑾峰彇鍐呭鐨勬鐜囥��', + enable: false, + actionType: 'switch', + }, + { + id: 4, + title: '鍐呭鍒嗗彂瑙勫垯', + description: '鍐呭鍒嗗彂鏃讹紝瀵规煇浜涘唴瀹归渶瑕佸浐瀹氬湪C绔睍绀虹殑浣嶇疆銆�', + enable: true, + actionType: 'switch', + }, + { + id: 5, + title: '杩濈鍐呭璇嗗埆', + description: '绮惧噯璇嗗埆璧屽崥銆佸垁鏋�佹瘨鍝併�侀�犲亣銆佽穿鍋囩瓑杩濊鐗╁搧鍜岃繚瑙勮涓恒��', + enable: false, + actionType: 'switch', + }, + { + id: 6, + title: '澶氳瑷�鏂囧瓧绗﹀彿璇嗗埆', + description: + '绮惧噯璇嗗埆鑻辫銆佺淮璇�佽棌璇�佽挋鍙よ銆佹湞椴滆绛夊绉嶈瑷�浠ュ強emoji琛ㄦ儏褰㈡�佺殑璇箟璇嗗埆銆�', + enable: false, + actionType: 'switch', + }, +]; + +setupMock({ + setup() { + // Quality Inspection + Mock.mock(new RegExp('/api/list/quality-inspection'), () => { + return successResponseWrap( + qualityInspectionList.map((_, index) => ({ + ...qualityInspectionList[index % qualityInspectionList.length], + id: Mock.Random.guid(), + })) + ); + }); + + // the service + Mock.mock(new RegExp('/api/list/the-service'), () => { + return successResponseWrap( + theServiceList.map((_, index) => ({ + ...theServiceList[index % theServiceList.length], + id: Mock.Random.guid(), + })) + ); + }); + + // rules preset + Mock.mock(new RegExp('/api/list/rules-preset'), () => { + return successResponseWrap( + rulesPresetList.map((_, index) => ({ + ...rulesPresetList[index % rulesPresetList.length], + id: Mock.Random.guid(), + })) + ); + }); + }, +}); diff --git a/src/views/dmx/knowledgeLib/config.vue b/src/views/dmx/knowledgeLib/config.vue index 68974a9..8af79cf 100644 --- a/src/views/dmx/knowledgeLib/config.vue +++ b/src/views/dmx/knowledgeLib/config.vue @@ -1,7 +1,7 @@ <template> <div class="main-container"> <div style="position: absolute;top: 0;left: 0;width: 100%;padding: 0 20px"> - <h4 style="margin-bottom: 10px">閰嶇疆</h4> + <h4 style="margin-bottom: 10px"></h4> <div style="color: #666666;">鍦ㄨ繖閲屾洿鏂版偍鐨勭煡璇嗗簱璇︾粏淇℃伅锛屽挨鍏舵槸瑙f瀽鏂规硶銆�</div> <a-divider style="margin-top: 20px" /> </div> @@ -432,7 +432,7 @@ height: 100%; overflow: auto; //background: #626aea; - //background: #ffffff; + background: var(--color-bg-2); padding-top: 80px; &-lf { @@ -440,7 +440,7 @@ //height: 100%; //border: 1px solid #cccccc; border-radius: 10px; - + //border: 1px solid var(--color-fill-3); &-top { width: 100%; height: 60px; @@ -493,10 +493,10 @@ border-radius: 10px; overflow: hidden; padding: 20px; - section { width: 100%; - color: #333333; + //color: #333333; + color: var(--color-text-1); } } } diff --git a/src/views/dmx/knowledgeLib/index.vue b/src/views/dmx/knowledgeLib/index.vue index 31d1c7d..610025d 100644 --- a/src/views/dmx/knowledgeLib/index.vue +++ b/src/views/dmx/knowledgeLib/index.vue @@ -176,34 +176,41 @@ <template #run="{ record }"> <div style="display: flex;align-items: center;"> <div style="width: 100px"> + <a-popover title="Title" v-if="record.run == '4'"> + <a-tag :loading="record.loading" :color="'blue'" border>{{$t('dmx.list.complete')}}</a-tag> + <template #content> + <p></p> + </template> + </a-popover> <a-popover title="Title" v-if="record.run == '3'"> <a-tag :loading="record.loading" :color="'blue'" border>{{$t('dmx.list.complete')}}</a-tag> <template #content> - <p>Here is the text content</p> + <p></p> </template> </a-popover> <a-popover title="Title" v-if="record.run == '1'"> <a-tag :loading="record.loading" :color="'blue'" border>{{$t('dmx.list.complete')}}</a-tag> <template #content> - <p>Here is the text content</p> + <p></p> </template> </a-popover> <a-popover title="Title" v-if="record.run == '2'"> <a-tag :loading="record.loading" :color="'gold'" border>{{$t('dmx.list.cancel')}}</a-tag> <template #content> - <p>Here is the text content</p> + <p></p> </template> </a-popover> <a-popover title="Title" v-if="record.run == '0'"> <a-tag :loading="record.loading" :color="'green'" border>{{$t('dmx.list.NotStarted')}}</a-tag> <template #content> - <p>Here is the text content</p> + <p></p> </template> </a-popover> </div> <div > <a-button type="text" size="large" @click="run(record)" :loading="record.loading"> <template #icon> + <icon-sync v-if="record.run == '4'"/> <icon-sync v-if="record.run == '3'"/> <icon-sync v-if="record.run == '2'"/> <icon-sync style="color: green" v-if="record.run == '1'"/> @@ -515,9 +522,9 @@ pagination.current = params.page; pagination.total = data.data.total; // 鏌ヨ鐭ヨ瘑搴撹鎯� - kbdetail = await queryKbdetail({ - kb_id:params.kb_id, - }); + // kbdetail = await queryKbdetail({ + // kb_id:params.kb_id, + // }); } } catch (err) { @@ -785,7 +792,8 @@ flex-direction: column; align-items: center; justify-content: space-evenly; - background: #ffffff; + //background: #ffffff; + background: var(--color-bg-2); width: 200px; .lf-container-top{ display: flex; @@ -797,7 +805,7 @@ box-sizing: border-box; width: 90%; //height: 56rem; - border: 1px solid #eeeeee; + border: 1px solid var(--color-fill-3); //padding: 10px; margin-bottom: 10px; //.tabs{ diff --git a/src/views/dmx/knowledgeLib/test.vue b/src/views/dmx/knowledgeLib/test.vue index ba702dc..1064d95 100644 --- a/src/views/dmx/knowledgeLib/test.vue +++ b/src/views/dmx/knowledgeLib/test.vue @@ -176,8 +176,8 @@ &-lf{ width: 30%; height: 100%; - //border: 1px solid #cccccc; - background: #ffffff; + //border: 1px solid var(--color-fill-3); + background: var(--color-bg-2); border-radius: 10px; overflow: hidden; &-top{ @@ -223,8 +223,8 @@ width: 69%; height: 100%; //background: #626aea; - //border: 1px solid #cccccc; - background: #ffffff; + //border: 1px solid var(--color-fill-3); + background: var(--color-bg-2); border-radius: 10px; } } diff --git a/src/views/dmx/knowledgeLib/tool.vue b/src/views/dmx/knowledgeLib/tool.vue index a636442..e3641b7 100644 --- a/src/views/dmx/knowledgeLib/tool.vue +++ b/src/views/dmx/knowledgeLib/tool.vue @@ -149,7 +149,7 @@ <a-divider style="margin-top: 10px" /> <div class="groupMain"> <a-checkbox-group v-model="data" @change="handleChange" > - <div class="groupList" :style="{background:keyBg=='1'?'#eff8ff':'white'}"> + <div class="groupList" :class="{groupActive:keyBg=='1',groupNoActive:keyBg!='1'}"> <a-checkbox value="1"></a-checkbox> <div class="groupList-content" @click="groupListContentClick('1')" @dblclick="contentClick(1)"> 鑰� stable version 鏄渶鏂扮ǔ瀹氱増锛岀粡杩囧厖鍒嗘祴璇曞拰楠岃瘉锛宐ug 杈冨皯锛� @@ -164,7 +164,7 @@ </div> </div> - <div class="groupList" :style="{background:keyBg=='2'?'#eff8ff':'white'}"> + <div class="groupList" :class="{groupActive:keyBg=='2',groupNoActive:keyBg!='2'}"> <a-checkbox value="1"></a-checkbox> <div class="groupList-content" @click="groupListContentClick('2')" @dblclick="contentClick(1)"> 鑰� stable version 鏄渶鏂扮ǔ瀹氱増锛岀粡杩囧厖鍒嗘祴璇曞拰楠岃瘉锛宐ug 杈冨皯锛� @@ -403,13 +403,18 @@ box-sizing: border-box; margin: 0; padding: 0; - color: rgba(0, 0, 0, 0.88); + color: #2a2a2b; font-size: 14px; font-family: Inter; position: relative; - - } } } +.groupActive{ + background: #eff8ff; +} +.groupNoActive{ + background: var(--color-bg-1); + color: var(--color-text-1); +} </style> \ No newline at end of file diff --git a/src/views/login/components/login-form.vue b/src/views/login/components/login-form.vue index b628dad..8d4c702 100644 --- a/src/views/login/components/login-form.vue +++ b/src/views/login/components/login-form.vue @@ -83,12 +83,12 @@ const loginConfig = useStorage('login-config', { rememberPassword: true, - email: '1750082535@qq.com', // 婕旂ず榛樿鍊� - password: 'basic2024', // demo default value + email: '', // 婕旂ず榛樿鍊� + password: '', // demo default value }); const userInfo = reactive({ - email: '1750082535@qq.com', // 婕旂ず榛樿鍊� - password: 'basic2024', // demo default value + email: '', // 婕旂ず榛樿鍊� + password: '', // demo default value }); const handleSubmit = async ({ -- Gitblit v1.8.0