feat: 新增配置管理和视图管理

This commit is contained in:
sy2084
2024-07-15 11:54:32 +08:00
parent aeba86bb91
commit 8f9cef2a90
36 changed files with 2322 additions and 81 deletions

View File

@@ -0,0 +1,268 @@
<template>
<div class="normal-container">
<div class="view-create-box">
<div class="left-box">
<a-form :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
<a-form-item label="项目"
><a-select
placeholder="请选择项目"
:options="projectSel"
v-model:value="projectId"
@change="onProjectChange"
></a-select
></a-form-item>
<a-form-item label="数据表">
<a-select
placeholder="请选择"
:options="modularSel"
v-model:value="modularId"
@change="onModularChange"
></a-select>
</a-form-item>
<a-form-item label="字段">
<a-checkbox-group v-if="fieldList.length" v-model:value="fieldIds">
<a-checkbox
v-for="(item, index) in fieldList"
:key="index"
:value="item.value"
>{{ item.label }}</a-checkbox
>
</a-checkbox-group>
<a-empty v-else description="暂无字段数据" />
</a-form-item>
</a-form>
<div class="footer">
<a-button
class="preview-btn"
:loading="previewLoading"
@click="toPreview"
>预览</a-button
>
<a-button type="primary" @click="addViewName">点击保存</a-button>
</div>
</div>
<div class="right-box">
<div class="y-table-container" v-if="previewData.type === 'table'">
<div class="y-table-filter">
<div
v-for="(item, index) in previewData.filterConfig"
:key="item.name"
class="filter-item"
>
<span>{{ item.label }}</span>
<a-select
v-if="item.type === 'select'"
class="input-item"
:options="item.options"
v-model:value="previewData.filterData[item.name]"
placeholder="请选择"
@change="toFilt"
></a-select>
<a-input
v-else
class="input-item"
placeholder="请输入"
v-model:value="previewData.filterData[item.name]"
@change="
(e) => {
toFilt(item.name, e.target.value);
}
"
/>
</div>
</div>
<div class="y-table-content">
<a-table
:columns="previewData.columnConfig"
:data-source="previewData.dataList"
:pagination="false"
size="small"
bordered
></a-table>
<a-pagination
v-model:current="previewData.page"
:total="previewData.total"
:page-size="previewData.perPage"
:hide-on-single-page="false"
size="small"
class="pagination-box"
@change="toPreview"
/>
</div>
</div>
</div>
<a-modal
:open="nameVisible"
title="保存视图"
:bodyStyle="{ paddingTop: '20px' }"
@cancel="nameVisible = false"
@ok="toSaveView"
>
<a-form :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
<a-form-item label="视图名称">
<a-input placeholder="请输入视图名称" v-model:value="previewName" />
</a-form-item>
</a-form>
</a-modal>
</div>
</div>
</template>
<script setup>
import { onMounted, reactive, ref } from "vue";
import { getProModularField, preview, saveView } from "./service";
import { message } from "ant-design-vue";
const projectSel = ref([]);
const modularSel = ref([]);
const fieldList = ref([]);
const projectId = ref();
const modularId = ref();
const fieldIds = ref([]);
const previewLoading = ref(false);
const nameVisible = ref(false);
const previewName = ref();
const previewData = reactive({
type: "",
filterConfig: [], // 筛选条件
columnConfig: [], // 表格表头
dataList: [], // 表格数据
filterData: {},
page: 1,
perPage: 20,
total: 0,
});
onMounted(() => {
toGetProModularField();
});
const toGetProModularField = () => {
getProModularField().then((res) => {
projectSel.value = res.data;
});
};
const onProjectChange = (val) => {
const target = projectSel.value.find((item) => item.value === val);
modularSel.value = target.child;
modularId.value = undefined;
fieldList.value = [];
fieldIds.value = [];
};
const onModularChange = (val) => {
const target = modularSel.value.find((item) => item.value === val);
fieldList.value = target.child;
};
const toPreview = () => {
previewLoading.value = true;
const filter = previewData.filterConfig.map((item) => {
return {
name: item.name,
type: item.type,
value: previewData.filterData[item.name],
};
});
preview({
modularId: modularId.value,
fieldIds: fieldIds.value.toString(),
page: previewData.page,
perPage: previewData.perPage,
filter,
})
.then((res) => {
previewData.type = res.data.type;
if (res.data.type === "table") {
previewData.filterConfig = res.data.filter;
previewData.filterConfig.forEach((item) => {
previewData.filterData[item.name] = previewData.filterData[item.name]
? previewData.filterData[item.name]
: undefined;
});
console.log("filterData", previewData.filterData);
previewData.columnConfig = res.data.header;
previewData.dataList = res.data.data;
previewData.total = res.data.count;
}
})
.finally(() => {
previewLoading.value = false;
});
};
const addViewName = () => {
nameVisible.value = true;
previewName.value = null;
};
const toSaveView = () => {
if (!previewName.value) {
message.error("请输入名称");
return;
}
saveView({
modularId: modularId.value,
fieldIds: fieldIds.value.toString(),
previewName: previewName.value,
}).then(() => {
message.success("保存成功");
nameVisible.value = false;
});
};
const toFilt = (key, value) => {
previewData.filterData[key] = value;
previewData.page = 1;
toPreview();
};
</script>
<style lang="less" scoped>
.normal-container {
height: calc(100vh - 120px);
}
.view-create-box {
display: flex;
height: 100%;
}
.left-box {
width: 400px;
height: calc(100% - 20px);
padding: 10px;
border-right: 1px solid #ddd;
.footer {
text-align: right;
.preview-btn {
margin-right: 10px;
}
}
}
.right-box {
padding: 10px;
flex-grow: 1;
overflow: auto;
}
.y-table-filter {
display: flex;
flex-wrap: wrap;
}
.filter-item {
margin-right: 10px;
margin-bottom: 6px;
}
.input-item {
width: 180px;
}
.y-table-content {
margin-top: 10px;
}
.pagination-box {
text-align: center;
}
</style>

