mirror of
https://gh-proxy.org/https://github.com/klinsmaya/SQLBot.git
synced 2026-11-08 01:06:59 +08:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
@@ -400,7 +400,9 @@ def updateNum(session: SessionDep, ds: CoreDatasource):
|
||||
|
||||
def get_table_obj_by_ds(session: SessionDep, current_user: CurrentUser, ds: CoreDatasource) -> List[TableAndFields]:
|
||||
_list: List = []
|
||||
tables = session.query(CoreTable).filter(CoreTable.ds_id == ds.id).all()
|
||||
tables = session.query(CoreTable).filter(
|
||||
and_(CoreTable.ds_id == ds.id, CoreTable.checked == True)
|
||||
).all()
|
||||
conf = DatasourceConf(**json.loads(aes_decrypt(ds.configuration))) if ds.type != "excel" else get_engine_config()
|
||||
schema = conf.dbSchema if conf.dbSchema is not None and conf.dbSchema != "" else conf.database
|
||||
|
||||
|
||||
@@ -670,7 +670,7 @@ def check_sql_read(sql: str, ds: CoreDatasource | AssistantOutDsSchema):
|
||||
write_types = (
|
||||
exp.Insert, exp.Update, exp.Delete,
|
||||
exp.Create, exp.Drop, exp.Alter,
|
||||
exp.Merge, exp.Command
|
||||
exp.Merge, exp.Command, exp.Copy
|
||||
)
|
||||
|
||||
for stmt in statements:
|
||||
@@ -688,6 +688,7 @@ def check_sql_read(sql: str, ds: CoreDatasource | AssistantOutDsSchema):
|
||||
def checkParams(extraParams: str, illegalParams: List[str]):
|
||||
kvs = extraParams.split('&')
|
||||
for kv in kvs:
|
||||
k, v = kv.split('=')
|
||||
if k in illegalParams:
|
||||
raise HTTPException(status_code=500, detail=f'Illegal Parameter: {k}')
|
||||
if kv and '=' in kv:
|
||||
k, v = kv.split('=')
|
||||
if k in illegalParams:
|
||||
raise HTTPException(status_code=500, detail=f'Illegal Parameter: {k}')
|
||||
|
||||
@@ -180,7 +180,8 @@ async def create(session: SessionDep, creator: UserCreator, trans: Trans):
|
||||
raise Exception(trans('i18n_exist', msg = f"{trans('i18n_user.email')} [{creator.email}]"))
|
||||
if not check_email_format(creator.email):
|
||||
raise Exception(trans('i18n_format_invalid', key = f"{trans('i18n_user.email')} [{creator.email}]"))
|
||||
data = creator.model_dump(exclude_unset=True)
|
||||
#data = creator.model_dump(exclude_unset=True)
|
||||
data = creator.model_dump()
|
||||
user_model = UserModel.model_validate(data)
|
||||
#user_model.create_time = get_timestamp()
|
||||
user_model.language = "zh-CN"
|
||||
|
||||
@@ -21,6 +21,7 @@ from common.core.sqlbot_cache import cache
|
||||
from common.utils.aes_crypto import simple_aes_decrypt
|
||||
from common.utils.utils import SQLBotLogUtil, equals_ignore_case, get_domain_list, string_to_numeric_hash
|
||||
from common.core.deps import Trans
|
||||
from common.core.response_middleware import ResponseMiddleware
|
||||
|
||||
|
||||
@cache(namespace=CacheNamespace.EMBEDDED_INFO, cacheName=CacheName.ASSISTANT_INFO, keyExpression="assistant_id")
|
||||
@@ -87,13 +88,20 @@ def init_dynamic_cors(app: FastAPI):
|
||||
seen.add(domain)
|
||||
unique_domains.append(domain)
|
||||
cors_middleware = None
|
||||
response_middleware = None
|
||||
for middleware in app.user_middleware:
|
||||
if middleware.cls == CORSMiddleware:
|
||||
if not cors_middleware and middleware.cls == CORSMiddleware:
|
||||
cors_middleware = middleware
|
||||
if not response_middleware and middleware.cls == ResponseMiddleware:
|
||||
response_middleware = middleware
|
||||
if cors_middleware and response_middleware:
|
||||
break
|
||||
|
||||
updated_origins = list(set(settings.all_cors_origins + unique_domains))
|
||||
if cors_middleware:
|
||||
updated_origins = list(set(settings.all_cors_origins + unique_domains))
|
||||
cors_middleware.kwargs['allow_origins'] = updated_origins
|
||||
if response_middleware:
|
||||
response_middleware.kwargs['allow_origins'] = updated_origins
|
||||
except Exception as e:
|
||||
return False, e
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Author: Junjun
|
||||
# Date: 2026/1/26
|
||||
import datetime
|
||||
|
||||
from typing import List
|
||||
|
||||
from fastapi import HTTPException
|
||||
from sqlalchemy import and_
|
||||
from sqlmodel import select
|
||||
@@ -37,11 +37,12 @@ def delete(session: SessionDep, ids: List[int]):
|
||||
|
||||
def list_all(session: SessionDep, trans: Trans, variable: SystemVariable):
|
||||
if variable.name is None:
|
||||
records = session.query(SystemVariable).order_by(SystemVariable.type.desc()).all()
|
||||
records = session.query(SystemVariable).order_by(SystemVariable.type.desc(),
|
||||
SystemVariable.name.asc()).all()
|
||||
else:
|
||||
records = session.query(SystemVariable).filter(
|
||||
and_(SystemVariable.name.like(f'%{variable.name}%'), SystemVariable.type != 'system')).order_by(
|
||||
SystemVariable.type.desc()).all()
|
||||
and_(SystemVariable.name.ilike(f'%{variable.name}%'), SystemVariable.type != 'system')).order_by(
|
||||
SystemVariable.type.desc(), SystemVariable.name.asc()).all()
|
||||
|
||||
res = []
|
||||
for r in records:
|
||||
@@ -58,11 +59,11 @@ async def list_page(session: SessionDep, trans: Trans, pageNum: int, pageSize: i
|
||||
filters = {}
|
||||
|
||||
if variable.name is None:
|
||||
stmt = select(SystemVariable).order_by(SystemVariable.type.desc())
|
||||
stmt = select(SystemVariable).order_by(SystemVariable.type.desc(), SystemVariable.name.asc())
|
||||
else:
|
||||
stmt = select(SystemVariable).where(
|
||||
and_(SystemVariable.name.like(f'%{variable.name}%'), SystemVariable.type != 'system')).order_by(
|
||||
SystemVariable.type.desc())
|
||||
and_(SystemVariable.name.ilike(f'%{variable.name}%'), SystemVariable.type != 'system')).order_by(
|
||||
SystemVariable.type.desc(), SystemVariable.name.asc())
|
||||
|
||||
variable_page = await paginator.get_paginated_response(
|
||||
stmt=stmt,
|
||||
@@ -92,7 +93,7 @@ def checkName(session: SessionDep, trans: Trans, variable: SystemVariable):
|
||||
raise HTTPException(status_code=500, detail=trans('i18n_variable.name_exist'))
|
||||
|
||||
|
||||
def checkValue(session: SessionDep, trans: Trans, values:List):
|
||||
def checkValue(session: SessionDep, trans: Trans, values: List):
|
||||
# values: [{"variableId":1,"variableValues":["a","b"]}]
|
||||
|
||||
pass
|
||||
pass
|
||||
|
||||
@@ -58,7 +58,7 @@ class UserCreator(BaseUser):
|
||||
status: int = Field(default=1, description=f"{PLACEHOLDER_PREFIX}status")
|
||||
origin: Optional[int] = Field(default=0, description=f"{PLACEHOLDER_PREFIX}origin")
|
||||
oid_list: Optional[list[int]] = Field(default=None, description=f"{PLACEHOLDER_PREFIX}oid")
|
||||
system_variables: Optional[List] = Field(default=None)
|
||||
system_variables: Optional[List] = Field(default=[])
|
||||
|
||||
""" @field_validator("email")
|
||||
def validate_email(cls, lang: str) -> str:
|
||||
|
||||
@@ -165,6 +165,7 @@ session_maker = scoped_session(sessionmaker(bind=engine, class_=Session))
|
||||
|
||||
@router.post("/uploadExcel", summary=f"{PLACEHOLDER_PREFIX}upload_term")
|
||||
@system_log(LogConfig(operation_type=OperationType.IMPORT, module=OperationModules.TERMINOLOGY))
|
||||
@require_permissions(permission=SqlbotPermission(role=['ws_admin']))
|
||||
async def upload_excel(trans: Trans, current_user: CurrentUser, file: UploadFile = File(...)):
|
||||
ALLOWED_EXTENSIONS = {"xlsx", "xls"}
|
||||
if not file.filename.lower().endswith(tuple(ALLOWED_EXTENSIONS)):
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import json
|
||||
|
||||
from redis import typing
|
||||
from starlette.exceptions import HTTPException
|
||||
from starlette.middleware.base import BaseHTTPMiddleware
|
||||
from starlette.requests import Request
|
||||
@@ -11,6 +12,7 @@ from common.utils.utils import SQLBotLogUtil
|
||||
|
||||
class ResponseMiddleware(BaseHTTPMiddleware):
|
||||
def __init__(self, app):
|
||||
self.allow_origins = ["'self'"]
|
||||
super().__init__(app)
|
||||
|
||||
async def dispatch(self, request, call_next):
|
||||
@@ -76,7 +78,13 @@ class ResponseMiddleware(BaseHTTPMiddleware):
|
||||
if k.lower() not in ("content-length", "content-type")
|
||||
}
|
||||
)
|
||||
|
||||
content_type = response.headers.get("content-type", "")
|
||||
static_content_types = ["text/html", "javascript", "typescript", "css"]
|
||||
if any(ct in content_type for ct in static_content_types):
|
||||
if self.allow_origins:
|
||||
frame_ancestors_value = " ".join(self.allow_origins)
|
||||
response.headers["Content-Security-Policy"] = f"frame-ancestors {frame_ancestors_value};"
|
||||
|
||||
return response
|
||||
|
||||
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
"eslint-plugin-prettier": "^5.4.1",
|
||||
"eslint-plugin-vue": "^10.2.0",
|
||||
"globals": "^16.2.0",
|
||||
"less": "^4.3.0",
|
||||
"less": "4.4.2",
|
||||
"pinia": "^3.0.2",
|
||||
"prettier": "^3.5.3",
|
||||
"typescript": "~5.7.2",
|
||||
@@ -76,4 +76,4 @@
|
||||
"vite-svg-loader": "^5.1.0",
|
||||
"vue-tsc": "^2.2.8"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1618217035616" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6354" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M554.666667 256v640h-85.333334V256H213.333333V170.666667h597.333334v85.333333z" p-id="6355"></path></svg>
|
||||
|
After Width: | Height: | Size: 483 B |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1664337058571" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1356" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M309.312 85.312a32 32 0 0 1 32 32V128h341.312v-10.688a32 32 0 0 1 32-32h21.376a32 32 0 0 1 32 32V128h128c23.552 0 42.624 19.072 42.624 42.624V896a42.688 42.688 0 0 1-42.624 42.624H128A42.688 42.688 0 0 1 85.312 896V170.624C85.312 147.072 104.384 128 128 128h128v-10.688a32 32 0 0 1 32-32h21.312z m373.312 128H341.312V224a32 32 0 0 1-32 32H288a32 32 0 0 1-32-32v-10.688H170.624v640h682.688v-640H768V224a32 32 0 0 1-32 32h-21.376a32 32 0 0 1-32-32v-10.688zM384 437.312a32 32 0 0 0-32-32h-64a32 32 0 0 0-32 32v64a32 32 0 0 0 32 32h64a32 32 0 0 0 32-32v-64z m64 0a32 32 0 0 1 32-32h64a32 32 0 0 1 32 32v64a32 32 0 0 1-32 32h-64a32 32 0 0 1-32-32v-64z m-64 192a32 32 0 0 0-32-32h-64a32 32 0 0 0-32 32v64a32 32 0 0 0 32 32h64a32 32 0 0 0 32-32v-64z m64 0a32 32 0 0 1 32-32h64a32 32 0 0 1 32 32v64a32 32 0 0 1-32 32h-64a32 32 0 0 1-32-32v-64z m320-192a32 32 0 0 0-32-32h-64a32 32 0 0 0-32 32v64a32 32 0 0 0 32 32h64a32 32 0 0 0 32-32v-64z" p-id="1357"></path><path d="M768 629.312a32 32 0 0 0-32-32h-64a32 32 0 0 0-32 32v64a32 32 0 0 0 32 32h64a32 32 0 0 0 32-32v-64z" p-id="1358"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1618218878362" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9183" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M159.926857 689.426286h130.724572l-39.003429 193.718857c-0.859429 4.278857-1.28 9.435429-1.28 13.714286 0 20.992 14.555429 32.566857 34.706286 32.566857 20.571429 0 35.565714-11.154286 39.862857-32.146286l41.984-207.853714h202.715428L530.651429 883.145143c-1.28 4.278857-1.700571 9.435429-1.700572 13.714286 0 20.992 14.573714 32.566857 35.145143 32.566857s35.565714-11.154286 39.862857-32.146286L645.485714 689.426286h152.996572c23.570286 0 39.862857-17.133714 39.862857-40.283429 0-18.852571-12.854857-34.285714-32.146286-34.285714h-145.298286L706.377143 388.571429h149.997714c23.588571 0 39.862857-17.152 39.862857-40.283429 0-18.852571-12.854857-34.285714-32.146285-34.285714h-142.72l35.145142-172.726857c0.420571-2.56 1.28-8.137143 1.28-13.714286 0-20.992-14.994286-32.987429-35.565714-32.987429-23.990857 0-34.706286 13.275429-39.003428 33.426286l-37.705143 186.002286H442.788571l35.145143-172.726857c0.420571-2.56 1.28-8.137143 1.28-13.714286 0-20.992-15.433143-32.987429-35.565714-32.987429-24.429714 0-35.584 13.275429-39.442286 33.426286l-37.705143 186.002286h-140.580571c-23.570286 0-39.862857 17.993143-39.862857 41.563428 0 19.291429 12.873143 33.005714 32.164571 33.005715h133.284572l-45.44 226.285714h-138.422857c-23.588571 0-39.862857 17.993143-39.862858 41.563428 0 19.291429 12.854857 33.005714 32.146286 33.005715z m221.988572-74.569143l45.878857-226.285714H630.491429l-45.842286 226.285714z" p-id="9184"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
@@ -8,6 +8,8 @@
|
||||
"Details": "Details"
|
||||
},
|
||||
"variables": {
|
||||
"please_select_date": "Please select a date",
|
||||
"number_variable_error": "Please enter the correct numerical range.",
|
||||
"built_in": "Built-in",
|
||||
"normal_value": "Normal value",
|
||||
"cannot_be_empty": "Variable values cannot be empty.",
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
"return_to_view": "화면으로 돌아가기"
|
||||
},
|
||||
"variables": {
|
||||
"please_select_date": "날짜를 선택하십시오",
|
||||
"number_variable_error": "올바른 숫자 범위를 입력하십시오.",
|
||||
"built_in": "내장형",
|
||||
"normal_value": "정상값",
|
||||
"cannot_be_empty": "변수 값은 비어 있을 수 없습니다.",
|
||||
@@ -943,4 +945,4 @@
|
||||
"to_doc": "API 보기",
|
||||
"trigger_limit": "최대 {0}개의 API 키 생성 지원"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,8 @@
|
||||
"return_to_view": "返回查看"
|
||||
},
|
||||
"variables": {
|
||||
"please_select_date": "请选择日期",
|
||||
"number_variable_error": "请输入正确的数值范围",
|
||||
"built_in": "已内置",
|
||||
"normal_value": "常规值",
|
||||
"cannot_be_empty": "变量值不能为空",
|
||||
|
||||
@@ -419,3 +419,13 @@ strong {
|
||||
margin-top: -7px;
|
||||
}
|
||||
}
|
||||
|
||||
.text-variables.text-variables {
|
||||
color: #3370ff;
|
||||
}
|
||||
.number-variables.number-variables {
|
||||
color: #04b49c;
|
||||
}
|
||||
.datetime-variables.datetime-variables {
|
||||
color: #3370ff;
|
||||
}
|
||||
|
||||
@@ -173,6 +173,7 @@ defineExpose({
|
||||
border: 1px solid #dee0e3;
|
||||
padding: 16px;
|
||||
margin-bottom: 8px;
|
||||
cursor: pointer;
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
type S2Options,
|
||||
type SortMethod,
|
||||
TableSheet,
|
||||
type SortFuncParam,
|
||||
} from '@antv/s2'
|
||||
import { debounce, filter } from 'lodash-es'
|
||||
import { i18n } from '@/i18n'
|
||||
@@ -14,6 +15,60 @@ import '@antv/s2/dist/s2.min.css'
|
||||
|
||||
const { t } = i18n.global
|
||||
|
||||
const createSmartSortFunc = (sortMethod: string) => {
|
||||
const compareNumericString = (a: string, b: string): number => {
|
||||
const isNegA = a.startsWith('-')
|
||||
const isNegB = b.startsWith('-')
|
||||
|
||||
// 负数 < 正数
|
||||
if (isNegA && !isNegB) return -1
|
||||
if (!isNegA && isNegB) return 1
|
||||
|
||||
const [intA, decA = ''] = isNegA ? a.slice(1).split('.') : a.split('.')
|
||||
const [intB, decB = ''] = isNegB ? b.slice(1).split('.') : b.split('.')
|
||||
|
||||
// 都是正数
|
||||
if (!isNegA && !isNegB) {
|
||||
if (intA.length !== intB.length) return intA.length - intB.length
|
||||
const intCmp = intA.localeCompare(intB)
|
||||
if (intCmp !== 0) return intCmp
|
||||
if (decA && decB) return decA.localeCompare(decB)
|
||||
return decA ? 1 : decB ? -1 : 0
|
||||
}
|
||||
|
||||
// 都是负数:绝对值大的实际值小,比较结果取反
|
||||
if (intA.length !== intB.length) return -(intA.length - intB.length)
|
||||
const intCmp = intA.localeCompare(intB)
|
||||
if (intCmp !== 0) return -intCmp
|
||||
if (decA && decB) return -decA.localeCompare(decB)
|
||||
return decA ? 1 : decB ? -1 : 0
|
||||
}
|
||||
|
||||
return (params: SortFuncParam) => {
|
||||
const { data, sortFieldId } = params
|
||||
if (!data || data.length === 0) return data
|
||||
const isAsc = sortMethod.toLowerCase() === 'asc'
|
||||
return [...data].sort((a: any, b: any) => {
|
||||
const valA = a[sortFieldId],
|
||||
valB = b[sortFieldId]
|
||||
if (valA == null) return isAsc ? -1 : 1
|
||||
if (valB == null) return isAsc ? 1 : -1
|
||||
const strA = String(valA),
|
||||
strB = String(valB)
|
||||
const isNumA = !isNaN(Number(strA)) && strA.trim() !== ''
|
||||
const isNumB = !isNaN(Number(strB)) && strB.trim() !== ''
|
||||
if (isNumA && !isNumB) return isAsc ? -1 : 1
|
||||
if (!isNumA && isNumB) return isAsc ? 1 : -1
|
||||
if (isNumA && isNumB) {
|
||||
const cmp = compareNumericString(strA, strB)
|
||||
return isAsc ? cmp : -cmp
|
||||
}
|
||||
const cmp = strA.localeCompare(strB)
|
||||
return isAsc ? cmp : -cmp
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export class Table extends BaseChart {
|
||||
table?: TableSheet = undefined
|
||||
|
||||
@@ -81,7 +136,17 @@ export class Table extends BaseChart {
|
||||
const sortOrder = ['none', 'desc', 'asc']
|
||||
const nextMethod = sortOrder[(sortOrder.indexOf(currentMethod) + 1) % sortOrder.length]
|
||||
sortState[fieldId] = nextMethod
|
||||
s2.groupSortByMethod(nextMethod === 'none' ? 'none' : (nextMethod as SortMethod), meta)
|
||||
if (nextMethod === 'none') {
|
||||
s2.emit(S2Event.RANGE_SORT, [{ sortFieldId: fieldId, sortMethod: 'none' as SortMethod }])
|
||||
} else {
|
||||
s2.emit(S2Event.RANGE_SORT, [
|
||||
{
|
||||
sortFieldId: fieldId,
|
||||
sortMethod: nextMethod as SortMethod,
|
||||
sortFunc: createSmartSortFunc(nextMethod),
|
||||
},
|
||||
])
|
||||
}
|
||||
s2.render()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,6 +190,15 @@ const editTable = () => {
|
||||
tableComment.value = currentTable.value.custom_comment
|
||||
tableDialog.value = true
|
||||
}
|
||||
const changeChecked = () => {
|
||||
datasourceApi.saveTable(currentTable.value).then(() => {
|
||||
ElMessage({
|
||||
message: t('common.save_success'),
|
||||
type: 'success',
|
||||
showClose: true,
|
||||
})
|
||||
})
|
||||
}
|
||||
const saveTable = () => {
|
||||
currentTable.value.custom_comment = tableComment.value
|
||||
datasourceApi.saveTable(currentTable.value).then(() => {
|
||||
@@ -473,7 +482,27 @@ const btnSelectClick = (val: any) => {
|
||||
class="info-table"
|
||||
>
|
||||
<div class="table-name">
|
||||
<div class="name">{{ currentTable.table_name }}</div>
|
||||
<div class="name">
|
||||
{{ currentTable.table_name }}
|
||||
<div
|
||||
style="
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin-left: 30px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
"
|
||||
>
|
||||
<el-switch
|
||||
v-model="currentTable.checked"
|
||||
@change="changeChecked"
|
||||
size="small"
|
||||
style="margin-right: 8px"
|
||||
/>
|
||||
|
||||
{{ currentTable.checked ? t('user.disable') : t('user.enable') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="notes">
|
||||
{{ $t('about.remark') }}:
|
||||
<span :title="currentTable.custom_comment" class="field-notes">{{
|
||||
|
||||
@@ -275,7 +275,7 @@ const initOptions = () => {
|
||||
<div
|
||||
v-if="!searchLoading"
|
||||
class="table-content"
|
||||
:class="multipleSelectionAll?.length && 'show-pagination_height'"
|
||||
:class="multipleSelectionAll.length ? 'show-pagination_height' : ''"
|
||||
>
|
||||
<filter-text
|
||||
:total="pageInfo.total"
|
||||
|
||||
@@ -356,7 +356,7 @@ const copyCode = (row: any, key: any = 'app_secret') => {
|
||||
<div
|
||||
v-if="!searchLoading"
|
||||
class="table-content"
|
||||
:class="multipleSelectionAll.length && 'show-pagination_height'"
|
||||
:class="multipleSelectionAll.length ? 'show-pagination_height' : ''"
|
||||
>
|
||||
<template v-if="!oldKeywords && !fieldList.length">
|
||||
<EmptyBackground
|
||||
|
||||
@@ -240,7 +240,7 @@ const handleCurrentChange = (val: number) => {
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-content" :class="multipleSelectionAll.length && 'show-pagination_height'">
|
||||
<div class="table-content" :class="multipleSelectionAll.length ? 'show-pagination_height' : ''">
|
||||
<div class="preview-or-schema">
|
||||
<el-table
|
||||
ref="multipleTableRef"
|
||||
|
||||
@@ -4,6 +4,10 @@ import { ref, inject, computed, onBeforeMount, toRefs, type Ref, shallowRef } fr
|
||||
import { variablesApi } from '@/api/variables'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { allOptions } from '../options'
|
||||
import field_text from '@/assets/svg/field_text.svg'
|
||||
import field_time from '@/assets/svg/field_time.svg'
|
||||
import field_value from '@/assets/svg/field_value.svg'
|
||||
|
||||
export interface Item {
|
||||
term: string
|
||||
field_id: string
|
||||
@@ -118,6 +122,12 @@ const initEnumOptions = () => {
|
||||
console.info('initEnumOptions')
|
||||
}
|
||||
|
||||
const iconMap = {
|
||||
text: field_text,
|
||||
number: field_value,
|
||||
datetime: field_time,
|
||||
}
|
||||
|
||||
const selectItem = ({ field_name, id }: any) => {
|
||||
Object.assign(item.value, {
|
||||
field_id: id,
|
||||
@@ -248,6 +258,12 @@ const emits = defineEmits(['update:item', 'del'])
|
||||
:placeholder="t('datasource.Please_select')"
|
||||
>
|
||||
<el-option v-for="ele in variables" :key="ele.id" :label="ele.name" :value="ele.id">
|
||||
<div style="width: 100%; display: flex; align-items: center">
|
||||
<el-icon :class="`${ele.var_type}-variables`" size="16" style="margin-right: 4px">
|
||||
<component :is="iconMap[ele.var_type as keyof typeof iconMap]"></component>
|
||||
</el-icon>
|
||||
{{ ele.name }}
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { ref, computed } from 'vue'
|
||||
import AuthTree from './AuthTree.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { variablesApi } from '@/api/variables'
|
||||
|
||||
const { t } = useI18n()
|
||||
const errorMessage = ref('')
|
||||
@@ -26,9 +27,10 @@ const svgDashinePath = computed(() => {
|
||||
return path
|
||||
})
|
||||
|
||||
const init = (expressionTree: any) => {
|
||||
const init = async (expressionTree: any) => {
|
||||
const { logic: lg = 'or', items = [] } = expressionTree
|
||||
logic.value = lg
|
||||
await getVariables()
|
||||
relationList.value = dfsInit(items)
|
||||
}
|
||||
const submit = () => {
|
||||
@@ -65,6 +67,17 @@ const errorDetected = ({ filter_type, field_id, term, value, value_type, variabl
|
||||
}
|
||||
}
|
||||
}
|
||||
const variables = ref<any[]>([])
|
||||
const getVariables = () => {
|
||||
return variablesApi.listAll().then((res: any) => {
|
||||
variables.value = res || []
|
||||
})
|
||||
}
|
||||
|
||||
const canPush = (value_type: any, variable_id: any) => {
|
||||
if (value_type === 'normal') return true
|
||||
return variables.value.some((ele) => ele.id === variable_id)
|
||||
}
|
||||
const dfsInit = (arr: any[]) => {
|
||||
const elementList: any[] = []
|
||||
arr.forEach((ele: any) => {
|
||||
@@ -85,16 +98,18 @@ const dfsInit = (arr: any[]) => {
|
||||
variable_id = '',
|
||||
} = ele
|
||||
const { name } = field || {}
|
||||
elementList.push({
|
||||
enum_value: enum_value.join(','),
|
||||
field_id,
|
||||
filter_type,
|
||||
term,
|
||||
value,
|
||||
name,
|
||||
value_type,
|
||||
variable_id,
|
||||
})
|
||||
if (canPush(value_type, variable_id)) {
|
||||
elementList.push({
|
||||
enum_value: enum_value.join(','),
|
||||
field_id,
|
||||
filter_type,
|
||||
term,
|
||||
value,
|
||||
name,
|
||||
value_type,
|
||||
variable_id,
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
return elementList
|
||||
|
||||
@@ -470,7 +470,7 @@ const changeStatus = (id: any, val: any) => {
|
||||
<div
|
||||
v-if="!searchLoading"
|
||||
class="table-content"
|
||||
:class="multipleSelectionAll?.length && 'show-pagination_height'"
|
||||
:class="multipleSelectionAll.length ? 'show-pagination_height' : ''"
|
||||
>
|
||||
<filter-text
|
||||
:total="pageInfo.total"
|
||||
|
||||
@@ -506,7 +506,7 @@ const drawerMainClose = () => {
|
||||
<div
|
||||
v-if="!searchLoading"
|
||||
class="table-content"
|
||||
:class="multipleSelectionAll?.length && 'show-pagination_height'"
|
||||
:class="multipleSelectionAll.length ? 'show-pagination_height' : ''"
|
||||
>
|
||||
<filter-text
|
||||
:total="pageInfo.total"
|
||||
|
||||
@@ -393,7 +393,7 @@ const onRowFormClose = () => {
|
||||
<div
|
||||
v-if="!searchLoading"
|
||||
class="table-content"
|
||||
:class="multipleSelectionAll?.length && 'show-pagination_height'"
|
||||
:class="multipleSelectionAll?.length ? 'show-pagination_height' : ''"
|
||||
>
|
||||
<div class="preview-or-schema">
|
||||
<el-table
|
||||
|
||||
@@ -391,8 +391,23 @@
|
||||
v-for="item in variables"
|
||||
:key="item.id"
|
||||
:label="item.name"
|
||||
:disabled="
|
||||
state.form.system_variables.map((ele: any) => ele.variableId).includes(item.id)
|
||||
"
|
||||
:value="item.id"
|
||||
>
|
||||
<div style="width: 100%; display: flex; align-items: center">
|
||||
<el-icon
|
||||
:class="`${variableValueMap[item.id].var_type}-variables`"
|
||||
size="16"
|
||||
style="margin-right: 4px"
|
||||
>
|
||||
<component
|
||||
:is="iconMap[variableValueMap[item.id].var_type as keyof typeof iconMap]"
|
||||
></component>
|
||||
</el-icon>
|
||||
{{ item.name }}
|
||||
</div>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-select
|
||||
@@ -422,7 +437,7 @@
|
||||
>
|
||||
</el-option>
|
||||
</el-select>
|
||||
<el-input
|
||||
<el-input-number
|
||||
v-else-if="
|
||||
variableValueMap[state.form.system_variables[index].variableId].var_type ===
|
||||
'number'
|
||||
@@ -430,19 +445,17 @@
|
||||
v-model.number="state.form.system_variables[index].variableValue"
|
||||
style="width: 236px"
|
||||
:placeholder="$t('variables.please_enter_value')"
|
||||
autocomplete="off"
|
||||
maxlength="50"
|
||||
clearable
|
||||
max="10000000000000000"
|
||||
controls-position="right"
|
||||
/>
|
||||
<el-date-picker
|
||||
v-else
|
||||
v-model="state.form.system_variables[index].variableValues"
|
||||
type="daterange"
|
||||
style="max-width: 236px"
|
||||
v-model="state.form.system_variables[index].variableValue"
|
||||
type="date"
|
||||
style="width: 236px"
|
||||
value-format="YYYY-MM-DD"
|
||||
range-separator=""
|
||||
:start-placeholder="$t('variables.start_date')"
|
||||
:end-placeholder="$t('variables.end_date')"
|
||||
:placeholder="$t('variables.please_select_date')"
|
||||
/>
|
||||
<el-tooltip
|
||||
:offset="14"
|
||||
@@ -530,6 +543,7 @@ import UserImport from './UserImport.vue'
|
||||
import SuccessFilled from '@/assets/svg/gou_icon.svg'
|
||||
import icon_replace_outlined from '@/assets/svg/icon_replace_outlined.svg'
|
||||
import CircleCloseFilled from '@/assets/svg/icon_ban_filled.svg'
|
||||
import { ElButton } from 'element-plus-secondary'
|
||||
import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlined.svg'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import EmptyBackground from '@/views/dashboard/common/EmptyBackground.vue'
|
||||
@@ -544,6 +558,9 @@ import logo_lark from '@/assets/img/lark.png'
|
||||
import logo_wechat_work from '@/assets/img/wechat.png'
|
||||
import icon_add_outlined from '@/assets/svg/icon_add_outlined.svg'
|
||||
import { userApi } from '@/api/user'
|
||||
import field_text from '@/assets/svg/field_text.svg'
|
||||
import field_time from '@/assets/svg/field_time.svg'
|
||||
import field_value from '@/assets/svg/field_value.svg'
|
||||
import { request } from '@/utils/request'
|
||||
import { workspaceList } from '@/api/workspace'
|
||||
import { variablesApi } from '@/api/variables'
|
||||
@@ -566,6 +583,12 @@ const drawerMainRef = ref()
|
||||
const userImportRef = ref()
|
||||
const syncUserRef = ref()
|
||||
const selectionLoading = ref(false)
|
||||
|
||||
const iconMap = {
|
||||
text: field_text,
|
||||
number: field_value,
|
||||
datetime: field_time,
|
||||
}
|
||||
const filterOption = ref<any[]>([
|
||||
{
|
||||
type: 'enum',
|
||||
@@ -995,10 +1018,9 @@ const formatVariableValues = () => {
|
||||
if (!state.form.system_variables?.length) return []
|
||||
return state.form.system_variables.map((ele: any) => ({
|
||||
variableId: ele.variableId,
|
||||
variableValues:
|
||||
variableValueMap.value[ele.variableId].var_type === 'number'
|
||||
? [ele.variableValue]
|
||||
: ele.variableValues,
|
||||
variableValues: ['number', 'datetime'].includes(variableValueMap.value[ele.variableId].var_type)
|
||||
? [ele.variableValue]
|
||||
: ele.variableValues,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -1055,12 +1077,12 @@ const validateSystemVariables = () => {
|
||||
if (system_variables?.length) {
|
||||
return system_variables.some((ele: any) => {
|
||||
const obj = variableValueMap.value[ele.variableId]
|
||||
if (obj.var_type !== 'number' && !ele.variableValues.length) {
|
||||
if (obj.var_type === 'text' && !ele.variableValues.length) {
|
||||
ElMessage.error(t('variables.cannot_be_empty'))
|
||||
return true
|
||||
}
|
||||
|
||||
if (obj.var_type === 'number' && !ele.variableValue) {
|
||||
if (obj.var_type === 'number' && [null, undefined, ''].includes(ele.variableValue)) {
|
||||
ElMessage.error(t('variables.cannot_be_empty'))
|
||||
return true
|
||||
}
|
||||
@@ -1075,12 +1097,9 @@ const validateSystemVariables = () => {
|
||||
|
||||
if (obj.var_type === 'datetime') {
|
||||
const [min, max] = obj.value
|
||||
const [minVal, maxVal] = ele.variableValues
|
||||
if (
|
||||
+new Date(minVal) > +new Date(max) ||
|
||||
+new Date(maxVal) < +new Date(min) ||
|
||||
+new Date(maxVal) > +new Date(max) ||
|
||||
+new Date(minVal) < +new Date(min)
|
||||
+new Date(ele.variableValue) > +new Date(max) ||
|
||||
+new Date(ele.variableValue) < +new Date(min)
|
||||
) {
|
||||
ElMessage.error(
|
||||
t('variables.1_to_100_de', {
|
||||
|
||||
@@ -7,6 +7,9 @@ import IconOpeDelete from '@/assets/svg/icon_delete.svg'
|
||||
import icon_searchOutline_outlined from '@/assets/svg/icon_search-outline_outlined.svg'
|
||||
import EmptyBackground from '@/views/dashboard/common/EmptyBackground.vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import field_text from '@/assets/svg/field_text.svg'
|
||||
import field_time from '@/assets/svg/field_time.svg'
|
||||
import field_value from '@/assets/svg/field_value.svg'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
interface Form {
|
||||
@@ -21,6 +24,11 @@ const multipleSelectionAll = ref<any[]>([])
|
||||
const keywords = ref('')
|
||||
const oldKeywords = ref('')
|
||||
const searchLoading = ref(false)
|
||||
const iconMap = {
|
||||
text: field_text,
|
||||
number: field_value,
|
||||
datetime: field_time,
|
||||
}
|
||||
|
||||
const selectable = (row: any) => {
|
||||
return ![1, 2, 3].includes(row.id)
|
||||
@@ -74,7 +82,7 @@ const deleteBatchUser = () => {
|
||||
message: t('dashboard.delete_success'),
|
||||
})
|
||||
multipleSelectionAll.value = []
|
||||
search()
|
||||
handleCurrentChange(1)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -94,7 +102,7 @@ const deleteHandler = (row: any) => {
|
||||
type: 'success',
|
||||
message: t('dashboard.delete_success'),
|
||||
})
|
||||
search()
|
||||
handleCurrentChange(1)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -181,7 +189,12 @@ const validateValue = (_: any, value: any, callback: any) => {
|
||||
}
|
||||
return
|
||||
}
|
||||
if (value.some((ele: any) => ele === '')) {
|
||||
if (var_type === 'datetime') {
|
||||
if (value === null) {
|
||||
callback(new Error(t('datasource.please_enter') + t('common.empty') + t('variables.date')))
|
||||
}
|
||||
}
|
||||
if (value.some((ele: any) => ele === '' || ele === null)) {
|
||||
callback(
|
||||
new Error(
|
||||
t('datasource.please_enter') +
|
||||
@@ -229,12 +242,23 @@ const saveHandler = () => {
|
||||
obj.value = [...new Set(obj.value)]
|
||||
}
|
||||
|
||||
if (obj.var_type === 'number') {
|
||||
const [min = 0, max = 0] = obj.value
|
||||
if (min > max) {
|
||||
ElMessage({
|
||||
type: 'error',
|
||||
message: t('variables.number_variable_error'),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
variablesApi.save(obj).then(() => {
|
||||
ElMessage({
|
||||
type: 'success',
|
||||
message: t('common.save_success'),
|
||||
})
|
||||
search()
|
||||
handleCurrentChange(1)
|
||||
onFormClose()
|
||||
})
|
||||
}
|
||||
@@ -302,7 +326,7 @@ const handleCurrentChange = (val: number) => {
|
||||
<div
|
||||
v-if="!searchLoading"
|
||||
class="table-content"
|
||||
:class="multipleSelectionAll.length && 'show-pagination_height'"
|
||||
:class="multipleSelectionAll.length ? 'show-pagination_height' : ''"
|
||||
>
|
||||
<template v-if="!oldKeywords && !fieldList.length">
|
||||
<EmptyBackground
|
||||
@@ -322,7 +346,30 @@ const handleCurrentChange = (val: number) => {
|
||||
<el-table-column prop="name" :label="$t('variables.variable_name')">
|
||||
<template #default="scope">
|
||||
<div style="display: flex; align-items: center" :title="scope.row.name">
|
||||
<div class="ellipsis" style="max-width: calc(100% - 60px); width: fit-content">
|
||||
<div
|
||||
class="ellipsis"
|
||||
style="
|
||||
max-width: calc(100% - 60px);
|
||||
width: fit-content;
|
||||
position: relative;
|
||||
padding-left: 20px;
|
||||
"
|
||||
>
|
||||
<el-icon
|
||||
:class="`${scope.row.var_type}-variables`"
|
||||
size="16"
|
||||
style="
|
||||
margin-right: 4px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
"
|
||||
>
|
||||
<component
|
||||
:is="iconMap[scope.row.var_type as keyof typeof iconMap]"
|
||||
></component>
|
||||
</el-icon>
|
||||
{{ scope.row.name }}
|
||||
</div>
|
||||
<div v-if="scope.row.type === 'system'" class="system-flag">
|
||||
@@ -522,12 +569,14 @@ const handleCurrentChange = (val: number) => {
|
||||
v-model.number="pageForm.value[0]"
|
||||
:placeholder="$t('variables.please_enter_value')"
|
||||
clearable
|
||||
max="10000000000000000"
|
||||
controls-position="right"
|
||||
/>
|
||||
<span class="ed-range-separator separator"></span>
|
||||
<el-input-number
|
||||
v-model.number="pageForm.value[1]"
|
||||
:placeholder="$t('variables.please_enter_value')"
|
||||
max="10000000000000000"
|
||||
clearable
|
||||
controls-position="right"
|
||||
/>
|
||||
@@ -629,8 +678,11 @@ const handleCurrentChange = (val: number) => {
|
||||
margin-left: 4px;
|
||||
color: var(--ed-color-primary-15-d, #189e7a);
|
||||
}
|
||||
.ed-icon {
|
||||
color: #646a73;
|
||||
|
||||
&:not(:has(.ellipsis)) {
|
||||
.ed-icon {
|
||||
color: #646a73;
|
||||
}
|
||||
}
|
||||
|
||||
.field-comment {
|
||||
|
||||
@@ -428,7 +428,10 @@ const handleCurrentChange = (val: number) => {
|
||||
</el-input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-content" :class="multipleSelectionAll.length && 'show-pagination_height'">
|
||||
<div
|
||||
class="table-content"
|
||||
:class="{ 'show-pagination_height': multipleSelectionAll.length > 0 }"
|
||||
>
|
||||
<div class="preview-or-schema">
|
||||
<el-table
|
||||
ref="multipleTableRef"
|
||||
|
||||
Reference in New Issue
Block a user