Merge branch 'feature/new-sys' into 'master'
悦码项目首次上线 See merge request workbench/y-code!12
This commit is contained in:
commit
7247ee9c13
@ -4,3 +4,5 @@ VITE_NODE_ENV = pre
|
||||
VITE_OA_BASEURL = https://oa-pre.shiyue.com
|
||||
|
||||
VITE_YCODE_BASEURL = https://custom-chart-pre-api.shiyue.com
|
||||
|
||||
VITE_YCODE_BASEURL_FRONT = https://custom-chart.shiyue.com
|
||||
|
@ -3,3 +3,5 @@ VITE_NODE_ENV = prod
|
||||
VITE_OA_BASEURL = https://oa.shiyuegame.com
|
||||
|
||||
VITE_YCODE_BASEURL = https://custom-chart-api.shiyuegame.com
|
||||
|
||||
VITE_YCODE_BASEURL_FRONT = https://custom-chart.shiyuegame.com
|
||||
|
@ -3,3 +3,5 @@ VITE_NODE_ENV = pre
|
||||
VITE_OA_BASEURL = https://oa-pre.shiyue.com
|
||||
|
||||
VITE_YCODE_BASEURL = https://custom-chart-pre-api.shiyue.com
|
||||
|
||||
VITE_YCODE_BASEURL_FRONT = https://custom-chart.shiyue.com
|
||||
|
@ -12,7 +12,7 @@ module.exports = {
|
||||
ecmaVersion: 'latest',
|
||||
},
|
||||
rules: {
|
||||
semi: 2,
|
||||
semi: 0,
|
||||
'vue/multi-word-component-names': 0,
|
||||
indent: [
|
||||
2, 2, {
|
||||
|
10
components.d.ts
vendored
10
components.d.ts
vendored
@ -12,9 +12,9 @@ declare module 'vue' {
|
||||
AButton: typeof import('ant-design-vue/es')['Button']
|
||||
ACheckbox: typeof import('ant-design-vue/es')['Checkbox']
|
||||
ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup']
|
||||
ACol: typeof import('ant-design-vue/es')['Col']
|
||||
AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider']
|
||||
ADropdown: typeof import('ant-design-vue/es')['Dropdown']
|
||||
AEmpty: typeof import('ant-design-vue/es')['Empty']
|
||||
AFloatButton: typeof import('ant-design-vue/es')['FloatButton']
|
||||
AForm: typeof import('ant-design-vue/es')['Form']
|
||||
AFormItem: typeof import('ant-design-vue/es')['FormItem']
|
||||
@ -25,14 +25,18 @@ declare module 'vue' {
|
||||
AModal: typeof import('ant-design-vue/es')['Modal']
|
||||
APagination: typeof import('ant-design-vue/es')['Pagination']
|
||||
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']
|
||||
ARangePicker: typeof import('ant-design-vue/es')['RangePicker']
|
||||
ARow: typeof import('ant-design-vue/es')['Row']
|
||||
ASelect: typeof import('ant-design-vue/es')['Select']
|
||||
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
|
||||
ASpace: typeof import('ant-design-vue/es')['Space']
|
||||
ASpin: typeof import('ant-design-vue/es')['Spin']
|
||||
ASwitch: typeof import('ant-design-vue/es')['Switch']
|
||||
ATable: typeof import('ant-design-vue/es')['Table']
|
||||
RouterLink: typeof import('vue-router')['RouterLink']
|
||||
RouterView: typeof import('vue-router')['RouterView']
|
||||
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']
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
<title>悦码后台</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id="y-code-app"></div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
801
package-lock.json
generated
801
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
@ -4,7 +4,8 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --mode staging",
|
||||
"dev": "cross-env DEV_ENV=development vite --mode staging",
|
||||
"pro": "cross-env DEV_ENV=development vite --mode production",
|
||||
"build:pre": "vite build --mode staging",
|
||||
"build:pro": "vite build --mode production",
|
||||
"type-check": "vue-tsc --build --force",
|
||||
@ -15,10 +16,14 @@
|
||||
"@vueuse/core": "^10.11.0",
|
||||
"ant-design-vue": "^4.1.2",
|
||||
"axios": "^1.6.7",
|
||||
"cross-env": "^7.0.3",
|
||||
"lodash": "^4.17.21",
|
||||
"p-limit": "^6.1.0",
|
||||
"pinia": "^2.1.7",
|
||||
"vue": "^3.4.15",
|
||||
"vue-router": "^4.2.5"
|
||||
"vue-grid-layout": "^3.0.0-beta1",
|
||||
"vue-router": "^4.2.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.3.3",
|
||||
@ -35,6 +40,7 @@
|
||||
"typescript": "~5.3.0",
|
||||
"unplugin-vue-components": "^0.26.0",
|
||||
"vite": "^5.0.11",
|
||||
"vite-plugin-qiankun": "^1.0.15",
|
||||
"vue-tsc": "^1.8.27"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { get } from '@/utils/request';
|
||||
import { get } from "@/utils/request";
|
||||
|
||||
export interface UserInfoType {
|
||||
alias: string;
|
||||
@ -15,8 +15,20 @@ export interface UserInfoType {
|
||||
username: string;
|
||||
}
|
||||
|
||||
export const getUserInfo = () => get<UserInfoType>({
|
||||
url: '/api/home/grade',
|
||||
});
|
||||
interface DropListItem {
|
||||
label: string;
|
||||
value: string | number;
|
||||
mark: string;
|
||||
}
|
||||
|
||||
export const logout = () => get({ url: '/api/common/logout' });
|
||||
export const getUserInfo = () =>
|
||||
get<UserInfoType>({
|
||||
url: "/api/home/grade",
|
||||
});
|
||||
|
||||
export const logout = () => get({ url: "/api/common/logout" });
|
||||
|
||||
export const getProjectDrop = () =>
|
||||
get<DropListItem[]>({
|
||||
url: "/api/v1/project/get-project-drop",
|
||||
});
|
||||
|
@ -1,28 +0,0 @@
|
||||
import { get, post } from "@/utils/request";
|
||||
|
||||
// 预览
|
||||
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 searchInfo({ previewId, page, perPage, filter }) {
|
||||
return get({
|
||||
url: `/api/v1/preview/info`,
|
||||
params: {
|
||||
preview_id: previewId,
|
||||
page,
|
||||
per_page: perPage,
|
||||
filter,
|
||||
},
|
||||
});
|
||||
}
|
21
src/api/preview/index.ts
Normal file
21
src/api/preview/index.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { post } from "@/utils/request";
|
||||
|
||||
interface PreviewItemParams {
|
||||
previewId: string | number;
|
||||
filter?: string | [];
|
||||
page?: number;
|
||||
perPage?: number;
|
||||
}
|
||||
|
||||
// 查看视图
|
||||
export function searchInfo(data: PreviewItemParams) {
|
||||
return post({
|
||||
url: `/api/v1/preview/info`,
|
||||
data: {
|
||||
preview_id: data.previewId,
|
||||
filter: data.filter,
|
||||
page: data.page,
|
||||
per_page: data.perPage,
|
||||
},
|
||||
});
|
||||
}
|
@ -1,34 +1,120 @@
|
||||
<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>
|
||||
</a-radio-group>
|
||||
</div>
|
||||
<div class="chart-wrap">
|
||||
<Column v-if="chartType === 'bar'" />
|
||||
<Column v-if="chartType === 'bar'" :config="currentChart" />
|
||||
<Line v-if="chartType === 'line'" :config="currentChart" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { 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];
|
||||
})
|
||||
|
||||
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>
|
||||
|
@ -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,6 +34,7 @@
|
||||
:columns="columnConfig"
|
||||
:data-source="dataList"
|
||||
:pagination="false"
|
||||
:scroll="{ x: 1000, y: `calc(100vh - 280px)` }"
|
||||
size="small"
|
||||
bordered
|
||||
></a-table>
|
||||
@ -68,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({});
|
||||
|
||||
@ -78,25 +87,19 @@ const pageState = reactive({
|
||||
perPage: 20,
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.filterConfig,
|
||||
(newVal) => {
|
||||
console.log("newVal", newVal);
|
||||
|
||||
newVal.forEach((item) => {
|
||||
filterData.value[item.name] = undefined;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
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' && filterData.value[item.name] ? {
|
||||
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 +122,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;
|
||||
@ -126,14 +136,19 @@ const pageChange = () => {
|
||||
.filter-item {
|
||||
margin-right: 10px;
|
||||
margin-bottom: 6px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.input-item {
|
||||
width: 180px;
|
||||
}
|
||||
.date-item {
|
||||
width: 240px;
|
||||
}
|
||||
.y-table-content {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.pagination-box {
|
||||
text-align: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { useUserInfoStore } from "@/stores/useUserInfoStore";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import Header from "./components/Header.vue";
|
||||
import Sider from "./components/Sider.vue";
|
||||
import {
|
||||
@ -9,6 +9,11 @@ import {
|
||||
FullscreenExitOutlined,
|
||||
} from "@ant-design/icons-vue";
|
||||
import { useEventListener } from "@vueuse/core";
|
||||
import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
|
||||
|
||||
const __POWERED_BY_QIANKUN__ = computed(() => {
|
||||
return qiankunWindow.__POWERED_BY_QIANKUN__ || window.proxy?.__POWERED_BY_QIANKUN__
|
||||
})
|
||||
|
||||
// const userInfoStore = useUserInfoStore();
|
||||
const isCollapsed = ref(false);
|
||||
@ -34,7 +39,7 @@ const handleExitFullscreen = () => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="root">
|
||||
<section v-if="!__POWERED_BY_QIANKUN__" class="root">
|
||||
<section
|
||||
class="left-aside"
|
||||
:class="{ 'left-aside-collapsed': isCollapsed }"
|
||||
@ -68,6 +73,7 @@ const handleExitFullscreen = () => {
|
||||
</a-float-button>
|
||||
</section>
|
||||
</section>
|
||||
<router-view v-else />
|
||||
</template>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
61
src/main.ts
61
src/main.ts
@ -1,12 +1,55 @@
|
||||
import { createApp } from 'vue';
|
||||
import { createPinia } from 'pinia';
|
||||
import App from './App.vue';
|
||||
import router from './router';
|
||||
import './global.less';
|
||||
import { createApp } from "vue";
|
||||
import { createPinia } from "pinia";
|
||||
import App from "./App.vue";
|
||||
import { createProjectRouter } from './router'
|
||||
import "./global.less";
|
||||
import VueGridLayout from "vue-grid-layout"; // 引入layout
|
||||
import { renderWithQiankun, qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
|
||||
|
||||
const app = createApp(App);
|
||||
let app
|
||||
function render(props: Object = {}) {
|
||||
app = createApp(App);
|
||||
const router = createProjectRouter(props.base)
|
||||
app.use(router)
|
||||
app.use(VueGridLayout);
|
||||
app.use(createPinia())
|
||||
app.mount("#y-code-app")
|
||||
// const getContainer = () => {
|
||||
// props.container ? props.container.querySelector('#y-code-container') : document.getElementById('y-code-container')
|
||||
// }
|
||||
// const container = getContainer()
|
||||
// if (container) {
|
||||
// app.mount(container)
|
||||
// } else {
|
||||
// window.addEventListener("DOMContentLoaded", () => {
|
||||
// app.mount(getContainer())
|
||||
// })
|
||||
// }
|
||||
}
|
||||
|
||||
app.use(createPinia());
|
||||
app.use(router);
|
||||
const __POWERED_BY_QIANKUN__ = qiankunWindow.__POWERED_BY_QIANKUN__ || window.proxy?.__POWERED_BY_QIANKUN__
|
||||
|
||||
if (__POWERED_BY_QIANKUN__) {
|
||||
renderWithQiankun({
|
||||
bootstrap() {
|
||||
console.log('bootstrap')
|
||||
return Promise.resolve()
|
||||
},
|
||||
mount(props) {
|
||||
console.log('mount')
|
||||
render(props)
|
||||
return Promise.resolve()
|
||||
},
|
||||
unmount() {
|
||||
console.log('unmount')
|
||||
if (app) {
|
||||
app.unmount()
|
||||
}
|
||||
return Promise.resolve()
|
||||
},
|
||||
update() {},
|
||||
})
|
||||
} else {
|
||||
render()
|
||||
}
|
||||
|
||||
app.mount('#app');
|
||||
|
@ -22,5 +22,5 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const { container } = useChart(Column, props.config);
|
||||
const { container } = useChart(Column, props);
|
||||
</script>
|
||||
|
@ -3,6 +3,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
|
||||
import { Line } from "@antv/g2plot";
|
||||
// hooks
|
||||
import useChart from "./useChart";
|
||||
@ -22,5 +23,5 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const { container } = useChart(Line, props.config);
|
||||
const { container } = useChart(Line, props);
|
||||
</script>
|
||||
|
@ -22,5 +22,5 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const { container } = useChart(Pie, props.config);
|
||||
const { container } = useChart(Pie, props);
|
||||
</script>
|
||||
|
@ -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;
|
||||
|
@ -1,13 +1,19 @@
|
||||
import { createRouter, createWebHistory } from 'vue-router';
|
||||
import { createRouter, createWebHistory, type Router } from 'vue-router';
|
||||
import { titleGuard } from './guards';
|
||||
import routeList from './routes';
|
||||
import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
|
||||
|
||||
const router = createRouter({
|
||||
history: createWebHistory(''),
|
||||
routes: routeList,
|
||||
});
|
||||
let router: Router | null = null
|
||||
export const createProjectRouter = (base = '') => {
|
||||
const __POWERED_BY_QIANKUN__ = qiankunWindow.__POWERED_BY_QIANKUN__ || window.proxy?.__POWERED_BY_QIANKUN__
|
||||
router = createRouter({
|
||||
history: createWebHistory(base || (__POWERED_BY_QIANKUN__ ? '/y-code-app/' : '')),
|
||||
routes: routeList,
|
||||
})
|
||||
|
||||
// 全局前置守卫
|
||||
router.beforeEach(titleGuard);
|
||||
// 全局前置守卫
|
||||
router.beforeEach(titleGuard)
|
||||
return router
|
||||
}
|
||||
|
||||
export default router;
|
||||
|
@ -1,7 +1,11 @@
|
||||
import Layout from '@/layout/index.vue';
|
||||
import { HomeOutlined, BarChartOutlined } from '@ant-design/icons-vue';
|
||||
import { h } from 'vue';
|
||||
import type { VNode, RendererNode, RendererElement } from 'vue';
|
||||
import Layout from "@/layout/index.vue";
|
||||
import {
|
||||
HomeOutlined,
|
||||
BarChartOutlined,
|
||||
AppstoreOutlined,
|
||||
} from "@ant-design/icons-vue";
|
||||
import { h } from "vue";
|
||||
import type { VNode, RendererNode, RendererElement } from "vue";
|
||||
|
||||
export interface RouteType {
|
||||
path: string;
|
||||
@ -11,70 +15,96 @@ export interface RouteType {
|
||||
isMenu?: boolean;
|
||||
redirect?: string;
|
||||
children: RouteType[];
|
||||
icon?: () => VNode<RendererNode, RendererElement, {
|
||||
[key: string]: any;
|
||||
}>
|
||||
icon?: () => VNode<
|
||||
RendererNode,
|
||||
RendererElement,
|
||||
{
|
||||
[key: string]: any;
|
||||
}
|
||||
>;
|
||||
}
|
||||
|
||||
const routeList: RouteType[] = [
|
||||
{
|
||||
path: '/',
|
||||
name: 'layout',
|
||||
path: "/",
|
||||
name: "layout",
|
||||
component: Layout,
|
||||
meta: { title: '首页' },
|
||||
meta: { title: "首页" },
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
name: '-',
|
||||
path: "",
|
||||
name: "-",
|
||||
meta: {},
|
||||
children: [],
|
||||
redirect: '/config-manage/project-cfg',
|
||||
redirect: "/config-manage/project-cfg",
|
||||
},
|
||||
{
|
||||
path: '/config-manage',
|
||||
name: 'config-manage',
|
||||
path: "/config-manage",
|
||||
name: "config-manage",
|
||||
isMenu: true,
|
||||
meta: { title: '配置管理' },
|
||||
meta: { title: "配置管理" },
|
||||
icon: () => h(HomeOutlined),
|
||||
children: [
|
||||
{
|
||||
path: 'project-cfg',
|
||||
name: 'project-cfg',
|
||||
component: () => import('@/views/config-manage/project-cfg/index.vue'),
|
||||
meta: { title: '项目配置' },
|
||||
path: "project-cfg",
|
||||
name: "project-cfg",
|
||||
component: () =>
|
||||
import("@/views/config-manage/project-cfg/index.vue"),
|
||||
meta: { title: "项目配置" },
|
||||
isMenu: true,
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
path: 'module-cfg',
|
||||
name: 'module-cfg',
|
||||
component: () => import('@/views/config-manage/module-cfg/index.vue'),
|
||||
meta: { title: '数据表配置' },
|
||||
path: "module-cfg",
|
||||
name: "module-cfg",
|
||||
component: () =>
|
||||
import("@/views/config-manage/module-cfg/index.vue"),
|
||||
meta: { title: "数据来源配置" },
|
||||
isMenu: true,
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/view-all-manage',
|
||||
name: 'view-all-manage',
|
||||
path: "/view-all-manage",
|
||||
name: "view-all-manage",
|
||||
isMenu: true,
|
||||
meta: { title: '视图管理' },
|
||||
meta: { title: "视图管理" },
|
||||
icon: () => h(BarChartOutlined),
|
||||
children: [
|
||||
{
|
||||
path: 'view-list',
|
||||
name: 'view-list',
|
||||
component: () => import('@/views/view-all-manage/view-list/index.vue'),
|
||||
meta: { title: '视图列表' },
|
||||
path: "view-list",
|
||||
name: "view-list",
|
||||
component: () =>
|
||||
import("@/views/view-all-manage/view-list/index.vue"),
|
||||
meta: { title: "视图列表" },
|
||||
isMenu: true,
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
path: 'create-view',
|
||||
name: 'create-view',
|
||||
component: () => import('@/views/view-all-manage/create-view/index.vue'),
|
||||
meta: { title: '创建视图' },
|
||||
path: "create-view",
|
||||
name: "create-view",
|
||||
component: () =>
|
||||
import("@/views/view-all-manage/create-view/index.vue"),
|
||||
meta: { title: "创建视图" },
|
||||
isMenu: true,
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "/page-show-info",
|
||||
name: "page-show-info",
|
||||
isMenu: true,
|
||||
meta: { title: "视图预览" },
|
||||
icon: () => h(AppstoreOutlined),
|
||||
children: [
|
||||
{
|
||||
path: "page-info",
|
||||
name: "page-info",
|
||||
component: () =>
|
||||
import("@/views/page-show-info/page-info/index,.vue"),
|
||||
meta: { title: "项目报表" },
|
||||
isMenu: true,
|
||||
children: [],
|
||||
},
|
||||
|
@ -12,11 +12,12 @@
|
||||
placeholder="请选择所属项目"
|
||||
v-model:value="formData.project_id"
|
||||
:options="projectSelect"
|
||||
@change="toGetDbTable"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="数据表名称" name="modular_name">
|
||||
<a-form-item label="数据来源" name="modular_name">
|
||||
<a-input
|
||||
placeholder="请输入数据表名称"
|
||||
placeholder="请输入数据来源"
|
||||
v-model:value="formData.modular_name"
|
||||
/>
|
||||
</a-form-item>
|
||||
@ -27,26 +28,90 @@
|
||||
:unCheckedValue="0"
|
||||
/>
|
||||
</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 label="数据源类型" name="original_type">
|
||||
<a-radio-group v-model:value="formData.original_type">
|
||||
<a-radio :value="1">自定义</a-radio>
|
||||
<a-radio :value="2">指定表</a-radio>
|
||||
</a-radio-group>
|
||||
</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
|
||||
placeholder="请输入sql数据源"
|
||||
v-model:value="formData.original_sql"
|
||||
/>
|
||||
</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="is_other_database">
|
||||
<a-switch
|
||||
v-model:checked="formData.is_other_database"
|
||||
:checkedValue="1"
|
||||
:unCheckedValue="0"
|
||||
@change="isOtherChange"
|
||||
/>
|
||||
</a-form-item>
|
||||
<template v-if="formData.is_other_database">
|
||||
<a-form-item label="数据库驱动" name="drive_type">
|
||||
<a-radio-group v-model:value="formData.drive_type">
|
||||
<a-radio :value="1">MySQL</a-radio>
|
||||
<a-radio :value="2">Click House</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
<a-form-item label="数据库地址" name="database_address">
|
||||
<a-input
|
||||
placeholder="请输入数据库地址"
|
||||
v-model:value="formData.database_address"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="数据库端口" name="database_port">
|
||||
<a-input-number
|
||||
placeholder="请输入数据库端口"
|
||||
v-model:value="formData.database_port"
|
||||
style="width: 200px"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="数据库名称" name="database_name">
|
||||
<a-input
|
||||
placeholder="请输入数据库名称"
|
||||
v-model:value="formData.database_name"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="数据库用户" name="database_username">
|
||||
<a-input
|
||||
placeholder="请输入数据库用户"
|
||||
v-model:value="formData.database_username"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item label="数据库密码" name="database_password">
|
||||
<a-space>
|
||||
<a-input
|
||||
placeholder="请输入数据库密码"
|
||||
v-model:value="formData.database_password"
|
||||
/>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
</template>
|
||||
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
import { getShowTypeSelect } from "@/views/config-manage/module-cfg/service";
|
||||
import { ref, watch } from "vue";
|
||||
import { getDbTableSelect } from "@/views/config-manage/module-cfg/service";
|
||||
|
||||
const props = defineProps({
|
||||
open: {
|
||||
@ -70,20 +135,31 @@ const props = defineProps({
|
||||
const emit = defineEmits(["ok"]);
|
||||
const formRules = ref({
|
||||
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" }],
|
||||
table: [{ required: true, message: "请选择", trigger: "submit" }],
|
||||
});
|
||||
|
||||
const showTypes = ref([]);
|
||||
const tableTypes = ref([]);
|
||||
const formRef = ref();
|
||||
const formData = ref({
|
||||
project_id: undefined,
|
||||
modular_name: undefined,
|
||||
is_show: 0,
|
||||
show_type_id: undefined,
|
||||
original_type: 1, // 1 - 自定义,2 - 指定表
|
||||
// show_type_id: undefined,
|
||||
original_sql: undefined,
|
||||
table: undefined,
|
||||
is_other_database: 0,
|
||||
drive_type: 1,
|
||||
database_address: undefined,
|
||||
database_port: undefined,
|
||||
database_name: undefined,
|
||||
database_username: undefined,
|
||||
database_password: undefined,
|
||||
});
|
||||
|
||||
watch(
|
||||
@ -97,30 +173,53 @@ watch(
|
||||
project_id: newVal.project_id,
|
||||
modular_name: newVal.modular_name,
|
||||
is_show: newVal.is_show,
|
||||
show_type_id: newVal.show_type_id,
|
||||
original_type: newVal.original_type,
|
||||
// show_type_id: newVal.show_type_id,
|
||||
original_sql: newVal.original_sql,
|
||||
table: newVal.table,
|
||||
drive_type: newVal.drive_type,
|
||||
is_other_database: newVal.is_other_database,
|
||||
database_address: newVal.database_address,
|
||||
database_port: newVal.database_port,
|
||||
database_name: newVal.database_name,
|
||||
database_username: newVal.database_username,
|
||||
database_password: newVal.database_password,
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
toGetShowType();
|
||||
});
|
||||
|
||||
const toGetShowType = () => {
|
||||
getShowTypeSelect().then((res) => {
|
||||
showTypes.value = res.data;
|
||||
const toGetDbTable = () => {
|
||||
getDbTableSelect({ projectId: formData.value.project_id }).then((res) => {
|
||||
tableTypes.value = res.data;
|
||||
});
|
||||
};
|
||||
|
||||
const isOtherChange = (val) => {
|
||||
formData.value.drive_type = val ? 1 : undefined
|
||||
formData.value.database_address = undefined
|
||||
formData.value.database_port = undefined
|
||||
formData.value.database_name = undefined
|
||||
formData.value.database_username = undefined
|
||||
formData.value.database_password = undefined
|
||||
}
|
||||
|
||||
const resetFormData = () => {
|
||||
formData.value = {
|
||||
project_id: undefined,
|
||||
modular_name: undefined,
|
||||
is_show: 0,
|
||||
show_type_id: undefined,
|
||||
original_type: 1, // 1 - 自定义,2 - 指定表
|
||||
// show_type_id: undefined,
|
||||
original_sql: undefined,
|
||||
table: undefined,
|
||||
is_other_database: 0,
|
||||
drive_type: undefined,
|
||||
database_address: undefined,
|
||||
database_port: undefined,
|
||||
database_name: undefined,
|
||||
database_username: undefined,
|
||||
database_password: undefined,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -34,18 +34,33 @@
|
||||
<a-input
|
||||
v-if="editableData[record.field_id]"
|
||||
v-model:value="record[column.dataIndex]"
|
||||
allow-clear
|
||||
placeholder="请输入"
|
||||
/>
|
||||
<template v-else>
|
||||
{{ 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="请选择"
|
||||
allow-clear
|
||||
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]"
|
||||
v-model:value="record.field_type_id"
|
||||
:options="fieldTypeSel"
|
||||
placeholder="请选择"
|
||||
allow-clear
|
||||
style="width: 160px"
|
||||
>
|
||||
</a-select>
|
||||
@ -64,17 +79,30 @@
|
||||
{{ record.is_search ? "是" : "否" }}
|
||||
</template>
|
||||
</template>
|
||||
<template v-if="column.dataIndex === 'original_type'">
|
||||
<a-select
|
||||
v-if="editableData[record.field_id]"
|
||||
placeholder="请选择"
|
||||
v-model:value="record.original_type"
|
||||
:options="originalTypes"
|
||||
allow-clear
|
||||
>
|
||||
</a-select>
|
||||
<template v-else>
|
||||
{{ record.original_type_name }}
|
||||
</template>
|
||||
</template>
|
||||
<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>
|
||||
@ -93,9 +121,10 @@
|
||||
|
||||
<script setup>
|
||||
import { onMounted, reactive, ref, watch } from "vue";
|
||||
import { viewCfgCols } from "@/views/config-manage/module-cfg/config";
|
||||
import { viewCfgCols, originalTypes } from "@/views/config-manage/module-cfg/config";
|
||||
import {
|
||||
getFieldTypeSelect,
|
||||
getFieldNumSelect,
|
||||
getFieldList,
|
||||
// deleteField,
|
||||
saveField,
|
||||
@ -117,6 +146,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 +165,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,9 +210,11 @@ 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,
|
||||
original_type: undefined,
|
||||
original_sql: undefined,
|
||||
sort: 0,
|
||||
};
|
||||
@ -200,21 +240,38 @@ const handleCancel = (record) => {
|
||||
|
||||
const handleSave = (record) => {
|
||||
const params = {
|
||||
field_id: record.field_id,
|
||||
field_title: record.field_title,
|
||||
field_name: record.field_name,
|
||||
is_search: record.is_search,
|
||||
field_type_id: record.field_type_id,
|
||||
belong_to_table: record.belong_to_table,
|
||||
original_sql: record.original_sql,
|
||||
modular_id: props.modularId,
|
||||
};
|
||||
if (typeof params.field_id === "string") {
|
||||
// 新建
|
||||
delete params.field_id;
|
||||
} else {
|
||||
// 检验必填参数
|
||||
const validateFields = [
|
||||
{ field: 'field_title', msg: "请填写字段标题" },
|
||||
{ field: 'field_name', msg: "请填写字段名称" },
|
||||
{ field: 'field_numerical_type_id', msg: "请选择字段类型" },
|
||||
{ field: 'belong_to_table', msg: "请填写关联表" },
|
||||
{ field: 'original_type', msg: '请选择数据源类型' },
|
||||
{ field: 'original_sql', msg: "请填写sql数据源" },
|
||||
]
|
||||
for(let i = 0; i < validateFields.length; i++) {
|
||||
const curr = validateFields[i];
|
||||
if (!record[curr.field]) {
|
||||
message.error(curr.msg);
|
||||
return;
|
||||
} else {
|
||||
params[curr.field] = record[curr.field];
|
||||
}
|
||||
}
|
||||
if (record.is_search && !record.field_type_id) {
|
||||
message.error("请选择搜索类型");
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果是编辑操作
|
||||
if (typeof record.field_id === "number") {
|
||||
params.field_id = record.field_id;
|
||||
}
|
||||
|
||||
saveField(params).then(() => {
|
||||
delete editableData[record.field_id];
|
||||
message.success("保存成功");
|
||||
|
@ -1,9 +1,9 @@
|
||||
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: 'show_type_handle', title: '展示类型', align: 'center'},
|
||||
{ dataIndex: 'original_type_handle', title: '数据源类型', align: 'center'},
|
||||
// { dataIndex: 'sort', title: '排序', align: 'center'},
|
||||
{ dataIndex: 'action', title: '操作', align: 'center'},
|
||||
];
|
||||
@ -11,10 +11,17 @@ 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'},
|
||||
{ dataIndex: 'original_sql', title: 'sql数据源', align: 'center'},
|
||||
{ dataIndex: 'original_type', title: '数据源类型', align: 'center'},
|
||||
{ dataIndex: 'original_sql', title: '数据源', align: 'center', width: 400},
|
||||
{ dataIndex: 'action', title: '操作', align: 'center'},
|
||||
];
|
||||
|
||||
export const originalTypes = [
|
||||
{ label: 'sql', value: 1 },
|
||||
{ label: 'json', value: 2 },
|
||||
]
|
||||
|
@ -4,7 +4,7 @@
|
||||
<a-space>
|
||||
<a-input
|
||||
v-model:value="modularName"
|
||||
placeholder="请输入数据表名称"
|
||||
placeholder="请输入数据来源名称"
|
||||
allow-clear
|
||||
style="width: 200px"
|
||||
@change="search"
|
||||
|
@ -54,20 +54,30 @@ export function getProjectSelect() {
|
||||
});
|
||||
}
|
||||
|
||||
// 展示类型下拉
|
||||
export function getShowTypeSelect() {
|
||||
// 数据表源下拉
|
||||
export function getDbTableSelect({ projectId }) {
|
||||
return get({
|
||||
url: `/api/v1/modular/get-show-type-drop`,
|
||||
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({
|
||||
|
@ -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
|
||||
@ -59,6 +59,12 @@
|
||||
>
|
||||
</a-space>
|
||||
</a-form-item>
|
||||
<a-form-item label="数据库驱动" name="drive_type">
|
||||
<a-radio-group v-model:value="formData.drive_type">
|
||||
<a-radio :value="1">MySQL</a-radio>
|
||||
<a-radio :value="2">Click House</a-radio>
|
||||
</a-radio-group>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
</a-modal>
|
||||
</template>
|
||||
@ -98,12 +104,6 @@ const formRules = {
|
||||
database_name: [
|
||||
{ required: true, message: "请输入数据库名称", trigger: "submit" },
|
||||
],
|
||||
database_username: [
|
||||
{ required: true, message: "请输入数据库用户", trigger: "submit" },
|
||||
],
|
||||
database_password: [
|
||||
{ required: true, message: "请输入数据库密码", trigger: "submit" },
|
||||
],
|
||||
};
|
||||
|
||||
const formRef = ref();
|
||||
@ -116,6 +116,7 @@ const formData = ref({
|
||||
database_name: undefined,
|
||||
database_username: undefined,
|
||||
database_password: undefined,
|
||||
drive_type: 1,
|
||||
});
|
||||
|
||||
watch(
|
||||
@ -138,6 +139,7 @@ const toCheckDbConnect = () => {
|
||||
database_address: formData.value.database_address,
|
||||
database_username: formData.value.database_username,
|
||||
database_password: formData.value.database_password,
|
||||
drive_type: formData.value.drive_type,
|
||||
}).then((res) => {
|
||||
message.success(res.message);
|
||||
});
|
||||
@ -149,8 +151,6 @@ const validateConnect = () => {
|
||||
database_name: "请输入数据库名称",
|
||||
database_port: "请输入数据库端口",
|
||||
database_address: "请输入数据库地址",
|
||||
database_username: "请输入数据库用户",
|
||||
database_password: "请输入数据库密码",
|
||||
};
|
||||
for (const key in fields) {
|
||||
if (!formData.value[key]) {
|
||||
@ -171,6 +171,7 @@ const resetFormData = () => {
|
||||
database_name: undefined,
|
||||
database_username: undefined,
|
||||
database_password: undefined,
|
||||
drive_type: 1,
|
||||
};
|
||||
};
|
||||
|
||||
|
337
src/views/page-show-info/page-info/index,.vue
Normal file
337
src/views/page-show-info/page-info/index,.vue
Normal file
@ -0,0 +1,337 @@
|
||||
<template>
|
||||
<div class="page-view-wrapp">
|
||||
<div v-if="!isInQiankun" class="project">
|
||||
<span>项目: </span>
|
||||
<a-select
|
||||
style="min-width: 160px"
|
||||
placeholder="请选择项目"
|
||||
v-model:value="projectVal"
|
||||
:options="projectOptions"
|
||||
@change="handleProjectChange"
|
||||
></a-select>
|
||||
</div>
|
||||
<div>
|
||||
<grid-layout
|
||||
v-if="isDraggable"
|
||||
:layout.sync="layoutList"
|
||||
:col-num="2"
|
||||
:is-draggable="true"
|
||||
:is-resizable="false"
|
||||
:is-mirrored="false"
|
||||
:vertical-compact="true"
|
||||
:use-css-transforms="true"
|
||||
>
|
||||
<grid-item
|
||||
v-for="(item, index) in layoutList"
|
||||
:x="item.x"
|
||||
:y="item.y"
|
||||
:w="item.w"
|
||||
:h="item.h"
|
||||
:i="item.i"
|
||||
:key="item.i"
|
||||
drag-allow-from=".vue-draggable-handle"
|
||||
drag-ignore-from=".no-drag"
|
||||
>
|
||||
<div class="view-box view-draggable">
|
||||
<div class="vue-draggable-handle"><BarsOutlined /></div>
|
||||
<div class="content no-drag">
|
||||
<a-spin :spinning="ids[index].loading">
|
||||
<div class="card-content">
|
||||
<y-table
|
||||
v-if="item.data.type === VIEW_TYPE.TABLE"
|
||||
:filter-config="item.data.filter"
|
||||
:data-list="item.data.data"
|
||||
:column-config="item.data.header"
|
||||
:total="item.data.count"
|
||||
:title="item.data.preview_name"
|
||||
@toFilt="
|
||||
(params?:object) => {
|
||||
handleSingle(ids[index], params);
|
||||
}
|
||||
"
|
||||
></y-table>
|
||||
<y-chart
|
||||
v-if="item.data.type === VIEW_TYPE.CHART"
|
||||
:chartCfg="item.data.config"
|
||||
:title="item.data.preview_name"
|
||||
:filter-config="item.data.filter"
|
||||
@toFilt="
|
||||
(params?:object) => {
|
||||
handleSingle(ids[index], params);
|
||||
}
|
||||
"
|
||||
></y-chart>
|
||||
</div>
|
||||
</a-spin>
|
||||
</div>
|
||||
</div>
|
||||
</grid-item>
|
||||
</grid-layout>
|
||||
|
||||
<a-row v-else :gutter="[16, 16]">
|
||||
<a-col v-for="(item, index) in layoutList" :span="24">
|
||||
<a-spin :spinning="item.loading">
|
||||
<div>
|
||||
<div class="view-box">
|
||||
<div class="content">
|
||||
<div class="card-content">
|
||||
<y-table
|
||||
v-if="item.data.type === VIEW_TYPE.TABLE"
|
||||
:filter-config="item.data.filter"
|
||||
:data-list="item.data.data"
|
||||
:column-config="item.data.header"
|
||||
:total="item.data.count"
|
||||
:title="item.data.preview_name"
|
||||
@toFilt="
|
||||
(params?:object) => {
|
||||
handleSingle(ids[index], params,);
|
||||
}
|
||||
"
|
||||
></y-table>
|
||||
<y-chart
|
||||
v-if="item.data.type === VIEW_TYPE.CHART"
|
||||
:chartCfg="item.data.config"
|
||||
:title="item.data.preview_name"
|
||||
:filter-config="item.data.filter"
|
||||
@toFilt="
|
||||
(params?:object) => {
|
||||
handleSingle(ids[index], params);
|
||||
}
|
||||
"
|
||||
></y-chart>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a-spin>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, shallowRef, computed, onMounted, watch } from "vue";
|
||||
import { useRoute, useRouter } from "vue-router";
|
||||
import { BarsOutlined } from "@ant-design/icons-vue";
|
||||
// utils
|
||||
import PLimit from "p-limit";
|
||||
// api
|
||||
import { searchInfo } from "@/api/preview/index";
|
||||
import { getProjectDrop } from "@/api/common";
|
||||
import { getPageInfo } from "./service";
|
||||
import type { SelectProps } from "ant-design-vue";
|
||||
import { qiankunWindow } from 'vite-plugin-qiankun/dist/helper'
|
||||
|
||||
interface ItemDetail {
|
||||
id: number | string;
|
||||
data: any;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
interface Item {
|
||||
id: number | string;
|
||||
data: any;
|
||||
loading: boolean;
|
||||
}
|
||||
|
||||
interface Option extends SelectProps {
|
||||
mark: string;
|
||||
}
|
||||
|
||||
const VIEW_TYPE = {
|
||||
TABLE: "table",
|
||||
CHART: "chart",
|
||||
};
|
||||
|
||||
const SEARCH_TYPE = {
|
||||
SEARCH: "search",
|
||||
INIT: "init",
|
||||
};
|
||||
|
||||
// hooks
|
||||
const route = useRoute();
|
||||
const router = useRouter();
|
||||
const projectTag = shallowRef();
|
||||
const projectVal = shallowRef();
|
||||
const pageId = shallowRef(route.query.pageId);
|
||||
const projectOptions = shallowRef<Option[]>();
|
||||
const isDraggable = false;
|
||||
|
||||
const isInQiankun = computed(() => {
|
||||
return qiankunWindow.__POWERED_BY_QIANKUN__ || window.proxy?.__POWERED_BY_QIANKUN__
|
||||
})
|
||||
|
||||
const layoutList = computed(() => {
|
||||
return ids.value.map((item, index) => {
|
||||
// 当前是第几行
|
||||
const row = Math.floor(index / 2);
|
||||
// 当前是第几列ji
|
||||
const col = index % 2;
|
||||
return {
|
||||
i: item?.id,
|
||||
x: col,
|
||||
y: row,
|
||||
w: 1,
|
||||
h: 3,
|
||||
minH: 3,
|
||||
...item,
|
||||
};
|
||||
});
|
||||
});
|
||||
const ids = ref<Item[]>([]);
|
||||
|
||||
const pLimit = PLimit(2);
|
||||
|
||||
watch(() => route.query.viewId, () => {
|
||||
getPageInfoData()
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
getProjectList();
|
||||
});
|
||||
|
||||
const handleSingle = (info: ItemDetail, otherParams?: object) => {
|
||||
getSinglePreview({ info, otherParams, type: SEARCH_TYPE.SEARCH });
|
||||
};
|
||||
|
||||
const handleProjectChange = (value: string | number, option: Option) => {
|
||||
projectTag.value = option.mark;
|
||||
router.replace({
|
||||
path: route.path,
|
||||
query: {
|
||||
...route.query,
|
||||
projectTag: projectTag.value,
|
||||
},
|
||||
});
|
||||
getPageInfoData();
|
||||
};
|
||||
|
||||
// 请求
|
||||
|
||||
// 获取项目下拉
|
||||
const getProjectList = () => {
|
||||
getProjectDrop()
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
projectOptions.value = res.data;
|
||||
projectTag.value = route.query.projectTag || res.data[0].mark;
|
||||
projectVal.value =
|
||||
projectOptions.value?.find((item) => {
|
||||
return item.mark === route.query.projectTag;
|
||||
})?.value || res.data[0].value;
|
||||
getPageInfoData();
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
projectOptions.value = [];
|
||||
})
|
||||
.finally(() => {});
|
||||
};
|
||||
|
||||
// 单个视图请求
|
||||
const getSinglePreview = (data: {
|
||||
info: ItemDetail;
|
||||
otherParams?: object;
|
||||
type?: string;
|
||||
}) => {
|
||||
const { info, otherParams, type } = data;
|
||||
info.loading = true;
|
||||
const params = { previewId: info.id, page: 1, perPage: 20, ...otherParams };
|
||||
searchInfo(params)
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
info.data = res.data;
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
info.loading = false;
|
||||
});
|
||||
};
|
||||
|
||||
// 获取页面信息所有的id
|
||||
const getPageInfoData = () => {
|
||||
getPageInfo({ mark:projectTag.value, page_id: pageId.value ?? "-1" })
|
||||
.then((res) => {
|
||||
if (res.code === 200) {
|
||||
if (route.query.viewId) {
|
||||
ids.value = res.data?.filter((item: any) => {
|
||||
return item.preview_id === Number(route.query.viewId);
|
||||
}).map((item: any) => {
|
||||
return {
|
||||
id: item.preview_id,
|
||||
data: item,
|
||||
loading: false,
|
||||
}
|
||||
})
|
||||
} else {
|
||||
ids.value = res.data?.map((item: any) => {
|
||||
return {
|
||||
id: item.preview_id,
|
||||
data: item,
|
||||
loading: false,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
getAllCardsData();
|
||||
}
|
||||
})
|
||||
.finally(() => {});
|
||||
};
|
||||
|
||||
const fetchFn = (delay: number, info: ItemDetail) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve(info);
|
||||
getSinglePreview({ info, type: SEARCH_TYPE.INIT });
|
||||
}, delay);
|
||||
});
|
||||
};
|
||||
|
||||
const getAllCardsData = async () => {
|
||||
let listDB = [];
|
||||
for (let i in ids.value) {
|
||||
listDB.push(pLimit(() => fetchFn(i === "0" ? 200 : 1000, ids.value[i])));
|
||||
}
|
||||
await Promise.all(listDB);
|
||||
//此处的listDB就是最后整合的数据
|
||||
};
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
.view-box {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
min-height: 350px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 4px;
|
||||
transition: all 0.3s;
|
||||
&:hover {
|
||||
box-shadow: 0 0 20px 0 #0a103205, 0 14px 40px 0 #0a103208,
|
||||
0 20px 60px 0 #0a10320d;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.project {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.view-draggable {
|
||||
height: auto;
|
||||
min-height: 450px;
|
||||
}
|
||||
|
||||
.vue-draggable-handle {
|
||||
padding: 0 8px 8px 0;
|
||||
border-radius: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vue-grid-item {
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
10
src/views/page-show-info/page-info/service.ts
Normal file
10
src/views/page-show-info/page-info/service.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { get, post } from "@/utils/request";
|
||||
interface PageInfoParams {
|
||||
mark: string;
|
||||
page_id: number | string;
|
||||
}
|
||||
export const getPageInfo = (data: PageInfoParams) =>
|
||||
get({
|
||||
url: "/api/v1/preview/get-preview-info",
|
||||
params: data,
|
||||
});
|
@ -2,16 +2,16 @@
|
||||
<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 :label-col="{ span: 6 }" :wrapper-col="{ span: 18 }">
|
||||
<a-form-item label="项目"
|
||||
><a-select
|
||||
placeholder="请选择项目"
|
||||
:options="projectSel"
|
||||
v-model:value="projectId"
|
||||
@change="onProjectChange"
|
||||
></a-select
|
||||
><a-select
|
||||
placeholder="请选择项目"
|
||||
:options="projectSel"
|
||||
v-model:value="projectId"
|
||||
@change="onProjectChange"
|
||||
></a-select
|
||||
></a-form-item>
|
||||
<a-form-item label="数据表">
|
||||
<a-form-item label="数据来源">
|
||||
<a-select
|
||||
placeholder="请选择"
|
||||
:options="modularSel"
|
||||
@ -19,33 +19,49 @@
|
||||
@change="onModularChange"
|
||||
></a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="字段">
|
||||
<a-checkbox-group v-if="fieldList.length" v-model:value="fieldIds">
|
||||
<a-form-item label="展示类型">
|
||||
<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
|
||||
v-for="(item, index) in fieldList"
|
||||
:key="index"
|
||||
:value="item.value"
|
||||
>{{ item.label }}</a-checkbox
|
||||
>{{ item.label }}</a-checkbox
|
||||
>
|
||||
</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>
|
||||
<div class="footer">
|
||||
<a-button
|
||||
class="preview-btn"
|
||||
:loading="previewLoading"
|
||||
@click="toPreview"
|
||||
>预览</a-button
|
||||
@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-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"
|
||||
>
|
||||
@ -67,6 +83,7 @@
|
||||
v-model:value="previewData.filterData[item.name]"
|
||||
@change="toFilt"
|
||||
/>
|
||||
<a-range-picker v-if="item.type === 'time'" class="date-item" v-model:value="previewData.filterData[item.name]" @change="toFilt" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="y-table-content">
|
||||
@ -74,7 +91,7 @@
|
||||
:columns="previewData.columnConfig"
|
||||
:data-source="previewData.dataList"
|
||||
:pagination="false"
|
||||
:scroll="{ x: 1200 }"
|
||||
:scroll="{ x: 1000, y: `calc(100vh - 260px)` }"
|
||||
size="small"
|
||||
bordered
|
||||
></a-table>
|
||||
@ -85,10 +102,11 @@
|
||||
:hide-on-single-page="false"
|
||||
size="small"
|
||||
class="pagination-box"
|
||||
@change="toPreview"
|
||||
@change="() => { toPreview({}) }"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
@ -113,16 +131,30 @@
|
||||
|
||||
<script setup>
|
||||
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 { BarChartOutlined } from "@ant-design/icons-vue";
|
||||
import yChart from "@/components/common/y-chart.vue";
|
||||
import _ from 'lodash'
|
||||
|
||||
const projectSel = ref([]);
|
||||
const modularSel = ref([]);
|
||||
const fieldList = ref([]);
|
||||
const projectSel = ref([]); // 项目下拉
|
||||
const modularSel = ref([]) // 数据来源下拉
|
||||
const showTypeSel = ref([]); // 展示类型下拉
|
||||
const fieldList = ref([]); // 字段列表
|
||||
const xDataList = ref([]); // x轴数据列表
|
||||
const yDataList = ref([]); // y轴数据列表
|
||||
const projectId = ref();
|
||||
const modularId = ref();
|
||||
const showTypeId = ref();
|
||||
const fieldIds = ref([]);
|
||||
const xDataId = ref();
|
||||
const yDataId = ref();
|
||||
|
||||
const previewLoading = ref(false);
|
||||
const nameVisible = ref(false);
|
||||
@ -134,6 +166,8 @@ const previewData = reactive({
|
||||
columnConfig: [], // 表格表头
|
||||
dataList: [], // 表格数据
|
||||
filterData: {},
|
||||
config: {},
|
||||
filter: [],
|
||||
page: 1,
|
||||
perPage: 20,
|
||||
total: 0,
|
||||
@ -141,6 +175,7 @@ const previewData = reactive({
|
||||
|
||||
onMounted(() => {
|
||||
toGetProModularField();
|
||||
toGetShowTypes();
|
||||
});
|
||||
|
||||
const toGetProModularField = () => {
|
||||
@ -149,51 +184,117 @@ 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 target = projectSel.value.find((item) => item.value === val);
|
||||
modularSel.value = target.child;
|
||||
modularId.value = undefined;
|
||||
resetSelectData();
|
||||
resetPreviewData();
|
||||
};
|
||||
|
||||
const onModularChange = () => {
|
||||
resetSelectData();
|
||||
resetPreviewData();
|
||||
};
|
||||
|
||||
const onShowTypeChange = () => {
|
||||
toGetFieldOpts();
|
||||
};
|
||||
|
||||
const tranformList = (list) => {
|
||||
return list.map((item) => {
|
||||
return {
|
||||
label: item.field_name,
|
||||
value: item.field_id,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// 重置配置数据
|
||||
const resetSelectData = () => {
|
||||
showTypeId.value = undefined
|
||||
fieldList.value = [];
|
||||
fieldIds.value = [];
|
||||
resetPreviewData();
|
||||
};
|
||||
|
||||
const onModularChange = (val) => {
|
||||
const target = modularSel.value.find((item) => item.value === val);
|
||||
fieldList.value = target.child;
|
||||
resetPreviewData();
|
||||
};
|
||||
xDataList.value = [];
|
||||
yDataList.value = [];
|
||||
xDataId.value = undefined;
|
||||
yDataId.value = [];
|
||||
}
|
||||
|
||||
// 重置预览数据
|
||||
const resetPreviewData = () => {
|
||||
previewData.type = "";
|
||||
previewData.filterConfig = [];
|
||||
previewData.columnConfig = [];
|
||||
previewData.dataList = [];
|
||||
previewData.filterData = {};
|
||||
previewData.config = {};
|
||||
previewData.page = 1;
|
||||
previewData.perPage = 20;
|
||||
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) {
|
||||
const cloneFilter = _.cloneDeep(previewData.filterConfig)
|
||||
filterData = cloneFilter
|
||||
.filter((item) => {
|
||||
return previewData.filterData[item.name] !== undefined && previewData.filterData[item.name] !== null;
|
||||
})
|
||||
.map((item) => {
|
||||
return item.type === 'time' && previewData.filterData[item.name] ? {
|
||||
name: item.name,
|
||||
type: item.type,
|
||||
start_time: previewData.filterData[item.name][0].format('YYYY-MM-DD'),
|
||||
end_time: previewData.filterData[item.name][1].format('YYYY-MM-DD'),
|
||||
} : {
|
||||
name: item.name,
|
||||
type: item.type,
|
||||
value: previewData.filterData[item.name],
|
||||
}
|
||||
});
|
||||
} else {
|
||||
filterData = filter;
|
||||
}
|
||||
|
||||
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(),
|
||||
})
|
||||
.then((res) => {
|
||||
previewData.type = res.data.type;
|
||||
@ -207,6 +308,9 @@ const toPreview = () => {
|
||||
previewData.columnConfig = res.data.header;
|
||||
previewData.dataList = res.data.data;
|
||||
previewData.total = res.data.count;
|
||||
} else {
|
||||
previewData.chartCfg = res.data.config;
|
||||
previewData.filter = res.data.filter;
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
@ -228,15 +332,18 @@ const toSaveView = () => {
|
||||
modularId: modularId.value,
|
||||
fieldIds: fieldIds.value.toString(),
|
||||
previewName: previewName.value,
|
||||
showTypeId: showTypeId.value,
|
||||
xDataId: xDataId.value?.toString(),
|
||||
yDataId: yDataId.value?.toString(),
|
||||
}).then(() => {
|
||||
message.success("保存成功");
|
||||
message.success("保存成功,可前往视图列表查看");
|
||||
nameVisible.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
const toFilt = () => {
|
||||
previewData.page = 1;
|
||||
toPreview();
|
||||
toPreview({});
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -282,7 +389,12 @@ const toFilt = () => {
|
||||
font-size: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
.y-table-name {
|
||||
.title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.y-table-filter {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
@ -290,10 +402,14 @@ const toFilt = () => {
|
||||
.filter-item {
|
||||
margin-right: 10px;
|
||||
margin-bottom: 6px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.input-item {
|
||||
width: 180px;
|
||||
}
|
||||
.date-item {
|
||||
width: 240px;
|
||||
}
|
||||
.y-table-content {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
@ -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({
|
||||
url: "api/v1/preview/view",
|
||||
data: {
|
||||
@ -17,18 +35,24 @@ export function preview({ modularId, fieldIds, page, perPage, filter }) {
|
||||
page,
|
||||
per_page: perPage,
|
||||
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({
|
||||
url: "api/v1/preview/save",
|
||||
data: {
|
||||
modular_id: modularId,
|
||||
field_ids: fieldIds,
|
||||
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="view-list-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-select
|
||||
:options="projectSel"
|
||||
@ -11,11 +11,11 @@
|
||||
@change="onProjectChange"
|
||||
></a-select>
|
||||
</a-form-item>
|
||||
<a-form-item label="数据表">
|
||||
<a-form-item label="数据来源">
|
||||
<a-select
|
||||
:options="modularSel"
|
||||
v-model:value="modularId"
|
||||
placeholder="请选择数据表"
|
||||
placeholder="请先选好项目再选择"
|
||||
@change="onModularChange"
|
||||
></a-select>
|
||||
</a-form-item>
|
||||
@ -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({
|
||||
@ -182,6 +189,7 @@ const toDelete = (previewId) => {
|
||||
padding: 10px;
|
||||
flex-shrink: 0;
|
||||
border-right: 1px solid #ddd;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
:deep(.ant-table-row:hover) {
|
||||
|
@ -4,10 +4,41 @@ import vue from '@vitejs/plugin-vue';
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx';
|
||||
import Components from 'unplugin-vue-components/vite';
|
||||
import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
|
||||
import { server } from 'typescript';
|
||||
import qiankun from 'vite-plugin-qiankun'
|
||||
import yargsParser from 'yargs-parser'
|
||||
|
||||
const argv = yargsParser(process.argv.slice(2))
|
||||
|
||||
console.log(process.env.DEV_ENV)
|
||||
|
||||
let base: string
|
||||
switch (argv.mode) {
|
||||
case 'staging':
|
||||
case 'test':
|
||||
base = 'https://custom-chart.shiyue.com/'
|
||||
break
|
||||
case 'production':
|
||||
base = 'https://custom-chart.shiyuegame.com/'
|
||||
break
|
||||
default:
|
||||
base = 'http://localhost:8080/'
|
||||
}
|
||||
if (process.env.DEV_ENV === 'development') {
|
||||
base = 'http://localhost:8080/'
|
||||
}
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
build: {
|
||||
sourcemap: false,
|
||||
rollupOptions: {
|
||||
output: {
|
||||
assetFileNames: '[name]-ycode-[hash:8].[ext]',
|
||||
chunkFileNames: '[name]-ycode-[hash:8].js',
|
||||
entryFileNames: '[name]-ycode-[hash:8].js',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
vue(),
|
||||
vueJsx(),
|
||||
@ -16,14 +47,20 @@ export default defineConfig({
|
||||
importStyle: 'less',
|
||||
})],
|
||||
}),
|
||||
qiankun('y-code-app', { useDevMode: process.env.DEV_ENV === 'development' }),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||
},
|
||||
},
|
||||
base,
|
||||
define: {
|
||||
_BASE_HOST_: `'${base}'`,
|
||||
},
|
||||
server: {
|
||||
hmr: true,
|
||||
host: '0.0.0.0',
|
||||
port: 8080,
|
||||
},
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user