Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
C
company_app
概览
概览
详情
活动
周期分析
版本库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
问题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
毛细亚
company_app
Commits
65c7e701
提交
65c7e701
authored
5月 21, 2025
作者:
毛细亚
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
修改钉钉扫码
上级
72b75eb3
显示空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
260 行增加
和
4 行删除
+260
-4
README.md
README.md
+3
-0
App.vue
src/App.vue
+0
-1
index.js
src/router/index.js
+30
-0
ddLogin.vue
src/views/ddLogin.vue
+1
-3
login.vue
src/views/login.vue
+226
-0
没有找到文件。
README.md
浏览文件 @
65c7e701
...
...
@@ -49,3 +49,5 @@
-
懒加载实现
## UI 规范
因为当前页面是在企微的侧边栏中打开的 所以需要适配企微的侧边栏样式 企微侧边栏 最大的宽度是 320px 所有页面需要适配320px的宽度,必须要使用自适应的方法 来开发页面 不能写死超过 320px 的宽度 宽度的样式一切都是可伸缩的
\ No newline at end of file
src/App.vue
浏览文件 @
65c7e701
...
...
@@ -2,7 +2,6 @@
<div
id=
"app"
>
<!--
<h1>
客服id:
{{
userInfo
.
userid
}}
</h1>
<h1>
客户id:
{{
userInfo
.
externalUserId
}}
</h1>
-->
<DdLogin/>
<router-view
/>
</div>
</
template
>
...
...
src/router/index.js
浏览文件 @
65c7e701
import
Vue
from
'vue'
import
VueRouter
from
'vue-router'
import
HomeView
from
'../views/HomeView.vue'
import
Cookies
from
'js-cookie'
Vue
.
use
(
VueRouter
)
const
routes
=
[
{
path
:
'/login'
,
name
:
'login'
,
component
:
()
=>
import
(
'../views/login.vue'
)
},
{
path
:
'/'
,
name
:
'home'
,
component
:
HomeView
...
...
@@ -24,4 +30,28 @@ const router = new VueRouter({
base
:
process
.
env
.
BASE_URL
,
routes
})
// router/index.js
router
.
beforeEach
((
to
,
from
,
next
)
=>
{
// 需要登录态的页面
const
needAuth
=
!
[
'/login'
].
includes
(
to
.
path
)
// 检查登录信息
const
wecomUserId
=
Cookies
.
get
(
'wecom_userid'
)
const
dingUserId
=
Cookies
.
get
(
'ding_userid'
)
const
externalUserId
=
Cookies
.
get
(
'wecom_external_userid'
)
if
(
needAuth
)
{
if
(
wecomUserId
&&
dingUserId
&&
externalUserId
)
{
// 登录信息齐全,允许进入
next
()
}
else
{
// 缺少登录信息,跳转到登录页
next
(
'/login'
)
}
}
else
{
// 登录页、回调页等不需要校验
next
()
}
})
export
default
router
src/views/ddLogin.vue
浏览文件 @
65c7e701
...
...
@@ -52,9 +52,7 @@ export default {
if
(
res
.
status_code
===
1
)
{
this
.
organizationList
=
res
.
data
.
data
this
.
initCurrentApp
();
this
.
$nextTick
(()
=>
{
this
.
dingInit
();
});
}
},
...
...
src/views/login.vue
0 → 100644
浏览文件 @
65c7e701
// UnifiedLogin.vue
<
template
>
<div>
<div>
<div>
当前组织:
<span
class=
"current-org"
>
{{
currentOrg
.
name
}}
</span>
<el-button
type=
"text"
@
click=
"showOrgDialog = true"
>
切换组织
</el-button>
</div>
<div
id=
"dingTalkLoginContainer"
></div>
<!-- 组织切换弹窗 -->
<el-dialog
:visible
.
sync=
"showOrgDialog"
width=
"300px"
title=
"选择组织"
>
<ul
style=
"list-style:none;padding:0;margin-top: -20px;"
>
<li
v-for=
"org in orgList"
:key=
"org.app_key"
@
click=
"switchOrg(org)"
:style=
"
{
padding: '8px 16px',
cursor: 'pointer',
background: org.app_key === currentOrg.app_key ? '#e6f7ff' : '',
color: org.app_key === currentOrg.app_key ? '#1890ff' : '',
fontWeight: org.app_key === currentOrg.app_key ? 'bold' : 'normal',
borderRadius: '4px',
marginBottom: '4px',
transition: 'background 0.2s'
}"
@mouseover="hoveredOrg = org.app_key"
@mouseleave="hoveredOrg = null"
>
{{
org
.
name
}}
<span
v-if=
"org.app_key === currentOrg.app_key"
style=
"margin-left:8px;"
>
(当前)
</span>
</li>
</ul>
</el-dialog>
<div
v-if=
"dingUserInfo"
>
钉钉用户:
{{
dingUserInfo
.
name
}}
</div>
<div
v-if=
"externalUserId"
>
企微外部联系人ID:
{{
externalUserId
}}
</div>
</div>
</div>
</
template
>
<
script
>
import
*
as
ww
from
'@wecom/jssdk'
import
{
getOrganization
}
from
'@/api/user'
import
Cookies
from
'js-cookie'
export
default
{
data
()
{
return
{
wecomUserInfo
:
null
,
// 企微用户信息
dingUserInfo
:
null
,
// 钉钉用户信息
externalUserId
:
null
,
// 企微外部联系人ID
signData
:
null
,
// 企微签名数据
orgList
:
[],
currentOrg
:
{},
showOrgDialog
:
false
,
hoveredOrg
:
null
,
}
},
mounted
()
{
this
.
$nextTick
(
()
=>
{
// await this.startWeComSilentAuth();
this
.
initOrganization
();
this
.
initDingTalkLogin
();
})
},
/*
1.把钉钉的逻辑中所有用的 appid 换成已选中的组织的 appid 也就是 this.currentOrg.app_key
2.点击切换切换组织没反应 并且给切换组织加点样式优化一下
*/
methods
:
{
// 1. 企微静默授权
async
startWeComSilentAuth
()
{
const
urlParams
=
this
.
getQueryParams
();
if
(
!
urlParams
.
code
)
{
// 跳转企微静默授权
const
redirectUri
=
encodeURIComponent
(
window
.
location
.
href
);
const
appid
=
'你的企微CorpID'
;
const
authUrl
=
`https://open.weixin.qq.com/connect/oauth2/authorize?appid=
${
appid
}
&redirect_uri=
${
redirectUri
}
&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect`
;
window
.
location
.
href
=
authUrl
;
return
;
}
// 用code换取用户信息和签名
const
res
=
await
this
.
$api
.
getWeComUserAndSignature
({
code
:
urlParams
.
code
,
url
:
window
.
location
.
href
});
if
(
res
.
status_code
===
1
)
{
this
.
wecomUserInfo
=
res
.
data
.
userInfo
;
this
.
signData
=
res
.
data
.
signData
;
// 注册JS-SDK
this
.
registerWeComSDK
();
// 初始化钉钉扫码
this
.
initDingTalkLogin
();
}
else
{
// 错误处理
}
},
// 2. 注册企微JS-SDK
registerWeComSDK
()
{
ww
.
register
({
corpId
:
this
.
signData
.
corp_id
,
agentId
:
this
.
signData
.
agent_id
,
jsApiList
:
[
'getCurExternalContact'
],
getConfigSignature
:
()
=>
Promise
.
resolve
({
nonceStr
:
this
.
signData
.
nonceStr
,
timestamp
:
this
.
signData
.
timestamp
,
signature
:
this
.
signData
.
corp_signature
,
}),
getAgentConfigSignature
:
()
=>
Promise
.
resolve
({
nonceStr
:
this
.
signData
.
nonceStr
,
timestamp
:
this
.
signData
.
timestamp
,
signature
:
this
.
signData
.
agent_signature
,
}),
onAgentConfigSuccess
:
()
=>
{
// 注册成功后不立即获取外部联系人,等钉钉扫码后再获取
},
onAgentConfigFail
:
(
err
)
=>
{
// 错误处理
}
});
},
// 3. 获取组织列表并选取默认组织
async
initOrganization
()
{
const
res
=
await
getOrganization
();
if
(
res
.
status_code
===
1
)
{
this
.
orgList
=
res
.
data
.
data
;
// 默认组织逻辑:可根据业务自定义
this
.
initCurrentApp
();
}
},
initCurrentApp
()
{
const
currentApp
=
this
.
orgList
.
find
(
(
item
)
=>
item
.
app_key
===
"dingjigp0ksn9nbljdli"
);
this
.
$set
(
this
,
"currentOrg"
,
currentApp
);
},
// 4. 初始化钉钉扫码
initDingTalkLogin
()
{
if
(
!
this
.
currentOrg
.
app_key
)
return
;
const
appid
=
this
.
currentOrg
.
app_key
;
const
redirectUri
=
encodeURIComponent
(
window
.
location
.
origin
+
'/ding-callback'
);
// 清空二维码容器,防止切换组织后二维码不刷新
const
container
=
document
.
getElementById
(
'dingTalkLoginContainer'
);
if
(
container
)
container
.
innerHTML
=
''
;
DDLogin
({
id
:
'dingTalkLoginContainer'
,
goto
:
encodeURIComponent
(
`https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=
${
appid
}
&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=
${
redirectUri
}
`
),
style
:
'border:none;background-color:#FFFFFF;margin:0'
,
width
:
'210'
,
height
:
'250'
});
window
.
addEventListener
(
'message'
,
this
.
handleDingTalkLogin
,
false
);
},
// 5. 切换组织
switchOrg
(
org
)
{
if
(
org
.
app_key
===
this
.
currentOrg
.
app_key
)
return
;
// 已是当前组织不处理
this
.
currentOrg
=
org
;
this
.
showOrgDialog
=
false
;
this
.
initDingTalkLogin
();
},
// 6. 钉钉扫码回调
async
handleDingTalkLogin
(
event
)
{
if
(
event
.
origin
!==
'https://login.dingtalk.com'
)
return
;
const
loginTmpCode
=
event
.
data
;
// 跳转到后端,后端用loginTmpCode换取钉钉用户信息
const
redirectUri
=
encodeURIComponent
(
window
.
location
.
origin
);
const
appid
=
this
.
currentOrg
.
app_key
;
const
url
=
`https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=
${
appid
}
&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=
${
redirectUri
}
&loginTmpCode=
${
loginTmpCode
}
`
;
window
.
location
.
href
=
url
;
},
// 7. 钉钉扫码回调页面处理
async
handleDingCallback
()
{
const
{
code
}
=
this
.
getQueryParams
();
if
(
!
code
)
return
;
// 用code换取钉钉用户信息
const
res
=
await
this
.
$api
.
getDingUser
({
code
});
if
(
res
.
status_code
===
1
)
{
this
.
dingUserInfo
=
res
.
data
;
// 再次校验企微签名(可选,若页面未刷新可省略)
// this.registerWeComSDK();
// 获取外部联系人
this
.
getCurExternalContact
();
}
else
{
// 错误处理
}
},
// 8. 获取企微外部联系人
getCurExternalContact
()
{
ww
.
getCurExternalContact
({
success
:
(
res
)
=>
{
if
(
res
.
err_msg
===
"getCurExternalContact:ok"
)
{
this
.
externalUserId
=
res
.
userId
;
}
},
fail
:
(
err
)
=>
{
// 错误处理
}
});
},
// 工具方法:解析URL参数
getQueryParams
()
{
const
params
=
{};
window
.
location
.
search
.
replace
(
/
[
?&
]
+
([^
=&
]
+
)
=
([^
&
]
*
)
/gi
,
function
(
str
,
key
,
value
)
{
params
[
key
]
=
value
;
});
return
params
;
}
},
created
()
{
// 如果是钉钉扫码回调页面
if
(
window
.
location
.
pathname
===
'/ding-callback'
)
{
this
.
handleDingCallback
();
}
}
}
</
script
>
<
style
lang=
"scss"
scoped
>
.current-org
{
font-weight
:
bold
;
margin-right
:
5px
;
}
</
style
>
\ No newline at end of file
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论