View File

@@ -0,0 +1,34 @@
import { get, post } from "@/utils/request";
// 项目-表-字段下拉
export function getProModularField() {
return get({
url: "/api/v1/field/get-project-modular-field-drop",
});
}
// 预览
export function preview({ modularId, fieldIds, page, perPage, filter }) {
return post({
url: "api/v1/preview/view",
data: {
modular_id: modularId,
field_ids: fieldIds,
page,
per_page: perPage,
filter,
},
});
}
// 点击保存
export function saveView({ modularId, fieldIds, previewName }) {
return post({
url: "api/v1/preview/save",
data: {
modular_id: modularId,
field_ids: fieldIds,
preview_name: previewName,
},
});
}

View File

@@ -0,0 +1,5 @@
export const viewListCols = [
{ dataIndex: 'preview_name', title: '视图名称', align: 'center' },
{ dataIndex: 'created_at', title: '创建时间', align: 'center' },
{ dataIndex: 'action', title: '操作', align: 'center' },
];

View File

@@ -0,0 +1,165 @@
<template>
<div class="normal-container">
<div class="view-list-box">
<div class="left-box">
<a-form :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
<a-form-item label="项目">
<a-select
:options="projectSel"
v-model:value="projectId"
placeholder="请选择项目"
@change="onProjectChange"
></a-select>
</a-form-item>
<a-form-item label="数据表">
<a-select
:options="modularSel"
v-model:value="modularId"
placeholder="请选择数据表"
@change="onModularChange"
></a-select>
</a-form-item>
</a-form>
<a-table
:data-source="dataList"
:columns="viewListCols"
:pagination="false"
:row-class-name="
(record) =>
record.preview_id === selectedRowId ? 'selected-row' : ''
"
:custom-row="
(record, index) => {
return {
onClick: () => {
selectedRowId = record.preview_id;
toGetViewInfo();
},
};
}
"
size="small"
bordered
></a-table>
<a-pagination
v-model:current="pageState.page"
:total="pageState.total"
:page-size="pageState.perPage"
:hide-on-single-page="false"
size="small"
class="pagination-box"
@change="toGetList"
/>
</div>
<div class="right-box">
<y-table
v-if="selectViewInfo.type === 'table'"
:filterConfig="selectViewInfo.filter"
:dataList="selectViewInfo.data"
:columnConfig="selectViewInfo.header"
:total="selectViewInfo.count"
@toFilt="
(params) => {
toGetViewInfo(params);
}
"
/>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, ref, reactive } from "vue";
import { getProModular, getViewList, getViewInfo } from "./service";
import { viewListCols } from "./config";
import yTable from "@/components/common/y-table.vue";
const projectSel = ref([]);
const modularSel = ref([]);
const projectId = ref();
const modularId = ref();
const dataList = ref([]);
const selectedRowId = ref();
const selectViewInfo = ref({
type: "",
});
const pageState = reactive({
page: 1,
perPage: 20,
total: 0,
});
onMounted(() => {
toGetProModular();
});
const toGetProModular = () => {
getProModular().then((res) => {
projectSel.value = res.data;
});
};
const toGetList = () => {
getViewList({
modularId: modularId.value,
page: pageState.page,
perPage: pageState.perPage,
}).then((res) => {
dataList.value = res.data.list;
pageState.total = res.data.total;
});
};
const toGetViewInfo = (params = {}) => {
getViewInfo({
previewId: selectedRowId.value,
...params,
}).then((res) => {
selectViewInfo.value = res.data;
});
};
const onProjectChange = (val) => {
modularSel.value = projectSel.value.find((item) => item.value === val).child;
modularId.value = null;
};
const onModularChange = () => {
pageState.page = 1;
toGetList();
};
</script>
<style lang="less" scoped>
.normal-container {
height: calc(100vh - 120px);
}
.view-list-box {
display: flex;
height: 100%;
}
.left-box {
width: 400px;
height: calc(100% - 20px);
padding: 10px;
border-right: 1px solid #ddd;
}
.selected-row {
background-color: beige;
}
.pagination-box {
text-align: center;
margin-top: 10px;
}
.right-box {
padding: 10px;
flex-grow: 1;
overflow: auto;
}
</style>

View File

@@ -0,0 +1,38 @@
import { get } from "@/utils/request";
// 联动下拉
export function getProModular() {
return get({
url: "/api/v1/field/get-project-modular-drop",
});
}
// 视图列表
export function getViewList({ modularId, page = 1, perPage = 20 }) {
return get({
url: "/api/v1/preview/list",
params: {
modular_id: modularId,
page,
perPage: perPage,
},
});
}
// 查看视图
export function getViewInfo({
previewId,
page = 1,
perPage = 20,
filter = {},
}) {
return get({
url: "/api/v1/preview/info",
params: {
preview_id: previewId,
page,
perPage: perPage,
filter,
},
});
}