提交 e96a9bf0 作者: 施汉文

feat: 新增最后交互时间和会话存档答问比同步

上级 2faed5c0
...@@ -284,3 +284,19 @@ export function getUserQrCode(data) { ...@@ -284,3 +284,19 @@ export function getUserQrCode(data) {
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,
});
}
<template> <template>
<div> <div>
<el-drawer <el-drawer
:lock-scroll="true" :lock-scroll="true"
title="玩家申诉" title="玩家申诉"
...@@ -20,69 +20,49 @@ ...@@ -20,69 +20,49 @@
<div <div
v-if=" v-if="
item.value != 'plan_type' && item.value != 'plan_type' &&
item.value != 'target' && item.value != 'target' &&
item.value != 'finished_event' && item.value != 'finished_event' &&
item.value != 'username' item.value != 'username'
" "
class="rowFlex" class="rowFlex"
> >
<div class="label">{{ item.label }}</div> <div class="label">{{ item.label }}</div>
<div <div v-if="item.type == 'money'" class="value">
v-if="item.type == 'money'"
class="value"
>
<p> <p>
<span></span><span>{{ assionInfo[item.value] || 0 }}</span> <span></span><span>{{ assionInfo[item.value] || 0 }}</span>
</p> </p>
</div> </div>
<div <div v-else class="value">
v-else
class="value"
>
<span v-if="assionInfo[item.value]">{{ <span v-if="assionInfo[item.value]">{{
assionInfo[item.value] || "" assionInfo[item.value] || ''
}}</span> }}</span>
</div> </div>
</div> </div>
<div <div v-else-if="item.value == 'plan_type'" class="rowFlex">
v-else-if="item.value == 'plan_type'"
class="rowFlex"
>
<div class="label">{{ item.label }}</div> <div class="label">{{ item.label }}</div>
<div class="value"> <div class="value">
<span style="color: #0787f2">{{ <span style="color: #0787f2">{{
taskTypeList.find((k) => k.value == assionInfo[item.value]) taskTypeList.find((k) => k.value == assionInfo[item.value])
? taskTypeList.find((k) => k.value == assionInfo[item.value]) ? taskTypeList.find(
.label (k) => k.value == assionInfo[item.value]
: "" ).label
: ''
}}</span> }}</span>
</div> </div>
</div> </div>
<div <div v-else-if="item.value == 'target'" class="rowFlex">
v-else-if="item.value == 'target'"
class="rowFlex"
>
<div class="label">{{ item.label }}</div> <div class="label">{{ item.label }}</div>
<div class="value"> <div class="value">
<span <span v-if="assionInfo.target" style="color: #0787f2">{{
v-if="assionInfo.target"
style="color: #0787f2"
>{{
assionInfo.target.first && assionInfo.target.first.is_finished assionInfo.target.first && assionInfo.target.first.is_finished
? "已完成" ? '已完成'
: "未完成" : '未完成'
}}</span> }}</span>
</div> </div>
</div> </div>
<div <div v-else-if="item.value == 'finished_event'" class="rowFlex">
v-else-if="item.value == 'finished_event'"
class="rowFlex"
>
<div class="label">{{ item.label }}</div> <div class="label">{{ item.label }}</div>
<div <div v-if="assionInfo.finished_event" class="value">
v-if="assionInfo.finished_event"
class="value"
>
<span <span
v-for="(item, index) in assionInfo.finished_event" v-for="(item, index) in assionInfo.finished_event"
:key="index" :key="index"
...@@ -92,20 +72,14 @@ ...@@ -92,20 +72,14 @@
</div> </div>
</div> </div>
<!-- w 账号 --> <!-- w 账号 -->
<div <div v-else-if="item.value == 'username'" class="rowFlex">
v-else-if="item.value == 'username'"
class="rowFlex"
>
<div class="label">{{ item.label }}</div> <div class="label">{{ item.label }}</div>
<div <div
v-if="assionInfo.username && assionInfo.username.length > 0" v-if="assionInfo.username && assionInfo.username.length > 0"
class="value" class="value"
> >
<div <div v-if="assionInfo.username.length <= 1" class="rowFlex">
v-if="assionInfo.username.length <= 1"
class="rowFlex"
>
<div <div
v-for="(items, indexs) in assionInfo.username" v-for="(items, indexs) in assionInfo.username"
:key="indexs" :key="indexs"
...@@ -113,15 +87,13 @@ ...@@ -113,15 +87,13 @@
> >
<p <p
class="textHidden rowFlex userAlias" class="textHidden rowFlex userAlias"
style="max-width:150px;" style="max-width: 150px"
>{{ items }}</p> >
{{ items }}
</p>
</div> </div>
</div> </div>
<el-popover <el-popover v-else placement="top" trigger="click">
v-else
placement="top"
trigger="click"
>
<div style="max-width: 400px"> <div style="max-width: 400px">
<p <p
v-for="(items, indexs) in assionInfo.username" v-for="(items, indexs) in assionInfo.username"
...@@ -129,10 +101,9 @@ ...@@ -129,10 +101,9 @@
class="rowFlex columnCenter userInfoStyle" class="rowFlex columnCenter userInfoStyle"
style="margin-bottom: 10px" style="margin-bottom: 10px"
> >
<span <span class="textHidden" style="max-width: 150px">{{
class="textHidden" items
style="max-width:150px;" }}</span>
>{{ items }}</span>
</p> </p>
</div> </div>
<el-button <el-button
...@@ -140,7 +111,8 @@ ...@@ -140,7 +111,8 @@
type="text" type="text"
size="medium" size="medium"
style="margin-top: -10px" style="margin-top: -10px"
>{{ assionInfo.username.length }}</el-button> >{{ assionInfo.username.length }}</el-button
>
</el-popover> </el-popover>
</div> </div>
</div> </div>
...@@ -149,24 +121,12 @@ ...@@ -149,24 +121,12 @@
<div class="contentInfo"> <div class="contentInfo">
<div class="contentInfoItem rowFlex"> <div class="contentInfoItem rowFlex">
<div class="label">跟进状态</div> <div class="label">跟进状态</div>
<div <div v-if="assionInfo.status == 1" class="noSend">待跟进</div>
v-if="assionInfo.status == 1" <div v-else-if="assionInfo.status == 2" class="noSend">跟进中</div>
class="noSend" <div v-else-if="assionInfo.status == 3" class="sended">已跟进</div>
>待跟进</div>
<div
v-else-if="assionInfo.status == 2"
class="noSend"
>跟进中</div>
<div
v-else-if="assionInfo.status == 3"
class="sended"
>已跟进</div>
</div> </div>
<div v-if="remarks.remarks" class="remarks rowFlex flexWarp"> <div v-if="remarks.remarks" class="remarks rowFlex flexWarp">
<div <div v-for="(item, index) in remarks.remarks" :key="index">
v-for="(item, index) in remarks.remarks"
:key="index"
>
<div class="contentInfoItem rowFlex"> <div class="contentInfoItem rowFlex">
<div class="label">跟进时间</div> <div class="label">跟进时间</div>
<div class="value">{{ item.update_time }}</div> <div class="value">{{ item.update_time }}</div>
...@@ -174,10 +134,7 @@ ...@@ -174,10 +134,7 @@
<div class="contentInfoItem rowFlex"> <div class="contentInfoItem rowFlex">
<div class="label">备注</div> <div class="label">备注</div>
<div class="value"> <div class="value">
<div <div class="remarkContent" v-html="item.remark"></div>
class="remarkContent"
v-html="item.remark"
></div>
</div> </div>
</div> </div>
</div> </div>
...@@ -185,21 +142,22 @@ ...@@ -185,21 +142,22 @@
<!-- 发起会话 --> <!-- 发起会话 -->
<!-- 新增判断逻辑 根据 taskDetails 中的is_bind 判断 1:显示发起会话按钮 0:不显示发起会话按钮 --> <!-- 新增判断逻辑 根据 taskDetails 中的is_bind 判断 1:显示发起会话按钮 0:不显示发起会话按钮 -->
<div <div
v-if="kfhList && kfhList.length > 0 && assionInfo.status_name !== '已完成'" v-if="
kfhList &&
kfhList.length > 0 &&
assionInfo.status_name !== '已完成'
"
class="kfhList rowFlex columnCenter flexWarp" class="kfhList rowFlex columnCenter flexWarp"
> >
<div <div
v-for="(item, index) in kfhList" v-for="(item, index) in kfhList"
:key="index" :key="index"
class="sessionUserList " class="sessionUserList"
> >
<div style="margin-bottom: 10px" class="sessionUser"> <div style="margin-bottom: 10px" class="sessionUser">
<div class="kfhItem rowFlex spaceBetween"> <div class="kfhItem rowFlex spaceBetween">
<div class="left rowFlex columnCenter"> <div class="left rowFlex columnCenter">
<el-image <el-image :src="item.user.avatar" class="image"></el-image>
:src="item.user.avatar"
class="image"
></el-image>
<div class="name">{{ item.user.alias }}</div> <div class="name">{{ item.user.alias }}</div>
</div> </div>
<el-button <el-button
...@@ -207,12 +165,13 @@ ...@@ -207,12 +165,13 @@
type="primary" type="primary"
size="small" size="small"
@click="requestSession(item)" @click="requestSession(item)"
>发起会话</el-button> >发起会话</el-button
>
</div> </div>
<div class="wxUserInfo columnFlex"> <div class="wxUserInfo columnFlex">
<p> <p>
<span>用户备注:</span> <span>用户备注:</span>
<label style="word-break: break-all;">{{ <label style="word-break: break-all">{{
item.external_user.remark || item.external_user.name item.external_user.remark || item.external_user.name
}}</label> }}</label>
</p> </p>
...@@ -222,746 +181,757 @@ ...@@ -222,746 +181,757 @@
</div> </div>
</div> </div>
<el-button <el-button
v-if="kfhList.length == 0 && taskDetails.status != 3 && !is_finished" v-if="
kfhList.length == 0 && taskDetails.status != 3 && !is_finished
"
type="primary" type="primary"
size="small" size="small"
style="margin-top: 20px" style="margin-top: 20px"
@click="showLayer = true" @click="showLayer = true"
>完成任务</el-button> >完成任务</el-button
>
</div> </div>
</div> </div>
</el-drawer> </el-drawer>
<layer <layer
:show.sync="showLayer" :show.sync="showLayer"
title="填写跟进结果" title="填写跟进结果"
width="320px" width="320px"
@confirm="onConfirm" @confirm="onConfirm"
> >
<div class="editLayer"> <div class="editLayer">
<el-form <el-form
ref="ruleForm" ref="ruleForm"
:model="webForm" :model="webForm"
label-position="top" label-position="top"
:rules="webFormRule" :rules="webFormRule"
label-width="100px" label-width="100px"
>
<!-- 新增异常原因筛选 当 plan_type==5 5:为大R异跟进异常时 新增异常原因筛选 -->
<el-form-item
v-if="taskDetails.plan_type == 5"
label="异常原因"
prop="abnormal_types"
> >
<!-- 新增异常原因筛选 当 plan_type==5 5:为大R异跟进异常时 新增异常原因筛选 --> <el-select
<el-form-item v-model="webForm.abnormal_types"
v-if="taskDetails.plan_type==5" style="width: 100%"
label="异常原因" placeholder="请选择"
prop="abnormal_types" multiple
collapse-tags
> >
<el-select <el-option
v-model="webForm.abnormal_types" v-for="item in errorTypeList"
style="width: 100%" :key="item.value"
placeholder="请选择" :label="item.label"
multiple :value="item.value"
collapse-tags
> >
<el-option </el-option>
v-for="item in errorTypeList" </el-select>
:key="item.value" </el-form-item>
:label="item.label" <el-form-item label="跟进结果:" prop="trace_result">
:value="item.value" <el-select
> v-model="webForm.trace_result"
</el-option> style="width: 100%"
</el-select> placeholder="请选择"
</el-form-item>
<el-form-item
label="跟进结果:"
prop="trace_result"
> >
<el-select <el-option
v-model="webForm.trace_result" v-for="item in traceList"
style="width: 100%" :key="item.value"
placeholder="请选择" :label="item.label"
:value="item.value"
> >
<el-option </el-option>
v-for="item in traceList" </el-select>
:key="item.value" </el-form-item>
:label="item.label" <el-form-item label="备注:" prop="remark">
:value="item.value" <el-input
> v-model="webForm.remark"
</el-option> type="textarea"
</el-select> style="width: 100%; height: 150px"
</el-form-item> placeholder="备注请填写异常原因和异常类型,并列举后续维护策略/难以维护的原因"
<el-form-item ></el-input>
label="备注:" </el-form-item>
prop="remark" </el-form>
> </div>
<el-input </layer>
v-model="webForm.remark" </div>
type="textarea" </template>
style="width: 100%; height: 150px" <script>
placeholder="备注请填写异常原因和异常类型,并列举后续维护策略/难以维护的原因" import { mapState, mapMutations } from 'vuex';
></el-input> import {
</el-form-item> taskRecord,
searchcondition,
</el-form> memberOrder,
</div> RoleTodayOrder,
</layer> taskDetails,
</div> taskTrack,
</template> } from '@/api/game';
<script> import { memberBindExternalUser, clientSessionBindTaskApi } from '@/api/works';
import { mapState, mapMutations } from 'vuex' import layer from '@/components/dialog.vue';
import { export default {
taskRecord, computed: {
searchcondition, ...mapState('game', ['taskDetails']),
memberOrder, ...mapState('user', ['userInfo']),
RoleTodayOrder, },
taskDetails, components: {
taskTrack, layer,
} from '@/api/game' },
import { memberBindExternalUser } from '@/api/works' props: ['show'],
import layer from '@/components/dialog.vue' data() {
export default { return {
computed: { is_finished: false,
...mapState('game', ['taskDetails']), loading: false,
...mapState('user', ['userInfo']) remarks: [],
}, kfhList: {},
components: { traceList: [],
layer taskTypeList: [],
}, errorTypeList: [],
props: ['show'], approvalProcessList: [],
data() { assionInfo: {},
return { current: 0,
is_finished: false, showLayer: false,
loading: false, dialogRemake: '',
remarks: [], webForm: {
kfhList: {}, trace_result: '',
traceList: [], remark: '',
taskTypeList: [], abnormal_types: [],
errorTypeList: [], },
approvalProcessList: [], webFormRule: {
assionInfo: {}, remark: [{ required: true, message: '请输入备注', trigger: 'blur' }],
current: 0, trace_result: [
showLayer: false, { required: true, message: '请选择跟进结果', trigger: 'change' },
dialogRemake: '',
webForm: {
trace_result: '',
remark: '',
abnormal_types: []
},
webFormRule: {
remark: [{ required: true, message: '请输入备注', trigger: 'blur' }],
trace_result: [
{ required: true, message: '请选择跟进结果', trigger: 'change' }
],
abnormal_types: [
{ required: true, message: '请选择异常原因', trigger: 'change' }
]
},
detailsList: [
{ label: '游戏名称', value: 'main_game_name' },
{ label: '计划名称', value: 'plan_name' },
{ label: 'CP角色ID', value: 'cp_role_id' },
{ label: '角色名称', value: 'role_name' },
{ label: '区服', value: 'server_name' },
{ label: '任务类型', value: 'plan_type' },
{ label: 'W账号', value: 'username' },
{ label: '角色充值金额', value: 'recharge_total', type: 'money' },
{ label: '用户累充金额', value: 'member_recharge', type: 'money' },
{ label: '今日充值金额', value: 'today_amount', type: 'money' },
{ label: '跟进人', value: 'tracer_name' },
{ label: '举报人角色', value: 'report_role_name' },
{ label: '米大师支付', value: 'm_pay_amount', type: 'money' },
{ label: 'H5支付', value: 'h5_pay_amount', type: 'money' },
{ label: 'IOS支付', value: 'ios_pay_amount', type: 'money' },
{ label: '待维护时间', value: 'assignment_time' },
{ label: '最近充值时间', value: 'last_pay_time' },
{ label: '最近登录时间', value: 'last_login_time' },
{ label: '任务截止时间', value: 'deadline_time' },
{ label: '任务状态', value: 'status_name' },
{ label: '目标完成状态', value: 'target' },
{ label: '马甲包', value: 'game_name' },
{ label: '完成事件', value: 'finished_event' },
{ label: '目标客服号', value: 'target_service_name' },
{ label: '实名累充金额', value: 'recharge_total', type: 'money' },
], ],
abnormal_types: [
{ required: true, message: '请选择异常原因', trigger: 'change' },
],
},
detailsList: [
{ label: '游戏名称', value: 'main_game_name' },
{ label: '计划名称', value: 'plan_name' },
{ label: 'CP角色ID', value: 'cp_role_id' },
{ label: '角色名称', value: 'role_name' },
{ label: '区服', value: 'server_name' },
{ label: '任务类型', value: 'plan_type' },
{ label: 'W账号', value: 'username' },
{ label: '角色充值金额', value: 'recharge_total', type: 'money' },
{ label: '用户累充金额', value: 'member_recharge', type: 'money' },
{ label: '今日充值金额', value: 'today_amount', type: 'money' },
{ label: '跟进人', value: 'tracer_name' },
{ label: '举报人角色', value: 'report_role_name' },
{ label: '米大师支付', value: 'm_pay_amount', type: 'money' },
{ label: 'H5支付', value: 'h5_pay_amount', type: 'money' },
{ label: 'IOS支付', value: 'ios_pay_amount', type: 'money' },
{ label: '待维护时间', value: 'assignment_time' },
{ label: '最近充值时间', value: 'last_pay_time' },
{ label: '最近登录时间', value: 'last_login_time' },
{ label: '任务截止时间', value: 'deadline_time' },
{ label: '任务状态', value: 'status_name' },
{ label: '目标完成状态', value: 'target' },
{ label: '马甲包', value: 'game_name' },
{ label: '完成事件', value: 'finished_event' },
{ label: '目标客服号', value: 'target_service_name' },
{ label: '实名累充金额', value: 'recharge_total', type: 'money' },
],
};
},
watch: {
taskDetails(newVal, oldVal) {
if (newVal.member_id) {
this.requestInit();
} }
}, },
watch: { },
taskDetails(newVal, oldVal) { created() {
if (newVal.member_id) { this.assionInfo = this.taskDetails;
this.requestInit() },
} mounted() {
if (this.taskDetails.id) {
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();
// 只有状态是 5 的时候 才请求
if (this.taskDetails.plan_type == 5) {
this.searchconditionError();
} }
}, },
created() { close() {
this.assionInfo = this.taskDetails this.$emit('update:show', false);
}, },
mounted() { searchconditionError() {
if (this.taskDetails.id) { const data = {
this.requestInit() type: 'dictionaries',
} table_name: 'zs_operator_task',
field_name: 'abnormal_type',
};
searchcondition(data).then((res) => {
this.errorTypeList = res.data.data;
});
}, },
methods: { searchcondition() {
...mapMutations('game', ['set_taskDetails', 'set_task_session_member_id']), const data = {
requestInit() { type: 'dictionaries',
this.current = 0 table_name: 'zs_operator_plan',
this.is_finished = false field_name: 'plan_type',
this.assionInfo = this.taskDetails };
this.taskRecord() searchcondition(data).then((res) => {
this.memberOrder() this.taskTypeList = res.data.data;
this.requestTaskDetails() });
this.searchTrackList() },
// 只有状态是 5 的时候 才请求 searchTrackList() {
if (this.taskDetails.plan_type == 5) { const data = {
this.searchconditionError() type: 'dictionaries',
} table_name: 'zs_operator_task',
}, field_name: 'trace_result',
close() { };
this.$emit('update:show', false) searchcondition(data).then((res) => {
}, this.traceList = res.data.data;
searchconditionError() { });
const data = { },
type: 'dictionaries', // 完成任务
table_name: 'zs_operator_task', submitForm() {
field_name: 'abnormal_type' const data = {
} id: this.taskDetails.id,
searchcondition(data).then((res) => { trace_result: this.webForm.trace_result,
this.errorTypeList = res.data.data create_user: this.userInfo.username,
}) remark: this.webForm.remark,
}, abnormal_types: this.webForm.abnormal_types,
searchcondition() { create_department: this.userInfo.department_name,
const data = { };
type: 'dictionaries', taskTrack(data).then((res) => {
table_name: 'zs_operator_plan', if (res.status_code == 1) {
field_name: 'plan_type' this.$message.success(res.msg);
} this.webForm = {
searchcondition(data).then((res) => { trace_result: '',
this.taskTypeList = res.data.data remark: '',
}) abnormal_types: [],
}, };
searchTrackList() { this.is_finished = true;
const data = { this.showLayer = false;
type: 'dictionaries',
table_name: 'zs_operator_task',
field_name: 'trace_result'
} }
searchcondition(data).then((res) => { });
this.traceList = res.data.data },
}) onConfirm() {
}, this.$refs.ruleForm.validate((valid) => {
// 完成任务 if (valid) {
submitForm() { this.submitForm();
const data = { } else {
id: this.taskDetails.id, console.log('error submit!!');
trace_result: this.webForm.trace_result,
create_user: this.userInfo.username,
remark: this.webForm.remark,
abnormal_types: this.webForm.abnormal_types,
create_department: this.userInfo.department_name
} }
taskTrack(data).then((res) => { });
if (res.status_code == 1) { },
this.$message.success(res.msg) requestTaskDetails() {
this.webForm = { const data = {
trace_result: '', id: this.taskDetails.id,
remark: '', };
abnormal_types: [] taskDetails(data).then((res) => {
} res.data && res.data.id
this.is_finished = true ? (this.assionInfo = { ...this.assionInfo, ...res.data })
this.showLayer = false : '';
} this.memberBindExternalUser();
}) if (
}, this.assionInfo &&
onConfirm() { this.assionInfo.username &&
this.$refs.ruleForm.validate((valid) => { this.assionInfo.username.indexOf('\n') !== -1
if (valid) { ) {
this.submitForm() this.assionInfo.username = this.assionInfo.username.split('\n');
} else { } else {
console.log('error submit!!') this.assionInfo.username = [this.assionInfo.username];
}
})
},
requestTaskDetails() {
const data = {
id: this.taskDetails.id
} }
taskDetails(data).then((res) => { });
res.data && res.data.id ? this.assionInfo = { ...this.assionInfo, ...res.data } : '' },
this.memberBindExternalUser() requestSession(item) {
if (this.assionInfo && this.assionInfo.username && this.assionInfo.username.indexOf('\n') !== -1) { clientSessionBindTaskApi({
this.assionInfo.username = this.assionInfo.username.split('\n') userid: item.userid,
} else { external_userid: item.external_userid,
this.assionInfo.username = [this.assionInfo.username] task_id: this.assionInfo.id,
} member_id: item.member_id,
}) username: item.username,
}, });
requestSession(item) { this.$ww.openEnterpriseChat({
this.$ww.openEnterpriseChat({ externalUserIds: item.external_userid,
externalUserIds:item.external_userid,
success: (res) => { success: (res) => {
console.log(res, '打开会话窗口成功') console.log(res, '打开会话窗口成功');
}, },
fail: (err) => { fail: (err) => {
console.log(err, '打开会话窗口失败') console.log(err, '打开会话窗口失败');
} },
}) });
}, },
async memberOrder() { async memberOrder() {
let res = {} let res = {};
if (!this.taskDetails.cp_role_id || this.taskDetails.cp_role_id == '') { 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 { } 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 }
},
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:''}]
}
},
async memberBindExternalUser() {
let member_list = []
if (this.assionInfo.members?.length > 0) {
member_list = this.assionInfo.members.map((item) => item.member_id)
} else {
member_list = [this.assionInfo.member_id]
}
this.loading = true
if (member_list.length === 0) {
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
} catch (error) {
this.loading = false
}
} }
} this.todayOrder = res.data[0];
} this.assionInfo = { ...this.assionInfo, ...this.todayOrder };
</script> },
<style lang="scss" scoped> async taskRecord() {
.contet { const res = await taskRecord({
height: 100%; task_id: this.taskDetails.id,
background: #fff; user_type: '',
padding: 10px; });
console.log(res.data.data, 'res.data.data');
overflow: auto; if (res.data.data.length > 0) {
.title { this.remarks = res.data.data[0].remarks;
font-size: 14px; } else {
font-family: PingFangSC-Medium, PingFang SC; this.remarks = [{ remark: '' }];
font-weight: 500;
color: #333333;
margin-bottom: 10px;
}
.taskInfo {
height: auto;
background: #f7f8fa;
border-radius: 4px;
padding-bottom: 3px;
padding-top: 10px;
position: relative;
.icon {
font-size: 52px;
} }
},
.approval_status { async memberBindExternalUser() {
position: absolute; let member_list = [];
top: 50%; if (this.assionInfo.members?.length > 0) {
right: 20px; member_list = this.assionInfo.members.map((item) => item.member_id);
transform: translateY(-50%); } else {
member_list = [this.assionInfo.member_id];
} }
this.loading = true;
.taskInfoItem { if (member_list.length === 0) {
width: 250px; return false;
margin-bottom: 5px; }
try {
.label { const res = await memberBindExternalUser({
width: 100px; member_id: member_list.toString(),
font-size: 14px; is_bind: this.assionInfo.is_bind,
font-family: PingFangSC-Regular, PingFang SC; });
font-weight: 400; this.kfhList = res.data;
color: #99a3b4; this.loading = false;
text-align: right; } catch (error) {
margin-right: 10px; this.loading = false;
}
.value {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
text-align: left;
}
} }
},
},
};
</script>
<style lang="scss" scoped>
.contet {
height: 100%;
background: #fff;
padding: 10px;
overflow: auto;
.title {
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
margin-bottom: 10px;
}
.taskInfo {
height: auto;
background: #f7f8fa;
border-radius: 4px;
padding-bottom: 3px;
padding-top: 10px;
position: relative;
.icon {
font-size: 52px;
} }
.remarks { .approval_status {
margin-top: 20px; position: absolute;
top: 50%;
right: 20px;
transform: translateY(-50%);
} }
.contentInfo { .taskInfoItem {
margin-top: 20px; width: 250px;
margin-bottom: 5px;
.contentInfoItem {
margin-right: 40px; .label {
margin-top: 10px; width: 100px;
font-size: 14px;
.label { font-family: PingFangSC-Regular, PingFang SC;
width: 60px; font-weight: 400;
font-size: 14px; color: #99a3b4;
font-family: PingFangSC-Regular, PingFang SC; text-align: right;
font-weight: 400; margin-right: 10px;
color: #99a3b4;
text-align: right;
margin-right: 10px;
}
.remarkContent {
width: 200px;
height: auto;
::v-deep img {
max-width: 200px;
}
}
.value {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
text-align: left;
}
} }
}
.value {
.kfhList { font-size: 14px;
width: 100%; font-family: PingFangSC-Regular, PingFang SC;
height: auto; font-weight: 400;
margin-top: 22px; color: #333333;
margin-bottom: 60px; text-align: left;
.sessionUser{
width: 100%;
height: auto;
background: #F8F8F8;
border-radius: 4px;
padding: 10px;
} }
}
.wxUserInfo { }
span{
font-family: PingFangSC, PingFang SC; .remarks {
font-weight: 400; margin-top: 20px;
font-size: 14px; }
color: #949FB0;
} .contentInfo {
margin-top: 20px;
.contentInfoItem {
margin-right: 40px;
margin-top: 10px;
.label {
width: 60px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #99a3b4;
text-align: right;
margin-right: 10px;
} }
.kfhItem { .remarkContent {
width: 330px; width: 200px;
background: #f8f8f8; height: auto;
border-radius: 4px;
margin-right: 20px; ::v-deep img {
margin-bottom: 5px; max-width: 200px;
.left {
.image {
width: 30px;
height: 30px;
border-radius: 50%;
margin-right: 10px;
}
.name {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
}
} }
} }
}
.value {
.approvalProcessList { font-size: 14px;
margin-bottom: 20px; font-family: PingFangSC-Regular, PingFang SC;
margin-top: 20px; font-weight: 400;
} color: #333333;
text-align: left;
// 掌游的样式
::v-deep.el-step .el-step__line {
width: 1px;
}
::v-deep .el-step > .is-success {
color: #00bf8a;
border-color: #00bf8a;
.el-step__line {
background-color: #e5e6eb;
}
}
::v-deep .el-step__main > .is-success {
color: #00bf8a;
}
::v-deep .el-step > .is-process {
color: #00bf8a;
border-color: #00bf8a;
.el-step__line {
background-color: #e5e6eb;
} }
} }
}
::v-deep .el-step__main > .is-process {
color: #00bf8a; .kfhList {
} width: 100%;
height: auto;
.form-item-btn { margin-top: 22px;
margin: 0 0 0 20px; margin-bottom: 60px;
} .sessionUser {
width: 100%;
.audit-label { height: auto;
font-size: 14px; background: #f8f8f8;
font-weight: 800; border-radius: 4px;
margin: 0 0 10px 0; padding: 10px;
}
.remark-label {
color: #949fb0;
font-size: 14px;
} }
.preview-btn { .wxUserInfo {
cursor: pointer; span {
font-size: 14px; font-family: PingFangSC, PingFang SC;
color: #00bf8a; font-weight: 400;
margin: 0 0 0 10px; font-size: 14px;
color: #949fb0;
i {
margin: 0 5px 0 0;
} }
} }
.remark-value { .kfhItem {
width: 480px; width: 330px;
min-height: 100px; background: #f8f8f8;
margin: 10px 0 0 40px;
padding: 6px 12px;
border: 1px solid #d9d9d9;
border-radius: 4px; border-radius: 4px;
cursor: not-allowed; margin-right: 20px;
color: #333; margin-bottom: 5px;
} .left {
.image {
.flex-box { width: 30px;
display: flex; height: 30px;
border-radius: 50%;
.remark-lebel { margin-right: 10px;
width: 50px; }
text-align: right; .name {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
}
} }
} }
}
.refund-flow-drawer {
position: fixed; .approvalProcessList {
top: 0; margin-bottom: 20px;
right: 700px; margin-top: 20px;
}
// 掌游的样式
::v-deep.el-step .el-step__line {
width: 1px;
}
::v-deep .el-step > .is-success {
color: #00bf8a;
border-color: #00bf8a;
.el-step__line {
background-color: #e5e6eb;
}
}
::v-deep .el-step__main > .is-success {
color: #00bf8a;
}
::v-deep .el-step > .is-process {
color: #00bf8a;
border-color: #00bf8a;
.el-step__line {
background-color: #e5e6eb;
} }
}
.btm-btn-box {
position: fixed; ::v-deep .el-step__main > .is-process {
bottom: 20px; color: #00bf8a;
width: 560px; }
height: 32px;
.form-item-btn {
margin: 0 0 0 20px;
}
.audit-label {
font-size: 14px;
font-weight: 800;
margin: 0 0 10px 0;
}
.remark-label {
color: #949fb0;
font-size: 14px;
}
.preview-btn {
cursor: pointer;
font-size: 14px;
color: #00bf8a;
margin: 0 0 0 10px;
i {
margin: 0 5px 0 0;
} }
}
.audit-state {
.remark-value {
width: 480px;
min-height: 100px;
margin: 10px 0 0 40px;
padding: 6px 12px;
border: 1px solid #d9d9d9;
border-radius: 4px;
cursor: not-allowed;
color: #333;
}
.flex-box {
display: flex;
.remark-lebel {
width: 50px; width: 50px;
height: 50px; text-align: right;
position: absolute;
top: 50%;
right: 0;
transform: translateY(-50%);
z-index: 100;
.audit-state-stamp {
font-size: 50px;
}
} }
}
.info-item {
width: 45%; .refund-flow-drawer {
display: flex; position: fixed;
height: 18px; top: 0;
margin: 0 0 12px 0; right: 700px;
}
.btm-btn-box {
position: fixed;
bottom: 20px;
width: 560px;
height: 32px;
}
.audit-state {
width: 50px;
height: 50px;
position: absolute;
top: 50%;
right: 0;
transform: translateY(-50%);
z-index: 100;
.audit-state-stamp {
font-size: 50px;
} }
}
.info-item-pic {
width: 100%; .info-item {
min-height: 96px; width: 45%;
max-height: 192px; display: flex;
height: 18px;
margin: 0 0 12px 0;
}
.info-item-pic {
width: 100%;
min-height: 96px;
max-height: 192px;
display: flex;
.img-list {
width: 464px;
display: flex; display: flex;
flex-wrap: wrap;
.img-list {
width: 464px; &-item {
display: flex; width: 80px;
flex-wrap: wrap; height: 80px;
border-radius: 4px;
&-item { overflow: hidden;
margin: 0 10px 10px 0;
position: relative;
.preview-pic {
width: 80px; width: 80px;
height: 80px; height: 80px;
border-radius: 4px; background: rgba(0, 0, 0, 0.5);
overflow: hidden; position: absolute;
margin: 0 10px 10px 0; top: 0;
position: relative; left: 0;
z-index: -1;
.preview-pic { text-align: center;
width: 80px; line-height: 80px;
height: 80px;
background: rgba(0, 0, 0, 0.5); .preview-icon {
position: absolute; font-size: 16px;
top: 0; color: #fff;
left: 0; cursor: pointer;
z-index: -1;
text-align: center;
line-height: 80px;
.preview-icon {
font-size: 16px;
color: #fff;
cursor: pointer;
}
}
.screenshot {
object-fit: center;
width: 80px;
height: 80px;
}
&:hover > .preview-pic {
z-index: 100;
} }
} }
.screenshot {
object-fit: center;
width: 80px;
height: 80px;
}
&:hover > .preview-pic {
z-index: 100;
}
} }
} }
}
.flex-btn {
display: flex; .flex-btn {
justify-content: space-between; display: flex;
} justify-content: space-between;
}
.info-label {
// width: 90px; .info-label {
// text-align: right; // width: 90px;
display: block; // text-align: right;
margin: 0 10px 0 0; display: block;
font-size: 14px; margin: 0 10px 0 0;
color: #949fb0; font-size: 14px;
} color: #949fb0;
}
.info-value {
display: block; .info-value {
font-size: 14px; display: block;
color: #333; font-size: 14px;
} color: #333;
}
.card-style {
background: #f2f2f7; .card-style {
border-radius: 4px; background: #f2f2f7;
} border-radius: 4px;
}
.trans-follow-1 {
width: 548px; .trans-follow-1 {
min-height: fit-content; width: 548px;
margin: 6px 0 12px 0; min-height: fit-content;
padding: 12px 12px 0; margin: 6px 0 12px 0;
display: flex; padding: 12px 12px 0;
flex-wrap: wrap; display: flex;
position: relative; flex-wrap: wrap;
position: relative;
.collapse-btn {
position: absolute; .collapse-btn {
top: 20px; position: absolute;
right: 15px; top: 20px;
} right: 15px;
.follow-item-remark {
width: 100%;
line-height: 20px;
margin: 0 0 12px 0;
}
.info-value-color {
color: #00bf8a;
margin-left: 5px;
}
} }
.follow-item { .follow-item-remark {
width: 50%; width: 100%;
height: 20px;
line-height: 20px; line-height: 20px;
margin: 0 0 12px 0; margin: 0 0 12px 0;
display: flex;
.label-left {
width: 90px;
text-align: right;
}
}
.left-label {
width: 60px;
} }
.follow-info-label { .info-value-color {
width: fit-content; color: #00bf8a;
text-align: left; margin-left: 5px;
display: inline-block;
margin: 0 10px 0 0;
} }
}
.info-value {
font-size: 14px; .follow-item {
color: #333; width: 50%;
height: 20px;
line-height: 20px;
margin: 0 0 12px 0;
display: flex;
.label-left {
width: 90px;
text-align: right;
} }
}
.label-font {
font-size: 14px; .left-label {
color: #949fb0; width: 60px;
}
.follow-info-label {
width: fit-content;
text-align: left;
display: inline-block;
margin: 0 10px 0 0;
}
.info-value {
font-size: 14px;
color: #333;
}
.label-font {
font-size: 14px;
color: #949fb0;
}
.info-item-remark {
width: 100%;
padding: 0 0 12px 0;
line-height: 20px;
.info-label {
display: block;
} }
.info-item-remark { .info-value {
width: 100%; display: block;
padding: 0 0 12px 0; width: 440px;
line-height: 20px;
.info-label {
display: block;
}
.info-value {
display: block;
width: 440px;
}
} }
} }
}
.editLayer {
padding: 20px; .editLayer {
padding-right: 0; padding: 20px;
::v-deep .el-textarea__inner { padding-right: 0;
height: 150px; ::v-deep .el-textarea__inner {
} height: 150px;
} }
</style> }
</style>
\ No newline at end of file
...@@ -4,11 +4,13 @@ ...@@ -4,11 +4,13 @@
<div class="content" v-loading="viewLoading"> <div class="content" v-loading="viewLoading">
<div v-if="chatUserDetails.is_phishing_account == 1" class="warnText"> <div v-if="chatUserDetails.is_phishing_account == 1" class="warnText">
<p>高风险玩家,请立即通知组长!!!!</p> <p>高风险玩家,请立即通知组长!!!!</p>
<p>①千万不能推转游!!不要发送违禁词汇!!不要发送礼包和告知任何礼包信息!!</p> <p>
①千万不能推转游!!不要发送违禁词汇!!不要发送礼包和告知任何礼包信息!!
</p>
<p>②不能以任何形式推送APP/网页链接,也不可承认有APP/网页端口!!</p> <p>②不能以任何形式推送APP/网页链接,也不可承认有APP/网页端口!!</p>
</div> </div>
<div v-if="change_appraisal" class="warnText"> <div v-if="change_appraisal" class="warnText">
<p> 钓鱼号 禁止转端通知组长!</p> <p>钓鱼号 禁止转端通知组长!</p>
</div> </div>
<div v-else-if="gameUserInfo.exp_ip" class="warnText"> <div v-else-if="gameUserInfo.exp_ip" class="warnText">
<p>高风险用户,禁止转端 !!!</p> <p>高风险用户,禁止转端 !!!</p>
...@@ -20,66 +22,138 @@ ...@@ -20,66 +22,138 @@
<!-- 添加客服状态显示及按钮 --> <!-- 添加客服状态显示及按钮 -->
<div class="cser_status"> <div class="cser_status">
<div class="status-actions"> <div class="status-actions">
<el-button type="danger" v-if="clientStatus !== 'offline'" style="margin-left: 0px;" size="mini" <el-button
@click="logout">下线</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" <el-button
@click="handleFinishRest">结束休息</el-button> v-if="clientStatus === 'rest'"
type="primary"
size="mini"
@click="handleFinishRest"
>结束休息</el-button
>
<!-- 在线状态显示开始休息按钮 --> <!-- 在线状态显示开始休息按钮 -->
<el-tooltip v-if="clientStatus === 'online'" content="午休或者临时有事可点击休息" placement="top"> <el-tooltip
<el-button type="warning" size="mini" @click="handleStartRest">开始休息</el-button> v-if="clientStatus === 'online'"
content="午休或者临时有事可点击休息"
placement="top"
>
<el-button type="warning" size="mini" @click="handleStartRest"
>开始休息</el-button
>
</el-tooltip> </el-tooltip>
<!-- 发送评价按钮 --> <!-- 发送评价按钮 -->
<el-button type="primary" style="margin-left: 0px;" size="mini" <el-button
@click="handleSendComment">发送评价</el-button> type="primary"
style="margin-left: 0px"
size="mini"
@click="handleSendComment"
>发送评价</el-button
>
</div> </div>
</div> </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="agreeStatus !== 'Agree'">当前微信用户未开启会话内容存档</p>
<p v-if="!hasPermit">当前客服号未授权开启会话内容存档</p> <p v-if="!hasPermit">当前客服号未授权开启会话内容存档</p>
</div> </div>
<div class="item rowFlex"> <div class="item rowFlex">
<!-- 公共的信息 --> <!-- 公共的信息 -->
<el-image fit="fill" draggable="false" style="-webkit-user-drag: none" :src="chatUserDetails.avatar" <el-image
class="tableImage"></el-image> fit="fill"
draggable="false"
style="-webkit-user-drag: none"
:src="chatUserDetails.avatar"
class="tableImage"
></el-image>
<div class="columnFlex"> <div class="columnFlex">
<div class="rowFlex" style="margin-bottom: 3px"> <div class="rowFlex" style="margin-bottom: 3px">
<p class="text" style="font-weight: 600"> <p class="text" style="font-weight: 600">
{{ chatUserDetails.name }} {{ chatUserDetails.name }}
</p> </p>
<span v-if="chatUserDetails.add_way_text" style="color: #09b159; margin-left: 10px">@{{ <span
chatUserDetails.add_way_text }}</span> v-if="chatUserDetails.add_way_text"
style="color: #09b159; margin-left: 10px"
>@{{ chatUserDetails.add_way_text }}</span
>
</div> </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" /> <vipLevel :gameUserInfo="gameUserInfo" />
<el-button-group> <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="autoResetPassword">修改密码</el-button>
<el-button type="text" size="mini" @click="changePhoneClick">修改手机号</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
<el-button type="text" v-if="false" @click="errorHandle">误操作</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> </el-button-group>
</div> </div>
</div> </div>
</div> </div>
<div class="item rowFlex columnCenter"> <div class="item rowFlex columnCenter">
<div class="rowFlex columnCenter"> <div class="rowFlex columnCenter">
<span class="label" style="min-width: 45px;">备注:</span> <span class="label" style="min-width: 45px">备注:</span>
<p v-if="!showInputRemark" class="text" style="max-width: 170px;"> <p v-if="!showInputRemark" class="text" style="max-width: 170px">
{{ {{
chatUserDetails.remark && chatUserDetails.remark != "" chatUserDetails.remark && chatUserDetails.remark != ''
? chatUserDetails.remark ? chatUserDetails.remark
: chatUserDetails.name : chatUserDetails.name
}} }}
</p> </p>
</div> </div>
<el-input v-if="showInputRemark" v-model="showInputRemarkValue" class="showInputRemarkInput" type="textarea" <el-input
@change="handleInputRemark" @blur="showInputRemark = false"></el-input> v-if="showInputRemark"
<i class="el-icon-edit icon" style="font-size: 14px" @click="editRemark"></i> 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">
<div class="rowFlex columnCenter">
<span class="label">最后交互日期:</span>
<span>
<span v-if="getDaysDifference">({{ 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>
<div> <div>
<!-- 自定义列 --> <!-- 自定义列 -->
...@@ -110,35 +184,66 @@ ...@@ -110,35 +184,66 @@
</div> </div>
</div> --> </div> -->
<!-- 游戏业务的账号信息 --> <!-- 游戏业务的账号信息 -->
<gameDetails v-if="gameUserInfo.username && !viewLoading" :chat-user-details="chatUserDetails" <gameDetails
:game-user-info="gameUserInfo" @changeAppraisal="changeAppraisal" /> v-if="gameUserInfo.username && !viewLoading"
:chat-user-details="chatUserDetails"
:game-user-info="gameUserInfo"
@changeAppraisal="changeAppraisal"
/>
<!-- 游戏标签 --> <!-- 游戏标签 -->
<div class="item rowFlex columnCenter spaceBetween tagsLost"> <div class="item rowFlex columnCenter spaceBetween tagsLost">
<div class="rowFlex"> <div class="rowFlex">
<span class="label">关联标签:</span> <span class="label">关联标签:</span>
<div v-if=" <div
chatUserDetails.tag_group && v-if="
chatUserDetails.tag_group.length > 0 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 --> <!-- 如果有多个标签组,显示+n -->
<el-popover v-if="chatUserDetails.tag_group.length > 1" placement="top" trigger="hover" <el-popover
popper-class="tag-popover"> v-if="chatUserDetails.tag_group.length > 1"
<div class="groups-popover-content" style="max-height: 600px;overflow-y: auto;"> placement="top"
<div v-for="(group, groupIndex) in chatUserDetails.tag_group.slice(1)" :key="groupIndex" trigger="hover"
class="group-item"> popper-class="tag-popover"
<el-tag v-for="(tagItem, tagIndex) in group.tag" :key="tagIndex" style="margin-right: 10px;">{{ >
tagItem.name }}</el-tag> <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>
</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> </el-popover>
</div> </div>
</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> </div>
<!-- 共享信息 --> <!-- 共享信息 -->
<shareInfo :chat-user-details="chatUserDetails" /> <shareInfo :chat-user-details="chatUserDetails" />
...@@ -146,26 +251,50 @@ ...@@ -146,26 +251,50 @@
</div> </div>
</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 || []" <selectTag
@submit="selectTags" /> v-if="showTag"
:show.sync="showTag"
:checkbox="true"
:check-list="chatUserDetails.tag_group || []"
@submit="selectTags"
/>
</div> </div>
</template> </template>
<script> <script>
import { mapState, mapMutations, mapActions } from 'vuex' import { mapState, mapMutations, mapActions } from 'vuex';
import gameDetails from './gameInfo/gameUserInfo.vue' import gameDetails from './gameInfo/gameUserInfo.vue';
import shareInfo from './shareInfo.vue' import shareInfo from './shareInfo.vue';
import changePhone from './changePhone.vue' import changePhone from './changePhone.vue';
import watchMember from '@/mixins/watchMember' import watchMember from '@/mixins/watchMember';
import { autoResetPassword, bindUserSelfAdd } from '@/api/game' import { autoResetPassword, bindUserSelfAdd } from '@/api/game';
import { memberBindCser, editUser, zyouUnBind } from '@/api/works' import {
import selectTag from '@/components/selectTag.vue' memberBindCser,
import { getClientStatus, remarkSessionIntelTag, finishRest, client_session_rest, checkSingleAgree, checkUserPermit, sendComment, logout } from '@/api/user.js' editUser,
import { sendChatMessage } from '@/utils/index.js' zyouUnBind,
import { getToken, removeToken } from '@/utils/auth' getMemberInfoApi,
import vipLevel from './gameInfo/vipLevel.vue' } from '@/api/works';
import Cookies from 'js-cookie' 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 { export default {
name: 'info', name: 'info',
components: { components: {
...@@ -173,13 +302,13 @@ export default { ...@@ -173,13 +302,13 @@ export default {
changePhone, changePhone,
shareInfo, shareInfo,
selectTag, selectTag,
vipLevel vipLevel,
}, },
props: { props: {
// 用户详情 // 用户详情
chatUserDetails: { chatUserDetails: {
type: Object, type: Object,
default: () => ({}) default: () => ({}),
}, },
}, },
data() { data() {
...@@ -197,121 +326,158 @@ export default { ...@@ -197,121 +326,158 @@ export default {
// 新增状态数据 // 新增状态数据
agreeStatus: '', // 用户是否同意聊天内容存档:Agreen同意 Disagree不同意 agreeStatus: '', // 用户是否同意聊天内容存档:Agreen同意 Disagree不同意
hasPermit: false, // 客服号是否开启会话内容存档权限 hasPermit: false, // 客服号是否开启会话内容存档权限
} lastTime: '', //上一次交互时间
};
}, },
computed: { computed: {
...mapState('game', [ ...mapState('game', [
'accountSelect', 'accountSelect',
'gameUserInfo', 'gameUserInfo',
'bindGameUserList', '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() { clientStatusText() {
const statusMap = { const statusMap = {
'online': '在线', online: '在线',
'offline': '离线', offline: '离线',
'rest': '休息中' rest: '休息中',
} };
return statusMap[this.client_online_status] || '未知' return statusMap[this.client_online_status] || '未知';
}, },
// 客服休息状态:online上线 offline下线 rest休息中 // 客服休息状态:online上线 offline下线 rest休息中
clientStatus() { 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], mixins: [watchMember],
mounted() { mounted() {
// 初始化企业微信SDK // 初始化企业微信SDK
this.initializeWecom() this.initializeWecom();
// 获取客服状态和相关信息 // 获取客服状态和相关信息
if (this.cser_id && this.token) { if (this.cser_id && this.token) {
this.getInitialData() this.getInitialData();
} }
//获取最后一次交互时间
this.getLastTime();
}, },
methods: { methods: {
...mapMutations('game', ['set_accountSelect']), ...mapMutations('game', ['set_accountSelect', 'accountSelect']),
...mapActions('user', ['initWecom']), ...mapActions('user', ['initWecom']),
// 初始化企业微信SDK // 初始化企业微信SDK
async initializeWecom() { async initializeWecom() {
try { try {
console.log('🚀 开始初始化企业微信 SDK') console.log('🚀 开始初始化企业微信 SDK');
const result = await this.initWecom() const result = await this.initWecom();
console.log('✅ 企业微信 SDK 初始化成功', result) console.log('✅ 企业微信 SDK 初始化成功', result);
} catch (error) { } catch (error) {
console.error('❌ 企业微信 SDK 初始化失败:', error) console.error('❌ 企业微信 SDK 初始化失败:', error);
} }
}, },
logout() { logout() {
if (this.client_online_status === 'rest') { if (this.client_online_status === 'rest') {
this.$message({ this.$message({
type: 'error', type: 'error',
message: '当前客服号处于休息状态,不能下线' message: '当前客服号处于休息状态,不能下线',
}) });
return return;
} }
this.$confirm('确定下线吗?', '提示', { this.$confirm('确定下线吗?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning',
}).then(() => {
this.userLogout()
}).catch(() => {
this.$message({
type: 'info',
message: '已取消'
})
}) })
.then(() => {
this.userLogout();
})
.catch(() => {
this.$message({
type: 'info',
message: '已取消',
});
});
}, },
async userLogout() { async userLogout() {
const data = { const data = {
userid: this.userid, userid: this.userid,
} };
const res = await logout(data) const res = await logout(data);
if (res.status_code === 1) { if (res.status_code === 1) {
this.$message({ this.$message({
type: 'success', type: 'success',
message: '下线成功' message: '下线成功',
}) });
removeToken() removeToken();
Cookies.remove('external_userid') Cookies.remove('external_userid');
Cookies.remove('userid') Cookies.remove('userid');
window.location.href = window.location.origin + '/company_app/index.html?corp_id=' + this.corp_id window.location.href =
window.location.origin +
'/company_app/index.html?corp_id=' +
this.corp_id;
} else { } else {
this.$message({ this.$message({
type: 'error', type: 'error',
message: '下线失败' message: '下线失败',
}) });
} }
}, },
// 获取初始数据 // 获取初始数据
async getInitialData() { async getInitialData() {
try { try {
// 1. 获取客服休息状态 // 1. 获取客服休息状态
const statusRes = await getClientStatus() const statusRes = await getClientStatus();
if (statusRes.status_code === 1) { if (statusRes.status_code === 1) {
if (statusRes.data.client_online_status === 'offline') { if (statusRes.data.client_online_status === 'offline') {
removeToken() removeToken();
window.location.href = window.location.origin + '/company_app/index.html?corp_id=' + this.corp_id 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. 同步智能标签 // 2. 同步智能标签
this.syncIntelligentTags() this.syncIntelligentTags();
// 3. 检查用户是否同意聊天内容存档 // 3. 检查用户是否同意聊天内容存档
this.checkAgreeStatus() this.checkAgreeStatus();
// 4. 检查客服号是否开启会话内容存档 // 4. 检查客服号是否开启会话内容存档
this.checkPermitStatus() this.checkPermitStatus();
} catch (error) { } catch (error) {
console.error('获取初始数据失败:', error) console.error('获取初始数据失败:', error);
} }
}, },
...@@ -321,11 +487,11 @@ export default { ...@@ -321,11 +487,11 @@ export default {
await remarkSessionIntelTag({ await remarkSessionIntelTag({
corp_id: this.corp_id, corp_id: this.corp_id,
external_userid: this.external_userid, external_userid: this.external_userid,
userid: this.userid userid: this.userid,
}) });
console.log('智能标签同步成功') console.log('智能标签同步成功');
} catch (error) { } catch (error) {
console.error('智能标签同步失败:', error) console.error('智能标签同步失败:', error);
} }
}, },
...@@ -334,13 +500,13 @@ export default { ...@@ -334,13 +500,13 @@ export default {
try { try {
const res = await checkSingleAgree({ const res = await checkSingleAgree({
external_userid: this.external_userid, external_userid: this.external_userid,
userid: this.userid userid: this.userid,
}) });
if (res.status_code === 1) { if (res.status_code === 1) {
this.agreeStatus = res.data.agree_status this.agreeStatus = res.data.agree_status;
} }
} catch (error) { } catch (error) {
console.error('检查用户同意状态失败:', error) console.error('检查用户同意状态失败:', error);
} }
}, },
...@@ -348,45 +514,45 @@ export default { ...@@ -348,45 +514,45 @@ export default {
async checkPermitStatus() { async checkPermitStatus() {
try { try {
const res = await checkUserPermit({ const res = await checkUserPermit({
userid: this.userid userid: this.userid,
}) });
if (res.status_code === 1) { if (res.status_code === 1) {
this.hasPermit = res.data.has_permit this.hasPermit = res.data.has_permit;
} }
} catch (error) { } catch (error) {
console.error('检查客服权限失败:', error) console.error('检查客服权限失败:', error);
} }
}, },
// 开始休息 // 开始休息
async handleStartRest() { async handleStartRest() {
try { try {
const res = await client_session_rest() const res = await client_session_rest();
if (res.status_code === 1) { if (res.status_code === 1) {
this.$store.commit('user/set_client_online_status', 'rest') this.$store.commit('user/set_client_online_status', 'rest');
this.$message.success('已开始休息') this.$message.success('已开始休息');
} else { } else {
this.$message.error(res.msg || '开始休息失败') this.$message.error(res.msg || '开始休息失败');
} }
} catch (error) { } catch (error) {
console.error('开始休息失败:', error) console.error('开始休息失败:', error);
this.$message.error('开始休息失败') this.$message.error('开始休息失败');
} }
}, },
// 结束休息 // 结束休息
async handleFinishRest() { async handleFinishRest() {
try { try {
const res = await finishRest() const res = await finishRest();
if (res.status_code === 1) { if (res.status_code === 1) {
this.$store.commit('user/set_client_online_status', 'online') this.$store.commit('user/set_client_online_status', 'online');
this.$message.success('已结束休息') this.$message.success('已结束休息');
} else { } else {
this.$message.error(res.msg || '结束休息失败') this.$message.error(res.msg || '结束休息失败');
} }
} catch (error) { } catch (error) {
console.error('结束休息失败:', error) console.error('结束休息失败:', error);
this.$message.error('结束休息失败') this.$message.error('结束休息失败');
} }
}, },
...@@ -396,195 +562,210 @@ export default { ...@@ -396,195 +562,210 @@ export default {
const res = await sendComment({ const res = await sendComment({
corp_id: this.corp_id, corp_id: this.corp_id,
external_userid: this.external_userid, external_userid: this.external_userid,
userid: this.userid userid: this.userid,
}) });
if (res.status_code === 1 && res.data.news) { if (res.status_code === 1 && res.data.news) {
// 使用企业微信JSSDK发送评价 // 使用企业微信JSSDK发送评价
const result = await sendChatMessage(res.data.news, 'link') const result = await sendChatMessage(res.data.news, 'link');
if (result.success) { if (result.success) {
this.$message.success('评价已发送') this.$message.success('评价已发送');
} else { } else {
this.$message.error('评价发送失败') this.$message.error('评价发送失败');
} }
} else { } else {
this.$message.error(res.msg || '获取评价内容失败') this.$message.error(res.msg || '获取评价内容失败');
} }
} catch (error) { } catch (error) {
console.error('发送评价失败:', error) console.error('发送评价失败:', error);
this.$message.error('发送评价失败') this.$message.error('发送评价失败');
} }
}, },
memberChange() { memberChange() {
this.requestBindUser() this.requestBindUser();
}, },
// 解绑确认 // 解绑确认
zyouUnBindConfirm() { zyouUnBindConfirm() {
this.$confirm('确定要解绑当前账号么?', '确认提示', { this.$confirm('确定要解绑当前账号么?', '确认提示', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning',
}) })
.then(() => { .then(() => {
this.zyouUnBind() this.zyouUnBind();
}) })
.catch(() => { .catch(() => {
this.$message({ this.$message({
type: 'info', type: 'info',
message: '已取消' message: '已取消',
}) });
}) });
}, },
requestBindUser() { requestBindUser() {
const data = { const data = {
member_id: this.accountSelect member_id: this.accountSelect,
} };
memberBindCser(data).then((res) => { 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) { 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 { } else {
this.$set(this.chatUserDetails, 'bind_cser', '') this.$set(this.chatUserDetails, 'bind_cser', '');
} }
}) });
}, },
zyouUnBind() { zyouUnBind() {
const data = { const data = {
userid: this.chatUserDetails.userid, userid: this.chatUserDetails.userid,
external_userid: this.chatUserDetails.external_userid, external_userid: this.chatUserDetails.external_userid,
member_id: this.accountSelect member_id: this.accountSelect,
} };
zyouUnBind(data).then((res) => { zyouUnBind(data).then((res) => {
if (res.status_code == 1) { if (res.status_code == 1) {
this.$message.success(res.msg) this.$message.success(res.msg);
const index = this.bindGameUserList.findIndex(item => item.member_id == this.accountSelect) const index = this.bindGameUserList.findIndex(
this.bindGameUserList.splice(index, 1) (item) => item.member_id == this.accountSelect
this.set_accountSelect(this.bindGameUserList[0].member_id) );
this.bindGameUserList.splice(index, 1);
this.set_accountSelect(this.bindGameUserList[0].member_id);
} }
}) });
}, },
// 修改密码 之前是客服手动设置密码 现在改成系统自动设置密码 // 修改密码 之前是客服手动设置密码 现在改成系统自动设置密码
autoResetPassword() { autoResetPassword() {
this.$confirm('确认重置密码吗?密码重置后玩家将无法登录,请谨慎操作!', '重置密码', { this.$confirm(
confirmButtonText: '确定', '确认重置密码吗?密码重置后玩家将无法登录,请谨慎操作!',
cancelButtonText: '取消', '重置密码',
type: 'warning' {
}).then(res => { confirmButtonText: '确定',
const data = { cancelButtonText: '取消',
member_id: this.accountSelect, type: 'warning',
zq_user_name: this.cser_name
} }
autoResetPassword(data).then((res) => { )
if (res.status_code == 1) { .then((res) => {
this.$message.success('密码重置成功') const data = {
} member_id: this.accountSelect,
}) zq_user_name: this.cser_name,
}).catch(() => { };
this.$message({ autoResetPassword(data).then((res) => {
type: 'info', if (res.status_code == 1) {
message: '已取消' this.$message.success('密码重置成功');
}
});
}) })
}) .catch(() => {
this.$message({
type: 'info',
message: '已取消',
});
});
}, },
// 修改手机号 // 修改手机号
changePhoneClick() { changePhoneClick() {
this.changePhone = true this.changePhone = true;
}, },
// 关联客服 // 关联客服
relationKfh() { relationKfh() {
const username = this.bindGameUserList.find( const username = this.bindGameUserList.find(
(item) => item.value == this.accountSelect (item) => item.value == this.accountSelect
) );
const params = { const params = {
member_id: this.accountSelect, member_id: this.accountSelect,
user_id: this.cser_id, user_id: this.cser_id,
user_name: this.cser_name, user_name: this.cser_name,
username: username.username username: username.username,
} };
bindUserSelfAdd(params).then((res) => { bindUserSelfAdd(params).then((res) => {
if (res.status_code == 1) { if (res.status_code == 1) {
this.$set(this.chatUserDetails, 'bind_cser', 1) this.$set(this.chatUserDetails, 'bind_cser', 1);
this.$message.success(res.msg) this.$message.success(res.msg);
} }
}) });
}, },
// 误操作处理 // 误操作处理
errorHandle() { errorHandle() {
this.$emit('error-handle') this.$emit('error-handle');
}, },
// 编辑备注 // 编辑备注
editRemark() { editRemark() {
this.showInputRemark = true this.showInputRemark = true;
this.showInputRemarkValue = this.chatUserDetails.remark || this.chatUserDetails.name this.showInputRemarkValue =
this.chatUserDetails.remark || this.chatUserDetails.name;
this.$nextTick(() => { this.$nextTick(() => {
// document.querySelector('.showInputRemarkInput input').focus() // document.querySelector('.showInputRemarkInput input').focus()
}) });
}, },
// 处理备注输入 // 处理备注输入
handleInputRemark(val) { handleInputRemark(val) {
this.showInputRemark = false this.showInputRemark = false;
this.chatUserDetails.remark = this.showInputRemarkValue this.chatUserDetails.remark = this.showInputRemarkValue;
const data = { const data = {
userid: this.chatUserDetails.userid, userid: this.chatUserDetails.userid,
external_userid: this.chatUserDetails.external_userid, external_userid: this.chatUserDetails.external_userid,
remark: this.chatUserDetails.remark, remark: this.chatUserDetails.remark,
self_defined_columns: this.chatUserDetails.self_defined_columns, self_defined_columns: this.chatUserDetails.self_defined_columns,
tag_group: this.chatUserDetails.tag_group tag_group: this.chatUserDetails.tag_group,
} };
this.editUserInfo(data) this.editUserInfo(data);
}, },
editUserInfo(data) { editUserInfo(data) {
editUser(data).then((res) => { editUser(data).then((res) => {
if (res.status_code == 1) { if (res.status_code == 1) {
this.$message({ this.$message({
type: 'success', type: 'success',
message: res.msg message: res.msg,
}) });
} }
}) });
}, },
// 显示自定义列输入 // 显示自定义列输入
inputShow(item, index) { inputShow(item, index) {
this.showInput = true this.showInput = true;
this.inputIndex = index this.inputIndex = index;
this.showInputValue = item.value this.showInputValue = item.value;
this.$nextTick(() => { this.$nextTick(() => {
document.querySelectorAll('input')[0].focus() document.querySelectorAll('input')[0].focus();
}) });
}, },
// 处理自定义列输入 // 处理自定义列输入
handleInput(item, index) { handleInput(item, index) {
this.$emit('update-custom-column', { this.$emit('update-custom-column', {
item, item,
index, index,
value: this.showInputValue value: this.showInputValue,
}) });
this.showInput = false this.showInput = false;
}, },
// 编辑标签 // 编辑标签
editTags() { editTags() {
this.showTag = true this.showTag = true;
}, },
// 处理评估变更 // 处理评估变更
changeAppraisal(val) { changeAppraisal(val) {
this.change_appraisal = val this.change_appraisal = val;
}, },
// 选择的标签 // 选择的标签
selectTags(data, is_tag_sync) { selectTags(data, is_tag_sync) {
this.chatUserDetails.tag_group = data this.chatUserDetails.tag_group = data;
const params = { const params = {
userid: this.chatUserDetails.userid, userid: this.chatUserDetails.userid,
external_userid: this.chatUserDetails.external_userid, external_userid: this.chatUserDetails.external_userid,
remark: this.chatUserDetails.remark, remark: this.chatUserDetails.remark,
is_tag_sync: is_tag_sync, is_tag_sync: is_tag_sync,
self_defined_columns: this.chatUserDetails.self_defined_columns, self_defined_columns: this.chatUserDetails.self_defined_columns,
tag_group: this.chatUserDetails.tag_group tag_group: this.chatUserDetails.tag_group,
} };
this.editUserInfo(params) this.editUserInfo(params);
}, },
} async getLastTime() {
} const { data } = await getMemberInfoApi({
member_id: this.accountSelect,
});
this.lastTime = data.last_chat_time;
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.info-tab-content { .info-tab-content {
...@@ -607,7 +788,7 @@ export default { ...@@ -607,7 +788,7 @@ export default {
font-size: 18px; font-size: 18px;
p { p {
color: #F56C6C; color: #f56c6c;
line-height: 25px; line-height: 25px;
} }
} }
...@@ -639,7 +820,7 @@ export default { ...@@ -639,7 +820,7 @@ export default {
p { p {
margin: 5px 0; margin: 5px 0;
color: #F56C6C; color: #f56c6c;
font-weight: 600; font-weight: 600;
} }
} }
...@@ -663,7 +844,7 @@ export default { ...@@ -663,7 +844,7 @@ export default {
margin-bottom: 10px; margin-bottom: 10px;
p { p {
color: #F56C6C; color: #f56c6c;
line-height: 25px; line-height: 25px;
} }
} }
...@@ -697,7 +878,7 @@ export default { ...@@ -697,7 +878,7 @@ export default {
} }
.noBind { .noBind {
color: #3491FA; color: #3491fa;
cursor: pointer; cursor: pointer;
margin-right: 10px; margin-right: 10px;
} }
...@@ -772,7 +953,7 @@ export default { ...@@ -772,7 +953,7 @@ export default {
.tag-more { .tag-more {
display: inline-block; display: inline-block;
color: #3491FA; color: #3491fa;
margin-left: 5px; margin-left: 5px;
cursor: pointer; cursor: pointer;
} }
...@@ -829,4 +1010,4 @@ export default { ...@@ -829,4 +1010,4 @@ export default {
min-width: 200px; min-width: 200px;
max-width: 300px; max-width: 300px;
} }
</style> </style>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论