diff --git a/i18n/zh_cn.properties b/i18n/zh_cn.properties index 4154eed..33db53d 100644 --- a/i18n/zh_cn.properties +++ b/i18n/zh_cn.properties @@ -110,7 +110,7 @@ Dec-Dcm_Connection_Deleted=该数据连接已被删除,无法进行操作 Dec-Dcm_Connection_Click_Connect_Database=点击连接数据库 Dec-Dcm_Connection_Read_Mode_List=以读取模式列表 Dec-Dcm_Connection_NO_Connection_Pool=无数据连接,可在数据连接管理页面添加 -Dec-Dcm_Connection_Cannot_Too_Lang=文本长度不能大于200个字符 +Dec-Dcm_Connection_Cannot_Too_Lang=文本长度不能大于{R1}个字符 Dec-Dcm_Login_Error=登录信息已失效,请重新登录 BI-Multi_Date_Quarter_End= 季度末 BI-Multi_Date_Month_Begin= 月初 @@ -300,4 +300,5 @@ BI-Basic_Million= 百万 BI-Basic_Billion= 亿 BI-Basic_Quarter= 季度 BI-Basic_No_Select= 不选 -BI-Basic_Now= 此刻 \ No newline at end of file +BI-Basic_Now= 此刻 +Dec-Dcm_Connection_Analytic_DB=阿里云AnalyticDB \ No newline at end of file diff --git a/private/i18n.ts b/private/i18n.ts index 77be638..97b308f 100644 --- a/private/i18n.ts +++ b/private/i18n.ts @@ -109,7 +109,7 @@ export default { 'Dec-Dcm_Connection_Click_Connect_Database': '点击连接数据库', 'Dec-Dcm_Connection_Read_Mode_List': '以读取模式列表', 'Dec-Dcm_Connection_NO_Connection_Pool': '无数据连接,可在数据连接管理页面添加', - 'Dec-Dcm_Connection_Cannot_Too_Lang': '文本长度不能大于200个字符', + 'Dec-Dcm_Connection_Cannot_Too_Lang': '文本长度不能大于{R1}个字符', 'Dec-Dcm_Login_Error': '登录信息已失效,请重新登录', 'BI-Multi_Date_Quarter_End': '季度末', 'BI-Multi_Date_Month_Begin': '月初', @@ -300,4 +300,5 @@ export default { 'BI-Basic_Quarter': '季度', 'BI-Basic_No_Select': '不选', 'BI-Basic_Now': '此刻', + 'Dec-Dcm_Connection_Analytic_DB': '阿里云AnalyticDB', }; diff --git a/src/modules/__test__/app.test.ts b/src/modules/__test__/app.test.ts index 9ea92be..d1a205f 100644 --- a/src/modules/__test__/app.test.ts +++ b/src/modules/__test__/app.test.ts @@ -52,6 +52,33 @@ test('解析url', () => { databaseName: 'database', urlInfo: '', }); + expect(resolveUrlInfo('jdbc:sqlserver://hostname:port;databaseName=database')).toEqual({ + host: 'hostname', + port: '', + databaseName: 'database', + urlInfo: '', + }); + expect(resolveUrlInfo('jdbc:oracle:thin:@192.168.5.143:1521/orcl')).toEqual({ + host: '192.168.5.143', + port: '1521', + databaseName: 'orcl', + urlInfo: '', + }); + expect(resolveUrlInfo('jdbc:oracle:thin:@192.168.5.143:1521:orcl')).toEqual({ + host: '192.168.5.143', + port: '1521', + databaseName: 'orcl', + urlInfo: '', + }); +}); + +test('数据库可能为空', () => { + expect(resolveUrlInfo('jdbc:mysql://secure.finedevelop.com:62306/')).toEqual({ + host: 'secure.finedevelop.com', + port: '62306', + databaseName: '', + urlInfo: '', + }); }); /** diff --git a/src/modules/app.constant.ts b/src/modules/app.constant.ts index ebb5253..618bdc3 100644 --- a/src/modules/app.constant.ts +++ b/src/modules/app.constant.ts @@ -1,2 +1,6 @@ export const CONSTANT_PLUGIN_TYPES = 'dec.constant.database.conf.connect.types'; BI.constant(CONSTANT_PLUGIN_TYPES, []); +/** + * 数据连接名称的最大长度 + */ +export const NAME_MAX_LENGTH = 150; diff --git a/src/modules/app.service.ts b/src/modules/app.service.ts index fc18f77..5a06d77 100644 --- a/src/modules/app.service.ts +++ b/src/modules/app.service.ts @@ -49,7 +49,17 @@ export function getJdbcDatabaseType(database: string, driver: string): DatabaseT export function resolveUrlInfo (url: string) { if (BI.isNull(url)) return {}; - const greenplumUrl = url.match(/^jdbc:(pivotal:greenplum):(thin:([0-9a-zA-Z/]*)?@\/\/|\/\/|)([0-9a-zA-Z_\\.-]+)(:([0-9|port]+))?(:|\/|;)([^]+)(.*)/i); + const oracleUlr = url.match(/^jdbc:(oracle):(thin:([0-9a-zA-Z/]*)?@|thin:([0-9a-zA-Z/]*)?@\/\/|\/\/|)([0-9a-zA-Z_\\.-]+)(:([0-9|port]+))?(:|\/)([^]+)(.*)/i); + if (oracleUlr) { + return { + host: oracleUlr[5], + port: oracleUlr[7] === 'port' ? '' : oracleUlr[7], + databaseName: oracleUlr[9], + urlInfo: oracleUlr[10], + }; + } + + const greenplumUrl = url.match(/^jdbc:(pivotal:greenplum):(thin:([0-9a-zA-Z/]*)?@\/\/|\/\/|)([0-9a-zA-Z_\\.-]+)(:([0-9|port]+))?(\/|;)([^]+)(.*)/i); if (greenplumUrl) { return { host: greenplumUrl[4], @@ -58,12 +68,12 @@ export function resolveUrlInfo (url: string) { urlInfo: greenplumUrl[9], }; } - const result = url.match(/^jdbc:(oracle|mysql|sqlserver|db2|impala|kylin|phoenix|derby|gbase|gbasedbt-sqli|informix-sqli|h2|postgresql|hive2|vertica|kingbase|presto|redshift|postgresql):(thin:([0-9a-zA-Z/]*)?@|thin:([0-9a-zA-Z/]*)?@\/\/|\/\/|)([0-9a-zA-Z_\\.-]+)(:([0-9|port]+))?(:|\/|;DatabaseName=)([^]+)(.*)/i); + const result = url.match(/^jdbc:(mysql|sqlserver|db2|impala|kylin|phoenix|derby|gbase|gbasedbt-sqli|informix-sqli|h2|postgresql|hive2|vertica|kingbase|presto|redshift|postgresql):(thin:([0-9a-zA-Z/]*)?@|thin:([0-9a-zA-Z/]*)?@\/\/|\/\/|)([0-9a-zA-Z_\\.-]+)(:([0-9|port]+))?(\/|;DatabaseName=)?([^]+)?(.*)/i); if (result) { return { host: result[5], port: result[7] === 'port' ? '' : result[7], - databaseName: result[9], + databaseName: result[9] || '', urlInfo: result[10], }; } diff --git a/src/modules/constants/constant.ts b/src/modules/constants/constant.ts index d2d22a6..445b57d 100644 --- a/src/modules/constants/constant.ts +++ b/src/modules/constants/constant.ts @@ -197,7 +197,7 @@ export const DESIGN_DRIVER_TYPE = [ ]; export const DATA_BASE_TYPES = [ { - text: 'ADS', + text: BI.i18nText('Dec-Dcm_Connection_Analytic_DB'), databaseType: 'ads', driver: 'com.mysql.jdbc.Driver', url: 'jdbc:mysql://hostname:port/database', diff --git a/src/modules/constants/env.ts b/src/modules/constants/env.ts index 3030fbb..8ff0057 100644 --- a/src/modules/constants/env.ts +++ b/src/modules/constants/env.ts @@ -1,5 +1,6 @@ -const fineServletURL = Dec.fineServletURL; -export const ReqPrefix = `${fineServletURL}/v10/config/connection`; +export const fineServletURL = Dec.fineServletURL; +export const ReqPath = '/v10/config/connection'; +export const ReqPrefix = `${fineServletURL}${ReqPath}`; export const ImgPrefix = `${fineServletURL}/resources?path=/com/fr/web/resources/dist/images/2x/icon/database/`; export const PluginImgPrefix = `${fineServletURL}/resources?path=`; diff --git a/src/modules/crud/crud.service.ts b/src/modules/crud/crud.service.ts index 483b918..19297e7 100644 --- a/src/modules/crud/crud.service.ts +++ b/src/modules/crud/crud.service.ts @@ -1,121 +1,38 @@ -import 'es6-promise/auto'; -import axios, { AxiosResponse, AxiosError } from 'axios'; -import { CrudReqOpts, CrudParams, ResultType } from './crud.typings.d'; -import { ReqPrefix, errorCode } from '../constants/env'; -const defaultHeaders = { - 'Content-Type': 'application/json', - 'X-Requested-With': 'XMLHttpRequest', -}; +import { ResultType } from './crud.typings.d'; +import { ReqPath } from '../constants/env'; -export function paramsSerializer(params: { [key: string]: any }) { - return Object.keys(params || {}) - .map(paramKey => { - const paramValue = params[paramKey]; - - let value = ''; - - if (BI.isObject(paramValue)) { - value = encodeURIComponent(JSON.stringify(paramValue)); - } else { - value = paramValue; - } - - return BI.isNull(value) ? '' : `${paramKey}=${value}`; - }) - .filter(v => v !== '') - .join('&'); -} -function getCookieByName(name: string):string { - let value = null; - const regExpName = new RegExp(name); - document.cookie.split(';').forEach((item: string) => { - if (item.match(regExpName)) { - value = item.split(`${name}=`)[1]; - - return false; - } - }); - - return value; -} - -function checkStatus(response: AxiosResponse) { - const status = response.status; - const noLoginErr = [errorCode.LOGIN_INFO_ERROR, errorCode.LOGIN_INFO_NOT_AVAILABLE, errorCode.TIMEOUT]; - - const resData = status === 200 - ? typeof response.data === 'string' - ? BI.jsonDecode(response.data) - : response.data - : {}; - if (noLoginErr.includes(BI.get(resData, 'errorCode'))) { - BI.Msg.alert(BI.i18nText('BI-Basic_Prompt'), BI.i18nText('Dec-Dcm_Login_Error'), () => { - window.location.reload(true); - }); - - return new Promise(() => {}); - } - - return resData; +function getFullUrl(url: string) { + return url ? `${ReqPath}/${url}` : ReqPath; } -export async function request(reqOptions: CrudReqOpts = {}): Promise { - const { url, type, headers, data, params } = reqOptions; - - return axios - .request({ - url, - baseURL: ReqPrefix, - method: type, - headers: { - ...defaultHeaders, - ...headers, - Authorization: `Bearer ${getCookieByName('fine_auth_token')}`, - 'Content-Type': 'application/json;charset=UTF-8', - }, - params, - paramsSerializer, - data, - }) - .then(checkStatus) - .catch((error: AxiosError) => { - console.log(error); +export function requestGet(url: string, data?: any): Promise { + return new Promise(resolve => { + Dec.reqGet(getFullUrl(url), '', re => { + resolve(re); }); -} - -export function requestGet(url: string, data?: any, params: CrudParams = {}) { - const timeStamp = new Date().getTime(); - - return request({ - url: url.includes('?') ? `${url}&_=${timeStamp}` : `${url}?_=${timeStamp}`, - type: 'GET', - data, - params, }); } -export function requestPost(url: string, data = {}, params: CrudParams = {}) { - return request({ - url, - type: 'POST', - data, - params, +export function requestPost(url: string, data = {}): Promise { + return new Promise(resolve => { + Dec.reqPost(getFullUrl(url), data, re => { + resolve(re); + }); }); } export function requestDelete(url: string, data = {}) { - return request({ - url, - type: 'DELETE', - data, + return new Promise(resolve => { + Dec.reqDelete(getFullUrl(url), data, re => { + resolve(re); + }); }); } -export function requestPut(url: string, data = {}, params: CrudParams = {}) { - return request({ - url, - type: 'PUT', - data, - params, +export function requestPut(url: string, data = {}) { + return new Promise(resolve => { + Dec.reqPut(getFullUrl(url), data, re => { + resolve(re); + }); }); } diff --git a/src/modules/pages/connection/list/list_item/list_item.model.ts b/src/modules/pages/connection/list/list_item/list_item.model.ts index 1e5ab05..efc02ca 100644 --- a/src/modules/pages/connection/list/list_item/list_item.model.ts +++ b/src/modules/pages/connection/list/list_item/list_item.model.ts @@ -2,6 +2,8 @@ import { model, Model } from '@core/core'; import { AppModel } from '../../../../app.model'; import { ApiFactory } from '../../../../crud/apiFactory'; import { ResultType } from '../../../../crud/crud.typings'; +import { getChartLength } from '../../../../app.service'; +import { NAME_MAX_LENGTH } from '../../../../app.constant'; const api = new ApiFactory().create(); export const ListItemModelXtype = 'dec.dcm.model.connection.list_item'; @@ -63,6 +65,11 @@ export class ListItemModel extends Model<{ resolve({ errorCode: '1', errorMsg: 'Dec-Dcm_Connection_ConnectionName_Cannt_Null' }); }); } + if (getChartLength(newName) > NAME_MAX_LENGTH) { + return new Promise(resolve => { + resolve({ errorCode: '1', errorMsg: BI.i18nText('Dec-Dcm_Connection_Cannot_Too_Lang', NAME_MAX_LENGTH) }); + }); + } const hasNamed = this.model.connections.some(item => item.connectionName === newName); if (hasNamed && oldName !== newName) { return new Promise(resolve => { diff --git a/src/modules/pages/maintain/forms/form.ts b/src/modules/pages/maintain/forms/form.ts index 34fa0f2..6eec4d3 100644 --- a/src/modules/pages/maintain/forms/form.ts +++ b/src/modules/pages/maintain/forms/form.ts @@ -7,6 +7,7 @@ import { connectionType, errorCode } from '@constants/env'; import { ConnectionJDBC, Connection, ResultType } from 'src/modules/crud/crud.typings'; import { DEFAULT_JNDI_DATA, DEFAULT_JDBC_POOL, DATEBASE_FILTER_TYPE } from '@constants/constant'; import { getJdbcDatabaseType, getChartLength } from '../../../app.service'; +import { NAME_MAX_LENGTH } from '../../../app.constant'; export const MaintainFormXtype = 'dec.dcm.maintain.form'; @shortcut(MaintainFormXtype) @store(MaintainFormModelXtype) @@ -186,8 +187,8 @@ export class MaintainForm extends BI.Widget { return false; } } - if (getChartLength(value.connectionName) > 200) { - this.setFromError(BI.i18nText('Dec-Dcm_Connection_Cannot_Too_Lang')); + if (getChartLength(value.connectionName) > NAME_MAX_LENGTH) { + this.setFromError(BI.i18nText('Dec-Dcm_Connection_Cannot_Too_Lang', NAME_MAX_LENGTH)); return false; } @@ -220,8 +221,8 @@ export class MaintainForm extends BI.Widget { return; } - if (getChartLength(formValue.connectionName) > 200) { - this.setFromError(BI.i18nText('Dec-Dcm_Connection_Cannot_Too_Lang')); + if (getChartLength(formValue.connectionName) > NAME_MAX_LENGTH) { + this.setFromError(BI.i18nText('Dec-Dcm_Connection_Cannot_Too_Lang', NAME_MAX_LENGTH)); return false; } diff --git a/src/request.ts b/src/request.ts new file mode 100644 index 0000000..b7f4d9a --- /dev/null +++ b/src/request.ts @@ -0,0 +1,118 @@ +import 'es6-promise/auto'; +import axios, { AxiosResponse, AxiosError } from 'axios'; +import { CrudReqOpts, ResultType } from './modules/crud/crud.typings'; +import { fineServletURL, errorCode } from './modules/constants/env'; +const defaultHeaders = { + 'Content-Type': 'application/json', + 'X-Requested-With': 'XMLHttpRequest', +}; + +export function paramsSerializer(params: { [key: string]: any }) { + return Object.keys(params || {}) + .map(paramKey => { + const paramValue = params[paramKey]; + + let value = ''; + + if (BI.isObject(paramValue)) { + value = encodeURIComponent(JSON.stringify(paramValue)); + } else { + value = paramValue; + } + + return BI.isNull(value) ? '' : `${paramKey}=${value}`; + }) + .filter(v => v !== '') + .join('&'); +} +function getCookieByName(name: string):string { + let value = null; + const regExpName = new RegExp(name); + document.cookie.split(';').forEach((item: string) => { + if (item.match(regExpName)) { + value = item.split(`${name}=`)[1]; + + return false; + } + }); + + return value; +} + +function checkStatus(response: AxiosResponse) { + const status = response.status; + const noLoginErr = [errorCode.LOGIN_INFO_ERROR, errorCode.LOGIN_INFO_NOT_AVAILABLE, errorCode.TIMEOUT]; + + const resData = status === 200 + ? typeof response.data === 'string' + ? BI.jsonDecode(response.data) + : response.data + : {}; + if (noLoginErr.includes(BI.get(resData, 'errorCode'))) { + BI.Msg.alert(BI.i18nText('BI-Basic_Prompt'), BI.i18nText('Dec-Dcm_Login_Error'), () => { + window.location.reload(true); + }); + + return new Promise(() => {}); + } + + return resData; +} + +export async function request(reqOptions: CrudReqOpts = {}): Promise { + const { url, type, headers, data, params } = reqOptions; + + return axios + .request({ + url, + baseURL: fineServletURL, + method: type, + headers: { + ...defaultHeaders, + ...headers, + Authorization: `Bearer ${getCookieByName('fine_auth_token')}`, + 'Content-Type': 'application/json;charset=UTF-8', + }, + params, + paramsSerializer, + data, + }) + .then(checkStatus) + .catch((error: AxiosError) => { + console.log(error); + }); +} + +Dec.reqGet = (url: string, data: any, callback: (re: any) => void) => { + const timeStamp = new Date().getTime(); + + request({ + url: url.includes('?') ? `${url}&_=${timeStamp}` : `${url}?_=${timeStamp}`, + type: 'GET', + data, + }).then(re => callback(re)); +}; + +Dec.reqPost = (url: string, data: any, callback: (re: any) => void) => { + request({ + url, + type: 'POST', + data, + }).then(re => callback(re)); +}; + +Dec.reqDelete = (url: string, data: any, callback: (re: any) => void) => { + request({ + url, + type: 'DELETE', + data, + }).then(re => callback(re)); +}; + +Dec.reqPut = (url: string, data: any, callback: (re: any) => void) => { + request({ + url, + type: 'PUT', + data, + }).then(re => callback(re)); +}; diff --git a/types/globals.d.ts b/types/globals.d.ts index ea354bf..e761929 100644 --- a/types/globals.d.ts +++ b/types/globals.d.ts @@ -5,4 +5,16 @@ interface Obj { declare let BI: Obj & import('fineui')._BI; declare const Fix: Obj; declare const DecCst: Obj; -declare const Dec: Obj; \ No newline at end of file +declare const Dec: { + fineServletURL: string; + socket: { + connected: boolean; + }; + personal: { + username: string; + }; + reqGet: (url: string, data: any, callback: (re: any) => void) => void; + reqPost: (url: string, data: any, callback: (re: any) => void) => void; + reqPut: (url: string, data: any, callback: (re: any) => void) => void; + reqDelete: (url: string, data: any, callback: (re: any) => void) => void; +}; \ No newline at end of file diff --git a/webpack/webpack.dev.js b/webpack/webpack.dev.js index f7e3bd1..d93e397 100644 --- a/webpack/webpack.dev.js +++ b/webpack/webpack.dev.js @@ -36,7 +36,7 @@ chokidar module.exports = merge(common, { devtool: 'eval-source-map', entry: { - show: ['./src/i18n.ts', './src/index.ts'], + show: ['./src/i18n.ts', './src/request.ts', './src/index.ts'], }, output: { path: dirs.DEST,