Merge branch 'feature/new-sys' into 'release'
feat: 新增图表渲染 See merge request workbench/y-code!3
This commit is contained in:
@@ -12,7 +12,7 @@ module.exports = {
|
|||||||
ecmaVersion: 'latest',
|
ecmaVersion: 'latest',
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
semi: 2,
|
semi: 0,
|
||||||
'vue/multi-word-component-names': 0,
|
'vue/multi-word-component-names': 0,
|
||||||
indent: [
|
indent: [
|
||||||
2, 2, {
|
2, 2, {
|
||||||
|
|||||||
4
components.d.ts
vendored
4
components.d.ts
vendored
@@ -25,6 +25,9 @@ declare module 'vue' {
|
|||||||
AModal: typeof import('ant-design-vue/es')['Modal']
|
AModal: typeof import('ant-design-vue/es')['Modal']
|
||||||
APagination: typeof import('ant-design-vue/es')['Pagination']
|
APagination: typeof import('ant-design-vue/es')['Pagination']
|
||||||
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
|
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
|
||||||
|
ARadio: typeof import('ant-design-vue/es')['Radio']
|
||||||
|
ARadioButton: typeof import('ant-design-vue/es')['RadioButton']
|
||||||
|
ARadioGroup: typeof import('ant-design-vue/es')['RadioGroup']
|
||||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||||
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
||||||
ASpace: typeof import('ant-design-vue/es')['Space']
|
ASpace: typeof import('ant-design-vue/es')['Space']
|
||||||
@@ -33,6 +36,7 @@ declare module 'vue' {
|
|||||||
RouterLink: typeof import('vue-router')['RouterLink']
|
RouterLink: typeof import('vue-router')['RouterLink']
|
||||||
RouterView: typeof import('vue-router')['RouterView']
|
RouterView: typeof import('vue-router')['RouterView']
|
||||||
Table: typeof import('./src/components/common/table.vue')['default']
|
Table: typeof import('./src/components/common/table.vue')['default']
|
||||||
|
YChart: typeof import('./src/components/common/y-chart.vue')['default']
|
||||||
YTable: typeof import('./src/components/common/y-table.vue')['default']
|
YTable: typeof import('./src/components/common/y-table.vue')['default']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
3212
package-lock.json
generated
3212
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -6,14 +6,16 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --mode staging",
|
"dev": "vite --mode staging",
|
||||||
"build:pre": "vite build --mode staging",
|
"build:pre": "vite build --mode staging",
|
||||||
"build": "vite build --mode production",
|
"build:pro": "vite build --mode production",
|
||||||
"type-check": "vue-tsc --build --force",
|
"type-check": "vue-tsc --build --force",
|
||||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
|
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@antv/g2plot": "^2.4.31",
|
||||||
"@vueuse/core": "^10.11.0",
|
"@vueuse/core": "^10.11.0",
|
||||||
"ant-design-vue": "^4.1.2",
|
"ant-design-vue": "^4.1.2",
|
||||||
"axios": "^1.6.7",
|
"axios": "^1.6.7",
|
||||||
|
"lodash": "^4.17.21",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"vue": "^3.4.15",
|
"vue": "^3.4.15",
|
||||||
"vue-router": "^4.2.5"
|
"vue-router": "^4.2.5"
|
||||||
@@ -35,4 +37,4 @@
|
|||||||
"vite": "^5.0.11",
|
"vite": "^5.0.11",
|
||||||
"vue-tsc": "^1.8.27"
|
"vue-tsc": "^1.8.27"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
39
src/components/common/y-chart.vue
Normal file
39
src/components/common/y-chart.vue
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
<template>
|
||||||
|
<div class="chart-show-box">
|
||||||
|
<div class="switch-type">
|
||||||
|
<a-radio-group v-model:value="chartType">
|
||||||
|
<a-radio-button value="line">折线图</a-radio-button>
|
||||||
|
<a-radio-button value="bar">柱状图</a-radio-button>
|
||||||
|
</a-radio-group>
|
||||||
|
</div>
|
||||||
|
<div class="chart-wrap">
|
||||||
|
<Column v-if="chartType === 'bar'" :config="currentChart" />
|
||||||
|
<Line v-if="chartType === 'line'" :config="currentChart" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from "vue";
|
||||||
|
import Line from "@/plugins/antv-g2plot/line.vue";
|
||||||
|
import Column from "@/plugins/antv-g2plot/column.vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
chartCfg: {
|
||||||
|
type: Array,
|
||||||
|
default: () => [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const chartType = ref("line");
|
||||||
|
|
||||||
|
const currentChart = computed(() => {
|
||||||
|
return props.chartCfg[chartType.value];
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.chart-wrap {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
v-if="item.type === 'select'"
|
v-if="item.type === 'select'"
|
||||||
class="input-item"
|
class="input-item"
|
||||||
:options="item.options"
|
:options="item.options"
|
||||||
|
allow-clear
|
||||||
v-model:value="filterData[item.name]"
|
v-model:value="filterData[item.name]"
|
||||||
@change="toFilt"
|
@change="toFilt"
|
||||||
></a-select>
|
></a-select>
|
||||||
@@ -18,6 +19,7 @@
|
|||||||
v-if="item.type === 'text'"
|
v-if="item.type === 'text'"
|
||||||
class="input-item"
|
class="input-item"
|
||||||
placeholder="请输入"
|
placeholder="请输入"
|
||||||
|
allow-clear
|
||||||
v-model:value="filterData[item.name]"
|
v-model:value="filterData[item.name]"
|
||||||
@change="toFilt"
|
@change="toFilt"
|
||||||
/>
|
/>
|
||||||
@@ -28,6 +30,7 @@
|
|||||||
:columns="columnConfig"
|
:columns="columnConfig"
|
||||||
:data-source="dataList"
|
:data-source="dataList"
|
||||||
:pagination="false"
|
:pagination="false"
|
||||||
|
:scroll="{ x: 1000, y: `calc(100vh - 260px)` }"
|
||||||
size="small"
|
size="small"
|
||||||
bordered
|
bordered
|
||||||
></a-table>
|
></a-table>
|
||||||
@@ -47,6 +50,7 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { reactive, ref, watch } from "vue";
|
import { reactive, ref, watch } from "vue";
|
||||||
import { useDebounceFn } from "@vueuse/core";
|
import { useDebounceFn } from "@vueuse/core";
|
||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
filterConfig: {
|
filterConfig: {
|
||||||
@@ -69,9 +73,6 @@ const props = defineProps({
|
|||||||
const emit = defineEmits(["handleFilt"]);
|
const emit = defineEmits(["handleFilt"]);
|
||||||
|
|
||||||
const filterData = ref({});
|
const filterData = ref({});
|
||||||
// const filterConfig = ref([]);
|
|
||||||
// const columnConfig = ref([]);
|
|
||||||
// const dataList = ref([]);
|
|
||||||
|
|
||||||
const pageState = reactive({
|
const pageState = reactive({
|
||||||
page: 1,
|
page: 1,
|
||||||
@@ -81,26 +82,28 @@ const pageState = reactive({
|
|||||||
watch(
|
watch(
|
||||||
() => props.filterConfig,
|
() => props.filterConfig,
|
||||||
(newVal) => {
|
(newVal) => {
|
||||||
console.log("newVal", newVal);
|
|
||||||
|
|
||||||
newVal.forEach((item) => {
|
newVal.forEach((item) => {
|
||||||
filterData.value[item.name] = undefined;
|
filterData.value[item.name] = undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let i = 0; i < newVal.length; i++) {
|
|
||||||
console.log(
|
|
||||||
"props.filterConfig",
|
|
||||||
newVal[i].label,
|
|
||||||
newVal[i].name,
|
|
||||||
newVal[i].type
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const getData = () => {
|
const getData = () => {
|
||||||
|
const cloneFilter = _.cloneDeep(props.filterConfig);
|
||||||
|
const filter = cloneFilter
|
||||||
|
.filter((item) => {
|
||||||
|
return filterData.value[item.name] !== undefined;
|
||||||
|
})
|
||||||
|
.map((item) => {
|
||||||
|
return {
|
||||||
|
name: item.name,
|
||||||
|
type: item.type,
|
||||||
|
value: filterData.value[item.name],
|
||||||
|
};
|
||||||
|
});
|
||||||
emit("toFilt", {
|
emit("toFilt", {
|
||||||
filter: filterData.value,
|
filter,
|
||||||
page: pageState.page,
|
page: pageState.page,
|
||||||
perPage: pageState.perPage,
|
perPage: pageState.perPage,
|
||||||
});
|
});
|
||||||
@@ -123,6 +126,7 @@ const pageChange = () => {
|
|||||||
.filter-item {
|
.filter-item {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
.input-item {
|
.input-item {
|
||||||
width: 180px;
|
width: 180px;
|
||||||
|
|||||||
26
src/plugins/antv-g2plot/column.vue
Normal file
26
src/plugins/antv-g2plot/column.vue
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="className" :style="style" ref="container"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { Column } from "@antv/g2plot";
|
||||||
|
// hooks
|
||||||
|
import useChart from "./useChart";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
className: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { container } = useChart(Column, props.config);
|
||||||
|
</script>
|
||||||
26
src/plugins/antv-g2plot/line.vue
Normal file
26
src/plugins/antv-g2plot/line.vue
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="className" :style="style" ref="container"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { Line } from "@antv/g2plot";
|
||||||
|
// hooks
|
||||||
|
import useChart from "./useChart";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
className: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { container } = useChart(Line, props.config);
|
||||||
|
</script>
|
||||||
26
src/plugins/antv-g2plot/pie.vue
Normal file
26
src/plugins/antv-g2plot/pie.vue
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="className" :style="style" ref="container"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { Pie } from "@antv/g2plot";
|
||||||
|
// hooks
|
||||||
|
import useChart from "./useChart";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
className: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({}),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { container } = useChart(Pie, props.config);
|
||||||
|
</script>
|
||||||
91
src/plugins/antv-g2plot/useChart.js
Normal file
91
src/plugins/antv-g2plot/useChart.js
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import { onBeforeUnmount, onMounted, ref, watch } from "vue";
|
||||||
|
import _ from "lodash";
|
||||||
|
|
||||||
|
export default function useChart(ChartClass, config) {
|
||||||
|
const chart = ref(null); // 表格实例
|
||||||
|
const chartOptions = ref(null); // 图表配置
|
||||||
|
const container = ref(null); // 渲染图表元素
|
||||||
|
const { onReady, onEvent } = config;
|
||||||
|
|
||||||
|
// 全局事件侦听器
|
||||||
|
let handler;
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
chartOptions.value = _.cloneDeep(config);
|
||||||
|
|
||||||
|
// 实例化图表
|
||||||
|
const chartInstance = new ChartClass(container.value, { ...config });
|
||||||
|
chartInstance.toDataURL = (type, encoderOptions) => {
|
||||||
|
return toDataURL(type, encoderOptions);
|
||||||
|
};
|
||||||
|
chartInstance.downloadImage = (name, type, encoderOptions) => {
|
||||||
|
return downloadImage(name, type, encoderOptions);
|
||||||
|
};
|
||||||
|
chartInstance.render(); // 渲染图表
|
||||||
|
|
||||||
|
chart.value = chartInstance;
|
||||||
|
|
||||||
|
// 图表渲染完成回调
|
||||||
|
if (onReady) {
|
||||||
|
onReady(chartInstance);
|
||||||
|
}
|
||||||
|
// 侦听全局事件
|
||||||
|
handler = (event) => {
|
||||||
|
if (onEvent) {
|
||||||
|
onEvent(chartInstance, event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
chartInstance.on("*", handler);
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
chart.value.destroy();
|
||||||
|
chart.value.off("*", handler);
|
||||||
|
chart.value = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 配置更改时更新图表
|
||||||
|
watch(
|
||||||
|
() => config,
|
||||||
|
(config) => {
|
||||||
|
const newConfig = _.cloneDeep(config);
|
||||||
|
chartOptions.value = newConfig;
|
||||||
|
chart.value.update(newConfig);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const toDataURL = (type = "image/png", encoderOptions) => {
|
||||||
|
return chart.value?.chart.canvas.cfg.el.toDataURL(type, encoderOptions);
|
||||||
|
};
|
||||||
|
|
||||||
|
const downloadImage = (
|
||||||
|
name = "download",
|
||||||
|
type = "image/png",
|
||||||
|
encoderOptions
|
||||||
|
) => {
|
||||||
|
let imageName = name;
|
||||||
|
if (name.indexOf(".") === -1) {
|
||||||
|
imageName = `${name}.${type.split("/")[1]}`;
|
||||||
|
}
|
||||||
|
const base64 = chart.value?.chart.canvas.cfg.el.toDataURL(
|
||||||
|
type,
|
||||||
|
encoderOptions
|
||||||
|
);
|
||||||
|
let a = document.createElement("a");
|
||||||
|
a.href = base64;
|
||||||
|
a.download = imageName;
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
a = null;
|
||||||
|
return imageName;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
chart,
|
||||||
|
container,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -74,7 +74,7 @@ const routeList: RouteType[] = [
|
|||||||
path: 'create-view',
|
path: 'create-view',
|
||||||
name: 'create-view',
|
name: 'create-view',
|
||||||
component: () => import('@/views/view-all-manage/create-view/index.vue'),
|
component: () => import('@/views/view-all-manage/create-view/index.vue'),
|
||||||
meta: { title: '创建' },
|
meta: { title: '创建视图' },
|
||||||
isMenu: true,
|
isMenu: true,
|
||||||
children: [],
|
children: [],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,9 +14,9 @@
|
|||||||
:options="projectSelect"
|
:options="projectSelect"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="数据表名称" name="modular_name">
|
<a-form-item label="数据来源" name="modular_name">
|
||||||
<a-input
|
<a-input
|
||||||
placeholder="请输入数据表名称"
|
placeholder="请输入数据来源"
|
||||||
v-model:value="formData.modular_name"
|
v-model:value="formData.modular_name"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
@@ -27,26 +27,48 @@
|
|||||||
:unCheckedValue="0"
|
:unCheckedValue="0"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="展示类型" name="show_type_id">
|
<a-form-item label="数据源类型" name="original_type">
|
||||||
<a-select
|
<a-radio-group v-model:value="formData.original_type">
|
||||||
placeholder="请选择展示类型"
|
<a-radio :value="1">自定义</a-radio>
|
||||||
v-model:value="formData.show_type_id"
|
<a-radio :value="2">指定表</a-radio>
|
||||||
:options="showTypes"
|
</a-radio-group>
|
||||||
/>
|
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="sql数据源" name="original_sql">
|
<a-form-item
|
||||||
|
v-if="formData.original_type === 1"
|
||||||
|
label="sql数据源"
|
||||||
|
name="original_sql"
|
||||||
|
>
|
||||||
<a-input
|
<a-input
|
||||||
placeholder="请输入sql数据源"
|
placeholder="请输入sql数据源"
|
||||||
v-model:value="formData.original_sql"
|
v-model:value="formData.original_sql"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item
|
||||||
|
v-if="formData.original_type === 2"
|
||||||
|
label="数据表"
|
||||||
|
name="table"
|
||||||
|
>
|
||||||
|
<a-select
|
||||||
|
placeholder="请选择数据表"
|
||||||
|
v-model:value="formData.table"
|
||||||
|
:options="tableTypes"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<!-- <a-form-item label="展示类型" name="show_type_id">
|
||||||
|
<a-select
|
||||||
|
placeholder="请选择展示类型"
|
||||||
|
v-model:value="formData.show_type_id"
|
||||||
|
:options="showTypes"
|
||||||
|
/>
|
||||||
|
</a-form-item> -->
|
||||||
</a-form>
|
</a-form>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, watch } from "vue";
|
import { onMounted, ref, watch } from "vue";
|
||||||
import { getShowTypeSelect } from "@/views/config-manage/module-cfg/service";
|
import { getDbTableSelect } from "@/views/config-manage/module-cfg/service";
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
open: {
|
open: {
|
||||||
@@ -70,20 +92,24 @@ const props = defineProps({
|
|||||||
const emit = defineEmits(["ok"]);
|
const emit = defineEmits(["ok"]);
|
||||||
const formRules = ref({
|
const formRules = ref({
|
||||||
modular_name: [
|
modular_name: [
|
||||||
{ required: true, message: "请输入数据表名称", trigger: "submit" },
|
{ required: true, message: "请输入数据来源", trigger: "submit" },
|
||||||
],
|
],
|
||||||
show_type_id: [{ required: true, message: "请选择", trigger: "submit" }],
|
// show_type_id: [{ required: true, message: "请选择", trigger: "submit" }],
|
||||||
|
original_type: [{ required: true, message: "请选择", trigger: "submit" }],
|
||||||
original_sql: [{ required: true, message: "请输入", trigger: "submit" }],
|
original_sql: [{ required: true, message: "请输入", trigger: "submit" }],
|
||||||
|
table: [{ required: true, message: "请选择", trigger: "submit" }],
|
||||||
});
|
});
|
||||||
|
|
||||||
const showTypes = ref([]);
|
const tableTypes = ref([]);
|
||||||
const formRef = ref();
|
const formRef = ref();
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
project_id: undefined,
|
project_id: undefined,
|
||||||
modular_name: undefined,
|
modular_name: undefined,
|
||||||
is_show: 0,
|
is_show: 0,
|
||||||
show_type_id: undefined,
|
original_type: 1, // 1 - 自定义,2 - 指定表
|
||||||
|
// show_type_id: undefined,
|
||||||
original_sql: undefined,
|
original_sql: undefined,
|
||||||
|
table: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
@@ -97,20 +123,21 @@ watch(
|
|||||||
project_id: newVal.project_id,
|
project_id: newVal.project_id,
|
||||||
modular_name: newVal.modular_name,
|
modular_name: newVal.modular_name,
|
||||||
is_show: newVal.is_show,
|
is_show: newVal.is_show,
|
||||||
show_type_id: newVal.show_type_id,
|
// show_type_id: newVal.show_type_id,
|
||||||
original_sql: newVal.original_sql,
|
original_sql: newVal.original_sql,
|
||||||
|
table: newVal.table,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
toGetShowType();
|
toGetDbTable();
|
||||||
});
|
});
|
||||||
|
|
||||||
const toGetShowType = () => {
|
const toGetDbTable = () => {
|
||||||
getShowTypeSelect().then((res) => {
|
getDbTableSelect().then((res) => {
|
||||||
showTypes.value = res.data;
|
tableTypes.value = res.data;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -119,8 +146,10 @@ const resetFormData = () => {
|
|||||||
project_id: undefined,
|
project_id: undefined,
|
||||||
modular_name: undefined,
|
modular_name: undefined,
|
||||||
is_show: 0,
|
is_show: 0,
|
||||||
show_type_id: undefined,
|
original_type: 1, // 1 - 自定义,2 - 指定表
|
||||||
|
// show_type_id: undefined,
|
||||||
original_sql: undefined,
|
original_sql: undefined,
|
||||||
|
table: undefined,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -200,6 +200,7 @@ const handleCancel = (record) => {
|
|||||||
|
|
||||||
const handleSave = (record) => {
|
const handleSave = (record) => {
|
||||||
const params = {
|
const params = {
|
||||||
|
field_id: record.field_id,
|
||||||
field_title: record.field_title,
|
field_title: record.field_title,
|
||||||
field_name: record.field_name,
|
field_name: record.field_name,
|
||||||
is_search: record.is_search,
|
is_search: record.is_search,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ export const moduleCfgCols = [
|
|||||||
{ dataIndex: 'modular_name', title: '数据表名称', align: 'center'},
|
{ dataIndex: 'modular_name', title: '数据表名称', align: 'center'},
|
||||||
{ dataIndex: 'project_name', title: '项目名称', align: 'center'},
|
{ dataIndex: 'project_name', title: '项目名称', align: 'center'},
|
||||||
{ dataIndex: 'is_show', title: '展示状态', align: 'center'},
|
{ dataIndex: 'is_show', title: '展示状态', align: 'center'},
|
||||||
{ dataIndex: 'show_type_handle', title: '展示类型', align: 'center'},
|
{ dataIndex: 'original_type_handle', title: '数据源类型', align: 'center'},
|
||||||
// { dataIndex: 'sort', title: '排序', align: 'center'},
|
// { dataIndex: 'sort', title: '排序', align: 'center'},
|
||||||
{ dataIndex: 'action', title: '操作', align: 'center'},
|
{ dataIndex: 'action', title: '操作', align: 'center'},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -54,10 +54,10 @@ export function getProjectSelect() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 展示类型下拉
|
// 数据源表下拉
|
||||||
export function getShowTypeSelect() {
|
export function getDbTableSelect() {
|
||||||
return get({
|
return get({
|
||||||
url: `/api/v1/modular/get-show-type-drop`,
|
url: `/api/v1/modular/get-database-table-drop`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
v-model:value="formData.project_name"
|
v-model:value="formData.project_name"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<a-form-item label="项目标识" name="mark">
|
||||||
|
<a-input placeholder="请输入项目标识,例如:oa" />
|
||||||
|
</a-form-item>
|
||||||
<a-form-item label="展示状态" name="is_show">
|
<a-form-item label="展示状态" name="is_show">
|
||||||
<a-switch
|
<a-switch
|
||||||
v-model:checked="formData.is_show"
|
v-model:checked="formData.is_show"
|
||||||
@@ -85,6 +88,7 @@ const formRules = {
|
|||||||
project_name: [
|
project_name: [
|
||||||
{ required: true, message: "请输入项目名称", trigger: "submit" },
|
{ required: true, message: "请输入项目名称", trigger: "submit" },
|
||||||
],
|
],
|
||||||
|
mark: [{ required: true, message: "请输入项目标识", trigger: "submit" }],
|
||||||
database_address: [
|
database_address: [
|
||||||
{ required: true, message: "请输入数据库地址", trigger: "submit" },
|
{ required: true, message: "请输入数据库地址", trigger: "submit" },
|
||||||
],
|
],
|
||||||
@@ -105,6 +109,7 @@ const formRules = {
|
|||||||
const formRef = ref();
|
const formRef = ref();
|
||||||
const formData = ref({
|
const formData = ref({
|
||||||
project_name: undefined,
|
project_name: undefined,
|
||||||
|
mark: undefined,
|
||||||
is_show: 0,
|
is_show: 0,
|
||||||
database_address: undefined,
|
database_address: undefined,
|
||||||
database_port: undefined,
|
database_port: undefined,
|
||||||
@@ -159,6 +164,7 @@ const validateConnect = () => {
|
|||||||
const resetFormData = () => {
|
const resetFormData = () => {
|
||||||
formData.value = {
|
formData.value = {
|
||||||
project_name: undefined,
|
project_name: undefined,
|
||||||
|
mark: undefined,
|
||||||
is_show: 0,
|
is_show: 0,
|
||||||
database_address: undefined,
|
database_address: undefined,
|
||||||
database_port: undefined,
|
database_port: undefined,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
export const projectCfgCols = [
|
export const projectCfgCols = [
|
||||||
{ dataIndex: 'project_id', title: '编号', align: 'center'},
|
{ dataIndex: 'project_id', title: '编号', align: 'center'},
|
||||||
{ dataIndex: 'project_name', title: '项目名称', align: 'center'},
|
{ dataIndex: 'project_name', title: '项目名称', align: 'center'},
|
||||||
|
{ dataIndex: 'mark', title: '项目标识', align: 'center'},
|
||||||
{ dataIndex: 'database_name', title: '数据库名', align: 'center'},
|
{ dataIndex: 'database_name', title: '数据库名', align: 'center'},
|
||||||
{ dataIndex: 'is_show', title: '展示状态', align: 'center'},
|
{ dataIndex: 'is_show', title: '展示状态', align: 'center'},
|
||||||
// { dataIndex: 'sort', title: '排序', align: 'center'},
|
// { dataIndex: 'sort', title: '排序', align: 'center'},
|
||||||
|
|||||||
@@ -2,16 +2,16 @@
|
|||||||
<div class="normal-container">
|
<div class="normal-container">
|
||||||
<div class="view-create-box">
|
<div class="view-create-box">
|
||||||
<div class="left-box">
|
<div class="left-box">
|
||||||
<a-form :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
|
<a-form :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
|
||||||
<a-form-item label="项目"
|
<a-form-item label="项目"
|
||||||
><a-select
|
><a-select
|
||||||
placeholder="请选择项目"
|
placeholder="请选择项目"
|
||||||
:options="projectSel"
|
:options="projectSel"
|
||||||
v-model:value="projectId"
|
v-model:value="projectId"
|
||||||
@change="onProjectChange"
|
@change="onProjectChange"
|
||||||
></a-select
|
></a-select
|
||||||
></a-form-item>
|
></a-form-item>
|
||||||
<a-form-item label="数据表">
|
<a-form-item label="数据来源">
|
||||||
<a-select
|
<a-select
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
:options="modularSel"
|
:options="modularSel"
|
||||||
@@ -19,16 +19,29 @@
|
|||||||
@change="onModularChange"
|
@change="onModularChange"
|
||||||
></a-select>
|
></a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="字段">
|
<a-form-item label="展示类型">
|
||||||
<a-checkbox-group v-if="fieldList.length" v-model:value="fieldIds">
|
<a-select
|
||||||
|
placeholder="请选择展示类型"
|
||||||
|
:options="showTypeSel"
|
||||||
|
v-model:value="showTypeId"
|
||||||
|
@change="onShowTypeChange"
|
||||||
|
></a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="字段" v-if="fieldList.length">
|
||||||
|
<a-checkbox-group v-model:value="fieldIds">
|
||||||
<a-checkbox
|
<a-checkbox
|
||||||
v-for="(item, index) in fieldList"
|
v-for="(item, index) in fieldList"
|
||||||
:key="index"
|
:key="index"
|
||||||
:value="item.value"
|
:value="item.value"
|
||||||
>{{ item.label }}</a-checkbox
|
>{{ item.label }}</a-checkbox
|
||||||
>
|
>
|
||||||
</a-checkbox-group>
|
</a-checkbox-group>
|
||||||
<a-empty v-else description="暂无字段数据" />
|
</a-form-item>
|
||||||
|
<a-form-item label="x轴" v-if="xDataList.length">
|
||||||
|
<a-radio-group :options="xDataList" v-model:value="xDataId"></a-radio-group>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="y轴" v-if="yDataList.length">
|
||||||
|
<a-checkbox-group :options="yDataList" v-model:value="yDataId"></a-checkbox-group>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
@@ -36,7 +49,7 @@
|
|||||||
class="preview-btn"
|
class="preview-btn"
|
||||||
:loading="previewLoading"
|
:loading="previewLoading"
|
||||||
@click="toPreview"
|
@click="toPreview"
|
||||||
>预览</a-button
|
>预览</a-button
|
||||||
>
|
>
|
||||||
<a-button type="primary" @click="addViewName">点击保存</a-button>
|
<a-button type="primary" @click="addViewName">点击保存</a-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -56,18 +69,16 @@
|
|||||||
:options="item.options"
|
:options="item.options"
|
||||||
v-model:value="previewData.filterData[item.name]"
|
v-model:value="previewData.filterData[item.name]"
|
||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
|
allow-clear
|
||||||
@change="toFilt"
|
@change="toFilt"
|
||||||
></a-select>
|
></a-select>
|
||||||
<a-input
|
<a-input
|
||||||
v-else
|
v-if="item.type === 'text'"
|
||||||
class="input-item"
|
class="input-item"
|
||||||
placeholder="请输入"
|
placeholder="请输入"
|
||||||
|
allow-clear
|
||||||
v-model:value="previewData.filterData[item.name]"
|
v-model:value="previewData.filterData[item.name]"
|
||||||
@change="
|
@change="toFilt"
|
||||||
(e) => {
|
|
||||||
toFilt(item.name, e.target.value);
|
|
||||||
}
|
|
||||||
"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -76,6 +87,7 @@
|
|||||||
:columns="previewData.columnConfig"
|
:columns="previewData.columnConfig"
|
||||||
:data-source="previewData.dataList"
|
:data-source="previewData.dataList"
|
||||||
:pagination="false"
|
:pagination="false"
|
||||||
|
:scroll="{ x: 1000, y: `calc(100vh - 260px)` }"
|
||||||
size="small"
|
size="small"
|
||||||
bordered
|
bordered
|
||||||
></a-table>
|
></a-table>
|
||||||
@@ -90,6 +102,11 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<y-chart v-if="previewData.type === 'chart'" :chartCfg="previewData.chartCfg"></y-chart>
|
||||||
|
<div class="preview-area" v-else>
|
||||||
|
<div><BarChartOutlined /></div>
|
||||||
|
<div>预览区</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a-modal
|
<a-modal
|
||||||
:open="nameVisible"
|
:open="nameVisible"
|
||||||
@@ -110,15 +127,29 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, reactive, ref } from "vue";
|
import { onMounted, reactive, ref } from "vue";
|
||||||
import { getProModularField, preview, saveView } from "./service";
|
import {
|
||||||
|
getProModularField,
|
||||||
|
preview,
|
||||||
|
saveView,
|
||||||
|
getShowTypeSelect,
|
||||||
|
getFieldOpts,
|
||||||
|
} from "./service";
|
||||||
import { message } from "ant-design-vue";
|
import { message } from "ant-design-vue";
|
||||||
|
import { BarChartOutlined } from "@ant-design/icons-vue";
|
||||||
|
import yChart from "@/components/common/y-chart.vue";
|
||||||
|
|
||||||
const projectSel = ref([]);
|
const projectSel = ref([]); // 项目下拉
|
||||||
const modularSel = ref([]);
|
const modularSel = ref([]) // 数据来源下拉
|
||||||
const fieldList = ref([]);
|
const showTypeSel = ref([]); // 展示类型下拉
|
||||||
|
const fieldList = ref([]); // 字段列表
|
||||||
|
const xDataList = ref([]); // x轴数据列表
|
||||||
|
const yDataList = ref([]); // y轴数据列表
|
||||||
const projectId = ref();
|
const projectId = ref();
|
||||||
const modularId = ref();
|
const modularId = ref();
|
||||||
|
const showTypeId = ref();
|
||||||
const fieldIds = ref([]);
|
const fieldIds = ref([]);
|
||||||
|
const xDataId = ref();
|
||||||
|
const yDataId = ref();
|
||||||
|
|
||||||
const previewLoading = ref(false);
|
const previewLoading = ref(false);
|
||||||
const nameVisible = ref(false);
|
const nameVisible = ref(false);
|
||||||
@@ -130,6 +161,7 @@ const previewData = reactive({
|
|||||||
columnConfig: [], // 表格表头
|
columnConfig: [], // 表格表头
|
||||||
dataList: [], // 表格数据
|
dataList: [], // 表格数据
|
||||||
filterData: {},
|
filterData: {},
|
||||||
|
chartCfg: {},
|
||||||
page: 1,
|
page: 1,
|
||||||
perPage: 20,
|
perPage: 20,
|
||||||
total: 0,
|
total: 0,
|
||||||
@@ -137,6 +169,7 @@ const previewData = reactive({
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
toGetProModularField();
|
toGetProModularField();
|
||||||
|
toGetShowTypes();
|
||||||
});
|
});
|
||||||
|
|
||||||
const toGetProModularField = () => {
|
const toGetProModularField = () => {
|
||||||
@@ -145,34 +178,92 @@ const toGetProModularField = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取展示类型下拉
|
||||||
|
const toGetShowTypes = () => {
|
||||||
|
getShowTypeSelect().then((res) => {
|
||||||
|
showTypeSel.value = res.data;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 获取字段列表
|
||||||
|
const toGetFieldOpts = () => {
|
||||||
|
getFieldOpts({
|
||||||
|
modularId: modularId.value,
|
||||||
|
showTypeId: showTypeId.value,
|
||||||
|
}).then((res) => {
|
||||||
|
fieldList.value = res.data.list ? tranformList(res.data.list) : [];
|
||||||
|
xDataList.value = res.data.x_data ? tranformList(res.data.x_data) : [];
|
||||||
|
yDataList.value = res.data.y_data ? tranformList(res.data.y_data) : [];
|
||||||
|
if (!fieldList.value.length) {
|
||||||
|
fieldIds.value = [];
|
||||||
|
} else {
|
||||||
|
xDataId.value = undefined;
|
||||||
|
yDataId.value = [];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const onProjectChange = (val) => {
|
const onProjectChange = (val) => {
|
||||||
const target = projectSel.value.find((item) => item.value === val);
|
const target = projectSel.value.find((item) => item.value === val);
|
||||||
modularSel.value = target.child;
|
modularSel.value = target.child;
|
||||||
modularId.value = undefined;
|
modularId.value = undefined;
|
||||||
fieldList.value = [];
|
fieldList.value = [];
|
||||||
fieldIds.value = [];
|
fieldIds.value = [];
|
||||||
|
resetPreviewData();
|
||||||
};
|
};
|
||||||
|
|
||||||
const onModularChange = (val) => {
|
const onModularChange = (val) => {
|
||||||
const target = modularSel.value.find((item) => item.value === val);
|
// const target = modularSel.value.find((item) => item.value === val);
|
||||||
fieldList.value = target.child;
|
// fieldList.value = target.child;
|
||||||
|
resetPreviewData();
|
||||||
|
};
|
||||||
|
|
||||||
|
const onShowTypeChange = () => {
|
||||||
|
toGetFieldOpts();
|
||||||
|
};
|
||||||
|
|
||||||
|
const tranformList = (list) => {
|
||||||
|
return list.map((item) => {
|
||||||
|
return {
|
||||||
|
label: item.field_name,
|
||||||
|
value: item.field_id,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const resetPreviewData = () => {
|
||||||
|
previewData.type = "";
|
||||||
|
previewData.filterConfig = [];
|
||||||
|
previewData.columnConfig = [];
|
||||||
|
previewData.dataList = [];
|
||||||
|
previewData.filterData = {};
|
||||||
|
previewData.page = 1;
|
||||||
|
previewData.perPage = 20;
|
||||||
|
previewData.total = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const toPreview = () => {
|
const toPreview = () => {
|
||||||
previewLoading.value = true;
|
previewLoading.value = true;
|
||||||
const filter = previewData.filterConfig.map((item) => {
|
const filter = previewData.filterConfig
|
||||||
return {
|
.filter((item) => {
|
||||||
name: item.name,
|
return previewData.filterData[item.name] !== undefined;
|
||||||
type: item.type,
|
})
|
||||||
value: previewData.filterData[item.name],
|
.map((item) => {
|
||||||
};
|
return {
|
||||||
});
|
name: item.name,
|
||||||
|
type: item.type,
|
||||||
|
value: previewData.filterData[item.name],
|
||||||
|
};
|
||||||
|
});
|
||||||
preview({
|
preview({
|
||||||
modularId: modularId.value,
|
modularId: modularId.value,
|
||||||
fieldIds: fieldIds.value.toString(),
|
fieldIds: fieldIds.value.toString(),
|
||||||
page: previewData.page,
|
page: previewData.page,
|
||||||
perPage: previewData.perPage,
|
perPage: previewData.perPage,
|
||||||
filter,
|
filter,
|
||||||
|
showTypeId: showTypeId.value,
|
||||||
|
xDataId: xDataId.value.toString(),
|
||||||
|
yDataId: yDataId.value.toString(),
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
previewData.type = res.data.type;
|
previewData.type = res.data.type;
|
||||||
@@ -183,10 +274,11 @@ const toPreview = () => {
|
|||||||
? previewData.filterData[item.name]
|
? previewData.filterData[item.name]
|
||||||
: undefined;
|
: undefined;
|
||||||
});
|
});
|
||||||
console.log("filterData", previewData.filterData);
|
|
||||||
previewData.columnConfig = res.data.header;
|
previewData.columnConfig = res.data.header;
|
||||||
previewData.dataList = res.data.data;
|
previewData.dataList = res.data.data;
|
||||||
previewData.total = res.data.count;
|
previewData.total = res.data.count;
|
||||||
|
} else {
|
||||||
|
previewData.chartCfg = res.data.config;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
@@ -208,14 +300,16 @@ const toSaveView = () => {
|
|||||||
modularId: modularId.value,
|
modularId: modularId.value,
|
||||||
fieldIds: fieldIds.value.toString(),
|
fieldIds: fieldIds.value.toString(),
|
||||||
previewName: previewName.value,
|
previewName: previewName.value,
|
||||||
|
showTypeId: showTypeId.value,
|
||||||
|
xDataId: xDataId.value.toString(),
|
||||||
|
yDataId: yDataId.value.toString(),
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
message.success("保存成功");
|
message.success("保存成功,可前往视图列表查看");
|
||||||
nameVisible.value = false;
|
nameVisible.value = false;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const toFilt = (key, value) => {
|
const toFilt = () => {
|
||||||
previewData.filterData[key] = value;
|
|
||||||
previewData.page = 1;
|
previewData.page = 1;
|
||||||
toPreview();
|
toPreview();
|
||||||
};
|
};
|
||||||
@@ -224,13 +318,15 @@ const toFilt = (key, value) => {
|
|||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.normal-container {
|
.normal-container {
|
||||||
height: calc(100vh - 120px);
|
height: calc(100vh - 120px);
|
||||||
|
padding: 16px;
|
||||||
}
|
}
|
||||||
.view-create-box {
|
.view-create-box {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
.left-box {
|
.left-box {
|
||||||
width: 400px;
|
width: 320px;
|
||||||
|
flex-shrink: 0;
|
||||||
height: calc(100% - 20px);
|
height: calc(100% - 20px);
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
border-right: 1px solid #ddd;
|
border-right: 1px solid #ddd;
|
||||||
@@ -243,11 +339,24 @@ const toFilt = (key, value) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.right-box {
|
.right-box {
|
||||||
padding: 10px;
|
padding: 0 0 0 10px;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
.preview-area {
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #999;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
.anticon-bar-chart {
|
||||||
|
font-size: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
.y-table-filter {
|
.y-table-filter {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
@@ -255,6 +364,7 @@ const toFilt = (key, value) => {
|
|||||||
.filter-item {
|
.filter-item {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 6px;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
.input-item {
|
.input-item {
|
||||||
width: 180px;
|
width: 180px;
|
||||||
@@ -264,5 +374,6 @@ const toFilt = (key, value) => {
|
|||||||
}
|
}
|
||||||
.pagination-box {
|
.pagination-box {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -7,8 +7,26 @@ export function getProModularField() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 展示类型下拉
|
||||||
|
export function getShowTypeSelect() {
|
||||||
|
return get({
|
||||||
|
url: `/api/v1/modular/get-show-type-drop`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 字段列表
|
||||||
|
export function getFieldOpts({ modularId, showTypeId }) {
|
||||||
|
return get({
|
||||||
|
url: "/api/v1/preview/get-preview-field",
|
||||||
|
params: {
|
||||||
|
modular_id: modularId,
|
||||||
|
show_type_id: showTypeId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 预览
|
// 预览
|
||||||
export function preview({ modularId, fieldIds, page, perPage, filter }) {
|
export function preview({ modularId, fieldIds, page, perPage, filter, showTypeId, xDataId, yDataId }) {
|
||||||
return post({
|
return post({
|
||||||
url: "api/v1/preview/view",
|
url: "api/v1/preview/view",
|
||||||
data: {
|
data: {
|
||||||
@@ -17,18 +35,24 @@ export function preview({ modularId, fieldIds, page, perPage, filter }) {
|
|||||||
page,
|
page,
|
||||||
per_page: perPage,
|
per_page: perPage,
|
||||||
filter,
|
filter,
|
||||||
|
show_type_id: showTypeId,
|
||||||
|
x_data_id: xDataId,
|
||||||
|
y_data_id: yDataId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 点击保存
|
// 点击保存
|
||||||
export function saveView({ modularId, fieldIds, previewName }) {
|
export function saveView({ modularId, fieldIds, previewName, showTypeId, xDataId, yDataId }) {
|
||||||
return post({
|
return post({
|
||||||
url: "api/v1/preview/save",
|
url: "api/v1/preview/save",
|
||||||
data: {
|
data: {
|
||||||
modular_id: modularId,
|
modular_id: modularId,
|
||||||
field_ids: fieldIds,
|
field_ids: fieldIds,
|
||||||
preview_name: previewName,
|
preview_name: previewName,
|
||||||
|
show_type_id: showTypeId,
|
||||||
|
x_data_id: xDataId,
|
||||||
|
y_data_id: yDataId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="normal-container">
|
<div class="normal-container">
|
||||||
<div class="view-list-box">
|
<div class="view-list-box">
|
||||||
<div class="left-box">
|
<div class="left-box">
|
||||||
<a-form :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
|
<a-form :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
|
||||||
<a-form-item label="项目">
|
<a-form-item label="项目">
|
||||||
<a-select
|
<a-select
|
||||||
:options="projectSel"
|
:options="projectSel"
|
||||||
@@ -11,11 +11,11 @@
|
|||||||
@change="onProjectChange"
|
@change="onProjectChange"
|
||||||
></a-select>
|
></a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<a-form-item label="数据表">
|
<a-form-item label="数据来源">
|
||||||
<a-select
|
<a-select
|
||||||
:options="modularSel"
|
:options="modularSel"
|
||||||
v-model:value="modularId"
|
v-model:value="modularId"
|
||||||
placeholder="请选择数据表"
|
placeholder="请先选好项目再选择"
|
||||||
@change="onModularChange"
|
@change="onModularChange"
|
||||||
></a-select>
|
></a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
@@ -40,7 +40,26 @@
|
|||||||
"
|
"
|
||||||
size="small"
|
size="small"
|
||||||
bordered
|
bordered
|
||||||
></a-table>
|
>
|
||||||
|
<template #bodyCell="{ column, record }">
|
||||||
|
<template v-if="column.dataIndex === 'action'">
|
||||||
|
<a-popconfirm
|
||||||
|
title="确定删除?"
|
||||||
|
@confirm="toDelete(record.preview_id)"
|
||||||
|
>
|
||||||
|
<a-button
|
||||||
|
type="link"
|
||||||
|
@click="
|
||||||
|
(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>删除</a-button
|
||||||
|
>
|
||||||
|
</a-popconfirm>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
<a-pagination
|
<a-pagination
|
||||||
v-model:current="pageState.page"
|
v-model:current="pageState.page"
|
||||||
:total="pageState.total"
|
:total="pageState.total"
|
||||||
@@ -64,6 +83,10 @@
|
|||||||
}
|
}
|
||||||
"
|
"
|
||||||
/>
|
/>
|
||||||
|
<div class="preview-area" v-else>
|
||||||
|
<div><BarChartOutlined /></div>
|
||||||
|
<div>展示区</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -71,9 +94,11 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, ref, reactive } from "vue";
|
import { onMounted, ref, reactive } from "vue";
|
||||||
import { getProModular, getViewList, getViewInfo } from "./service";
|
import { getProModular, getViewList, getViewInfo, deleteView } from "./service";
|
||||||
import { viewListCols } from "./config";
|
import { viewListCols } from "./config";
|
||||||
import yTable from "@/components/common/y-table.vue";
|
import yTable from "@/components/common/y-table.vue";
|
||||||
|
import { message } from "ant-design-vue";
|
||||||
|
import { BarChartOutlined } from "@ant-design/icons-vue";
|
||||||
|
|
||||||
const projectSel = ref([]);
|
const projectSel = ref([]);
|
||||||
const modularSel = ref([]);
|
const modularSel = ref([]);
|
||||||
@@ -83,6 +108,7 @@ const dataList = ref([]);
|
|||||||
const selectedRowId = ref();
|
const selectedRowId = ref();
|
||||||
const selectViewInfo = ref({
|
const selectViewInfo = ref({
|
||||||
type: "",
|
type: "",
|
||||||
|
filter: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const pageState = reactive({
|
const pageState = reactive({
|
||||||
@@ -130,11 +156,19 @@ const onModularChange = () => {
|
|||||||
pageState.page = 1;
|
pageState.page = 1;
|
||||||
toGetList();
|
toGetList();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const toDelete = (previewId) => {
|
||||||
|
deleteView({ previewId }).then(() => {
|
||||||
|
message.success("删除成功");
|
||||||
|
toGetList();
|
||||||
|
});
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.normal-container {
|
.normal-container {
|
||||||
height: calc(100vh - 120px);
|
height: calc(100vh - 120px);
|
||||||
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.view-list-box {
|
.view-list-box {
|
||||||
@@ -143,14 +177,20 @@ const onModularChange = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.left-box {
|
.left-box {
|
||||||
width: 400px;
|
width: 320px;
|
||||||
height: calc(100% - 20px);
|
height: calc(100% - 20px);
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
flex-shrink: 0;
|
||||||
border-right: 1px solid #ddd;
|
border-right: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selected-row {
|
:deep(.ant-table-row:hover) {
|
||||||
background-color: beige;
|
cursor: pointer;
|
||||||
|
background-color: #e6f4ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.selected-row) {
|
||||||
|
background-color: #e6f4ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pagination-box {
|
.pagination-box {
|
||||||
@@ -158,8 +198,23 @@ const onModularChange = () => {
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
.right-box {
|
.right-box {
|
||||||
padding: 10px;
|
padding: 0 0 0 10px;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.preview-area {
|
||||||
|
background-color: #f6f6f6;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #999;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
.anticon-bar-chart {
|
||||||
|
font-size: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { get } from "@/utils/request";
|
import { get, post } from "@/utils/request";
|
||||||
|
|
||||||
// 联动下拉
|
// 联动下拉
|
||||||
export function getProModular() {
|
export function getProModular() {
|
||||||
@@ -24,15 +24,25 @@ export function getViewInfo({
|
|||||||
previewId,
|
previewId,
|
||||||
page = 1,
|
page = 1,
|
||||||
perPage = 20,
|
perPage = 20,
|
||||||
filter = {},
|
filter = [],
|
||||||
}) {
|
}) {
|
||||||
return get({
|
return post({
|
||||||
url: "/api/v1/preview/info",
|
url: "/api/v1/preview/info",
|
||||||
params: {
|
data: {
|
||||||
preview_id: previewId,
|
preview_id: previewId,
|
||||||
page,
|
page,
|
||||||
perPage: perPage,
|
per_page: perPage,
|
||||||
filter,
|
filter,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除视图
|
||||||
|
export function deleteView({ previewId }) {
|
||||||
|
return post({
|
||||||
|
url: "/api/v1/preview/del",
|
||||||
|
data: {
|
||||||
|
preview_id: previewId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user