c046732c by lihua

数据申请前端页面开发

1 parent bc5cc150
...@@ -676,7 +676,7 @@ const panelChange = (scope, row) => { ...@@ -676,7 +676,7 @@ const panelChange = (scope, row) => {
676 </div> 676 </div>
677 </template> 677 </template>
678 <template v-else-if="item.type === 'label'"> 678 <template v-else-if="item.type === 'label'">
679 <div :class="[item.col, { is_block: item.block }]"> 679 <div :class="[item.col, { is_block: item.block }]" @click.stop="item.click?.()">
680 <span>{{ item.default }}</span> 680 <span>{{ item.default }}</span>
681 </div> 681 </div>
682 </template> 682 </template>
...@@ -1484,7 +1484,7 @@ const panelChange = (scope, row) => { ...@@ -1484,7 +1484,7 @@ const panelChange = (scope, row) => {
1484 v-model="formInline[item.field]" type="daterange" range-separator="至" start-placeholder="开始日期" :format="item.format ?? null" 1484 v-model="formInline[item.field]" type="daterange" range-separator="至" start-placeholder="开始日期" :format="item.format ?? null"
1485 :value-format="item.valueFormat ?? null" 1485 :value-format="item.valueFormat ?? null"
1486 end-placeholder="结束日期" :unlink-panels="item.unlink ?? false" :shortcuts="item.shortcuts ?? []" 1486 end-placeholder="结束日期" :unlink-panels="item.unlink ?? false" :shortcuts="item.shortcuts ?? []"
1487 :default-value="item.defaultDate" :disabled="item.disabled ?? false" /> 1487 :default-value="item.defaultDate" :disabled="item.disabled ?? false" :disabled-date="item.disabledDate" />
1488 <el-date-picker :class="[item.col, { is_block: item.block }]" v-else-if="item.type == 'date-year'" 1488 <el-date-picker :class="[item.col, { is_block: item.block }]" v-else-if="item.type == 'date-year'"
1489 v-model="formInline[item.field]" type="year" format="YYYY" value-format="YYYY" 1489 v-model="formInline[item.field]" type="year" format="YYYY" value-format="YYYY"
1490 :placeholder="item.placeholder" :unlink-panels="item.unlink ?? false" :shortcuts="item.shortcuts ?? []" 1490 :placeholder="item.placeholder" :unlink-panels="item.unlink ?? false" :shortcuts="item.shortcuts ?? []"
......
...@@ -387,6 +387,51 @@ const routes: RouteRecordRaw[] = [ ...@@ -387,6 +387,51 @@ const routes: RouteRecordRaw[] = [
387 } 387 }
388 }, 388 },
389 ] 389 ]
390 },
391 {
392 path: '/data-product/data-application',
393 component: Layout,
394 meta: {
395 title: '数据申请',
396 icon: 'sidebar-videos',
397 },
398 children: [
399 {
400 path: '',
401 name: 'productApplicationManage',
402 component: () => import('@/views/data_asset/productApplicationManage.vue'),
403 meta: {
404 title: '',
405 sidebar: false,
406 breadcrumb: false,
407 cache: true
408 },
409 },
410 {
411 path: 'application-edit',
412 name: 'productApplicationEdit',
413 component: () => import('@/views/data_asset/productApplicationEdit.vue'),
414 meta: {
415 title: '数据申请-',
416 sidebar: false,
417 breadcrumb: false,
418 cache: true,
419 reuse: true
420 }
421 },
422 {
423 path: 'application-detail',
424 name: 'productApplicationDetail',
425 component: () => import('@/views/data_asset/productApplicationDetail.vue'),
426 meta: {
427 title: '数据申请-',
428 sidebar: false,
429 breadcrumb: false,
430 cache: true,
431 reuse: true
432 }
433 },
434 ]
390 } 435 }
391 ] 436 ]
392 export default routes 437 export default routes
......
1 const useDataProductApplicationStore = defineStore(
2 // 资产目录guid
3 'productApplication',
4 () => {
5 const isRefresh = ref<boolean>(false);
6 function setIsRefresh(v: boolean) {
7 isRefresh.value = v;
8 }
9
10 return {
11 isRefresh,
12 setIsRefresh,
13 };
14 }
15 );
16
17 export default useDataProductApplicationStore;
1 <template>
2 <div class="container_wrap full" v-loading="fullscreenLoading">
3 <div class="content_main">
4 <ContentWrap id="id-baseInfo" title="数据申请信息" description="" :isExpand="baseInfoExpand" :expand-swicth="true"
5 class="mb16" @expand="(v) => baseInfoExpand = v">
6 <div class="list_panel">
7 <div class="list_item">
8 <span class="item_label">产品名称:</span>
9 <span class="item_value link" @click="viewProductDetail">
10 <ellipsis-tooltip :content="detailInfo.damName || '--'" class-name="w100f mr8-i"
11 :refName="'tooltipOver' + 'damName'"></ellipsis-tooltip>
12 </span>
13 </div>
14 <div class="list_item">
15 <span class="item_label">产品编号:</span>
16 <span class="item_value">{{ detailInfo.productCode || '--' }}</span>
17 </div>
18 <div class="list_item">
19 <span class="item_label">资产类型:</span>
20 <span class="item_value">{{ detailInfo.damTypeName || '--' }}</span>
21 </div>
22 <div class="list_item">
23 <span class="item_label">预计使用期限:</span>
24 <span class="item_value">{{ detailInfo.damTypeName || '--' }}</span>
25 </div>
26 <div class="list_item">
27 <span class="item_label">数据范围:</span>
28 <span class="item_value">{{ detailInfo.damTypeName || '--' }}</span>
29 </div>
30 <div class="list_item">
31 <span class="item_label">产品发布机构:</span>
32 <span class="item_value">{{ detailInfo.productPublisherName || '--' }}</span>
33 </div>
34 <div class="list_item is_block">
35 <span class="item_label">数据粒度说明:</span>
36 <span class="item_value">{{ detailInfo.description || '--' }}</span>
37 </div>
38 <div class="list_item is_block">
39 <span class="item_label">使用场景描述:</span>
40 <span class="item_value">{{ detailInfo.description || '--' }}</span>
41 </div>
42 </div>
43 </ContentWrap>
44 <ContentWrap id="id-approveInfo" title="流程审批" expandSwicth style="margin-top: 15px" :isExpand="expandApprove"
45 @expand="(v) => expandApprove = v">
46 <ApprovalProcess ref="approvalProcessRef" v-if="deploymentId" :deploymentId="deploymentId"
47 :processInstanceId="processInstanceId">
48 </ApprovalProcess>
49 </ContentWrap>
50 </div>
51 <div class="tool_btns">
52 <div class="btns">
53 <el-button v-for="btn in toolBtns" :type="btn.type" :plain="btn.plain" @click="btnClick(btn)">{{ btn.label
54 }}</el-button>
55 </div>
56 </div>
57 </div>
58 </template>
59
60 <script lang="ts" setup name="productApplicationEdit">
61 import useUserStore from "@/store/modules/user";
62
63 const { proxy } = getCurrentInstance() as any;
64 const userStore = useUserStore();
65 const route = useRoute();
66 const router = useRouter();
67 const fullPath = route.fullPath;
68
69 const fullscreenLoading = ref(false);
70 const baseInfoExpand = ref(true);
71 const expandApprove = ref(true);
72
73 const deploymentId = ref('');
74 const processInstanceId = ref('');
75
76 const detailInfo: any = ref({});
77
78 const viewProductDetail = () => {
79 // TODO
80 }
81
82
83 const toolBtns: any = computed(() => {
84 let btnsArr: any = [{
85 label: "关闭", value: "cancel", plain: true
86 }];
87 // TODO,资产运营平台TODO
88 return btnsArr;
89 });
90
91 const btnClick = (btn: any) => {
92 switch (btn.value) {
93 case 'cancel':
94 cancel();
95 break;
96 default:
97 break;
98 }
99 }
100
101 const cancel = () => {
102 userStore.setTabbar(userStore.tabbar.filter((tab: any) => tab.fullPath !== fullPath));
103 router.push({
104 name: 'productApplicationManage'
105 });
106 }
107
108 onBeforeMount(() => {
109
110 })
111
112 </script>
113
114 <style lang="scss" scoped>
115
116 .content_main {
117 height: calc(100% - 44px);
118 padding: 16px;
119 overflow: hidden auto;
120 position: sticky;
121 }
122
123 .list_panel {
124 display: flex;
125 flex-wrap: wrap;
126 display: flex;
127 align-items: center;
128
129 .list_item {
130 width: 33.33%;
131 line-height: 32px;
132 font-size: 14px;
133 color: var(--el-text-color-regular);
134 display: flex;
135 justify-content: space-between;
136 min-width: 120px;
137
138 .item_label {
139 text-align: left;
140 }
141
142 .item_value {
143 color: var(--el-color-regular);
144 padding: 0 4px;
145 flex: 1;
146 text-align: justify;
147 min-width: 0;
148
149 &.link {
150 color: var(--el-color-primary);
151 cursor: pointer;
152 }
153 }
154
155 &.is_block {
156 width: 100%;
157
158 .item_value {
159 white-space: pre-wrap;
160 }
161 }
162 }
163 }
164
165 .tool_btns {
166 display: flex;
167 justify-content: center;
168 align-items: center;
169 height: 44px;
170 padding: 0 16px;
171 border-top: 1px solid #d9d9d9;
172 }
173 </style>
...\ No newline at end of file ...\ No newline at end of file
1 <template>
2 <div class="container_wrap full" v-loading="fullscreenLoading">
3 <div class="content_main">
4 <ContentWrap id="id-baseInfo" title="数据申请信息" description="" :isExpand="baseInfoExpand" :expand-swicth="true"
5 class="mb16" @expand="(v) => baseInfoExpand = v">
6 <Form ref="baseInfoFormRef" :itemList="baseInfoFormItems" formId="base-info-form" :rules="baseInfoFormRules"
7 col="col3" />
8 </ContentWrap>
9 <ContentWrap id="id-approveInfo" title="流程审批" expandSwicth style="margin-top: 15px" :isExpand="expandApprove"
10 @expand="(v) => expandApprove = v">
11 <ApprovalProcess ref="approvalProcessRef" v-if="deploymentId" :deploymentId="deploymentId"
12 :processInstanceId="processInstanceId">
13 </ApprovalProcess>
14 </ContentWrap>
15 </div>
16 <div class="bottom_tool_wrap">
17 <el-button @click="cancel">取消</el-button>
18 <el-button @click="save" v-preReClick>保存</el-button>
19 <el-button type="primary" @click="submit" v-preReClick>提交审批</el-button>
20 </div>
21 </div>
22 </template>
23
24 <script lang="ts" setup name="productApplicationEdit">
25 import { getCamundaDeploymentId } from "@/api/modules/workFlowService";
26 import {
27 getRegisterCatalogDetail
28 } from "@/api/modules/dataAsset";
29 import useUserStore from "@/store/modules/user";
30 import useDataProductApplicationStore from "@/store/modules/productApplication";
31 import { useValidator } from '@/hooks/useValidator';
32 const { required } = useValidator();
33
34 const { proxy } = getCurrentInstance() as any;
35
36 const userStore = useUserStore();
37 const productApplicationStore = useDataProductApplicationStore();
38 const route = useRoute();
39 const router = useRouter();
40 const userData = JSON.parse(localStorage.userData);
41 const fullPath = route.fullPath;
42
43 const fullscreenLoading = ref(false);
44 const baseInfoExpand = ref(true);
45 const expandApprove = ref(true);
46
47 const deploymentId = ref('');
48 const processInstanceId = ref('');
49
50 const baseInfoFormRef = ref();
51
52 const baseInfoFormItems = ref([{
53 label: '产品名称',
54 type: 'label',
55 field: 'damName',
56 col: 'link',
57 default: '-',
58 click: () => {
59 //TODO
60 debugger
61 router.push({
62 name: 'productDetail',
63 query: {
64 id: route.query.id,
65 type: 'view'
66 }
67 })
68 }
69 },
70 {
71 label: '产品编码',
72 type: 'input',
73 placeholder: '请输入',
74 field: 'productCode',
75 default: '-',
76 disabled: true
77 },
78 {
79 label: '产品类型',
80 type: 'input',
81 placeholder: '请输入',
82 field: 'damTypeName',
83 default: '-',
84 disabled: true
85 },
86 {
87 label: "预计使用期限",
88 type: "date-picker",
89 field: "useDateRange",
90 default: null,
91 placeholder: "开始时间~结束时间",
92 clearable: true,
93 disabledDate: (date) => {
94 const today = new Date();
95 // 将 today 设置为 00:00:00,只比较日期部分(本地时间)
96 const todayStart = new Date(
97 today.getFullYear(),
98 today.getMonth(),
99 today.getDate()
100 );
101
102 // 将 date 也转换为本地日期的开始时间(避免 UTC 问题)
103 const dateStart = new Date(
104 date.getFullYear(),
105 date.getMonth(),
106 date.getDate()
107 );
108
109 // 禁用 dateStart < todayStart 的日期(即今天之前)
110 return dateStart.getTime() < todayStart.getTime();
111 },
112 required: true,
113 },
114 {
115 label: "数据范围",
116 type: "date-picker",
117 field: "useDataDateRange",
118 default: null,
119 placeholder: "开始时间~结束时间",
120 clearable: true,
121 required: true,
122 },
123 {
124 label: '产品发布机构',
125 type: 'input',
126 placeholder: '请输入',
127 field: 'productPublisherName',
128 default: '',
129 disabled: true
130 },
131 {
132 label: '数据粒度说明',
133 type: 'textarea',
134 placeholder: '请输入需要的需求字段',
135 field: 'dataDescription',
136 default: '',
137 block: true,
138 maxlength: 500,
139 clearable: true,
140 required: true,
141 },
142 {
143 label: '使用场景描述',
144 type: 'textarea',
145 placeholder: '请输入使用该数据产品的场景描述信息',
146 field: 'useDescription',
147 default: '',
148 block: true,
149 maxlength: 500,
150 clearable: true,
151 required: true,
152 },
153 ])
154
155 const baseInfoFormRules = ref({
156 useDateRange: [{
157 type: 'array', required: true, message: '请选择预计使用期限', trigger: 'change',
158 }],
159 useDataDateRange: [{
160 type: 'array', required: true, message: '请选择数据范围', trigger: 'change',
161 }],
162 dataDescription: [required('请输入数据粒度说明')],
163 useDescription: [required('请输入使用场景描述')]
164 })
165
166 const cancel = () => {
167 proxy.$openMessageBox("当前页面尚未保存,确定放弃修改吗?", () => {
168 userStore.setTabbar(userStore.tabbar.filter((tab: any) => tab.fullPath !== fullPath));
169 router.push({
170 name: 'productApplicationManage'
171 });
172 }, () => {
173 proxy.$ElMessage.info("已取消");
174 });
175 }
176
177 const save = () => {
178 // 保存不检验。
179 }
180
181 const submit = () => {
182 baseInfoFormRef.value?.ruleFormRef?.validate().then((valid, errorItem) => {
183 if (valid) {
184 let formInline = baseInfoFormRef.value.formInline;
185 // fullscreenLoading.value = true;
186 // listingSavePortal(params).then((res: any) => {
187 // fullscreenLoading.value = false;
188 // if (res?.code == proxy.$passCode) {
189 // proxy.$ElMessage.success('提交审批成功');
190 // userStore.setTabbar(userStore.tabbar.filter((tab: any) => tab.fullPath !== fullPath));
191 // productApplicationStore.setIsRefresh(true);
192 // router.push({
193 // name: "productApplicationManage",
194 // });
195 // } else {
196 // res?.msg && proxy.$ElMessage.error(res.msg);
197 // }
198 // }).catch((res) => {
199 // fullscreenLoading.value = false;
200 // });
201 } else {
202 var obj = Object.keys(errorItem);
203 baseInfoFormRef.value.ruleFormRef.scrollToField(obj[0]);
204 }
205 })
206 }
207
208 onActivated(() => {
209 let tab: any = userStore.tabbar.find((tab: any) => tab.fullPath == fullPath);
210 let detailType = route.query.type;
211 let name = route.query.name;
212 if (tab) {
213 switch (detailType) {
214 case 'edit':
215 tab.meta.title = `编辑-${name}`;
216 break;
217 case 'redit':
218 tab.meta.title = `编辑-${name}`;
219 break;
220 default:
221 tab.meta.title = '新增数据申请';
222 }
223 document.title = tab.meta.title;
224 };
225 })
226
227 onBeforeMount(() => {
228 // getCamundaDeploymentId('10016', userData.tenantGuid, userData.staffGuid).then((res: any) => {
229 // if (res.code == proxy.$passCode) {
230 // deploymentId.value = res.data;
231 // } else {
232 // proxy.$ElMessage.error(res.msg);
233 // }
234 // })
235 fullscreenLoading.value = true;
236 getRegisterCatalogDetail(route.query.guid).then((res: any) => {
237 fullscreenLoading.value = false;
238 if (res?.code == proxy.$passCode) {
239 let detail = res.data || {};
240 baseInfoFormItems.value[0].default = <string>route.query.damName;
241 baseInfoFormItems.value[1].default = detail.productCode;
242 baseInfoFormItems.value[2].default = detail.damTypeName;
243 } else {
244 res?.msg && proxy.$ElMessage.error(res.msg);
245 }
246 })
247 })
248
249 </script>
250
251 <style lang="scss" scoped>
252 .content_main {
253 height: calc(100% - 40px);
254 padding: 16px;
255 overflow: hidden auto;
256 position: sticky;
257 }
258
259 .bottom_tool_wrap {
260 height: 40px;
261 padding: 0 16px;
262 border-top: 1px solid #d9d9d9;
263 display: flex;
264 justify-content: center;
265 align-items: center;
266 }
267
268 :deep(.el-form) {
269 .link {
270 color: var(--el-color-primary);
271 cursor: pointer;
272 line-height: 32px;
273 }
274 }
275 </style>
...\ No newline at end of file ...\ No newline at end of file
1 <template>
2 <div class="container_wrap">
3 <div class="table_tool_wrap">
4 <TableTools :searchItems="searchItemList" :searchId="'data-application-search'" @search="toSearch" />
5 </div>
6 <div class="table_panel_wrap" :style="{ height: 'calc(100% - 48px)' }">
7 <Table :tableInfo="tableInfo" @tablePageChange="tablePageChange" />
8 </div>
9 </div>
10 </template>
11
12 <script lang="ts" setup name="productApplicationManage">
13 import { commonPageConfig } from "@/components/PageNav";
14 import TableTools from "@/components/Tools/table_tools.vue";
15 import useUserStore from "@/store/modules/user";
16 import { TableColumnWidth } from "@/utils/enum";
17 import { getDamTypesList } from "@/api/modules/dataAsset";
18
19 const { proxy } = getCurrentInstance() as any;
20 const router = useRouter();
21 const userStore = useUserStore();
22 const userData = JSON.parse(userStore.userData);
23
24 const damTypes: any = ref([]);
25 const searchItemList: any = ref([
26 {
27 type: "input",
28 label: "",
29 field: "damName",
30 default: "",
31 placeholder: "产品名称",
32 clearable: true
33 },
34 {
35 type: "select",
36 label: "",
37 field: "damType",
38 default: "",
39 props: {
40 value: 'value',
41 label: 'label'
42 },
43 placeholder: "产品类型",
44 options: damTypes.value,
45 clearable: true,
46 },
47 {
48 type: 'select',
49 label: '',
50 field: 'approveState',
51 default: '',
52 placeholder: '审批状态',
53 options: [
54 { label: '草稿中', value: 'N' },
55 { label: '审批中', value: 'A' },
56 { label: '已通过', value: 'Y' },
57 { label: '已驳回', value: 'R' },
58 { label: '已撤销', value: 'C' },
59 ],
60 clearable: true
61 },
62 ]);
63
64 const page = ref({
65 ...commonPageConfig,
66 damName: '',
67 damType: null,
68 approveState: null,
69 });
70
71 const tableInfo = ref({
72 id: "mapping-table",
73 fields: [
74 { label: "序号", type: "index", width: 56, align: "center", fixed: "left" },
75 { label: "数据产品编号", field: "productCode", width: 265 },
76 { label: "数据产品名称", field: "damName", width: 180 },
77 {
78 label: "产品类型", field: "damTypeName", width: 100
79 },
80 {
81 label: "审批状态", field: "approveState", type: "tag", width: TableColumnWidth.STATE, align: 'center'
82 },
83 { label: "申请方", field: "tenantName", width: 240 },
84 { label: "数据提供方", field: "dataProviderName", width: 240 },
85 { label: "提交时间", field: "submitTime", width: 170 },
86 ],
87 loading: false,
88 data: [],
89 page: {
90 type: "normal",
91 rows: 0,
92 ...page.value,
93 },
94 actionInfo: {
95 label: "操作",
96 type: "btn",
97 width: 170,
98 btns: (scope) => {
99 const { row } = scope;
100 const bizApproveState = row.approveState;
101 let flowState;
102 if (bizApproveState == 'N') {
103 flowState = 1;
104 }
105
106 const currentStaffGuid = userData.userGuid
107 const staffGuid = row.createUserId || '';
108 let isShowCancel = false;
109 let list: any = [];
110 if (bizApproveState == 'N') {
111 flowState = 1;
112 }
113 if ((bizApproveState == 'D' || bizApproveState == 'C' || bizApproveState == 'R' || bizApproveState == 'E' || bizApproveState == 'R') && staffGuid == currentStaffGuid) {
114 flowState = 3;
115 }
116 if (bizApproveState == 'A' && staffGuid == currentStaffGuid) {
117 isShowCancel = true;
118 }
119 if (flowState === 1) {
120 list = [{ label: "编辑", value: "edit", click: btnHandlers.edit }, { label: "删除", value: "del", click: btnHandlers.del }]
121 }
122 if (flowState === 3) {
123 list.push({ label: "删除", value: "del", click: btnHandlers.del })
124 }
125 if (flowState === 3) { //重新提交过的不能再重新提交 && bizApproveState != 'D'
126 list.push({ label: "重新提交", value: "redit", click: btnHandlers.redit }) //已驳回
127 }
128 if (flowState !== 1) {
129 list.push({ label: "详情", value: "detail", click: btnHandlers.detail })
130 }
131 return list
132 },
133 }
134 });
135
136 const btnHandlers = {
137 edit: (scope) => {
138 router.push({
139 // name: "data-product-edit",
140 // query: {
141 // id: scope.row.id,
142 // },
143 });
144 },
145 redit: (scope) => {
146 },
147 detail: (scope) => {
148 router.push({
149 // name: "data-product-detail",
150 // query: {
151 // id: scope.row.id,
152 // },
153 })
154 },
155 del: (scope) => {
156 proxy.$openMessageBox('数据申请删除后不可恢复,确定继续删除吗?', () => {
157 // delCertificate([row.guid]).then((res: any) => {
158 // if (res?.code == proxy.$passCode) {
159 // proxy.$ElMessage.success('删除资产登记证件成功');
160 // page.value.curr = 1;
161 // getTableData();
162 // } else {
163 // proxy.$ElMessage.error(res.msg);
164 // }
165 // })
166 }, () => {
167 proxy.$ElMessage.info("已取消删除");
168 });
169 },
170 }
171 const toSearch = (val: any, clear: boolean = false) => {
172 if (clear) {
173 searchItemList.value.map(item => item.default = "");
174 page.value.damName = '';
175 page.value.approveState = null;
176 page.value.damType = null;
177 } else {
178 page.value.damName = val.damName;
179 page.value.approveState = val.approveState;
180 page.value.damType = val.damType;
181 }
182 page.value.curr = 1;
183 tableInfo.value.page.curr = 1;
184 getTableData();
185 };
186
187 const getTableData = () => {
188 // tableInfo.value.loading = true;
189 // getListingList({
190 // pageIndex: page.value.curr,
191 // pageSize: page.value.limit,
192 // damName: page.value.damName,
193 // damType: page.value.damType,
194 // approveState: page.value.approveState
195 // }).then((res: any) => {
196 // tableInfo.value.loading = false;
197 // tableInfo.value.data = res.data.records || [];
198 // tableInfo.value.page.curr = res.data.pageIndex;
199 // tableInfo.value.page.limit = res.data.pageSize;
200 // tableInfo.value.page.rows = res.data.totalRows;
201 // }).catch((res) => {
202 // tableInfo.value.loading = false;
203 // });
204 };
205
206 const tablePageChange = (info) => {
207 page.value.curr = Number(info.curr);
208 page.value.limit = Number(info.limit);
209 tableInfo.value.page.limit = page.value.limit;
210 tableInfo.value.page.curr = page.value.curr;
211 getTableData();
212 };
213
214 onBeforeMount(() => {
215 getDamTypesList({
216 dictType: "资产类型",
217 }).then((res: any) => {
218 if (res.code == proxy.$passCode) {
219 damTypes.value = res.data || [];
220 searchItemList.value[1].options = damTypes.value;
221 } else {
222 proxy.$ElMessage.error(res.msg);
223 }
224 })
225 })
226
227 </script>
228
229 <style lang="scss" scoped>
230 .container_wrap {
231 width: 100%;
232 height: 100%;
233 overflow-y: auto;
234
235 .table_tool_wrap {
236 width: 100%;
237 padding: 0 8px;
238
239 .tools_btns {
240 padding: 0px 0 8px;
241 }
242 }
243
244 .table_panel_wrap {
245 width: 100%;
246 padding: 0px 8px 0;
247 }
248 }
249 </style>
...\ No newline at end of file ...\ No newline at end of file
1 <template> 1 <template>
2 <div class="container_wrap full flex"> 2 <div class="container_wrap full flex">
3 <!-- 侧边栏容器,放置产品分类树 -->
3 <div class="aside_wrap"> 4 <div class="aside_wrap">
4 <div class="aside_title">产品分类</div> 5 <div class="aside_title">产品分类</div>
5 <Tree ref="treeRef" :treeInfo="treeInfo" @nodeCheck="handleTreeNodeChange" /> 6 <Tree ref="treeRef" :treeInfo="treeInfo" @nodeCheck="handleTreeNodeChange" />
6 </div> 7 </div>
8 <!-- 主内容区域,包含搜索框和表格 -->
7 <div class="main_wrap"> 9 <div class="main_wrap">
8 <div class="header-bg"> 10 <div class="header-bg">
9 <el-input v-model.trim="page.searchKey" size="large" placeholder="请输入关键字搜索" :prefix-icon="Search" 11 <el-input v-model.trim="page.searchKey" size="large" placeholder="请输入关键字搜索" :prefix-icon="Search"
...@@ -26,7 +28,12 @@ import { USERROLE } from '@/utils/enum'; ...@@ -26,7 +28,12 @@ import { USERROLE } from '@/utils/enum';
26 const router = useRouter(); 28 const router = useRouter();
27 const route = useRoute(); 29 const route = useRoute();
28 const { proxy } = getCurrentInstance() as any; 30 const { proxy } = getCurrentInstance() as any;
29 const dataSourceList = ref([{ //如果是授权数据则不能选择其余的 31
32 /**
33 * 数据源选项列表
34 * 包含四种不同类型的数据来源
35 */
36 const dataSourceList = ref([{
30 value: 1, 37 value: 1,
31 label: '授权数据', 38 label: '授权数据',
32 }, { 39 }, {
...@@ -42,105 +49,163 @@ const dataSourceList = ref([{ //如果是授权数据则不能选择其余的 ...@@ -42,105 +49,163 @@ const dataSourceList = ref([{ //如果是授权数据则不能选择其余的
42 label: '其他来源', 49 label: '其他来源',
43 }]); 50 }]);
44 51
45 /** 是否是数据使用方 */ 52 /**
53 * 判断当前用户角色是否为数据使用方
54 * 如果是使用方,则显示特定的操作按钮
55 */
46 const isDataUse = computed(() => { 56 const isDataUse = computed(() => {
47 return localStorage.getItem('userRole') == USERROLE.USE; 57 return localStorage.getItem('userRole') == USERROLE.USE;
48 }) 58 })
49 59
50 const treeRef = ref(); 60 const treeRef = ref(); // Tree组件引用,用于访问树组件实例
51 61
62 /**
63 * 树形控件配置信息
64 * 包含树的基本配置、数据结构定义等
65 */
52 const treeInfo = ref({ 66 const treeInfo = ref({
53 id: "data-product-tree", 67 id: "data-product-tree", // 树的唯一标识
54 filter: true, 68 filter: true, // 是否启用过滤功能
55 queryValue: "", 69 queryValue: "", // 过滤输入框的值
56 queryPlaceholder: "请输入关键字搜索", 70 queryPlaceholder: "请输入关键字搜索", // 过滤输入框提示文字
57 showCheckbox: true, 71 showCheckbox: true, // 显示复选框
58 checkStrictly: false, 72 checkStrictly: false, // 不严格遵循父子节点不互相关联
59 props: { 73 props: {
60 label: "label", 74 label: "label", // 节点标签字段
61 value: "value", 75 value: "value", // 节点值字段
62 children: 'childDictList' 76 children: 'childDictList' // 子节点数据字段
63 }, 77 },
64 nodeKey: 'value', 78 nodeKey: 'value', // 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的
65 expandOnNodeClick: false, 79 expandOnNodeClick: false, // 点击节点时不展开或收缩节点
66 data: <any>[], 80 data: <any>[], // 树形数据
67 loading: false 81 loading: false // 加载状态
68 }); 82 });
69 83
70 //记录每次点击的节点。 84 /**
85 * 处理树节点选择变化事件
86 * 处理半选和全选节点的逻辑
87 * @param checkedObj - 选中的对象信息
88 * @param id - 节点ID
89 * @param nodeObj - 节点对象
90 */
71 const handleTreeNodeChange = (checkedObj, id, nodeObj) => { 91 const handleTreeNodeChange = (checkedObj, id, nodeObj) => {
72 debugger 92 debugger
73 let treeRefs = treeRef.value.treeRef; 93 let treeRefs = treeRef.value.treeRef;
74 let checkedKeys = checkedObj.checkedObj || [];//全勾选的所有节点。 94 let checkedKeys = checkedObj.checkedObj || []; // 全勾选的所有节点
75 let halfCheckedKeys = checkedObj.halfCheckedKeys || [];//半勾选的节点。 95 let halfCheckedKeys = checkedObj.halfCheckedKeys || []; // 半勾选的节点
76 //思路,一个个的分类判断是否在半勾选,如果是,就将其勾选的子节点获取出来。 96
77 /** 先damType */ 97 // 思路:一个个的分类判断是否在半勾选,如果是,就将其勾选的子节点获取出来
98
99 /** 产品类型 */
78 if (halfCheckedKeys.includes('damType')) { 100 if (halfCheckedKeys.includes('damType')) {
79 // 获取出来勾选的子节点。 101 // 获取勾选的子节点
80 treeRefs.getNode("damType").childNodes?.filter(c=> c.checked == true); 102 treeRefs.getNode("damType").childNodes?.filter(c => c.checked == true);
81 } //如果是全选,则不需要处理传参。 103 }
104 // 如果是全选,则不需要处理传参
105
82 /** 数据来源 */ 106 /** 数据来源 */
83 if (halfCheckedKeys.includes('dataSources')) { 107 if (halfCheckedKeys.includes('dataSources')) {
84 108
85 } 109 }
110
86 /** 行业分类 */ 111 /** 行业分类 */
112
87 /** 机构分类 */ 113 /** 机构分类 */
88 /** 复杂的领域及应用场景。 */ 114
115 /** 领域及应用场景 */
89 if (halfCheckedKeys.includes('domain')) { 116 if (halfCheckedKeys.includes('domain')) {
90 //计算领域下勾选的子节点。同时判断医疗健康和工业制造。 117 // 计算领域下勾选的子节点,同时判断医疗健康和工业制造
91 } 118 }
92 } 119 }
93 120
121 /**
122 * 页面配置信息
123 * 包含分页、搜索等公共配置
124 */
94 const page = ref({ 125 const page = ref({
95 ...commonPageConfig, 126 ...commonPageConfig, // 继承通用页面配置
96 searchKey: '', 127 searchKey: '', // 搜索关键词
97 }); 128 });
98 129
99 const oldKeyWord = ref(""); //记录上次输入的关键字,若是输入值未变化,则失去焦点时不用触发搜索。 130 const oldKeyWord = ref(""); // 记录上次输入的关键字,避免重复搜索
100 const isEnter = ref(false); 131 const isEnter = ref(false); // 标识是否通过回车键触发搜索
101 132
102 /** 触发搜索查询 */ 133 /**
134 * 触发搜索查询
135 * @param clear - 是否清空页码,默认为true
136 * @param isBlur - 是否是失焦触发,默认为false
137 */
103 const toSearch = (clear: boolean = true, isBlur: boolean = false) => { 138 const toSearch = (clear: boolean = true, isBlur: boolean = false) => {
104 if (clear) { 139 if (clear) {
105 page.value.curr = 1 140 page.value.curr = 1 // 重置为第一页
106 } 141 }
142 // 如果是失焦且不是回车触发,且关键词没有变化,则不执行搜索
107 if (isBlur && !isEnter.value && oldKeyWord.value === page.value.searchKey) { 143 if (isBlur && !isEnter.value && oldKeyWord.value === page.value.searchKey) {
108 return; 144 return;
109 } 145 }
110 isEnter.value = false; 146 isEnter.value = false; // 重置回车状态
111 oldKeyWord.value = page.value.searchKey; 147 oldKeyWord.value = page.value.searchKey; // 更新关键词记录
112 getSearchData(clear); 148 getSearchData(clear);
113 } 149 }
114 150
151 /**
152 * 回车搜索事件处理
153 * 在输入框按下回车键时触发
154 * @param event - 键盘事件对象
155 */
115 const searchEnterFun = (event) => { 156 const searchEnterFun = (event) => {
116 isEnter.value = true; 157 isEnter.value = true; // 标记为回车触发
117 event.target?.blur(); 158 event.target?.blur(); // 输入框失去焦点
118 } 159 }
119 160
120 /** 查询表格数据 */ 161 /**
162 * 查询表格数据
163 * 根据筛选条件获取表格数据
164 * @param clear - 是否清除现有数据
165 */
121 const getSearchData = (clear = false) => { 166 const getSearchData = (clear = false) => {
122 167 // TODO: 实现具体的数据获取逻辑
123 } 168 }
124 169
170 /**
171 * 表格配置信息
172 * 定义表格列、数据、分页、操作按钮等
173 */
125 const tableInfo = ref({ 174 const tableInfo = ref({
126 id: 'contract-table', 175 id: 'contract-table', // 表格唯一标识
127 rowKey: 'guid', 176 rowKey: 'guid', // 行数据的唯一标识
128 loading: false, 177 loading: false, // 加载状态
129 fields: [{ label: "序号", type: "index", width: 56, align: "center" }, 178 // 表格列定义
179 fields: [
180 {
181 label: "序号",
182 type: "index",
183 width: 56,
184 align: "center"
185 },
130 { 186 {
131 label: "数据产品名称", field: "dataProductName", width: 160, type: "text_btn", columClass: 'text_btn', value: "detail", disabled: (scope) => { 187 label: "数据产品名称",
188 field: "dataProductName",
189 width: 160,
190 type: "text_btn",
191 columClass: 'text_btn',
192 value: "detail",
193 // 合同状态为06时禁用点击
194 disabled: (scope) => {
132 return scope.row.contractStatus == '06'; 195 return scope.row.contractStatus == '06';
133 }, click: (scope) => { 196 },
197 // 点击查看详细信息
198 click: (scope) => {
134 if (scope.row.contractStatus == '06') { 199 if (scope.row.contractStatus == '06') {
135 return; 200 return;
136 } 201 }
137 router.push({ 202 router.push({
138 name: 'productSortCatalogDetail', 203 name: 'productSortCatalogDetail',
139 query: { 204 query: {
140 guid: scope.row.dataProductGuid, 205 guid: scope.row.dataProductGuid, // 产品GUID
141 type: 'detail', 206 type: 'detail', // 查看类型
142 foundMode: 'use', 207 foundMode: 'use', // 发现模式
143 name: scope.row.dataProductName, 208 name: scope.row.dataProductName, // 产品名称
144 } 209 }
145 }); 210 });
146 } 211 }
...@@ -150,56 +215,82 @@ const tableInfo = ref({ ...@@ -150,56 +215,82 @@ const tableInfo = ref({
150 { label: "行业分类", field: "industryName", width: 140 }, 215 { label: "行业分类", field: "industryName", width: 140 },
151 { label: "机构分类", field: "institutionTypeName", width: 120 }, 216 { label: "机构分类", field: "institutionTypeName", width: 120 },
152 { 217 {
153 label: "数据来源", field: "dataSources", width: 100, getName: (scope) => { 218 label: "数据来源",
219 field: "dataSources",
220 width: 100,
221 // 获取数据源名称
222 getName: (scope) => {
154 return scope.row.dataSources && dataSourceList.value.find(i => i.value == scope.row.dataSources)?.label || '--' 223 return scope.row.dataSources && dataSourceList.value.find(i => i.value == scope.row.dataSources)?.label || '--'
155 } 224 }
156 }, 225 },
157 { label: "上架时间", field: "listingTime", width: 170 }, 226 { label: "上架时间", field: "listingTime", width: 170 },
158 ], 227 ],
159 data: [{}], 228 data: [{}], // 表格数据
229 // 分页配置
160 page: { 230 page: {
161 type: "normal", 231 type: "normal", // 分页类型
162 rows: 0, 232 rows: 0, // 总行数
163 ...page.value, 233 ...page.value, // 继承页面配置
164 }, 234 },
235 // 操作按钮配置
165 actionInfo: { 236 actionInfo: {
166 label: "操作", 237 label: "操作",
167 type: "btn", 238 type: "btn",
168 show: isDataUse.value, 239 show: isDataUse.value, // 仅对数据使用方显示
169 width: 120, 240 width: 120,
241 // 操作按钮定义
170 btns: (scope) => { 242 btns: (scope) => {
171 return [{ 243 return [{
172 value: 'approve', label: "数据申请", click: (scope) => { //TODO,是否申请过的不能再申请? 244 value: 'approve',
173 245 label: "数据申请",
246 // 点击申请数据
247 click: (scope) => {
248 // TODO,是否申请过的不能再申请?
249 router.push({
250 name: 'productApplicationEdit',
251 query: {
252 damGuid: scope.row.guid, // 数据资产GUID
253 damName: scope.row.dataProductName // 数据产品名称
254 }
255 });
174 } 256 }
175 }] 257 }]
176 } 258 }
177 } 259 }
178 }); 260 });
179 261
262 /**
263 * 表格分页变化事件处理
264 * 当分页信息改变时更新页面配置并重新加载数据
265 * @param info - 分页信息对象
266 */
180 const tablePageChange = (info) => { 267 const tablePageChange = (info) => {
181 page.value.curr = Number(info.curr); 268 page.value.curr = Number(info.curr); // 更新当前页
182 page.value.limit = Number(info.limit); 269 page.value.limit = Number(info.limit); // 更新每页条数
183 tableInfo.value.page.curr = page.value.curr; 270 tableInfo.value.page.curr = page.value.curr; // 同步到表格分页
184 tableInfo.value.page.limit = page.value.limit; 271 tableInfo.value.page.limit = page.value.limit;
185 getSearchData(); 272 getSearchData(); // 重新获取数据
186 }; 273 };
187 274
188 const damTypes: any = ref([]); 275 // 数据字典变量定义
189 /** 所属主题多级列表 */ 276 const damTypes: any = ref([]); // 产品类型字典列表
190 const subjectDomainListData: any = ref([]); 277 const subjectDomainListData: any = ref([]); // 主题域列表
191 /** 行业分类类型列表 */ 278 const industryDictList: any = ref([]); // 行业分类字典列表
192 const industryDictList: any = ref([]); 279 const domainDictList: any = ref([]); // 领域字典列表
193 /** 领域字典列表 */ 280 const institutionTypeDictList: any = ref([]); // 机构类型字典列表
194 const domainDictList: any = ref([]); 281 const medDepartmentCodeList: any = ref([]); // 科室代码列表
195 /** 机构类型字典列表 */
196 const institutionTypeDictList: any = ref([]);
197 /** 所属科室下拉列表 */
198 const medDepartmentCodeList: any = ref([]);
199 282
283 /**
284 * 组件挂载前生命周期钩子
285 * 初始化树形控件所需的各种字典数据
286 */
200 onBeforeMount(() => { 287 onBeforeMount(() => {
201 treeInfo.value.loading = true; 288 treeInfo.value.loading = true; // 开启加载状态
289
290 // 并发请求所有字典数据
202 let psAll: any[] = []; 291 let psAll: any[] = [];
292
293 // 获取产品类型字典
203 psAll.push(getDamTypesList({ 294 psAll.push(getDamTypesList({
204 dictType: "资产类型", 295 dictType: "资产类型",
205 }).then((res: any) => { 296 }).then((res: any) => {
...@@ -209,6 +300,8 @@ onBeforeMount(() => { ...@@ -209,6 +300,8 @@ onBeforeMount(() => {
209 proxy.$ElMessage.error(res.msg); 300 proxy.$ElMessage.error(res.msg);
210 } 301 }
211 })) 302 }))
303
304 // 获取行业分类字典(一级)
212 psAll.push(getDamTypesList({ 305 psAll.push(getDamTypesList({
213 dictType: "行业分类", 306 dictType: "行业分类",
214 level: 1 307 level: 1
...@@ -219,6 +312,8 @@ onBeforeMount(() => { ...@@ -219,6 +312,8 @@ onBeforeMount(() => {
219 proxy.$ElMessage.error(res.msg); 312 proxy.$ElMessage.error(res.msg);
220 } 313 }
221 })) 314 }))
315
316 // 获取领域字典
222 psAll.push(getDamTypesList({ dictType: '领域' }).then((res: any) => { 317 psAll.push(getDamTypesList({ dictType: '领域' }).then((res: any) => {
223 if (res.code == proxy.$passCode) { 318 if (res.code == proxy.$passCode) {
224 domainDictList.value = res.data || []; 319 domainDictList.value = res.data || [];
...@@ -226,6 +321,8 @@ onBeforeMount(() => { ...@@ -226,6 +321,8 @@ onBeforeMount(() => {
226 proxy.$ElMessage.error(res.msg); 321 proxy.$ElMessage.error(res.msg);
227 } 322 }
228 })); 323 }));
324
325 // 获取机构类型字典
229 psAll.push(getDamTypesList({ 326 psAll.push(getDamTypesList({
230 dictType: "组织机构性质", 327 dictType: "组织机构性质",
231 }).then((res: any) => { 328 }).then((res: any) => {
...@@ -235,6 +332,8 @@ onBeforeMount(() => { ...@@ -235,6 +332,8 @@ onBeforeMount(() => {
235 proxy.$ElMessage.error(res.msg); 332 proxy.$ElMessage.error(res.msg);
236 } 333 }
237 })) 334 }))
335
336 // 获取主题域字典
238 psAll.push(getDamTypesList({ 337 psAll.push(getDamTypesList({
239 dictType: "数据资产目录主题名称", 338 dictType: "数据资产目录主题名称",
240 }).then((res: any) => { 339 }).then((res: any) => {
...@@ -245,6 +344,7 @@ onBeforeMount(() => { ...@@ -245,6 +344,7 @@ onBeforeMount(() => {
245 } 344 }
246 })) 345 }))
247 346
347 // 获取科室字典
248 psAll.push(getDamTypesList({ 348 psAll.push(getDamTypesList({
249 dictType: "科室", 349 dictType: "科室",
250 }).then((res: any) => { 350 }).then((res: any) => {
...@@ -255,63 +355,79 @@ onBeforeMount(() => { ...@@ -255,63 +355,79 @@ onBeforeMount(() => {
255 } 355 }
256 })); 356 }));
257 357
358 // 等待所有请求完成,然后构建树形数据
258 Promise.all(psAll).then(() => { 359 Promise.all(psAll).then(() => {
259 treeInfo.value.loading = false; 360 treeInfo.value.loading = false; // 关闭加载状态
260 treeInfo.value.data = []; 361 treeInfo.value.data = []; // 清空原有数据
362
363 // 构建树形结构数据
261 treeInfo.value.data.push({ 364 treeInfo.value.data.push({
262 value: 'damType', 365 value: 'damType',
263 label: '产品类型', 366 label: '产品类型',
264 childDictList: damTypes.value 367 childDictList: damTypes.value
265 }); 368 });
266 let item = domainDictList.value.find(i => i.value == '003');//医疗健康,下级应用场景和所属科室 369
370 // 特殊处理医疗健康领域(003)
371 let item = domainDictList.value.find(i => i.value == '003'); // 医疗健康,下级应用场景和所属科室
267 let childDictList = item.childDictList || []; 372 let childDictList = item.childDictList || [];
268 item.childDictList = [{ 373 item.childDictList = [{
269 value: 'scenario', 374 value: 'scenario',
270 label: '应用场景', 375 label: '应用场景',
271 childDictList: childDictList 376 childDictList: childDictList
272 }]; 377 }];
378 // 添加所属科室节点
273 item.childDictList.push({ 379 item.childDictList.push({
274 value: 'medDepartmentCode', 380 value: 'medDepartmentCode',
275 label: '所属科室', 381 label: '所属科室',
276 childDictList: medDepartmentCodeList.value 382 childDictList: medDepartmentCodeList.value
277 }); 383 });
278 let item4 = domainDictList.value.find(i => i.value == '004'); //工业制造 384
385 // 特殊处理工业制造领域(004)
386 let item4 = domainDictList.value.find(i => i.value == '004'); // 工业制造
279 let childDictList4 = item4.childDictList || []; 387 let childDictList4 = item4.childDictList || [];
280 item4.childDictList = [{ 388 item4.childDictList = [{
281 value: 'scenario', 389 value: 'scenario',
282 label: '应用场景', 390 label: '应用场景',
283 childDictList: childDictList4 391 childDictList: childDictList4
284 }]; 392 }];
393 // 添加所属主题节点
285 item4.childDictList.push({ 394 item4.childDictList.push({
286 value: 'subjectDomain', 395 value: 'subjectDomain',
287 label: '所属主题', 396 label: '所属主题',
288 childDictList: subjectDomainListData.value 397 childDictList: subjectDomainListData.value
289 }); 398 });
399
400 // 添加领域及应用场景节点
290 treeInfo.value.data.push({ 401 treeInfo.value.data.push({
291 value: 'domain', 402 value: 'domain',
292 label: '领域及应用场景', 403 label: '领域及应用场景',
293 childDictList: domainDictList.value //TODO,需要带上主题和科室。 404 childDictList: domainDictList.value // TODO,需要带上主题和科室
294 }); 405 });
406
407 // 添加数据来源节点
295 treeInfo.value.data.push({ 408 treeInfo.value.data.push({
296 value: 'dataSource', 409 value: 'dataSource',
297 label: '数据来源', 410 label: '数据来源',
298 childDictList: dataSourceList.value 411 childDictList: dataSourceList.value
299 }); 412 });
413
414 // 添加行业分类节点
300 treeInfo.value.data.push({ 415 treeInfo.value.data.push({
301 value: 'industry', 416 value: 'industry',
302 label: '行业分类', 417 label: '行业分类',
303 childDictList: industryDictList.value 418 childDictList: industryDictList.value
304 }); 419 });
420
421 // 添加机构分类节点
305 treeInfo.value.data.push({ 422 treeInfo.value.data.push({
306 value: 'institutionType', 423 value: 'institutionType',
307 label: '机构分类', 424 label: '机构分类',
308 childDictList: institutionTypeDictList.value 425 childDictList: institutionTypeDictList.value
309 }); 426 });
310 }).catch(() => { 427 }).catch(() => {
311 treeInfo.value.loading = false; 428 treeInfo.value.loading = false; // 出错时关闭加载状态
312 }) 429 })
313 }) 430 })
314
315 </script> 431 </script>
316 432
317 <style lang="scss" scoped> 433 <style lang="scss" scoped>
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!