parent
497c5196f8
commit
731781b19a
@ -1,33 +1,146 @@ |
||||
<template> |
||||
<input |
||||
ref="fileInput" |
||||
class="file-input" |
||||
type="file" |
||||
accept="image/jpeg,image/png,image/gif,image/webp" |
||||
@change="handleFileChange" |
||||
/> |
||||
</template> |
||||
|
||||
<script setup> |
||||
import { ref, inject, onMounted } from 'vue' |
||||
import { ref, inject, unref } from 'vue' |
||||
import { showToast } from 'vant' |
||||
import utils from '@/utils/utils' |
||||
import { compressImage } from '@/utils/CompressImage' |
||||
import { Post } from '@/utils/https' |
||||
import { upLoadImgHttp } from '@/utils/https' |
||||
|
||||
const emit = defineEmits(['image-selected', 'image-sent', 'image-failed']) |
||||
|
||||
const store = inject('appStore', null) |
||||
const userId = inject('userId', ref('')) |
||||
const token = inject('token', ref('')) |
||||
const manualService = inject('manualService', ref('1')) |
||||
const sessionId = inject('sessionId', ref('')) |
||||
const source = inject('source', ref('')) |
||||
const mescrollContent = inject('mescrollContent', null) |
||||
const elder = inject('elder', false) |
||||
|
||||
const upImage = ref(true) |
||||
const showImage = ref(false) |
||||
const srcImg = ref('') |
||||
const isWxAndroid = ref(false) |
||||
const fileInput = ref(null) |
||||
const uploading = ref(false) |
||||
|
||||
const MAX_IMAGE_SIZE = 5 * 1024 * 1024 |
||||
const ALLOWED_IMAGE_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'] |
||||
|
||||
function openFilePicker() { |
||||
if (uploading.value) { |
||||
showToast('图片正在发送,请稍候') |
||||
return |
||||
} |
||||
fileInput.value?.click() |
||||
} |
||||
|
||||
function readAsDataUrl(file) { |
||||
return new Promise((resolve, reject) => { |
||||
const reader = new FileReader() |
||||
reader.onload = () => resolve(reader.result) |
||||
reader.onerror = reject |
||||
reader.readAsDataURL(file) |
||||
}) |
||||
} |
||||
|
||||
async function getUploadFile(file, dataUrl) { |
||||
try { |
||||
const result = await compressImage(dataUrl, { |
||||
file: { file }, |
||||
quality: 0.8, |
||||
maxWidth: 1600, |
||||
maxHeight: 1600, |
||||
}) |
||||
if (!result?.blob || result.blob.size >= file.size) return file |
||||
return new File([result.blob], file.name, { |
||||
type: result.blob.type || file.type, |
||||
lastModified: Date.now(), |
||||
}) |
||||
} catch (error) { |
||||
console.log('图片压缩失败,使用原图上传', error) |
||||
return file |
||||
} |
||||
} |
||||
|
||||
function getResponseData(response) { |
||||
let data = response?.data ?? response |
||||
if (typeof data === 'string') { |
||||
try { |
||||
data = JSON.parse(data) |
||||
} catch (error) { |
||||
return { value: data } |
||||
} |
||||
} |
||||
return data?.data ?? data ?? {} |
||||
} |
||||
|
||||
function isBusinessFailure(response) { |
||||
if (response?.success === false) return true |
||||
const code = Number(response?.code) |
||||
return Number.isFinite(code) && (code < 0 || code >= 400) |
||||
} |
||||
|
||||
async function handleFileChange(event) { |
||||
const input = event.target |
||||
const file = input.files?.[0] |
||||
input.value = '' |
||||
|
||||
if (!file || uploading.value) return |
||||
if (!ALLOWED_IMAGE_TYPES.includes(file.type)) { |
||||
showToast('请选择 JPG、PNG、GIF 或 WebP 图片') |
||||
return |
||||
} |
||||
if (file.size > MAX_IMAGE_SIZE) { |
||||
showToast('图片大小不能超过5M') |
||||
return |
||||
} |
||||
|
||||
const localId = `image_${Date.now()}_${Math.random().toString(36).slice(2, 8)}` |
||||
let previewUrl = '' |
||||
|
||||
try { |
||||
previewUrl = await readAsDataUrl(file) |
||||
emit('image-selected', { localId, imageUrl: previewUrl, fileName: file.name }) |
||||
uploading.value = true |
||||
|
||||
onMounted(() => { |
||||
if (utils.isWeiXin() && utils.isAndroid() === 'isAndroid') { |
||||
isWxAndroid.value = true |
||||
const uploadFile = await getUploadFile(file, previewUrl) |
||||
const formData = new FormData() |
||||
formData.append('file', uploadFile, file.name) |
||||
formData.append('fromFlag', '1') |
||||
formData.append('userId', unref(userId) || '') |
||||
formData.append('sessionId', unref(sessionId) || '') |
||||
formData.append('source', unref(source) || '') |
||||
formData.append('reqAndResType', '2') |
||||
formData.append('msgSource', String(unref(manualService) || '1')) |
||||
formData.append('timestamp', String(Date.now())) |
||||
|
||||
const response = await upLoadImgHttp('FileUpLoad/uploadImgAndVideo', formData) |
||||
if (isBusinessFailure(response)) { |
||||
throw new Error(response?.msg || '图片发送失败') |
||||
} |
||||
|
||||
const data = getResponseData(response) |
||||
emit('image-sent', { |
||||
localId, |
||||
imageUrl: data?.imgUrl || data?.url || previewUrl, |
||||
imageKey: data?.imgKey || data?.fileKey || data?.key || '', |
||||
response, |
||||
}) |
||||
} catch (error) { |
||||
console.log('图片发送失败', error) |
||||
if (previewUrl) emit('image-failed', { localId }) |
||||
showToast(error?.message || '图片发送失败,请稍后重试') |
||||
} finally { |
||||
uploading.value = false |
||||
} |
||||
} |
||||
|
||||
// ... 方法中: |
||||
// this.$store.commit('set_sendLoading') → store?.set_sendLoading?.(value) |
||||
// this.$post('FileUpLoad/uploadImgAndVideo') → Post('FileUpLoad/uploadImgAndVideo', ...) |
||||
// this.mescrollContent → mescrollContent.value |
||||
// this.$elder → elder |
||||
defineExpose({ openFilePicker }) |
||||
</script> |
||||
|
||||
<style scoped> |
||||
.file-input { |
||||
display: none; |
||||
} |
||||
</style> |
||||
|
||||
@ -1,64 +1,17 @@ |
||||
let curWwwPath = window.location.href; |
||||
let pathName = ''; // window.location.pathname
|
||||
let pos = curWwwPath.indexOf(pathName); |
||||
let host = window.location.host; |
||||
let protocol = window.location.protocol; |
||||
let localhostPath = curWwwPath // downSource.substring(0, pos);
|
||||
let projectName = pathName.substring(0, pathName.substr(1).indexOf('/') + 1); |
||||
let isWs = protocol == 'https:' ? 'wss' : 'ws'; |
||||
const currentUrl = new URL(window.location.href) |
||||
const host = currentUrl.host |
||||
const protocol = currentUrl.protocol |
||||
const isWs = protocol === 'https:' ? 'wss' : 'ws' |
||||
|
||||
let baseUrl = ""; |
||||
let WSURL = ''; |
||||
let envType = ''; |
||||
|
||||
//开发环境
|
||||
if(localhostPath.indexOf("localhost") >=0 || localhostPath.indexOf("172.16") >=0){ |
||||
baseUrl = '/api'; |
||||
WSURL = `${isWs}://${host}/api/liics_api/webSocket/`; //ws://ssp-dev.trace.com.cn/liics_api/webSocket/
|
||||
envType = 'dev'; |
||||
|
||||
//测试环境
|
||||
}else if( |
||||
localhostPath.includes("-dev") || |
||||
localhostPath.includes("-sit") || |
||||
localhostPath.includes("-uat") || |
||||
localhostPath.includes("-pt") |
||||
){ |
||||
baseUrl = localhostPath; |
||||
WSURL = `${isWs}://${host}/liics_api/webSocket/`; //ws://ssp-dev.trace.com.cn/liics_api/webSocket/
|
||||
envType = 'sit'; |
||||
//生产环境
|
||||
}else{ |
||||
baseUrl = localhostPath; |
||||
WSURL = `${isWs}://${host}/liics_api/webSocket/`; //ws://ssp-dev.trace.com.cn/liics_api/webSocket/
|
||||
envType = 'production'; |
||||
// liics 的 HTTP/WebSocket 服务与页面使用同一域名;本地开发也由 Vite
|
||||
// 直接代理 /liics_api,因此浏览器里看到的请求路径在各环境保持一致。
|
||||
const config = { |
||||
baseUrl: '/liics_api/', |
||||
WSURL: `${isWs}://${host}/liics_api/webSocket/`, |
||||
envType: import.meta.env.DEV ? 'dev' : 'production', |
||||
BASEURL: currentUrl.origin, |
||||
} |
||||
console.log('baseUrl', baseUrl, localhostPath, window.location.href, window.location.pathname); |
||||
|
||||
// switch (process.env.NODE_ENV) {
|
||||
// case 'development':
|
||||
// baseUrl = process.env.VUE_APP_BASE_API //这里是本地的请求url
|
||||
// WSURL = process.env.VUE_APP_WEBSOCKET_URL;
|
||||
// break
|
||||
// case 'sit': // 注意这里的名字要和步骤二中设置的环境名字对应起来
|
||||
// baseUrl = process.env.VUE_APP_BASE_API //这里是测试环境中的url
|
||||
// WSURL = process.env.VUE_APP_WEBSOCKET_URL;
|
||||
// break
|
||||
// case 'production':
|
||||
// baseUrl = process.env.VUE_APP_BASE_API //生产环境url
|
||||
// WSURL = process.env.VUE_APP_WEBSOCKET_URL;
|
||||
// break
|
||||
// default:
|
||||
// baseUrl = process.env.VUE_APP_BASE_API //生产环境url
|
||||
// WSURL = process.env.VUE_APP_WEBSOCKET_URL;
|
||||
// }
|
||||
|
||||
console.log('liics api config', config) |
||||
|
||||
let config = { |
||||
baseUrl: `${baseUrl}/liics_api/`,//后台请求链接
|
||||
WSURL: WSURL,//websocket链接
|
||||
envType: envType,//环境类型
|
||||
BASEURL: baseUrl, |
||||
} |
||||
|
||||
export default config; |
||||
export default config |
||||
|
||||
@ -0,0 +1,29 @@ |
||||
import { fetchPost, upLoadImgHttp } from '@/utils/https' |
||||
|
||||
// The legacy liics chat used a small set of HTTP endpoints. Keeping those
|
||||
// calls here gives the Vue 3 store a single transport boundary and preserves
|
||||
// the payload contract expected by the existing chat components.
|
||||
export const postConversation = (url, data = {}) => fetchPost(url, data) |
||||
|
||||
export const sendRobotMessage = (payload) => postConversation('semantic/qaChat', payload) |
||||
|
||||
export const sendVoiceMessage = (payload) => postConversation('upload/hxVoice', payload) |
||||
|
||||
export const uploadConversationImage = (formData) => upLoadImgHttp('upload/image', formData) |
||||
|
||||
export const connectHumanService = (payload) => postConversation('user/connectToEasemob', payload) |
||||
|
||||
export const updateReadMessages = (payload) => postConversation('HumanChat/msgCallBack', payload) |
||||
|
||||
export const submitUserBehavior = (payload) => postConversation('user/interactive', payload) |
||||
|
||||
export const submitSatisfaction = (payload) => postConversation('semantic/savePaperResult', payload) |
||||
|
||||
export const loadSystemConfig = (payload) => postConversation('config/sysConfig', payload) |
||||
|
||||
export const loadHeaderAvatar = (payload) => postConversation('config/avatar', payload) |
||||
|
||||
export const loadTipsConfig = (payload) => |
||||
postConversation('insuranceQuery/longTermRiskConfigValue', payload) |
||||
|
||||
export const getLegacyApi = (url, params) => postConversation(url, params) |
||||
Loading…
Reference in new issue