Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
company_app
概览
概览
详情
活动
周期分析
版本库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
毛细亚
company_app
Commits
2f879c47
提交
2f879c47
authored
7月 21, 2025
作者:
毛细亚
浏览文件
操作
浏览文件
下载
差异文件
Merge branch '6.3' into 6.5
上级
4b6ae3ab
8fa1cd1f
显示空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
396 行增加
和
5 行删除
+396
-5
App.vue
src/App.vue
+1
-1
user.js
src/api/user.js
+16
-2
index.js
src/router/index.js
+1
-1
newLogin.vue
src/views/newLogin.vue
+377
-0
userInfo.vue
src/views/userInfo/userInfo.vue
+1
-1
没有找到文件。
src/App.vue
浏览文件 @
2f879c47
...
@@ -144,7 +144,7 @@ export default {
...
@@ -144,7 +144,7 @@ export default {
// 监听用户信息变化,只在初始化时获取一次任务数据
// 监听用户信息变化,只在初始化时获取一次任务数据
userInfo
:
{
userInfo
:
{
handler
(
newVal
,
oldVal
)
{
handler
(
newVal
,
oldVal
)
{
if
(
newVal
&&
newVal
.
id
&&
(
!
oldVal
||
!
oldVal
.
id
))
{
if
(
newVal
&&
newVal
.
id
&&
(
!
oldVal
||
!
oldVal
.
id
)
&&
this
.
token
)
{
console
.
log
(
'用户信息初始化完成,获取任务数据:'
,
newVal
)
console
.
log
(
'用户信息初始化完成,获取任务数据:'
,
newVal
)
// 只在用户信息第一次设置时获取任务数据
// 只在用户信息第一次设置时获取任务数据
this
.
getTaskUnReadData
()
this
.
getTaskUnReadData
()
...
...
src/api/user.js
浏览文件 @
2f879c47
...
@@ -125,6 +125,20 @@ export function getClientStatus(data) {
...
@@ -125,6 +125,20 @@ export function getClientStatus(data) {
data
data
})
})
}
}
// 获取客服号绑定的客服人员
export
function
getUserList
(
data
)
{
return
request
({
url
:
'/api/corp/getCserByUser'
,
method
:
'post'
,
data
})
}
// 选择客服人员登录
export
function
cserSelected
(
data
)
{
return
request
({
url
:
'/api/sidebar_login/cserSelected'
,
method
:
'post'
,
data
})
}
src/router/index.js
浏览文件 @
2f879c47
...
@@ -86,7 +86,7 @@ const routes = [
...
@@ -86,7 +86,7 @@ const routes = [
{
{
path
:
'/login'
,
path
:
'/login'
,
name
:
'login'
,
name
:
'login'
,
component
:
()
=>
import
(
'../views/
l
ogin.vue'
)
component
:
()
=>
import
(
'../views/
newL
ogin.vue'
)
},
},
]
]
const
router
=
new
VueRouter
({
const
router
=
new
VueRouter
({
...
...
src/views/newLogin.vue
0 → 100644
浏览文件 @
2f879c47
// UnifiedLogin.vue
<
template
>
<div
class=
"loginContent"
>
<div
class=
"loginContentContainer"
>
<p
class=
"loginContentTitle"
>
选择客服:
</p>
<div
class=
"loginContentInput rowFlex alignCenter"
>
<el-select
v-model=
"cser_user_id"
filterable
placeholder=
"请选择客服"
>
<el-option
v-for=
"item in userList"
:key=
"item.zq_user_id"
clearable
:label=
"item.name"
:value=
"item.zq_user_id"
>
</el-option>
</el-select>
<el-button
type=
"primary"
style=
"margin-left: 10px;"
size=
"small"
@
click=
"loginConfirm"
>
点击登录
</el-button>
</div>
</div>
</div>
</
template
>
<
script
>
import
*
as
ww
from
'@wecom/jssdk'
import
{
getOrganization
,
getAuthUser
,
getSignature
,
getUserList
,
cserSelected
}
from
'@/api/user'
import
Cookies
from
'js-cookie'
import
{
getParams
}
from
'@/utils/index'
import
{
mapMutations
,
mapState
}
from
'vuex'
import
{
getToken
,
setToken
}
from
'@/utils/auth'
import
jsApiList
from
'@/utils/jsApiList'
export
default
{
name
:
'login'
,
components
:
{
},
data
()
{
return
{
wecomUserInfo
:
null
,
// 企微用户信息
dingUserInfo
:
null
,
// 钉钉用户信息
signData
:
null
,
// 企微签名数据
orgList
:
[],
organizationNum
:
5
,
urlParams
:
{},
currentOrg
:
{},
showOrgDialog
:
false
,
hoveredOrg
:
null
,
showRefresh
:
false
,
// 控制刷新按钮显示
qrLoading
:
false
,
// 控制二维码 loading
redirectUri
:
process
.
env
.
NODE_ENV
===
'production'
?
'https://companywx.zwnet.cn/api/api/sidebar_login/ding'
:
'https://companywx.zwwlkj03.top/api/api/sidebar_login/ding'
,
DDTestUrl
:
''
,
token
:
getToken
(),
userList
:
[],
cser_user_id
:
null
,
}
},
async
mounted
()
{
this
.
$nextTick
(()
=>
{
this
.
initLogin
()
})
},
computed
:
{
...
mapState
(
'user'
,
[
'corp_id'
])
},
methods
:
{
...
mapMutations
(
'user'
,
[
'set_corp_id'
,
'set_userid'
,
'set_userInfo'
,
'set_token'
,
'set_cser_info'
,
'set_signData'
,
'set_cser_id'
,
'set_cser_name'
,
'set_external_userid'
]),
async
initLogin
()
{
const
urlParams
=
getParams
();
const
userid
=
Cookies
.
get
(
'userid'
);
if
(
this
.
token
&&
userid
)
{
// 已经钉钉扫码过 重新获取授权 获取签名 注册企微js-sdk
this
.
getUserList
(
userid
)
await
this
.
getSignature
();
}
else
if
(
!
userid
)
{
await
this
.
startWeComSilentAuth
();
}
else
if
(
!
this
.
token
){
this
.
getUserList
(
userid
)
}
},
async
getUserList
(
userid
)
{
this
.
urlParams
=
getParams
();
const
corp_id
=
Cookies
.
get
(
'corp_id'
)
||
this
.
urlParams
.
corp_id
const
res
=
await
getUserList
({
userid
:
userid
,
corp_id
:
corp_id
});
this
.
userList
=
res
.
data
},
async
userStartLogin
(){
if
(
!
this
.
cser_user_id
){
this
.
$message
.
error
(
'请选择客服人员'
)
return
}
const
cser_user
=
this
.
userList
.
find
(
item
=>
item
.
zq_user_id
===
this
.
cser_user_id
)
const
corp_id
=
Cookies
.
get
(
'corp_id'
)
const
userid
=
Cookies
.
get
(
'userid'
)
this
.
cacheCser
(
cser_user
.
zq_user_id
,
cser_user
.
name
)
try
{
const
res
=
await
cserSelected
({
cser_id
:
cser_user
.
zq_user_id
,
corp_id
:
corp_id
,
userid
:
userid
});
console
.
log
(
res
,
'选择客服人员登录'
)
if
(
res
.
status_code
===
1
&&
res
.
data
.
tokens
){
this
.
$message
({
type
:
'warning'
,
message
:
`当前【
${
cser_user
.
name
}
】已上线,下班后请记得点击下线哦~`
,
duration
:
3
*
1000
})
setTimeout
(()
=>
{
this
.
handleDingCallback
(
res
.
data
.
tokens
)
},
2000
)
}
else
{
this
.
$message
.
error
(
res
.
msg
)
setTimeout
(()
=>
{
window
.
location
.
href
=
window
.
location
.
origin
+
'/company_app/index.html?corp_id='
+
corp_id
+
'&msg=cser_error'
},
5000
)
}
}
catch
(
error
)
{
console
.
log
(
error
,
'选择客服人员登录失败'
)
this
.
$message
.
error
(
error
.
msg
)
setTimeout
(()
=>
{
window
.
location
.
href
=
window
.
location
.
origin
+
'/company_app/index.html?corp_id='
+
corp_id
+
'&msg=cser_error'
},
5000
)
}
},
loginConfirm
(){
const
cser_user
=
this
.
userList
.
find
(
item
=>
item
.
zq_user_id
===
this
.
cser_user_id
)
this
.
$confirm
(
`确认登录上线吗,上线后所有会话都会归属到客服【
${
cser_user
.
name
}
】`
,
'提示'
,
{
confirmButtonText
:
'确定'
,
cancelButtonText
:
'取消'
,
type
:
'warning'
}).
then
(()
=>
{
this
.
userStartLogin
()
}).
catch
(()
=>
{
this
.
$message
.
info
(
'已取消登录'
)
})
},
// 设置缓存
cacheCorp_id
(
corp_id
)
{
Cookies
.
set
(
'corp_id'
,
corp_id
,
{
expires
:
7
})
this
.
set_corp_id
(
corp_id
)
},
cacheuserid
(
userid
)
{
Cookies
.
set
(
'userid'
,
userid
,
{
expires
:
7
})
this
.
set_userid
(
userid
)
},
cacheCser
(
cser_id
,
cser_name
)
{
Cookies
.
set
(
'cser_id'
,
cser_id
,
{
expires
:
7
})
Cookies
.
set
(
'cser_name'
,
cser_name
,
{
expires
:
7
})
this
.
set_cser_info
({
cser_id
:
cser_id
,
cser_name
:
cser_name
})
this
.
set_cser_id
(
cser_id
)
this
.
set_cser_name
(
cser_name
)
},
cacheSignData
(
signData
)
{
Cookies
.
set
(
'signData'
,
JSON
.
stringify
(
signData
),
{
expires
:
7
})
this
.
set_signData
(
signData
)
},
// 进入的页面地址是 https://companywx.jianshuwenhua.com/company_app/index.html?corp_id=wweaefe716636df3d1
// 1. 企微静默授权
async
startWeComSilentAuth
()
{
this
.
urlParams
=
getParams
();
const
corp_id
=
Cookies
.
get
(
'corp_id'
)
||
this
.
urlParams
.
corp_id
if
(
!
corp_id
)
{
this
.
$message
.
error
(
'当前客服号信息异常,请切换会话后重试'
)
return
}
// 确定是第一次进入页面 没有 code 和 state
if
(
!
this
.
urlParams
.
code
&&
!
this
.
urlParams
.
state
)
{
// 跳转企微静默授权
const
redirectUri
=
encodeURIComponent
(
window
.
location
.
href
);
const
authUrl
=
`https://open.weixin.qq.com/connect/oauth2/authorize?appid=
${
corp_id
}
&redirect_uri=
${
redirectUri
}
&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect`
;
window
.
location
.
href
=
authUrl
;
return
;
}
// 用code
const
res
=
await
getAuthUser
({
code
:
this
.
urlParams
.
code
,
url
:
window
.
location
.
href
,
corp_id
:
corp_id
});
if
(
res
.
status_code
===
1
)
{
if
(
res
.
data
.
userid
){
this
.
cacheuserid
(
res
.
data
.
userid
)
this
.
getUserList
(
res
.
data
.
userid
)
}
else
{
this
.
$message
.
error
(
'获取用户id失败'
)
return
}
}
else
{
console
.
log
(
'获取useid失败'
,
res
)
// 错误处理
}
},
async
getSignature
()
{
console
.
log
(
'获取签名'
,
window
.
location
.
href
)
const
corp_id
=
Cookies
.
get
(
'corp_id'
)
try
{
const
res
=
await
getSignature
({
corp_id
:
corp_id
,
path
:
window
.
location
.
href
});
if
(
res
.
status_code
===
1
)
{
this
.
signData
=
res
.
data
this
.
cacheSignData
(
res
.
data
)
try
{
this
.
registerWeComSDK
();
}
catch
(
err
)
{
console
.
log
(
err
,
'初始化sdk 失败'
)
}
}
}
catch
(
err
)
{
console
.
log
(
err
,
'获取签名失败'
)
window
.
location
.
href
=
window
.
location
.
origin
+
'/company_app/index.html?corp_id='
+
corp_id
+
'&msg=signerror'
}
},
getCurExternalContact
()
{
this
.
$ww
.
getCurExternalContact
({
success
:
(
res
)
=>
{
if
(
res
.
err_msg
===
"getCurExternalContact:ok"
)
{
console
.
log
(
res
,
'重新进入获取企微外部联系人'
)
this
.
set_external_userid
(
res
.
userId
)
// 确保 Vuex 状态更新后再跳转
this
.
$nextTick
(()
=>
{
this
.
$router
.
replace
(
'/'
)
console
.
log
(
window
.
location
.
href
,
'window.location.hrefuserInfo'
)
})
}
},
fail
:
(
err
)
=>
{
console
.
log
(
err
,
'获取企微外部联系人失败'
)
// 错误处理
}
});
},
// 2. 注册企微JS-SDK
registerWeComSDK
()
{
console
.
log
(
'删除企业签名'
,
1231
)
this
.
$ww
.
register
({
corpId
:
Cookies
.
get
(
'corp_id'
),
agentId
:
this
.
signData
.
agent_id
,
jsApiList
:
jsApiList
,
// getConfigSignature: () => Promise.resolve({
// nonceStr: this.signData.nonce_str,
// timestamp: this.signData.signature_time,
// signature: this.signData.corp_signature,
// }),
// 只用到应用的 api 可以只进行应用的签名
getAgentConfigSignature
:
()
=>
Promise
.
resolve
({
nonceStr
:
this
.
signData
.
nonce_str
,
timestamp
:
this
.
signData
.
signature_time
,
signature
:
this
.
signData
.
agent_signature
,
}),
onAgentConfigSuccess
:
(
res
)
=>
{
console
.
log
(
'注册成功可以调用企微 js-sdk'
,
res
)
// 注册成功后不立即获取外部联系人,等钉钉扫码后再获取
this
.
getCurExternalContact
()
},
onAgentConfigFail
:
(
err
)
=>
{
console
.
log
(
'注册失败不能使用企微js-sdk'
,
err
)
// 错误处理123
}
});
},
// 3. 获取组织列表并选取默认组织
async
initOrganization
()
{
const
res
=
await
getOrganization
();
if
(
res
.
data
.
status_code
===
1
)
{
this
.
orgList
=
res
.
data
.
data
.
data
.
filter
(
item
=>
item
.
id
<=
this
.
organizationNum
)
// 默认组织逻辑:可根据业务自定义
this
.
initCurrentApp
();
}
},
initCurrentApp
()
{
const
currentApp
=
this
.
orgList
.
find
(
(
item
)
=>
item
.
app_key
===
"dingjigp0ksn9nbljdli"
);
this
.
$set
(
this
,
"currentOrg"
,
currentApp
);
},
// 7. 钉钉扫码回调页面处理
async
handleDingCallback
(
token
)
{
// 在这里处理钉钉扫码成功的回调
const
corp_id
=
Cookies
.
get
(
'corp_id'
)
if
(
token
&&
token
!=
'undefined'
)
{
setToken
(
token
)
this
.
set_token
(
token
)
// 获取签名
await
this
.
getSignature
();
}
else
{
window
.
location
.
href
=
window
.
location
.
origin
+
'/company_app/index.html?corp_id='
+
corp_id
+
'&msg=notoken'
}
},
},
}
</
script
>
<
style
lang=
"scss"
scoped
>
.current-org
{
font-weight
:
bold
;
margin-right
:
5px
;
}
.loginContent
{
display
:
flex
;
flex-direction
:
column
;
align-items
:
center
;
justify-content
:
center
;
}
.loginContentTitle
{
font-size
:
14px
;
line-height
:
32px
;
margin-right
:
10px
;
text-align
:
left
;
}
.qr-contain
{
margin
:
0
auto
;
/* margin-top: 20px; */
width
:
260px
;
height
:
260px
;
position
:
relative
;
overflow
:
hidden
;
#dingTalkLoginContainer
{
padding
:
15px
;
position
:
absolute
;
left
:
10px
;
bottom
:
0
;
}
.refresh
{
display
:
none
;
text-align
:
center
;
position
:
absolute
;
width
:
40px
;
background
:
#fff
;
height
:
40px
;
transform
:
translate
(
-50%
,
-50%
);
left
:
50%
;
top
:
50%
;
i
{
line-height
:
40px
;
font-size
:
26px
;
color
:
#3491FA
;
cursor
:
pointer
;
}
}
&
:hover
{
.refresh
{
display
:
block
;
}
}
}
.loading
{
position
:
absolute
;
left
:
0
;
top
:
0
;
width
:
100%
;
height
:
100%
;
background
:
rgba
(
255
,
255
,
255
,
0.7
);
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
z-index
:
20
;
transition
:
opacity
0.3s
;
}
.loading-spinner
{
width
:
40px
;
height
:
40px
;
border
:
4px
solid
#e0e0e0
;
border-top
:
4px
solid
#3491FA
;
border-radius
:
50%
;
animation
:
spin
1s
linear
infinite
;
}
@keyframes
spin
{
0
%
{
transform
:
rotate
(
0deg
);
}
100
%
{
transform
:
rotate
(
360deg
);
}
}
</
style
>
\ No newline at end of file
src/views/userInfo/userInfo.vue
浏览文件 @
2f879c47
...
@@ -22,7 +22,7 @@ import roleInfo from '@/views/roleInfo.vue'
...
@@ -22,7 +22,7 @@ import roleInfo from '@/views/roleInfo.vue'
import
orderList
from
'@/views/orderList.vue'
import
orderList
from
'@/views/orderList.vue'
import
violationRecord
from
'@/views/ViolationRecord.vue'
import
violationRecord
from
'@/views/ViolationRecord.vue'
import
{
mapState
,
mapMutations
}
from
'vuex'
import
{
mapState
,
mapMutations
}
from
'vuex'
import
Cookies
from
'js-cookie'
export
default
{
export
default
{
name
:
'userInfo'
,
name
:
'userInfo'
,
components
:
{
components
:
{
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论