diff --git a/im-admin-ui/src/api/im/agent/index.ts b/im-admin-ui/src/api/im/agent/index.ts new file mode 100644 index 0000000..ee930ca --- /dev/null +++ b/im-admin-ui/src/api/im/agent/index.ts @@ -0,0 +1,30 @@ +import request from '@/utils/request'; +import { AxiosPromise } from 'axios'; + +/** + * 保存/更新代理悬浮球图片配置 + * @param data 配置参数 + */ +export function updateAgentFloatBall(data: { + uniqueToken: string; + pcFloatBall: string; + mobileFloatBall: string; +}): AxiosPromise { + return request({ + url: '/im/agent/updateFloatBall', + method: 'post', + data: data + }); +} + +/** + * 根据token获取代理悬浮球配置 + * @param token 代理唯一标识 + */ +export function getAgentFloatBallConfig(token: string): AxiosPromise { + return request({ + url: '/im/agent/infoByToken', + method: 'get', + params: { token } + }); +} \ No newline at end of file diff --git a/im-admin-ui/src/views/im/code/components/FloatBallSetting.vue b/im-admin-ui/src/views/im/code/components/FloatBallSetting.vue new file mode 100644 index 0000000..9fe489c --- /dev/null +++ b/im-admin-ui/src/views/im/code/components/FloatBallSetting.vue @@ -0,0 +1,247 @@ + + + + + \ No newline at end of file diff --git a/im-admin-ui/src/views/im/code/components/wangye.vue b/im-admin-ui/src/views/im/code/components/wangye.vue index c15045a..1073fe0 100644 --- a/im-admin-ui/src/views/im/code/components/wangye.vue +++ b/im-admin-ui/src/views/im/code/components/wangye.vue @@ -1,7 +1,7 @@ + @@ -52,12 +53,12 @@ --> - + - + @@ -73,6 +74,9 @@ + + + @@ -121,7 +125,10 @@ import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd } from '@/api/im/user/customer'; import { UserVO, UserQuery, UserForm } from '@/api/im/user/types'; import { to } from 'await-to-js'; +import { getInfo } from '@/api/login'; +import { getCurrentInstance, ComponentInternalInstance } from 'vue'; const { proxy } = getCurrentInstance() as ComponentInternalInstance; +const uniqueToken = ref(''); const userList = ref([]); const loading = ref(true); @@ -217,6 +224,76 @@ const handleQuery = () => { console.log('handleQuery'); }; +/** + * 获取当前登录用户的 uniqueToken + */ +const fetchUniqueToken = async () => { + try { + const res = await getInfo(); + if (res.data?.tokenInfo?.uniqueToken) { + uniqueToken.value = res.data.tokenInfo.uniqueToken; + } else { + console.warn('未获取到 uniqueToken'); + } + } catch (error) { + console.error('获取 uniqueToken 失败:', error); + } +}; +/** + * 复制客服链接 + * @param row 客服信息 + */ +const handleCopyLink = async (row: UserVO) => { + // 构建链接,拼接 kefuid 参数 + const baseUrl = `${location.origin}/h5`; + const linkUrl = `${baseUrl}?token=${uniqueToken.value}&kefuid=${row.id}`; + + try { + // 使用现代 Clipboard API + await navigator.clipboard.writeText(linkUrl); + ElMessage.success('链接已复制到剪贴板'); + } catch (err) { + // 降级方案:使用传统方法 + fallbackCopyTextToClipboard(linkUrl); + } +}; +/** + * 降级复制方案(兼容旧浏览器) + */ +const fallbackCopyTextToClipboard = (text: string) => { + const textArea = document.createElement('textarea'); + textArea.value = text; + + // 避免闪烁 + // textArea.style.position = 'fixed'; + // textArea.style.top = '0'; + // textArea.style.left = '0'; + // textArea.style.width = '2em'; + // textArea.style.height = '2em'; + // textArea.style.padding = '0'; + // textArea.style.border = 'none'; + // textArea.style.outline = 'none'; + // textArea.style.boxShadow = 'none'; + // textArea.style.background = 'transparent'; + + document.body.appendChild(textArea); + textArea.focus(); + textArea.select(); + + try { + const successful = document.execCommand('copy'); + if (successful) { + ElMessage.success('链接已复制到剪贴板'); + } else { + ElMessage.error('复制失败,请手动复制'); + } + } catch (err) { + console.error('Fallback: Oops, unable to copy', err); + ElMessage.error('复制失败,请手动复制'); + } + + document.body.removeChild(textArea); +}; /** 重置按钮操作 */ const resetQuery = () => { queryFormRef.value?.resetFields(); @@ -344,5 +421,6 @@ const handleExport = () => { onMounted(() => { getList(); + fetchUniqueToken(); });