c046732c by lihua

数据申请前端页面开发

1 parent bc5cc150
......@@ -676,7 +676,7 @@ const panelChange = (scope, row) => {
</div>
</template>
<template v-else-if="item.type === 'label'">
<div :class="[item.col, { is_block: item.block }]">
<div :class="[item.col, { is_block: item.block }]" @click.stop="item.click?.()">
<span>{{ item.default }}</span>
</div>
</template>
......@@ -1484,7 +1484,7 @@ const panelChange = (scope, row) => {
v-model="formInline[item.field]" type="daterange" range-separator="至" start-placeholder="开始日期" :format="item.format ?? null"
:value-format="item.valueFormat ?? null"
end-placeholder="结束日期" :unlink-panels="item.unlink ?? false" :shortcuts="item.shortcuts ?? []"
:default-value="item.defaultDate" :disabled="item.disabled ?? false" />
:default-value="item.defaultDate" :disabled="item.disabled ?? false" :disabled-date="item.disabledDate" />
<el-date-picker :class="[item.col, { is_block: item.block }]" v-else-if="item.type == 'date-year'"
v-model="formInline[item.field]" type="year" format="YYYY" value-format="YYYY"
:placeholder="item.placeholder" :unlink-panels="item.unlink ?? false" :shortcuts="item.shortcuts ?? []"
......
......@@ -387,6 +387,51 @@ const routes: RouteRecordRaw[] = [
}
},
]
},
{
path: '/data-product/data-application',
component: Layout,
meta: {
title: '数据申请',
icon: 'sidebar-videos',
},
children: [
{
path: '',
name: 'productApplicationManage',
component: () => import('@/views/data_asset/productApplicationManage.vue'),
meta: {
title: '',
sidebar: false,
breadcrumb: false,
cache: true
},
},
{
path: 'application-edit',
name: 'productApplicationEdit',
component: () => import('@/views/data_asset/productApplicationEdit.vue'),
meta: {
title: '数据申请-',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true
}
},
{
path: 'application-detail',
name: 'productApplicationDetail',
component: () => import('@/views/data_asset/productApplicationDetail.vue'),
meta: {
title: '数据申请-',
sidebar: false,
breadcrumb: false,
cache: true,
reuse: true
}
},
]
}
]
export default routes
......
const useDataProductApplicationStore = defineStore(
// 资产目录guid
'productApplication',
() => {
const isRefresh = ref<boolean>(false);
function setIsRefresh(v: boolean) {
isRefresh.value = v;
}
return {
isRefresh,
setIsRefresh,
};
}
);
export default useDataProductApplicationStore;
<template>
<div class="container_wrap full" v-loading="fullscreenLoading">
<div class="content_main">
<ContentWrap id="id-baseInfo" title="数据申请信息" description="" :isExpand="baseInfoExpand" :expand-swicth="true"
class="mb16" @expand="(v) => baseInfoExpand = v">
<div class="list_panel">
<div class="list_item">
<span class="item_label">产品名称:</span>
<span class="item_value link" @click="viewProductDetail">
<ellipsis-tooltip :content="detailInfo.damName || '--'" class-name="w100f mr8-i"
:refName="'tooltipOver' + 'damName'"></ellipsis-tooltip>
</span>
</div>
<div class="list_item">
<span class="item_label">产品编号:</span>
<span class="item_value">{{ detailInfo.productCode || '--' }}</span>
</div>
<div class="list_item">
<span class="item_label">资产类型:</span>
<span class="item_value">{{ detailInfo.damTypeName || '--' }}</span>
</div>
<div class="list_item">
<span class="item_label">预计使用期限:</span>
<span class="item_value">{{ detailInfo.damTypeName || '--' }}</span>
</div>
<div class="list_item">
<span class="item_label">数据范围:</span>
<span class="item_value">{{ detailInfo.damTypeName || '--' }}</span>
</div>
<div class="list_item">
<span class="item_label">产品发布机构:</span>
<span class="item_value">{{ detailInfo.productPublisherName || '--' }}</span>
</div>
<div class="list_item is_block">
<span class="item_label">数据粒度说明:</span>
<span class="item_value">{{ detailInfo.description || '--' }}</span>
</div>
<div class="list_item is_block">
<span class="item_label">使用场景描述:</span>
<span class="item_value">{{ detailInfo.description || '--' }}</span>
</div>
</div>
</ContentWrap>
<ContentWrap id="id-approveInfo" title="流程审批" expandSwicth style="margin-top: 15px" :isExpand="expandApprove"
@expand="(v) => expandApprove = v">
<ApprovalProcess ref="approvalProcessRef" v-if="deploymentId" :deploymentId="deploymentId"
:processInstanceId="processInstanceId">
</ApprovalProcess>
</ContentWrap>
</div>
<div class="tool_btns">
<div class="btns">
<el-button v-for="btn in toolBtns" :type="btn.type" :plain="btn.plain" @click="btnClick(btn)">{{ btn.label
}}</el-button>
</div>
</div>
</div>
</template>
<script lang="ts" setup name="productApplicationEdit">
import useUserStore from "@/store/modules/user";
const { proxy } = getCurrentInstance() as any;
const userStore = useUserStore();
const route = useRoute();
const router = useRouter();
const fullPath = route.fullPath;
const fullscreenLoading = ref(false);
const baseInfoExpand = ref(true);
const expandApprove = ref(true);
const deploymentId = ref('');
const processInstanceId = ref('');
const detailInfo: any = ref({});
const viewProductDetail = () => {
// TODO
}
const toolBtns: any = computed(() => {
let btnsArr: any = [{
label: "关闭", value: "cancel", plain: true
}];
// TODO,资产运营平台TODO
return btnsArr;
});
const btnClick = (btn: any) => {
switch (btn.value) {
case 'cancel':
cancel();
break;
default:
break;
}
}
const cancel = () => {
userStore.setTabbar(userStore.tabbar.filter((tab: any) => tab.fullPath !== fullPath));
router.push({
name: 'productApplicationManage'
});
}
onBeforeMount(() => {
})
</script>
<style lang="scss" scoped>
.content_main {
height: calc(100% - 44px);
padding: 16px;
overflow: hidden auto;
position: sticky;
}
.list_panel {
display: flex;
flex-wrap: wrap;
display: flex;
align-items: center;
.list_item {
width: 33.33%;
line-height: 32px;
font-size: 14px;
color: var(--el-text-color-regular);
display: flex;
justify-content: space-between;
min-width: 120px;
.item_label {
text-align: left;
}
.item_value {
color: var(--el-color-regular);
padding: 0 4px;
flex: 1;
text-align: justify;
min-width: 0;
&.link {
color: var(--el-color-primary);
cursor: pointer;
}
}
&.is_block {
width: 100%;
.item_value {
white-space: pre-wrap;
}
}
}
}
.tool_btns {
display: flex;
justify-content: center;
align-items: center;
height: 44px;
padding: 0 16px;
border-top: 1px solid #d9d9d9;
}
</style>
\ No newline at end of file
<template>
<div class="container_wrap full" v-loading="fullscreenLoading">
<div class="content_main">
<ContentWrap id="id-baseInfo" title="数据申请信息" description="" :isExpand="baseInfoExpand" :expand-swicth="true"
class="mb16" @expand="(v) => baseInfoExpand = v">
<Form ref="baseInfoFormRef" :itemList="baseInfoFormItems" formId="base-info-form" :rules="baseInfoFormRules"
col="col3" />
</ContentWrap>
<ContentWrap id="id-approveInfo" title="流程审批" expandSwicth style="margin-top: 15px" :isExpand="expandApprove"
@expand="(v) => expandApprove = v">
<ApprovalProcess ref="approvalProcessRef" v-if="deploymentId" :deploymentId="deploymentId"
:processInstanceId="processInstanceId">
</ApprovalProcess>
</ContentWrap>
</div>
<div class="bottom_tool_wrap">
<el-button @click="cancel">取消</el-button>
<el-button @click="save" v-preReClick>保存</el-button>
<el-button type="primary" @click="submit" v-preReClick>提交审批</el-button>
</div>
</div>
</template>
<script lang="ts" setup name="productApplicationEdit">
import { getCamundaDeploymentId } from "@/api/modules/workFlowService";
import {
getRegisterCatalogDetail
} from "@/api/modules/dataAsset";
import useUserStore from "@/store/modules/user";
import useDataProductApplicationStore from "@/store/modules/productApplication";
import { useValidator } from '@/hooks/useValidator';
const { required } = useValidator();
const { proxy } = getCurrentInstance() as any;
const userStore = useUserStore();
const productApplicationStore = useDataProductApplicationStore();
const route = useRoute();
const router = useRouter();
const userData = JSON.parse(localStorage.userData);
const fullPath = route.fullPath;
const fullscreenLoading = ref(false);
const baseInfoExpand = ref(true);
const expandApprove = ref(true);
const deploymentId = ref('');
const processInstanceId = ref('');
const baseInfoFormRef = ref();
const baseInfoFormItems = ref([{
label: '产品名称',
type: 'label',
field: 'damName',
col: 'link',
default: '-',
click: () => {
//TODO
debugger
router.push({
name: 'productDetail',
query: {
id: route.query.id,
type: 'view'
}
})
}
},
{
label: '产品编码',
type: 'input',
placeholder: '请输入',
field: 'productCode',
default: '-',
disabled: true
},
{
label: '产品类型',
type: 'input',
placeholder: '请输入',
field: 'damTypeName',
default: '-',
disabled: true
},
{
label: "预计使用期限",
type: "date-picker",
field: "useDateRange",
default: null,
placeholder: "开始时间~结束时间",
clearable: true,
disabledDate: (date) => {
const today = new Date();
// 将 today 设置为 00:00:00,只比较日期部分(本地时间)
const todayStart = new Date(
today.getFullYear(),
today.getMonth(),
today.getDate()
);
// 将 date 也转换为本地日期的开始时间(避免 UTC 问题)
const dateStart = new Date(
date.getFullYear(),
date.getMonth(),
date.getDate()
);
// 禁用 dateStart < todayStart 的日期(即今天之前)
return dateStart.getTime() < todayStart.getTime();
},
required: true,
},
{
label: "数据范围",
type: "date-picker",
field: "useDataDateRange",
default: null,
placeholder: "开始时间~结束时间",
clearable: true,
required: true,
},
{
label: '产品发布机构',
type: 'input',
placeholder: '请输入',
field: 'productPublisherName',
default: '',
disabled: true
},
{
label: '数据粒度说明',
type: 'textarea',
placeholder: '请输入需要的需求字段',
field: 'dataDescription',
default: '',
block: true,
maxlength: 500,
clearable: true,
required: true,
},
{
label: '使用场景描述',
type: 'textarea',
placeholder: '请输入使用该数据产品的场景描述信息',
field: 'useDescription',
default: '',
block: true,
maxlength: 500,
clearable: true,
required: true,
},
])
const baseInfoFormRules = ref({
useDateRange: [{
type: 'array', required: true, message: '请选择预计使用期限', trigger: 'change',
}],
useDataDateRange: [{
type: 'array', required: true, message: '请选择数据范围', trigger: 'change',
}],
dataDescription: [required('请输入数据粒度说明')],
useDescription: [required('请输入使用场景描述')]
})
const cancel = () => {
proxy.$openMessageBox("当前页面尚未保存,确定放弃修改吗?", () => {
userStore.setTabbar(userStore.tabbar.filter((tab: any) => tab.fullPath !== fullPath));
router.push({
name: 'productApplicationManage'
});
}, () => {
proxy.$ElMessage.info("已取消");
});
}
const save = () => {
// 保存不检验。
}
const submit = () => {
baseInfoFormRef.value?.ruleFormRef?.validate().then((valid, errorItem) => {
if (valid) {
let formInline = baseInfoFormRef.value.formInline;
// fullscreenLoading.value = true;
// listingSavePortal(params).then((res: any) => {
// fullscreenLoading.value = false;
// if (res?.code == proxy.$passCode) {
// proxy.$ElMessage.success('提交审批成功');
// userStore.setTabbar(userStore.tabbar.filter((tab: any) => tab.fullPath !== fullPath));
// productApplicationStore.setIsRefresh(true);
// router.push({
// name: "productApplicationManage",
// });
// } else {
// res?.msg && proxy.$ElMessage.error(res.msg);
// }
// }).catch((res) => {
// fullscreenLoading.value = false;
// });
} else {
var obj = Object.keys(errorItem);
baseInfoFormRef.value.ruleFormRef.scrollToField(obj[0]);
}
})
}
onActivated(() => {
let tab: any = userStore.tabbar.find((tab: any) => tab.fullPath == fullPath);
let detailType = route.query.type;
let name = route.query.name;
if (tab) {
switch (detailType) {
case 'edit':
tab.meta.title = `编辑-${name}`;
break;
case 'redit':
tab.meta.title = `编辑-${name}`;
break;
default:
tab.meta.title = '新增数据申请';
}
document.title = tab.meta.title;
};
})
onBeforeMount(() => {
// getCamundaDeploymentId('10016', userData.tenantGuid, userData.staffGuid).then((res: any) => {
// if (res.code == proxy.$passCode) {
// deploymentId.value = res.data;
// } else {
// proxy.$ElMessage.error(res.msg);
// }
// })
fullscreenLoading.value = true;
getRegisterCatalogDetail(route.query.guid).then((res: any) => {
fullscreenLoading.value = false;
if (res?.code == proxy.$passCode) {
let detail = res.data || {};
baseInfoFormItems.value[0].default = <string>route.query.damName;
baseInfoFormItems.value[1].default = detail.productCode;
baseInfoFormItems.value[2].default = detail.damTypeName;
} else {
res?.msg && proxy.$ElMessage.error(res.msg);
}
})
})
</script>
<style lang="scss" scoped>
.content_main {
height: calc(100% - 40px);
padding: 16px;
overflow: hidden auto;
position: sticky;
}
.bottom_tool_wrap {
height: 40px;
padding: 0 16px;
border-top: 1px solid #d9d9d9;
display: flex;
justify-content: center;
align-items: center;
}
:deep(.el-form) {
.link {
color: var(--el-color-primary);
cursor: pointer;
line-height: 32px;
}
}
</style>
\ No newline at end of file
<template>
<div class="container_wrap">
<div class="table_tool_wrap">
<TableTools :searchItems="searchItemList" :searchId="'data-application-search'" @search="toSearch" />
</div>
<div class="table_panel_wrap" :style="{ height: 'calc(100% - 48px)' }">
<Table :tableInfo="tableInfo" @tablePageChange="tablePageChange" />
</div>
</div>
</template>
<script lang="ts" setup name="productApplicationManage">
import { commonPageConfig } from "@/components/PageNav";
import TableTools from "@/components/Tools/table_tools.vue";
import useUserStore from "@/store/modules/user";
import { TableColumnWidth } from "@/utils/enum";
import { getDamTypesList } from "@/api/modules/dataAsset";
const { proxy } = getCurrentInstance() as any;
const router = useRouter();
const userStore = useUserStore();
const userData = JSON.parse(userStore.userData);
const damTypes: any = ref([]);
const searchItemList: any = ref([
{
type: "input",
label: "",
field: "damName",
default: "",
placeholder: "产品名称",
clearable: true
},
{
type: "select",
label: "",
field: "damType",
default: "",
props: {
value: 'value',
label: 'label'
},
placeholder: "产品类型",
options: damTypes.value,
clearable: true,
},
{
type: 'select',
label: '',
field: 'approveState',
default: '',
placeholder: '审批状态',
options: [
{ label: '草稿中', value: 'N' },
{ label: '审批中', value: 'A' },
{ label: '已通过', value: 'Y' },
{ label: '已驳回', value: 'R' },
{ label: '已撤销', value: 'C' },
],
clearable: true
},
]);
const page = ref({
...commonPageConfig,
damName: '',
damType: null,
approveState: null,
});
const tableInfo = ref({
id: "mapping-table",
fields: [
{ label: "序号", type: "index", width: 56, align: "center", fixed: "left" },
{ label: "数据产品编号", field: "productCode", width: 265 },
{ label: "数据产品名称", field: "damName", width: 180 },
{
label: "产品类型", field: "damTypeName", width: 100
},
{
label: "审批状态", field: "approveState", type: "tag", width: TableColumnWidth.STATE, align: 'center'
},
{ label: "申请方", field: "tenantName", width: 240 },
{ label: "数据提供方", field: "dataProviderName", width: 240 },
{ label: "提交时间", field: "submitTime", width: 170 },
],
loading: false,
data: [],
page: {
type: "normal",
rows: 0,
...page.value,
},
actionInfo: {
label: "操作",
type: "btn",
width: 170,
btns: (scope) => {
const { row } = scope;
const bizApproveState = row.approveState;
let flowState;
if (bizApproveState == 'N') {
flowState = 1;
}
const currentStaffGuid = userData.userGuid
const staffGuid = row.createUserId || '';
let isShowCancel = false;
let list: any = [];
if (bizApproveState == 'N') {
flowState = 1;
}
if ((bizApproveState == 'D' || bizApproveState == 'C' || bizApproveState == 'R' || bizApproveState == 'E' || bizApproveState == 'R') && staffGuid == currentStaffGuid) {
flowState = 3;
}
if (bizApproveState == 'A' && staffGuid == currentStaffGuid) {
isShowCancel = true;
}
if (flowState === 1) {
list = [{ label: "编辑", value: "edit", click: btnHandlers.edit }, { label: "删除", value: "del", click: btnHandlers.del }]
}
if (flowState === 3) {
list.push({ label: "删除", value: "del", click: btnHandlers.del })
}
if (flowState === 3) { //重新提交过的不能再重新提交 && bizApproveState != 'D'
list.push({ label: "重新提交", value: "redit", click: btnHandlers.redit }) //已驳回
}
if (flowState !== 1) {
list.push({ label: "详情", value: "detail", click: btnHandlers.detail })
}
return list
},
}
});
const btnHandlers = {
edit: (scope) => {
router.push({
// name: "data-product-edit",
// query: {
// id: scope.row.id,
// },
});
},
redit: (scope) => {
},
detail: (scope) => {
router.push({
// name: "data-product-detail",
// query: {
// id: scope.row.id,
// },
})
},
del: (scope) => {
proxy.$openMessageBox('数据申请删除后不可恢复,确定继续删除吗?', () => {
// delCertificate([row.guid]).then((res: any) => {
// if (res?.code == proxy.$passCode) {
// proxy.$ElMessage.success('删除资产登记证件成功');
// page.value.curr = 1;
// getTableData();
// } else {
// proxy.$ElMessage.error(res.msg);
// }
// })
}, () => {
proxy.$ElMessage.info("已取消删除");
});
},
}
const toSearch = (val: any, clear: boolean = false) => {
if (clear) {
searchItemList.value.map(item => item.default = "");
page.value.damName = '';
page.value.approveState = null;
page.value.damType = null;
} else {
page.value.damName = val.damName;
page.value.approveState = val.approveState;
page.value.damType = val.damType;
}
page.value.curr = 1;
tableInfo.value.page.curr = 1;
getTableData();
};
const getTableData = () => {
// tableInfo.value.loading = true;
// getListingList({
// pageIndex: page.value.curr,
// pageSize: page.value.limit,
// damName: page.value.damName,
// damType: page.value.damType,
// approveState: page.value.approveState
// }).then((res: any) => {
// tableInfo.value.loading = false;
// tableInfo.value.data = res.data.records || [];
// tableInfo.value.page.curr = res.data.pageIndex;
// tableInfo.value.page.limit = res.data.pageSize;
// tableInfo.value.page.rows = res.data.totalRows;
// }).catch((res) => {
// tableInfo.value.loading = false;
// });
};
const tablePageChange = (info) => {
page.value.curr = Number(info.curr);
page.value.limit = Number(info.limit);
tableInfo.value.page.limit = page.value.limit;
tableInfo.value.page.curr = page.value.curr;
getTableData();
};
onBeforeMount(() => {
getDamTypesList({
dictType: "资产类型",
}).then((res: any) => {
if (res.code == proxy.$passCode) {
damTypes.value = res.data || [];
searchItemList.value[1].options = damTypes.value;
} else {
proxy.$ElMessage.error(res.msg);
}
})
})
</script>
<style lang="scss" scoped>
.container_wrap {
width: 100%;
height: 100%;
overflow-y: auto;
.table_tool_wrap {
width: 100%;
padding: 0 8px;
.tools_btns {
padding: 0px 0 8px;
}
}
.table_panel_wrap {
width: 100%;
padding: 0px 8px 0;
}
}
</style>
\ No newline at end of file
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!