Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
提交反馈
为 GitLab 提交贡献
登录
切换导航
功
功能演示系统
项目
项目
详情
动态
版本
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
示例
功能演示系统
提交
0dc2f7ca
提交
0dc2f7ca
编写于
11月 02, 2022
作者:
ibizdev
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
ShineKOT 发布系统代码 [后台服务,演示应用]
上级
30265302
变更
30
隐藏空白字符变更
内嵌
并排
正在显示
30 个修改的文件
包含
1922 行增加
和
4 行删除
+1922
-4
dingding.svg
app_Web/public/assets/img/dingding.svg
+1
-0
qiyeweixin.svg
app_Web/public/assets/img/qiyeweixin.svg
+1
-0
app-register.ts
app_Web/src/app-register.ts
+20
-0
dingding.svg
app_Web/src/assets/img/dingding.svg
+1
-0
qiyeweixin.svg
app_Web/src/assets/img/qiyeweixin.svg
+1
-0
app-login-button.less
...yout-element/login/app-login-button/app-login-button.less
+3
-0
app-login-button.vue
...ayout-element/login/app-login-button/app-login-button.vue
+26
-0
app-login-captcha.vue
...out-element/login/app-login-captcha/app-login-captcha.vue
+61
-0
reset.png
...element/login/app-login-captcha/vue-puzzle-code/reset.png
+0
-0
vue-puzzle-code.less
...in/app-login-captcha/vue-puzzle-code/vue-puzzle-code.less
+239
-0
vue-puzzle-code.vue
...gin/app-login-captcha/vue-puzzle-code/vue-puzzle-code.vue
+578
-0
app-login-input.vue
.../layout-element/login/app-login-input/app-login-input.vue
+32
-0
app-login-message.less
...ut-element/login/app-login-message/app-login-message.less
+15
-0
app-login-message.vue
...out-element/login/app-login-message/app-login-message.vue
+26
-0
app-login-note-verify.less
...nt/login/app-login-note-verify/app-login-note-verify.less
+21
-0
app-login-note-verify.vue
...ent/login/app-login-note-verify/app-login-note-verify.vue
+153
-0
app-login-org.less
...nts/layout-element/login/app-login-org/app-login-org.less
+34
-0
app-login-org.vue
...ents/layout-element/login/app-login-org/app-login-org.vue
+129
-0
app-login-third.less
...layout-element/login/app-login-third/app-login-third.less
+11
-0
app-login-third.vue
.../layout-element/login/app-login-third/app-login-third.vue
+310
-0
app-preset-caption.less
...t-element/text/app-preset-caption/app-preset-caption.less
+9
-0
app-preset-caption.vue
...ut-element/text/app-preset-caption/app-preset-caption.vue
+16
-0
app-preset-text.less
.../layout-element/text/app-preset-text/app-preset-text.less
+4
-0
app-preset-text.vue
...s/layout-element/text/app-preset-text/app-preset-text.vue
+172
-0
app-preset-title.less
...ayout-element/text/app-preset-title/app-preset-title.less
+5
-0
app-preset-title.vue
...layout-element/text/app-preset-title/app-preset-title.vue
+32
-0
components_en_US_base.ts
...Web/src/locale/lanres/components/components_en_US_base.ts
+9
-0
components_zh_CN_base.ts
...Web/src/locale/lanres/components/components_zh_CN_base.ts
+9
-0
default-searchform-base.vue
...s/ibizbook/default-searchform/default-searchform-base.vue
+2
-2
quicksearchform-searchform-base.vue
...searchform-searchform/quicksearchform-searchform-base.vue
+2
-2
未找到文件。
app_Web/public/assets/img/dingding.svg
0 → 100644
浏览文件 @
0dc2f7ca
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
t=
"1616652640756"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"651"
width=
"48"
height=
"48"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
><defs><style
type=
"text/css"
></style></defs><path
d=
"M512 2C230.2 2 2 230.2 2 512s228.2 510 510 510 510-228.2 510-510S793.3 2 512 2z m235.9 442c-1 4.6-3.6 10.8-7.2 19.1l-0.5 0.5c-21.6 45.8-77.3 135.5-77.3 135.5l-0.5-0.5-16.5 28.3h78.8L574.3 826.8l34-136h-61.8l21.6-90.2c-17.5 4.1-38.1 9.8-62.3 18 0 0-33 19.1-94.8-37.1 0 0-41.7-37.1-17.5-45.8 10.3-4.1 50-8.8 81.4-12.9 42.2-5.7 68.5-8.8 68.5-8.8s-130.3 2.1-161.2-3.1c-30.9-4.6-70.1-56.7-78.3-102 0 0-12.9-24.7 27.8-12.9 40.2 11.8 209.2 45.8 209.2 45.8S321.4 375 307 358.5c-14.4-16.5-42.8-89.6-39.2-134.5 0 0 1.5-11.3 12.9-8.2 0 0 161.8 74.2 272.5 114.4C664.5 371.4 760.8 392 747.9 444z"
fill=
"#3296FA"
p-id=
"652"
></path></svg>
\ No newline at end of file
app_Web/public/assets/img/qiyeweixin.svg
0 → 100644
浏览文件 @
0dc2f7ca
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
t=
"1616652700601"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"973"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"48"
height=
"48"
><defs><style
type=
"text/css"
></style></defs><path
d=
"M512 2c281.7 0 510 228.3 510 510s-228.3 510-510 510S2 793.7 2 512 230.3 2 512 2z m159.8 680.3c-4 3.9-4 10.2-0.2 14.1 0.4 0.5 0.9 0.9 1.5 1.2 22.1 20.4 36.4 47.9 40.4 77.7 6.2 22.4 29.7 35.7 52.4 29.5 22.5-5.9 35.9-28.9 30-51.3 0-0.1-0.1-0.2-0.1-0.4-4.7-16.8-19.3-29.1-36.7-30.8-28-5.1-53.5-19.2-72.8-40.1-4.1-3.8-10.5-3.8-14.5 0.1z m-225.7-483c-76.4 8.3-145.8 40.6-195.6 91-19.4 19.4-35.5 41.8-47.8 66.3-37.7 74.9-31.4 164.4 16.5 233.2 13.5 20.2 35.8 45.4 56.1 63.3l-9.2 71.3-1 3c-0.3 0.9-0.3 1.9-0.4 2.8l-0.2 2.3 0.2 2.3c1.2 12.7 12.5 22 25.2 20.9 3.5-0.3 6.8-1.4 9.8-3.1h0.4l1.4-1 22-10.8 65.5-32.5c31.1 8.8 63.4 13.2 95.8 13 40 0.1 79.8-6.7 117.5-20.2-18.8-6-30.9-24.3-29-44-39 12.4-80.2 16.4-120.8 11.9l-6.5-0.9c-14.7-1.9-29.2-4.9-43.4-8.9-7.8-2.4-16.1-1.5-23.3 2.4l-1.8 0.9-53.9 31.3-2.3 1.4c-1.3 0.7-1.9 1-2.6 1-2-0.1-3.5-1.8-3.4-3.8l2-8.2 2.4-8.9 3.9-14.7 4.5-16.4c3-9.2-0.3-19.2-8.2-24.8-21.1-15.5-39.5-34.4-54.4-56-37.9-54.2-43-124.8-13.3-183.8 9.9-19.5 22.9-37.4 38.4-52.9 40.9-41.6 98.3-68.1 161.9-74.9 22-2.4 44.2-2.4 66.2 0 63.2 7.2 120.4 34 161.1 75.4 15.4 15.7 28.2 33.6 37.9 53.2 12.5 24.8 19 52.3 19.1 80.1 0 2.9-0.3 5.8-0.4 8.6 16.8-10.2 38.4-7.7 52.4 6.1l1.9 2.3c3.3-41.2-4.8-82.5-23.3-119.5-12.1-24.5-28.1-46.8-47.3-66.3-52.5-52-121.4-84.3-194.9-91.7-26.4-3.4-52.9-3.5-79.1-0.7z m418.2 405.4c-7.2 1.9-13.8 5.7-19.2 11h-0.1c-6.9 6.8-11.2 15.7-12.2 25.3-5.2 27.8-19.5 53.1-40.5 72-4 3.8-4.1 10.1-0.3 14.1l0.1 0.1c4 4 10.5 4.1 14.6 0.1 0.5-0.5 0.9-0.9 1.2-1.5 20.9-21.9 48.7-36 78.7-39.8 22.8-6.1 36.2-29.2 30.1-51.6-6.2-22.5-29.6-35.8-52.4-29.7z m-160.4-42l-0.7 0.7c-20.9 22.7-49.2 37.3-79.9 41.2-22.6 5.9-36.2 28.7-30.2 51.1 1.9 7.3 5.9 14 11.3 19.3 16.7 16.4 43.7 16.4 60.4-0.1 6.8-6.8 11.1-15.7 12.2-25.2 5.3-27.8 19.6-53.1 40.7-72 4.1-3.7 4.5-10 0.9-14.1l-0.1-0.1c-4-4.2-10.4-4.5-14.6-0.8z m39.6-76.6c-7.1 1.9-13.6 5.7-18.7 10.8-16.4 16.2-16.6 42.6-0.4 59l0.5 0.5c6.9 6.8 15.9 11 25.5 12.1 28 5.1 53.6 19.1 72.9 39.9 4 4 10.4 4 14.4 0.1 4-3.8 4.1-10.1 0.3-14.1-0.5-0.5-1.1-1-1.7-1.4-22.1-20.4-36.4-47.8-40.4-77.6-6.1-22.4-29.6-35.5-52.4-29.3z"
fill=
"#0082EF"
p-id=
"974"
></path></svg>
\ No newline at end of file
app_Web/src/app-register.ts
浏览文件 @
0dc2f7ca
...
...
@@ -115,6 +115,16 @@ import AppStandardContainer from './components/layout-element/container/app-stan
import
AppTabPanel
from
'./components/layout-element/container/app-tab-panel/app-tab-panel.vue'
;
import
AppTabPage
from
'./components/layout-element/container/app-tab-page/app-tab-page.vue'
;
import
AppNavPos
from
'./components/layout-element/container/app-nav-pos/app-nav-pos.vue'
;
import
AppPreSetText
from
'./components/layout-element/text/app-preset-text/app-preset-text.vue'
;
import
AppPreSetCaption
from
'./components/layout-element/text/app-preset-caption/app-preset-caption.vue'
;
import
AppPreSetTitle
from
'./components/layout-element/text/app-preset-title/app-preset-title.vue'
;
import
AppLoginInput
from
'./components/layout-element/login/app-login-input/app-login-input.vue'
;
import
AppLoginButton
from
'./components/layout-element/login/app-login-button/app-login-button.vue'
;
import
AppLoginOrg
from
'./components/layout-element/login/app-login-org/app-login-org.vue'
;
import
AppLoginMessage
from
'./components/layout-element/login/app-login-message/app-login-message.vue'
;
import
AppLoginThird
from
'./components/layout-element/login/app-login-third/app-login-third.vue'
;
import
AppLoginCaptcha
from
'./components/layout-element/login/app-login-captcha/app-login-captcha.vue'
;
import
AppLoginNoteVerify
from
'./components/layout-element/login/app-login-note-verify/app-login-note-verify.vue'
;
// 全局挂载UI实体服务注册中心
window
[
'uiServiceRegister'
]
=
uiServiceRegister
;
// 全局挂载实体权限服务注册中心
...
...
@@ -244,5 +254,15 @@ export const AppComponents = {
v
.
component
(
'app-tab-panel'
,
AppTabPanel
);
v
.
component
(
'app-tab-page'
,
AppTabPage
);
v
.
component
(
'app-nav-pos'
,
AppNavPos
);
v
.
component
(
'app-preset-text'
,
AppPreSetText
);
v
.
component
(
'app-preset-caption'
,
AppPreSetCaption
);
v
.
component
(
'app-preset-title'
,
AppPreSetTitle
);
v
.
component
(
'app-login-input'
,
AppLoginInput
);
v
.
component
(
'app-login-button'
,
AppLoginButton
);
v
.
component
(
'app-login-org'
,
AppLoginOrg
);
v
.
component
(
'app-login-message'
,
AppLoginMessage
);
v
.
component
(
'app-login-third'
,
AppLoginThird
);
v
.
component
(
'app-login-captcha'
,
AppLoginCaptcha
);
v
.
component
(
'app-login-note-verify'
,
AppLoginNoteVerify
);
},
};
\ No newline at end of file
app_Web/src/assets/img/dingding.svg
0 → 100644
浏览文件 @
0dc2f7ca
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
t=
"1616652640756"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"651"
width=
"48"
height=
"48"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
><defs><style
type=
"text/css"
></style></defs><path
d=
"M512 2C230.2 2 2 230.2 2 512s228.2 510 510 510 510-228.2 510-510S793.3 2 512 2z m235.9 442c-1 4.6-3.6 10.8-7.2 19.1l-0.5 0.5c-21.6 45.8-77.3 135.5-77.3 135.5l-0.5-0.5-16.5 28.3h78.8L574.3 826.8l34-136h-61.8l21.6-90.2c-17.5 4.1-38.1 9.8-62.3 18 0 0-33 19.1-94.8-37.1 0 0-41.7-37.1-17.5-45.8 10.3-4.1 50-8.8 81.4-12.9 42.2-5.7 68.5-8.8 68.5-8.8s-130.3 2.1-161.2-3.1c-30.9-4.6-70.1-56.7-78.3-102 0 0-12.9-24.7 27.8-12.9 40.2 11.8 209.2 45.8 209.2 45.8S321.4 375 307 358.5c-14.4-16.5-42.8-89.6-39.2-134.5 0 0 1.5-11.3 12.9-8.2 0 0 161.8 74.2 272.5 114.4C664.5 371.4 760.8 392 747.9 444z"
fill=
"#3296FA"
p-id=
"652"
></path></svg>
\ No newline at end of file
app_Web/src/assets/img/qiyeweixin.svg
0 → 100644
浏览文件 @
0dc2f7ca
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg
t=
"1616652700601"
class=
"icon"
viewBox=
"0 0 1024 1024"
version=
"1.1"
xmlns=
"http://www.w3.org/2000/svg"
p-id=
"973"
xmlns:xlink=
"http://www.w3.org/1999/xlink"
width=
"48"
height=
"48"
><defs><style
type=
"text/css"
></style></defs><path
d=
"M512 2c281.7 0 510 228.3 510 510s-228.3 510-510 510S2 793.7 2 512 230.3 2 512 2z m159.8 680.3c-4 3.9-4 10.2-0.2 14.1 0.4 0.5 0.9 0.9 1.5 1.2 22.1 20.4 36.4 47.9 40.4 77.7 6.2 22.4 29.7 35.7 52.4 29.5 22.5-5.9 35.9-28.9 30-51.3 0-0.1-0.1-0.2-0.1-0.4-4.7-16.8-19.3-29.1-36.7-30.8-28-5.1-53.5-19.2-72.8-40.1-4.1-3.8-10.5-3.8-14.5 0.1z m-225.7-483c-76.4 8.3-145.8 40.6-195.6 91-19.4 19.4-35.5 41.8-47.8 66.3-37.7 74.9-31.4 164.4 16.5 233.2 13.5 20.2 35.8 45.4 56.1 63.3l-9.2 71.3-1 3c-0.3 0.9-0.3 1.9-0.4 2.8l-0.2 2.3 0.2 2.3c1.2 12.7 12.5 22 25.2 20.9 3.5-0.3 6.8-1.4 9.8-3.1h0.4l1.4-1 22-10.8 65.5-32.5c31.1 8.8 63.4 13.2 95.8 13 40 0.1 79.8-6.7 117.5-20.2-18.8-6-30.9-24.3-29-44-39 12.4-80.2 16.4-120.8 11.9l-6.5-0.9c-14.7-1.9-29.2-4.9-43.4-8.9-7.8-2.4-16.1-1.5-23.3 2.4l-1.8 0.9-53.9 31.3-2.3 1.4c-1.3 0.7-1.9 1-2.6 1-2-0.1-3.5-1.8-3.4-3.8l2-8.2 2.4-8.9 3.9-14.7 4.5-16.4c3-9.2-0.3-19.2-8.2-24.8-21.1-15.5-39.5-34.4-54.4-56-37.9-54.2-43-124.8-13.3-183.8 9.9-19.5 22.9-37.4 38.4-52.9 40.9-41.6 98.3-68.1 161.9-74.9 22-2.4 44.2-2.4 66.2 0 63.2 7.2 120.4 34 161.1 75.4 15.4 15.7 28.2 33.6 37.9 53.2 12.5 24.8 19 52.3 19.1 80.1 0 2.9-0.3 5.8-0.4 8.6 16.8-10.2 38.4-7.7 52.4 6.1l1.9 2.3c3.3-41.2-4.8-82.5-23.3-119.5-12.1-24.5-28.1-46.8-47.3-66.3-52.5-52-121.4-84.3-194.9-91.7-26.4-3.4-52.9-3.5-79.1-0.7z m418.2 405.4c-7.2 1.9-13.8 5.7-19.2 11h-0.1c-6.9 6.8-11.2 15.7-12.2 25.3-5.2 27.8-19.5 53.1-40.5 72-4 3.8-4.1 10.1-0.3 14.1l0.1 0.1c4 4 10.5 4.1 14.6 0.1 0.5-0.5 0.9-0.9 1.2-1.5 20.9-21.9 48.7-36 78.7-39.8 22.8-6.1 36.2-29.2 30.1-51.6-6.2-22.5-29.6-35.8-52.4-29.7z m-160.4-42l-0.7 0.7c-20.9 22.7-49.2 37.3-79.9 41.2-22.6 5.9-36.2 28.7-30.2 51.1 1.9 7.3 5.9 14 11.3 19.3 16.7 16.4 43.7 16.4 60.4-0.1 6.8-6.8 11.1-15.7 12.2-25.2 5.3-27.8 19.6-53.1 40.7-72 4.1-3.7 4.5-10 0.9-14.1l-0.1-0.1c-4-4.2-10.4-4.5-14.6-0.8z m39.6-76.6c-7.1 1.9-13.6 5.7-18.7 10.8-16.4 16.2-16.6 42.6-0.4 59l0.5 0.5c6.9 6.8 15.9 11 25.5 12.1 28 5.1 53.6 19.1 72.9 39.9 4 4 10.4 4 14.4 0.1 4-3.8 4.1-10.1 0.3-14.1-0.5-0.5-1.1-1-1.7-1.4-22.1-20.4-36.4-47.8-40.4-77.6-6.1-22.4-29.6-35.5-52.4-29.3z"
fill=
"#0082EF"
p-id=
"974"
></path></svg>
\ No newline at end of file
app_Web/src/components/layout-element/login/app-login-button/app-login-button.less
0 → 100644
浏览文件 @
0dc2f7ca
.app-user-button {
width: 100%;
}
\ No newline at end of file
app_Web/src/components/layout-element/login/app-login-button/app-login-button.vue
0 → 100644
浏览文件 @
0dc2f7ca
<
template
>
<div
class=
"app-user-button"
>
<i-button
@
click=
"handleSubmit"
:type=
"type"
>
{{
caption
}}
</i-button>
</div>
</
template
>
<
script
lang=
"ts"
>
import
{
Vue
,
Component
,
Watch
,
Prop
,
Model
}
from
"vue-property-decorator"
;
@
Component
({})
export
default
class
AppUserId
extends
Vue
{
@
Prop
()
public
predefinedType
!
:
string
;
@
Prop
()
public
type
?:
string
;
@
Prop
()
public
caption
!
:
string
;
public
handleSubmit
()
{
this
.
$emit
(
'itemClick'
,
this
.
predefinedType
);
}
}
</
script
>
<
style
lang=
"less"
>
@import './app-login-button.less';
</
style
>
\ No newline at end of file
app_Web/src/components/layout-element/login/app-login-captcha/app-login-captcha.vue
0 → 100644
浏览文件 @
0dc2f7ca
<
template
>
<div
class=
"app-preset-auth"
>
<auth-puzzle-vcode
:show=
"show"
@
success=
"onSuccess"
@
fail=
"onFail"
/>
<i-button
ghost
@
click=
"executeOpen"
long
class=
"app-preset-auth-button"
>
验证
</i-button
>
</div>
</
template
>
<
script
lang=
"ts"
>
import
{
Vue
,
Component
,
Prop
,
Model
}
from
"vue-property-decorator"
;
import
AuthPuzzleVcode
from
"./vue-puzzle-code/vue-puzzle-code.vue"
;
@
Component
({
components
:
{
"auth-puzzle-vcode"
:
AuthPuzzleVcode
,
},
})
export
default
class
AppPreSetAuth
extends
Vue
{
/**
* 是否显示
*/
public
show
:
boolean
=
false
;
/**
* 打开
*/
public
executeOpen
()
{
this
.
show
=
true
;
}
/**
* 成功
*/
public
onSuccess
()
{
this
.
show
=
false
;
this
.
$emit
(
"success"
);
}
/**
* 失败
*/
public
onFail
()
{
this
.
$emit
(
"fail"
);
}
}
</
script
>
<
style
lang=
'less'
>
.app-preset-auth {
.app-preset-auth-button {
border: 1px solid #dcdee2;
border-radius: 4px;
color: #515a6e;
&:hover{
border: 1px solid #dcdee2;
color: #515a6e;
}
}
}
</
style
>
\ No newline at end of file
app_Web/src/components/layout-element/login/app-login-captcha/vue-puzzle-code/reset.png
0 → 100644
浏览文件 @
0dc2f7ca
1.1 KB
app_Web/src/components/layout-element/login/app-login-captcha/vue-puzzle-code/vue-puzzle-code.less
0 → 100644
浏览文件 @
0dc2f7ca
.vue-puzzle-vcode {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.3);
z-index: 999;
opacity: 0;
pointer-events: none;
transition: opacity 200ms;
&.show_ {
opacity: 1;
pointer-events: auto;
}
}
.vue-auth-box_ {
position: absolute;
top: 40%;
left: 50%;
transform: translate(-50%, -50%);
padding: 20px;
background: #fff;
user-select: none;
border-radius: 3px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
.auth-body_ {
position: relative;
overflow: hidden;
border-radius: 3px;
.loading-box_ {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.8);
z-index: 20;
opacity: 1;
transition: opacity 200ms;
display: flex;
align-items: center;
justify-content: center;
&.hide_ {
opacity: 0;
pointer-events: none;
.loading-gif_ {
span {
animation-play-state: paused;
}
}
}
.loading-gif_ {
flex: none;
height: 5px;
line-height: 0;
@keyframes load {
0% {
opacity: 1;
transform: scale(1.3);
}
100% {
opacity: 0.2;
transform: scale(0.3);
}
}
span {
display: inline-block;
width: 5px;
height: 100%;
margin-left: 2px;
border-radius: 50%;
background-color: #888;
animation: load 1.04s ease infinite;
&:nth-child(1) {
margin-left: 0;
}
&:nth-child(2) {
animation-delay: 0.13s;
}
&:nth-child(3) {
animation-delay: 0.26s;
}
&:nth-child(4) {
animation-delay: 0.39s;
}
&:nth-child(5) {
animation-delay: 0.52s;
}
}
}
}
.info-box_ {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 24px;
line-height: 24px;
text-align: center;
overflow: hidden;
font-size: 13px;
background-color: #83ce3f;
opacity: 0;
transform: translateY(24px);
transition: all 200ms;
color: #fff;
z-index: 10;
&.show {
opacity: 0.95;
transform: translateY(0);
}
&.fail {
background-color: #ce594b;
}
}
.auth-canvas2_ {
position: absolute;
top: 0;
left: 0;
width: 60px;
height: 100%;
z-index: 2;
}
.auth-canvas3_ {
position: absolute;
top: 0;
left: 0;
opacity: 0;
transition: opacity 600ms;
z-index: 3;
&.show {
opacity: 1;
}
}
.flash_ {
position: absolute;
top: 0;
left: 0;
width: 30px;
height: 100%;
background-color: rgba(255, 255, 255, 0.1);
z-index: 3;
&.show {
transition: transform 600ms;
}
}
.reset_ {
position: absolute;
top: 2px;
right: 2px;
width: 35px;
height: auto;
z-index: 12;
cursor: pointer;
transition: transform 200ms;
transform: rotate(0deg);
&:hover {
transform: rotate(-90deg);
}
}
}
.auth-control_ {
.range-box {
position: relative;
width: 100%;
background-color: #eef1f8;
margin-top: 20px;
border-radius: 3px;
box-shadow: 0 0 8px rgba(240, 240, 240, 0.6) inset;
.range-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 14px;
color: #b7bcd1;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
width: 100%;
}
.range-slider {
position: absolute;
height: 100%;
width: 50px;
background-color: rgba(106, 160, 255, 0.8);
border-radius: 3px;
.range-btn {
position: absolute;
display: flex;
align-items: center;
justify-content: center;
right: 0;
width: 50px;
height: 100%;
background-color: #fff;
border-radius: 3px;
box-shadow: 0 0 4px #ccc;
cursor: pointer;
& > div {
width: 0;
height: 40%;
transition: all 200ms;
&:nth-child(2) {
margin: 0 4px;
}
border: solid 1px #6aa0ff;
}
&:hover,
&.isDown {
& > div:first-child {
border: solid 4px transparent;
height: 0;
border-right-color: #6aa0ff;
}
& > div:nth-child(2) {
border-width: 3px;
height: 0;
border-radius: 3px;
margin: 0 6px;
border-right-color: #6aa0ff;
}
& > div:nth-child(3) {
border: solid 4px transparent;
height: 0;
border-left-color: #6aa0ff;
}
}
}
}
}
}
}
.vue-puzzle-overflow {
overflow: hidden !important;
}
\ No newline at end of file
app_Web/src/components/layout-element/login/app-login-captcha/vue-puzzle-code/vue-puzzle-code.vue
0 → 100644
浏览文件 @
0dc2f7ca
<
template
>
<!-- 本体部分 -->
<div
:id=
"id"
:class=
"['vue-puzzle-vcode',
{ show_: show }]"
@mousedown="onCloseMouseDown"
@mouseup="onCloseMouseUp"
@touchstart="onCloseMouseDown"
@touchend="onCloseMouseUp">
<div
class=
"vue-auth-box_"
@
mousedown
.
stop
@
touchstart
.
stop
>
<div
class=
"auth-body_"
:style=
"`height: $
{canvasHeight}px`">
<!-- 主图,有缺口 -->
<canvas
ref=
"canvas1"
:width=
"canvasWidth"
:height=
"canvasHeight"
:style=
"`width:$
{canvasWidth}px;height:${canvasHeight}px`" />
<!-- 成功后显示的完整图 -->
<canvas
ref=
"canvas3"
:class=
"['auth-canvas3_',
{ show: isSuccess }]"
:width="canvasWidth"
:height="canvasHeight"
:style="`width:${canvasWidth}px;height:${canvasHeight}px`" />
<!-- 小图 -->
<canvas
:width=
"puzzleBaseSize"
class=
"auth-canvas2_"
:height=
"canvasHeight"
ref=
"canvas2"
:style=
"
`width:$
{puzzleBaseSize}px;height:${canvasHeight}px;transform:translateX(${styleWidth -
sliderBaseSize -
(puzzleBaseSize - sliderBaseSize) *
((styleWidth - sliderBaseSize) /
(canvasWidth - sliderBaseSize))}px)`
" />
<div
:class=
"['loading-box_',
{ hide_: !loading }]">
<div
class=
"loading-gif_"
>
<span></span>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
</div>
<div
:class=
"['info-box_',
{ show: infoBoxShow }, { fail: infoBoxFail }]">
{{
infoText
}}
</div>
<div
:class=
"['flash_',
{ show: isSuccess }]"
:style="
`transform: translateX(${
isSuccess
? `${canvasWidth + canvasHeight * 0.578}px`
: `-${canvasHeight * 0.578}px`
}) skew(-30deg, 0);`
">
</div>
<img
class=
"reset_"
@
click=
"reset"
:src=
"resetSvg"
/>
</div>
<div
class=
"auth-control_"
>
<div
class=
"range-box"
:style=
"`height:$
{sliderBaseSize}px`">
<div
class=
"range-text"
>
{{
sliderText
}}
</div>
<div
class=
"range-slider"
ref=
"range-slider"
:style=
"`width:$
{styleWidth}px`">
<div
:class=
"['range-btn',
{ isDown: mouseDown }]"
:style="`width:${sliderBaseSize}px`"
@mousedown="onRangeMouseDown($event)"
@touchstart="onRangeMouseDown($event)">
<div></div>
<div></div>
<div></div>
</div>
</div>
</div>
</div>
</div>
</div>
</
template
>
<
script
>
import
resetSvg
from
"./reset.png"
;
export
default
{
/** 私有数据 **/
data
()
{
return
{
mouseDown
:
false
,
// 鼠标是否在按钮上按下
startWidth
:
50
,
// 鼠标点下去时父级的width
startX
:
0
,
// 鼠标按下时的X
newX
:
0
,
// 鼠标当前的偏移X
pinX
:
0
,
// 拼图的起始X
pinY
:
0
,
// 拼图的起始Y
loading
:
true
,
// 是否正在加在中,主要是等图片onload
isCanSlide
:
false
,
// 是否可以拉动滑动条
error
:
false
,
// 图片加在失败会出现这个,提示用户手动刷新
infoBoxShow
:
false
,
// 提示信息是否出现
infoText
:
""
,
// 提示等信息
infoBoxFail
:
false
,
// 是否验证失败
timer1
:
null
,
// setTimout1
closeDown
:
false
,
// 为了解决Mac上的click BUG
isSuccess
:
false
,
// 验证成功
resetSvg
,
imgIndex
:
-
1
// 用于自定义图片时不会随机到重复的图片
};
},
/** 父级参数 **/
props
:
{
id
:
{
type
:
String
},
canvasWidth
:
{
type
:
Number
,
default
:
310
},
// 主canvas的宽
canvasHeight
:
{
type
:
Number
,
default
:
160
},
// 主canvas的高
// 是否出现,由父级控制
show
:
{
type
:
Boolean
,
default
:
false
},
puzzleScale
:
{
type
:
Number
,
default
:
1
},
// 拼图块的大小缩放比例
sliderSize
:
{
type
:
Number
,
default
:
50
},
// 滑块的大小
range
:
{
type
:
Number
,
default
:
10
},
// 允许的偏差值
// 所有的背景图片
imgs
:
{
type
:
Array
},
successText
:
{
type
:
String
,
default
:
"验证通过!"
},
failText
:
{
type
:
String
,
default
:
"验证失败,请重试"
},
sliderText
:
{
type
:
String
,
default
:
"拖动滑块完成拼图"
}
},
/** 生命周期 **/
mounted
()
{
document
.
body
.
appendChild
(
this
.
$el
);
document
.
addEventListener
(
"mousemove"
,
this
.
onRangeMouseMove
,
false
);
document
.
addEventListener
(
"mouseup"
,
this
.
onRangeMouseUp
,
false
);
document
.
addEventListener
(
"touchmove"
,
this
.
onRangeMouseMove
,
{
passive
:
false
});
document
.
addEventListener
(
"touchend"
,
this
.
onRangeMouseUp
,
false
);
if
(
this
.
show
)
{
document
.
body
.
classList
.
add
(
"vue-puzzle-overflow"
);
}
this
.
reset
();
},
beforeDestroy
()
{
clearTimeout
(
this
.
timer1
);
document
.
body
.
removeChild
(
this
.
$el
);
document
.
removeEventListener
(
"mousemove"
,
this
.
onRangeMouseMove
,
false
);
document
.
removeEventListener
(
"mouseup"
,
this
.
onRangeMouseUp
,
false
);
document
.
removeEventListener
(
"touchmove"
,
this
.
onRangeMouseMove
,
{
passive
:
false
});
document
.
removeEventListener
(
"touchend"
,
this
.
onRangeMouseUp
,
false
);
},
/** 监听 **/
watch
:
{
show
(
newV
)
{
// 每次出现都应该重新初始化
if
(
newV
)
{
document
.
body
.
classList
.
add
(
"vue-puzzle-overflow"
);
this
.
reset
();
}
else
{
document
.
body
.
classList
.
remove
(
"vue-puzzle-overflow"
);
}
}
},
/** 计算属性 **/
computed
:
{
// styleWidth是底部用户操作的滑块的父级,就是轨道在鼠标的作用下应该具有的宽度
styleWidth
()
{
const
w
=
this
.
startWidth
+
this
.
newX
-
this
.
startX
;
return
w
<
this
.
sliderBaseSize
?
this
.
sliderBaseSize
:
w
>
this
.
canvasWidth
?
this
.
canvasWidth
:
w
;
},
// 图中拼图块的60 * 用户设定的缩放比例计算之后的值 0.2~2
puzzleBaseSize
()
{
return
Math
.
round
(
Math
.
max
(
Math
.
min
(
this
.
puzzleScale
,
2
),
0.2
)
*
52.5
+
6
);
},
// 处理一下sliderSize,弄成整数,以免计算有偏差
sliderBaseSize
()
{
return
Math
.
max
(
Math
.
min
(
Math
.
round
(
this
.
sliderSize
),
Math
.
round
(
this
.
canvasWidth
*
0.5
)
),
10
);
}
},
/** 方法 **/
methods
:
{
// 关闭
onClose
()
{
if
(
!
this
.
mouseDown
)
{
clearTimeout
(
this
.
timer1
);
this
.
$emit
(
"close"
);
}
},
onCloseMouseDown
()
{
this
.
closeDown
=
true
;
},
onCloseMouseUp
()
{
if
(
this
.
closeDown
)
{
this
.
onClose
();
}
this
.
closeDown
=
false
;
},
// 鼠标按下准备拖动
onRangeMouseDown
(
e
)
{
if
(
this
.
isCanSlide
)
{
this
.
mouseDown
=
true
;
this
.
startWidth
=
this
.
$refs
[
"range-slider"
].
clientWidth
;
this
.
newX
=
e
.
clientX
||
e
.
changedTouches
[
0
].
clientX
;
this
.
startX
=
e
.
clientX
||
e
.
changedTouches
[
0
].
clientX
;
}
},
// 鼠标移动
onRangeMouseMove
(
e
)
{
if
(
this
.
mouseDown
)
{
e
.
preventDefault
();
this
.
newX
=
e
.
clientX
||
e
.
changedTouches
[
0
].
clientX
;
}
},
// 鼠标抬起
onRangeMouseUp
()
{
if
(
this
.
mouseDown
)
{
this
.
mouseDown
=
false
;
this
.
submit
();
}
},
/**
* 开始进行
* @param withCanvas 是否强制使用canvas随机作图
*/
init
(
withCanvas
)
{
this
.
loading
=
true
;
this
.
isCanSlide
=
false
;
const
c
=
this
.
$refs
.
canvas1
;
const
c2
=
this
.
$refs
.
canvas2
;
const
c3
=
this
.
$refs
.
canvas3
;
const
ctx
=
c
.
getContext
(
"2d"
);
const
ctx2
=
c2
.
getContext
(
"2d"
);
const
ctx3
=
c3
.
getContext
(
"2d"
);
const
img
=
document
.
createElement
(
"img"
);
ctx
.
clearRect
(
0
,
0
,
this
.
canvasWidth
,
this
.
canvasHeight
);
ctx2
.
clearRect
(
0
,
0
,
this
.
canvasWidth
,
this
.
canvasHeight
);
// 取一个随机坐标,作为拼图块的位置
this
.
pinX
=
this
.
getRandom
(
this
.
puzzleBaseSize
,
this
.
canvasWidth
-
this
.
puzzleBaseSize
-
20
);
// 留20的边距
this
.
pinY
=
this
.
getRandom
(
20
,
this
.
canvasHeight
-
this
.
puzzleBaseSize
-
20
);
// 主图高度 - 拼图块自身高度 - 20边距
img
.
crossOrigin
=
"anonymous"
;
// 匿名,想要获取跨域的图片
img
.
onload
=
()
=>
{
const
[
x
,
y
,
w
,
h
]
=
this
.
makeImgSize
(
img
);
ctx
.
save
();
// 先画小图
this
.
paintBrick
(
ctx
);
ctx
.
closePath
();
if
(
!
(
navigator
.
userAgent
.
indexOf
(
"Firefox"
)
>=
0
&&
navigator
.
userAgent
.
indexOf
(
"Windows"
)
>=
0
)
)
{
// 非火狐,在此画外阴影
ctx
.
shadowOffsetX
=
0
;
ctx
.
shadowOffsetY
=
0
;
ctx
.
shadowColor
=
"#000"
;
ctx
.
shadowBlur
=
3
;
ctx
.
fill
();
}
ctx
.
clip
();
// 按照外阴影区域切割
ctx
.
save
();
// 小图外阴影
ctx
.
shadowOffsetX
=
0
;
ctx
.
shadowOffsetY
=
0
;
ctx
.
shadowColor
=
"#000"
;
ctx
.
shadowBlur
=
2
;
ctx
.
fill
();
ctx
.
restore
();
ctx
.
drawImage
(
img
,
x
,
y
,
w
,
h
);
ctx3
.
drawImage
(
img
,
x
,
y
,
w
,
h
);
// 设置小图的内阴影
ctx
.
globalCompositeOperation
=
"source-atop"
;
this
.
paintBrick
(
ctx
);
ctx
.
arc
(
this
.
pinX
+
Math
.
ceil
(
this
.
puzzleBaseSize
/
2
),
this
.
pinY
+
Math
.
ceil
(
this
.
puzzleBaseSize
/
2
),
this
.
puzzleBaseSize
*
1.2
,
0
,
Math
.
PI
*
2
,
true
);
ctx
.
closePath
();
ctx
.
shadowColor
=
"rgba(255, 255, 255, .8)"
;
ctx
.
shadowOffsetX
=
-
1
;
ctx
.
shadowOffsetY
=
-
1
;
ctx
.
shadowBlur
=
Math
.
min
(
Math
.
ceil
(
8
*
this
.
puzzleScale
),
12
);
ctx
.
fillStyle
=
"#ffffaa"
;
ctx
.
fill
();
// 将小图赋值给ctx2
const
imgData
=
ctx
.
getImageData
(
this
.
pinX
-
3
,
// 为了阴影 是从-3px开始截取,判定的时候要+3px
this
.
pinY
-
20
,
this
.
pinX
+
this
.
puzzleBaseSize
+
5
,
this
.
pinY
+
this
.
puzzleBaseSize
+
5
);
ctx2
.
putImageData
(
imgData
,
0
,
this
.
pinY
-
20
);
// 清理
ctx
.
restore
();
ctx
.
clearRect
(
0
,
0
,
this
.
canvasWidth
,
this
.
canvasHeight
);
// 画缺口
ctx
.
save
();
this
.
paintBrick
(
ctx
);
ctx
.
globalAlpha
=
0.8
;
ctx
.
fillStyle
=
"#ffffff"
;
ctx
.
fill
();
ctx
.
restore
();
// 画缺口的内阴影
ctx
.
save
();
ctx
.
globalCompositeOperation
=
"source-atop"
;
this
.
paintBrick
(
ctx
);
ctx
.
arc
(
this
.
pinX
+
Math
.
ceil
(
this
.
puzzleBaseSize
/
2
),
this
.
pinY
+
Math
.
ceil
(
this
.
puzzleBaseSize
/
2
),
this
.
puzzleBaseSize
*
1.2
,
0
,
Math
.
PI
*
2
,
true
);
ctx
.
shadowColor
=
"#000"
;
ctx
.
shadowOffsetX
=
2
;
ctx
.
shadowOffsetY
=
2
;
ctx
.
shadowBlur
=
16
;
ctx
.
fill
();
ctx
.
restore
();
// 画整体背景图
ctx
.
save
();
ctx
.
globalCompositeOperation
=
"destination-over"
;
ctx
.
drawImage
(
img
,
x
,
y
,
w
,
h
);
ctx
.
restore
();
this
.
loading
=
false
;
this
.
isCanSlide
=
true
;
};
img
.
onerror
=
()
=>
{
this
.
init
(
true
);
// 如果图片加载错误就重新来,并强制用canvas随机作图
};
if
(
!
withCanvas
&&
this
.
imgs
&&
this
.
imgs
.
length
)
{
let
randomNum
=
this
.
getRandom
(
0
,
this
.
imgs
.
length
-
1
);
if
(
randomNum
===
this
.
imgIndex
)
{
if
(
randomNum
===
this
.
imgs
.
length
-
1
)
{
randomNum
=
0
;
}
else
{
randomNum
++
;
}
}
this
.
imgIndex
=
randomNum
;
img
.
src
=
this
.
imgs
[
randomNum
];
}
else
{
img
.
src
=
this
.
makeImgWithCanvas
();
}
},
// 工具 - 范围随机数
getRandom
(
min
,
max
)
{
return
Math
.
ceil
(
Math
.
random
()
*
(
max
-
min
)
+
min
);
},
// 工具 - 设置图片尺寸cover方式贴合canvas尺寸 w/h
makeImgSize
(
img
)
{
const
imgScale
=
img
.
width
/
img
.
height
;
const
canvasScale
=
this
.
canvasWidth
/
this
.
canvasHeight
;
let
x
=
0
,
y
=
0
,
w
=
0
,
h
=
0
;
if
(
imgScale
>
canvasScale
)
{
h
=
this
.
canvasHeight
;
w
=
imgScale
*
h
;
y
=
0
;
x
=
(
this
.
canvasWidth
-
w
)
/
2
;
}
else
{
w
=
this
.
canvasWidth
;
h
=
w
/
imgScale
;
x
=
0
;
y
=
(
this
.
canvasHeight
-
h
)
/
2
;
}
return
[
x
,
y
,
w
,
h
];
},
// 绘制拼图块的路径
paintBrick
(
ctx
)
{
const
moveL
=
Math
.
ceil
(
15
*
this
.
puzzleScale
);
// 直线移动的基础距离
ctx
.
beginPath
();
ctx
.
moveTo
(
this
.
pinX
,
this
.
pinY
);
ctx
.
lineTo
(
this
.
pinX
+
moveL
,
this
.
pinY
);
ctx
.
arcTo
(
this
.
pinX
+
moveL
,
this
.
pinY
-
moveL
/
2
,
this
.
pinX
+
moveL
+
moveL
/
2
,
this
.
pinY
-
moveL
/
2
,
moveL
/
2
);
ctx
.
arcTo
(
this
.
pinX
+
moveL
+
moveL
,
this
.
pinY
-
moveL
/
2
,
this
.
pinX
+
moveL
+
moveL
,
this
.
pinY
,
moveL
/
2
);
ctx
.
lineTo
(
this
.
pinX
+
moveL
+
moveL
+
moveL
,
this
.
pinY
);
ctx
.
lineTo
(
this
.
pinX
+
moveL
+
moveL
+
moveL
,
this
.
pinY
+
moveL
);
ctx
.
arcTo
(
this
.
pinX
+
moveL
+
moveL
+
moveL
+
moveL
/
2
,
this
.
pinY
+
moveL
,
this
.
pinX
+
moveL
+
moveL
+
moveL
+
moveL
/
2
,
this
.
pinY
+
moveL
+
moveL
/
2
,
moveL
/
2
);
ctx
.
arcTo
(
this
.
pinX
+
moveL
+
moveL
+
moveL
+
moveL
/
2
,
this
.
pinY
+
moveL
+
moveL
,
this
.
pinX
+
moveL
+
moveL
+
moveL
,
this
.
pinY
+
moveL
+
moveL
,
moveL
/
2
);
ctx
.
lineTo
(
this
.
pinX
+
moveL
+
moveL
+
moveL
,
this
.
pinY
+
moveL
+
moveL
+
moveL
);
ctx
.
lineTo
(
this
.
pinX
,
this
.
pinY
+
moveL
+
moveL
+
moveL
);
ctx
.
lineTo
(
this
.
pinX
,
this
.
pinY
+
moveL
+
moveL
);
ctx
.
arcTo
(
this
.
pinX
+
moveL
/
2
,
this
.
pinY
+
moveL
+
moveL
,
this
.
pinX
+
moveL
/
2
,
this
.
pinY
+
moveL
+
moveL
/
2
,
moveL
/
2
);
ctx
.
arcTo
(
this
.
pinX
+
moveL
/
2
,
this
.
pinY
+
moveL
,
this
.
pinX
,
this
.
pinY
+
moveL
,
moveL
/
2
);
ctx
.
lineTo
(
this
.
pinX
,
this
.
pinY
);
},
// 用canvas随机生成图片
makeImgWithCanvas
()
{
const
canvas
=
document
.
createElement
(
"canvas"
);
const
ctx
=
canvas
.
getContext
(
"2d"
);
canvas
.
width
=
this
.
canvasWidth
;
canvas
.
height
=
this
.
canvasHeight
;
ctx
.
fillStyle
=
`rgb(
${
this
.
getRandom
(
100
,
255
)}
,
${
this
.
getRandom
(
100
,
255
)}
,
${
this
.
getRandom
(
100
,
255
)}
)`
;
ctx
.
fillRect
(
0
,
0
,
this
.
canvasWidth
,
this
.
canvasHeight
);
// 随机画10个图形
for
(
let
i
=
0
;
i
<
12
;
i
++
)
{
ctx
.
fillStyle
=
`rgb(
${
this
.
getRandom
(
100
,
255
)}
,
${
this
.
getRandom
(
100
,
255
)}
,
${
this
.
getRandom
(
100
,
255
)}
)`
;
ctx
.
strokeStyle
=
`rgb(
${
this
.
getRandom
(
100
,
255
)}
,
${
this
.
getRandom
(
100
,
255
)}
,
${
this
.
getRandom
(
100
,
255
)}
)`
;
if
(
this
.
getRandom
(
0
,
2
)
>
1
)
{
// 矩形
ctx
.
save
();
ctx
.
rotate
((
this
.
getRandom
(
-
90
,
90
)
*
Math
.
PI
)
/
180
);
ctx
.
fillRect
(
this
.
getRandom
(
-
20
,
canvas
.
width
-
20
),
this
.
getRandom
(
-
20
,
canvas
.
height
-
20
),
this
.
getRandom
(
10
,
canvas
.
width
/
2
+
10
),
this
.
getRandom
(
10
,
canvas
.
height
/
2
+
10
)
);
ctx
.
restore
();
}
else
{
// 圆
ctx
.
beginPath
();
const
ran
=
this
.
getRandom
(
-
Math
.
PI
,
Math
.
PI
);
ctx
.
arc
(
this
.
getRandom
(
0
,
canvas
.
width
),
this
.
getRandom
(
0
,
canvas
.
height
),
this
.
getRandom
(
10
,
canvas
.
height
/
2
+
10
),
ran
,
ran
+
Math
.
PI
*
1.5
);
ctx
.
closePath
();
ctx
.
fill
();
}
}
return
canvas
.
toDataURL
(
"image/png"
);
},
// 开始判定
submit
()
{
// 偏差 x = puzzle的起始X - (用户真滑动的距离) + (puzzle的宽度 - 滑块的宽度) * (用户真滑动的距离/canvas总宽度)
// 最后+ 的是补上slider和滑块宽度不一致造成的缝隙
const
x
=
Math
.
abs
(
this
.
pinX
-
(
this
.
styleWidth
-
this
.
sliderBaseSize
)
+
(
this
.
puzzleBaseSize
-
this
.
sliderBaseSize
)
*
((
this
.
styleWidth
-
this
.
sliderBaseSize
)
/
(
this
.
canvasWidth
-
this
.
sliderBaseSize
))
-
3
);
if
(
x
<
this
.
range
)
{
// 成功
this
.
infoText
=
this
.
successText
;
this
.
infoBoxFail
=
false
;
this
.
infoBoxShow
=
true
;
this
.
isCanSlide
=
false
;
this
.
isSuccess
=
true
;
// 成功后准备关闭
clearTimeout
(
this
.
timer1
);
this
.
timer1
=
setTimeout
(()
=>
{
// 成功的回调
this
.
$emit
(
"success"
,
x
);
},
800
);
}
else
{
// 失败
this
.
infoText
=
this
.
failText
;
this
.
infoBoxFail
=
true
;
this
.
infoBoxShow
=
true
;
this
.
isCanSlide
=
false
;
// 失败的回调
this
.
$emit
(
"fail"
,
x
);
// 800ms后重置
clearTimeout
(
this
.
timer1
);
this
.
timer1
=
setTimeout
(()
=>
{
this
.
reset
();
},
800
);
}
},
// 重置
reset
()
{
this
.
infoBoxFail
=
false
;
this
.
infoBoxShow
=
false
;
this
.
isCanSlide
=
true
;
this
.
isSuccess
=
false
;
this
.
startWidth
=
this
.
sliderBaseSize
;
// 鼠标点下去时父级的width
this
.
startX
=
0
;
// 鼠标按下时的X
this
.
newX
=
0
;
// 鼠标当前的偏移X
this
.
init
();
}
}
};
</
script
>
<
style
lang=
"less"
>
@import './vue-puzzle-code.less';
</
style
>
app_Web/src/components/layout-element/login/app-login-input/app-login-input.vue
0 → 100644
浏览文件 @
0dc2f7ca
<
template
>
<div
class=
"app-user-input"
>
<i-input
size=
'large'
:prefix=
'icon'
v-model=
"value"
:placeholder=
"placeholder"
>
</i-input>
</div>
</
template
>
<
script
lang=
"ts"
>
import
{
Vue
,
Component
,
Watch
,
Prop
,
Model
}
from
'vue-property-decorator'
;
@
Component
({
})
export
default
class
AppUserId
extends
Vue
{
/**
* 登录名称
*
* @type {string}
* @memberof AppUserId
*/
@
Prop
({
default
:
''
})
public
value
!
:
string
;
@
Prop
()
public
icon
?:
string
;
@
Prop
()
public
placeholder
?:
string
;
}
</
script
>
app_Web/src/components/layout-element/login/app-login-message/app-login-message.less
0 → 100644
浏览文件 @
0dc2f7ca
.app-login-message{
.ivu-alert{
display: flex;
align-items: center;
background-color: rgb(255, 225, 225);
.ivu-alert-icon{
position: unset;
margin-right: 5px;
}
}
.ivu-alert-error,
.ivu-alert-with-icon{
padding-left: 10px;
}
}
\ No newline at end of file
app_Web/src/components/layout-element/login/app-login-message/app-login-message.vue
0 → 100644
浏览文件 @
0dc2f7ca
<
template
>
<div
class=
"app-login-message"
>
<alert
v-show=
"value"
type=
"error"
show-icon
>
{{
value
}}
</alert>
</div>
</
template
>
<
script
lang=
'ts'
>
import
{
Component
,
Vue
,
Prop
}
from
"vue-property-decorator"
;
@
Component
({})
export
default
class
AppPreSetLoginMessage
extends
Vue
{
/**
* 内容
*
* @type {string}
* @memberof AppPreSetLoginMessage
*/
@
Prop
()
public
value
?:
string
;
}
</
script
>
<
style
lang=
'less'
>
@import "./app-login-message.less";
</
style
>
\ No newline at end of file
app_Web/src/components/layout-element/login/app-login-note-verify/app-login-note-verify.less
0 → 100644
浏览文件 @
0dc2f7ca
.app-preset-smsverification{
.content {
display: flex;
margin: 5px 0;
.el-button {
border: 1px solid #dcdee2;
margin-left: 10px;
color: #606266;
background-color: #fff;
&:hover {
border: 1px solid #dcdee2;
}
}
}
.code{
padding-top: 8px;
}
.error {
color: red;
}
}
\ No newline at end of file
app_Web/src/components/layout-element/login/app-login-note-verify/app-login-note-verify.vue
0 → 100644
浏览文件 @
0dc2f7ca
<
template
>
<div
class=
"app-preset-smsverification"
>
<div
class=
"content"
>
<i-input
size=
"default"
type=
"text"
v-model=
"phoneNumber"
:placeholder=
"$t('components.login.phoneplaceholder')"
@
on-blur=
"veriPhoneNumber"
></i-input>
<el-button
:disabled=
"disabled"
size=
"mini"
type=
"primary"
@
click=
"getVeriCode()"
>
{{
disabled
?
`${countDown
}
s ${$t('components.login.getcodeafter')
}
`
:
`${$t('components.login.getcode')
}
`
}}
<
/el-butto
n
>
<
/div
>
<
div
class
=
"code"
>
<
i
-
input
size
=
"default"
type
=
"text"
:
value
=
"currentValue"
@
input
=
"codeChange"
:
placeholder
=
"$t('components.login.codeplaceholder')"
><
/i-input
>
<
/div
>
<
/div
>
<
/template
>
<
script
lang
=
'ts'
>
import
{
Vue
,
Component
,
Prop
}
from
"vue-property-decorator"
;
@
Component
({
}
)
export
default
class
AppPresetSmsVerification
extends
Vue
{
/**
*验证码值
*
* @type {string
}
* @memberof AppPresetSmsVerification
*/
@
Prop
()
public
value
!
:
string
;
/**
*验证码当前值
*
* @type {string
}
* @memberof AppPresetSmsVerification
*/
get
currentValue
():
string
{
return
this
.
value
;
}
/**
* 手机号
*
* @type {*
}
* @memberof AppPresetSmsVerification
*/
public
phoneNumber
:
string
=
''
;
/**
* 倒计时
*
* @type {*
}
* @memberof AppPresetSmsVerification
*/
public
countDown
:
number
=
60
;
/**
* 错误提示
* @type {*
}
* @memberof AppPresetSmsVerification
*/
public
phoneError
=
false
;
/**
* 是否禁用获取验证码按钮
*
* @type {*
}
* @memberof AppPresetSmsVerification
*/
public
disabled
:
boolean
=
false
;
/**
* 定时器
*
* @type {*
}
* @memberof AppPresetSmsVerification
*/
public
timer
:
any
;
/**
* @description 设置倒计时
* @memberof AppPresetSmsVerification
*/
public
setCountDown
()
{
if
(
this
.
countDown
>
0
)
{
this
.
countDown
--
;
}
else
{
this
.
countDown
=
60
;
this
.
disabled
=
false
;
clearInterval
(
this
.
timer
);
}
this
.
$forceUpdate
();
}
/**
* @description 验证码输入变化
* @memberof AppPresetSmsVerification
*/
public
codeChange
(
value
:
string
)
{
this
.
$emit
(
"change"
,
value
);
}
/**
* @description 校验手机号
* @memberof AppPresetSmsVerification
*/
public
veriPhoneNumber
():
boolean
{
this
.
phoneError
=
!
/^1
[
3-9
]\d
{9
}
$/
.
test
(
this
.
phoneNumber
);
if
(
this
.
phoneError
)
{
this
.
$emit
(
"error"
,
this
.
$t
(
'components.login.phonefailed'
));
}
else
{
this
.
$emit
(
"error"
,
''
);
}
return
this
.
phoneError
;
}
/**
* @description 获取验证码
* @memberof AppPresetSmsVerification
*/
public
getVeriCode
()
{
if
(
this
.
phoneError
)
return
;
// todo
this
.
$http
.
post
(
``
,
{
}
).
then
((
response
:
any
)
=>
{
if
(
response
.
status
==
200
)
{
this
.
disabled
=
true
;
this
.
timer
=
setInterval
(()
=>
{
this
.
setCountDown
();
}
,
1000
);
}
}
);
}
}
<
/script
>
<
style
lang
=
'less'
>
@
import
"./app-login-note-verify.less"
;
<
/style>
\ No newline at end of file
app_Web/src/components/layout-element/login/app-login-org/app-login-org.less
0 → 100644
浏览文件 @
0dc2f7ca
.app-auth-org-picker {
height: 36px;
width: 100%;
.app-org-sector-remote {
width: 100%;
.org-sector-choice{
background-color: #e6f7ff;
}
}
.ivu-dropdown{
width: inherit;
position: relative;
.ivu-select-dropdown{
width: 100%;
}
}
.auth-org-picker-dropdown{
width: inherit;
position: relative;
border-radius: 5px;
border: 1px solid gray;
.ivu-select-dropdown{
width: 100%;
}
}
.menu-item-no-data{
width: 100%;
font-size: 16px;
text-align: center;
color: #dbdbdb;
padding: 5px 0;
}
}
\ No newline at end of file
app_Web/src/components/layout-element/login/app-login-org/app-login-org.vue
0 → 100644
浏览文件 @
0dc2f7ca
<
template
>
<div
class=
"app-org-picker"
>
<div
class=
"app-org-sector-remote"
>
<dropdown
@
on-click=
"orgSelect"
@
on-visible-change=
"visibleChange"
>
<div
class=
"org-sector"
>
<Input
:value=
"getSelectedOrgName"
placeholder=
"请选择部门"
readonly
:icon=
"iconClass"
/>
</div>
<dropdown-menu
slot=
"list"
>
<dropdown-item
:class=
"
{ 'org-sector-choice': Object.is(item.srforgsectorid, getSelectedOrgName) }"
:name="item.srforgsectorid"
v-for="(item, index) in selectedOrgArray"
:key="index"
>
{{
item
.
srforgsectorname
}}
</dropdown-item>
<div
class=
"menu-item-no-data"
v-show=
"!selectedOrgArray.length"
>
暂无数据
</div>
</dropdown-menu>
</dropdown>
</div>
</div>
</
template
>
<
script
lang=
'ts'
>
import
{
Vue
,
Component
,
Inject
,
Prop
}
from
'vue-property-decorator'
;
@
Component
({})
export
default
class
AppAuthOrgPicker
extends
Vue
{
/**
* 输入值
*
* @type {*}
* @memberof AppAuthOrgPicker
*/
@
Prop
()
public
value
!
:
string
;
/**
* 默认数据来源模式
*
* @type {string}
* @memberof AppAuthOrgPicker
*
*/
public
selectMode
:
'REMOTE'
|
'LOCAL'
=
'LOCAL'
;
/**
* 选中组织部门id
*
* @type {string}
* @memberof AppAuthOrgPicker
*/
public
selectedOrgId
:
string
=
''
;
/**
* 图标名称
*
* @type {boolean}
* @memberof AppAuthOrgPicker
*/
public
iconClass
:
string
=
'ios-arrow-down'
;
/**
* 选中组织部门名称
*
* @type {string}
* @memberof AppAuthOrgPicker
*/
get
getSelectedOrgName
()
{
if
(
this
.
value
)
{
const
selectedValue
=
this
.
selectedOrgArray
.
find
((
item
:
any
)
=>
{
return
item
.
srforgsectorid
==
this
.
value
;
});
return
selectedValue
?.
srforgsectorname
;
}
}
/**
* 组织部门名称数组
*
* @type {Array<any>}
* @memberof AppAuthOrgPicker
*/
public
selectedOrgArray
:
Array
<
any
>
=
[];
/**
* 组件初始化数据,vue生命周期
*
* @memberof AppAuthOrgPicker
*/
public
created
()
{
this
.
getOrgData
();
}
/**
* 选择组织部门回调
*
* @memberof AppAuthOrgPicker
*/
public
orgSelect
(
data
:
string
)
{
if
(
Object
.
is
(
data
,
this
.
selectedOrgId
))
{
return
;
}
let
item
:
any
=
this
.
selectedOrgArray
.
find
((
_item
:
any
)
=>
Object
.
is
(
_item
.
srforgsectorid
,
data
));
this
.
$emit
(
'valueChange'
,
{
value
:
item
.
srforgsectorid
});
}
/**
* 下拉框打开或收起回调
*
* @memberof AppAuthOrgPicker
*/
visibleChange
(
data
:
boolean
)
{
this
.
iconClass
=
data
?
'ios-arrow-up'
:
'ios-arrow-down'
;
}
/**
* 获取数据
*
* @memberof AppAuthOrgPicker
*/
public
async
getOrgData
()
{
// todo
console
.
log
(
'获取数据暂未实现'
);
}
}
</
script
>
<
style
lang=
"less"
>
@import './app-login-org.less';
</
style
>
\ No newline at end of file
app_Web/src/components/layout-element/login/app-login-third/app-login-third.less
0 → 100644
浏览文件 @
0dc2f7ca
.app-login-third {
text-align: center;
.app-login-third-imgrwap {
.sign-btn {
.third-svg-container {
margin: 0px;
padding: 0px;
}
}
}
}
\ No newline at end of file
app_Web/src/components/layout-element/login/app-login-third/app-login-third.vue
0 → 100644
浏览文件 @
0dc2f7ca
<
template
>
<div
class=
"app-login-third"
>
<span
class=
"title"
>
{{
$t
(
"components.login.other"
)
}}
</span>
<div
class=
"app-login-third-imgrwap"
>
<div
class=
"sign-btn"
@
click=
"handleThirdLogin('DINGDING')"
>
<img
class=
"third-svg-container"
src=
"@/assets/img/dingding.svg"
/>
</div>
<div
class=
"sign-btn"
@
click=
"handleThirdLogin('WXWORK')"
>
<img
class=
"third-svg-container"
src=
"@/assets/img/qiyeweixin.svg"
/>
</div>
</div>
</div>
</
template
>
<
script
lang=
"ts"
>
import
{
Component
,
Vue
}
from
"vue-property-decorator"
;
import
qs
from
"qs"
;
import
*
as
dd
from
"dingtalk-jsapi"
;
import
axios
from
"axios"
;
import
{
Util
}
from
"@/utils"
;
@
Component
({})
export
default
class
AppThirdLogin
extends
Vue
{
/**
* 处理第三方登录
*
* @param type 登录类型
* @memberof AppThirdLogin
*/
handleThirdLogin
(
type
:
string
)
{
switch
(
type
)
{
case
"DINGDING"
:
this
.
dingTalkHandleClick
();
break
;
case
"WXWORK"
:
this
.
wxWorkHandleClick
();
break
;
default
:
console
.
warn
(
`暂不支持
${
type
}
登录`
);
break
;
}
}
/**
* 钉钉登录
*
* @memberof AppThirdLogin
*/
async
dingTalkHandleClick
()
{
let
result
:
any
=
await
this
.
dingtalkLogin
();
if
(
result
)
{
if
(
result
.
state
&&
Object
.
is
(
result
.
state
,
"SUCCESS"
))
{
const
data
=
result
.
data
;
// 截取地址,拼接需要部分组成新地址
const
baseUrl
=
this
.
getNeedLocation
();
// 1.钉钉开放平台提供的appId
const
appId
=
data
.
appid
;
// 2.钉钉扫码后回调地址,需要UrlEncode转码
const
redirect_uri
=
baseUrl
+
"assets/third/dingdingRedirect.html?id="
+
data
.
appid
;
const
redirect_uri_encode
=
encodeURIComponent
(
redirect_uri
);
// 3.钉钉扫码url
const
url
=
"https://oapi.dingtalk.com/connect/qrconnect?response_type=code"
+
"&appid="
+
appId
+
"&redirect_uri="
+
redirect_uri_encode
+
"&scope=snsapi_login"
+
"&state=STATE"
;
// 4.跳转钉钉扫码
window
.
location
.
href
=
url
;
}
else
if
(
result
.
message
)
{
throw
new
Error
(
result
.
message
);
}
}
}
/**
* 微信登录
*
* @memberof AppThirdLogin
*/
async
wxWorkHandleClick
()
{
let
result
:
any
=
await
this
.
wxWorkLogin
();
if
(
result
)
{
if
(
result
.
state
&&
Object
.
is
(
result
.
state
,
"SUCCESS"
))
{
const
data
=
result
.
data
;
// 截取地址,拼接需要部分组成新地址
const
baseUrl
=
this
.
getNeedLocation
();
// 1.微信平台提供的appId
const
appId
=
data
.
corp_id
;
const
agentId
=
data
.
agentid
;
// 2.微信扫码后回调地址,需要UrlEncode转码
const
redirect_uri
=
baseUrl
+
"assets/third/wxWorkRedirect.html?id="
+
data
.
appid
;
const
redirect_uri_encode
=
encodeURIComponent
(
redirect_uri
);
// 3.微信扫码url
const
url
=
"https://open.work.weixin.qq.com/wwopen/sso/qrConnect?state=STATE"
+
"&appid="
+
appId
+
"&agentid="
+
agentId
+
"&redirect_uri="
+
redirect_uri_encode
;
// 4.跳转微信扫码
window
.
location
.
href
=
url
;
}
else
if
(
result
.
message
)
{
throw
new
Error
(
result
.
message
);
}
}
}
/**
* 截取地址
*
* @memberof AppThirdLogin
*/
private
getNeedLocation
()
{
// 截取地址,拼接需要部分组成新地址
const
scheme
=
window
.
location
.
protocol
;
const
host
=
window
.
location
.
host
;
let
baseUrl
:
any
=
scheme
+
"//"
+
host
;
const
port
=
window
.
location
.
port
;
if
(
port
)
{
if
(
port
==
"80"
||
port
==
"443"
)
{
baseUrl
+=
"/"
;
}
else
{
baseUrl
+=
":"
+
port
+
"/"
;
}
}
else
{
baseUrl
+=
"/"
;
}
return
baseUrl
;
}
/**
* 钉钉授权登录
*
* @memberof AppThirdService
*/
public
dingtalkLogin
():
Promise
<
any
>
{
return
new
Promise
((
resolve
)
=>
{
// 请求头
const
headers
=
{};
const
tempViewParam
=
Util
.
getDcSystemIdViewParam
();
if
(
tempViewParam
&&
tempViewParam
.
srfdcsystem
)
{
Object
.
assign
(
headers
,
{
srfdcsystem
:
tempViewParam
.
srfdcsystem
});
}
const
get
:
Promise
<
any
>
=
this
.
getData
(
"/uaa/open/dingtalk/appid"
,
{},
false
,
headers
);
get
.
then
((
response
:
any
)
=>
{
if
(
response
&&
response
.
status
===
200
)
{
const
data
=
response
.
data
;
if
(
data
&&
data
.
appid
)
{
resolve
({
state
:
"SUCCESS"
,
data
:
data
});
}
else
{
resolve
({
state
:
"ERROR"
,
message
:
`获取网站应用appid失败,
${
data
.
detail
}
`
,
});
}
}
}).
catch
((
error
:
any
)
=>
{
const
data
=
error
.
data
;
if
(
data
&&
data
.
detail
)
{
resolve
({
state
:
"ERROR"
,
message
:
`获取网站应用appid失败,
${
data
.
detail
}
`
,
});
}
else
{
resolve
({
state
:
"ERROR"
,
message
:
`获取网站应用appid失败`
});
}
});
});
}
/**
* 企业微信授权登录
*
* @memberof AppThirdService
*/
public
wxWorkLogin
():
Promise
<
any
>
{
return
new
Promise
((
resolve
)
=>
{
// 请求头
const
headers
=
{};
const
tempViewParam
=
Util
.
getDcSystemIdViewParam
();
if
(
tempViewParam
&&
tempViewParam
.
srfdcsystem
)
{
Object
.
assign
(
headers
,
{
srfdcsystem
:
tempViewParam
.
srfdcsystem
});
}
const
get
:
Promise
<
any
>
=
this
.
getData
(
"/uaa/open/wxwork/appid"
,
{},
false
,
headers
);
get
.
then
((
response
:
any
)
=>
{
if
(
response
&&
response
.
status
===
200
)
{
const
data
=
response
.
data
;
if
(
data
&&
(
data
.
corp_id
||
data
.
appid
))
{
resolve
({
state
:
"SUCCESS"
,
data
:
data
});
}
else
{
resolve
({
state
:
"ERROR"
,
message
:
`获取网站应用appid失败,
${
data
.
detail
}
`
,
});
}
}
}).
catch
((
error
:
any
)
=>
{
const
data
=
error
.
data
;
if
(
data
&&
data
.
detail
)
{
resolve
({
state
:
"ERROR"
,
message
:
`获取网站应用appid失败,
${
data
.
detail
}
`
,
});
}
else
{
resolve
({
state
:
"ERROR"
,
message
:
`获取网站应用appid失败`
});
}
});
});
}
/**
* 钉钉内部免登
*
* @memberof AppThirdService
*/
public
embedDingTalkLogin
(
Environment
:
any
):
Promise
<
any
>
{
return
new
Promise
((
resolve
)
=>
{
// 请求头
const
headers
=
{};
const
tempViewParam
=
Util
.
getDcSystemIdViewParam
();
if
(
tempViewParam
&&
tempViewParam
.
srfdcsystem
)
{
Object
.
assign
(
headers
,
{
srfdcsystem
:
tempViewParam
.
srfdcsystem
});
}
const
param
=
Util
.
handleViewParam
(
window
.
location
.
href
);
if
(
param
.
corpId
)
{
let
corpId
:
string
=
param
.
corpId
;
if
(
corpId
.
indexOf
(
"#"
)
>
-
1
)
{
corpId
=
corpId
.
split
(
"#"
)[
0
];
}
dd
.
runtime
.
permission
.
requestAuthCode
({
corpId
})
.
then
((
res
:
any
)
=>
{
if
(
res
&&
res
.
code
)
{
this
.
getData
(
`/uaa/open/dingtalk/auth/
${
res
.
code
}
`
,
{},
false
,
headers
).
then
((
res
:
any
)
=>
{
if
(
res
.
status
==
200
&&
(
res
.
data
.
token
||
res
.
data
.
user
))
{
resolve
({
state
:
"SUCCESS"
,
data
:
res
.
data
});
}
else
{
resolve
({
state
:
"ERROR"
,
message
:
`
${
res
.
data
.
message
}
`
});
}
});
}
else
{
resolve
({
state
:
"ERROR"
,
message
:
`钉钉用户信息获取失败`
});
}
})
.
catch
((
error
:
any
)
=>
{
resolve
({
state
:
"ERROR"
,
message
:
`钉钉用户信息获取失败`
});
});
}
else
{
resolve
({
state
:
"ERROR"
,
message
:
`获取企业ID失败`
});
}
});
}
/**
* 获取数据
*
* @memberof AppThirdService
*/
public
getData
(
url
:
string
,
params
:
any
=
{},
isloading
?:
boolean
,
headers
:
any
=
{})
{
params
=
this
.
handleRequestData
(
params
);
if
(
params
.
srfparentdata
)
{
Object
.
assign
(
params
,
params
.
srfparentdata
);
delete
params
.
srfparentdata
;
}
if
(
Object
.
keys
(
params
).
length
>
0
)
{
let
tempParam
:
any
=
{};
Object
.
keys
(
params
).
forEach
((
item
:
any
)
=>
{
if
(
params
[
item
]
||
Object
.
is
(
params
[
item
],
0
))
{
tempParam
[
item
]
=
params
[
item
];
}
});
if
(
Object
.
keys
(
tempParam
).
length
>
0
)
{
url
+=
`?
${
qs
.
stringify
(
tempParam
)}
`
;
}
}
return
new
Promise
((
resolve
:
any
,
reject
:
any
)
=>
{
axios
.
get
(
url
,
{
headers
:
headers
}).
then
((
response
:
any
)
=>
{
resolve
(
response
);
});
});
}
/**
* 处理请求数据
*
* @memberof AppThirdService
*/
public
handleRequestData
(
data
:
any
)
{
if
(
data
?.
srfsessionkey
)
{
delete
data
.
srfsessionkey
;
}
if
(
data
?.
srfsessionid
)
{
delete
data
.
srfsessionid
;
}
if
(
data
?.
srfparentdemapname
)
{
delete
data
.
srfparentdemapname
;
}
return
data
;
}
}
</
script
>
<
style
lang=
"less"
>
@import "./app-login-third.less";
</
style
>
app_Web/src/components/layout-element/text/app-preset-caption/app-preset-caption.less
0 → 100644
浏览文件 @
0dc2f7ca
.app-preset-caption {
padding: 8px;
.caption-info {
font-weight: 600;
font-family: "Microsoft YaHei";
font-size: 14px;
}
}
\ No newline at end of file
app_Web/src/components/layout-element/text/app-preset-caption/app-preset-caption.vue
0 → 100644
浏览文件 @
0dc2f7ca
<
template
>
<div
class=
"app-preset-caption"
>
<slot></slot>
</div>
</
template
>
<
script
lang=
"ts"
>
import
{
Vue
,
Component
}
from
"vue-property-decorator"
;
@
Component
({})
export
default
class
AppPreSetCaption
extends
Vue
{}
</
script
>
<
style
lang=
'less'
>
@import "./app-preset-caption.less";
</
style
>
\ No newline at end of file
app_Web/src/components/layout-element/text/app-preset-text/app-preset-text.less
0 → 100644
浏览文件 @
0dc2f7ca
.app-preset-text {
width: 100%;
height: 100%;
}
\ No newline at end of file
app_Web/src/components/layout-element/text/app-preset-text/app-preset-text.vue
0 → 100644
浏览文件 @
0dc2f7ca
<
template
>
<div
:class=
"['app-preset-text', `app-preset-text--$
{contentType.toLowerCase()}`]">
<!-- 直接内容类型 -->
<template
v-if=
"Object.is(contentType, 'RAW')"
>
<template
v-if=
"Object.is(renderMode, 'TEXT')"
>
<span
:style=
"cssStyle"
>
{{
value
}}
</span>
</
template
>
<
template
v-else-if=
"Object.is(renderMode, 'HEADING1')"
>
<h1
:style=
"cssStyle"
>
{{
value
}}
</h1>
</
template
>
<
template
v-else-if=
"Object.is(renderMode, 'HEADING2')"
>
<h2
:style=
"cssStyle"
>
{{
value
}}
</h2>
</
template
>
<
template
v-else-if=
"Object.is(renderMode, 'HEADING3')"
>
<h3
:style=
"cssStyle"
>
{{
value
}}
</h3>
</
template
>
<
template
v-else-if=
"Object.is(renderMode, 'HEADING4')"
>
<h4
:style=
"cssStyle"
>
{{
value
}}
</h4>
</
template
>
<
template
v-else-if=
"Object.is(renderMode, 'HEADING5')"
>
<h5
:style=
"cssStyle"
>
{{
value
}}
</h5>
</
template
>
<
template
v-else-if=
"Object.is(renderMode, 'HEADING6')"
>
<h6
:style=
"cssStyle"
>
{{
value
}}
</h6>
</
template
>
<
template
v-else-if=
"Object.is(renderMode, 'PARAGRAPH')"
>
<p
:style=
"cssStyle"
>
{{
value
}}
</p>
</
template
>
</template>
<!-- 图片类型 -->
<
template
v-else-if=
"Object.is(contentType, 'IMAGE')"
>
<img
:style=
"cssStyle"
v-if=
"imgUrl"
:src=
"imgUrl"
/>
<i
:style=
"cssStyle"
v-else
:class=
"imageClass ? imageClass : ''"
></i>
</
template
>
<!-- HTML类型 -->
<
template
v-else-if=
"Object.is(contentType, 'HTML')"
>
<div
:style=
"cssStyle"
v-html=
"value"
/>
</
template
>
<!-- MARKDOWN类型 -->
<
template
v-else-if=
"Object.is(contentType, 'MARKDOWN')"
>
MARKDOWN暂未支持
<!--
<app-markdown-editor
:style=
"cssStyle"
mode=
"PREVIEWONLY"
:itemValue=
"value"
></app-markdown-editor>
-->
</
template
>
</div>
</template>
<
script
lang=
"ts"
>
import
{
Vue
,
Component
,
Prop
}
from
'vue-property-decorator'
;
@
Component
({})
export
default
class
AppPreSetText
extends
Vue
{
/**
* 输入值
*
* @type {*}
* @memberof AppPreSetText
*/
@
Prop
()
public
value
!
:
any
;
/**
* 内容类型
*
* @type {string}
* @memberof AppPreSetText
*/
@
Prop
({
default
:
'RAW'
})
public
contentType
!
:
'RAW'
|
'HTML'
|
'IMAGE'
|
'MARKDOWN'
;
/**
* 绘制模式
*
* @type {string}
* @memberof AppPreSetText
*/
@
Prop
({
default
:
'TEXT'
})
public
renderMode
!
:
'TEXT'
|
'HEADING1'
|
'HEADING2'
|
'HEADING3'
|
'HEADING4'
|
'HEADING5'
|
'HEADING6'
|
'PARAGRAPH'
;
/**
* 内容样式
*
* @type {string}
* @memberof AppPreSetText
*/
@
Prop
()
public
contentStyle
?:
string
;
/**
* 预置类型
*
* @type {string}
* @memberof AppPreSetText
*/
@
Prop
({
default
:
'STATIC_TEXT'
})
public
predefinedType
!
:
'FIELD_TEXT_DYNAMIC'
|
'STATIC_LABEL'
|
'STATIC_TEXT'
;
/**
* 图标
*
* @memberof AppPreSetText
*/
@
Prop
()
public
imageClass
?:
string
;
/**
* 动态图片路径
*
* @memberof AppPreSetText
*/
protected
dynaImgUrl
:
string
=
''
;
/**
* 样式
*
* @memberof AppPreSetText
*/
protected
cssStyle
:
string
=
''
;
/**
* 图片路径
*
* @memberof AppPreSetText
*/
get
imgUrl
():
string
{
return
this
.
dynaImgUrl
;
}
/**
* Vue生命周期 --- Created
*
* @memberof AppPreSetText
*/
created
()
{
this
.
handleText
();
this
.
handleDynaImg
();
}
/**
* 处理文本
*
* @memberof AppPreSetText
*/
protected
handleText
()
{
if
(
this
.
predefinedType
===
'STATIC_LABEL'
)
{
this
.
cssStyle
+=
"white-space: nowrap;overflow: hidden;text-overflow: ellipsis;"
;
}
}
/**
* 处理动态图片
*
* @memberof AppPreSetText
*/
protected
handleDynaImg
()
{
// TODO 动态图片
// if (this.value && typeof this.value == 'string') {
// // 默认识别文件对象形式,识别失败则为全路径模式
// try {
// const _files = JSON.parse(this.value);
// const file = _files instanceof Array ? _files[0] : null;
// const url = file && file.id ? `${this.downloadUrl}/${file.id}` : '';
// ImgurlBase64.getInstance()
// .getImgURLOfBase64(url)
// .then((res: any) => {
// this.dynaImgUrl = res;
// });
// } catch (error) {
// this.dynaImgUrl = this.value;
// }
// }
}
}
</
script
>
<
style
lang=
"less"
>
@import './app-preset-text.less';
</
style
>
\ No newline at end of file
app_Web/src/components/layout-element/text/app-preset-title/app-preset-title.less
0 → 100644
浏览文件 @
0dc2f7ca
.app-preset-title {
padding: 16px;
font-weight: 600;
font-size: 24px;
}
\ No newline at end of file
app_Web/src/components/layout-element/text/app-preset-title/app-preset-title.vue
0 → 100644
浏览文件 @
0dc2f7ca
<
template
>
<h1
class=
"app-preset-title"
>
{{
curValue
}}
</h1>
</
template
>
<
script
lang=
"ts"
>
import
{
Environment
}
from
"@/environments/environment"
;
import
{
Vue
,
Component
}
from
'vue-property-decorator'
;
@
Component
({})
export
default
class
AppPreSetTitle
extends
Vue
{
/**
* 当前值
*
* @memberof AppPreSetTitle
*/
public
curValue
:
string
=
''
;
/**
* 初始化
*
* @memberof AppPreSetTitle
*/
public
created
()
{
this
.
curValue
=
Environment
.
AppTitle
;
}
}
</
script
>
<
style
lang=
'less'
>
@import './app-preset-title.less';
</
style
>
\ No newline at end of file
app_Web/src/locale/lanres/components/components_en_US_base.ts
浏览文件 @
0dc2f7ca
...
...
@@ -158,6 +158,8 @@ function getLocaleResourceBase(){
placeholder2
:
'Password'
,
name
:
'Login'
,
reset
:
'Reset'
,
register
:
'Register'
,
logout
:
'Logout'
,
other
:
'Other login methods'
,
tip
:
'Enter username and password'
,
warning1
:
'QQ authorization login not supported'
,
...
...
@@ -171,6 +173,13 @@ function getLocaleResourceBase(){
message
:
'The password cannot be empty'
,
},
loginfailed
:
'Login failed'
,
authfailed
:
'Authentication failed'
,
phoneplaceholder
:
'Please enter your mobile phone number'
,
phonefailed
:
'The phone number is incorrect'
,
codeplaceholder
:
'Please enter the verification code'
,
getcode
:
'Get verification code'
,
getcodeafter
:
'Get verification code after'
,
entervercode
:
'Please enter the verification code'
,
},
appUser
:
{
name
:
'System'
,
...
...
app_Web/src/locale/lanres/components/components_zh_CN_base.ts
浏览文件 @
0dc2f7ca
...
...
@@ -159,6 +159,8 @@ function getLocaleResourceBase(){
placeholder2
:
'密码'
,
name
:
'登录'
,
reset
:
'重置'
,
register
:
'注册'
,
logout
:
'登出'
,
other
:
'其他登录方式'
,
tip
:
'输入用户名和密码'
,
warning1
:
'qq授权登录暂未支持'
,
...
...
@@ -172,6 +174,13 @@ function getLocaleResourceBase(){
message
:
'密码不能为空'
,
},
loginfailed
:
'登录失败'
,
authfailed
:
'验证失败'
,
phoneplaceholder
:
'请输入手机号'
,
phonefailed
:
'手机号不正确'
,
codeplaceholder
:
'请输入验证码'
,
getcode
:
'获取验证码'
,
getcodeafter
:
'后获取验证码'
,
entervercode
:
'请输入验证码'
,
},
appUser
:
{
name
:
'系统管理员'
,
...
...
app_Web/src/widgets/ibizbook/default-searchform/default-searchform-base.vue
浏览文件 @
0dc2f7ca
...
...
@@ -663,7 +663,7 @@ export default class DefaultBase extends Vue implements ControlInterface {
*/
public
load
(
opt
:
any
=
{}):
void
{
if
(
!
this
.
loadAction
){
this
.
$Notice
.
error
({
title
:
(
this
.
$t
(
'app.commonWords.wrong'
)
as
string
),
desc
:
'IBIZBOOKUsr
3
GridView'
+
(
this
.
$t
(
'app.searchForm.notConfig.loadAction'
)
as
string
)
});
this
.
$Notice
.
error
({
title
:
(
this
.
$t
(
'app.commonWords.wrong'
)
as
string
),
desc
:
'IBIZBOOKUsr
9
GridView'
+
(
this
.
$t
(
'app.searchForm.notConfig.loadAction'
)
as
string
)
});
return
;
}
const
arg
:
any
=
{
...
opt
};
...
...
@@ -699,7 +699,7 @@ export default class DefaultBase extends Vue implements ControlInterface {
*/
public
loadDraft
(
opt
:
any
=
{},
mode
?:
string
):
void
{
if
(
!
this
.
loaddraftAction
){
this
.
$Notice
.
error
({
title
:
(
this
.
$t
(
'app.commonWords.wrong'
)
as
string
),
desc
:
'IBIZBOOKUsr
3
GridView'
+
(
this
.
$t
(
'app.searchForm.notConfig.loaddraftAction'
)
as
string
)
});
this
.
$Notice
.
error
({
title
:
(
this
.
$t
(
'app.commonWords.wrong'
)
as
string
),
desc
:
'IBIZBOOKUsr
9
GridView'
+
(
this
.
$t
(
'app.searchForm.notConfig.loaddraftAction'
)
as
string
)
});
return
;
}
const
arg
:
any
=
{
...
opt
}
;
...
...
app_Web/src/widgets/ibizbook/quicksearchform-searchform/quicksearchform-searchform-base.vue
浏览文件 @
0dc2f7ca
...
...
@@ -621,7 +621,7 @@ export default class QUICKSEARCHFORMBase extends Vue implements ControlInterface
*/
public
load
(
opt
:
any
=
{}):
void
{
if
(
!
this
.
loadAction
){
this
.
$Notice
.
error
({
title
:
(
this
.
$t
(
'app.commonWords.wrong'
)
as
string
),
desc
:
'IBIZBOOK
List
View'
+
(
this
.
$t
(
'app.searchForm.notConfig.loadAction'
)
as
string
)
});
this
.
$Notice
.
error
({
title
:
(
this
.
$t
(
'app.commonWords.wrong'
)
as
string
),
desc
:
'IBIZBOOK
Calendar
View'
+
(
this
.
$t
(
'app.searchForm.notConfig.loadAction'
)
as
string
)
});
return
;
}
const
arg
:
any
=
{
...
opt
};
...
...
@@ -657,7 +657,7 @@ export default class QUICKSEARCHFORMBase extends Vue implements ControlInterface
*/
public
loadDraft
(
opt
:
any
=
{},
mode
?:
string
):
void
{
if
(
!
this
.
loaddraftAction
){
this
.
$Notice
.
error
({
title
:
(
this
.
$t
(
'app.commonWords.wrong'
)
as
string
),
desc
:
'IBIZBOOK
List
View'
+
(
this
.
$t
(
'app.searchForm.notConfig.loaddraftAction'
)
as
string
)
});
this
.
$Notice
.
error
({
title
:
(
this
.
$t
(
'app.commonWords.wrong'
)
as
string
),
desc
:
'IBIZBOOK
Calendar
View'
+
(
this
.
$t
(
'app.searchForm.notConfig.loaddraftAction'
)
as
string
)
});
return
;
}
const
arg
:
any
=
{
...
opt
}
;
...
...
编辑
预览
Markdown
格式
0%
请重试
or
添加新附件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
先完成此消息的编辑!
取消
想要评论请
注册
或
登录