f8d07716 by xukangle

update: 联调分类分级目录接口

1 parent e74fabf2
# 页面标题
VITE_APP_TITLE = 数据资产管理系统
# 接口域名
VITE_API_BASEURL = https://www.zgsjzc.com/api
VITE_API_BASEURL = http://192.168.6.20:28052/
# VITE_API_BASEURL = http://49.4.26.201:31709/
# # 平台用户 接口请地址
# VITE_APP_USER_API_BASEURL = gateway-server
# # 系统管理 接口地址
# VITE_APP_API_BASEURL = ms-daop-zcgl-system-manager-service
# # 文件上传请求地址
# VITE_APP_ADD_FILE = ms-daop-import-data-service
# # 调试工具,可设置 eruda 或 vconsole,如果不需要开启则留空
# VITE_APP_DEBUG_TOOL =
# # 是否开启代理
# VITE_OPEN_PROXY = true
# # vite serve base
# VITE_SERVE_BASE = /
# # 流程设计访问地址
# VITE_BPMN_URL = https://workflow.zgsjzc.com
# # 数据标准、元数据、数据目录 接口地址
# VITE_APP_PLAN_BASEURL = ms-daop-jgjf-data-plan-service
# #数据质量接口地址
# VITE_APP_QUALITY_BASEURL = ms-daop-data-quality-service
# #门户接口
# VITE_API_PORTALURL = https://www.zgsjzc.com/portal
# #数据资产接口地址
# VITE_API_ASSET_BASEURL = ms-swzl-data-dam-service
# #数据同步接口地址
# VITE_API_DATA_SYNC = ms-swzl-data-sync-service
# #消息接口
# VITE_API_MESSAGE = ms-swzl-message-notification-service
# 平台用户 接口请地址
VITE_APP_USER_API_BASEURL = gateway-server
#AUTH服务
VITE_APP_AUTH_URL = 'ms-daop-auth-service'
# 系统管理 接口地址
VITE_APP_API_BASEURL = ms-daop-zcgl-system-manager-service
# 文件上传请求地址
VITE_APP_ADD_FILE = ms-daop-import-data-service
# 调试工具,可设置 eruda 或 vconsole,如果不需要开启则留空
......@@ -16,14 +49,22 @@ VITE_OPEN_PROXY = true
# vite serve base
VITE_SERVE_BASE = /
# 流程设计访问地址
VITE_BPMN_URL = https://workflow.zgsjzc.com
VITE_BPMN_URL = https://workflow-swzl-test.csbr.cn
# 数据标准、元数据、数据目录 接口地址
VITE_APP_PLAN_BASEURL = ms-daop-jgjf-data-plan-service
#数据质量接口地址
VITE_APP_QUALITY_BASEURL = ms-daop-data-quality-service
#数据盘点接口地址ms-daop-zcgl-data-inventory
# VITE_APP_CHECK_BASEURL = /mock
VITE_APP_CHECK_BASEURL = ms-daop-zcgl-data-inventory
# 数据字典接口地址
VITE_APP_CONFIG_URL = 'ms-daop-configure-service'
#门户接口
VITE_API_PORTALURL = https://www.zgsjzc.com/portal
VITE_API_PORTALURL = https://swzl-test.zgsjzc.com/portal
#数据资产接口地址
VITE_API_ASSET_BASEURL = ms-swzl-data-dam-service
......
FROM 192.168.5.4:82/csbr/nginx:stable-alpine
FROM 192.168.6.22:8081/csbr/nginx:stable-alpine
VOLUME /tmp
#将当前文件夹的dist文件复制到容器的/usr/share/nginx/html目录
COPY ./dist/* /usr/share/nginx/html/
COPY ./dist/assets /usr/share/nginx/html/assets
#COPY ./dist/importTemplate /usr/share/nginx/html/importTemplate
COPY default.conf /etc/nginx/conf.d/
#声明运行时容器暴露的端口(容器提供的服务端口)
EXPOSE 8911
RUN chown -R nginx:nginx /usr/share/nginx/html
EXPOSE 29900
#CMD:指定容器启动时要运行的命令
CMD ["nginx", "-g", "daemon off;"]
\ No newline at end of file
CMD ["nginx", "-g", "daemon off;"]
......
......@@ -3,21 +3,22 @@ pipeline {
//环境定义
environment{
//服务名称
SVN_FOLD = "fe-swzl-asset-temp"
SVN_FOLD = "fe-data-asset-management"
//部署远程服务器
//192.168.4.4服务器
//SSH_PATH = "csbr4.4"
//192.168.5.4
SSH_PATH = "csbr5.2"
SSH_PATH = "csbr20"
SVN_TYPE = "dev"
//139.9.190.186
//SSH_PATH = "csbr190.186"
//SVN_TYPE = "master"
//镜像版本号
image_tag = "1.0.0"
//docker私服ip
ip = "192.168.5.4:82"
ip = "192.168.6.22:8081"
//前端端口号
port = "8911"
port = "29900"
//映射端口号
vport = "80"
......@@ -63,9 +64,9 @@ pipeline {
steps {
//分分支构建
script{
if(env.BRANCH_NAME=='master-asset'){
if(env.BRANCH_NAME=='develop'){
//master-asset分支环境
echo 'start to deploy ${SVN_FOLD} on master-asset ...'
echo 'start to deploy ${SVN_FOLD} on develop ...'
sh '''
#docker rmi -f $(docker images | grep "none" | awk '{print $3}')
CID=$(docker ps -a | grep "${SVN_FOLD}" | awk '{print $1}')
......@@ -107,14 +108,14 @@ pipeline {
echo 'Deploying'
//分分支部署
script{
if(env.BRANCH_NAME=='master-asset'){
if(env.BRANCH_NAME=='develop'){
//master-asset分支环境
echo 'start to deploy ${SVN_FOLD} on master-asset ...'
echo 'start to deploy ${SVN_FOLD} on develop ...'
//调用Publish Over SSH插件,上传docker-compose.yaml文件并且执行deploy脚本
sshPublisher(publishers: [sshPublisherDesc(configName: "csbr5.3", transfers: [sshTransfer(cleanRemote: false, excludes: '', execCommand: """
#使用k8s构建
kubectl delete -f /mnt/k8s/production/fe-swzl-asset.yaml
kubectl apply -f /mnt/k8s/production/fe-swzl-asset.yaml
kubectl delete -f /mnt/k8s/develop/daop-jgjf/fe-data-asset-management.yaml
kubectl apply -f /mnt/k8s/develop/daop-jgjf/fe-data-asset-management.yaml
""", execTimeout: 120000, flatten: false, makeEmptyDirs: false, noDefaultExcludes: false, patternSeparator: '[, ]+', remoteDirectory: '/mnt/csbr/data', remoteDirectorySDF: false, removePrefix: '', sourceFiles: 'output/*.*')], usePromotionTimestamp: false, useWorkspaceInPromotion: false, verbose: false)])
echo 'Depoly ${SVN_FOLD} success ...'
......
......@@ -2,48 +2,53 @@ server {
listen 80;
listen [::]:80;
server_name localhost;
# server_name http://192.168.6.20:8052;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
# 设置允许跨域的域名,可以使用通配符 '*' 允许所有域访问
add_header 'Access-Control-Allow-Origin' * always;
# 设置允许的 HTTP 方法
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT';
# 设置允许的请求头
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Accept, Origin, X-Requested-With';
# 如果需要支持 cookie,可以设置以下 header
add_header 'Access-Control-Allow-Credentials' 'true';
# 缓存设置
add_header Cache-Control no-cache;
add_header Cache-Control private;
# # 预检请求处理
# if ($request_method = OPTIONS) {
# return 204;
# }
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
expires -1s;
}
location /api {
# 设置允许跨域的域名,可以使用通配符 '*' 允许所有域访问
add_header 'Access-Control-Allow-Origin' * always;
# 设置允许的 HTTP 方法
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, PUT';
# 设置允许的请求头
add_header 'Access-Control-Allow-Headers' 'Authorization, Content-Type, Accept, Origin, X-Requested-With';
# 如果需要支持 cookie,可以设置以下 header
add_header 'Access-Control-Allow-Credentials' 'true';
# 缓存设置
add_header Cache-Control no-cache;
add_header Cache-Control private;
expires -1s;
# 使用 rewrite 将 /api 替换为 /new-api
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://192.168.6.20:28052;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
......
......@@ -4,6 +4,7 @@ import request from "@/utils/request";
/**
* 数据字典
**/
// 编码规则流水号
export const getCoderuleList = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/code-rule/list`,
......@@ -48,11 +49,11 @@ export const checkDeleteDictionaryScheme = (params) => request({
data: params
})
// 分页查询
export const getDictionary = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/data-dictionary-general/page-list`,
method: 'post',
data: params
})
// export const getDictionary = (params) => request({
// url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/data-dictionary-general/page-list`,
// method: 'post',
// data: params
// })
// 查询数据字典启用状态的数据
export const getDictionaryAll = (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/data-dictionary-general/list-all`,
......@@ -161,10 +162,14 @@ export const checkDictionaryData = (params) => request({
* DATA-CLASSIFY 数据类别
* DATA-GRADE 数据级别
*/
export const getLargeCategoryList = (data) => request({
url:`${import.meta.env.VITE_APP_API_BASEURL}/data-dict/get-data-list`,
method: 'post',
data
// export const getLargeCategoryList = (data) => request({
// url:`${import.meta.env.VITE_APP_API_BASEURL}/data-dict/get-data-list`,
// method: 'post',
// data
// })
export const getLargeCategoryList = (params) => request({
url: `${import.meta.env.VITE_APP_CONFIG_URL}/dict/data/get-by-dictType?dictType=${params.dictType}`,
method: 'get',
})
......@@ -355,6 +360,18 @@ export const getCgTemplateClassifyTreeList = (data) => request({
/**-------------------------分类分级目录--------------------------------- */
/**
* 查询执行guid和目录名称
* @param {no params}
* @path /cg-dir/get-exec-guid-and-name
*/
export const getExecGuidAndName = () => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/cg-dir/get-exec-guid-and-name`,
method: 'post',
})
/**
* 分类分级目录树形列表
......@@ -383,10 +400,10 @@ export const getCgDirFieldPageList = (data) => request({
/** 获取字典列表
* VITE_APP_PLAN_BASEURL 为环境变量 现在只是mock数据
*/
// export const getDictionary = (params) => request({
// url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/data-dictionary-general/list-all?state=1`,
// method: 'post'
// })
export const getDictionary = (params) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/data-dictionary-general/list-all?state=1`,
method: 'post'
})
......@@ -422,7 +439,109 @@ export const getDbDirTablePageList = (data) => request({
data
})
/**
* 数据库目录-已有数据库列表
* @param {no params}
* @path /db-dir/data-source/list
*/
export const getDbDirDataSourceList = (params) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/db-dir/data-source/list?execGuid=${params.execGuid}`,
method: 'post',
})
/**
* 获取列表
* @param {Object}
* @path /db-dir/field/page-list
* @returns
*/
export const getDbDirFieldPageList = (data) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/db-dir/field/page-list`,
method: 'post',
data
})
/** 获取已有字段信息 */
export const getDsTableStructure= (data) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/db-dir/field/list-by-table-guid`,
method: 'post',
data
});
/** 根据选择的连接池获取表列表 */
export const getDsTableByDs = (params) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/db-dir/table/list-by-datasource-guid`,
method: 'post',
data: params
})
/** 根据数据表获取表结构 */
export const getDsData= (params) => request({
url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/data-catalog-subject/table-column-list`,
method: 'post',
data: params
});
/**
* 数据库新建目录表
* @param {Object}
* @path /db-dir/table/save
*/
export const saveDbDirTable = (data) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/db-dir/table/save`,
method: 'post',
data
})
/**
* 数据库目录修改表
* @param {Object}
* @path /db-dir/table/update
*/
export const updateDbDirTable = (data) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/db-dir/table/update`,
method: 'post',
data
})
/**
* 生成建表sql语句
* @param {Object}
* @path /db-dir/table/create-table-sql
*/
export const createTableSql = (data) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/db-dir/table/create-table-sql`,
method: 'post',
data
})
/*********************业务规则配置 ************数据库目录************************* */
/**
* 业务规则配置-详情
* @param {Object}
* @path /biz-rule-config/detail
* @returns
*/
export const getBizRuleConfigDetail = (params) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/biz-rule-config/detail?tableGuid=${params.tableGuid}&execGuid=${params.execGuid}`,
method: 'get',
})
/**
* 业务规则配置-修改
* @param {Object}
* @path /biz-rule-config/update
* @returns
*/
export const updateBizRuleConfig = (data) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/biz-rule-config/update`,
method: 'post',
data
})
......
......@@ -284,14 +284,340 @@ export const getDbDirTablePageList = {
databaseChName: '@cword(3, 5)',
foundMode: '@integer(1, 3)',
state: '@integer(0,2)',
isDataAsset: 'Y'
isDataAsset: 'Y',
description: '@cword(10, 15)',
}]
}
}
}
}
/**
* export const getDbDirDataSourceList = () => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/db-dir/data-source/list`,
method: 'post',
})
"data": [
{
"tableGuid": "string",
"tableName": "string",
"tableChName": "string",
"databaseGuid": "string",
"database": "string",
"databaseChName": "string"
}
],
*/
export const getDbDirDataSourceList = {
url: '/mock/db-dir/data-source/list',
method: 'post',
response: ({body}:{body:any}) => {
return {
code: '00000',
message: '成功',
'data|10-30': [{
tableGuid: '@guid',
tableName: '@cword(3, 5)',
tableChName: '@cword(3, 5)',
databaseGuid: '@guid',
database: '@cword(3, 5)',
databaseChName: '@cword(3, 5)'
}]
}
}
}
/**
* export const getDsData = (params) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/db-dir/table/list-by-datasource-guid`,
method: 'post',
data: params
});
"data": {
"totalRows": 0,
"totalPages": 0,
"pageSize": 0,
"pageIndex": 0,
"records": [
{
"tableGuid": "string",
"tableName": "string",
"tableChName": "string",
"databaseGuid": "string",
"database": "string",
"databaseChName": "string"
}
],
*/
export const getDsTableByDs = {
url: '/mock/db-dir/table/list-by-datasource-guid',
method: 'post',
response: ({body}:{body:any}) => {
return {
code: '00000',
message: '成功',
'data': {
totalRows: '@integer(50, 100)',
totalPages: '@integer(1, 10)',
pageSize: 10,
pageIndex: 1,
'records|50-100': [{
tableGuid: '@guid',
tableName: '@cword(3, 5)',
tableChName: '@cword(3, 5)',
databaseGuid: '@guid',
database: '@cword(3, 5)',
databaseChName: '@cword(3, 5)'
}]
}
}
}
}
export const getDsTableStructure = {
url: '/mock/db-dir/field/list-by-table-guid',
method: 'post',
response: ({body}:{body:any}) => {
return {
code: '00000',
message: '成功',
'data|2-5': [{
guid: '@guid',
tableGuid: '@guid',
tableName: '@cword(3, 5)',
tableChName: '@cword(3, 5)',
databaseGuid: '@guid',
database: '@cword(3, 5)',
databaseChName: '@cword(3, 5)',
fieldGuid: '@guid',
fieldName: '@cword(3, 5)',
fieldChName: '@cword(3, 5)',
fieldType: '@cword(3, 5)',
fieldLength: '@integer(1, 100)',
fieldPrecision: '@integer(1, 100)',
dimGuid: '@guid',
dictionaryGuid: '@guid',
sortValue: '@integer(1, 100)',
isPrimary: 'Y',
isFk: 'Y',
isNotNull: 'Y'
}]
}
}
}
/**
* export const getDbDirFieldPageList = (data) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/db-dir/field/page-list`,
method: 'post',
data
})
{
"code": "string",
"msg": "string",
"data": {
"totalRows": 0,
"totalPages": 0,
"pageSize": 0,
"pageIndex": 0,
"records": [
{
"guid": "string",
"tenantGuid": "string",
"cgDirName": "string",
"dirGuid": "string",
"classifyName": "string",
"gradeDetailName": "string",
"label": "string",
"fieldName": "string",
"fieldChName": "string",
"tableName": "string",
"tableChName": "string",
"database": "string",
"databaseChName": "string"
}
],
*/
export const getDbDirFieldPageList = {
url: '/mock/db-dir/field/page-list',
method: 'post',
response: ({body}:{body:any}) => {
return {
code: '00000',
message: '成功',
'data': {
totalRows: '@integer(50, 100)',
totalPages: '@integer(1, 10)',
pageSize: 10,
pageIndex: 1,
'records|20-30': [{
guid: '@guid',
tenantGuid: '@guid',
cgDirName: '@cword(3, 5)',
dirGuid: '@guid',
classifyName: '@cword(3, 5)',
gradeDetailName: '@cword(3, 5)',
label: '@cword(3, 5)',
fieldName: '@cword(3, 5)',
fieldChName: '@cword(3, 5)',
tableName: '@cword(3, 5)',
tableChName: '@cword(3, 5)',
database: '@cword(3, 5)',
databaseChName: '@cword(3, 5)'
}]
}
}
}
}
/**
* export const getBizRuleConfigDetail = (params) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/biz-rule-config/detail?tableGuid=${params.tableGuid}&execGuid=${params.execGuid}`,
method: 'get',
})
"data": [
{
"guid": "string",
"tenantGuid": "string",
"classifyName": "string",
"gradeDetailName": "string",
"fieldName": "string",
"fieldChName": "string",
"fieldGuid": "string",
"fieldType": "string",
"fieldLengthCondition": "string",
"fieldPrecision": 0,
"dictionaryGuid": "string",
"isUnique": "string",
"isNotNull": "string",
"fieldValueRange": "string"
}
],
*/
export const getBizRuleConfigDetail = {
url: '/mock/biz-rule-config/detail',
method: 'get',
response: ({body}:{body:any}) => {
return {
code: '00000',
message: '成功',
'data|1-3': [{
guid: '@guid',
tenantGuid: '@guid',
classifyName: '@cword(3, 5)',
gradeDetailName: '@cword(3, 5)',
fieldName: '@cword(3, 5)',
fieldChName: '@cword(3, 5)',
fieldGuid: '@guid',
fieldType: '@cword(3, 5)',
fieldLengthCondition: '>#10',
fieldPrecision: '@integer(1, 100)',
dictionaryGuid: '@guid',
isUnique: 'Y',
isNotNull: 'Y',
fieldValueRange: '0-100'
}]
}
}
}
/**
* export const updateBizRuleConfig = (data) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/biz-rule-config/update`,
method: 'post',
data
}){
"code": "string",
"msg": "string",
"data": true,
"at": "string",
"serviceCode": "string"
}
*/
export const updateBizRuleConfig = {
url: '/mock/biz-rule-config/update',
method: 'post',
response: ({body}:{body:any}) => {
return {
code: '00000',
message: '成功',
data: true,
at: 'string',
serviceCode: 'string'
}
}
}
/**
* /**
* 数据库新建目录表
* @param {Object}
* @path /db-dir/table/save
* export const saveDbDirTable = (data) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/db-dir/table/save`,
method: 'post',
data
})
*/
export const saveDbDirTable = {
url: '/mock/db-dir/table/save',
method: 'post',
response: ({body}:{body:any}) => {
return {
code: '00000',
message: '成功'
}
}
}
/**
* /**
* 数据库目录修改表
* @param {Object}
* @path /db-dir/table/update
* export const updateDbDirTable = (data) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/db-dir/table/update`,
method: 'post',
data
})
*/
export const updateDbDirTable = {
url: '/mock/db-dir/table/update',
method: 'post',
response: ({body}:{body:any}) => {
return {
code: '00000',
message: '成功'
}
}
}
/***
* /**
* 生成建表sql语句
* @param {Object}
* @path /db-dir/table/create-table-sql
* export const createTableSql = (data) => request({
url: `${import.meta.env.VITE_APP_CHECK_BASEURL}/db-dir/table/create-table-sql`,
method: 'post',
data
})
*/
export const createTableSql = {
url: '/mock/db-dir/table/create-table-sql',
method: 'post',
response: ({body}:{body:any}) => {
return {
code: '00000',
message: '成功',
data: 'create table test_table (id int, name varchar(255))'
}
}
}
export default [getCgDirTreeList,getCgDirFieldPageList, getDictionary,saveBizRuleConfig, getDbDirTreeList, getDbDirTablePageList] as MockMethod[]
export default [getCgDirTreeList,getCgDirFieldPageList,
getDictionary,saveBizRuleConfig, getDbDirTreeList,
getDbDirTablePageList,getDbDirDataSourceList,getDsTableByDs,
getDsTableStructure,getDbDirFieldPageList,getBizRuleConfigDetail,
updateBizRuleConfig,saveDbDirTable,createTableSql,updateDbDirTable] as MockMethod[]
......
......@@ -219,7 +219,7 @@ const routes: RouteRecordRaw[] = [
{
path: 'configure-rules',
name: 'configureRules',
component: () => import('@/views/data_inventory/configureRules.vue'),
component: () => import('@/views/data_inventory/configureRules1.vue'),
meta: {
title: '配置业务规则',
sidebar: false,
......@@ -230,10 +230,43 @@ const routes: RouteRecordRaw[] = [
activeMenu: '/data-inventory/classify-grade-catalogue',
},
},
{
path: 'table-create-existing',
name: 'tableCreateExisting',
component: () => import('@/views/data_inventory/tableCreateExisting.vue'),
meta: {
title: '已有表新建',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true
},
beforeEnter: (to, from) => {
if (to.query.domainName) {
to.meta.title = `已有表新建(${to.query.domainName})`;
to.meta.editPage = true;
}
}
},
{
path: 'table-create-file',
name: 'tableCreateFile',
component: () => import('@/views/data_inventory/tableCreateFile.vue'),
meta: {
title: '根据文件新建',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true
},
beforeEnter: (to, from) => {
}
},
],
},
{
path: '/data-standards/data-dictionary',
path: '/data-inventory/data-dictionary',
component: Layout,
meta: {
title: '数据字典',
......@@ -243,7 +276,7 @@ const routes: RouteRecordRaw[] = [
{
path: '',
name: 'dictionary',
component: () => import('@/views/data_standards/dictionary.vue'),
component: () => import('@/views/data_inventory/dictionary.vue'),
meta: {
title: '数据字典',
sidebar: false,
......
......@@ -101,6 +101,13 @@ const systemRoutes: RouteRecordRaw[] = [
// 动态路由(异步路由、导航栏路由)
const asyncRoutes: Route.recordMainRaw[] = [
{
meta:{
title: '首页',
},
children: [
],
},
{
meta: {
title: '数据资产管理',
},
......
......@@ -72,9 +72,12 @@ const tableInfo = ref({
return status == 'Y' ? '有效' : '停用';
}
},
{ label: "定义说明", width: 360, field: "description", },
{ label: "定义说明", width: 140, field: "description", },
{
label: "最低安全级别参考", field: "name", width: 140,
label: "最低安全级别参考", field: "name", width: 140, getName: (scope) => {
let dataGrade = scope.row.dataGrade;
return dataGrade + '级';
}
},
{ label: "修改人", field: "updateUserName", width: 140 },
{ label: "更新时间", field: "updateTime", width: 180 },
......@@ -386,6 +389,7 @@ const getGradeListData = async () => {
const newCreateClass = () => {
drawerInfo.value.visible = true;
classEditFormItems.value[2].options = treeListData.value;
drawerInfo.value.header.title = '添加分类';
classEditFormItems.value.forEach(item => {
if (item.field == 'status') {
......@@ -702,7 +706,7 @@ onMounted(() => {
style="margin-top:16px; height: calc(100% - 161px)">
<div class="tools_btns">
<el-button v-show="dataShowMethod == 'table'" type="primary" @click="newCreateClass">添加分类</el-button>
<el-button v-show="dataShowMethod == 'table'" @click="importClass">导入分类</el-button>
<!-- <el-button v-show="dataShowMethod == 'table'" @click="importClass">导入分类</el-button> -->
<el-button class="show-change-btn" @click="changeShowMethod">{{ '图形展示' }}</el-button>
</div>
<Table v-show="dataShowMethod == 'table'" :tableInfo="tableInfo" />
......
......@@ -31,14 +31,14 @@ const getGradeListData = async () => {
// 获取数据类别
const getDataGrade = async () => {
const params = {
paramCode: "DATA-CLASSIFY"
dictType: "数据类别"
}
const res: any = await getLargeCategoryList(params);
if (res.code == proxy.$passCode) {
// 提出value和label 作为select的options
const options = res.data.map((item: any) => ({
label: item.paramName,
value: item.paramValue
label: item.label,
value: item.value
}));
newCreateGradeFormItems.value[1].options = options;
classDataRef.value = options;
......@@ -50,14 +50,14 @@ const getDataGrade = async () => {
// 获取数据级别
const getDataClassify = async () => {
const params = {
paramCode: "DATA-GRADE"
dictType: "数据级别"
}
const res: any = await getLargeCategoryList(params);
if (res.code == proxy.$passCode) {
// 提出value和label 作为select的options
const options = res.data.map((item: any) => ({
label: item.paramName,
value: item.paramValue
label: item.label,
value: item.value
}));
newCreateGradeFormItems.value[0].options = options;
// 这里需要过滤已经在表格中数据级别
......
......@@ -5,11 +5,13 @@
<script lang="ts" setup name="classifyGradeCatalogue">
import { Warning } from "@element-plus/icons-vue";
import TableTools from '@/components/Tools/table_tools.vue';
import { getCgDirTreeList, getCgDirFieldPageList, getDictionary, saveBizRuleConfig, getDbDirTreeList, getDbDirTablePageList } from '@/api/modules/dataInventory';
import {
getCgDirTreeList, getCgDirFieldPageList, getDictionary, saveBizRuleConfig,
getDbDirTreeList, getDbDirTablePageList, getDbDirFieldPageList, getExecGuidAndName
} from '@/api/modules/dataInventory';
import { TableColumnWidth } from "@/utils/enum";
import router from "@/router";
const currentPath = ref<string[]>([]);
const { proxy } = getCurrentInstance() as any;
......@@ -76,10 +78,23 @@ const getDictionaryList = () => {
})
};
// 获取执行guid
const execGuidInfo = ref<any>({});
const getExecGuid = async () => {
const res: any = await getExecGuidAndName();
if (res.code == proxy.$passCode) {
execGuidInfo.value = res.data;
} else {
proxy.$ElMessage.error(res.msg);
}
}
onMounted(() => {
getCgDirTreeData();
getCgDirFieldPage();
getDictionaryList();
getExecGuid();
})
// 左侧tree-list
......@@ -124,20 +139,20 @@ const searchItemList = ref([
},
clearable: true,
},
{
label: '字段名',
type: 'select',
maxlength: 19,
placeholder: '选择字段名',
field: 'fieldName',
default: '',
options: [],
props: {
label: 'name',
value: 'guid',
},
clearable: true,
},
// {
// label: '字段名',
// type: 'select',
// maxlength: 19,
// placeholder: '选择字段名',
// field: 'fieldName',
// default: '',
// options: [],
// props: {
// label: 'name',
// value: 'guid',
// },
// clearable: true,
// },
{
label: '分类',
type: 'select',
......@@ -164,34 +179,7 @@ const searchItemList = ref([
value: 'guid',
},
clearable: true,
}, {
label: '数据库名',
type: 'select',
maxlength: 19,
placeholder: '选择数据库名',
field: 'databaseName',
default: '',
options: [],
props: {
label: 'name',
value: 'guid',
},
clearable: true,
},
{
label: '表名',
type: 'select',
maxlength: 19,
placeholder: '选择表名',
field: 'tableName',
default: '',
options: [],
props: {
label: 'name',
value: 'guid',
},
clearable: true,
}
])
const searchParams = ref({})
const toSearch = (val: any, clear: boolean = false) => {
......@@ -339,7 +327,7 @@ const batchControlRules = () => {
// 数据库目录
// 左侧tree-list
const dataBaseTreeInfo = ref({
const dataBaseTreeInfo = ref<any>({
id: "data-pickup-tree",
filter: true,
editTreeItem: false,
......@@ -376,9 +364,9 @@ const dataBaseTableInfo = ref({
fixedSelection: true,
fields: [
{ label: "序号", type: "index", width: 56, align: "center" },
{ label: "数据源", field: "databaseChName", width: 140 },
{ label: "表名称", field: "tableChName", width: 180 },
{ label: "数据库表", field: "enName", width: 120 },
{ label: "数据源", field: "cgDirName", width: 140 },
{ label: "表名称", field: "tableName", width: 180 },
{ label: "数据库表", field: "tableChName", width: 120 },
{
label: "新建方式", field: "foundMode", width: 140, getName: (scope) => {
let dataGrade = scope.row.foundMode;
......@@ -394,7 +382,7 @@ const dataBaseTableInfo = ref({
},
{ label: "任务修改人", field: "damName", width: 120 },
{ label: "修改时间", field: "updateTime", width: TableColumnWidth.DATETIME },
{ label: "描述", field: "databaseName", width: 120, align: 'center' },
{ label: "描述", field: "description", width: 120, align: 'center' },
{ label: "规划数据资产", field: "isDataAsset", type: 'switch', activeText: '是', inactiveText: '否', activeValue: 'Y', inactiveValue: 'N', switchWidth: 56, width: 120, align: 'center' },
],
......@@ -415,16 +403,15 @@ const dataBaseTableInfo = ref({
console.log('编辑', scope);
// 路由跳转configure-rules
router.push({
name: 'configure-rules',
name: 'configureRules',
query: {
guid: scope.row.guid,
cgDirName: scope.row.cgDirName,
tableName: scope.row.tableName,
tableChName: scope.row.tableChName,
databaseChName: scope.row.databaseChName,
databaseGuid: scope.row.databaseGuid,
tableGuid: scope.row.guid,
guid: scope.row.guid,
description: scope.row.description,
}
});
}
},
......@@ -646,6 +633,7 @@ const handleClick = (tab: any) => {
if (tab.props.name === 'second') {
getDataBaseTreeData();
getDataBaseTableData();
getDataBaseFieldData();
}
}
......@@ -656,9 +644,12 @@ const getDataBaseTreeData = async () => {
try {
const res: any = await getDbDirTreeList({});
if (res.code == proxy.$passCode) {
res.data.forEach(addGuids);
dataBaseTreeData.value = res.data;
dataBaseTreeInfo.value.data = res.data;
const dataArray = [res.data];
// 遍历并添加 GUIDs
dataArray.forEach(addGuids);
// 更新到绑定的响应式数据
dataBaseTreeData.value = dataArray;
dataBaseTreeInfo.value.data = dataArray;
} else {
proxy.$ElMessage.error(res.msg);
}
......@@ -668,8 +659,7 @@ const getDataBaseTreeData = async () => {
dataBaseTreeInfo.value.loading = false;
}
};
// 递归添加 GUID 的函数
// 处理数据,给每个节点添加 GUID
const addGuids = (node) => {
if (node.databaseGuid) {
node.guid = node.databaseGuid;
......@@ -687,6 +677,7 @@ const addGuids = (node) => {
}
};
// 获取数据列表
const dataBaseTableDataList = ref<any>();
const getDataBaseTableData = async (params = {}) => {
......@@ -696,6 +687,7 @@ const getDataBaseTableData = async (params = {}) => {
pageSize: 10,
databaseGuid: "",
isDataAsset: checked.value ? 'Y' : 'N',
execGuid: execGuidInfo.value.execGuid,
};
const finalParams = { ...dataBaseParams, ...params };
......@@ -723,9 +715,96 @@ const dataBaseTablePageChange = (info) => {
}
// 获取字段信息getDbDirFieldPageList
const tableFieldsLoading = ref(false);
const tableFieldsData = ref([]);
const getDataBaseFieldData = async (params = {}) => {
tableFieldsLoading.value = true;
const dataBaseParams = {
pageIndex: 1,
pageSize: 10,
tableGuid: "",
execGuid: execGuidInfo.value.execGuid,
databaseGuid: "",
isDataAsset: checked.value ? 'Y' : 'N',
};
const finalParams = { ...dataBaseParams, ...params };
const res: any = await getDbDirFieldPageList(finalParams);
if (res.code == proxy.$passCode) {
tableFieldsData.value = res.data.records;
tableFieldsDataInfo.value.data = res.data.records;
} else {
proxy.$ElMessage.error(res.msg);
}
tableFieldsLoading.value = false;
};
const tableFieldsDataInfo = ref({
id: "data-field-table",
multiple: false,
fixedSelection: true,
fields: [
{ label: "序号", type: "index", width: 56, align: "center" },
{ label: "字段名", field: "fieldName", width: 140 },
{ label: "字段中文名", field: "fieldChName", width: 180 },
{ label: "表名", field: "tableName", width: 120 },
{ label: "表中文名", field: "tableChName", width: 140, },
{ label: "数据库名称", field: "database", width: 120 },
{ label: "数据库中文名", field: "databaseChName", width: TableColumnWidth.DATETIME },
{ label: "分类", field: "description", width: 120, align: 'center' },
{ label: "分级", field: "isDataAsset", width: 120, align: 'center' },
{ label: "标签", field: "label", width: 120, align: 'center' },
],
data: [],
showPage: false,
page: {
// type: "normal",
// rows: 0,
// ...dataBasePage.value,
},
actionInfo: {
show: false,
},
loading: false
});
const showTableOrDatabase = ref(true);
// 定义tableGuid
const tableGuid = ref('');
const dataBaseGuid = ref('');
const dataBasenodeClick = (data: any) => {
console.log('dataBasenodeClick', data);
if (data.cgDirName) {
tableGuid.value = '';
dataBaseGuid.value = '';
getDataBaseFieldData();
getDataBaseTableData();
}
if (data.databaseGuid) {
dataBaseGuid.value = data.databaseGuid;
tableGuid.value = '';
getDataBaseFieldData({
databaseGuid: data.databaseGuid
});
getDataBaseTableData({
databaseGuid: data.databaseGuid
});
}
if (data.tableGuid) {
tableGuid.value = data.tableGuid;
dataBaseGuid.value = '';
getDataBaseFieldData({
tableGuid: data.tableGuid
});
getDataBaseTableData({
tableGuid: data.tableGuid
});
}
if (data.databaseGuid || data.cgDirName) {
showTableOrDatabase.value = true;
return;
......@@ -736,9 +815,28 @@ const dataBasenodeClick = (data: any) => {
}
}
const nodeSelectChange = (data: any) => {
console.log('nodeSelectChange', data);
}
const handleSubjectTableCommand = (command: string) => {
console.log('handleSubjectTableCommand', command);
if (command === 'manualCreate') {
router.push({
name: 'tableCreateFile',
query: {
type: 'tableCreateFile'
}
});
} else if (command === 'existingCreate') {
// 已有表新建
router.push({
name: 'tableCreateExisting',
query: {
execGuid: execGuidInfo.value.execGuid
}
});
}
}
// 文字提示区域
......@@ -760,11 +858,103 @@ const setActiveTab = (tab) => {
activeTab.value = tab;
};
// 模拟后端接口
const fetchOptionsA = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve([
{ label: "选项 A1", value: "a1" },
{ label: "选项 A2", value: "a2" },
]);
}, 500);
});
};
const fetchOptionsB = (aValue) => {
return new Promise((resolve) => {
setTimeout(() => {
const data = {
a1: [
{ label: "B1-1", value: "b1" },
{ label: "B1-2", value: "b2" },
],
a2: [
{ label: "B2-1", value: "b3" },
{ label: "B2-2", value: "b4" },
],
};
resolve(data[aValue] || []);
}, 500);
});
};
const fetchOptionsC = (bValue) => {
return new Promise((resolve) => {
setTimeout(() => {
const data = {
b1: [
{ label: "C1-1", value: "c1" },
{ label: "C1-2", value: "c2" },
],
b3: [
{ label: "C2-1", value: "c3" },
{ label: "C2-2", value: "c4" },
],
};
resolve(data[bValue] || []);
}, 500);
});
};
const selectedA = ref<any>(null);
const selectedB = ref<any>(null);
const selectedC = ref<any>(null);
const optionsA = ref<any>([]);
const optionsB = ref<any>([]);
const optionsC = ref<any>([]);
// 初始化加载第一个下拉框的选项
const loadOptionsA = async () => {
optionsA.value = await fetchOptionsA();
};
// 第一个下拉框值改变时
const onAChange = async () => {
selectedB.value = null;
selectedC.value = null;
optionsB.value = [];
optionsC.value = [];
optionsB.value = await fetchOptionsB(selectedA.value); // 根据 A 动态加载 B 的选项
};
// 第二个下拉框值改变时
const onBChange = async () => {
selectedC.value = null;
optionsC.value = [];
optionsC.value = await fetchOptionsC(selectedB.value); // 根据 B 动态加载 C 的选项
};
// 页面加载时初始化 A 的数据
loadOptionsA();
</script>
<template>
<div class="classification-template-content">
<div class="v-table-tools">
<el-select v-model="selectedA" placeholder="选择数据库名" @change="onAChange" style="width: 140px; margin-right: 8px"
clearable>
<el-option v-for="item in optionsA" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<el-select v-model="selectedB" placeholder="选择表名" :disabled="!selectedA" @change="onBChange"
style="width: 140px; margin-right: 8px" clearable>
<el-option v-for="item in optionsB" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<el-select v-model="selectedC" placeholder="选择字段名" :disabled="!selectedB" style="width: 140px;margin-right: 8px"
clearable>
<el-option v-for="item in optionsC" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
<TableTools :searchItems="searchItemList" :init="false" :searchId="'files-standard-search'" @search="toSearch" />
</div>
<div class="container_wrap full flex">
......@@ -774,7 +964,7 @@ const setActiveTab = (tab) => {
<Tree :treeInfo="treeInfo" @nodeClick="nodeClick" @itemMenuClick="handleTreeItemMenuClick" />
</el-tab-pane>
<el-tab-pane label="数据库目录" name="second">
<Tree :treeInfo="dataBaseTreeInfo" @nodeClick="dataBasenodeClick" />
<Tree :treeInfo="dataBaseTreeInfo" @nodeClick="dataBasenodeClick" @nodeSelectChange='nodeSelectChange' />
</el-tab-pane>
</el-tabs>
</div>
......@@ -838,7 +1028,9 @@ const setActiveTab = (tab) => {
字段信息
</div>
</div>
<div class="btns-area">
<div class="btns-area" v-if="!tableGuid && activeTab === 'table'">
<div class="left-btns">
<div class="dropdown_btn">
<el-dropdown popper-class="table-create-menu" @command="handleSubjectTableCommand"
......@@ -878,9 +1070,12 @@ const setActiveTab = (tab) => {
<el-checkbox v-model="checked" label="仅看规划数据资产表" size="large" @change="changeCheck" />
</div>
</div>
<div class="table_panel_wrap_database">
<div class="table_panel_wrap_database" v-if="!tableGuid && activeTab === 'table'">
<Table :tableInfo="dataBaseTableInfo" @tablePageChange="dataBaseTablePageChange" />
</div>
<div class="table_field" v-if="tableGuid || activeTab === 'word'">
<Table :tableInfo="tableFieldsDataInfo" :loading="tableFieldsLoading" />
</div>
</div>
<Drawer :drawerInfo="drawerInfo" @drawerBtnClick="drawerBtnClick" class="v-drawer" />
......@@ -898,6 +1093,8 @@ const setActiveTab = (tab) => {
flex-direction: column;
.v-table-tools {
display: flex;
align-items: center;
padding: 8px 12px;
}
......@@ -911,6 +1108,11 @@ const setActiveTab = (tab) => {
border-right: 1px solid #d9d9d9;
box-shadow: none;
:deep(.el-tabs__item) {
padding: 0 8px;
}
.v-tabs {
height: 100%;
......@@ -922,11 +1124,11 @@ const setActiveTab = (tab) => {
}
}
:deep(.v-tabs) {
.el-tabs__item {
padding: 0 10px;
}
}
// :deep(.v-tabs) {
// .el-tabs__item {
// padding: 0 12px;
// }
// }
.tree_panel {
height: 100%;
......@@ -1019,6 +1221,13 @@ const setActiveTab = (tab) => {
overflow: visible;
}
.table_field {
width: 100%;
height: calc(100% - 180px);
min-height: 210px;
overflow: visible;
}
/* 外层容器 */
.tab-btn {
display: flex;
......
<template>
<el-select v-if="!readonly && isEdit && isSelectType(dbType, scope)" v-model="scope.row['defaultValue']" placeholder="请选择" collapse-tags-tooltip
filterable allow-create default-first-option :reserve-keyword="false">
<el-option v-for="opt in optionsConfig[dataType]" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
</el-select>
<el-date-picker v-else-if="!readonly && isEdit && dataType === 'date'" v-model="scope.row['defaultValue']" type="date"
format="YYYY-MM-DD" value-format="YYYY-MM-DD" placeholder="请选择" />
<el-date-picker v-else-if="!readonly && isEdit && dbType === 'mysql' && dataType === 'datetime'"
v-model="scope.row['defaultValue']" placeholder="请选择" type="datetime" format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss" />
<el-input v-else-if="!readonly && isEdit" v-model.trim="scope.row['defaultValue']" placeholder="请填写"
@input="(val) => inputChange(val, scope.row.dataType, scope)" />
<span v-else>{{ scope.row["defaultValue"] == null ? '--' : (isSelectType(dbType, scope) ?
(optionsConfig[dataType].find(s => s.value == scope.row["defaultValue"])?.label ??
scope.row["defaultValue"]) : scope.row["defaultValue"]) }}</span>
</template>
<script lang="ts" setup name="tableDefaultValue">
import { ref } from "vue";
import { useDefault } from "@/hooks/useDefault";
const { optionsConfig, inputChange, isSelectType } = useDefault()
const props = defineProps({
dbType: {
type: String,
default: ''
},
scope: {
type: Object,
default: {}
},
readonly: {
type: Boolean,
default: false
}
})
const isEdit = computed(() => {
return props.scope.row['isEdit'];
});
const dataType = computed(() => {
return props.scope.row['dataType'];
});
</script>
\ No newline at end of file
<script lang="ts" setup name="uploadExcelFile">
import { ref } from "vue";
import { ElMessage, ElMessageBox, ElTable } from "element-plus";
import { TableColumnWidth } from '@/utils/enum';
import Moment from 'moment';
import { calcColumnWidth } from "@/utils/index";
import * as XLSX from 'xlsx';
import {
getImageContent
} from '@/api/modules/queryService';
const props = defineProps({
noUpload: {
type: Boolean,
default: false
}
})
const emits = defineEmits([
"fileDataChange"
]);
const noUpload = computed(() => props.noUpload)
const sheetList: any = ref([]);
const fileFormRef = ref();
/** 文件上传表单配置。 */
const fileFormItems: any = ref([
{
label: '选择文件上传',
tip: '支持扩展名:xlsx、xls,文件大小不超过20MB',
type: 'upload-file',
accept: '.xlsx, .xls',
limit: 1,
limitSize: 20,
isExcel: true,
required: true,
default: [],
field: 'file',
},
{
label: '选择sheet页',
type: 'select',
placeholder: '请选择',
field: 'sheet',
default: '',
options: sheetList,
required: true,
visible: true
},
]);
const fileFormRules = ref({
file: [{
validator: (rule: any, value: any, callback: any) => {
if (!value?.length) {
callback(new Error('请上传文件'))
} else {
callback();
}
}, trigger: 'change'
}],
sheet: [
{ required: true, trigger: 'change', message: "请选择sheet页" }
],
});
const uploadFileChange = (file) => {
fileTableFields.value = [];
fileTableData.value = [];
sheetList.value = [];
if (!file.length) {
fileTableFields.value = [];
fileTableData.value = [];
sheetList.value = [];
fileFormItems.value[1].options = sheetList.value;
fileFormItems.value[1].default = '';
fileFormItems.value[0].default = file;
fileWb.value = {};
emits("fileDataChange", fileTableFields.value, file, '', fileTableData.value);
return;
}
let fileRaw = file[0].file;
fileFieldLoading.value = true;
fileRaw.arrayBuffer().then((f) => {
const wb = XLSX.read(f, {
raw: false, cellDates: true
});
fileWb.value = wb;
console.log(wb);
sheetList.value = wb.SheetNames?.map(s => {
return {
value: s,
label: s
}
}) || [];
fileFormItems.value[1].options = sheetList.value;
fileFormItems.value[1].default = wb.SheetNames[0];
fileFormItems.value[0].default = file;
const sheet = wb.Sheets[wb.SheetNames[0]];
const json: any[] = XLSX.utils.sheet_to_json(sheet, { header: 1 });
if (json.length == 0) {
fileTableFields.value = [];
fileTableData.value = [];
} else {
fileTableFields.value = json[0]?.map((j, index) => {
return {
index: index,
enName: j + '',
chName: j + '',
dataType: 'varchar'
}
}) || [];
if (json.length > 1) {
fileTableData.value = json.slice(1, 51).map((info, row) => {
let object = {};
json[0].forEach((name, col) => {
if (info[col] === "" || info[col] == null) {
object[name] = info[col];
} else {
var cellRef = XLSX.utils.encode_cell({ r: row + 1, c: col });
var cell = sheet[cellRef];
object[name] = cell.w || info[col];
let isNum = cell.t == 'n';
if (isNum && fileTableFields.value[col].dataType != 'int') {
fileTableFields.value[col].dataType = 'int';
}
}
});
return object;
});
} else {
fileTableData.value = [];
}
}
fileFieldLoading.value = false;
emits("fileDataChange", fileTableFields.value, file, wb.SheetNames[0], fileTableData.value);
});
}
/** 切换sheet页 */
const handleSelectChange = (val, row, info) => {
if (!val) {
return;
}
let wb = fileWb.value;
const sheet = wb.Sheets[val];
const json: any[] = XLSX.utils.sheet_to_json(sheet, { header: 1 });
if (json.length == 0) {
fileTableFields.value = [];
fileTableData.value = [];
} else {
fileTableFields.value = json[0]?.map((j, index) => {
return {
index: index,
enName: j + '',
chName: j + '',
dataType: 'varchar'
}
}) || [];
if (json.length > 1) {
fileTableData.value = json.slice(1, 51).map((info, row) => {
let object = {};
json[0].forEach((name, col) => {
if (info[col] === "" || info[col] == null) {
object[name] = info[col];
} else {
var cellRef = XLSX.utils.encode_cell({ r: row + 1, c: col });
var cell = sheet[cellRef];
object[name] = cell.w || info[col];
let isNum = cell.t == 'n';
if (isNum && fileTableFields.value[col].dataType != 'int') {
fileTableFields.value[col].dataType = 'int';
}
}
});
return object;
});
} else {
fileTableData.value = [];
}
}
emits("fileDataChange", fileTableFields.value, info.file, val, fileTableData.value);
}
/** 上传文件之后解析出字段和数据 */
const fileFieldLoading = ref(false);
const fileTableFields: any = ref([]);
const fileTableData: any = ref([]);
/** 解析后的excel文件流信息,切换sheet页选择时使用。 */
const fileWb: any = ref({});
const getTextAlign = (field) => {
if (field.dataType === 'decimal' || field.dataType === 'int') {
return 'right';
}
return 'left'
}
/** otherWidth表示使用标题宽度时添加标题排序图标等宽度 */
const calcTableColumnWidth = (data: any[], prop, title, otherWidth = 0) => {
let d: any[] = [];
data.forEach((dt) => d.push(dt[prop]));
return calcColumnWidth(
d,
title,
{
fontSize: 14,
fontFamily: "SimSun",
},
{
fontSize: 14,
fontFamily: "SimSun",
},
otherWidth
);
};
/** 每列字段对应的列宽计算结果。 */
const originTableFieldColumn = ref({});
watch(
fileTableData,
(val: any[], oldVal) => {
if (!fileTableFields.value?.length) {
originTableFieldColumn.value = {};
return;
}
originTableFieldColumn.value = {};
fileTableFields.value.forEach((field, index) => {
originTableFieldColumn.value[field.enName] = calcTableColumnWidth(
val?.slice(0, 20) || [],
field.enName,
field.chName,
24
);
});
},
{
deep: true,
}
);
const formatterPreviewDate = (row, info) => {
let enName = info.enName;
let v = row[enName];
if (v === 0) {
return v;
}
if (!v) {
return v || '--';
}
if (info.dataType === 'datetime') {
return Moment(v).format('YYYY-MM-DD HH:mm:ss');
}
if (info.dataType === 'date') {
if (isNaN(<any>(new Date(v)))) {
return Moment(parseInt(v)).format('YYYY-MM-DD');
} else {
return Moment(v).format('YYYY-MM-DD');
}
}
return v;
};
const setFormValue = (v) => {
fileFormItems.value[1].default = v.sheetName || "";
let url = v.file?.[0]?.url;
if (fileFormItems.value[0].default?.[0]?.url !== url) {
fileFormItems.value[0].default = v.file || [];
//获取文件流去解析出数据和字段。
fileFieldLoading.value = true;
fileTableFields.value = [];
fileTableData.value = [];
getImageContent(url).then((res: any) => {
if (res && !res.msg) {
let urlNames = url.split('/');
let name = urlNames.at(-1);
let reader = new FileReader();
reader.onload = function (e) {
if (!e?.target) {
fileFieldLoading.value = false;
return;
}
let data = new Uint8Array(<any>e.target.result);
const wb = XLSX.read(data, { type: 'array', raw: false, cellDates: true });
fileWb.value = wb;
console.log(wb);
sheetList.value = wb.SheetNames?.map(s => {
return {
value: s,
label: s
}
}) || [];
fileFormItems.value[1].options = sheetList.value;
fileFormItems.value[1].default = v.sheetName || "";
const sheet = wb.Sheets[v.sheetName];
const json: any[] = XLSX.utils.sheet_to_json(sheet, { header: 1 });
if (json.length == 0) {
fileTableFields.value = [];
fileTableData.value = [];
} else {
fileTableFields.value = json[0]?.map((j, index) => {
return {
index: index,
enName: j + '',
chName: j + '',
dataType: 'varchar'
}
}) || [];
if (json.length > 1) {
fileTableData.value = json.slice(1, 51).map((info, row) => {
let object = {};
json[0].forEach((name, col) => {
if (info[col] === "" || info[col] == null) {
object[name] = info[col];
} else {
var cellRef = XLSX.utils.encode_cell({ r: row + 1, c: col });
var cell = sheet[cellRef];
object[name] = cell.w || info[col];
let isNum = cell.t == 'n';
if (isNum && fileTableFields.value[col].dataType != 'int') {
fileTableFields.value[col].dataType = 'int';
}
}
});
return object;
});
} else {
fileTableData.value = [];
}
}
fileFieldLoading.value = false;
};
reader.readAsArrayBuffer(res);
} else {
res?.msg && ElMessage.error(res?.msg);
}
})
}
}
defineExpose({
fileFormRef,
setFormValue
});
</script>
<template>
<div class="upload-main">
<div class="header-bg-title">选择文件上传</div>
<div class="form-main">
<Form ref="fileFormRef" :itemList="fileFormItems" :noUpload="noUpload" formId="file-form" :rules="fileFormRules"
@uploadFileChange="uploadFileChange" @select-change="handleSelectChange" />
</div>
<div class="header-bg-title">预览文件
<div class="preview-data-totals">
<span>该页面仅显示</span>
<span class="fontC-4fa1a4"> 50 </span>
<span>条数据</span>
</div>
</div>
<div class="table-main">
<el-table ref="tableRef" v-loading="fileFieldLoading" v-show="fileTableFields.length" :data="fileTableData"
:highlight-current-row="true" stripe border tooltip-effect="light" height="100%" row-key="guid"
:style="{ width: '100%', height: '100%' }">
<template v-for="(item, index) in (fileTableFields || [])">
<el-table-column :label="item.chName" :width="item.dataType === 'datetime'
? TableColumnWidth.DATETIME
: item.dataType === 'date'
? TableColumnWidth.DATE
: originTableFieldColumn[item.enName]
" :align="getTextAlign(item)" :header-align="getTextAlign(item)"
:formatter="(row) => formatterPreviewDate(row, item)" :show-overflow-tooltip="true">
</el-table-column>
</template>
</el-table>
<div v-show="!fileTableFields.length" class="empty-content">
<img src="../../../assets/images/empty-data.png" :style="{ width: '168px', height: '96px' }" />
<div class="empty-text">暂无数据</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.upload-main {
height: calc(100% - 96px);
}
.header-bg-title {
margin: 16px 16px 0px;
background: #F5F5F5;
padding-left: 16px;
height: 48px;
font-size: 14px;
color: #212121;
letter-spacing: 0;
line-height: 21px;
font-weight: 600;
display: flex;
align-items: center;
position: relative;
.preview-data-totals {
position: absolute;
right: 16px;
line-height: 32px;
font-size: 14px;
color: #666666;
font-weight: 400;
}
.fontC-4fa1a4 {
color: var(--el-color-primary);
}
}
.form-main {
border: 1px solid #d9d9d9;
margin: 0px 16px;
padding: 16px 16px 0px 16px;
height: 125px;
.dialog-form-inline {
align-items: flex-start;
}
:deep(.el-form) {
.item-label {
width: 100%;
}
.el-select {
max-width: 300px;
}
}
}
.table-main {
height: calc(100% - 253px);
border: 1px solid #d9d9d9;
margin: 0px 16px 16px 16px;
padding: 16px;
}
.empty-content {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
flex-direction: column;
.empty-text {
font-size: 14px;
color: #b2b2b2;
}
}
:deep(.upload-file .el-upload-list) {
.el-upload-list__item {
&:first-child {
display: flex;
}
display: none
}
}
</style>
\ No newline at end of file
......@@ -3,85 +3,423 @@
</route>
<script lang="ts" setup name="configureRules">
import { TableColumnWidth } from '@/utils/enum';
const dataBasePage = ref({
limit: 10,
curr: 1,
sizes: [
{ label: "10", value: 10 },
{ label: "20", value: 20 },
{ label: "100", value: 100 },
{ label: "150", value: 150 },
{ label: "200", value: 200 },
],
});
const dataBaseTableInfo = ref({
id: "data-base-table",
multiple: false,
fixedSelection: true,
fields: [
{ label: "序号", type: "index", width: 56, align: "center" },
{ label: "数据源", field: "databaseChName", width: 140 },
{ label: "表名称", field: "tableChName", width: 180 },
{ label: "数据库表", field: "enName", width: 120 },
{
label: "新建方式", field: "foundMode", width: 140, getName: (scope) => {
let dataGrade = scope.row.foundMode;
return dataGrade == 1 ? '根据文件新建' : '已有表新建';
import { ref } from "vue";
import router from "@/router";
import { getBizRuleConfigDetail, updateBizRuleConfig } from '@/api/modules/dataInventory'
const { proxy } = getCurrentInstance() as any;
const bizRuleConfigData = ref<any>()
const getBizRuleConfigDetailData = async () => {
const params = {
tableGuid: router.currentRoute.value.query.guid,
execGuid: router.currentRoute.value.query.execGuid
}
const res: any = await getBizRuleConfigDetail(params)
if (res.code === proxy.$passCode) {
bizRuleConfigData.value = res.data
// 每条数据添加一个isEdit: false 属性,用于判断是否进入编辑模式
bizRuleConfigData.value.forEach((item: any) => {
item.isEdit = false
})
tableData.value = bizRuleConfigData.value
} else {
proxy.$message.error(res.msg)
}
}
onMounted(() => {
getBizRuleConfigDetailData()
})
const tableData1 = ref([
{
cgDirName: router.currentRoute.value.query.cgDirName,
tableName: router.currentRoute.value.query.tableName,
tableChName: router.currentRoute.value.query.tableChName,
description: router.currentRoute.value.query.description,
},
])
// 表格数据
const tableData = ref()
// 配置哪些字段可编辑
const editableFields = {
fieldName: true, // 字段中文名可编辑
length: true, // 长度可编辑
isUnique: true, // 数据是否唯一可编辑
fieldPrecision: true, // 精度可编辑
dictionaryGuid: true, // 关联字典可编辑
}
const tableFieldsLoading = ref(false)
const selectedRows = ref([]);
// 监听选中行
const selectionFieldsChange = (selection) => {
console.log('selection', selection)
selectedRows.value = selection;
};
// 上移功能
const moveUp = () => {
// 1. 找到选中行在 tableData 中的索引
const selectedIds = selectedRows.value.map((row: any) => row.id);
// 2. 遍历选中行,按顺序上移
for (let i = 0; i < tableData.value.length; i++) {
const currentRow = tableData.value[i];
// 如果当前行被选中,且不是第一行,则交换位置
if (selectedIds.includes(currentRow.id) && i > 0) {
const previousRow = tableData.value[i - 1];
// 如果上一行没有被选中,交换位置
if (!selectedIds.includes(previousRow.id)) {
[tableData.value[i], tableData.value[i - 1]] = [tableData.value[i - 1], tableData.value[i]];
}
},
{
label: "状态", field: "state", type: 'tag', width: 180, getName: (scope) => {
let status = scope.row.state;
// 0 草稿中 1 已建表 2 已有默认表
return status == 0 ? '草稿中' : status == 1 ? '已建表' : '已有默认表';
}
}
};
// 下移功能
const moveDown = () => {
// 1. 找到选中行在 tableData 中的索引
const selectedIds = selectedRows.value.map((row: any) => row.id);
// 2. 遍历选中行,倒序下移
for (let i = tableData.value.length - 1; i >= 0; i--) {
const currentRow = tableData.value[i];
// 如果当前行被选中,且不是最后一行,则交换位置
if (selectedIds.includes(currentRow.id) && i < tableData.value.length - 1) {
const nextRow = tableData.value[i + 1];
// 如果下一行没有被选中,交换位置
if (!selectedIds.includes(nextRow.id)) {
[tableData.value[i], tableData.value[i + 1]] = [tableData.value[i + 1], tableData.value[i]];
}
},
{ label: "任务修改人", field: "damName", width: 120 },
{ label: "修改时间", field: "updateTime", width: TableColumnWidth.DATETIME },
{ label: "描述", field: "databaseName", width: 120, align: 'center' },
{
label: "规划数据资产", field: "isDataAsset", type: 'switch', activeText: '是', inactiveText: '否', activeValue: 'Y',
inactiveValue: 'N', switchWidth: 56, width: 120, align: 'center'
},
],
data: [],
page: {
type: "normal",
rows: 0,
...dataBasePage.value,
}
}
};
// 编辑行
const editRow = (row) => {
if (!row.isEdit) {
const [symbol, value] = row.fieldLengthCondition.split('#');
row.lengthSymbol = symbol; // 初始化符号部分
row.lengthValue = value; // 初始化数值部分
row.isEdit = true; // 进入编辑模式
}
};
// 保存数据
const saveRow = (row) => {
row.fieldLengthCondition = `${row.lengthSymbol}#${row.lengthValue}`;
row.isEdit = false
}
// 删除行
const deleteRow = (index) => {
tableData.value.splice(index, 1)
}
// 批量删除功能
const batchDelete = () => {
selectedRows.value.forEach((row: any) => {
const index = tableData.value.findIndex((item) => item.id === row.id);
if (index !== -1) tableData.value.splice(index, 1);
});
selectedRows.value = [];
};
const data = [
{
value: '1',
label: 'Level one 1',
children: [
{
value: '1-1',
label: 'Level two 1-1',
children: [
{
value: '1-1-1',
label: 'Level three 1-1-1',
},
],
},
],
},
{
value: '2',
label: 'Level one 2',
children: [
{
value: '2-1',
label: 'Level two 2-1',
children: [
{
value: '2-1-1',
label: 'Level three 2-1-1',
},
],
},
{
value: '2-2',
label: 'Level two 2-2',
children: [
{
value: '2-2-1',
label: 'Level three 2-2-1',
},
],
},
],
},
actionInfo: {
label: "操作",
type: "btn",
width: 300,
fixed: 'right',
btns: [
{
value: '3',
label: 'Level one 3',
children: [
{
value: '3-1',
label: 'Level two 3-1',
children: [
{
value: '3-1-1',
label: 'Level three 3-1-1',
},
],
},
{
label: "配置业务规则", value: "edit", click: (scope) => {
console.log('编辑', scope);
// 路由跳转configure-rules
value: '3-2',
label: 'Level two 3-2',
children: [
{
value: '3-2-1',
label: 'Level three 3-2-1',
},
],
},
],
},
]
const saveData = async () => {
}
},
/**入参
* "guid": "string",
"fieldGuid": "string",
"fieldLengthCondition": "string",
"fieldPrecision": 0,
"dictionaryGuid": "string",
"isUnique": "string",
"isNotNull": "string",
"fieldValueRange": "string"
*/
const params = tableData.value.map((item: any) => {
return {
guid: item.guid,
fieldGuid: item.fieldGuid,
fieldLengthCondition: item.fieldLengthCondition,
fieldPrecision: item.fieldPrecision,
dictionaryGuid: item.dictionaryGuid,
isUnique: item.isUnique,
isNotNull: item.isNotNull,
fieldValueRange: item.fieldValueRange
}
})
const res: any = await updateBizRuleConfig(params)
if (res.code === proxy.$passCode) {
proxy.$message.success('修改配置规则成功!')
router.back()
} else {
proxy.$message.error(res.msg)
}
}
{
label: "编辑表结构", value: "copy", click: (scope) => {
console.log('复制', scope);
}
}
]
const cancel = () => {
router.back()
}
},
loading: false
});
</script>
<template>
<div class="table_panel_wrap">
<Table :tableInfo="dataBaseTableInfo" />
<div class="configure-rules">
<div class="table_panel_wrap">
<el-table :data="tableData1" :highlight-current-row="true" stripe border height="100%" row-key="guid"
tooltip-effect="light" :style="{
width: '100%',
'max-height': 'calc(100% - 16px)',
display: 'inline-block',
}">
<el-table-column prop="cgDirName" label="数据源" width="180" />
<el-table-column prop="tableName" label="表名称" width="180" />
<el-table-column prop="tableChName" label="数据库表" width="280" />
<el-table-column prop="description" label="描述" width="180" show-overflow-tooltip />
</el-table>
</div>
<div class="btn-area">
<el-button @click="moveUp">上移</el-button>
<el-button @click="moveDown">下移</el-button>
<el-button @click="batchDelete">批量删除</el-button>
</div>
<div class="bottom_table">
<el-table :data="tableData" v-loading="tableFieldsLoading" :highlight-current-row="true" stripe border
height="100%" row-key="guid" @selection-change="selectionFieldsChange" tooltip-effect="light" :style="{
width: '100%',
'max-height': 'calc(100% - 16px)',
display: 'inline-block',
}">
<el-table-column type="selection" :width="32" align="center" />
<!-- 排序列(不可编辑) -->
<el-table-column prop="index" label="排序" width="80" align="center" />
<!-- 字段中文名(不可编辑)fieldChName -->
<el-table-column prop="fieldName" label="字段中文名" width="120">
<template #default="scope">
{{ scope.row.fieldName ? scope.row.fieldName : '--' }}
</template>
</el-table-column>
<!-- 字段英文名(不可编辑) -->
<el-table-column prop="fieldEnglish" label="字段英文名" width="120">
<template #default="scope">
{{ scope.row.fieldEnglish ? scope.row.fieldEnglish : '--' }}
</template>
</el-table-column>
<!-- 分类(不可编辑)classifyName -->
<el-table-column prop="fieldEnglish" label="分类" width="120">
<template #default="scope">
{{ scope.row.fieldEnglish ? scope.row.fieldEnglish : '--' }}
</template>
</el-table-column>
<!-- 分级(不可编辑) -->
<el-table-column prop="gradeDetailName" label="分级" width="120" align="center">
<template #default="scope">
{{ scope.row.gradeDetailName ? scope.row.gradeDetailName : '--' }}
</template>
</el-table-column>
<!-- 字段类型fieldType (不可编辑) -->
<el-table-column prop="fieldType" label="字段类型" width="150" align="center">
<template #default="scope">
{{ scope.row.fieldType ? scope.row.fieldType : '--' }}
</template>
</el-table-column>
<!-- 长度列 fieldLengthCondition: '>#10',-->
<el-table-column prop="fieldLengthCondition" label="长度" width="240" align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit">{{ scope.row.fieldLengthCondition || '--' }}</span>
<div v-else>
<el-select v-model="scope.row.lengthSymbol" placeholder="请选择" style="width: 50%;margin-right: 8px;">
<el-option label="大于" value=">"></el-option>
<el-option label="等于" value="="></el-option>
<el-option label="小于" value="<"></el-option>
</el-select>
<el-input v-model="scope.row.lengthValue" placeholder="请输入" style="width: 45%;" />
</div>
</template>
</el-table-column>
<!-- 精度列 -->
<!-- <el-table-column prop="fieldPrecision" label="精度" width="240" align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit">{{ scope.row.fieldPrecision || '--' }}</span>
<div v-else>
<el-select v-model="scope.row.fieldPrecision" placeholder="请选择" style="width: 50%;margin-right: 8px;">
<el-option label="<=500" value="<=500"></el-option>
<el-option label=">500" value=">500"></el-option>
</el-select>
<el-input v-model="scope.row.precisionValue" placeholder="请输入" style="width: 45%;" />
</div>
</template>
</el-table-column> -->
<!-- 精度(可编辑)fieldPrecision -->
<el-table-column prop="fieldPrecision" label="精度" width="120" align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit || !editableFields.fieldPrecision">{{
scope.row.fieldPrecision ? scope.row.fieldPrecision : '--' }}</span>
<el-input v-else v-model="scope.row.fieldPrecision" placeholder="请输入精度" />
</template>
</el-table-column>
<!-- 关联字典(可编辑)el-tree-select 形式下拉形式 -->
<el-table-column prop="dictionaryGuid" label="关联字典" width="150" align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit || !editableFields.dictionaryGuid">{{ scope.row.isDict ? scope.row.isDict :
'--' }}</span>
<el-tree-select v-else v-model="scope.row.isDict" :data="data" placeholder="请选择" />
</template>
</el-table-column>
<!-- 数据是否唯一(可编辑) -->
<el-table-column prop="isUnique" label="数据是否唯一" width="150" align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit || !editableFields.isUnique">{{ scope.row.isUnique ? scope.row.isUnique : '--'
}}</span>
<el-select v-else v-model="scope.row.isUnique" placeholder="请选择">
<el-option label="是" value="Y" />
<el-option label="否" value="N" />
</el-select>
</template>
</el-table-column>
<!-- 是否必填(可编辑) -->
<el-table-column prop="isRequired" label="是否必填" width="120" align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit">{{ scope.row.isRequired ? scope.row.isRequired : '--' }}</span>
<el-select v-else v-model="scope.row.isRequired" placeholder="请选择">
<el-option label="是" value="Y" />
<el-option label="否" value="N" />
</el-select>
</template>
</el-table-column>
<!-- 字段取值范围 fieldValueRange(可编辑)-->
<el-table-column prop="fieldValueRange" label="字段取值范围" width="150" align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit">{{ scope.row.fieldValueRange ? scope.row.fieldValueRange : '--' }}</span>
<el-input v-else v-model="scope.row.fieldValueRange" placeholder="请输入字段取值范围" />
</template>
</el-table-column>
<!-- 操作列 -->
<el-table-column label="操作" width="100" align="center" fixed="right">
<template #default="scope">
<span class="text_btn" v-if="!scope.row.isEdit" @click="editRow(scope.row)">编辑</span>
<span class="text_btn" v-else @click="saveRow(scope.row)">保存</span>
<el-divider direction="vertical" />
<span class="text_btn" @click="deleteRow(scope.$index)">删除</span>
</template>
</el-table-column>
</el-table>
</div>
<div class="botton_btn">
<el-button type="primary" @click="saveData">保存</el-button>
<el-button @click="cancel">取消</el-button>
</div>
</div>
</template>
<style lang="scss" scoped>
.configure-rules {
padding: 16px;
height: 100%;
.table_panel_wrap {
width: 100%;
height: auto;
overflow: visible;
}
.btn-area {
margin-top: 12px;
}
:deep(.bottom_table) {
margin-top: 12px;
height: calc(100% - 150px);
overflow-y: auto;
.el-table td.el-table__cell {
padding: 2px 0;
height: 36px;
}
}
}
</style>
......
......@@ -123,7 +123,7 @@ const treeInfo = ref<any>({
filter: true,
queryValue: "",
className: 'tree-list',
queryPlaceholder: "输入标准集名称搜索",
queryPlaceholder: "输入目录名称搜索",
props: {
label: "classifyName",
value: "guid",
......
<route lang="yaml">
name: dictFileds
</route>
<script lang="ts" setup name="dictFileds">
import { ref } from 'vue'
import router from '@/router'
import { ElMessage, ElMessageBox } from "element-plus";
import Table from '@/components/Table/index.vue'
// import Dialog from '@/components/Dialog/index.vue'
import useCatchStore from "@/store/modules/catch";
import { chunk } from '@/utils/common'
import {
saveDictionaryData,
getDictionaryFileds,
deleteDictionaryData,
checkDictionaryData,
showDictionary,
getDictionaryRuleData
} from '@/api/modules/dataInventory';
const emits = defineEmits(["exportData"])
const { proxy } = getCurrentInstance() as any;
const cacheStore = useCatchStore()
const dictionaryGuid = ref("")
const tableSearchInput = ref('')
const tableFields: any = ref([])
const orginData: any = ref([])
const currTableData: any = ref<Object>({});
const selectRowData = ref([])
const page = ref({
limit: 50,
curr: 1,
// sizes: [
// { label: "100", value: 100 },
// { label: "200", value: 200 },
// { label: "300", value: 300 },
// { label: "400", value: 400 },
// { label: "500", value: 500 },
// ],
});
const tableChunkData: any = ref([])
const tableData: any = ref([])
const tableInfo: any = ref({
id: 'data-fileds-table',
multiple: true,
fields: [],
data: [],
page: {
type: "count",
rows: 0,
...page.value,
},
// showPage: false,
actionInfo: {
label: "操作",
type: "btn",
width: 92,
btns: (scope) => {
return [
{ label: "编辑", value: "edit", visible: scope.row['STATE'] !== 'Running' },
{ label: "删除", value: "remove", visible: scope.row['STATE'] !== 'Running' },
{ label: "保存", value: "save", visible: scope.row['STATE'] === 'Running' },
{ label: "取消", value: "cancel", visible: scope.row['STATE'] === 'Running' },
]
},
},
editInfo: {},
loading: false
})
const uploadFiles = ref([])
const uploadInfo = ref({
type: 'upload',
title: '',
col: '',
uploadInfo: {
id: 'upload-file-form',
type: 'panel',
action: '',
auto: false,
cover: true,
fileList: [],
accept: '.xlsx, .xls',
triggerBtn: {
label: '导入',
value: 'import_file',
icon: 'Upload',
},
tips: '当前支持xls、xlsx文件,默认使用第一个sheet'
},
})
const dialogInfo = ref({
visible: false,
size: 640,
direction: "column",
header: {
title: "新建",
},
type: '',
contents: [
uploadInfo.value
],
footer: {
visible: true,
btns: [
{ type: "default", label: "取消", value: "cancel" },
{ type: "primary", label: "开始导入", value: "submit" },
],
},
})
const getFirstPageData = () => {
toSearch({})
}
const toSearch = (val: any, clear: boolean = false) => {
let params = dictionaryGuid.value
getTableData(params);
};
const getTableData = (params) => {
tableInfo.value.loading = true
getDictionaryFileds(params).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data ?? {}
setUploadDataInfo(data, true)
} else {
ElMessage({
type: 'error',
message: res.msg,
})
}
tableInfo.value.loading = false
}).catch(xhr => {
tableInfo.value.loading = false
})
};
const tableSelectionChange = (val, tId) => {
selectRowData.value = val;
};
const tablePageChange = (info) => {
page.value.curr = Number(info.curr);
if (page.value.limit != Number(info.limit)) {
page.value.limit = Number(info.limit);
chunkData()
} else {
tableData.value = tableChunkData.value[page.value.curr - 1]
tableInfo.value.data = tableData.value
tableInfo.value.page.limit = page.value.limit
tableInfo.value.page.curr = page.value.curr
}
};
const toolBtnClick = (btn) => {
const type = btn.value
if (type == 'export') {
exportData()
} else if (type == 'import') {
const info = {
type: 'dictionary',
dictionaryGuid: dictionaryGuid.value
}
cacheStore.setCatch('uploadSetting', info)
nextTick(() => {
router.push({
path: '/data-standards/import-file',
});
})
} else if (type == 'submit') {
saveData()
} else if (type == 'add_row') {
const params = {
guid: dictionaryGuid.value
}
getDictionaryRuleData(params).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data ?? {}
let rowInfo: any = {}
tableFields.value.map(item => {
rowInfo[item.field] = data[item.field] ?? ''
})
rowInfo.guid = undefined;
rowInfo.STATE = 'Running'
rowInfo.STATUS = 'edit'
rowInfo.ROWID = `upload_${tableData.value.length}`
tableData.value.unshift(rowInfo)
orginData.value.unshift(rowInfo)
tableInfo.value.page.rows = tableData.value.length
// orginData.value.unshift(rowInfo)
// page.value.curr = 1
// chunkData()
} else {
ElMessage({
type: 'error',
message: res.msg
})
}
})
}
}
const tableBtnClick = (scope, btn) => {
const type = btn.value;
let row = scope.row;
currTableData.value = row;
if (type == "edit") {
row.STATE = 'Running'
row.STATUS = 'edit'
tableData.value[scope.$index] = row
} else if (type == 'save') {
saveData(scope)
} else if (type == 'cancel') {
if (row.guid != undefined) {
// row = orginData.value[(page.value.curr - 1) * page.value.limit + scope.$index]
row = JSON.parse(JSON.stringify(orginData.value[scope.$index]))
row.STATE = ''
row.STATUS = ''
tableData.value[scope.$index] = row
} else {
tableData.value.splice(scope.$index, 1)
orginData.value.splice(scope.$index, 1)
// orginData.value.splice((page.value.curr - 1) * page.value.limit + scope.$index, 1)
// if (scope.$index == 0) {
// page.value.curr = (page.value.curr - 1 > 1) ? page.value.curr - 1 : 1
// }
// chunkData()
}
tableInfo.value.page.rows = tableData.value.length
} else if (type == 'remove') {
open("是否确定删除所选数据?", "warning");
}
};
const onUpload = (file, fileList) => {
uploadFiles.value = fileList
}
const uploadBtnClick = (btn) => {
exportData('model')
}
const exportData = (type: any = null) => {
emits('exportData', type)
}
const importData = (file: any = null) => {
let params = new FormData()
if (file) {
params.append("file", file.raw);
} else {
if (uploadFiles.value.length) {
uploadFiles.value.forEach((item: any, index: number) => {
params.append("file", item.raw);
});
}
}
params.append("dictionaryGuid", dictionaryGuid.value);
showDictionary(params).then((res: any) => {
if (res.code == proxy.$passCode) {
dialogInfo.value.visible = false
let data = res.data ?? []
// data.map((item: any, i) => {
// item.index = tableData.value.length + i
// })
const tData = { jsonArray: data }
setUploadDataInfo(tData)
// saveData(null, tData)
} else {
ElMessage({
type: "error",
message: res.msg,
});
// dialogInfo.value.footer.btns.map((item: any) => delete item.disabled)
}
}).catch(() => {
// dialogInfo.value.footer.btns.map((item: any) => delete item.disabled)
});
}
const checkSave = () => {
const toSaveData = tableData.value.filter(item => item.STATE === 'Running')
return toSaveData.length == 0 ? true : false
}
const checkParamsData = (scope: any = null) => {
let addJsonArray: any = [], upJsonArray: any = [], jsonArray: any = [], pass = true
let passArr = scope ? [scope.row] : tableData.value
passArr.map((item, index) => {
const obj = JSON.parse(JSON.stringify(item))
delete obj.STATUS
delete obj.NOTES
delete obj.STATE
delete obj.ROWID
// if (item.STATE === 'Running') {
for (var i in obj) {
if (obj[i] == '') {
pass = false
}
}
// }
if (obj.guid !== undefined) {
upJsonArray.push(obj)
} else {
addJsonArray.push(obj)
}
if (scope) {
obj.index = scope.$index
jsonArray.push(obj)
} else {
obj.index = index
jsonArray.push(obj)
}
})
return { pass, addJsonArray, upJsonArray, jsonArray }
}
const saveData = async (scope: any = null, checkParamData: any = null) => {
let passInfo: any = {}
if (checkParamData) {
passInfo = checkParamData
} else {
passInfo = await checkParamsData(scope)
if (!passInfo.pass) {
// ElMessage({
// type: 'error',
// message: '请填写所有数据项'
// })
// return
}
}
const checkParams = {
dictionaryGuid: dictionaryGuid.value,
addJsonArray: passInfo.jsonArray
}
checkDictionaryData(checkParams).then((res: any) => {
if (res.code == proxy.$passCode) {
const data = res.data
if (Object.keys(data).length) {
addColumn(data)
} else {
addColumn()
const params = {
dictionaryGuid: dictionaryGuid.value,
addJsonArray: passInfo.addJsonArray,
upJsonArray: passInfo.upJsonArray
}
saveDictionaryData(params).then((res: any) => {
if (res.code == proxy.$passCode) {
getFirstPageData();
ElMessage({
type: 'success',
message: '保存成功'
})
} else {
ElMessage({
type: 'error',
message: res.msg,
})
}
})
}
} else {
ElMessage({
type: 'error',
message: res.msg,
})
}
})
}
const addColumn = (info: any = null) => {
const fields = tableFields.value
const existIndex = fields.findIndex(item => item.field == 'NOTES')
if (info) {
if (existIndex == -1) {
fields.push({
label: '备注',
field: 'NOTES',
width: 200
})
}
for (var d in info) {
tableData.value[d].NOTES = info[d].join(',')
}
} else {
if (existIndex > -1) {
fields.splice(existIndex, 1)
}
}
}
// 生成表头
const setUploadDataFields = (data) => {
let fields: any = [], editInfo: any = {}
data.map(item => {
let fieldItem: any = {
label: item.description, field: item.fieldName, width: 140
}
fieldItem.type = 'edit'
fieldItem.columClass = 'edit-colum'
editInfo[item.fieldName] = {
label: '',
type: 'input',
placeholder: '',
maxlength: 50,
field: item.fieldName,
default: '',
disabled: item.codeRuleGuid ? true : false,
clearable: true,
}
fields.push(fieldItem)
})
tableFields.value = fields
tableInfo.value.fields = tableFields.value
tableInfo.value.editInfo = editInfo
}
// 生成表数据
const setUploadDataInfo = async (info, setField = false) => {
if (setField) {
const fields = info.schemaDataVOS ?? []
await setUploadDataFields(fields)
}
let data = info.jsonArray ?? []
// 设置表数据
data.map((item, i) => {
item.ROWID = `upload_${tableData.value.length + i}`
})
if (setField) {
tableData.value = data
} else {
tableData.value = [...tableData.value, ...data]
}
orginData.value = JSON.parse(JSON.stringify(tableData.value))
tableInfo.value.data = tableData.value
tableInfo.value.page.rows = tableData.value.length
// if (setField) {
// orginData.value = data
// } else {
// orginData.value = [...orginData.value, ...data]
// }
// chunkData()
}
const chunkData = () => {
const data = orginData.value
tableChunkData.value = chunk(data, page.value.limit)
tableData.value = tableChunkData.value[page.value.curr - 1]
tableInfo.value.data = tableData.value
tableInfo.value.page.limit = page.value.limit
tableInfo.value.page.curr = page.value.curr
tableInfo.value.page.rows = orginData.value.length
}
const batching = (type) => {
if (type == 'delete') {
if (selectRowData.value.length == 0) {
ElMessage({
type: 'error',
message: '请选择需要删除的数据',
})
return
}
open("是否确定删除所选数据?", "warning", true);
}
};
const open = (msg, type, isBatch = false) => {
ElMessageBox.confirm(msg, "提示", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: type,
}).then(() => {
let guids: any = []
if (isBatch) {
const list = selectRowData.value.filter((item: any) => item.guid !== undefined)
if (list.length) {
guids = list.map((l: any) => l.guid)
}
const newRows = selectRowData.value.filter((item: any) => item.guid == undefined)
newRows.map((n: any, r) => {
const existIndex = tableData.value.findIndex(t => t.ROWID == n.ROWID)
if (existIndex > -1) {
tableData.value.splice(existIndex, 1)
orginData.value.splice(existIndex, 1)
}
// const existIndex = orginData.value.findIndex(t => t.id == n.id)
// existIndex > -1 && orginData.value.splice(existIndex, 1)
// if (r == newRows.length - 1) {
// page.value.curr = 1
// chunkData()
// }
})
tableInfo.value.page.rows = tableData.value.length
} else {
guids = [currTableData.value.guid]
}
if (guids.length) {
const params = {
guid: dictionaryGuid.value,
delGuids: guids
}
deleteDictionaryData(params).then((res: any) => {
if (res.code == proxy.$passCode) {
getFirstPageData();
ElMessage({
type: "success",
message: "删除成功",
});
} else {
ElMessage({
type: "error",
message: res.msg,
});
}
});
}
});
};
const dialogBtnClick = (btn, info) => {
if (btn.value == 'submit') {
// dialogInfo.value.footer.btns.map((item: any) => item.disabled = true)
importData()
} else if (btn.value == 'cancel') {
// dialogInfo.value.footer.btns.map((item: any) => delete item.disabled)
nextTick(() => {
dialogInfo.value.visible = false;
})
}
};
defineExpose({
dictionaryGuid,
getFirstPageData,
checkSave
});
</script>
<template>
<div class="container_wrap full flex">
<div class="main_wrap">
<div class="table_tool_wrap">
<div class="tools_btns">
<el-button type="primary" @click="toolBtnClick({ value: 'add_row' })" v-preReClick>新增行</el-button>
<el-button type="primary" plain @click="toolBtnClick({ value: 'submit' })" v-preReClick>保存数据</el-button>
<el-button @click="batching('delete')" v-preReClick>批量删除</el-button>
<el-button @click="toolBtnClick({ value: 'import' })" v-preReClick>导入数据</el-button>
<el-button @click="toolBtnClick({ value: 'export' })" v-preReClick>导出数据</el-button>
</div>
<!-- <el-input class="table_search_input" v-model.trim="tableSearchInput" placeholder="输入名称搜索" :suffix-icon="Search" clearable
@change="val => toSearch({})" /> -->
</div>
<div class="table_panel_wrap full">
<Table :tableInfo="tableInfo" @tableBtnClick="tableBtnClick" @tableSelectionChange="tableSelectionChange"
@tablePageChange="tablePageChange" />
</div>
</div>
<!-- <Dialog :dialogInfo="dialogInfo" @btnClick="dialogBtnClick" @onUpload="onUpload" @uploadBtnClick="uploadBtnClick" /> -->
</div>
</template>
<style lang="scss" scoped>
.container_wrap {
width: calc(100% - 200px);
.main_wrap {
width: 100%;
.table_panel_wrap {
height: calc(100% - 44px);
}
}
}
</style>
<script lang="ts" setup name="existingTableSelect">
import { ref } from "vue";
import { Search, Close } from "@element-plus/icons-vue";
import { ElMessage, ElTable } from "element-plus";
import PageNav from "@/components/PageNav/index.vue";
import Moment from 'moment';
import {
getDsTableByDs,
getDsData,
getDsTableStructure,
} from "@/api/modules/dataInventory";
/** 需要从父组件接收已选中的数据表 和 数据库列表(由父组件获取,只需获取一次,因为父组件也需要使用)。 */
const props = defineProps({
databaseList: {
type: Array<any>,
default: [],
},
dataSourceGuid: {
type: String,
default: ''
},
dsList: {
type: Array<any>,
default: [],
},
isLook: {
type: Boolean,
default: false,
},
tableCreateType: {
type: Number,
default: 2,
},
subjectDomainGuid: {
type: String,
default: ''
},
execGuid: {
type: String,
default: ''
}
});
watch(() => { }, () => {
// datasourceSelectedRows.value = props.dsList?.slice(0) || [];
let selectTableName = currDatasourceSelect.value?.tableName;
if (selectTableName) {
let ds = datasourceSelectedRows.value?.find(d => d.tableName === selectTableName);
if (!ds) {
currDatasourceSelect.value = {};
}
}
})
const datasourceSelectedRows: any = ref([]);
const emits = defineEmits(["datasourceSelectedChange"]);
const { proxy } = getCurrentInstance() as any;
/** 当前选中的数据源连接池guid,和相关信息。 */
const databaseInfo: any = computed(() => {
if (!databaseGuid.value) {
return {};
}
return props.databaseList.find(d => d.guid == databaseGuid.value);
});
const databaseGuid: any = ref('');
watch(() => props.databaseList, (val) => {
if (!val?.length) {
return;
}
if (props.dataSourceGuid != "") {
databaseGuid.value = props.dataSourceGuid;
} else if (!databaseInfo.value.guid) {
databaseGuid.value = val[0]?.guid;
}
})
const searchKey = ref("");
const dsTableList: Ref<any> = ref();
const dsTableListLoading = ref(false);
const datasourceTableRef = ref<InstanceType<typeof ElTable>>();
const dsPageInfo = ref({
limit: 50,
curr: 1,
rows: 0,
type: "concise",
});
const currDatasourceSelect: Ref<any> = ref({});
const currDsPreviewActiveName = ref("resultData");
const currDsPreviewData = ref([]);
const currDsFields: Ref<any> = ref([]);
/** 每列字段对应的列宽计算结果。 */
const originTableFieldColumn = ref({});
const currDsPreviewDataLoading = ref(false);
const currDsTableStructure = ref([]);
const currDsTableStructureLoading = ref(false);
// const calcTableColumnWidth = (data: any[], prop, title) => {
// let d: any[] = [];
// data.forEach((dt) => d.push(dt[prop]));
// return calcColumnWidth(
// d,
// title,
// {
// fontSize: 14,
// fontFamily: "SimSun",
// },
// {
// fontSize: 14,
// fontFamily: "SimSun",
// }
// );
// };
const formatterPreviewDate = (row, info) => {
let enName = info.enName;
let v = row[enName];
if (v === 0) {
return v;
}
if (!v) {
return v || '--';
}
if (info.dataType === 'datetime') {
return Moment(v).format('YYYY-MM-DD HH:mm:ss');
}
if (info.dataType === 'date') {
if (isNaN(<any>(new Date(v)))) {
return Moment(parseInt(v)).format('YYYY-MM-DD');
} else {
return Moment(v).format('YYYY-MM-DD');
}
}
return v;
};
const getTableListPromise = ref();
const getDsTableList = (params) => {
dsTableList.value = [];
dsTableListLoading.value = true;
let promise: any = null;
promise = getTableListPromise.value = getDsTableByDs(params).then((res: any) => {
if (promise !== getTableListPromise.value) {
return;
}
dsTableListLoading.value = false;
if (res.code == proxy.$passCode) {
dsPageInfo.value.rows = res.data?.totalRows || 0;
dsTableList.value = res.data?.records || [];
//需要根据新的datasourceList 和选中行,设置表格的选中。
nextTick(() => {
datasourceSelectedRows.value.forEach((d) => {
let row = dsTableList.value.find((v: any) => v.tableName == d.tableName);
if (row) {
datasourceTableRef.value?.toggleRowSelection(row, true);
}
});
});
} else {
ElMessage.error(res.msg);
}
})
};
const getPreviewData = () => {
currDsPreviewData.value = [];
currDsPreviewDataLoading.value = true;
getDsData({
pageSize: 50,
pageIndex: 1,
dataSourceGuid: databaseInfo.value.guid,
database: currDatasourceSelect.value.database,
tableName: currDatasourceSelect.value.tableName,
}).then((res: any) => {
currDsPreviewDataLoading.value = false;
if (res.code == proxy.$passCode) {
currDsPreviewData.value = res.data.datas || [];
currDsFields.value = res.data.fields || [];
} else {
ElMessage.error(res.msg);
}
});
};
const getTableStructure = () => {
let tableName = currDatasourceSelect.value.tableName;
currDsTableStructureLoading.value = true;
currDsTableStructure.value = [];
getDsTableStructure({
tableName: tableName,
dataSourceGuid: databaseInfo.value.guid,
database: databaseInfo.value.databaseNameEn,
databaseType: databaseInfo.value.databaseType
}).then((res: any) => {
currDsTableStructureLoading.value = false;
if (res.code == proxy.$passCode) {
currDsTableStructure.value = res.data || [];
} else {
ElMessage.error(res.msg);
}
});
};
watch(() => databaseInfo.value, (val) => {
if (!val) {
return;
}
dsPageInfo.value.curr = 1;
searchKey.value = "";
getDsTableList({
pageSize: dsPageInfo.value.limit,
pageIndex: dsPageInfo.value.curr,
dataSourceGuid: val.guid,
execGuid: props.execGuid
});
})
const handleSearchInputChange = () => {
dsPageInfo.value.curr = 1;
getDsTableList({
pageSize: dsPageInfo.value.limit,
pageIndex: dsPageInfo.value.curr,
dataSourceGuid: databaseInfo.value.guid,
execGuid: props.execGuid
});
};
const dsPageChange = (page) => {
console.log(page);
dsPageInfo.value.curr = page.curr;
dsPageInfo.value.limit = page.limit;
getDsTableList({
pageSize: dsPageInfo.value.limit,
pageIndex: dsPageInfo.value.curr,
dataSourceGuid: databaseInfo.value.guid,
execGuid: props.execGuid
});
};
const datasource_row_class_name = ({ row, rowIndex }) => {
return datasourceSelectedRows.value.find((v: any) => v.tableName == row.tableName)
? "selected"
: "";
};
const datasource_selection_all_change = (selection) => {
let isChecked = selection.length > 0;
dsTableList.value.forEach((d) => {
let index = datasourceSelectedRows.value.findIndex(
(v: any) => v.tableName == d.tableName
);
if (index === -1 && isChecked) {
datasourceSelectedRows.value.push(Object.assign({}, d, databaseInfo.value));
} else if (index !== -1 && !isChecked) {
datasourceSelectedRows.value.splice(index, 1);
if (currDatasourceSelect.value?.tableName === d.tableName) {
currDatasourceSelect.value = {};
}
}
});
};
const datasource_selection_change = (selection, row) => {
console.log(selection, row);
let index = selection.findIndex((s) => s.tableName == row.tableName);
if (index === -1) {
datasourceSelectedRows.value.splice(
datasourceSelectedRows.value.findIndex((v: any) => v.tableName == row.tableName),
1
);
if (currDatasourceSelect.value?.tableName === row.tableName) {
currDatasourceSelect.value = {};
}
} else {
datasourceSelectedRows.value.push(Object.assign({}, row));
}
};
/** 点击行选中或再次点击取消。不知是否有此种需求,一般都是点击勾选框选中。@row-click="datasource_row_click" */
// const datasource_row_click = (row, column, event) => {
// let index = datasourceSelectedRows.value.findIndex(
// (v: any) => v.tableName == row.tableName
// );
// datasourceTableRef.value?.toggleRowSelection(row, index === -1);
// if (index === -1) {
// datasourceSelectedRows.value.push(Object.assign({}, row, databaseInfo.value));
// } else {
// datasourceSelectedRows.value.splice(index, 1);
// }
// };
const handleDsSelect = (item) => {
currDatasourceSelect.value = item;
};
const delSelectDs = (item, i) => {
datasourceSelectedRows.value.splice(i, 1);
if (currDatasourceSelect.value?.tableName === item.tableName) {
currDatasourceSelect.value = {};
}
let table = dsTableList.value.find(t => t.tableName === item.tableName);
table && datasourceTableRef.value?.toggleRowSelection(table, false);
};
watch(
datasourceSelectedRows,
(val, oldVal) => {
if (val?.length && !currDatasourceSelect.value?.tableName) {
currDatasourceSelect.value = val[0];
}
emits("datasourceSelectedChange", val);
},
{
deep: true,
}
);
watch(currDatasourceSelect, (val) => {
if (val?.tableName) {
getPreviewData();
getTableStructure();
}
});
const getTextAlign = (field) => {
if (field.dataType === 'decimal' || field.dataType === 'int' || field.dataType == 'bit' || field.dataType == 'tinyint') {
return 'right';
}
return 'left'
}
</script>
<template>
<div class="first-step-content">
<div class="content-left">
<div class="title-left">待选库表</div>
<div class="content-selecte-left">
<span class="select-ds-title">数据存储连接池</span>
<el-select v-model="databaseGuid" placeholder="请选择" filterable value-key="guid">
<el-option v-for="opt in databaseList" :key="opt['guid']" :label="opt['databaseChName']"
:value="opt['guid']" />
</el-select>
<el-input class="table_search_input" v-model.trim="searchKey" placeholder="关键字搜索" :prefix-icon="Search"
@change="handleSearchInputChange" clearable />
<el-table class="datasource-small-table" ref="datasourceTableRef" :data="dsTableList"
v-loading="dsTableListLoading" :border="false" row-key="tableName" :row-class-name="datasource_row_class_name"
@select="datasource_selection_change" @select-all="datasource_selection_all_change" tooltip-effect="light">
<el-table-column type="selection" :width="22" align="center" />
<el-table-column prop="tableName" label="名称" width="100px" align="left" show-overflow-tooltip>
</el-table-column>
<el-table-column prop="tableComment" label="表注释" width="60px" align="left" show-overflow-tooltip>
<template #default="scope">
<span>{{ scope.row['tableComment'] ?? '--' }}</span>
</template>
</el-table-column>
</el-table>
<PageNav :class="[dsPageInfo.type]" :pageInfo="dsPageInfo" @pageChange="dsPageChange" />
</div>
</div>
<div class="content-right">
<div class="title-right">已选库表</div>
<div class="ds-select-container">
<template v-if="datasourceSelectedRows.length">
<div v-for="(item, i) in datasourceSelectedRows" :key="item.tableName" :class="currDatasourceSelect?.tableName === item.tableName
? 'ds-select-item selected'
: 'ds-select-item'
" @click="handleDsSelect(item)" v-preReClick>
<span class="item-title">{{ item.tableName }}</span>
<el-icon v-if="!isLook" @click.stop="delSelectDs(item, i)" v-preReClick>
<Close />
</el-icon>
</div>
</template>
<div v-if="!datasourceSelectedRows.length" class="ds-select-placeholder">
请从左侧待选库表选择
</div>
</div>
<div class="ds-data-preview">
<div class="preview-data-totals t-left" v-show="currDsPreviewActiveName == 'resultData'">
<span>该页面仅显示</span>
<span style="color: var(--el-color-primary)"> 50 </span>
<span>条数据</span>
</div>
<el-tabs class="preview-tabs" v-model="currDsPreviewActiveName">
<el-tab-pane label="查询结果" name="resultData" class="t-left">
<div v-if="!currDatasourceSelect?.tableName" class="no-select-table">
<img src="../../assets/images/no-data.png" :style="{ width: '96px', height: '96px' }" />
<span>请从已选库表中选择</span>
</div>
<el-table key="previewTableData" v-loading="currDsPreviewDataLoading" :data="currDsPreviewData" border
tooltip-effect="light" style="
width: 100%;
min-width: 200px;
max-width: calc(100% - 17px);
height: calc(100% - 8px);
display: inline-block;
margin: 0 8px;
" stripe ref="previewTable">
<el-table-column v-for="(field, index) in currDsFields" :key="field.enName" :prop="field.enName"
:label="field.chName" :width="field.dataType === 'datetime'
? 180
: field.dataType === 'date'
? 140
: originTableFieldColumn[field.enName]
" :align="getTextAlign(field)" :header-align="getTextAlign(field)" :show-overflow-tooltip="true"
:formatter="(row) => formatterPreviewDate(row, field)">
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="库表结构" name="tableStructure" class="t-left">
<div v-if="!currDatasourceSelect?.tableName" class="no-select-table">
<img src="../../assets/images/no-data.png" :style="{ width: '96px', height: '96px' }" />
<span>请从已选库表中选择</span>
</div>
<el-table key="previewTableStructure" v-loading="currDsTableStructureLoading" tooltip-effect="light"
:data="currDsTableStructure" border style="
width: 100%;
max-width: calc(100% - 17px);
height: calc(100% - 8px);
display: inline-block;
margin: 0 8px;
" stripe ref="previewTableStructure">
<el-table-column type="index" label="序号" :width="56" align="center" />
<el-table-column prop="fieldName" label="字段英文名" width="150px" align="left" header-align="left"
show-overflow-tooltip>
</el-table-column>
<el-table-column prop="fieldChName" label="字段名" width="150px" align="left" header-align="left"
show-overflow-tooltip>
<template #default="scope">
<span>{{ scope.row['fieldChName'] ?? '--' }}</span>
</template>
</el-table-column>
<el-table-column prop="fieldType" label="字段类型" width="100px" align="left" header-align="left"
show-overflow-tooltip>
<template #default="scope">
<span>{{ scope.row['fieldType'] ?? '--' }}</span>
</template>
</el-table-column>
<el-table-column prop="fieldLength" label="长度" width="100px" align="left" header-align="left"
show-overflow-tooltip>
<template #default="scope">
<!--- 直接用??会导致空字符串时无法显示'--',此处需要区分0和“” -->
<span>{{ (scope.row['fieldLength'] !== 0 && !scope.row['fieldLength']) ? "--" :
scope.row['fieldLength'] }}</span>
</template>
</el-table-column>
<el-table-column prop="fieldPrecision" label="精度" width="100px" align="left" header-align="left"
show-overflow-tooltip>
<template #default="scope">
<!--- 直接用??会导致空字符串时无法显示'--',此处需要区分0和“” -->
<span>{{ (scope.row['fieldPrecision'] !== 0 && !scope.row['fieldPrecision']) ? "--" :
scope.row['fieldPrecision'] }}</span>
</template>
</el-table-column>
<el-table-column prop="isPrimary" label="是否主键" width="100px" align="left" header-align="left"
show-overflow-tooltip>
<template #default="scope">
<span>{{ scope.row['isPrimary'] ?? '--' }}</span>
</template>
</el-table-column>
<el-table-column prop="isNotNull" label="是否必填" width="100px" align="left" header-align="left"
show-overflow-tooltip>
<template #default="scope">{{ scope.row['isNotNull'] === 'Y' ? 'N' : 'Y' }}</template>
</el-table-column>
<el-table-column prop="isFk" label="是否外键" width="100px" align="left" header-align="left"
show-overflow-tooltip>
<template #default="scope">
<span>{{ scope.row['isFk'] ?? '--' }}</span>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.first-step-content {
display: flex;
flex-direction: row;
height: calc(100% - 80px);
.content-left {
width: 200px;
border-right: 1px solid #d9d9d9;
.title-left {
height: 44px;
line-height: 44px;
border-bottom: 1px solid #d9d9d9;
padding-left: 8px;
font-size: 14px;
color: #212121;
}
.content-selecte-left {
height: calc(100% - 44px);
padding: 6px 8px 0px 8px;
.select-ds-title {
display: block;
font-size: 14px;
color: #999999;
line-height: 21px;
margin-bottom: 2px;
}
.table_search_input {
margin-top: 16px;
}
.page_nav_wrap.concise {
justify-content: center;
}
}
}
.content-right {
width: calc(100% - 200px);
.title-right {
height: 44px;
line-height: 44px;
border-bottom: 1px solid #d9d9d9;
padding-left: 8px;
font-size: 14px;
color: #212121;
}
.ds-select-container {
background: #f2f2f2;
height: 100px;
display: flex;
padding: 0px 0 12px 12px;
flex-direction: row;
flex-wrap: wrap;
overflow-y: auto;
.ds-select-placeholder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
color: #999999;
}
.ds-select-item {
height: 32px;
border: 2px solid #d9d9d9;
display: flex;
align-items: center;
padding: 0 8px;
background: #fff;
cursor: pointer;
margin-right: 12px;
margin-top: 12px;
.item-title {
font-size: 14px;
color: #212121;
margin-right: 16px;
}
}
.ds-select-item:hover {
border: 2px solid var(--el-color-primary);
}
.ds-select-item.selected {
border: 2px solid var(--el-color-primary);
background-color: var(--el-menu-hover-bg-color);
}
}
.ds-data-preview {
height: calc(100% - 144px);
position: relative;
.preview-data-totals {
position: absolute;
right: 0;
top: 10px;
right: 16px;
}
}
}
}
:deep(.datasource-small-table) {
height: calc(100% - 143px);
margin-top: 4px;
border: 1px solid #d9d9d9;
td.el-table__cell::after,
.el-table__inner-wrapper::before {
height: 0px;
}
.cell {
padding: 0 2px;
}
th.el-table__cell {
line-height: 18px;
font-size: 12px;
color: #999999;
background-color: #fff;
}
td.el-table__cell .cell {
line-height: 18px;
font-size: 12px;
color: #212121;
}
tr.selected {
background-color: var(--el-menu-hover-bg-color);
td {
background-color: var(--el-menu-hover-bg-color);
}
}
.el-table__body tr.selected:hover>td.el-table__cell {
background-color: var(--el-menu-hover-bg-color);
}
}
:deep(.preview-tabs) {
height: 100%;
.el-tabs__header {
margin: 0 0 8px;
}
.el-tabs__nav-wrap::after {
height: 1px;
}
.el-tabs__item {
width: 88px;
padding: 0;
}
.el-tabs__nav {
padding-left: 8px;
}
.el-tabs__content {
height: calc(100% - 48px);
.el-tab-pane {
height: 100%;
:deep(.el-table) {
.cell {
white-space: nowrap;
}
}
.no-select-table {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
color: #999999;
background-color: #fafafa;
}
}
}
}
:deep(.el-table) {
.el-scrollbar__view {
height: 100%;
}
}
</style>
<route lang="yaml">
name: tableCreateExisting
</route>
<script lang="ts" setup name="tableCreateExisting">
import { ref } from "vue";
import { ElMessage } from "element-plus";
import StepBar from "@/components/StepBar/index.vue";
import {
getDbDirDataSourceList,
getDsData,
getDsTableStructure,
saveDbDirTable,
updateDbDirTable,
createTableSql,
} from "@/api/modules/dataInventory";
import existingTableSelect from "./existingTableSelect.vue";
/** 草稿中未建表时就可以编辑表相关信息。如果建表之后就只能编辑字段。 不能修改字段英文名称,数据库修改英文名就相当于删除再添加。都可以直接跳转到*/
const { proxy } = getCurrentInstance() as any;
const router = useRouter();
const route = useRoute();
const isDimTable = route.query.isDim;
const execGuid: any = ref(route.query.execGuid);
// 获取数据库列表
const databaseList: any = ref([]);
const getDbDirDataSourceListData = async () => {
const params = {
execGuid: execGuid.value,
};
const res: any = await getDbDirDataSourceList(params);
if (res.code === proxy.$passCode) {
databaseList.value = processData(res.data);
} else {
proxy.$ElMessage.error(res.msg);
}
};
// 数据处理函数
const processData = (data) => {
return data.map(item => ({
...item,
guid: item.databaseGuid, // 添加新键 "guid"
databaseGuid: undefined, // 删除旧键 "databaseGuid"
})).map(({ databaseGuid, ...rest }) => rest); // 过滤掉 undefined 键
};
onMounted(async () => {
await getDbDirDataSourceListData();
});
const stepsInfo = ref({
step: 0,
list: [
{ title: "选择数据库表", value: 1 },
{ title: "设置属性字段", value: 2 },
],
});
const datasourceSelectedRows: Ref<any> = ref([]);
//记录下一步时选中的库表信息。
const selectedDatabaseTable: Ref<any> = ref([]);
const handlDsSelectedChange = (v) => {
datasourceSelectedRows.value = v || [];
const params: any = [];
v.forEach((item) => {
params.push({
tableName: item.tableName,
database: item.database,
});
});
selectedDatabaseTable.value = params;
console.log('params', params)
// if (isPrevious.value) {
// tableCreateInfo.value.tableFields = [];
// tableCreateInfo.value.inputNameValue = '';
// tableCreateInfo.value.tableData[0].chName = '';
// }
};
const fullscreenLoading = ref(false);
/** 下一步 */
const nextStep = () => {
if (!datasourceSelectedRows.value.length) {
ElMessage({
type: "error",
message: "已选库表不能为空!",
});
return;
}
getNextTableInfo();
stepsInfo.value.step = 1;
};
//下一步获取表字段信息getNextTableInfo。getDsData 入参selectedDatabaseTable.value
const getNextTableInfo = async () => {
const res: any = await getDsTableStructure(selectedDatabaseTable.value);
if (res.code === proxy.$passCode) {
tableDataDetailInfo.value = res.data;
} else {
proxy.$ElMessage.error(res.msg);
}
};
const isPrevious = ref(false);
/** 上一步 */
const previousStep = () => {
stepsInfo.value.step = 0;
isPrevious.value = true;
};
//记录当前正在编辑的表创建信息。
const tableCreateInfo: Ref<any> = ref({
guid: "",
isCreate: false,
inputNameValue: '',
tableData: [],
partitionAttribute: {},
tableFields: [], // 字段标准数组。
});
const tableDataInfo = ref([
{
tableName: '',
tableChName: '',
description: '',
},
])
// 表格数据
const tableDataDetailInfo = ref([
{ id: 1, fieldName: '系统唯一标识', fieldEnglish: 'ID', length: '<200', isUnique: '是', isEdit: false },
{ id: 2, fieldName: '姓名', fieldEnglish: 'NAME', length: '<=200', isUnique: '否', isEdit: false },
{ id: 3, fieldName: '年纪', fieldEnglish: 'AGE', length: '=200', isUnique: '否', isEdit: false },
{ id: 4, fieldName: '系统唯一标识', fieldEnglish: 'ID', length: '<200', isUnique: '是', isEdit: false },
{ id: 5, fieldName: '姓名', fieldEnglish: 'NAME', length: '<=200', isUnique: '否', isEdit: false },
{ id: 6, fieldName: '年纪', fieldEnglish: 'AGE', length: '=200', isUnique: '否', isEdit: false },
])
// 配置哪些字段可编辑
const editableFields = {
fieldName: true, // 字段中文名可编辑
length: true, // 长度可编辑
isUnique: true, // 数据是否唯一可编辑
fieldPrecision: true, // 精度可编辑
dictionaryGuid: true, // 关联字典可编辑
}
const tableFieldsLoading = ref(false)
const selectedRows = ref([]);
// 监听选中行
const selectionFieldsChange = (selection) => {
console.log('selection', selection)
selectedRows.value = selection;
};
// 上移功能
const moveUp = () => {
// 1. 找到选中行在 tableData 中的索引
const selectedIds = selectedRows.value.map((row: any) => row.id);
// 2. 遍历选中行,按顺序上移
for (let i = 0; i < tableDataDetailInfo.value.length; i++) {
const currentRow = tableDataDetailInfo.value[i];
// 如果当前行被选中,且不是第一行,则交换位置
if (selectedIds.includes(currentRow.id) && i > 0) {
const previousRow = tableDataDetailInfo.value[i - 1];
// 如果上一行没有被选中,交换位置
if (!selectedIds.includes(previousRow.id)) {
[tableDataDetailInfo.value[i], tableDataDetailInfo.value[i - 1]] = [tableDataDetailInfo.value[i - 1], tableDataDetailInfo.value[i]];
}
}
}
};
// 下移功能
const moveDown = () => {
// 1. 找到选中行在 tableData 中的索引
const selectedIds = selectedRows.value.map((row: any) => row.id);
// 2. 遍历选中行,倒序下移
for (let i = tableDataDetailInfo.value.length - 1; i >= 0; i--) {
const currentRow = tableDataDetailInfo.value[i];
// 如果当前行被选中,且不是最后一行,则交换位置
if (selectedIds.includes(currentRow.id) && i < tableDataDetailInfo.value.length - 1) {
const nextRow = tableDataDetailInfo.value[i + 1];
// 如果下一行没有被选中,交换位置
if (!selectedIds.includes(nextRow.id)) {
[tableDataDetailInfo.value[i], tableDataDetailInfo.value[i + 1]] = [tableDataDetailInfo.value[i + 1], tableDataDetailInfo.value[i]];
}
}
}
};
// 进入编辑模式
const editRow = (row) => {
row.isEdit = true
}
// 保存数据
const saveRow = (row) => {
row.isEdit = false
}
// 删除行
const deleteRow = (index) => {
// confirm 弹窗
proxy.$confirm('是否删除该行数据?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
tableDataDetailInfo.value.splice(index, 1)
}).catch(() => {
proxy.$message({
type: 'info',
message: '已取消删除'
});
});
}
// 批量删除功能
const batchDelete = () => {
selectedRows.value.forEach((row: any) => {
const index = tableDataDetailInfo.value.findIndex((item) => item.id === row.id);
if (index !== -1) tableDataDetailInfo.value.splice(index, 1);
});
selectedRows.value = [];
};
// 新增一行
const addRow = () => {
tableDataDetailInfo.value.push({
id: tableDataDetailInfo.value.length + 1,
fieldName: '',
fieldEnglish: '', // 英文名不可编辑
length: '',
isUnique: '',
isEdit: true, // 新增时默认进入编辑模式
})
}
const data = [
{
value: '1',
label: 'Level one 1',
children: [
{
value: '1-1',
label: 'Level two 1-1',
children: [
{
value: '1-1-1',
label: 'Level three 1-1-1',
},
],
},
],
},
{
value: '2',
label: 'Level one 2',
children: [
{
value: '2-1',
label: 'Level two 2-1',
children: [
{
value: '2-1-1',
label: 'Level three 2-1-1',
},
],
},
{
value: '2-2',
label: 'Level two 2-2',
children: [
{
value: '2-2-1',
label: 'Level three 2-2-1',
},
],
},
],
},
{
value: '3',
label: 'Level one 3',
children: [
{
value: '3-1',
label: 'Level two 3-1',
children: [
{
value: '3-1-1',
label: 'Level three 3-1-1',
},
],
},
{
value: '3-2',
label: 'Level two 3-2',
children: [
{
value: '3-2-1',
label: 'Level three 3-2-1',
},
],
},
],
},
]
const submitAsDraft = () => {
// 保存为草稿,无论有没有guid 都传入guid
saveOrUpdate({ isDraft: 'Y' }, 0)
}
/**
* 需求写一个校验函数,校验表格数据是否填写完整
* 1、表名称、数据库表、为空
* 2、tableDataDetailInfo.value 每一项中的字段名称、字段英文名、字段类型、长度、精度、是否唯一、是否必填、字段取值范围、关联字典、不能为空
*/
const checkTableData = (tableDataInfo, tableDataDetailInfo) => {
const tableDataInfoKeys = ['tableName', 'tableChName']
const tableDataDetailInfoKeys = ['fieldName', 'fieldEnglish', 'fieldType', 'length', 'fieldPrecision', 'isUnique', 'isRequired', 'fieldValueRange', 'dictionaryGuid']
let flag = true
tableDataInfo.forEach(item => {
tableDataInfoKeys.forEach(key => {
if (!item[key]) {
flag = false
proxy.$ElMessage.error('表名称、数据库表不能为空')
}
})
})
tableDataDetailInfo.forEach(item => {
tableDataDetailInfoKeys.forEach(key => {
if (!item[key]) {
flag = false
proxy.$ElMessage.error('字段名称、字段英文名、字段类型、长度、精度、是否唯一、是否必填、字段取值范围、关联字典不能为空')
}
})
})
return flag
}
const guid = ref('')
const submit = async () => {
console.log('提交', tableDataDetailInfo.value, tableDataInfo.value)
// 校验表格数据是否填写完整
if (!checkTableData(tableDataDetailInfo.value, tableDataInfo.value)) {
return
}
/**
"guid": "string",
"cgDirName": "string",
"dirGuid": "string",
"tableGuid": "string",
"tableName": "string",
"tableChName": "string",
"databaseGuid": "string",
"database": "string",
"dbType": "string",
"databaseChName": "string",
"foundMode": 0,
"state": 0,
"isDraft": "string",
"fieldRQVOList": [
{
"guid": "string",
"cgDirName": "string",
"dirGuid": "string",
"classifyName": "string",
"gradeDetailName": "string",
"tableGuid": "string",
"tableName": "string",
"tableChName": "string",
"databaseGuid": "string",
"database": "string",
"databaseChName": "string",
"fieldGuid": "string",
"fieldName": "string",
"fieldChName": "string",
"fieldType": "string",
"fieldLength": 0,
"fieldPrecision": 0,
"dimGuid": "string",
"dictionaryGuid": "string",
"sortValue": 0,
"isPrimary": "string",
"isFk": "string",
"isNotNull": "string",
"defaultValue": "string"
}
], 这是入参
*/
// 如果提交时没有 guid 则为新增type 0,否则为修改 type 1, 也要传参
if (!guid.value) {
saveOrUpdate({}, 0)
} else {
saveOrUpdate({}, 1)
}
}
// 单独将保存和修改函数提取出来 type 0 保存 1 修改 2 生成建表语句
const saveOrUpdate = async (params: any = {}, type) => {
const InParams = {
guid: '',
cgDirName: '',
dirGuid: '',
tableGuid: '',
tableName: '',
tableChName: '',
databaseGuid: '',
database: '',
dbType: '',
databaseChName: '',
foundMode: 0,
state: 0,
isDraft: '',
fieldRQVOList: tableDataDetailInfo.value
}
const finalParams = { ...InParams, ...params }
// 使用switch case 语句
switch (type) {
case 0:
// 保存/保存为草稿
const res: any = await saveDbDirTable(finalParams);
if (res.code === proxy.$passCode) {
if (params.isDraft === 'Y') {
proxy.$ElMessage.success('保存为草稿成功!');
}
proxy.$ElMessage.success('保存成功!');
router.push({ name: 'classifyGradeCatalogue' });
} else {
proxy.$ElMessage.error(res.msg);
}
break;
case 1:
// 修改
const res1: any = await updateDbDirTable(finalParams);
if (res1.code === proxy.$passCode) {
proxy.$ElMessage.success('修改成功!');
router.push({ name: 'classifyGradeCatalogue' });
} else {
proxy.$ElMessage.error(res1.msg);
}
break;
case 2:
// 生成建表语句
const res2: any = await createTableSql(finalParams);
if (res2.code === proxy.$passCode) {
proxy.$ElMessage.success('建表生成成功!');
} else {
proxy.$ElMessage.error(res2.msg);
}
break;
default:
break;
}
}
// 生成建表弹窗区域
const options = [
{ value: 'mysql', label: 'mysql' },
{ value: 'doris', label: 'doris' },
];
const newCreateSqlFormItems = ref([{
label: '选择数据库',
type: 'select',
maxlength: 50,
placeholder: '请输入',
field: 'name',
default: 'mysql',
options: options,
block: true,
clearable: true,
required: true
}]);
const newCreateSqlFormRules = ref({
name: [
{ required: true, message: '请选择数据库名称', trigger: 'blur' },
]
});
const newCreateSqlDialogInfo = ref({
visible: false,
size: 460,
title: "生成建表语句",
type: "",
formInfo: {
id: "grade-form",
items: newCreateSqlFormItems.value,
rules: newCreateSqlFormRules.value,
},
submitBtnLoading: false,
btns: {
cancel: () => {
newCreateSqlDialogInfo.value.visible = false;
},
submit: async (btn, info) => {
newCreateSqlDialogInfo.value.submitBtnLoading = true;
const params = {
...info,
};
await saveOrUpdate(params, 2);
newCreateSqlDialogInfo.value.submitBtnLoading = false;
newCreateSqlDialogInfo.value.visible = false;
}
}
})
// 生成建表语句
const createNewSql = () => {
newCreateSqlDialogInfo.value.visible = true;
}
</script>
<template>
<div class="container_wrap full" v-loading.fullscreen.lock="fullscreenLoading">
<div class="content_main">
<div class="top_tool_wrap">
<StepBar :steps-info="stepsInfo" />
</div>
<existingTableSelect v-show="stepsInfo.step === 0" :databaseList="databaseList" :table-create-type="2"
:execGuid="execGuid" @datasource-selected-change="handlDsSelectedChange"></existingTableSelect>
<div class="second-step-content" v-show="stepsInfo.step === 1">
<div class="table_panel_wrap">
<el-table :data="tableDataInfo" :highlight-current-row="true" stripe border height="100%" row-key="guid"
tooltip-effect="light" :style="{
width: '100%',
'max-height': 'calc(100% - 16px)',
display: 'inline-block',
}">
<!-- 表名称列 -->
<el-table-column prop="tableName" label="表名称" width="180">
<template #header>
<span>表名称</span>
<span style="color:red;margin-left: 2px;">*</span>
</template>
<template #default="scope">
<el-input v-model="scope.row.tableName" placeholder="请输入表名称" />
</template>
</el-table-column>
<!-- 数据库表列 -->
<el-table-column prop="tableChName" label="数据库表" width="280">
<template #header>
<span>数据库表</span>
<span style="color:red;margin-left: 2px;">*</span>
</template>
<template #default="scope">
<el-input v-model="scope.row.tableChName" placeholder="请输入数据库表" />
</template>
</el-table-column>
<!-- 描述列 -->
<el-table-column prop="description" label="描述" width="180">
<template #default="scope">
<el-input v-model="scope.row.description" placeholder="请输入描述" />
</template>
</el-table-column>
</el-table>
</div>
<div class="btn-area">
<el-button type="primary" @click="addRow">新增</el-button>
<el-button @click="moveUp">上移</el-button>
<el-button @click="moveDown">下移</el-button>
<el-button @click="batchDelete">批量删除</el-button>
<el-button @click="createNewSql">生成建表语句</el-button>
</div>
<div class="bottom_table">
<el-table :data="tableDataDetailInfo" v-loading="tableFieldsLoading" :highlight-current-row="true" stripe
border height="100%" row-key="guid" @selection-change="selectionFieldsChange" tooltip-effect="light" :style="{
width: '100%',
'max-height': 'calc(100% - 16px)',
display: 'inline-block',
}">
<el-table-column type="selection" :width="32" align="center" />
<!-- 排序列(不可编辑) -->
<el-table-column prop="id" label="排序" width="80" align="center" />
<!-- 字段中文名(不可编辑)fieldChName -->
<el-table-column prop="fieldName" label="字段中文名" width="150">
<template #default="scope">
{{ scope.row.fieldName ? scope.row.fieldName : '--' }}
</template>
</el-table-column>
<!-- 字段英文名(不可编辑) -->
<el-table-column prop="fieldEnglish" label="字段英文名" width="150">
<template #default="scope">
{{ scope.row.fieldEnglish ? scope.row.fieldEnglish : '--' }}
</template>
</el-table-column>
<!-- 分类(不可编辑)classifyName -->
<el-table-column prop="classifyName" label="分类" width="150">
<template #default="scope">
{{ scope.row.classifyName ? scope.row.classifyName : '--' }}
</template>
</el-table-column>
<!-- 分级(不可编辑) -->
<el-table-column prop="gradeDetailName" label="分级" width="120" align="center">
<template #default="scope">
{{ scope.row.gradeDetailName ? scope.row.gradeDetailName : '--' }}
</template>
</el-table-column>
<!-- 字段类型fieldType (不可编辑) -->
<el-table-column prop="fieldType" label="字段类型" width="150" align="center">
<template #default="scope">
{{ scope.row.fieldType ? scope.row.fieldType : '--' }}
</template>
</el-table-column>
<!-- 长度(可编辑) -->
<el-table-column prop="length" label="长度" width="120" align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit || !editableFields.length">{{ scope.row.length ? scope.row.length
: '--' }}</span>
<el-input v-else v-model="scope.row.length" placeholder="请输入长度" />
</template>
</el-table-column>
<!-- 精度(可编辑)fieldPrecision -->
<el-table-column prop="fieldPrecision" label="精度" width="120" align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit || !editableFields.fieldPrecision">{{ scope.row.fieldPrecision ?
scope.row.fieldPrecision : '--' }}</span>
<el-input v-else v-model="scope.row.fieldPrecision" placeholder="请输入精度" />
</template>
</el-table-column>
<!-- 关联字典(可编辑)el-tree-select 形式下拉形式 -->
<el-table-column prop="dictionaryGuid" label="关联字典" width="150" align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit || !editableFields.dictionaryGuid">{{ scope.row.isDict ? scope.row.isDict
: '--' }}</span>
<el-tree-select v-else v-model="scope.row.isDict" :data="data" placeholder="请选择" />
</template>
</el-table-column>
<!-- 数据是否唯一(可编辑) -->
<el-table-column prop="isUnique" label="数据是否唯一" width="150" align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit || !editableFields.isUnique">{{ scope.row.isUnique ? scope.row.isUnique :
'--' }}</span>
<el-select v-else v-model="scope.row.isUnique" placeholder="请选择">
<el-option label="是" value="是" />
<el-option label="否" value="否" />
</el-select>
</template>
</el-table-column>
<!-- 是否必填(可编辑) -->
<el-table-column prop="isRequired" label="是否必填" width="120" align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit">{{ scope.row.isRequired ? scope.row.isRequired : '--' }}</span>
<el-select v-else v-model="scope.row.isRequired" placeholder="请选择">
<el-option label="是" value="是" />
<el-option label="否" value="否" />
</el-select>
</template>
</el-table-column>
<!-- 字段取值范围 fieldValueRange(可编辑)-->
<el-table-column prop="fieldValueRange" label="字段取值范围" width="150" align="center">
<template #default="scope">
<span v-if="!scope.row.isEdit">{{ scope.row.fieldValueRange ? scope.row.fieldValueRange : '--' }}</span>
<el-input v-else v-model="scope.row.fieldValueRange" placeholder="请输入字段取值范围" />
</template>
</el-table-column>
<!-- 操作列 -->
<el-table-column label="操作" width="100" align="center" fixed="right">
<template #default="scope">
<!-- <el-button v-if="!scope.row.isEdit" type="primary" size="small" @click="editRow(scope.row)">
编辑
</el-button> -->
<!-- <el-button v-else type="success" size="small" @click="saveRow(scope.row)">
保存
</el-button>
<el-button type="danger" size="small" @click="deleteRow(scope.$index)">
删除
</el-button> -->
<span class="text_btn" v-if="!scope.row.isEdit" @click="editRow(scope.row)">编辑</span>
<span class="text_btn" v-else @click="saveRow(scope.row)">保存</span>
<el-divider direction="vertical" />
<span class="text_btn" @click="deleteRow(scope.$index)">删除</span>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
<div class="bottom_tool_wrap">
<template v-if="stepsInfo.step == 0">
<el-button type="primary" @click="nextStep">下一步</el-button>
</template>
<template v-else>
<el-button @click="previousStep">上一步</el-button>
<el-button type="primary" @click="submitAsDraft">保存为草稿</el-button>
<el-button type="primary" @click="submit">提交</el-button>
</template>
</div>
<Dialog_form :dialogConfigInfo="newCreateSqlDialogInfo" />
</div>
</template>
<style lang="scss" scoped>
.top_tool_wrap {
width: 100%;
height: 80px;
display: flex;
justify-content: center;
align-items: center;
border-bottom: 1px solid #d9d9d9;
:deep(.el-steps) {
width: 30%;
}
}
.content_main {
height: calc(100% - 40px);
.second-step-content {
height: calc(100% - 80px);
width: 100%;
padding: 16px;
.table_panel_wrap {
width: 100%;
height: auto;
overflow: visible;
}
.btn-area {
margin-top: 12px;
}
:deep(.bottom_table) {
margin-top: 12px;
height: calc(100% - 150px);
overflow-y: auto;
.el-table td.el-table__cell {
padding: 2px 0;
height: 36px;
}
}
}
}
:deep(.el-dialog) {
.dialog-form-inline {
.checkbox_input {
display: flex;
flex-direction: column;
.input_panel {
margin: 0;
}
}
.select_group {
.el-form-item__content>.el-input {
margin-top: 21px;
}
}
.radio_panel {
.panel_content {
display: none;
}
}
}
}
:deep(.batchDialog) {
.el-tree-node__content {
padding-left: 8px !important;
.el-icon {
display: none;
}
}
}
.bottom_tool_wrap {
height: 40px;
padding: 0 16px;
border-top: 1px solid #d9d9d9;
display: flex;
justify-content: flex-end;
align-items: center;
}
</style>
<route lang="yaml">
name: tableCreateFile
</route>
<script lang="ts" setup name="tableCreateFile">
import { ref } from "vue";
import { ElMessage, ElMessageBox, ElTable } from "element-plus";
import useUserStore from "@/store/modules/user";
import useDataCatalogStore from "@/store/modules/dataCatalog";
import expandPropertyDialog from "./expandPropertyDialog.vue";
import tableDefaultValue from "./components/tableDefaultValue.vue";
// import {
// getDatabase,
// getFileStandards,
// getDictionary,
// getSubjectFieldByFile,
// tableCategoryList,
// syncPolicys,
// getDataTypeList,
// tableModels,
// aggMethodList,
// getCharacterList,
// saveSubjectTable,
// updateSubjectTable,
// getTableStandardDetail,
// getSubjectDomainDetail,
// saveSubjectTableDraft,
// updateSubjectTableDraft,
// getFieldStandardTree,
// dimTypeList,
// getDimList,
// getSubjectTableDetail,
// checkSubjectTableData
// } from "@/api/modules/dataCatalogService";
import { useDefault } from "@/hooks/useDefault";
import uploadExcelFile from "./components/uploadExcelFile.vue";
const userStore = useUserStore();
const dataCatalogStore = useDataCatalogStore();
const { checkDefault } = useDefault();
const userData = JSON.parse(userStore.userData);
const { proxy } = getCurrentInstance() as any;
const router = useRouter();
const route = useRoute();
const isDimTable = route.query.isDim;
const subjectDomainGuid: any = ref(route.query.domainGuid);
const fullPath = route.fullPath;
const standardSetGuids = ref([]);
//记录已入库的表创建信息。
const originTableCreateInfo = ref({});
//记录当前正在编辑的表创建信息。
const tableCreateInfo: Ref<any> = ref({
guid: "",
isCreate: false,
inputNameValue: '',
isSync: 'Y', //是否默认同步数据。
sheetName: '', //所选择的sheet页。
tableData: [
{
//数据库表信息。
dataSourceGuid: '',
dataServerName: "",
dataServerChName: "",
enName: "",
chName: "",
subjectDomain: route.query.domainName,
subjectDomainGuid: subjectDomainGuid.value,
tableCategory: route.query.layereAttribute == '3' ? 6 : 1,
dimType: isDimTable ? 1 : null,
codeColumn: '',
codeName: '',
syncPolicy: 3,
characterSet: 'utf8mb3',
tableModel: 1, //若是聚合模型,下方出现一列聚合方式选择。处了主键列,其余列都需要选择。每个表里都要有主键。
description: "",
},
],
partitionAttribute: {},
tableFields: [], // 字段标准数组。
});
const stepsInfo = ref({
step: 0,
list: [
{ title: "上传文件", value: 1 },
{ title: "设置属性字段", value: 2 },
],
});
/** 上传的文件字段信息。 */
const fileTableFields: any = ref([]);
/** 上传的文件数据信息 */
const fileTableData: any = ref([]);
/** 上传的文件信息。 */
const uploadDataFileInfo: any = ref([]);
const handleFileDataChange = (fileFields, files, sheetName, data) => {
if (fileTableFields.value != fileFields) {//文件字段改变,下一步时需要清空。
fileTableFields.value = fileFields.slice(0);
tableCreateInfo.value.tableFields = [];
}
fileTableData.value = data;
uploadDataFileInfo.value = files;
tableCreateInfo.value.sheetName = sheetName;
console.log(files);
}
const uploadFileRef = ref();
// const getSubjectField = () => {
// tableFieldsLoading.value = true;
// getSubjectFieldByFile(fileTableFields.value.map(f => f.chName), tableCreateInfo.value.tableData[0].subjectDomainGuid).then((res: any) => {
// tableFieldsLoading.value = false;
// if (res.code == proxy.$passCode) {
// tableCreateInfo.value.tableFields = res.data?.map((field, i) => {
// field.dimOrdictionaryGuid = field.dictionaryGuid;
// field.fileFieldName = fileTableFields.value[i].chName;
// field.isEdit = true;
// !field.notNull && (field.notNull = 'N');
// return field;
// }) || [];
// } else {
// ElMessage.error(res.msg);
// }
// });
// }
const nextStep = () => {
uploadFileRef.value.fileFormRef.ruleFormRef.validate((valid) => {
if (valid) {
if (!fileTableFields.value.length) {
ElMessage({
type: "error",
message: "上传文件字段不能为空!",
});
return;
}
if (!fileTableData.value.length) {
tableCreateInfo.value.isSync = 'N';
} else {
tableCreateInfo.value.isSync = 'Y';
}
stepsInfo.value.step = 1;
// getDictionaryList();
// getDimListData();
// if (!fieldTypes.value.length) {
// getFieldTypeList();
// getCharacterListData();
// }
// if (!databaseList.value.length) {
// getDatabaseList();
// }
// getDomainDetail(subjectDomainGuid.value);
// if (!tableCreateInfo.value.tableFields.length) {
// getSubjectField();
// }
}
});
};
const isPrevious = ref(false);
/** 上一步 */
const previousStep = () => {
stepsInfo.value.step = 0;
isPrevious.value = true;
};
/** 记录是否开启字段标准,根据主题域相关信息获取 */
const isOpenStandard = ref(true);
const selectTableFieldRows = ref([]);
const tableStandardGuid = ref('');
const tableStandardDetail: any = ref({});
const fieldStandardSetGuids = ref([]);
// 实际显示的字段标准列表
const standardListOptions: any = ref([]);
const databaseList: any = ref([]);
//字段类型
const fieldTypes: any = ref([]);
//字符集
const characterList: any = ref([]);
//是否列表
const isNotList = ref([
{
label: "Y",
value: "Y",
},
{
label: "N",
value: "N",
},
]);
const batchAddFieldStandardPage = ref({
pageSize: 50,
pageIndex: 1,
standardSetGuids: [],
approveState: 'Y',
name: '',
standardSetLevelCode: ""
});
const init = ref(true);
const fullscreenLoading = ref(false);
/** 表里有数据时不能修改字段类型,长度,精度 */
const hasSubjectData = ref(false);
/** 保存表 */
const saveTable = () => {
}
</script>
<template>
<div class="container_wrap full" v-loading.fullscreen.lock="fullscreenLoading">
<div class="content_main">
<div class="top_tool_wrap">
<StepBar :steps-info="stepsInfo" />
</div>
<uploadExcelFile ref="uploadFileRef" v-show="stepsInfo.step === 0" @fileDataChange="handleFileDataChange">
</uploadExcelFile>
<div class="second-step-content" v-show="stepsInfo.step === 1">
aaa
</div>
</div>
<div class="bottom_tool_wrap">
<template v-if="stepsInfo.step == 0">
<el-button type="primary" @click="nextStep">下一步</el-button>
</template>
<template v-else>
<el-checkbox v-model="tableCreateInfo.isSync" true-label="Y" :disabled="!fileTableData?.length"
false-label="N">同步数据(说明:勾选代表建表同时写入表格数据。)</el-checkbox>
<el-button @click="previousStep">上一步</el-button>
<el-button type="primary">保存为草稿</el-button>
<el-button type="primary" @click="saveTable">提交</el-button>
</template>
</div>
</div>
</template>
<style lang="scss" scoped>
.top_tool_wrap {
width: 100%;
height: 80px;
display: flex;
justify-content: center;
align-items: center;
border-bottom: 1px solid #d9d9d9;
:deep(.el-steps) {
width: 30%;
}
}
.content_main {
height: calc(100% - 40px);
.header-bg-title {
margin: 16px 16px 0px;
background: #F5F5F5;
padding-left: 16px;
height: 48px;
font-size: 14px;
color: #212121;
letter-spacing: 0;
line-height: 21px;
font-weight: 600;
display: flex;
align-items: center;
position: relative;
.preview-data-totals {
position: absolute;
right: 16px;
line-height: 32px;
font-size: 14px;
color: #666666;
font-weight: 400;
}
.fontC-4fa1a4 {
color: var(--el-color-primary);
}
}
.form-main {
border: 1px solid #d9d9d9;
margin: 0px 16px;
padding: 16px 16px 0px 16px;
height: 125px;
.dialog-form-inline {
align-items: flex-start;
}
:deep(.el-form) {
.item-label {
width: 100%;
}
.el-select {
max-width: 300px;
}
}
}
.table-main {
height: calc(100% - 350px);
border: 1px solid #d9d9d9;
margin: 0px 16px 16px 16px;
padding: 16px;
}
.empty-content {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
flex-direction: column;
.empty-text {
font-size: 14px;
color: #b2b2b2;
}
}
.second-step-content {
height: calc(100% - 80px);
width: 100%;
padding: 16px;
.tools_btns {
padding: 8px 0;
}
:deep(.el-table) {
.cell {
.prefix-or-suffix-cell {
display: inline-flex;
align-items: center;
}
}
}
.table_panel {
height: calc(100% - 114px);
}
:deep(.el-table) {
& td.el-table__cell {
padding: 3px 0;
height: 36px;
}
}
}
}
:deep(.el-dialog) {
.dialog-form-inline {
.checkbox_input {
display: flex;
flex-direction: column;
.input_panel {
margin: 0;
}
}
.select_group {
.el-form-item__content>.el-input {
margin-top: 21px;
}
}
.radio_panel {
.panel_content {
display: none;
}
}
}
}
:deep(.batchDialog) {
.el-tree-node__content {
padding-left: 8px !important;
.el-icon {
display: none;
}
}
}
.bottom_tool_wrap {
height: 40px;
padding: 0 16px;
border-top: 1px solid #d9d9d9;
display: flex;
justify-content: flex-end;
align-items: center;
.el-checkbox {
margin-right: 20px;
}
:deep(.el-checkbox__input.is-checked + .el-checkbox__label) {
color: var(--el-color-regular);
}
}
</style>
......@@ -137,6 +137,9 @@ const handleClassDataEdit = (params) => {
if (item.field === 'classStandardName') {
item.default = params.name
}
if (item.field === 'description') {
item.default = params.description
}
})
}
......@@ -209,6 +212,15 @@ const classStandardFormItems = ref([{
default: '',
required: true,
block: true,
}, {
label: '分类描述',
type: 'textarea',
placeholder: '请输入',
field: 'description',
default: '',
clearable: true,
required: false,
block: true
}]);
const classStandardFormRules = ref({
......@@ -235,6 +247,7 @@ const newCreateClassStandardDialogInfo = ref({
if (newCreateClassStandardDialogInfo.value.title === '新增分类') {
newCreateClassStandardDialogInfo.value.submitBtnLoading = true;
const params = {
description: info.description,
name: info.classStandardName,
refGradeGuid: info.refGradeGuid,
type: 'C'
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!