Merge branch 'feature/new-sys' into 'release'

fix: 调整数据来源配置

See merge request workbench/y-code!4
This commit is contained in:
姚晓琼 2024-07-17 23:38:24 +08:00
commit 59c2db7ca3
16 changed files with 242 additions and 57 deletions

1
components.d.ts vendored
View File

@ -28,6 +28,7 @@ declare module 'vue' {
ARadio: typeof import('ant-design-vue/es')['Radio']
ARadioButton: typeof import('ant-design-vue/es')['RadioButton']
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
ARangePicker: typeof import('ant-design-vue/es')['RangePicker']
ASelect: typeof import('ant-design-vue/es')['Select']
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
ASpace: typeof import('ant-design-vue/es')['Space']

View File

@ -1,6 +1,21 @@
<template>
<div class="chart-show-box">
<div class="switch-type">
<div class="chart-name">
<div class="title">{{ title }}</div>
</div>
<div class="chart-header">
<div class="chart-filter">
<div v-for="(item, index) in filterConfig" :key="index" class="filter-item">
<div>
<a-radio-group v-model:value="dateType" button-style="solid">
<a-radio-button value="day"></a-radio-button>
<a-radio-button value="week"></a-radio-button>
<a-radio-button value="month"></a-radio-button>
</a-radio-group>
<a-range-picker v-if="item.type === 'time'" class="date-item" v-model:value="filterData[item.name]" :picker="rangePicker" @change="toFilt" />
</div>
</div>
</div>
<a-radio-group v-model:value="chartType">
<a-radio-button value="line">折线图</a-radio-button>
<a-radio-button value="bar">柱状图</a-radio-button>
@ -14,26 +29,101 @@
</template>
<script setup>
import { computed, ref } from "vue";
import { computed, ref, watch } from "vue";
import Line from "@/plugins/antv-g2plot/line.vue";
import Column from "@/plugins/antv-g2plot/column.vue";
import _ from 'lodash';
const props = defineProps({
title: {
type: String,
default: "",
},
chartCfg: {
type: Object,
default: () => ({}),
},
filterConfig: {
type: Array,
default: () => [],
},
});
const emit = defineEmits(["toFilt"]);
const chartType = ref("line");
const dateType = ref("day");
const filterData = ref({
});
const rangePicker = computed(() => {
switch(dateType.value) {
case 'week':
return 'week';
case 'month':
return 'month';
default:
return 'date';
}
});
const currentChart = computed(() => {
return props.chartCfg[chartType.value];
})
watch(
() => props.filterConfig,
(newVal) => {
// newVal.forEach((item) => {
// filterData.value[item.name] = undefined;
// });
},
);
const toFilt = () => {
const cloneFilter = _.cloneDeep(props.filterConfig);
const filter = cloneFilter
.filter((item) => {
return filterData.value[item.name] !== undefined && filterData.value[item.name] !== null;
})
.map((item) => {
return item.type === 'time' ? {
name: item.name,
type: item.type,
start_time: filterData.value[item.name][0].format('YYYY-MM-DD'),
end_time: filterData.value[item.name][1].format('YYYY-MM-DD'),
date_type: dateType.value,
} : {
name: item.name,
type: item.type,
value: filterData.value[item.name],
}
})
emit('toFilt', {
filter,
});
};
</script>
<style lang="less" scoped>
.chart-wrap {
padding: 20px;
}
.chart-name {
margin-bottom: 8px;
.title {
font-size: 18px;
font-weight: bold;
}
}
.chart-header {
display: flex;
justify-content: space-between;
}
.date-item {
margin-left: 10px;
}
</style>

View File

@ -1,5 +1,8 @@
<template>
<div class="y-table-container">
<div class="y-table-name">
<div class="title">{{ title }}</div>
</div>
<div class="y-table-filter">
<div
v-for="(item, index) in filterConfig"
@ -16,13 +19,14 @@
@change="toFilt"
></a-select>
<a-input
v-if="item.type === 'text'"
v-else-if="item.type === 'text'"
class="input-item"
placeholder="请输入"
allow-clear
v-model:value="filterData[item.name]"
@change="toFilt"
/>
<a-range-picker v-else-if="item.type === 'time'" class="date-item" v-model:value="filterData[item.name]" @change="toFilt" />
</div>
</div>
<div class="y-table-content">
@ -30,7 +34,7 @@
:columns="columnConfig"
:data-source="dataList"
:pagination="false"
:scroll="{ x: 1000, y: `calc(100vh - 260px)` }"
:scroll="{ x: 1000, y: `calc(100vh - 280px)` }"
size="small"
bordered
></a-table>
@ -69,8 +73,12 @@ const props = defineProps({
type: Number,
default: 0,
},
title: {
type: String,
default: "",
},
});
const emit = defineEmits(["handleFilt"]);
const emit = defineEmits(["toFilt"]);
const filterData = ref({});
@ -83,9 +91,9 @@ watch(
() => props.filterConfig,
(newVal) => {
newVal.forEach((item) => {
filterData.value[item.name] = undefined;
});
// newVal.forEach((item) => {
// filterData.value[item.name] = undefined;
// });
}
);
@ -93,10 +101,15 @@ const getData = () => {
const cloneFilter = _.cloneDeep(props.filterConfig);
const filter = cloneFilter
.filter((item) => {
return filterData.value[item.name] !== undefined;
return filterData.value[item.name] !== undefined && filterData.value[item.name] !== null;
})
.map((item) => {
return {
return item.type === 'time' ? {
name: item.name,
type: item.type,
start_time: filterData.value[item.name][0].format('YYYY-MM-DD'),
end_time: filterData.value[item.name][1].format('YYYY-MM-DD'),
} : {
name: item.name,
type: item.type,
value: filterData.value[item.name],
@ -119,6 +132,13 @@ const pageChange = () => {
</script>
<style lang="less" scoped>
.y-table-name {
margin-bottom: 10px;
.title {
font-size: 18px;
font-weight: bold;
}
}
.y-table-filter {
display: flex;
flex-wrap: wrap;
@ -131,10 +151,14 @@ const pageChange = () => {
.input-item {
width: 180px;
}
.date-item {
width: 240px;
}
.y-table-content {
margin-top: 10px;
}
.pagination-box {
text-align: center;
margin-top: 10px;
}
</style>

View File

@ -22,5 +22,5 @@ const props = defineProps({
},
});
const { container } = useChart(Column, props.config);
const { container } = useChart(Column, props);
</script>

View File

@ -3,6 +3,7 @@
</template>
<script setup>
import { watch } from "vue";
import { Line } from "@antv/g2plot";
// hooks
import useChart from "./useChart";
@ -21,6 +22,8 @@ const props = defineProps({
default: () => ({}),
},
});
const { container } = useChart(Line, props.config);
watch(() => props.config, (newVal) => {
console.log('newVal', newVal)
})
const { container } = useChart(Line, props);
</script>

View File

@ -22,5 +22,5 @@ const props = defineProps({
},
});
const { container } = useChart(Pie, props.config);
const { container } = useChart(Pie, props);
</script>

View File

@ -1,20 +1,20 @@
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
import _ from "lodash";
export default function useChart(ChartClass, config) {
export default function useChart(ChartClass, props) {
const chart = ref(null); // 表格实例
const chartOptions = ref(null); // 图表配置
const container = ref(null); // 渲染图表元素
const { onReady, onEvent } = config;
const { onReady, onEvent } = props.config;
// 全局事件侦听器
let handler;
onMounted(() => {
chartOptions.value = _.cloneDeep(config);
chartOptions.value = _.cloneDeep(props.config);
// 实例化图表
const chartInstance = new ChartClass(container.value, { ...config });
const chartInstance = new ChartClass(container.value, { ...props.config });
chartInstance.toDataURL = (type, encoderOptions) => {
return toDataURL(type, encoderOptions);
};
@ -46,7 +46,7 @@ export default function useChart(ChartClass, config) {
// 配置更改时更新图表
watch(
() => config,
() => props.config,
(config) => {
const newConfig = _.cloneDeep(config);
chartOptions.value = newConfig;

View File

@ -49,7 +49,7 @@ const routeList: RouteType[] = [
path: 'module-cfg',
name: 'module-cfg',
component: () => import('@/views/config-manage/module-cfg/index.vue'),
meta: { title: '数据配置' },
meta: { title: '数据来源配置' },
isMenu: true,
children: [],
},

View File

@ -12,6 +12,7 @@
placeholder="请选择所属项目"
v-model:value="formData.project_id"
:options="projectSelect"
@change="toGetDbTable"
/>
</a-form-item>
<a-form-item label="数据来源" name="modular_name">
@ -49,7 +50,7 @@
name="table"
>
<a-select
placeholder="请选择数据表"
placeholder="请先选择项目再选择数据表"
v-model:value="formData.table"
:options="tableTypes"
/>
@ -131,12 +132,12 @@ watch(
}
);
onMounted(() => {
toGetDbTable();
});
// onMounted(() => {
// toGetDbTable();
// });
const toGetDbTable = () => {
getDbTableSelect().then((res) => {
getDbTableSelect({ projectId: formData.value.project_id }).then((res) => {
tableTypes.value = res.data;
});
};

View File

@ -40,6 +40,18 @@
{{ record[column.dataIndex] }}
</template>
</template>
<template v-if="column.dataIndex === 'field_numerical_name'">
<a-select
v-if="editableData[record.field_id]"
v-model:value="record.field_numerical_type_id"
:options="fieldNumTypeSel"
placeholder="请选择"
style="width: 160px">
</a-select>
<template v-else>
{{ record.field_numerical_name }}
</template>
</template>
<template v-if="column.dataIndex === 'field_type_name'">
<a-select
v-if="editableData[record.field_id]"
@ -67,14 +79,14 @@
<template v-if="column.dataIndex === 'action'">
<a-space v-if="editableData[record.field_id]">
<a-button type="primary" size="small" @click="handleSave(record)"
>保存</a-button
>保存</a-button
>
<a-button size="small" @click="handleCancel(record)"
>取消</a-button
>取消</a-button
>
</a-space>
<a-button v-else type="link" @click="handleEdit(record)"
>修改</a-button
>修改</a-button
>
</template>
</template>
@ -96,6 +108,7 @@ import { onMounted, reactive, ref, watch } from "vue";
import { viewCfgCols } from "@/views/config-manage/module-cfg/config";
import {
getFieldTypeSelect,
getFieldNumSelect,
getFieldList,
// deleteField,
saveField,
@ -117,6 +130,7 @@ const listLoading = ref(false);
const fieldName = ref("");
const dataList = ref([]);
const fieldTypeSel = ref([]);
const fieldNumTypeSel = ref([]);
const pageState = reactive({
page: 1,
perPage: 20,
@ -135,15 +149,23 @@ watch(
onMounted(() => {
toGetFieldTypes();
toGetFieldNumSelect();
});
//
//
const toGetFieldTypes = () => {
getFieldTypeSelect().then((res) => {
fieldTypeSel.value = res.data;
});
};
//
const toGetFieldNumSelect = () => {
getFieldNumSelect().then((res) => {
fieldNumTypeSel.value = res.data;
})
};
//
const toGetList = () => {
listLoading.value = true;
@ -172,6 +194,7 @@ const addField = () => {
field_id: new Date().getTime() + "",
field_title: undefined,
field_name: undefined,
field_numerical_type_id: undefined,
is_search: 0,
field_type_id: undefined,
belong_to_table: undefined,
@ -203,6 +226,7 @@ const handleSave = (record) => {
field_id: record.field_id,
field_title: record.field_title,
field_name: record.field_name,
field_numerical_type_id: record.field_numerical_type_id,
is_search: record.is_search,
field_type_id: record.field_type_id,
belong_to_table: record.belong_to_table,

View File

@ -1,6 +1,6 @@
export const moduleCfgCols = [
{ dataIndex: 'modular_id', title: '编号', align: 'center'},
{ dataIndex: 'modular_name', title: '数据名称', align: 'center'},
{ dataIndex: 'modular_name', title: '数据来源名称', align: 'center'},
{ dataIndex: 'project_name', title: '项目名称', align: 'center'},
{ dataIndex: 'is_show', title: '展示状态', align: 'center'},
{ dataIndex: 'original_type_handle', title: '数据源类型', align: 'center'},
@ -11,7 +11,8 @@ export const moduleCfgCols = [
export const viewCfgCols = [
{ dataIndex: 'field_name', title: '字段名称', align: 'center'},
{ dataIndex: 'field_title', title: '字段标题', align: 'center'},
{ dataIndex: 'field_type_name', title: '字段类型', align: 'center'},
{ dataIndex: 'field_numerical_name', title: '字段类型', align: 'center'},
{ dataIndex: 'field_type_name', title: '搜索类型', align: 'center'},
{ dataIndex: 'is_search', title: '是否可搜索', align: 'center'},
{ dataIndex: 'sort', title: '排序', align: 'center'},
{ dataIndex: 'belong_to_table', title: '所属表名称', align: 'center'},

View File

@ -4,7 +4,7 @@
<a-space>
<a-input
v-model:value="modularName"
placeholder="请输入数据名称"
placeholder="请输入数据来源名称"
allow-clear
style="width: 200px"
@change="search"

View File

@ -54,20 +54,30 @@ export function getProjectSelect() {
});
}
// 数据表下拉
export function getDbTableSelect() {
// 数据下拉
export function getDbTableSelect({ projectId }) {
return get({
url: `/api/v1/modular/get-database-table-drop`,
params: {
project_id: projectId,
},
});
}
// 字段类型下拉
// 字段搜索类型下拉
export function getFieldTypeSelect() {
return get({
url: `/api/v1/field/get-field-type-drop`,
});
}
// 字段类型下拉
export function getFieldNumSelect() {
return get({
url: `/api/v1/field/get-field-numerical-type-drop`,
})
}
// 获取字段列表
export function getFieldList({ modularId, fieldName, page, perPage }) {
return get({

View File

@ -14,7 +14,7 @@
/>
</a-form-item>
<a-form-item label="项目标识" name="mark">
<a-input placeholder="请输入项目标识例如oa" />
<a-input placeholder="请输入项目标识例如oa" v-model:value="formData.mark" />
</a-form-item>
<a-form-item label="展示状态" name="is_show">
<a-switch

View File

@ -56,9 +56,12 @@
</div>
<div class="right-box">
<div class="y-table-container" v-if="previewData.type === 'table'">
<div class="y-table-name">
<div class="title">{{ previewData.preview_name }}</div>
</div>
<div class="y-table-filter">
<div
v-for="(item, index) in previewData.filterConfig"
v-for="item in previewData.filterConfig"
:key="item.name"
class="filter-item"
>
@ -80,6 +83,7 @@
v-model:value="previewData.filterData[item.name]"
@change="toFilt"
/>
<a-range-picker v-if="item.type === 'date'" class="input-item" v-model:value="previewData.filterData[item.name]" @change="toFilt" />
</div>
</div>
<div class="y-table-content">
@ -102,7 +106,7 @@
/>
</div>
</div>
<y-chart v-if="previewData.type === 'chart'" :chartCfg="previewData.chartCfg"></y-chart>
<y-chart v-else-if="previewData.type === 'chart'" :chart-cfg="previewData.chartCfg" :filter-config="previewData.filter" @toFilt="toPreview"></y-chart>
<div class="preview-area" v-else>
<div><BarChartOutlined /></div>
<div>预览区</div>
@ -161,7 +165,8 @@ const previewData = reactive({
columnConfig: [], //
dataList: [], //
filterData: {},
chartCfg: {},
config: {},
filter: [],
page: 1,
perPage: 20,
total: 0,
@ -242,28 +247,36 @@ const resetPreviewData = () => {
previewData.total = 0;
};
const toPreview = () => {
const toPreview = ({filter}) => {
previewLoading.value = true;
const filter = previewData.filterConfig
.filter((item) => {
return previewData.filterData[item.name] !== undefined;
})
.map((item) => {
return {
name: item.name,
type: item.type,
value: previewData.filterData[item.name],
};
});
let filterData
if (!filter) {
filterData = previewData.filterConfig
.filter((item) => {
return previewData.filterData[item.name] !== undefined;
})
.map((item) => {
return {
name: item.name,
type: item.type,
value: previewData.filterData[item.name],
};
});
} else {
filterData = filter;
}
console.log('filterData',filterData)
preview({
modularId: modularId.value,
fieldIds: fieldIds.value.toString(),
page: previewData.page,
perPage: previewData.perPage,
filter,
filter: filterData,
showTypeId: showTypeId.value,
xDataId: xDataId.value.toString(),
yDataId: yDataId.value.toString(),
xDataId: xDataId.value?.toString(),
yDataId: yDataId.value?.toString(),
})
.then((res) => {
previewData.type = res.data.type;
@ -279,6 +292,7 @@ const toPreview = () => {
previewData.total = res.data.count;
} else {
previewData.chartCfg = res.data.config;
previewData.filter = res.data.filter;
}
})
.finally(() => {
@ -357,6 +371,12 @@ const toFilt = () => {
font-size: 100px;
}
}
.y-table-name {
.title {
font-size: 18px;
font-weight: bold;
}
}
.y-table-filter {
display: flex;
flex-wrap: wrap;

View File

@ -73,16 +73,18 @@
<div class="right-box">
<y-table
v-if="selectViewInfo.type === 'table'"
:filterConfig="selectViewInfo.filter"
:dataList="selectViewInfo.data"
:columnConfig="selectViewInfo.header"
:filter-config="selectViewInfo.filter"
:data-list="selectViewInfo.data"
:column-config="selectViewInfo.header"
:total="selectViewInfo.count"
:title="selectViewInfo.preview_name"
@toFilt="
(params) => {
toGetViewInfo(params);
}
"
/>
<y-chart v-else-if="selectViewInfo.type === 'chart'" :chartCfg="selectViewInfo.config" :title="selectViewInfo.preview_name" :filter-config="selectViewInfo.filter" @toFilt="toGetViewInfo" />
<div class="preview-area" v-else>
<div><BarChartOutlined /></div>
<div>展示区</div>
@ -109,6 +111,11 @@ const selectedRowId = ref();
const selectViewInfo = ref({
type: "",
filter: [],
config: {
line: {
data: []
}
}
});
const pageState = reactive({
@ -144,6 +151,9 @@ const toGetViewInfo = (params = {}) => {
...params,
}).then((res) => {
selectViewInfo.value = res.data;
delete selectViewInfo.value.config.line.isGroup
delete selectViewInfo.value.config.line.label
selectViewInfo.value.config.line.data = res.data.config.line.data
});
};
@ -182,6 +192,7 @@ const toDelete = (previewId) => {
padding: 10px;
flex-shrink: 0;
border-right: 1px solid #ddd;
overflow: auto;
}
:deep(.ant-table-row:hover) {