Merge branch 'feature/new-sys' into 'release'
feat: 新增配置管理和视图管理 See merge request workbench/y-code!1
This commit is contained in:
		
						commit
						1fe3e6cd43
					
				
							
								
								
									
										6
									
								
								.env.development
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.env.development
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | ||||
| # .env.development | ||||
| VITE_NODE_ENV = pre | ||||
| 
 | ||||
| VITE_OA_BASEURL = https://oa-pre.shiyue.com | ||||
| 
 | ||||
| VITE_YCODE_BASEURL = https://custom-chart-pre-api.shiyue.com | ||||
| @ -1 +1,5 @@ | ||||
| VITE_NODE_ENV = prod | ||||
| 
 | ||||
| VITE_OA_BASEURL = https://oa.shiyuegame.com | ||||
| 
 | ||||
| VITE_YCODE_BASEURL = https://custom-chart-api.shiyuegame.com | ||||
|  | ||||
| @ -1 +1,5 @@ | ||||
| VITE_NODE_ENV = pre | ||||
| 
 | ||||
| VITE_OA_BASEURL = https://oa-pre.shiyue.com | ||||
| 
 | ||||
| VITE_YCODE_BASEURL = https://custom-chart-pre-api.shiyue.com | ||||
|  | ||||
							
								
								
									
										18
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										18
									
								
								components.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -9,12 +9,30 @@ declare module 'vue' { | ||||
|   export interface GlobalComponents { | ||||
|     ABreadcrumb: typeof import('ant-design-vue/es')['Breadcrumb'] | ||||
|     ABreadcrumbItem: typeof import('ant-design-vue/es')['BreadcrumbItem'] | ||||
|     AButton: typeof import('ant-design-vue/es')['Button'] | ||||
|     ACheckbox: typeof import('ant-design-vue/es')['Checkbox'] | ||||
|     ACheckboxGroup: typeof import('ant-design-vue/es')['CheckboxGroup'] | ||||
|     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'] | ||||
|     AInput: typeof import('ant-design-vue/es')['Input'] | ||||
|     AInputNumber: typeof import('ant-design-vue/es')['InputNumber'] | ||||
|     AMenu: typeof import('ant-design-vue/es')['Menu'] | ||||
|     AMenuItem: typeof import('ant-design-vue/es')['MenuItem'] | ||||
|     AModal: typeof import('ant-design-vue/es')['Modal'] | ||||
|     APagination: typeof import('ant-design-vue/es')['Pagination'] | ||||
|     APopconfirm: typeof import('ant-design-vue/es')['Popconfirm'] | ||||
|     ASelect: typeof import('ant-design-vue/es')['Select'] | ||||
|     ASelectOption: typeof import('ant-design-vue/es')['SelectOption'] | ||||
|     ASpace: typeof import('ant-design-vue/es')['Space'] | ||||
|     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'] | ||||
|     YTable: typeof import('./src/components/common/y-table.vue')['default'] | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -4,7 +4,7 @@ | ||||
|     <meta charset="UTF-8"> | ||||
|     <link rel="icon" href="/favicon.ico"> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||||
|     <title>Vite App</title> | ||||
|     <title>悦码后台</title> | ||||
|   </head> | ||||
|   <body> | ||||
|     <div id="app"></div> | ||||
|  | ||||
							
								
								
									
										6
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -8,7 +8,7 @@ | ||||
|       "name": "y-code", | ||||
|       "version": "0.0.0", | ||||
|       "dependencies": { | ||||
|         "@vueuse/core": "^10.9.0", | ||||
|         "@vueuse/core": "^10.11.0", | ||||
|         "ant-design-vue": "^4.1.2", | ||||
|         "axios": "^1.6.7", | ||||
|         "pinia": "^2.1.7", | ||||
| @ -1944,7 +1944,7 @@ | ||||
|     }, | ||||
|     "node_modules/@vueuse/core": { | ||||
|       "version": "10.11.0", | ||||
|       "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-10.11.0.tgz", | ||||
|       "resolved": "http://sy-registry.shiyue.com/@vueuse/core/-/core-10.11.0.tgz", | ||||
|       "integrity": "sha512-x3sD4Mkm7PJ+pcq3HX8PLPBadXCAlSDR/waK87dz0gQE+qJnaaFhc/dZVfJz+IUYzTMVGum2QlR7ImiJQN4s6g==", | ||||
|       "dependencies": { | ||||
|         "@types/web-bluetooth": "^0.0.20", | ||||
| @ -6143,7 +6143,7 @@ | ||||
|     }, | ||||
|     "@vueuse/core": { | ||||
|       "version": "10.11.0", | ||||
|       "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-10.11.0.tgz", | ||||
|       "resolved": "http://sy-registry.shiyue.com/@vueuse/core/-/core-10.11.0.tgz", | ||||
|       "integrity": "sha512-x3sD4Mkm7PJ+pcq3HX8PLPBadXCAlSDR/waK87dz0gQE+qJnaaFhc/dZVfJz+IUYzTMVGum2QlR7ImiJQN4s6g==", | ||||
|       "requires": { | ||||
|         "@types/web-bluetooth": "^0.0.20", | ||||
|  | ||||
| @ -11,7 +11,7 @@ | ||||
|     "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@vueuse/core": "^10.9.0", | ||||
|     "@vueuse/core": "^10.11.0", | ||||
|     "ant-design-vue": "^4.1.2", | ||||
|     "axios": "^1.6.7", | ||||
|     "pinia": "^2.1.7", | ||||
|  | ||||
							
								
								
									
										28
									
								
								src/api/preview/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								src/api/preview/index.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| 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, | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
							
								
								
									
										136
									
								
								src/components/common/y-table.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								src/components/common/y-table.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,136 @@ | ||||
| <template> | ||||
|   <div class="y-table-container"> | ||||
|     <div class="y-table-filter"> | ||||
|       <div | ||||
|         v-for="(item, index) in filterConfig" | ||||
|         :key="index" | ||||
|         class="filter-item" | ||||
|       > | ||||
|         <span>{{ item.label }}:</span> | ||||
|         <a-select | ||||
|           v-if="item.type === 'select'" | ||||
|           class="input-item" | ||||
|           :options="item.options" | ||||
|           v-model:value="filterData[item.name]" | ||||
|           @change="toFilt" | ||||
|         ></a-select> | ||||
|         <a-input | ||||
|           v-if="item.type === 'text'" | ||||
|           class="input-item" | ||||
|           placeholder="请输入" | ||||
|           v-model:value="filterData[item.name]" | ||||
|           @change="toFilt" | ||||
|         /> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="y-table-content"> | ||||
|       <a-table | ||||
|         :columns="columnConfig" | ||||
|         :data-source="dataList" | ||||
|         :pagination="false" | ||||
|         size="small" | ||||
|         bordered | ||||
|       ></a-table> | ||||
|       <a-pagination | ||||
|         v-model:current="pageState.page" | ||||
|         :total="total" | ||||
|         :page-size="pageState.perPage" | ||||
|         :hide-on-single-page="false" | ||||
|         size="small" | ||||
|         class="pagination-box" | ||||
|         @change="pageChange" | ||||
|       /> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script setup> | ||||
| import { reactive, ref, watch } from "vue"; | ||||
| import { useDebounceFn } from "@vueuse/core"; | ||||
| 
 | ||||
| const props = defineProps({ | ||||
|   filterConfig: { | ||||
|     type: Array, | ||||
|     default: () => [], | ||||
|   }, | ||||
|   columnConfig: { | ||||
|     type: Array, | ||||
|     default: () => [], | ||||
|   }, | ||||
|   dataList: { | ||||
|     type: Array, | ||||
|     default: () => [], | ||||
|   }, | ||||
|   total: { | ||||
|     type: Number, | ||||
|     default: 0, | ||||
|   }, | ||||
| }); | ||||
| const emit = defineEmits(["handleFilt"]); | ||||
| 
 | ||||
| const filterData = ref({}); | ||||
| // const filterConfig = ref([]); | ||||
| // const columnConfig = ref([]); | ||||
| // const dataList = ref([]); | ||||
| 
 | ||||
| const pageState = reactive({ | ||||
|   page: 1, | ||||
|   perPage: 20, | ||||
| }); | ||||
| 
 | ||||
| watch( | ||||
|   () => props.filterConfig, | ||||
|   (newVal) => { | ||||
|     console.log("newVal", newVal); | ||||
| 
 | ||||
|     newVal.forEach((item) => { | ||||
|       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 = () => { | ||||
|   emit("toFilt", { | ||||
|     filter: filterData.value, | ||||
|     page: pageState.page, | ||||
|     perPage: pageState.perPage, | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| const toFilt = useDebounceFn(() => { | ||||
|   getData(); | ||||
| }, 500); | ||||
| 
 | ||||
| const pageChange = () => { | ||||
|   getData(); | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style lang="less" scoped> | ||||
| .y-table-filter { | ||||
|   display: flex; | ||||
|   flex-wrap: wrap; | ||||
| } | ||||
| .filter-item { | ||||
|   margin-right: 10px; | ||||
|   margin-bottom: 6px; | ||||
| } | ||||
| .input-item { | ||||
|   width: 180px; | ||||
| } | ||||
| .y-table-content { | ||||
|   margin-top: 10px; | ||||
| } | ||||
| .pagination-box { | ||||
|   text-align: center; | ||||
| } | ||||
| </style> | ||||
| @ -1,19 +1,21 @@ | ||||
| <script setup lang="ts"> | ||||
| import { useRoute } from 'vue-router'; | ||||
| import { HomeOutlined, FullscreenOutlined } from '@ant-design/icons-vue'; | ||||
| import { useUserInfoStore } from '@/stores/useUserInfoStore'; | ||||
| import avatar from '@/assets/avatar.png'; | ||||
| import { OA_BASEURL } from '@/utils/request'; | ||||
| import { logout } from '@/api/common'; | ||||
| import { useRoute } from "vue-router"; | ||||
| import { HomeOutlined, FullscreenOutlined } from "@ant-design/icons-vue"; | ||||
| import { useUserInfoStore } from "@/stores/useUserInfoStore"; | ||||
| import avatar from "@/assets/avatar.png"; | ||||
| import { YCODE_BASEURL } from "@/utils/request"; | ||||
| import { logout } from "@/api/common"; | ||||
| 
 | ||||
| const emits = defineEmits(['requestFullscreen']); | ||||
| const emits = defineEmits(["requestFullscreen"]); | ||||
| 
 | ||||
| const route = useRoute(); | ||||
| const userInfoStore = useUserInfoStore(); | ||||
| 
 | ||||
| const handleLogout = () => { | ||||
|   logout().then(() => { | ||||
|     window.location.href = `${OA_BASEURL}/login?redirect=${encodeURIComponent(window.location.href)}`; | ||||
|     window.location.href = `${YCODE_BASEURL}/login?redirect=${encodeURIComponent( | ||||
|       window.location.href | ||||
|     )}`; | ||||
|   }); | ||||
| }; | ||||
| </script> | ||||
| @ -31,12 +33,10 @@ const handleLogout = () => { | ||||
|       <div class="fullscreen-icon-area" @click="emits('requestFullscreen')"> | ||||
|         <FullscreenOutlined class="fullscreen-icon" /> | ||||
|       </div> | ||||
|       <a-dropdown | ||||
|         placement="bottom" | ||||
|       > | ||||
|         <div style="display: flex;align-items: center;cursor: pointer;"> | ||||
|       <a-dropdown placement="bottom"> | ||||
|         <div style="display: flex; align-items: center; cursor: pointer"> | ||||
|           <img :src="userInfoStore.userInfo?.avatar || avatar" class="avatar" /> | ||||
|           <div>{{ userInfoStore.userInfo?.alias || '-' }}</div> | ||||
|           <div>{{ userInfoStore.userInfo?.alias || "-" }}</div> | ||||
|         </div> | ||||
| 
 | ||||
|         <template #overlay> | ||||
| @ -45,9 +45,7 @@ const handleLogout = () => { | ||||
|               <span>退出登录</span> | ||||
|             </a-menu-item> | ||||
|             <a-menu-item> | ||||
|               <a class="back-oa" :href="`${OA_BASEURL}/front/`"> | ||||
|                 返回OA | ||||
|               </a> | ||||
|               <a class="back-oa" :href="`${OA_BASEURL}/front/`"> 返回OA </a> | ||||
|             </a-menu-item> | ||||
|           </a-menu> | ||||
|         </template> | ||||
| @ -63,7 +61,7 @@ const handleLogout = () => { | ||||
|   align-items: center; | ||||
|   padding: 0 30px; | ||||
|   background-color: #fff; | ||||
|   box-shadow: 0 0 12px 0 rgba(0,0,0,.08); | ||||
|   box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.08); | ||||
|   .user-area { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|  | ||||
| @ -1,21 +1,25 @@ | ||||
| <script setup lang="ts"> | ||||
| import { useUserInfoStore } from '@/stores/useUserInfoStore'; | ||||
| import { onMounted, ref } from 'vue'; | ||||
| import Header from './components/Header.vue'; | ||||
| import Sider from './components/Sider.vue'; | ||||
| import { MenuFoldOutlined, MenuUnfoldOutlined, FullscreenExitOutlined } from '@ant-design/icons-vue'; | ||||
| import { useEventListener } from '@vueuse/core'; | ||||
| import { useUserInfoStore } from "@/stores/useUserInfoStore"; | ||||
| import { onMounted, ref } from "vue"; | ||||
| import Header from "./components/Header.vue"; | ||||
| import Sider from "./components/Sider.vue"; | ||||
| import { | ||||
|   MenuFoldOutlined, | ||||
|   MenuUnfoldOutlined, | ||||
|   FullscreenExitOutlined, | ||||
| } from "@ant-design/icons-vue"; | ||||
| import { useEventListener } from "@vueuse/core"; | ||||
| 
 | ||||
| const userInfoStore = useUserInfoStore(); | ||||
| // const userInfoStore = useUserInfoStore(); | ||||
| const isCollapsed = ref(false); | ||||
| const isFullscreen = ref(false); | ||||
| const container = ref<HTMLDivElement>(); | ||||
| 
 | ||||
| onMounted(() => { | ||||
|   userInfoStore.fetchUserInfo(); | ||||
|   // userInfoStore.fetchUserInfo(); | ||||
| }); | ||||
| 
 | ||||
| useEventListener(window, 'fullscreenchange', () => { | ||||
| useEventListener(window, "fullscreenchange", () => { | ||||
|   isFullscreen.value = !!document.fullscreenElement; | ||||
| }); | ||||
| 
 | ||||
| @ -31,17 +35,32 @@ const handleExitFullscreen = () => { | ||||
| 
 | ||||
| <template> | ||||
|   <section class="root"> | ||||
|     <header class="header"> | ||||
|       <Header @requestFullscreen="handleFullscreen" /> | ||||
|     </header> | ||||
|     <section class="left-aside" :class="{ 'left-aside-collapsed': isCollapsed }"> | ||||
|     <section | ||||
|       class="left-aside" | ||||
|       :class="{ 'left-aside-collapsed': isCollapsed }" | ||||
|     > | ||||
|       <Sider :inlineCollapsed="isCollapsed" /> | ||||
|       <div class="collapsed-icon"> | ||||
|         <component :is="isCollapsed ? MenuUnfoldOutlined : MenuFoldOutlined" @click="isCollapsed = !isCollapsed" /> | ||||
|         <component | ||||
|           :is="isCollapsed ? MenuUnfoldOutlined : MenuFoldOutlined" | ||||
|           @click="isCollapsed = !isCollapsed" | ||||
|         /> | ||||
|       </div> | ||||
|     </section> | ||||
|     <section class="container" :class="{ 'container-fullscreen': isFullscreen, 'container-collapsed': isCollapsed }" ref="container"> | ||||
|       <router-view /> | ||||
|     <section | ||||
|       class="container" | ||||
|       :class="{ | ||||
|         'container-fullscreen': isFullscreen, | ||||
|         'container-collapsed': isCollapsed, | ||||
|       }" | ||||
|       ref="container" | ||||
|     > | ||||
|       <header class="header"> | ||||
|         <Header @requestFullscreen="handleFullscreen" /> | ||||
|       </header> | ||||
|       <div class="i-container"> | ||||
|         <router-view /> | ||||
|       </div> | ||||
|       <a-float-button @click="handleExitFullscreen" v-if="isFullscreen"> | ||||
|         <template #icon> | ||||
|           <FullscreenExitOutlined /> | ||||
| @ -62,21 +81,18 @@ const handleExitFullscreen = () => { | ||||
|   .header { | ||||
|     height: @header-height; | ||||
|     position: fixed; | ||||
|     width: 100%; | ||||
|     width: calc(100% - 220px); | ||||
|     z-index: 1; | ||||
|     top: 0; | ||||
|   } | ||||
|   .left-aside { | ||||
|     width: @aside-width; | ||||
|     position: fixed; | ||||
|     top: @header-height; | ||||
|     left: 0; | ||||
|     z-index: 1; | ||||
|     height: calc(100% - @header-height - @header-margin); | ||||
|     height: 100vh; | ||||
|     overflow-y: hidden; | ||||
|     margin-top: @header-margin; | ||||
|     border-radius: 8px; | ||||
|     box-shadow: 0 0 12px 0 rgba(0,0,0,.08); | ||||
|     box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.08); | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     background-color: #fff; | ||||
| @ -90,7 +106,7 @@ const handleExitFullscreen = () => { | ||||
|     } | ||||
|   } | ||||
|   .container { | ||||
|     padding-left: @aside-width + 8px; | ||||
|     padding-left: @aside-width; | ||||
|     padding-top: @header-height + @header-margin; | ||||
|     height: calc(100% - @header-height - @header-margin); | ||||
|     position: relative; | ||||
| @ -98,6 +114,9 @@ const handleExitFullscreen = () => { | ||||
|     transition: padding 0.3s cubic-bezier(0.2, 0, 0, 1) 0s; | ||||
|     margin-right: 8px; | ||||
|   } | ||||
|   .i-container { | ||||
|     padding: 0 8px 8px 8px; | ||||
|   } | ||||
|   .container-collapsed { | ||||
|     padding-left: @aside-width-collapsed + 8px; | ||||
|   } | ||||
| @ -105,7 +124,10 @@ const handleExitFullscreen = () => { | ||||
|     padding: 0; | ||||
|     height: 100%; | ||||
|   } | ||||
|   :deep(:where(.css-dev-only-do-not-override-1hsjdkk).ant-menu-inline-collapsed), .left-aside-collapsed { | ||||
|   :deep( | ||||
|       :where(.css-dev-only-do-not-override-1hsjdkk).ant-menu-inline-collapsed | ||||
|     ), | ||||
|   .left-aside-collapsed { | ||||
|     width: @aside-width-collapsed; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @ -2,7 +2,7 @@ import type { NavigationGuardWithThis } from 'vue-router'; | ||||
| 
 | ||||
| const titleGuard: NavigationGuardWithThis<undefined> = (to, from, next) => { | ||||
|   next(); | ||||
|   document.title = to.meta.title ? `${to.meta.title} | 机制系统` : '机制系统'; | ||||
|   document.title = to.meta.title ? `${to.meta.title} | 悦码` : '悦码'; | ||||
| }; | ||||
| 
 | ||||
| export { titleGuard }; | ||||
|  | ||||
| @ -28,41 +28,57 @@ const routeList: RouteType[] = [ | ||||
|         name: '-', | ||||
|         meta: {}, | ||||
|         children: [], | ||||
|         redirect: '/flow-manager/list', | ||||
|         redirect: '/config-manage/project-cfg', | ||||
|       }, | ||||
|       { | ||||
|         path: '/flow-manager', | ||||
|         name: 'flow-manager', | ||||
|         path: '/config-manage', | ||||
|         name: 'config-manage', | ||||
|         isMenu: true, | ||||
|         meta: { title: '机制管理' }, | ||||
|         meta: { title: '配置管理' }, | ||||
|         icon: () => h(HomeOutlined), | ||||
|         children: [ | ||||
|           { | ||||
|             path: 'list', | ||||
|             name: 'list', | ||||
|             component: () => import('@/views/flow-manager/list/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: 'create', | ||||
|             name: 'create', | ||||
|             component: () => import('@/views/flow-manager/create/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: '/data-overview', | ||||
|         name: 'data-overview', | ||||
|         path: '/view-all-manage', | ||||
|         name: 'view-all-manage', | ||||
|         isMenu: true, | ||||
|         meta: { title: '数据总览' }, | ||||
|         children: [], | ||||
|         meta: { title: '视图管理' }, | ||||
|         icon: () => h(BarChartOutlined), | ||||
|         component: () => import('@/views/data-overview/index.vue'), | ||||
|         children: [ | ||||
|           { | ||||
|             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: '创建' }, | ||||
|             isMenu: true, | ||||
|             children: [], | ||||
|           }, | ||||
|         ], | ||||
|       }, | ||||
|     ], | ||||
|   }, | ||||
|  | ||||
| @ -8,10 +8,10 @@ export interface ResopnseType<T> { | ||||
|   data: T | ||||
|   ts: string | ||||
| } | ||||
| export const OA_BASEURL: string = import.meta.env.VITE_OA_BASEURL; | ||||
| export const YCODE_BASEURL: string = import.meta.env.VITE_YCODE_BASEURL; | ||||
| 
 | ||||
| const requestType  = { | ||||
|   base: OA_BASEURL, | ||||
|   base: YCODE_BASEURL, | ||||
| }; | ||||
| 
 | ||||
| const baseAxios: AxiosInstance = axios.create({ | ||||
| @ -26,7 +26,7 @@ const errorHandle = (error: AxiosError) => { | ||||
|     switch (status) { | ||||
|       case 401: | ||||
|         message.warning('请先登录'); | ||||
|         window.location.href = `${OA_BASEURL}/login?redirect=${encodeURIComponent(window.location.href)}`; | ||||
|         window.location.href = `${YCODE_BASEURL}/login?redirect=${encodeURIComponent(window.location.href)}`; | ||||
|         break; | ||||
|       case 403: | ||||
|         message.warning('权限不足'); | ||||
|  | ||||
							
								
								
									
										132
									
								
								src/views/config-manage/module-cfg/components/create-modal.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								src/views/config-manage/module-cfg/components/create-modal.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,132 @@ | ||||
| <template> | ||||
|   <a-modal :open="open" @ok="handleOk"> | ||||
|     <a-form | ||||
|       :model="formData" | ||||
|       ref="formRef" | ||||
|       :rules="formRules" | ||||
|       :label-col="{ span: 4 }" | ||||
|       :wrapper-col="{ span: 20 }" | ||||
|     > | ||||
|       <a-form-item label="所属项目" name="project_id"> | ||||
|         <a-select | ||||
|           placeholder="请选择所属项目" | ||||
|           v-model:value="formData.project_id" | ||||
|           :options="projectSelect" | ||||
|         /> | ||||
|       </a-form-item> | ||||
|       <a-form-item label="数据表名称" name="modular_name"> | ||||
|         <a-input | ||||
|           placeholder="请输入数据表名称" | ||||
|           v-model:value="formData.modular_name" | ||||
|         /> | ||||
|       </a-form-item> | ||||
|       <a-form-item label="展示状态" name="is_show"> | ||||
|         <a-switch | ||||
|           v-model:checked="formData.is_show" | ||||
|           :checkedValue="1" | ||||
|           :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> | ||||
|       <a-form-item label="sql数据源" name="original_sql"> | ||||
|         <a-input | ||||
|           placeholder="请输入sql数据源" | ||||
|           v-model:value="formData.original_sql" | ||||
|         /> | ||||
|       </a-form-item> | ||||
|     </a-form> | ||||
|   </a-modal> | ||||
| </template> | ||||
| 
 | ||||
| <script setup> | ||||
| import { onMounted, ref, watch } from "vue"; | ||||
| import { getShowTypeSelect } from "@/views/config-manage/module-cfg/service"; | ||||
| 
 | ||||
| const props = defineProps({ | ||||
|   open: { | ||||
|     type: Boolean, | ||||
|     default: false, | ||||
|   }, | ||||
|   type: { | ||||
|     type: String, | ||||
|     default: "add", | ||||
|   }, | ||||
|   data: { | ||||
|     type: Object, | ||||
|     default: () => ({}), | ||||
|   }, | ||||
|   projectSelect: { | ||||
|     type: Array, | ||||
|     default: () => [], | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| const emit = defineEmits(["ok"]); | ||||
| const formRules = ref({ | ||||
|   modular_name: [ | ||||
|     { required: true, message: "请输入数据表名称", trigger: "submit" }, | ||||
|   ], | ||||
|   show_type_id: [{ required: true, message: "请选择", trigger: "submit" }], | ||||
|   original_sql: [{ required: true, message: "请输入", trigger: "submit" }], | ||||
| }); | ||||
| 
 | ||||
| const showTypes = ref([]); | ||||
| const formRef = ref(); | ||||
| const formData = ref({ | ||||
|   project_id: undefined, | ||||
|   modular_name: undefined, | ||||
|   is_show: 0, | ||||
|   show_type_id: undefined, | ||||
|   original_sql: undefined, | ||||
| }); | ||||
| 
 | ||||
| watch( | ||||
|   () => props.data, | ||||
|   (newVal) => { | ||||
|     if (props.type === "add") { | ||||
|       resetFormData(); | ||||
|     } else { | ||||
|       formData.value = { | ||||
|         modular_id: newVal.modular_id, | ||||
|         project_id: newVal.project_id, | ||||
|         modular_name: newVal.modular_name, | ||||
|         is_show: newVal.is_show, | ||||
|         show_type_id: newVal.show_type_id, | ||||
|         original_sql: newVal.original_sql, | ||||
|       }; | ||||
|     } | ||||
|   } | ||||
| ); | ||||
| 
 | ||||
| onMounted(() => { | ||||
|   toGetShowType(); | ||||
| }); | ||||
| 
 | ||||
| const toGetShowType = () => { | ||||
|   getShowTypeSelect().then((res) => { | ||||
|     showTypes.value = res.data; | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| const resetFormData = () => { | ||||
|   formData.value = { | ||||
|     project_id: undefined, | ||||
|     modular_name: undefined, | ||||
|     is_show: 0, | ||||
|     show_type_id: undefined, | ||||
|     original_sql: undefined, | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| const handleOk = () => { | ||||
|   formRef.value.validate().then(() => { | ||||
|     emit("ok", formData.value); | ||||
|   }); | ||||
| }; | ||||
| </script> | ||||
							
								
								
									
										233
									
								
								src/views/config-manage/module-cfg/components/field-modal.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								src/views/config-manage/module-cfg/components/field-modal.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,233 @@ | ||||
| <template> | ||||
|   <a-modal :open="open" title="字段管理" style="top: 30px" :footer="null"> | ||||
|     <div class="field-manager"> | ||||
|       <div class="header-box"> | ||||
|         <a-space> | ||||
|           <a-input | ||||
|             v-model:value="fieldName" | ||||
|             placeholder="请输入字段名称" | ||||
|             allow-clear | ||||
|             style="width: 200px" | ||||
|             @change="search" | ||||
|           /> | ||||
|           <a-button type="primary" @click="addField">新建</a-button> | ||||
|         </a-space> | ||||
|       </div> | ||||
|       <a-table | ||||
|         :columns="viewCfgCols" | ||||
|         :data-source="dataList" | ||||
|         :pagination="false" | ||||
|         size="small" | ||||
|         bordered | ||||
|       > | ||||
|         <template #bodyCell="{ column, record }"> | ||||
|           <template | ||||
|             v-if=" | ||||
|               [ | ||||
|                 'field_name', | ||||
|                 'field_title', | ||||
|                 'belong_to_table', | ||||
|                 'original_sql', | ||||
|               ].includes(column.dataIndex) | ||||
|             " | ||||
|           > | ||||
|             <a-input | ||||
|               v-if="editableData[record.field_id]" | ||||
|               v-model:value="record[column.dataIndex]" | ||||
|               placeholder="请输入" | ||||
|             /> | ||||
|             <template v-else> | ||||
|               {{ record[column.dataIndex] }} | ||||
|             </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="请选择" | ||||
|               style="width: 160px" | ||||
|             > | ||||
|             </a-select> | ||||
|             <template v-else> | ||||
|               {{ record.field_type_name }} | ||||
|             </template> | ||||
|           </template> | ||||
|           <template v-if="column.dataIndex === 'is_search'"> | ||||
|             <a-switch | ||||
|               v-if="editableData[record.field_id]" | ||||
|               v-model:checked="record.is_search" | ||||
|               :checkedValue="1" | ||||
|               :unCheckedValue="0" | ||||
|             /> | ||||
|             <template v-else> | ||||
|               {{ record.is_search ? "是" : "否" }} | ||||
|             </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 size="small" @click="handleCancel(record)" | ||||
|                 >取消</a-button | ||||
|               > | ||||
|             </a-space> | ||||
|             <a-button v-else type="link" @click="handleEdit(record)" | ||||
|               >修改</a-button | ||||
|             > | ||||
|           </template> | ||||
|         </template> | ||||
|       </a-table> | ||||
|       <a-pagination | ||||
|         :current="pageState.page" | ||||
|         :page-size="pageState.perPage" | ||||
|         :total="pageState.total" | ||||
|         class="pagination-box" | ||||
|         size="small" | ||||
|         @change="pageChange" | ||||
|       /> | ||||
|     </div> | ||||
|   </a-modal> | ||||
| </template> | ||||
| 
 | ||||
| <script setup> | ||||
| import { onMounted, reactive, ref, watch } from "vue"; | ||||
| import { viewCfgCols } from "@/views/config-manage/module-cfg/config"; | ||||
| import { | ||||
|   getFieldTypeSelect, | ||||
|   getFieldList, | ||||
|   // deleteField, | ||||
|   saveField, | ||||
|   // getFieldDetail, | ||||
| } from "@/views/config-manage/module-cfg/service"; | ||||
| import { message } from "ant-design-vue"; | ||||
| 
 | ||||
| const props = defineProps({ | ||||
|   open: { | ||||
|     type: Boolean, | ||||
|     default: false, | ||||
|   }, | ||||
|   modularId: { | ||||
|     type: Number, | ||||
|     default: 0, | ||||
|   }, | ||||
| }); | ||||
| const listLoading = ref(false); | ||||
| const fieldName = ref(""); | ||||
| const dataList = ref([]); | ||||
| const fieldTypeSel = ref([]); | ||||
| const pageState = reactive({ | ||||
|   page: 1, | ||||
|   perPage: 20, | ||||
|   total: 0, | ||||
| }); | ||||
| const editableData = reactive({}); | ||||
| 
 | ||||
| watch( | ||||
|   () => props.open, | ||||
|   (newVal) => { | ||||
|     if (newVal) { | ||||
|       toGetList(); | ||||
|     } | ||||
|   } | ||||
| ); | ||||
| 
 | ||||
| onMounted(() => { | ||||
|   toGetFieldTypes(); | ||||
| }); | ||||
| 
 | ||||
| // 字段类型下拉 | ||||
| const toGetFieldTypes = () => { | ||||
|   getFieldTypeSelect().then((res) => { | ||||
|     fieldTypeSel.value = res.data; | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| // 字段列表 | ||||
| const toGetList = () => { | ||||
|   listLoading.value = true; | ||||
|   getFieldList({ | ||||
|     fieldName: fieldName.value, | ||||
|     modularId: props.modularId, | ||||
|     page: pageState.page, | ||||
|     perPage: pageState.perPage, | ||||
|   }).then((res) => { | ||||
|     dataList.value = res.data.list; | ||||
|     pageState.total = res.data.total; | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| const pageChange = () => { | ||||
|   toGetList(); | ||||
| }; | ||||
| 
 | ||||
| const search = () => { | ||||
|   pageState.page = 1; | ||||
|   toGetList(); | ||||
| }; | ||||
| 
 | ||||
| const addField = () => { | ||||
|   const item = { | ||||
|     field_id: new Date().getTime() + "", | ||||
|     field_title: undefined, | ||||
|     field_name: undefined, | ||||
|     is_search: 0, | ||||
|     field_type_id: undefined, | ||||
|     belong_to_table: undefined, | ||||
|     original_sql: undefined, | ||||
|     sort: 0, | ||||
|   }; | ||||
|   dataList.value.unshift(item); | ||||
|   editableData[item.field_id] = { | ||||
|     ...item, | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| const handleEdit = (record) => { | ||||
|   editableData[record.field_id] = { | ||||
|     ...record, | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| const handleCancel = (record) => { | ||||
|   if (typeof record.field_id === "string") { | ||||
|     dataList.value.shift(); | ||||
|   } else { | ||||
|     delete editableData[record.field_id]; | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| const handleSave = (record) => { | ||||
|   const params = { | ||||
|     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 { | ||||
|     params.field_id = record.field_id; | ||||
|   } | ||||
|   saveField(params).then(() => { | ||||
|     delete editableData[record.field_id]; | ||||
|     message.success("保存成功"); | ||||
|     toGetList(); | ||||
|   }); | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style lang="less" scoped> | ||||
| .header-box { | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
| 
 | ||||
| .pagination-box { | ||||
|   text-align: center; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										20
									
								
								src/views/config-manage/module-cfg/config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/views/config-manage/module-cfg/config.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| export const moduleCfgCols = [ | ||||
|   { dataIndex: 'modular_id', 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: 'sort', title: '排序', align: 'center'},
 | ||||
|   { dataIndex: 'action', title: '操作', align: 'center'}, | ||||
| ]; | ||||
| 
 | ||||
| export const viewCfgCols = [ | ||||
|   { dataIndex: 'field_name', title: '字段名称', align: 'center'}, | ||||
|   { dataIndex: 'field_title', 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: 'action', title: '操作', align: 'center'}, | ||||
| ]; | ||||
							
								
								
									
										233
									
								
								src/views/config-manage/module-cfg/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										233
									
								
								src/views/config-manage/module-cfg/index.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,233 @@ | ||||
| <template> | ||||
|   <div class="normal-container module-cfg-box"> | ||||
|     <div class="header-box"> | ||||
|       <a-space> | ||||
|         <a-input | ||||
|           v-model:value="modularName" | ||||
|           placeholder="请输入数据表名称" | ||||
|           allow-clear | ||||
|           style="width: 200px" | ||||
|           @change="search" | ||||
|         /> | ||||
|         <a-select | ||||
|           placeholder="请选择项目" | ||||
|           v-model:value="projectId" | ||||
|           :options="projectSel" | ||||
|           allow-clear | ||||
|           style="width: 200px" | ||||
|           @change="search" | ||||
|         ></a-select> | ||||
|         <a-button type="primary" @click="openCreateModal">新建</a-button> | ||||
|       </a-space> | ||||
|     </div> | ||||
|     <div class="content-box"> | ||||
|       <a-table | ||||
|         :columns="moduleCfgCols" | ||||
|         :data-source="dataList" | ||||
|         :pagination="false" | ||||
|         size="small" | ||||
|         bordered | ||||
|       > | ||||
|         <template #bodyCell="{ column, record }"> | ||||
|           <template v-if="column.dataIndex === 'is_show'"> | ||||
|             <a-switch | ||||
|               :checked="record.is_show" | ||||
|               :checkedValue="1" | ||||
|               :unCheckedValue="0" | ||||
|               @change="toChangeStatus(record.modular_id, $event)" | ||||
|             /> | ||||
|           </template> | ||||
|           <template v-if="column.dataIndex === 'action'"> | ||||
|             <a-space> | ||||
|               <a-button type="link" size="small" @click="openFieldModal(record)" | ||||
|                 >字段管理</a-button | ||||
|               > | ||||
|               <a-button | ||||
|                 type="link" | ||||
|                 size="small" | ||||
|                 @click="toGetModularDetail(record.modular_id)" | ||||
|                 >编辑</a-button | ||||
|               > | ||||
|               <a-popconfirm | ||||
|                 title="确定删除吗?" | ||||
|                 @confirm="toDelete(record.modular_id)" | ||||
|               > | ||||
|                 <a-button type="link" size="small">删除</a-button> | ||||
|               </a-popconfirm> | ||||
|             </a-space> | ||||
|           </template> | ||||
|         </template> | ||||
|       </a-table> | ||||
|       <a-pagination | ||||
|         v-model:current="pageState.page" | ||||
|         :total="pageState.total" | ||||
|         :page-size="pageState.perPage" | ||||
|         :hide-on-single-page="false" | ||||
|         size="small" | ||||
|         class="pagination-box" | ||||
|         @change="toGetModularList" | ||||
|       /> | ||||
|     </div> | ||||
|     <CreateModal | ||||
|       :width="700" | ||||
|       :open="modalState.visible" | ||||
|       :title="modalState.title" | ||||
|       :type="modalState.type" | ||||
|       :data="modalState.data" | ||||
|       :projectSelect="projectSel" | ||||
|       @cancel="modalState.visible = false" | ||||
|       @ok="toSave" | ||||
|     /> | ||||
|     <FieldModal | ||||
|       title="字段管理" | ||||
|       width="80%" | ||||
|       :open="fieldModalState.visible" | ||||
|       :modularId="fieldModalState.modularId" | ||||
|       @cancel="fieldModalState.visible = false" | ||||
|     /> | ||||
|   </div> | ||||
| </template> | ||||
| <script setup> | ||||
| import { ref, reactive, onMounted } from "vue"; | ||||
| import { message } from "ant-design-vue"; | ||||
| import { moduleCfgCols } from "./config"; | ||||
| import { | ||||
|   getModularList, | ||||
|   deleteModular, | ||||
|   getModularDetail, | ||||
|   getProjectSelect, | ||||
|   saveModular, | ||||
|   updateStatus, | ||||
| } from "./service"; | ||||
| import CreateModal from "./components/create-modal.vue"; | ||||
| import FieldModal from "./components/field-modal.vue"; | ||||
| 
 | ||||
| const dataList = ref([]); | ||||
| const listLoading = ref(false); | ||||
| const saveLoading = ref(false); | ||||
| const detailLoading = ref(false); | ||||
| const modularName = ref(""); | ||||
| const projectId = ref(); | ||||
| const projectSel = ref([]); | ||||
| const modalState = reactive({ | ||||
|   title: "", | ||||
|   visible: false, | ||||
|   type: "", // add - 新建,edit - 编辑 | ||||
|   data: {}, | ||||
| }); | ||||
| const fieldModalState = reactive({ | ||||
|   visible: false, | ||||
|   title: "", | ||||
|   modularId: undefined, | ||||
| }); | ||||
| 
 | ||||
| const pageState = reactive({ | ||||
|   page: 1, | ||||
|   pageSize: 20, | ||||
|   total: 0, | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => { | ||||
|   toGetModularList(); | ||||
|   toGetProjectSel(); | ||||
| }); | ||||
| 
 | ||||
| const toGetProjectSel = () => { | ||||
|   getProjectSelect().then((res) => { | ||||
|     projectSel.value = res.data; | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| const toGetModularList = () => { | ||||
|   listLoading.value = true; | ||||
|   getModularList({ | ||||
|     page: pageState.page, | ||||
|     perPage: pageState.pageSize, | ||||
|     modularName: modularName.value, | ||||
|     projectId: projectId.value, | ||||
|   }).then((res) => { | ||||
|     dataList.value = res.data.list; | ||||
|     pageState.total = res.data.total; | ||||
|     listLoading.value = false; | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| // 详情 | ||||
| const toGetModularDetail = (modularId) => { | ||||
|   detailLoading.value = true; | ||||
|   modalState.visible = true; | ||||
|   modalState.title = "编辑"; | ||||
|   modalState.type = "edit"; | ||||
|   getModularDetail({ modularId }) | ||||
|     .then((res) => { | ||||
|       modalState.data = res.data; | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       detailLoading.value = false; | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| // 保存 | ||||
| const toSave = (data) => { | ||||
|   saveLoading.value = true; | ||||
|   saveModular(data) | ||||
|     .then(() => { | ||||
|       message.success("保存成功"); | ||||
|       modalState.visible = false; | ||||
|       toGetModularList(); | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       saveLoading.value = false; | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| // 删除 | ||||
| const toDelete = (id) => { | ||||
|   deleteModular({ modular_id: id }).then(() => { | ||||
|     message.success("删除成功"); | ||||
|     search(); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| const toChangeStatus = (id, status) => { | ||||
|   updateStatus({ | ||||
|     modular_id: id, | ||||
|     status, | ||||
|   }).then(() => { | ||||
|     message.success("修改成功"); | ||||
|     search(); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| // 点击新建 | ||||
| const openCreateModal = () => { | ||||
|   modalState.visible = true; | ||||
|   modalState.title = "新建"; | ||||
|   modalState.type = "add"; | ||||
|   modalState.data = {}; | ||||
| }; | ||||
| 
 | ||||
| const search = () => { | ||||
|   pageState.page = 1; | ||||
|   toGetModularList(); | ||||
| }; | ||||
| 
 | ||||
| const openFieldModal = (record) => { | ||||
|   fieldModalState.visible = true; | ||||
|   fieldModalState.modularId = record.modular_id; | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style lang="less"> | ||||
| .header-box { | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
| 
 | ||||
| .ant-table-wrapper { | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
| 
 | ||||
| .pagination-box { | ||||
|   text-align: center; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										108
									
								
								src/views/config-manage/module-cfg/service.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								src/views/config-manage/module-cfg/service.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,108 @@ | ||||
| import { get, post } from "@/utils/request"; | ||||
| 
 | ||||
| // 获取数据表配置列表
 | ||||
| export function getModularList({ page, perPage, modularName, projectId }) { | ||||
|   return get({ | ||||
|     url: "/api/v1/modular/list", | ||||
|     params: { | ||||
|       page, | ||||
|       per_page: perPage, | ||||
|       modular_name: modularName, | ||||
|       project_id: projectId, | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 获取数据表配置详情
 | ||||
| export function getModularDetail({ modularId }) { | ||||
|   return get({ | ||||
|     url: "/api/v1/modular/info", | ||||
|     params: { | ||||
|       modular_id: modularId, | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 保存数据库配置
 | ||||
| export function saveModular(data) { | ||||
|   return post({ | ||||
|     url: "/api/v1/modular/save", | ||||
|     data, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 删除数据库配置
 | ||||
| export function deleteModular(data) { | ||||
|   return post({ | ||||
|     url: "/api/v1/modular/del", | ||||
|     data, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 修改数据表状态
 | ||||
| export function updateStatus(data) { | ||||
|   return post({ | ||||
|     url: "/api/v1/modular/change-status", | ||||
|     data, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 项目下拉
 | ||||
| export function getProjectSelect() { | ||||
|   return get({ | ||||
|     url: `/api/v1/project/get-project-drop`, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 展示类型下拉
 | ||||
| export function getShowTypeSelect() { | ||||
|   return get({ | ||||
|     url: `/api/v1/modular/get-show-type-drop`, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 字段类型下拉
 | ||||
| export function getFieldTypeSelect() { | ||||
|   return get({ | ||||
|     url: `/api/v1/field/get-field-type-drop`, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 获取字段列表
 | ||||
| export function getFieldList({ modularId, fieldName, page, perPage }) { | ||||
|   return get({ | ||||
|     url: "/api/v1/field/list", | ||||
|     params: { | ||||
|       modular_id: modularId, | ||||
|       field_name: fieldName, | ||||
|       page, | ||||
|       per_page: perPage, | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 获取字段详情
 | ||||
| export function getFieldDetail({ fieldId }) { | ||||
|   return get({ | ||||
|     url: "/api/v1/field/info", | ||||
|     params: { | ||||
|       field_id: fieldId, | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 保存字段
 | ||||
| export function saveField(data) { | ||||
|   return post({ | ||||
|     url: "/api/v1/field/save", | ||||
|     data, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 删除字段
 | ||||
| export function deleteField(data) { | ||||
|   return post({ | ||||
|     url: "/api/v1/field/del", | ||||
|     data, | ||||
|   }); | ||||
| } | ||||
							
								
								
									
										176
									
								
								src/views/config-manage/project-cfg/components/create-modal.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								src/views/config-manage/project-cfg/components/create-modal.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,176 @@ | ||||
| <template> | ||||
|   <a-modal :open="open" @ok="handleOk"> | ||||
|     <a-form | ||||
|       :model="formData" | ||||
|       ref="formRef" | ||||
|       :rules="formRules" | ||||
|       :label-col="{ span: 4 }" | ||||
|       :wrapper-col="{ span: 20 }" | ||||
|     > | ||||
|       <a-form-item label="项目名称" name="project_name"> | ||||
|         <a-input | ||||
|           placeholder="请输入项目名称,例如:OA" | ||||
|           v-model:value="formData.project_name" | ||||
|         /> | ||||
|       </a-form-item> | ||||
|       <a-form-item label="展示状态" name="is_show"> | ||||
|         <a-switch | ||||
|           v-model:checked="formData.is_show" | ||||
|           :checkedValue="1" | ||||
|           :unCheckedValue="0" | ||||
|         /> | ||||
|       </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-button type="primary" @click="toCheckDbConnect" | ||||
|             >检测数据库连接</a-button | ||||
|           > | ||||
|         </a-space> | ||||
|       </a-form-item> | ||||
|     </a-form> | ||||
|   </a-modal> | ||||
| </template> | ||||
| 
 | ||||
| <script setup> | ||||
| import { ref, watch } from "vue"; | ||||
| import { checkDbConnect } from "@/views/config-manage/project-cfg/service"; | ||||
| import { message } from "ant-design-vue"; | ||||
| 
 | ||||
| const props = defineProps({ | ||||
|   open: { | ||||
|     type: Boolean, | ||||
|     default: false, | ||||
|   }, | ||||
|   type: { | ||||
|     type: String, | ||||
|     default: "add", | ||||
|   }, | ||||
|   data: { | ||||
|     type: Object, | ||||
|     default: () => ({}), | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| const emit = defineEmits(["ok"]); | ||||
| const formRules = { | ||||
|   project_name: [ | ||||
|     { required: true, message: "请输入项目名称", trigger: "submit" }, | ||||
|   ], | ||||
|   database_address: [ | ||||
|     { required: true, message: "请输入数据库地址", trigger: "submit" }, | ||||
|   ], | ||||
|   database_port: [ | ||||
|     { required: true, message: "请输入数据库端口", trigger: "submit" }, | ||||
|   ], | ||||
|   database_name: [ | ||||
|     { required: true, message: "请输入数据库名称", trigger: "submit" }, | ||||
|   ], | ||||
|   database_username: [ | ||||
|     { required: true, message: "请输入数据库用户", trigger: "submit" }, | ||||
|   ], | ||||
|   database_password: [ | ||||
|     { required: true, message: "请输入数据库密码", trigger: "submit" }, | ||||
|   ], | ||||
| }; | ||||
| 
 | ||||
| const formRef = ref(); | ||||
| const formData = ref({ | ||||
|   project_name: undefined, | ||||
|   is_show: 0, | ||||
|   database_address: undefined, | ||||
|   database_port: undefined, | ||||
|   database_name: undefined, | ||||
|   database_username: undefined, | ||||
|   database_password: undefined, | ||||
| }); | ||||
| 
 | ||||
| watch( | ||||
|   () => props.data, | ||||
|   (newVal) => { | ||||
|     if (props.type === "add") { | ||||
|       resetFormData(); | ||||
|     } else { | ||||
|       formData.value = newVal; | ||||
|     } | ||||
|   } | ||||
| ); | ||||
| 
 | ||||
| // 检查数据库连接 | ||||
| const toCheckDbConnect = () => { | ||||
|   if (validateConnect()) { | ||||
|     checkDbConnect({ | ||||
|       database_name: formData.value.database_name, | ||||
|       database_port: formData.value.database_port, | ||||
|       database_address: formData.value.database_address, | ||||
|       database_username: formData.value.database_username, | ||||
|       database_password: formData.value.database_password, | ||||
|     }).then((res) => { | ||||
|       message.success(res.message); | ||||
|     }); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| const validateConnect = () => { | ||||
|   const fields = { | ||||
|     database_name: "请输入数据库名称", | ||||
|     database_port: "请输入数据库端口", | ||||
|     database_address: "请输入数据库地址", | ||||
|     database_username: "请输入数据库用户", | ||||
|     database_password: "请输入数据库密码", | ||||
|   }; | ||||
|   for (const key in fields) { | ||||
|     if (!formData.value[key]) { | ||||
|       message.error(fields[key]); | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|   return true; | ||||
| }; | ||||
| 
 | ||||
| const resetFormData = () => { | ||||
|   formData.value = { | ||||
|     project_name: undefined, | ||||
|     is_show: 0, | ||||
|     database_address: undefined, | ||||
|     database_port: undefined, | ||||
|     database_name: undefined, | ||||
|     database_username: undefined, | ||||
|     database_password: undefined, | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| const handleOk = () => { | ||||
|   formRef.value.validate().then(() => { | ||||
|     emit("ok", formData.value); | ||||
|   }); | ||||
| }; | ||||
| </script> | ||||
							
								
								
									
										8
									
								
								src/views/config-manage/project-cfg/config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/views/config-manage/project-cfg/config.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,8 @@ | ||||
| export const projectCfgCols = [ | ||||
|   { dataIndex: 'project_id', title: '编号', align: 'center'}, | ||||
|   { dataIndex: 'project_name', title: '项目名称', align: 'center'}, | ||||
|   { dataIndex: 'database_name', title: '数据库名', align: 'center'}, | ||||
|   { dataIndex: 'is_show', title: '展示状态', align: 'center'}, | ||||
|   // { dataIndex: 'sort', title: '排序', align: 'center'},
 | ||||
|   { dataIndex: 'action', title: '操作', align: 'center'}, | ||||
| ]; | ||||
							
								
								
									
										200
									
								
								src/views/config-manage/project-cfg/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								src/views/config-manage/project-cfg/index.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,200 @@ | ||||
| <template> | ||||
|   <div class="normal-container project-cfg-box"> | ||||
|     <div class="header-box"> | ||||
|       <a-space> | ||||
|         <a-input | ||||
|           v-model:value="projectName" | ||||
|           placeholder="请输入项目名称" | ||||
|           allow-clear | ||||
|           style="width: 200px" | ||||
|           @change="search" | ||||
|         /> | ||||
|         <a-button type="primary" @click="openCreateModal">新建</a-button> | ||||
|       </a-space> | ||||
|     </div> | ||||
|     <div class="content-box"> | ||||
|       <a-table | ||||
|         :columns="projectCfgCols" | ||||
|         :data-source="dataList" | ||||
|         :pagination="false" | ||||
|         size="small" | ||||
|         bordered | ||||
|       > | ||||
|         <template #bodyCell="{ column, record }"> | ||||
|           <template v-if="column.dataIndex === 'is_show'"> | ||||
|             <a-switch | ||||
|               v-model:checked="record.is_show" | ||||
|               :checkedValue="1" | ||||
|               :unCheckedValue="0" | ||||
|               @change="toChangeStatus(record.project_id, $event)" | ||||
|             /> | ||||
|           </template> | ||||
|           <template v-if="column.dataIndex === 'action'"> | ||||
|             <a-space> | ||||
|               <a-button | ||||
|                 type="link" | ||||
|                 size="small" | ||||
|                 @click="toGetDetail(record.project_id)" | ||||
|                 >编辑</a-button | ||||
|               > | ||||
|               <a-popconfirm | ||||
|                 title="确定删除?" | ||||
|                 @confirm="toDelete(record.project_id)" | ||||
|               > | ||||
|                 <a-button type="link" size="small">删除</a-button> | ||||
|               </a-popconfirm> | ||||
|             </a-space> | ||||
|           </template> | ||||
|         </template> | ||||
|       </a-table> | ||||
|       <a-pagination | ||||
|         v-model:current="pageState.page" | ||||
|         :total="pageState.total" | ||||
|         :page-size="pageState.perPage" | ||||
|         :hide-on-single-page="false" | ||||
|         size="small" | ||||
|         class="pagination-box" | ||||
|         @change="toGetProjectList" | ||||
|       /> | ||||
|     </div> | ||||
|     <CreateModal | ||||
|       :width="700" | ||||
|       :open="modalState.visible" | ||||
|       :title="modalState.title" | ||||
|       :type="modalState.type" | ||||
|       :data="modalState.data" | ||||
|       :confirmLoading="saveLoading" | ||||
|       @cancel="modalState.visible = false" | ||||
|       @ok="toSave" | ||||
|     /> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script setup> | ||||
| import { onMounted, ref, reactive } from "vue"; | ||||
| import { message } from "ant-design-vue"; | ||||
| import { projectCfgCols } from "./config"; | ||||
| import { | ||||
|   getProjectList, | ||||
|   saveProject, | ||||
|   deleteProject, | ||||
|   getProjectDetail, | ||||
|   updateStatus, | ||||
| } from "./service"; | ||||
| import CreateModal from "./components/create-modal.vue"; | ||||
| 
 | ||||
| const dataList = ref([]); | ||||
| const listLoading = ref(false); | ||||
| const saveLoading = ref(false); | ||||
| const detailLoading = ref(false); | ||||
| const projectName = ref(""); | ||||
| 
 | ||||
| const modalState = reactive({ | ||||
|   title: undefined, | ||||
|   visible: false, | ||||
|   type: "", // add - 新建,edit - 编辑 | ||||
|   data: { | ||||
|     project_name: undefined, | ||||
|     is_show: 0, | ||||
|     database_address: undefined, | ||||
|     database_port: undefined, | ||||
|     database_name: undefined, | ||||
|     database_username: undefined, | ||||
|     database_password: undefined, | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| const pageState = reactive({ | ||||
|   page: 1, | ||||
|   perPage: 20, | ||||
|   total: 0, | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => { | ||||
|   toGetProjectList(); | ||||
| }); | ||||
| 
 | ||||
| // 获取列表 | ||||
| const toGetProjectList = () => { | ||||
|   listLoading.value = true; | ||||
|   getProjectList({ | ||||
|     page: pageState.page, | ||||
|     perPage: pageState.perPage, | ||||
|     projectName: projectName.value, | ||||
|   }) | ||||
|     .then((res) => { | ||||
|       dataList.value = res.data.list; | ||||
|       pageState.total = res.data.total; | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       listLoading.value = false; | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| // 保存 | ||||
| const toSave = (data) => { | ||||
|   saveLoading.value = true; | ||||
|   saveProject(data) | ||||
|     .then(() => { | ||||
|       message.success("保存成功"); | ||||
|       modalState.visible = false; | ||||
|       toGetProjectList(); | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       saveLoading.value = false; | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| // 获取详情 | ||||
| const toGetDetail = (projectId) => { | ||||
|   detailLoading.value = true; | ||||
|   modalState.visible = true; | ||||
|   modalState.title = "编辑"; | ||||
|   modalState.type = "edit"; | ||||
|   getProjectDetail({ projectId }).then((res) => { | ||||
|     modalState.data = res.data; | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| // 删除 | ||||
| const toDelete = (id) => { | ||||
|   deleteProject({ projectId: id }).then(() => { | ||||
|     message.success("删除成功"); | ||||
|     search(); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| const toChangeStatus = (id, status) => { | ||||
|   updateStatus({ project_id: id, status }).then(() => { | ||||
|     message.success("修改成功"); | ||||
|     search(); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| const search = () => { | ||||
|   pageState.page = 1; | ||||
|   toGetProjectList(); | ||||
| }; | ||||
| 
 | ||||
| // 点击新建 | ||||
| const openCreateModal = () => { | ||||
|   modalState.visible = true; | ||||
|   modalState.title = "新建"; | ||||
|   modalState.type = "add"; | ||||
|   modalState.data = {}; | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style lang="less" scope> | ||||
| .header-box { | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
| 
 | ||||
| .ant-table-wrapper { | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
| 
 | ||||
| .pagination-box { | ||||
|   text-align: center; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										57
									
								
								src/views/config-manage/project-cfg/service.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								src/views/config-manage/project-cfg/service.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,57 @@ | ||||
| import { get, post } from "@/utils/request"; | ||||
| 
 | ||||
| // 获取项目列表
 | ||||
| export function getProjectList({ page, perPage, projectName }) { | ||||
|   return get({ | ||||
|     url: `/api/v1/project/list`, | ||||
|     params: { | ||||
|       page, | ||||
|       per_page: perPage, | ||||
|       project_name: projectName, | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 获取项目详情
 | ||||
| export function getProjectDetail({ projectId }) { | ||||
|   return get({ | ||||
|     url: `api/v1/project/info`, | ||||
|     params: { | ||||
|       project_id: projectId, | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 保存
 | ||||
| export function saveProject(data) { | ||||
|   return post({ | ||||
|     url: `/api/v1/project/save`, | ||||
|     data, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 删除
 | ||||
| export function deleteProject({ projectId }) { | ||||
|   return post({ | ||||
|     url: `/api/v1/project/del`, | ||||
|     data: { | ||||
|       project_id: projectId, | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 检测数据库链接
 | ||||
| export function checkDbConnect(data) { | ||||
|   return post({ | ||||
|     url: `/api/v1/project/check-database-connect`, | ||||
|     data, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 修改展示状态
 | ||||
| export function updateStatus(data) { | ||||
|   return post({ | ||||
|     url: `/api/v1/project/change-status`, | ||||
|     data, | ||||
|   }); | ||||
| } | ||||
							
								
								
									
										110
									
								
								src/views/config-manage/view-cfg/components/create-modal.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								src/views/config-manage/view-cfg/components/create-modal.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,110 @@ | ||||
| <template> | ||||
|   <a-modal @ok="handleOk"> | ||||
|     <a-form | ||||
|       :model="formData" | ||||
|       ref="formRef" | ||||
|       :rules="formRules" | ||||
|       :label-col="{ span: 4 }" | ||||
|       :wrapper-col="{ span: 20 }" | ||||
|     > | ||||
|       <a-form-item label="字段标题" name="field_title"> | ||||
|         <a-input | ||||
|           placeholder="请输入字段标题" | ||||
|           v-model:value="formData.field_title" | ||||
|         /> | ||||
|       </a-form-item> | ||||
|       <a-form-item label="字段名称" name="field_name"> | ||||
|         <a-input placeholder="请输入字段名称" v-model="formData.field_name" /> | ||||
|       </a-form-item> | ||||
|       <a-form-item label="搜索状态" name="is_search"> | ||||
|         <a-switch | ||||
|           v-model:checked="formData.is_search" | ||||
|           :checkedValue="1" | ||||
|           :unCheckedValue="0" | ||||
|         /> | ||||
|       </a-form-item> | ||||
|       <a-form-item label="字段类型" name="field_type_id"> | ||||
|         <a-select | ||||
|           placeholder="请选择字段类型" | ||||
|           v-model:value="formData.field_type_id" | ||||
|         /> | ||||
|       </a-form-item> | ||||
|       <a-form-item label="所属表名称" name="belong_to_table"> | ||||
|         <a-input | ||||
|           placeholder="请输入所属表名称" | ||||
|           v-model="formData.belong_to_table" | ||||
|         /> | ||||
|       </a-form-item> | ||||
|       <a-form-item label="sql数据源" name="original_sql"> | ||||
|         <a-input | ||||
|           placeholder="请输入sql数据源" | ||||
|           v-model="formData.original_sql" | ||||
|         /> | ||||
|       </a-form-item> | ||||
|     </a-form> | ||||
|   </a-modal> | ||||
| </template> | ||||
| 
 | ||||
| <script setup> | ||||
| import { ref, watch } from "vue"; | ||||
| 
 | ||||
| const props = defineProps({ | ||||
|   type: { | ||||
|     type: String, | ||||
|     default: "add", | ||||
|   }, | ||||
|   data: { | ||||
|     type: Object, | ||||
|     default: () => ({}), | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| const emit = defineEmits(["ok"]); | ||||
| const formRules = { | ||||
|   field_title: [ | ||||
|     { required: true, message: "请输入字段标题", trigger: "submit" }, | ||||
|   ], | ||||
|   field_name: [ | ||||
|     { required: true, message: "请输入字段名称", trigger: "submit" }, | ||||
|   ], | ||||
|   field_type_id: [ | ||||
|     { required: true, message: "请选择字段类型", trigger: "submit" }, | ||||
|   ], | ||||
|   belong_to_table: [ | ||||
|     { required: true, message: "请输入所属表", trigger: "submit" }, | ||||
|   ], | ||||
|   original_sql: [ | ||||
|     { required: true, message: "请输入sql数据源", trigger: "submit" }, | ||||
|   ], | ||||
| }; | ||||
| 
 | ||||
| const formRef = ref(); | ||||
| const formData = ref({ | ||||
|   field_title: undefined, | ||||
|   field_name: undefined, | ||||
|   is_search: 0, | ||||
|   field_type_id: undefined, | ||||
|   belong_to_table: undefined, | ||||
|   original_sql: undefined, | ||||
|   modular_id: undefined, | ||||
| }); | ||||
| 
 | ||||
| watch( | ||||
|   () => props.type, | ||||
|   (newVal) => { | ||||
|     if (newVal === "add") { | ||||
|       resetFormData(); | ||||
|     } else { | ||||
|       formData.value = props.data; | ||||
|     } | ||||
|   } | ||||
| ); | ||||
| 
 | ||||
| const resetFormData = () => {}; | ||||
| 
 | ||||
| const handleOk = () => { | ||||
|   formRef.value.validate().then(() => { | ||||
|     emit("ok", formData.value); | ||||
|   }); | ||||
| }; | ||||
| </script> | ||||
							
								
								
									
										10
									
								
								src/views/config-manage/view-cfg/config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/views/config-manage/view-cfg/config.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | ||||
| export const viewCfgCols = [ | ||||
|   { dataIndex: 'field_name', title: '字段名称', align: 'center'}, | ||||
|   { dataIndex: 'field_title', 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: 'action', title: '操作', align: 'center'}, | ||||
| ]; | ||||
							
								
								
									
										181
									
								
								src/views/config-manage/view-cfg/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								src/views/config-manage/view-cfg/index.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,181 @@ | ||||
| <template> | ||||
|   <div class="normal-container view-cfg-box"> | ||||
|     <div class="header-box"> | ||||
|       <a-space> | ||||
|         <a-input | ||||
|           v-model:value="fieldName" | ||||
|           placeholder="请输入字段名称" | ||||
|           allow-clear | ||||
|           style="width: 200px" | ||||
|           @change="search" | ||||
|         /> | ||||
|         <a-select | ||||
|           placeholder="请选择数据表id" | ||||
|           v-model:value="modularId" | ||||
|           allow-clear | ||||
|           style="width: 160px" | ||||
|           @change="search" | ||||
|         ></a-select> | ||||
|         <a-button type="primary" @click="openCreateModal">新建</a-button> | ||||
|       </a-space> | ||||
|     </div> | ||||
|     <div class="content-box"> | ||||
|       <a-table | ||||
|         :columns="viewCfgCols" | ||||
|         :data-source="dataList" | ||||
|         :pagination="false" | ||||
|         size="small" | ||||
|         bordered | ||||
|       > | ||||
|         <template #bodyCell="{ column, record }"> | ||||
|           <template v-if="column.dataIndex === 'action'"> | ||||
|             <a-space> | ||||
|               <a-button | ||||
|                 type="link" | ||||
|                 size="small" | ||||
|                 @click="toGetDetail(record.field_id)" | ||||
|                 >编辑</a-button | ||||
|               > | ||||
|               <a-popconfirm | ||||
|                 title="确定删除?" | ||||
|                 @confirm="toDelete(record.field_id)" | ||||
|               > | ||||
|                 <a-button type="link" size="small">删除</a-button> | ||||
|               </a-popconfirm> | ||||
|             </a-space> | ||||
|           </template> | ||||
|         </template> | ||||
|       </a-table> | ||||
|       <a-pagination | ||||
|         v-model:current="pageState.page" | ||||
|         :total="pageState.total" | ||||
|         :page-size="pageState.perPage" | ||||
|         :hide-on-single-page="false" | ||||
|         size="small" | ||||
|         class="pagination-box" | ||||
|         @change="toGetFieldList" | ||||
|       /> | ||||
|     </div> | ||||
|     <CreateModal | ||||
|       :width="700" | ||||
|       :open="modalState.visible" | ||||
|       :title="modalState.title" | ||||
|       :type="modalState.type" | ||||
|       :data="modalState.data" | ||||
|       @cancel="modalState.visible = false" | ||||
|       @ok="toSave" | ||||
|     /> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script setup> | ||||
| import { onMounted, ref, reactive } from "vue"; | ||||
| import { viewCfgCols } from "./config"; | ||||
| import { | ||||
|   getFieldList, | ||||
|   deleteField, | ||||
|   saveField, | ||||
|   getFieldDetail, | ||||
| } from "./service"; | ||||
| import CreateModal from "./components/create-modal.vue"; | ||||
| import { message } from "ant-design-vue"; | ||||
| 
 | ||||
| const listLoading = ref(false); | ||||
| const saveLoading = ref(false); | ||||
| const dataList = ref([]); | ||||
| const fieldName = ref(""); | ||||
| const modularId = ref(""); | ||||
| const modalState = reactive({ | ||||
|   title: undefined, | ||||
|   visible: false, | ||||
|   type: "", // add - 新建,edit - 编辑 | ||||
|   data: {}, | ||||
| }); | ||||
| const pageState = reactive({ | ||||
|   page: 1, | ||||
|   perPage: 20, | ||||
|   total: 0, | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => { | ||||
|   toGetFieldList(); | ||||
| }); | ||||
| 
 | ||||
| const toGetFieldList = () => { | ||||
|   listLoading.value = true; | ||||
|   getFieldList({ | ||||
|     fieldName: fieldName.value, | ||||
|     modularId: modularId.value, | ||||
|     page: pageState.page, | ||||
|     perPage: pageState.perPage, | ||||
|   }) | ||||
|     .then((res) => { | ||||
|       dataList.value = res.data.list; | ||||
|       pageState.total = res.data.total; | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       listLoading.value = false; | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| // 保存 | ||||
| const toSave = (data) => { | ||||
|   saveLoading.value = true; | ||||
|   saveField(data) | ||||
|     .then(() => { | ||||
|       message.success("保存成功"); | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       saveLoading.value = false; | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| // 获取详情 | ||||
| const toGetDetail = (fieldId) => { | ||||
|   modalState.visible = true; | ||||
|   modalState.title = "编辑"; | ||||
|   modalState.type = "edit"; | ||||
|   getFieldDetail({ fieldId }).then((res) => { | ||||
|     modalState.data = res.data; | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| // 删除 | ||||
| const toDelete = (fieldId) => { | ||||
|   deleteField({ field_id: fieldId }).then(() => { | ||||
|     message.success("删除成功"); | ||||
|     search(); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| // 点击新建 | ||||
| const openCreateModal = () => { | ||||
|   modalState.visible = true; | ||||
|   modalState.title = "新建"; | ||||
|   modalState.type = "add"; | ||||
|   modalState.data = {}; | ||||
| }; | ||||
| 
 | ||||
| const handleEdit = (record) => { | ||||
|   console.log(record); | ||||
| }; | ||||
| 
 | ||||
| const search = () => { | ||||
|   pageState.page = 1; | ||||
|   toGetFieldList(); | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style lang="less" scoped> | ||||
| .header-box { | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
| 
 | ||||
| .ant-table-wrapper { | ||||
|   margin-bottom: 10px; | ||||
| } | ||||
| 
 | ||||
| .pagination-box { | ||||
|   text-align: center; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										40
									
								
								src/views/config-manage/view-cfg/service.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/views/config-manage/view-cfg/service.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | ||||
| import { get, post } from "@/utils/request"; | ||||
| 
 | ||||
| // 获取列表
 | ||||
| export function getFieldList({ modularId, fieldName, page, perPage }) { | ||||
|   return get({ | ||||
|     url: "/api/v1/field/list", | ||||
|     params: { | ||||
|       modularId, | ||||
|       fieldName, | ||||
|       page, | ||||
|       perPage, | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 获取详情
 | ||||
| export function getFieldDetail({ fieldId }) { | ||||
|   return get({ | ||||
|     url: "/api/v1/field/info", | ||||
|     params: { | ||||
|       fieldId, | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 保存字段
 | ||||
| export function saveField(data) { | ||||
|   return post({ | ||||
|     url: "/api/v1/field/save", | ||||
|     data, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 删除字段
 | ||||
| export function deleteField(data) { | ||||
|   return post({ | ||||
|     url: "/api/v1/field/del", | ||||
|     data, | ||||
|   }); | ||||
| } | ||||
| @ -1,3 +0,0 @@ | ||||
| <template> | ||||
|   data | ||||
| </template> | ||||
| @ -1,3 +0,0 @@ | ||||
| <template> | ||||
|   create | ||||
| </template> | ||||
| @ -1,8 +0,0 @@ | ||||
| <template> | ||||
|   <div class="normal-container"> | ||||
|     111 | ||||
|   </div> | ||||
|   <div class="normal-container mt-16"> | ||||
|     222 | ||||
|   </div> | ||||
| </template> | ||||
							
								
								
									
										268
									
								
								src/views/view-all-manage/create-view/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										268
									
								
								src/views/view-all-manage/create-view/index.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,268 @@ | ||||
| <template> | ||||
|   <div class="normal-container"> | ||||
|     <div class="view-create-box"> | ||||
|       <div class="left-box"> | ||||
|         <a-form :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }"> | ||||
|           <a-form-item label="项目" | ||||
|             ><a-select | ||||
|               placeholder="请选择项目" | ||||
|               :options="projectSel" | ||||
|               v-model:value="projectId" | ||||
|               @change="onProjectChange" | ||||
|             ></a-select | ||||
|           ></a-form-item> | ||||
|           <a-form-item label="数据表"> | ||||
|             <a-select | ||||
|               placeholder="请选择" | ||||
|               :options="modularSel" | ||||
|               v-model:value="modularId" | ||||
|               @change="onModularChange" | ||||
|             ></a-select> | ||||
|           </a-form-item> | ||||
|           <a-form-item label="字段"> | ||||
|             <a-checkbox-group v-if="fieldList.length" v-model:value="fieldIds"> | ||||
|               <a-checkbox | ||||
|                 v-for="(item, index) in fieldList" | ||||
|                 :key="index" | ||||
|                 :value="item.value" | ||||
|                 >{{ item.label }}</a-checkbox | ||||
|               > | ||||
|             </a-checkbox-group> | ||||
|             <a-empty v-else description="暂无字段数据" /> | ||||
|           </a-form-item> | ||||
|         </a-form> | ||||
|         <div class="footer"> | ||||
|           <a-button | ||||
|             class="preview-btn" | ||||
|             :loading="previewLoading" | ||||
|             @click="toPreview" | ||||
|             >预览</a-button | ||||
|           > | ||||
|           <a-button type="primary" @click="addViewName">点击保存</a-button> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="right-box"> | ||||
|         <div class="y-table-container" v-if="previewData.type === 'table'"> | ||||
|           <div class="y-table-filter"> | ||||
|             <div | ||||
|               v-for="(item, index) in previewData.filterConfig" | ||||
|               :key="item.name" | ||||
|               class="filter-item" | ||||
|             > | ||||
|               <span>{{ item.label }}:</span> | ||||
|               <a-select | ||||
|                 v-if="item.type === 'select'" | ||||
|                 class="input-item" | ||||
|                 :options="item.options" | ||||
|                 v-model:value="previewData.filterData[item.name]" | ||||
|                 placeholder="请选择" | ||||
|                 @change="toFilt" | ||||
|               ></a-select> | ||||
|               <a-input | ||||
|                 v-else | ||||
|                 class="input-item" | ||||
|                 placeholder="请输入" | ||||
|                 v-model:value="previewData.filterData[item.name]" | ||||
|                 @change=" | ||||
|                   (e) => { | ||||
|                     toFilt(item.name, e.target.value); | ||||
|                   } | ||||
|                 " | ||||
|               /> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div class="y-table-content"> | ||||
|             <a-table | ||||
|               :columns="previewData.columnConfig" | ||||
|               :data-source="previewData.dataList" | ||||
|               :pagination="false" | ||||
|               size="small" | ||||
|               bordered | ||||
|             ></a-table> | ||||
|             <a-pagination | ||||
|               v-model:current="previewData.page" | ||||
|               :total="previewData.total" | ||||
|               :page-size="previewData.perPage" | ||||
|               :hide-on-single-page="false" | ||||
|               size="small" | ||||
|               class="pagination-box" | ||||
|               @change="toPreview" | ||||
|             /> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <a-modal | ||||
|         :open="nameVisible" | ||||
|         title="保存视图" | ||||
|         :bodyStyle="{ paddingTop: '20px' }" | ||||
|         @cancel="nameVisible = false" | ||||
|         @ok="toSaveView" | ||||
|       > | ||||
|         <a-form :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }"> | ||||
|           <a-form-item label="视图名称"> | ||||
|             <a-input placeholder="请输入视图名称" v-model:value="previewName" /> | ||||
|           </a-form-item> | ||||
|         </a-form> | ||||
|       </a-modal> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script setup> | ||||
| import { onMounted, reactive, ref } from "vue"; | ||||
| import { getProModularField, preview, saveView } from "./service"; | ||||
| import { message } from "ant-design-vue"; | ||||
| 
 | ||||
| const projectSel = ref([]); | ||||
| const modularSel = ref([]); | ||||
| const fieldList = ref([]); | ||||
| const projectId = ref(); | ||||
| const modularId = ref(); | ||||
| const fieldIds = ref([]); | ||||
| 
 | ||||
| const previewLoading = ref(false); | ||||
| const nameVisible = ref(false); | ||||
| const previewName = ref(); | ||||
| 
 | ||||
| const previewData = reactive({ | ||||
|   type: "", | ||||
|   filterConfig: [], // 筛选条件 | ||||
|   columnConfig: [], // 表格表头 | ||||
|   dataList: [], // 表格数据 | ||||
|   filterData: {}, | ||||
|   page: 1, | ||||
|   perPage: 20, | ||||
|   total: 0, | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => { | ||||
|   toGetProModularField(); | ||||
| }); | ||||
| 
 | ||||
| const toGetProModularField = () => { | ||||
|   getProModularField().then((res) => { | ||||
|     projectSel.value = res.data; | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| const onProjectChange = (val) => { | ||||
|   const target = projectSel.value.find((item) => item.value === val); | ||||
|   modularSel.value = target.child; | ||||
|   modularId.value = undefined; | ||||
|   fieldList.value = []; | ||||
|   fieldIds.value = []; | ||||
| }; | ||||
| 
 | ||||
| const onModularChange = (val) => { | ||||
|   const target = modularSel.value.find((item) => item.value === val); | ||||
|   fieldList.value = target.child; | ||||
| }; | ||||
| 
 | ||||
| const toPreview = () => { | ||||
|   previewLoading.value = true; | ||||
|   const filter = previewData.filterConfig.map((item) => { | ||||
|     return { | ||||
|       name: item.name, | ||||
|       type: item.type, | ||||
|       value: previewData.filterData[item.name], | ||||
|     }; | ||||
|   }); | ||||
|   preview({ | ||||
|     modularId: modularId.value, | ||||
|     fieldIds: fieldIds.value.toString(), | ||||
|     page: previewData.page, | ||||
|     perPage: previewData.perPage, | ||||
|     filter, | ||||
|   }) | ||||
|     .then((res) => { | ||||
|       previewData.type = res.data.type; | ||||
|       if (res.data.type === "table") { | ||||
|         previewData.filterConfig = res.data.filter; | ||||
|         previewData.filterConfig.forEach((item) => { | ||||
|           previewData.filterData[item.name] = previewData.filterData[item.name] | ||||
|             ? previewData.filterData[item.name] | ||||
|             : undefined; | ||||
|         }); | ||||
|         console.log("filterData", previewData.filterData); | ||||
|         previewData.columnConfig = res.data.header; | ||||
|         previewData.dataList = res.data.data; | ||||
|         previewData.total = res.data.count; | ||||
|       } | ||||
|     }) | ||||
|     .finally(() => { | ||||
|       previewLoading.value = false; | ||||
|     }); | ||||
| }; | ||||
| 
 | ||||
| const addViewName = () => { | ||||
|   nameVisible.value = true; | ||||
|   previewName.value = null; | ||||
| }; | ||||
| 
 | ||||
| const toSaveView = () => { | ||||
|   if (!previewName.value) { | ||||
|     message.error("请输入名称"); | ||||
|     return; | ||||
|   } | ||||
|   saveView({ | ||||
|     modularId: modularId.value, | ||||
|     fieldIds: fieldIds.value.toString(), | ||||
|     previewName: previewName.value, | ||||
|   }).then(() => { | ||||
|     message.success("保存成功"); | ||||
|     nameVisible.value = false; | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| const toFilt = (key, value) => { | ||||
|   previewData.filterData[key] = value; | ||||
|   previewData.page = 1; | ||||
|   toPreview(); | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style lang="less" scoped> | ||||
| .normal-container { | ||||
|   height: calc(100vh - 120px); | ||||
| } | ||||
| .view-create-box { | ||||
|   display: flex; | ||||
|   height: 100%; | ||||
| } | ||||
| .left-box { | ||||
|   width: 400px; | ||||
|   height: calc(100% - 20px); | ||||
|   padding: 10px; | ||||
|   border-right: 1px solid #ddd; | ||||
| 
 | ||||
|   .footer { | ||||
|     text-align: right; | ||||
|     .preview-btn { | ||||
|       margin-right: 10px; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| .right-box { | ||||
|   padding: 10px; | ||||
|   flex-grow: 1; | ||||
|   overflow: auto; | ||||
| } | ||||
| 
 | ||||
| .y-table-filter { | ||||
|   display: flex; | ||||
|   flex-wrap: wrap; | ||||
| } | ||||
| .filter-item { | ||||
|   margin-right: 10px; | ||||
|   margin-bottom: 6px; | ||||
| } | ||||
| .input-item { | ||||
|   width: 180px; | ||||
| } | ||||
| .y-table-content { | ||||
|   margin-top: 10px; | ||||
| } | ||||
| .pagination-box { | ||||
|   text-align: center; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										34
									
								
								src/views/view-all-manage/create-view/service.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/views/view-all-manage/create-view/service.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | ||||
| import { get, post } from "@/utils/request"; | ||||
| 
 | ||||
| // 项目-表-字段下拉
 | ||||
| export function getProModularField() { | ||||
|   return get({ | ||||
|     url: "/api/v1/field/get-project-modular-field-drop", | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 预览
 | ||||
| export function preview({ modularId, fieldIds, page, perPage, filter }) { | ||||
|   return post({ | ||||
|     url: "api/v1/preview/view", | ||||
|     data: { | ||||
|       modular_id: modularId, | ||||
|       field_ids: fieldIds, | ||||
|       page, | ||||
|       per_page: perPage, | ||||
|       filter, | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 点击保存
 | ||||
| export function saveView({ modularId, fieldIds, previewName }) { | ||||
|   return post({ | ||||
|     url: "api/v1/preview/save", | ||||
|     data: { | ||||
|       modular_id: modularId, | ||||
|       field_ids: fieldIds, | ||||
|       preview_name: previewName, | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
							
								
								
									
										5
									
								
								src/views/view-all-manage/view-list/config.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/views/view-all-manage/view-list/config.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,5 @@ | ||||
| export const viewListCols = [ | ||||
|   { dataIndex: 'preview_name', title: '视图名称', align: 'center' }, | ||||
|   { dataIndex: 'created_at', title: '创建时间', align: 'center' }, | ||||
|   { dataIndex: 'action', title: '操作', align: 'center' }, | ||||
| ]; | ||||
							
								
								
									
										165
									
								
								src/views/view-all-manage/view-list/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								src/views/view-all-manage/view-list/index.vue
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,165 @@ | ||||
| <template> | ||||
|   <div class="normal-container"> | ||||
|     <div class="view-list-box"> | ||||
|       <div class="left-box"> | ||||
|         <a-form :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }"> | ||||
|           <a-form-item label="项目"> | ||||
|             <a-select | ||||
|               :options="projectSel" | ||||
|               v-model:value="projectId" | ||||
|               placeholder="请选择项目" | ||||
|               @change="onProjectChange" | ||||
|             ></a-select> | ||||
|           </a-form-item> | ||||
|           <a-form-item label="数据表"> | ||||
|             <a-select | ||||
|               :options="modularSel" | ||||
|               v-model:value="modularId" | ||||
|               placeholder="请选择数据表" | ||||
|               @change="onModularChange" | ||||
|             ></a-select> | ||||
|           </a-form-item> | ||||
|         </a-form> | ||||
|         <a-table | ||||
|           :data-source="dataList" | ||||
|           :columns="viewListCols" | ||||
|           :pagination="false" | ||||
|           :row-class-name=" | ||||
|             (record) => | ||||
|               record.preview_id === selectedRowId ? 'selected-row' : '' | ||||
|           " | ||||
|           :custom-row=" | ||||
|             (record, index) => { | ||||
|               return { | ||||
|                 onClick: () => { | ||||
|                   selectedRowId = record.preview_id; | ||||
|                   toGetViewInfo(); | ||||
|                 }, | ||||
|               }; | ||||
|             } | ||||
|           " | ||||
|           size="small" | ||||
|           bordered | ||||
|         ></a-table> | ||||
|         <a-pagination | ||||
|           v-model:current="pageState.page" | ||||
|           :total="pageState.total" | ||||
|           :page-size="pageState.perPage" | ||||
|           :hide-on-single-page="false" | ||||
|           size="small" | ||||
|           class="pagination-box" | ||||
|           @change="toGetList" | ||||
|         /> | ||||
|       </div> | ||||
|       <div class="right-box"> | ||||
|         <y-table | ||||
|           v-if="selectViewInfo.type === 'table'" | ||||
|           :filterConfig="selectViewInfo.filter" | ||||
|           :dataList="selectViewInfo.data" | ||||
|           :columnConfig="selectViewInfo.header" | ||||
|           :total="selectViewInfo.count" | ||||
|           @toFilt=" | ||||
|             (params) => { | ||||
|               toGetViewInfo(params); | ||||
|             } | ||||
|           " | ||||
|         /> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| <script setup> | ||||
| import { onMounted, ref, reactive } from "vue"; | ||||
| import { getProModular, getViewList, getViewInfo } from "./service"; | ||||
| import { viewListCols } from "./config"; | ||||
| import yTable from "@/components/common/y-table.vue"; | ||||
| 
 | ||||
| const projectSel = ref([]); | ||||
| const modularSel = ref([]); | ||||
| const projectId = ref(); | ||||
| const modularId = ref(); | ||||
| const dataList = ref([]); | ||||
| const selectedRowId = ref(); | ||||
| const selectViewInfo = ref({ | ||||
|   type: "", | ||||
| }); | ||||
| 
 | ||||
| const pageState = reactive({ | ||||
|   page: 1, | ||||
|   perPage: 20, | ||||
|   total: 0, | ||||
| }); | ||||
| 
 | ||||
| onMounted(() => { | ||||
|   toGetProModular(); | ||||
| }); | ||||
| 
 | ||||
| const toGetProModular = () => { | ||||
|   getProModular().then((res) => { | ||||
|     projectSel.value = res.data; | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| const toGetList = () => { | ||||
|   getViewList({ | ||||
|     modularId: modularId.value, | ||||
|     page: pageState.page, | ||||
|     perPage: pageState.perPage, | ||||
|   }).then((res) => { | ||||
|     dataList.value = res.data.list; | ||||
|     pageState.total = res.data.total; | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| const toGetViewInfo = (params = {}) => { | ||||
|   getViewInfo({ | ||||
|     previewId: selectedRowId.value, | ||||
|     ...params, | ||||
|   }).then((res) => { | ||||
|     selectViewInfo.value = res.data; | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| const onProjectChange = (val) => { | ||||
|   modularSel.value = projectSel.value.find((item) => item.value === val).child; | ||||
|   modularId.value = null; | ||||
| }; | ||||
| 
 | ||||
| const onModularChange = () => { | ||||
|   pageState.page = 1; | ||||
|   toGetList(); | ||||
| }; | ||||
| </script> | ||||
| 
 | ||||
| <style lang="less" scoped> | ||||
| .normal-container { | ||||
|   height: calc(100vh - 120px); | ||||
| } | ||||
| 
 | ||||
| .view-list-box { | ||||
|   display: flex; | ||||
|   height: 100%; | ||||
| } | ||||
| 
 | ||||
| .left-box { | ||||
|   width: 400px; | ||||
|   height: calc(100% - 20px); | ||||
|   padding: 10px; | ||||
|   border-right: 1px solid #ddd; | ||||
| } | ||||
| 
 | ||||
| .selected-row { | ||||
|   background-color: beige; | ||||
| } | ||||
| 
 | ||||
| .pagination-box { | ||||
|   text-align: center; | ||||
|   margin-top: 10px; | ||||
| } | ||||
| .right-box { | ||||
|   padding: 10px; | ||||
|   flex-grow: 1; | ||||
|   overflow: auto; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										38
									
								
								src/views/view-all-manage/view-list/service.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/views/view-all-manage/view-list/service.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| import { get } from "@/utils/request"; | ||||
| 
 | ||||
| // 联动下拉
 | ||||
| export function getProModular() { | ||||
|   return get({ | ||||
|     url: "/api/v1/field/get-project-modular-drop", | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 视图列表
 | ||||
| export function getViewList({ modularId, page = 1, perPage = 20 }) { | ||||
|   return get({ | ||||
|     url: "/api/v1/preview/list", | ||||
|     params: { | ||||
|       modular_id: modularId, | ||||
|       page, | ||||
|       perPage: perPage, | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| // 查看视图
 | ||||
| export function getViewInfo({ | ||||
|   previewId, | ||||
|   page = 1, | ||||
|   perPage = 20, | ||||
|   filter = {}, | ||||
| }) { | ||||
|   return get({ | ||||
|     url: "/api/v1/preview/info", | ||||
|     params: { | ||||
|       preview_id: previewId, | ||||
|       page, | ||||
|       perPage: perPage, | ||||
|       filter, | ||||
|     }, | ||||
|   }); | ||||
| } | ||||
| @ -4,6 +4,7 @@ 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'; | ||||
| 
 | ||||
| // https://vitejs.dev/config/
 | ||||
| export default defineConfig({ | ||||
| @ -21,4 +22,8 @@ export default defineConfig({ | ||||
|       '@': fileURLToPath(new URL('./src', import.meta.url)), | ||||
|     }, | ||||
|   }, | ||||
|   server: { | ||||
|     hmr: true, | ||||
|     host: '0.0.0.0', | ||||
|   }, | ||||
| }); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 林梓阳
						林梓阳