15
LICENSE
|
@ -19,3 +19,18 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<name>北京敲敲云科技有限公司</name>
|
||||||
|
<email>jeecgos@163.com</email>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
|
||||||
|
<scm>
|
||||||
|
<connection>http://www.jeecg.com</connection>
|
||||||
|
<developerConnection>https://qiaoqiaoyun.com</developerConnection>
|
||||||
|
<url>http://www.jeecg.com/vip</url>
|
||||||
|
</scm>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
JEECG BOOT 低代码开发平台(Vue3前端)
|
JEECG BOOT 低代码开发平台(Vue3前端)
|
||||||
===============
|
===============
|
||||||
当前最新版本: 3.4.4(发布时间:2022-11-21)
|
当前最新版本: 3.5.0(发布时间:2023-03-08)
|
||||||
|
|
||||||
[![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
|
[![AUR](https://img.shields.io/badge/license-Apache%20License%202.0-blue.svg)](https://github.com/zhangdaiscott/jeecg-boot/blob/master/LICENSE)
|
||||||
[![](https://img.shields.io/badge/Author-北京敲敲云科技-orange.svg)](http://www.jeecg.com)
|
[![](https://img.shields.io/badge/Author-北京敲敲云科技-orange.svg)](http://www.jeecg.com)
|
||||||
[![](https://img.shields.io/badge/Blog-官方博客-blue.svg)](https://jeecg.blog.csdn.net)
|
[![](https://img.shields.io/badge/Blog-官方博客-blue.svg)](https://jeecg.blog.csdn.net)
|
||||||
[![](https://img.shields.io/badge/version-3.4.4-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot)
|
[![](https://img.shields.io/badge/version-3.5.0-brightgreen.svg)](https://github.com/zhangdaiscott/jeecg-boot)
|
||||||
[![GitHub stars](https://img.shields.io/github/stars/zhangdaiscott/jeecg-boot.svg?style=social&label=Stars)](https://github.com/zhangdaiscott/jeecg-boot)
|
[![GitHub stars](https://img.shields.io/github/stars/zhangdaiscott/jeecg-boot.svg?style=social&label=Stars)](https://github.com/zhangdaiscott/jeecg-boot)
|
||||||
[![GitHub forks](https://img.shields.io/github/forks/zhangdaiscott/jeecg-boot.svg?style=social&label=Fork)](https://github.com/zhangdaiscott/jeecg-boot)
|
[![GitHub forks](https://img.shields.io/github/forks/zhangdaiscott/jeecg-boot.svg?style=social&label=Fork)](https://github.com/zhangdaiscott/jeecg-boot)
|
||||||
|
|
||||||
|
|
106
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "jeecgboot-vue3",
|
"name": "jeecgboot-vue3",
|
||||||
"version": "3.4.4",
|
"version": "3.5.0",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "jeecg",
|
"name": "jeecg",
|
||||||
"email": "jeecgos@163.com",
|
"email": "jeecgos@163.com",
|
||||||
|
@ -67,6 +67,7 @@
|
||||||
"path-to-regexp": "^6.2.0",
|
"path-to-regexp": "^6.2.0",
|
||||||
"pinia": "2.0.12",
|
"pinia": "2.0.12",
|
||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
|
"pinyin-pro": "^3.11.0",
|
||||||
"qs": "^6.10.3",
|
"qs": "^6.10.3",
|
||||||
"qrcode": "^1.5.0",
|
"qrcode": "^1.5.0",
|
||||||
"qrcodejs2": "0.0.2",
|
"qrcodejs2": "0.0.2",
|
||||||
|
@ -107,6 +108,7 @@
|
||||||
"@types/nprogress": "^0.2.0",
|
"@types/nprogress": "^0.2.0",
|
||||||
"@types/qrcode": "^1.4.2",
|
"@types/qrcode": "^1.4.2",
|
||||||
"@types/qs": "^6.9.7",
|
"@types/qs": "^6.9.7",
|
||||||
|
"@types/pinyin": "^2.10.0",
|
||||||
"@types/showdown": "^1.9.4",
|
"@types/showdown": "^1.9.4",
|
||||||
"@types/sortablejs": "^1.10.7",
|
"@types/sortablejs": "^1.10.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.20.0",
|
"@typescript-eslint/eslint-plugin": "^5.20.0",
|
||||||
|
@ -194,7 +196,107 @@
|
||||||
"vite": {
|
"vite": {
|
||||||
"optimizeDeps": {
|
"optimizeDeps": {
|
||||||
"include": [
|
"include": [
|
||||||
|
"@ant-design/colors",
|
||||||
|
"@ant-design/icons-vue",
|
||||||
|
"@vueuse/core",
|
||||||
|
"@vueuse/shared",
|
||||||
|
"@zxcvbn-ts/core",
|
||||||
|
"ant-design-vue",
|
||||||
|
"axios",
|
||||||
|
"china-area-data",
|
||||||
|
"clipboard",
|
||||||
|
"codemirror",
|
||||||
|
"codemirror/addon/fold/brace-fold.js",
|
||||||
|
"codemirror/addon/fold/comment-fold.js",
|
||||||
|
"codemirror/addon/fold/foldcode.js",
|
||||||
|
"codemirror/addon/fold/foldgutter.js",
|
||||||
|
"codemirror/addon/fold/indent-fold.js",
|
||||||
|
"codemirror/addon/hint/anyword-hint.js",
|
||||||
|
"codemirror/addon/hint/show-hint.js",
|
||||||
|
"codemirror/addon/selection/active-line.js",
|
||||||
|
"codemirror/mode/clike/clike.js",
|
||||||
|
"codemirror/mode/css/css.js",
|
||||||
|
"codemirror/mode/javascript/javascript.js",
|
||||||
|
"codemirror/mode/markdown/markdown.js",
|
||||||
|
"codemirror/mode/python/python.js",
|
||||||
|
"codemirror/mode/r/r.js",
|
||||||
|
"codemirror/mode/shell/shell.js",
|
||||||
|
"codemirror/mode/sql/sql.js",
|
||||||
|
"codemirror/mode/swift/swift.js",
|
||||||
|
"codemirror/mode/vue/vue.js",
|
||||||
|
"codemirror/mode/xml/xml.js",
|
||||||
|
"cron-parser",
|
||||||
|
"cropperjs",
|
||||||
|
"crypto-js/aes",
|
||||||
|
"crypto-js/enc-base64",
|
||||||
|
"crypto-js/enc-utf8",
|
||||||
|
"crypto-js/md5",
|
||||||
|
"crypto-js/mode-ecb",
|
||||||
|
"crypto-js/pad-pkcs7",
|
||||||
|
"dom-align",
|
||||||
|
"echarts",
|
||||||
|
"echarts/charts",
|
||||||
|
"echarts/components",
|
||||||
|
"echarts/core",
|
||||||
|
"echarts/renderers",
|
||||||
|
"emoji-mart-vue-fast/src",
|
||||||
|
"intro.js",
|
||||||
|
"lodash-es",
|
||||||
|
"md5",
|
||||||
|
"nprogress",
|
||||||
|
"path-to-regexp",
|
||||||
|
"pinia",
|
||||||
|
"print-js",
|
||||||
|
"qrcode",
|
||||||
|
"qs",
|
||||||
|
"resize-observer-polyfill",
|
||||||
|
"showdown",
|
||||||
|
"sortablejs",
|
||||||
|
"tinymce/icons/default/icons",
|
||||||
|
"tinymce/plugins/advlist",
|
||||||
|
"tinymce/plugins/anchor",
|
||||||
|
"tinymce/plugins/autolink",
|
||||||
|
"tinymce/plugins/autosave",
|
||||||
|
"tinymce/plugins/code",
|
||||||
|
"tinymce/plugins/codesample",
|
||||||
|
"tinymce/plugins/contextmenu",
|
||||||
|
"tinymce/plugins/directionality",
|
||||||
|
"tinymce/plugins/fullscreen",
|
||||||
|
"tinymce/plugins/hr",
|
||||||
|
"tinymce/plugins/image",
|
||||||
|
"tinymce/plugins/insertdatetime",
|
||||||
|
"tinymce/plugins/link",
|
||||||
|
"tinymce/plugins/lists",
|
||||||
|
"tinymce/plugins/media",
|
||||||
|
"tinymce/plugins/nonbreaking",
|
||||||
|
"tinymce/plugins/noneditable",
|
||||||
|
"tinymce/plugins/pagebreak",
|
||||||
|
"tinymce/plugins/paste",
|
||||||
|
"tinymce/plugins/preview",
|
||||||
|
"tinymce/plugins/print",
|
||||||
|
"tinymce/plugins/save",
|
||||||
|
"tinymce/plugins/searchreplace",
|
||||||
|
"tinymce/plugins/spellchecker",
|
||||||
|
"tinymce/plugins/tabfocus",
|
||||||
|
"tinymce/plugins/table",
|
||||||
|
"tinymce/plugins/template",
|
||||||
|
"tinymce/plugins/textcolor",
|
||||||
|
"tinymce/plugins/textpattern",
|
||||||
|
"tinymce/plugins/visualblocks",
|
||||||
|
"tinymce/plugins/visualchars",
|
||||||
|
"tinymce/plugins/wordcount",
|
||||||
|
"tinymce/themes/silver",
|
||||||
|
"tinymce/tinymce",
|
||||||
|
"vditor",
|
||||||
|
"vue",
|
||||||
|
"vue-i18n",
|
||||||
|
"vue-print-nb-jeecg/src/printarea",
|
||||||
|
"vue-router",
|
||||||
|
"vue-types",
|
||||||
|
"vxe-table",
|
||||||
|
"vxe-table-plugin-antd",
|
||||||
|
"xe-utils",
|
||||||
|
"xss"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
6721
pnpm-lock.yaml
Before Width: | Height: | Size: 894 B After Width: | Height: | Size: 430 B |
|
@ -23,6 +23,7 @@ export interface LoginResultModel {
|
||||||
userId: string | number;
|
userId: string | number;
|
||||||
token: string;
|
token: string;
|
||||||
role: RoleInfo;
|
role: RoleInfo;
|
||||||
|
userInfo?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -78,7 +78,7 @@ export function phoneLoginApi(params: LoginParams, mode: ErrorMessageMode = 'mod
|
||||||
* @description: getUserInfo
|
* @description: getUserInfo
|
||||||
*/
|
*/
|
||||||
export function getUserInfo() {
|
export function getUserInfo() {
|
||||||
return defHttp.get<GetUserInfoModel>({ url: Api.GetUserInfo }, { errorMessageMode: 'none' }).catch((e) => {
|
return defHttp.get<GetUserInfoModel>({ url: Api.GetUserInfo }, {}).catch((e) => {
|
||||||
// update-begin--author:zyf---date:20220425---for:【VUEN-76】捕获接口超时异常,跳转到登录界面
|
// update-begin--author:zyf---date:20220425---for:【VUEN-76】捕获接口超时异常,跳转到登录界面
|
||||||
if (e && (e.message.includes('timeout') || e.message.includes('401'))) {
|
if (e && (e.message.includes('timeout') || e.message.includes('401'))) {
|
||||||
//接口不通时跳转到登录界面
|
//接口不通时跳转到登录界面
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<?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="1671872759315" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="29438" xmlns:xlink="http://www.w3.org/1999/xlink" width="128" height="128"><path d="M136.005284 399.993557h751.9874c35.198978 0 63.999619 28.79861 63.99962 63.999619v495.992986c0 35.198978-28.79861 63.999619-63.99962 63.999619H136.005284c-35.198978 0-63.999619-28.79861-63.999619-63.999619V463.993176c0-35.198978 28.800641-63.999619 63.999619-63.999619z" fill="#ECC45C" p-id="29439"></path><path d="M136.005284 367.993748h751.9874c35.198978 0 63.999619 28.79861 63.99962 63.999619v31.999809c0 35.198978-28.79861 63.999619-63.99962 63.99962H136.005284c-35.198978 0-63.999619-28.79861-63.999619-63.99962v-31.999809c0-35.198978 28.800641-63.999619 63.999619-63.999619z" fill="#F8D578" p-id="29440"></path><path d="M232.002682 415.993462c-39.998746 0-71.998556 14.399305-71.998556 31.99981s31.99981 31.99981 71.998556 31.999809 71.998556-14.399305 71.998556-31.999809c0.002031-17.600505-31.997778-31.99981-71.998556-31.99981z m559.992605 0c-39.998746 0-71.998556 14.399305-71.998556 31.99981s31.99981 31.99981 71.998556 31.999809 71.998556-14.399305 71.998556-31.999809S831.994033 415.993462 791.995287 415.993462zM512 655.990003c66.398488 0 119.99827 53.599783 119.99827 119.99827s-53.599783 119.99827-119.99827 119.99827-119.99827-53.599783-119.99827-119.99827 53.597751-119.99827 119.99827-119.99827z" fill="#D4B053" p-id="29441"></path><path d="M512 687.989812c48.800014 0 87.998461 39.198446 87.998461 87.998461s-39.198446 87.998461-87.998461 87.998461-87.998461-39.198446-87.998461-87.998461a87.742527 87.742527 0 0 1 87.998461-87.998461z" fill="#E4E7E7" p-id="29442"></path><path d="M512 735.987495c8.799237 0 15.999905 7.200668 15.999905 15.999905v47.999714c0 8.799237-7.200668 15.999905-15.999905 15.999905s-15.999905-7.200668-15.999905-15.999905v-47.999714c0-8.799237 7.198637-15.999905 15.999905-15.999905z" fill="#324D5B" p-id="29443"></path><path d="M512 0C326.401511 0 176.004031 150.39748 176.004031 335.993938v95.999429c0 17.600505 24.799141 31.99981 55.998651 31.999809s55.998651-14.399305 55.998651-31.999809v-95.999429c0-123.997739 99.998897-223.996636 223.996636-223.996636s223.996636 99.998897 223.996636 223.996636v95.999429c0 17.600505 24.799141 31.99981 55.998651 31.999809s55.998651-14.399305 55.998651-31.999809v-95.999429C847.993938 150.39748 697.596458 0 512 0z" fill="#E4E7E7" p-id="29444"></path><path d="M512 63.999619c-150.39748 0-271.99635 121.59887-271.99635 271.99635v127.997207c27.200041-2.4009 47.999714-15.199605 47.999714-31.999809v-95.999429c0-123.997739 99.998897-223.996636 223.996636-223.996636s223.996636 99.998897 223.996636 223.996636v95.999429c0 15.999905 20.799673 29.59891 47.999714 31.999809v-127.997207c-0.002031-150.399511-121.59887-271.99635-271.99635-271.99635z" fill="#CDCFCF" p-id="29445"></path></svg>
|
After Width: | Height: | Size: 2.9 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 4.1 KiB |
After Width: | Height: | Size: 3.0 KiB |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 2.6 KiB |
After Width: | Height: | Size: 536 B |
After Width: | Height: | Size: 84 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 12 KiB |
After Width: | Height: | Size: 3.9 KiB |
|
@ -0,0 +1,365 @@
|
||||||
|
::-webkit-input-placeholder {
|
||||||
|
/* WebKit browsers */
|
||||||
|
color: #868686;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-moz-placeholder {
|
||||||
|
/* Mozilla Firefox 19+ */
|
||||||
|
color: #868686;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:-ms-input-placeholder {
|
||||||
|
/* Internet Explorer 10+ */
|
||||||
|
color: #868686;
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:-webkit-autofill {
|
||||||
|
transition: background-color 5000s ease-in-out 0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body {
|
||||||
|
color: #333;
|
||||||
|
margin: 0;
|
||||||
|
height: 100%;
|
||||||
|
font-family: 'Myriad Set Pro', 'Helvetica Neue', Helvetica, Arial, Verdana, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
-webkit-box-sizing: border-box;
|
||||||
|
-moz-box-sizing: border-box;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
a,
|
||||||
|
label,
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
select {
|
||||||
|
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
display: block;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: #e3f0ff;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,
|
||||||
|
body,
|
||||||
|
div,
|
||||||
|
dl,
|
||||||
|
dt,
|
||||||
|
dd,
|
||||||
|
ol,
|
||||||
|
ul,
|
||||||
|
li,
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
p,
|
||||||
|
blockquote,
|
||||||
|
pre,
|
||||||
|
button,
|
||||||
|
fieldset,
|
||||||
|
form,
|
||||||
|
input,
|
||||||
|
legend,
|
||||||
|
textarea,
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #08acee;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
outline: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
optgroup,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
margin: 0;
|
||||||
|
font: inherit;
|
||||||
|
color: inherit;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clearfix::after {
|
||||||
|
clear: both;
|
||||||
|
content: '.';
|
||||||
|
display: block;
|
||||||
|
height: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clearfix {
|
||||||
|
}
|
||||||
|
|
||||||
|
.divHeight {
|
||||||
|
width: 100%;
|
||||||
|
height: 10px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.r-line {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.r-line:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
z-index: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 100%;
|
||||||
|
border-right: 1px solid #d9d9d9;
|
||||||
|
-webkit-transform: scaleX(0.5);
|
||||||
|
transform: scaleX(0.5);
|
||||||
|
-webkit-transform-origin: 100% 0;
|
||||||
|
transform-origin: 100% 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-line {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b-line:after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 1px;
|
||||||
|
border-bottom: 1px solid #dedede;
|
||||||
|
-webkit-transform: scaleY(0.5);
|
||||||
|
transform: scaleY(0.5);
|
||||||
|
-webkit-transform-origin: 0 100%;
|
||||||
|
transform-origin: 0 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-arrow {
|
||||||
|
position: relative;
|
||||||
|
padding-right: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-arrow span {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #9b9b9b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-arrow:after {
|
||||||
|
content: ' ';
|
||||||
|
display: inline-block;
|
||||||
|
height: 6px;
|
||||||
|
width: 6px;
|
||||||
|
border-width: 2px 2px 0 0;
|
||||||
|
border-color: #848484;
|
||||||
|
border-style: solid;
|
||||||
|
-webkit-transform: matrix(0.71, 0.71, -0.71, 0.71, 0, 0);
|
||||||
|
transform: matrix(0.71, 0.71, -0.71, 0.71, 0, 0);
|
||||||
|
position: relative;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -4px;
|
||||||
|
right: 2px;
|
||||||
|
border-radius: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-flex {
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-webkit-align-items: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-flex-box {
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
-webkit-flex: 1;
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 必要布局样式css */
|
||||||
|
.aui-flexView {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin: 0 auto;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-box-direction: normal;
|
||||||
|
-webkit-flex-direction: column;
|
||||||
|
-ms-flex-direction: column;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-scrollView {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
-webkit-box-flex: 1;
|
||||||
|
-webkit-flex: 1;
|
||||||
|
-ms-flex: 1;
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 53px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-navBar {
|
||||||
|
height: 44px;
|
||||||
|
position: relative;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
z-index: 102;
|
||||||
|
background-color: #5064eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-navBar-item {
|
||||||
|
height: 44px;
|
||||||
|
min-width: 15%;
|
||||||
|
-webkit-box-flex: 0;
|
||||||
|
-webkit-flex: 0 0 15%;
|
||||||
|
-ms-flex: 0 0 15%;
|
||||||
|
flex: 0 0 15%;
|
||||||
|
padding: 0 0.9rem;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-webkit-align-items: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #808080;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-navBar-item:first-child {
|
||||||
|
-webkit-box-ordinal-group: 2;
|
||||||
|
-webkit-order: 1;
|
||||||
|
-ms-flex-order: 1;
|
||||||
|
order: 1;
|
||||||
|
margin-right: -25%;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-navBar-item:last-child {
|
||||||
|
-webkit-box-ordinal-group: 4;
|
||||||
|
-webkit-order: 3;
|
||||||
|
-ms-flex-order: 3;
|
||||||
|
order: 3;
|
||||||
|
-webkit-box-pack: end;
|
||||||
|
-webkit-justify-content: flex-end;
|
||||||
|
-ms-flex-pack: end;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-center {
|
||||||
|
-webkit-box-ordinal-group: 3;
|
||||||
|
-webkit-order: 2;
|
||||||
|
-ms-flex-order: 2;
|
||||||
|
order: 2;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
-webkit-justify-content: center;
|
||||||
|
-ms-flex-pack: center;
|
||||||
|
justify-content: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-webkit-align-items: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 44px;
|
||||||
|
width: 80%;
|
||||||
|
margin-left: 22%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-center-title {
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
display: block;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
display: block;
|
||||||
|
border: none;
|
||||||
|
float: left;
|
||||||
|
background-size: 20px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-background-img {
|
||||||
|
background-image: url(../icon/jeecg_bg.png);
|
||||||
|
background-size: cover;
|
||||||
|
background-position: top center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
|
@ -0,0 +1,612 @@
|
||||||
|
.aui-content {
|
||||||
|
padding: 40px 60px;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-container {
|
||||||
|
max-width: 1000px;
|
||||||
|
margin: 0 auto;
|
||||||
|
box-shadow: 0 4px 8px 1px rgba(0, 0, 0, 0.2);
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 92%;
|
||||||
|
height: auto;
|
||||||
|
-webkit-transform: translateX(-50%) translateY(-50%);
|
||||||
|
-moz-transform: translateX(-50%) translateY(-50%);
|
||||||
|
-ms-transform: translateX(-50%) translateY(-50%);
|
||||||
|
transform: translateX(-50%) translateY(-50%);
|
||||||
|
-webkit-transform: translateX(-50%) translateY(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-form {
|
||||||
|
width: 100%;
|
||||||
|
background: #eee;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -moz-box;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-image {
|
||||||
|
padding: 180px 80px;
|
||||||
|
flex-basis: 60%;
|
||||||
|
-webkit-flex-basis: 60%;
|
||||||
|
background-color: #0198cd;
|
||||||
|
background-image: url(../icon/jeecg_ad.png);
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-image-text {
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-formBox {
|
||||||
|
flex-basis: 40%;
|
||||||
|
-webkit-flex-basis: 40%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 30px 20px;
|
||||||
|
background: #fff;
|
||||||
|
box-shadow: 2px 9px 49px -17px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-logo {
|
||||||
|
width: 180px;
|
||||||
|
height: 80px;
|
||||||
|
position: absolute;
|
||||||
|
top: 2%;
|
||||||
|
left: 8%;
|
||||||
|
z-index: 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-account-line {
|
||||||
|
padding-top: 20px;
|
||||||
|
padding-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-code-line {
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
border-left: 3px solid #fff;
|
||||||
|
height: 42px;
|
||||||
|
padding: 0 15px;
|
||||||
|
line-height: 40px;
|
||||||
|
font-size: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-eye {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
top: 10px;
|
||||||
|
width: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-input-line {
|
||||||
|
background: #f5f5f9;
|
||||||
|
border-radius: 2px;
|
||||||
|
position: relative;
|
||||||
|
margin: 12px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-input-line input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px 10px;
|
||||||
|
border: none;
|
||||||
|
color: #333333;
|
||||||
|
font-size: 14px;
|
||||||
|
background: unset;
|
||||||
|
padding-left: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-input-line .icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-line-user {
|
||||||
|
background-image: url(../icon/icon-line-user.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-line-tel {
|
||||||
|
background-image: url(../icon/icon-line-tel.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-line-msg {
|
||||||
|
background-image: url(../icon/icon-line-msg.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-line-pad {
|
||||||
|
background-image: url(../icon/icon-line-pad.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-forgot .aui-input-line input {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-forgot .aui-input-line {
|
||||||
|
background: none;
|
||||||
|
border: 1px solid #dbdbdb;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-forgot .aui-input-line:focus {
|
||||||
|
border-color: #1b90ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-forgot .aui-input-line:hover {
|
||||||
|
border-color: #1b90ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-forgot .aui-input-line .aui-code-line {
|
||||||
|
border-left: 1px solid #dbdbdb;
|
||||||
|
height: 40px;
|
||||||
|
color: #1b90ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-step-box {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-top: 50px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-step-box::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
left: 50%;
|
||||||
|
width: 76%;
|
||||||
|
margin-left: -38%;
|
||||||
|
height: 1px;
|
||||||
|
background: #bcbcbc;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-step-item {
|
||||||
|
width: 33.333%;
|
||||||
|
float: left;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-step-tags em {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
border: 8px solid #fff;
|
||||||
|
line-height: 1.3;
|
||||||
|
border-radius: 100px;
|
||||||
|
background: #bcbcbc;
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
font-style: normal;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 19px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-step-tags p {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #bcbcbc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activeStep .aui-step-tags em {
|
||||||
|
background: #1b90ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activeStep .aui-step-tags p {
|
||||||
|
color: #1b90ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-success {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
height: 80px;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: -40px;
|
||||||
|
margin-left: -50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-success-icon {
|
||||||
|
width: 40px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-success h3 {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
color: #515151;
|
||||||
|
font-size: 18px;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-form-nav {
|
||||||
|
text-align: center;
|
||||||
|
padding-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-form-nav .aui-flex-box {
|
||||||
|
color: #040404;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-clear-left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-clear-left .activeNav::after {
|
||||||
|
left: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activeNav {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.activeNav::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
z-index: 0;
|
||||||
|
bottom: -10px;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -15px;
|
||||||
|
width: 30px;
|
||||||
|
height: 4px;
|
||||||
|
background: #1b90ff;
|
||||||
|
border-radius: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phone .aui-inputClear {
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phone .aui-inputClear input {
|
||||||
|
//padding-left: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phone .aui-inputClear .aui-code {
|
||||||
|
text-align: right;
|
||||||
|
width: auto;
|
||||||
|
bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phone .aui-inputClear .aui-code a {
|
||||||
|
color: #1b90ff;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phoneChina {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 10px;
|
||||||
|
left: 0;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #040404;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phoneChina::after {
|
||||||
|
position: absolute;
|
||||||
|
right: -25px;
|
||||||
|
bottom: 0;
|
||||||
|
content: '';
|
||||||
|
background-image: url(../icon/icon_dow.png);
|
||||||
|
background-size: 18px;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phoneChina:before {
|
||||||
|
position: absolute;
|
||||||
|
right: -42px;
|
||||||
|
bottom: -15px;
|
||||||
|
content: ' ';
|
||||||
|
background: #fff;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-ewm {
|
||||||
|
width: 280px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-formEwm {
|
||||||
|
padding: 50px 40px 55px 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-inputClear {
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: 1px solid #cccccc;
|
||||||
|
position: relative;
|
||||||
|
padding-left: 20px;
|
||||||
|
background: #fff;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-inputClear .icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 10px;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-inputClear input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
border: none;
|
||||||
|
color: #333333;
|
||||||
|
font-size: 14px;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-code {
|
||||||
|
position: absolute;
|
||||||
|
right: 8px;
|
||||||
|
bottom: 0;
|
||||||
|
width: 115px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-code {
|
||||||
|
background-image: url(../icon/icon-user.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-password {
|
||||||
|
background-image: url(../icon/icon-password.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-code {
|
||||||
|
background-image: url(../icon/icon-code.png);
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-inputClear:focus {
|
||||||
|
border-bottom: 1px solid #1b90ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-inputClear:hover {
|
||||||
|
border-bottom: 1px solid #1b90ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-choice {
|
||||||
|
position: relative;
|
||||||
|
font-size: 12px;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-webkit-align-items: center;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
color: #040404;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-choice input {
|
||||||
|
width: 14px;
|
||||||
|
height: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-forget a {
|
||||||
|
color: #1b90ff;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-forget a:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-formButton {
|
||||||
|
padding-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-formButton a {
|
||||||
|
height: 42px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
font-size: 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
border-color: #67b5ff;
|
||||||
|
background: #1b90ff;
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
border: none;
|
||||||
|
color: #fff;
|
||||||
|
margin: 8px 0;
|
||||||
|
display: block;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-formButton a:focus {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-formButton a:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-formButton .aui-linek-code {
|
||||||
|
background: #fff;
|
||||||
|
color: #3c3c3c;
|
||||||
|
border: 1px solid #dbdbdb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-formButton .aui-linek-code:hover {
|
||||||
|
color: #1b90ff;
|
||||||
|
border: 1px solid #1b90ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-third-text {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #3c3c3c;
|
||||||
|
margin-top: 25px;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-third-text span {
|
||||||
|
color: #afafaf;
|
||||||
|
display: block;
|
||||||
|
width: 38%;
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: center;
|
||||||
|
position: relative;
|
||||||
|
background: #fff;
|
||||||
|
z-index: 100;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-third-border {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-third-border::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
z-index: 0;
|
||||||
|
top: 8px;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 1px;
|
||||||
|
border-top: 1px solid #d9d9d9;
|
||||||
|
-webkit-transform: scaleY(0.5);
|
||||||
|
transform: scaleY(0.5);
|
||||||
|
-webkit-transform-origin: 0 100%;
|
||||||
|
transform-origin: 0 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-third-login {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
margin: 0 auto;
|
||||||
|
border-radius: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-third-login a {
|
||||||
|
font-size: 22px;
|
||||||
|
margin: 0 auto;
|
||||||
|
border-radius: 100px;
|
||||||
|
display: inline-block;
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-third-login a:hover {
|
||||||
|
color: #1b90ff;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-third-login:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 320px) {
|
||||||
|
.aui-form {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-image {
|
||||||
|
order: 2;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-container {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 550px;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-content {
|
||||||
|
justify-content: initial;
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 321px) and (max-width: 375px) {
|
||||||
|
.aui-form {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-image {
|
||||||
|
order: 2;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-container {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 550px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-content {
|
||||||
|
justify-content: initial;
|
||||||
|
width: 100%;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 375px) and (max-width: 425px) {
|
||||||
|
.aui-form {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-image {
|
||||||
|
order: 2;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-container {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 550px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-content {
|
||||||
|
justify-content: initial;
|
||||||
|
width: 100%;
|
||||||
|
padding: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: 425px) and (max-width: 768px) {
|
||||||
|
.aui-form {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-image {
|
||||||
|
order: 2;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-container {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 550px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-content {
|
||||||
|
justify-content: initial;
|
||||||
|
width: 100%;
|
||||||
|
padding: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-step-box::after {
|
||||||
|
width: 70%;
|
||||||
|
margin-left: -35%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 767px) {
|
||||||
|
.aui-logo {
|
||||||
|
top: 3%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 300px) {
|
||||||
|
.aui-logo {
|
||||||
|
top: 3%;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,15 +14,18 @@
|
||||||
>
|
>
|
||||||
<a-popconfirm v-if="popconfirm && item.popConfirm" v-bind="getPopConfirmAttrs(item.popConfirm)">
|
<a-popconfirm v-if="popconfirm && item.popConfirm" v-bind="getPopConfirmAttrs(item.popConfirm)">
|
||||||
<template #icon v-if="item.popConfirm.icon">
|
<template #icon v-if="item.popConfirm.icon">
|
||||||
<Icon :icon="item.popConfirm.icon" />
|
<Icon v-if="item.iconColor" :icon="item.popConfirm.icon" :color="item.iconColor"/>
|
||||||
|
<Icon v-else :icon="item.popConfirm.icon"/>
|
||||||
</template>
|
</template>
|
||||||
<div class="dropdown-event-area">
|
<div class="dropdown-event-area">
|
||||||
<Icon :icon="item.icon" v-if="item.icon" />
|
<Icon :icon="item.icon" v-if="item.icon && item.iconColor" :color="item.iconColor"/>
|
||||||
|
<Icon :icon="item.icon" v-else-if="item.icon"/>
|
||||||
<span class="ml-1">{{ item.text }}</span>
|
<span class="ml-1">{{ item.text }}</span>
|
||||||
</div>
|
</div>
|
||||||
</a-popconfirm>
|
</a-popconfirm>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<Icon :icon="item.icon" v-if="item.icon" />
|
<Icon :icon="item.icon" v-if="item.icon && item.iconColor" :color="item.iconColor"/>
|
||||||
|
<Icon :icon="item.icon" v-else-if="item.icon"/>
|
||||||
<span class="ml-1">{{ item.text }}</span>
|
<span class="ml-1">{{ item.text }}</span>
|
||||||
</template>
|
</template>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
|
|
|
@ -53,6 +53,7 @@
|
||||||
import { basicProps } from './props';
|
import { basicProps } from './props';
|
||||||
import { useDesign } from '/@/hooks/web/useDesign';
|
import { useDesign } from '/@/hooks/web/useDesign';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
|
import { useDebounceFn } from '@vueuse/core';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
name: 'BasicForm',
|
name: 'BasicForm',
|
||||||
|
@ -239,13 +240,19 @@
|
||||||
propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
|
propsRef.value = deepMerge(unref(propsRef) || {}, formProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//update-begin-author:taoyan date:2022-11-28 for: QQYUN-3121 【优化】表单视图问题#scott测试 8、此功能未实现
|
||||||
|
const onFormSubmitWhenChange = useDebounceFn(handleSubmit, 300);
|
||||||
function setFormModel(key: string, value: any) {
|
function setFormModel(key: string, value: any) {
|
||||||
formModel[key] = value;
|
formModel[key] = value;
|
||||||
const { validateTrigger } = unref(getBindValue);
|
const { validateTrigger } = unref(getBindValue);
|
||||||
if (!validateTrigger || validateTrigger === 'change') {
|
if (!validateTrigger || validateTrigger === 'change') {
|
||||||
validateFields([key]).catch((_) => {});
|
validateFields([key]).catch((_) => {});
|
||||||
}
|
}
|
||||||
|
if(props.autoSearch === true){
|
||||||
|
onFormSubmitWhenChange();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
//update-end-author:taoyan date:2022-11-28 for: QQYUN-3121 【优化】表单视图问题#scott测试 8、此功能未实现
|
||||||
|
|
||||||
function handleEnterPress(e: KeyboardEvent) {
|
function handleEnterPress(e: KeyboardEvent) {
|
||||||
const { autoSubmitOnEnter } = unref(getProps);
|
const { autoSubmitOnEnter } = unref(getProps);
|
||||||
|
|
|
@ -58,7 +58,9 @@ import JSearchSelect from './jeecg/components/JSearchSelect.vue';
|
||||||
import JAddInput from './jeecg/components/JAddInput.vue';
|
import JAddInput from './jeecg/components/JAddInput.vue';
|
||||||
import { Time } from '/@/components/Time';
|
import { Time } from '/@/components/Time';
|
||||||
import JRangeNumber from './jeecg/components/JRangeNumber.vue';
|
import JRangeNumber from './jeecg/components/JRangeNumber.vue';
|
||||||
|
import UserSelect from './jeecg/components/userSelect/index.vue';
|
||||||
import JRangeDate from './jeecg/components/JRangeDate.vue'
|
import JRangeDate from './jeecg/components/JRangeDate.vue'
|
||||||
|
import JRangeTime from './jeecg/components/JRangeTime.vue'
|
||||||
|
|
||||||
const componentMap = new Map<ComponentType, Component>();
|
const componentMap = new Map<ComponentType, Component>();
|
||||||
|
|
||||||
|
@ -126,7 +128,9 @@ componentMap.set('JUpload', JUpload);
|
||||||
componentMap.set('JSearchSelect', JSearchSelect);
|
componentMap.set('JSearchSelect', JSearchSelect);
|
||||||
componentMap.set('JAddInput', JAddInput);
|
componentMap.set('JAddInput', JAddInput);
|
||||||
componentMap.set('JRangeNumber', JRangeNumber);
|
componentMap.set('JRangeNumber', JRangeNumber);
|
||||||
|
componentMap.set('UserSelect', UserSelect);
|
||||||
componentMap.set('RangeDate', JRangeDate);
|
componentMap.set('RangeDate', JRangeDate);
|
||||||
|
componentMap.set('RangeTime', JRangeTime);
|
||||||
|
|
||||||
export function add(compName: ComponentType, component: Component) {
|
export function add(compName: ComponentType, component: Component) {
|
||||||
componentMap.set(compName, component);
|
componentMap.set(compName, component);
|
||||||
|
|
|
@ -5,8 +5,7 @@
|
||||||
<RadioGroup v-bind="attrs" v-model:value="state" button-style="solid">
|
<RadioGroup v-bind="attrs" v-model:value="state" button-style="solid">
|
||||||
<template v-for="item in getOptions" :key="`${item.value}`">
|
<template v-for="item in getOptions" :key="`${item.value}`">
|
||||||
<RadioButton :value="item.value" :disabled="item.disabled">
|
<RadioButton :value="item.value" :disabled="item.disabled">
|
||||||
<Icon v-if="item.icon" :icon="item.icon" />
|
{{ item.label }}
|
||||||
{{ item.label ? item.label : '' }}
|
|
||||||
</RadioButton>
|
</RadioButton>
|
||||||
</template>
|
</template>
|
||||||
</RadioGroup>
|
</RadioGroup>
|
||||||
|
@ -17,13 +16,8 @@
|
||||||
import { isString } from '/@/utils/is';
|
import { isString } from '/@/utils/is';
|
||||||
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
|
import { useRuleFormItem } from '/@/hooks/component/useFormItem';
|
||||||
import { useAttrs } from '/@/hooks/core/useAttrs';
|
import { useAttrs } from '/@/hooks/core/useAttrs';
|
||||||
import { Icon } from '/@/components/Icon';
|
|
||||||
type OptionsItem = {
|
type OptionsItem = { label: string; value: string | number | boolean; disabled?: boolean };
|
||||||
icon?: string;
|
|
||||||
label?: string;
|
|
||||||
value: string | number | boolean;
|
|
||||||
disabled?: boolean;
|
|
||||||
};
|
|
||||||
type RadioItem = string | OptionsItem;
|
type RadioItem = string | OptionsItem;
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
@ -31,7 +25,6 @@
|
||||||
components: {
|
components: {
|
||||||
RadioGroup: Radio.Group,
|
RadioGroup: Radio.Group,
|
||||||
RadioButton: Radio.Button,
|
RadioButton: Radio.Button,
|
||||||
Icon,
|
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
|
|
|
@ -146,24 +146,26 @@
|
||||||
|
|
||||||
function handleChange(e) {
|
function handleChange(e) {
|
||||||
const { mode } = unref<Recordable>(getBindValue);
|
const { mode } = unref<Recordable>(getBindValue);
|
||||||
|
let changeValue:any;
|
||||||
// 兼容多选模式
|
// 兼容多选模式
|
||||||
|
|
||||||
|
//update-begin---author:wangshuai ---date:20230216 for:[QQYUN-4290]公文发文:选择机关代字报错,是因为值改变触发了change事件三次,导致数据发生改变------------
|
||||||
|
//采用一个值,不然的话state值变换触发多个change
|
||||||
if (mode === 'multiple') {
|
if (mode === 'multiple') {
|
||||||
state.value = e?.target?.value ?? e;
|
changeValue = e?.target?.value ?? e;
|
||||||
|
// 过滤掉空值
|
||||||
|
if (changeValue == null || changeValue === '') {
|
||||||
|
changeValue = [];
|
||||||
|
}
|
||||||
|
if (Array.isArray(changeValue)) {
|
||||||
|
changeValue = changeValue.filter((item) => item != null && item !== '');
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
state.value = [e?.target?.value ?? e];
|
changeValue = e?.target?.value ?? e;
|
||||||
}
|
}
|
||||||
// 过滤掉空值
|
state.value = changeValue;
|
||||||
if (state.value == null || state.value === '') {
|
//update-end---author:wangshuai ---date:20230216 for:[QQYUN-4290]公文发文:选择机关代字报错,是因为值改变触发了change事件三次,导致数据发生改变------------
|
||||||
state.value = [];
|
|
||||||
}
|
|
||||||
if (Array.isArray(state.value)) {
|
|
||||||
state.value = state.value.filter((item) => item != null && item !== '');
|
|
||||||
}
|
|
||||||
//update-begin---author:wangshuai ---date:20221123 for:单选模式要改成字符串------------
|
|
||||||
if(mode !== 'multiple' && state.value && state.value.length>0){
|
|
||||||
state.value = state.value[0];
|
|
||||||
}
|
|
||||||
//update-end---author:wangshuai ---date:20221123 for:单选模式要改成字符串--------------
|
|
||||||
// nextTick(() => formItemContext.onFieldChange());
|
// nextTick(() => formItemContext.onFieldChange());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
import { propTypes } from '/@/utils/propTypes';
|
import { propTypes } from '/@/utils/propTypes';
|
||||||
import { Form } from 'ant-design-vue';
|
import { Form } from 'ant-design-vue';
|
||||||
|
|
||||||
const placeholder = ['最小值', '最大值']
|
const placeholder = ['开始日期', '结束日期']
|
||||||
/**
|
/**
|
||||||
* 用于范围查询
|
* 用于范围查询
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
<template>
|
||||||
|
<a-time-range-picker v-model:value="rangeValue" @change="handleChange" :placeholder="placeholder" :valueFormat="format" :format="format"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineComponent, ref, watch } from 'vue';
|
||||||
|
import { propTypes } from '/@/utils/propTypes';
|
||||||
|
import { Form } from 'ant-design-vue';
|
||||||
|
|
||||||
|
const placeholder = ['开始时间', '结束时间']
|
||||||
|
/**
|
||||||
|
* 用于时间-time组件的范围查询
|
||||||
|
*/
|
||||||
|
export default defineComponent({
|
||||||
|
name: "JRangeTime",
|
||||||
|
props:{
|
||||||
|
value: propTypes.string.def(''),
|
||||||
|
format: propTypes.string.def('HH:mm:ss'),
|
||||||
|
placeholder: propTypes.string.def(''),
|
||||||
|
},
|
||||||
|
emits:['change', 'update:value'],
|
||||||
|
setup(props, {emit}){
|
||||||
|
const rangeValue = ref([])
|
||||||
|
const formItemContext = Form.useInjectFormItemContext();
|
||||||
|
|
||||||
|
watch(()=>props.value, (val)=>{
|
||||||
|
if(val){
|
||||||
|
rangeValue.value = val.split(',')
|
||||||
|
}else{
|
||||||
|
rangeValue.value = []
|
||||||
|
}
|
||||||
|
}, {immediate: true});
|
||||||
|
|
||||||
|
|
||||||
|
function handleChange(arr){
|
||||||
|
let str = ''
|
||||||
|
if(arr && arr.length>0){
|
||||||
|
if(arr[1] && arr[0]){
|
||||||
|
str = arr.join(',')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit('change', str);
|
||||||
|
emit('update:value', str);
|
||||||
|
formItemContext.onFieldChange();
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
rangeValue,
|
||||||
|
placeholder,
|
||||||
|
handleChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -13,6 +13,7 @@
|
||||||
v-bind="attrs"
|
v-bind="attrs"
|
||||||
@change="onChange"
|
@change="onChange"
|
||||||
@search="onSearch"
|
@search="onSearch"
|
||||||
|
:tree-checkable="treeCheckAble"
|
||||||
>
|
>
|
||||||
</a-tree-select>
|
</a-tree-select>
|
||||||
</template>
|
</template>
|
||||||
|
@ -50,8 +51,12 @@
|
||||||
reload: propTypes.number.def(1),
|
reload: propTypes.number.def(1),
|
||||||
//update-begin-author:taoyan date:2022-11-8 for: issues/4173 Online JTreeSelect控件changeOptions方法未生效
|
//update-begin-author:taoyan date:2022-11-8 for: issues/4173 Online JTreeSelect控件changeOptions方法未生效
|
||||||
url: propTypes.string.def(''),
|
url: propTypes.string.def(''),
|
||||||
params: propTypes.object.def({})
|
params: propTypes.object.def({}),
|
||||||
//update-end-author:taoyan date:2022-11-8 for: issues/4173 Online JTreeSelect控件changeOptions方法未生效
|
//update-end-author:taoyan date:2022-11-8 for: issues/4173 Online JTreeSelect控件changeOptions方法未生效
|
||||||
|
//update-begin---author:wangshuai date: 20230202 for: 新增是否有复选框
|
||||||
|
//默认没有选择框
|
||||||
|
treeCheckAble: propTypes.bool.def(false),
|
||||||
|
//update-end---author:wangshuai date: 20230202 for: 新增是否有复选框
|
||||||
});
|
});
|
||||||
const attrs = useAttrs();
|
const attrs = useAttrs();
|
||||||
const emit = defineEmits(['change', 'update:value']);
|
const emit = defineEmits(['change', 'update:value']);
|
||||||
|
|
|
@ -291,7 +291,7 @@
|
||||||
fileSize: item.size,
|
fileSize: item.size,
|
||||||
};
|
};
|
||||||
newFileList.push(fileJson);
|
newFileList.push(fileJson);
|
||||||
} else {
|
}else{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,282 @@
|
||||||
|
<template>
|
||||||
|
<BasicModal
|
||||||
|
@register="register"
|
||||||
|
:getContainer="getContainer"
|
||||||
|
:canFullscreen="false"
|
||||||
|
:title="title"
|
||||||
|
:width="500"
|
||||||
|
destroyOnClose
|
||||||
|
@ok="handleOk"
|
||||||
|
wrapClassName="j-user-select-modal2" >
|
||||||
|
|
||||||
|
<div style="position: relative; min-height: 350px">
|
||||||
|
<div style="width: 100%">
|
||||||
|
<a-input v-model:value="searchText" allowClear style="width: 100%" placeholder="搜索">
|
||||||
|
<template #prefix>
|
||||||
|
<SearchOutlined style="color: #c0c0c0" />
|
||||||
|
</template>
|
||||||
|
</a-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- tabs -->
|
||||||
|
<div class="modal-select-list-container">
|
||||||
|
<div class="scroll">
|
||||||
|
<div class="content" style="right: -10px">
|
||||||
|
|
||||||
|
<label class="item" v-for="item in showDataList" @click="(e)=>onSelect(e, item)">
|
||||||
|
<a-checkbox v-model:checked="item.checked">
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
</a-checkbox>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 选中用户 -->
|
||||||
|
<div class="selected-users" style="width: 100%; overflow-x: hidden">
|
||||||
|
<SelectedUserItem v-for="item in selectedList" :info="item" @unSelect="unSelect" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
|
import { SearchOutlined, CloseOutlined } from '@ant-design/icons-vue';
|
||||||
|
import SelectedUserItem from '../userSelect/SelectedUserItem.vue';
|
||||||
|
import { defHttp } from '/@/utils/http/axios';
|
||||||
|
import { computed, ref, toRaw, watch } from 'vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'PositionSelectModal',
|
||||||
|
components: {
|
||||||
|
BasicModal,
|
||||||
|
SearchOutlined,
|
||||||
|
CloseOutlined,
|
||||||
|
SelectedUserItem,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
multi: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
getContainer: {
|
||||||
|
type: Function,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
title:{
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'sys_position',
|
||||||
|
},
|
||||||
|
appId: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['selected', 'register'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
|
||||||
|
const searchText = ref('');
|
||||||
|
const selectedIdList = computed(() => {
|
||||||
|
let arr = selectedList.value;
|
||||||
|
if (!arr || arr.length == 0) {
|
||||||
|
return [];
|
||||||
|
} else {
|
||||||
|
return arr.map((k) => k.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(()=>props.appId, async (val)=>{
|
||||||
|
if(val){
|
||||||
|
await loadDataList();
|
||||||
|
}
|
||||||
|
}, {immediate: true});
|
||||||
|
|
||||||
|
|
||||||
|
// 弹窗事件
|
||||||
|
const [register] = useModalInner(() => {
|
||||||
|
let list = dataList.value;
|
||||||
|
if(!list || list.length ==0 ){
|
||||||
|
}
|
||||||
|
for(let item of list){
|
||||||
|
item.checked = false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 确定事件
|
||||||
|
function handleOk() {
|
||||||
|
let arr = toRaw(selectedIdList.value);
|
||||||
|
emit('selected', arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataList = ref<any[]>([]);
|
||||||
|
const showDataList = computed(()=>{
|
||||||
|
let list = dataList.value;
|
||||||
|
if(!list || list.length ==0 ){
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
let text = searchText.value;
|
||||||
|
if(!text){
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
return list.filter(item=>item.name.indexOf(text)>=0)
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedList = computed(()=>{
|
||||||
|
let list = dataList.value;
|
||||||
|
if(!list || list.length ==0 ){
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return list.filter(item=>item.checked)
|
||||||
|
});
|
||||||
|
|
||||||
|
function unSelect(id) {
|
||||||
|
let list = dataList.value;
|
||||||
|
if(!list || list.length ==0 ){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let arr = list.filter(item=>item.id == id);
|
||||||
|
arr[0].checked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadDataList() {
|
||||||
|
let params = {
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 200,
|
||||||
|
column: 'createTime',
|
||||||
|
order: 'desc'
|
||||||
|
};
|
||||||
|
const url = '/sys/position/list'
|
||||||
|
const data = await defHttp.get({ url, params }, { isTransformResponse: false });
|
||||||
|
if (data.success) {
|
||||||
|
const { records } = data.result;
|
||||||
|
let arr:any[] = [];
|
||||||
|
if(records && records.length>0){
|
||||||
|
for(let item of records){
|
||||||
|
arr.push({
|
||||||
|
id: item.id,
|
||||||
|
name: item.name || item.roleName,
|
||||||
|
selectType: props.type,
|
||||||
|
checked: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataList.value = arr;
|
||||||
|
} else {
|
||||||
|
console.error(data.message);
|
||||||
|
}
|
||||||
|
console.log('loadDataList', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function onSelect(e, item) {
|
||||||
|
prevent(e);
|
||||||
|
console.log('onselect');
|
||||||
|
item.checked = !item.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prevent(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
register,
|
||||||
|
showDataList,
|
||||||
|
searchText,
|
||||||
|
handleOk,
|
||||||
|
selectedList,
|
||||||
|
selectedIdList,
|
||||||
|
unSelect,
|
||||||
|
onSelect
|
||||||
|
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
.modal-select-list-container{
|
||||||
|
height: 352px;
|
||||||
|
margin-top: 12px;
|
||||||
|
overflow: auto;
|
||||||
|
.scroll{
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
.content{
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
overflow: scroll;
|
||||||
|
overflow-x: hidden;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
.item{
|
||||||
|
padding: 7px 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
&:hover{
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.j-user-select-modal2 {
|
||||||
|
.depart-select {
|
||||||
|
.ant-select-selector {
|
||||||
|
color: #fff !important;
|
||||||
|
background-color: #409eff !important;
|
||||||
|
border-radius: 5px !important;
|
||||||
|
}
|
||||||
|
.ant-select-selection-item,
|
||||||
|
.ant-select-arrow {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.my-search {
|
||||||
|
position: absolute;
|
||||||
|
top: 14px;
|
||||||
|
z-index: 1;
|
||||||
|
&.all-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.anticon {
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
color: #0a8fe9 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-tabs {
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-users {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-direction: row;
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-container {
|
||||||
|
padding-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,282 @@
|
||||||
|
<template>
|
||||||
|
<BasicModal
|
||||||
|
@register="register"
|
||||||
|
:getContainer="getContainer"
|
||||||
|
:canFullscreen="false"
|
||||||
|
:title="title"
|
||||||
|
:width="500"
|
||||||
|
destroyOnClose
|
||||||
|
@ok="handleOk"
|
||||||
|
wrapClassName="j-user-select-modal2" >
|
||||||
|
|
||||||
|
<div style="position: relative; min-height: 350px">
|
||||||
|
<div style="width: 100%">
|
||||||
|
<a-input v-model:value="searchText" allowClear style="width: 100%" placeholder="搜索">
|
||||||
|
<template #prefix>
|
||||||
|
<SearchOutlined style="color: #c0c0c0" />
|
||||||
|
</template>
|
||||||
|
</a-input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- tabs -->
|
||||||
|
<div class="modal-select-list-container">
|
||||||
|
<div class="scroll">
|
||||||
|
<div class="content" style="right: -10px">
|
||||||
|
|
||||||
|
<label class="item" v-for="item in showDataList" @click="(e)=>onSelect(e, item)">
|
||||||
|
<a-checkbox v-model:checked="item.checked">
|
||||||
|
<span class="text">{{ item.name }}</span>
|
||||||
|
</a-checkbox>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 选中用户 -->
|
||||||
|
<div class="selected-users" style="width: 100%; overflow-x: hidden">
|
||||||
|
<SelectedUserItem v-for="item in selectedList" :info="item" @unSelect="unSelect" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
|
import { SearchOutlined, CloseOutlined } from '@ant-design/icons-vue';
|
||||||
|
import SelectedUserItem from '../userSelect/SelectedUserItem.vue';
|
||||||
|
import { defHttp } from '/@/utils/http/axios';
|
||||||
|
|
||||||
|
import { computed, ref, toRaw, watch } from 'vue';
|
||||||
|
export default {
|
||||||
|
name: 'RoleSelectModal',
|
||||||
|
components: {
|
||||||
|
BasicModal,
|
||||||
|
SearchOutlined,
|
||||||
|
CloseOutlined,
|
||||||
|
SelectedUserItem,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
multi: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
},
|
||||||
|
getContainer: {
|
||||||
|
type: Function,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
title:{
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'sys_role',
|
||||||
|
},
|
||||||
|
appId: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['selected', 'register'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
|
||||||
|
const searchText = ref('');
|
||||||
|
const selectedIdList = computed(() => {
|
||||||
|
let arr = selectedList.value;
|
||||||
|
if (!arr || arr.length == 0) {
|
||||||
|
return [];
|
||||||
|
} else {
|
||||||
|
return arr.map((k) => k.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(()=>props.appId, async (val)=>{
|
||||||
|
if(val){
|
||||||
|
await loadDataList();
|
||||||
|
}
|
||||||
|
}, {immediate: true});
|
||||||
|
|
||||||
|
|
||||||
|
// 弹窗事件
|
||||||
|
const [register] = useModalInner(() => {
|
||||||
|
let list = dataList.value;
|
||||||
|
if(!list || list.length ==0 ){
|
||||||
|
}
|
||||||
|
for(let item of list){
|
||||||
|
item.checked = false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 确定事件
|
||||||
|
function handleOk() {
|
||||||
|
let arr = toRaw(selectedIdList.value);
|
||||||
|
emit('selected', arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataList = ref<any[]>([]);
|
||||||
|
const showDataList = computed(()=>{
|
||||||
|
let list = dataList.value;
|
||||||
|
if(!list || list.length ==0 ){
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
let text = searchText.value;
|
||||||
|
if(!text){
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
return list.filter(item=>item.name.indexOf(text)>=0)
|
||||||
|
});
|
||||||
|
|
||||||
|
const selectedList = computed(()=>{
|
||||||
|
let list = dataList.value;
|
||||||
|
if(!list || list.length ==0 ){
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return list.filter(item=>item.checked)
|
||||||
|
});
|
||||||
|
|
||||||
|
function unSelect(id) {
|
||||||
|
let list = dataList.value;
|
||||||
|
if(!list || list.length ==0 ){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let arr = list.filter(item=>item.id == id);
|
||||||
|
arr[0].checked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadDataList() {
|
||||||
|
let params = {
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 200,
|
||||||
|
column: 'createTime',
|
||||||
|
order: 'desc'
|
||||||
|
};
|
||||||
|
const url = '/sys/role/listByTenant';
|
||||||
|
const data = await defHttp.get({ url, params }, { isTransformResponse: false });
|
||||||
|
if (data.success) {
|
||||||
|
const { records } = data.result;
|
||||||
|
let arr:any[] = [];
|
||||||
|
if(records && records.length>0){
|
||||||
|
for(let item of records){
|
||||||
|
arr.push({
|
||||||
|
id: item.id,
|
||||||
|
name: item.name || item.roleName,
|
||||||
|
selectType: props.type,
|
||||||
|
checked: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataList.value = arr;
|
||||||
|
} else {
|
||||||
|
console.error(data.message);
|
||||||
|
}
|
||||||
|
console.log('loadDataList', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function onSelect(e, item) {
|
||||||
|
prevent(e);
|
||||||
|
console.log('onselect');
|
||||||
|
item.checked = !item.checked;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prevent(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
register,
|
||||||
|
showDataList,
|
||||||
|
searchText,
|
||||||
|
handleOk,
|
||||||
|
selectedList,
|
||||||
|
selectedIdList,
|
||||||
|
unSelect,
|
||||||
|
onSelect
|
||||||
|
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style scoped lang="less">
|
||||||
|
.modal-select-list-container{
|
||||||
|
height: 352px;
|
||||||
|
margin-top: 12px;
|
||||||
|
overflow: auto;
|
||||||
|
.scroll{
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
.content{
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
overflow: scroll;
|
||||||
|
overflow-x: hidden;
|
||||||
|
position: absolute;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
.item{
|
||||||
|
padding: 7px 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: block;
|
||||||
|
&:hover{
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.j-user-select-modal2 {
|
||||||
|
.depart-select {
|
||||||
|
.ant-select-selector {
|
||||||
|
color: #fff !important;
|
||||||
|
background-color: #409eff !important;
|
||||||
|
border-radius: 5px !important;
|
||||||
|
}
|
||||||
|
.ant-select-selection-item,
|
||||||
|
.ant-select-arrow {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.my-search {
|
||||||
|
position: absolute;
|
||||||
|
top: 14px;
|
||||||
|
z-index: 1;
|
||||||
|
&.all-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.anticon {
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
color: #0a8fe9 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-tabs {
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-users {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-direction: row;
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-container {
|
||||||
|
padding-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,144 @@
|
||||||
|
<template>
|
||||||
|
<div class="user-selected-item">
|
||||||
|
<div
|
||||||
|
style="
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
height: 24px;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding-right: 10px;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span style="width: 24px; height: 24px; line-height: 20px; margin-right: 3px; display: inline-block">
|
||||||
|
<a-avatar v-if="info.avatar" :src="getFileAccessHttpUrl(info.avatar)" :size="24"></a-avatar>
|
||||||
|
|
||||||
|
<a-avatar v-else-if="info.selectType == 'sys_role'" :size="24" style="background-color: rgb(255, 173, 0);">
|
||||||
|
<template #icon>
|
||||||
|
<team-outlined style="font-size: 16px"/>
|
||||||
|
</template>
|
||||||
|
</a-avatar>
|
||||||
|
<a-avatar v-else-if="info.selectType == 'sys_position'" :size="24" style="background-color: rgb(245, 34, 45);">
|
||||||
|
<template #icon>
|
||||||
|
<TagsOutlined style="font-size: 16px"/>
|
||||||
|
</template>
|
||||||
|
</a-avatar>
|
||||||
|
|
||||||
|
<a-avatar :size="24" v-else>
|
||||||
|
<template #icon><UserOutlined /></template>
|
||||||
|
</a-avatar>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<div style="height: 24px; line-height: 24px" class="ellipsis">
|
||||||
|
{{ info.realname || info.name }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="showClose" class="icon-close">
|
||||||
|
<CloseOutlined @click="removeSelect"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="!showClose" class="icon-remove">
|
||||||
|
<MinusCircleFilled @click="removeSelect" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { UserOutlined, CloseOutlined, MinusCircleFilled, TagsOutlined, TeamOutlined } from '@ant-design/icons-vue';
|
||||||
|
import {computed} from 'vue'
|
||||||
|
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'SelectedUserItem',
|
||||||
|
components: {
|
||||||
|
UserOutlined,
|
||||||
|
MinusCircleFilled,
|
||||||
|
CloseOutlined,
|
||||||
|
TagsOutlined,
|
||||||
|
TeamOutlined
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
info: {
|
||||||
|
type: Object,
|
||||||
|
default: () => {},
|
||||||
|
},
|
||||||
|
// 是否作为查询条件
|
||||||
|
query:{
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['unSelect'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
function removeSelect(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
emit('unSelect', props.info.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const showClose = computed(()=>{
|
||||||
|
if(props.query===true){
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
showClose,
|
||||||
|
removeSelect,
|
||||||
|
getFileAccessHttpUrl
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.user-selected-item {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 8px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 12px;
|
||||||
|
line-height: 30px;
|
||||||
|
vertical-align: middle;
|
||||||
|
|
||||||
|
.ellipsis {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.icon-remove {
|
||||||
|
position: absolute;
|
||||||
|
top: -10px;
|
||||||
|
right: -4px;
|
||||||
|
font-size: 18px;
|
||||||
|
width: 15px;
|
||||||
|
height: 15px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-close{
|
||||||
|
height: 22px;
|
||||||
|
line-height: 24px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-left: 7px;
|
||||||
|
&:hover{
|
||||||
|
color: #0a8fe9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.icon-remove {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,175 @@
|
||||||
|
<template>
|
||||||
|
<a-list item-layout="horizontal" :data-source="showDataList">
|
||||||
|
<template #renderItem="{ item }">
|
||||||
|
<a-list-item style="padding: 3px 0">
|
||||||
|
<div class="user-select-user-info" @click="(e) => onClickUser(e, item)">
|
||||||
|
<div>
|
||||||
|
<a-checkbox v-model:checked="checkStatus[item.id]" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a-avatar v-if="item.avatar" :src="getFileAccessHttpUrl(item.avatar)"></a-avatar>
|
||||||
|
<a-avatar v-else>
|
||||||
|
<template #icon><UserOutlined /></template>
|
||||||
|
</a-avatar>
|
||||||
|
</div>
|
||||||
|
<div :style="nameStyle">
|
||||||
|
{{ item.realname }}
|
||||||
|
</div>
|
||||||
|
<div :style="departStyle">
|
||||||
|
{{ item.orgCodeTxt }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-list-item>
|
||||||
|
</template>
|
||||||
|
</a-list>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { UserOutlined } from '@ant-design/icons-vue';
|
||||||
|
import { computed, toRaw, reactive, watchEffect, ref } from 'vue';
|
||||||
|
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'UserList',
|
||||||
|
props: {
|
||||||
|
dataList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
// 是否显示部门文本
|
||||||
|
depart: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
selectedIdList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
excludeUserIdList:{
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
UserOutlined,
|
||||||
|
},
|
||||||
|
emits: ['selected', 'unSelect'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
function onClickUser(e, user) {
|
||||||
|
e && prevent(e);
|
||||||
|
let status = checkStatus[user.id];
|
||||||
|
if (status === true) {
|
||||||
|
emit('unSelect', user.id);
|
||||||
|
} else {
|
||||||
|
emit('selected', toRaw(user));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTwoText(text) {
|
||||||
|
if (!text) {
|
||||||
|
return '';
|
||||||
|
} else {
|
||||||
|
return text.substr(0, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const departStyle = computed(() => {
|
||||||
|
if (props.depart === true) {
|
||||||
|
// 如果显示部门信息
|
||||||
|
return {
|
||||||
|
flex: 1,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
display: 'none',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const nameStyle = computed(() => {
|
||||||
|
if (props.depart === true) {
|
||||||
|
// 如果显示部门信息
|
||||||
|
return {
|
||||||
|
width: '200px',
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
flex: 1,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function onChangeChecked(e) {
|
||||||
|
console.error('onChangeChecked', e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// const showDataList = ref<any[]>([])
|
||||||
|
const checkStatus = reactive<any>({});
|
||||||
|
watchEffect(() => {
|
||||||
|
let arr1 = props.dataList;
|
||||||
|
if (!arr1 || arr1.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let idList = props.selectedIdList;
|
||||||
|
for (let item of arr1) {
|
||||||
|
if (idList.indexOf(item.id) >= 0) {
|
||||||
|
checkStatus[item.id] = true;
|
||||||
|
} else {
|
||||||
|
checkStatus[item.id] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
function prevent(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function records2DataList() {
|
||||||
|
let arr:any[] = [];
|
||||||
|
let excludeList = props.excludeUserIdList;
|
||||||
|
let records = props.dataList;
|
||||||
|
if(records && records.length>0){
|
||||||
|
for(let item of records){
|
||||||
|
if(excludeList.indexOf(item.id)<0){
|
||||||
|
arr.push({...item})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const showDataList = computed(()=>{
|
||||||
|
let excludeList = props.excludeUserIdList;
|
||||||
|
if(excludeList && excludeList.length>0){
|
||||||
|
return records2DataList();
|
||||||
|
}
|
||||||
|
return props.dataList;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
onClickUser,
|
||||||
|
getTwoText,
|
||||||
|
departStyle,
|
||||||
|
nameStyle,
|
||||||
|
onChangeChecked,
|
||||||
|
checkStatus,
|
||||||
|
showDataList,
|
||||||
|
getFileAccessHttpUrl
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.user-select-user-info {
|
||||||
|
display: flex;
|
||||||
|
> div {
|
||||||
|
height: 36px;
|
||||||
|
line-height: 36px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,181 @@
|
||||||
|
<template>
|
||||||
|
<a-row>
|
||||||
|
<a-col :span="12">
|
||||||
|
<div :style="containerStyle">
|
||||||
|
<a-tree
|
||||||
|
v-if="treeData.length > 0"
|
||||||
|
:load-data="loadChildren"
|
||||||
|
showIcon
|
||||||
|
autoExpandParent
|
||||||
|
:treeData="treeData"
|
||||||
|
:selectedKeys="selectedKeys"
|
||||||
|
v-model:expandedKeys="expandedKeys"
|
||||||
|
@select="onSelect"
|
||||||
|
>
|
||||||
|
</a-tree>
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12" style="padding-left: 10px">
|
||||||
|
<div :style="containerStyle">
|
||||||
|
<user-list :excludeUserIdList="excludeUserIdList" :dataList="userDataList" :selectedIdList="selectedIdList" @selected="onSelectUser" @unSelect="unSelectUser" />
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defHttp } from '/@/utils/http/axios';
|
||||||
|
import { computed, ref, watch } from 'vue';
|
||||||
|
import UserList from './UserList.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DepartUserList',
|
||||||
|
components: {
|
||||||
|
UserList,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
searchText: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
selectedIdList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
excludeUserIdList:{
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['loaded', 'selected', 'unSelect'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
//export const queryById = (params) => defHttp.get({ url: Api.queryById, params }, { isTransformResponse: false });
|
||||||
|
|
||||||
|
async function loadDepartTree(pid?) {
|
||||||
|
const url = '/sys/sysDepart/queryDepartTreeSync';
|
||||||
|
let params = {};
|
||||||
|
if (pid) {
|
||||||
|
params['pid'] = pid;
|
||||||
|
}
|
||||||
|
const data = await defHttp.get({ url, params }, { isTransformResponse: false });
|
||||||
|
console.log('loadDepartTree', data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function initRoot() {
|
||||||
|
console.log('initRoot');
|
||||||
|
const data = await loadDepartTree();
|
||||||
|
if (data.success) {
|
||||||
|
let arr = data.result;
|
||||||
|
treeData.value = arr;
|
||||||
|
emitDepartOptions(arr);
|
||||||
|
} else {
|
||||||
|
console.error(data.message);
|
||||||
|
}
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitDepartOptions(arr) {
|
||||||
|
let options = [];
|
||||||
|
if (arr && arr.length > 0) {
|
||||||
|
options = arr.map((k) => {
|
||||||
|
return {
|
||||||
|
value: k.id,
|
||||||
|
label: k.departName,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
emit('loaded', options);
|
||||||
|
}
|
||||||
|
|
||||||
|
initRoot();
|
||||||
|
|
||||||
|
const treeData = ref<any[]>([]);
|
||||||
|
const selectedKeys = ref<string[]>([]);
|
||||||
|
const expandedKeys = ref<string[]>([]);
|
||||||
|
const selectedDepartId = ref('');
|
||||||
|
function onSelect(ids, e) {
|
||||||
|
let record = e.node.dataRef;
|
||||||
|
selectedKeys.value = [record.key];
|
||||||
|
|
||||||
|
let id = ids[0];
|
||||||
|
selectedDepartId.value = id;
|
||||||
|
loadUserList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
selectedDepartId.value = '';
|
||||||
|
}
|
||||||
|
async function loadChildren(treeNode) {
|
||||||
|
console.log('loadChildren', treeNode);
|
||||||
|
const data = await loadDepartTree(treeNode.eventKey);
|
||||||
|
if (data.success) {
|
||||||
|
let arr = data.result;
|
||||||
|
treeNode.dataRef.children = [...arr];
|
||||||
|
treeData.value = [...treeData.value];
|
||||||
|
} else {
|
||||||
|
console.error(data.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxHeight = ref(300);
|
||||||
|
maxHeight.value = window.innerHeight - 300;
|
||||||
|
const containerStyle = computed(() => {
|
||||||
|
return {
|
||||||
|
'overflow-y': 'auto',
|
||||||
|
'max-height': maxHeight.value + 'px',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const userDataList = ref<any[]>([]);
|
||||||
|
async function loadUserList() {
|
||||||
|
const url = '/sys/user/selectUserList';
|
||||||
|
let params = {
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
};
|
||||||
|
if (props.searchText) {
|
||||||
|
params['keyword'] = props.searchText;
|
||||||
|
}
|
||||||
|
if (selectedDepartId.value) {
|
||||||
|
params['departId'] = selectedDepartId.value;
|
||||||
|
}
|
||||||
|
const data = await defHttp.get({ url, params }, { isTransformResponse: false });
|
||||||
|
if (data.success) {
|
||||||
|
const { records } = data.result;
|
||||||
|
userDataList.value = records;
|
||||||
|
} else {
|
||||||
|
console.error(data.message);
|
||||||
|
}
|
||||||
|
console.log('depart-loadUserList', data);
|
||||||
|
}
|
||||||
|
watch(
|
||||||
|
() => props.searchText,
|
||||||
|
() => {
|
||||||
|
loadUserList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function onSelectUser(info) {
|
||||||
|
emit('selected', info);
|
||||||
|
}
|
||||||
|
function unSelectUser(id) {
|
||||||
|
emit('unSelect', id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
containerStyle,
|
||||||
|
treeData,
|
||||||
|
selectedKeys,
|
||||||
|
expandedKeys,
|
||||||
|
onSelect,
|
||||||
|
loadChildren,
|
||||||
|
onSelectUser,
|
||||||
|
unSelectUser,
|
||||||
|
userDataList,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
|
@ -0,0 +1,136 @@
|
||||||
|
<template>
|
||||||
|
<a-row>
|
||||||
|
<a-col :span="12">
|
||||||
|
<div :style="containerStyle">
|
||||||
|
<a-tree v-if="treeData.length > 0" showIcon :treeData="treeData" :selectedKeys="selectedKeys" @select="onSelect"> </a-tree>
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="12" style="padding-left: 10px">
|
||||||
|
<div :style="containerStyle">
|
||||||
|
<user-list :excludeUserIdList="excludeUserIdList" :dataList="userDataList" :selectedIdList="selectedIdList" @selected="onSelectUser" @unSelect="unSelectUser" />
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { computed, ref, watch } from 'vue';
|
||||||
|
import { defHttp } from '/@/utils/http/axios';
|
||||||
|
import UserList from './UserList.vue';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'RoleUserList',
|
||||||
|
components: {
|
||||||
|
UserList,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
searchText: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
selectedIdList: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
excludeUserIdList:{
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['selected', 'unSelect'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const treeData = ref<any[]>([]);
|
||||||
|
async function loadRoleList() {
|
||||||
|
const url = '/sys/role/listByTenant';
|
||||||
|
let params = {
|
||||||
|
order: 'desc',
|
||||||
|
column: 'createTime',
|
||||||
|
pageSize: 200,
|
||||||
|
};
|
||||||
|
let arr = [];
|
||||||
|
const data = await defHttp.get({ url, params }, { isTransformResponse: false });
|
||||||
|
if (data.success) {
|
||||||
|
const { records } = data.result;
|
||||||
|
arr = records.map((k) => {
|
||||||
|
return {
|
||||||
|
title: k.roleName,
|
||||||
|
id: k.id,
|
||||||
|
key: k.id,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.log('loadRoleList', data);
|
||||||
|
treeData.value = arr;
|
||||||
|
}
|
||||||
|
loadRoleList();
|
||||||
|
|
||||||
|
const selectedKeys = ref<any[]>([]);
|
||||||
|
const selectedRoleId = ref('');
|
||||||
|
function onSelect(ids, e) {
|
||||||
|
let record = e.node.dataRef;
|
||||||
|
selectedKeys.value = [record.key];
|
||||||
|
|
||||||
|
let id = ids[0];
|
||||||
|
selectedRoleId.value = id;
|
||||||
|
loadUserList();
|
||||||
|
}
|
||||||
|
|
||||||
|
const userDataList = ref<any[]>([]);
|
||||||
|
async function loadUserList() {
|
||||||
|
const url = '/sys/user/selectUserList';
|
||||||
|
let params = {
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
};
|
||||||
|
if (props.searchText) {
|
||||||
|
params['keyword'] = props.searchText;
|
||||||
|
}
|
||||||
|
if (selectedRoleId.value) {
|
||||||
|
params['roleId'] = selectedRoleId.value;
|
||||||
|
}
|
||||||
|
const data = await defHttp.get({ url, params }, { isTransformResponse: false });
|
||||||
|
if (data.success) {
|
||||||
|
const { records } = data.result;
|
||||||
|
userDataList.value = records;
|
||||||
|
} else {
|
||||||
|
console.error(data.message);
|
||||||
|
}
|
||||||
|
console.log('role-loadUserList', data);
|
||||||
|
}
|
||||||
|
watch(
|
||||||
|
() => props.searchText,
|
||||||
|
() => {
|
||||||
|
loadUserList();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
function onSelectUser(info) {
|
||||||
|
emit('selected', info);
|
||||||
|
}
|
||||||
|
function unSelectUser(id) {
|
||||||
|
emit('unSelect', id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const maxHeight = ref(300);
|
||||||
|
maxHeight.value = window.innerHeight - 300;
|
||||||
|
const containerStyle = computed(() => {
|
||||||
|
return {
|
||||||
|
'overflow-y': 'auto',
|
||||||
|
'max-height': maxHeight.value + 'px',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
containerStyle,
|
||||||
|
treeData,
|
||||||
|
selectedKeys,
|
||||||
|
onSelect,
|
||||||
|
onSelectUser,
|
||||||
|
unSelectUser,
|
||||||
|
userDataList,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped></style>
|
|
@ -0,0 +1,347 @@
|
||||||
|
<template>
|
||||||
|
<BasicModal
|
||||||
|
@register="register"
|
||||||
|
:getContainer="getContainer"
|
||||||
|
:canFullscreen="false"
|
||||||
|
title="选择用户"
|
||||||
|
:width="600"
|
||||||
|
wrapClassName="j-user-select-modal2"
|
||||||
|
>
|
||||||
|
<!-- 部门下拉框 -->
|
||||||
|
<a-select v-model:value="selectedDepart" style="width: 100%" class="depart-select" @change="onDepartChange">
|
||||||
|
<a-select-option v-for="item in departOptions" :value="item.value">{{ item.label }}</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
|
||||||
|
<div style="position: relative; min-height: 350px">
|
||||||
|
<!-- 用户搜索框 -->
|
||||||
|
<div :class="searchInputStatus ? 'my-search all-width' : 'my-search'">
|
||||||
|
<span :class="searchInputStatus ? 'hidden' : ''" style="margin-left: 10px"
|
||||||
|
><SearchOutlined style="color: #c0c0c0" @click="showSearchInput"
|
||||||
|
/></span>
|
||||||
|
<div style="width: 100%" :class="searchInputStatus ? '' : 'hidden'">
|
||||||
|
<a-input v-model:value="searchText" @pressEnter="onSearchUser" style="width: 100%" placeholder="请输入用户名按回车搜索">
|
||||||
|
<template #prefix>
|
||||||
|
<SearchOutlined style="color: #c0c0c0" />
|
||||||
|
</template>
|
||||||
|
<template #suffix>
|
||||||
|
<CloseOutlined title="退出搜索" @click="clearSearch" />
|
||||||
|
</template>
|
||||||
|
</a-input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- tabs -->
|
||||||
|
<div class="my-tabs">
|
||||||
|
<a-tabs v-model:activeKey="myActiveKey" :centered="true" @change="onChangeTab">
|
||||||
|
<!-- 所有用户 -->
|
||||||
|
<a-tab-pane key="1" tab="全部" forceRender>
|
||||||
|
<user-list :excludeUserIdList="excludeUserIdList" :dataList="userDataList" :selectedIdList="selectedIdList" depart @selected="onSelectUser" @unSelect="unSelectUser" />
|
||||||
|
</a-tab-pane>
|
||||||
|
|
||||||
|
<!-- 部门用户 -->
|
||||||
|
<a-tab-pane key="2" tab="按部门" forceRender>
|
||||||
|
<depart-user-list
|
||||||
|
:searchText="searchText"
|
||||||
|
:selectedIdList="selectedIdList"
|
||||||
|
:excludeUserIdList="excludeUserIdList"
|
||||||
|
@loaded="initDepartOptions"
|
||||||
|
@selected="onSelectUser"
|
||||||
|
@unSelect="unSelectUser"
|
||||||
|
/>
|
||||||
|
</a-tab-pane>
|
||||||
|
|
||||||
|
<!-- 角色用户 -->
|
||||||
|
<a-tab-pane key="3" tab="按角色" forceRender>
|
||||||
|
<role-user-list :excludeUserIdList="excludeUserIdList" :searchText="searchText" :selectedIdList="selectedIdList" @selected="onSelectUser" @unSelect="unSelectUser" />
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 选中用户 -->
|
||||||
|
<div class="selected-users" style="width: 100%; overflow-x: hidden">
|
||||||
|
<SelectedUserItem v-for="item in selectedUserList" :info="item" @unSelect="unSelectUser" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<div style="display: flex; justify-content: space-between; width: 100%">
|
||||||
|
<div class="select-user-page-info">
|
||||||
|
<a-pagination
|
||||||
|
v-if="myActiveKey == '1'"
|
||||||
|
v-model:current="pageNo"
|
||||||
|
size="small"
|
||||||
|
:total="totalRecord"
|
||||||
|
show-quick-jumper
|
||||||
|
@change="onPageChange"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<a-button type="primary" @click="handleOk">确 定</a-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</BasicModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { BasicModal, useModalInner } from '/@/components/Modal';
|
||||||
|
import { SearchOutlined, CloseOutlined } from '@ant-design/icons-vue';
|
||||||
|
import UserList from './UserList.vue';
|
||||||
|
import SelectedUserItem from './SelectedUserItem.vue';
|
||||||
|
import DepartUserList from './UserListAndDepart.vue';
|
||||||
|
import RoleUserList from './UserListAndRole.vue';
|
||||||
|
import { Pagination } from 'ant-design-vue';
|
||||||
|
const APagination = Pagination;
|
||||||
|
import { defHttp } from '/@/utils/http/axios';
|
||||||
|
|
||||||
|
import { computed, ref, toRaw } from 'vue';
|
||||||
|
import { useUserStore } from '/@/store/modules/user';
|
||||||
|
export default {
|
||||||
|
name: 'UserSelectModal',
|
||||||
|
components: {
|
||||||
|
BasicModal,
|
||||||
|
SearchOutlined,
|
||||||
|
CloseOutlined,
|
||||||
|
SelectedUserItem,
|
||||||
|
UserList,
|
||||||
|
DepartUserList,
|
||||||
|
RoleUserList,
|
||||||
|
APagination,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
multi: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
getContainer: {
|
||||||
|
type: Function,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
//是否排除我自己
|
||||||
|
izExcludeMy: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
emits: ['selected', 'register'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const myActiveKey = ref('1');
|
||||||
|
const selectedUserList = ref<any[]>([]);
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const selectedIdList = computed(() => {
|
||||||
|
let arr = selectedUserList.value;
|
||||||
|
if (!arr || arr.length == 0) {
|
||||||
|
return [];
|
||||||
|
} else {
|
||||||
|
return arr.map((k) => k.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// QQYUN-4152【应用】已经存在的用户,添加的时候还可以重复选择
|
||||||
|
const excludeUserIdList = ref<any[]>([]);
|
||||||
|
|
||||||
|
// 弹窗事件
|
||||||
|
const [register] = useModalInner((data) => {
|
||||||
|
let list = data.list;
|
||||||
|
if (list && list.length > 0) {
|
||||||
|
selectedUserList.value = [...list];
|
||||||
|
} else {
|
||||||
|
selectedUserList.value = [];
|
||||||
|
}
|
||||||
|
if(data.excludeUserIdList){
|
||||||
|
excludeUserIdList.value = data.excludeUserIdList;
|
||||||
|
}else{
|
||||||
|
excludeUserIdList.value = [];
|
||||||
|
}
|
||||||
|
//如果排除我自己,直接excludeUserIdList.push排除即可
|
||||||
|
if (props.izExcludeMy) {
|
||||||
|
excludeUserIdList.value.push(userStore.getUserInfo.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 确定事件
|
||||||
|
function handleOk() {
|
||||||
|
let arr = toRaw(selectedUserList.value);
|
||||||
|
emit('selected', arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*--------------部门下拉框,用于筛选用户---------------*/
|
||||||
|
const selectedDepart = ref('');
|
||||||
|
const departOptions = ref<any[]>([]);
|
||||||
|
function initDepartOptions(options) {
|
||||||
|
departOptions.value = [{ value: '', label: '全部用户' }, ...options];
|
||||||
|
selectedDepart.value = '';
|
||||||
|
}
|
||||||
|
function onDepartChange() {
|
||||||
|
loadUserList();
|
||||||
|
}
|
||||||
|
/*--------------部门下拉框,用于筛选用户---------------*/
|
||||||
|
|
||||||
|
/*--------------第一页 搜索框---------------*/
|
||||||
|
const searchInputStatus = ref(false);
|
||||||
|
const searchText = ref('');
|
||||||
|
function showSearchInput(e) {
|
||||||
|
e && prevent(e);
|
||||||
|
searchInputStatus.value = true;
|
||||||
|
}
|
||||||
|
function onSearchUser() {
|
||||||
|
console.log('onSearchUser');
|
||||||
|
loadUserList();
|
||||||
|
}
|
||||||
|
function clearSearch(e) {
|
||||||
|
e && prevent(e);
|
||||||
|
searchText.value = '';
|
||||||
|
searchInputStatus.value = false;
|
||||||
|
loadUserList();
|
||||||
|
}
|
||||||
|
/*--------------第一页 搜索框---------------*/
|
||||||
|
|
||||||
|
/*--------------加载数据---------------*/
|
||||||
|
const pageNo = ref(1);
|
||||||
|
const totalRecord = ref(0);
|
||||||
|
const userDataList = ref<any[]>([]);
|
||||||
|
async function onPageChange() {
|
||||||
|
console.log('onPageChange', pageNo.value);
|
||||||
|
await loadUserList();
|
||||||
|
}
|
||||||
|
async function loadUserList() {
|
||||||
|
const url = '/sys/user/selectUserList';
|
||||||
|
let params = {
|
||||||
|
pageNo: pageNo.value,
|
||||||
|
pageSize: 10,
|
||||||
|
};
|
||||||
|
if (searchText.value) {
|
||||||
|
params['keyword'] = searchText.value;
|
||||||
|
}
|
||||||
|
if (selectedDepart.value) {
|
||||||
|
params['departId'] = selectedDepart.value;
|
||||||
|
}
|
||||||
|
const data = await defHttp.get({ url, params }, { isTransformResponse: false });
|
||||||
|
if (data.success) {
|
||||||
|
const { records, total } = data.result;
|
||||||
|
totalRecord.value = total;
|
||||||
|
userDataList.value = records;
|
||||||
|
} else {
|
||||||
|
console.error(data.message);
|
||||||
|
}
|
||||||
|
console.log('loadUserList', data);
|
||||||
|
}
|
||||||
|
/*--------------加载数据---------------*/
|
||||||
|
|
||||||
|
/*--------------选中/取消选中---------------*/
|
||||||
|
function onSelectUser(info) {
|
||||||
|
if (props.multi === true) {
|
||||||
|
let arr = selectedUserList.value;
|
||||||
|
let idList = selectedIdList.value;
|
||||||
|
if (idList.indexOf(info.id) < 0) {
|
||||||
|
arr.push({ ...info });
|
||||||
|
selectedUserList.value = arr;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
selectedUserList.value = [{ ...info }];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function unSelectUser(id) {
|
||||||
|
let arr = selectedUserList.value;
|
||||||
|
let index = -1;
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
if (arr[i].id === id) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index >= 0) {
|
||||||
|
arr.splice(index, 1);
|
||||||
|
selectedUserList.value = arr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*--------------选中/取消选中---------------*/
|
||||||
|
|
||||||
|
function onChangeTab(tab) {
|
||||||
|
myActiveKey.value = tab;
|
||||||
|
}
|
||||||
|
|
||||||
|
function prevent(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
|
||||||
|
//加载第一页数据
|
||||||
|
loadUserList();
|
||||||
|
|
||||||
|
return {
|
||||||
|
selectedDepart,
|
||||||
|
departOptions,
|
||||||
|
initDepartOptions,
|
||||||
|
onDepartChange,
|
||||||
|
|
||||||
|
register,
|
||||||
|
handleOk,
|
||||||
|
|
||||||
|
searchText,
|
||||||
|
searchInputStatus,
|
||||||
|
showSearchInput,
|
||||||
|
onSearchUser,
|
||||||
|
clearSearch,
|
||||||
|
|
||||||
|
myActiveKey,
|
||||||
|
onChangeTab,
|
||||||
|
|
||||||
|
pageNo,
|
||||||
|
totalRecord,
|
||||||
|
onPageChange,
|
||||||
|
userDataList,
|
||||||
|
selectedUserList,
|
||||||
|
selectedIdList,
|
||||||
|
onSelectUser,
|
||||||
|
unSelectUser,
|
||||||
|
excludeUserIdList
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
.j-user-select-modal2 {
|
||||||
|
.depart-select {
|
||||||
|
.ant-select-selector {
|
||||||
|
color: #fff !important;
|
||||||
|
background-color: #409eff !important;
|
||||||
|
border-radius: 5px !important;
|
||||||
|
}
|
||||||
|
.ant-select-selection-item,
|
||||||
|
.ant-select-arrow {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.my-search {
|
||||||
|
position: absolute;
|
||||||
|
top: 14px;
|
||||||
|
z-index: 1;
|
||||||
|
&.all-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.anticon {
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
color: #0a8fe9 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.my-tabs {
|
||||||
|
}
|
||||||
|
|
||||||
|
.selected-users {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
flex-direction: row;
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scroll-container {
|
||||||
|
padding-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,245 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div v-if="isSearchFormComp" @click="click2Add" :class="disabled?'disabled-user-select':''" style="padding:0 5px;background-color: #fff;border: 1px solid #ccc;border-radius: 3px;box-sizing: border-box;display:flex;color: #9e9e9e;font-size: 14px;flex-wrap: wrap;min-height: 32px;">
|
||||||
|
<template v-if="selectedUserList.length > 0">
|
||||||
|
<SelectedUserItem v-for="item in showUserList" :info="item" @unSelect="unSelectUser" query />
|
||||||
|
</template>
|
||||||
|
<span v-else style="height: 30px;line-height: 30px;display: inline-block;margin-left: 7px;color: #bfbfbf;">请选择用户</span>
|
||||||
|
<div v-if="ellipsisInfo.status" class="user-selected-item">
|
||||||
|
<div class="user-select-ellipsis">
|
||||||
|
<span style="color: red">+{{ellipsisInfo.count}}...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-else style="display: flex; flex-wrap: wrap; flex-direction: row" >
|
||||||
|
<template v-if="selectedUserList.length > 0">
|
||||||
|
<SelectedUserItem v-for="item in selectedUserList" :info="item" @unSelect="unSelectUser" />
|
||||||
|
</template>
|
||||||
|
<a-button v-if="showAddButton" shape="circle" @click="onShowModal"><PlusOutlined /></a-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<user-select-modal :multi="multi" :getContainer="getContainer" @register="registerModal" @selected="onSelected" :izExcludeMy="izExcludeMy"></user-select-modal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, watch, ref, computed, toRaw } from 'vue';
|
||||||
|
import { Form } from 'ant-design-vue';
|
||||||
|
import { PlusOutlined } from '@ant-design/icons-vue';
|
||||||
|
import { useModal } from '/@/components/Modal';
|
||||||
|
import UserSelectModal from './UserSelectModal.vue';
|
||||||
|
import { defHttp } from '/@/utils/http/axios';
|
||||||
|
import SelectedUserItem from './SelectedUserItem.vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'UserSelect',
|
||||||
|
components: {
|
||||||
|
PlusOutlined,
|
||||||
|
UserSelectModal,
|
||||||
|
SelectedUserItem,
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
store: {
|
||||||
|
type: String,
|
||||||
|
default: 'id',
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
multi: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
getContainer: {
|
||||||
|
type: Function,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
// 是否作为查询条件
|
||||||
|
query:{
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
//最多显示几个人员-query为true有效
|
||||||
|
maxCount:{
|
||||||
|
type: Number,
|
||||||
|
default: 2
|
||||||
|
},
|
||||||
|
disabled:{
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
//是否排除我自己
|
||||||
|
izExcludeMy:{
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update:value', 'change'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const formItemContext = Form.useInjectFormItemContext();
|
||||||
|
const loading = ref(true);
|
||||||
|
const selectedUserList = ref<any[]>([]);
|
||||||
|
const showUserList = computed(()=>{
|
||||||
|
let list = selectedUserList.value
|
||||||
|
let max = props.maxCount;
|
||||||
|
if(list.length<=max){
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
return list.filter((_item, index)=>index<max);
|
||||||
|
});
|
||||||
|
const ellipsisInfo = computed(()=>{
|
||||||
|
let max = props.maxCount;
|
||||||
|
let len = selectedUserList.value.length
|
||||||
|
if(len > max){
|
||||||
|
return {status: true, count: len-max};
|
||||||
|
}else{
|
||||||
|
return {status: false}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 注册弹窗
|
||||||
|
const [registerModal, { openModal, closeModal }] = useModal();
|
||||||
|
function onShowModal() {
|
||||||
|
if(props.disabled===true){
|
||||||
|
return ;
|
||||||
|
}
|
||||||
|
let list = toRaw(selectedUserList.value);
|
||||||
|
openModal(true, {
|
||||||
|
list,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSelected(arr) {
|
||||||
|
console.log('onSelected', arr);
|
||||||
|
selectedUserList.value = arr;
|
||||||
|
onSelectedChange();
|
||||||
|
closeModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSelectedChange() {
|
||||||
|
loading.value = false;
|
||||||
|
let temp: any[] = [];
|
||||||
|
let arr = selectedUserList.value;
|
||||||
|
if (arr && arr.length > 0) {
|
||||||
|
temp = arr.map((k) => {
|
||||||
|
return k[props.store];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
let str = temp.join(',');
|
||||||
|
emit('update:value', str);
|
||||||
|
emit('change', str);
|
||||||
|
formItemContext.onFieldChange();
|
||||||
|
console.log('选中数据', str);
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.value,
|
||||||
|
async (val) => {
|
||||||
|
if (val) {
|
||||||
|
if (loading.value === true) {
|
||||||
|
await getUserList(val);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
selectedUserList.value = [];
|
||||||
|
}
|
||||||
|
loading.value = true;
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
async function getUserList(ids) {
|
||||||
|
const url = '/sys/user/list';
|
||||||
|
let params = {
|
||||||
|
[props.store]: ids,
|
||||||
|
};
|
||||||
|
selectedUserList.value = [];
|
||||||
|
const data = await defHttp.get({ url, params }, { isTransformResponse: false });
|
||||||
|
if (data.success) {
|
||||||
|
const { records } = data.result;
|
||||||
|
selectedUserList.value = records;
|
||||||
|
} else {
|
||||||
|
console.error(data.message);
|
||||||
|
}
|
||||||
|
console.log('getUserList', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
const showAddButton = computed(() => {
|
||||||
|
if(props.disabled === true){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (props.multi === true) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (selectedUserList.value.length > 0) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function unSelectUser(id) {
|
||||||
|
console.log('unSelectUser', id);
|
||||||
|
let arr = selectedUserList.value;
|
||||||
|
let index = -1;
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
if (arr[i].id == id) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index >= 0) {
|
||||||
|
arr.splice(index, 1);
|
||||||
|
selectedUserList.value = arr;
|
||||||
|
|
||||||
|
onSelectedChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function click2Add(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
onShowModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
const isSearchFormComp = computed(()=>{
|
||||||
|
if(props.query===true){
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
registerModal,
|
||||||
|
onShowModal,
|
||||||
|
isSearchFormComp,
|
||||||
|
onSelected,
|
||||||
|
showAddButton,
|
||||||
|
unSelectUser,
|
||||||
|
selectedUserList,
|
||||||
|
showUserList,
|
||||||
|
ellipsisInfo,
|
||||||
|
click2Add
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.user-select-ellipsis{
|
||||||
|
width: 40px;
|
||||||
|
height: 24px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 22px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #f5f5f5;
|
||||||
|
border: 1px solid #f0f0f0;
|
||||||
|
}
|
||||||
|
.disabled-user-select{
|
||||||
|
cursor: not-allowed;
|
||||||
|
background-color: #f5f5f5 !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -29,6 +29,9 @@ export function useTreeBiz(treeRef, getList, props) {
|
||||||
watch(
|
watch(
|
||||||
selectValues,
|
selectValues,
|
||||||
({ value: values }: Recordable) => {
|
({ value: values }: Recordable) => {
|
||||||
|
if(!values){
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (openModal.value == false && values.length > 0) {
|
if (openModal.value == false && values.length > 0) {
|
||||||
loadingEcho.value = isFirstLoadEcho;
|
loadingEcho.value = isFirstLoadEcho;
|
||||||
isFirstLoadEcho = false;
|
isFirstLoadEcho = false;
|
||||||
|
|
|
@ -115,4 +115,7 @@ export const basicProps = {
|
||||||
labelAlign: propTypes.string,
|
labelAlign: propTypes.string,
|
||||||
|
|
||||||
rowProps: Object as PropType<RowProps>,
|
rowProps: Object as PropType<RowProps>,
|
||||||
|
|
||||||
|
// 当表单是查询条件的时候 当表单改变后自动查询,不需要点击查询按钮
|
||||||
|
autoSearch: propTypes.bool.def(false),
|
||||||
};
|
};
|
||||||
|
|
|
@ -141,6 +141,14 @@ export type ComponentType =
|
||||||
| 'JSearchSelect'
|
| 'JSearchSelect'
|
||||||
| 'JAddInput'
|
| 'JAddInput'
|
||||||
| 'Time'
|
| 'Time'
|
||||||
|
| 'OnlineSelectCascade'
|
||||||
|
| 'LinkTableCard'
|
||||||
|
| 'LinkTableSelect'
|
||||||
|
| 'LinkTableForQuery'
|
||||||
|
| 'CascaderPcaForQuery'
|
||||||
|
| 'UserSelect'
|
||||||
| 'RangeDate'
|
| 'RangeDate'
|
||||||
| 'RangeNumber'
|
| 'RangeNumber'
|
||||||
|
| 'linkRecordSelect'
|
||||||
|
| 'RangeTime'
|
||||||
| 'JRangeNumber';
|
| 'JRangeNumber';
|
||||||
|
|
|
@ -89,6 +89,7 @@
|
||||||
copy: propTypes.bool.def(false),
|
copy: propTypes.bool.def(false),
|
||||||
mode: propTypes.oneOf<('svg' | 'iconify')[]>(['svg', 'iconify']).def('iconify'),
|
mode: propTypes.oneOf<('svg' | 'iconify')[]>(['svg', 'iconify']).def('iconify'),
|
||||||
disabled: propTypes.bool.def(true),
|
disabled: propTypes.bool.def(true),
|
||||||
|
clearSelect: propTypes.bool.def(false)
|
||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(['change', 'update:value']);
|
const emit = defineEmits(['change', 'update:value']);
|
||||||
|
@ -126,13 +127,22 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClick(icon: string) {
|
function handleClick(icon: string) {
|
||||||
currentSelect.value = icon;
|
if(props.clearSelect === true){
|
||||||
if (props.copy) {
|
if(currentSelect.value===icon){
|
||||||
clipboardRef.value = icon;
|
currentSelect.value = ''
|
||||||
if (unref(isSuccessRef)) {
|
}else{
|
||||||
createMessage.success(t('component.icon.copy'));
|
currentSelect.value = icon;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
currentSelect.value = icon;
|
||||||
|
if (props.copy) {
|
||||||
|
clipboardRef.value = icon;
|
||||||
|
if (unref(isSuccessRef)) {
|
||||||
|
createMessage.success(t('component.icon.copy'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSearchChange(e: ChangeEvent) {
|
function handleSearchChange(e: ChangeEvent) {
|
||||||
|
|
|
@ -142,10 +142,13 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
visibleRef.value = !!props.visible;
|
|
||||||
fullScreenRef.value = !!props.defaultFullscreen;
|
fullScreenRef.value = !!props.defaultFullscreen;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
watchEffect(() => {
|
||||||
|
visibleRef.value = !!props.visible;
|
||||||
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => unref(visibleRef),
|
() => unref(visibleRef),
|
||||||
(v) => {
|
(v) => {
|
||||||
|
@ -265,4 +268,4 @@
|
||||||
.jeecg-modal-content {
|
.jeecg-modal-content {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
<!-- 是否开启评论区域 -->
|
<!-- 是否开启评论区域 -->
|
||||||
<template v-if="enableComment">
|
<template v-if="enableComment">
|
||||||
<Tooltip title="关闭" placement="bottom" v-if="commentSpan>0">
|
<Tooltip title="收起" placement="bottom" v-if="commentSpan>0">
|
||||||
<RightSquareOutlined @click="handleCloseComment" style="font-size: 16px"/>
|
<RightSquareOutlined @click="handleCloseComment" style="font-size: 16px"/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip title="展开" placement="bottom" v-else>
|
<Tooltip title="展开" placement="bottom" v-else>
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
prefixCls,
|
prefixCls,
|
||||||
`${prefixCls}--custom`,
|
`${prefixCls}--custom`,
|
||||||
{
|
{
|
||||||
[`${prefixCls}--can-full`]: props.canFullscreen,
|
[`${prefixCls}--can-full`]: props.canFullscreen || props.enableComment,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
@ -156,4 +156,4 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -205,9 +205,13 @@
|
||||||
footer: unref(getFooterProps),
|
footer: unref(getFooterProps),
|
||||||
...unref(getExpandOption),
|
...unref(getExpandOption),
|
||||||
};
|
};
|
||||||
if (slots.expandedRowRender) {
|
|
||||||
|
//update-begin---author:wangshuai ---date:20230214 for:[QQYUN-4237]代码生成 内嵌子表模式 没有滚动条------------
|
||||||
|
//额外的展开行存在插槽时会将滚动移除掉,注释掉
|
||||||
|
/*if (slots.expandedRowRender) {
|
||||||
propsData = omit(propsData, 'scroll');
|
propsData = omit(propsData, 'scroll');
|
||||||
}
|
}*/
|
||||||
|
//update-end---author:wangshuai ---date:20230214 for:[QQYUN-4237]代码生成 内嵌子表模式 没有滚动条------------
|
||||||
|
|
||||||
propsData = omit(propsData, ['class', 'onChange']);
|
propsData = omit(propsData, ['class', 'onChange']);
|
||||||
return propsData;
|
return propsData;
|
||||||
|
|
|
@ -65,7 +65,9 @@ export function useTableScroll(
|
||||||
if (!tableEl) return;
|
if (!tableEl) return;
|
||||||
|
|
||||||
if (!bodyEl) {
|
if (!bodyEl) {
|
||||||
bodyEl = tableEl.querySelector('.ant-table-body');
|
//update-begin-author:taoyan date:2023-2-11 for: issues/355 前端-jeecgboot-vue3 3.4.4版本,BasicTable高度自适应功能失效,设置BasicTable组件maxHeight失效; 原因已找到,请看详情
|
||||||
|
bodyEl = tableEl.querySelector('.ant-table-tbody');
|
||||||
|
//update-end-author:taoyan date:2023-2-11 for: issues/355 前端-jeecgboot-vue3 3.4.4版本,BasicTable高度自适应功能失效,设置BasicTable组件maxHeight失效; 原因已找到,请看详情
|
||||||
if (!bodyEl) return;
|
if (!bodyEl) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +93,7 @@ export function useTableScroll(
|
||||||
await nextTick();
|
await nextTick();
|
||||||
//Add a delay to get the correct bottomIncludeBody paginationHeight footerHeight headerHeight
|
//Add a delay to get the correct bottomIncludeBody paginationHeight footerHeight headerHeight
|
||||||
|
|
||||||
const headEl = tableEl.querySelector('.ant-table-thead ');
|
const headEl = tableEl.querySelector('.ant-table-thead');
|
||||||
|
|
||||||
if (!headEl) return;
|
if (!headEl) return;
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@ export interface ActionItem extends ButtonProps {
|
||||||
tooltip?: string | TooltipProps;
|
tooltip?: string | TooltipProps;
|
||||||
// 自定义类名
|
// 自定义类名
|
||||||
class?: string | Record<string, boolean> | any[];
|
class?: string | Record<string, boolean> | any[];
|
||||||
|
// 自定义图标颜色
|
||||||
|
iconColor?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PopConfirm {
|
export interface PopConfirm {
|
||||||
|
|
|
@ -89,6 +89,9 @@
|
||||||
let props = originColumn.value.props || {};
|
let props = originColumn.value.props || {};
|
||||||
props['mode'] = 'multiple';
|
props['mode'] = 'multiple';
|
||||||
props['maxTagCount'] = 1;
|
props['maxTagCount'] = 1;
|
||||||
|
//update-begin-author:taoyan date:2022-12-5 for: issues/271 Online表单主子表单下拉多选无法搜索
|
||||||
|
originColumn.value.allowSearch = true;
|
||||||
|
//update-end-author:taoyan date:2022-12-5 for: issues/271 Online表单主子表单下拉多选无法搜索
|
||||||
originColumn.value.props = props;
|
originColumn.value.props = props;
|
||||||
} else if (searchTypes.includes(props.type)) {
|
} else if (searchTypes.includes(props.type)) {
|
||||||
// 处理搜索
|
// 处理搜索
|
||||||
|
|
|
@ -353,6 +353,7 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps,
|
||||||
insertIndex: index,
|
insertIndex: index,
|
||||||
$table: xTable,
|
$table: xTable,
|
||||||
target: instanceRef.value,
|
target: instanceRef.value,
|
||||||
|
isModalData: options?.isModalData
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -368,6 +369,8 @@ export function useMethods(props: JVxeTableProps, { emit }, data: JVxeDataProps,
|
||||||
setActive?: boolean;
|
setActive?: boolean;
|
||||||
//是否需要触发change事件
|
//是否需要触发change事件
|
||||||
emitChange?:boolean
|
emitChange?:boolean
|
||||||
|
// 是否是modal弹窗添加的数据
|
||||||
|
isModalData?:boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -123,7 +123,7 @@
|
||||||
queryParam,
|
queryParam,
|
||||||
dictOptions,
|
dictOptions,
|
||||||
},
|
},
|
||||||
] = usePopBiz(getBindValue);
|
] = usePopBiz(getBindValue, tableRef);
|
||||||
|
|
||||||
const showSearchFlag = computed(() => unref(queryInfo) && unref(queryInfo).length > 0);
|
const showSearchFlag = computed(() => unref(queryInfo) && unref(queryInfo).length > 0);
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -559,6 +559,11 @@ export function usePopBiz(props, tableRef?) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
dataSource.value = data.records;
|
dataSource.value = data.records;
|
||||||
|
//update-begin-author:taoyan date:2023-2-11 for:issues/356 在线报表分页有问题
|
||||||
|
tableRef.value && tableRef.value.setPagination({
|
||||||
|
total: Number(data.total)
|
||||||
|
})
|
||||||
|
//update-end-author:taoyan date:2023-2-11 for:issues/356 在线报表分页有问题
|
||||||
} else {
|
} else {
|
||||||
pagination.total = 0;
|
pagination.total = 0;
|
||||||
dataSource.value = [];
|
dataSource.value = [];
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
<template>
|
||||||
|
<div class="user-avatar-info">
|
||||||
|
<a-popover title="" :overlayStyle="{width: '250px'}">
|
||||||
|
<template #content>
|
||||||
|
<div style="display: flex;flex-direction: row;align-items: center">
|
||||||
|
<div style="width: 60px;text-align: center">
|
||||||
|
<a-avatar v-if="userAvatar" :src="userAvatar" :size="47"/>
|
||||||
|
<a-avatar v-else :size="47">{{ getAvatarText() }}</a-avatar>
|
||||||
|
</div>
|
||||||
|
<div style="flex: 1;display: flex;flex-direction: column;margin-left: 12px">
|
||||||
|
<div style="color: #000;display: inline-block;font-size: 15px;font-weight: 700;margin-top: 3px;vertical-align: top;width: 170px;">
|
||||||
|
{{ userLabel }}
|
||||||
|
</div>
|
||||||
|
<div style="color: #757575;display: block;margin-top: 4px;">
|
||||||
|
{{ phone }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<span style="cursor: pointer">
|
||||||
|
<a-avatar v-if="userAvatar" :src="userAvatar" :loadError="loadError"/>
|
||||||
|
<a-avatar v-else>{{ getAvatarText() }}</a-avatar>
|
||||||
|
</span>
|
||||||
|
</a-popover>
|
||||||
|
<span class="realname-ellipsis">
|
||||||
|
{{ userLabel }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { ref, watchEffect, defineComponent } from 'vue';
|
||||||
|
import { defHttp } from '/@/utils/http/axios';
|
||||||
|
import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'UserAvatar',
|
||||||
|
props: {
|
||||||
|
username: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
detail:{
|
||||||
|
type: Object,
|
||||||
|
default: ()=>{},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const userAvatar = ref('');
|
||||||
|
const userLabel = ref('');
|
||||||
|
const phone = ref('');
|
||||||
|
|
||||||
|
watchEffect(async ()=>{
|
||||||
|
userAvatar.value = '';
|
||||||
|
userLabel.value = '';
|
||||||
|
phone.value = '';
|
||||||
|
let username = props.username;
|
||||||
|
if(username){
|
||||||
|
await initUserInfo(username);
|
||||||
|
}
|
||||||
|
let userInfo = props.detail;
|
||||||
|
if(userInfo){
|
||||||
|
if(userInfo.avatar){
|
||||||
|
userAvatar.value = getFileAccessHttpUrl(userInfo.avatar);
|
||||||
|
}
|
||||||
|
if(userInfo.realname){
|
||||||
|
userLabel.value = userInfo.realname;
|
||||||
|
}
|
||||||
|
if(userInfo.phone){
|
||||||
|
phone.value = userInfo.phone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function initUserInfo(val) {
|
||||||
|
const params = {
|
||||||
|
username: val,
|
||||||
|
};
|
||||||
|
const url = '/sys/user/getMultiUser';
|
||||||
|
const data = await defHttp.get({ url, params }, {isTransformResponse: false});
|
||||||
|
if(data && data.length > 0){
|
||||||
|
let temp = data[0].avatar;
|
||||||
|
if (temp) {
|
||||||
|
userAvatar.value = getFileAccessHttpUrl(temp)
|
||||||
|
}
|
||||||
|
userLabel.value = data[0].realname;
|
||||||
|
phone.value = data[0].phone;
|
||||||
|
}else{
|
||||||
|
console.log(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAvatarText() {
|
||||||
|
let text = userLabel.value;
|
||||||
|
if (!text) {
|
||||||
|
text = props.username;
|
||||||
|
}
|
||||||
|
if (text) {
|
||||||
|
if (text.length > 2) {
|
||||||
|
return text.substr(0, 2);
|
||||||
|
} else {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadError() {
|
||||||
|
userAvatar.value = '';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
userAvatar,
|
||||||
|
userLabel,
|
||||||
|
getAvatarText,
|
||||||
|
phone,
|
||||||
|
loadError
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
.user-avatar-info{
|
||||||
|
.ant-avatar-image{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.realname-ellipsis {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
vertical-align: top;
|
||||||
|
white-space: nowrap;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -1,13 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="comment-tabs-warp" v-if="showStatus">
|
<div class="comment-tabs-warp" v-if="showStatus">
|
||||||
<a-tabs @change="handleChange" :animated="false">
|
<a-tabs @change="handleChange" :animated="false">
|
||||||
<a-tab-pane tab="评论" key="comment" class="comment-list-tab">
|
<a-tab-pane v-if="showComment" tab="评论" key="comment" class="comment-list-tab">
|
||||||
<comment-list :tableName="tableName" :dataId="dataId" :datetime="datetime1"></comment-list>
|
<comment-list :tableName="tableName" :dataId="dataId" :datetime="datetime1"></comment-list>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane tab="文件" key="file">
|
<a-tab-pane v-if="showFiles" tab="文件" key="file">
|
||||||
<comment-files :tableName="tableName" :dataId="dataId" :datetime="datetime2"></comment-files>
|
<comment-files :tableName="tableName" :dataId="dataId" :datetime="datetime2"></comment-files>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
<a-tab-pane tab="日志" key="log">
|
<a-tab-pane v-if="showDataLog" tab="日志" key="log">
|
||||||
<data-log-list :tableName="tableName" :dataId="dataId" :datetime="datetime3"></data-log-list>
|
<data-log-list :tableName="tableName" :dataId="dataId" :datetime="datetime3"></data-log-list>
|
||||||
</a-tab-pane>
|
</a-tab-pane>
|
||||||
</a-tabs>
|
</a-tabs>
|
||||||
|
@ -35,6 +35,12 @@
|
||||||
props: {
|
props: {
|
||||||
tableName: propTypes.string.def(''),
|
tableName: propTypes.string.def(''),
|
||||||
dataId: propTypes.string.def(''),
|
dataId: propTypes.string.def(''),
|
||||||
|
// 显示评论
|
||||||
|
showComment: propTypes.bool.def(true),
|
||||||
|
// 显示文件
|
||||||
|
showFiles: propTypes.bool.def(true),
|
||||||
|
// 显示日志
|
||||||
|
showDataLog: propTypes.bool.def(true),
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
const showStatus = computed(() => {
|
const showStatus = computed(() => {
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<template #overlay>
|
<template #overlay>
|
||||||
<a-menu @click="handleMenuClick">
|
<a-menu @click="handleMenuClick">
|
||||||
<a-menu-item v-if="syncToApp" key="to-app">同步到{{ name }}</a-menu-item>
|
<a-menu-item v-if="syncToApp" key="to-app">同步到{{ name }}</a-menu-item>
|
||||||
<a-menu-item v-if="syncToLocal" key="to-local">同步到本地</a-menu-item>
|
<a-menu-item v-if="getSyncToLocal" key="to-local">同步到本地</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
</template>
|
</template>
|
||||||
</a-dropdown>
|
</a-dropdown>
|
||||||
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
/* JThirdAppButton 的子组件,不可单独使用 */
|
/* JThirdAppButton 的子组件,不可单独使用 */
|
||||||
|
import { computed } from 'vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
type: String,
|
type: String,
|
||||||
|
@ -26,6 +27,14 @@
|
||||||
// 声明Emits
|
// 声明Emits
|
||||||
const emit = defineEmits(['to-app', 'to-local']);
|
const emit = defineEmits(['to-app', 'to-local']);
|
||||||
|
|
||||||
|
const getSyncToLocal = computed(() => {
|
||||||
|
// 由于企业微信接口变更,将不再支持同步到本地
|
||||||
|
if (props.type === 'wechatEnterprise') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return props.syncToLocal;
|
||||||
|
});
|
||||||
|
|
||||||
function handleMenuClick(event) {
|
function handleMenuClick(event) {
|
||||||
emit(event.key, { type: props.type });
|
emit(event.key, { type: props.type });
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,9 @@ export const TENANT_ID = 'TENANT_ID';
|
||||||
// login info key
|
// login info key
|
||||||
export const LOGIN_INFO_KEY = 'LOGIN__INFO__';
|
export const LOGIN_INFO_KEY = 'LOGIN__INFO__';
|
||||||
|
|
||||||
|
// 聊天UID key
|
||||||
|
export const JEECG_CHAT_UID = 'JEECG_CHAT_UID';
|
||||||
|
|
||||||
export enum CacheTypeEnum {
|
export enum CacheTypeEnum {
|
||||||
SESSION,
|
SESSION,
|
||||||
LOCAL,
|
LOCAL,
|
||||||
|
|
|
@ -42,7 +42,7 @@ export enum ConfigEnum {
|
||||||
// Sign
|
// Sign
|
||||||
Sign = 'X-Sign',
|
Sign = 'X-Sign',
|
||||||
// 租户id
|
// 租户id
|
||||||
TENANT_ID = 'tenant-id',
|
TENANT_ID = 'X-Tenant-Id',
|
||||||
// 版本
|
// 版本
|
||||||
VERSION = 'X-Version',
|
VERSION = 'X-Version',
|
||||||
// 低代码应用ID
|
// 低代码应用ID
|
||||||
|
|
|
@ -9,4 +9,6 @@ export enum PageEnum {
|
||||||
ERROR_LOG_PAGE = '/error-log/list',
|
ERROR_LOG_PAGE = '/error-log/list',
|
||||||
// auth2登录路由路径
|
// auth2登录路由路径
|
||||||
OAUTH2_LOGIN_PAGE_PATH = '/oauth2-app/login',
|
OAUTH2_LOGIN_PAGE_PATH = '/oauth2-app/login',
|
||||||
|
//文件路由
|
||||||
|
SYS_FILES_PATH = '/file/share',
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,8 +73,10 @@ export function useMethods() {
|
||||||
<span>具体详情请<a href = ${href} download = ${fileName}> 点击下载 </a> </span>
|
<span>具体详情请<a href = ${href} download = ${fileName}> 点击下载 </a> </span>
|
||||||
</div>`,
|
</div>`,
|
||||||
});
|
});
|
||||||
} else if (fileInfo.code === 500) {
|
//update-begin---author:wangshuai ---date:20221121 for:[VUEN-2827]导入无权限,提示图标错误------------
|
||||||
|
} else if (fileInfo.code === 500 || fileInfo.code === 510) {
|
||||||
createMessage.error(fileInfo.message || `${data.file.name} 导入失败`);
|
createMessage.error(fileInfo.message || `${data.file.name} 导入失败`);
|
||||||
|
//update-end---author:wangshuai ---date:20221121 for:[VUEN-2827]导入无权限,提示图标错误------------
|
||||||
} else {
|
} else {
|
||||||
createMessage.success(fileInfo.message || `${data.file.name} 文件上传成功`);
|
createMessage.success(fileInfo.message || `${data.file.name} 文件上传成功`);
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,11 +88,19 @@ const getBaseOptions = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
function createModalOptions(options: ModalOptionsPartial, icon: string): ModalOptionsPartial {
|
function createModalOptions(options: ModalOptionsPartial, icon: string): ModalOptionsPartial {
|
||||||
|
//update-begin-author:taoyan date:2023-1-10 for: 可以自定义图标
|
||||||
|
let titleIcon:any = ''
|
||||||
|
if(options.icon){
|
||||||
|
titleIcon = options.icon;
|
||||||
|
}else{
|
||||||
|
titleIcon = getIcon(icon)
|
||||||
|
}
|
||||||
|
//update-end-author:taoyan date:2023-1-10 for: 可以自定义图标
|
||||||
return {
|
return {
|
||||||
...getBaseOptions(),
|
...getBaseOptions(),
|
||||||
...options,
|
...options,
|
||||||
content: renderContent(options),
|
content: renderContent(options),
|
||||||
icon: getIcon(icon),
|
icon: titleIcon
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,15 @@ import { isArray } from '/@/utils/is';
|
||||||
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
|
import { useMultipleTabStore } from '/@/store/modules/multipleTab';
|
||||||
|
|
||||||
// User permissions related operations
|
// User permissions related operations
|
||||||
export function usePermission(formData?) {
|
export function usePermission() {
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
const appStore = useAppStore();
|
const appStore = useAppStore();
|
||||||
const permissionStore = usePermissionStore();
|
const permissionStore = usePermissionStore();
|
||||||
|
//动态加载流程节点表单权限
|
||||||
|
let formData: any = {};
|
||||||
|
function initBpmFormData(_bpmFormData) {
|
||||||
|
formData = _bpmFormData;
|
||||||
|
}
|
||||||
const { closeAll } = useTabs(router);
|
const { closeAll } = useTabs(router);
|
||||||
|
|
||||||
//==================================工作流权限判断-begin=========================================
|
//==================================工作流权限判断-begin=========================================
|
||||||
|
@ -165,5 +170,5 @@ export function usePermission(formData?) {
|
||||||
}
|
}
|
||||||
//update-end-author:taoyan date:2022-6-17 for: VUEN-1342【流程】编码方式 节点权限配置好后,未生效
|
//update-end-author:taoyan date:2022-6-17 for: VUEN-1342【流程】编码方式 节点权限配置好后,未生效
|
||||||
|
|
||||||
return { changeRole, hasPermission, togglePermissionMode, refreshMenu, isDisabledAuth };
|
return { changeRole, hasPermission, togglePermissionMode, refreshMenu, isDisabledAuth, initBpmFormData };
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,6 @@
|
||||||
initWebSocket();
|
initWebSocket();
|
||||||
});
|
});
|
||||||
|
|
||||||
const messageCount = ref<number>(0)
|
|
||||||
function mapAnnouncement(item) {
|
function mapAnnouncement(item) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
|
@ -92,12 +91,6 @@
|
||||||
listData.value[1].list = sysMsgList.map(mapAnnouncement);
|
listData.value[1].list = sysMsgList.map(mapAnnouncement);
|
||||||
listData.value[0].count = anntMsgTotal;
|
listData.value[0].count = anntMsgTotal;
|
||||||
listData.value[1].count = sysMsgTotal;
|
listData.value[1].count = sysMsgTotal;
|
||||||
//update-begin-author:taoyan date:2022-8-30 for: 消息数量改变触发chat组件事件
|
|
||||||
let msgCount = anntMsgTotal+sysMsgTotal;
|
|
||||||
//update-begin-author:wangshuai date:2022-09-02 for: 消息未读数为0也需要传递,因为聊天需要计算总数
|
|
||||||
messageCount.value = msgCount
|
|
||||||
//update-end-author:wangshuai date:2022-09-02 for: 消息未读数为0也需要传递,因为聊天需要计算总数
|
|
||||||
//update-end-author:taoyan date:2022-8-30 for: 消息数量改变触发chat组件事件
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn('系统消息通知异常:', e);
|
console.warn('系统消息通知异常:', e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,7 +151,7 @@
|
||||||
* 提交数据
|
* 提交数据
|
||||||
*/
|
*/
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
if (unref(isMultiTenant) && !unref(tenantSelected)) {
|
if (unref(isMultiTenant) && unref(tenantSelected)==null) {
|
||||||
validate_status.value = 'error';
|
validate_status.value = 'error';
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -165,6 +165,9 @@
|
||||||
userStore.setTenant(unref(tenantSelected));
|
userStore.setTenant(unref(tenantSelected));
|
||||||
}
|
}
|
||||||
createMessage.success('切换成功');
|
createMessage.success('切换成功');
|
||||||
|
|
||||||
|
//切换租户后要刷新首页
|
||||||
|
window.location.reload();
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.log('登录选择出现问题', e);
|
console.log('登录选择出现问题', e);
|
||||||
|
@ -187,6 +190,7 @@
|
||||||
const result = await selectDepart({
|
const result = await selectDepart({
|
||||||
username: userStore.getUserInfo.username,
|
username: userStore.getUserInfo.username,
|
||||||
orgCode: unref(departSelected),
|
orgCode: unref(departSelected),
|
||||||
|
loginTenantId: unref(tenantSelected),
|
||||||
});
|
});
|
||||||
if (result.userInfo) {
|
if (result.userInfo) {
|
||||||
const userInfo = result.userInfo;
|
const userInfo = result.userInfo;
|
||||||
|
|
|
@ -156,7 +156,9 @@
|
||||||
updatePassword();
|
updatePassword();
|
||||||
break;
|
break;
|
||||||
case 'account':
|
case 'account':
|
||||||
go(`/page-demo/account/setting`);
|
//update-begin---author:wangshuai ---date:20221125 for:进入用户设置页面------------
|
||||||
|
go(`/system/usersetting`);
|
||||||
|
//update-end---author:wangshuai ---date:20221125 for:进入用户设置页面--------------
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
/>
|
/>
|
||||||
<LayoutBreadcrumb v-if="getShowContent && getShowBread" :theme="getHeaderTheme" />
|
<LayoutBreadcrumb v-if="getShowContent && getShowBread" :theme="getHeaderTheme" />
|
||||||
<!-- 欢迎语 -->
|
<!-- 欢迎语 -->
|
||||||
<span v-if="getShowContent && getShowBreadTitle" :class="[prefixCls, `${prefixCls}--${getHeaderTheme}`,'headerIntroductionClass']"> 欢迎进入 {{ title }} </span>
|
<span v-if="getShowContent && getShowBreadTitle && !getIsMobile" :class="[prefixCls, `${prefixCls}--${getHeaderTheme}`,'headerIntroductionClass']"> 欢迎进入 {{ title }} </span>
|
||||||
</div>
|
</div>
|
||||||
<!-- left end -->
|
<!-- left end -->
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,11 @@ export default {
|
||||||
// user dropdown
|
// user dropdown
|
||||||
dropdownItemDoc: 'Document',
|
dropdownItemDoc: 'Document',
|
||||||
dropdownItemLoginOut: 'Login Out',
|
dropdownItemLoginOut: 'Login Out',
|
||||||
|
dropdownItemSwitchPassword: 'Password Change',
|
||||||
dropdownItemSwitchDepart: 'Switch Department',
|
dropdownItemSwitchDepart: 'Switch Department',
|
||||||
dropdownItemRefreshCache: 'Clean cache',
|
dropdownItemRefreshCache: 'Clean cache',
|
||||||
|
dropdownItemSwitchAccount: 'Account Setting',
|
||||||
|
|
||||||
tooltipErrorLog: 'Error log',
|
tooltipErrorLog: 'Error log',
|
||||||
tooltipLock: 'Lock screen',
|
tooltipLock: 'Lock screen',
|
||||||
tooltipNotify: 'Notification',
|
tooltipNotify: 'Notification',
|
||||||
|
|
|
@ -94,9 +94,17 @@ export default {
|
||||||
|
|
||||||
userName: 'Username',
|
userName: 'Username',
|
||||||
password: 'Password',
|
password: 'Password',
|
||||||
|
inputCode: 'Verification code',
|
||||||
confirmPassword: 'Confirm Password',
|
confirmPassword: 'Confirm Password',
|
||||||
email: 'Email',
|
email: 'Email',
|
||||||
smsCode: 'SMS code',
|
smsCode: 'SMS code',
|
||||||
mobile: 'Mobile',
|
mobile: 'Mobile',
|
||||||
|
|
||||||
|
//重置密码页面英文
|
||||||
|
authentication:'authentication',
|
||||||
|
resetLoginPassword:'reset login password',
|
||||||
|
resetSuccess:'reset succeeded',
|
||||||
|
nextStep:'next step',
|
||||||
|
goToLogin:'go to login'
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -69,7 +69,7 @@ export default {
|
||||||
|
|
||||||
signInTitle: 'Jeecg Boot',
|
signInTitle: 'Jeecg Boot',
|
||||||
signInDesc: '是中国最具影响力的 企业级低代码平台!在线开发,可视化拖拽设计,零代码实现80%的基础功能~',
|
signInDesc: '是中国最具影响力的 企业级低代码平台!在线开发,可视化拖拽设计,零代码实现80%的基础功能~',
|
||||||
policy: '我同意xxx隐私政策',
|
policy: '我同意敲敲云隐私政策',
|
||||||
scanSign: `扫码后,即可完成登录`,
|
scanSign: `扫码后,即可完成登录`,
|
||||||
scanSuccess: `扫码成功,登录中`,
|
scanSuccess: `扫码成功,登录中`,
|
||||||
|
|
||||||
|
@ -101,5 +101,12 @@ export default {
|
||||||
mobile: '手机号码',
|
mobile: '手机号码',
|
||||||
|
|
||||||
subTitleText: '{0}秒后返回登录页面',
|
subTitleText: '{0}秒后返回登录页面',
|
||||||
|
|
||||||
|
//重置密码页面中文
|
||||||
|
authentication:'验证身份',
|
||||||
|
resetLoginPassword:'重置登录密码',
|
||||||
|
resetSuccess:'重置成功',
|
||||||
|
nextStep:'下一步',
|
||||||
|
goToLogin:'去登录'
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,6 +18,7 @@ import { setupI18n } from '/@/locales/setupI18n';
|
||||||
import { registerGlobComp } from '/@/components/registerGlobComp';
|
import { registerGlobComp } from '/@/components/registerGlobComp';
|
||||||
import { registerThirdComp } from '/@/settings/registerThirdComp';
|
import { registerThirdComp } from '/@/settings/registerThirdComp';
|
||||||
import { useSso } from '/@/hooks/web/useSso';
|
import { useSso } from '/@/hooks/web/useSso';
|
||||||
|
// 注册online模块lib
|
||||||
import { registerPackages } from '/@/utils/monorepo/registerPackages';
|
import { registerPackages } from '/@/utils/monorepo/registerPackages';
|
||||||
|
|
||||||
// 在本地开发中引入的,以提高浏览器响应速度
|
// 在本地开发中引入的,以提高浏览器响应速度
|
||||||
|
@ -37,7 +38,7 @@ async function bootstrap() {
|
||||||
// 初始化内部系统配置
|
// 初始化内部系统配置
|
||||||
initAppConfigStore();
|
initAppConfigStore();
|
||||||
|
|
||||||
// 注册外部模块路由
|
// 注册外部模块路由(注册online模块lib)
|
||||||
registerPackages(app);
|
registerPackages(app);
|
||||||
|
|
||||||
// 注册全局组件
|
// 注册全局组件
|
||||||
|
|
|
@ -15,10 +15,15 @@ const LOGIN_PATH = PageEnum.BASE_LOGIN;
|
||||||
//auth2登录路由
|
//auth2登录路由
|
||||||
const OAUTH2_LOGIN_PAGE_PATH = PageEnum.OAUTH2_LOGIN_PAGE_PATH;
|
const OAUTH2_LOGIN_PAGE_PATH = PageEnum.OAUTH2_LOGIN_PAGE_PATH;
|
||||||
|
|
||||||
|
//分享免登录路由
|
||||||
|
const SYS_FILES_PATH = PageEnum.SYS_FILES_PATH;
|
||||||
|
|
||||||
const ROOT_PATH = RootRoute.path;
|
const ROOT_PATH = RootRoute.path;
|
||||||
|
|
||||||
//update-begin---author:wangshuai ---date:20220629 for:[issues/I5BG1I]vue3不支持auth2登录------------
|
//update-begin---author:wangshuai ---date:20220629 for:[issues/I5BG1I]vue3不支持auth2登录------------
|
||||||
const whitePathList: PageEnum[] = [LOGIN_PATH, OAUTH2_LOGIN_PAGE_PATH];
|
//update-begin---author:wangshuai ---date:20221111 for: [VUEN-2472]分享免登录------------
|
||||||
|
const whitePathList: PageEnum[] = [LOGIN_PATH, OAUTH2_LOGIN_PAGE_PATH,SYS_FILES_PATH];
|
||||||
|
//update-end---author:wangshuai ---date:20221111 for: [VUEN-2472]分享免登录------------
|
||||||
//update-end---author:wangshuai ---date:20220629 for:[issues/I5BG1I]vue3不支持auth2登录------------
|
//update-end---author:wangshuai ---date:20220629 for:[issues/I5BG1I]vue3不支持auth2登录------------
|
||||||
|
|
||||||
export function createPermissionGuard(router: Router) {
|
export function createPermissionGuard(router: Router) {
|
||||||
|
|
|
@ -5,8 +5,9 @@ import { getParentLayout, LAYOUT, EXCEPTION_COMPONENT } from '/@/router/constant
|
||||||
import { cloneDeep, omit } from 'lodash-es';
|
import { cloneDeep, omit } from 'lodash-es';
|
||||||
import { warn } from '/@/utils/log';
|
import { warn } from '/@/utils/log';
|
||||||
import { createRouter, createWebHashHistory } from 'vue-router';
|
import { createRouter, createWebHashHistory } from 'vue-router';
|
||||||
import { getTenantId, getToken } from '/@/utils/auth';
|
import { getTenantId, getToken } from "/@/utils/auth";
|
||||||
import { URL_HASH_TAB } from '/@/utils';
|
import { URL_HASH_TAB } from '/@/utils';
|
||||||
|
//引入online lib路由
|
||||||
import { packageViews } from '/@/utils/monorepo/dynamicRouter';
|
import { packageViews } from '/@/utils/monorepo/dynamicRouter';
|
||||||
import {useI18n} from "/@/hooks/web/useI18n";
|
import {useI18n} from "/@/hooks/web/useI18n";
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ let dynamicViewsModules: Record<string, () => Promise<Recordable>>;
|
||||||
function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
|
function asyncImportRoute(routes: AppRouteRecordRaw[] | undefined) {
|
||||||
if (!dynamicViewsModules) {
|
if (!dynamicViewsModules) {
|
||||||
dynamicViewsModules = import.meta.glob('../../views/**/*.{vue,tsx}');
|
dynamicViewsModules = import.meta.glob('../../views/**/*.{vue,tsx}');
|
||||||
// 跟模块views合并
|
//合并online lib路由
|
||||||
dynamicViewsModules = Object.assign({}, dynamicViewsModules, packageViews);
|
dynamicViewsModules = Object.assign({}, dynamicViewsModules, packageViews);
|
||||||
}
|
}
|
||||||
if (!routes) return;
|
if (!routes) return;
|
||||||
|
|
|
@ -31,7 +31,9 @@ export const RootRoute: AppRouteRecordRaw = {
|
||||||
export const LoginRoute: AppRouteRecordRaw = {
|
export const LoginRoute: AppRouteRecordRaw = {
|
||||||
path: '/login',
|
path: '/login',
|
||||||
name: 'Login',
|
name: 'Login',
|
||||||
component: () => import('/@/views/sys/login/Login.vue'),
|
//新版后台登录,如果想要使用旧版登录放开即可
|
||||||
|
// component: () => import('/@/views/sys/login/Login.vue'),
|
||||||
|
component: () => import('/@/views/system/loginmini/MiniLogin.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: t('routes.basic.login'),
|
title: t('routes.basic.login'),
|
||||||
},
|
},
|
||||||
|
@ -41,7 +43,9 @@ export const LoginRoute: AppRouteRecordRaw = {
|
||||||
export const Oauth2LoginRoute: AppRouteRecordRaw = {
|
export const Oauth2LoginRoute: AppRouteRecordRaw = {
|
||||||
path: '/oauth2-app/login',
|
path: '/oauth2-app/login',
|
||||||
name: 'oauth2-app-login',
|
name: 'oauth2-app-login',
|
||||||
component: () => import('/@/views/sys/login/OAuth2Login.vue'),
|
//新版钉钉免登录,如果想要使用旧版放开即可
|
||||||
|
// component: () => import('/@/views/sys/login/OAuth2Login.vue'),
|
||||||
|
component: () => import('/@/views/system/loginmini/OAuth2Login.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: t('routes.oauth2.login'),
|
title: t('routes.oauth2.login'),
|
||||||
},
|
},
|
||||||
|
|
|
@ -14,6 +14,10 @@ const lsLocaleSetting = (ls.get(LOCALE_KEY) || localeSetting) as LocaleSetting;
|
||||||
interface LocaleState {
|
interface LocaleState {
|
||||||
localInfo: LocaleSetting;
|
localInfo: LocaleSetting;
|
||||||
pathTitleMap: object;
|
pathTitleMap: object;
|
||||||
|
// myapps主题色(低代码应用列表首页)
|
||||||
|
appIndexTheme: string
|
||||||
|
// myapps - 跳转前路由地址
|
||||||
|
appMainPth: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useLocaleStore = defineStore({
|
export const useLocaleStore = defineStore({
|
||||||
|
@ -21,6 +25,8 @@ export const useLocaleStore = defineStore({
|
||||||
state: (): LocaleState => ({
|
state: (): LocaleState => ({
|
||||||
localInfo: lsLocaleSetting,
|
localInfo: lsLocaleSetting,
|
||||||
pathTitleMap: {},
|
pathTitleMap: {},
|
||||||
|
appIndexTheme: '',
|
||||||
|
appMainPth: ''
|
||||||
}),
|
}),
|
||||||
getters: {
|
getters: {
|
||||||
getShowPicker(): boolean {
|
getShowPicker(): boolean {
|
||||||
|
@ -34,6 +40,12 @@ export const useLocaleStore = defineStore({
|
||||||
return (path) => state.pathTitleMap[path];
|
return (path) => state.pathTitleMap[path];
|
||||||
},
|
},
|
||||||
//update-end-author:taoyan date:2022-6-1 for: VUEN-1144 online 配置成菜单后,打开菜单,显示名称未展示为菜单名称
|
//update-end-author:taoyan date:2022-6-1 for: VUEN-1144 online 配置成菜单后,打开菜单,显示名称未展示为菜单名称
|
||||||
|
getAppIndexTheme(): string {
|
||||||
|
return this.appIndexTheme;
|
||||||
|
},
|
||||||
|
getAppMainPth(): string {
|
||||||
|
return this.appMainPth;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
/**
|
/**
|
||||||
|
@ -58,6 +70,12 @@ export const useLocaleStore = defineStore({
|
||||||
this.pathTitleMap[path] = title;
|
this.pathTitleMap[path] = title;
|
||||||
},
|
},
|
||||||
//update-end-author:taoyan date:2022-6-1 for: VUEN-1144 online 配置成菜单后,打开菜单,显示名称未展示为菜单名称
|
//update-end-author:taoyan date:2022-6-1 for: VUEN-1144 online 配置成菜单后,打开菜单,显示名称未展示为菜单名称
|
||||||
|
setAppIndexTheme(theme) {
|
||||||
|
this.appIndexTheme = theme;
|
||||||
|
},
|
||||||
|
setAppMainPth(path) {
|
||||||
|
this.appMainPth = path;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -123,9 +123,10 @@ export const useUserStore = defineStore({
|
||||||
try {
|
try {
|
||||||
const { goHome = true, mode, ...loginParams } = params;
|
const { goHome = true, mode, ...loginParams } = params;
|
||||||
const data = await loginApi(loginParams, mode);
|
const data = await loginApi(loginParams, mode);
|
||||||
const { token } = data;
|
const { token, userInfo } = data;
|
||||||
// save token
|
// save token
|
||||||
this.setToken(token);
|
this.setToken(token);
|
||||||
|
this.setTenant(userInfo.loginTenantId);
|
||||||
return this.afterLoginAction(goHome, data);
|
return this.afterLoginAction(goHome, data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
|
@ -246,6 +247,7 @@ export const useUserStore = defineStore({
|
||||||
this.setSessionTimeout(false);
|
this.setSessionTimeout(false);
|
||||||
this.setUserInfo(null);
|
this.setUserInfo(null);
|
||||||
this.setLoginInfo(null);
|
this.setLoginInfo(null);
|
||||||
|
this.setTenant(null);
|
||||||
//update-begin-author:liusq date:2022-5-5 for:退出登录后清除拖拽模块的接口前缀
|
//update-begin-author:liusq date:2022-5-5 for:退出登录后清除拖拽模块的接口前缀
|
||||||
localStorage.removeItem(JDragConfigEnum.DRAG_BASE_URL);
|
localStorage.removeItem(JDragConfigEnum.DRAG_BASE_URL);
|
||||||
//update-end-author:liusq date:2022-5-5 for: 退出登录后清除拖拽模块的接口前缀
|
//update-end-author:liusq date:2022-5-5 for: 退出登录后清除拖拽模块的接口前缀
|
||||||
|
|
|
@ -40,7 +40,7 @@ export const rules = {
|
||||||
if (required && !value) {
|
if (required && !value) {
|
||||||
return Promise.reject('请输入手机号码1!');
|
return Promise.reject('请输入手机号码1!');
|
||||||
}
|
}
|
||||||
if (!new RegExp(/^1[3|4|5|7|8|9][0-9]\d{8}$/).test(value)) {
|
if (!/^1[3456789]\d{9}$/.test(value)) {
|
||||||
return Promise.reject('手机号码格式有误');
|
return Promise.reject('手机号码格式有误');
|
||||||
}
|
}
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
|
|
|
@ -102,7 +102,7 @@
|
||||||
span: 12,
|
span: 12,
|
||||||
},
|
},
|
||||||
dynamicRules: ({ values }) => {
|
dynamicRules: ({ values }) => {
|
||||||
return values.field8 ? [{ required: true, message: '字段4必填' }] : [];
|
return values.field8 ? [{ required: true, message: '字段必填' }] : [];
|
||||||
},
|
},
|
||||||
componentProps: {
|
componentProps: {
|
||||||
options: [
|
options: [
|
||||||
|
|
|
@ -77,7 +77,7 @@
|
||||||
function onSearch(value: string) {
|
function onSearch(value: string) {
|
||||||
keyword.value = value;
|
keyword.value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const superQueryConfig = {
|
const superQueryConfig = {
|
||||||
name:{ title: "名称", view: "text", type: "string", order: 1 },
|
name:{ title: "名称", view: "text", type: "string", order: 1 },
|
||||||
birthday:{ title: "生日", view: "date", type: "string", order: 2 },
|
birthday:{ title: "生日", view: "date", type: "string", order: 2 },
|
||||||
|
@ -92,7 +92,7 @@
|
||||||
model[field] = str
|
model[field] = str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
schemas,
|
schemas,
|
||||||
formElRef,
|
formElRef,
|
||||||
|
@ -102,6 +102,7 @@
|
||||||
onSearch: useDebounceFn(onSearch, 300),
|
onSearch: useDebounceFn(onSearch, 300),
|
||||||
searchParams,
|
searchParams,
|
||||||
superQueryConfig,
|
superQueryConfig,
|
||||||
|
handleSuperQuery,
|
||||||
handleReset: () => {
|
handleReset: () => {
|
||||||
keyword.value = '';
|
keyword.value = '';
|
||||||
},
|
},
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
//ts语法
|
//ts语法
|
||||||
|
import type { ComputedRef } from 'vue';
|
||||||
import { ref, computed, unref, watch, inject } from 'vue';
|
import { ref, computed, unref, watch, inject } from 'vue';
|
||||||
import { BasicTable, TableAction } from '/@/components/Table';
|
import { BasicTable, TableAction } from '/@/components/Table';
|
||||||
import JeecgOrderCustomerModal from './components/JeecgOrderCustomerModal.vue';
|
import JeecgOrderCustomerModal from './components/JeecgOrderCustomerModal.vue';
|
||||||
|
@ -42,7 +43,10 @@
|
||||||
import { isEmpty } from '/@/utils/is';
|
import { isEmpty } from '/@/utils/is';
|
||||||
import { useMessage } from '/@/hooks/web/useMessage';
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
//接收主表id
|
//接收主表id
|
||||||
const orderId = inject('orderId') || '';
|
const orderId = inject<ComputedRef<string>>(
|
||||||
|
'orderId',
|
||||||
|
computed(() => '')
|
||||||
|
);
|
||||||
//提示弹窗
|
//提示弹窗
|
||||||
const $message = useMessage();
|
const $message = useMessage();
|
||||||
//弹窗model
|
//弹窗model
|
||||||
|
@ -51,7 +55,7 @@
|
||||||
// 列表页面公共参数、方法
|
// 列表页面公共参数、方法
|
||||||
const { prefixCls, tableContext } = useListPage({
|
const { prefixCls, tableContext } = useListPage({
|
||||||
tableProps: {
|
tableProps: {
|
||||||
api: customList,
|
api: getCustomList,
|
||||||
tableSetting:{
|
tableSetting:{
|
||||||
cacheKey:'customer'
|
cacheKey:'customer'
|
||||||
},
|
},
|
||||||
|
@ -70,13 +74,24 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
//注册table数据
|
//注册table数据
|
||||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
const [registerTable, { reload, setSelectedRowKeys }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||||
|
|
||||||
watch(orderId, () => {
|
watch(orderId, () => {
|
||||||
searchInfo['orderId'] = unref(orderId);
|
searchInfo['orderId'] = unref(orderId);
|
||||||
reload();
|
reload();
|
||||||
|
// 主表id变化时,清空子表的选中状态
|
||||||
|
setSelectedRowKeys([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function getCustomList(params) {
|
||||||
|
let { orderId } = params;
|
||||||
|
// 主表Id为空时,不查询子表数据,直接返回空数组
|
||||||
|
if (orderId == null || isEmpty(orderId)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return await customList(params);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增事件
|
* 新增事件
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
//ts语法
|
//ts语法
|
||||||
|
import type { ComputedRef } from 'vue';
|
||||||
import { ref, computed, unref, watch, inject } from 'vue';
|
import { ref, computed, unref, watch, inject } from 'vue';
|
||||||
import { BasicTable, TableAction } from '/@/components/Table';
|
import { BasicTable, TableAction } from '/@/components/Table';
|
||||||
import JeecgOrderTicketModal from './components/JeecgOrderTicketModal.vue';
|
import JeecgOrderTicketModal from './components/JeecgOrderTicketModal.vue';
|
||||||
|
@ -42,7 +43,10 @@
|
||||||
import { isEmpty } from '/@/utils/is';
|
import { isEmpty } from '/@/utils/is';
|
||||||
import { useMessage } from '/@/hooks/web/useMessage';
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
//接收主表id
|
//接收主表id
|
||||||
const orderId = inject('orderId');
|
const orderId = inject<ComputedRef<string>>(
|
||||||
|
'orderId',
|
||||||
|
computed(() => '')
|
||||||
|
);
|
||||||
//提示弹窗
|
//提示弹窗
|
||||||
const $message = useMessage();
|
const $message = useMessage();
|
||||||
//弹窗model
|
//弹窗model
|
||||||
|
@ -51,7 +55,7 @@
|
||||||
// 列表页面公共参数、方法
|
// 列表页面公共参数、方法
|
||||||
const { prefixCls, tableContext } = useListPage({
|
const { prefixCls, tableContext } = useListPage({
|
||||||
tableProps: {
|
tableProps: {
|
||||||
api: ticketList,
|
api: getTicketList,
|
||||||
tableSetting:{
|
tableSetting:{
|
||||||
cacheKey:'ticket'
|
cacheKey:'ticket'
|
||||||
},
|
},
|
||||||
|
@ -70,13 +74,24 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
//注册table数据
|
//注册table数据
|
||||||
const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
|
const [registerTable, { reload, setSelectedRowKeys }, { rowSelection, selectedRowKeys }] = tableContext;
|
||||||
|
|
||||||
watch(orderId, () => {
|
watch(orderId, () => {
|
||||||
searchInfo['orderId'] = unref(orderId);
|
searchInfo['orderId'] = unref(orderId);
|
||||||
reload();
|
reload();
|
||||||
|
// 主表id变化时,清空子表的选中状态
|
||||||
|
setSelectedRowKeys([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function getTicketList(params) {
|
||||||
|
let { orderId } = params;
|
||||||
|
// 主表Id为空时,不查询子表数据,直接返回空数组
|
||||||
|
if (orderId == null || isEmpty(orderId)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return await ticketList(params);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 新增事件
|
* 新增事件
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -179,7 +179,7 @@ export const customerFormSchema: FormSchema[] = [
|
||||||
label: '联系方式',
|
label: '联系方式',
|
||||||
field: 'telphone',
|
field: 'telphone',
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
rules: [{ required: false, pattern: /^1[3|4|5|7|8|9][0-9]\d{8}$/, message: '手机号码格式有误' }],
|
rules: [{ required: false, pattern: /^1[3456789]\d{9}$/, message: '手机号码格式有误' }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'orderId',
|
label: 'orderId',
|
||||||
|
|
|
@ -138,6 +138,21 @@ export const schemas: FormSchema[] = [
|
||||||
label: '选择值',
|
label: '选择值',
|
||||||
colProps: { span: 12 },
|
colProps: { span: 12 },
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: 'xldx2',
|
||||||
|
component: 'JSelectMultiple',
|
||||||
|
label: '字典下拉多选2',
|
||||||
|
colProps: { span: 12 },
|
||||||
|
componentProps: {
|
||||||
|
dictCode: 'sex',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'xldx2',
|
||||||
|
component: 'JEllipsis',
|
||||||
|
label: '选择值',
|
||||||
|
colProps: { span: 12 },
|
||||||
|
},
|
||||||
{
|
{
|
||||||
field: 'dxxlk',
|
field: 'dxxlk',
|
||||||
component: 'JDictSelectTag',
|
component: 'JDictSelectTag',
|
||||||
|
@ -645,26 +660,21 @@ export const schemas: FormSchema[] = [
|
||||||
label: '选中值',
|
label: '选中值',
|
||||||
colProps: { span: 12 },
|
colProps: { span: 12 },
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
field: 'radioButtonGroup',
|
field: 'userSelect2',
|
||||||
component: 'RadioButtonGroup',
|
component: 'UserSelect',
|
||||||
label: 'RadioButtonGroup',
|
label: '高级用户选择',
|
||||||
helpMessage: ['component模式'],
|
helpMessage: ['component模式'],
|
||||||
colProps: { span: 12 },
|
colProps: { span: 12 },
|
||||||
defaultValue: '0',
|
|
||||||
componentProps: {
|
|
||||||
options: [
|
|
||||||
{ value: '0',icon: 'ant-design:setting'},
|
|
||||||
{ label: '停用', value: '1',icon: 'mdi:home' },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'radioButtonGroup',
|
field: 'userSelect2',
|
||||||
component: 'JEllipsis',
|
component: 'JEllipsis',
|
||||||
label: '选中值',
|
label: '选中值',
|
||||||
colProps: { span: 12 },
|
colProps: { span: 12 },
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
field: 'superQuery',
|
field: 'superQuery',
|
||||||
component: 'Input',
|
component: 'Input',
|
||||||
|
|
|
@ -78,7 +78,7 @@ export const baseSetschemas: FormSchema[] = [
|
||||||
dynamicRules: ({ model, schema }) => {
|
dynamicRules: ({ model, schema }) => {
|
||||||
return [
|
return [
|
||||||
{ ...rules.duplicateCheckRule('sys_user', 'phone', model, schema, false)[0] },
|
{ ...rules.duplicateCheckRule('sys_user', 'phone', model, schema, false)[0] },
|
||||||
{ pattern: /^1[3|4|5|7|8|9][0-9]\d{8}$/, message: '手机号码格式有误' },
|
{ pattern: /^1[3456789]\d{9}$/, message: '手机号码格式有误' },
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
colProps: { span: 18 },
|
colProps: { span: 18 },
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { BasicColumn, FormSchema } from '/@/components/Table';
|
import { BasicColumn, FormSchema } from '/@/components/Table';
|
||||||
import { usePermission } from '/@/hooks/web/usePermission';
|
import { usePermission } from '/@/hooks/web/usePermission';
|
||||||
import { JVxeColumn, JVxeTypes } from '/@/components/jeecg/JVxeTable/types';
|
import { JVxeColumn, JVxeTypes } from '/@/components/jeecg/JVxeTable/types';
|
||||||
|
const { isDisabledAuth, hasPermission, initBpmFormData} = usePermission();
|
||||||
|
|
||||||
export const columns: BasicColumn[] = [
|
export const columns: BasicColumn[] = [
|
||||||
{
|
{
|
||||||
|
@ -47,7 +48,9 @@ export const columns: BasicColumn[] = [
|
||||||
];
|
];
|
||||||
|
|
||||||
export function getBpmFormSchema(formData) {
|
export function getBpmFormSchema(formData) {
|
||||||
const { isDisabledAuth, hasPermission } = usePermission(formData);
|
//注入流程节点表单权限
|
||||||
|
initBpmFormData(formData);
|
||||||
|
|
||||||
const formSchema2: FormSchema[] = [
|
const formSchema2: FormSchema[] = [
|
||||||
{
|
{
|
||||||
label: '订单号',
|
label: '订单号',
|
||||||
|
@ -94,7 +97,9 @@ export function getBpmFormSchema(formData) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getOrderCustomerFormSchema(formData) {
|
export function getOrderCustomerFormSchema(formData) {
|
||||||
const { isDisabledAuth, hasPermission } = usePermission(formData);
|
//注入流程节点表单权限
|
||||||
|
initBpmFormData(formData);
|
||||||
|
|
||||||
const formSchema2: FormSchema[] = [
|
const formSchema2: FormSchema[] = [
|
||||||
{
|
{
|
||||||
label: '客户名',
|
label: '客户名',
|
||||||
|
|
|
@ -46,7 +46,7 @@ export const columns: JVxeColumn[] = [
|
||||||
placeholder: '请输入${title}',
|
placeholder: '请输入${title}',
|
||||||
validateRules: [
|
validateRules: [
|
||||||
{
|
{
|
||||||
pattern: '^1(3|4|5|7|8)\\d{9}$',
|
pattern: '^1[3456789]\\d{9}$',
|
||||||
message: '${title}格式不正确',
|
message: '${title}格式不正确',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -122,7 +122,7 @@
|
||||||
const rememberMe = ref(false);
|
const rememberMe = ref(false);
|
||||||
|
|
||||||
const formData = reactive({
|
const formData = reactive({
|
||||||
account: 'admin',
|
account: 'jeecg',
|
||||||
password: '123456',
|
password: '123456',
|
||||||
inputCode: '',
|
inputCode: '',
|
||||||
});
|
});
|
||||||
|
|
|
@ -137,6 +137,12 @@
|
||||||
* 处理部门情况
|
* 处理部门情况
|
||||||
*/
|
*/
|
||||||
function bizDepart(loginResult) {
|
function bizDepart(loginResult) {
|
||||||
|
//如果登录接口返回了用户上次登录租户ID,则不需要重新选择
|
||||||
|
if(loginResult.userInfo?.orgCode && loginResult.userInfo?.orgCode!==''){
|
||||||
|
isMultiDepart.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let multi_depart = loginResult.multi_depart;
|
let multi_depart = loginResult.multi_depart;
|
||||||
//0:无部门 1:一个部门 2:多个部门
|
//0:无部门 1:一个部门 2:多个部门
|
||||||
if (multi_depart == 0) {
|
if (multi_depart == 0) {
|
||||||
|
@ -158,6 +164,12 @@
|
||||||
* 处理租户情况
|
* 处理租户情况
|
||||||
*/
|
*/
|
||||||
function bizTenantList(loginResult) {
|
function bizTenantList(loginResult) {
|
||||||
|
//如果登录接口返回了用户上次登录租户ID,则不需要重新选择
|
||||||
|
if(loginResult.userInfo?.loginTenantId && loginResult.userInfo?.loginTenantId!==0){
|
||||||
|
isMultiTenant.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let tenantArr = loginResult.tenantList;
|
let tenantArr = loginResult.tenantList;
|
||||||
if (Array.isArray(tenantArr)) {
|
if (Array.isArray(tenantArr)) {
|
||||||
if (tenantArr.length === 0) {
|
if (tenantArr.length === 0) {
|
||||||
|
@ -210,10 +222,10 @@
|
||||||
*/
|
*/
|
||||||
function departResolve() {
|
function departResolve() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!unref(isMultiDepart)) {
|
if (!unref(isMultiDepart) && !unref(isMultiTenant)) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
let params = { orgCode: formState.orgCode, username: unref(username) };
|
let params = { orgCode: formState.orgCode,loginTenantId: formState.tenantId, username: unref(username) };
|
||||||
defHttp.put({ url: '/sys/selectDepart', params }).then((res) => {
|
defHttp.put({ url: '/sys/selectDepart', params }).then((res) => {
|
||||||
if (res.userInfo) {
|
if (res.userInfo) {
|
||||||
userStore.setUserInfo(res.userInfo);
|
userStore.setUserInfo(res.userInfo);
|
||||||
|
|
|
@ -21,6 +21,9 @@ export enum Api {
|
||||||
|
|
||||||
getCurrentUserDeparts = '/sys/user/getCurrentUserDeparts',
|
getCurrentUserDeparts = '/sys/user/getCurrentUserDeparts',
|
||||||
selectDepart = '/sys/selectDepart',
|
selectDepart = '/sys/selectDepart',
|
||||||
|
getUpdateDepartInfo = '/sys/user/getUpdateDepartInfo',
|
||||||
|
doUpdateDepartInfo = '/sys/user/doUpdateDepartInfo',
|
||||||
|
changeDepartChargePerson = '/sys/user/changeDepartChargePerson',
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -93,3 +96,27 @@ export const getUserDeparts = (params?) => defHttp.get({ url: Api.getCurrentUser
|
||||||
* 切换选择部门
|
* 切换选择部门
|
||||||
*/
|
*/
|
||||||
export const selectDepart = (params?) => defHttp.put({ url: Api.selectDepart, params });
|
export const selectDepart = (params?) => defHttp.put({ url: Api.selectDepart, params });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑部门前获取部门相关信息
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const getUpdateDepartInfo = (id) => defHttp.get({ url: Api.getUpdateDepartInfo, params: {id} });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑部门
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
export const doUpdateDepartInfo = (params) => defHttp.put({ url: Api.doUpdateDepartInfo, params });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除部门
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export const deleteDepart = (id) => defHttp.delete({ url: Api.delete, params:{ id } }, { joinParamsToUrl: true });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置负责人 取消负责人
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
export const changeDepartChargePerson = (params) => defHttp.put({ url: Api.changeDepartChargePerson, params });
|
||||||
|
|
|
@ -9,7 +9,7 @@ export const columns: BasicColumn[] = [
|
||||||
width: 240,
|
width: 240,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '字典编号',
|
title: '字典编码',
|
||||||
dataIndex: 'dictCode',
|
dataIndex: 'dictCode',
|
||||||
width: 240,
|
width: 240,
|
||||||
},
|
},
|
||||||
|
@ -27,7 +27,7 @@ export const recycleBincolumns: BasicColumn[] = [
|
||||||
width: 120,
|
width: 120,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '字典编号',
|
title: '字典编码',
|
||||||
dataIndex: 'dictCode',
|
dataIndex: 'dictCode',
|
||||||
width: 120,
|
width: 120,
|
||||||
},
|
},
|
||||||
|
|
|
@ -211,4 +211,10 @@ export const formSchema: FormSchema[] = [
|
||||||
placeholder: '请输入个人简介',
|
placeholder: '请输入个人简介',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
field: 'updateCount',
|
||||||
|
label: '乐观锁',
|
||||||
|
show: false,
|
||||||
|
component: 'Input',
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -53,12 +53,15 @@
|
||||||
<a-button preIcon="ant-design:import-outlined" type="primary">导入</a-button>
|
<a-button preIcon="ant-design:import-outlined" type="primary">导入</a-button>
|
||||||
</a-upload>
|
</a-upload>
|
||||||
<a-button preIcon="ant-design:export-outlined" type="primary" @click="handleExportXls('单表示例', getExportUrl,exportParams)">导出</a-button>
|
<a-button preIcon="ant-design:export-outlined" type="primary" @click="handleExportXls('单表示例', getExportUrl,exportParams)">导出</a-button>
|
||||||
|
<a-button preIcon="ant-design:filter" type="primary" @click="">高级查询</a-button>
|
||||||
<a-button preIcon="ant-design:plus-outlined" type="primary" @click="openTab">打开Tab页</a-button>
|
<a-button preIcon="ant-design:plus-outlined" type="primary" @click="openTab">打开Tab页</a-button>
|
||||||
<a-button preIcon="ant-design:retweet-outlined" type="primary" @click="customSearch = !customSearch">{{
|
<a-button preIcon="ant-design:retweet-outlined" type="primary" @click="customSearch = !customSearch">{{
|
||||||
customSearch ? '表单配置查询' : '自定义查询'
|
customSearch ? '表单配置查询' : '自定义查询'
|
||||||
}}</a-button>
|
}}</a-button>
|
||||||
<a-button preIcon="ant-design:import-outlined" type="primary" @click="handleImport">弹窗导入</a-button>
|
<a-button preIcon="ant-design:import-outlined" type="primary" @click="handleImport">弹窗导入</a-button>
|
||||||
|
|
||||||
|
<super-query :config="superQueryConfig" @search="handleSuperQuery"/>
|
||||||
|
|
||||||
<a-dropdown v-if="checkedKeys.length > 0">
|
<a-dropdown v-if="checkedKeys.length > 0">
|
||||||
<template #overlay>
|
<template #overlay>
|
||||||
<a-menu>
|
<a-menu>
|
||||||
|
@ -122,7 +125,7 @@
|
||||||
},
|
},
|
||||||
//自定义默认排序
|
//自定义默认排序
|
||||||
defSort: {
|
defSort: {
|
||||||
column: 'sex,salaryMoney',
|
column: 'createTime,sex',
|
||||||
order: 'desc',
|
order: 'desc',
|
||||||
},
|
},
|
||||||
striped: true,
|
striped: true,
|
||||||
|
@ -285,6 +288,17 @@
|
||||||
}
|
}
|
||||||
//自定义查询----end---------
|
//自定义查询----end---------
|
||||||
|
|
||||||
|
const superQueryConfig = reactive({
|
||||||
|
name:{ title: "名称", view: "text", type: "string", order: 1 },
|
||||||
|
sex:{ title: "性别", view: "list", type: "string", dictCode:'sex', order: 2 },
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleSuperQuery(params) {
|
||||||
|
Object.keys(params).map(k=>{
|
||||||
|
queryParam[k] = params[k]
|
||||||
|
});
|
||||||
|
searchQuery();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.jeecg-basic-table-form-container {
|
.jeecg-basic-table-form-container {
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
<template>
|
||||||
|
<div class="aui-content">
|
||||||
|
<div class="aui-container">
|
||||||
|
<div class="aui-form">
|
||||||
|
<div class="aui-image">
|
||||||
|
<div class="aui-image-text">
|
||||||
|
<img :src="adTextImg" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-formBox aui-formEwm">
|
||||||
|
<div class="aui-formWell">
|
||||||
|
<form>
|
||||||
|
<div class="aui-flex aui-form-nav investment_title" style="padding-bottom: 19px">
|
||||||
|
<div class="aui-flex-box activeNav">{{t('sys.login.qrSignInFormTitle')}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-form-box">
|
||||||
|
<div class="aui-account" style="padding: 30px 0">
|
||||||
|
<div class="aui-ewm">
|
||||||
|
<QrCode :value="qrCodeUrl" class="enter-x flex justify-center xl:justify-start" :width="280" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-formButton">
|
||||||
|
<a class="aui-linek-code aui-link-register" @click="goBackHandleClick">{{t('sys.login.backSignIn')}}</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex aui-third-text">
|
||||||
|
<div class="aui-flex-box aui-third-border">
|
||||||
|
<span>{{ t('sys.login.otherSignIn') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex" :class="`${prefixCls}-sign-in-way`">
|
||||||
|
<div class="aui-flex-box">
|
||||||
|
<div class="aui-third-login">
|
||||||
|
<a href="" title="github" @click="onThirdLogin('github')"><GithubFilled /></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex-box">
|
||||||
|
<div class="aui-third-login">
|
||||||
|
<a href="" title="企业微信" @click="onThirdLogin('wechat_enterprise')"><icon-font class="item-icon" type="icon-qiyeweixin3" /></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex-box">
|
||||||
|
<div class="aui-third-login">
|
||||||
|
<a href="" title="钉钉" @click="onThirdLogin('dingtalk')"><DingtalkCircleFilled /></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex-box">
|
||||||
|
<div class="aui-third-login">
|
||||||
|
<a href="" title="微信" @click="onThirdLogin('wechat_open')"><WechatFilled /></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 第三方登录相关弹框 -->
|
||||||
|
<ThirdModal ref="thirdModalRef"></ThirdModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup name="mini-code-login">
|
||||||
|
import { ref, onUnmounted } from 'vue';
|
||||||
|
import { getLoginQrcode, getQrcodeToken } from '/@/api/sys/user';
|
||||||
|
import { useUserStore } from '/@/store/modules/user';
|
||||||
|
import { QrCode } from '/@/components/Qrcode/index';
|
||||||
|
import ThirdModal from '/@/views/sys/login/ThirdModal.vue';
|
||||||
|
import logoImg from '/@/assets/loginmini/icon/jeecg_logo.png';
|
||||||
|
import adTextImg from '/@/assets/loginmini/icon/jeecg_ad_text.png';
|
||||||
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
|
import { useDesign } from "/@/hooks/web/useDesign";
|
||||||
|
import { GithubFilled, WechatFilled, DingtalkCircleFilled, createFromIconfontCN } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
|
const IconFont = createFromIconfontCN({
|
||||||
|
scriptUrl: '//at.alicdn.com/t/font_2316098_umqusozousr.js',
|
||||||
|
});
|
||||||
|
const { prefixCls } = useDesign('minilogin');
|
||||||
|
const { t } = useI18n();
|
||||||
|
const qrCodeUrl = ref<string>('');
|
||||||
|
let timer: IntervalHandle;
|
||||||
|
const state = ref('0');
|
||||||
|
const thirdModalRef = ref();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const emit = defineEmits(['go-back', 'success', 'register']);
|
||||||
|
|
||||||
|
//加载二维码信息
|
||||||
|
function loadQrCode() {
|
||||||
|
state.value = '0';
|
||||||
|
getLoginQrcode().then((res) => {
|
||||||
|
qrCodeUrl.value = res.qrcodeId;
|
||||||
|
if (res.qrcodeId) {
|
||||||
|
openTimer(res.qrcodeId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
//监控扫码状态
|
||||||
|
function watchQrcodeToken(qrcodeId) {
|
||||||
|
getQrcodeToken({ qrcodeId: qrcodeId }).then((res) => {
|
||||||
|
let token = res.token;
|
||||||
|
if (token == '-2') {
|
||||||
|
//二维码过期重新获取
|
||||||
|
loadQrCode();
|
||||||
|
clearInterval(timer);
|
||||||
|
}
|
||||||
|
//扫码成功
|
||||||
|
if (res.success) {
|
||||||
|
state.value = '2';
|
||||||
|
clearInterval(timer);
|
||||||
|
setTimeout(() => {
|
||||||
|
userStore.qrCodeLogin(token);
|
||||||
|
}, 500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 开启定时器 */
|
||||||
|
function openTimer(qrcodeId) {
|
||||||
|
watchQrcodeToken(qrcodeId);
|
||||||
|
closeTimer();
|
||||||
|
timer = setInterval(() => {
|
||||||
|
watchQrcodeToken(qrcodeId);
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 关闭定时器 */
|
||||||
|
function closeTimer() {
|
||||||
|
if (timer) clearInterval(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方登录
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
function onThirdLogin(type) {
|
||||||
|
thirdModalRef.value.onThirdLogin(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化表单
|
||||||
|
*/
|
||||||
|
function initFrom() {
|
||||||
|
loadQrCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回
|
||||||
|
*/
|
||||||
|
function goBackHandleClick() {
|
||||||
|
emit('go-back');
|
||||||
|
closeTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
closeTimer();
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
initFrom,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import '/@/assets/loginmini/style/home.less';
|
||||||
|
@import '/@/assets/loginmini/style/base.less';
|
||||||
|
</style>
|
|
@ -0,0 +1,282 @@
|
||||||
|
<template>
|
||||||
|
<div class="aui-content">
|
||||||
|
<div class="aui-container">
|
||||||
|
<div class="aui-form">
|
||||||
|
<div class="aui-image">
|
||||||
|
<div class="aui-image-text">
|
||||||
|
<img :src="adTextImg" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-formBox">
|
||||||
|
<div class="aui-formWell">
|
||||||
|
<div class="aui-step-box">
|
||||||
|
<div class="aui-step-item" :class="activeKey === 1 ? 'activeStep' : ''">
|
||||||
|
<div class="aui-step-tags">
|
||||||
|
<em>1</em>
|
||||||
|
<p>{{t('sys.login.authentication')}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-step-item" :class="activeKey === 2 ? 'activeStep' : ''">
|
||||||
|
<div class="aui-step-tags">
|
||||||
|
<em>2</em>
|
||||||
|
<p>{{t('sys.login.resetLoginPassword')}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-step-item" :class="activeKey === 3 ? 'activeStep' : ''">
|
||||||
|
<div class="aui-step-tags">
|
||||||
|
<em>3</em>
|
||||||
|
<p>{{t('sys.login.resetSuccess')}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="" style="height: 230px; position: relative">
|
||||||
|
<a-form ref="formRef" :model="formData" v-if="activeKey === 1">
|
||||||
|
<!-- 身份验证 begin -->
|
||||||
|
<div class="aui-account aui-account-line aui-forgot">
|
||||||
|
<a-form-item>
|
||||||
|
<div class="aui-input-line">
|
||||||
|
<a-input type="text" :placeholder="t('sys.login.mobile')" v-model:value="formData.mobile" />
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
<div class="aui-input-line">
|
||||||
|
<a-form-item>
|
||||||
|
<a-input type="text" :placeholder="t('sys.login.smsCode')" v-model:value="formData.smscode" />
|
||||||
|
</a-form-item>
|
||||||
|
<div v-if="showInterval" class="aui-code-line" @click="getLoginCode">{{t('component.countdown.normalText')}}</div>
|
||||||
|
<div v-else class="aui-code-line">{{t('component.countdown.sendText',[unref(timeRuning)])}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- 身份验证 end -->
|
||||||
|
</a-form>
|
||||||
|
<a-form ref="pwdFormRef" :model="pwdFormData" v-else-if="activeKey === 2">
|
||||||
|
<!-- 重置密码 begin -->
|
||||||
|
<div class="aui-account aui-account-line aui-forgot">
|
||||||
|
<a-form-item>
|
||||||
|
<div class="aui-input-line">
|
||||||
|
<a-input type="password" :placeholder="t('sys.login.passwordPlaceholder')" v-model:value="pwdFormData.password" />
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<div class="aui-input-line">
|
||||||
|
<a-input type="password" :placeholder="t('sys.login.confirmPassword')" v-model:value="pwdFormData.confirmPassword" />
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
</div>
|
||||||
|
<!-- 重置密码 end -->
|
||||||
|
</a-form>
|
||||||
|
<!-- 重置成功 begin -->
|
||||||
|
<div class="aui-success" v-else>
|
||||||
|
<div class="aui-success-icon">
|
||||||
|
<img :src="successImg"/>
|
||||||
|
</div>
|
||||||
|
<h3>恭喜您,重置密码成功!</h3>
|
||||||
|
</div>
|
||||||
|
<!-- 重置成功 end -->
|
||||||
|
</div>
|
||||||
|
<div class="aui-formButton" style="padding-bottom: 40px">
|
||||||
|
<div class="aui-flex" v-if="activeKey === 1 || activeKey === 2">
|
||||||
|
<a class="aui-link-login aui-flex-box" @click="nextStepClick">{{t('sys.login.nextStep')}}</a>
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex" v-else>
|
||||||
|
<a class="aui-linek-code aui-flex-box" @click="toLogin">{{t('sys.login.goToLogin')}}</a>
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex">
|
||||||
|
<a class="aui-linek-code aui-flex-box" @click="goBack"> {{ t('sys.login.backSignIn') }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" name="mini-forgotpad" setup>
|
||||||
|
import { reactive, ref, toRaw, unref } from 'vue';
|
||||||
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
|
import { SmsEnum, useFormRules, useFormValid, useLoginState } from '/@/views/sys/login/useLogin';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
import { getCaptcha, passwordChange, phoneVerify } from '/@/api/sys/user';
|
||||||
|
import logoImg from '/@/assets/loginmini/icon/jeecg_logo.png'
|
||||||
|
import adTextImg from '/@/assets/loginmini/icon/jeecg_ad_text.png'
|
||||||
|
import successImg from '/@/assets/loginmini/icon/icon-success.png'
|
||||||
|
|
||||||
|
//下一步控制
|
||||||
|
const activeKey = ref<number>(1);
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { handleBackLogin } = useLoginState();
|
||||||
|
const { notification, createMessage, createErrorModal } = useMessage();
|
||||||
|
//是否显示获取验证码
|
||||||
|
const showInterval = ref<boolean>(true);
|
||||||
|
//60s
|
||||||
|
const timeRuning = ref<number>(60);
|
||||||
|
//定时器
|
||||||
|
const timer = ref<any>(null);
|
||||||
|
const formRef = ref();
|
||||||
|
const pwdFormRef = ref();
|
||||||
|
//账号数据
|
||||||
|
const accountInfo = reactive<any>({});
|
||||||
|
//手机号表单
|
||||||
|
const formData = reactive({
|
||||||
|
mobile: '',
|
||||||
|
smscode: '',
|
||||||
|
});
|
||||||
|
//密码表单
|
||||||
|
const pwdFormData = reactive<any>({
|
||||||
|
password: '',
|
||||||
|
confirmPassword: '',
|
||||||
|
});
|
||||||
|
const emit = defineEmits(['go-back', 'success', 'register']);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下一步
|
||||||
|
*/
|
||||||
|
async function handleNext() {
|
||||||
|
if (!formData.mobile) {
|
||||||
|
createMessage.warn(t('sys.login.mobilePlaceholder'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!formData.smscode) {
|
||||||
|
createMessage.warn(t('sys.login.smsPlaceholder'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const resultInfo = await phoneVerify(
|
||||||
|
toRaw({
|
||||||
|
phone: formData.mobile,
|
||||||
|
smscode: formData.smscode,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if (resultInfo.success) {
|
||||||
|
Object.assign(accountInfo, {
|
||||||
|
username: resultInfo.result.username,
|
||||||
|
phone: formData.mobile,
|
||||||
|
smscode: formData.smscode,
|
||||||
|
});
|
||||||
|
activeKey.value = 2;
|
||||||
|
setTimeout(()=>{
|
||||||
|
pwdFormRef.value.resetFields();
|
||||||
|
},300)
|
||||||
|
} else {
|
||||||
|
notification.error({
|
||||||
|
message: '错误提示',
|
||||||
|
description: resultInfo.message || t('sys.api.networkExceptionMsg'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完成修改密码
|
||||||
|
*/
|
||||||
|
async function finishedPwd() {
|
||||||
|
if (!pwdFormData.password) {
|
||||||
|
createMessage.warn(t('sys.login.passwordPlaceholder'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!pwdFormData.confirmPassword) {
|
||||||
|
createMessage.warn(t('sys.login.confirmPassword'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pwdFormData.password !== pwdFormData.confirmPassword) {
|
||||||
|
createMessage.warn(t('sys.login.diffPwd'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const resultInfo = await passwordChange(
|
||||||
|
toRaw({
|
||||||
|
username: accountInfo.username,
|
||||||
|
password: pwdFormData.password,
|
||||||
|
smscode: accountInfo.smscode,
|
||||||
|
phone: accountInfo.phone,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if (resultInfo.success) {
|
||||||
|
accountInfo.password = pwdFormData.password;
|
||||||
|
//修改密码
|
||||||
|
activeKey.value = 3;
|
||||||
|
} else {
|
||||||
|
//错误提示
|
||||||
|
createErrorModal({
|
||||||
|
title: t('sys.api.errorTip'),
|
||||||
|
content: resultInfo.message || t('sys.api.networkExceptionMsg'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 下一步
|
||||||
|
*/
|
||||||
|
function nextStepClick() {
|
||||||
|
if (unref(activeKey) == 1) {
|
||||||
|
handleNext();
|
||||||
|
} else if (unref(activeKey) == 2) {
|
||||||
|
finishedPwd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 去登录
|
||||||
|
*/
|
||||||
|
function toLogin() {
|
||||||
|
emit('success', { username: accountInfo.username, password: accountInfo.password });
|
||||||
|
initForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回
|
||||||
|
*/
|
||||||
|
function goBack() {
|
||||||
|
emit('go-back');
|
||||||
|
initForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取手机验证码
|
||||||
|
*/
|
||||||
|
async function getLoginCode() {
|
||||||
|
if (!formData.mobile) {
|
||||||
|
createMessage.warn(t('sys.login.mobilePlaceholder'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const result = await getCaptcha({ mobile: formData.mobile, smsmode: SmsEnum.FORGET_PASSWORD });
|
||||||
|
if (result) {
|
||||||
|
const TIME_COUNT = 60;
|
||||||
|
if (!unref(timer)) {
|
||||||
|
timeRuning.value = TIME_COUNT;
|
||||||
|
showInterval.value = false;
|
||||||
|
timer.value = setInterval(() => {
|
||||||
|
if (unref(timeRuning) > 0 && unref(timeRuning) <= TIME_COUNT) {
|
||||||
|
timeRuning.value = timeRuning.value - 1;
|
||||||
|
} else {
|
||||||
|
showInterval.value = true;
|
||||||
|
clearInterval(unref(timer));
|
||||||
|
timer.value = null;
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化表单
|
||||||
|
*/
|
||||||
|
function initForm() {
|
||||||
|
activeKey.value = 1;
|
||||||
|
Object.assign(formData, { phone: '', smscode: '' });
|
||||||
|
Object.assign(pwdFormData, { password: '', confirmPassword: '' });
|
||||||
|
Object.assign(accountInfo, {});
|
||||||
|
if(unref(timer)){
|
||||||
|
clearInterval(unref(timer));
|
||||||
|
timer.value = null;
|
||||||
|
showInterval.value = true;
|
||||||
|
}
|
||||||
|
setTimeout(()=>{
|
||||||
|
formRef.value.resetFields();
|
||||||
|
},300)
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
initForm,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import '/@/assets/loginmini/style/home.less';
|
||||||
|
@import '/@/assets/loginmini/style/base.less';
|
||||||
|
</style>
|
|
@ -0,0 +1,557 @@
|
||||||
|
<template>
|
||||||
|
<div :class="prefixCls" class="login-background-img">
|
||||||
|
<AppLocalePicker class="absolute top-4 right-4 enter-x xl:text-gray-600" :showText="false"/>
|
||||||
|
<AppDarkModeToggle class="absolute top-3 right-7 enter-x" />
|
||||||
|
<div class="aui-logo" v-if="!getIsMobile">
|
||||||
|
<div>
|
||||||
|
<h3>
|
||||||
|
<img :src="logoImg" alt="jeecg" />
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-else class="aui-phone-logo">
|
||||||
|
<img :src="logoImg" alt="jeecg" />
|
||||||
|
</div>
|
||||||
|
<div v-show="type === 'login'">
|
||||||
|
<div class="aui-content">
|
||||||
|
<div class="aui-container">
|
||||||
|
<div class="aui-form">
|
||||||
|
<div class="aui-image">
|
||||||
|
<div class="aui-image-text">
|
||||||
|
<img :src="adTextImg" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-formBox">
|
||||||
|
<div class="aui-formWell">
|
||||||
|
<div class="aui-flex aui-form-nav investment_title">
|
||||||
|
<div class="aui-flex-box" :class="activeIndex === 'accountLogin' ? 'activeNav on' : ''" @click="loginClick('accountLogin')"
|
||||||
|
>{{ t('sys.login.signInFormTitle') }}
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex-box" :class="activeIndex === 'phoneLogin' ? 'activeNav on' : ''" @click="loginClick('phoneLogin')"
|
||||||
|
>{{ t('sys.login.mobileSignInFormTitle') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-form-box" style="height: 180px">
|
||||||
|
<a-form ref="loginRef" :model="formData" v-if="activeIndex === 'accountLogin'" @keyup.enter.native="loginHandleClick">
|
||||||
|
<div class="aui-account">
|
||||||
|
<div class="aui-inputClear">
|
||||||
|
<i class="icon icon-code"></i>
|
||||||
|
<a-form-item>
|
||||||
|
<a-input class="fix-auto-fill" :placeholder="t('sys.login.userName')" v-model:value="formData.username" />
|
||||||
|
</a-form-item>
|
||||||
|
</div>
|
||||||
|
<div class="aui-inputClear">
|
||||||
|
<i class="icon icon-password"></i>
|
||||||
|
<a-form-item>
|
||||||
|
<a-input class="fix-auto-fill" type="password" :placeholder="t('sys.login.password')" v-model:value="formData.password" />
|
||||||
|
</a-form-item>
|
||||||
|
</div>
|
||||||
|
<div class="aui-inputClear">
|
||||||
|
<i class="icon icon-code"></i>
|
||||||
|
<a-form-item>
|
||||||
|
<a-input class="fix-auto-fill" type="text" :placeholder="t('sys.login.inputCode')" v-model:value="formData.inputCode" />
|
||||||
|
</a-form-item>
|
||||||
|
<div class="aui-code">
|
||||||
|
<img v-if="randCodeData.requestCodeSuccess" :src="randCodeData.randCodeImage" @click="handleChangeCheckCode" />
|
||||||
|
<img v-else style="margin-top: 2px; max-width: initial" :src="codeImg" @click="handleChangeCheckCode" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex">
|
||||||
|
<div class="aui-flex-box">
|
||||||
|
<div class="aui-choice">
|
||||||
|
<a-input class="fix-auto-fill" type="checkbox" v-model:value="rememberMe" />
|
||||||
|
<span style="margin-left: 5px">{{ t('sys.login.rememberMe') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-forget">
|
||||||
|
<a @click="forgetHandelClick"> {{ t('sys.login.forgetPassword') }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-form>
|
||||||
|
<a-form v-else ref="phoneFormRef" :model="phoneFormData" @keyup.enter.native="loginHandleClick">
|
||||||
|
<div class="aui-account phone">
|
||||||
|
<div class="aui-inputClear phoneClear">
|
||||||
|
<a-input class="fix-auto-fill" :placeholder="t('sys.login.mobile')" v-model:value="phoneFormData.mobile" />
|
||||||
|
</div>
|
||||||
|
<div class="aui-inputClear">
|
||||||
|
<a-input class="fix-auto-fill" :maxlength="6" :placeholder="t('sys.login.smsCode')" v-model:value="phoneFormData.smscode" />
|
||||||
|
<div v-if="showInterval" class="aui-code" @click="getLoginCode">
|
||||||
|
<a>{{ t('component.countdown.normalText') }}</a>
|
||||||
|
</div>
|
||||||
|
<div v-else class="aui-code">
|
||||||
|
<span class="aui-get-code code-shape">{{ t('component.countdown.sendText', [unref(timeRuning)]) }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
<div class="aui-formButton">
|
||||||
|
<div class="aui-flex">
|
||||||
|
<a-button :loading="loginLoading" class="aui-link-login aui-flex-box" type="primary" @click="loginHandleClick">
|
||||||
|
{{ t('sys.login.loginButton') }}</a-button>
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex">
|
||||||
|
<a class="aui-linek-code aui-flex-box" @click="codeHandleClick">{{ t('sys.login.qrSignInFormTitle') }}</a>
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex">
|
||||||
|
<a class="aui-linek-code aui-flex-box" @click="registerHandleClick">{{ t('sys.login.registerButton') }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<a-form @keyup.enter.native="loginHandleClick">
|
||||||
|
<div class="aui-flex aui-third-text">
|
||||||
|
<div class="aui-flex-box aui-third-border">
|
||||||
|
<span>{{ t('sys.login.otherSignIn') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex" :class="`${prefixCls}-sign-in-way`">
|
||||||
|
<div class="aui-flex-box">
|
||||||
|
<div class="aui-third-login">
|
||||||
|
<a title="github" @click="onThirdLogin('github')"><GithubFilled /></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex-box">
|
||||||
|
<div class="aui-third-login">
|
||||||
|
<a title="企业微信" @click="onThirdLogin('wechat_enterprise')"><icon-font class="item-icon" type="icon-qiyeweixin3" /></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex-box">
|
||||||
|
<div class="aui-third-login">
|
||||||
|
<a title="钉钉" @click="onThirdLogin('dingtalk')"><DingtalkCircleFilled /></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex-box">
|
||||||
|
<div class="aui-third-login">
|
||||||
|
<a title="微信" @click="onThirdLogin('wechat_open')"><WechatFilled /></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-show="type === 'forgot'" :class="`${prefixCls}-form`">
|
||||||
|
<MiniForgotpad ref="forgotRef" @go-back="goBack" @success="handleSuccess" />
|
||||||
|
</div>
|
||||||
|
<div v-show="type === 'register'" :class="`${prefixCls}-form`">
|
||||||
|
<MiniRegister ref="registerRef" @go-back="goBack" @success="handleSuccess" />
|
||||||
|
</div>
|
||||||
|
<div v-show="type === 'codeLogin'" :class="`${prefixCls}-form`">
|
||||||
|
<MiniCodelogin ref="codeRef" @go-back="goBack" @success="handleSuccess" />
|
||||||
|
</div>
|
||||||
|
<!-- 第三方登录相关弹框 -->
|
||||||
|
<ThirdModal ref="thirdModalRef"></ThirdModal>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup name="login-mini">
|
||||||
|
import { getCaptcha, getCodeInfo } from '/@/api/sys/user';
|
||||||
|
import { computed, onMounted, reactive, ref, toRaw, unref } from 'vue';
|
||||||
|
import codeImg from '/@/assets/images/checkcode.png';
|
||||||
|
import { Rule } from '/@/components/Form';
|
||||||
|
import { useUserStore } from '/@/store/modules/user';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
import { useI18n } from '/@/hooks/web/useI18n';
|
||||||
|
import { SmsEnum } from '/@/views/sys/login/useLogin';
|
||||||
|
import ThirdModal from '/@/views/sys/login/ThirdModal.vue';
|
||||||
|
import MiniForgotpad from './MiniForgotpad.vue';
|
||||||
|
import MiniRegister from './MiniRegister.vue';
|
||||||
|
import MiniCodelogin from './MiniCodelogin.vue';
|
||||||
|
import logoImg from '/@/assets/loginmini/icon/jeecg_logo.png';
|
||||||
|
import adTextImg from '/@/assets/loginmini/icon/jeecg_ad_text.png';
|
||||||
|
import { AppLocalePicker, AppDarkModeToggle } from '/@/components/Application';
|
||||||
|
import { useLocaleStore } from '/@/store/modules/locale';
|
||||||
|
import { useDesign } from "/@/hooks/web/useDesign";
|
||||||
|
import { useAppInject } from "/@/hooks/web/useAppInject";
|
||||||
|
import { GithubFilled, WechatFilled, DingtalkCircleFilled, createFromIconfontCN } from '@ant-design/icons-vue';
|
||||||
|
|
||||||
|
const IconFont = createFromIconfontCN({
|
||||||
|
scriptUrl: '//at.alicdn.com/t/font_2316098_umqusozousr.js',
|
||||||
|
});
|
||||||
|
const { prefixCls } = useDesign('mini-login');
|
||||||
|
const { notification, createMessage } = useMessage();
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const { t } = useI18n();
|
||||||
|
const localeStore = useLocaleStore();
|
||||||
|
const showLocale = localeStore.getShowPicker;
|
||||||
|
const randCodeData = reactive<any>({
|
||||||
|
randCodeImage: '',
|
||||||
|
requestCodeSuccess: false,
|
||||||
|
checkKey: null,
|
||||||
|
});
|
||||||
|
const rememberMe = ref<string>('0');
|
||||||
|
//手机号登录还是账号登录
|
||||||
|
const activeIndex = ref<string>('accountLogin');
|
||||||
|
const type = ref<string>('login');
|
||||||
|
//账号登录表单字段
|
||||||
|
const formData = reactive<any>({
|
||||||
|
inputCode: '',
|
||||||
|
username: 'admin',
|
||||||
|
password: '123456',
|
||||||
|
});
|
||||||
|
//手机登录表单字段
|
||||||
|
const phoneFormData = reactive<any>({
|
||||||
|
mobile: '',
|
||||||
|
smscode: '',
|
||||||
|
});
|
||||||
|
const loginRef = ref();
|
||||||
|
//第三方登录弹窗
|
||||||
|
const thirdModalRef = ref();
|
||||||
|
//扫码登录
|
||||||
|
const codeRef = ref();
|
||||||
|
//是否显示获取验证码
|
||||||
|
const showInterval = ref<boolean>(true);
|
||||||
|
//60s
|
||||||
|
const timeRuning = ref<number>(60);
|
||||||
|
//定时器
|
||||||
|
const timer = ref<any>(null);
|
||||||
|
//忘记密码
|
||||||
|
const forgotRef = ref();
|
||||||
|
//注册
|
||||||
|
const registerRef = ref();
|
||||||
|
const loginLoading = ref<boolean>(false);
|
||||||
|
const { getIsMobile } = useAppInject();
|
||||||
|
|
||||||
|
defineProps({
|
||||||
|
sessionTimeout: {
|
||||||
|
type: Boolean,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取验证码
|
||||||
|
*/
|
||||||
|
function handleChangeCheckCode() {
|
||||||
|
formData.inputCode = '';
|
||||||
|
|
||||||
|
randCodeData.checkKey = 1629428467008;
|
||||||
|
getCodeInfo(randCodeData.checkKey).then((res) => {
|
||||||
|
randCodeData.randCodeImage = res;
|
||||||
|
randCodeData.requestCodeSuccess = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 切换登录方式
|
||||||
|
*/
|
||||||
|
function loginClick(type) {
|
||||||
|
activeIndex.value = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 账号或者手机登录
|
||||||
|
*/
|
||||||
|
async function loginHandleClick() {
|
||||||
|
if (unref(activeIndex) === 'accountLogin') {
|
||||||
|
accountLogin();
|
||||||
|
} else {
|
||||||
|
//手机号登录
|
||||||
|
phoneLogin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function accountLogin() {
|
||||||
|
if (!formData.username) {
|
||||||
|
createMessage.warn(t('sys.login.accountPlaceholder'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!formData.password) {
|
||||||
|
createMessage.warn(t('sys.login.passwordPlaceholder'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
loginLoading.value = true;
|
||||||
|
const { userInfo } = await userStore.login(
|
||||||
|
toRaw({
|
||||||
|
password: formData.password,
|
||||||
|
username: formData.username,
|
||||||
|
captcha: formData.inputCode,
|
||||||
|
checkKey: randCodeData.checkKey,
|
||||||
|
mode: 'none', //不要默认的错误提示
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if (userInfo) {
|
||||||
|
notification.success({
|
||||||
|
message: t('sys.login.loginSuccessTitle'),
|
||||||
|
description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realname}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notification.error({
|
||||||
|
message: t('sys.api.errorTip'),
|
||||||
|
description: error.message || t('sys.login.networkExceptionMsg'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
handleChangeCheckCode();
|
||||||
|
} finally {
|
||||||
|
loginLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机号登录
|
||||||
|
*/
|
||||||
|
async function phoneLogin() {
|
||||||
|
if (!phoneFormData.mobile) {
|
||||||
|
createMessage.warn(t('sys.login.mobilePlaceholder'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!phoneFormData.smscode) {
|
||||||
|
createMessage.warn(t('sys.login.smsPlaceholder'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
loginLoading.value = true;
|
||||||
|
const { userInfo }: any = await userStore.phoneLogin({
|
||||||
|
mobile: phoneFormData.mobile,
|
||||||
|
captcha: phoneFormData.smscode,
|
||||||
|
mode: 'none', //不要默认的错误提示
|
||||||
|
});
|
||||||
|
if (userInfo) {
|
||||||
|
notification.success({
|
||||||
|
message: t('sys.login.loginSuccessTitle'),
|
||||||
|
description: `${t('sys.login.loginSuccessDesc')}: ${userInfo.realname}`,
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notification.error({
|
||||||
|
message: t('sys.api.errorTip'),
|
||||||
|
description: error.message || t('sys.login.networkExceptionMsg'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
loginLoading.value = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取手机验证码
|
||||||
|
*/
|
||||||
|
async function getLoginCode() {
|
||||||
|
if (!phoneFormData.mobile) {
|
||||||
|
createMessage.warn(t('sys.login.mobilePlaceholder'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const result = await getCaptcha({ mobile: phoneFormData.mobile, smsmode: SmsEnum.FORGET_PASSWORD });
|
||||||
|
if (result) {
|
||||||
|
const TIME_COUNT = 60;
|
||||||
|
if (!unref(timer)) {
|
||||||
|
timeRuning.value = TIME_COUNT;
|
||||||
|
showInterval.value = false;
|
||||||
|
timer.value = setInterval(() => {
|
||||||
|
if (unref(timeRuning) > 0 && unref(timeRuning) <= TIME_COUNT) {
|
||||||
|
timeRuning.value = timeRuning.value - 1;
|
||||||
|
} else {
|
||||||
|
showInterval.value = true;
|
||||||
|
clearInterval(unref(timer));
|
||||||
|
timer.value = null;
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 第三方登录
|
||||||
|
* @param type
|
||||||
|
*/
|
||||||
|
function onThirdLogin(type) {
|
||||||
|
thirdModalRef.value.onThirdLogin(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 忘记密码
|
||||||
|
*/
|
||||||
|
function forgetHandelClick() {
|
||||||
|
type.value = 'forgot';
|
||||||
|
setTimeout(() => {
|
||||||
|
forgotRef.value.initForm();
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回登录页面
|
||||||
|
*/
|
||||||
|
function goBack() {
|
||||||
|
activeIndex.value = 'accountLogin';
|
||||||
|
type.value = 'login';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 忘记密码/注册账号回调事件
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
function handleSuccess(value) {
|
||||||
|
Object.assign(formData, value);
|
||||||
|
Object.assign(phoneFormData, { mobile: "", smscode: "" });
|
||||||
|
type.value = 'login';
|
||||||
|
activeIndex.value = 'accountLogin';
|
||||||
|
handleChangeCheckCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册
|
||||||
|
*/
|
||||||
|
function registerHandleClick() {
|
||||||
|
type.value = 'register';
|
||||||
|
setTimeout(() => {
|
||||||
|
registerRef.value.initForm();
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册
|
||||||
|
*/
|
||||||
|
function codeHandleClick() {
|
||||||
|
type.value = 'codeLogin';
|
||||||
|
setTimeout(() => {
|
||||||
|
codeRef.value.initFrom();
|
||||||
|
}, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
//加载验证码
|
||||||
|
handleChangeCheckCode();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import '/@/assets/loginmini/style/home.less';
|
||||||
|
@import '/@/assets/loginmini/style/base.less';
|
||||||
|
|
||||||
|
:deep(.ant-input:focus) {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
.aui-get-code {
|
||||||
|
float: right;
|
||||||
|
position: relative;
|
||||||
|
z-index: 3;
|
||||||
|
background: #ffffff;
|
||||||
|
color: #1573e9;
|
||||||
|
border-radius: 100px;
|
||||||
|
padding: 5px 16px;
|
||||||
|
margin: 7px;
|
||||||
|
border: 1px solid #1573e9;
|
||||||
|
top: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-get-code:hover {
|
||||||
|
color: #1573e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-shape {
|
||||||
|
border-color: #dadada !important;
|
||||||
|
color: #aaa !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.jeecg-dark-switch){
|
||||||
|
position:absolute;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.aui-link-login{
|
||||||
|
height: 42px;
|
||||||
|
padding: 10px 15px;
|
||||||
|
font-size: 14px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-top: 15px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
.aui-phone-logo{
|
||||||
|
position: absolute;
|
||||||
|
margin-left: 10px;
|
||||||
|
width: 60px;
|
||||||
|
top:2px;
|
||||||
|
z-index: 4;
|
||||||
|
}
|
||||||
|
.top-3{
|
||||||
|
top: 0.45rem;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
@prefix-cls: ~'@{namespace}-mini-login';
|
||||||
|
@dark-bg: #293146;
|
||||||
|
|
||||||
|
html[data-theme='dark'] {
|
||||||
|
.@{prefix-cls} {
|
||||||
|
background-color: @dark-bg !important;
|
||||||
|
background-image: none;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
background-image: url(/@/assets/svg/login-bg-dark.svg);
|
||||||
|
}
|
||||||
|
.aui-inputClear{
|
||||||
|
background-color: #232a3b !important;
|
||||||
|
}
|
||||||
|
.ant-input,
|
||||||
|
.ant-input-password {
|
||||||
|
background-color: #232a3b !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-btn:not(.ant-btn-link):not(.ant-btn-primary) {
|
||||||
|
border: 1px solid #4a5569 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-form {
|
||||||
|
background: @dark-bg !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-iconify {
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
.aui-inputClear input,.aui-input-line input,.aui-choice{
|
||||||
|
color: #c9d1d9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-formBox{
|
||||||
|
background-color: @dark-bg !important;
|
||||||
|
}
|
||||||
|
.aui-third-text span{
|
||||||
|
background-color: @dark-bg !important;
|
||||||
|
}
|
||||||
|
.aui-form-nav .aui-flex-box{
|
||||||
|
color: #c9d1d9 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.aui-formButton .aui-linek-code{
|
||||||
|
background: @dark-bg !important;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
.aui-code-line{
|
||||||
|
border-left: none !important;
|
||||||
|
}
|
||||||
|
.ant-checkbox-inner,.aui-success h3{
|
||||||
|
border-color: #c9d1d9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input.fix-auto-fill,
|
||||||
|
.fix-auto-fill input {
|
||||||
|
-webkit-text-fill-color: #c9d1d9 !important;
|
||||||
|
box-shadow: inherit !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-sign-in-way {
|
||||||
|
.anticon {
|
||||||
|
font-size: 22px !important;
|
||||||
|
color: #888 !important;
|
||||||
|
cursor: pointer !important;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: @primary-color !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-divider-inner-text {
|
||||||
|
font-size: 12px !important;
|
||||||
|
color: @text-color-secondary !important;
|
||||||
|
}
|
||||||
|
.aui-third-login a{
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,266 @@
|
||||||
|
<template>
|
||||||
|
<div class="aui-content">
|
||||||
|
<div class="aui-container">
|
||||||
|
<div class="aui-form">
|
||||||
|
<div class="aui-image">
|
||||||
|
<div class="aui-image-text">
|
||||||
|
<img :src="jeecgAdTextImg" alt="" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-formBox">
|
||||||
|
<div class="aui-formWell">
|
||||||
|
<a-form ref="formRef" :model="formData">
|
||||||
|
<div class="aui-flex aui-form-nav aui-clear-left" style="padding-bottom: 21px">
|
||||||
|
<div class="aui-flex-box activeNav on">{{t('sys.login.signUpFormTitle')}}</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-form-box">
|
||||||
|
<div class="aui-account aui-account-line">
|
||||||
|
<a-form-item>
|
||||||
|
<div class="aui-input-line">
|
||||||
|
<Icon class="aui-icon" icon="ant-design:user-outlined"/>
|
||||||
|
<a-input class="fix-auto-fill" type="text" :placeholder="t('sys.login.userName')" v-model:value="formData.username" />
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<div class="aui-input-line">
|
||||||
|
<Icon class="aui-icon" icon="ant-design:mobile-outlined"/>
|
||||||
|
<a-input class="fix-auto-fill" type="text" :placeholder="t('sys.login.mobile')" v-model:value="formData.mobile" />
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<div class="aui-input-line">
|
||||||
|
<Icon class="aui-icon" icon="ant-design:mail-outlined"/>
|
||||||
|
<a-input class="fix-auto-fill" type="text" :placeholder="t('sys.login.smsCode')" v-model:value="formData.smscode" />
|
||||||
|
<div v-if="showInterval" class="aui-code-line" @click="getLoginCode">{{t('component.countdown.normalText')}}</div>
|
||||||
|
<div v-else class="aui-code-line">{{t('component.countdown.sendText',[unref(timeRuning)])}}</div>
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<div class="aui-input-line">
|
||||||
|
<Icon class="aui-icon" icon="ant-design:lock-outlined"/>
|
||||||
|
<a-input class="fix-auto-fill" :type="pwdIndex==='close'?'password':'text'" :placeholder="t('sys.login.password')" v-model:value="formData.password" />
|
||||||
|
<div class="aui-eye">
|
||||||
|
<img :src="eyeKImg" alt="开启" v-if="pwdIndex==='open'" @click="pwdClick('close')" />
|
||||||
|
<img :src="eyeGImg" alt="关闭" v-else-if="pwdIndex==='close'" @click="pwdClick('open')" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item>
|
||||||
|
<div class="aui-input-line">
|
||||||
|
<Icon class="aui-icon" icon="ant-design:lock-outlined"/>
|
||||||
|
<a-input class="fix-auto-fill" :type="confirmPwdIndex==='close'?'password':'text'" :placeholder="t('sys.login.confirmPassword')" v-model:value="formData.confirmPassword" />
|
||||||
|
<div class="aui-eye">
|
||||||
|
<img :src="eyeKImg" alt="开启" v-if="confirmPwdIndex==='open'" @click="confirmPwdClick('close')" />
|
||||||
|
<img :src="eyeGImg" alt="关闭" v-else-if="confirmPwdIndex==='close'" @click="confirmPwdClick('open')" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item name="policy">
|
||||||
|
<div class="aui-flex">
|
||||||
|
<div class="aui-flex-box">
|
||||||
|
<div class="aui-choice">
|
||||||
|
<a-checkbox v-model:checked="formData.policy" />
|
||||||
|
<span style="color: #1b90ff;margin-left: 4px">{{ t('sys.login.policy') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="aui-formButton">
|
||||||
|
<div class="aui-flex">
|
||||||
|
<a class="aui-link-login aui-flex-box" @click="registerHandleClick"> {{ t('sys.login.registerButton') }}</a>
|
||||||
|
</div>
|
||||||
|
<div class="aui-flex">
|
||||||
|
<a class="aui-linek-code aui-flex-box" @click="goBackHandleClick">{{ t('sys.login.backSignIn') }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup name="mini-register">
|
||||||
|
import { ref, reactive, unref, toRaw } from 'vue';
|
||||||
|
import { getCaptcha, register } from '/@/api/sys/user';
|
||||||
|
import { SmsEnum } from '/@/views/sys/login/useLogin';
|
||||||
|
import { useMessage } from '/@/hooks/web/useMessage';
|
||||||
|
import logoImg from '/@/assets/loginmini/icon/jeecg_logo.png';
|
||||||
|
import jeecgAdTextImg from '/@/assets/loginmini/icon/jeecg_ad_text.png';
|
||||||
|
import eyeKImg from '/@/assets/loginmini/icon/icon-eye-k.png';
|
||||||
|
import eyeGImg from '/@/assets/loginmini/icon/icon-eye-g.png';
|
||||||
|
import { useI18n } from "/@/hooks/web/useI18n";
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
const { notification, createErrorModal, createMessage } = useMessage();
|
||||||
|
const emit = defineEmits(['go-back', 'success', 'register']);
|
||||||
|
const formRef = ref();
|
||||||
|
const formData = reactive<any>({
|
||||||
|
username: '',
|
||||||
|
mobile: '',
|
||||||
|
smscode: '',
|
||||||
|
password: '',
|
||||||
|
confirmPassword: '',
|
||||||
|
policy: false,
|
||||||
|
});
|
||||||
|
//是否显示获取验证码
|
||||||
|
const showInterval = ref<boolean>(true);
|
||||||
|
//60s
|
||||||
|
const timeRuning = ref<number>(60);
|
||||||
|
//定时器
|
||||||
|
const timer = ref<any>(null);
|
||||||
|
//密码眼睛打开关闭
|
||||||
|
const pwdIndex = ref<string>('close');
|
||||||
|
//确认密码眼睛打开关闭
|
||||||
|
const confirmPwdIndex = ref<string>('close');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回
|
||||||
|
*/
|
||||||
|
function goBackHandleClick() {
|
||||||
|
emit('go-back');
|
||||||
|
initForm();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取手机验证码
|
||||||
|
*/
|
||||||
|
async function getLoginCode() {
|
||||||
|
if (!formData.mobile) {
|
||||||
|
createMessage.warn(t('sys.login.mobilePlaceholder'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const result = await getCaptcha({ mobile: formData.mobile, smsmode: SmsEnum.REGISTER });
|
||||||
|
if (result) {
|
||||||
|
const TIME_COUNT = 60;
|
||||||
|
if (!unref(timer)) {
|
||||||
|
timeRuning.value = TIME_COUNT;
|
||||||
|
showInterval.value = false;
|
||||||
|
timer.value = setInterval(() => {
|
||||||
|
if (unref(timeRuning) > 0 && unref(timeRuning) <= TIME_COUNT) {
|
||||||
|
timeRuning.value = timeRuning.value - 1;
|
||||||
|
} else {
|
||||||
|
showInterval.value = true;
|
||||||
|
clearInterval(unref(timer));
|
||||||
|
timer.value = null;
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerHandleClick() {
|
||||||
|
if (!formData.username) {
|
||||||
|
createMessage.warn(t('sys.login.accountPlaceholder'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!formData.mobile) {
|
||||||
|
createMessage.warn(t('sys.login.mobilePlaceholder'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!formData.smscode) {
|
||||||
|
createMessage.warn(t('sys.login.smsPlaceholder'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!formData.password) {
|
||||||
|
createMessage.warn(t('sys.login.passwordPlaceholder'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!formData.confirmPassword) {
|
||||||
|
createMessage.warn(t('sys.login.confirmPassword'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (formData.password !== formData.confirmPassword) {
|
||||||
|
createMessage.warn(t('sys.login.diffPwd'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!formData.policy){
|
||||||
|
createMessage.warn(t('sys.login.policyPlaceholder'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
registerAccount();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 注册账号
|
||||||
|
*/
|
||||||
|
async function registerAccount() {
|
||||||
|
try {
|
||||||
|
const resultInfo = await register(
|
||||||
|
toRaw({
|
||||||
|
username: formData.username,
|
||||||
|
password: formData.password,
|
||||||
|
phone: formData.mobile,
|
||||||
|
smscode: formData.smscode,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if (resultInfo && resultInfo.data.success) {
|
||||||
|
notification.success({
|
||||||
|
description: resultInfo.data.message || t('sys.api.registerMsg'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
emit('success', { username: formData.username, password: formData.password });
|
||||||
|
initForm();
|
||||||
|
} else {
|
||||||
|
notification.warning({
|
||||||
|
message: t('sys.api.errorTip'),
|
||||||
|
description: resultInfo.data.message || t('sys.api.networkExceptionMsg'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notification.error({
|
||||||
|
message: t('sys.api.errorTip'),
|
||||||
|
description: error.message || t('sys.api.networkExceptionMsg'),
|
||||||
|
duration: 3,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化表单
|
||||||
|
*/
|
||||||
|
function initForm() {
|
||||||
|
Object.assign(formData,{username:'',mobile: '', smscode: '', password: '', confirmPassword: '', policy: false})
|
||||||
|
if(!unref(timer)){
|
||||||
|
showInterval.value = true;
|
||||||
|
clearInterval(unref(timer));
|
||||||
|
timer.value = null;
|
||||||
|
}
|
||||||
|
formRef.value.resetFields();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码打开或关闭
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
function pwdClick(value) {
|
||||||
|
pwdIndex.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认密码打开或关闭
|
||||||
|
* @param value
|
||||||
|
*/
|
||||||
|
function confirmPwdClick(value) {
|
||||||
|
confirmPwdIndex.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
initForm
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="less" scoped>
|
||||||
|
@import '/@/assets/loginmini/style/home.less';
|
||||||
|
@import '/@/assets/loginmini/style/base.less';
|
||||||
|
.aui-input-line .aui-icon{
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
top: 10px;
|
||||||
|
left: 10px;
|
||||||
|
font-size: 20px !important;
|
||||||
|
}
|
||||||
|
</style>
|