提交 a3ab1107 作者: 毛细亚

合并分支 'release' 到 'master'

Release

查看合并请求 !31
......@@ -284,3 +284,19 @@ export function getUserQrCode(data) {
data,
});
}
// 打开会话绑定任务
export function clientSessionBindTaskApi(data) {
return request({
url: returnApi('/client_session/bindTask'),
method: 'post',
data,
});
}
// 根据w账号获取上一次交互时间
export function getMemberInfoApi(data) {
return request({
url: returnApi('/corp_zyou_bind/getMemberInfo'),
method: 'post',
data,
});
}
......@@ -27,62 +27,42 @@
class="rowFlex"
>
<div class="label">{{ item.label }}</div>
<div
v-if="item.type == 'money'"
class="value"
>
<div v-if="item.type == 'money'" class="value">
<p>
<span></span><span>{{ assionInfo[item.value] || 0 }}</span>
</p>
</div>
<div
v-else
class="value"
>
<div v-else class="value">
<span v-if="assionInfo[item.value]">{{
assionInfo[item.value] || ""
assionInfo[item.value] || ''
}}</span>
</div>
</div>
<div
v-else-if="item.value == 'plan_type'"
class="rowFlex"
>
<div v-else-if="item.value == 'plan_type'" class="rowFlex">
<div class="label">{{ item.label }}</div>
<div class="value">
<span style="color: #0787f2">{{
taskTypeList.find((k) => k.value == assionInfo[item.value])
? taskTypeList.find((k) => k.value == assionInfo[item.value])
.label
: ""
? taskTypeList.find(
(k) => k.value == assionInfo[item.value]
).label
: ''
}}</span>
</div>
</div>
<div
v-else-if="item.value == 'target'"
class="rowFlex"
>
<div v-else-if="item.value == 'target'" class="rowFlex">
<div class="label">{{ item.label }}</div>
<div class="value">
<span
v-if="assionInfo.target"
style="color: #0787f2"
>{{
<span v-if="assionInfo.target" style="color: #0787f2">{{
assionInfo.target.first && assionInfo.target.first.is_finished
? "已完成"
: "未完成"
? '已完成'
: '未完成'
}}</span>
</div>
</div>
<div
v-else-if="item.value == 'finished_event'"
class="rowFlex"
>
<div v-else-if="item.value == 'finished_event'" class="rowFlex">
<div class="label">{{ item.label }}</div>
<div
v-if="assionInfo.finished_event"
class="value"
>
<div v-if="assionInfo.finished_event" class="value">
<span
v-for="(item, index) in assionInfo.finished_event"
:key="index"
......@@ -92,20 +72,14 @@
</div>
</div>
<!-- w 账号 -->
<div
v-else-if="item.value == 'username'"
class="rowFlex"
>
<div v-else-if="item.value == 'username'" class="rowFlex">
<div class="label">{{ item.label }}</div>
<div
v-if="assionInfo.username && assionInfo.username.length > 0"
class="value"
>
<div
v-if="assionInfo.username.length <= 1"
class="rowFlex"
>
<div v-if="assionInfo.username.length <= 1" class="rowFlex">
<div
v-for="(items, indexs) in assionInfo.username"
:key="indexs"
......@@ -113,15 +87,13 @@
>
<p
class="textHidden rowFlex userAlias"
style="max-width:150px;"
>{{ items }}</p>
style="max-width: 150px"
>
{{ items }}
</p>
</div>
</div>
<el-popover
v-else
placement="top"
trigger="click"
>
<el-popover v-else placement="top" trigger="click">
<div style="max-width: 400px">
<p
v-for="(items, indexs) in assionInfo.username"
......@@ -129,10 +101,9 @@
class="rowFlex columnCenter userInfoStyle"
style="margin-bottom: 10px"
>
<span
class="textHidden"
style="max-width:150px;"
>{{ items }}</span>
<span class="textHidden" style="max-width: 150px">{{
items
}}</span>
</p>
</div>
<el-button
......@@ -140,7 +111,8 @@
type="text"
size="medium"
style="margin-top: -10px"
>{{ assionInfo.username.length }}</el-button>
>{{ assionInfo.username.length }}</el-button
>
</el-popover>
</div>
</div>
......@@ -149,24 +121,12 @@
<div class="contentInfo">
<div class="contentInfoItem rowFlex">
<div class="label">跟进状态</div>
<div
v-if="assionInfo.status == 1"
class="noSend"
>待跟进</div>
<div
v-else-if="assionInfo.status == 2"
class="noSend"
>跟进中</div>
<div
v-else-if="assionInfo.status == 3"
class="sended"
>已跟进</div>
<div v-if="assionInfo.status == 1" class="noSend">待跟进</div>
<div v-else-if="assionInfo.status == 2" class="noSend">跟进中</div>
<div v-else-if="assionInfo.status == 3" class="sended">已跟进</div>
</div>
<div v-if="remarks.remarks" class="remarks rowFlex flexWarp">
<div
v-for="(item, index) in remarks.remarks"
:key="index"
>
<div v-for="(item, index) in remarks.remarks" :key="index">
<div class="contentInfoItem rowFlex">
<div class="label">跟进时间</div>
<div class="value">{{ item.update_time }}</div>
......@@ -174,10 +134,7 @@
<div class="contentInfoItem rowFlex">
<div class="label">备注</div>
<div class="value">
<div
class="remarkContent"
v-html="item.remark"
></div>
<div class="remarkContent" v-html="item.remark"></div>
</div>
</div>
</div>
......@@ -185,41 +142,40 @@
<!-- 发起会话 -->
<!-- 新增判断逻辑 根据 taskDetails 中的is_bind 判断 1:显示发起会话按钮 0:不显示发起会话按钮 -->
<div
v-if="kfhList && kfhList.length > 0 && assionInfo.status_name !== '已完成'"
v-if="
kfhList &&
kfhList.length > 0 &&
assionInfo.status_name !== '已完成'
"
class="kfhList rowFlex columnCenter flexWarp"
>
<div
v-for="(item, index) in kfhList"
:key="index"
class="sessionUserList "
class="sessionUserList"
>
<div style="margin-bottom: 10px" class="sessionUser">
<div class="kfhItem rowFlex spaceBetween">
<div class="left rowFlex columnCenter">
<el-image
:src="item.user.avatar"
class="image"
></el-image>
<el-image :src="item.user.avatar" class="image"></el-image>
<div class="name">{{ item.user.alias }}</div>
</div>
<el-button
v-if="item.userid == userid "
v-if="item.userid == userid"
class="right"
type="primary"
size="small"
@click="requestSession(item)"
>发起会话</el-button>
>发起会话</el-button
>
<div v-else>
<svg-icon
icon-class="chat"
style="font-size:26px;"
/>
<svg-icon icon-class="chat" style="font-size: 26px" />
</div>
</div>
<div class="wxUserInfo columnFlex">
<p>
<span>用户备注:</span>
<label style="word-break: break-all;">{{
<label style="word-break: break-all">{{
item.external_user.remark || item.external_user.name
}}</label>
</p>
......@@ -229,12 +185,15 @@
</div>
</div>
<el-button
v-if="kfhList.length == 0 && taskDetails.status != 3 && !is_finished"
v-if="
kfhList.length == 0 && taskDetails.status != 3 && !is_finished
"
type="primary"
size="small"
style="margin-top: 20px"
@click="showLayer = true"
>完成任务</el-button>
>完成任务</el-button
>
</div>
</div>
</el-drawer>
......@@ -255,7 +214,7 @@
>
<!-- 新增异常原因筛选 当 plan_type==5 5:为大R异跟进异常时 新增异常原因筛选 -->
<el-form-item
v-if="taskDetails.plan_type==5"
v-if="taskDetails.plan_type == 5"
label="异常原因"
prop="abnormal_types"
>
......@@ -275,10 +234,7 @@
</el-option>
</el-select>
</el-form-item>
<el-form-item
label="跟进结果:"
prop="trace_result"
>
<el-form-item label="跟进结果:" prop="trace_result">
<el-select
v-model="webForm.trace_result"
style="width: 100%"
......@@ -293,10 +249,7 @@
</el-option>
</el-select>
</el-form-item>
<el-form-item
label="备注:"
prop="remark"
>
<el-form-item label="备注:" prop="remark">
<el-input
v-model="webForm.remark"
type="textarea"
......@@ -304,31 +257,30 @@
placeholder="备注请填写异常原因和异常类型,并列举后续维护策略/难以维护的原因"
></el-input>
</el-form-item>
</el-form>
</div>
</layer>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
import {
</template>
<script>
import { mapState, mapMutations } from 'vuex';
import {
taskRecord,
searchcondition,
memberOrder,
RoleTodayOrder,
taskDetails,
taskTrack,
} from '@/api/game'
import { memberBindExternalUser } from '@/api/works'
import layer from '@/components/dialog.vue'
export default {
} from '@/api/game';
import { memberBindExternalUser, clientSessionBindTaskApi } from '@/api/works';
import layer from '@/components/dialog.vue';
export default {
computed: {
...mapState('game', ['taskDetails']),
...mapState('user', ['userInfo','userid'])
...mapState('user', ['userInfo', 'userid']),
},
components: {
layer
layer,
},
props: ['show'],
data() {
......@@ -348,16 +300,16 @@
webForm: {
trace_result: '',
remark: '',
abnormal_types: []
abnormal_types: [],
},
webFormRule: {
remark: [{ required: true, message: '请输入备注', trigger: 'blur' }],
trace_result: [
{ required: true, message: '请选择跟进结果', trigger: 'change' }
{ required: true, message: '请选择跟进结果', trigger: 'change' },
],
abnormal_types: [
{ required: true, message: '请选择异常原因', trigger: 'change' }
]
{ required: true, message: '请选择异常原因', trigger: 'change' },
],
},
detailsList: [
{ label: '游戏名称', value: 'main_game_name' },
......@@ -386,70 +338,70 @@
{ label: '目标客服号', value: 'target_service_name' },
{ label: '实名累充金额', value: 'recharge_total', type: 'money' },
],
}
};
},
watch: {
taskDetails(newVal, oldVal) {
if (newVal.member_id) {
this.requestInit()
}
this.requestInit();
}
},
},
created() {
this.assionInfo = this.taskDetails
this.assionInfo = this.taskDetails;
},
mounted() {
if (this.taskDetails.id) {
this.requestInit()
this.requestInit();
}
},
methods: {
...mapMutations('game', ['set_taskDetails', 'set_task_session_member_id']),
requestInit() {
this.current = 0
this.is_finished = false
this.assionInfo = this.taskDetails
this.taskRecord()
this.memberOrder()
this.requestTaskDetails()
this.searchTrackList()
this.current = 0;
this.is_finished = false;
this.assionInfo = this.taskDetails;
this.taskRecord();
this.memberOrder();
this.requestTaskDetails();
this.searchTrackList();
// 只有状态是 5 的时候 才请求
if (this.taskDetails.plan_type == 5) {
this.searchconditionError()
this.searchconditionError();
}
},
close() {
this.$emit('update:show', false)
this.$emit('update:show', false);
},
searchconditionError() {
const data = {
type: 'dictionaries',
table_name: 'zs_operator_task',
field_name: 'abnormal_type'
}
field_name: 'abnormal_type',
};
searchcondition(data).then((res) => {
this.errorTypeList = res.data.data
})
this.errorTypeList = res.data.data;
});
},
searchcondition() {
const data = {
type: 'dictionaries',
table_name: 'zs_operator_plan',
field_name: 'plan_type'
}
field_name: 'plan_type',
};
searchcondition(data).then((res) => {
this.taskTypeList = res.data.data
})
this.taskTypeList = res.data.data;
});
},
searchTrackList() {
const data = {
type: 'dictionaries',
table_name: 'zs_operator_task',
field_name: 'trace_result'
}
field_name: 'trace_result',
};
searchcondition(data).then((res) => {
this.traceList = res.data.data
})
this.traceList = res.data.data;
});
},
// 完成任务
submitForm() {
......@@ -459,101 +411,117 @@
create_user: this.userInfo.username,
remark: this.webForm.remark,
abnormal_types: this.webForm.abnormal_types,
create_department: this.userInfo.department_name
}
create_department: this.userInfo.department_name,
};
taskTrack(data).then((res) => {
if (res.status_code == 1) {
this.$message.success(res.msg)
this.$message.success(res.msg);
this.webForm = {
trace_result: '',
remark: '',
abnormal_types: []
}
this.is_finished = true
this.showLayer = false
abnormal_types: [],
};
this.is_finished = true;
this.showLayer = false;
}
})
});
},
onConfirm() {
this.$refs.ruleForm.validate((valid) => {
if (valid) {
this.submitForm()
this.submitForm();
} else {
console.log('error submit!!')
console.log('error submit!!');
}
})
});
},
requestTaskDetails() {
const data = {
id: this.taskDetails.id
}
id: this.taskDetails.id,
};
taskDetails(data).then((res) => {
res.data && res.data.id ? this.assionInfo = { ...this.assionInfo, ...res.data } : ''
this.memberBindExternalUser()
if (this.assionInfo && this.assionInfo.username && this.assionInfo.username.indexOf('\n') !== -1) {
this.assionInfo.username = this.assionInfo.username.split('\n')
res.data && res.data.id
? (this.assionInfo = { ...this.assionInfo, ...res.data })
: '';
this.memberBindExternalUser();
if (
this.assionInfo &&
this.assionInfo.username &&
this.assionInfo.username.indexOf('\n') !== -1
) {
this.assionInfo.username = this.assionInfo.username.split('\n');
} else {
this.assionInfo.username = [this.assionInfo.username]
this.assionInfo.username = [this.assionInfo.username];
}
})
});
},
requestSession(item) {
clientSessionBindTaskApi({
userid: item.userid,
external_userid: item.external_userid,
task_id: this.assionInfo.id,
member_id: item.member_id,
username: item.username,
});
this.$ww.openEnterpriseChat({
externalUserIds:item.external_userid,
externalUserIds: item.external_userid,
success: (res) => {
console.log(res, '打开会话窗口成功')
console.log(res, '打开会话窗口成功');
},
fail: (err) => {
console.log(err, '打开会话窗口失败')
}
})
console.log(err, '打开会话窗口失败');
},
});
},
async memberOrder() {
let res = {}
let res = {};
if (!this.taskDetails.cp_role_id || this.taskDetails.cp_role_id == '') {
res = await memberOrder({ member_id: this.taskDetails.member_id })
res = await memberOrder({ member_id: this.taskDetails.member_id });
} else {
res = await RoleTodayOrder({ role_id: this.taskDetails.role_id })
res = await RoleTodayOrder({ role_id: this.taskDetails.role_id });
}
this.todayOrder = res.data[0]
this.assionInfo = { ...this.assionInfo, ...this.todayOrder }
this.todayOrder = res.data[0];
this.assionInfo = { ...this.assionInfo, ...this.todayOrder };
},
async taskRecord() {
const res = await taskRecord({ task_id: this.taskDetails.id,user_type:'' })
console.log(res.data.data, 'res.data.data')
if(res.data.data.length > 0){
this.remarks = res.data.data[0].remarks
}else{
this.remarks = [{remark:''}]
const res = await taskRecord({
task_id: this.taskDetails.id,
user_type: '',
});
console.log(res.data.data, 'res.data.data');
if (res.data.data.length > 0) {
this.remarks = res.data.data[0].remarks;
} else {
this.remarks = [{ remark: '' }];
}
},
async memberBindExternalUser() {
let member_list = []
let member_list = [];
if (this.assionInfo.members?.length > 0) {
member_list = this.assionInfo.members.map((item) => item.member_id)
member_list = this.assionInfo.members.map((item) => item.member_id);
} else {
member_list = [this.assionInfo.member_id]
member_list = [this.assionInfo.member_id];
}
this.loading = true
this.loading = true;
if (member_list.length === 0) {
return false
return false;
}
try {
const res = await memberBindExternalUser({
member_id: member_list.toString(),
is_bind: this.assionInfo.is_bind
})
this.kfhList = res.data
this.loading = false
is_bind: this.assionInfo.is_bind,
});
this.kfhList = res.data;
this.loading = false;
} catch (error) {
this.loading = false
this.loading = false;
}
}
}
}
</script>
<style lang="scss" scoped>
.contet {
},
},
};
</script>
<style lang="scss" scoped>
.contet {
height: 100%;
background: #fff;
padding: 10px;
......@@ -655,23 +623,23 @@
height: auto;
margin-top: 22px;
margin-bottom: 60px;
.sessionUserList{
margin-right: 10px;
}
.sessionUser{
.sessionUser {
width: 100%;
height: auto;
background: #F8F8F8;
background: #f8f8f8;
border-radius: 4px;
padding: 10px;
}
.sessionUserList {
margin-right: 10px;
}
.wxUserInfo {
span{
span {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #949FB0;
color: #949fb0;
}
}
......@@ -964,14 +932,13 @@
width: 440px;
}
}
}
}
.editLayer {
.editLayer {
padding: 20px;
padding-right: 0;
::v-deep .el-textarea__inner {
height: 150px;
}
}
</style>
\ No newline at end of file
}
</style>
......@@ -4,11 +4,13 @@
<div class="content" v-loading="viewLoading">
<div v-if="chatUserDetails.is_phishing_account == 1" class="warnText">
<p>高风险玩家,请立即通知组长!!!!</p>
<p>①千万不能推转游!!不要发送违禁词汇!!不要发送礼包和告知任何礼包信息!!</p>
<p>
①千万不能推转游!!不要发送违禁词汇!!不要发送礼包和告知任何礼包信息!!
</p>
<p>②不能以任何形式推送APP/网页链接,也不可承认有APP/网页端口!!</p>
</div>
<div v-if="change_appraisal" class="warnText">
<p> 钓鱼号 禁止转端通知组长!</p>
<p>钓鱼号 禁止转端通知组长!</p>
</div>
<div v-else-if="gameUserInfo.exp_ip" class="warnText">
<p>高风险用户,禁止转端 !!!</p>
......@@ -20,66 +22,138 @@
<!-- 添加客服状态显示及按钮 -->
<div class="cser_status">
<div class="status-actions">
<el-button type="danger" v-if="clientStatus !== 'offline'" style="margin-left: 0px;" size="mini"
@click="logout">下线</el-button>
<el-button
type="danger"
v-if="clientStatus !== 'offline'"
style="margin-left: 0px"
size="mini"
@click="logout"
>下线</el-button
>
<!-- 休息中状态显示结束休息按钮 -->
<el-button v-if="clientStatus === 'rest'" type="primary" size="mini"
@click="handleFinishRest">结束休息</el-button>
<el-button
v-if="clientStatus === 'rest'"
type="primary"
size="mini"
@click="handleFinishRest"
>结束休息</el-button
>
<!-- 在线状态显示开始休息按钮 -->
<el-tooltip v-if="clientStatus === 'online'" content="午休或者临时有事可点击休息" placement="top">
<el-button type="warning" size="mini" @click="handleStartRest">开始休息</el-button>
<el-tooltip
v-if="clientStatus === 'online'"
content="午休或者临时有事可点击休息"
placement="top"
>
<el-button type="warning" size="mini" @click="handleStartRest"
>开始休息</el-button
>
</el-tooltip>
<!-- 发送评价按钮 -->
<el-button type="primary" style="margin-left: 0px;" size="mini"
@click="handleSendComment">发送评价</el-button>
<el-button
type="primary"
style="margin-left: 0px"
size="mini"
@click="handleSendComment"
>发送评价</el-button
>
</div>
</div>
</div>
<!-- 会话内容存档状态 -->
<div class="archive-status" v-if="agreeStatus !== 'Agree' || !hasPermit">
<div
class="archive-status"
v-if="agreeStatus !== 'Agree' || !hasPermit"
>
<p v-if="agreeStatus !== 'Agree'">当前微信用户未开启会话内容存档</p>
<p v-if="!hasPermit">当前客服号未授权开启会话内容存档</p>
</div>
<div class="item rowFlex">
<!-- 公共的信息 -->
<el-image fit="fill" draggable="false" style="-webkit-user-drag: none" :src="chatUserDetails.avatar"
class="tableImage"></el-image>
<el-image
fit="fill"
draggable="false"
style="-webkit-user-drag: none"
:src="chatUserDetails.avatar"
class="tableImage"
></el-image>
<div class="columnFlex">
<div class="rowFlex" style="margin-bottom: 3px">
<p class="text" style="font-weight: 600">
{{ chatUserDetails.name }}
</p>
<span v-if="chatUserDetails.add_way_text" style="color: #09b159; margin-left: 10px">@{{
chatUserDetails.add_way_text }}</span>
<span
v-if="chatUserDetails.add_way_text"
style="color: #09b159; margin-left: 10px"
>@{{ chatUserDetails.add_way_text }}</span
>
</div>
<!-- 游戏模块特有 -->
<div v-if="accountSelect && accountSelect !== ''" class="rowFlex columnCenter" style="margin-top: 3px">
<div
v-if="accountSelect && accountSelect !== ''"
class="rowFlex columnCenter"
style="margin-top: 3px"
>
<vipLevel :gameUserInfo="gameUserInfo" />
<el-button-group>
<el-button type="text" @click="zyouUnBindConfirm">解绑</el-button>
<el-button type="text" @click="zyouUnBindConfirm"
>解绑</el-button
>
<!-- <el-button type="text" size="mini" @click="autoResetPassword">修改密码</el-button>
<el-button type="text" size="mini" @click="changePhoneClick">修改手机号</el-button> -->
<el-button v-if="!chatUserDetails.bind_cser" type="text" @click="relationKfh">关联客服</el-button>
<el-button type="text" v-if="false" @click="errorHandle">误操作</el-button>
<el-button
v-if="!chatUserDetails.bind_cser"
type="text"
@click="relationKfh"
>关联客服</el-button
>
<el-button type="text" v-if="false" @click="errorHandle"
>误操作</el-button
>
</el-button-group>
</div>
</div>
</div>
<div class="item rowFlex columnCenter">
<div class="rowFlex columnCenter">
<span class="label" style="min-width: 45px;">备注:</span>
<p v-if="!showInputRemark" class="text" style="max-width: 170px;">
<span class="label" style="min-width: 45px">备注:</span>
<p v-if="!showInputRemark" class="text" style="max-width: 170px">
{{
chatUserDetails.remark && chatUserDetails.remark != ""
chatUserDetails.remark && chatUserDetails.remark != ''
? chatUserDetails.remark
: chatUserDetails.name
}}
</p>
</div>
<el-input v-if="showInputRemark" v-model="showInputRemarkValue" class="showInputRemarkInput" type="textarea"
@change="handleInputRemark" @blur="showInputRemark = false"></el-input>
<i class="el-icon-edit icon" style="font-size: 14px" @click="editRemark"></i>
<el-input
v-if="showInputRemark"
v-model="showInputRemarkValue"
class="showInputRemarkInput"
type="textarea"
@change="handleInputRemark"
@blur="showInputRemark = false"
></el-input>
<i
class="el-icon-edit icon"
style="font-size: 14px"
@click="editRemark"
></i>
</div>
<div class="item rowFlex columnCenter" v-if="lastTime">
<div class="rowFlex columnCenter">
<span class="label">最后交互日期:</span>
<span>
<span>({{ getDaysDifference }})</span>
{{ lastTime }}
</span>
<el-popover
placement="top-start"
width="200"
trigger="hover"
content="最后交互时间为VIP客服号与客户的最近一次会话发起时间"
>
<i class="el-icon-question ml-[4px]" slot="reference"></i>
</el-popover>
</div>
</div>
<div>
<!-- 自定义列 -->
......@@ -110,35 +184,66 @@
</div>
</div> -->
<!-- 游戏业务的账号信息 -->
<gameDetails v-if="gameUserInfo.username && !viewLoading" :chat-user-details="chatUserDetails"
:game-user-info="gameUserInfo" @changeAppraisal="changeAppraisal" />
<gameDetails
v-if="gameUserInfo.username && !viewLoading"
:chat-user-details="chatUserDetails"
:game-user-info="gameUserInfo"
@changeAppraisal="changeAppraisal"
/>
<!-- 游戏标签 -->
<div class="item rowFlex columnCenter spaceBetween tagsLost">
<div class="rowFlex">
<span class="label">关联标签:</span>
<div v-if="
<div
v-if="
chatUserDetails.tag_group &&
chatUserDetails.tag_group.length > 0
">
"
>
<!-- 第一个标签组的所有标签 -->
<el-tag v-for="(items, indexs) in chatUserDetails.tag_group[0].tag" :key="indexs">{{ items.name
}}</el-tag>
<el-tag
v-for="(items, indexs) in chatUserDetails.tag_group[0].tag"
:key="indexs"
>{{ items.name }}</el-tag
>
<!-- 如果有多个标签组,显示+n -->
<el-popover v-if="chatUserDetails.tag_group.length > 1" placement="top" trigger="hover"
popper-class="tag-popover">
<div class="groups-popover-content" style="max-height: 600px;overflow-y: auto;">
<div v-for="(group, groupIndex) in chatUserDetails.tag_group.slice(1)" :key="groupIndex"
class="group-item">
<el-tag v-for="(tagItem, tagIndex) in group.tag" :key="tagIndex" style="margin-right: 10px;">{{
tagItem.name }}</el-tag>
<el-popover
v-if="chatUserDetails.tag_group.length > 1"
placement="top"
trigger="hover"
popper-class="tag-popover"
>
<div
class="groups-popover-content"
style="max-height: 600px; overflow-y: auto"
>
<div
v-for="(
group, groupIndex
) in chatUserDetails.tag_group.slice(1)"
:key="groupIndex"
class="group-item"
>
<el-tag
v-for="(tagItem, tagIndex) in group.tag"
:key="tagIndex"
style="margin-right: 10px"
>{{ tagItem.name }}</el-tag
>
</div>
</div>
<span slot="reference" class="tag-more">+{{ chatUserDetails.tag_group.length - 1 }}</span>
<span slot="reference" class="tag-more"
>+{{ chatUserDetails.tag_group.length - 1 }}</span
>
</el-popover>
</div>
</div>
<i class="el-icon-edit icon" style="font-size: 14px;margin-right: 10px;" @click="editTags"></i>
<i
class="el-icon-edit icon"
style="font-size: 14px; margin-right: 10px"
@click="editTags"
></i>
</div>
<!-- 共享信息 -->
<shareInfo :chat-user-details="chatUserDetails" />
......@@ -146,26 +251,50 @@
</div>
</div>
<!-- 修改手机号 -->
<changePhone :show.sync="changePhone" :phone.sync="gameUserInfo.mobile" title="修改手机号" width="350px" />
<changePhone
:show.sync="changePhone"
:phone.sync="gameUserInfo.mobile"
title="修改手机号"
width="350px"
/>
<!-- 修改标签 -->
<selectTag v-if="showTag" :show.sync="showTag" :checkbox="true" :check-list="chatUserDetails.tag_group || []"
@submit="selectTags" />
<selectTag
v-if="showTag"
:show.sync="showTag"
:checkbox="true"
:check-list="chatUserDetails.tag_group || []"
@submit="selectTags"
/>
</div>
</template>
<script>
import { mapState, mapMutations, mapActions } from 'vuex'
import gameDetails from './gameInfo/gameUserInfo.vue'
import shareInfo from './shareInfo.vue'
import changePhone from './changePhone.vue'
import watchMember from '@/mixins/watchMember'
import { autoResetPassword, bindUserSelfAdd } from '@/api/game'
import { memberBindCser, editUser, zyouUnBind } from '@/api/works'
import selectTag from '@/components/selectTag.vue'
import { getClientStatus, remarkSessionIntelTag, finishRest, client_session_rest, checkSingleAgree, checkUserPermit, sendComment, logout } from '@/api/user.js'
import { sendChatMessage } from '@/utils/index.js'
import { getToken, removeToken } from '@/utils/auth'
import vipLevel from './gameInfo/vipLevel.vue'
import Cookies from 'js-cookie'
import { mapState, mapMutations, mapActions } from 'vuex';
import gameDetails from './gameInfo/gameUserInfo.vue';
import shareInfo from './shareInfo.vue';
import changePhone from './changePhone.vue';
import watchMember from '@/mixins/watchMember';
import { autoResetPassword, bindUserSelfAdd } from '@/api/game';
import {
memberBindCser,
editUser,
zyouUnBind,
getMemberInfoApi,
} from '@/api/works';
import selectTag from '@/components/selectTag.vue';
import {
getClientStatus,
remarkSessionIntelTag,
finishRest,
client_session_rest,
checkSingleAgree,
checkUserPermit,
sendComment,
logout,
} from '@/api/user.js';
import { sendChatMessage } from '@/utils/index.js';
import { getToken, removeToken } from '@/utils/auth';
import vipLevel from './gameInfo/vipLevel.vue';
import Cookies from 'js-cookie';
export default {
name: 'info',
components: {
......@@ -173,13 +302,13 @@ export default {
changePhone,
shareInfo,
selectTag,
vipLevel
vipLevel,
},
props: {
// 用户详情
chatUserDetails: {
type: Object,
default: () => ({})
default: () => ({}),
},
},
data() {
......@@ -197,121 +326,159 @@ export default {
// 新增状态数据
agreeStatus: '', // 用户是否同意聊天内容存档:Agreen同意 Disagree不同意
hasPermit: false, // 客服号是否开启会话内容存档权限
}
lastTime: '', //上一次交互时间
};
},
computed: {
...mapState('game', [
'accountSelect',
'gameUserInfo',
'bindGameUserList',
'viewLoading'
'viewLoading',
]),
...mapState('user', [
'cser_info',
'cser_id',
'cser_name',
'corp_id',
'external_userid',
'userid',
'client_online_status',
'token',
]),
...mapState('user', ['cser_info', 'cser_id', 'cser_name', 'corp_id', 'external_userid', 'userid', 'client_online_status', 'token']),
// 客服状态文本
clientStatusText() {
const statusMap = {
'online': '在线',
'offline': '离线',
'rest': '休息中'
}
return statusMap[this.client_online_status] || '未知'
online: '在线',
offline: '离线',
rest: '休息中',
};
return statusMap[this.client_online_status] || '未知';
},
// 客服休息状态:online上线 offline下线 rest休息中
clientStatus() {
return this.client_online_status
return this.client_online_status;
},
getDaysDifference() {
// 解析目标日期字符串
const targetDate = new Date(this.lastTime);
// 获取当前日期(去除时间部分,只保留日期)
const currentDate = new Date();
currentDate.setHours(0, 0, 0, 0);
// 计算时间戳差值(毫秒)
const timeDiff = targetDate.getTime() - currentDate.getTime();
// 将毫秒转换为天数(24小时 × 60分钟 × 60秒 × 1000毫秒)
const daysDiff = Math.abs(Math.floor(timeDiff / (1000 * 60 * 60 * 24)));
return daysDiff;
},
},
mixins: [watchMember],
mounted() {
// 初始化企业微信SDK
this.initializeWecom()
this.initializeWecom();
// 获取客服状态和相关信息
if (this.cser_id && this.token) {
this.getInitialData()
this.getInitialData();
}
//获取最后交互时间
this.getLastTime();
},
methods: {
...mapMutations('game', ['set_accountSelect']),
...mapMutations('game', ['set_accountSelect', 'accountSelect']),
...mapActions('user', ['initWecom']),
// 初始化企业微信SDK
async initializeWecom() {
try {
console.log('🚀 开始初始化企业微信 SDK')
const result = await this.initWecom()
console.log('✅ 企业微信 SDK 初始化成功', result)
console.log('🚀 开始初始化企业微信 SDK');
const result = await this.initWecom();
console.log('✅ 企业微信 SDK 初始化成功', result);
} catch (error) {
console.error('❌ 企业微信 SDK 初始化失败:', error)
console.error('❌ 企业微信 SDK 初始化失败:', error);
}
},
logout() {
if (this.client_online_status === 'rest') {
this.$message({
type: 'error',
message: '当前客服号处于休息状态,不能下线'
})
return
message: '当前客服号处于休息状态,不能下线',
});
return;
}
this.$confirm('确定下线吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.userLogout()
}).catch(() => {
this.$message({
type: 'info',
message: '已取消'
type: 'warning',
})
.then(() => {
this.userLogout();
})
.catch(() => {
this.$message({
type: 'info',
message: '已取消',
});
});
},
async userLogout() {
const data = {
userid: this.userid,
}
const res = await logout(data)
};
const res = await logout(data);
if (res.status_code === 1) {
this.$message({
type: 'success',
message: '下线成功'
})
removeToken()
Cookies.remove('external_userid')
Cookies.remove('userid')
window.location.href = window.location.origin + '/company_app/index.html?corp_id=' + this.corp_id
message: '下线成功',
});
removeToken();
Cookies.remove('external_userid');
Cookies.remove('userid');
window.location.href =
window.location.origin +
'/company_app/index.html?corp_id=' +
this.corp_id;
} else {
this.$message({
type: 'error',
message: '下线失败'
})
message: '下线失败',
});
}
},
// 获取初始数据
async getInitialData() {
try {
// 1. 获取客服休息状态
const statusRes = await getClientStatus()
const statusRes = await getClientStatus();
if (statusRes.status_code === 1) {
if (statusRes.data.client_online_status === 'offline') {
removeToken()
window.location.href = window.location.origin + '/company_app/index.html?corp_id=' + this.corp_id
removeToken();
window.location.href =
window.location.origin +
'/company_app/index.html?corp_id=' +
this.corp_id;
}
this.$store.commit('user/set_client_online_status', statusRes.data.client_online_status)
this.$store.commit(
'user/set_client_online_status',
statusRes.data.client_online_status
);
}
// 2. 同步智能标签
this.syncIntelligentTags()
this.syncIntelligentTags();
// 3. 检查用户是否同意聊天内容存档
this.checkAgreeStatus()
this.checkAgreeStatus();
// 4. 检查客服号是否开启会话内容存档
this.checkPermitStatus()
this.checkPermitStatus();
} catch (error) {
console.error('获取初始数据失败:', error)
console.error('获取初始数据失败:', error);
}
},
......@@ -321,11 +488,11 @@ export default {
await remarkSessionIntelTag({
corp_id: this.corp_id,
external_userid: this.external_userid,
userid: this.userid
})
console.log('智能标签同步成功')
userid: this.userid,
});
console.log('智能标签同步成功');
} catch (error) {
console.error('智能标签同步失败:', error)
console.error('智能标签同步失败:', error);
}
},
......@@ -334,13 +501,13 @@ export default {
try {
const res = await checkSingleAgree({
external_userid: this.external_userid,
userid: this.userid
})
userid: this.userid,
});
if (res.status_code === 1) {
this.agreeStatus = res.data.agree_status
this.agreeStatus = res.data.agree_status;
}
} catch (error) {
console.error('检查用户同意状态失败:', error)
console.error('检查用户同意状态失败:', error);
}
},
......@@ -348,45 +515,45 @@ export default {
async checkPermitStatus() {
try {
const res = await checkUserPermit({
userid: this.userid
})
userid: this.userid,
});
if (res.status_code === 1) {
this.hasPermit = res.data.has_permit
this.hasPermit = res.data.has_permit;
}
} catch (error) {
console.error('检查客服权限失败:', error)
console.error('检查客服权限失败:', error);
}
},
// 开始休息
async handleStartRest() {
try {
const res = await client_session_rest()
const res = await client_session_rest();
if (res.status_code === 1) {
this.$store.commit('user/set_client_online_status', 'rest')
this.$message.success('已开始休息')
this.$store.commit('user/set_client_online_status', 'rest');
this.$message.success('已开始休息');
} else {
this.$message.error(res.msg || '开始休息失败')
this.$message.error(res.msg || '开始休息失败');
}
} catch (error) {
console.error('开始休息失败:', error)
this.$message.error('开始休息失败')
console.error('开始休息失败:', error);
this.$message.error('开始休息失败');
}
},
// 结束休息
async handleFinishRest() {
try {
const res = await finishRest()
const res = await finishRest();
if (res.status_code === 1) {
this.$store.commit('user/set_client_online_status', 'online')
this.$message.success('已结束休息')
this.$store.commit('user/set_client_online_status', 'online');
this.$message.success('已结束休息');
} else {
this.$message.error(res.msg || '结束休息失败')
this.$message.error(res.msg || '结束休息失败');
}
} catch (error) {
console.error('结束休息失败:', error)
this.$message.error('结束休息失败')
console.error('结束休息失败:', error);
this.$message.error('结束休息失败');
}
},
......@@ -396,195 +563,213 @@ export default {
const res = await sendComment({
corp_id: this.corp_id,
external_userid: this.external_userid,
userid: this.userid
})
userid: this.userid,
});
if (res.status_code === 1 && res.data.news) {
// 使用企业微信JSSDK发送评价
const result = await sendChatMessage(res.data.news, 'link')
const result = await sendChatMessage(res.data.news, 'link');
if (result.success) {
this.$message.success('评价已发送')
this.$message.success('评价已发送');
} else {
this.$message.error('评价发送失败')
this.$message.error('评价发送失败');
}
} else {
this.$message.error(res.msg || '获取评价内容失败')
this.$message.error(res.msg || '获取评价内容失败');
}
} catch (error) {
console.error('发送评价失败:', error)
this.$message.error('发送评价失败')
console.error('发送评价失败:', error);
this.$message.error('发送评价失败');
}
},
memberChange() {
this.requestBindUser()
this.requestBindUser();
//获取最后一次交互时间
this.getLastTime();
},
// 解绑确认
zyouUnBindConfirm() {
this.$confirm('确定要解绑当前账号么?', '确认提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
type: 'warning',
})
.then(() => {
this.zyouUnBind()
this.zyouUnBind();
})
.catch(() => {
this.$message({
type: 'info',
message: '已取消'
})
})
message: '已取消',
});
});
},
requestBindUser() {
const data = {
member_id: this.accountSelect
}
member_id: this.accountSelect,
};
memberBindCser(data).then((res) => {
console.log(res.data.cser_name, 'cser_namecser_namecser_namecser_name')
console.log(res.data.cser_name, 'cser_namecser_namecser_namecser_name');
if (res.data.cser_name) {
this.$set(this.chatUserDetails, 'bind_cser', res.data.cser_name)
this.$set(this.chatUserDetails, 'bind_cser', res.data.cser_name);
} else {
this.$set(this.chatUserDetails, 'bind_cser', '')
this.$set(this.chatUserDetails, 'bind_cser', '');
}
})
});
},
zyouUnBind() {
const data = {
userid: this.chatUserDetails.userid,
external_userid: this.chatUserDetails.external_userid,
member_id: this.accountSelect
}
member_id: this.accountSelect,
};
zyouUnBind(data).then((res) => {
if (res.status_code == 1) {
this.$message.success(res.msg)
const index = this.bindGameUserList.findIndex(item => item.member_id == this.accountSelect)
this.bindGameUserList.splice(index, 1)
this.set_accountSelect(this.bindGameUserList[0].member_id)
this.$message.success(res.msg);
const index = this.bindGameUserList.findIndex(
(item) => item.member_id == this.accountSelect
);
this.bindGameUserList.splice(index, 1);
this.set_accountSelect(this.bindGameUserList[0].member_id);
}
})
});
},
// 修改密码 之前是客服手动设置密码 现在改成系统自动设置密码
autoResetPassword() {
this.$confirm('确认重置密码吗?密码重置后玩家将无法登录,请谨慎操作!', '重置密码', {
this.$confirm(
'确认重置密码吗?密码重置后玩家将无法登录,请谨慎操作!',
'重置密码',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(res => {
type: 'warning',
}
)
.then((res) => {
const data = {
member_id: this.accountSelect,
zq_user_name: this.cser_name
}
zq_user_name: this.cser_name,
};
autoResetPassword(data).then((res) => {
if (res.status_code == 1) {
this.$message.success('密码重置成功')
this.$message.success('密码重置成功');
}
});
})
}).catch(() => {
.catch(() => {
this.$message({
type: 'info',
message: '已取消'
})
})
message: '已取消',
});
});
},
// 修改手机号
changePhoneClick() {
this.changePhone = true
this.changePhone = true;
},
// 关联客服
relationKfh() {
const username = this.bindGameUserList.find(
(item) => item.value == this.accountSelect
)
);
const params = {
member_id: this.accountSelect,
user_id: this.cser_id,
user_name: this.cser_name,
username: username.username
}
username: username.username,
};
bindUserSelfAdd(params).then((res) => {
if (res.status_code == 1) {
this.$set(this.chatUserDetails, 'bind_cser', 1)
this.$message.success(res.msg)
this.$set(this.chatUserDetails, 'bind_cser', 1);
this.$message.success(res.msg);
}
})
});
},
// 误操作处理
errorHandle() {
this.$emit('error-handle')
this.$emit('error-handle');
},
// 编辑备注
editRemark() {
this.showInputRemark = true
this.showInputRemarkValue = this.chatUserDetails.remark || this.chatUserDetails.name
this.showInputRemark = true;
this.showInputRemarkValue =
this.chatUserDetails.remark || this.chatUserDetails.name;
this.$nextTick(() => {
// document.querySelector('.showInputRemarkInput input').focus()
})
});
},
// 处理备注输入
handleInputRemark(val) {
this.showInputRemark = false
this.chatUserDetails.remark = this.showInputRemarkValue
this.showInputRemark = false;
this.chatUserDetails.remark = this.showInputRemarkValue;
const data = {
userid: this.chatUserDetails.userid,
external_userid: this.chatUserDetails.external_userid,
remark: this.chatUserDetails.remark,
self_defined_columns: this.chatUserDetails.self_defined_columns,
tag_group: this.chatUserDetails.tag_group
}
this.editUserInfo(data)
tag_group: this.chatUserDetails.tag_group,
};
this.editUserInfo(data);
},
editUserInfo(data) {
editUser(data).then((res) => {
if (res.status_code == 1) {
this.$message({
type: 'success',
message: res.msg
})
message: res.msg,
});
}
})
});
},
// 显示自定义列输入
inputShow(item, index) {
this.showInput = true
this.inputIndex = index
this.showInputValue = item.value
this.showInput = true;
this.inputIndex = index;
this.showInputValue = item.value;
this.$nextTick(() => {
document.querySelectorAll('input')[0].focus()
})
document.querySelectorAll('input')[0].focus();
});
},
// 处理自定义列输入
handleInput(item, index) {
this.$emit('update-custom-column', {
item,
index,
value: this.showInputValue
})
this.showInput = false
value: this.showInputValue,
});
this.showInput = false;
},
// 编辑标签
editTags() {
this.showTag = true
this.showTag = true;
},
// 处理评估变更
changeAppraisal(val) {
this.change_appraisal = val
this.change_appraisal = val;
},
// 选择的标签
selectTags(data, is_tag_sync) {
this.chatUserDetails.tag_group = data
this.chatUserDetails.tag_group = data;
const params = {
userid: this.chatUserDetails.userid,
external_userid: this.chatUserDetails.external_userid,
remark: this.chatUserDetails.remark,
is_tag_sync: is_tag_sync,
self_defined_columns: this.chatUserDetails.self_defined_columns,
tag_group: this.chatUserDetails.tag_group
}
this.editUserInfo(params)
tag_group: this.chatUserDetails.tag_group,
};
this.editUserInfo(params);
},
}
}
async getLastTime() {
if (!this.accountSelect) return;
const { data } = await getMemberInfoApi({
member_id: this.accountSelect,
});
this.lastTime = data.last_chat_time;
},
},
};
</script>
<style lang="scss" scoped>
.info-tab-content {
......@@ -607,7 +792,7 @@ export default {
font-size: 18px;
p {
color: #F56C6C;
color: #f56c6c;
line-height: 25px;
}
}
......@@ -639,7 +824,7 @@ export default {
p {
margin: 5px 0;
color: #F56C6C;
color: #f56c6c;
font-weight: 600;
}
}
......@@ -663,7 +848,7 @@ export default {
margin-bottom: 10px;
p {
color: #F56C6C;
color: #f56c6c;
line-height: 25px;
}
}
......@@ -697,7 +882,7 @@ export default {
}
.noBind {
color: #3491FA;
color: #3491fa;
cursor: pointer;
margin-right: 10px;
}
......@@ -772,7 +957,7 @@ export default {
.tag-more {
display: inline-block;
color: #3491FA;
color: #3491fa;
margin-left: 5px;
cursor: pointer;
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论