Browse Source

网页内嵌添加可选客服的功能

master
[yxf] 6 days ago
parent
commit
48b5819f19
  1. 23
      im-admin-ui/src/api/im/agent/index.ts
  2. 3
      im-admin-ui/src/views/im/code/components/wangye.vue
  3. 65
      im-admin-ui/src/views/im/code/index.vue
  4. 19
      im-admin/ruoyi-im/src/main/java/org/dromara/im/controller/ImAgentController.java
  5. 5
      im-admin/ruoyi-im/src/main/java/org/dromara/im/domain/ImAgent.java
  6. 6
      im-admin/ruoyi-im/src/main/java/org/dromara/im/domain/bo/ImAgentBo.java
  7. 6
      im-admin/ruoyi-im/src/main/java/org/dromara/im/domain/vo/ImAgentVo.java
  8. 11
      im-admin/ruoyi-im/src/main/java/org/dromara/im/service/IImAgentService.java
  9. 33
      im-admin/ruoyi-im/src/main/java/org/dromara/im/service/impl/ImAgentServiceImpl.java

23
im-admin-ui/src/api/im/agent/index.ts

@ -28,3 +28,26 @@ export function getAgentFloatBallConfig(token: string): AxiosPromise<any> {
params: { token }
});
}
/**
* ID
*/
export function getDefaultKefu(): AxiosPromise<any> {
return request({
url: '/im/agent/defaultKefu',
method: 'get'
});
}
/**
* ID
* @param kefuId IDnull表示清除
*/
export function saveDefaultKefu(kefuId: number | null): AxiosPromise<any> {
return request({
url: '/im/agent/saveDefaultKefu',
method: 'post',
data: { defaultKefuId: kefuId }
});
}

3
im-admin-ui/src/views/im/code/components/wangye.vue

