Merge branch 'dev' into pr@dev_memory_component

This commit is contained in:
dataeaseShu 2023-02-20 16:18:15 +08:00
commit 038a33efcf
28 changed files with 749 additions and 598 deletions

View File

@ -84,7 +84,7 @@ public class F2CRealm extends AuthorizingRealm {
token = (String) auth.getCredentials();
// 解密获得username用于和数据库进行对比
tokenInfo = JWTUtils.tokenInfoByToken(token);
if (!TokenCacheUtils.validate(token)) {
if (TokenCacheUtils.invalid(token)) {
throw new AuthenticationException("token invalid");
}
} catch (Exception e) {

View File

@ -66,7 +66,7 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
if (StringUtils.startsWith(authorization, "Basic")) {
return false;
}
if (!TokenCacheUtils.validate(authorization) && !TokenCacheUtils.validateDelay(authorization)) {
if (TokenCacheUtils.invalid(authorization)) {
throw new AuthenticationException(expireMessage);
}
// 当没有出现登录超时 且需要刷新token 则执行刷新token
@ -75,8 +75,6 @@ public class JWTFilter extends BasicHttpAuthenticationFilter {
throw new AuthenticationException(expireMessage);
}
if (JWTUtils.needRefresh(authorization)) {
TokenCacheUtils.addWithTtl(authorization, 1L);
TokenCacheUtils.remove(authorization);
authorization = refreshToken(request, response);
}
JWTToken token = new JWTToken(authorization);

View File

@ -148,7 +148,7 @@ public class AuthServer implements AuthApi {
AccountLockStatus lockStatus = authUserService.recordLoginFail(username, 0);
DataEaseException.throwException(appendLoginErrorMsg(Translator.get("i18n_id_or_pwd_error"), lockStatus));
}
if(user.getIsAdmin() && user.getPassword().equals("40b8893ea9ebc2d631c4bb42bb1e8996")){
if (user.getIsAdmin() && user.getPassword().equals("40b8893ea9ebc2d631c4bb42bb1e8996")) {
result.put("passwordModified", false);
}
}
@ -237,7 +237,7 @@ public class AuthServer implements AuthApi {
if (StringUtils.isBlank(result)) {
result = "success";
}
TokenCacheUtils.remove(token);
TokenCacheUtils.add(token, userId);
} catch (Exception e) {
LogUtil.error(e);
if (StringUtils.isBlank(result)) {
@ -291,7 +291,7 @@ public class AuthServer implements AuthApi {
if (StringUtils.isBlank(result)) {
result = "success";
}
TokenCacheUtils.remove(token);
TokenCacheUtils.add(token, userId);
} catch (Exception e) {
LogUtil.error(e);
if (StringUtils.isBlank(result)) {

View File

@ -10,7 +10,6 @@ import com.auth0.jwt.interfaces.Verification;
import io.dataease.auth.entity.TokenInfo;
import io.dataease.auth.entity.TokenInfo.TokenInfoBuilder;
import io.dataease.commons.utils.CommonBeanFactory;
import io.dataease.commons.utils.TokenCacheUtils;
import io.dataease.exception.DataEaseException;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
@ -68,7 +67,8 @@ public class JWTUtils {
public static boolean needRefresh(String token) {
Date exp = JWTUtils.getExp(token);
return new Date().getTime() >= exp.getTime();
Long advanceTime = 5000L;
return (new Date().getTime() + advanceTime) >= exp.getTime();
}
/**
@ -119,7 +119,6 @@ public class JWTUtils {
.withClaim("username", tokenInfo.getUsername())
.withClaim("userId", tokenInfo.getUserId());
String sign = builder.withExpiresAt(date).sign(algorithm);
TokenCacheUtils.add(sign, tokenInfo.getUserId());
return sign;
} catch (Exception e) {

View File

@ -359,8 +359,8 @@ public class ExcelXlsxReader extends DefaultHandler {
formatIndex = style.getDataFormat();
formatString = style.getDataFormatString();
short format = this.formatIndex;
if ((14 <= format && format <= 17) || format == 0 || format == 20 || format == 22 || format == 31 || format == 35 || (45 <= format && format <= 49) || format == 46 || format == 47 || (57 <= format && format <= 59)
|| (59 < format && format <= 76) || (175 < format && format <= 196) || (210 <= format && format <= 213) || (208 == format)) { // 日期
if ((14 <= format && format <= 17) || format == 20 || format == 22 || format == 31 || format == 35 || format == 45 || format == 46 || format == 47 || (57 <= format && format <= 59)
|| (175 < format && format < 178) || (182 <= format && format <= 196) || (210 <= format && format <= 213) || (208 == format)) { // 日期
isDateFormat = true;
}

View File

@ -3,36 +3,76 @@ package io.dataease.commons.utils;
import io.dataease.listener.util.CacheUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
@Component
public class TokenCacheUtils {
private static final String KEY = "sys_token_store";
private static final String DELAY_KEY = "sys_token_store_delay";
private static String cacheType;
private static Long expTime;
@Value("${spring.cache.type:ehcache}")
public void setCacheType(String cacheType) {
TokenCacheUtils.cacheType = cacheType;
}
@Value("${dataease.login_timeout:480}")
public void setExpTime(Long expTime) {
TokenCacheUtils.expTime = expTime;
}
private static boolean useRedis() {
return StringUtils.equals(cacheType, "redis");
}
private static ValueOperations cacheHandler() {
RedisTemplate redisTemplate = (RedisTemplate) CommonBeanFactory.getBean("redisTemplate");
ValueOperations valueOperations = redisTemplate.opsForValue();
return valueOperations;
}
public static void add(String token, Long userId) {
CacheUtils.put(KEY, token, userId, null, null);
if (useRedis()) {
ValueOperations valueOperations = cacheHandler();
valueOperations.set(KEY + token, userId, expTime, TimeUnit.MINUTES);
return;
}
Long time = expTime * 60;
CacheUtils.put(KEY, token, userId, time.intValue(), null);
}
public static void remove(String token) {
if (useRedis()) {
RedisTemplate redisTemplate = (RedisTemplate) CommonBeanFactory.getBean("redisTemplate");
String key = KEY + token;
if (redisTemplate.hasKey(key)) {
redisTemplate.delete(key);
}
return;
}
CacheUtils.remove(KEY, token);
}
public static boolean validate(String token) {
public static boolean invalid(String token) {
if (useRedis()) {
RedisTemplate redisTemplate = (RedisTemplate) CommonBeanFactory.getBean("redisTemplate");
return redisTemplate.hasKey(KEY + token);
}
Object sys_token_store = CacheUtils.get(KEY, token);
return ObjectUtils.isNotEmpty(sys_token_store) && StringUtils.isNotBlank(sys_token_store.toString());
}
public static boolean validate(String token, Long userId) {
Object sys_token_store = CacheUtils.get(KEY, token);
return ObjectUtils.isNotEmpty(sys_token_store) && StringUtils.isNotBlank(sys_token_store.toString()) && userId == Long.parseLong(sys_token_store.toString());
}
public static void addWithTtl(String token, Long userId) {
CacheUtils.put(DELAY_KEY, token, userId, 3, 5);
}
public static boolean validateDelay(String token) {
Object tokenObj = CacheUtils.get(DELAY_KEY, token);
return ObjectUtils.isNotEmpty(tokenObj) && StringUtils.isNotBlank(tokenObj.toString());
}
}

View File

@ -1,6 +1,7 @@
package io.dataease.controller.panel;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.dataease.controller.handler.annotation.I18n;
import io.dataease.plugins.common.base.domain.PanelPdfTemplate;
import io.dataease.service.panel.PanelPdfTemplateService;
import io.swagger.annotations.Api;
@ -26,6 +27,7 @@ public class PanelPdfTemplateController {
private PanelPdfTemplateService panelPdfTemplateService;
@GetMapping("queryAll")
@I18n
@ApiOperation("查询所有仪表板模板")
public List<PanelPdfTemplate> queryAll() {
return panelPdfTemplateService.queryAll();

View File

@ -808,7 +808,7 @@ public class MysqlQueryProvider extends QueryProvider {
}
return stringBuilder.toString();
}).toArray(String[]::new);
return MessageFormat.format("SELECT {0} FROM {1} LIMIT DE_OFFSET, DE_PAGE_SIZE ", StringUtils.join(array, ","), table);
return MessageFormat.format("SELECT {0} FROM {1} LIMIT DE_OFFSET, DE_PAGE_SIZE ", StringUtils.join(array, ","), String.format(MySQLConstants.KEYWORD_TABLE, table));
}
public String getTotalCount(boolean isTable, String sql, Datasource ds) {

View File

@ -880,6 +880,7 @@ public class OracleQueryProvider extends QueryProvider {
ChartViewFieldDTO f = new ChartViewFieldDTO();
f.setOriginName(datasetTableField.getOriginName());
f.setDeType(0);
f.setType(datasetTableField.getType());
xAxis.add(f);
});
@ -916,6 +917,9 @@ public class OracleQueryProvider extends QueryProvider {
continue;
}
String originField = String.format(OracleConstants.KEYWORD_FIX, tableObj.getTableAlias(), x.getOriginName());
if(xAxis.get(i).getType().equals("DATE")){
originField = String.format(OracleConstants.TO_CHAR, originField, OracleConstants.DEFAULT_DATE_FORMAT);
}
String fieldAlias = String.format(OracleConstants.KEYWORD_TABLE, x.getOriginName());
xFields.add(getXFields(x, originField, fieldAlias));
}

View File

@ -2,3 +2,5 @@ UPDATE `my_plugin`
SET `version` = '1.18.3'
where `plugin_id` > 0
and `version` = '1.18.2';
UPDATE `panel_pdf_template` SET `name` = 'I18N_PANEL_PDF_TEMPLATE_WITH_PARAMS',`template_content` = '<div style=\"margin-top: 5px\">\n <div contenteditable=\"true\"> \n $t(''panel.panel_name'')$panelName$ </br>\n $t(''panel.export_time'')$yyyy-MM-dd hh:mm:ss$ </br>\n $t(''panel.export_user'')$nickName$ </br>\n $t(''panel.you_can_type_here'')\n </div>\n <div>\n <img width=\"100%\" src=\"$snapshot$\">\n </div>\n </div>' WHERE id='1';
UPDATE `panel_pdf_template` SET `name` = 'I18N_PANEL_PDF_TEMPLATE_ONLY_PIC' WHERE id='2';

View File

@ -273,23 +273,13 @@
<cache
name="sys_token_store"
eternal="true"
maxElementsInMemory="100"
maxElementsOnDisk="3000"
maxElementsInMemory="1"
maxElementsOnDisk="0"
overflowToDisk="true"
diskPersistent="false"
diskPersistent="true"
/>
<cache
name="sys_token_store_delay"
eternal="false"
maxElementsInMemory="100"
maxElementsOnDisk="3000"
overflowToDisk="true"
diskPersistent="false"
timeToIdleSeconds="3"
timeToLiveSeconds="5"
memoryStoreEvictionPolicy="LRU"
/>
</ehcache>

View File

@ -62,7 +62,7 @@ i18n_panel_list=Dashboard
i18n_processing_data=Processing data now, Refresh later
i18n_union_already_exists=Union relation already exists
i18n_union_field_exists=The same field can't in two dataset
i18n_cron_time_error=Start time can't greater then end time
i18n_cron_time_error=Start time can't greater than end time
i18n_auth_source_be_canceled=This Auth Resource Already Be Canceled,Please Connect Admin
i18n_username_exists=ID is already exists
i18n_nickname_exists=NickName is already exists
@ -134,7 +134,7 @@ theme_name_empty=name can not be empty
i18n_public_chart=\u3010Public Chart\u3011
i18n_class_blue=Blue Tone
\u63D2\u4EF6\u7BA1\u7406=Plugins
i18n_plugin_not_allow_delete=The plugin in in use cannot be deleted
i18n_plugin_not_allow_delete=The plugin in use cannot be deleted
i18n_wrong_content=Wrong content
i18n_wrong_tel=Wrong tel format
i18n_wrong_email=Wrong email format
@ -146,7 +146,7 @@ OPERATE_TYPE_DELETE=Delete
OPERATE_TYPE_SHARE=Share
OPERATE_TYPE_UNSHARE=Unshare
OPERATE_TYPE_AUTHORIZE=Authorize
OPERATE_TYPE_UNAUTHORIZE=Unauthorize
OPERATE_TYPE_UNAUTHORIZE=Unauthorized
OPERATE_TYPE_CREATELINK=Create Link
OPERATE_TYPE_DELETELINK=Delete Link
OPERATE_TYPE_MODIFYLINK=Modify Link
@ -261,4 +261,16 @@ I18N_LOG_FORMAT_PREFIX=With authority of %s\u3010%s\u3011
\u6C34\u5370\u7BA1\u7406=Watermark
\u8840\u7F18\u5173\u7CFB=Relationship
I18N_CRON_ERROR=Cron expression error
I18N_CRON_ERROR=Cron expression error
I18N_PANEL_PDF_TEMPLATE_WITH_PARAMS=Default template with params
I18N_PANEL_PDF_TEMPLATE_ONLY_PIC=Default template only screenshot
\u8FB9\u68461=Border 1
\u8FB9\u68462=Border 2
\u8FB9\u68463=Border 3
\u8FB9\u68464=Border 4
\u8FB9\u68465=Border 5
\u8FB9\u68466=Border 6
\u8FB9\u68467=Border 7
\u8FB9\u68468=Border 8
\u8FB9\u68469=Border 9
\u8FB9\u684610=Border 10

View File

@ -262,4 +262,6 @@ I18N_LOG_FORMAT_PREFIX=\u4EE5%s\u3010%s\u3011\u6743\u9650
\u8840\u7F18\u5173\u7CFB=\u8840\u7F18\u5173\u7CFB
I18N_CRON_ERROR=cron\u8868\u8FBE\u5F0F\u9519\u8BEF
I18N_PANEL_PDF_TEMPLATE_WITH_PARAMS=\u9ED8\u8BA4\u6A21\u677F(\u52A0\u53C2\u6570\u6837\u5F0F)
I18N_PANEL_PDF_TEMPLATE_ONLY_PIC=\u9ED8\u8BA4\u6A21\u677F(\u53EA\u622A\u56FE)

View File

@ -257,4 +257,16 @@ I18N_LOG_FORMAT_PREFIX=\u4EE5%s\u3010%s\u3011\u6B0A\u9650
\u6C34\u5370\u7BA1\u7406=\u6C34\u5370\u7BA1\u7406
\u8840\u7F18\u5173\u7CFB=\u8840\u7DE3\u95DC\u7CFB
I18N_CRON_ERROR=cron\u8868\u9054\u5F0F\u932F\u8AA4
I18N_CRON_ERROR=cron\u8868\u9054\u5F0F\u932F\u8AA4
I18N_PANEL_PDF_TEMPLATE_WITH_PARAMS=\u9ED8\u8A8D\u6A21\u677F(\u52A0\u53C3\u6578\u6A23\u5F0F)
I18N_PANEL_PDF_TEMPLATE_ONLY_PIC=\u9ED8\u8A8D\u6A21\u677F(\u53EA\u622A\u5716)
\u8FB9\u68461=\u908A\u6846 1
\u8FB9\u68462=\u908A\u6846 2
\u8FB9\u68463=\u908A\u6846 3
\u8FB9\u68464=\u908A\u6846 4
\u8FB9\u68465=\u908A\u6846 5
\u8FB9\u68466=\u908A\u6846 6
\u8FB9\u68467=\u908A\u6846 7
\u8FB9\u68468=\u908A\u6846 8
\u8FB9\u68469=\u908A\u6846 9
\u8FB9\u684610=\u908A\u6846 10

View File

@ -35,6 +35,7 @@ export const addUser = (data) => {
return request({
url: pathMap.createPath,
method: 'post',
loading: true,
data
})
}

View File

@ -2316,7 +2316,13 @@ export default {
fold: 'Fold',
expand: 'Expand',
pdf_export: 'PDF Export',
switch_pdf_template: 'Switch PDF Template'
switch_pdf_template: 'Switch PDF Template',
pdf_template_with_params: 'Default template(with params)',
pdf_template_only_pic: 'Default template(only screenshot)',
panel_name: 'Panel name',
export_user: 'Export User',
export_time: 'Export Time',
you_can_type_here: 'You can type here'
},
plugin: {
local_install: 'Local installation',

View File

@ -2310,7 +2310,13 @@ export default {
fold: '收起',
expand: '展開',
pdf_export: 'PDF 導出',
switch_pdf_template: '切換 PDF 模板'
switch_pdf_template: '切換 PDF 模板',
pdf_template_with_params: '默認模板(加參數樣式)',
pdf_template_only_pic: '默認模板(只截圖)',
panel_name: '儀錶板名稱',
export_user: '導出用戶',
export_time: '導出時間',
you_can_type_here: '可以在這裡輸入其他內容'
},
plugin: {
local_install: '本地安裝',

View File

@ -2310,7 +2310,13 @@ export default {
fold: '收起',
expand: '展开',
pdf_export: 'PDF 导出',
switch_pdf_template: '切换 PDF 模板'
switch_pdf_template: '切换 PDF 模板',
pdf_template_with_params: '默认模板(加参数样式)',
pdf_template_only_pic: '默认模板(只截图)',
panel_name: '仪表板名称',
export_user: '导出用户',
export_time: '导出时间',
you_can_type_here: '可以在这里输入其他内容'
},
plugin: {
local_install: '本地安装',

View File

@ -18,9 +18,13 @@ import {
changeFavicon
} from '@/utils/index'
import Layout from '@/layout/index'
import { getSysUI } from '@/utils/auth'
import {
getSysUI
} from '@/utils/auth'
import { getSocket } from '@/websocket'
import {
getSocket
} from '@/websocket'
NProgress.configure({
showSpinner: false
@ -53,14 +57,19 @@ const routeBefore = (callBack) => {
callBack()
}
}
router.beforeEach(async (to, from, next) => routeBefore(() => {
router.beforeEach(async(to, from, next) => routeBefore(() => {
// start progress bar
NProgress.start()
const mobileIgnores = ['/delink']
const mobileIgnores = ['/delink', '/de-auto-login']
const mobilePreview = '/preview/'
const hasToken = getToken()
if (isMobile() && !to.path.includes(mobilePreview) && mobileIgnores.indexOf(to.path) === -1) {
window.location.href = window.origin + '/app.html'
let urlSuffix = '/app.html'
if (hasToken) {
urlSuffix += ('?detoken=' + hasToken)
}
window.location.href = window.origin + urlSuffix
NProgress.done()
}
@ -68,7 +77,7 @@ router.beforeEach(async (to, from, next) => routeBefore(() => {
document.title = getPageTitle(to.meta.title)
// determine whether the user has logged in
const hasToken = getToken()
if (hasToken) {
if (to.path === '/login') {
// if is logged in, redirect to the home page

View File

@ -1,3 +1,5 @@
import i18n from '@/lang'
// 替换所有 标准模板格式 为 $panelName$
export function pdfTemplateReplaceAll(content, source, target) {
const pattern = '\\$' + source + '\\$'
@ -37,3 +39,20 @@ export function includesAny(target, ...sources) {
}
return false
}
// 替换字符串中的国际化内容, 格式为$t('xxx')
export function replaceInlineI18n(rawString) {
const res = []
const reg = /\$t\('([\w.]+)'\)/gm
let tmp
if (!rawString) {
return res
}
while ((tmp = reg.exec(rawString)) !== null) {
res.push(tmp)
}
res.forEach((tmp) => {
rawString = rawString.replaceAll(tmp[0], i18n.t(tmp[1]))
})
return rawString
}

View File

@ -179,13 +179,13 @@
:span="5"
style="padding-left: 10px;padding-top: 8px"
>
输入框样式(颜色):
{{ $t('panel.input_style') }}:
</el-col>
<el-col
:span="2"
style="padding-left: 10px;padding-top: 8px"
>
边框
{{ $t('panel.board') }}
</el-col>
<el-col
:span="3"
@ -202,7 +202,7 @@
:span="2"
style="padding-left: 10px;padding-top: 8px"
>
文字
{{ $t('panel.text') }}
</el-col>
<el-col
:span="3"
@ -219,7 +219,7 @@
:span="2"
style="padding-left: 10px;padding-top: 8px"
>
背景
{{ $t('panel.background') }}
</el-col>
<el-col
:span="3"

View File

@ -39,7 +39,7 @@
import JsPDF from 'jspdf'
import html2canvas from 'html2canvasde'
import { formatTimeToStr } from './date.js'
import { pdfTemplateReplaceAll } from '@/utils/StringUtils.js'
import { pdfTemplateReplaceAll, replaceInlineI18n } from '@/utils/StringUtils.js'
export default {
name: 'PDFPreExport',
@ -121,6 +121,7 @@ export default {
for (const [key, value] of Object.entries(this.varsInfo)) {
this.templateContentChange = pdfTemplateReplaceAll(this.templateContentChange, key, value || '')
}
this.templateContentChange = replaceInlineI18n(this.templateContentChange)
},
cancel() {

View File

@ -1,5 +1,6 @@
<template>
<el-dialog
v-loading="loading"
:title="formType == 'add' ? $t('user.create') : $t('user.modify')"
:visible.sync="dialogVisible"
class="user-editer-form"
@ -229,6 +230,7 @@ import { pluginLoaded, defaultPwd, wecomStatus, dingtalkStatus, larkStatus } fro
export default {
data() {
return {
loading: false,
defaultProps: {
children: 'children',
label: 'label',
@ -553,12 +555,13 @@ export default {
save() {
this.$refs.createUserForm.validate((valid) => {
if (valid) {
// !this.form.deptId && (this.form.deptId = 0)
this.loading = true
const method = this.formType === 'add' ? addUser : editUser
method(this.form).then((res) => {
this.$success(this.$t('commons.save_success'))
this.reset()
this.$emit('saved')
this.loading = false
})
} else {
return false

View File

@ -142,4 +142,17 @@ export function parseLanguage() {
const language = getLanguage()
if(language === 'sys') return uni.getLocale()
return language
}
}
export function getUrlParams(url){
const Params = {}
if(url.indexOf('?')>0){//判断是否有qurey
let parmas = url.slice(url.indexOf('?')+1)//截取出query
const paramlists = parmas.split('&')//分割键值对
for (const param of paramlists) {
let a = param.split('=')
Object.assign(Params,{[a[0]]:a[1]})//将键值对封装成对象
}
}
return Params
}

View File

@ -1,5 +1,5 @@
{
"app.name": "Hello uni-app",
"app.name": "DataEase",
"navigate.menuHome": "首页",
"navigate.menuDir": "目录",

View File

@ -1,5 +1,5 @@
{
"app.name": "Hello uni-app",
"app.name": "DataEase",
"navigate.menuHome": "首頁",
"navigate.menuDir": "目錄",
"navigate.menuMe": "我的",

View File

@ -1,192 +1,192 @@
{
"pages": [
"pages": [
{
"path": "pages/login/index",
"style": {
"navigationBarTitleText": "%app.name%",
"app-plus": {
"titleNView": false
}
}
},
{
"path": "pages/tabBar/home/index",
"style": {
"navigationBarTitleText": "%navigate.menuHome%",
"app-plus": {
"titleNView": false
{
"path": "pages/login/index",
"style": {
"navigationBarTitleText": "%navigate.login%",
"app-plus": {
"titleNView": false
}
}
},
{
"path": "pages/tabBar/home/index",
"style": {
"navigationBarTitleText": "%navigate.menuHome%",
"app-plus": {
"titleNView": false
},
"enablePullDownRefresh": true
}
},
{
"path": "pages/tabBar/home/detail",
"style": {
"navigationBarTitleText": "",
"app-plus": {
"titleNView": false,
"bounce": "none"
}
}
},
{
"path": "pages/tabBar/dir/index",
"style": {
"navigationBarTitleText": "%navigate.menuDir%",
"app-plus": {
"titleNView": {
"type": "transparent",
"titleColor": "#fff",
"backgroundColor": "#0faeff",
"buttons": [],
"searchInput": {
"backgroundColor": "#fff",
"borderRadius": "6px",
"placeholder": "%searchPlaceholder%",
"disabled": true
}
}
},
"enablePullDownRefresh": true
}
},
{
"path": "pages/tabBar/dir/search",
"style": {
"navigationBarTitleText": "%navigate.search%",
"app-plus": {
"titleNView": {
"titleColor": "#fff",
"backgroundColor": "#0faeff",
"searchInput": {
"backgroundColor": "#fff",
"borderRadius": "6px",
"placeholder": "%searchPlaceholder%",
"autoFocus": true
}
}
}
"enablePullDownRefresh": true
}
},
{
"path": "pages/tabBar/home/detail",
"style": {
"navigationBarTitleText": "",
"app-plus": {
"titleNView": false,
"bounce": "none"
}
}
},
{
"path": "pages/tabBar/dir/index",
"style": {
"navigationBarTitleText": "%navigate.menuDir%",
"app-plus": {
"titleNView": {
"type": "transparent",
"titleColor": "#fff",
"backgroundColor": "#0faeff",
"buttons": [],
"searchInput": {
"backgroundColor": "#fff",
"borderRadius": "6px",
"placeholder": "%searchPlaceholder%",
"disabled": true
}
}
},
{
"path": "pages/tabBar/dir/folder",
"style": {
"navigationBarTitleText": "",
"app-plus": {
"titleNView": {
"type": "transparent"
}
},
"h5": {
"titleNView": {
"type": "transparent",
"buttons": []
}
}
"enablePullDownRefresh": true
}
},
{
"path": "pages/tabBar/dir/search",
"style": {
"navigationBarTitleText": "%navigate.search%",
"app-plus": {
"titleNView": {
"titleColor": "#fff",
"backgroundColor": "#0faeff",
"searchInput": {
"backgroundColor": "#fff",
"borderRadius": "6px",
"placeholder": "%searchPlaceholder%",
"autoFocus": true
}
}
}
}
},
{
"path": "pages/tabBar/dir/folder",
"style": {
"navigationBarTitleText": "",
"app-plus": {
"titleNView": {
"type": "transparent"
}
},
{
"path": "pages/tabBar/me/index",
"style": {
"navigationBarTitleText": "%navigate.menuMe%",
"app-plus": {
"titleNView": false
}
}
},
{
"path": "pages/tabBar/me/person",
"style": {
"navigationBarTitleText": "%navigate.personInfo%",
"app-plus": {
"titleNView": {
"type": "transparent"
}
}
}
},
{
"path": "pages/tabBar/me/language",
"style": {
"navigationBarTitleText": "%navigate.language%",
"app-plus": {
"titleNView": {
"type": "transparent"
}
}
}
},
{
"path": "pages/tabBar/me/about",
"style": {
"navigationBarTitleText": "%navigate.about%",
"app-plus": {
"titleNView": {
"type": "transparent"
}
}
}
},
{
"path": "pages/tabBar/me/outlink",
"style": {
"navigationBarTitleText": "",
"app-plus": {
"titleNView": {
"type": "transparent"
}
}
}
},
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "%app.name%",
"h5": {
"maxWidth": 1190,
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#F1F1F1"
}
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "%app.name%",
"navigationBarBackgroundColor": "#ffffff",
"backgroundColor": "#ffffff"
},
"tabBar": {
"color": "#7A7E83",
"selectedColor": "#007AFF",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/tabBar/home/index",
"iconPath": "static/home.png",
"selectedIconPath": "static/home_select.png",
"text": "%navigate.menuHome%"
},
{
"pagePath": "pages/tabBar/dir/index",
"iconPath": "static/dir.png",
"selectedIconPath": "static/dir_select.png",
"text": "%navigate.menuDir%"
}, {
"pagePath": "pages/tabBar/me/index",
"iconPath": "static/me.png",
"selectedIconPath": "static/me_select.png",
"text": "%navigate.menuMe%"
}
]
}
}
"h5": {
"titleNView": {
"type": "transparent",
"buttons": []
}
}
}
},
{
"path": "pages/tabBar/me/index",
"style": {
"navigationBarTitleText": "%navigate.menuMe%",
"app-plus": {
"titleNView": false
}
}
},
{
"path": "pages/tabBar/me/person",
"style": {
"navigationBarTitleText": "%navigate.personInfo%",
"app-plus": {
"titleNView": {
"type": "transparent"
}
}
}
},
{
"path": "pages/tabBar/me/language",
"style": {
"navigationBarTitleText": "%navigate.language%",
"app-plus": {
"titleNView": {
"type": "transparent"
}
}
}
},
{
"path": "pages/tabBar/me/about",
"style": {
"navigationBarTitleText": "%navigate.about%",
"app-plus": {
"titleNView": {
"type": "transparent"
}
}
}
},
{
"path": "pages/tabBar/me/outlink",
"style": {
"navigationBarTitleText": "",
"app-plus": {
"titleNView": {
"type": "transparent"
}
}
}
},
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "%app.name%",
"h5": {
"maxWidth": 1190,
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#F1F1F1"
}
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "%app.name%",
"navigationBarBackgroundColor": "#ffffff",
"backgroundColor": "#ffffff"
},
"tabBar": {
"color": "#7A7E83",
"selectedColor": "#007AFF",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/tabBar/home/index",
"iconPath": "static/home.png",
"selectedIconPath": "static/home_select.png",
"text": "%navigate.menuHome%"
},
{
"pagePath": "pages/tabBar/dir/index",
"iconPath": "static/dir.png",
"selectedIconPath": "static/dir_select.png",
"text": "%navigate.menuDir%"
}, {
"pagePath": "pages/tabBar/me/index",
"iconPath": "static/me.png",
"selectedIconPath": "static/me_select.png",
"text": "%navigate.menuMe%"
}
]
}
}

View File

@ -1,385 +1,411 @@
<template>
<view
v-if="axiosFinished"
:class="mobileBG ? 'content-de' : 'content'"
:style="mobileBG ? {background:'url(' + mobileBG + ') no-repeat', 'backgroundSize':'cover'} : ''"
>
<view class="input-group" >
<view class="input-row">
<text class="welcome">{{$t('login.title')}}</text>
</view>
<view class="input-row border">
<text class="title">{{$t('login.account')}}</text>
<m-input class="m-input" type="text" clearable focus v-model="username" :placeholder="$t('login.accountPlaceholder')"></m-input>
</view>
<view class="input-row border">
<text class="title">{{$t('login.password')}}</text>
<m-input type="password" displayable v-model="password" :placeholder="$t('login.passwordPlaceholder')"></m-input>
</view>
</view>
<view class="btn-row">
<button type="primary" class="primary" :loading="loginBtnLoading" @tap="bindLogin">{{$t('login.loginbtn')}}</button>
</view>
</view>
<view v-if="axiosFinished" :class="mobileBG ? 'content-de' : 'content'"
:style="mobileBG ? {background:'url(' + mobileBG + ') no-repeat', 'backgroundSize':'cover'} : ''">
<view class="input-group">
<view class="input-row">
<text class="welcome">{{$t('login.title')}}</text>
</view>
<view class="input-row border">
<text class="title">{{$t('login.account')}}</text>
<m-input class="m-input" type="text" clearable focus v-model="username"
:placeholder="$t('login.accountPlaceholder')"></m-input>
</view>
<view class="input-row border">
<text class="title">{{$t('login.password')}}</text>
<m-input type="password" displayable v-model="password" :placeholder="$t('login.passwordPlaceholder')">
</m-input>
</view>
</view>
<view class="btn-row">
<button type="primary" class="primary" :loading="loginBtnLoading"
@tap="bindLogin">{{$t('login.loginbtn')}}</button>
</view>
</view>
</template>
<script>
import {
mapState,
mapMutations
} from 'vuex'
import mInput from '../../components/m-input.vue'
import {login, getInfo, getPublicKey, getUIinfo } from '@/api/auth'
import {encrypt, setLocalPK, getLocalPK, setToken, getToken, setUserInfo, getUserInfo } from '@/common/utils'
import {
mapState,
mapMutations
} from 'vuex'
import mInput from '../../components/m-input.vue'
import {
login,
getInfo,
getPublicKey,
getUIinfo
} from '@/api/auth'
import {
encrypt,
setLocalPK,
getLocalPK,
setToken,
getToken,
setUserInfo,
getUserInfo,
getUrlParams
} from '@/common/utils'
export default {
components: {
mInput
},
data() {
return {
username: '',
loginBtnLoading: false,
password: '',
mobileBG: null,
axiosFinished: false
}
},
computed: mapState(['forcedLogin', 'hasLogin', 'univerifyErrorMsg', 'hideUniverify']),
onLoad() {
uni.showLoading({
title: this.$t('commons.loading')
});
this.loadUiInfo()
this.loadPublicKey()
if(getToken() && getUserInfo()) {
this.toMain()
export default {
components: {
mInput
},
data() {
return {
username: '',
loginBtnLoading: false,
password: '',
mobileBG: null,
axiosFinished: false
}
},
computed: mapState(['forcedLogin', 'hasLogin', 'univerifyErrorMsg', 'hideUniverify']),
onLoad() {
uni.showLoading({
title: this.$t('commons.loading')
});
this.loadUiInfo()
this.loadPublicKey()
if (!this.autoLogin() && getToken() && getUserInfo()) {
this.toMain()
}
},
methods: {
...mapMutations(['login']),
async loginByPwd() {
if (this.username.length < 1) {
uni.showToast({
icon: 'none',
title: this.$t('login.accFmtError')
});
return;
}
if (this.password.length < 1) {
uni.showToast({
icon: 'none',
title: this.$t('login.passwordPlaceholder')
});
return;
}
const data = {
username: encrypt(this.username),
password: encrypt(this.password)
};
this.loginBtnLoading = true
login(data).then(res => {
if (res.success) {
setToken(res.data.token)
this.toMain()
}
}).catch(error => {
this.loginBtnLoading = false
uni.showToast({
icon: 'error',
title: error.response.data.message,
});
})
},
bindLogin() {
this.loginByPwd()
},
toMain(userName) {
getInfo().then(res => {
setUserInfo(res.data)
uni.reLaunch({
url: '../tabBar/home/index',
});
})
},
loadUiInfo() {
getUIinfo().then(res => {
const list = res.data
list.forEach(item => {
if (item.paramKey === 'ui.mobileBG' && item.paramValue) {
this.mobileBG = '/system/ui/image/' + item.paramValue
return false
}
},
methods: {
...mapMutations(['login']),
async loginByPwd() {
if (this.username.length < 1) {
uni.showToast({
icon: 'none',
title: this.$t('login.accFmtError')
});
return;
}
if (this.password.length < 1) {
uni.showToast({
icon: 'none',
title: this.$t('login.passwordPlaceholder')
});
return;
}
const data = {
username: encrypt(this.username),
password: encrypt(this.password)
};
this.loginBtnLoading = true
login(data).then(res => {
if(res.success) {
setToken(res.data.token)
this.toMain()
}
}).catch(error => {
this.loginBtnLoading = false
uni.showToast({
icon: 'error',
title: error.response.data.message,
});
})
},
bindLogin() {
this.loginByPwd()
},
toMain(userName) {
getInfo().then(res => {
setUserInfo(res.data)
uni.reLaunch({
url: '../tabBar/home/index',
});
})
},
loadUiInfo() {
getUIinfo().then(res => {
const list = res.data
list.forEach(item => {
if(item.paramKey === 'ui.mobileBG' && item.paramValue) {
this.mobileBG = '/system/ui/image/' + item.paramValue
return false
}
})
setTimeout(() => {
uni.hideLoading()
this.axiosFinished = true
}, 1500)
})
},
})
setTimeout(() => {
uni.hideLoading()
this.axiosFinished = true
}, 1500)
loadPublicKey() {
if(!getLocalPK()) {
getPublicKey().then(res => {
setLocalPK(res.data)
})
}
},
},
onReady() {
}
}
})
},
loadPublicKey() {
if (!getLocalPK()) {
getPublicKey().then(res => {
setLocalPK(res.data)
})
}
},
autoLogin() {
const url = window.location.href
const param = getUrlParams(url)
if (param?.detoken) {
if(param.detoken.endsWith('#/'))
param.detoken = param.detoken.substr(0, param.detoken.length - 2)
setToken(param.detoken)
getInfo().then(res => {
setUserInfo(res.data)
const redirect = window.location.href.split('?')[0]
window.location.href = redirect
})
return true
}
return false
}
},
onReady() {
}
}
</script>
<style>
@import "@/components/m-icon/m-icon.css";
@import "@/components/m-icon/m-icon.css";
/*每个页面公共css */
page {
min-height: 100%;
display: flex;
font-size: 14px;
}
/*每个页面公共css */
page {
min-height: 100%;
display: flex;
font-size: 14px;
}
input,
textarea,
button {
font-size: 14px;
}
input,
textarea,
button {
font-size: 14px;
}
/* #ifdef MP-BAIDU */
page {
width: 100%;
height: 100%;
display: block;
}
/* #ifdef MP-BAIDU */
page {
width: 100%;
height: 100%;
display: block;
}
swan-template {
width: 100%;
min-height: 100%;
display: flex;
}
swan-template {
width: 100%;
min-height: 100%;
display: flex;
}
/* 原生组件模式下需要注意组件外部样式 */
custom-component {
width: 100%;
min-height: 100%;
display: flex;
}
/* 原生组件模式下需要注意组件外部样式 */
custom-component {
width: 100%;
min-height: 100%;
display: flex;
}
/* #endif */
/* #endif */
/* #ifdef MP-ALIPAY */
page {
min-height: 100vh;
}
/* #ifdef MP-ALIPAY */
page {
min-height: 100vh;
}
/* #endif */
/* #endif */
/* 原生组件模式下需要注意组件外部样式 */
m-input {
width: 100%;
/* min-height: 100%; */
display: flex;
flex: 1;
}
/* 原生组件模式下需要注意组件外部样式 */
m-input {
width: 100%;
/* min-height: 100%; */
display: flex;
flex: 1;
}
.content {
display: flex;
flex: 1;
flex-direction: column;
background-color: #000000;
background-image: url(../../static/logo-bg.jpg);
padding: 10px;
justify-content: center;
background-repeat: no-repeat;
background-size: 100% 100%;
opacity: 0.75;
}
.content-de {
display: flex;
flex: 1;
flex-direction: column;
background-color: #000000;
padding: 10px;
justify-content: center;
background-repeat: no-repeat;
background-size: 100% 100%;
opacity: 0.75;
}
.content {
display: flex;
flex: 1;
flex-direction: column;
background-color: #000000;
background-image: url(../../static/logo-bg.jpg);
padding: 10px;
justify-content: center;
background-repeat: no-repeat;
background-size: 100% 100%;
opacity: 0.75;
}
.input-group {
background-color: #ffffff;
margin-top: 20px;
position: relative;
opacity: 0.95;
border-radius: 10px;
overflow: hidden;
}
.content-de {
display: flex;
flex: 1;
flex-direction: column;
background-color: #000000;
padding: 10px;
justify-content: center;
background-repeat: no-repeat;
background-size: 100% 100%;
opacity: 0.75;
}
.input-group::before {
position: absolute;
right: 0;
top: 0;
left: 0;
height: 1px;
content: '';
-webkit-transform: scaleY(.5);
transform: scaleY(.5);
background-color: #c8c7cc;
}
.input-group {
background-color: #ffffff;
margin-top: 20px;
position: relative;
opacity: 0.95;
border-radius: 10px;
overflow: hidden;
}
.input-group::after {
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 1px;
content: '';
-webkit-transform: scaleY(.5);
transform: scaleY(.5);
background-color: #c8c7cc;
}
.input-group::before {
position: absolute;
right: 0;
top: 0;
left: 0;
height: 1px;
content: '';
-webkit-transform: scaleY(.5);
transform: scaleY(.5);
background-color: #c8c7cc;
}
.input-row {
display: flex;
flex-direction: row;
position: relative;
/* font-size: 18px; */
height: 50px;
line-height: 50px;
}
.input-group::after {
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 1px;
content: '';
-webkit-transform: scaleY(.5);
transform: scaleY(.5);
background-color: #c8c7cc;
}
.input-row .title {
width: 70px;
padding-left: 15px;
}
.input-row {
display: flex;
flex-direction: row;
position: relative;
/* font-size: 18px; */
height: 50px;
line-height: 50px;
}
.input-row.border::after {
position: absolute;
right: 0;
bottom: 0;
left: 8px;
height: 1px;
content: '';
-webkit-transform: scaleY(.5);
transform: scaleY(.5);
background-color: #c8c7cc;
}
.input-row .title {
width: 70px;
padding-left: 15px;
}
.btn-row {
margin-top: 10px;
padding: 10px 0;
}
.input-row.border::after {
position: absolute;
right: 0;
bottom: 0;
left: 8px;
height: 1px;
content: '';
-webkit-transform: scaleY(.5);
transform: scaleY(.5);
background-color: #c8c7cc;
}
button.primary {
background-color: #0faeff;
line-height: 40px;
border-radius: 5px;
overflow: hidden;
}
.login-type {
display: flex;
justify-content: center;
}
.btn-row {
margin-top: 10px;
padding: 10px 0;
}
.login-type-btn {
line-height: 30px;
margin: 0px 15px;
}
button.primary {
background-color: #0faeff;
line-height: 40px;
border-radius: 5px;
overflow: hidden;
}
.login-type-btn.act {
color: #0FAEFF;
border-bottom: solid 1px #0FAEFF;
}
.login-type {
display: flex;
justify-content: center;
}
.send-code-btn {
width: 120px;
text-align: center;
background-color: #0FAEFF;
color: #FFFFFF;
}
.login-type-btn {
line-height: 30px;
margin: 0px 15px;
}
.action-row {
display: flex;
flex-direction: row;
justify-content: center;
}
.login-type-btn.act {
color: #0FAEFF;
border-bottom: solid 1px #0FAEFF;
}
.action-row navigator {
color: #007aff;
padding: 0 10px;
}
.send-code-btn {
width: 120px;
text-align: center;
background-color: #0FAEFF;
color: #FFFFFF;
}
.oauth-row {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
flex-wrap: wrap;
position: absolute;
top: 0;
left: 0;
width: 100%;
}
.action-row {
display: flex;
flex-direction: row;
justify-content: center;
}
.oauth-image {
position: relative;
width: 50px;
height: 50px;
border: 1px solid #dddddd;
border-radius: 50px;
background-color: #ffffff;
}
.action-row navigator {
color: #007aff;
padding: 0 10px;
}
.oauth-image image {
width: 30px;
height: 30px;
margin: 10px;
}
.oauth-row {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
flex-wrap: wrap;
position: absolute;
top: 0;
left: 0;
width: 100%;
}
.oauth-image button {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
opacity: 0;
}
.oauth-image {
position: relative;
width: 50px;
height: 50px;
border: 1px solid #dddddd;
border-radius: 50px;
background-color: #ffffff;
}
.captcha-view {
line-height: 0;
justify-content: center;
align-items: center;
display: flex;
position: relative;
background-color: #f3f3f3;
}
.welcome {
padding-left: 15px;
font-size: x-large;
font-weight: 500;
letter-spacing: 2px;
}
</style>
.oauth-image image {
width: 30px;
height: 30px;
margin: 10px;
}
.oauth-image button {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
opacity: 0;
}
.captcha-view {
line-height: 0;
justify-content: center;
align-items: center;
display: flex;
position: relative;
background-color: #f3f3f3;
}
.welcome {
padding-left: 15px;
font-size: x-large;
font-weight: 500;
letter-spacing: 2px;
}
</style>