调整界面和底座风格基本保持一致
This commit is contained in:
		
							
								
								
									
										201
									
								
								examples/App.vue
									
									
									
									
									
								
							
							
						
						
									
										201
									
								
								examples/App.vue
									
									
									
									
									
								
							| @@ -5,17 +5,17 @@ | ||||
|       <el-button type="text" @click="showTools=false">隐藏工具栏</el-button> | ||||
|       <el-button type="text" @click="handleLogin">点此登录</el-button> | ||||
|     </div> | ||||
|     <el-row class="main-content" type="flex"> | ||||
|       <el-scrollbar class="menu" v-if="showTools"> | ||||
|         <el-input size="small" v-model="search" placeholder="应用名称或文件名" clearable @change="recordSearch"/> | ||||
|         <el-menu router> | ||||
|           <el-menu-item v-for="(menu,j) in menus" :key="j" :index="menu.path"> | ||||
|             {{ menu.label }} | ||||
|           </el-menu-item> | ||||
|         </el-menu> | ||||
|       </el-scrollbar> | ||||
|       <router-view v-if="selectedApp"/> | ||||
|       <ai-empty v-else>请选择应用</ai-empty> | ||||
|     <el-row class="fill" type="flex"> | ||||
|       <slider-nav v-if="showTools"/> | ||||
|       <el-tabs class="layout fill" type="card" :value="currentTab" @tab-click="handleTabClick" | ||||
|                @tab-remove="handleTabRemove"> | ||||
|         <el-tab-pane label="默认页" class="layoutItem"> | ||||
|           <ai-empty>欢迎使用村微产品库</ai-empty> | ||||
|         </el-tab-pane> | ||||
|         <el-tab-pane v-for="op in tabs" :key="op.name" :closable="op.name!='工作台'" :name="op.name" :label="op.label" lazy> | ||||
|           <router-view/> | ||||
|         </el-tab-pane> | ||||
|       </el-tabs> | ||||
|     </el-row> | ||||
|     <div v-if="dialog" class="sign-box"> | ||||
|       <ai-sign style="margin: auto" :instance="$axios" :action="{login}" | ||||
| @@ -27,9 +27,11 @@ | ||||
|  | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
| import SliderNav from "./components/sliderNav"; | ||||
|  | ||||
| export default { | ||||
|   name: 'app', | ||||
|   components: {SliderNav}, | ||||
|   computed: { | ||||
|     ...mapState(['apps']), | ||||
|     serveName() { | ||||
| @@ -39,10 +41,6 @@ export default { | ||||
|       } | ||||
|       return names[process.env.NODE_ENV] | ||||
|     }, | ||||
|     menus() { | ||||
|       let reg = new RegExp(`.*${this.search.replace(/-/g,'')||''}.*`, 'gi') | ||||
|       return (this.apps || []).filter(e => !this.search || reg.test(e.name) || reg.test(e.label)) | ||||
|     }, | ||||
|     selectedApp() { | ||||
|       return this.$route.matched.length > 0 | ||||
|     }, | ||||
| @@ -50,14 +48,26 @@ export default { | ||||
|       let url = '/auth/oauth/token'; | ||||
|       /project\/sass/g.test(location.pathname) && (url += "?corpId=ww596787bb70f08288") | ||||
|       return url | ||||
|     }, | ||||
|     currentTab() { | ||||
|       let {name, query, hash} = this.$route | ||||
|       return [name, query?.id, hash].join("") | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     $route: { | ||||
|       immediate: true, | ||||
|       handler(v) { | ||||
|         this.getTabs(v) | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       token: "", | ||||
|       search: "", | ||||
|       dialog: false, | ||||
|       showTools: true | ||||
|       showTools: true, | ||||
|       tabs: [] | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
| @@ -86,12 +96,37 @@ export default { | ||||
|         this.dialog = true | ||||
|       }) | ||||
|     }, | ||||
|     recordSearch() { | ||||
|       localStorage.setItem("searchApp", this.search) | ||||
|     handleTabClick(tab) { | ||||
|       let to = {}, selectedTab = this.tabs.find(e => e.name == tab.name) | ||||
|       if (selectedTab) { | ||||
|         to = {...selectedTab, params: {tabclick: 1}} | ||||
|       } else { | ||||
|         let {name, query, hash} = tab | ||||
|         to = {name, query, hash, params: {tabclick: 1}} | ||||
|       } | ||||
|       this.$router.push({...to}) | ||||
|     }, | ||||
|     handleTabRemove(id = this.currentTab) { | ||||
|       let tabs = JSON.parse(JSON.stringify(this.tabs)), | ||||
|           index = tabs?.findIndex(e => id == e.name) | ||||
|       if (id == this.currentTab) { | ||||
|         let next = tabs?.[index + 1] || tabs?.[index - 1] | ||||
|         this.handleTabClick(next) | ||||
|       } | ||||
|       this.tabs.splice(index, 1) | ||||
|     }, | ||||
|     getTabs() { | ||||
|       let {name, query, hash} = this.$route | ||||
|       let tab = this.tabs.find(e => e.name == this.currentTab) | ||||
|       if (tab) { | ||||
|       } else if (name) { | ||||
|         let menu = this.apps.find(e => e.name == name) | ||||
|         this.tabs.push({name, query, hash, label: menu?.label}) | ||||
|       } | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.search = localStorage.getItem("searchApp") || "" | ||||
|     this.getTabs() | ||||
|     this.token = localStorage.getItem("ui-token") | ||||
|     if (this.token) this.getUserInfo() | ||||
|     wx = jWeixin | ||||
| @@ -112,35 +147,6 @@ html, body { | ||||
|   margin: 0; | ||||
| } | ||||
|  | ||||
| .villageFinance-autocomplete { | ||||
|   width: auto !important; | ||||
|  | ||||
|   li { | ||||
|     line-height: normal !important; | ||||
|     padding: 7px !important; | ||||
|     border-bottom: 1px solid #f1f1f1; | ||||
|  | ||||
|     &:hover { | ||||
|       background-color: #f4f4f4 !important; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .name { | ||||
|     text-overflow: ellipsis; | ||||
|     line-height: normal; | ||||
|     overflow: hidden; | ||||
|   } | ||||
|  | ||||
|   .addr { | ||||
|     font-size: 12px; | ||||
|     color: #b4b4b4; | ||||
|   } | ||||
|  | ||||
|   .highlighted .addr { | ||||
|     color: #ddd; | ||||
|   } | ||||
| } | ||||
|  | ||||
| #app { | ||||
|   font-family: 'Avenir', Helvetica, Arial, sans-serif; | ||||
|   -webkit-font-smoothing: antialiased; | ||||
| @@ -207,18 +213,6 @@ html, body { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   & > .main-content { | ||||
|     width: 100%; | ||||
|     flex: 1; | ||||
|     min-height: 0; | ||||
|     box-sizing: border-box; | ||||
|  | ||||
|     & > *:last-child { | ||||
|       flex: 1; | ||||
|       min-width: 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .sign-box { | ||||
|     z-index: 99; | ||||
|     margin: -10px; | ||||
| @@ -229,5 +223,90 @@ html, body { | ||||
|     height: 100%; | ||||
|     background: rgba(0, 0, 0, 0.2); | ||||
|   } | ||||
|  | ||||
|  | ||||
| } | ||||
|  | ||||
| .layout { | ||||
|   flex: 1; | ||||
|   min-width: 0; | ||||
|   height: 100%; | ||||
|   background: #F5F6F9; | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|  | ||||
|   & > .el-tabs__header { | ||||
|     margin-bottom: 0; | ||||
|     background: linear-gradient(180deg, #FCFCFC 0%, #E0E2E4 100%); | ||||
|     height: 40px; | ||||
|     display: flex; | ||||
|     align-items: flex-end; | ||||
|     border: none; | ||||
|  | ||||
|     .el-tabs__nav { | ||||
|       border: none; | ||||
|     } | ||||
|  | ||||
|     .el-tabs__item { | ||||
|       padding: 0 8px 0 12px; | ||||
|       text-align: left; | ||||
|       min-width: 130px; | ||||
|       height: 36px; | ||||
|       line-height: 36px; | ||||
|       border: none; | ||||
|       color: #555; | ||||
|       font-size: 12px; | ||||
|  | ||||
|       & + .el-tabs__item { | ||||
|         margin-left: 2px; | ||||
|       } | ||||
|  | ||||
|       .el-icon-close { | ||||
|         float: right; | ||||
|         width: auto; | ||||
|         height: 100%; | ||||
|         line-height: 36px; | ||||
|         background: transparent; | ||||
|         font-size: 16px; | ||||
|         color: #89b; | ||||
|  | ||||
|         &:hover { | ||||
|           color: #000; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       &.is-active { | ||||
|         border: 1px solid #D8DCE3; | ||||
|         border-bottom: none; | ||||
|         border-radius: 4px 4px 0 0; | ||||
|         background: #F5F6F9; | ||||
|         color: #222; | ||||
|  | ||||
|         &:after { | ||||
|           display: none; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       &:after { | ||||
|         position: absolute; | ||||
|         right: 0; | ||||
|         content: " "; | ||||
|         width: 1px; | ||||
|         background: #D8DCE3; | ||||
|         height: 24px; | ||||
|         top: 50%; | ||||
|         transform: translateY(-50%); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .el-tabs__content { | ||||
|     flex: 1; | ||||
|     min-height: 0; | ||||
|  | ||||
|     .el-tab-pane { | ||||
|       height: 100%; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|   | ||||
							
								
								
									
										254
									
								
								examples/components/sliderNav.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										254
									
								
								examples/components/sliderNav.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,254 @@ | ||||
| <template> | ||||
|   <section class="sliderNav"> | ||||
|     <el-input class="searchApp" size="small" v-model="searchApp" placeholder="搜索应用" clearable | ||||
|               prefix-icon="iconfont iconSearch" @change="recordSearch"/> | ||||
|     <el-scrollbar class="ai-menu"> | ||||
|       <div v-for="(item,i) in navs" :key="i"> | ||||
|         <div class="rootMenu" :class="{isActive:menuPath.includes(item.name)}" | ||||
|              @click.stop="openKidMenu(item)"> | ||||
|           <i class="prep-icon" :class="item.style||'iconfont iconloudongmoxing'"/> | ||||
|           <span class="menuName fill" v-text="item.label"/> | ||||
|           <i v-if="item.children" class="iconfont" :class="arrowIcon(item.showChildren)"/> | ||||
|         </div> | ||||
|         <div class="kidMenu" v-if="item.showChildren" @click.stop> | ||||
|           <div class="kidPane"> | ||||
|             <div class="submenu wrap" flex v-for="menu in item.children" :key="menu.name"> | ||||
|               <b v-text="menu.label" :class="{menuBtn:menu.type==1,current:menuPath.includes(menu.name)}" | ||||
|                  @click="handleSelect(menu)"/> | ||||
|               <div class="menuBtn" v-for="kid in menu.children" :key="kid.name" v-text="kid.label" | ||||
|                    @click="handleSelect(kid)" | ||||
|                    :class="{current:menuPath.includes(kid.name)}"/> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="divider"/> | ||||
|     </el-scrollbar> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
|  | ||||
| export default { | ||||
|   name: "sliderNav", | ||||
|   data() { | ||||
|     return { | ||||
|       searchApp: "", | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user', 'apps']), | ||||
|     navs() { | ||||
|       let reg = new RegExp(`.*${this.searchApp?.replace(/-/g,'')||''}.*`, 'gi') | ||||
|       return (this.apps || []).filter(e => !this.searchApp || reg?.test(e.name) || reg?.test(e.label)) | ||||
|     }, | ||||
|     isConsoleRoute() { | ||||
|       return this.$route.name == "工作台" | ||||
|     }, | ||||
|     menuPath() { | ||||
|       let paths = [], current = this.apps?.find(e => e.name == this.$route.name) | ||||
|       const findParent = name => { | ||||
|         let menu = this.apps?.find(e => e.name == name) | ||||
|         if (menu) { | ||||
|           paths.push(menu.name) | ||||
|           if (!!menu.parentId) findParent(menu.parentId) | ||||
|         } | ||||
|       } | ||||
|       if (current) { | ||||
|         findParent(current.name) | ||||
|       } | ||||
|       return paths | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     openKidMenu(parent) { | ||||
|       if (parent.children) { | ||||
|         parent.showChildren = !parent.showChildren | ||||
|       } else { | ||||
|         this.handleSelect(parent) | ||||
|       } | ||||
|     }, | ||||
|     handleSelect(item) { | ||||
|       if (!item.path) return | ||||
|       if (item.name == this.$route.name) { | ||||
|         //避免同一路由跳转的BUG vue-router官方BUG | ||||
|       } else { | ||||
|         let {name, path} = item | ||||
|         if (/\?app=/.test(path)) { | ||||
|           this.goto({name, query: {app: path.replace(/.+\?app=/, '')}}) | ||||
|         } else if (/\?moduleId=/.test(path)) { | ||||
|           this.goto({name, query: {moduleId: path.replace(/.+\?moduleId=/, '')}}) | ||||
|         } else { | ||||
|           this.goto({name}) | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     goto(item) { | ||||
|       this.$router.push(item) | ||||
|     }, | ||||
|     subMenuIcon(flag) { | ||||
|       return flag ? 'iconfont iconArrow_Down' : "iconfont iconArrow_Right" | ||||
|     }, | ||||
|     arrowIcon(v) { | ||||
|       return v ? "iconArrow_Down" : "iconArrow_Right" | ||||
|     }, | ||||
|     recordSearch() { | ||||
|       localStorage.setItem("searchApp", this.searchApp) | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.searchApp = localStorage.getItem("searchApp") || "" | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .sliderNav { | ||||
|   width: 200px; | ||||
|   height: 100%; | ||||
|   transition: width .1s; | ||||
|   display: flex; | ||||
|   justify-content: space-between; | ||||
|   flex-direction: column; | ||||
|   border-right: 1px solid #e5e5e5; | ||||
|   flex-shrink: 0; | ||||
|   box-sizing: border-box; | ||||
|   background: #EFF1F4; | ||||
|   color: #222; | ||||
|   position: relative; | ||||
|  | ||||
|   .kidMenu { | ||||
|     padding: 0 16px; | ||||
|     background: #EFF1F4; | ||||
|  | ||||
|     .rootName { | ||||
|       font-size: 20px; | ||||
|       color: #333; | ||||
|       cursor: default; | ||||
|     } | ||||
|  | ||||
|     .kidPane { | ||||
|       font-size: 13px; | ||||
|  | ||||
|       .submenu { | ||||
|         margin-top: 8px; | ||||
|         width: 100%; | ||||
|         color: #aaa; | ||||
|  | ||||
|         & > b { | ||||
|           width: 100%; | ||||
|           line-height: 28px; | ||||
|         } | ||||
|  | ||||
|         & > * { | ||||
|           cursor: default; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .menuBtn { | ||||
|         display: block; | ||||
|         width: 50%; | ||||
|         cursor: pointer; | ||||
|         line-height: 32px; | ||||
|         color: #333; | ||||
|         flex-shrink: 0; | ||||
|  | ||||
|         &:hover { | ||||
|           color: #26f; | ||||
|         } | ||||
|  | ||||
|         &.current { | ||||
|           color: #26f; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .rootMenu { | ||||
|     padding: 0 16px; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     height: 44px; | ||||
|     cursor: pointer; | ||||
|     box-shadow: 0px -1px 0px 0px #D8DCE3 inset, 0px 1px 0px 0px #FFF inset, -1px 0px 0px 0px #E5E5E5 inset; | ||||
|     gap: 8px; | ||||
|     font-size: 13px; | ||||
|  | ||||
|     .iconfont { | ||||
|       color: #89B; | ||||
|       font-size: 20px; | ||||
|     } | ||||
|  | ||||
|     &.isActive { | ||||
|       color: #26f; | ||||
|  | ||||
|       .iconfont { | ||||
|         color: #26f !important; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     &:hover { | ||||
|       color: #26f; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ::v-deep .ai-menu { | ||||
|     padding-left: 0; | ||||
|     flex: 1; | ||||
|     min-height: 0; | ||||
|  | ||||
|     .el-scrollbar__wrap { | ||||
|       overflow-x: auto; | ||||
|     } | ||||
|  | ||||
|     &::-webkit-scrollbar { | ||||
|       display: none; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ::v-deep .searchApp { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     height: 44px; | ||||
|     padding: 0 16px; | ||||
|     box-shadow: 0px -1px 0px 0px #E5E5E5 inset; | ||||
|  | ||||
|     .el-input__inner { | ||||
|       border: none; | ||||
|       background: inherit; | ||||
|       padding: 0 28px; | ||||
|     } | ||||
|  | ||||
|     .el-input__prefix { | ||||
|       left: 16px; | ||||
|  | ||||
|       .iconSearch { | ||||
|         font-size: 20px; | ||||
|         width: fit-content; | ||||
|         color: #89B; | ||||
|         line-height: 44px; | ||||
|       } | ||||
|  | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .divider { | ||||
|     color: #aaa; | ||||
|     border-top: 1px solid #ddd; | ||||
|     position: relative; | ||||
|     font-size: 12px; | ||||
|     margin: 16px 16px 32px; | ||||
|  | ||||
|     &:before { | ||||
|       content: "到达底部"; | ||||
|       position: absolute; | ||||
|       top: 50%; | ||||
|       left: 50%; | ||||
|       transform: translate(-50%, -50%); | ||||
|       padding: 0 16px; | ||||
|       background: #EFF1F4; | ||||
|       white-space: nowrap; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @@ -1,13 +1,10 @@ | ||||
| import store from "../store"; | ||||
| import {waiting} from "../utils"; | ||||
| import appEntry from "../views/apps/appEntry"; | ||||
| import router from "./router"; | ||||
|  | ||||
| export default { | ||||
|   routes: () => store.state.apps.map(e => { | ||||
|     return { | ||||
|       ...e, | ||||
|       component: () => import(`../views/apps/${e.entry}`) | ||||
|     } | ||||
|   }), | ||||
|   routes: () => store.state.apps, | ||||
|   init() { | ||||
|     //约束正则式 | ||||
|     store.commit("cleanApps") | ||||
| @@ -22,57 +19,16 @@ export default { | ||||
|       if (file.default) { | ||||
|         let {name, label} = file.default, | ||||
|             addApp = { | ||||
|               name: [path.replace(/\.\/([^\/]+)\/.*/, '$1'), name].join("_"), label: label || name, | ||||
|               path: path.replace(/\.(\/.+\/App.+)\.vue$/, '/$1'), | ||||
|               entry: 'appEntry', | ||||
|               name: path.replace(/\.\/?(vue)?/g, '')?.split("/").join("_"), label: label || name, | ||||
|               path: path.replace(/\.(\/.+\/App.+)\.vue$/, '$1'), | ||||
|               component: appEntry, | ||||
|               module: file.default | ||||
|             } | ||||
|         waiting.setContent(`加载${name}...`) | ||||
|         router.addRoute(addApp) | ||||
|         //命名规范入口文件必须以App开头 | ||||
|         return store.commit("addApp", addApp) | ||||
|       } else return 0 | ||||
|     }))).then(() => waiting.close()) | ||||
|     // let files = require.context('../../packages', true, /\.(\/.+)\/App[A-Z][^\/]+\.vue$/) | ||||
|     // files.keys().map(path => { | ||||
|     //   if (files(path).default) { | ||||
|     //     let {name, label} = files(path).default, | ||||
|     //         addApp = { | ||||
|     //           name, label: label || name, | ||||
|     //           path: path.replace(/\.(\/.+\/App.+)\.vue$/, '/packages$1'), | ||||
|     //           entry: 'appEntry', | ||||
|     //           module: files(path).default | ||||
|     //         } | ||||
|     //     //命名规范入口文件必须以App开头 | ||||
|     //     store.commit("addApp", addApp) | ||||
|     //   } | ||||
|     // }) | ||||
|     // let cores = require.context('../../core', true, /\.(\/.+)\/App[^\/]+\.vue$/) | ||||
|     // cores.keys().map(path => { | ||||
|     //   if (cores(path).default) { | ||||
|     //     let {name, label} = cores(path).default, | ||||
|     //         addApp = { | ||||
|     //           name, label: label || name, | ||||
|     //           path: path.replace(/\.(\/.+\/App.+)\.vue$/, '/core$1'), | ||||
|     //           entry: 'appEntry', | ||||
|     //           module: cores(path).default | ||||
|     //         } | ||||
|     //     //命名规范入口文件必须以App开头 | ||||
|     //     store.commit("addApp", addApp) | ||||
|     //   } | ||||
|     // }) | ||||
|     // let project = require.context('../../project', true, /\.(\/.+)\/App[^\/]+\.vue$/) | ||||
|     // project.keys().map(path => { | ||||
|     //   if (project(path).default) { | ||||
|     //     let {name, label} = project(path).default, | ||||
|     //         addApp = { | ||||
|     //           name: [path.replace(/\.\/([^\/]+)\/.*/, '$1'), name].join("_"), label: label || name, | ||||
|     //           path: path.replace(/\.(\/.+\/App.+)\.vue$/, '/project$1'), | ||||
|     //           entry: 'appEntry', | ||||
|     //           module: project(path).default | ||||
|     //         } | ||||
|     //     //命名规范入口文件必须以App开头 | ||||
|     //     store.commit("addApp", addApp) | ||||
|     //   } | ||||
|     // }) | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -28,6 +28,7 @@ export default { | ||||
|   flex: 1; | ||||
|   min-width: 0; | ||||
|   min-height: 0; | ||||
|   height: 100%; | ||||
|  | ||||
|   & > * { | ||||
|     height: 100%; | ||||
|   | ||||
| @@ -1,169 +0,0 @@ | ||||
| <template> | ||||
|   <section class="AppInterview"> | ||||
|     <ai-list v-if="!isDetail"> | ||||
|       <template #title> | ||||
|         <ai-title title="调查走访" isShowBottomBorder isShowArea v-model="search.areaId" :instance="instance" | ||||
|                   :hideLevel="hideLevel" @change="page.current=1,getTableData()"/> | ||||
|       </template> | ||||
|       <template #content> | ||||
|         <ai-search-bar> | ||||
|           <template #left> | ||||
|             <ai-search label="创建日期"> | ||||
|               <el-date-picker | ||||
|                   size="small" | ||||
|                   v-model="search.startTime" | ||||
|                   placeholder="开始日期" | ||||
|                   @change="page.current = 1, getTableData()" | ||||
|                   value-format="yyyy-MM-dd"/> | ||||
|               <el-date-picker | ||||
|                   size="small" | ||||
|                   v-model="search.endTime" | ||||
|                   placeholder="结束日期" | ||||
|                   @change="page.current = 1, getTableData()" | ||||
|                   value-format="yyyy-MM-dd"/> | ||||
|             </ai-search> | ||||
|           </template> | ||||
|           <template #right> | ||||
|             <el-input | ||||
|                 suffix-icon="iconfont iconSearch" | ||||
|                 v-model="search.title" | ||||
|                 placeholder="标题" | ||||
|                 clearable | ||||
|                 v-throttle="() => {page.current = 1, getTableData()}" | ||||
|                 @clear="page.current = 1, search.title = '', getTableData()" | ||||
|                 size="small"/> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <ai-table | ||||
|             :tableData="tableData" | ||||
|             :colConfigs="colConfigs" | ||||
|             :total="page.total" | ||||
|             :current.sync="page.current" | ||||
|             :size.sync="page.size" | ||||
|             @getList="getTableData"> | ||||
|           <el-table-column label="操作" align="center" slot="options" fixed="right" width="160"> | ||||
|             <template slot-scope="{row}"> | ||||
|               <div class="table-options"> | ||||
|                 <el-button type="text" title="详情" @click="handleShow(row.id)">详情</el-button> | ||||
|                 <el-button type="text" title="删除" @click="handleDelete(row.id)" | ||||
|                            v-if="permissions('app_appinterview_del')">删除 | ||||
|                 </el-button> | ||||
|               </div> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|         </ai-table> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|     <interview-detail v-else/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import InterviewDetail from "./interviewDetail"; | ||||
| import {mapState} from "vuex"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppInterview", | ||||
|   label: "调查走访", | ||||
|   components: {InterviewDetail}, | ||||
|   provide() { | ||||
|     return { | ||||
|       interview: this | ||||
|     } | ||||
|   }, | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     colConfigs() { | ||||
|       return [ | ||||
|         {label: "标题", prop: "title"}, | ||||
|         {label: "时间", prop: "createTime"}, | ||||
|         {label: "所属区域", prop: "areaName"}, | ||||
|         {label: "操作人", prop: "createUserId", openType: 'userName'}, | ||||
|         {slot: "options"} | ||||
|       ] | ||||
|     }, | ||||
|     isDetail() { | ||||
|       return !!this.$route.query.id | ||||
|     }, | ||||
|     hideLevel() { | ||||
|       return this.user.info.areaList?.length - 1 | ||||
|     } | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       search: {startTime: null, endTime: null, title: "", areaId: "445203000000"}, | ||||
|       page: {current: 1, size: 10, total: 0}, | ||||
|       tableData: [] | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     // this.search.areaId = JSON.parse(JSON.stringify(this.user.info.areaId)) | ||||
|     if (this.isDetail) { | ||||
|     } else this.getTableData() | ||||
|   }, | ||||
|   methods: { | ||||
|     getTableData() { | ||||
|       this.instance.post("/app/appinterview/list", null, { | ||||
|         params: {...this.search, ...this.page} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.tableData = res.data.records | ||||
|           this.page.total = res.data.total | ||||
|  | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     handleShow(id) { | ||||
|       if (id) { | ||||
|         this.$router.push({query: {id}}) | ||||
|       } else this.$message.error('该条数据异常,无法打开!') | ||||
|     }, | ||||
|     handleDelete(ids) { | ||||
|       this.$confirm("是否要删除该调查走访?").then(() => { | ||||
|         this.instance.post("/app/appinterview/delete", null, {params: {ids}}).then(res => { | ||||
|           if (res?.code == 0) { | ||||
|             this.$message.success("删除成功!") | ||||
|             this.getTableData() | ||||
|           } | ||||
|         }) | ||||
|       }).catch(() => 0) | ||||
|     }, | ||||
|     back() { | ||||
|       this.$router.push({query: null}) | ||||
|       this.getTableData() | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AppInterview { | ||||
|   height: 100%; | ||||
|  | ||||
|   ::v-deep .dateRange { | ||||
|     .dateLabel { | ||||
|       height: 32px; | ||||
|       border: 1px solid #D0D4DC; | ||||
|       line-height: 32px; | ||||
|       padding: 0 8px; | ||||
|       background: #F5F5F5; | ||||
|     } | ||||
|  | ||||
|     .el-input__inner { | ||||
|       border-radius: 0; | ||||
|       transform: translateX(-1px); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   ::v-deep .ai-list__content--right-wrapper { | ||||
|     display: flex; | ||||
|     flex-direction: column; | ||||
|     gap: 10px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @@ -1,97 +0,0 @@ | ||||
| <template> | ||||
|   <section class="interviewDetail"> | ||||
|     <ai-detail> | ||||
|       <template #title> | ||||
|         <ai-title title="调查随访详情" isShowBottomBorder isShowBack @onBackClick="interview.back()"/> | ||||
|       </template> | ||||
|       <template #content> | ||||
|         <ai-card title="基本信息"> | ||||
|           <template #content> | ||||
|             <ai-wrapper | ||||
|                 label-width="56px"> | ||||
|               <ai-info-item label="标题" isLine>{{ detail.title }}</ai-info-item> | ||||
|               <ai-info-item label="内容" isLine>{{ detail.content }}</ai-info-item> | ||||
|               <ai-info-item label="图片" isLine> | ||||
|                 <div class="images"> | ||||
|                   <el-image | ||||
|                       v-for="(op,i) in detail.fileList" | ||||
|                       :key="i" | ||||
|                       :src="op.accessUrl" | ||||
|                       :preview-src-list="detail.fileList.map(e=>e.accessUrl)"> | ||||
|                     <i slot="placeholder" class="el-icon-picture-outline"/> | ||||
|                     <i slot="error" class="el-icon-picture-outline"/> | ||||
|                   </el-image> | ||||
|                 </div> | ||||
|               </ai-info-item> | ||||
|             </ai-wrapper> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|       </template> | ||||
|       <!-- <template #footer> | ||||
|         <el-button @click="interview.back()">取消</el-button> | ||||
|         <el-button type="primary" @click="submitInterview" v-if="interview.permissions('app_appinterview_edit')">保存</el-button> | ||||
|       </template> --> | ||||
|     </ai-detail> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "interviewDetail", | ||||
|   inject: ['interview'], | ||||
|   data() { | ||||
|     return { | ||||
|       detail: { | ||||
|         fileList: [] | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.getDetail() | ||||
|   }, | ||||
|   methods: { | ||||
|     getDetail() { | ||||
|       let {id} = this.$route.query | ||||
|       this.interview.instance.post("/app/appinterview/queryDetailById", null, {params: {id}}).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.detail = res.data | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     submitInterview() { | ||||
|       this.$refs.interviewForm.validate(v => { | ||||
|         if (v) { | ||||
|           this.interview.instance.post("/app/appinterview/update-web", this.detail).then(res => { | ||||
|             if (res?.code == 0) { | ||||
|               this.$message.success("保存成功!") | ||||
|               this.interview.back() | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .interviewDetail { | ||||
|   height: 100%; | ||||
|  | ||||
|   ::v-deep .images { | ||||
|     display: flex; | ||||
|     gap: 16px; | ||||
|     flex-wrap: wrap; | ||||
|  | ||||
|     &:before { | ||||
|       content: none; | ||||
|     } | ||||
|  | ||||
|     .el-image__inner { | ||||
|       width: 82px !important; | ||||
|       height: 82px !important; | ||||
|       margin-right: 16px; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @@ -31,6 +31,7 @@ module.exports = { | ||||
|     .add(path.resolve(__dirname, 'core')) | ||||
|     .add(path.resolve(__dirname, 'project')) | ||||
|     .add(path.resolve(__dirname, 'oms')) | ||||
|     .add(path.resolve(__dirname, 'examples')) | ||||
|     .add(path.resolve(__dirname, 'node_modules/dvcp-dv-ui')) | ||||
|     .add(path.resolve(__dirname, 'node_modules/dvcp-ui')) | ||||
|     .end() | ||||
|   | ||||
		Reference in New Issue
	
	Block a user