@ -19,7 +19,7 @@
openUrl: '{{ siteUrl }}',
token: '{{ uniqueToken }}',
isShowTip: true,
kefuid: '',
kefuid: '{{ kefuId || "" }}',
mobileIcon: '{{ floatConfig?.mobileImage || "" }}',
pcIcon: '{{ floatConfig?.pcImage || "" }}',
windowStyle:'',
@ -49,6 +49,7 @@ const props = defineProps<{
tokeninfo?: any;
siteUrl?: string;
uniqueToken: string;
kefuId?: number;
floatConfig?: { //
pcImage: string;
mobileImage: string;

65
im-admin-ui/src/views/im/code/index.vue

@ -2,6 +2,30 @@
<div class="getCode_container">
<div class="content">
<el-card shadow="never">
<!-- 客服选择 -->
<div class="kefu-selector">
<span class="kefu-label">指定客服</span>
<el-select
v-model="selectedKefuId"
placeholder="不指定(系统自动分配)"
clearable
size="small"
style="width: 240px;"
@change="onKefuChange"
>
<el-option
v-for="item in kefuList"
:key="item.id"
:label="item.nickName"
:value="item.id"
>
<div style="display: flex; align-items: center; gap: 8px;">
<el-avatar :src="item.headImageThumb" :size="24" v-if="item.headImageThumb" />
<span>{{ item.nickName }}</span>
</div>
</el-option>
</el-select>
</div>
<!-- 使用悬浮球设置组件 -->
<FloatBallSetting
ref="floatBallSettingRef"
@ -15,7 +39,7 @@
<alink :tokeninfo="token" :site-url="siteUrl" :unique-token="uniqueToken" @cget-copy="getCopy"></alink>
</el-collapse-item>
<el-collapse-item title="网页内嵌" name="2">
<wangye :tokeninfo="token" :site-url="siteUrl" :unique-token="uniqueToken" :float-config="floatBallConfig" @cget-copy="getCopy"></wangye>
<wangye :tokeninfo="token" :site-url="siteUrl" :unique-token="uniqueToken" :kefu-id="selectedKefuId" :float-config="floatBallConfig" @cget-copy="getCopy"></wangye>
</el-collapse-item>
</el-collapse>
</el-card>
@ -30,8 +54,10 @@ import { ref, computed, onMounted, getCurrentInstance } from 'vue';
import alink from './components/alink.vue';
import wangye from './components/wangye.vue';
import FloatBallSetting from './components/FloatBallSetting.vue';
import { listUser } from '@/api/im/user/customer';
import type { FloatBallConfig } from './components/FloatBallSetting.vue';
import { getInfo } from '@/api/login';
import { getDefaultKefu, saveDefaultKefu } from '@/api/im/agent';
// import kaifa from './components/kaifa';
// import setting from './components/setting';
@ -57,6 +83,9 @@ const siteUrl = ref(`${location.origin}`);
const cloneTip = ref(false);
const canCustomerServer = ref('');
const selectedKefuId = ref<number | ''>('');
const kefuList = ref<any[]>([]);
const linkUrl = computed(() => `${location.origin}/chat/index?token=${token.value?.token_md5}&noCanClose=1`);
onMounted(() => {
// uniqueToken
@ -86,13 +115,45 @@ async function fetchAgentToken() {
if (res.data?.tokenInfo?.uniqueToken) {
// token
uniqueToken.value = res.data.tokenInfo.uniqueToken;
console.log('✅ 获取成功 uniqueToken =', uniqueToken.value);
await Promise.all([loadKefuList(), loadDefaultKefu()]);
}
} catch (e) {
console.error('获取token失败', e);
}
}
async function loadKefuList() {
try {
const res = await listUser();
const data = (res as any)?.rows || [];
kefuList.value = data;
} catch (e) {
console.error('获取客服列表失败', e);
}
}
// ID
async function loadDefaultKefu() {
try {
const kefuId = await getDefaultKefu();
if (kefuId.data) {
selectedKefuId.value = kefuId.data;
}
} catch (e) {
console.error('获取默认客服失败', e);
}
}
async function onKefuChange(val: number | '') {
try {
await saveDefaultKefu(val || null);
proxy?.$Message?.success('已保存');
} catch (e) {
console.error('保存默认客服失败', e);
}
}
//
function handleFloatBallConfigUpdate(config: FloatBallConfig) {
floatBallConfig.value = config;

19
im-admin/ruoyi-im/src/main/java/org/dromara/im/controller/ImAgentController.java

@ -139,4 +139,23 @@ public class ImAgentController extends BaseController {
public R<List<Map<String, Object>>> getAllAgentNameList() {
return R.ok(imAgentService.getAllAgentNameList());
}
/**
* 获取默认客服ID
*/
@GetMapping("/defaultKefu")
public R<Long> getDefaultKefu() {
return R.ok(imAgentService.getDefaultKefuId());
}
/**
* 保存默认客服ID
*/
@RepeatSubmit()
@PostMapping("/saveDefaultKefu")
public R<Void> saveDefaultKefu(@RequestBody ImAgentBo bo) {
imAgentService.saveDefaultKefuId(bo.getDefaultKefuId());
return R.ok();
}
}

5
im-admin/ruoyi-im/src/main/java/org/dromara/im/domain/ImAgent.java

@ -76,4 +76,9 @@ public class ImAgent implements TransPojo {
*/
private String mobileFloatBall;
/**
* 默认客服
*/
private Long defaultKefuId;
}

6
im-admin/ruoyi-im/src/main/java/org/dromara/im/domain/bo/ImAgentBo.java

@ -75,4 +75,10 @@ public class ImAgentBo {
* 移动端悬浮球图片
*/
private String mobileFloatBall;
/**
* 默认客服id
*/
private Long defaultKefuId;
}

6
im-admin/ruoyi-im/src/main/java/org/dromara/im/domain/vo/ImAgentVo.java

@ -87,4 +87,10 @@ public class ImAgentVo implements Serializable {
*/
private String mobileFloatBall;
/**
* 默认客服
*/
private Long defaultKefuId;
}

11
im-admin/ruoyi-im/src/main/java/org/dromara/im/service/IImAgentService.java

@ -100,4 +100,15 @@ public interface IImAgentService {
* 更新悬浮球图片配置
*/
void updateFloatBall(ImAgentBo bo);
/**
* 获取默认客服ID
*/
Long getDefaultKefuId();
/**
* 保存默认客服ID
*/
void saveDefaultKefuId(Long kefuId);
}

33
im-admin/ruoyi-im/src/main/java/org/dromara/im/service/impl/ImAgentServiceImpl.java

@ -4,6 +4,7 @@ import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
@ -257,4 +258,36 @@ public class ImAgentServiceImpl implements IImAgentService {
agent.setMobileFloatBall(bo.getMobileFloatBall());
baseMapper.updateById(agent);
}
@Override
public Long getDefaultKefuId() {
Long userId = LoginHelper.getUserId();
if (userId == null || LoginHelper.isSuperAdmin()) {
return null;
}
ImAgent agent = baseMapper.selectOne(
new LambdaQueryWrapper<ImAgent>().eq(ImAgent::getSysId, userId)
);
return agent != null ? agent.getDefaultKefuId() : null;
}
@Override
public void saveDefaultKefuId(Long kefuId) {
Long userId = LoginHelper.getUserId();
if (userId == null || LoginHelper.isSuperAdmin()) {
throw new RuntimeException("无权限操作");
}
ImAgent agent = baseMapper.selectOne(
new LambdaQueryWrapper<ImAgent>().eq(ImAgent::getSysId, userId)
);
if (agent == null) {
throw new RuntimeException("代理不存在");
}
LambdaUpdateWrapper<ImAgent> wrapper = new LambdaUpdateWrapper<>();
wrapper.eq(ImAgent::getId, agent.getId());
wrapper.set(ImAgent::getDefaultKefuId, kefuId);
baseMapper.update(null, wrapper);
}
}

Loading…
Cancel
Save