提交 aa6c25af 作者: 毛细亚

更新代码

上级 2867edc8
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
<script> <script>
import bindUserList from '@/views/components/bindGameAccount/bindUserList.vue' import bindUserList from '@/views/components/bindGameAccount/bindUserList.vue'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import { mapState } from 'vuex' import { mapState, mapMutations } from 'vuex'
import Cookies from 'js-cookie' import Cookies from 'js-cookie'
export default { export default {
name: 'App', name: 'App',
...@@ -40,14 +40,14 @@ export default { ...@@ -40,14 +40,14 @@ export default {
label: '客户信息', label: '客户信息',
path: '/userInfo' path: '/userInfo'
}, },
// { {
// label: '快捷回复', label: '快捷回复',
// path: '/quickReply' path: '/quickReply'
// }, },
// { {
// label: '礼包记录', label: '礼包记录',
// path: '/giftRecord' path: '/giftRecord'
// }, },
// { // {
// label: '申请记录', // label: '申请记录',
// path: '/applyRecord' // path: '/applyRecord'
...@@ -94,6 +94,23 @@ export default { ...@@ -94,6 +94,23 @@ export default {
} }
}, },
mounted() { mounted() {
// 页面刷新时从 Cookie 恢复 token 到 store
const cookieToken = Cookies.get('token')
if (cookieToken && !this.token) {
this.set_token(cookieToken)
console.log('从 Cookie 恢复 token:', cookieToken)
}
// 调试信息:检查所有关键状态
console.log('App mounted - 关键状态检查:', {
token: this.token,
external_userid: this.external_userid,
showMemberId: this.showMemberId,
cookieToken: Cookies.get('token'),
cookieExternalUserId: Cookies.get('external_userid'),
currentPath: this.$route.path
})
// 初始化时处理路径 // 初始化时处理路径
const currentPath = this.$route.path const currentPath = this.$route.path
if (currentPath === '/' || currentPath === '' || currentPath === '/index.html') { if (currentPath === '/' || currentPath === '' || currentPath === '/index.html') {
...@@ -104,6 +121,7 @@ export default { ...@@ -104,6 +121,7 @@ export default {
console.log('创建时路径:', currentPath, '选中路径:', this.selectedPath) console.log('创建时路径:', currentPath, '选中路径:', this.selectedPath)
}, },
methods:{ methods:{
...mapMutations('user', ['set_token']),
handleSelect(key, keyPath) { handleSelect(key, keyPath) {
console.log('菜单选择:', key, keyPath, window.location.href) console.log('菜单选择:', key, keyPath, window.location.href)
} }
......
import request from '@/utils/request'
import store from '@/store/index'
// 所属分组下拉
function returnApi(api){
return '/sidebar' + api
}
export function procedure_group(data) {
return request({
url: returnApi('/procedure_group/index'),
method: 'post',
data
})
}
// 话术列表
export function procedureList(data) {
return request({
url: returnApi('/procedure/index'),
method: 'post',
data
})
}
// 删除话术
export function proceduredel(data) {
return request({
url: returnApi('/procedure/del'),
method: 'post',
data
})
}
// 批量移动
export function proceduremove(data) {
return request({
url: returnApi('/procedure/move'),
method: 'post',
data
})
}
// 新增话术
export function procedureadd(data) {
return request({
url: returnApi('/procedure/add'),
method: 'post',
data
})
}
// 分组添加/修改
export function procedure_groupAdd(data) {
return request({
url: returnApi('/procedure_group/add'),
method: 'post',
data
})
}
// 分组删除
export function procedure_groupDel(data) {
return request({
url: returnApi('/procedure_group/del'),
method: 'post',
data
})
}
// 个人话术移到企业库
export function addCompany(data) {
return request({
url: returnApi('/procedure/addCompany'),
method: 'post',
data
})
}
// 个人话术详情
export function procedureInfo(data) {
return request({
url: returnApi('/procedure/info'),
method: 'post',
data
})
}
// 个人话术排序
export function procedureSort(data) {
return request({
url: returnApi('/procedure/sort'),
method: 'post',
data
})
}
// 个人话术租排序
export function procedureGroupSort(data) {
return request({
url: returnApi('/procedure_group/sort'),
method: 'post',
data
})
}
// 企业话术增至个人
export function addToPersonal(data) {
return request({
url: returnApi('/procedure/addToPersonal'),
method: 'post',
data
})
}
// 话术使用次数
export function skillQuote(data) {
return request({
url: '/admin/procedure/quote',
method: 'post',
data
})
}
/* ----------- 知识库的接口 ---------- */
// 知识库分组列表
export function groupList(data) {
return request({
url: returnApi('/knowledge_group/index'),
method: 'post',
data
})
}
// 知识库分组下拉
export function libraryIndex(data) {
return request({
url: returnApi('/knowledge_base/index'),
method: 'post',
data
})
}
// 新增和编辑
export function groupHandle(data) {
return request({
url: returnApi('/knowledge_group/add'),
method: 'post',
data
})
}
// 删除分组
export function groupDel(data) {
return request({
url: returnApi('/knowledge_group/del'),
method: 'post',
data
})
}
// 新增知识库任务
export function addLibraryTask(data) {
return request({
url: returnApi('/knowledge_base/add'),
method: 'post',
data
})
}
// 详情
export function libraryTaskView(data) {
return request({
url: returnApi('/knowledge_base/view'),
method: 'post',
data
})
}
// 编辑
export function libraryTaskEdit(data) {
return request({
url: returnApi('/knowledge_base/edit'),
method: 'post',
data
})
}
// 删除
export function libraryTaskDel(data) {
return request({
url: returnApi('/knowledge_base/del'),
method: 'post',
data
})
}
// 批量删除
export function multipleDel(data) {
return request({
url: returnApi('/knowledge_base/batchDel'),
method: 'post',
data
})
} // 导入
export function importData(data) {
return request({
url: returnApi('/knowledge_base/importKnowledgeBase'),
method: 'post',
data
})
}
// 知识库计数
export function logClickTime(data) {
return request({
url: returnApi('/knowledge_base/logClickTime'),
method: 'post',
data
})
}
// 大模型 ai
export function getCorpBetaConfig(data) {
return request({
url: '/admin/corp_beta_config/getCorpBetaConfig',
method: 'post',
data
})
}
// 问答模块
export function getAiResponse(data) {
return request({
url: returnApi('/corp_beta_question_log/getAiResponse'),
method: 'post',
data
})
}
// 问答模块
export function Aihistory(data) {
return request({
url: returnApi('/corp_beta_question_log/history'),
method: 'post',
data
})
}
// 赞同模块
export function answerComment(data) {
return request({
url: returnApi('/corp_beta_question_log/answerComment'),
method: 'post',
data
})
}
// 复制次数统计
export function calAnswerClickTime(data) {
return request({
url: returnApi('/corp_beta_question_log/calAnswerClickTime'),
method: 'post',
data
})
}
// 获取来源
export function getQuoteData(data) {
return request({
url: returnApi('/corp_beta_question_log/getQuoteData'),
method: 'post',
data
})
}
// 同步知识库
export function asyncKnowledge(data) {
return request({
url: returnApi('/knowledge_base/syncToCorp'),
method: 'post',
data
})
}
/* -------------------- 机器人知识库 ----------------------- */
// 新增机器人知识库任务
export function corp_robot_knowledge_add(data) {
return request({
url: returnApi('/corp_robot_knowledge_base/add'),
method: 'post',
data
})
}
// 机器人知识库列表
export function corp_robot_knowledge_list(data) {
return request({
url: returnApi('/corp_robot_knowledge_base/index'),
method: 'post',
data
})
}
// 机器人知识库编辑
export function corp_robot_knowledge_edit(data) {
return request({
url: returnApi('/corp_robot_knowledge_base/edit'),
method: 'post',
data
})
}
// 机器人知识库详情
export function corp_robot_knowledge_view(data) {
return request({
url: returnApi('/corp_robot_knowledge_base/view'),
method: 'post',
data
})
}
// 机器人知识库删除
export function corp_robot_knowledge_del(data) {
return request({
url: returnApi('/corp_robot_knowledge_base/delete'),
method: 'post',
data
})
}
// 机器人知识库批量删除
export function corp_robot_knowledge_batchDelete(data) {
return request({
url: returnApi('/corp_robot_knowledge_base/batchDelete'),
method: 'post',
data
})
}
// 机器人知识库批量导入
export function corp_robot_knowledge_import(data) {
return request({
url: returnApi('/corp_robot_knowledge_base/import'),
method: 'post',
data
})
}
/* --------------------机器人知识库分组-----------------------*/
// 知识库分组列表
export function corp_robot_knowledge_group_index(data) {
return request({
url: returnApi('/corp_robot_knowledge_group/index'),
method: 'post',
data
})
}
// 知识库分组新增
export function corp_robot_knowledge_group_add(data) {
return request({
url: returnApi('/corp_robot_knowledge_group/add'),
method: 'post',
data
})
}
// 知识库分组编辑
export function corp_robot_knowledge_group_edit(data) {
return request({
url: returnApi('/corp_robot_knowledge_group/edit'),
method: 'post',
data
})
}
// 知识库分组删除
export function corp_robot_knowledge_group_del(data) {
return request({
url: returnApi('/corp_robot_knowledge_group/delete'),
method: 'post',
data
})
}
// AI问答对列表
export function AI_list(data) {
return request({
url: returnApi('/corp_ai_question_answer/index'),
method: 'post',
data
})
}
// 业务下拉
export function search_condition(data) {
return request({
url: '/admin/search_condition',
method: 'post',
data
})
}
// 智能体列表
export function corp_beta_config(data) {
return request({
url: '/admin/corp_beta_config/index',
method: 'post',
data
})
}
// 标记有用/无用
export function markUseful(data) {
return request({
url: returnApi('/corp_ai_question_answer/markUseful'),
method: 'post',
data
})
}
...@@ -90,3 +90,12 @@ export function zyouUnBind(data) { ...@@ -90,3 +90,12 @@ export function zyouUnBind(data) {
data data
}) })
} }
// 获取礼包码列表
export function getSendingCodeList(data) {
return request({
url: returnApi('/corp_gift_package_list/getSendingCodeList'),
method: 'post',
data
})
}
\ No newline at end of file
// 引入所有需要注册的全局组件
import noContent from '@/components/noContent.vue'
const globalComponents = [
noContent
]
export default {
install(Vue) {
globalComponents.forEach((component) => {
Vue.component(component.name, component)
})
}
}
<template>
<div class="search-item">
<div v-if=" label&& label.length<6" class="item-label">{{ label }}</div>
<div v-else-if="label &&label.length>=6 " class="item-label">
{{ label.slice(0,4) }} <br> {{ label.slice(4,label.length) }}
</div>
<div v-else class="item-label"></div>
<div class="item-content selectUser">
<BiDatePicker
v-model="dateValue"
:disabled="disabled"
:style="{'width':width ||''}"
:type="type?'datetimerange':'daterange'"
:format="type?'yyyy-MM-dd HH:mm:ss':'yyyy-MM-dd'"
:value-format="type?'yyyy-MM-dd HH:mm:ss':'yyyy-MM-dd'"
:default-time="['00:00:00','23:59:59']"
range-separator="~"
start-placeholder="开始日期"
end-placeholder="结束日期"
:clearable="noClearable?!noClearable:true"
@change="selectChange"
/>
</div>
</div>
</template>
<script>
export default {
name: 'SelectDate',
// noClearable 默认 clearable : true 特殊的关闭
props: ['label', 'width', 'isResize', 'defaultValue', 'pickerOptions', 'index', 'type', 'noClearable', 'disabled'],
data() {
return {
dateValue: []
}
},
watch: {
// 监听是否重置
isResize(newVal, oldVal) {
if (newVal) {
if (this.defaultValue) {
this.dateValue = this.defaultValue
} else {
this.dateValue = ''
}
}
},
defaultValue(newVal) {
if (newVal) {
this.dateValue = newVal
}
}
},
mounted() {
this.defaultValue ? this.dateValue = this.defaultValue : ''
},
methods: {
selectChange(value) {
console.log(value, 'value')
if (this.dateValue) {
this.$emit('result', { start_date: this.dateValue[0], end_date: this.dateValue[1], index: this.index || null })
} else {
this.$emit('result', { start_date: '', end_date: '', index: this.index || null })
}
}
}
}
</script>
<style lang="scss" scoped>
</style>
\ No newline at end of file
...@@ -21,17 +21,21 @@ import uploading from '@/utils/cos-upload' ...@@ -21,17 +21,21 @@ import uploading from '@/utils/cos-upload'
import 'element-ui/lib/theme-chalk/index.css'; import 'element-ui/lib/theme-chalk/index.css';
import errorHandle from '@/utils/errorHandle' import errorHandle from '@/utils/errorHandle'
import { getParams } from '@/utils/index' import { getParams } from '@/utils/index'
import globalComponent from '@/components/register.js'
Vue.use(globalComponent)
if(isTest()){ if(isTest()){
new VConsole(); new VConsole();
} }
function isTest(){ function isTest(){
return process.env.NODE_ENV !== 'production' return process.env.NODE_ENV !== 'production'
} }
// 开发环境不收集日志
if (process.env.NODE_ENV !== 'development') {
errorHandle.onload()
}
errorHandle.onload()
// // 开发环境不收集日志
// if (process.env.NODE_ENV !== 'development') {
// errorHandle.onload()
// }
// 测试一下 // 测试一下
Vue.use(uploading) Vue.use(uploading)
......
...@@ -69,7 +69,7 @@ const router = new VueRouter({ ...@@ -69,7 +69,7 @@ const router = new VueRouter({
用 hash 模式不用修改 nginx 配置 直接用就行了 用 hash 模式不用修改 nginx 配置 直接用就行了
如果用 history 需要在 vue.config.js 中配置 historyApiFallback: true, 解决404问题 如果用 history 需要在 vue.config.js 中配置 historyApiFallback: true, 解决404问题
*/ */
mode: 'history', mode: process.env.NODE_ENV === 'development' ? 'hash' : 'history',
base:process.env.NODE_ENV === 'development' ? '/' : '/company_app', base:process.env.NODE_ENV === 'development' ? '/' : '/company_app',
routes routes
}) })
......
...@@ -26,8 +26,7 @@ const state = { ...@@ -26,8 +26,7 @@ const state = {
corp_signature:'', corp_signature:'',
time:'' time:''
}, },
weixin_blongs_id_list:[], weixin_blongs_id_list:[]
external_userid:''
// 六子的 用户id wm5rUgMgAAjqjOcqp8i3lEhFZDQieWug // 六子的 用户id wm5rUgMgAAjqjOcqp8i3lEhFZDQieWug
// 我的 userid JinDuoXia cser_id 4090 corp_id wweaefe716636df3d1 cser_id 4090 token token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJpc3MiOjQwOTAsImlhdCI6MTc0NzgxMjMxMiwiZXhwIjoxNzQ4NDE3MTEyLCJuYmYiOjE3NDc4MTIzMTIsInN1YiI6InRva2Vu6K6k6K-BIiwianRpIjoiMjBkOTY3MDZiYzI1MDdmY2MxOWI2MjU1YTM0YWQ3M2YifQ.yX7E7QHV7x2ubpa8iK3Avy794EiHNCaW2CtB4A4UQWo // 我的 userid JinDuoXia cser_id 4090 corp_id wweaefe716636df3d1 cser_id 4090 token token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. eyJpc3MiOjQwOTAsImlhdCI6MTc0NzgxMjMxMiwiZXhwIjoxNzQ4NDE3MTEyLCJuYmYiOjE3NDc4MTIzMTIsInN1YiI6InRva2Vu6K6k6K-BIiwianRpIjoiMjBkOTY3MDZiYzI1MDdmY2MxOWI2MjU1YTM0YWQ3M2YifQ.yX7E7QHV7x2ubpa8iK3Avy794EiHNCaW2CtB4A4UQWo
} }
......
...@@ -49,31 +49,31 @@ export default { ...@@ -49,31 +49,31 @@ export default {
}, 3000) }, 3000)
} }
// 由于errorHandler是全局配置的,因此window.onerror将会“失效”,即errorHandler能捕获的错误,onerror将不能捕获;errorHandler不能捕获的异常,onerror将捕获错误。如果errorCaptured函数返回为false,那么此error将不会传到errorHandler // 由于errorHandler是全局配置的,因此window.onerror将会“失效”,即errorHandler能捕获的错误,onerror将不能捕获;errorHandler不能捕获的异常,onerror将捕获错误。如果errorCaptured函数返回为false,那么此error将不会传到errorHandler
// window.onerror = (message, source, lineno, colno, error) => { window.onerror = (message, source, lineno, colno, error) => {
// // message: 错误信息 // message: 错误信息
// // source:发生错误的资源 // source:发生错误的资源
// // line:发生错误的行号 // line:发生错误的行号
// // column:发生错误的列数 // column:发生错误的列数
// // error:Error错误对象 // error:Error错误对象
// this.windowErrors.push({ type: 'windowError', content: { message, source, lineno, colno, error: error.stack || '无法捕获错误' }}) this.windowErrors.push({ type: 'windowError', content: { message, source, lineno, colno, error: error.stack || '无法捕获错误' }})
// if (this.time1 != null) { if (this.time1 != null) {
// clearTimeout(this.time1) clearTimeout(this.time1)
// } }
// this.time1 = setTimeout(() => { this.time1 = setTimeout(() => {
// if (this.windowErrors.length > 0) { if (this.windowErrors.length > 0) {
// const list = this.removeDp2(this.windowErrors) const list = this.removeDp2(this.windowErrors)
// console.log('window错误', list) console.log('window错误', list)
// this.sendError(list) this.sendError(list)
// this.windowErrors = [] this.windowErrors = []
// } }
// }, 3000) }, 3000)
// } }
}, },
initTrack() { initTrack() {
const opts = { const opts = {
host: 'cn-hangzhou.log.aliyuncs.com', host: 'cn-hangzhou.log.aliyuncs.com',
project: 'zwwl2022', project: 'company-wx-frontend',
logstore: 'frontend_log', logstore: 'company-wx-sidebar',
time: 3, // 发送日志的时间间隔,默认是10秒。 time: 3, // 发送日志的时间间隔,默认是10秒。
count: 100, // 发送日志的数量大小,默认是10条。 count: 100, // 发送日志的数量大小,默认是10条。
topic: '掌微侧边栏' // 自定义日志主题。 topic: '掌微侧边栏' // 自定义日志主题。
...@@ -82,6 +82,7 @@ export default { ...@@ -82,6 +82,7 @@ export default {
Vue.prototype.$tracker = this.tracker Vue.prototype.$tracker = this.tracker
}, },
sendError(data) { sendError(data) {
console.log('开始发送错误', data)
this.tracker.sendBatchLogs(data) this.tracker.sendBatchLogs(data)
} }
} }
......
<template>
<el-drawer
:lock-scroll="true"
:title="title"
:visible="show"
size="450px"
@close="close"
>
<div>
<el-form ref="ruleForm" :model="ruleForm" label-width="100px" class="content">
<el-form-item label="选择角色">
<el-select v-model="ruleForm.role_id" placeholder="请选择角色" style="width:90%;margin-bottom:10px;" @change="selectRole">
<el-option
v-for="(item,index) in roleList"
:key="index+1"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="活动类型">
<el-select v-model="ruleForm.gift_type" placeholder="请选择" style="width:90%;margin-bottom:10px;" @change="giftTypeResult">
<el-option
v-for="(item,index) in giftTypeList"
:key="index+1"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</el-form-item>
<!-- 活动类型为角色累充的时候 活动可以多选其他的都为单选 -->
<el-form-item label="选择活动" prop="rule_id">
<el-select v-model="ruleForm.rule_id" :disabled="activeList.length==0" placeholder="请选择" style="width:90%;margin-bottom:10px;" :multiple="ruleForm.gift_type==1 || ruleForm.gift_type == 4 || ruleForm.gift_type== 5 " clearable @change="activeListResult">
<el-option
v-for="(item,index) in activeList"
:key="index+1"
:label="item.title_name"
:value="item.id"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item v-if="ruleForm.gift_type==3 && selectDate.min_date!==''" label="充值日期">
<el-date-picker
v-model="ruleForm.recharge_date"
style="width:90%;"
type="date"
value-format="yyyy-MM-dd"
:picker-options="pickerOptions"
@change="dateChange"
>
</el-date-picker>
</el-form-item>
</el-form>
<!-- 申请礼包 -->
<!-- 角色累充 -->
<roleRecharge v-if="showGiftDetails && (ruleForm.gift_type==1 || ruleForm.gift_type==4 || ruleForm.gift_type==5) && roleActiveInfo.length>0" :show.sync="showGiftDetails" :request-loading="requestLoading" :active-info="roleActiveInfo" :gift-info="giftDetailsInfo" title="礼包详情" />
<!-- 时间段累充 和 单日累充 积分关的情况 -->
<roleTimeRecharge v-if="showGiftDetails && (ruleForm.gift_type==2 || (ruleForm.gift_type==3 && activeInfo.exchange_score_status==2 ) ) && activeInfo.id " :change-date="changeDate" :request-loading="requestLoading" :show.sync="showGiftDetails" :active-info="activeInfo" :gift-info="giftDetailsInfo" title="礼包详情" @changeDateResult="changeDateResult" @giftDetailsInfo="requestDetailsInfo" />
<!-- 单日累充 积分开的情况 -->
<oneDayCharge v-if="showGiftDetails && ruleForm.gift_type==3 && activeInfo.exchange_score_status==1 && activeInfo.id" :show.sync="showGiftDetails" :request-loading="requestLoading" :active-info="activeInfo" :change-date="changeDate" :gift-info="giftDetailsInfo" title="礼包详情" @changeDateResult="changeDateResult" @giftDetailsInfo="requestDetailsInfo" />
</div>
</el-drawer>
</template>
<script type="text/javascript">
import { roleList, activeList, giftBagApply, giftTypeList, giftDetailsData } from '@/api/game'
import { mapState, mapMutations, mapActions } from 'vuex'
// import giftDetails from './giftDetails.vue'
import roleRecharge from './giftDetails/roleRecharge.vue'
import oneDayCharge from './giftDetails/oneDay.vue'
import roleTimeRecharge from './giftDetails/roleTimeRecharge.vue'
import { debounce } from '@/utils/index'
export default {
components: {
roleRecharge, // 角色累充
oneDayCharge, // 单日累充
roleTimeRecharge // 角色时间段累充
},
// type 3:image 4:video
props: ['show', 'width', 'title'],
data() {
return {
roleList: [],
activeList: [],
giftTypeList: [],
changeDate: false,
requestLoading: false,
showGiftDetails: false,
selectDate: {
start_date: '',
end_date: ''
}, // 时间选择区间
ruleForm: {
role_id: '',
rule_id: [],
gift_type: '',
recharge_date: ''
},
gift_type_text: '',
giftDetailsInfo: {},
activeInfo: {},
roleActiveInfo: [],
pickerOptions: {
disabledDate: (item) => {
return item.getTime() < new Date(this.selectDate.start_date).getTime() - 24 * 3600 * 1000 || item.getTime() > new Date(this.selectDate.end_date).getTime()
}
}
}
},
computed: {
...mapState('game', ['accountSelect'])
},
watch: {
show(newVal, oldVal) {
if (newVal) {
// this.requestRoleList()
}
}
},
mounted() {
this.requestRoleList()
this.giftTypeListData()
},
methods: {
requestActiveList() {
if (this.ruleForm.role_id !== '' && this.ruleForm.gift_type !== '') {
activeList({ role_id: this.ruleForm.role_id, gift_type: this.ruleForm.gift_type }).then(res => {
this.activeList = res.data
})
}
},
changeDateResult(data) {
this.$set(this.ruleForm, 'recharge_date', data)
this.$forceUpdate()
},
selectRole(value) {
this.ruleForm.rule_id = ''
this.ruleForm.gift_type = ''
this.ruleForm.recharge_date = ''
this.activeInfo = {}
this.giftInfo = {}
},
giftTypeListData() {
// 掌游后台说这边写死固定参数
giftTypeList({
type: 'dictionaries',
table_name: 'role_gift_bag',
field_name: 'gift_type'
}).then(res => {
if (res.status_code === 1) {
this.giftTypeList = res.data.data.filter(item => item.value !== 6)
}
})
},
requestRoleList() {
if (this.accountSelect == '') {
this.$message.warning('暂无关联的账号,请先去关联账号!')
return false
}
const data = {
api_search_name: '',
member_id: this.accountSelect
}
roleList(data).then(res => {
if (res.status_code == 1) {
if (res.data.data.length > 0) {
const list = res.data.data.sort((a, b) => { return Number(b.recharge_total) - Number(a.recharge_total) })
this.roleList = list.map(item => {
return {
label: item.role_name + ' / ' + item.server_name,
value: item.role_id
}
})
} else {
this.roleList = []
}
}
})
},
requestDetailsInfo(value) {
this.activeInfo.recharge_date = value
this.requestGiftDetails(value)
},
giftTypeResult(data) {
console.log(data, 'data')
this.ruleForm.recharge_date = ''
this.activeInfo = {}
this.giftInfo = {}
if (data == 1 || data == 4 || data == 5) {
this.ruleForm.rule_id = []
} else {
this.ruleForm.rule_id = ''
}
this.activeList = []
const gift_type = this.giftTypeList.find(item => item.value == data)
console.log(gift_type, 'gift_type')
this.gift_type_text = gift_type.label
this.requestActiveList()
this.activeInfo = {}
this.giftInfo = {}
},
// 活动类型为角色累充的时候 活动可以多选其他的都为单选
activeListResult: debounce(async function(value) {
if (!value) {
return false
}
this.ruleForm.recharge_date = ''
this.activeInfo = {}
this.giftInfo = {}
// 全平台角色累充和微端角色累充
if (this.ruleForm.gift_type == 1 || this.ruleForm.gift_type == 4 || this.ruleForm.gift_type == 5) {
if (value.length === 0) {
this.roleActiveInfo = []
return false
}
this.requestLoading = true
const promise = value.map(async (valueItem, index) => {
return new Promise(async (resolve, reject) => {
const item = value[index]
const giftType = await this.giftTypeDetails(index)
const giftItem = this.activeList.find(items => items.id == item)
const roleInfo = this.roleList.find(item => item.value === this.ruleForm.role_id)
resolve({
...giftItem,
role_info: roleInfo,
type_details: giftType,
gift_type_text: this.gift_type_text
})
})
})
let activeList = []
try {
activeList = await Promise.all(promise)
console.log(activeList, 'activeList')
this.requestLoading = false
} catch (error) {
this.requestLoading = false
} finally {
this.requestLoading = false
}
this.roleActiveInfo = activeList
this.showGiftDetails = true
} else {
this.ruleForm.recharge_date = ''
if (this.ruleForm.gift_type == 2) {
this.requestGiftDetails()
this.showGiftDetails = true
}
const giftItem = this.activeList.find(item => item.id == value)
this.activeInfo = giftItem
console.log(giftItem, '1231')
this.activeInfo.gift_type_text = this.gift_type_text
this.selectDate = { start_date: giftItem.min_date, end_date: giftItem.max_date }
this.activeInfo.pickerOptions = this.pickerOptions
if (this.ruleForm.role_id !== '') {
const roleInfo = this.roleList.find(item => item.value === this.ruleForm.role_id)
this.activeInfo.role_info = roleInfo
}
}
}, 1000),
dateChange(value) {
if (value) {
this.activeInfo.recharge_date = value
this.changeDate = true
setTimeout(() => {
this.changeDate = false
}, 50)
this.requestGiftDetails()
} else {
this.$message.warning('请选择充值日期')
}
},
requestGiftDetails(value) {
const data = {
role_id: this.ruleForm.role_id,
rule_id: this.ruleForm.rule_id.toString(),
recharge_date: value || this.ruleForm.recharge_date
}
giftDetailsData(data).then(res => {
this.giftDetailsInfo = res.data
this.showGiftDetails = true
})
},
giftTypeDetails(index) {
return new Promise((resolve, reject) => {
const data = {
role_id: this.ruleForm.role_id,
rule_id: Array.isArray(this.ruleForm.rule_id) ? this.ruleForm.rule_id[index] : this.ruleForm.rule_id,
recharge_date: this.ruleForm.recharge_date
}
giftDetailsData(data).then(res => {
resolve(res.data)
})
})
},
close() {
this.$emit('update:show', false)
},
submit() {
if (this.ruleForm.role_id === '') {
this.$message.warning('请选择角色')
return false
}
if (this.ruleForm.rule_id.length === 0) {
this.$message.warning('请选择活动')
return false
}
}
}
}
</script>
<style lang="scss" scoped>
.dialog-footer{
width: calc(100% - 20px);
height: 52px;
position: absolute;
right: 20px;
bottom: 20px;
padding-top: 20px;
border-top: 1px solid rgba(0, 0, 0, 0.06);
justify-content: flex-end;
.btn{
width:84px ;
height: 32px;
}
}
.content{
width: 100%;
height: auto;
}
</style>
\ No newline at end of file
<template>
<el-dialog :title="title" :visible="show" width="400" :append-to-body="true" class="giftDetailsDialog" @close="close">
<div class="content">
<div v-for="(item,index) in activeInfo" :key="index" class="item">
<div v-for="(items,indexs) in item.type_details.rule.level_attribute " :key="indexs" style="background:#F9FAFF;">
<!-- 角色累充 -->
<div v-if="item.gift_type==1 || item.gift_type==4 || item.gift_type==5" class="contentConfirm">
<div v-for="(prize,prizeIndex) in items.prize_default" :key="prizeIndex" class="contentConfirmItem rowFlex spaceBetween">
<p class="info"> {{ prize.name }}</p>
</div>
</div>
<!-- 时间段充值 和 单日累充 -->
<div v-else-if="items.apply_num > 0 && (item.gift_type==2 || item.gift_type==3)" class="contentConfirm">
<div v-if=" item.gift_type==2 || item.gift_type==3">
<div v-if="items.prize_default && items.prize_default.length>0">
<div class="contentConfirmItem">
<!-- 标题 -->
<div class="title rowFlex spaceBetween">
<span>{{ items.prize_level_name }}</span>
<!-- 积分开 -->
<div v-if="item.gift_type == 3 && item.type_details.rule.exchange_score_status==1">{{ items.compare_amount ? items.compare_amount + '积分' : items.compare_amount }}<span> * {{ items.apply_num }}</span></div>
<!-- 积分关 -->
<div v-else-if="item.gift_type == 3 && item.type_details.rule.exchange_score_status==2">{{ items.compare_amount ? items.compare_amount + '金额' : items.compare_amount }}<span> * {{ items.apply_num }}</span></div>
<div v-else-if="item.gift_type == 2 ">{{ items.compare_amount ? items.compare_amount + '金额' : items.compare_amount }}<span> * {{ items.apply_num }}</span></div>
</div>
<p class="title">固定奖 <span v-if="item.gift_type==3 && item.type_details.rule.exchange_score_status==1">{{ items.apply_num ? '*' + items.apply_num : '' }}</span> </p>
<div v-for="(prize,prizeIndex) in items.prize_default" :key="prizeIndex" class="contentConfirmItem rowFlex spaceBetween prizeStyle">
<p class="info"> {{ prize.name }}</p>
</div>
</div>
</div>
</div>
<div class="contentConfirmItem">
<div v-if="items.prize_auto.length>0 && ( !items.prize_default|| items.prize_default.length==0)" class="title rowFlex spaceBetween">
<span>{{ items.prize_level_name }}</span>
<div v-if="item.gift_type == 3 & item.type_details.rule.exchange_score_status==1">{{ items.compare_amount ? items.compare_amount + '积分' : items.compare_amount }}<span> * {{ items.apply_num }}</span></div>
<!-- 积分关 -->
<div v-if="item.gift_type == 3 & item.type_details.rule.exchange_score_status==2">{{ items.compare_amount ? items.compare_amount + '金额' : items.compare_amount }}<span> * {{ items.apply_num }}</span></div>
</div>
<p v-if="items.prize_auto.length>0" class="title">自选奖 ({{ items.prize_auto.length }}{{ items.prize_auto_num }}) <span v-if="item.gift_type==3 && item.type_details.rule.exchange_score_status==1">* {{ items.apply_num ? items.apply_num : 0 * items.prize_auto_num }}</span> </p>
<div v-for="(prize,prizeIndex) in items.prize_auto" :key="prizeIndex" class="contentConfirmItem prizeStyle">
<div v-for="(auto,autoIndex) in prize.group" :key="autoIndex">
<div v-if="prize.apply_num > 0" class="rowFlex spaceBetween">
<span>{{ auto.name }}</span>
<div>*{{ prize.apply_num }}</div>
</div>
</div>
</div>
</div>
<div v-if="item.gift_type == 3 && item.exchange_score_status==1 " class="expendIcon">消耗:{{ items.compare_amount * items.apply_num }} 积分</div>
</div>
</div>
</div>
</div>
<!-- 活动列表 -->
<span class="dialog-footer rowFlex">
<el-button class="btn" type="primary" :loading="loading" @click="submit">确 定</el-button>
<el-button class="btn" @click="close">取 消</el-button>
</span>
</el-dialog>
</template>
<script type="text/javascript">
import { giftBagApply } from '@/api/game'
import { mapState } from 'vuex'
export default {
// type 3:image 4:video
props: ['show', 'width', 'title', 'activeInfo', 'remark'],
data() {
return {
loading: false
}
},
computed: {
...mapState('user', ['cser_name'])
},
watch: {
show(newVal, oldVal) {
}
},
mounted() {},
methods: {
close() {
this.$emit('update:show', false)
},
submit() {
this.loading = true
const role_id = this.activeInfo[0].role_info.value
const rule = this.activeInfo.map(item => {
let level_attribute = []
if (item.type_details.rule.gift_type == 1) {
level_attribute = item.type_details.rule.level_attribute
} else {
level_attribute = item.type_details.rule.level_attribute.filter(item => item.apply_num > 0)
}
return { level_attribute: level_attribute, id: item.id }
})
const data = {
role_id,
remark: this.remark,
recharge_date: this.activeInfo[0].recharge_date || '',
create_user: this.cser_name,
rule: rule
}
giftBagApply(data).then(res => {
this.loading = false
if (res.status_code === 1) {
this.$message.success(res.msg)
this.close()
this.$emit('close')
} else {
this.close()
}
}, err => {
this.loading = false
})
}
}
}
</script>
<style lang="scss" scoped>
.content{
padding-bottom: 40px;
}
.contentConfirm{
padding:10px 20px;
background: #F9FAFF;
margin-bottom: 20px;
.prizeStyle{
margin-top: 10px;
margin-bottom: 10px;
}
.contentConfirmItem{
width: 100%;
height: auto;
background: #F9FAFF;
.title{
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
color: #333333;
line-height: 20px;
}
.info{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
}
}
}
.expendIcon{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
text-align: center;
margin-top:20px;
}
.dialog-footer {
width: calc(100% - 20px);
height: 52px;
position: absolute;
right: 20px;
bottom: 20px;
padding-top: 20px;
border-top: 1px solid rgba(0, 0, 0, 0.06);
justify-content: flex-end;
.btn {
width: 84px;
height: 32px;
}
}
.allIcon{
width: 137px;
height: 20px;
background: #F2AC51;
border-radius: 13px;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 80px;
}
.content {
width: 100%;
height: auto;
}
</style>
\ No newline at end of file
<template>
<div class="detailsGiftApply columnFlex">
<div class="detailsGiftApplyTitle rowFlex spaceBetween columnCenter">
<!-- <p>充值礼包</p> -->
<span></span>
<el-button
type="primary"
@click="showApplyGift = true"
>礼包申请</el-button>
</div>
<div class="detailsGiftApplyContent">
<!-- 过滤条件 -->
<div class="filterList">
<div class="inputItem rowFlex allCenter">
<span class="label">主游戏:</span>
<el-select
v-model.trim="form.main_game_id"
filterable
remote
clearable
reserve-keyword
placeholder="请输入主游戏名"
style="width:80%;"
:remote-method="remoteMethod"
:loading="loading"
@change="searchInput"
@focus="gameNameList=optionsList"
>
<el-option
v-for="item in gameNameList"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</div>
<div class="inputItem rowFlex allCenter">
<span class="label">区服:</span>
<el-select
v-model.trim="form.zyou_server_id"
filterable
remote
multiple
reserve-keyword
style="width:80%;"
placeholder="请先选择主游戏"
:remote-method="remoteMethodServer"
:loading="loading"
@change="searchInput"
>
<el-option
v-for="item in serverNameList"
:key="item.id"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
</div>
<div class="inputItem rowFlex allCenter">
<span class="label">角色名称:</span>
<el-input
v-model="form.role_name_or_cp_id"
placeholder="请输入角色名称"
style="width:80%;"
@change="searchInput"
></el-input>
</div>
<div class="inputItem rowFlex allCenter">
<span class="label">礼包标题:</span>
<el-input
v-model="form.active_title"
placeholder="请输入礼包名称"
style="width:80%;"
@change="searchInput"
></el-input>
</div>
</div>
<el-tabs
v-model="form.gift_type"
class="tabStyle"
@tab-click="tabChange"
>
<el-tab-pane
v-for="(item,index) in giftTypeList"
:key="index"
:label="item.label"
:name="item.value"
></el-tab-pane>
</el-tabs>
<!-- 订单列表 -->
<div
v-infinite-scroll="requestemailGiftList"
v-loading="listLoading"
:infinite-scroll-disabled="!isloadMore"
class="email-gift-main-scroll"
>
<div
v-if="emailGiftList.length>0"
style="height:auto;"
>
<div
v-for="(item,index) in emailGiftList"
:key="index"
class="orderDetails"
>
<div class="orderDetailsTitle">
<div class="rowFlex spaceBetween columnCenter">
<div>
<p class="text"><label>角色信息:</label> {{ `${item.role_name} - ${item.server_name}` }}</p>
<p class="text hidden"><label>礼包标题:</label> {{ item.active_title }}</p>
<p class="text hidden"><label>充值金额:</label> ¥{{ item.amount }}</p>
<p class="text hidden"><label>充值日期:</label> {{ item.apply_recharge_date }}</p>
</div>
<i
v-if="item.showDetails"
class="el-icon-arrow-down iconStyle"
@click="closePage(item,index)"
></i>
<i
v-else
class="el-icon-arrow-right iconStyle"
@click="openPage(item,index)"
></i>
</div>
<el-collapse-transition>
<div v-if="item.showDetails">
<p
v-if="item.status=='待提交'"
class="text"
><label>状态:</label> <span class="noSend">{{ item.status }}</span> </p>
<p
v-else-if="item.status=='已提交'"
class="text"
><label>状态:</label> <span class="sended">{{ item.status }}</span> </p>
<p
v-else-if="item.status=='已驳回'"
class="text"
><label>状态:</label> <span class="sendFail">{{ item.status }}</span> </p>
<p class="text"><label>申请时间:</label> {{ item.create_time }} </p>
<p class="text"><label>提交时间:</label> {{ item.confirm_time }} </p>
<label
style="margin-right:10px;margin-top:3px;"
class="text"
> <label>奖品信息:</label> </label>
<div
v-for="items in item.level_attribute"
:key="items.rule_id"
class="columnCenter userInfoStyle"
style="border-top: 1px solid rgb(196 205 226);margin-top: 5px;"
>
<div
class="contentConfirmItem rowFlex spaceBetween"
style="padding-left:0;margin-top:10px;"
>
<p class="title">{{ items.prize_level_name }}</p>
<p v-if="items.compare_amount">
{{ items.compare_amount ? Number(items.compare_amount)/100 + (item.exchange_score_status==1?'积分':'金额') : items.compare_amount }}<span> * {{ items.apply_num }}
</span></p>
</div>
<!-- 固定奖 -->
<div v-if="items.prize_default">
<div class="contentConfirmItem">
<p class="title">固定奖 <span v-if="item.exchange_score_status == 1">{{ items.apply_num ? '*' + items.apply_num : '' }}</span></p>
<div
v-for="(prize,prizeIndex) in items.prize_default"
:key="prizeIndex"
class="contentConfirmItem rowFlex "
>
<p class="info"> {{ prize.name }}</p>
<p
class="info"
style="margin-left:40px;"
>ID: {{ prize.prize_id }}</p>
</div>
</div>
</div>
<!-- 自选奖 -->
<div
v-if="items.prize_auto"
class="contentConfirmItem"
>
<p class="title">自选奖 ({{ items.prize_auto.length }}{{ items.prize_auto_num }})</p>
<div
v-for="(prize,prizeIndex) in items.prize_auto"
:key="prizeIndex"
class="contentConfirmItem "
>
<div
v-for="(auto,autoIndex) in prize.group"
:key="autoIndex"
>
<div
v-if="prize.apply_num > 0"
class="rowFlex spaceBetween"
>
<span>{{ auto.name }}</span>
<span> ID:{{ auto.prize_id }}</span>
<div>*{{ prize.apply_num }}</div>
</div>
</div>
</div>
</div>
<!-- 返利 -->
<div v-if="item.rebate_ratio_amount" class="contentConfirmItem">
<p class="rowFlex spaceBetween"> <span>返利:¥ {{ item.rebate_ratio_amount }}</span> <span>1:{{ items.rebate_ratio_rate }}</span> </p>
</div>
</div>
<div v-if="item.prize && item.prize.length>0">
<div
v-for="(prize,prizeIndex) in item.prize"
:key="prizeIndex"
class="contentConfirmItem rowFlex "
>
<p class="info"> {{ prize.name }}</p>
<p
class="info"
style="margin-left:40px;"
>ID: {{ prize.prize_id }}</p>
</div>
</div>
</div>
</el-collapse-transition>
</div>
</div>
</div>
<div
v-else-if="!listLoading && emailGiftList.length==0"
class="noContent rowFlex allCenter"
>
<noContent/>
</div>
</div>
</div>
<!-- 申请礼包 -->
<applyGift
v-if="showApplyGift"
:show.sync="showApplyGift"
title="礼包申请"
width="25%"
@requestData="requestData"
/>
</div>
</template>
<script>
import { emailGiftList, memberView, completionOrder, selectSearch } from '@/api/game'
import { mapMutations, mapActions, mapState } from 'vuex'
import { removeDp, debounce } from '@/utils/index'
// import { roleList, memberView, zyouBind, selectSearch } from '@/api/game'
import applyGift from './applyGift.vue'
import selectDate from '@/components/selectDate.vue'
export default {
components: {
selectDate,
applyGift
},
data() {
return {
isloadMore: true,
showApplyGift: false,
collapseValue: ['1'],
emailGiftList: [],
optionsList: [],
gameNameList: [],
loading: false,
listLoading: false,
serverNameList: [],
giftTypeList: [],
form: {
main_game_id: '',
zyou_server_id: [],
role_name_or_cp_id: '',
member_id: '',
active_title: '',
gift_type: ''
},
inputValue: '',
pageInfo: {
page: 0,
page_size: 20,
total: 0
}
}
},
computed: {
...mapState('game', ['accountSelect']),
},
watch: {
accountSelect(newVal, oldVal) {
if (newVal && newVal !== '') {
this.pageInfo = {
page: 0,
page_size: 20,
total: 0
}
this.emailGiftList = []
this.isloadMore = true
this.requestemailGiftList()
}
}
},
mounted() {
this.requestGameList()
this.requestGiftType()
},
methods: {
// 重新拉去数据
requestData() {
this.emailGiftList = []
this.isloadMore = true
this.requestemailGiftList()
},
tabChange: debounce(function() {
this.pageInfo.page = 0
this.emailGiftList = []
this.isloadMore = true
this.requestemailGiftList()
}, 1000),
async requestGiftType() {
const data = {
field_name: 'gift_type',
table_name: 'role_gift_bag',
type: 'dictionaries'
}
const res = await selectSearch(data)
if (res.status_code === 1) {
res.data.data.map(item => {
item.value = item.value.toString()
})
this.giftTypeList = res.data.data
this.giftTypeList.unshift({
value: '',
label: '全部'
})
}
},
requestGameList() {
const data = {
type: 'mainGameList',
value: '',
weixin_blong_id: ''
}
selectSearch(data).then(res => {
this.loading = false
if (res.status_code == 1) {
this.gameNameList = this.optionsList = res.data.data
}
})
},
closePage(item, index) {
this.$set(this.emailGiftList[index], 'showDetails', false)
},
openPage(item, index) {
this.$set(this.emailGiftList[index], 'showDetails', true)
},
remoteMethodServer(query) {
if (query !== '') {
this.loading = true
const data = {
type: 'server_info',
value: query,
main_game_ids: this.form.main_game_id
}
selectSearch(data).then(res => {
this.loading = false
if (res.status_code == 1) {
this.serverNameList = res.data.data
}
})
}
},
remoteMethod(query) {
if (query !== '') {
this.gameNameList = this.optionsList.filter(item => {
return item.label.toLowerCase()
.indexOf(query.toLowerCase()) > -1
})
} else {
this.gameNameList = []
}
},
searchInput(value) {
console.log(value)
this.pageInfo = {
page: 0,
page_size: 20,
total: 0
}
this.isloadMore = true
this.emailGiftList = []
this.requestemailGiftList()
},
requestemailGiftList() {
this.listLoading = true
if (this.accountSelect == '') {
this.$message.warning('暂无关联的账号,请先去关联账号!')
return false
}
if (!this.isloadMore) {
console.log('没有更多数据了')
return false
}
this.pageInfo.page += 1
this.form.member_id = this.accountSelect
emailGiftList({ ...this.form, ...this.pageInfo }).then(res => {
this.listLoading = false
if (res.data.data && res.data.data.length < 20) {
this.isloadMore = false
}
res.data.data.map((item, index) => {
item.showDetails = false
})
this.emailGiftList = removeDp(res.data.data, this.emailGiftList, 'id')
}, err => {
this.listLoading = false
})
}
}
}
</script>
<style lang="scss" scoped>
.detailsGiftApply {
width: 100%;
height: calc(100vh - 60px);
background: #fff;
position: relative;
overflow-y: hidden;
::v-deep .el-tabs__nav-next,::v-deep .el-tabs__nav-prev{
line-height: 50px;
}
.detailsGiftApplyTitle {
width: 100%;
height: 60px;
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
p {
color: #333333;
}
}
.detailsGiftApplyContent {
width: 100%;
height: calc(100% - 100px);
padding: 0 10px;
.item {
width: 100%;
height: auto;
font-size: 14px;
font-weight: 400;
color: #333333;
padding: 6px 0;
transition: all 0.5s;
position: relative;
padding-left: 10px;
cursor: pointer;
div {
width: 100%;
}
.label {
color: #999999;
}
.text {
color: #333333;
margin-left: 10px;
word-break: break-all;
max-width: 80%;
}
.icon {
display: none;
position: absolute;
right: 0;
top: 12px;
}
.dianFail {
display: inline-block;
width: 8px;
height: 8px;
background: #f45454;
border-radius: 5px;
}
.dian {
display: inline-block;
width: 8px;
height: 8px;
background: #00bf8a;
border-radius: 5px;
}
.dian2 {
display: inline-block;
width: 8px;
height: 8px;
background: #ff9d02;
border-radius: 5px;
}
}
.orderMoney {
width: calc(100% + 40px);
height: 80px;
// margin-left: -20px;
padding: 10px 0;
.orderMoneyItem {
width: 50%;
text-align: center;
margin-top: 5px;
span {
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
}
p {
font-size: 22px;
color: #00bf8a;
}
}
}
.filterList {
margin-bottom: 10px;
.label {
width: 80px;
text-align: center;
display: inline-block;
}
.filterListInput {
width: 60%;
margin-left: 15px;
margin-bottom: 10px;
}
.filterListDate {
width: 150px;
margin-bottom: 10px;
}
}
.email-gift-main-scroll {
width: 100%;
height: calc(100% - 200px);
overflow: auto;
overflow-x: hidden;
.orderDetails {
width: 100%;
height: auto;
margin-bottom: 10px;
position: relative;
.bridgeMain {
position: absolute;
top: 0px;
right: 0px;
width: 50px;
height: 50px;
.text {
font-size: 8px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #ff9d02;
transform: rotate(48deg);
z-index: 100;
position: absolute;
right: -6px;
top: 10px;
width: 50px;
text-align: center;
}
.bridge {
font-size: 50px;
position: absolute;
top: 0;
right: 0;
}
}
.orderDetailsTitle {
width: 100%;
height: auto;
background: #f9faff;
padding: 10px;
.iconStyle {
font-size: 18px;
cursor: pointer;
color: #00bf8a;
}
.money {
width: 100%;
height: auto;
margin-bottom: 12px;
margin-top: 4px;
.btns {
padding-right: 40px;
}
.btn {
background: #fff;
border-radius: 4px;
padding: 2px 5px;
margin-left: 10px;
font-size: 12px;
border: 1px solid rgba(0, 0, 0, 0.15);
color: #333333;
cursor: pointer;
}
.btnnot {
background: #ffdddd;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #f56c6c;
border: none;
}
.btnsuccess {
background: #e1fff0;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #00bf8a;
border: none;
}
}
.text {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 26px;
margin-right: 10px;
label {
color: #999999;
}
}
}
.orderDetailsList {
width: 100%;
height: auto;
background: #f9faff;
padding: 5px 0;
position: relative;
.text {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 20px;
label {
color: #999999;
}
}
}
}
}
}
.tabStyle {
::v-deep .el-tabs__item {
padding: 0 10px;
}
}
.email-gift-main-scroll {
::v-deep .el-tabs__item {
line-height: 26px;
font-size: 16px;
font-weight: 500;
}
::v-deep .el-collapse {
border: none;
}
::v-deep .el-collapse-item__header {
border: none;
}
::v-deep .el-collapse-item__header {
width: 100%;
height: 44px;
color: #333333;
padding-left: 66px;
font-size: 14px;
font-weight: 400;
/* 单行显示省略号 */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
::v-deep .el-collapse-item__wrap {
border: none;
}
}
.inputItem {
margin-bottom: 10px;
}
}
.contentConfirmItem {
width: 100%;
height: auto;
background: #f9faff;
margin-top: 10px;
.title {
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 20px;
}
.info {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
margin-top: 10px;
}
}
.expendIcon {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
text-align: center;
margin-top: 20px;
}
.dialog-footer {
width: calc(100% - 20px);
height: 52px;
position: absolute;
right: 20px;
bottom: 20px;
padding-top: 20px;
border-top: 1px solid rgba(0, 0, 0, 0.06);
justify-content: flex-end;
.btn {
width: 84px;
height: 32px;
}
}
.allIcon {
width: 137px;
height: 20px;
background: #f2ac51;
border-radius: 13px;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 80px;
}
</style>
\ No newline at end of file
<template>
<!-- 单日累充 分 积分开和积分关两种情况 -->
<el-drawer :lock-scroll="true" :title="title" :visible="show" size="540px" :modal="false" :modal-append-to-body="false" class="giftDetails" @close="close">
<div class="content">
<div class="giftDetailsText">
<div class="activeItem rowFlex">
<div class="activeLabel">活动名称</div>
<div class="activeValue">{{ activeInfo.title_name }}</div>
</div>
<div class="activeItem rowFlex">
<div class="activeLabel">活动类型</div>
<div class="activeValue">{{ activeInfo.gift_type_text }}</div>
</div>
<div class="activeItem rowFlex">
<div class="activeLabel">活动详情</div>
<div class="activeValue">{{ activeInfo.describe }}</div>
</div>
<div v-if="activeInfo.start_date" class="activeItem rowFlex">
<div class="activeLabel">活动时间</div>
<div class="activeValue">{{ activeInfo.start_date + '至' + activeInfo.end_date }}</div>
</div>
<div v-if="activeInfo.recharge_start_date && activeInfo.recharge_start_date!== null" class="activeItem rowFlex">
<div class="activeLabel">充值时间</div>
<div class="activeValue">{{ activeInfo.recharge_start_date + '至' + activeInfo.recharge_end_date }}</div>
</div>
<!-- 选择的时候重新请求活动详情接口 -->
<div class="activeItem rowFlex">
<div class="activeLabel">充值日期</div>
<el-date-picker v-model="recharge_date_time" :default-value="activeInfo.recharge_date" style="width: 210px" type="date" value-format="yyyy-MM-dd" :picker-options="activeInfo.pickerOptions " @change="dateChange"> </el-date-picker>
</div>
<div class="activeItem rowFlex">
<div class="activeLabel">申请角色</div>
<div class="activeValue">{{ activeInfo.role_info.label }}</div>
</div>
<div class="rowFlex">
<div class="activeItem rowFlex">
<div class="activeLabel" style="width: auto">充值积分</div>
<div class="activeValue" style="width: auto">{{ giftInfo.total_recharge }}</div>
</div>
<div class="activeItem rowFlex">
<div class="activeLabel" style="width: auto">剩余积分</div>
<div class="activeValue" style="width: auto">{{ giftInfo.real_score }}</div>
</div>
</div>
</div>
<div class="activeList">
<div v-for="(item,index) in giftInfo.rule.level_attribute" :key="index">
<div class="activeListItem">
<div class="activeListItemTitle rowFlex spaceBetween columnCenter">
<p class="title">{{ item.prize_level_name }}</p>
<div class="rowFlex handle columnCenter">
<p>{{ item.compare_amount + '积分' }}</p>
<el-input-number
v-model="item.apply_num"
class="inputNumber"
size="mini"
:max="activeInfo.exchange_score_status == 2 ? 1 : 999"
:min="0"
@change="packNumChange(index)"
></el-input-number>
<i v-if="!item.showContent" class="el-icon-arrow-down icon" @click="openPrizeItem(item,index,true)"></i>
<i v-else class="el-icon-arrow-right icon" @click="openPrizeItem(item,index,false)"></i>
</div>
</div>
<el-collapse-transition>
<div v-if="!item.showContent" class="activeListItemContent">
<div v-if="item.prize_default.length>0" class="activeListItemTitle">
<div class="title">固定奖 * {{ item.apply_num ? item.apply_num : 0 }}</div>
<div class="handle">
<div
v-for="(trem, mark) in item.prize_default"
:key="mark"
>
{{ trem.name }}
{{ trem.id }}
</div>
</div>
</div>
<div v-if="item.prize_auto.length > 0" class="activeListItemTitle">
<div class="title">自选奖 ({{ item.prize_auto.length + '选' + item.prize_auto_num }} ) * {{ item.apply_num ? item.apply_num : 0 * item.prize_auto_num }}</div>
</div>
<!-- 自选奖 -->
<div v-for="(trem, mark) in item.prize_auto" :key="mark" class="activeListItemTitle rowFlex spaceBetween columnCenter">
<div>
<div
v-for="(entry, sign) in trem.group"
:key="sign"
>
<div>
{{ entry.name }}
</div>
</div>
</div>
<div class="rowFlex handle columnCenter" style="margin-right:23px;">
<el-input-number
v-model="trem.apply_num"
size="mini"
:max="item.exchange_score_status == 2 ? 1 : item.residuePackNum || item.residuePackNum === 0 ? item.residuePackNum + trem.apply_num : 0"
:min="0"
@change="packAutoNumChange(index, trem)"
></el-input-number>
</div>
</div>
<div
v-if="activeInfo.exchange_score_status == 1"
class="consumption-points rowFlex allCenter"
>消耗:{{ item.compare_amount * item.apply_num }}积分</div>
</div>
</el-collapse-transition>
</div>
<div class="allIcon rowFlex allCenter">合计:{{ allpoints }} 积分</div>
</div>
<div class="activeItem rowFlex" style="margin-top:20px;">
<div class="activeLabel" style="text-align:right;">备注</div>
<div class="activeValue">
<el-input v-model="remark" type="textarea" maxlength="150" style="width:90%;" placeholder="请输入备注"></el-input>
</div>
</div>
</div>
<span class="dialog-footer rowFlex">
<el-button :disabled="requestLoading" class="btn" type="primary" @click="submit">确 定</el-button>
<el-button class="btn" @click="close">取 消</el-button>
</span>
<!-- 确认弹窗 -->
<confirmLayer v-if="showConfirmLayer" :remark="remark" :active-info="[activeInfo]" :show.sync="showConfirmLayer" title="请核对申请奖品信息" @close="close" />
</div>
</el-drawer>
</template>
<script type="text/javascript">
import { giftBagApply } from '@/api/game'
import { mapState, mapMutations, mapActions } from 'vuex'
import confirmLayer from '../confirmLayer'
export default {
// type 3:image 4:video
components: {
confirmLayer
},
props: ['show', 'width', 'title', 'info', 'body', 'giftInfo', 'activeInfo', 'changeDate','requestLoading'],
data() {
return {
remark: '',
pickerOptions: {
disabledDate: (item) => {
return new Date(this.activeInfo.min_date).getTime() - 24 * 3600 * 1000 > item.getTime() || item.getTime() > new Date(this.activeInfo.max_date).getTime()
}
},
recharge_date_time: '',
num: '',
allpoints: 0,
showContent: true,
showConfirmLayer: false
}
},
watch: {
show(newVal, oldVal) {
if (newVal) {
this.ruleForm = this.activeInfo
this.recharge_date_time = this.activeInfo.recharge_date
this.$forceUpdate()
}
},
changeDate(newVal, oldVa) {
if (newVal) {
this.recharge_date_time = this.activeInfo.recharge_date
}
}
},
mounted() {
this.recharge_date_time = this.activeInfo.recharge_date
},
methods: {
close() {
this.$emit('update:show', false)
},
dateChange(value) {
console.log(value)
if (value) {
this.$emit('changeDateResult', value)
this.$emit('giftDetailsInfo', value)
}
},
openPrizeItem(item, index, value) {
console.log(item, index, value)
this.$set(this.giftInfo.rule.level_attribute[index], 'showContent', value)
this.$forceUpdate()
},
packAutoNumChange(index) {
// 总共要选择的奖项
let num = this.giftInfo.rule.level_attribute[index].prize_auto_num * this.giftInfo.rule.level_attribute[index].apply_num
this.giftInfo.rule.level_attribute[index].prize_auto.forEach((item) => {
num = num - (item.apply_num ? item.apply_num : 0)
})
this.giftInfo.rule.level_attribute[index].residuePackNum = num
},
packNumChange(index) {
if (this.giftInfo.rule.level_attribute[index].apply_num == 0 && this.giftInfo.rule.level_attribute[index].prize_auto?.length > 0) {
this.giftInfo.rule.level_attribute[index].prize_auto.map(item => {
item.apply_num = 0
})
}
const num = this.giftInfo.rule.level_attribute[index].prize_auto_num * this.giftInfo.rule.level_attribute[index].apply_num
this.$set(this.giftInfo.rule.level_attribute[index], 'residuePackNum', num)
let points = 0
this.giftInfo.rule.level_attribute.forEach((item) => {
points += item.apply_num * item.compare_amount
})
this.allpoints = points
},
submit() {
if (this.allpoints > this.giftInfo.real_score) {
this.$message.warning('剩余积分不足')
return
}
if (this.giftInfo.rule.level_attribute.length === 0) {
this.$message.warning('暂无可领取的礼包')
return
}
const list = this.giftInfo.rule.level_attribute.filter(item => {
const prizeNum = item.prize_auto_num * item.apply_num // 所有的奖品数量
let checkPrizeNum = 0// 选中的奖品数量
if (item.prize_auto.length > 0) {
item.prize_auto.map(items => {
checkPrizeNum += items.apply_num
})
return checkPrizeNum < prizeNum
} else {
return false
}
})
console.log(list)
if (list.length > 0) {
this.$message.warning('请选择对应数量的自选奖')
return false
}
this.showConfirmLayer = true
this.activeInfo.type_details = this.giftInfo
}
}
}
</script>
<style lang="scss" scoped>
.giftDetails {
position: fixed;
right: 450px;
top: 0;
box-shadow: 0px 9px 28px 0px rgba(0, 0, 0, 0.05);
.icon{
font-size:14px;
cursor: pointer;
margin-left: 10px;
}
.content {
padding: 0 20px;
width: 100%;
height: calc(100% - 100px);
overflow: auto;
.activeItem {
width: 100%;
height: auto;
margin-bottom: 10px;
.activeLabel {
width: 60px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
line-height: 20px;
margin-right: 10px;
}
.activeValue {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 20px;
text-align: left;
display: flex;
flex: 1;
}
}
.activeList{
width: 100%;
height:auto;
.activeListItem{
width: 100%;
height: auto;
background: #F9FAFF;
border-radius: 5px;
padding: 10px;
margin-top: 20px;
.title{
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
color: #333333;
line-height: 20px;
max-width: 50%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.handle{
p{
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
color: #333333;
margin-right: 10px;
}
}
.inputNumber{
width: 130px;
}
}
.activeListItemTitle,.contentItem{
line-height: 30px;
margin-bottom: 10px;
}
.activeListItemContent{
width: 100%;
height: auto;
.title{
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: bold;
color: #333333;
}
.infoText{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
margin-top: 5px;
}
.expendIcon{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
text-align: center;
margin-top:20px;
}
}
}
}
}
.allIcon{
width: 137px;
height: 20px;
background: #F2AC51;
border-radius: 13px;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 100px;
}
.consumption-point{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
}
</style>
<template>
<!-- 角色累充 -->
<el-drawer :lock-scroll="true" :title="title" :visible="show" size="540px" :modal="false" :modal-append-to-body="false" class="giftDetails" @close="close">
<div class="content">
<div v-for="(item,index) in activeInfo" :key="index" class="list">
<div class="giftDetailsText">
<div class="activeItem rowFlex">
<div class="activeLabel">活动名称</div>
<div class="activeValue">{{ item.title_name }}</div>
</div>
<div class="activeItem rowFlex">
<div class="activeLabel">活动类型</div>
<div class="activeValue">{{ item.gift_type_text }}</div>
</div>
<div class="activeItem rowFlex">
<div class="activeLabel">活动详情</div>
<div class="activeValue">{{ item.describe }}</div>
</div>
<div v-if="item.start_date && item.end_date" class="activeItem rowFlex">
<div class="activeLabel">活动时间</div>
<div class="activeValue">{{ item.start_date + '至' + item.end_date }}</div>
</div>
<div class="activeItem rowFlex">
<div class="activeValue">{{ item.payment_method_text }}</div>
</div>
<div v-if="item.type_details.total_recharge" class="activeItem rowFlex">
<div class="activeLabel">充值金额</div>
<div class="activeValue">{{ item.type_details.total_recharge }}</div>
</div>
<div class="activeItem rowFlex">
<div class="activeLabel">申请角色</div>
<div class="activeValue">{{ item.role_info.label || '' }}</div>
</div>
<!-- 充值积分才有 -->
</div>
<!-- 角色累充 level_attribute 档位 每个档位下面有 固定奖 和 自选奖 -->
<div v-for="(items,indexs) in item.type_details.rule.level_attribute" :key="indexs" class="activeList">
<div v-for="(k,j) in items.prize_default" :key="j" class="level_attribute_item">
<div class="activeListItemContent rowFlex">
<div class="rowFlex spaceBetween">
<div class="title">ID:{{ k.prize_id }} </div>
<div class="handle" style="margin-left:50px;">{{ k.name }}</div>
</div>
</div>
</div>
</div>
</div>
<div class="activeItem rowFlex" style="margin-top:20px;">
<div class="activeLabel" style="text-align:right;">备注</div>
<div class="activeValue">
<el-input v-model="remark" type="textarea" maxlength="150" style="width:90%;" placeholder="请输入备注"></el-input>
</div>
</div>
<span class="dialog-footer rowFlex">
<el-button class="btn" :disabled="requestLoading" type="primary" :loading='btnLoading' @click="submit">确 定</el-button>
<el-button class="btn" @click="close">取 消</el-button>
</span>
<!-- 确认弹窗 -->
<confirmLayer :is-submit="isSubmit" :remark="remark" :active-info="activeInfo" :show.sync="showConfirmLayer" title="请核对申请奖品信息" @close="close" />
</div>
</el-drawer>
</template>
<script type="text/javascript">
import { giftBagApply } from '@/api/game'
import confirmLayer from '../confirmLayer'
import { mapState } from 'vuex'
export default {
// type 3:image 4:video
components: {
confirmLayer
},
props: ['show', 'width', 'title', 'info', 'body', 'giftInfo', 'activeInfo','requestLoading'],
data() {
return {
isSubmit: false,
btnLoading:false,
remark: '',
loading: false,
showConfirmLayer: false
}
},
computed: {
...mapState('user', ['cser_name'])
},
watch: {
show(newVal, oldVal) {
if (newVal) {
// this.ruleForm = this.activeInfo
// this.recharge_date = this.activeInfo.start_date
}
}
},
mounted() {},
methods: {
close() {
this.$emit('update:show', false)
},
dateChange() {
},
handleChange() {
},
submit() {
this.btnLoading = true
const role_id = this.activeInfo[0].role_info.value
const rule = this.activeInfo.map(item => {
let level_attribute = []
if (item.type_details.rule.gift_type == 1 || item.type_details.rule.gift_type == 4 || item.type_details.rule.gift_type == 5) {
level_attribute = item.type_details.rule.level_attribute
} else {
level_attribute = item.type_details.rule.level_attribute.filter(item => item.apply_num > 0)
}
return { level_attribute: level_attribute, id: item.id }
})
this.loading = true
const data = {
role_id,
remark: this.remark,
recharge_date: this.activeInfo[0].recharge_date || '',
create_user: this.cser_name,
rule: rule
}
giftBagApply(data).then(res => {
this.loading = false
this.btnLoading =false
if (res.status_code === 1) {
this.$message.success(res.msg)
this.close()
this.$emit('close')
} else {
this.close()
}
}, err => {
this.loading = false
this.btnLoading =false
})
}
}
}
</script>
<style lang="scss" scoped>
.giftDetails {
position: fixed;
right: 450px;
top: 0;
box-shadow: 0px 9px 28px 0px rgba(0, 0, 0, 0.05);
.icon{
font-size:14px;
cursor: pointer;
margin-left: 10px;
}
.content {
padding: 0 20px;
width: 100%;
height: calc(100% - 100px);
overflow: auto;
.list{
border-bottom: 1px solid #E8E8E8;
padding: 20px 0;
}
.activeItem {
width: 100%;
height: auto;
margin-bottom: 10px;
.activeLabel {
width: 60px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
line-height: 20px;
margin-right: 10px;
}
.activeValue {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 20px;
text-align: left;
display: flex;
flex: 1;
}
}
.activeList{
width: 100%;
height:auto;
.activeListItem{
width: 100%;
height: auto;
background: #F9FAFF;
border-radius: 5px;
padding: 10px;
margin-top: 20px;
.title{
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
color: #333333;
line-height: 20px;
max-width: 50%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.handle{
p{
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
color: #333333;
margin-right: 10px;
}
}
.inputNumber{
width: 130px;
}
}
.activeListItemTitle,.contentItem{
line-height: 30px;
}
.activeListItemContent{
width: 100%;
height: auto;
.title{
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
color: #333333;
}
.infoText{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
margin-top: 5px;
}
.expendIcon{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
text-align: center;
margin-top:20px;
}
}
}
}
}
.allIcon{
width: 137px;
height: 20px;
background: #F2AC51;
border-radius: 13px;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 80px;
}
.remark{
margin-top:20px;
}
</style>
<template>
<!-- 角色时间段累充 和单日累充的积分关的情况 exchange_score_status 2 关 1 开 -->
<el-drawer :lock-scroll="true"
:title="title"
:visible="show"
size="540px"
:modal="false"
:modal-append-to-body="false"
class="giftDetails"
@close="close"
>
<div
v-if="activeInfo.title_name"
class="content"
>
<div class="giftDetailsText">
<div class="activeItem rowFlex">
<div class="activeLabel">活动名称</div>
<div class="activeValue">{{ activeInfo.title_name }}</div>
</div>
<div class="activeItem rowFlex">
<div class="activeLabel">活动类型</div>
<div class="activeValue">{{ activeInfo.gift_type_text }}</div>
</div>
<div class="activeItem rowFlex">
<div class="activeLabel">活动详情</div>
<div class="activeValue">{{ activeInfo.describe }}</div>
</div>
<div
v-if="activeInfo.start_date"
class="activeItem rowFlex"
>
<div class="activeLabel">活动时间</div>
<div class="activeValue">{{ activeInfo.start_date + '至' + activeInfo.end_date }}</div>
</div>
<div
v-if="activeInfo.recharge_start_date "
class="activeItem rowFlex"
>
<div class="activeLabel">充值时间</div>
<div class="activeValue">{{ activeInfo.recharge_start_date + '至' + activeInfo.recharge_end_date }}</div>
</div>
<!-- 选择的时候重新请求活动详情接口 -->
<div
v-if="activeInfo.gift_type==3"
class="activeItem rowFlex"
>
<div class="activeLabel">充值日期</div>
<el-date-picker
v-model="recharge_date_time"
:default-value="activeInfo.recharge_date"
style="width: 210px"
type="date"
value-format="yyyy-MM-dd"
:picker-options="pickerOptions"
@change="dateChange"
> </el-date-picker>
</div>
<div class="activeItem rowFlex">
<div class="activeLabel">申请角色</div>
<div
v-if="activeInfo.role_info"
class="activeValue"
>{{ activeInfo.role_info.label }}</div>
</div>
<!-- 积分关的情况 -->
<div
v-if="activeInfo.gift_type == 2"
class="activeItem rowFlex"
>
<div class="activeLabel">充值金额</div>
<div
v-if="activeInfo.role_info"
class="activeValue"
>{{ giftInfo.total_recharge }}</div>
</div>
<div
v-else-if="activeInfo.gift_type == 3"
class="rowFlex"
>
<!-- 无积分 -->
<div
v-if="activeInfo.exchange_score_status == 2"
class="activeItem rowFlex"
>
<div class="activeLabel">充值金额</div>
<div
v-if="activeInfo.role_info"
class="activeValue"
>{{ giftInfo.total_recharge }}</div>
</div>
<!-- 有积分 -->
<div v-else>
<div class="activeItem rowFlex">
<div
class="activeLabel"
style="width: auto"
>充值积分</div>
<div
class="activeValue"
style="width: auto"
>{{ giftInfo.total_recharge }}</div>
</div>
<div class="activeItem rowFlex">
<div
class="activeLabel"
style="width: auto"
>剩余积分</div>
<div
class="activeValue"
style="width: auto"
>{{ giftInfo.real_score }}</div>
</div>
</div>
</div>
</div>
<div class="details">
<div v-if="giftInfo.rule && giftInfo.rule.level_attribute">
<div
v-for="(it, i) in giftInfo.rule.level_attribute"
:key="i"
>
<div
v-if="show_level_attribute(it)"
class="pack-item"
>
<div class="pack-name rowFlex spaceBetween">
<div class="pack-name-left">{{ it.prize_level_name }}</div>
<div class="pack-name-right">
<div class="pack-integral">
{{ giftInfo.rule.compare_type == 1 ? it.compare_amount + '金额' : it.min_amount + `~` +it.max_amount + '金额' }}
</div>
<i
v-if="!it.showContent"
class="el-icon-arrow-down icon"
@click="openPrizeItem(it,i,true)"
></i>
<i
v-else
class="el-icon-arrow-right icon"
@click="openPrizeItem(it,i,false)"
></i>
</div>
</div>
<el-collapse-transition>
<div
v-if="!it.showContent"
class="pack-content"
>
<div
v-if="it.prize_default.length>0"
class="pack-default"
>
<!-- * {{ it.apply_num ? it.apply_num : 0 }} -->
<div style="font-weight:bold;"> 固定奖 </div>
<div
v-for="(trem, mark) in it.prize_default"
:key="mark"
>
{{ trem.name }}
</div>
</div>
<div
v-if="it.prize_auto.length > 0"
class="pack-auto"
>
<!-- * {{ it.apply_num ? it.apply_num : 0 * it.prize_auto_num }} -->
<div style="font-weight:bold;">自选奖 ( {{ it.prize_auto.length + '选' + it.prize_auto_num }}<span v-if="activeInfo.exchange_score_status == 1"></span></div>
<div
v-for="(trem, mark) in it.prize_auto"
:key="mark"
class="pack-auto-item"
>
<div style="display: flex;align-items: center;">
<div
v-if="activeInfo.exchange_score_status == 2"
style="margin-right: 20px;"
>
<el-checkbox
v-model="trem.default_type"
:disabled="it.residuePackNum >= it.prize_auto_num && !trem.default_type"
@change="onCheckboxDefaultType(i)"
></el-checkbox>
</div>
<div>
<div
v-for="(entry, sign) in trem.group"
:key="sign"
>
<div class="pack-default_name ">
{{ entry.name }}
</div>
</div>
</div>
</div>
</div>
</div>
<div
v-if="activeInfo.gift_type == 3 && activeInfo.exchange_score_status == 1"
class="consumption-points"
>消耗:{{ it.compare_amount * it.apply_num }}积分</div>
</div>
</el-collapse-transition>
</div>
</div>
</div>
</div>
<div v-if="activeInfo.gift_type == 3 && activeInfo.exchange_score_status == 1">合计:{{ allpoints }}</div>
<div class="activeItem rowFlex spaceBetween">
<div
class="activeLabel"
style="text-align:right;"
>备注</div>
<div class="activeValue">
<el-input
v-model="remark"
type="textarea"
maxlength="150"
style="width:100%;"
placeholder="请输入备注"
></el-input>
</div>
</div>
<span class="dialog-footer rowFlex">
<el-button
class="btn"
type="primary"
:disabled="requestLoading"
@click="submit"
:loading="btnLoading"
>确 定</el-button>
<el-button
class="btn"
@click="close"
>取 消</el-button>
</span>
<!-- 确认弹窗 -->
<confirmLayer
v-if="showConfirmLayer"
:remark="remark"
:active-info="[activeInfo]"
:show.sync="showConfirmLayer"
title="请核对申请奖品信息"
@close="close"
/>
</div>
</el-drawer>
</template>
<script type="text/javascript">
import { giftBagApply, checkRoleReceivedBag } from '@/api/game'
import { mapState, mapMutations, mapActions } from 'vuex'
import confirmLayer from '../confirmLayer'
export default {
// type 3:image 4:video
components: {
confirmLayer
},
props: ['show', 'width', 'title', 'info', 'body', 'giftInfo', 'activeInfo', 'changeDate','requestLoading'],
data() {
return {
remark: '',
recharge_date: '',
checkGiftList: [], // 选中的奖品
pickerOptions: {
disabledDate: (item) => {
return item.getTime() < new Date(this.activeInfo.min_date).getTime() - 24 * 3600 * 1000 || item.getTime() > new Date(this.activeInfo.max_date).getTime()
}
},
num: '',
recharge_date_time: '',
btnLoading:false,
allpoints: 0,
showContent: true,
showConfirmLayer: false
}
},
watch: {
show(newVal, oldVal) {
if (newVal) {
this.ruleForm = this.activeInfo
this.recharge_date_time = this.activeInfo.recharge_date
}
},
changeDate(newVal, oldVa) {
if (newVal) {
this.recharge_date_time = this.activeInfo.recharge_date
}
},
giftInfo(newVal, oldVal) {
if (newVal) {
this.handleGiftInfo(newVal)
}
}
},
mounted() {
this.recharge_date_time = this.activeInfo.recharge_date
this.$nextTick(() => {
this.handleGiftInfo(this.giftInfo)
})
},
methods: {
handleGiftInfo(newVal) {
if (newVal?.rule?.level_attribute) {
newVal.rule.level_attribute.forEach((item, i) => {
this.allpoints += item.compare_amount
newVal.rule.level_attribute[i].apply_num = 1
newVal.rule.level_attribute[i].residuePackNum = 0
newVal.rule.level_attribute[i].prize_auto.forEach((it, idx) => {
if (it.default_type) {
newVal.rule.level_attribute[i].residuePackNum += 1
newVal.rule.level_attribute[i].prize_auto[idx].apply_num = 1
}
})
})
}
},
onCheckboxDefaultType(i) {
this.giftInfo.rule.level_attribute[i].residuePackNum = 0
this.giftInfo.rule.level_attribute[i].prize_auto.forEach((item, index) => {
if (item.default_type) {
this.giftInfo.rule.level_attribute[i].prize_auto[index].apply_num = 1
console.log(this.giftInfo.rule.level_attribute[i].residuePackNum)
this.giftInfo.rule.level_attribute[i].residuePackNum += 1
} else {
this.giftInfo.rule.level_attribute[i].prize_auto[index].apply_num = 0
}
})
},
openPrizeItem(item, index, value) {
console.log(item, index, value)
this.$set(this.giftInfo.rule.level_attribute[index], 'showContent', value)
this.$forceUpdate()
},
show_level_attribute(it) {
if (this.giftInfo.rule.compare_type == 1 && Number(it.compare_amount) <= Number(this.giftInfo.total_recharge)) {
return true
} else if (this.giftInfo.rule.compare_type == 2 && Number(it.min_amount) <= Number(this.giftInfo.total_recharge) && Number(this.giftInfo.total_recharge) <= Number(it.max_amount)) {
return true
} else {
return false
}
},
packAutoNumChange(index) {
let num = this.giftInfo.rule.level_attribute[index].prize_auto_num * this.giftInfo.rule.level_attribute[index].apply_num
console.log(num)
this.giftInfo.rule.level_attribute[index].prize_auto.forEach((item) => {
console.log(item)
num = num - (item.apply_num ? item.apply_num : 0)
})
this.giftInfo.rule.level_attribute[index].residuePackNum = num
},
packNumChange(index) {
const num = this.giftInfo.rule.level_attribute[index].prize_auto_num * this.giftInfo.rule.level_attribute[index].apply_num
this.$set(this.giftInfo.rule.level_attribute[index], 'residuePackNum', num)
let points = 0
this.giftInfo.rule.level_attribute.forEach((item) => {
points += item.apply_num * item.compare_amount
})
this.allpoints = points
},
close() {
this.$emit('update:show', false)
},
dateChange(value) {
console.log(value)
if (value) {
this.$emit('changeDateResult', value)
this.$emit('giftDetailsInfo', value)
}
},
changeGiftItemValue(item, $event) {
item.isCheck = $event
},
handleChange() {
},
async submit() {
this.btnLoading = true
const data = {
role_id: this.giftInfo.role_id,
rule_id: this.activeInfo.id
}
try {
const res = await checkRoleReceivedBag(data)
this.btnLoading = false
if (res.status_code === 1 && res.data && res.data.id) {
this.$confirm('当前角色申请过选中礼包确认要再次申请吗?', '确认提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(res => {
this.showConfirmLayer = true
this.activeInfo.type_details = this.giftInfo
})
.catch(() => {
this.$message({
type: 'info',
message: '已取消'
})
})
} else {
this.showConfirmLayer = true
this.activeInfo.type_details = this.giftInfo
}
} catch (error) {
this.btnLoading = false
this.showConfirmLayer = true
this.activeInfo.type_details = this.giftInfo
} finally{
this.btnLoading = false
this.showConfirmLayer = true
this.activeInfo.type_details = this.giftInfo
}
}
}
}
</script>
<style lang="scss" scoped>
.giftDetails {
position: fixed;
right: 450px;
top: 0;
box-shadow: 0px 9px 28px 0px rgba(0, 0, 0, 0.05);
.icon {
font-size: 14px;
cursor: pointer;
margin-left: 10px;
}
.content {
padding: 0 20px;
width: 100%;
height: calc(100% - 100px);
overflow: auto;
.activeItem {
width: 100%;
height: auto;
margin-bottom: 10px;
.activeLabel {
width: 60px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
line-height: 20px;
margin-right: 10px;
}
.activeValue {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 20px;
text-align: left;
display: flex;
flex: 1;
}
}
.activeList {
width: 100%;
.activeListItem {
width: 100%;
background: #f9faff;
border-radius: 5px;
padding: 10px;
margin-top: 20px;
.title {
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
color: #333333;
line-height: 20px;
max-width: 50%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.handle {
p {
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
color: #333333;
margin-right: 10px;
}
}
.inputNumber {
width: 130px;
}
}
.activeListItemTitle,
.contentItem {
line-height: 30px;
}
.activeListItemContent {
width: 100%;
height: auto;
.title {
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 600;
color: #333333;
}
.infoText {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
margin-top: 5px;
}
.expendIcon {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
text-align: center;
margin-top: 20px;
}
}
}
}
}
.allIcon {
width: 137px;
height: 20px;
background: #f2ac51;
border-radius: 13px;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 80px;
}
.pack-item {
margin-bottom: 12px;
background: #f9faff;
padding: 12px;
.pack-name {
width: 100%;
display: flex;
justify-content: space-between;
.pack-name-left {
font-weight: 600;
width: 180px;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
}
.pack-name-right {
justify-content: space-between;
display: flex;
align-items: center;
.pack-integral {
width: 100px;
}
}
}
.pack-auto-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 5px 0;
}
}
.items {
width: 100%;
display: flex;
padding-bottom: 10px;
.title {
width: 110px;
flex-shrink: 0;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
line-height: 20px;
}
}
.recharge {
display: flex;
}
.pack-default {
div {
line-height: 25px;
}
}
.pack-name {
div {
line-height: 25px;
}
}
.pack-auto {
div {
line-height: 25px;
}
}
</style>
<template>
<div v-loading="loading" class="wx-gift-container">
<div ref="giftList" class="gift-list" @scroll="handleScroll">
<div v-for="item in giftList" :key="item._id" class="gift-item">
<div class="gift-info">
<div class="rowFlex spaceBetween columnCenter">
<div class="gift-name hidden">{{ item.gift_package_name }}</div>
<div class="gift-time">{{ item.send_time }}</div>
</div>
<div class="gift-code">
<span class="giftCodeText">{{ item.code }}</span>
</div>
<div class="rowFlex spaceBetween columnCenter gift-sender">
<div>发送客服:{{ item.cser_name }}</div>
<i class="el-icon-document-copy" style="cursor: pointer;" @click="handleCopy(item.code)"></i>
</div>
</div>
</div>
<div v-if="loading" class="loading-more">加载中...</div>
<div v-if="!hasMore && giftList.length > 0" class="no-more">没有更多数据了</div>
<div v-if="giftList.length == 0" class="noContent rowFlex allCenter">
<noContent/>
</div>
</div>
</div>
</template>
<script>
import Clipboard from 'clipboard'
import { getSendingCodeList } from '@/api/works'
import { debounce,copyText } from '@/utils/index'
import { mapState } from 'vuex'
export default {
name: 'WxGift',
data() {
return {
loading: false,
giftList: [],
page: 1,
pageSize: 20,
hasMore: true
}
},
computed: {
...mapState('game', ['chatUserInfo'])
},
created() {
console.log(this.chatUserInfo, 'chatUserInfo')
this.fetchGiftList()
},
methods: {
async fetchGiftList() {
if (this.loading || !this.hasMore) return
this.loading = true
try {
const params = {
page: this.page,
page_size: this.pageSize,
corp_id: this.chatUserInfo.corp_id,
userid: this.chatUserInfo.userid || this.chatUserInfo.user.userid,
external_userid: this.chatUserInfo.external_userid || this.chatUserInfo.external_user.external_userid
}
const res = await getSendingCodeList(params)
if (res.data && res.data.data) {
this.giftList = this.page === 1 ? res.data.data : [...this.giftList, ...res.data.data]
this.hasMore = res.data.data.length === this.pageSize
this.page++
}
} catch (error) {
console.error('获取礼包列表失败:', error)
} finally {
this.loading = false
}
},
handleScroll: debounce(function(e) {
const { scrollHeight, scrollTop, clientHeight } = e.target
if (scrollHeight - scrollTop - clientHeight < 50) {
this.fetchGiftList()
}
}, 500),
handleCopy(code) {
copyText('giftCodeText', this)
// const clipboard = new Clipboard('.')
// clipboard.on('success', e => {
// this.$message.success('复制成功')
// // 释放内存
// clipboard.destroy()
// })
}
}
}
</script>
<style lang="scss" scoped>
.wx-gift-container {
height: calc(100vh - 160px);
width: 100%;
background-color: #fff;
.gift-list {
height: 100%;
overflow-y: auto;
padding: 10px;
.gift-item {
padding: 16px;
background: #F7F8FA;
border-radius: 12px;
border: 1px solid #E5E6EB;
margin-bottom:12px;
.gift-info {
.gift-name {
font-weight: 400;
font-size: 14px;
color: #4E5969;
text-align: left;
font-style: normal;
width: calc(100% - 180px);
}
.gift-time {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 14px;
color: #4E5969;
text-align: left;
font-style: normal;
width: 150px;
}
.gift-code {
display: flex;
align-items: center;
justify-content: space-between;
border-radius: 4px;
font-family: PingFangSC, PingFang SC;
font-weight: 500;
font-size: 14px;
color: #323335;
text-align: justify;
font-style: normal;
margin: 10px 0;
span {
color: #323335;
font-size: 14px;
font-family: PingFangSC-Medium;
}
.el-button {
padding: 5px 12px;
border: 1px solid #dcdfe6;
border-radius: 4px;
font-size: 13px;
color: #606266;
&:hover {
color: #409eff;
border-color: #c6e2ff;
background-color: #ecf5ff;
}
}
}
.gift-sender {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: #4E5969;
line-height: 18px;
text-align: justify;
font-style: normal;
i{
color: #00BF8A;
font-size: 14px;
}
}
}
}
.loading-more,
.no-more,
.empty-data {
text-align: center;
padding: 16px;
color: #999999;
font-size: 13px;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="AiLibrary">
<div class="aiSelect rowFlex columnCenter">
<p
class="label"
style="margin-right:10px;"
>选择应用</p>
<el-select
v-model="selectAiApp"
style="width:70%;"
placeholder="请选择"
:clearable="false"
:disabled="!userInfo.operation_auth['game-work-aichat']"
>
<el-option
v-for="item in aiAppList"
:key="item._id"
:label="item.name"
:value="item._id"
>
</el-option>
</el-select>
</div>
<div class="AiChatList">
<div
ref="ai-box"
v-debounce="paperScroll"
v-loadingChat="loading"
class="msg-box columnFlex flex1"
>
<div>
<div
v-if="!isHistory"
class="rowFlex rowCenter linkStyle"
>
<div class="rowFlex columnCenter">
<div class="line"></div>
<svg-icon
icon-class="start"
style="margin-left:5px;"
/>
</div>
<el-link
type="primary"
class="moreLink"
@click="Aihistory"
>加载更多问答记录</el-link>
<div class="rowFlex columnCenter">
<svg-icon icon-class="start" />
<div class="line"></div>
</div>
</div>
<div
v-for="(i,index) in recordMessage"
:key="i._id"
class="item"
>
<div class="msgBoxItem">
<div
v-if=" i._id && i.message"
class="msg rowFlex columnCenter"
:style="i.send_type==1?'flex-direction:row-reverse':''"
>
<div class="columnFlex userHead">
<div class="user-head columnFlex">
<el-image
class="image"
fit="contain"
:src="i.send_type==2?i.from.robot.avatar: i.from.cser.avatar"
></el-image>
</div>
</div>
<div
class="user-msg columnFlex"
:style="i.send_type == 1 ? 'margin-right:10px;' : 'margin-left:10px;'"
>
<p
class="time"
:style="i.send_type == 1 ? 'text-align: right;' : ' '"
>
{{ i.create_time }}
<el-popover
v-if="i.request_id && i.is_used_knowledge==1"
placement="right"
width="400"
trigger="click"
>
<div
class="comeIngText"
style="max-height:500px;overflow:auto"
>
<p
v-for="(item,index) in i.doc_references"
:key="index"
style="margin-bottom:15px;"
>
<span style="color:#000;font-weight:bold">来源{{ index+1 }}:</span> {{ item }}
</p>
</div>
<el-button
slot="reference"
type="text"
@click.stop="rqeustSource(i,index)"
>回答来源</el-button>
</el-popover>
</p>
<!-- 文字 -->
<div
class="rowFlex resizeBtn chatItemBox"
:class="i.send_type == 1?'rowEnd':'rowStart'"
>
<!-- 客服发的消息 -->
<div
v-if="i.message.msgType == 'text'&& i.message.text && i.message.text.content && !i.loading"
class="chatItem"
:style="i.send_type == 1 ? 'float: right;' : ''"
:class="[i.send_type == 1 ? 'right' : 'left chatItemleft chatItemWidth']"
v-html="i.message.text.content.trim()"
></div>
<!-- 图片 -->
<div
v-else-if="i.message.msgType == 'image'&& i.message.image && i.message.image.picurl && !i.loading"
class="chatItem"
:style="i.send_type == 1 ? 'float: right;' : ''"
:class="[i.send_type == 1 ? 'right' : 'left chatItemleft chatItemWidth']"
>
<el-image
class="aiImage"
fit="contain"
:src="i.message.image.picurl"
@click="watchImage(i)"
></el-image>
</div>
<!-- 加在 loading -->
<div
v-else-if="i.loading"
class="chatItem"
:style="i.send_type == 1 ? 'float: right;' : ''"
:class="[i.send_type == 1 ? 'right' : 'left chatItemWidth']"
>
<div class="rowFlex allCenter chatItemLoading">
<svg-icon
icon-class="answer"
class="loadingRotage"
/>
<i class="loadingRotage"></i>
<p style="margin-left:5px;">答案整理中....</p>
</div>
</div>
<!-- 复制客户的消息 -->
<div
v-if="i.send_type == 2 && i.is_used_knowledge == 1 && !answerLoading "
class="likeBtn rowFlex "
>
<svg-icon
v-if="i.like_status == 0"
class="copy likeIcon"
icon-class="like"
@click.stop="likeAnswer(i,1,index)"
/>
<svg-icon
v-else-if="i.like_status == 1"
class="copy likeIcon"
icon-class="likeActive"
/>
<svg-icon
v-if="i.like_status == 0"
class="copy likeIcon"
icon-class="hate"
@click.stop="likeAnswer(i,2,index)"
/>
<svg-icon
v-else-if="i.like_status == 2"
class="copy likeIcon"
icon-class="hateActive"
/>
<svg-icon
v-if="i.message.msgType == 'text'"
class="copy copyIcon"
:data-clipboard-text="i.message.text.content"
icon-class="fuzhi"
@click="copyText(i,index)"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<el-input
v-model="aiText"
class="aiText"
placeholder="请输入你的问题"
@keydown.enter.native="submitEntry"
>
<svg-icon
slot="suffix"
icon-class="fasong"
class="addIcon"
:class="aiText.length==0?'addIconOpcity':''"
@click="submitEntry"
/>
</el-input>
<el-dialog
:visible.sync="dialogRemarkVisible"
append-to-body
title="查看大图"
custom-class="remake-dialog"
>
<div class="remake-box">
<el-image
:src="watchImageUrl"
style="max-width:600px;"
fit="contain"
>
</el-image>
</div>
</el-dialog>
</div>
</template>
<script >
import { mapState } from 'vuex'
import Clipboard from 'clipboard'
import debounce from '@/directive/debounce/index'
import loadingChat from '@/directive/loading/index'
import { getCorpBetaConfig, getAiResponse, Aihistory, answerComment, calAnswerClickTime, getQuoteData } from '@/api/skill'
export default {
name: 'AiLibrary',
directives: {
debounce,
loadingChat
},
computed: {
...mapState('common', ['chatUserInfo', 'zqUserInfo']),
...mapState('user', ['userInfo'])
},
data() {
return {
selectAiApp: '',
loading: false,
aiAppList: [],
answerLoading: false,
dialogRemarkVisible: false,
watchImageUrl: '',
session_id: '',
recordMessage: [],
aiText: '',
aiAnswer: {},
isHistory: false,
answerItem: {
session_id: '',
create_time: '',
doc_references: [],
fail_msg: '',
from: {
robot: {
avatar: 'https://companywx-1300623068.cos.ap-nanjing.myqcloud.com/zhangsheng/service/avatars/20240530/YMYZyis7hKP7tDEznsk5dhKzjkDctMa81717052051104.png',
name: '机器人',
robot_id: ''
},
cser: {
avatar: '',
name: '',
zq_user_id: ''
}
},
to: {
robot: {
avatar: 'https://companywx-1300623068.cos.ap-nanjing.myqcloud.com/zhangsheng/service/avatars/20240530/YMYZyis7hKP7tDEznsk5dhKzjkDctMa81717052051104.png',
name: '机器人',
robot_id: ''
},
cser: {
avatar: '',
name: '',
zq_user_id: ''
}
},
message: {
msgType: 'text',
text: {
content: ''
}
},
send_type: '',
_id: ''
}
}
},
mounted() {
this.getCorpBetaConfig()
// this.Aihistory()
this.initanswerItem()
},
methods: {
initanswerItem() {
this.answerItem.to.cser.avatar = this.zqUserInfo.avatar
this.answerItem.to.cser.name = this.zqUserInfo.name
this.answerItem.to.cser.zq_user_id = this.zqUserInfo.zq_user_id
this.answerItem.from.cser = this.answerItem.to.cser
this.answerItem.zq_user_id = this.zqUserInfo.zq_user_id
},
watchImage(i) {
this.watchImageUrl = i.message.image.picurl
this.dialogRemarkVisible = true
this.copyTextNum(i)
},
async Aihistory() {
this.recordMessage = []
const res = await Aihistory()
if (res.status_code === 1) {
this.isHistory = true
this.recordMessage = res.data.reverse().concat(this.recordMessage)
this.scrollBottm()
}
},
// 复制消息
copyText(i, index) {
const clipboard = new Clipboard('.copy')
clipboard.on('success', e => {
this.$message.success('复制成功')
// 释放内存
clipboard.destroy()
})
i.is_used_knowledge == 1 && i.request_id ? this.copyTextNum(i) : ''
},
// 统计复制的次数
async copyTextNum(i) {
const data = {
request_id: i.request_id
}
const res = await calAnswerClickTime(data)
},
async rqeustSource(i, index) {
const res = await getQuoteData({ request_id: i.request_id })
if (res.status_code == 1) {
this.$set(this.recordMessage[index], 'doc_references', res.data)
}
},
// 赞
async likeAnswer(i, type, index) {
const data = {
request_id: i.request_id,
like_status: type
}
const res = await answerComment(data)
if (res.status_code === 1) {
this.$message.success(res.msg)
this.$set(this.recordMessage[index], 'like_status', type)
}
},
async getCorpBetaConfig() {
const res = await getCorpBetaConfig({ scene: 2 })
if (res.status_code === 1 && res.data.length > 0) {
this.aiAppList = res.data
this.selectAiApp = res.data[0]._id
} else {
this.$message({
type: 'error',
message: '没有可用的AI应用'
})
}
},
submitEntry() {
if (this.selectAiApp === '') {
this.$message({
type: 'warning',
message: '请选择应用模型'
})
return
}
if (this.answerLoading) {
this.$message({
type: 'warning',
message: '请等待AI回复'
})
return
}
if (this.aiText.trim() === '') {
this.$message({
type: 'warning',
message: '请输入问题'
})
return
}
this.requestAiAnswer()
},
async requestAiAnswer() {
this.answerLoading = true
const question = this.aiText
this.addMessageList()
try {
const res = await getAiResponse({
question: question,
beta_config_id: this.selectAiApp,
session_id: this.session_id
})
if (res.status_code === 1) {
this.answerLoading = false
this.aiAnswer = res.data
this.session_id = res.data.session_id
this.$set(this.recordMessage[this.recordMessage.length - 1], 'loading', false)
this.$set(this.recordMessage[this.recordMessage.length - 1], 'like_status', 0)
this.$set(this.recordMessage[this.recordMessage.length - 1], 'is_used_knowledge', res.data.is_used_knowledge)
this.$set(this.recordMessage[this.recordMessage.length - 1], 'message', res.data.message)
this.$set(this.recordMessage[this.recordMessage.length - 1], 'request_id', res.data.request_id)
this.$set(this.recordMessage[this.recordMessage.length - 1], 'session_id', this.aiAnswer.session_id)
this.$set(this.recordMessage[this.recordMessage.length - 1], 'create_time', this.aiAnswer.create_time)
}
} catch (error) {
this.answerLoading = false
}
},
addMessageList() {
this.answerItem.session_id = this.session_id
this.answerItem.message.text.content = this.aiText
this.answerItem.create_time = this.$moment().format('YYYY-MM-DD HH:mm:ss')
this.answerItem._id = this.$moment()
const questionItem = JSON.parse(JSON.stringify(this.answerItem))
const answerItem = JSON.parse(JSON.stringify(this.answerItem))
questionItem.send_type = 1
answerItem.send_type = 2
answerItem._id = answerItem._id + '123'
answerItem.loading = true
this.recordMessage.push(questionItem)
this.recordMessage.push(answerItem)
this.scrollBottm()
this.aiText = ''
},
scrollBottm() {
this.$nextTick(() => {
const el = this.$refs['ai-box']
if (el) {
el.scrollTop = el.scrollHeight
}
})
},
paperScroll() {
// 监听滚动事件
const el = this.$refs['ai-box']
if (el.scrollTop <= 5 && this.isMoreRecord) {
this.messageList()
} else if (!this.isMoreRecord) {
// this.$message({
// type: 'error',
// message: '没有更多数据了'
// })
}
}
}
}
</script>
<style lang="scss" scoped>
.AiLibrary {
width: 100%;
height: 100%;
.AiChatList {
width: 100%;
height: calc(100% - 100px);
overflow: auto;
margin-top: 10px;
}
.msg-box {
height: calc(100% - 10px);
width: 100%;
overflow-y: auto;
padding: 10px 0;
.linkStyle {
.line {
width: vw(70);
height: 1px;
border: 1px solid #f2f3f5;
}
.linkRadio {
width: 8px;
height: 8px;
border-radius: 8px;
margin: 0 vw(5);
background: linear-gradient(
90deg,
#6ee7e9 0%,
#9ff2cd 47%,
#e3fdb2 100%
);
}
}
.moreLink {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: #3a88f6;
line-height: 18px;
text-align: left;
font-style: normal;
text-decoration-line: underline;
margin: 0 vw(5);
}
.remind {
padding: 5px 10px 2px 10px;
border-radius: 10px;
background: #fff;
box-shadow: 0.5px 0px 5.3px rgba(0, 0, 0, 0.08),
4px 0px 42px rgba(0, 0, 0, 0.16);
position: fixed;
left: 48%;
transform: translate(-50%);
bottom: vw(290);
cursor: pointer;
.iconDown {
transform: rotate(-90deg);
color: #00bf8a;
margin-right: 2px;
}
p {
color: #00bf8a;
font-size: 12px;
}
}
.msg {
width: 100%;
min-height: 2.5rem;
display: flex;
margin-top: 40px;
justify-content: flex-start !important;
.user-head {
min-width: 2.5rem;
width: 20%;
width: 2.5rem;
height: 2.5rem;
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
.image {
width: 40px;
height: 40px;
border-radius: 5px;
}
}
.chatItemBox {
border-radius: 10px;
position: relative;
width: 100%;
}
.user-msg {
width: 100%;
word-break: break-all;
font-size: 14px;
line-height: 20px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(0, 0, 0, 0.85);
position: relative;
top: -15px;
.time {
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
}
.uploadImage {
max-width: vw(130);
cursor: pointer;
}
.chatItem {
display: inline-block;
padding: 5px 10px;
border-radius: 0.5rem;
margin-top: 0.2rem;
font-size: 0.88rem;
}
.chatItemWidth {
width: vw(250) !important;
}
.chatItemLoading {
width: 100%;
}
.chatItemleft {
padding-bottom: 25px;
}
.fileItem {
width: auto;
}
// .chatItemLangth{
// position: relative !important;
// }
.left {
background: #ffffff;
border: 1px solid transparent;
border-radius: 6px;
border: 1px solid #00bf8a;
background-origin: border-box;
background-clip: content-box, border-box;
float: left;
}
.right {
background: linear-gradient(
135deg,
#6ee7e9 0%,
#9ff2cd 48%,
#e3fdb2 100%,
#e3fdb2 100%
);
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(0, 0, 0, 0.85);
animation: toright 0.5s ease both 1;
min-width: 50px;
display: inline-block;
}
.leftNoa {
background: white;
padding: 0.5rem 0;
float: right;
}
.rightNoa {
background: #94ec69;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: rgba(0, 0, 0, 0.85);
padding: 0.5rem 0;
}
.leftVideo {
background: white;
padding: 0.5rem 0;
}
.rightVideo {
background: white;
padding: 0.5rem 0;
}
@keyframes toLeft {
0% {
opacity: 0;
transform: translateX(-10px);
}
100% {
opacity: 1;
transform: translateX(0px);
}
}
@keyframes toright {
0% {
opacity: 0;
transform: translateX(10px);
}
100% {
opacity: 1;
transform: translateX(0px);
}
}
}
}
.msgMaxLanth {
min-height: vw(110);
}
.msgMaxLanth2 {
min-height: vw(210);
}
.msgMaxLanth3 {
min-height: vw(280);
}
.msgMaxLanth4 {
min-height: vw(450);
}
.msgMaxLanth5 {
min-height: vw(600);
}
@media only screen and (min-width: 1500px) {
.msgMaxLanth {
min-height: vw(100);
}
.msgMaxLanth2 {
min-height: vw(130);
}
.msgMaxLanth3 {
min-height: vw(160);
}
.msgMaxLanth4 {
min-height: vw(200);
}
.msgMaxLanth5 {
min-height: vw(320);
}
}
@media only screen and (min-width: 1800px) {
.msgMaxLanth {
min-height: vw(70);
}
.msgMaxLanth2 {
min-height: vw(120);
}
.msgMaxLanth3 {
min-height: vw(140);
}
.msgMaxLanth4 {
min-height: vw(180);
}
.msgMaxLanth5 {
min-height: vw(230);
}
}
@media only screen and (min-width: 2000px) {
.msgMaxLanth {
min-height: vw(60);
}
.msgMaxLanth2 {
min-height: vw(90);
}
.msgMaxLanth3 {
min-height: vw(140);
}
.msgMaxLanth4 {
min-height: vw(200);
}
.msgMaxLanth5 {
min-height: vw(220);
}
}
// 暂无好友
.no-friend {
font-size: 12px;
width: 100%;
height: 80px;
color: rgb(85, 79, 79);
}
}
.aiImage {
max-width: vw(300);
border-radius: 5px;
cursor: pointer;
}
.aiText {
::v-deep .el-input__inner {
width: 100%;
height: 46px;
background: #ffffff;
box-shadow: 0px 3px 9px 0px rgba(0, 0, 0, 0.12);
border-radius: 46px;
}
.addIcon {
font-size: 18px;
margin-top: 15px;
margin-right: 10px;
cursor: pointer;
}
.addIconOpcity {
opacity: 0.3;
}
}
.loadingRotage {
cursor: pointer;
font-size: 20px;
animation: rotage linear 1s infinite;
}
.copyIcon {
cursor: pointer;
font-size: 18px;
z-index: 10;
margin-right: 5px;
}
.likeIcon {
cursor: pointer;
font-size: 18px;
z-index: 10;
margin-right: 5px;
}
.likeBtn {
width: vw(250);
position: absolute;
bottom: 5px;
display: flex;
flex-direction: row-reverse;
}
}
@keyframes rotage {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
\ No newline at end of file
<template>
<div class="skillTab">
<div class="inputContent">
<el-input v-model="requestData.content" placeholder="请输入话术内容" class="input-with-select" @change="contentSearch">
<el-button slot="append" icon="el-icon-search"></el-button>
</el-input>
</div>
<div v-loading="loading" class="rowFlex skillBox">
<!-- 标签 -->
<el-collapse-transition>
<div v-if="groupList.length > 0" class="tagList columnFlex">
<div v-for="(item, index) in groupList" :key="index" class="tagItem rowFlex columnCenter" :draggable="activeName == 'personal' ? true : false" :class="groupActive == item.value ? 'tagItemActive' : ''" @dragstart="handleDragStart($event, item, index)" @dragover.prevent="handleDragOver($event, item)" @dragenter="handleDragEnter($event, item, 'group')" @dragend="handleDragEnd($event, item, 'group')">
<i class="el-icon-rank icon" style="cursor: move"></i>
<p class="text hidden" @click="groupFilter(item, index)">{{ item.group_name }}</p>
</div>
</div>
<div v-else>暂无话术内容</div>
</el-collapse-transition>
<!-- 话术 -->
<div v-loading="skillLoading" class="scrollList">
<el-collapse v-model="collapseActive" @change="handleChange">
<transition-group v-if="groupDataList.length > 0" tag="div" class="container">
<div v-for="(items, indexs) in groupDataList" :key="indexs" :draggable="activeName == 'personal' ? true : false" class="draggable" @dragstart="handleDragStart($event, items, indexs)" @dragover.prevent="handleDragOver($event, items)" @dragenter="handleDragEnter($event, items, 'item')" @dragend="handleDragEnd($event, items, 'item')">
<el-popover placement="top" width="300" trigger="hover">
<p>{{ items.title }}</p>
<div slot="reference" class="contentItemTitle allCenter" :style="{ top: items.title.length > 8 ? '5px' : '13px' }">{{ items.title }}</div>
</el-popover>
<div class="rowFlex titleFixed columnCenter">
<div class="num">{{ items.message.attachments.length > 1 ? `+${items.message.attachments.length - 1}条` : '' }}</div>
<el-button class="button rowFlex allCenter" :disabled="Boolean(setIntervalTimer)" @click.stop="sendMessage(items.message.attachments, items._id)">发送</el-button>
</div>
<el-collapse-item title="" :name="items._id" class="contentItem">
<div v-for="(i, j) in items.message.attachments" :key="j">
<div>
<div v-if="i.msgtype == 'text'" class="contentItemDetails rowFlex spaceBetween columnCenter">
<div class="text">{{ i.text.content }}</div>
<el-button class="sendButton rowFlex allCenter" :disabled="Boolean(setIntervalTimer)" @click.stop="sendMessageEdit(i, items._id)">发送</el-button>
</div>
<div v-if="i.msgtype == 'image'" class="contentItemDetails rowFlex spaceBetween columnCenter">
<el-image class="image" :src="i.image.picurl" :preview-src-list="[i.image.picurl]" fit="contain"></el-image>
<el-button class="sendButton rowFlex allCenter" :disabled="Boolean(setIntervalTimer)" @click.stop="sendMessage([i], items._id)">发送</el-button>
</div>
</div>
</div>
</el-collapse-item>
</div>
</transition-group>
<div v-else class="rowFlex rowCenter">暂无话术内容</div>
</el-collapse>
</div>
</div>
</div>
</template>
<script>
import { procedure_group, procedureList, procedureSort, procedureGroupSort, skillQuote } from '@/api/skill'
import { mapState, mapMutations, mapActions } from 'vuex'
import { throttle } from '@/utils/index'
export default {
components: {},
props: {
activeName: {
default: '',
type: String
}
},
data() {
return {
collapseActive: '',
groupActive: '0',
activeGroup: {},
groupList: [],
groupLastList: [],
groupDataList: [],
groupLastDataList: [],
pageInfo: {
page: 1,
page_size: 100,
total: 0
},
skillLoading: false,
loading: false,
requestData: {
content: '',
type: '',
procedure_group_id: ''
},
sortType: '',
sortID: {
_id: '',
before_id: '',
after_id: ''
},
filterText: {},
dragging: null,
orderList: [
{ label: '个人话术', type: 'personal' },
{ label: '企业话术', type: 'company' }
]
}
},
computed: {
...mapState('game', ['accountSelect', 'gameTabActive']),
...mapState('user', ['setIntervalTimer'])
},
watch: {
accountSelect(newVal, oldVal) {
if (newVal && newVal !== '' && this.gameTabActive == 3) {
this.pageInfo = {
page: 1,
page_size: 100,
total: 0
}
}
},
activeName(newVal, oldVal) {
if (newVal == 'company' && newVal != oldVal) {
this.resizeSelect()
this.requestGroup()
}
}
},
mounted() {
// this.requestGroup()
},
methods: {
...mapMutations('common', ['set_sendSkillMessage', 'set_isEditSkill']),
sendMessage: throttle(function(item, id) {
if (!this.setIntervalTimer) {
this.set_sendSkillMessage(item)
this.skillQuote(id, item.length)
}
}, 500),
handleDragStart(e, item, index) {
this.sortID._id = item._id
this.dragging = item
},
skillQuote(id, num) {
const data = {
type: this.activeName,
procedure_id: id,
quote_count: num || 1
}
skillQuote(data).then((res) => {
console.log(res)
})
},
sortSkill() {
procedureSort(this.sortID).then((res) => {
if (res.status_code == 1) {
this.$message.success(res.msg)
}
})
},
sortSkillGroup() {
procedureGroupSort(this.sortID).then((res) => {
if (res.status_code == 1) {
this.$message.success(res.msg)
}
})
},
handleDragEnd(e, item, type) {
// type group 话术库排序 item 话术排序
console.log(type, 'type', this.sortID)
this.dragging = null
this.groupLastDataList = this.groupDataList
this.groupLastList = this.groupList
type === 'group' ? this.sortSkillGroup() : this.sortSkill()
},
// 首先把div变成可以放置的元素,即重写dragenter/dragover
// DataTransfer 对象用来保存,通过拖放动作,拖动到浏览器的数据。
// 如果dropEffect 属性设定为none,则不允许被拖放到目标元素中。
handleDragOver(e) {
e.dataTransfer.dropEffect = 'move' // e.dataTransfer.dropEffect="move";//在dragenter中针对放置目标来设置!
},
handleDragEnter(e, item, type) {
e.dataTransfer.effectAllowed = 'move' // 为需要移动的元素设置dragstart事件
if (item === this.dragging) {
return
}
if (type === 'group') {
// 话术租排序
const newItems = [...this.groupList]
const src = newItems.indexOf(this.dragging)
const dst = newItems.indexOf(item)
if (src > dst) {
// 往上拖动
this.sortID.after_id = this.groupLastList[dst]._id
this.groupLastList[dst - 1] ? (this.sortID.before_id = this.groupLastList[dst - 1]._id) : (this.sortID.before_id = '')
// 替换
} else {
// 往下拖动
this.sortID.before_id = this.groupLastList[dst]._id
this.groupLastList[dst + 1] ? (this.sortID.after_id = this.groupLastList[dst + 1]._id) : (this.sortID.after_id = '')
}
// 替换
newItems.splice(dst, 0, ...newItems.splice(src, 1))
// 让item的颜色等于新交换的颜色
this.groupList = newItems
} else {
// 话术排序
const newItems = [...this.groupDataList]
const src = newItems.indexOf(this.dragging)
const dst = newItems.indexOf(item)
if (src > dst) {
// 往上拖动
this.sortID.after_id = this.groupLastDataList[dst]._id
this.groupLastDataList[dst - 1] ? (this.sortID.before_id = this.groupLastDataList[dst - 1]._id) : (this.sortID.before_id = '')
// 替换
} else {
// 往下拖动
this.sortID.before_id = this.groupLastDataList[dst]._id
this.groupLastDataList[dst + 1] ? (this.sortID.after_id = this.groupLastDataList[dst + 1]._id) : (this.sortID.after_id = '')
}
newItems.splice(dst, 0, ...newItems.splice(src, 1))
// 让item的颜色等于新交换的颜色
this.groupDataList = newItems
}
},
// 发送语音的时候 先编辑再发送
sendMessageEdit(item, id) {
console.log(item, id, '--------------')
if (!this.setIntervalTimer) {
this.set_isEditSkill([item])
this.skillQuote(id, 1)
}
},
contentSearch() {
this.pageInfo = {
page: 1,
page_size: 100,
total: 0
}
this.searchTable()
},
requestGroup() {
this.loading = true
const data = {
page: 1,
pageSize: 100,
type: this.activeName
}
procedure_group(data).then((res) => {
this.loading = false
if (res.data.data && res.data.data.length > 0) {
this.groupList = res.data.data.map((item, index) => {
item.label = item.group_name
item.value = item._id
return item
})
this.groupLastList = this.groupList
this.groupFilter(this.groupList[0])
} else {
this.groupList = []
this.groupLastList = []
}
})
},
// 62bd394d3747fe7c600a04f1
groupFilter(item, index) {
if (!item._id) {
this.requestData.second_group_id = ''
this.activeGroup = {}
}
this.groupActive = item.value
this.activeGroup = item
this.searchTable()
},
// 搜索结果
async searchTable(msg) {
this.skillLoading = true
this.requestData.type = this.activeName
this.requestData.procedure_group_id = this.activeGroup._id || ''
const data = { ...this.requestData, ...this.pageInfo }
procedureList(data).then((res) => {
this.skillLoading = false
this.groupDataList = res.data.data
this.groupDataList.map((item, index) => {
const text = item.message.attachments.find((item) => item.msgtype === 'text')
if (text) {
item.title = text.text.content
} else {
item.title = ''
}
})
this.groupLastDataList = this.groupDataList
})
},
handleChange() {},
// 重置select
resizeSelect() {
this.groupActive = '0'
this.isResize = true
this.groupDataList = []
this.requestData.content = ''
this.pageInfo.page = 1
setTimeout(() => {
this.isResize = false
}, 2000)
},
handleClick(tab, event) {
// 切换table
this.resizeSelect()
this.requestGroup()
}
}
}
</script>
<style lang="scss" scoped>
.details {
width: vw(444);
height: 100%;
background: #fff;
margin-left: 2px;
.detailsTitle {
width: 100%;
padding: 0 vw(20);
height: 60px;
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
border-bottom: 1px solid #ebeef5;
border-left: 1px solid #ebeef5;
p {
color: #333333;
}
}
.content {
width: 100%;
padding: vw(20);
height: 100%;
background: red;
.contentItemTitle {
position: absolute;
left: 10px;
z-index: 10;
cursor: pointer;
max-width: 45%;
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2; /* 这里是超出几行省略 */
overflow: hidden;
}
.titleFixed {
position: absolute;
right: 0px;
top: 10px;
margin-left: 15px;
margin-right: 25px;
z-index: 10;
.num {
width: auto;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #00bf8a;
margin-right: 10px;
}
.button {
width: 50px;
height: 24px;
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.15);
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
padding: 0;
}
}
.contentItem {
position: relative;
margin-bottom: 5px;
cursor: move;
.contentItemDetails {
width: 100%;
height: auto;
margin: 20px 0;
padding-left: 10px;
.text {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
word-wrap: break-word;
line-height: 18px;
max-width: calc(100% - 60px);
}
.sendButton {
width: 50px;
height: 24px;
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.15);
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
padding: 0;
}
.image {
max-width: 25%;
border-radius: 5px;
}
}
}
.item {
width: 100%;
height: auto;
font-size: 14px;
font-weight: 400;
color: #333333;
padding: 5px 0;
transition: all 0.5s;
position: relative;
padding-left: 10px;
cursor: move;
.tableImage {
width: 40px;
height: 40px;
border-radius: 6px;
margin-right: vw(10);
}
.label {
color: #999999;
}
.text {
color: #333333;
margin-left: 10px;
word-break: break-all;
max-width: 80%;
}
.icon {
display: none;
position: absolute;
right: 0;
top: 12px;
}
.tags {
width: vw(300);
margin-left: 10px;
.tagsItem {
width: vw(300);
}
.tag {
height: 22px;
line-height: 22px;
padding: 0 8px;
background: #ffffff;
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.2);
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
margin-right: 10px;
margin-bottom: 10px;
}
}
}
.item:hover .icon {
display: block;
}
}
::v-deep .el-collapse-item {
margin-bottom: 20px;
}
::v-deep .el-collapse-item__content {
padding-bottom: 10px;
}
::v-deep .el-collapse {
border: none;
}
::v-deep .el-tabs--border-card .is-active {
border: none !important;
}
::v-deep .el-collapse-item__header {
width: 100%;
height: 44px;
background: #f9faff;
color: #333333;
padding-left: 35px;
font-size: 14px;
font-weight: 400;
// cursor: move;
}
::v-deep .is-active {
border: none;
}
.inputContent {
width: 100%;
::v-deep .el-input {
width: 80%;
}
}
.skillBox {
width: 100%;
height: 100%;
overflow: auto;
margin-top: 20px;
}
.tagList {
width: vw(130);
height: 100%;
position: relative;
border-right: 1px solid #e0e0e0;
.tagItem {
width: vw(128);
height: 36px;
background: #fff;
border-radius: 4px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
padding-left: 10px;
margin-bottom: 6px;
cursor: pointer;
.text {
max-width: vw(90);
margin-left: 10px;
}
}
.iconFont {
font-size: 20px;
color: #999999;
position: absolute;
right: 0;
top: 20px;
cursor: pointer;
.upIcon {
transform: rotate(90deg);
}
}
.tagItemActive {
color: #00bf8a;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
background: #e4fff1;
}
}
.scrollList {
width: 100%;
height: 100%;
}
.container {
// margin-top: -20px;
}
::v-deep .el-tabs,
.el-tabs__content,
.el-tab-pane {
width: 100%;
height: 100%;
}
::v-deep .el-tabs__content {
width: 100%;
height: calc(100% - 50px);
}
::v-deep .el-tab-pane {
width: 100%;
height: 100%;
}
.scrollList {
width: 100%;
height: calc(100% - 40px);
overflow: auto;
}
.draggable {
position: relative;
transition: all 0.3s;
.icon {
position: absolute;
left: 10px;
top: 15px;
z-index: 10;
}
}
::v-deep .el-icon-circle-close {
color: #fff;
}
}
.skillTab {
width: 100%;
height: calc(100% - 60px);
}
</style>
<template>
<div class="skillLibrary">
<div v-loading="loading" class="rowFlex skillBox">
<!-- 标签 -->
<el-collapse-transition>
<div v-if="groupList.length > 0" class="tagList columnFlex">
<div v-for="(item, index) in groupList" :key="index" class="tagItem columnCenter" :draggable="false" :class="groupActive == item.value ? 'tagItemActiveText' : ''" @dragstart="handleDragStart($event, item, index)" @dragover.prevent="handleDragOver($event, item)" @dragenter="handleDragEnter($event, item, 'group')" @dragend="handleDragEnd($event, item, 'group')">
<div class="rowFlex columnCenter spaceBetween tagItemGroup" @click="groupFilter(item, index)">
<div class="rowFlex columnCenter">
<i class="el-icon-rank icon" style="cursor: move"></i>
<p class="text hidden">{{ item.name }}</p>
</div>
<i class="el-icon-caret-right rotageIcon" :class="groupActive == item.value ? 'rotage' : ''"></i>
</div>
<!-- 二级分组 -->
<div v-if="item.child.length > 0 && groupActive == item.value" class="childGroup">
<div v-for="child in item.child" :key="child._id" class="childGroupText" :class="[groupActiveChild == child._id ? 'tagItemActive' : '']" @click.stop="groupFilterChild(child)">
<p class="text hidden">{{ child.name }}</p>
</div>
</div>
</div>
</div>
<div v-else class="noContent rowFlex allCenter">
<!-- <svg-icon icon-class="noContent" /> -->
<noContent/>
</div>
</el-collapse-transition>
<!-- 话术 -->
<div class="libraryListContent">
<div class="inputContent">
<el-input v-model="requestData.title" placeholder="请输入话术内容" class="input-with-select">
<el-button slot="append" icon="el-icon-search" @click="contentSearch"></el-button>
</el-input>
</div>
<div ref="skillLibrary" v-loading="skillLoading" @scroll="paperScroll" class="scrollList">
<div v-for="(items, indexs) in groupDataList" :key="indexs" class="answerContent">
<div class="question"><span class="title">Q:</span>{{ items.name }}</div>
<div v-for="(answer, answerIndex) in items.answer" :key="answerIndex" class="answerItem" style="width: 100%">
<!-- <span class="question">{{ answerIndex + 1 }}: {{ answer }}</span> -->
<div v-if="answer.msgtype == 'text'" class="answerText rowFlex spaceBetween">
<span class="title rowFlex">A{{ answerIndex + 1 }}:</span>
<p v-if="answer.msgtype == 'text'" class="rowFlex textAnswer flex1">
{{ answer.text.content || '' }}
</p>
<i class="el-icon-document-copy copyIcon rowFlex" @click="sendMessageEdit(answer, items._id)"></i>
</div>
<div v-else-if="answer.msgtype == 'image'" class="answerText rowFlex">
<span class="title rowFlex">A{{ answerIndex + 1 }}:</span>
<el-image style="max-width: 200px" :src="answer.image.picurl" :preview-src-list="[answer.image.picurl]" @click="logClickTime(items._id)"> </el-image>
</div>
</div>
</div>
</div>
</div>
<!-- <div v-else class="noContent rowFlex allCenter">
<svg-icon icon-class="noContent" />
</div> -->
<!-- <el-collapse v-model="collapseActive" @change="handleChange">
<transition-group v-if="groupDataList.length > 0" tag="div" class="container">
<div v-for="(items, indexs) in groupDataList" :key="indexs" :draggable="activeName == 'personal' ? true : false" class="draggable" @dragstart="handleDragStart($event, items, indexs)" @dragover.prevent="handleDragOver($event, items)" @dragenter="handleDragEnter($event, items, 'item')" @dragend="handleDragEnd($event, items, 'item')">
<el-popover placement="top" width="300" trigger="hover">
<p>{{ items.title }}</p>
<div slot="reference" class="contentItemTitle allCenter" :style="{ top: items.title.length > 8 ? '5px' : '13px' }">{{ items.title }}</div>
</el-popover>
<div class="rowFlex titleFixed columnCenter">
<div class="num">{{ items.message.attachments.length > 1 ? `+${items.message.attachments.length - 1}条` : '' }}</div>
<el-button class="button rowFlex allCenter" :disabled="Boolean(setIntervalTimer)" @click.stop="sendMessage(items.message.attachments, items._id)">发送</el-button>
</div>
<el-collapse-item title="" :name="items._id" class="contentItem">
<div v-for="(i, j) in items.message.attachments" :key="j">
<div>
<div v-if="i.msgtype == 'text'" class="contentItemDetails rowFlex spaceBetween columnCenter">
<div class="text">{{ i.text.content }}</div>
<el-button class="sendButton rowFlex allCenter" :disabled="Boolean(setIntervalTimer)" @click.stop="sendMessageEdit(i, items._id)">发送</el-button>
</div>
<div v-if="i.msgtype == 'image'" class="contentItemDetails rowFlex spaceBetween columnCenter">
<el-image class="image" :src="i.image.picurl" :preview-src-list="[i.image.picurl]" fit="contain"></el-image>
<el-button class="sendButton rowFlex allCenter" :disabled="Boolean(setIntervalTimer)" @click.stop="sendMessage([i], items._id)">发送</el-button>
</div>
</div>
</div>
</el-collapse-item>
</div>
</transition-group>
<div v-else class="rowFlex rowCenter">暂无话术内容</div>
</el-collapse> -->
</div>
</div>
</template>
<script>
// procedure_group, procedureList, procedureSort, procedureGroupSort, skillQuote,
import { groupList, libraryIndex, logClickTime } from '@/api/skill'
import { mapState, mapMutations, mapActions } from 'vuex'
import { throttle,debounce } from '@/utils/index'
import noContent from '@/components/noContent.vue'
export default {
components: {
noContent
},
props: {
activeName: {
default: '',
type: String
}
},
data() {
return {
collapseActive: '',
groupActive: '0',
groupActiveChild: '0',
activeGroup: {},
groupList: [],
groupLastList: [],
groupDataList: [],
groupLastDataList: [],
pageInfo: {
page: 1,
page_size: 20,
total: 0
},
skillLoading: false,
loading: false,
requestData: {
title: '',
first_group_id: '',
second_group_id: ''
},
sortType: '',
sortID: {
_id: '',
before_id: '',
after_id: ''
},
filterText: {},
dragging: null,
orderList: [
{ label: '知识库', type: 'library' },
{ label: '个人话术', type: 'personal' },
{ label: '企业话术', type: 'company' }
]
}
},
computed: {
...mapState('game', ['accountSelect','chatUserInfo']),
},
watch: {
accountSelect(newVal, oldVal) {
if (newVal && newVal !== '' && this.gameTabActive == 3) {
this.pageInfo = {
page: 1,
page_size: 20,
total: 0
}
}
},
activeName(newVal, oldVal) {
if (newVal == 'library' && newVal != oldVal) {
this.resizeSelect()
this.requestLibraryData()
}
}
},
mounted() {
this.requestLibraryData()
},
methods: {
sendMessage: throttle(function(item, id) {
console.log(item, id)
// this.skillQuote(id, item.length)
}, 500),
handleDragStart(e, item, index) {
this.sortID._id = item._id
this.dragging = item
},
paperScroll:debounce(function(){
const el = this.$refs.skillLibrary
if (el.offsetHeight + el.scrollTop + 10 >= el.scrollHeight) {
console.log('下一页')
this.pageInfo.page++
this.searchTable()
}
},500),
// skillQuote(id, num) {
// const data = {
// type: this.activeName,
// procedure_id: id,
// quote_count: num || 1
// }
// skillQuote(data).then((res) => {
// console.log(res)
// })
// },
sortSkill() {
procedureSort(this.sortID).then((res) => {
if (res.status_code == 1) {
this.$message.success(res.msg)
}
})
},
sortSkillGroup() {
procedureGroupSort(this.sortID).then((res) => {
if (res.status_code == 1) {
this.$message.success(res.msg)
}
})
},
// 发送语音的时候 先编辑再发送
sendMessageEdit(item, id) {
console.log(item, id, '----------')
this.logClickTime(id)
// this.skillQuote(id, 1)
},
async logClickTime(id) {
console.log(id, 'id')
const res = await logClickTime({ _id: id })
if (res.status_code === 1) {
console.log(res.msg)
}
},
contentSearch() {
this.pageInfo = {
page: 1,
page_size: 20,
total: 0
}
this.searchTable('msg')
},
// 知识库话术
requestLibraryData() {
console.log(this.chatUserInfo, 'chatUserInfo')
this.loading = true
const data = {
page: 1,
page_size: 100,
userid: this.chatUserInfo.userid
}
groupList(data).then((res) => {
this.loading = false
if (res.data.data) {
res.data.data.unshift({
name: '全部分组',
value: '',
child: []
})
this.groupList = res.data.data.map((item, index) => {
item.label = item.name
item.value = item._id
return item
})
this.groupLastList = this.groupList
this.groupFilter(this.groupList[0])
} else {
this.groupList = []
this.groupLastList = []
}
})
},
groupFilter(item, index) {
if (!item._id) {
this.requestData.second_group_id = ''
this.activeGroup = {}
}
this.groupActive = item.value
item.child && item.child[0] ? ((this.activeGroup = item.child[0]), (this.groupActiveChild = item.child[0]._id)) : ''
this.searchTable()
},
groupFilterChild(child) {
this.groupActiveChild = 0
this.activeGroup = child
this.groupActiveChild = child._id
this.searchTable()
this.$forceUpdate()
},
// 搜索结果
async searchTable(msg) {
this.skillLoading = true
this.requestData.second_group_id = this.activeGroup._id || ''
this.requestData.title = this.requestData.title.trim()
const data = { ...this.requestData, ...this.pageInfo, log_scan: msg ? 1 : 0, userid: this.chatUserInfo.userid }
libraryIndex(data).then((res) => {
this.skillLoading = false
this.pageInfo.page === 1 ? this.groupDataList = res.data.data : this.groupDataList = this.groupDataList.concat(res.data.data)
this.groupLastDataList = this.groupDataList
})
},
handleChange() {},
// 重置select
resizeSelect() {
this.groupActive = '0'
this.isResize = true
this.groupDataList = []
this.requestData.content = ''
this.pageInfo.page = 1
setTimeout(() => {
this.isResize = false
}, 2000)
}
}
}
</script>
<style lang="scss" scoped>
.skillLibrary {
width: 100%;
height: 100%;
overflow-y: auto;
overflow-x: hidden;
.noContent {
font-size: 200px;
}
.contentItemTitle {
position: absolute;
left: 10px;
z-index: 10;
cursor: pointer;
max-width: 45%;
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2; /* 这里是超出几行省略 */
overflow: hidden;
}
.titleFixed {
position: absolute;
right: 0px;
top: 10px;
margin-left: 15px;
margin-right: 25px;
z-index: 10;
.num {
width: auto;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #00bf8a;
margin-right: 10px;
}
.button {
width: 50px;
height: 24px;
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.15);
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
padding: 0;
}
}
.contentItem {
position: relative;
margin-bottom: 5px;
cursor: move;
.contentItemDetails {
width: 100%;
height: auto;
margin: 20px 0;
padding-left: 10px;
.text {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
max-width: calc(100% - 60px);
word-wrap: break-word;
line-height: 18px;
}
.sendButton {
width: 50px;
height: 24px;
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.15);
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
padding: 0;
}
.image {
max-width: 25%;
border-radius: 5px;
}
}
}
.item {
width: 100%;
height: auto;
font-size: 14px;
font-weight: 400;
color: #333333;
padding: 5px 0;
transition: all 0.5s;
position: relative;
padding-left: 10px;
cursor: move;
.tableImage {
width: 40px;
height: 40px;
border-radius: 6px;
margin-right: vw(10);
}
.label {
color: #999999;
}
.text {
color: #333333;
margin-left: 10px;
word-break: break-all;
max-width: 80%;
}
.icon {
display: none;
position: absolute;
right: 0;
top: 12px;
}
.tags {
width: vw(300);
margin-left: 10px;
.tagsItem {
width: vw(300);
}
.tag {
height: 22px;
line-height: 22px;
padding: 0 8px;
background: #ffffff;
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.2);
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
margin-right: 10px;
margin-bottom: 10px;
}
}
}
.item:hover .icon {
display: block;
}
}
::v-deep .el-collapse-item {
margin-bottom: 20px;
}
::v-deep .el-collapse-item__content {
padding-bottom: 10px;
}
::v-deep .el-collapse {
border: none;
}
::v-deep .el-tabs--border-card .is-active {
border: none !important;
}
::v-deep .el-collapse-item__header {
width: 100%;
height: 44px;
background: #f9faff;
color: #333333;
padding-left: 35px;
font-size: 14px;
font-weight: 400;
// cursor: move;
}
::v-deep .is-active {
border: none;
}
.inputContent {
width: 100%;
margin-bottom: 20px;
margin-left: 20px;
::v-deep .el-input {
width: 90%;
}
}
.skillBox {
width: 100%;
height: calc(100% - 20px);
}
.tagList {
width: vw(130);
height: 100%;
position: relative;
border-right: 1px solid #e0e0e0;
.tagItem {
width: vw(128);
height: auto;
background: #fff;
border-radius: 4px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
margin-bottom: 6px;
cursor: pointer;
.text {
max-width: vw(90);
margin-left: 5px;
}
.tagItemGroup {
height: 36px;
padding-right: 10px;
}
}
.iconFont {
font-size: 20px;
color: #999999;
position: absolute;
right: 0;
top: 20px;
cursor: pointer;
.upIcon {
transform: rotate(90deg);
}
}
.tagItemActive {
color: #00bf8a !important;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
background: #e4fff1;
}
.tagItemActiveText {
color: #00bf8a;
}
}
.libraryListContent{
width: 100%;
height: 100%;
}
.rotageIcon {
cursor: pointer;
transition: all 0.5s;
transform: rotate(0deg);
font-size: 12px;
}
.rotage {
transform: rotate(90deg);
}
.childGroup {
p {
margin-left: 15px !important;
}
.childGroupText {
height: 36px;
line-height: 36px;
color: #333333;
}
}
.scrollList {
width: 100%;
height: 100%;
padding-left: 20px;
.answerContent {
width: 100%;
background: #f7f8fa;
border-radius: 5px;
border: 1px solid #e5e6eb;
padding: 10px;
margin-bottom: 20px;
.title {
width: 30px;
font-size: 14px;
font-weight: 500;
margin-right: 10px;
}
.answerItem {
margin-bottom: 10px;
}
.question {
font-weight: 500;
font-size: 14px;
color: #333333;
line-height: 20px;
text-align: left;
margin-bottom: 10px;
}
.answerText {
width: 100%;
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 12px;
color: #333333;
text-align: justify;
font-style: normal;
.answerTextTitle {
width: 30px;
font-size: 16px;
font-weight: 500;
}
.textAnswer {
word-wrap: break-word;
font-size: 13px;
}
.copyIcon {
width: 20px;
color: #00bf8a;
font-size: 16px;
position: relative;
top: 2px;
cursor: pointer;
margin-left: 10px;
}
}
}
}
.scrollList::-webkit-scrollbar {display:none}
.container {
// margin-top: -20px;
}
::v-deep .el-tabs,
.el-tabs__content,
.el-tab-pane {
width: 100%;
height: 100%;
}
::v-deep .el-tabs__content {
width: 100%;
height: calc(100% - 50px);
}
::v-deep .el-tab-pane {
width: 100%;
height: 100%;
}
.scrollList {
width: 100%;
height: calc(100% - 40px);
overflow: auto;
}
.draggable {
position: relative;
transition: all 0.3s;
.icon {
position: absolute;
left: 10px;
top: 15px;
z-index: 10;
}
}
.textAnswer {
word-wrap: break-word;
display: inline;
}
.img_drop {
width: 200px;
height: 200px;
background: rgba(0, 0, 0, 0.36);
position: absolute;
left: 0;
top: 0;
}
.skillLibrary::-webkit-scrollbar {display:none}
::v-deep .el-icon-circle-close {
color: #fff;
}
</style>
<template>
<div class="skillTab">
<div class="inputContent">
<el-input v-model="requestData.content" placeholder="请输入话术内容" class="input-with-select" @change="contentSearch">
<el-button slot="append" icon="el-icon-search"></el-button>
</el-input>
</div>
<div v-loading="loading" class="rowFlex skillBox">
<!-- 标签 -->
<el-collapse-transition>
<div v-if="groupList.length > 0" class="tagList columnFlex">
<div v-for="(item, index) in groupList" :key="index" class="tagItem rowFlex columnCenter" :draggable="activeName == 'personal' ? true : false" :class="groupActive == item.value ? 'tagItemActive' : ''" @dragstart="handleDragStart($event, item, index)" @dragover.prevent="handleDragOver($event, item)" @dragenter="handleDragEnter($event, item, 'group')" @dragend="handleDragEnd($event, item, 'group')">
<i class="el-icon-rank icon" v-if="activeName == 'personal'" style="cursor: move"></i>
<p class="text hidden" @click="groupFilter(item, index)">{{ item.group_name }}</p>
</div>
</div>
<div v-else>暂无话术内容</div>
</el-collapse-transition>
<!-- 话术 -->
<div v-loading="skillLoading" class="scrollList">
<el-collapse v-model="collapseActive" @change="handleChange">
<transition-group v-if="groupDataList.length > 0" tag="div" class="container">
<div v-for="(items, indexs) in groupDataList" :key="indexs" :draggable="activeName == 'personal' ? true : false" class="draggable" @dragstart="handleDragStart($event, items, indexs)" @dragover.prevent="handleDragOver($event, items)" @dragenter="handleDragEnter($event, items, 'item')" @dragend="handleDragEnd($event, items, 'item')">
<el-popover placement="top" width="300" trigger="hover">
<p>{{ items.title }}</p>
<div slot="reference" class="contentItemTitle allCenter" :style="{ top: items.title.length > 8 ? '5px' : '13px' }">{{ items.title }}</div>
</el-popover>
<div class="rowFlex titleFixed columnCenter">
<div class="num">{{ items.message.attachments.length > 1 ? `+${items.message.attachments.length - 1}条` : '' }}</div>
<el-button class="button rowFlex allCenter" @click.stop="sendMessage(items.message.attachments, items._id)">发送</el-button>
</div>
<el-collapse-item title="" :name="items._id" class="contentItem">
<div v-for="(i, j) in items.message.attachments" :key="j">
<div>
<div v-if="i.msgtype == 'text'" class="contentItemDetails rowFlex spaceBetween columnCenter">
<div class="text">{{ i.text.content }}</div>
<el-button class="sendButton rowFlex allCenter" @click.stop="sendMessageEdit(i, items._id)">发送</el-button>
</div>
<div v-if="i.msgtype == 'image'" class="contentItemDetails rowFlex spaceBetween columnCenter">
<el-image class="image" :src="i.image.picurl" :preview-src-list="[i.image.picurl]" fit="contain"></el-image>
<el-button class="sendButton rowFlex allCenter" @click.stop="sendMessage([i], items._id)">发送</el-button>
</div>
</div>
</div>
</el-collapse-item>
</div>
</transition-group>
<div v-else class="rowFlex rowCenter">暂无话术内容</div>
</el-collapse>
</div>
</div>
</div>
</template>
<script>
import { procedure_group, procedureList, procedureSort, procedureGroupSort, skillQuote } from '@/api/skill'
import { mapState, mapMutations, mapActions } from 'vuex'
import { debounce } from '@/utils/index'
export default {
components: {},
props: {
activeName: {
default: '',
type: String
}
},
data() {
return {
collapseActive: '',
groupActive: '0',
activeGroup: {},
groupList: [],
groupLastList: [],
groupDataList: [],
groupLastDataList: [],
pageInfo: {
page: 1,
page_size: 100,
total: 0
},
skillLoading: false,
loading: false,
requestData: {
content: '',
type: '',
procedure_group_id: ''
},
sortType: '',
sortID: {
_id: '',
before_id: '',
after_id: ''
},
filterText: {},
dragging: null,
orderList: [
{ label: '个人话术', type: 'personal' },
{ label: '企业话术', type: 'company' }
]
}
},
computed: {
...mapState('game', ['accountSelect']),
},
watch: {
accountSelect(newVal, oldVal) {
if (newVal && newVal !== '') {
this.pageInfo = {
page: 1,
page_size: 100,
total: 0
}
}
},
activeName(newVal, oldVal) {
if (newVal == 'personal' && newVal != oldVal) {
this.resizeSelect()
this.requestGroup()
}
}
},
mounted() {
this.requestGroup()
},
methods: {
// ...mapMutations('common', ['set_sendSkillMessage', 'set_isEditSkill']),
sendMessage: debounce(function(item, id) {
this.skillQuote(id, item.length)
}, 500),
handleDragStart(e, item, index) {
this.sortID._id = item._id
this.dragging = item
},
skillQuote(id, num) {
const data = {
type: this.activeName,
procedure_id: id,
quote_count: num || 1
}
skillQuote(data).then((res) => {
console.log(res)
})
},
sortSkill() {
procedureSort(this.sortID).then((res) => {
if (res.status_code == 1) {
this.$message.success(res.msg)
}
})
},
sortSkillGroup() {
if (this.sortID.before_id !== '' || this.sortID.after_id !== '') {
procedureGroupSort(this.sortID).then((res) => {
if (res.status_code == 1) {
this.$message.success(res.msg)
}
})
}
},
handleDragEnd(e, item, type) {
// type group 话术库排序 item 话术排序
console.log(type, 'type', this.sortID)
this.dragging = null
this.groupLastDataList = this.groupDataList
this.groupLastList = this.groupList
type === 'group' ? this.sortSkillGroup() : this.sortSkill()
},
// 首先把div变成可以放置的元素,即重写dragenter/dragover
// DataTransfer 对象用来保存,通过拖放动作,拖动到浏览器的数据。
// 如果dropEffect 属性设定为none,则不允许被拖放到目标元素中。
handleDragOver(e) {
e.dataTransfer.dropEffect = 'move' // e.dataTransfer.dropEffect="move";//在dragenter中针对放置目标来设置!
},
handleDragEnter(e, item, type) {
e.dataTransfer.effectAllowed = 'move' // 为需要移动的元素设置dragstart事件
if (item === this.dragging) {
return
}
if (type === 'group') {
// 话术租排序
const newItems = [...this.groupList]
const src = newItems.indexOf(this.dragging)
const dst = newItems.indexOf(item)
if (src > dst) {
// 往上拖动
this.sortID.after_id = this.groupLastList[dst]._id
this.groupLastList[dst - 1] ? (this.sortID.before_id = this.groupLastList[dst - 1]._id) : (this.sortID.before_id = '')
// 替换
} else {
// 往下拖动
this.sortID.before_id = this.groupLastList[dst]._id
this.groupLastList[dst + 1] ? (this.sortID.after_id = this.groupLastList[dst + 1]._id) : (this.sortID.after_id = '')
}
// 替换
newItems.splice(dst, 0, ...newItems.splice(src, 1))
// 让item的颜色等于新交换的颜色
this.groupList = newItems
} else {
// 话术排序
const newItems = [...this.groupDataList]
const src = newItems.indexOf(this.dragging)
const dst = newItems.indexOf(item)
if (src > dst) {
// 往上拖动
this.sortID.after_id = this.groupLastDataList[dst]._id
this.groupLastDataList[dst - 1] ? (this.sortID.before_id = this.groupLastDataList[dst - 1]._id) : (this.sortID.before_id = '')
// 替换
} else {
// 往下拖动
this.sortID.before_id = this.groupLastDataList[dst]._id
this.groupLastDataList[dst + 1] ? (this.sortID.after_id = this.groupLastDataList[dst + 1]._id) : (this.sortID.after_id = '')
}
newItems.splice(dst, 0, ...newItems.splice(src, 1))
// 让item的颜色等于新交换的颜色
this.groupDataList = newItems
}
},
// 发送语音的时候 先编辑再发送
sendMessageEdit(item, id) {
this.skillQuote(id, 1)
},
contentSearch() {
this.pageInfo = {
page: 1,
page_size: 100,
total: 0
}
this.searchTable()
},
requestGroup() {
this.loading = true
const data = {
page: 1,
pageSize: 100,
type: this.activeName
}
procedure_group(data).then((res) => {
this.loading = false
if (res.data.data && res.data.data.length > 0) {
this.groupList = res.data.data.map((item, index) => {
item.label = item.group_name
item.value = item._id
return item
})
this.groupLastList = this.groupList
this.groupFilter(this.groupList[0])
} else {
this.groupList = []
this.groupLastList = []
}
})
},
// 62bd394d3747fe7c600a04f1
groupFilter(item, index) {
if (!item._id) {
this.requestData.second_group_id = ''
this.activeGroup = {}
}
this.groupActive = item.value
this.activeGroup = item
this.searchTable()
},
// 搜索结果
async searchTable(msg) {
this.skillLoading = true
this.requestData.type = this.activeName
this.requestData.procedure_group_id = this.activeGroup._id || ''
const data = { ...this.requestData, ...this.pageInfo }
procedureList(data).then((res) => {
this.skillLoading = false
this.groupDataList = res.data.data
this.groupDataList.map((item, index) => {
const text = item.message.attachments.find((item) => item.msgtype === 'text')
if (text) {
item.title = text.text.content
} else {
item.title = ''
}
})
this.groupLastDataList = this.groupDataList
})
},
handleChange() {},
// 重置select
resizeSelect() {
this.groupActive = '0'
this.isResize = true
this.groupDataList = []
this.requestData.content = ''
this.pageInfo.page = 1
setTimeout(() => {
this.isResize = false
}, 2000)
},
handleClick(tab, event) {
// 切换table
this.resizeSelect()
this.requestGroup()
}
}
}
</script>
<style lang="scss" scoped>
.details {
width: vw(444);
height: 100%;
background: #fff;
margin-left: 2px;
.detailsTitle {
width: 100%;
padding: 0 vw(20);
height: 60px;
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
border-bottom: 1px solid #ebeef5;
border-left: 1px solid #ebeef5;
p {
color: #333333;
}
}
.content {
width: 100%;
padding: vw(20);
height: 100%;
background: red;
.contentItemTitle {
position: absolute;
left: 10px;
z-index: 10;
cursor: pointer;
max-width: 45%;
word-break: break-all;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2; /* 这里是超出几行省略 */
overflow: hidden;
}
.titleFixed {
position: absolute;
right: 0px;
top: 10px;
margin-left: 15px;
margin-right: 25px;
z-index: 10;
.num {
width: auto;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #00bf8a;
margin-right: 10px;
}
.button {
width: 50px;
height: 24px;
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.15);
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
padding: 0;
}
}
.contentItem {
position: relative;
margin-bottom: 5px;
cursor: move;
.contentItemDetails {
width: 100%;
height: auto;
margin: 20px 0;
padding-left: 10px;
.text {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
word-wrap: break-word;
line-height: 18px;
max-width: calc(100% - 60px);
}
.sendButton {
width: 50px;
height: 24px;
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.15);
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
padding: 0;
}
.image {
max-width: 25%;
border-radius: 5px;
}
}
}
.item {
width: 100%;
height: auto;
font-size: 14px;
font-weight: 400;
color: #333333;
padding: 5px 0;
transition: all 0.5s;
position: relative;
padding-left: 10px;
cursor: move;
.tableImage {
width: 40px;
height: 40px;
border-radius: 6px;
margin-right: vw(10);
}
.label {
color: #999999;
}
.text {
color: #333333;
margin-left: 10px;
word-break: break-all;
max-width: 80%;
}
.icon {
display: none;
position: absolute;
right: 0;
top: 12px;
}
.tags {
width: vw(300);
margin-left: 10px;
.tagsItem {
width: vw(300);
}
.tag {
height: 22px;
line-height: 22px;
padding: 0 8px;
background: #ffffff;
border-radius: 4px;
border: 1px solid rgba(0, 0, 0, 0.2);
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
margin-right: 10px;
margin-bottom: 10px;
}
}
}
.item:hover .icon {
display: block;
}
}
::v-deep .el-collapse-item {
margin-bottom: 20px;
}
::v-deep .el-collapse-item__content {
padding-bottom: 10px;
}
::v-deep .el-collapse {
border: none;
}
::v-deep .el-tabs--border-card .is-active {
border: none !important;
}
::v-deep .el-collapse-item__header {
width: 100%;
height: 44px;
background: #f9faff;
color: #333333;
padding-left: 35px;
font-size: 14px;
font-weight: 400;
// cursor: move;
}
::v-deep .is-active {
border: none;
}
.inputContent {
width: 100%;
::v-deep .el-input {
width: 80%;
}
}
.skillBox {
width: 100%;
height: 100%;
overflow: auto;
margin-top: 20px;
}
.tagList {
width: vw(130);
height: 100%;
position: relative;
border-right: 1px solid #e0e0e0;
.tagItem {
width: vw(128);
height: 36px;
background: #fff;
border-radius: 4px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
padding-left: 10px;
margin-bottom: 6px;
cursor: pointer;
.text {
max-width: vw(90);
margin-left: 10px;
}
}
.iconFont {
font-size: 20px;
color: #999999;
position: absolute;
right: 0;
top: 20px;
cursor: pointer;
.upIcon {
transform: rotate(90deg);
}
}
.tagItemActive {
color: #00bf8a;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
background: #e4fff1;
}
}
.scrollList {
width: 100%;
height: 100%;
}
.container {
// margin-top: -20px;
}
::v-deep .el-tabs,
.el-tabs__content,
.el-tab-pane {
width: 100%;
height: 100%;
}
::v-deep .el-tabs__content {
width: 100%;
height: calc(100% - 50px);
}
::v-deep .el-tab-pane {
width: 100%;
height: 100%;
}
.scrollList {
width: 100%;
height: calc(100% - 40px);
overflow: auto;
}
.draggable {
position: relative;
transition: all 0.3s;
.icon {
position: absolute;
left: 10px;
top: 15px;
z-index: 10;
}
}
::v-deep .el-icon-circle-close {
color: #fff;
}
}
.skillTab {
width: 100%;
height: calc(100% - 60px);
}
</style>
<template> <template>
<div class="giftRecord-content"> <div class="gift-tab-container-apply-gift">
礼包记录 <el-tabs v-model="activeTab">
<el-tab-pane label="充值礼包" name="email">
<email-gift></email-gift>
</el-tab-pane>
<el-tab-pane label="企微礼包" name="wx">
<wx-gift></wx-gift>
</el-tab-pane>
</el-tabs>
</div> </div>
</template> </template>
<script> <script>
import EmailGift from './components/giftRecord/emailGift.vue'
import WxGift from './components/giftRecord/wxGift.vue'
export default { export default {
name: 'GiftRecord', name: 'GiftTab',
components: {
EmailGift,
WxGift
},
data() {
return {
activeTab: 'email'
}
}
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.giftRecord-content{ .gift-tab-container-apply-gift {
width: 100%; width: 100%;
height: 100%; height: 100%;
padding-top: 10px;
background: #fff; background: #fff;
::v-deep .el-tabs .el-tabs__header{
margin: 0;
// height: 60px;
}
} }
</style> </style>
\ No newline at end of file
<template> <template>
<div class="quickReply-content"> <div class="details columnFlex">
快捷回复 <div class="content search-form">
<el-tabs v-model="activeName">
<el-tab-pane
label="个人话术"
name="personal"
>
<skillPersonal
v-if="activeName === 'personal'"
:active-name="activeName"
/>
</el-tab-pane>
<el-tab-pane
label="企业话术"
name="company"
>
<skillCompany
:active-name="activeName"
/>
</el-tab-pane>
<el-tab-pane
label="知识库"
name="library"
>
<skillLibrary
v-if="activeName === 'library'"
:active-name="activeName"
/>
</el-tab-pane>
<!-- <el-tab-pane
v-if="workerRouter==='game' && messageSource === 'company_work'"
label="AI微言"
name="aiLibrary"
>
<template slot="label">
AI微言
<span class="bate">beta</span>
</template>
<aiLibrary
v-if="activeName === 'aiLibrary'"
:active-name="activeName"
/>
</el-tab-pane> -->
</el-tabs>
</div>
</div> </div>
</template> </template>
<script> <script>
import skillCompany from './components/skill/skillCompany.vue'
import skillPersonal from './components/skill/skillPersonal.vue'
import skillLibrary from './components/skill/skillLibrary.vue'
// import aiLibrary from './components/skill/aiLibrary.vue'
import { mapState, mapMutations, mapActions } from 'vuex'
export default { export default {
name: 'QuickReply', components: {
skillCompany,
skillPersonal,
skillLibrary,
// aiLibrary
},
props: {
messageSource: {
type: String,
default: ''
}
},
data() {
return {
activeName: 'personal'
}
},
created() { },
mounted() { },
methods: {}
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.quickReply-content{ .details {
::v-deep .el-tabs__nav-next,::v-deep .el-tabs__nav-prev{
line-height: 50px;
}
width: 100%; width: 100%;
height: 100%; height: 100%;
background: #fff; background: #fff;
::v-deep .el-tabs__item {
padding: 0 15px;
}
.detailsTitle {
width: 100%;
padding: 0 vw(20);
height: 60px;
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
border-bottom: 1px solid #ebeef5;
border-left: 1px solid #ebeef5;
p {
color: #333333;
}
}
.content {
width: 100%;
height: calc(100% - 10px);
::v-deep .el-tabs__header {
margin: 0 0 20px;
}
}
::v-deep .el-collapse-item {
margin-bottom: 20px;
}
::v-deep .el-collapse-item__content {
padding-bottom: 10px;
}
::v-deep .el-collapse {
border: none;
}
::v-deep .el-tabs--border-card .is-active {
border: none !important;
}
::v-deep .el-collapse-item__header {
width: 100%;
height: 44px;
background: #f9faff;
color: #333333;
padding-left: 35px;
font-size: 14px;
font-weight: 400;
// cursor: move;
}
::v-deep .is-active {
border: none;
}
.inputContent {
width: 100%;
::v-deep .el-input {
width: 80%;
}
}
::v-deep .el-tabs,
.el-tabs__content,
.el-tab-pane {
width: 100%;
height: 100%;
}
::v-deep .el-tabs__content {
width: 100%;
height: calc(100% - 50px);
}
::v-deep .el-tab-pane {
width: 100%;
height: 100%;
}
.scrollList {
width: 100%;
height: calc(100% - 40px);
overflow: auto;
}
.draggable {
position: relative;
transition: all 0.3s;
.icon {
position: absolute;
left: 10px;
top: 15px;
z-index: 10;
}
}
::v-deep .el-icon-circle-close {
color: #fff;
}
.bate {
width: 42px;
height: 20px;
background: linear-gradient(135deg, #6ee7e9 0%, #9ff2cd 47%, #e3fdb2 100%);
border-radius: 10px;
padding: 0px 10px 3px 10px;
}
} }
</style> </style>
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论