mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 01:06:59 +08:00
feat(系统变量): 支持 key-value #1310
This commit is contained in:
@@ -23,6 +23,8 @@
|
||||
"variable_name": "Variable Name",
|
||||
"variable_type": "Variable Type",
|
||||
"variable_value": "Variable Value",
|
||||
"variable_key": "Variable Key",
|
||||
"kv": "Key-Value",
|
||||
"edit_variable": "Edit Variable",
|
||||
"no_variables_yet": "No Variables Yet",
|
||||
"please_enter_value": "Please Enter Value",
|
||||
@@ -30,7 +32,10 @@
|
||||
"start_date": "Start Date",
|
||||
"end_date": "End Date",
|
||||
"enter_variable_name": "Please Enter Variable Name",
|
||||
"enter_variable_value": "Please Enter Variable Value"
|
||||
"enter_variable_value": "Please Enter Variable Value",
|
||||
"enter_variable_key": "Please Enter Variable Key",
|
||||
"key_value_cannot_be_empty": "Key and value cannot be empty.",
|
||||
"key_repeat": "Keys cannot be duplicated."
|
||||
},
|
||||
"authorized_space": {
|
||||
"authorized_space": "Authorized Space",
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
"variable_name": "변수 이름",
|
||||
"variable_type": "변수 유형",
|
||||
"variable_value": "변수 값",
|
||||
"variable_key": "변수 키",
|
||||
"kv": "키-값",
|
||||
"edit_variable": "변수 편집",
|
||||
"no_variables_yet": "아직 변수가 없습니다",
|
||||
"please_enter_value": "값을 입력하세요",
|
||||
@@ -30,7 +32,10 @@
|
||||
"start_date": "시작일",
|
||||
"end_date": "종료일",
|
||||
"enter_variable_name": "변수 이름을 입력하세요",
|
||||
"enter_variable_value": "변수 값을 입력하세요"
|
||||
"enter_variable_value": "변수 값을 입력하세요",
|
||||
"enter_variable_key": "변수 키를 입력하세요",
|
||||
"key_value_cannot_be_empty": "키와 값은 비워둘 수 없습니다.",
|
||||
"key_repeat": "키는 중복될 수 없습니다."
|
||||
},
|
||||
"authorized_space": {
|
||||
"authorized_space": "권한 있는 공간",
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
"variable_name": "变量名称",
|
||||
"variable_type": "变量类型",
|
||||
"variable_value": "变量值",
|
||||
"variable_key": "变量键",
|
||||
"kv": "键值",
|
||||
"edit_variable": "编辑变量",
|
||||
"no_variables_yet": "暂无变量",
|
||||
"please_enter_value": "请输入数值",
|
||||
@@ -30,7 +32,10 @@
|
||||
"start_date": "开始日期",
|
||||
"end_date": "结束日期",
|
||||
"enter_variable_name": "请输入变量名称",
|
||||
"enter_variable_value": "请输入变量值"
|
||||
"enter_variable_value": "请输入变量值",
|
||||
"enter_variable_key": "请输入变量键",
|
||||
"key_value_cannot_be_empty": "键和值不能为空",
|
||||
"key_repeat": "键不能重复"
|
||||
},
|
||||
"authorized_space": {
|
||||
"authorized_space": "授权空间",
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
"variable_name": "變數名稱",
|
||||
"variable_type": "變數類型",
|
||||
"variable_value": "變數值",
|
||||
"variable_key": "變數鍵",
|
||||
"kv": "鍵值",
|
||||
"edit_variable": "編輯變數",
|
||||
"no_variables_yet": "暫無變數",
|
||||
"please_enter_value": "請輸入數值",
|
||||
@@ -30,7 +32,10 @@
|
||||
"start_date": "開始日期",
|
||||
"end_date": "結束日期",
|
||||
"enter_variable_name": "請輸入變數名稱",
|
||||
"enter_variable_value": "請輸入變數值"
|
||||
"enter_variable_value": "請輸入變數值",
|
||||
"enter_variable_key": "請輸入變數鍵",
|
||||
"key_value_cannot_be_empty": "鍵和值不能為空",
|
||||
"key_repeat": "鍵不能重複"
|
||||
},
|
||||
"authorized_space": {
|
||||
"authorized_space": "授權空間",
|
||||
|
||||
@@ -441,6 +441,9 @@ strong {
|
||||
.string-variables.string-variables {
|
||||
color: #3370ff;
|
||||
}
|
||||
.kv-variables.kv-variables {
|
||||
color: #3370ff;
|
||||
}
|
||||
.number-variables.number-variables,
|
||||
.int-variables.int-variables,
|
||||
.float-variables.float-variables {
|
||||
|
||||
@@ -124,6 +124,7 @@ const initEnumOptions = () => {
|
||||
|
||||
const iconMap = {
|
||||
text: field_text,
|
||||
kv: field_text,
|
||||
number: field_value,
|
||||
datetime: field_time,
|
||||
}
|
||||
|
||||
@@ -438,6 +438,23 @@
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-select
|
||||
v-else-if="
|
||||
variableValueMap[state.form.system_variables[index].variableId].var_type === 'kv'
|
||||
"
|
||||
v-model="state.form.system_variables[index].variableValues"
|
||||
multiple
|
||||
style="width: 236px"
|
||||
:placeholder="$t('datasource.Please_select')"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in getVariableOptionList(state.form.system_variables[index].variableId)"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.label"
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-input-number
|
||||
v-else-if="
|
||||
variableValueMap[state.form.system_variables[index].variableId].var_type ===
|
||||
@@ -587,6 +604,7 @@ const selectionLoading = ref(false)
|
||||
|
||||
const iconMap = {
|
||||
text: field_text,
|
||||
kv: field_text,
|
||||
number: field_value,
|
||||
datetime: field_time,
|
||||
}
|
||||
@@ -643,6 +661,56 @@ const defaultForm = {
|
||||
const options = ref<any[]>([])
|
||||
const variables = shallowRef<any[]>([])
|
||||
const variableValueMap = shallowRef<any>({})
|
||||
|
||||
const getVariableDefinition = (variableId: string) => variableValueMap.value[variableId]
|
||||
|
||||
const getVariableOptionList = (variableId: string) => {
|
||||
const variable = getVariableDefinition(variableId)
|
||||
if (!variable) return []
|
||||
|
||||
if (variable.var_type === 'text') {
|
||||
return variable.value.map((item: string) => ({
|
||||
label: item,
|
||||
value: item,
|
||||
}))
|
||||
}
|
||||
|
||||
if (variable.var_type === 'kv') {
|
||||
return variable.value.map((item: any) => ({
|
||||
label: item.key,
|
||||
value: item.key,
|
||||
actualValue: item.value,
|
||||
}))
|
||||
}
|
||||
|
||||
return []
|
||||
}
|
||||
|
||||
const getSelectedKeysFromStoredValues = (variableId: string, storedValues: any[] = []) => {
|
||||
const variable = getVariableDefinition(variableId)
|
||||
if (!variable || variable.var_type !== 'kv') return storedValues
|
||||
|
||||
return storedValues
|
||||
.map((storedValue: any) => {
|
||||
const matched = variable.value.find(
|
||||
(item: any) => item.key === storedValue || item.value === storedValue
|
||||
)
|
||||
return matched?.key
|
||||
})
|
||||
.filter(Boolean)
|
||||
}
|
||||
|
||||
const getStoredValuesFromSelectedKeys = (variableId: string, selectedKeys: any[] = []) => {
|
||||
const variable = getVariableDefinition(variableId)
|
||||
if (!variable || variable.var_type !== 'kv') return selectedKeys
|
||||
|
||||
return selectedKeys
|
||||
.map((selectedKey: any) => {
|
||||
const matched = variable.value.find((item: any) => item.key === selectedKey)
|
||||
return matched?.value
|
||||
})
|
||||
.filter((item: any) => item !== undefined && item !== null && item !== '')
|
||||
}
|
||||
const state = reactive<any>({
|
||||
tableData: [],
|
||||
filterTexts: [],
|
||||
@@ -653,7 +721,7 @@ const state = reactive<any>({
|
||||
pageSize: 20,
|
||||
total: 0,
|
||||
sortColumn: '',
|
||||
sortOrder: '', // 'ascending' | 'descending' | ''
|
||||
sortOrder: '', // 'ascending' | 'descending' | ''
|
||||
},
|
||||
})
|
||||
|
||||
@@ -908,20 +976,26 @@ const editHandler = (row: any) => {
|
||||
...row,
|
||||
system_variables: (row.system_variables || []).map((ele: any) => ({
|
||||
...ele,
|
||||
variableValue: ele.variableValues[0],
|
||||
variableValue: ele.variableValues?.[0],
|
||||
variableValues: Array.isArray(ele.variableValues) ? [...ele.variableValues] : [],
|
||||
})),
|
||||
}
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
state.form.system_variables = state.form.system_variables.filter((ele: any) => {
|
||||
if (variableValueMap.value[ele.variableId]) {
|
||||
if (variableValueMap.value[ele.variableId].var_type === 'text') {
|
||||
ele.variableValues = variableValueMap.value[ele.variableId].value.filter(
|
||||
const variable = variableValueMap.value[ele.variableId]
|
||||
if (variable) {
|
||||
if (variable.var_type === 'text') {
|
||||
ele.variableValues = variable.value.filter(
|
||||
(item: any) => ele.variableValues.indexOf(item) > -1
|
||||
)
|
||||
return !!ele.variableValues.length
|
||||
}
|
||||
if (variable.var_type === 'kv') {
|
||||
ele.variableValues = getSelectedKeysFromStoredValues(ele.variableId, ele.variableValues)
|
||||
return !!ele.variableValues.length
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -1036,9 +1110,19 @@ const formatVariableValues = () => {
|
||||
if (!state.form.system_variables?.length) return []
|
||||
return state.form.system_variables.map((ele: any) => ({
|
||||
variableId: ele.variableId,
|
||||
variableValues: ['number', 'datetime'].includes(variableValueMap.value[ele.variableId].var_type)
|
||||
? [ele.variableValue]
|
||||
: ele.variableValues,
|
||||
variableValues: (() => {
|
||||
const variable = variableValueMap.value[ele.variableId]
|
||||
if (!variable) {
|
||||
return ele.variableValues
|
||||
}
|
||||
if (['number', 'datetime'].includes(variable.var_type)) {
|
||||
return [ele.variableValue]
|
||||
}
|
||||
if (variable.var_type === 'kv') {
|
||||
return getStoredValuesFromSelectedKeys(ele.variableId, ele.variableValues)
|
||||
}
|
||||
return ele.variableValues
|
||||
})(),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -1097,11 +1181,26 @@ const validateSystemVariables = () => {
|
||||
if (system_variables?.length) {
|
||||
return system_variables.some((ele: any) => {
|
||||
const obj = variableValueMap.value[ele.variableId]
|
||||
if (!obj) {
|
||||
return false
|
||||
}
|
||||
if (obj.var_type === 'text' && !ele.variableValues.length) {
|
||||
ElMessage.error(t('variables.cannot_be_empty'))
|
||||
return true
|
||||
}
|
||||
|
||||
if (obj.var_type === 'kv') {
|
||||
if (!ele.variableValues.length) {
|
||||
ElMessage.error(t('variables.key_value_cannot_be_empty'))
|
||||
return true
|
||||
}
|
||||
|
||||
if (new Set(ele.variableValues).size !== ele.variableValues.length) {
|
||||
ElMessage.error(t('variables.key_repeat'))
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if (obj.var_type === 'number' && [null, undefined, ''].includes(ele.variableValue)) {
|
||||
ElMessage.error(t('variables.cannot_be_empty'))
|
||||
return true
|
||||
|
||||
@@ -26,6 +26,7 @@ const oldKeywords = ref('')
|
||||
const searchLoading = ref(false)
|
||||
const iconMap = {
|
||||
text: field_text,
|
||||
kv: field_text,
|
||||
number: field_value,
|
||||
datetime: field_time,
|
||||
}
|
||||
@@ -49,6 +50,7 @@ const pageInfo = reactive({
|
||||
|
||||
const var_type = {
|
||||
text: 'model.text',
|
||||
kv: 'variables.kv',
|
||||
number: 'model.number',
|
||||
datetime: 'variables.date',
|
||||
} as Record<string, unknown>
|
||||
@@ -62,6 +64,47 @@ const defaultForm = {
|
||||
}
|
||||
const pageForm = ref<Form>(cloneDeep(defaultForm))
|
||||
|
||||
const createKvValueItem = () => ({
|
||||
key: '',
|
||||
value: '',
|
||||
})
|
||||
|
||||
const formatVariableDisplayValue = (row: any) => {
|
||||
if (row.type === 'system') {
|
||||
return t('variables.built_in')
|
||||
}
|
||||
|
||||
if (row.var_type === 'text') {
|
||||
return Array.isArray(row.value) ? row.value.join(', ') : (row.value ?? '')
|
||||
}
|
||||
|
||||
if (row.var_type === 'kv') {
|
||||
return Array.isArray(row.value)
|
||||
? row.value.map((item: any) => `${item.key}: ${item.value}`).join(', ')
|
||||
: ''
|
||||
}
|
||||
|
||||
if (Array.isArray(row.value)) {
|
||||
return row.value.join(' ~ ')
|
||||
}
|
||||
|
||||
return row.value ?? ''
|
||||
}
|
||||
|
||||
const normalizeKvValue = (value: any[] = []) => {
|
||||
return value.map((item: any) => ({
|
||||
key: `${item?.key ?? ''}`.trim(),
|
||||
value: `${item?.value ?? ''}`.trim(),
|
||||
}))
|
||||
}
|
||||
|
||||
const getVariableTypeOptions = () => [
|
||||
{ value: 'text', label: t('model.text') },
|
||||
{ value: 'kv', label: t('variables.kv') },
|
||||
{ value: 'number', label: t('model.number') },
|
||||
{ value: 'datetime', label: t('variables.date') },
|
||||
]
|
||||
|
||||
const cancelDelete = () => {
|
||||
handleToggleRowSelection(false)
|
||||
multipleSelectionAll.value = []
|
||||
@@ -157,7 +200,8 @@ const search = ($event: any = {}) => {
|
||||
toggleRowLoading.value = true
|
||||
fieldList.value = res.items.map((ele: any) => ({
|
||||
...ele,
|
||||
value: ele.type === 'system' ? t('variables.built_in') : ele.value,
|
||||
displayValue: formatVariableDisplayValue(ele),
|
||||
rawValue: ele.value,
|
||||
}))
|
||||
pageInfo.total = res.total
|
||||
searchLoading.value = false
|
||||
@@ -189,9 +233,31 @@ const validateValue = (_: any, value: any, callback: any) => {
|
||||
}
|
||||
return
|
||||
}
|
||||
if (var_type === 'kv') {
|
||||
if (!Array.isArray(value) || !value.length) {
|
||||
callback(new Error(t('variables.key_value_cannot_be_empty')))
|
||||
return
|
||||
}
|
||||
|
||||
const normalized = normalizeKvValue(value)
|
||||
if (normalized.some((ele: any) => !ele.key || !ele.value)) {
|
||||
callback(new Error(t('variables.key_value_cannot_be_empty')))
|
||||
return
|
||||
}
|
||||
|
||||
const keyList = normalized.map((ele: any) => ele.key)
|
||||
if (new Set(keyList).size !== keyList.length) {
|
||||
callback(new Error(t('variables.key_repeat')))
|
||||
return
|
||||
}
|
||||
|
||||
callback()
|
||||
return
|
||||
}
|
||||
if (var_type === 'datetime') {
|
||||
if (value === null) {
|
||||
callback(new Error(t('datasource.please_enter') + t('common.empty') + t('variables.date')))
|
||||
return
|
||||
}
|
||||
}
|
||||
if (value.some((ele: any) => ele === '' || ele === null)) {
|
||||
@@ -227,10 +293,38 @@ const varTypeChange = (val: any) => {
|
||||
pageForm.value.value = ['']
|
||||
return
|
||||
}
|
||||
if (val === 'kv') {
|
||||
pageForm.value.value = [createKvValueItem()]
|
||||
return
|
||||
}
|
||||
pageForm.value.value = ['', '']
|
||||
}
|
||||
|
||||
const validateBeforeSave = () => {
|
||||
if (pageForm.value.var_type !== 'kv') {
|
||||
return true
|
||||
}
|
||||
|
||||
const normalized = normalizeKvValue(pageForm.value.value)
|
||||
if (!normalized.length || normalized.some((ele: any) => !ele.key || !ele.value)) {
|
||||
ElMessage.error(t('variables.key_value_cannot_be_empty'))
|
||||
return false
|
||||
}
|
||||
|
||||
const keyList = normalized.map((ele: any) => ele.key)
|
||||
if (new Set(keyList).size !== keyList.length) {
|
||||
ElMessage.error(t('variables.key_repeat'))
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
const saveHandler = () => {
|
||||
if (!validateBeforeSave()) {
|
||||
return
|
||||
}
|
||||
|
||||
termFormRef.value.validate((res: any) => {
|
||||
if (res) {
|
||||
const obj = unref(pageForm)
|
||||
@@ -242,6 +336,10 @@ const saveHandler = () => {
|
||||
obj.value = [...new Set(obj.value)]
|
||||
}
|
||||
|
||||
if (obj.var_type === 'kv') {
|
||||
obj.value = normalizeKvValue(obj.value)
|
||||
}
|
||||
|
||||
if (obj.var_type === 'number') {
|
||||
const [min = 0, max = 0] = obj.value
|
||||
if (min > max) {
|
||||
@@ -273,7 +371,7 @@ const editHandler = (row: any) => {
|
||||
pageForm.value.id = id
|
||||
pageForm.value.name = name
|
||||
pageForm.value.var_type = var_type
|
||||
pageForm.value.value = cloneDeep(value)
|
||||
pageForm.value.value = cloneDeep(row.rawValue ?? value)
|
||||
}
|
||||
dialogTitle.value = row?.id ? t('variables.edit_variable') : t('variables.add_variable')
|
||||
dialogFormVisible.value = true
|
||||
@@ -388,7 +486,11 @@ const handleCurrentChange = (val: number) => {
|
||||
width="420"
|
||||
:label="$t('variables.variable_value')"
|
||||
show-overflow-tooltip
|
||||
/>
|
||||
>
|
||||
<template #default="scope">
|
||||
{{ scope.row.displayValue }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column fixed="right" width="80" :label="t('ds.actions')">
|
||||
<template #default="scope">
|
||||
<div class="field-comment">
|
||||
@@ -509,12 +611,8 @@ const handleCurrentChange = (val: number) => {
|
||||
:disabled="!!pageForm.id"
|
||||
@change="varTypeChange"
|
||||
>
|
||||
<el-radio value="text">{{ $t('model.text') }}</el-radio>
|
||||
<el-radio value="number">
|
||||
{{ $t('model.number') }}
|
||||
</el-radio>
|
||||
<el-radio value="datetime">
|
||||
{{ $t('variables.date') }}
|
||||
<el-radio v-for="ele in getVariableTypeOptions()" :key="ele.value" :value="ele.value">
|
||||
{{ ele.label }}
|
||||
</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
@@ -562,6 +660,50 @@ const handleCurrentChange = (val: number) => {
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item v-else-if="pageForm.var_type === 'kv'" :label="t('variables.variable_value')">
|
||||
<template #label>
|
||||
<div style="display: flex; align-items: center; height: 22px">
|
||||
<span>{{ t('variables.variable_value') }}</span>
|
||||
<span class="btn" @click="pageForm.value.push(createKvValueItem())">
|
||||
<el-icon style="margin-right: 4px" size="16">
|
||||
<icon_add_outlined></icon_add_outlined>
|
||||
</el-icon>
|
||||
{{ $t('model.add') }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<div class="value-list">
|
||||
<div class="item kv-title">
|
||||
<span style="width: calc(48% - 0px)">{{ t('variables.variable_key') }}</span>
|
||||
<span style="width: calc(52% - 5px)">{{ t('variables.variable_value') }}</span>
|
||||
</div>
|
||||
<div v-for="(_, index) in pageForm.value" :key="index" class="item kv-item">
|
||||
<el-input
|
||||
v-model="pageForm.value[index].key"
|
||||
:placeholder="$t('variables.enter_variable_key')"
|
||||
autocomplete="off"
|
||||
maxlength="50"
|
||||
clearable
|
||||
/>
|
||||
<el-input
|
||||
v-model="pageForm.value[index].value"
|
||||
:placeholder="$t('variables.enter_variable_value')"
|
||||
autocomplete="off"
|
||||
maxlength="50"
|
||||
style="margin-left: 16px"
|
||||
clearable
|
||||
/>
|
||||
<el-icon
|
||||
class="action-btn"
|
||||
:class="index === 0 && pageForm.value.length === 1 && 'not-allow'"
|
||||
size="16"
|
||||
@click="deleteValues(index)"
|
||||
>
|
||||
<IconOpeDelete></IconOpeDelete>
|
||||
</el-icon>
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item v-else prop="value" :label="t('variables.variable_value')">
|
||||
<div class="value-number_date">
|
||||
<template v-if="pageForm.var_type === 'number'">
|
||||
@@ -818,6 +960,10 @@ const handleCurrentChange = (val: number) => {
|
||||
color: #bbbfc4;
|
||||
}
|
||||
}
|
||||
|
||||
&.kv-item {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.value-number_date {
|
||||
|
||||
Reference in New Issue
Block a user