069cee88 by lihua

支持根据标准新建数据集

1 parent 49c5d6f5
...@@ -404,7 +404,137 @@ export const getSankeyData = (guid) => request({ ...@@ -404,7 +404,137 @@ export const getSankeyData = (guid) => request({
404 404
405 /** 数仓目录树列表查询 */ 405 /** 数仓目录树列表查询 */
406 export const getDataWareCatalogList = (params) => request({ 406 export const getDataWareCatalogList = (params) => request({
407 url: `${import.meta.env.VITE_APP_DATA_DELIVERY}delivery/ms-daop-data-plan-service/data-catalog-directory/tree-list`, 407 // url: `${import.meta.env.VITE_APP_DATA_DELIVERY}delivery/ms-daop-data-plan-service/data-catalog-directory/tree-list`,
408 url: `http://localhost:9000/delivery/ms-daop-data-plan-service/data-catalog-directory/tree-list`,
408 method: 'post', 409 method: 'post',
409 data: params 410 data: params
410 }) 411 })
412
413 export const getAllFlowData = (dictType) => request({
414 url: `${import.meta.env.VITE_APP_CONFIG_URL}/dict/data/get-by-dictType?dictType=${dictType}`,
415 method: 'get',
416 })
417
418 /** 元数据标准guid查询新建数据集字段 */
419 export const getMetaStandardDsField = (guid) => request({
420 url: `${import.meta.env.VITE_APP_STANDARD_URL}/meta-standard/get-standard?metaStandardGuid=${guid}`,
421 method: 'get'
422 })
423
424 /** 表分类类型 */
425 export const tableCategoryList = [
426 {
427 value: 1,
428 label: "明细表",
429 },
430 {
431 value: 2,
432 label: "汇总表",
433 },
434 {
435 value: 3,
436 label: "应用表",
437 },
438 {
439 value: 6,
440 label: "业务表",
441 },
442 // {
443 // value: 4,
444 // label: "维度表",
445 // },
446 // {
447 // value: 5,
448 // label: "缓慢变化维",
449 // }
450 ];
451
452 /** 同步策略 */
453 export const syncPolicys = [
454 {
455 value: 1,
456 label: "实时",
457 },
458 {
459 value: 2,
460 label: "增量",
461 },
462 {
463 value: 3,
464 label: "全量",
465 },
466 {
467 value: 4,
468 label: "增量加更新",
469 },
470 ];
471
472 /** 维表类型 */
473 export const dimTypeList = [{
474 label: "列表",
475 value: 1,
476 },
477 {
478 label: "层级",
479 value: 2,
480 },
481 {
482 label: "螺旋",
483 value: 3,
484 },
485 {
486 label: "通用",
487 value: 4,
488 }];
489
490 /** 表模型分类 */
491 export const tableModels = [
492 {
493 label: "主键模型",
494 value: 1,
495 },
496 {
497 label: "聚合模型",
498 value: 2,
499 },
500 {
501 label: "明细模型",
502 value: 3,
503 }
504 ];
505
506 /** 聚合方式 */
507 export const aggMethodList = [{
508 value: 'SUM',
509 }, {
510 value: 'MAX'
511 }, {
512 value: 'MIN'
513 }, {
514 value: 'REPLACE'
515 }, {
516 value: 'REPLACE_IF_NOT_NULL'
517 }, {
518 value: 'HLL_UNION'
519 }, {
520 value: 'BITMAP_UNION'
521 }];
522
523 /** 保存主题表设置,直接入库 */
524 export const saveSubjectTable = (params) => request({
525 url: `http://localhost:9000/delivery/ms-daop-data-plan-service/data-catalog-subject/add`,
526 method: 'post',
527 data: params
528 })
529
530 /** 获取字典列表 */
531 export const getDictionary = (params) => request({
532 url: `${import.meta.env.VITE_APP_PLAN_BASEURL}/data-dictionary-general/list-all?state=1`,
533 method: 'post'
534 })
535
536 /** 获取维度列表 */
537 export const getDimList = () => request({
538 url: `http://localhost:9000/delivery/ms-daop-data-plan-service/data-catalog-subject/get-dim-list`,
539 method: 'get'
540 })
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -221,6 +221,44 @@ const routes: RouteRecordRaw[] = [ ...@@ -221,6 +221,44 @@ const routes: RouteRecordRaw[] = [
221 } 221 }
222 }, 222 },
223 { 223 {
224 path: 'table-create-manual',
225 name: 'tableCreateManual',
226 component: () => import('@/views/data_meta/tableCreateManual.vue'),
227 meta: {
228 title: '新建表',
229 sidebar: false,
230 breadcrumb: false,
231 cache: true,
232 reuse: true,
233 activeMenu: '/data-meta/metadata-standard/standard-query'
234 },
235 beforeEnter: (to, from) => {
236 if (to.query.domainName) {
237 to.meta.title = `新建表(${to.query.domainName})-${to.query.standardName}`;
238 to.meta.editPage = true;
239 }
240 }
241 },
242 {
243 path: 'dim-table-create-manual',
244 name: 'dimTableCreateManual',
245 component: () => import('@/views/data_meta/dimTableCreateManual.vue'),
246 meta: {
247 title: '新建表',
248 sidebar: false,
249 breadcrumb: false,
250 cache: true,
251 reuse: true,
252 activeMenu: '/data-meta/metadata-standard/standard-query'
253 },
254 beforeEnter: (to, from) => {
255 if (to.query.domainName) {
256 to.meta.title = `新建表(${to.query.domainName})-${to.query.standardName}`;
257 to.meta.editPage = true;
258 }
259 }
260 },
261 {
224 path: 'standard-codetable', 262 path: 'standard-codetable',
225 name: 'metadataStandardCodetable', 263 name: 'metadataStandardCodetable',
226 component: () => import('@/views/data_meta/standard-codetable.vue'), 264 component: () => import('@/views/data_meta/standard-codetable.vue'),
......
1 <script lang="ts" setup name="existingTableSelect">
2 import { ref } from "vue";
3 import Dialog from "@/components/Dialog/index.vue";
4
5 const emits = defineEmits([
6 "expandValueChange"
7 ]);
8
9 const props = defineProps({
10 tableCreateInfo: {
11 type: Object,
12 default: {},
13 },
14 partitionAttribute: {
15 type: Object,
16 default: {},
17 },
18 isLook: {
19 type: Boolean,
20 default: false
21 }
22 });
23
24 const expandProperties: any = computed(() => {
25 let partitionAttribute = props.tableCreateInfo.partitionAttribute;
26 return {
27 partitionMode: partitionAttribute?.partitionMode || 'dynamic',
28 staticPartitionType: partitionAttribute?.staticPartitionType || 'Range',
29 partitionCol: partitionAttribute?.partitionCol || "",
30 partitionTimeUnit: partitionAttribute?.partitionTimeUnit || "DAY",
31 dynamicPartitionEnd: partitionAttribute?.dynamicPartitionEnd == null ? 3 : partitionAttribute?.dynamicPartitionEnd,
32 staticPartitionRange: partitionAttribute?.staticPartitionRangeBegin ? [partitionAttribute?.staticPartitionRangeBegin,
33 partitionAttribute?.staticPartitionRangeEnd] : null,
34 dynamicPartitionHistory: partitionAttribute?.dynamicPartitionHistory === "Y",
35 dynamicPartitionHistoryNum: partitionAttribute?.dynamicPartitionHistoryNum,
36 staticPartitionEnum: partitionAttribute?.staticPartitionEnum,
37 }
38 })
39
40 const formItems: any = ref([
41 {
42 label: "分区模式",
43 type: "radio-panel",
44 placeholder: "",
45 field: "partitionMode",
46 default: "dynamic",
47 options: [
48 { label: "动态分区", value: "dynamic" },
49 { label: "静态分区", value: "static" },
50 ],
51 children: [],
52 required: true,
53 block: true,
54 col: "no-wrap col2",
55 },
56 {
57 label: "分区类型",
58 type: "select",
59 placeholder: "请选择",
60 options: [
61 {
62 label: "Range",
63 value: "Range",
64 },
65 {
66 label: "List",
67 value: "List",
68 },
69 ],
70 field: "staticPartitionType",
71 default: 'Range',
72 required: true,
73 visible: false,
74 },
75 {
76 label: "分区字段",
77 type: "select",
78 placeholder: "请选择",
79 options: [],
80 field: "partitionCol",
81 default: "",
82 props: {
83 label: 'chName',
84 value: 'enName'
85 },
86 tooltip: true,
87 tooltipContent: '分区字段为日期、日期时间类型且为主键的字段。',
88 clearable: true,
89 required: true,
90 visible: true,
91 },
92 {
93 label: "分区单位",
94 type: "select",
95 placeholder: "请选择",
96 options: [
97 {
98 value: "DAY",
99 label: "按天",
100 },
101 {
102 value: "WEEK",
103 label: "按星期",
104 },
105 {
106 value: "MONTH",
107 label: "按月",
108 },
109 {
110 value: "YEAR",
111 label: "按年",
112 },
113 ],
114 default: "DAY",
115 field: "partitionTimeUnit",
116 required: true,
117 visible: false,
118 },
119 {
120 type: "select-group",
121 field: "dynamicPartitionTimeUnit",
122 children: [
123 {
124 label: "分区单位",
125 type: "select",
126 placeholder: "请选择",
127 options: [
128 {
129 value: "HOUR",
130 label: "按小时",
131 },
132 {
133 value: "DAY",
134 label: "按天",
135 },
136 {
137 value: "WEEK",
138 label: "按星期",
139 },
140 {
141 value: "MONTH",
142 label: "按月",
143 },
144 {
145 value: "YEAR",
146 label: "按年",
147 },
148 ],
149 default: "DAY",
150 field: "partitionTimeUnit",
151 required: true,
152 visible: true,
153 },
154 {
155 label: " ",
156 type: "input",
157 placeholder: "结束偏移量",
158 default: 3,
159 field: "dynamicPartitionEnd",
160 required: true,
161 visible: true,
162 },
163 ],
164 col: "col2",
165 visible: true
166 },
167 {
168 label: "分区范围",
169 type: "date-picker",
170 field: "staticPartitionRange",
171 default: null,
172 placeholder: "开始时间~截止时间",
173 clearable: true,
174 required: true,
175 visible: false,
176 },
177 {
178 type: "checkbox-input",
179 placeholder: "创建历史分区",
180 field: "dynamicPartitionHistory",
181 default: false,
182 children: [
183 {
184 label: "",
185 type: "input",
186 placeholder: "历史分区数量",
187 field: "dynamicPartitionHistoryNum",
188 default: 1,
189 required: false,
190 visible: false,
191 },
192 ],
193 class: "dialog-checkbox-input",
194 visible: true,
195 required: false,
196 },
197 {
198 label: "分区枚举值",
199 type: "textarea",
200 placeholder: "请使用“,”号分隔",
201 field: "staticPartitionEnum",
202 default: "",
203 clearable: true,
204 required: true,
205 block: true,
206 visible: false,
207 },
208 ]);
209 const formRules = ref({
210 staticPartitionType: [
211 {
212 validator: (rule: any, value: any, callback: any) => {
213 if (!value) {
214 callback(new Error("分区类型不为空"));
215 } else {
216 callback();
217 }
218 },
219 trigger: "blur",
220 },
221 ],
222 partitionCol: [{
223 validator: (rule: any, value: any, callback: any) => {
224 if (!value) {
225 callback(new Error("分区字段不为空"));
226 } else {
227 callback();
228 }
229 },
230 trigger: "blur",
231 }],
232 staticPartitionRange: [{
233 validator: (rule: any, value: any, callback: any) => {
234 if (!value?.length) {
235 callback(new Error("分区范围不为空"));
236 } else {
237 callback();
238 }
239 },
240 trigger: "blur",
241 }],
242 staticPartitionEnum: [{
243 trigger: "blur",
244 required: true,
245 message: '分区枚举值不能为空'
246 }],
247 dynamicPartitionHistoryNum: {
248 validator: (rule: any, value: any, callback: any) => {
249 const r = /(^[0-9]([0-9]*)$|^[0-9]$)/; // 正整数(可以以0打头)
250 if (value && !r.test(value)) {
251 callback(new Error('请填写大于或等于零整数'));
252 return;
253 }
254 if ((value + '').length > 6) {
255 callback(new Error('请填写小于7位的整数'));
256 return;
257 }
258 callback();
259 },
260 trigger: "blur",
261 },
262 dynamicPartitionEnd: {
263 validator: (rule: any, value: any, callback: any) => {
264 const r = /(^[0-9]([0-9]*)$|^[0-9]$)/; // 正整数(可以以0打头)
265 if (value && !r.test(value)) {
266 callback(new Error('请填写大于或等于零整数'));
267 return;
268 }
269 if ((value + '').length > 6) {
270 callback(new Error('请填写小于7位的整数'));
271 return;
272 }
273 callback();
274 },
275 trigger: "blur",
276 },
277 });
278
279 const expandPropertyDialogInfo = ref({
280 readonly: false,
281 visible: false,
282 size: 700,
283 height: "270px",
284 header: {
285 title: "扩展属性",
286 },
287 direction: "column",
288 type: "",
289 contents: [
290 {
291 type: "form",
292 title: "",
293 formInfo: {
294 readonly: false,
295 id: "edit-expand-property",
296 items: formItems.value,
297 rules: formRules.value,
298 },
299 },
300 ],
301 footer: {
302 visible: true,
303 btns: [
304 { type: "default", label: "取消", value: "cancel" },
305 { type: "primary", label: "确定", value: "submit" },
306 ],
307 },
308 });
309
310 /** 记录对话框编辑过程中的扩展属性。提交之后才会记录在expandProperties */
311 const editExpandProperties: any = ref({});
312
313 /** 扩展属性弹出对话框 */
314 const handleClickExpand = () => {
315 expandPropertyDialogInfo.value.visible = true;
316 if (props.isLook || props.tableCreateInfo.isCreate) {
317 expandPropertyDialogInfo.value.contents[0].formInfo.readonly = true;
318 expandPropertyDialogInfo.value.footer.visible = false;
319 } else {
320 expandPropertyDialogInfo.value.contents[0].formInfo.readonly = false;
321 expandPropertyDialogInfo.value.footer.visible = true;
322 }
323 if (expandProperties.value.partitionMode === 'dynamic') {
324 formItems.value[1].visible = false;
325 formItems.value[2].visible = true;
326 formItems.value[3].visible = false;
327 formItems.value[4].visible = true;
328 formItems.value[5].visible = false;
329 formItems.value[6].visible = true;
330 formItems.value[7].visible = false;
331 formItems.value[6].children[0].visible = expandProperties.value.dynamicPartitionHistory;
332 formItems.value[2].options = props.tableCreateInfo.tableFields?.filter(field => field.isPrimary === 'Y' && (field.dataType === 'date' || field.dataType === 'datetime')) || [];
333 formItems.value[2].tooltipContent = '分区字段为日期、日期时间类型且为主键的字段。';
334 } else {
335 formItems.value[1].visible = true;
336 formItems.value[2].visible = true;
337 formItems.value[3].visible = true;
338 formItems.value[4].visible = false;
339 formItems.value[5].visible = true;
340 formItems.value[6].visible = false;
341 formItems.value[7].visible = false;
342 let val = expandProperties.value.staticPartitionType;
343 formItems.value[3].visible = val !== 'List';
344 formItems.value[5].visible = val !== 'List';
345 formItems.value[7].visible = val === 'List';
346 if (val !== 'List') {
347 formItems.value[2].options = props.tableCreateInfo.tableFields?.filter(field => field.isPrimary === 'Y' && (field.dataType === 'date' || field.dataType === 'datetime')) || [];
348 formItems.value[2].tooltipContent = '分区字段为日期、日期时间类型且为主键的字段。';
349 } else {
350 formItems.value[2].options = props.tableCreateInfo.tableFields?.filter(field => field.isPrimary === 'Y') || [];
351 formItems.value[2].tooltipContent = '分区字段为主键字段。';
352 }
353 }
354 expandPropertyDialogInfo.value.contents[0].formInfo.items = formItems.value;
355 editExpandProperties.value = Object.assign({}, expandProperties.value);
356 setFormItems(editExpandProperties.value);
357 };
358
359 /** 重置formItems的值 */
360 const setFormItems = (row: any = null) => {
361 formItems.value.forEach(item => {
362 if (item.field === 'dynamicPartitionTimeUnit') {
363 item.children.forEach(child => {
364 child.default = row[child.field];
365 });
366 } else if (item.field === 'dynamicPartitionHistory') {
367 item.default = row[item.field];
368 item.children.forEach(child => {
369 child.default = row[child.field];
370 });
371 } else {
372 item.default = row[item.field];
373 }
374 })
375 }
376
377 const radioGroupChange = (val, info) => {
378 formItems.value[0].default = val;
379 if (val == "dynamic") {
380 formItems.value[1].visible = false;
381 formItems.value[2].visible = true;
382 formItems.value[3].visible = false;
383 formItems.value[4].visible = true;
384 formItems.value[5].visible = false;
385 formItems.value[6].visible = true;
386 formItems.value[7].visible = false;
387 } else if (val == "static") {
388 formItems.value[1].visible = true;
389 formItems.value[2].visible = true;
390 formItems.value[3].visible = true;
391 formItems.value[4].visible = false;
392 formItems.value[5].visible = true;
393 formItems.value[6].visible = false;
394 formItems.value[7].visible = false;
395 }
396 expandPropertyDialogInfo.value.contents[0].formInfo.items = formItems.value;
397 editExpandProperties.value = Object.assign({}, editExpandProperties.value, info)
398 setFormItems(editExpandProperties.value);
399 };
400
401 const dialogCheckboxChange = (val, info) => {
402 let opts: any = formItems.value[6].children;
403 opts[0].visible = val;
404 editExpandProperties.value = Object.assign({}, editExpandProperties.value, info)
405 setFormItems(editExpandProperties.value);
406 };
407
408 const dialogSelectChange = (val, row, info) => {
409 if (row.field == 'staticPartitionType') {
410 formItems.value[3].visible = val !== 'List';
411 formItems.value[5].visible = val !== 'List';
412 formItems.value[7].visible = val === 'List';
413 if (val !== 'List') {
414 formItems.value[2].options = props.tableCreateInfo.tableFields?.filter(field => field.isPrimary === 'Y' && (field.dataType === 'date' || field.dataType === 'datetime')) || [];
415 formItems.value[2].tooltipContent = '分区字段为日期、日期时间类型且为主键的字段。';
416 } else {
417 formItems.value[2].options = props.tableCreateInfo.tableFields?.filter(field => field.isPrimary === 'Y') || [];
418 formItems.value[2].tooltipContent = '分区字段为主键字段。';
419 }
420 }
421 editExpandProperties.value = Object.assign({}, editExpandProperties.value, info)
422 setFormItems(editExpandProperties.value);
423 }
424
425 const expandPropertyDialogBtnClick = (btn, info) => {
426 if (btn.value == 'submit') {
427 emits('expandValueChange', info);
428 expandPropertyDialogInfo.value.visible = false;
429 } else if (btn.value == 'cancel') {
430 expandPropertyDialogInfo.value.visible = false;
431 }
432 };
433
434 defineExpose({
435 handleClickExpand
436 });
437
438 </script>
439
440 <template>
441 <Dialog ref="expandPropertyDialogRef" :dialogInfo="expandPropertyDialogInfo" @radioGroupChange="radioGroupChange"
442 @checkboxChange="dialogCheckboxChange" @selectChange="dialogSelectChange" @btnClick="expandPropertyDialogBtnClick" />
443 </template>
444
445 <style scoped lang="scss"></style>
446
1 <template>
2 <el-select v-if="!readonly && isEdit && isSelectType(dbType, scope)" v-model="scope.row['defaultValue']" placeholder="请选择" collapse-tags-tooltip
3 filterable allow-create default-first-option :reserve-keyword="false">
4 <el-option v-for="opt in optionsConfig[dataType]" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
5 </el-select>
6 <el-date-picker v-else-if="!readonly && isEdit && dataType === 'date'" v-model="scope.row['defaultValue']" type="date"
7 format="YYYY-MM-DD" value-format="YYYY-MM-DD" placeholder="请选择" />
8 <el-date-picker v-else-if="!readonly && isEdit && dbType === 'mysql' && dataType === 'datetime'"
9 v-model="scope.row['defaultValue']" placeholder="请选择" type="datetime" format="YYYY-MM-DD HH:mm:ss"
10 value-format="YYYY-MM-DD HH:mm:ss" />
11 <el-input v-else-if="!readonly && isEdit" v-model.trim="scope.row['defaultValue']" placeholder="请填写"
12 @input="(val) => inputChange(val, scope.row.dataType, scope)" />
13 <span v-else>{{ scope.row["defaultValue"] == null ? '-' : (isSelectType(dbType, scope) ?
14 (optionsConfig[dataType].find(s => s.value == scope.row["defaultValue"])?.label ??
15 scope.row["defaultValue"]) : scope.row["defaultValue"]) }}</span>
16 </template>
17
18 <script lang="ts" setup name="tableDefaultValue">
19 import { ref } from "vue";
20 import { useDefault } from "@/hooks/useDefault";
21 const { optionsConfig, inputChange, isSelectType } = useDefault()
22
23 const props = defineProps({
24 dbType: {
25 type: String,
26 default: ''
27 },
28 scope: {
29 type: Object,
30 default: {}
31 },
32 readonly: {
33 type: Boolean,
34 default: false
35 }
36 })
37
38 const isEdit = computed(() => {
39 return props.scope.row['isEdit'];
40 });
41
42 const dataType = computed(() => {
43 return props.scope.row['dataType'];
44 });
45
46 </script>
...\ No newline at end of file ...\ No newline at end of file
1 <route lang="yaml">
2 name: dimTableCreateManual
3 </route>
4
5 <script lang="ts" setup name="dimTableCreateManual">
6 import { ref } from "vue";
7 import { useRouter, useRoute } from "vue-router";
8 import { ElMessage, ElMessageBox, ElTable } from "element-plus";
9 import { QuestionFilled } from "@element-plus/icons-vue";
10 import {
11 getDatabase,
12 saveSubjectTable,
13 dimTypeList,
14 syncPolicys,
15 tableModels,
16 aggMethodList,
17 getMetaStandardDsField,
18 getAllFlowData
19 } from "@/api/modules/dataMetaService";
20 import useUserStore from "@/store/modules/user";
21 import expandPropertyDialog from "./components/expandPropertyDialog.vue";
22 import tableDefaultValue from "./components/tableDefaultValue.vue";
23 import { useDefault } from "@/hooks/useDefault"
24 import { getCamundaDeploymentId } from "@/api/modules/workFlowService"
25
26 const userStore = useUserStore();
27 const { checkDefault } = useDefault()
28
29 const router = useRouter();
30 const route = useRoute();
31 const fullPath = route.fullPath;
32 const isLook = <any>route.query.isLook == 1;
33 const subjectDomainGuid: any = ref(route.query.domainGuid);
34
35 const tableCreateInfoLoading = ref(false);
36
37 const { proxy } = getCurrentInstance() as any;
38 const fieldStandardTableRef = ref<InstanceType<typeof ElTable>>();
39
40 /** 表模型,只有doris数据库才有 */
41 const dbType = ref("");
42
43 const databaseList: any = ref([]);
44
45 const tableFieldsLoading = ref(false);
46
47 //记录当前正在编辑的表创建信息。
48 const tableCreateInfo: Ref<any> = ref({
49 guid: "",
50 isCreate: false,
51 inputNameValue: '',
52 tableCreateType: 1,
53 tableData: [
54 {
55 //数据库表信息。
56 dataSourceGuid: '',
57 dataServerName: "",
58 dataServerChName: "",
59 enName: "",
60 chName: "",
61 subjectDomain: route.query.domainName,
62 subjectDomainGuid: subjectDomainGuid.value,
63 dimType: 1,
64 codeColumn: '',
65 codeName: '',
66 syncPolicy: 3,
67 tableCategory: 4,
68 characterSet: 'utf8mb3',
69 tableModel: 1, //若是聚合模型,下方出现一列聚合方式选择。处了主键列,其余列都需要选择。每个表里都要有主键。
70 description: "",
71 },
72 ],
73 partitionAttribute: {},
74 tableFields: [], // 字段标准数组。
75 });
76
77 const selectTableFieldRows = ref([]);
78
79 //字段类型
80 const fieldTypes: any = ref([]);
81
82 //字符集
83 const characterList: any = ref([]);
84
85 //是否列表
86 const isNotList = ref([
87 {
88 label: "Y",
89 value: "Y",
90 },
91 {
92 label: "N",
93 value: "N",
94 },
95 ]);
96
97 const fullscreenLoading = ref(false);
98
99 /** 表里有数据时删除字段时提示。 */
100 const hasSubjectData = ref(false);
101
102 const expandProperties = ref({});
103
104 const deploymentId = ref('');
105 const flowExpand = ref(true);
106
107 onBeforeMount(() => {
108 getDatabaseList();
109 getFieldTypeList();
110 getCharacterListData();
111 if (route.query.metaStandard) {
112 tableCreateInfo.value.tableData[0].chName = route.query.standardName;
113 tableCreateInfoLoading.value = true;
114 getMetaStandardDsField(route.query.metaStandard).then((res: any) => {
115 tableCreateInfoLoading.value = false;
116 if (res.code == proxy.$passCode) {
117 tableCreateInfo.value.tableFields = res.data?.map((d, i) => {
118 d.orderNum = i;
119 d.isEdit = true;
120 return d;
121 }) || [];
122 } else {
123 proxy.$ElMessage.error(res.msg);
124 }
125 })
126 }
127 getCamundaDeploymentId('10025').then((res: any) => {
128 if (res.code == proxy.$passCode) {
129 deploymentId.value = res.data;
130 } else {
131 proxy.$ElMessage.error(res.msg);
132 }
133 })
134 })
135
136 onMounted(() => {
137 })
138
139 onActivated(() => {
140 });
141
142 const getDatabaseList = () => {
143 getDatabase({ connectStatus: 1 }).then((res: any) => {
144 databaseList.value = [];
145 if (res.code == proxy.$passCode) {
146 databaseList.value = res.data || [];
147 } else {
148 ElMessage.error(res.msg);
149 }
150 })
151 };
152
153 const getFieldTypeList = () => {
154 getAllFlowData('字段类型').then((res: any) => {
155 fieldTypes.value = [];
156 if (res.code == proxy.$passCode) {
157 fieldTypes.value = res.data || [];
158 } else {
159 ElMessage.error(res.msg);
160 }
161 })
162 }
163
164 const getCharacterListData = () => {
165 getAllFlowData('Mysql字符集').then((res: any) => {
166 characterList.value = [];
167 if (res.code == proxy.$passCode) {
168 characterList.value = res.data || [];
169 } else {
170 ElMessage.error(res.msg);
171 }
172 })
173 }
174
175 /** 限制长度输入框只能输入整型数字,表,字段英文名称,限制输入字符,数字和下划线。 */
176 const inputLengthKeyUp = (regexp, scope, field, max: any = null, min: any = null) => {
177 scope.row[field] = scope.row[field].replace(regexp, '');
178 if (field == 'fieldLength' && scope.row.dataType == 'decimal') {
179 max = 65;
180 }
181 /** 最大值设置2000 */
182 if (max && scope.row[field] > max) {
183 scope.row[field] = max;
184 }
185 if (min !== null && scope.row[field] != '' && scope.row[field] <= min) {
186 scope.row[field] = min;
187 }
188 }
189
190 /** 保存表 */
191 const saveTable = () => {
192 let tableData = tableCreateInfo.value.tableData[0];
193 if (!tableData.chName) {
194 ElMessage({
195 type: "error",
196 message: "主题表名称不能为空",
197 });
198 return;
199 }
200 if (!tableData.dataServerName) {
201 ElMessage({
202 type: "error",
203 message: "数据源不能为空",
204 });
205 return;
206 }
207 if (tableData.dataServerName.indexOf('-') > -1) {
208 ElMessage.error('数据库表名称不能包含中划线,可以改为下划线');
209 return;
210 }
211 if (!tableCreateInfo.value.inputNameValue) {
212 ElMessage({
213 type: "error",
214 message: "主题表名称不能为空",
215 });
216 return;
217 }
218 if (!tableData.codeColumn) {
219 ElMessage({
220 type: "error",
221 message: "编码字段不能为空",
222 });
223 return;
224 }
225 if (!tableData.codeName) {
226 ElMessage({
227 type: "error",
228 message: "编码名称不能为空",
229 });
230 return;
231 }
232 let tableFields = tableCreateInfo.value.tableFields;
233 if (!tableFields.length) {
234 ElMessage({
235 type: "error",
236 message: "表字段不能为0行",
237 });
238 return;
239 }
240 // 若开启了字段标准,则不能为空。
241 // 必须含有主键。若是聚合模型,则除了主键必须有聚合方式。
242 let isSumModel = tableData.tableModel === 2;
243 let hasPrimary = false;
244 let enNames: any = [];
245 let chNames: any = [];
246 const regex = /^[a-zA-Z]/;
247 for (const field of tableFields) {
248 if (!field.enName) {
249 ElMessage.error(`第 ${field.orderNum} 个字段的英文名称不能为空`);
250 return;
251 }
252 if (!regex.test(field.enName)) {
253 ElMessage.error(`第 ${field.orderNum} 个字段的英文名称必须以英文字符开头`);
254 return;
255 }
256 if (!field.dataType) {
257 ElMessage.error(`第 ${field.orderNum} 个字段的字段类型不能为空`);
258 return;
259 }
260 if (enNames.indexOf(field.enName) > -1) {
261 ElMessage.error(`字段的英文名称 ${field.enName} 不能重复`);
262 return;
263 }
264 if (chNames.indexOf(field.chName) > -1) {
265 ElMessage.error(`字段的中文名称 ${field.chName} 不能重复`);
266 return;
267 }
268 if (field.dataType === "decimal" && (!field.fieldPrecision && field.fieldPrecision != 0)) {
269 ElMessage.error(`第 ${field.orderNum} 个字段的字段类型为浮点型时,精度不能为空`);
270 return;
271 }
272 if (field.dataType === "varchar" && (!field.fieldLength && field.fieldLength != 0)) {
273 ElMessage.error(`第 ${field.orderNum} 个字段的字段类型为字符型时,长度不能为空`);
274 return;
275 }
276 if (field.dataType === "char" && (!field.fieldLength && field.fieldLength != 0)) {
277 ElMessage.error(`第 ${field.orderNum} 个字段的字段类型为单字符型时,长度不能为空`);
278 return;
279 }
280 if (field.dataType === "decimal" && (!field.fieldLength && field.fieldLength != 0)) {
281 ElMessage.error(`第 ${field.orderNum} 个字段的字段类型为浮点符型时,长度不能为空`);
282 return;
283 }
284 if (field.isPrimary === 'Y') {
285 hasPrimary = true;
286 if (field.notNull != 'Y') {
287 ElMessage.error(`第 ${field.orderNum} 个字段为主键,应设置为必填`);
288 return;
289 }
290 if (field.dataType == 'text') {
291 ElMessage.error(`第 ${field.orderNum} 个字段为主键,字段类型不能设置为‘大字段型’`);
292 return;
293 }
294 if (field.dataType == 'json') {
295 ElMessage.error(`第 ${field.orderNum} 个字段为主键,字段类型不能设置为‘JSON类型’`);
296 return;
297 }
298 if (field.dataType == 'bit') {
299 ElMessage.error(`第 ${field.orderNum} 个字段为主键,字段类型不能设置为‘布尔类型’`);
300 return;
301 }
302 } else {
303 if (!field.aggWay && isSumModel) {
304 ElMessage.error(`聚合模型的非主键字段必须设置聚合方式`);
305 return;
306 }
307 }
308 if (field.isEdit) {
309 if (checkDefault[field.dataType]) {
310 if (!field.fieldLength) { }
311 if (!checkDefault[field.dataType]({ row: field })) {
312 return;
313 }
314 }
315 }
316 enNames.push(field.enName);
317 chNames.push(field.chName);
318 field.fieldStandardGuid = route.query.metaStandard;
319 }
320 if (!hasPrimary) {
321 ElMessage.error(`字段至少有一个主键字段!`);
322 return;
323 }
324 let addInfo = Object.assign({}, tableCreateInfo.value.tableData[0], {
325 enName: tableCreateInfo.value.inputNameValue,
326 tableCreateType: tableCreateInfo.value.tableCreateType,
327 saveFlag: 1,
328 dbType: dbType.value,
329 dataState: 1,
330 partitionAttribute: !Object.keys(tableCreateInfo.value.partitionAttribute).length ? null : Object.assign({}, tableCreateInfo.value.partitionAttribute, {
331 dynamicPartitionHistory: tableCreateInfo.value.partitionAttribute ? "Y" : 'N'
332 }),
333 subjectFieldAddDTOS: tableCreateInfo.value.tableFields.map((field, i) => {
334 return Object.assign({}, field, { orderNum: i + 1 });
335 }),
336 })
337 if (!tableCreateInfo.value.guid) { //添加
338 fullscreenLoading.value = true;
339 saveSubjectTable(addInfo).then((res: any) => {
340 fullscreenLoading.value = false;
341 if (res.code == proxy.$passCode) {
342 ElMessage.success('新建表提交成功!');
343 router.push({
344 name: 'metadataStandardQuery'
345 });
346 userStore.setTabbar(userStore.tabbar.filter((tab: any) => tab.fullPath !== fullPath));
347 } else {
348 ElMessage.error(res.msg);
349 }
350 }).catch((err) => {
351 ElMessage.error(err);
352 fullscreenLoading.value = false;
353 });
354 }
355 };
356
357 //数据库选择改变,对应的表名称是否需要变化。需要根据此属性带出表名前缀,以及是否是doris数据库。
358 const selectDatabaseChange = (val) => {
359 let oldDbType = dbType.value;
360 let d = databaseList.value.find(d => d.guid === val);
361 if (d) {
362 dbType.value = d.databaseType;
363 tableCreateInfo.value.tableData[0].dataSourceGuid = d.guid;
364 tableCreateInfo.value.tableData[0].dataServerName = d.databaseNameEn;
365 } else {
366 dbType.value = "";
367 tableCreateInfo.value.tableData[0].dataSourceGuid = '';
368 tableCreateInfo.value.tableData[0].dataServerName = '';
369 }
370 if (oldDbType != dbType.value) {
371 tableCreateInfo.value.tableFields.forEach((tableField: any) => {
372 if (tableField['dataType'] === "datetime") {
373 tableField.defaultValue = ""
374 }
375 })
376 }
377 };
378
379 /** 添加字段标准 */
380 const addField = () => {
381 let len = tableCreateInfo.value.tableFields.length;
382 tableCreateInfo.value.tableFields.push({
383 orderNum: len + 1,
384 isDim: "N",
385 isPrimary: "N",
386 notNull: "N",
387 isEdit: true
388 });
389 //设置选中表格当前新增行。
390 fieldStandardTableRef.value?.setCurrentRow(
391 tableCreateInfo.value.tableFields[tableCreateInfo.value.tableFields.length - 1]
392 );
393 nextTick(() => {
394 let bodyWrapper = fieldStandardTableRef.value?.$el.querySelector('.el-table__body');
395 let domScroll = bodyWrapper.parentElement.parentElement;
396 let rect = domScroll.getBoundingClientRect();
397 let maxNum = len + 1;
398 if (maxNum * 36 > rect.height + domScroll.scrollTop) {
399 fieldStandardTableRef.value?.setScrollTop(maxNum * 36 - rect.height + 2)
400 }
401 })
402 };
403
404 /** 勾选字段标准选中变化。 */
405 const selectionFieldsChange = (val) => {
406 selectTableFieldRows.value = val;
407 };
408
409 /**
410 * 上移规则:
411 * 勾选多个时先从最上面开始逐个上移一行,若已经移到最上面一行,则不处理。
412 */
413 const moveUp = () => {
414 let selectRows = fieldStandardTableRef.value?.getSelectionRows();
415 if (!selectRows.length) {
416 ElMessage.error('请先选择需要勾选的数据进行上移');
417 return;
418 }
419 let data = tableCreateInfo.value.tableFields;
420 let selectRowIndexs: number[] = [];
421 let minNum: number = 0;
422 selectRows.forEach((row, i) => {
423 let orderNum = data.findIndex(d => d === row) + 1;
424 if (orderNum == 1) {
425 selectRowIndexs.push(orderNum);
426 minNum = orderNum;
427 return;
428 }
429 if (selectRowIndexs.includes(orderNum - 1)) {
430 //下一行也是选中的,则不做转换。
431 return;
432 }
433 let topNum = orderNum - 1;
434 if (i === 0) {
435 minNum = topNum;
436 }
437 row.orderNum = topNum;
438 let changeRow = data[topNum - 1];
439 changeRow.orderNum = orderNum;
440 selectRowIndexs.push(topNum);
441 data[topNum] = changeRow;
442 data[topNum - 1] = row;
443 });
444 nextTick().then(() => {
445 let bodyWrapper = fieldStandardTableRef.value?.$el.querySelector('.el-table__body');
446 let domScroll = bodyWrapper.parentElement.parentElement;
447 if ((minNum * 36 - 36 - 2) < domScroll.scrollTop) {
448 fieldStandardTableRef.value?.setScrollTop((domScroll.scrollTop - 36 - 2) < 0 ? 0 : (domScroll.scrollTop - 36 - 2))
449 }
450 });
451 }
452
453 /**
454 * 下移规则:
455 * 勾选多个时先从最下面开始逐个下移一行,若已经移到最下面一行,则不处理。
456 */
457 const moveDown = () => {
458 let selectRows = fieldStandardTableRef.value?.getSelectionRows();
459 if (!selectRows.length) {
460 ElMessage.error('请先选择需要勾选的数据进行下移');
461 return;
462 }
463 let data = tableCreateInfo.value.tableFields;
464 let selectRowIndexs: number[] = [];
465 let maxNum: number = 0;
466 selectRows.slice(0).reverse().forEach((row, i) => {
467 let orderNum = data.findIndex(d => d === row) + 1;
468 if (orderNum === data.length) {
469 maxNum = orderNum;
470 selectRowIndexs.push(orderNum);
471 return;
472 }
473 if (selectRowIndexs.includes(orderNum + 1)) {
474 //下一行也是选中的,则不做转换。
475 return;
476 }
477 let bottomNum = orderNum + 1;
478 row.orderNum = bottomNum;
479 if (i === 0) {
480 maxNum = bottomNum;
481 }
482 let changeRow = data[bottomNum - 1];
483 changeRow.orderNum = orderNum;
484 selectRowIndexs.push(bottomNum);
485 data[orderNum - 1] = changeRow;
486 data[bottomNum - 1] = row;
487 });
488 nextTick(() => {
489 let bodyWrapper = fieldStandardTableRef.value?.$el.querySelector('.el-table__body');
490 let domScroll = bodyWrapper.parentElement.parentElement;
491 let rect = domScroll.getBoundingClientRect();
492 if (maxNum * 36 > rect.height + domScroll.scrollTop) {
493 fieldStandardTableRef.value?.setScrollTop(maxNum * 36 - rect.height + 2)
494 }
495 })
496 }
497
498
499 /** 批量删除字段标准 */
500 const delFeilds = () => {
501 if (selectTableFieldRows.value.length == 0) {
502 ElMessage({
503 type: "info",
504 message: "请选择需要删除的字段",
505 });
506 return;
507 }
508 if (tableCreateInfo.value.isCreate) {
509 if (selectTableFieldRows.value.find((row: any) => row.isPrimary === 'Y')) {
510 ElMessage.error('已建表不能删除主键字段');
511 return;
512 }
513 }
514 let hasCreateField = selectTableFieldRows.value.some((row: any) => row.isCreate === 'Y');
515 ElMessageBox.confirm(hasCreateField && hasSubjectData.value ? '已选择的字段中含有已创建的表字段且有数据,此操作将永久删除,是否继续?' : "此操作将永久删除,是否继续?", "提示", {
516 confirmButtonText: "确定",
517 cancelButtonText: "取消",
518 type: "warning",
519 })
520 .then(() => {
521 //此删除是直接从库里删除,还是点击保存后再删除呢??如果是入库删除,后,调用接口获取数据。
522 let tableFields = tableCreateInfo.value.tableFields;
523 let tableData = tableCreateInfo.value.tableData[0];
524 selectTableFieldRows.value.forEach((r: any) => {
525 let index = tableFields.findIndex((t: any) => t.orderNum === r.orderNum);
526 if (index !== -1) {
527 let row = tableFields[index];
528 tableFields.splice(index, 1);
529 if (tableData.codeName == row.enName) {
530 tableData.codeName = "";
531 }
532 if (tableData.codeColumn == row.enName) {
533 tableData.codeColumn = "";
534 }
535 }
536 });
537 fieldStandardTableRef.value?.clearSelection();
538 tableCreateInfo.value.tableFields.forEach((field, i) => {
539 field.orderNum = i + 1;
540 });
541 ElMessage({
542 type: "success",
543 message: "删除成功",
544 });
545 })
546 .catch(() => {
547 ElMessage({
548 type: "info",
549 message: "已取消删除",
550 });
551 });
552 };
553
554 //点击编辑按钮
555 const handleFieldClickEdit = (scope) => {
556 scope.row['isEdit'] = true;
557 };
558
559 //点击保存按钮
560 const handleFieldClickSave = (scope) => {
561 if (!scope.row.fieldStandardCode) {
562 ElMessage({
563 type: "error",
564 message: "该主题域开启了字段标准,当前行字段标准不能为空!",
565 });
566 return;
567 }
568 if (!scope.row.enName) {
569 ElMessage({
570 type: "error",
571 message: "字段英文名不能为空!",
572 });
573 return;
574 }
575 scope.row['isEdit'] = false;
576 };
577
578 const handleFieldDelete = (scope) => {
579 ElMessageBox.confirm(scope.row['isCreate'] === 'Y' && hasSubjectData.value ? '该字段已被创建且表中有数据,此操作将永久删除,是否继续?' : "此操作将永久删除,是否继续?", "提示", {
580 confirmButtonText: "确定",
581 cancelButtonText: "取消",
582 type: "warning",
583 })
584 .then(() => {
585 let tableFields = tableCreateInfo.value.tableFields;
586 tableFields.splice(scope.$index, 1);
587 tableCreateInfo.value.tableFields.forEach((field, i) => {
588 field.orderNum = i + 1;
589 });
590 tableCreateInfo.value.tableFields.forEach((field, i) => {
591 field.orderNum = i + 1;
592 });
593 let row = scope.row;
594 let tableData = tableCreateInfo.value.tableData[0];
595 if (tableData.codeName == row.enName) {
596 tableData.codeName = "";
597 }
598 if (tableData.codeColumn == row.enName) {
599 tableData.codeColumn = "";
600 }
601 ElMessage({
602 type: "success",
603 message: "删除成功",
604 });
605 })
606 .catch(() => {
607 ElMessage({
608 type: "info",
609 message: "已取消删除",
610 });
611 });
612 }
613
614 const dataTypeChange = (val, scope) => {
615 scope.row['defaultValue'] = ''
616 scope.row['fieldLength'] = undefined
617 scope.row['fieldPrecision'] = undefined
618 }
619
620 /** 扩展属性弹出对话框 */
621 const expandPropertyDialogRef = ref();
622
623 /** 扩展属性弹出对话框 */
624 const handleClickExpand = () => {
625 expandPropertyDialogRef.value?.handleClickExpand();
626 }
627
628 const expandDialogValueChange = (val) => {
629 tableCreateInfo.value.partitionAttribute = val;
630 expandProperties.value = val;
631 }
632
633 const tableSelectFields = computed(() => {
634 return tableCreateInfo.value.tableFields.filter(t => !!t.enName);
635 })
636
637 </script>
638
639 <template>
640 <div class="table_tool_wrap" v-loading.fullscreen.lock="fullscreenLoading">
641 <div class="tools_btns">
642 <!-- <el-button type="primary" :disabled="isLook" @click="saveDraftTable" v-preReClick>保存为草稿</el-button> -->
643 <el-button type="primary" :disabled="isLook" @click="saveTable" v-preReClick>提交</el-button>
644 </div>
645 <el-table ref="tableRef" :data="tableCreateInfo.tableData" v-loading="tableCreateInfoLoading"
646 :highlight-current-row="true" stripe border height="100%" tooltip-effect="light" row-key="guid" :style="{
647 width: '100%',
648 height: 'auto',
649 display: 'inline-block',
650 }">
651 <el-table-column prop="dataSourceGuid" label="数据源" width="200px" align="left" show-overflow-tooltip>
652 <template #header>
653 <span>数据源</span>
654 <span v-if="!isLook" style="color:red;margin-left: 2px;">*</span>
655 </template>
656 <template #default="scope">
657 <el-select v-if="!isLook" v-model="scope.row['dataSourceGuid']" placeholder="请选择"
658 :disabled="tableCreateInfo.isCreate" @change="(val) => selectDatabaseChange(val)" clearable filterable>
659 <el-option v-for="opt in databaseList" :key="opt['guid']" :label="opt['databaseNameZh']"
660 :value="opt['guid']" />
661 </el-select>
662 <span v-else>{{ scope.row["dataServerChName"] }}</span>
663 </template>
664 </el-table-column>
665 <el-table-column prop="enName" label="数据库表" width="200px" align="left" show-overflow-tooltip>
666 <template #header>
667 <span>数据库表</span>
668 <span v-if="!isLook" style="color:red;margin-left: 2px;">*</span>
669 </template>
670 <template #default="scope">
671 <template v-if="!isLook">
672 <div class="prefix-or-suffix-cell">
673 <el-input :disabled="tableCreateInfo.isCreate" v-model.trim="tableCreateInfo.inputNameValue"
674 :maxlength="50" placeholder="必填" />
675 </div>
676 </template>
677 <span v-else>{{ scope.row["enName"] }}</span>
678 </template>
679 </el-table-column>
680 <el-table-column prop="chName" label="主题表名称" width="200px" align="left" show-overflow-tooltip>
681 <template #header>
682 <span>主题表名称</span>
683 <span v-if="!isLook" style="color:red;margin-left: 2px;">*</span>
684 </template>
685 <template #default="scope">
686 <el-input v-if="!isLook" v-model.trim="scope.row['chName']" placeholder="必填" :maxlength="50" />
687 <span v-else>{{ scope.row["chName"] }}</span>
688 </template>
689 </el-table-column>
690 <el-table-column prop="subjectDomain" label="主题域" width="180px" align="left" show-overflow-tooltip>
691 <template #default="scope">
692 <el-input v-if="!isLook" disabled v-model.trim="scope.row['subjectDomain']" />
693 <span v-else>{{ scope.row["subjectDomain"] }}</span>
694 </template>
695 </el-table-column>
696 <el-table-column prop="tableModel" label="表模型" :width="isLook ? '100px' : '150px'" align="left"
697 show-overflow-tooltip>
698 <template #default="scope">
699 <el-select v-if="dbType == 'doris' && !isLook" v-model="scope.row['tableModel']" placeholder="请选择"
700 :disabled="tableCreateInfo.isCreate">
701 <el-option v-for="opt in tableModels" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
702 </el-select>
703 <span v-else-if="dbType == 'doris'">{{tableModels.find(t => t.value === scope.row["tableModel"])?.label ||
704 '-'
705 }}</span>
706 <span v-else>--</span>
707 </template>
708 </el-table-column>
709 <el-table-column prop="dimType" label="维表类型" :width="isLook ? '100px' : '150px'" align="left"
710 show-overflow-tooltip>
711 <template #default="scope">
712 <el-select v-if="!isLook" v-model="scope.row['dimType']" placeholder="请选择">
713 <el-option v-for="opt in dimTypeList" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
714 </el-select>
715 <span v-else>{{dimTypeList.find(t => t.value === scope.row["dimType"])?.label || '-'}}</span>
716 </template>
717 </el-table-column>
718 <el-table-column prop="codeColumn" label="编码字段" :width="isLook ? '100px' : '150px'" align="left"
719 show-overflow-tooltip>
720 <template #header>
721 <div class="header_title">
722 <span>编码字段</span>
723 <span v-if="!isLook" style="color:red;margin-left: 2px;margin-right: 8px;">*</span>
724 <el-tooltip placement="top" effect="light" popper-class="table_tooltip">
725 <template #content>
726 <div style="max-width: 236px;">
727 下拉列表来自于该表的字段。
728 </div>
729 </template>
730 <el-icon>
731 <QuestionFilled />
732 </el-icon>
733 </el-tooltip>
734 </div>
735 </template>
736 <template #default="scope">
737 <el-select v-if="!isLook" v-model="scope.row['codeColumn']" placeholder="请选择">
738 <el-option v-for="opt in tableSelectFields" :key="opt['enName']" :label="opt['chName']"
739 :value="opt['enName']" />
740 </el-select>
741 <span v-else>{{ scope.row["codeColumn"] || '-' }}</span>
742 </template>
743 </el-table-column>
744 <el-table-column prop="codeName" label="编码名称" :width="isLook ? '100px' : '150px'" align="left"
745 show-overflow-tooltip>
746 <template #header>
747 <div class="header_title">
748 <span>编码名称</span>
749 <span v-if="!isLook" style="color:red;margin-left: 2px;margin-right: 8px;">*</span>
750 <el-tooltip placement="top" effect="light" popper-class="table_tooltip">
751 <template #content>
752 <div style="max-width: 236px;">
753 下拉列表来自于该表的字段。
754 </div>
755 </template>
756 <el-icon>
757 <QuestionFilled />
758 </el-icon>
759 </el-tooltip>
760 </div>
761 </template>
762 <template #default="scope">
763 <el-select v-if="!isLook" v-model="scope.row['codeName']" placeholder="请选择">
764 <el-option v-for="opt in tableSelectFields" :key="opt['enName']" :label="opt['chName']"
765 :value="opt['enName']" />
766 </el-select>
767 <span v-else>{{ scope.row["codeName"] || '-' }}</span>
768 </template>
769 </el-table-column>
770 <el-table-column prop="syncPolicy" label="同步策略" :width="isLook ? '100px' : '150px'" align="left"
771 show-overflow-tooltip>
772 <template #default="scope">
773 <el-select v-if="!isLook" v-model="scope.row['syncPolicy']" placeholder="请选择">
774 <el-option v-for="opt in syncPolicys" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
775 </el-select>
776 <span v-else>{{syncPolicys.find(s => s.value === scope.row["syncPolicy"])?.label || '-'}}</span>
777 </template>
778 </el-table-column>
779 <el-table-column prop="characterSet" label="字符集" :width="isLook ? '100px' : '150px'" align="left"
780 show-overflow-tooltip>
781 <template #default="scope">
782 <el-select v-if="!isLook" v-model="scope.row['characterSet']" placeholder="请选择">
783 <el-option v-for="opt in characterList" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
784 </el-select>
785 <span v-else>{{characterList.find(c => c.value === scope.row["characterSet"])?.label || '-'
786 }}</span>
787 </template>
788 </el-table-column>
789 <el-table-column prop="description" label="描述" width="220px" align="left" show-overflow-tooltip>
790 <template #default="scope">
791 <el-input v-if="!isLook" v-model.trim="scope.row['description']" />
792 <span v-else>{{ scope.row["description"] || '-' }}</span>
793 </template>
794 </el-table-column>
795 <el-table-column label="操作" width="100px" align="left" fixed="right" show-overflow-tooltip>
796 <template #default="scope">
797 <span class="text_btn" @click="handleClickExpand()" v-preReClick>扩展属性</span>
798 </template>
799 </el-table-column>
800 </el-table>
801 <div class="tools_btns">
802 <el-button type="primary" :disabled="isLook" @click="addField">新增</el-button>
803 <el-button @click="moveUp" :disabled="isLook">上移</el-button>
804 <el-button @click="moveDown" :disabled="isLook">下移</el-button>
805 <el-button @click="delFeilds" :disabled="isLook">批量删除</el-button>
806 </div>
807 <div class="table_panel">
808 <el-table ref="fieldStandardTableRef" :data="tableCreateInfo.tableFields" v-loading="tableFieldsLoading"
809 :highlight-current-row="true" stripe border height="100%" row-key="guid"
810 @selection-change="selectionFieldsChange" tooltip-effect="light" :style="{
811 width: '100%',
812 'max-height': 'calc(100% - 16px)',
813 display: 'inline-block',
814 }">
815 <el-table-column type="selection" v-if="!isLook" :width="32" align="center" />
816 <el-table-column label="排序" type="index" width="56px" align="center" show-overflow-tooltip>
817 </el-table-column>
818 <el-table-column prop="chName" label="字段中文名称" width="150px" align="left" show-overflow-tooltip>
819 <template #default="scope">
820 <el-input v-if="scope.row['isEdit']" placeholder="请输入" v-model.trim="scope.row['chName']" />
821 <span v-else>{{ scope.row["chName"] || '-' }}</span>
822 </template>
823 </el-table-column>
824 <el-table-column prop="enName" label="字段英文名" width="150px" align="left" show-overflow-tooltip>
825 <template #default="scope">
826 <el-input v-if="scope.row['isEdit'] && !(scope.row['guid'] && tableCreateInfo.isCreate)"
827 v-model.trim="scope.row['enName']" placeholder="必填"
828 @input="inputLengthKeyUp(/[^a-zA-Z0-9_]/g, scope, 'enName')" />
829 <span v-else>{{ scope.row["enName"] || '-' }}</span>
830 </template>
831 </el-table-column>
832 <el-table-column prop="dataType" label="字段类型" width="120px" align="left" show-overflow-tooltip>
833 <template #default="scope">
834 <el-select v-if="scope.row['isEdit'] && !(tableCreateInfo.isCreate && scope.row['isCreate'] === 'Y')"
835 v-model="scope.row['dataType']" placeholder="请选择" @change="(val) => dataTypeChange(val, scope)">
836 <el-option v-for="opt in fieldTypes" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
837 </el-select>
838 <span v-else>{{fieldTypes.find(f => f.value === scope.row["dataType"])?.label || '-'}}</span>
839 </template>
840 </el-table-column>
841 <el-table-column prop="fieldLength" label="长度" width="115px" align="left" show-overflow-tooltip>
842 <template #default="scope">
843 <el-input
844 v-if="scope.row['isEdit'] && !(tableCreateInfo.isCreate && scope.row['isCreate'] === 'Y') && (scope.row['dataType'] == 'varchar' || scope.row['dataType'] == 'decimal' || scope.row['dataType'] == 'char')"
845 v-model.trim="scope.row['fieldLength']" placeholder="必填"
846 @input="inputLengthKeyUp(/\D/g, scope, 'fieldLength', 2000, 1)" />
847 <span v-else>{{ scope.row["fieldLength"] == null ? '-' : scope.row["fieldLength"] }}</span>
848 </template>
849 </el-table-column>
850 <el-table-column prop="fieldPrecision" label="精度" width="115px" align="left" show-overflow-tooltip>
851 <template #default="scope">
852 <el-input
853 v-if="scope.row['isEdit'] && !(tableCreateInfo.isCreate && scope.row['isCreate'] === 'Y') && scope.row['dataType'] == 'decimal'"
854 v-model.trim="scope.row['fieldPrecision']" placeholder="必填"
855 @input="inputLengthKeyUp(/\D/g, scope, 'fieldPrecision', 30, 1)" />
856 <span v-else>{{ scope.row["fieldPrecision"] == null ? '-' : scope.row["fieldPrecision"] }}</span>
857 </template>
858 </el-table-column>
859 <el-table-column prop="isPrimary" label="是否主键" width="90px" align="left" show-overflow-tooltip>
860 <template #default="scope">
861 <el-select v-if="scope.row['isEdit'] && !tableCreateInfo.isCreate" v-model="scope.row['isPrimary']"
862 placeholder="请选择">
863 <el-option v-for="opt in isNotList" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
864 </el-select>
865 <span v-else>{{ scope.row["isPrimary"] || '-' }}</span>
866 </template>
867 </el-table-column>
868 <el-table-column v-if="tableCreateInfo.tableData[0].tableModel == 2" prop="aggWay" label="聚合方式" width="120px"
869 align="left" show-overflow-tooltip>
870 <template #default="scope">
871 <el-select v-if="scope.row['isEdit']" v-model="scope.row['aggWay']" placeholder="请选择">
872 <el-option v-for="opt in aggMethodList" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
873 </el-select>
874 <span v-else>{{ scope.row["aggWay"] || '-' }}</span>
875 </template>
876 </el-table-column>
877 <el-table-column prop="notNull" label="是否必填" width="90px" align="left" show-overflow-tooltip>
878 <template #default="scope">
879 <el-select v-if="scope.row['isEdit'] && !(scope.row.isCreate == 'Y' && scope.row['notNull'] == 'N')"
880 v-model="scope.row['notNull']" placeholder="请选择">
881 <el-option v-for="opt in isNotList" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
882 </el-select>
883 <span v-else>{{ scope.row["notNull"] || '-' }}</span>
884 </template>
885 </el-table-column>
886 <el-table-column prop="defaultValue" label="默认值" width="205px" align="left" show-overflow-tooltip>
887 <template #default="scope">
888 <tableDefaultValue :scope="scope" :dbType="dbType"
889 :readonly="dbType == 'doris' && scope.row.isCreate == 'Y'"></tableDefaultValue>
890 </template>
891 </el-table-column>
892 <el-table-column v-if="!isLook" label="操作" width="100px" align="left" fixed="right" show-overflow-tooltip>
893 <template #default="scope">
894 <template v-if="!(tableCreateInfo.isCreate && scope.row['isPrimary'] === 'Y')">
895 <span class="text_btn" v-if="!scope.row['isEdit']" @click="handleFieldClickEdit(scope)"
896 v-preReClick>编辑</span>
897 <span class="text_btn" v-else @click="handleFieldClickSave(scope)" v-preReClick>保存</span>
898 <el-divider direction="vertical" />
899 <span class="text_btn" @click="handleFieldDelete(scope)">删除</span>
900 </template>
901 <span v-else>--</span>
902 </template>
903 </el-table-column>
904 </el-table>
905 </div>
906 <ContentWrap title="流程审批" description="" :isExpand="flowExpand" :expand-swicth="true" class="mb16"
907 @expand="(v) => flowExpand = v">
908 <ApprovalProcess v-if="deploymentId" :deploymentId="deploymentId" :definitionId="''">
909 </ApprovalProcess>
910 </ContentWrap>
911 <expandPropertyDialog ref="expandPropertyDialogRef" :is-look="isLook" :partitionAttribute="expandProperties"
912 :table-create-info="tableCreateInfo" @expandValueChange="expandDialogValueChange" />
913 </div>
914 </template>
915
916 <style lang="scss" scoped>
917 .table_tool_wrap {
918 width: 100%;
919 height: 100%;
920 padding: 0 16px;
921 overflow: hidden auto;
922
923 .tools_btns {
924 padding: 8px 0;
925 }
926
927 :deep(.el-table) {
928 .cell {
929
930 .prefix-or-suffix-cell {
931 display: inline-flex;
932 align-items: center;
933 }
934 }
935 }
936
937 .table_panel {
938 height: 268px;
939
940 :deep(.el-table) {
941 & td.el-table__cell {
942 padding: 2px 0;
943 height: 36px;
944 }
945 }
946 }
947 }
948
949 :deep(.el-dialog) {
950 .dialog-form-inline {
951 .checkbox_input {
952 display: flex;
953 flex-direction: column;
954
955 .input_panel {
956 margin: 0;
957 }
958 }
959
960 .select_group {
961 .el-form-item__content>.el-input {
962 margin-top: 21px;
963 }
964 }
965
966 .radio_panel {
967 .panel_content {
968 display: none;
969 }
970 }
971 }
972 }
973
974 :deep(.batchDialog) {
975 .el-tree-node__content {
976 padding-left: 8px !important;
977
978 .el-icon {
979 display: none;
980 }
981 }
982 }
983
984 .header_title {
985 margin-left: 8px;
986 display: flex;
987 align-items: center;
988
989 .el-icon {
990 color: #b2b2b2;
991 width: 16px;
992 height: 16px;
993 }
994 }
995 </style>
...\ No newline at end of file ...\ No newline at end of file
...@@ -228,14 +228,7 @@ onBeforeUnmount(() => { ...@@ -228,14 +228,7 @@ onBeforeUnmount(() => {
228 }) 228 })
229 229
230 /** 数仓目录树形列表 */ 230 /** 数仓目录树形列表 */
231 const dataCatalogList = ref([{ 231 const dataCatalogList = ref([]);
232 name: '测试',
233 guid: '1',
234 children: [{
235 name: 'cesi',
236 guid: '1-1'
237 }]
238 }]);
239 232
240 const formItems = ref([{ 233 const formItems = ref([{
241 label: "数仓目录", 234 label: "数仓目录",
...@@ -299,12 +292,37 @@ const dialogBtnClick = (btn, info) => { ...@@ -299,12 +292,37 @@ const dialogBtnClick = (btn, info) => {
299 if (btn.value == 'submit') { 292 if (btn.value == 'submit') {
300 dialogInfo.value.visible = false; 293 dialogInfo.value.visible = false;
301 if (selectDataCatalogNodeObj.value.parent.data.layereAttribute == 2) { //维度 294 if (selectDataCatalogNodeObj.value.parent.data.layereAttribute == 2) { //维度
302 window.open(`${import.meta.env.VITE_APP_DATA_DELIVERY}data-catalog/data-warehouse/dim-table-create-manual?domainGuid=${info.domainGuid}&domainName=${selectDataCatalogNodeObj.value.data.name}&metaStandard=${contextNodeData.value.guid}`); 295 router.push({
296 name: 'dimTableCreateManual',
297 query: {
298 domainGuid: info.domainGuid,
299 domainName: selectDataCatalogNodeObj.value.data.name,
300 metaStandard: contextNodeData.value.guid,
301 standardName: contextNodeData.value.label
302 }
303 });
303 } else { 304 } else {
304 if (selectDataCatalogNodeObj.value.parent.data.layereAttribute == 4) { 305 if (selectDataCatalogNodeObj.value.parent.data.layereAttribute == 4) {
305 window.open(`${import.meta.env.VITE_APP_DATA_DELIVERY}data-catalog/data-warehouse/table-create-manual?domainGuid=${info.domainGuid}&domainName=${selectDataCatalogNodeObj.value.data.name}&layereAttribute=${selectDataCatalogNodeObj.value.parent.data.layereAttribute}&metaStandard=${contextNodeData.value.guid}`); 306 router.push({
307 name: 'tableCreateManual',
308 query: {
309 domainGuid: info.domainGuid,
310 domainName: selectDataCatalogNodeObj.value.data.name,
311 metaStandard: contextNodeData.value.guid,
312 layereAttribute: selectDataCatalogNodeObj.value.parent.data.layereAttribute,
313 standardName: contextNodeData.value.label
314 }
315 });
306 } else { 316 } else {
307 window.open(`${import.meta.env.VITE_APP_DATA_DELIVERY}data-catalog/data-warehouse/table-create-manual?domainGuid=${info.domainGuid}&domainName=${selectDataCatalogNodeObj.value.data.name}&metaStandard=${contextNodeData.value.guid}`); 317 router.push({
318 name: 'tableCreateManual',
319 query: {
320 domainGuid: info.domainGuid,
321 domainName: selectDataCatalogNodeObj.value.data.name,
322 metaStandard: contextNodeData.value.guid,
323 standardName: contextNodeData.value.label
324 }
325 });
308 } 326 }
309 } 327 }
310 } else if (btn.value == 'cancel') { 328 } else if (btn.value == 'cancel') {
......
1 <route lang="yaml">
2 name: tableCreateManual
3 </route>
4
5 <script lang="ts" setup name="tableCreateManual">
6 import { ref } from "vue";
7 import { useRouter, useRoute } from "vue-router";
8 import { ElMessage, ElMessageBox, ElTable } from "element-plus";
9 import { QuestionFilled } from "@element-plus/icons-vue";
10 import {
11 getDatabase,
12 saveSubjectTable,
13 syncPolicys,
14 tableModels,
15 tableCategoryList,
16 getDimList,
17 getDictionary,
18 aggMethodList,
19 getMetaStandardDsField,
20 getAllFlowData
21 } from "@/api/modules/dataMetaService";
22 import useUserStore from "@/store/modules/user";
23 import expandPropertyDialog from "./components/expandPropertyDialog.vue";
24 import tableDefaultValue from "./components/tableDefaultValue.vue";
25 import { useDefault } from "@/hooks/useDefault"
26 import { getCamundaDeploymentId } from "@/api/modules/workFlowService"
27
28 const userStore = useUserStore();
29 const { checkDefault } = useDefault()
30 const router = useRouter();
31 const route = useRoute();
32 const flowExpand = ref(true);
33 const deploymentId = ref('');
34 const fullPath = route.fullPath;
35 const isLook = <any>route.query.isLook == 1;
36 const subjectDomainGuid: any = ref(route.query.domainGuid);
37 const { proxy } = getCurrentInstance() as any;
38 const fieldStandardTableRef = ref<InstanceType<typeof ElTable>>();
39
40 /** 表模型,只有doris数据库才有 */
41 const dbType = ref("");
42
43 const databaseList: any = ref([]);
44
45 const tableFieldsLoading = ref(false);
46
47 const tableCreateInfoLoading = ref(false);
48
49 //记录当前正在编辑的表创建信息。
50 const tableCreateInfo: Ref<any> = ref({
51 guid: "",
52 isCreate: false,
53 inputNameValue: '',
54 tableCreateType: 1,
55 tableData: [
56 {
57 //数据库表信息。
58 dataSourceGuid: '',
59 dataServerName: "",
60 dataServerChName: "",
61 enName: "",
62 chName: "",
63 subjectDomain: route.query.domainName,
64 subjectDomainGuid: subjectDomainGuid.value,
65 tableCategory: route.query.layereAttribute == '3' ? 6 : 1,
66 syncPolicy: 3,
67 characterSet: 'utf8mb3',
68 tableModel: 1, //若是聚合模型,下方出现一列聚合方式选择。处了主键列,其余列都需要选择。每个表里都要有主键。
69 description: "",
70 },
71 ],
72 partitionAttribute: {},
73 tableFields: [], // 字段标准数组。
74 });
75
76 const selectTableFieldRows = ref([]);
77
78 //字段类型
79 const fieldTypes: any = ref([]);
80
81 //字符集
82 const characterList: any = ref([]);
83
84 //是否列表
85 const isNotList = ref([
86 {
87 label: "Y",
88 value: "Y",
89 },
90 {
91 label: "N",
92 value: "N",
93 },
94 ]);
95
96 //字典列表
97 const dictionaryList: any = ref([]);
98
99 // 可选择的关联维度的列表。
100 const dimListData: any = ref([]);
101
102 const fullscreenLoading = ref(false);
103
104 /** 表里有数据时不能修改字段类型,长度,精度 */
105 const hasSubjectData = ref(false);
106
107 const expandProperties = ref({});
108
109 onBeforeMount(() => {
110 getDatabaseList();
111 getFieldTypeList();
112 getCharacterListData();
113 if (route.query.metaStandard) {
114 tableCreateInfo.value.tableData[0].chName = route.query.standardName;
115 tableCreateInfoLoading.value = true;
116 getMetaStandardDsField(route.query.metaStandard).then((res: any) => {
117 tableCreateInfoLoading.value = false;
118 if (res.code == proxy.$passCode) {
119 tableCreateInfo.value.tableFields = res.data?.map((d, i) => {
120 d.orderNum = i;
121 d.isEdit = true;
122 return d;
123 }) || [];
124 } else {
125 proxy.$ElMessage.error(res.msg);
126 }
127 })
128 }
129 getCamundaDeploymentId('10025').then((res: any) => {
130 if (res.code == proxy.$passCode) {
131 deploymentId.value = res.data;
132 } else {
133 proxy.$ElMessage.error(res.msg);
134 }
135 })
136 })
137
138 onActivated(() => {
139 console.log("activated");
140 getDictionaryList();
141 getDimListData();
142 });
143
144
145 const getDatabaseList = () => {
146 getDatabase({ connectStatus: 1 }).then((res: any) => {
147 databaseList.value = [];
148 if (res.code == proxy.$passCode) {
149 databaseList.value = res.data || [];
150 } else {
151 ElMessage.error(res.msg);
152 }
153 })
154 };
155
156 const getDictionaryList = () => {
157 getDictionary({}).then((res: any) => {
158 dictionaryList.value = [];
159 if (res.code == proxy.$passCode) {
160 dictionaryList.value = res.data || [];
161 dimOrDictList.value[0].children = dictionaryList.value;
162 dimOrDictList.value[0].disabled = !dictionaryList.value.length;
163 } else {
164 ElMessage.error(res.msg);
165 }
166 })
167 };
168
169 const getDimListData = () => {
170 getDimList().then((res: any) => {
171 dimListData.value = [];
172 if (res.code == proxy.$passCode) {
173 dimListData.value = res.data?.map(r => {
174 return {
175 guid: r.guid,
176 chName: r.chName,
177 subjectDomainName: r.subjectDomainName,
178 parentGuid: '2'
179 }
180 }) || [];
181 dimOrDictList.value[1].children = dimListData.value;
182 dimOrDictList.value[1].disabled = !dimListData.value.length;
183 } else {
184 ElMessage.error(res.msg);
185 }
186 })
187 };
188
189 const getFieldTypeList = () => {
190 getAllFlowData('字段类型').then((res: any) => {
191 fieldTypes.value = [];
192 if (res.code == proxy.$passCode) {
193 fieldTypes.value = res.data || [];
194 } else {
195 ElMessage.error(res.msg);
196 }
197 })
198 }
199
200 const getCharacterListData = () => {
201 getAllFlowData('Mysql字符集').then((res: any) => {
202 characterList.value = [];
203 if (res.code == proxy.$passCode) {
204 characterList.value = res.data || [];
205 } else {
206 ElMessage.error(res.msg);
207 }
208 })
209 }
210
211 /** 限制长度输入框只能输入整型数字,表,字段英文名称,限制输入字符,数字和下划线。 */
212 const inputLengthKeyUp = (regexp, scope, field, max: any = null, min: any = null) => {
213 scope.row[field] = scope.row[field].replace(regexp, '');
214 if (field == 'fieldLength' && scope.row.dataType == 'decimal') {
215 max = 65;
216 }
217 /** 最大值设置2000 */
218 if (max && scope.row[field] > max) {
219 scope.row[field] = max;
220 }
221 if (min !== null && scope.row[field] != '' && scope.row[field] <= min) {
222 scope.row[field] = min;
223 }
224 }
225
226 /** 保存表 */
227 const saveTable = () => {
228 let tableData = tableCreateInfo.value.tableData[0];
229 if (!tableData.chName) {
230 ElMessage({
231 type: "error",
232 message: "主题表名称不能为空",
233 });
234 return;
235 }
236 if (!tableData.dataServerName) {
237 ElMessage({
238 type: "error",
239 message: "数据源不能为空",
240 });
241 return;
242 }
243 if (tableData.dataServerName.indexOf('-') > -1) {
244 ElMessage.error('数据库表名称不能包含中划线,可以改为下划线');
245 return;
246 }
247 if (!tableCreateInfo.value.inputNameValue) {
248 ElMessage({
249 type: "error",
250 message: "主题表名称不能为空",
251 });
252 return;
253 }
254 let tableFields = tableCreateInfo.value.tableFields;
255 if (!tableFields.length) {
256 ElMessage({
257 type: "error",
258 message: "表字段不能为0行",
259 });
260 return;
261 }
262 // 若开启了字段标准,则不能为空。
263 // 必须含有主键。若是聚合模型,则除了主键必须有聚合方式。
264 let isSumModel = tableData.tableModel === 2;
265 let hasPrimary = false;
266 let enNames: any = [];
267 let chNames: any = [];
268 const regex = /^[a-zA-Z]/;
269 for (const field of tableFields) {
270 if (!field.enName) {
271 ElMessage.error(`第 ${field.orderNum} 个字段的英文名称不能为空`);
272 return;
273 }
274 if (!regex.test(field.enName)) {
275 ElMessage.error(`第 ${field.orderNum} 个字段的英文名称必须以英文字符开头`);
276 return;
277 }
278 if (!field.dataType) {
279 ElMessage.error(`第 ${field.orderNum} 个字段的字段类型不能为空`);
280 return;
281 }
282 if (enNames.indexOf(field.enName) > -1) {
283 ElMessage.error(`字段的英文名称 ${field.enName} 不能重复`);
284 return;
285 }
286 if (chNames.indexOf(field.chName) > -1) {
287 ElMessage.error(`字段的中文名称 ${field.chName} 不能重复`);
288 return;
289 }
290 if (field.dataType === "decimal" && (!field.fieldPrecision && field.fieldPrecision != 0)) {
291 ElMessage.error(`第 ${field.orderNum} 个字段的字段类型为浮点型时,精度不能为空`);
292 return;
293 }
294 if (field.dataType === "varchar" && (!field.fieldLength && field.fieldLength != 0)) {
295 ElMessage.error(`第 ${field.orderNum} 个字段的字段类型为字符型时,长度不能为空`);
296 return;
297 }
298 if (field.dataType === "char" && (!field.fieldLength && field.fieldLength != 0)) {
299 ElMessage.error(`第 ${field.orderNum} 个字段的字段类型为单字符型时,长度不能为空`);
300 return;
301 }
302 if (field.dataType === "decimal" && (!field.fieldLength && field.fieldLength != 0)) {
303 ElMessage.error(`第 ${field.orderNum} 个字段的字段类型为浮点符型时,长度不能为空`);
304 return;
305 }
306 if (field.isPrimary === 'Y') {
307 hasPrimary = true;
308 if (field.notNull != 'Y') {
309 ElMessage.error(`第 ${field.orderNum} 个字段为主键,应设置为必填`);
310 return;
311 }
312 if (field.dataType == 'text') {
313 ElMessage.error(`第 ${field.orderNum} 个字段为主键,字段类型不能设置为‘大字段型’`);
314 return;
315 }
316 if (field.dataType == 'json') {
317 ElMessage.error(`第 ${field.orderNum} 个字段为主键,字段类型不能设置为‘JSON类型’`);
318 return;
319 }
320 if (field.dataType == 'bit') {
321 ElMessage.error(`第 ${field.orderNum} 个字段为主键,字段类型不能设置为‘布尔类型’`);
322 return;
323 }
324 } else {
325 if (!field.aggWay && isSumModel) {
326 ElMessage.error(`聚合模型的非主键字段必须设置聚合方式`);
327 return;
328 }
329 }
330 if (field.isEdit) {
331 if (checkDefault[field.dataType]) {
332 if (!field.fieldLength) { }
333 if (!checkDefault[field.dataType]({ row: field })) {
334 return;
335 }
336 }
337 }
338 field.fieldStandardGuid = route.query.metaStandard;
339 enNames.push(field.enName);
340 chNames.push(field.chName);
341 }
342 if (!hasPrimary) {
343 ElMessage.error(`字段至少有一个主键字段!`);
344 return;
345 }
346 let addInfo = Object.assign({}, tableCreateInfo.value.tableData[0], {
347 enName: tableCreateInfo.value.inputNameValue,
348 tableCreateType: tableCreateInfo.value.tableCreateType,
349 saveFlag: 1,
350 layereAttribute: route.query.layereAttribute,
351 dbType: dbType.value,
352 dataState: 1,
353 immediateApprove: true,
354 partitionAttribute: !Object.keys(tableCreateInfo.value.partitionAttribute).length ? null : Object.assign({}, tableCreateInfo.value.partitionAttribute, {
355 dynamicPartitionHistory: tableCreateInfo.value.partitionAttribute ? "Y" : 'N'
356 }),
357 subjectFieldAddDTOS: tableCreateInfo.value.tableFields.map((field, i) => {
358 return Object.assign({}, field, { orderNum: i + 1 });
359 })
360 })
361 if (!tableCreateInfo.value.guid) { //添加
362 fullscreenLoading.value = true;
363 saveSubjectTable(addInfo).then((res: any) => {
364 fullscreenLoading.value = false;
365 if (res.code == proxy.$passCode) {
366 ElMessage.success('新建表提交成功!');
367 router.push({
368 name: 'metadataStandardQuery'
369 });
370 userStore.setTabbar(userStore.tabbar.filter((tab: any) => tab.fullPath !== fullPath));
371 } else {
372 ElMessage.error(res.msg);
373 }
374 });
375 }
376 };
377
378 //数据库选择改变,对应的表名称是否需要变化。需要根据此属性带出表名前缀,以及是否是doris数据库。
379 const selectDatabaseChange = (val) => {
380 let d = databaseList.value.find(d => d.guid === val);
381 if (d) {
382 dbType.value = d.databaseType;
383 tableCreateInfo.value.tableData[0].dataSourceGuid = d.guid;
384 tableCreateInfo.value.tableData[0].dataServerName = d.databaseNameEn;
385 } else {
386 dbType.value = "";
387 tableCreateInfo.value.tableData[0].dataSourceGuid = '';
388 tableCreateInfo.value.tableData[0].dataServerName = '';
389 }
390 tableCreateInfo.value.tableFields.forEach((tableField: any) => {
391 if (tableField['dataType'] === "datetime") {
392 tableField.defaultValue = ""
393 }
394 })
395 };
396
397 /** 添加字段标准 */
398 const addField = () => {
399 let len = tableCreateInfo.value.tableFields.length;
400 tableCreateInfo.value.tableFields.push({
401 orderNum: len + 1,
402 isDim: "N",
403 isPrimary: "N",
404 notNull: "N",
405 isEdit: true
406 });
407 //设置选中表格当前新增行。
408 fieldStandardTableRef.value?.setCurrentRow(
409 tableCreateInfo.value.tableFields[tableCreateInfo.value.tableFields.length - 1]
410 );
411 nextTick(() => {
412 let bodyWrapper = fieldStandardTableRef.value?.$el.querySelector('.el-table__body');
413 let domScroll = bodyWrapper.parentElement.parentElement;
414 let rect = domScroll.getBoundingClientRect();
415 let maxNum = len + 1;
416 if (maxNum * 36 > rect.height + domScroll.scrollTop) {
417 fieldStandardTableRef.value?.setScrollTop(maxNum * 36 - rect.height + 2)
418 }
419 })
420 };
421
422 /** 勾选字段标准选中变化。 */
423 const selectionFieldsChange = (val) => {
424 selectTableFieldRows.value = val;
425 };
426
427 /**
428 * 上移规则:
429 * 勾选多个时先从最上面开始逐个上移一行,若已经移到最上面一行,则不处理。
430 */
431 const moveUp = () => {
432 let selectRows = fieldStandardTableRef.value?.getSelectionRows();
433 if (!selectRows.length) {
434 ElMessage.error('请先选择需要勾选的数据进行上移');
435 return;
436 }
437 let data = tableCreateInfo.value.tableFields;
438 let selectRowIndexs: number[] = [];
439 let minNum: number = 0;
440 selectRows.forEach((row, i) => {
441 let orderNum = data.findIndex(d => d === row) + 1;
442 if (orderNum == 1) {
443 selectRowIndexs.push(orderNum);
444 minNum = orderNum;
445 return;
446 }
447 let topNum = orderNum - 1;
448 if (selectRowIndexs.includes(topNum)) {
449 //下一行也是选中的,则不做转换。
450 return;
451 }
452 if (i === 0) {
453 minNum = topNum;
454 }
455 row.orderNum = topNum;
456 let changeRow = data[topNum - 1];
457 changeRow.orderNum = orderNum;
458 selectRowIndexs.push(topNum);
459 data[topNum] = changeRow;
460 data[topNum - 1] = row;
461 });
462 nextTick().then(() => {
463 let bodyWrapper = fieldStandardTableRef.value?.$el.querySelector('.el-table__body');
464 let domScroll = bodyWrapper.parentElement.parentElement;
465 if ((minNum * 36 - 38) < domScroll.scrollTop) {
466 let top = domScroll.scrollTop - 38;
467 fieldStandardTableRef.value?.setScrollTop(top < 0 ? 0 : top)
468 }
469 });
470 }
471
472 /**
473 * 下移规则:
474 * 勾选多个时先从最下面开始逐个下移一行,若已经移到最下面一行,则不处理。
475 */
476 const moveDown = () => {
477 let selectRows = fieldStandardTableRef.value?.getSelectionRows();
478 if (!selectRows.length) {
479 ElMessage.error('请先选择需要勾选的数据进行下移');
480 return;
481 }
482 let data = tableCreateInfo.value.tableFields;
483 let selectRowIndexs: number[] = [];
484 let maxNum: number = 0;
485 selectRows.slice(0).reverse().forEach((row, i) => {
486 let orderNum = data.findIndex(d => d === row) + 1;
487 if (orderNum === data.length) {
488 maxNum = orderNum;
489 selectRowIndexs.push(orderNum);
490 return;
491 }
492 if (selectRowIndexs.includes(orderNum + 1)) {
493 //下一行也是选中的,则不做转换。
494 return;
495 }
496 let bottomNum = orderNum + 1;
497 row.orderNum = bottomNum;
498 if (i === 0) {
499 maxNum = bottomNum;
500 }
501 let changeRow = data[bottomNum - 1];
502 changeRow.orderNum = orderNum;
503 selectRowIndexs.push(bottomNum);
504 data[orderNum - 1] = changeRow;
505 data[bottomNum - 1] = row;
506 });
507 nextTick(() => {
508 let bodyWrapper = fieldStandardTableRef.value?.$el.querySelector('.el-table__body');
509 let domScroll = bodyWrapper.parentElement.parentElement;
510 let rect = domScroll.getBoundingClientRect();
511 if (maxNum * 36 > rect.height + domScroll.scrollTop) {
512 fieldStandardTableRef.value?.setScrollTop(maxNum * 36 - rect.height + 2)
513 }
514 })
515 }
516
517 /** 批量删除字段标准 */
518 const delFeilds = () => {
519 if (selectTableFieldRows.value.length == 0) {
520 ElMessage({
521 type: "info",
522 message: "请选择需要删除的字段",
523 });
524 return;
525 }
526 if (tableCreateInfo.value.isCreate) {
527 if (selectTableFieldRows.value.find((row: any) => row.isPrimary === 'Y')) {
528 ElMessage.error('已建表不能删除主键字段');
529 return;
530 }
531 }
532 let hasCreateField = selectTableFieldRows.value.some((row: any) => row.isCreate === 'Y');
533 ElMessageBox.confirm(hasCreateField && hasSubjectData.value ? '已选择的字段中含有已创建的表字段且有数据,此操作将永久删除,是否继续?' : "此操作将永久删除,是否继续?", "提示", {
534 confirmButtonText: "确定",
535 cancelButtonText: "取消",
536 type: "warning",
537 })
538 .then(() => {
539 //此删除是直接从库里删除,还是点击保存后再删除呢??如果是入库删除,后,调用接口获取数据。
540 let tableFields = tableCreateInfo.value.tableFields;
541 selectTableFieldRows.value.forEach((r: any) => {
542 let index = tableFields.findIndex((t: any) => t.orderNum === r.orderNum);
543 if (index !== -1) {
544 tableFields.splice(index, 1);
545 }
546 });
547 fieldStandardTableRef.value?.clearSelection();
548 tableCreateInfo.value.tableFields.forEach((field, i) => {
549 field.orderNum = i + 1;
550 });
551 ElMessage({
552 type: "success",
553 message: "删除成功",
554 });
555 })
556 .catch(() => {
557 ElMessage({
558 type: "info",
559 message: "已取消删除",
560 });
561 });
562 };
563
564 //点击编辑按钮
565 const handleFieldClickEdit = (scope) => {
566 scope.row['isEdit'] = true;
567 };
568
569 //点击保存按钮
570 const handleFieldClickSave = (scope) => {
571 if (!scope.row.enName) {
572 ElMessage({
573 type: "error",
574 message: "字段英文名不能为空!",
575 });
576 return;
577 }
578 if (checkDefault[scope.row.dataType]) {
579 if (!scope.row.fieldLength) { }
580 if (!checkDefault[scope.row.dataType](scope)) {
581 return
582 }
583 }
584 scope.row['isEdit'] = false;
585 };
586
587 const handleFieldDelete = (scope) => {
588 ElMessageBox.confirm(scope.row['isCreate'] === 'Y' && hasSubjectData.value ? '该字段已被创建且表中有数据,此操作将永久删除,是否继续?' : "此操作将永久删除,是否继续?", "提示", {
589 confirmButtonText: "确定",
590 cancelButtonText: "取消",
591 type: "warning",
592 })
593 .then(() => {
594 //此删除是直接从库里删除,还是点击保存后再删除呢??如果是入库删除,后,调用接口获取数据。
595 let tableFields = tableCreateInfo.value.tableFields;
596 tableFields.splice(scope.$index, 1);
597 tableCreateInfo.value.tableFields.forEach((field, i) => {
598 field.orderNum = i + 1;
599 });
600 tableCreateInfo.value.tableFields.forEach((field, i) => {
601 field.orderNum = i + 1;
602 });
603 ElMessage({
604 type: "success",
605 message: "删除成功",
606 });
607 })
608 .catch(() => {
609 ElMessage({
610 type: "info",
611 message: "已取消删除",
612 });
613 });
614 }
615
616 const dataTypeChange = (val, scope) => {
617 scope.row['defaultValue'] = ''
618 scope.row['fieldLength'] = undefined
619 scope.row['fieldPrecision'] = undefined
620
621 }
622
623 /*** 以下是处理数据字典或维表的树形选择框。 */
624
625 const dimOrDictList: any = ref([{
626 guid: '1',
627 chName: '数据字典',
628 children: dictionaryList.value,
629 isLeaf: false,
630 disabled: !dictionaryList.value.length,
631 }, {
632 guid: '2',
633 chName: '维度',
634 isLeaf: false,
635 disabled: !dimListData.value.length,
636 children: dimListData.value
637 }]);
638
639 const dimOrDictInputFilterMethod = (v, data) => {
640 return data.label?.includes(v) || data.chName?.includes(v);
641 };
642
643 const dimOrDictSelectRef = ref();
644
645 const dimOrDictSelectNode = ref();
646
647 const handleDictSelectNodeChange = (node) => {
648 dimOrDictSelectNode.value = node;
649 }
650
651 const handleDictionaryChange = (val, scope) => {
652 if (!val) {
653 scope.row.dictionaryGuid = '';
654 scope.row.dimGuid = '';
655 scope.row.dictionaryChName = '';
656 scope.row.dimChName = '';
657 return;
658 }
659 let info = dimOrDictSelectNode.value;
660 if (!info) {
661 return;
662 }
663 if (info.parentGuid == '2') {
664 scope.row.dimGuid = val;
665 scope.row.dimChName = dimListData.value.find(d => d.guid === val)?.chName;
666 scope.row.dictionaryGuid = '';
667 scope.row.dictionaryChName = '';
668 } else {
669 scope.row.dictionaryGuid = val;
670 scope.row.dictionaryChName = dictionaryList.value.find(d => d.guid === val)?.chName;
671 scope.row.dimGuid = '';
672 scope.row.dimChName = '';
673 }
674 }
675
676 /** 扩展属性弹出对话框 */
677 const expandPropertyDialogRef = ref();
678
679 /** 扩展属性弹出对话框 */
680 const handleClickExpand = () => {
681 expandPropertyDialogRef.value?.handleClickExpand();
682 }
683
684 const expandDialogValueChange = (val) => {
685 tableCreateInfo.value.partitionAttribute = val;
686 expandProperties.value = val;
687 }
688
689 </script>
690
691 <template>
692 <div class="table_tool_wrap" v-loading.fullscreen.lock="fullscreenLoading">
693 <div class="tools_btns">
694 <!-- <el-button type="primary" :disabled="isLook" @click="saveDraftTable" v-preReClick>保存为草稿</el-button> -->
695 <el-button type="primary" :disabled="isLook" @click="saveTable" v-preReClick>提交</el-button>
696 </div>
697 <el-table ref="tableRef" :data="tableCreateInfo.tableData" v-loading="tableCreateInfoLoading"
698 :highlight-current-row="true" stripe border height="100%" tooltip-effect="light" row-key="guid" :style="{
699 width: '100%',
700 height: 'auto',
701 display: 'inline-block',
702 }">
703 <el-table-column prop="dataSourceGuid" label="数据源" width="200px" align="left" show-overflow-tooltip>
704 <template #header>
705 <span>数据源</span>
706 <span v-if="!isLook" style="color:red;margin-left: 2px;">*</span>
707 </template>
708 <template #default="scope">
709 <el-select v-if="!isLook" v-model="scope.row['dataSourceGuid']" placeholder="请选择"
710 :disabled="tableCreateInfo.isCreate" @change="(val) => selectDatabaseChange(val)" clearable filterable>
711 <el-option v-for="opt in databaseList" :key="opt['guid']" :label="opt['databaseNameZh']"
712 :value="opt['guid']" />
713 </el-select>
714 <span v-else>{{ scope.row["dataServerChName"] }}</span>
715 </template>
716 </el-table-column>
717 <el-table-column prop="enName" label="数据库表" width="200px" align="left" show-overflow-tooltip>
718 <template #header>
719 <span>数据库表</span>
720 <span v-if="!isLook" style="color:red;margin-left: 2px;">*</span>
721 </template>
722 <template #default="scope">
723 <template v-if="!isLook">
724 <div class="prefix-or-suffix-cell">
725 <el-input :disabled="tableCreateInfo.isCreate" v-model.trim="tableCreateInfo.inputNameValue"
726 :maxlength="50" placeholder="必填" />
727 </div>
728 </template>
729 <span v-else>{{ scope.row["enName"] }}</span>
730 </template>
731 </el-table-column>
732 <el-table-column prop="chName" label="主题表名称" width="200px" align="left" show-overflow-tooltip>
733 <template #header>
734 <span>主题表名称</span>
735 <span v-if="!isLook" style="color:red;margin-left: 2px;">*</span>
736 </template>
737 <template #default="scope">
738 <el-input v-if="!isLook" v-model.trim="scope.row['chName']" placeholder="必填" :maxlength="50" />
739 <span v-else>{{ scope.row["chName"] }}</span>
740 </template>
741 </el-table-column>
742 <el-table-column prop="subjectDomain" label="主题域" width="180px" align="left" show-overflow-tooltip>
743 <template #default="scope">
744 <el-input v-if="!isLook" disabled v-model="scope.row['subjectDomain']" />
745 <span v-else>{{ scope.row["subjectDomain"] }}</span>
746 </template>
747 </el-table-column>
748 <el-table-column prop="tableModel" label="表模型" :width="isLook ? '100px' : '150px'" align="left"
749 show-overflow-tooltip>
750 <template #default="scope">
751 <el-select v-if="dbType == 'doris' && !isLook" v-model="scope.row['tableModel']" placeholder="请选择"
752 :disabled="tableCreateInfo.isCreate">
753 <el-option v-for="opt in tableModels" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
754 </el-select>
755 <span v-else-if="dbType == 'doris'">{{tableModels.find(t => t.value === scope.row["tableModel"])?.label ||
756 '-'
757 }}</span>
758 <span v-else>--</span>
759 </template>
760 </el-table-column>
761 <el-table-column prop="tableCategory" label="表分类" :width="isLook ? '100px' : '150px'" align="left"
762 show-overflow-tooltip>
763 <template #default="scope">
764 <el-select v-if="!isLook" v-model="scope.row['tableCategory']" placeholder="请选择">
765 <el-option v-for="opt in tableCategoryList" :key="opt['value']" :label="opt['label']"
766 :value="opt['value']" />
767 </el-select>
768 <span v-else>{{tableCategoryList.find(t => t.value === scope.row["tableCategory"])?.label || '-'}}</span>
769 </template>
770 </el-table-column>
771 <el-table-column prop="syncPolicy" label="同步策略" :width="isLook ? '100px' : '150px'" align="left"
772 show-overflow-tooltip>
773 <template #default="scope">
774 <el-select v-if="!isLook" v-model="scope.row['syncPolicy']" placeholder="请选择">
775 <el-option v-for="opt in syncPolicys" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
776 </el-select>
777 <span v-else>{{syncPolicys.find(s => s.value === scope.row["syncPolicy"])?.label || '-'}}</span>
778 </template>
779 </el-table-column>
780 <el-table-column prop="characterSet" label="字符集" :width="isLook ? '100px' : '150px'" align="left"
781 show-overflow-tooltip>
782 <template #default="scope">
783 <el-select v-if="!isLook" v-model="scope.row['characterSet']" placeholder="请选择"
784 :disabled="tableCreateInfo.isCreate">
785 <el-option v-for="opt in characterList" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
786 </el-select>
787 <span v-else>{{characterList.find(c => c.value === scope.row["characterSet"])?.label || '-'}}</span>
788 </template>
789 </el-table-column>
790 <el-table-column prop="description" label="描述" width="220px" align="left" show-overflow-tooltip>
791 <template #default="scope">
792 <el-input v-if="!isLook" v-model.trim="scope.row['description']" />
793 <span v-else>{{ scope.row["description"] || '-' }}</span>
794 </template>
795 </el-table-column>
796 <el-table-column label="操作" width="100px" align="left" fixed="right" show-overflow-tooltip>
797 <template #default="scope">
798 <span class="text_btn" @click="handleClickExpand()" v-preReClick>扩展属性</span>
799 </template>
800 </el-table-column>
801 </el-table>
802 <div class="tools_btns">
803 <el-button type="primary" :disabled="isLook" @click="addField">新增</el-button>
804 <el-button @click="moveUp" :disabled="isLook">上移</el-button>
805 <el-button @click="moveDown" :disabled="isLook">下移</el-button>
806 <el-button @click="delFeilds" :disabled="isLook">批量删除</el-button>
807 </div>
808 <div class="table_panel">
809 <el-table ref="fieldStandardTableRef" :data="tableCreateInfo.tableFields" v-loading="tableFieldsLoading"
810 :highlight-current-row="true" stripe border height="100%" row-key="guid"
811 @selection-change="selectionFieldsChange" tooltip-effect="light" :style="{
812 width: '100%',
813 'max-height': 'calc(100% - 16px)',
814 display: 'inline-block',
815 }">
816 <el-table-column type="selection" v-if="!isLook" :width="32" align="center" />
817 <el-table-column label="排序" type="index" width="56px" align="center" show-overflow-tooltip>
818 </el-table-column>
819 <el-table-column prop="chName" label="字段中文名称" width="150px" align="left" show-overflow-tooltip>
820 <template #default="scope">
821 <el-input v-if="scope.row['isEdit']" :placeholder="'请输入'" v-model.trim="scope.row['chName']" />
822 <span v-else>{{ scope.row["chName"] || '-' }}</span>
823 </template>
824 </el-table-column>
825 <el-table-column prop="enName" label="字段英文名" width="150px" align="left" show-overflow-tooltip>
826 <template #default="scope">
827 <el-input v-if="scope.row['isEdit'] && !(scope.row['guid'] && tableCreateInfo.isCreate)"
828 v-model.trim="scope.row['enName']" placeholder="必填"
829 @input="inputLengthKeyUp(/[^a-zA-Z0-9_]/g, scope, 'enName')" />
830 <span v-else>{{ scope.row["enName"] || '-' }}</span>
831 </template>
832 </el-table-column>
833 <el-table-column prop="dataType" label="字段类型" width="120px" align="left" show-overflow-tooltip>
834 <template #default="scope">
835 <el-select v-if="scope.row['isEdit'] && !(tableCreateInfo.isCreate && scope.row['isCreate'] === 'Y')"
836 v-model="scope.row['dataType']" placeholder="请选择" @change="(val) => dataTypeChange(val, scope)">
837 <el-option v-for="opt in fieldTypes" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
838 </el-select>
839 <span v-else>{{fieldTypes.find(f => f.value === scope.row["dataType"])?.label || '-'}}</span>
840 </template>
841 </el-table-column>
842 <el-table-column prop="fieldLength" label="长度" width="115px" align="left" show-overflow-tooltip>
843 <template #default="scope">
844 <el-input
845 v-if="scope.row['isEdit'] && !(tableCreateInfo.isCreate && scope.row['isCreate'] === 'Y') && (scope.row['dataType'] == 'varchar' || scope.row['dataType'] == 'decimal' || scope.row['dataType'] == 'char')"
846 v-model.trim="scope.row['fieldLength']" placeholder="必填"
847 @input="inputLengthKeyUp(/\D/g, scope, 'fieldLength', 2000, 1)" />
848 <span v-else>{{ scope.row["fieldLength"] == null ? '-' : scope.row["fieldLength"] }}</span>
849 </template>
850 </el-table-column>
851 <el-table-column prop="fieldPrecision" label="精度" width="115px" align="left" show-overflow-tooltip>
852 <template #default="scope">
853 <el-input
854 v-if="scope.row['isEdit'] && !(tableCreateInfo.isCreate && scope.row['isCreate'] === 'Y') && scope.row['dataType'] == 'decimal'"
855 v-model.trim="scope.row['fieldPrecision']" placeholder="必填"
856 @input="inputLengthKeyUp(/\D/g, scope, 'fieldPrecision', 30, 1)" />
857 <span v-else>{{ scope.row["fieldPrecision"] == null ? '-' : scope.row["fieldPrecision"] }}</span>
858 </template>
859 </el-table-column>
860 <el-table-column prop="dimOrdictionaryGuid" label="关联维度/字典" width="130px" align="left" show-overflow-tooltip>
861 <template #default="scope">
862 <el-tree-select ref="dimOrDictSelectRef" v-if="scope.row['isEdit']" filterable clearable
863 :data="dimOrDictList" v-model="scope.row['dimOrdictionaryGuid']" node-key="guid"
864 :default-expanded-keys="scope.row['dictionaryGuid'] ? ['1'] : (scope.row['dimGuid'] ? ['2'] : [])"
865 placeholder="请选择" :filter-node-method="dimOrDictInputFilterMethod" :props="{
866 label: 'chName',
867 value: 'guid',
868 children: 'children',
869 isLeaf: 'isLeaf'
870 }" @change="(v) => handleDictionaryChange(v, scope)" @current-change="handleDictSelectNodeChange">
871 <template #default="{ node, data }">
872 <template v-if="node.level > 1 && data.parentGuid == '2'">
873 <span>{{ data["chName"] + `(${data["subjectDomainName"]})` }}</span>
874 </template>
875 <span v-else>{{ data['chName'] }}</span>
876 </template>
877 </el-tree-select>
878 <span v-else>{{ (scope.row['dictionaryGuid'] ? scope.row["dictionaryChName"] : (scope.row['dimGuid'] ?
879 scope.row['dimChName'] : '-')) || '-' }}</span>
880 </template>
881 </el-table-column>
882 <el-table-column prop="isPrimary" label="是否主键" width="90px" align="left" show-overflow-tooltip>
883 <template #default="scope">
884 <el-select v-if="scope.row['isEdit'] && !tableCreateInfo.isCreate" v-model="scope.row['isPrimary']"
885 placeholder="请选择">
886 <el-option v-for="opt in isNotList" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
887 </el-select>
888 <span v-else>{{ scope.row["isPrimary"] || '-' }}</span>
889 </template>
890 </el-table-column>
891 <el-table-column v-if="tableCreateInfo.tableData[0].tableModel == 2" prop="aggWay" label="聚合方式" width="120px"
892 align="left" show-overflow-tooltip>
893 <template #default="scope">
894 <el-select v-if="scope.row['isEdit']" v-model="scope.row['aggWay']" placeholder="请选择">
895 <el-option v-for="opt in aggMethodList" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
896 </el-select>
897 <span v-else>{{ scope.row["aggWay"] || '-' }}</span>
898 </template>
899 </el-table-column>
900 <el-table-column prop="notNull" label="是否必填" width="90px" align="left" show-overflow-tooltip>
901 <template #default="scope">
902 <el-select v-if="scope.row['isEdit'] && !(scope.row.isCreate == 'Y' && scope.row['notNull'] == 'N')"
903 v-model="scope.row['notNull']" placeholder="请选择">
904 <el-option v-for="opt in isNotList" :key="opt['value']" :label="opt['label']" :value="opt['value']" />
905 </el-select>
906 <span v-else>{{ scope.row["notNull"] || '-' }}</span>
907 </template>
908 </el-table-column>
909 <el-table-column prop="defaultValue" label="默认值" width="205px" align="left" show-overflow-tooltip>
910 <template #default="scope">
911 <tableDefaultValue :scope="scope" :dbType="dbType"
912 :readonly="dbType == 'doris' && scope.row.isCreate == 'Y'"></tableDefaultValue>
913 </template>
914 </el-table-column>
915 <el-table-column v-if="!isLook" label="操作" width="100px" align="left" fixed="right" show-overflow-tooltip>
916 <template #default="scope">
917 <template v-if="!(tableCreateInfo.isCreate && scope.row['isPrimary'] === 'Y')">
918 <span class="text_btn" v-if="!scope.row['isEdit']" @click="handleFieldClickEdit(scope)"
919 v-preReClick>编辑</span>
920 <span class="text_btn" v-else @click="handleFieldClickSave(scope)" v-preReClick>保存</span>
921 <el-divider direction="vertical" />
922 <span class="text_btn" @click="handleFieldDelete(scope)">删除</span>
923 </template>
924 <span v-else>--</span>
925 </template>
926 </el-table-column>
927 </el-table>
928 </div>
929 <ContentWrap title="流程审批" description="" :isExpand="flowExpand" :expand-swicth="true" class="mb16"
930 @expand="(v) => flowExpand = v">
931 <ApprovalProcess v-if="deploymentId" :deploymentId="deploymentId" :definitionId="''">
932 </ApprovalProcess>
933 </ContentWrap>
934 <expandPropertyDialog ref="expandPropertyDialogRef" :is-look="isLook" :partitionAttribute="expandProperties"
935 :table-create-info="tableCreateInfo" @expandValueChange="expandDialogValueChange" />
936 </div>
937 </template>
938
939 <style lang="scss" scoped>
940 .table_tool_wrap {
941 width: 100%;
942 height: 100%;
943 padding: 0 16px;
944 overflow: hidden auto;
945
946 .tools_btns {
947 padding: 8px 0;
948 }
949
950 :deep(.el-table) {
951 .cell {
952
953 .prefix-or-suffix-cell {
954 display: inline-flex;
955 align-items: center;
956 }
957 }
958 }
959
960 .table_panel {
961 height: 268px;
962
963 :deep(.el-table) {
964 & td.el-table__cell {
965 padding: 2px 0;
966 height: 36px;
967 }
968 }
969 }
970 }
971
972 :deep(.el-dialog) {
973 .dialog-form-inline {
974 .checkbox_input {
975 display: flex;
976 flex-direction: column;
977
978 .input_panel {
979 margin: 0;
980 }
981 }
982
983 .select_group {
984 .el-form-item__content>.el-input {
985 margin-top: 21px;
986 }
987 }
988
989 .radio_panel {
990 .panel_content {
991 display: none;
992 }
993 }
994 }
995 }
996 </style>
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!