diff --git a/ui/src/api/application/application-key.ts b/ui/src/api/application/application-key.ts index 81035bbb1..a0cd5d1e8 100644 --- a/ui/src/api/application/application-key.ts +++ b/ui/src/api/application/application-key.ts @@ -1,10 +1,15 @@ import { Result } from '@/request/Result' import { get, post, del, put } from '@/request/index' - +import useStore from '@/stores' import { type Ref } from 'vue' -const prefix = '/workspace/' + localStorage.getItem('workspace_id') + '/application' - +const prefix: any = { _value: '/workspace/' } +Object.defineProperty(prefix, 'value', { + get: function () { + const { user } = useStore() + return this._value + user.getWorkspaceId() + '/application' + }, +}) /** * API_KEY列表 * @param 参数 application_id @@ -13,7 +18,7 @@ const getAPIKey: (application_id: string, loading?: Ref) => Promise { - return get(`${prefix}/${application_id}/application`, undefined, loading) + return get(`${prefix.value}/${application_id}/application`, undefined, loading) } /** @@ -24,7 +29,7 @@ const postAPIKey: (application_id: string, loading?: Ref) => Promise { - return post(`${prefix}/${application_id}/application`, {}, undefined, loading) + return post(`${prefix.value}/${application_id}/application`, {}, undefined, loading) } /** @@ -36,7 +41,12 @@ const delAPIKey: ( api_key_id: string, loading?: Ref, ) => Promise> = (application_id, api_key_id, loading) => { - return del(`${prefix}/${application_id}/application/${api_key_id}`, undefined, undefined, loading) + return del( + `${prefix.value}/${application_id}/application/${api_key_id}`, + undefined, + undefined, + loading, + ) } /** @@ -52,7 +62,12 @@ const putAPIKey: ( data: any, loading?: Ref, ) => Promise> = (application_id, api_key_id, data, loading) => { - return put(`${prefix}/${application_id}/application/${api_key_id}`, data, undefined, loading) + return put( + `${prefix.value}/${application_id}/application/${api_key_id}`, + data, + undefined, + loading, + ) } export default { diff --git a/ui/src/api/application/application.ts b/ui/src/api/application/application.ts index 633b79fa3..e0c852cf7 100644 --- a/ui/src/api/application/application.ts +++ b/ui/src/api/application/application.ts @@ -3,9 +3,15 @@ import { get, post, postStream, del, put, request, download, exportFile } from ' import type { pageRequest } from '@/api/type/common' import type { ApplicationFormType } from '@/api/type/application' import { type Ref } from 'vue' +import useStore from '@/stores' -const prefix = '/workspace/' + localStorage.getItem('workspace_id') + '/application' - +const prefix: any = { _value: '/workspace/' } +Object.defineProperty(prefix, 'value', { + get: function () { + const { user } = useStore() + return this._value + user.getWorkspaceId() + '/application' + }, +}) /** * 获取全部应用 * @param 参数 @@ -14,7 +20,7 @@ const getAllApplication: (param?: any, loading?: Ref) => Promise { - return get(`${prefix}`, param, loading) + return get(`${prefix.value}`, param, loading) } /** @@ -28,7 +34,7 @@ const getApplication: ( param: any, loading?: Ref, ) => Promise> = (page, param, loading) => { - return get(`${prefix}/${page.current_page}/${page.page_size}`, param, loading) + return get(`${prefix.value}/${page.current_page}/${page.page_size}`, param, loading) } /** @@ -39,7 +45,7 @@ const postApplication: ( data: ApplicationFormType, loading?: Ref, ) => Promise> = (data, loading) => { - return post(`${prefix}`, data, undefined, loading) + return post(`${prefix.value}`, data, undefined, loading) } /** @@ -51,7 +57,7 @@ const putApplication: ( data: ApplicationFormType, loading?: Ref, ) => Promise> = (application_id, data, loading) => { - return put(`${prefix}/${application_id}`, data, undefined, loading) + return put(`${prefix.value}/${application_id}`, data, undefined, loading) } /** @@ -62,7 +68,7 @@ const delApplication: ( application_id: string, loading?: Ref, ) => Promise> = (application_id, loading) => { - return del(`${prefix}/${application_id}`, undefined, {}, loading) + return del(`${prefix.value}/${application_id}`, undefined, {}, loading) } /** @@ -73,7 +79,7 @@ const getApplicationDetail: ( application_id: string, loading?: Ref, ) => Promise> = (application_id, loading) => { - return get(`${prefix}/${application_id}`, undefined, loading) + return get(`${prefix.value}/${application_id}`, undefined, loading) } /** @@ -84,7 +90,7 @@ const getAccessToken: (application_id: string, loading?: Ref) => Promis application_id, loading, ) => { - return get(`${prefix}/${application_id}/access_token`, undefined, loading) + return get(`${prefix.value}/${application_id}/access_token`, undefined, loading) } /** @@ -99,7 +105,7 @@ const putAccessToken: ( data: any, loading?: Ref, ) => Promise> = (application_id, data, loading) => { - return put(`${prefix}/${application_id}/access_token`, data, undefined, loading) + return put(`${prefix.value}/${application_id}/access_token`, data, undefined, loading) } /** @@ -113,7 +119,7 @@ const exportApplication = ( ) => { return exportFile( application_name + '.mk', - `${prefix}/${application_id}/export`, + `${prefix.value}/${application_id}/export`, undefined, loading, ) @@ -126,7 +132,7 @@ const importApplication: (data: any, loading?: Ref) => Promise { - return post(`${prefix}/import`, data, undefined, loading) + return post(`${prefix.value}/import`, data, undefined, loading) } /** @@ -138,7 +144,7 @@ const getStatistics: ( data: any, loading?: Ref, ) => Promise> = (application_id, data, loading) => { - return get(`${prefix}/${application_id}/application_stats`, data, loading) + return get(`${prefix.value}/${application_id}/application_stats`, data, loading) } /** * 打开调试对话id @@ -150,7 +156,7 @@ const open: (application_id: string, loading?: Ref) => Promise { - return get(`${prefix}/${application_id}/open`, {}, loading) + return get(`${prefix.value}/${application_id}/open`, {}, loading) } /** * 对话 diff --git a/ui/src/api/chat/chat.ts b/ui/src/api/chat/chat.ts new file mode 100644 index 000000000..82cbbc402 --- /dev/null +++ b/ui/src/api/chat/chat.ts @@ -0,0 +1,54 @@ +import { Result } from '@/request/Result' +import { + get, + post, + postStream, + del, + put, + request, + download, + exportFile, +} from '@/request/chat/index' + +import { type Ref } from 'vue' + +const prefix = '/workspace/' + localStorage.getItem('workspace_id') + '/application' + +/** + * 打开调试对话id + * @param application_id 应用id + * @param loading 加载器 + * @returns + */ +const open: (application_id: string, loading?: Ref) => Promise> = ( + application_id, + loading, +) => { + return get(`${prefix}/${application_id}/open`, {}, loading) +} +/** + * 对话 + * @param 参数 + * chat_id: string + * data + */ +const chat: (chat_id: string, data: any) => Promise = (chat_id, data) => { + return postStream(`/api/chat_message/${chat_id}`, data) +} +const chatProfile: (assessToken: string, loading?: Ref) => Promise> = ( + assessToken, + loading, +) => { + return get('/auth/profile', { access_token: assessToken }, loading) +} +const applicationProfile: (assessToken: string, loading?: Ref) => Promise> = ( + assessToken, + loading, +) => { + return get('/chat/api/profile') +} +export default { + open, + chat, + chatProfile, +} diff --git a/ui/src/request/chat/Result.ts b/ui/src/request/chat/Result.ts new file mode 100644 index 000000000..f76b82c0b --- /dev/null +++ b/ui/src/request/chat/Result.ts @@ -0,0 +1,19 @@ +export class Result { + message: string + code: number + data: T + constructor(message: string, code: number, data: T) { + this.message = message + this.code = code + this.data = data + } + + static success(data: any) { + return new Result('请求成功', 200, data) + } + static error(message: string, code: number) { + return new Result(message, code, null) + } +} + +export default Result diff --git a/ui/src/request/chat/index.ts b/ui/src/request/chat/index.ts new file mode 100644 index 000000000..480a52691 --- /dev/null +++ b/ui/src/request/chat/index.ts @@ -0,0 +1,349 @@ +import axios, { type InternalAxiosRequestConfig, AxiosHeaders } from 'axios' +import { MsgError } from '@/utils/message' +import type { NProgress } from 'nprogress' +import type { Ref } from 'vue' +import type { Result } from '@/request/Result' +import useStore from '@/stores' +import router from '@/router' + +import { ref, type WritableComputedRef } from 'vue' + +const axiosConfig = { + baseURL: '/chat/api', + withCredentials: false, + timeout: 600000, + headers: {}, +} + +const instance = axios.create(axiosConfig) + +/* 设置请求拦截器 */ +instance.interceptors.request.use( + (config: InternalAxiosRequestConfig) => { + if (config.headers === undefined) { + config.headers = new AxiosHeaders() + } + const { user, login } = useStore() + const token = login.getToken() + const language = user.getLanguage() + config.headers['Accept-Language'] = `${language}` + if (token) { + config.headers['AUTHORIZATION'] = `Bearer ${token}` + } + return config + }, + (err: any) => { + return Promise.reject(err) + }, +) + +//设置响应拦截器 +instance.interceptors.response.use( + (response: any) => { + if (response.data) { + if (response.data.code !== 200 && !(response.data instanceof Blob)) { + if (response.config.url.includes('/application/authentication')) { + return Promise.reject(response.data) + } + if ( + !response.config.url.includes('/valid') && + !response.config.url.includes('/tool/debug') + ) { + MsgError(response.data.message) + return Promise.reject(response.data) + } + } + } + return response + }, + (err: any) => { + if (err.code === 'ECONNABORTED') { + MsgError(err.message) + console.error(err) + } + if (err.response?.status === 404) { + if (!err.response.config.url.includes('/application/authentication')) { + router.push('/404 ') + } + } + if (err.response?.status === 401) { + if ( + !err.response.config.url.includes('chat/open') && + !err.response.config.url.includes('application/profile') + ) { + router.push({ name: 'login' }) + } + } + + if (err.response?.status === 403 && !err.response.config.url.includes('chat/open')) { + MsgError( + err.response.data && err.response.data.message ? err.response.data.message : '没有权限访问', + ) + } + return Promise.reject(err) + }, +) + +export const request = instance + +/* 简化请求方法,统一处理返回结果,并增加loading处理,这里以{success,data,message}格式的返回值为例,具体项目根据实际需求修改 */ +const promise: ( + request: Promise, + loading?: NProgress | Ref | WritableComputedRef, +) => Promise> = (request, loading = ref(false)) => { + return new Promise((resolve, reject) => { + if ((loading as NProgress).start) { + ;(loading as NProgress).start() + } else { + ;(loading as Ref).value = true + } + request + .then((response) => { + // blob类型的返回状态是response.status + if (response.status === 200) { + resolve(response?.data || response) + } else { + reject(response?.data || response) + } + }) + .catch((error) => { + reject(error) + }) + .finally(() => { + if ((loading as NProgress).start) { + ;(loading as NProgress).done() + } else { + ;(loading as Ref).value = false + } + }) + }) +} + +/** + * 发送get请求 一般用来请求资源 + * @param url 资源url + * @param params 参数 + * @param loading loading + * @returns 异步promise对象 + */ +export const get: ( + url: string, + params?: unknown, + loading?: NProgress | Ref, + timeout?: number, +) => Promise> = ( + url: string, + params: unknown, + loading?: NProgress | Ref, + timeout?: number, +) => { + return promise(request({ url: url, method: 'get', params, timeout: timeout }), loading) +} + +/** + * faso post请求 一般用来添加资源 + * @param url 资源url + * @param params 参数 + * @param data 添加数据 + * @param loading loading + * @returns 异步promise对象 + */ +export const post: ( + url: string, + data?: unknown, + params?: unknown, + loading?: NProgress | Ref, + timeout?: number, +) => Promise | any> = (url, data, params, loading, timeout) => { + return promise(request({ url: url, method: 'post', data, params, timeout }), loading) +} + +/**| + * 发送put请求 用于修改服务器资源 + * @param url 资源地址 + * @param params params参数地址 + * @param data 需要修改的数据 + * @param loading 进度条 + * @returns + */ +export const put: ( + url: string, + data?: unknown, + params?: unknown, + loading?: NProgress | Ref, + timeout?: number, +) => Promise> = (url, data, params, loading, timeout) => { + return promise(request({ url: url, method: 'put', data, params, timeout }), loading) +} + +/** + * 删除 + * @param url 删除url + * @param params params参数 + * @param loading 进度条 + * @returns + */ +export const del: ( + url: string, + params?: unknown, + data?: unknown, + loading?: NProgress | Ref, + timeout?: number, +) => Promise> = (url, params, data, loading, timeout) => { + return promise(request({ url: url, method: 'delete', params, data, timeout }), loading) +} + +/** + * 流处理 + * @param url url地址 + * @param data 请求body + * @returns + */ +export const postStream: (url: string, data?: unknown) => Promise | any> = ( + url, + data, +) => { + const { user, login } = useStore() + const token = login.getToken() + const language = user.getLanguage() + const headers: HeadersInit = { 'Content-Type': 'application/json' } + if (token) { + headers['AUTHORIZATION'] = `Bearer ${token}` + } + headers['Accept-Language'] = `${language}` + return fetch(url, { + method: 'POST', + body: data ? JSON.stringify(data) : undefined, + headers: headers, + }) +} + +export const exportExcel: ( + fileName: string, + url: string, + params: any, + loading?: NProgress | Ref, +) => Promise = ( + fileName: string, + url: string, + params: any, + loading?: NProgress | Ref, +) => { + return promise(request({ url: url, method: 'get', params, responseType: 'blob' }), loading).then( + (res: any) => { + if (res) { + const blob = new Blob([res], { + type: 'application/vnd.ms-excel', + }) + const link = document.createElement('a') + link.href = window.URL.createObjectURL(blob) + link.download = fileName + link.click() + //释放内存 + window.URL.revokeObjectURL(link.href) + } + return true + }, + ) +} + +export const exportFile: ( + fileName: string, + url: string, + params: any, + loading?: NProgress | Ref, +) => Promise = ( + fileName: string, + url: string, + params: any, + loading?: NProgress | Ref, +) => { + return promise(request({ url: url, method: 'get', params, responseType: 'blob' }), loading).then( + (res: any) => { + if (res) { + const blob = new Blob([res], { + type: 'application/octet-stream', + }) + const link = document.createElement('a') + link.href = window.URL.createObjectURL(blob) + link.download = fileName + link.click() + //释放内存 + window.URL.revokeObjectURL(link.href) + } + return true + }, + ) +} + +export const exportExcelPost: ( + fileName: string, + url: string, + params: any, + data: any, + loading?: NProgress | Ref, +) => Promise = ( + fileName: string, + url: string, + params: any, + data: any, + loading?: NProgress | Ref, +) => { + return promise( + request({ + url: url, + method: 'post', + params, // 查询字符串参数 + data, // 请求体数据 + responseType: 'blob', + }), + loading, + ).then((res: any) => { + if (res) { + const blob = new Blob([res], { + type: 'application/vnd.ms-excel', + }) + const link = document.createElement('a') + link.href = window.URL.createObjectURL(blob) + link.download = fileName + link.click() + // 释放内存 + window.URL.revokeObjectURL(link.href) + } + return true + }) +} + +export const download: ( + url: string, + method: string, + data?: any, + params?: any, + loading?: NProgress | Ref, +) => Promise = ( + url: string, + method: string, + data?: any, + params?: any, + loading?: NProgress | Ref, +) => { + return promise(request({ url: url, method: method, data, params, responseType: 'blob' }), loading) +} + +/** + * 与服务器建立ws链接 + * @param url websocket路径 + * @returns 返回一个websocket实例 + */ +export const socket = (url: string) => { + let protocol = 'ws://' + if (window.location.protocol === 'https:') { + protocol = 'wss://' + } + let uri = protocol + window.location.host + url + if (!import.meta.env.DEV) { + uri = protocol + window.location.host + import.meta.env.VITE_BASE_PATH + url + } + return new WebSocket(uri) +} +export default instance diff --git a/ui/src/stores/modules/user.ts b/ui/src/stores/modules/user.ts index 1e4208955..1a16cdf0d 100644 --- a/ui/src/stores/modules/user.ts +++ b/ui/src/stores/modules/user.ts @@ -21,6 +21,7 @@ export interface userStateTypes { license_is_valid: boolean edition: 'CE' | 'PE' | 'EE' themeInfo: any + workspace_id: string } const useUserStore = defineStore('user', { @@ -31,6 +32,7 @@ const useUserStore = defineStore('user', { license_is_valid: false, edition: 'CE', themeInfo: null, + workspace_id: 'default', }), actions: { getLanguage() { @@ -56,6 +58,16 @@ const useUserStore = defineStore('user', { return this.asyncGetProfile() }) }, + getWorkspaceId(): string | null { + if (this.workspace_id) { + return this.workspace_id + } + const workspace_id = localStorage.getItem('workspace_id') + if (workspace_id) { + this.workspace_id = workspace_id + } + return workspace_id + }, async asyncGetProfile() { return new Promise((resolve, reject) => { UserApi.getProfile() diff --git a/ui/src/views/chat/index.vue b/ui/src/views/chat/index.vue index 7f58d1df3..261f218c3 100644 --- a/ui/src/views/chat/index.vue +++ b/ui/src/views/chat/index.vue @@ -14,7 +14,7 @@ v-model="is_auth" :style="{ '--el-color-primary': application_profile?.custom_theme?.theme_color, - '--el-color-primary-light-9': hexToRgba(application_profile?.custom_theme?.theme_color, 0.1) + '--el-color-primary-light-9': hexToRgba(application_profile?.custom_theme?.theme_color, 0.1), }" > @@ -26,17 +26,18 @@ import Auth from '@/views/chat/auth/index.vue' import { hexToRgba } from '@/utils/theme' import { useI18n } from 'vue-i18n' import { getBrowserLang } from '@/locales/index' +import ChatAPI from '@/api/chat/chat.ts' const { locale } = useI18n({ useScope: 'global' }) const route = useRoute() const { application, user } = useStore() const components: any = import.meta.glob('@/views/chat/**/index.vue', { - eager: true + eager: true, }) const { query: { mode }, - params: { accessToken } + params: { accessToken }, } = route as any const is_auth = ref(false) const currentTemplate = computed(() => { @@ -91,9 +92,14 @@ function getAccessToken(token: string) { return getAppProfile() }) } +const getChatProfile = () => { + return ChatAPI.chatProfile(accessToken).then((ok: any) => { + console.log(ok) + }) +} onBeforeMount(() => { user.changeUserType(2, accessToken) - Promise.all([user.asyncGetProfile(), getAccessToken(accessToken)]) + Promise.all([user.asyncGetProfile(), getChatProfile()]) .catch(() => { applicationAvailable.value = false }) diff --git a/ui/vite.config.ts b/ui/vite.config.ts index dfaf1654d..931f24539 100644 --- a/ui/vite.config.ts +++ b/ui/vite.config.ts @@ -25,6 +25,11 @@ export default defineConfig(({ mode }) => { changeOrigin: true, rewrite: (path: string) => path.replace(ENV.VITE_BASE_PATH, '/'), } + proxyConf['/chat'] = { + target: 'http://127.0.0.1:8080', + changeOrigin: true, + rewrite: (path: string) => path.replace(ENV.VITE_BASE_PATH, '/'), + } proxyConf['/doc'] = { target: 'http://127.0.0.1:8080', changeOrigin: true,