CN-1479 fix: 搜索组件showHint提示文本修改

This commit is contained in:
刘洪洪
2023-12-13 17:05:16 +08:00
parent 3d1fbfa5fd
commit f5f857bcb4
14 changed files with 471 additions and 579 deletions

View File

@@ -375,12 +375,16 @@ span.CodeMirror-selectedtext { background: none; }
}
.hint-title {
margin: 10px 10px 10px 4px;
line-height: 20px;
font-weight: bold;
margin: 10px 10px 10px 0;
height: 24px;
line-height: 24px;
/* 禁止选中 样式 */
background: #fff !important;
color: #000 !important;
font-family: NotoSansHans-Medium;
font-size: 14px;
color: #333333 !important;
letter-spacing: 0;
font-weight: 500;
}
.cm-s-eclipse span.cm-string-2 {
@@ -433,3 +437,55 @@ span.CodeMirror-selectedtext { background: none; }
.cm-variable-2{
font-weight: bold;
}
.default-tips-header,.default-tips-title {
height: 24px;
line-height: 24px;
font-weight: 700;
color: #333333;
font-size: 14px;
margin: 6px 0;
font-family: NotoSansSC-Bold;
letter-spacing: 0;
}
.default-tips-header {
font-size: 15px;
}
.show-hint-tips__p {
word-break: keep-all;
margin: 0;
line-height: 24px;
color: #575757;
font-weight: 400;
}
.Hint {
padding: 0;
z-index: 2;
.hint__block {
display: flex;
flex-direction: row;
width: calc(100% - 41px);
min-height: 320px;
margin-top: 6px;
box-shadow: 0 2px 8px 0 rgba(0,0,0,.3);
z-index: 2;
.hint__block-filter {
width: 326px;
background: #fff;
border-right: 1px solid #DEDEDE;
padding: 12px;
z-index: 2;
}
.hint__block-helper {
width: calc(100% - 326px);
background: #fff;
z-index: 2;
}
}
}

View File

@@ -43,7 +43,7 @@
align-content: center;
padding: 16px 0;
margin-bottom: 1px;
background-color: white;
//background-color: white;
border-radius: 0 4px 4px 0;
.cn-entity__icon {

View File

@@ -15,6 +15,7 @@ import filterTips from '@/components/advancedSearch/showhint/const/filterTips.js
import varTips from '@/components/advancedSearch/showhint/const/varTips.js'
import { fieldRender } from '@/components/advancedSearch/showhint/const/fieldTips.js'
import { EN, storageKey, ZH } from '@/utils/constants'
export default {
name: 'HelperInfo',
@@ -104,8 +105,12 @@ export default {
return fieldRender
}
}
const language = localStorage.getItem(storageKey.language) || EN
return defaultTips.default.description
if (language === ZH) {
return defaultTips.zhDefault.description
}
return defaultTips.enDefault.description
}
}
}
@@ -122,7 +127,7 @@ export default {
}
.tips-container {
padding: 6px;
padding: 12px;
}
/deep/ ul li {
@@ -143,9 +148,10 @@ export default {
/deep/ code,
.code {
background: initial;
border: 1px solid #ccc;
padding: 4px 12px;
border: 1px solid #DEDEDE;
height: 24px;
line-height: 24px;
padding: 0 12px;
margin: 6px 0;
display: block;
}

View File

@@ -1,19 +1,11 @@
<!-- 提示信息 -->
<template>
<div class="Hint" style="padding: 0;z-index: 2;" @click.stop>
<!-- <el-row style="padding: 0;display: flex;flex-direction: row">-->
<!-- <el-col style="width: 300px;min-height: 302px;z-index: 2;">-->
<!-- <hint-info v-on="$listeners" :hintList="hintList"></hint-info>-->
<!-- </el-col>-->
<!-- <el-col style="width: calc(100% - 300px);min-height: 302px">-->
<!-- <helper-info :hintSearch="hintSearch"></helper-info>-->
<!-- </el-col>-->
<!-- </el-row>-->
<div style="display: flex;flex-direction: row;width: calc(100% - 41px);box-shadow: 0 2px 12px 0 rgba(0,0,0,.2);margin-top: 6px;">
<div style="width: 324px;min-height: 302px;z-index: 2;border: 1px solid #DEDEDE;">
<div class="Hint" @click.stop>
<div class="hint__block">
<div class="hint__block-filter">
<hint-info v-on="$listeners" :hintList="hintList" @select="onSelect"></hint-info>
</div>
<div style="width: calc(100% - 324px);min-height: 302px;z-index:2">
<div class="hint__block-helper">
<helper-info :hintSearch="hintSearch"></helper-info>
</div>
</div>
@@ -41,7 +33,3 @@ export default {
}
}
</script>
<style lang="" scoped>
</style>

View File

@@ -1,6 +1,6 @@
<template>
<div class="HintInfo">
<ul class="CodeMirror-hints-manual eclipse" style="padding-left: 0">
<ul style="padding-left: 0;margin: -10px 0 0 0;">
<template v-for="(item,index) in hintList" :key="index">
<li :ref="'hint_'+index" class="relative-item CodeMirror-hint"
@click="handleSelect(item,index,hintList)"
@@ -115,8 +115,9 @@ export default {
}
.hint-title{
margin: 10px !important;
margin-left: 4px !important;
margin-left: 0 !important;
font-size: 14px;
line-height: 24px;
}
.el-dropdown-menu__item{
text-indent: 1em;

View File

@@ -1,56 +1,51 @@
export default {
default: {
enDefault: {
description () {
const code = `SELECT aggregate_function(field) [as field] … (5)
FROM [db.]table|$log_type(1)
WHERE $filter [and <expression-list> ](2)
GROUP BY <field-list>(3)
[HAVING <expression-list>](4)
[ORDER BY <sort-field> [ASC|DESC]](6)
[LIMIT [n, ]m ](7)`
return (<div className='default-tips'>
<h2>How To Search</h2>
<p> You can write a query to retieve logs from an log type, use group by aggregation keywords to calculate
metrics
and generate statistical results , search for specific conditions within a rolling time window, predict future
trends, and so on. </p>
<h3> 1. Filter Mode</h3>
<p> A query in SQL ( also known as a "Where clause") has three basic parts: fields, operators, and values. Where
clause can be combined with AND , OR and NOT keywords. </p>
<div class='default-tips-header'>How To Search</div>
<p class='show-hint-tips__p'> You can write queries to retrieve entities, including their basic information, activity levels, network performance, threat events, relationships with other entities, and so on. A query has three basic parts: fields, operators, and values.</p>
<code>[Field + operator + value] keyword [operator(Field)]</code>
<p class='show-hint-tips__p'>Field - Fields are different types of traffic attributes in the system. Fields include ip, domain, app, and so on.</p>
<p class='show-hint-tips__p'>Operator - Operators are the foundation of the query. They relate the field to the value and build a query condition. Common operators include =, IN, Like, and so on.</p>
<p class='show-hint-tips__p'>Value - Values are the actual data in the query.</p>
<p class='show-hint-tips__p'>Use the percent(%) wildcard substitutes for one or more characters in a string. Such as: </p>
<code>domain like '%google.com'</code>
<p class='show-hint-tips__p'>Strings containing spaces must be enclosed in single quotes ('). Such as:</p>
<code>ip=192.168.10.53</code>
<code>ip.country='United States'</code>
<p class='show-hint-tips__p'>Keyword - Keywords are specific words in the SQL. You can specify the AND and OR to create more complex query conditions. Currently only support AND.</p>
<p class='show-hint-tips__p'>There are two input modes, which can be switched by clicking the button on the right side of the input box.</p>
<ul>
<li>Field - Fields are different types of traffic attributes int the system. Fields include server_ip,
server_port, ssl_sni , and so on.
</li>
<li>Operator - Operators are the foundation of the query. They relate the field to the value and build a query
condition. Common operators include equals(=), IN, Like, etc.
</li>
<li>
<span>Value - Values are the actual data in the query.</span>
<ul class="sub-url">
<li>Use the percent (%) wildcard substitutes for one or more characters in a string. Such as ssl_sni like
'%google.com' .
</li>
<li>Use underscore (_) wildcard substitutes for exactly one character in a string. Such as
client_ip like '192.168.10.1_'.
</li>
<li>String requires single quotes (') around text values. Such as client_ip='192.168.10.53'.</li>
</ul>
</li>
<li>Keyword - Keywords are specific words in the SQL. You can specify the AND and OR in the WHERE clause to
create more complex query conditions.
</li>
</ul>
<h3> 2. Statistics Mode </h3>
<p>More advanced searches use the SQL keywords WHERE, GROUP BY to build aggregated query and return aggregated
results.</p>
<i class='ref-txt'>All clauses are optional , except for the required list of expressions after SELECT, WHERE and GROUP BY .</i>
<pre class="code">
{code}
</pre>
<div class='default-tips-title'> 1. Text Mode</div>
<p class='show-hint-tips__p'>In text mode, you will write your query with the help of input suggestions.</p>
<div class='default-tips-title'> 2. Tag Mode </div>
<p class='show-hint-tips__p'>In tag mode, you will be guided through preset steps to write a query.</p>
</div>)
}
},
zhDefault: {
description () {
return (<div className='default-tips'>
<div class='default-tips-header'>如何搜索</div>
<p class='show-hint-tips__p'>您可以编写查询来检索实体。查询具有三个基本部分:字段、运算符和值。</p>
<code>[字段 + 运算符 + 值] 关键字 [运算符(字段)]</code>
<p class='show-hint-tips__p'>字段 - 字段是系统中不同类型的属性。字段包括 ip、domain、app 等。</p>
<p class='show-hint-tips__p'>运算符 - 运算符是查询的基础。他们将字段与值相关联并构建查询条件。常见的运算符包括 =、IN、Like 等。</p>
<p class='show-hint-tips__p'>值 - 值是查询中的实际数据。</p>
<p class='show-hint-tips__p'>使用百分号(%)通配符替换字符串中的一个或多个字符。例如:</p>
<code>domain like '%google.com'</code>
<p class='show-hint-tips__p'>包含空格的字符串必须用单引号(')括住例如</p>
<code>ip=192.168.10.53</code>
<code>ip.country='United States'</code>
<p class='show-hint-tips__p'>关键字 - 关键字是 SQL 中的特定单词您可以指定 AND OR 来创建更复杂的查询条件暂时只支持AND</p>
<p class='show-hint-tips__p'>有两种输入模式通过点击输入框右侧的按钮进行切换</p>
<div class='default-tips-title'> 1. 文本模式</div>
<p class='show-hint-tips__p'>文本模式中您将在输入建议的帮助下编写查询语句</p>
<div class='default-tips-title'> 2. 标签模式 </div>
<p class='show-hint-tips__p'>标签模式中您将在引导下按预设好的步骤编写查询</p>
</div>)
}
}

View File

@@ -1,19 +1,20 @@
import i18n from '@/i18n'
export function fieldRender (h, { fieldInfo = {}, funcReference = [], operatorReference = [], operates = [], funs = [] }) {
return (<div className='field-tips'>
<h2>{fieldInfo.label}</h2>
<p> Name: {fieldInfo.name}</p>
<p> Type:{fieldInfo.type} </p>
<p> Operator: {operates.join(',')} </p>
<p> Function: {funs.join(',')} </p>
<div class='default-tips-header'>{fieldInfo.label}</div>
<p class='show-hint-tips__p'> {i18n.global.t('overall.name')}: {fieldInfo.name}</p>
<p class='show-hint-tips__p'> {i18n.global.t('overall.type')}: {typeof fieldInfo.type === 'object' ? fieldInfo.type.type : fieldInfo.type} </p>
<p class='show-hint-tips__p'> {i18n.global.t('overall.operators')}: {operates.join(',')} </p>
{/* <p> Function: {funs.join(',')} </p> */}
<p> {fieldInfo.options && (
'Options: ' + fieldInfo.options.map(item => {
return `${item.displayText}(${item.text})`
}).join(',')
)} </p>
<h3>Enable Operators</h3>
<div class='default-tips-header'>{i18n.global.t('overall.enableOperators')}</div>
{/* 提示超过一屏幕 明显不合理 --- 换成简单形式 */}
<ul style="padding-left: 20px;">
<ul style="padding-left: 0;margin: 12px 0;">
{operatorReference.map(item => {
return <li>
<span>{item.name}</span>
@@ -21,16 +22,5 @@ export function fieldRender(h, {fieldInfo = {}, funcReference = [], operatorRefe
</li>
})}
</ul>
<h3>Enable Functions</h3>
<ul style="padding-left: 20px;">
{funcReference.map(item => {
return <li>
<span>{item.name}</span>
<code> {item.function} </code>
</li>
})}
</ul>
</div>)
}

View File

@@ -1,110 +1,109 @@
import i18n from '@/i18n'
import { EN, storageKey, ZH } from '@/utils/constants'
export const helpInfo = [
{
operator: "AND",
describe: `Search logs that contain all the search fields. You can use parentheses "()" to control the order in which clauses are executed. `,
operator: 'AND',
zhDescribe: '搜索包含所有搜索字段的实体。',
enDescribe: 'Search entities that contain all the search fields. ',
example: [
"Client IP = '192.168.10.53' AND Server IP = '8.8.8.8'",
"Client IP = '192.168.10.53' AND SSL.SNI='google.com'",
"ip = '192.168.10.53' AND domain = 'google.com'",
"domain = 'google.com' AND app = 'google'"
]
},
}
// {
// operator: "OR",
// describe: `Search logs that contain any of the search fields. You can use parentheses "()" to control the order in which clauses are executed. `,
// // operator: '= , !=',
// operator: ' = ',
// describe: 'Search logs that do EQUALS or NOT EQUALS the search value. ',
// example: [
// "Client IP = '192.168.10.53' OR Server IP = '8.8.8.8'",
// "Client IP = '192.168.10.53' OR Client IP = '192.168.10.54'",
// "Client IP = '192.168.10.53' "
// // 'Server Port != 443'
// ]
// },
{
operator: "= , !=",
describe: `Search logs that do EQUALS or NOT EQUALS the search value. `,
example: [
"Client IP != '192.168.10.53' ",
"Server Port != 443",
// {
// operator: '> , < , >= , <=',
// describe: 'Search logs greater than and equal or less than and equal a value , or whtin a range. This operator cant be used with string fields. ',
// example: [
// 'Bytes Sent >= 751',
// 'Bytes Sent >= 751 and Bytes Sent <= 1024'
// ]
// },
// {
// operator: ' LIKE ',
// // operator: 'LIKE , NOT LIKE',
// describe: 'You can use wildcard searches for value that contain or not contain search fields. Using percent (%) wildcard substitutes for one or more characters in a string. Using underscore (_) wildcard substitutes for exactly one character in a string. ',
// example: [
// "SSL.SNI LIKE '%google.com' ",
// "Client IP LIKE '192.168.10.1_'"
// // "SSL.SNI NOT LIKE '%google.com'",
// // "Client IP NOT LIKE '192.168%'"
// ]
// },
// {
// operator: ' IN ',
// // operator: 'IN , NOT IN',
// describe: 'Specify or exclude multiple values for search fields. IN IN condition you can use when you need to use multiple OR condition. ',
// example: [
// "l7 Protocol IN ('HTTP', 'HTTPS')"
// // 'Server Port NOT IN (443,80)'
// ]
// },
// {
// operator: 'EMPTY , NOT EMPTY',
// describe: 'Specify or exclude empty value for search fields. A string or array is considered non-empty if it contains at least one byte, even if this is a space or a null byte. ',
// example: [
// 'NOT EMPTY(SSL.SNI)',
// 'EMPTY(Application Label)'
// ]
// },
// {
// operator: 'HAS',
// describe: 'Search logs that has element value for array type. Example:',
// example: [
// 'HAS(FQDN Category, music)'
// ]
// }
// {
// operator: 'bitAnd',
// describe: 'A bitwise And(&) is a binary operation that compares each bit of the first operand to the corresponding bit of the second operand. Both expressions must have integral types. Examples:',
// example: [
// 'bitAnd(Flags, Asymmetric|Download) = Asymmetric|Download',
// 'bitAnd(Flags, Asymmetric|Download) >0'
// ]
// }
]
},
{
operator: "> , < , >= , <=",
describe: `Search logs greater than and equal or less than and equal a value , or whtin a range. This operator cant be used with string fields. `,
example: [
"Bytes Sent >= 751",
"Bytes Sent >= 751 and Bytes Sent <= 1024",
const renderData = [
helpInfo[0]
]
},
{
operator: "LIKE , NOT LIKE",
describe: `You can use wildcard searches for value that contain or not contain search fields. Using percent (%) wildcard substitutes for one or more characters in a string. Using underscore (_) wildcard substitutes for exactly one character in a string. `,
example: [
"SSL.SNI LIKE '%google.com' ",
"Client IP LIKE '192.168.10.1_'",
"SSL.SNI NOT LIKE '%google.com'",
"Client IP NOT LIKE '192.168%'",
]
},
{
operator: "IN , NOT IN",
describe: `Specify or exclude multiple values for search fields. IN/NOT IN condition you can use when you need to use multiple OR condition. `,
example: [
"l7 Protocol IN ('HTTP', 'HTTPS')",
"Server Port NOT IN (443,80)"
]
},
{
operator: "EMPTY , NOT EMPTY",
describe: `Specify or exclude empty value for search fields. A string or array is considered non-empty if it contains at least one byte, even if this is a space or a null byte. `,
example: [
"NOT EMPTY(SSL.SNI)",
"EMPTY(Application Label)"
]
},
{
operator: "HAS",
describe: `Search logs that has element value for array type. Example:`,
example: [
"HAS(FQDN Category, music)"
]
},
{
operator: "bitAnd",
describe: `A bitwise And(&) is a binary operation that compares each bit of the first operand to the corresponding bit of the second operand. Both expressions must have integral types. Examples:`,
example: [
"bitAnd(Flags, Asymmetric|Download) = Asymmetric|Download",
"bitAnd(Flags, Asymmetric|Download) >0"
]
},
]
var renderData=[
helpInfo[0],
helpInfo[1],
];
export const filterList = renderData
function main () {
var sqlTips={}
const sqlTips = {}
const language = localStorage.getItem(storageKey.language) || EN
renderData.forEach((item, index) => {
var data=item // 这是个闭包
const data = item // 这是个闭包
sqlTips[item.operator] = {
name: item.operator,
// syntax: item.syntax,
type: "filter",
type: 'filter',
description () {
return (<div className='filter-tips'>
<h2>{data.operator}</h2>
<h3> Description: </h3>
<p> {data.describe}</p>
<h3>Examples:</h3>
<ul>
<div class='default-tips-header'>{data.operator}</div>
<div class='default-tips-title'> {i18n.global.t('overall.remark')}: </div>
<p class='show-hint-tips__p'> {language === ZH ? data.zhDescribe : data.enDescribe}</p>
<div class='default-tips-title'>{i18n.global.t('overall.examples')}:</div>
<ul style="padding-left: 0;">
{item.example.map(v => {
return <li>
<span>{v}</span>
<code>{v}</code>
</li>
})}
</ul>
</div>)
}
};
}
})
return sqlTips
}
var filterTips=main();
const filterTips = main()
export default filterTips

View File

@@ -1,17 +1,17 @@
var renderData = [
{
name: "COUNT",
syntax: "count(expr)",
description: "Aggregate function is used to count the number of rows",
name: 'COUNT',
syntax: 'count(expr)',
description: 'Aggregate function is used to count the number of rows',
example: [
{
purpose: "Total count of all logs :",
code: "count(*)"
purpose: 'Total count of all logs :',
code: 'count(*)'
},
{
purpose: "Counts the occurrences of a Client IP :",
code: "count(client_ip)"
},
purpose: 'Counts the occurrences of a Client IP :',
code: 'count(client_ip)'
}
],
details () {
// 支持jsx 嵌套写法,万一测试要关键字加重呢
@@ -25,18 +25,18 @@ var renderData = [
}
},
{
name: "COUNT_DISTINCT",
syntax: "count(distinct expr)",
description: "Aggregate function is used to count only distinct(unique) rows in the specified field",
name: 'COUNT_DISTINCT',
syntax: 'count(distinct expr)',
description: 'Aggregate function is used to count only distinct(unique) rows in the specified field',
example: [
{
purpose: "Counts the number of different Client IP :",
code: "count(distinct client_ip)"
purpose: 'Counts the number of different Client IP :',
code: 'count(distinct client_ip)'
},
{
purpose: `Counts the number of different "Server IP" and "Server port" :`,
code: "count(distinct server_ip, server_port)"
},
code: 'count(distinct server_ip, server_port)'
}
],
details () {
// 支持jsx 嵌套写法,万一测试要关键字加重呢
@@ -45,37 +45,38 @@ var renderData = [
}
},
{
name: "AVG",
syntax: "avg(expr)",
description: "Aggregate function is used to calculate the arithmetic mean in the specified field. EXPR must be Integer,Float or Decimal and returned value as Float.",
name: 'AVG',
syntax: 'avg(expr)',
description: 'Aggregate function is used to calculate the arithmetic mean in the specified field. EXPR must be Integer,Float or Decimal and returned value as Float.',
example: [
{
purpose: `Calculates the average(mean) "Byte sent (sent_bytes)" field:`,
code: "avg(sent_bytes)"
code: 'avg(sent_bytes)'
},
{
purpose: `Calculates the average(mean) "Bytes" , rounded to 2 decimal points:`,
code: "round(avg(sent_bytes+received_bytes),2)"
},
code: 'round(avg(sent_bytes+received_bytes),2)'
}
],
details () {
// 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div>You can use ROUND(expr[,decimal_places]) or FLOOR(expr[,decimal_places]) function that rounds or floors a value to a specified number of decimal places.</div>
return <div>You can use ROUND(expr[,decimal_places]) or FLOOR(expr[,decimal_places]) function that rounds or
floors a value to a specified number of decimal places.</div>
}
},
{
name: "SUM",
syntax: "sum(expr)",
description: "Aggregate function is used to sum of the values of the specified field. EXPR must be Integer,Float or Decimal.",
name: 'SUM',
syntax: 'sum(expr)',
description: 'Aggregate function is used to sum of the values of the specified field. EXPR must be Integer,Float or Decimal.',
example: [
{
purpose: `The sum of the "Byte sent (sent_bytes)" field:`,
code: "sum(sent_bytes)"
code: 'sum(sent_bytes)'
},
{
purpose: `The sum of the "sent_bytes" and "received_bytes" fields , and rename as "Bytes ":`,
code: "sum(sent_bytes+received_bytes) as Bytes"
},
code: 'sum(sent_bytes+received_bytes) as Bytes'
}
],
details () {
// 支持jsx 嵌套写法,万一测试要关键字加重呢
@@ -83,43 +84,45 @@ var renderData = [
}
},
{
name: "MAX",
syntax: "max(expr)",
description: "Aggregate function is used to return the maximum value of the specified field.",
name: 'MAX',
syntax: 'max(expr)',
description: 'Aggregate function is used to return the maximum value of the specified field.',
example: [
{
purpose: `Returns the maximum value of the "Byte sent (sent_bytes)" field:`,
code: "max(sent_bytes)"
code: 'max(sent_bytes)'
}
],
details () {
// 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div>The <b>MAX</b> aggregate function can also be used with the DateTime data type, where it will sort the DateTime values and return the last value from the sorted logs.</div>
return <div>The <b>MAX</b> aggregate function can also be used with the DateTime data type, where it will sort the
DateTime values and return the last value from the sorted logs.</div>
}
},
{
name: "MIN",
syntax: "min(expr)",
description: "Aggregate function is used to return the minimum value of the specified field.",
name: 'MIN',
syntax: 'min(expr)',
description: 'Aggregate function is used to return the minimum value of the specified field.',
example: [
{
purpose: `Returns the minimum value of the "Byte sent (sent_bytes)" field:`,
code: "min(sent_bytes)"
code: 'min(sent_bytes)'
}
],
details () {
// 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div>The MIN aggregate function can also be used with the DateTime data type, where it will sort the DateTime values and return the minimum value from the sorted logs.</div>
return <div>The MIN aggregate function can also be used with the DateTime data type, where it will sort the
DateTime values and return the minimum value from the sorted logs.</div>
}
},
{
name: "TIME_FLOOR_WITH_FILL",
syntax: "TIME_FLOOR_WITH_FILL(<timestamp_expr>, <period>[,<fill>])",
description: "Rounds down a timestamp, returning it as a new timestamp,optionally from some reference fill, and fills time gaps and impute missing values.",
name: 'TIME_FLOOR_WITH_FILL',
syntax: 'TIME_FLOOR_WITH_FILL(<timestamp_expr>, <period>[,<fill>])',
description: 'Rounds down a timestamp, returning it as a new timestamp,optionally from some reference fill, and fills time gaps and impute missing values.',
example: [
{
purpose: `Round the recv_time down to a 5 minutes increment and fill time gaps and impute zero value.`,
code: "TIME_FLOOR_WITH_FILL(recv_time,'PT5M','zero')"
code: 'TIME_FLOOR_WITH_FILL(recv_time,\'PT5M\',\'zero\')'
}
],
details () {
@@ -144,58 +147,62 @@ var renderData = [
}
},
{
name: "UNIX_TIMESTAMP",
name: 'UNIX_TIMESTAMP',
syntax: `UNIX_TIMESTAMP(date)`,
description: `Returns a Unix timestamp the value of the argument as seconds since '1970-01-01 00:00:00' UTC.`,
example: [
{
purpose: `Specify a datetime string "2019-06-06 19:11:12", calculate the Unix timestamp:`,
code: "UNIX_TIMESTAMP('2019-06-06 19:11:12')"
code: 'UNIX_TIMESTAMP(\'2019-06-06 19:11:12\')'
},
{
purpose: `Specify a ISO8601 datetime string with time zone information "2019-10-12T14:20:50+08:00", calculate the Unix timestamp:`,
code: "UNIX_TIMESTAMP('2019-10-12T14:20:50+08:00')"
code: 'UNIX_TIMESTAMP(\'2019-10-12T14:20:50+08:00\')'
},
{
purpose: `Specify a ISO8601 datetime string with UTC+0 time zone information "2019-10-12T14:20:50Z", calculate the Unix timestamp:`,
code: "UNIX_TIMESTAMP('2019-10-12T14:20:50Z')"
code: 'UNIX_TIMESTAMP(\'2019-10-12T14:20:50Z\')'
},
],
details () {
// 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div>
<p>The date argument may be a DATE, DATETIME or TIMESTAMP string, or a number in YYMMDD, YYMMDDhhmmss, YYYYMMDD, or YYYYMMDDhhmmss format.</p>
<p>The date argument may be a DATE, DATETIME or TIMESTAMP string, or a number in YYMMDD, YYMMDDhhmmss, YYYYMMDD,
or YYYYMMDDhhmmss format.</p>
<ul>
<li> Standard datetime string(UTC+0) : UNIX_TIMESTAMP('2019-06-06 19:11:12')</li>
<li>ISO8601 datetime stringUNIX_TIMESTAMP('2019-10-12T14:20:50Z') or UNIX_TIMESTAMP('2019-10-12T14:20:50+08:00')</li>
<li>ISO8601 datetime stringUNIX_TIMESTAMP('2019-10-12T14:20:50Z') or
UNIX_TIMESTAMP('2019-10-12T14:20:50+08:00')
</li>
<li>Date: UNIX_TIMESTAMP(DATE('2019-06-06 19:11:12'))</li>
</ul>
</div>
}
},
{
name: "FROM_UNIXTIME",
name: 'FROM_UNIXTIME',
syntax: `FROM_UNIXTIME(unix_timestamp)`,
description: `Returns a representation of unix_timestamp as a datetime or character string value. The value returned is expressed using the UTC+0 time zone.`,
example: [
{
purpose: `Specify a Unix Timestamp "1570881546", calculate the datetime string:`,
code: "FROM_UNIXTIME(1570881546)"
code: 'FROM_UNIXTIME(1570881546)'
},
],
details () {
// 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div>The unix_timestamp is an internal timestamp value representing seconds since '1970-01-01 00:00:00' UTC.</div>
return <div>The unix_timestamp is an internal timestamp value representing seconds since '1970-01-01 00:00:00'
UTC.</div>
}
},
{
name: "DATE_FORMAT",
syntax: "DATE_FORMAT(date, format)",
name: 'DATE_FORMAT',
syntax: 'DATE_FORMAT(date, format)',
description: `Formats the date value according to the format string.`,
example: [
{
purpose: `Specify a Unix Timestamp "1570881546", calculate the datetime string with format "%Y-%m-%d %H:%i:%s":`,
code: "DATE_FORMAT(FROM_UNIXTIME(1570881546), '%Y-%m-%d %H:%i:%s')"
code: 'DATE_FORMAT(FROM_UNIXTIME(1570881546), \'%Y-%m-%d %H:%i:%s\')'
}
],
details () {
@@ -225,21 +232,21 @@ var renderData = [
}
},
{
name: "CONVERT_TZ",
name: 'CONVERT_TZ',
syntax: `CONVERT_TZ(dt, from_tz, to_tz)`,
description: `Converts a datetime value dt from the time zone given by from_tz to the time zone given by to_tz and returns the resulting value.`,
example: [
{
purpose: `Specify a datetime string "2021-11-11 00:00:00", converted from GMT(Greenwich Mean Time) to Asia/Shanghai time zone:`,
code: "CONVERT_TZ('2021-11-11 00:00:00','GMT','Asia/Shanghai')"
code: 'CONVERT_TZ(\'2021-11-11 00:00:00\',\'GMT\',\'Asia/Shanghai\')'
},
{
purpose: `Specify a Unix timestamp "1636588800", converted from GMT(Greenwich Mean Time) to Asia/Shanghai time zone:`,
code: "CONVERT_TZ(FROM_UNIXTIME(1636588800),'GMT','Asia/Shanghai')"
code: 'CONVERT_TZ(FROM_UNIXTIME(1636588800),\'GMT\',\'Asia/Shanghai\')'
},
{
purpose: `Specify a Unix timestamp "1636588800", converted from Europe/London to America/New_York time zone:`,
code: "CONVERT_TZ(DATE_FORMAT(FROM_UNIXTIME(1636588800), '%Y-%m-%d %H:%i:%s'),'Europe/London','America/New_York')"
code: 'CONVERT_TZ(DATE_FORMAT(FROM_UNIXTIME(1636588800), \'%Y-%m-%d %H:%i:%s\'),\'Europe/London\',\'America/New_York\')'
},
],
details () {
@@ -255,28 +262,29 @@ var renderData = [
}
},
{
name: "MEDIAN",
name: 'MEDIAN',
syntax: `MEDIAN(<expr>)`,
description: `Aggregate function is used to calculate median value. expr must be Integer, Float or Decimal.`,
example: [
{
purpose: `Calculates the median "TCP Handshake Latency (tcp_handshake_latency_ms)" field:`,
code: "MEDIAN(tcp_handshake_latency_ms)"
code: 'MEDIAN(tcp_handshake_latency_ms)'
}
],
details () {
// 支持jsx 嵌套写法,万一测试要关键字加重呢
return <div>In Traffic logs analysis, the function can be useful in calculating the median of certain numbers, e.g. median SSL Handshake Latency or TCP Handshake Latency.</div>
return <div>In Traffic logs analysis, the function can be useful in calculating the median of certain numbers,
e.g. median SSL Handshake Latency or TCP Handshake Latency.</div>
}
},
{
name: "QUANTILE",
name: 'QUANTILE',
syntax: `QUANTILE(<expr>[, <level>])`,
description: `Aggregate function is used to calculate an approximate quantile of a numeric data sequence.`,
example: [
{
purpose: `Calculates the 90th percentile "TCP Handshake Latency (tcp_handshake_latency_ms)" field:`,
code: "QUANTILE(tcp_handshake_latency_ms, 0.9)"
code: 'QUANTILE(tcp_handshake_latency_ms, 0.9)'
}
],
details () {
@@ -285,12 +293,15 @@ var renderData = [
<p>The QUANTILE function accepts a two-parameter:</p>
<ul>
<li>expr - The column values resulting in integer, Flot or Decimal.</li>
<li>level - Level of quantile. Optional parameter. Constant floating-point number from 0 to 1. We recommend using a level value in the range of [0.01, 0.99]. Default value is 0.5. At level=0.5 the function calculates MEDIAN.</li>
<li>level - Level of quantile. Optional parameter. Constant floating-point number from 0 to 1. We recommend
using a level value in the range of [0.01, 0.99]. Default value is 0.5. At level=0.5 the function calculates
MEDIAN.
</li>
</ul>
</div>
}
},
];
]
function main () {
var functionTips = {}
@@ -299,9 +310,9 @@ function main() {
functionTips[item.name] = {
name: item.name,
syntax: item.syntax,
type: "Function",
type: 'Function',
description () {
return (<div className='function-tips'>
return (<div className="function-tips">
<h2>{data.name}</h2>
<h3>Syntax:<span>{data.syntax}</span></h3>
<h3> Description: </h3>
@@ -320,10 +331,11 @@ function main() {
<renderer renderFun={data.details}></renderer> : <p>{data.details} </p>}
</div>)
}
};
}
})
return functionTips
}
export const functionList = renderData
var functionTips = main();
var functionTips = main()
export default functionTips

View File

@@ -1,274 +1,111 @@
var renderData=[
import i18n from '@/i18n'
import { EN, storageKey, ZH } from '@/utils/constants'
const renderData = [
{
name:"EQUALS",
syntax:"=",
primaryKey:"=",
description:"Search for logs where the value of a specified field exactly matches a specified value.",
name: 'EQUALS',
syntax: '=',
primaryKey: '=',
zhDescription: '搜索指定字段的值与指定值完全匹配的实体。',
enDescription: 'Search for entities where the value of a specified field exactly matches a specified value.',
example: [
{
purpose:"Search all logs that are sent by 192.168.10.53:",
code:"client_ip='192.168.10.53'"
zhPurpose: '通过192.168.10.53查询ip实体:',
enPurpose: 'Search entity of ip by 192.168.10.53:',
code: 'ip=\'192.168.10.53\''
},
{
purpose:"Search all logs that are communication destination port by 443",
code:"server_port=443"
},
],
details(){
//支持jsx 嵌套写法,万一测试要关键字加重呢
return <div>If you want search for logs where the value of a specified field is one of multiple specified values. Use multiple <b>EQUALS(=)</b> statements with the OR keyword, or use IN operator.</div>
zhPurpose: '通过google.com查询domain实体',
enPurpose: 'Search entity of domain by google.com',
code: 'domain=\'google.com\''
}
]
},
{
name:"NOT EQUALS",
syntax:"!=",
primaryKey:"!=",
description:"Search for logs where the value of a specified field doesn't match a specified value.",
name: 'IN',
syntax: 'in',
primaryKey: 'IN',
zhDescription: '搜索指定字段的值是多个指定值之一的实体。',
enDescription: 'Search for entities where the value of a specified field is one of multiple specified values.',
example: [
{
purpose:"Search all logs that are sent to any Client IP except 192.168.10.53:",
code:"client_ip!='192.168.10.53'"
zhPurpose: '通过192.168.10.53 或 192.168.10.54查询ip实体',
enPurpose: 'Search entity by 192.168.10.53 or 192.168.10.54',
code: 'ip in (\'192.168.10.53\', \'192.168.10.54\')'
},
{
purpose:"Search all logs that are not communication port to 443",
code:"server_port!=443"
},
],
details:`If you want search for logs where the value of a specified field is one of multiple specified values. Use multiple NOT EQUALS(!=) statements with the AND keyword, or use NOT IN operator.`
},
{
name:"GREATER THAN",
syntax:">",
primaryKey:">",
description:"Search logs greater than a value . This operator can't be used with string fields. ",
example:[
{
purpose:"Search all logs more than 751 Bytes ",
code:"sent_bytes > 751"
},
{
purpose:"Search all logs where bandwidth is higher than 751 Bytes:",
code:"received_bytes + sent_bytes > 751"
},
],
details:`The GREATER THAN(>) condition is usally used with LESS THAN(<) as a range query. `
},
{
name:"GREATER THAN EQUALS",
syntax:">=",
primaryKey:">=",
description:"Search logs greater than and equal a value. This operator can't be used with string fields. ",
example:[
{
purpose:"Search all logs with 751 or more Bytes",
code:"sent_bytes >= 751"
},
{
purpose:"Search all logs where bandwidth is equal or higher than 751 Bytes:",
code:"received_bytes + sent_bytes >= 751"
},
],
details:`The GREATER THAN EQUALS(>=) condition is usally used with LESS THAN EQUALS(<=) as a range query.`
},
{
name:"LESS THAN",
syntax:"<",
primaryKey:"<",
description:"Search logs less than a value. This operator can't be used with string fields.",
example:[
{
purpose:"Search all logs less than 751 Bytes :",
code:"sent_bytes < 751"
},
{
purpose:"Search all logs where bandwidth is less than 751 Bytes:",
code:"received_bytes + sent_bytes < 751"
},
],
details:`The LESS THAN(<) condition is usally used with GREATER THAN(>) as a range query.`
},
{
name:"LESS THAN EQUALS",
syntax:"<=",
primaryKey:"<=",
description:"Search logs less than and equal a value. This operator can't be used with string fields. ",
example:[
{
purpose:"Search all logs with 751 or fewer Bytes",
code:"sent_bytes <= 751"
},
{
purpose:"Search all logs where bandwidth is equal or fewer than 751 Bytes:",
code:"received_bytes + sent_bytes <= 751"
},
],
details:`LESS THAN EQUALS(<=) condition is usally used with GREATER THAN EQUALS(>=) as a range query. `
},
{
name:"IN",
syntax:"in",
primaryKey:"IN",
description:"Search for logs where the value of a specified field is one of multiple specified values.",
example:[
{
purpose:"Search all logs in communication destination port 443 or 80",
code:"server_port in (443, 80)"
},
{
purpose:"Search all logs where the Server IP or Client IP is either 8.8.8.8 or 192.168.10.53:",
code:"client_ip in ('8.8.8.8', '192.168.50.53') or server_ip in ('8.8.8.8', '192.168.10.53')"
},
],
details:`The IN condition you can use when you need to use multiple OR condition. The values are specified as a comma-separated(,) list,surrouded by parentheses. Using IN is equivalent to using multiple EQUALS(=)statements with OR expression. That is server_port in (443,80) is the same as (server_port=443 OR server_port=80).`
},
{
name:"NOT IN",
syntax:"not in",
primaryKey:"NOT IN",
description:"Search for logs where the value of a specified field isn't one of multiple specified values.",
example:[
{
purpose:"Search all logs not in communication destination port 443 or 80",
code:"server_port not in (443, 80)"
},
{
purpose:"Search all logs where the Server IP and Client IP isn't 8.8.8.8 or 192.168.10.53:",
code:"client_ip not in ('8.8.8.8', '192.168.10.53') and server_ip not in ('8.8.8.8', '192.168.10.53')"
},
],
details:`The NOT IN condition you can use when you need to use multiple OR condition. The values are specified as a comma-separated(,) list,surrouded by parentheses. Using NOT IN is equivalent to using multiple NOT EQUALS(!=)statements with AND expression. That is , server_port not in (443,80) is the same as (server_port !=443 AND server_port !=80).`
},
{
name:"LIKE",
syntax:"like",
primaryKey:"LIKE",
description:"Search for logs where use wildcard searches for value that contain search fields. This operator can be used with string fields. ",
example:[
{
purpose:`Search all logs where the SSL SNI end with( suffix match) "google.com":`,
code:"ssl_sni like '%google.com'"
},
{
purpose:"Search all logs where the Client IP start with(prefix match) '192.168':",
code:"client_ip like '192.168%'"
},
{
purpose:`Search all logs where the Client IP contains "192.168.1" , between 192.168.10.10 and 192.168.10.19`,
code:"client_ip like '192.168.10.1_'"
},
],
details:`The LIKE condition supports single and multiple character searches.Using percent (%) wildcard substitutes for one or more characters in a string. Using underscore (_) wildcard substitutes for exactly one character in a string. This operator can be used for searval purposes : checking a substring , checking the start or end of a string.`
},
{
name:"NOT LIKE",
syntax:"not like",
primaryKey:"NOT LIKE",
description:"Search for logs where use wildcard searches for value that not contain search fields. This operator can be used with string fields.",
example:[
{
purpose:`Search all logs where the SSL SNI not contain end with( suffix match) "google.com":`,
code:"ssl_sni not like '%google.com'"
},
{
purpose:"Search all logs where the Client IP not contain start with(prefix match) '192.168':",
code:"client_ip not like '192.168%'"
},
{
purpose:`Search all logs where the Client IP not contains "192.168.1" , between 192.168.10.10 and 192.168.10.19`,
code:"client_ip not like '192.168.10.1_'"
},
],
details:`The NOT LIKE condition supports single and multiple character searches. Using percent (%) wildcard substitutes for one or more characters in a string. Using underscore (_) wildcard substitutes for exactly one character in a string. This operator can be used for searval purposes : checking a substring , checking the start or end of a string.`
},
{
name:"HAS",
syntax:"has",
primaryKey:"HAS",
description:"Search for logs where the values of a specified field is one of specified value.This operator can be used with array fields.",
example:[
{
purpose:`Search all logs where the FQDN Category has the music(60):`,
code:"has(service_category,60)"
zhPurpose: '通过appName1 或 appName2查询app实体:',
enPurpose: 'Search entity by appName1 or appName2:',
code: 'app in (\'appName1\', \'appName2\')'
}
],
details:`The HAS condition checks whether the "expr" array has the "value" element. The syntax has(expr, value).`
]
},
{
name:"EMPTY",
syntax:"empty",
primaryKey:"EMPTY",
description:"Search for logs where the specified field has empty value. This operator can be used with string and array fields.",
name: 'LIKE',
syntax: 'like',
primaryKey: 'LIKE',
zhDescription: '搜索使用通配符搜索包含搜索字段的值的实体。此运算符与字符串字段一起使用。',
enDescription: 'Search for entities where use wildcard searches for value that contain search fields. This operator is used with array fields.',
example: [
{
purpose:`Search all logs where Application is not identified.`,
code:"empty(common_app_label)"
}
],
details:`An empty string is a string of zero length. However , a NULL has no value at all. An empty string is useful when the data comes from multiple resources. NULL is used when some fields are optional, and the data is unknown.`
zhPurpose: '通过google.com查询domain实体:',
enPurpose: 'Search entity of domain by google.com:',
code: 'domain like \'%google.com\''
},
{
name:"NOT EMPTY",
syntax:"notEmpty",
primaryKey:"NOTEMPTY",
description:"Search for logs where the specified field has a value. This operator can be used with string and array fields.",
zhPurpose: '通过appName查询app实体:',
enPurpose: 'Search entity of app by appName:',
code: 'app like \'%appName%\''
}
]
},
{
name: 'HAS',
syntax: 'has',
primaryKey: 'HAS',
zhDescription: '搜索指定字段的值是指定值之一的实体。此运算符与数组字段一起使用。',
enDescription: 'Search for entities where the values of a specified field is one of specified value. This operator is used with array fields.',
example: [
{
purpose:`Search all logs that have one or more SNIs.`,
code:"notEmpty(ssl_sni)"
zhPurpose: '通过ADNS查询tag实体:',
enPurpose: 'Search entity of tag by ADNS:',
code: 'has(tag,\'ADNS\')'
}
],
details:`A not empty string is considered at least one byte, even if this a space.`
},
{
name:"Bitwise AND",
syntax:"bitAnd",
primaryKey:"BITAND",
description:`A bitwise And(&) is a binary operation that compares each bit of the first operand to the corresponding bit of the second operand. Both expressions must have integral types.`,
example:[
{
purpose:`Search all logs where the Flags has the Asymmetric(524288) and Download(134217728):`,
code:"bitAnd(Flags, 134742016) = 134742016"
},
{
purpose:`Search all logs where the flags has either Asymmetric(524288) or Download(134217728):`,
code:"bitAnd(Flags, 134742016)>0"
]
}
],
details:`The operands are converted to 64-bit integers and expressed by a series of bits (zeroes and ones). Sets each bit to 1 if both bits are 1.`
},
]
export const operatorList = renderData
function main () {
var operatorTips={}
const operatorTips = {}
const language = localStorage.getItem(storageKey.language) || EN
renderData.forEach((item, index) => {
var data=item // 这是个闭包
const data = item // 这是个闭包
operatorTips[item.primaryKey] = {
name: item.name,
syntax: item.syntax,
type: "Operators",
type: 'Operators',
description () {
return (<div className='operator-tips'>
<h2>{data.name}</h2>
<h3>Syntax:<span>{data.syntax}</span></h3>
<h3> Description: </h3>
<p> {data.description}</p>
<h3>Examples:</h3>
<ul>
return (<div className="operator-tips">
<div class='default-tips-header'>{data.name}</div>
<div class='default-tips-title'>{i18n.global.t('overall.syntax')}: <span>{data.syntax}</span></div>
<div class='default-tips-title'>{i18n.global.t('overall.remark')}: </div>
<p class='show-hint-tips__p'> {language === ZH ? data.zhDescription : data.enDescription}</p>
<div class='default-tips-title'>{i18n.global.t('overall.examples')}: </div>
<ul style="padding-left: 0;">
{item.example.map(v => {
return <li>
<span>{v.purpose}</span>
<span>{language === ZH ? v.zhPurpose : v.enPurpose}</span>
<code>{v.code}</code>
</li>
})}
</ul>
<h3> Details: </h3>
{Object.prototype.toString.call(data.details) === '[object Function]' ? <renderer renderFun={data.details}></renderer> : <p>{data.details} </p>}
</div>)
}
};
}
})
return operatorTips
}
var operatorTips=main();
const operatorTips = main()
export default operatorTips

View File

@@ -1,13 +1,13 @@
var renderData = [
{
name: "FROM",
name: 'FROM',
syntax: `FROM [db.]table |$log_type`,
description: {
title: `The table name of logs. If you type $log_type, the variable value is the current table name of logs.`
}
},
{
name: "SELECT",
name: 'SELECT',
syntax: `Optional. The selected columns(also known as dimensions and metrics).`,
description: {
title: '可选,获取列',
@@ -18,7 +18,7 @@ var renderData=[
}
},
{
name: "GROUP BY",
name: 'GROUP BY',
syntax: `GROUP BY <field-list>`,
description: {
title: 'Aggregate data. GROUP BY clause switches the SELECT query into an aggregation mode',
@@ -30,7 +30,7 @@ var renderData=[
}
},
{
name: "HAVING",
name: 'HAVING',
syntax: `HAVING <expression-list>`,
description: {
title: `Optional. HAVING clause filtering the aggregation results retrieved by GROUP BY. It is difference is that WHERE is performed before aggregation, while HAVING is performed after it.
@@ -38,21 +38,21 @@ var renderData=[
}
},
{
name: "LIMIT",
name: 'LIMIT',
syntax: `LIMIT [n, ]m`,
description: {
title: `Select the m rows from the aggregate results after skipping the first n rows. Default is 10 rows.`
}
},
{
name: "ORDER BY",
name: 'ORDER BY',
syntax: `ORDER BY <sort-field> [ASC|DESC]`,
description: {
title: `Sort all of the results by the specified fields.`
}
},
{
name: "WHERE",
name: 'WHERE',
syntax: `where $filter [and <expression-list>]`,
description: {
title: `Filter the data.`,
@@ -64,6 +64,7 @@ var renderData=[
}
]
export const sqlList = renderData
function main () {
var sqlTips = {}
renderData.forEach((item, index) => {
@@ -71,9 +72,9 @@ function main(){
sqlTips[item.name] = {
name: item.name,
syntax: item.syntax,
type: "sql",
type: 'sql',
description () {
return (<div className='sql-tips'>
return (<div className="sql-tips">
<h2>{data.name}</h2>
<h3>Syntax: <span>{data.syntax}</span></h3>
<h3> Description: </h3>
@@ -87,10 +88,10 @@ function main(){
}
</div>)
}
};
}
})
return sqlTips
}
var sqlTips=main();
var sqlTips = main()
export default sqlTips

View File

@@ -18,8 +18,8 @@ var renderData = [
$filter: The default filter clauses. such as time period, Vsys ID, and other default expressions, etc.
</div>
}
},
];
}
]
function main () {
const varTips = {}
@@ -29,7 +29,7 @@ function main() {
name: item.name,
type: 'Variables',
description () {
return (<div className='var-tips'>
return (<div className="var-tips">
<h2>{data.name}</h2>
<h3> Description: </h3>
<p> {data.description}</p>
@@ -38,7 +38,7 @@ function main() {
<renderer renderFun={data.details}></renderer> : <p>{data.details} </p>}
</div>)
}
};
}
})
return varTips
}

View File

@@ -1,5 +1,6 @@
// 改js 用户获取初始化的 SchemaData
import { Scheme } from './service/Scheme'
import i18n from '@/i18n'
export class Dataset {
constructor ({ operatesList, filtersList, operatesDic, funcDic, operatorManual, fields, doc }) {
@@ -66,7 +67,7 @@ export class Dataset {
type: 'abstract',
text: '',
// displayText: "Filter",
displayText: 'filter',
displayText: i18n.global.t('overall.fields'),
className: 'divider hint-title',
hint (cm, callback, options) {
}
@@ -96,7 +97,7 @@ export class Dataset {
type: 'abstract',
text: '',
// displayText: "Operator",
displayText: 'operator',
displayText: i18n.global.t('overall.keyword'),
className: 'divider hint-title'
// hint(cm, callback, options) {}
}

View File

@@ -6,7 +6,7 @@
<i class="cn-icon cn-icon-arrow-right"></i>
</span>
</div>
<div class="cn-entity__case">
<div class="cn-entity__case" ref="rowBlock">
<div class="cn-entity__icon"><i :class="iconClass"></i></div>
<div class="cn-entity__row">
<!--标签-->
@@ -327,6 +327,12 @@ export default {
/* 切换折叠状态 */
switchCollapse () {
this.isCollapse = !this.isCollapse
// 因为默认的背景白色会导致showhint的box-shadow被盖住所以展开详情时才渲染颜色
if (this.isCollapse) {
this.$refs.rowBlock.style.cssText = 'background-color: none'
} else {
this.$refs.rowBlock.style.cssText = 'background-color: #fff'
}
this.$emit('switchCollapse', this.isCollapse, this.index)
},
/* 设为折叠状态 */