Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
company_app
概览
概览
详情
活动
周期分析
版本库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
毛细亚
company_app
Commits
a5bbf545
提交
a5bbf545
authored
12月 03, 2025
作者:
施汉文
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
✨
feat: 7.1功能
上级
5593e9ce
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
13 个修改的文件
包含
341 行增加
和
48 行删除
+341
-48
index.html
public/index.html
+13
-8
game.js
src/api/game.js
+43
-0
copy.js
src/directive/copy/copy.js
+82
-0
index.js
src/directive/copy/index.js
+13
-0
main.js
src/main.js
+2
-1
user.js
src/store/modules/user.js
+5
-0
index.scss
src/styles/index.scss
+4
-0
index.vue
src/views/components/InstructionalVideo/index.vue
+146
-0
sendGame.vue
src/views/components/quickSendGame/sendGame.vue
+0
-0
roleInfoPanel.vue
src/views/components/roleInfo/roleInfoPanel.vue
+0
-0
crossLibrary.vue
src/views/components/skill/crossLibrary.vue
+0
-0
newLogin.vue
src/views/newLogin.vue
+0
-0
quickReply.vue
src/views/quickReply.vue
+33
-39
没有找到文件。
public/index.html
浏览文件 @
a5bbf545
<!DOCTYPE html>
<html
lang=
""
>
<head>
<meta
charset=
"utf-8"
>
<meta
http-equiv=
"X-UA-Compatible"
content=
"IE=edge"
>
<meta
name=
"viewport"
content=
"width=device-width,initial-scale=1.0"
>
<link
rel=
"icon"
href=
"<%= BASE_URL %>favicon.ico"
>
<meta
charset=
"utf-8"
/
>
<meta
http-equiv=
"X-UA-Compatible"
content=
"IE=edge"
/
>
<meta
name=
"viewport"
content=
"width=device-width,initial-scale=1.0"
/
>
<link
rel=
"icon"
href=
"<%= BASE_URL %>favicon.ico"
/
>
<!-- HTTP 1.1 -->
<meta
http-equiv=
"pragma"
content=
"no-cache"
>
<meta
http-equiv=
"pragma"
content=
"no-cache"
/
>
<!-- HTTP 1.0 -->
<meta
http-equiv=
"cache-control"
content=
"no-cache"
>
<meta
http-equiv=
"cache-control"
content=
"no-cache"
/
>
<!-- Prevent caching at the proxy server -->
<meta
http-equiv=
"expires"
content=
"0"
>
<meta
http-equiv=
"expires"
content=
"0"
/
>
<meta
http-equiv=
"X-UA-Compatible"
content=
"IE=EmulateIE9"
/>
<!-- <title><%= htmlWebpackPlugin.options.title %></title> -->
<title>
企微侧边栏
</title>
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0,shrink-to-fit=no,user-scalable=no"> -->
<script
src=
"https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"
></script>
<script
src=
"https://lf1-cdn-tos.bytegoofy.com/obj/iconpark/icons_27278_170.37925de07dae112aa781d3ef4c169912.es5.js"
></script>
</head>
<body>
<noscript>
<strong>
We're sorry but
<
%=
htmlWebpackPlugin
.
options
.
title
%
>
doesn't work properly without JavaScript enabled. Please enable it to continue.
</strong>
<strong
>
We're sorry but
<
%=
htmlWebpackPlugin
.
options
.
title
%
>
doesn't work
properly without JavaScript enabled. Please enable it to
continue.
</strong
>
</noscript>
<div
id=
"app"
></div>
</body>
...
...
src/api/game.js
浏览文件 @
a5bbf545
...
...
@@ -1467,3 +1467,45 @@ export function sendEmail(data) {
})
})
}
// 获取开/合服天数
export
function
getServerDayApi
(
data
)
{
return
new
Promise
((
resolve
,
reject
)
=>
{
cross_systemRequest
({
system
:
'zhangyou'
,
api
:
'/api/role/getServerDay'
,
params
:
data
}).
then
((
res
)
=>
{
resolve
(
res
)
}).
catch
((
error
)
=>
{
reject
(
error
)
})
})
}
// 项目-视频分类
export
function
teachingVideoCategoryListApi
(
data
)
{
return
new
Promise
((
resolve
,
reject
)
=>
{
cross_systemRequest
({
system
:
'zhangyou'
,
api
:
'/api/teaching_video/categoryList'
,
params
:
data
}).
then
((
res
)
=>
{
resolve
(
res
)
}).
catch
((
error
)
=>
{
reject
(
error
)
})
})
}
// 视频列表
export
function
teachingVideoVideoListApi
(
data
)
{
return
new
Promise
((
resolve
,
reject
)
=>
{
cross_systemRequest
({
system
:
'zhangyou'
,
api
:
'/api/teaching_video/videoList'
,
params
:
data
}).
then
((
res
)
=>
{
resolve
(
res
)
}).
catch
((
error
)
=>
{
reject
(
error
)
})
})
}
\ No newline at end of file
src/directive/copy/copy.js
0 → 100644
浏览文件 @
a5bbf545
import
Vue
from
'vue'
{
/* <iconpark-icon name="icon-fuzhi"></iconpark-icon> */
}
const
copy
=
{
// 当被绑定的元素插入到DOM中时
inserted
:
function
(
el
,
binding
)
{
// 创建复制图标元素
const
copyIcon
=
document
.
createElement
(
'iconpark-icon'
)
copyIcon
.
name
=
'icon-fuzhi'
copyIcon
.
style
.
cursor
=
'pointer'
copyIcon
.
style
.
marginLeft
=
'8px'
copyIcon
.
style
.
fontSize
=
'14px'
copyIcon
.
title
=
'点击复制'
// 设置元素的position为relative,确保图标的absolute定位正确
if
(
getComputedStyle
(
el
).
position
===
'static'
)
{
el
.
style
.
position
=
'relative'
}
// 添加复制图标到元素后面
el
.
insertBefore
(
copyIcon
,
el
.
nextSibling
)
// 复制功能实现
copyIcon
.
addEventListener
(
'click'
,
async
function
(
e
)
{
// 阻止事件冒泡
e
.
stopPropagation
()
try
{
// 获取要复制的内容
const
textToCopy
=
binding
.
value
||
''
if
(
!
textToCopy
)
{
Vue
.
prototype
.
$message
.
warning
(
'没有可复制的内容'
)
return
}
// 使用现代的剪贴板API
if
(
navigator
.
clipboard
&&
window
.
isSecureContext
)
{
await
navigator
.
clipboard
.
writeText
(
textToCopy
)
}
else
{
// 兼容旧版浏览器
const
textArea
=
document
.
createElement
(
'textarea'
)
textArea
.
value
=
textToCopy
textArea
.
style
.
position
=
'fixed'
textArea
.
style
.
left
=
'-999999px'
textArea
.
style
.
top
=
'-999999px'
document
.
body
.
appendChild
(
textArea
)
textArea
.
focus
()
textArea
.
select
()
// 执行复制命令
const
success
=
document
.
execCommand
(
'copy'
)
document
.
body
.
removeChild
(
textArea
)
if
(
!
success
)
{
throw
new
Error
(
'复制失败'
)
}
}
// 显示复制成功的提示
Vue
.
prototype
.
$message
.
success
(
'复制成功'
)
}
catch
(
error
)
{
console
.
error
(
'复制失败:'
,
error
)
Vue
.
prototype
.
$message
.
error
(
'复制失败,请手动复制'
)
}
})
// 存储图标引用,以便在组件卸载时清理
el
.
__copyIcon
=
copyIcon
},
// 当指令与元素解绑时
unbind
:
function
(
el
)
{
// 清理事件监听器和元素
if
(
el
.
__copyIcon
)
{
el
.
__copyIcon
.
removeEventListener
(
'click'
,
null
)
el
.
parentNode
.
removeChild
(
el
.
__copyIcon
)
delete
el
.
__copyIcon
}
}
}
export
default
copy
\ No newline at end of file
src/directive/copy/index.js
0 → 100644
浏览文件 @
a5bbf545
import
copy
from
'./copy.js'
const
install
=
function
(
Vue
)
{
Vue
.
directive
(
'copy'
,
copy
)
}
if
(
window
.
Vue
)
{
window
.
copy
=
copy
Vue
.
use
(
install
);
// eslint-disable-line
}
copy
.
install
=
install
export
default
copy
src/main.js
浏览文件 @
a5bbf545
...
...
@@ -15,6 +15,7 @@ import '@/styles/index.scss';
import
moment
from
'moment'
import
'@/styles/tailwind.css'
import
VConsole
from
'vconsole'
;
import
copy
from
'./directive/copy'
import
uploading
from
'@/utils/cos-upload'
import
errorHandle
from
'@/utils/errorHandle'
import
{
getParams
,
deepClone
}
from
'@/utils/index'
...
...
@@ -24,7 +25,7 @@ import loadmore from '@/directive/loadmore/index.js' // 加载更多
import
clickagain
from
'./directive/clickagain'
import
permission
from
'@/directive/permission/index.js'
// 权限判断指令
import
scroll
from
'@/directive/scroll'
// 下拉加载更多指令
Vue
.
use
(
globalComponent
).
use
(
permission
).
use
(
clickagain
).
use
(
loadmore
).
use
(
scroll
)
Vue
.
use
(
globalComponent
).
use
(
permission
).
use
(
clickagain
).
use
(
loadmore
).
use
(
scroll
)
.
use
(
copy
)
// 导入 VConsole 清理工具
import
'@/utils/vconsoleCleanup'
...
...
src/store/modules/user.js
浏览文件 @
a5bbf545
...
...
@@ -14,6 +14,7 @@ const state = {
external_userid
:
''
},
userid
:
Cookies
.
get
(
'userid'
),
weixin_blongs_id
:
Cookies
.
get
(
'weixin_blongs_id'
),
//客服号项目id
corp_id
:
''
,
external_userid
:
''
,
token
:
''
,
...
...
@@ -37,6 +38,10 @@ const state = {
}
const
mutations
=
{
set_weixin_blongs_id
(
state
,
weixin_blongs_id
){
state
.
weixin_blongs_id
=
weixin_blongs_id
Cookies
.
set
(
'weixin_blongs_id'
,
weixin_blongs_id
)
},
set_userInfo
(
state
,
userInfo
){
state
.
userInfo
=
userInfo
},
...
...
src/styles/index.scss
浏览文件 @
a5bbf545
...
...
@@ -537,6 +537,10 @@ li {
height
:
100%
;
font-size
:
300px
;
}
.el-loading-spinner
{
display
:
flex
;
justify-content
:
center
;
}
.el-loading-spinner
.circular
{
width
:
60px
!
important
;
...
...
src/views/components/InstructionalVideo/index.vue
0 → 100644
浏览文件 @
a5bbf545
<
template
>
<div
class=
"h-full flex flex-col"
>
<el-input
placeholder=
"请输入内容"
prefix-icon=
"el-icon-search"
v-model
.
trim=
"searchText"
>
</el-input>
<el-cascader
class=
"w-full mt-[8px]"
v-model=
"categoryValue"
:props=
"
{ emitPath: false, expandTrigger: 'click' }"
:options="categoryList"
@change="getVideoList"
>
</el-cascader>
<div
class=
"mt-[16px] space-y-[8px] flex-1 overflow-auto pb-[10px]"
>
<div
v-for=
"item in list"
:key=
"item.id"
class=
"flex justify-between items-center py-[3px] px-[8px] bottom-[1px] border border-[#E5E7EB] rounded-[4px]"
>
<div
class=
"text-[14px]"
>
{{
item
.
video_name
}}
</div>
<div
class=
"flex items-center"
>
<el-button
type=
"text"
size=
"small"
class=
"text-[12px] button-color-hover"
@
click=
"previewVideo(item)"
>
<div
class=
"flex items-center"
>
<iconpark-icon
name=
"xiaoxicaozuo-chakan"
class=
"mr-[4px]"
></iconpark-icon>
预览
</div>
</el-button>
<div
@
click=
"sendVideo(item)"
class=
"h-[24px] ml-[8px] cursor-pointer hover:bg-[#EAF7F3] text-[12px] w-[58px] p-0 flex justify-center items-center rounded-full bg-[#F7F8FA] text-[#00BF8A]"
>
<iconpark-icon
name=
"gongnengicon-kuaijiefasong"
class=
"text-[12px]"
></iconpark-icon>
<span>
发送
</span>
</div>
</div>
</div>
</div>
</div>
</
template
>
<
script
>
import
{
teachingVideoVideoListApi
,
teachingVideoCategoryListApi
,
}
from
"@/api/game"
;
import
{
mapMutations
,
mapState
}
from
"vuex"
;
import
{
sendChatMessage
}
from
"@/utils/index"
;
export
default
{
name
:
"InstructionalVideo"
,
data
()
{
return
{
searchText
:
""
,
categoryValue
:
{},
categoryList
:
[],
videoList
:
[],
};
},
mounted
()
{
this
.
getCategoryList
();
},
computed
:
{
...
mapState
(
"user"
,
[
"userInfo"
,
"weixin_blongs_id"
]),
list
()
{
return
this
.
videoList
.
filter
((
item
)
=>
item
.
video_name
.
includes
(
this
.
searchText
)
);
},
},
methods
:
{
...
mapMutations
(
"common"
,
[
"set_sendSkillMessage"
]),
// 视频分类
async
getCategoryList
()
{
console
.
log
(
this
.
userInfo
);
// return;
const
{
data
}
=
await
teachingVideoCategoryListApi
({
weixin_blongs_id
:
this
.
weixin_blongs_id
,
});
this
.
categoryList
=
this
.
formatCategoryList
(
data
);
},
formatCategoryList
(
data
)
{
return
data
.
map
((
item
)
=>
{
return
{
value
:
item
,
label
:
item
.
main_game_name
,
children
:
item
.
category
.
map
((
item
)
=>
({
value
:
item
,
label
:
item
.
category_name
,
})),
};
});
},
// 视频列表
async
getVideoList
()
{
if
(
!
this
.
categoryValue
.
id
)
{
return
;
}
const
{
data
}
=
await
teachingVideoVideoListApi
({
weixin_blongs_id
:
this
.
categoryValue
.
weixin_blongs_id
,
main_game_id
:
this
.
categoryValue
.
main_game_id
,
video_type
:
this
.
categoryValue
.
id
,
page
:
1
,
page_size
:
200
,
});
this
.
videoList
=
data
.
data
;
},
sendVideo
(
item
)
{
try
{
const
link
=
{
title
:
item
.
video_name
,
imgUrl
:
item
.
cover_url
||
""
,
desc
:
"点击观看教学视频"
,
link
:
item
.
video_url
,
};
sendChatMessage
(
link
,
"link"
);
}
catch
(
error
)
{
console
.
error
(
"发送视频链接失败:"
,
error
);
this
.
$message
({
message
:
"发送视频链接失败"
,
type
:
"error"
});
}
},
previewVideo
(
item
)
{
window
.
open
(
item
.
video_url
);
},
},
};
</
script
>
<
style
scoped
>
.button-color-hover.el-button--text
:hover
{
color
:
#00bf8a
!important
;
}
.button-color-hover.el-button--text
{
color
:
#86909c
;
}
</
style
>
src/views/components/quickSendGame/sendGame.vue
浏览文件 @
a5bbf545
差异被折叠。
点击展开。
src/views/components/roleInfo/roleInfoPanel.vue
浏览文件 @
a5bbf545
差异被折叠。
点击展开。
src/views/components/skill/crossLibrary.vue
浏览文件 @
a5bbf545
差异被折叠。
点击展开。
src/views/newLogin.vue
浏览文件 @
a5bbf545
差异被折叠。
点击展开。
src/views/quickReply.vue
浏览文件 @
a5bbf545
...
...
@@ -2,87 +2,81 @@
<div
class=
"details columnFlex"
>
<div
class=
"content search-form"
>
<el-tabs
v-model=
"activeName"
>
<el-tab-pane
label=
"个人话术"
name=
"personal"
>
<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
label=
"企业话术"
name=
"company"
>
<skillCompany
:active-name=
"activeName"
/>
</el-tab-pane>
<el-tab-pane
label=
"知识库"
name=
"library"
>
<el-tab-pane
label=
"知识库"
name=
"library"
>
<skillLibrary
v-if=
"activeName === 'library'"
:active-name=
"activeName"
/>
</el-tab-pane>
<el-tab-pane
label=
"跨主体知识库"
name=
"robotLibrary"
>
<el-tab-pane
label=
"跨主体知识库"
name=
"robotLibrary"
>
<crossLibrary
v-if=
"activeName === 'robotLibrary'"
:active-name=
"activeName"
/>
</el-tab-pane>
<el-tab-pane
label=
"教学视频"
name=
"instructionalVideo"
>
<InstructionalVideo
v-if=
"activeName === 'instructionalVideo'"
:active-name=
"activeName"
/>
</el-tab-pane>
</el-tabs>
</div>
</div>
</
template
>
<
script
>
import
skillCompany
from
'./components/skill/skillCompany.vue'
import
skillPersonal
from
'./components/skill/skillPersonal.vue'
import
skillLibrary
from
'./components/skill/skillLibrary.vue'
import
crossLibrary
from
'./components/skill/crossLibrary.vue'
import
{
mapActions
}
from
'vuex'
import
skillCompany
from
"./components/skill/skillCompany.vue"
;
import
skillPersonal
from
"./components/skill/skillPersonal.vue"
;
import
skillLibrary
from
"./components/skill/skillLibrary.vue"
;
import
crossLibrary
from
"./components/skill/crossLibrary.vue"
;
import
InstructionalVideo
from
"./components/InstructionalVideo/index.vue"
;
import
{
mapActions
}
from
"vuex"
;
export
default
{
name
:
'quickReply'
,
name
:
"quickReply"
,
components
:
{
skillCompany
,
skillPersonal
,
skillLibrary
,
crossLibrary
crossLibrary
,
InstructionalVideo
,
},
data
()
{
return
{
activeName
:
'personal'
}
},
created
()
{
activeName
:
"personal"
,
};
},
created
()
{},
mounted
()
{
this
.
initializeWecom
()
this
.
initializeWecom
()
;
},
methods
:
{
...
mapActions
(
'user'
,
[
'initWecom'
]),
...
mapActions
(
"user"
,
[
"initWecom"
]),
async
initializeWecom
()
{
try
{
console
.
log
(
'🚀 开始初始化企业微信 SDK'
)
const
result
=
await
this
.
initWecom
()
console
.
log
(
'✅ 企业微信 SDK 初始化成功'
,
result
)
console
.
log
(
"🚀 开始初始化企业微信 SDK"
);
const
result
=
await
this
.
initWecom
()
;
console
.
log
(
"✅ 企业微信 SDK 初始化成功"
,
result
);
}
catch
(
error
)
{
console
.
error
(
'❌ 企业微信 SDK 初始化失败:'
,
error
)
console
.
error
(
"❌ 企业微信 SDK 初始化失败:"
,
error
);
}
},
}
}
}
,
}
;
</
script
>
<
style
lang=
"scss"
scoped
>
.details
{
::v-deep
.el-tabs__nav-next,::v-deep
.el-tabs__nav-prev{
::v-deep
.el-tabs__nav-next,
::v-deep
.el-tabs__nav-prev
{
line-height
:
50px
;
}
width
:
100
%;
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论