Compare commits
	
		
			173 Commits
		
	
	
		
			feature/nu
			...
			a3ea6d9c51
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | a3ea6d9c51 | ||
|  | 5fa30a0e0e | ||
|  | 6b030791bb | ||
|  | d0922c5309 | ||
|  | d46bb82086 | ||
|  | 1ead1b2e9a | ||
|  | c5f4f9b356 | ||
|  | 3fbde7f193 | ||
|  | e5abd1514b | ||
|  | 33ed4fe5d5 | ||
|  | 4051b31101 | ||
|  | 94b1788e8c | ||
|  | 7944a1a8e3 | ||
|  | 17b28025d8 | ||
|  | 0a6b77943f | ||
|  | a599566b20 | ||
|  | 1a7031342f | ||
|  | 516a8edb5e | ||
|  | f4e2100882 | ||
|  | 9f6998e042 | ||
|  | f730850d93 | ||
|  | 0ef83a945f | ||
|  | cbfd68f50c | ||
|  | 7762eb6d24 | ||
|  | db1a323921 | ||
|  | 1a61475f57 | ||
|  | 356e6438e0 | ||
|  | 5fe82a68ef | ||
|  | 9b6e02810a | ||
|  | f0a32ad868 | ||
|  | ce64bfd54d | ||
|  | a53d25fae2 | ||
|  | 08d5e0e4fd | ||
|  | b23f8325f4 | ||
|  | 0adb2b1486 | ||
|  | 38082397a9 | ||
|  | 4d527dc8ec | ||
|  | d90aca62e4 | ||
|  | 44f11be05c | ||
|  | 7a21ab3804 | ||
|  | 6bb4802f15 | ||
|  | cfc8f3c8e0 | ||
|  | 3f26b8b6df | ||
|  | 350ca644cf | ||
|  | 99b507657f | ||
|  | 2e93f1465f | ||
|  | 07a4d0637f | ||
|  | 66a721c1eb | ||
|  | 5efd2a1d3f | ||
|  | d0c447bb41 | ||
|  | ebc143a052 | ||
|  | 70b77669ab | ||
|  | 7393bcbc6e | ||
|  | 2abdab1b20 | ||
|  | d1a8800a9b | ||
|  | ced505b585 | ||
|  | 25010984f9 | ||
|  | 75d5971e42 | ||
|  | f5085b1cb3 | ||
|  | baa5c3124a | ||
|  | d1ae5ff2c7 | ||
|  | 962d2a4068 | ||
|  | 3adbb68466 | ||
|  | 7f086f8b83 | ||
|  | 95689baff9 | ||
|  | d39650eca5 | ||
|  | 4f44f50db5 | ||
|  | 27a2052241 | ||
|  | 072390dc13 | ||
|  | 385447d3b4 | ||
|  | 532ceeb5e7 | ||
|  | 2275590461 | ||
|  | d25b082eff | ||
|  | 6feaeb22bf | ||
|  | dad169496c | ||
|  | 3eef1eeb3c | ||
|  | f108a61293 | ||
|  | e1231d408c | ||
|  | c073c8d0bd | ||
|  | 437ae1425c | ||
|  | b6dcddac6f | ||
|  | e283d6a650 | ||
|  | 230f8c3b80 | ||
|  | 382be3d32f | ||
|  | a7c3b22f87 | ||
|  | 3585cceca8 | ||
|  | 908e65f136 | ||
|  | 7828af24fd | ||
|  | 185630ad2c | ||
|  | 67c4c8032e | ||
|  | 39ce5404c1 | ||
|  | 9f02c2d011 | ||
|  | 9d369e9a0f | ||
|  | 19a9486f48 | ||
|  | ab9ec446c7 | ||
|  | 0d3d8f23bb | ||
|  | 971742b392 | ||
|  | 63a425cf77 | ||
|  | e11d504f18 | ||
|  | 0e35945d4a | ||
|  | 0762067bec | ||
|  | 290ecb6823 | ||
|  | ee15427e88 | ||
|  | 06fa7b636e | ||
|  | 225c0088e1 | ||
|  | ae83152271 | ||
|  | b1c0beb8f6 | ||
|  | 4d96417661 | ||
|  | 711db33df3 | ||
|  | b7c0350134 | ||
|  | 9ff89c19f3 | ||
|  | 4684952973 | ||
|  | 4ead05b251 | ||
|  | cf62d2f508 | ||
|  | a894db0144 | ||
|  | a748a8b337 | ||
|  | 37a6cb3457 | ||
|  | 045449331f | ||
|  | 4c72bd2ac9 | ||
|  | b3942f5822 | ||
|  | 0b6bc910c4 | ||
|  | a4233d5f2c | ||
|  | 31c874e1ba | ||
|  | d40830188d | ||
|  | e789570a1b | ||
|  | 0de94d76ee | ||
|  | 536f579523 | ||
|  | c8d75ab72a | ||
|  | ad9676c040 | ||
|  | 29bd119ff4 | ||
|  | b07cca9bcf | ||
|  | 1c2364574d | ||
|  | 528082fc6b | ||
|  | 823c327894 | ||
|  | 39f6275e31 | ||
|  | 44d971998a | ||
|  | 6d7769e61a | ||
|  | afe1df98f3 | ||
|  | 97bd799b6d | ||
|  | 3316b73450 | ||
|  | eee06c837d | ||
|  | c4ae782195 | ||
|  | 2b22db2bf3 | ||
|  | 30cf69df04 | ||
|  | 54352ece58 | ||
|  | daffd10bce | ||
|  | a22b574614 | ||
|  | e3c79f232d | ||
|  | 1ae371cb30 | ||
|  | 96d24a8b22 | ||
|  | 34eb7320fa | ||
|  | 9fa56ad890 | ||
|  | 263dd9ea37 | ||
|  | 85de031db2 | ||
|  | a6f11e56a7 | ||
|  | 15f6dc6499 | ||
|  | b64b102682 | ||
|  | 576553e962 | ||
|  | ff5e2d4fe2 | ||
|  | 3f41df22a9 | ||
|  | 043aaf8399 | ||
|  | a5e0f3a6c5 | ||
|  | f9123942ca | ||
|  | b67e30ce25 | ||
|  | 5a2762a7c6 | ||
|  | c43a8992fd | ||
|  | 705a252618 | ||
|  | e2e957880b | ||
|  | 104f5d1049 | ||
|  | b3f11698f2 | ||
|  | 285e242e9e | ||
|  | 00b2dbb4a4 | ||
|  | 0b41291bf1 | 
| @@ -1,5 +0,0 @@ | ||||
| VUE_APP_SCOPE=biaopin | ||||
| #VUE_APP_API=https://web.fdfengshou.cn/ | ||||
| #VUE_APP_API=http://192.168.1.87:9000/ | ||||
| VUE_APP_API=https://www.wyzzb.com | ||||
| #VUE_APP_API=http://test87web.cunwuyun.cn/ | ||||
| @@ -1,4 +0,0 @@ | ||||
| VUE_APP_SCOPE=fengdu | ||||
| #VUE_APP_API=https://web.fdfengshou.cn/ | ||||
| VUE_APP_API=http://192.168.1.87:9000/ | ||||
| #VUE_APP_API=http://test87web.cunwuyun.cn/ | ||||
							
								
								
									
										5
									
								
								.env.xumu
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.env.xumu
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| VUE_APP_SCOPE=xumu | ||||
| VUE_APP_API=http://192.168.1.87:12413 | ||||
| VUE_APP_IS_SIMPLE_SERVER=1 | ||||
| VUE_APP_PORT=12413 | ||||
| VUE_APP_OMS_ID=2cd70a15-a3cf-4b4d-9a22-0f3b3a888b08   # oms定制方案的ID | ||||
							
								
								
									
										29
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										29
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -27,32 +27,7 @@ yarn-error.log* | ||||
| /project/*/dist | ||||
| /ui/package-lock.json | ||||
| /examples/modules.json | ||||
|  | ||||
|  | ||||
| /examples/router/apps.js | ||||
| /src/apps/ | ||||
| /src/config.json | ||||
| /.nuxt/components/nuxt.js | ||||
| /.nuxt/components/nuxt-build-indicator.vue | ||||
| /.nuxt/components/nuxt-child.js | ||||
| /.nuxt/components/nuxt-error.vue | ||||
| /.nuxt/components/nuxt-link.client.js | ||||
| /.nuxt/components/nuxt-link.server.js | ||||
| /.nuxt/components/nuxt-loading.vue | ||||
| /.nuxt/layouts/default.vue | ||||
| /.nuxt/mixins/fetch.client.js | ||||
| /.nuxt/mixins/fetch.server.js | ||||
| /.nuxt/views/app.template.html | ||||
| /.nuxt/views/error.html | ||||
| /.nuxt/App.js | ||||
| /.nuxt/client.js | ||||
| /.nuxt/empty.js | ||||
| /.nuxt/index.js | ||||
| /.nuxt/jsonp.js | ||||
| /.nuxt/loading.html | ||||
| /.nuxt/middleware.js | ||||
| /.nuxt/router.js | ||||
| /.nuxt/router.scrollBehavior.js | ||||
| /.nuxt/routes.json | ||||
| /.nuxt/server.js | ||||
| /.nuxt/store.js | ||||
| /.nuxt/utils.js | ||||
| /src/utils/apps.js | ||||
|   | ||||
							
								
								
									
										99
									
								
								bin/build.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								bin/build.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | ||||
| const axios = require('axios') | ||||
| const {fsExtra, copyFiles, findApp, chalkTag, fs} = require("./tools"); | ||||
| const compiler = require('vue-template-compiler') | ||||
| const getBuildConfig = id => { | ||||
|   axios.post('http://192.168.1.87:12525/node/custom/detail', null, {params: {id}}).then(res => { | ||||
|     if (res?.data) { | ||||
|       const config = res.data.data | ||||
|       fsExtra.outputJson('src/config.json', config.extra) | ||||
|       createPages(config) | ||||
|     } | ||||
|   }) | ||||
| } | ||||
| const getAppInfo = (file, apps) => { | ||||
|   if (/[\\\/](App[A-Z][^\\\/]+)\.vue$/g.test(file)) { | ||||
|     const name = file.replace(/.+[\\\/](App[^\\\/]+)\.vue$/, '$1'), | ||||
|       source = fs.readFileSync(file).toString(), | ||||
|       parsed = compiler.parseComponent(source), | ||||
|       script = parsed.script?.content || "", | ||||
|       label = script.match(/label:[^,]+/)?.[0]?.replace(/.+["']([^"']+).+/, '$1') | ||||
|     const paths = file.split(/[\\\/]/) | ||||
|     apps.push({ | ||||
|       id: file.replace(/\.vue$/, '').replace(/[\\\/]/g, '_'), | ||||
|       label: label || name, | ||||
|       path: `/${file.replace(/\.vue$/, '').replace(/[\\\/]/g, '/')}`, | ||||
|       workspace: paths.at(0), | ||||
|       esm: file.replace(/[\\\/]/g, '/').substring(4), | ||||
|       name | ||||
|     }) | ||||
|   } | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * 根据配置生成应用路由 | ||||
|  * @param {Object} config - 配置对象,用于定制化路由生成过程 | ||||
|  * @returns {Promise} - 返回一个Promise对象,表示路由生成完成 | ||||
|  */ | ||||
| const createRoutes = (config = {}) => { | ||||
|   // 初始化路由数组 | ||||
|   const routes = [] | ||||
|   // 获取签到页面的路径,如果未指定,则使用默认路径 | ||||
|   let signPage = '../views/sign' | ||||
|   let {signPage: sign, homePage: home = "console"} = config.extra || {} | ||||
|   if (config.extra?.signPage) { | ||||
|     signPage = `../apps/custom/${sign}/${sign}` | ||||
|   } | ||||
|   let homePage = `../views/console` | ||||
|   if (config.extra?.homePage) { | ||||
|     homePage = `../apps/custom/${home}/${home}` | ||||
|   } | ||||
|   // 查找并处理所有应用,将它们的信息添加到路由中 | ||||
|   return findApp("src/apps", app => getAppInfo(app, routes)).then(() => { | ||||
|     // 生成并输出apps.js文件,定义所有应用的路由 | ||||
|     fsExtra.outputFile('src/utils/apps.js', `export default [ | ||||
|     {path: "/login", name: "登录", component: () => import('${signPage}')}, | ||||
|     {path: '/dv', name: '数据大屏入口', component: () => import('../views/dvIndex')}, | ||||
|     {path: '/v', name: 'Home', component: () => import('../views/home'), children: [ | ||||
|       {path:'/',name:'mainEntry', component:()=>import('../views/mainEntry'),children:[ | ||||
|       {name: "${home}", path: "${home}", component: () => import('${homePage}')}, | ||||
|       ${routes.filter(e => ![sign, home].includes(e.name)).map(e => { | ||||
|       // 解构每个路由的属性,用于生成路由配置 | ||||
|       const {name, label, esm} = e | ||||
|       // 生成单个路由配置的字符串表示 | ||||
|       return `{name:"${name}",label:"${label}",path:"${name}",component:()=>import("../${esm}")}` | ||||
|     }).join(',\n')}, | ||||
|       {path: '*',name: '404',component: ()=>import('../views/building')}, | ||||
|       ]} | ||||
|     ]}, | ||||
|     {path: '/', name: "init"}, | ||||
|      | ||||
|     ]`) | ||||
|     // 扫描完毕,使用chalkTag标记任务完成 | ||||
|     chalkTag.done("扫描完毕") | ||||
|   }) | ||||
| } | ||||
|  | ||||
| const createPages = (config = {}) => { | ||||
|   fsExtra.emptyDir("src/apps", err => { | ||||
|     if (!err) { | ||||
|       const {customPath, appList} = config | ||||
|       const stdApps = {} | ||||
|       appList.filter(e => !/project/.test(e.id))?.forEach(e => { | ||||
|         const paths = e.libPath.split('/').filter(Boolean) || [] | ||||
|         paths.pop() | ||||
|         stdApps[paths.join("/")] = 1 | ||||
|       }) | ||||
|       Promise.all([ | ||||
|         copyFiles("src/apps/core", "packages/core"), | ||||
|         copyFiles("src/apps/custom", `project/${customPath}`), | ||||
|         ...Object.keys(stdApps).map(e => copyFiles(`src/apps/${e.replace(/^packages[\\\/]/, '')}`, e)), | ||||
|       ]).then(() => createRoutes(config)).then(() => fsExtra.ensureFile("src/apps/actions.js")) | ||||
|     } | ||||
|   }) | ||||
| } | ||||
|  | ||||
| const start = () => { | ||||
|   const buildId = process.argv[2] || process.env.VUE_APP_OMS_ID || 'f670cc46-7cf7-4a0f-86ee-3077044c0b17' | ||||
|   getBuildConfig(buildId) | ||||
| } | ||||
| start() | ||||
							
								
								
									
										33
									
								
								bin/mods.js
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								bin/mods.js
									
									
									
									
									
								
							| @@ -1,33 +0,0 @@ | ||||
| const {chalkTag, findApp, fs, fsExtra} = require("./tools"); | ||||
| const compiler = require('vue-template-compiler') | ||||
| const getAppInfo = (file, apps) => { | ||||
|   if (/[\\\/](App[A-Z][^\\\/]+)\.vue$/g.test(file)) { | ||||
|     const name = file.replace(/.+[\\\/](App[^\\\/]+)\.vue$/, '$1'), | ||||
|         source = fs.readFileSync(file).toString(), | ||||
|         parsed = compiler.parseComponent(source), | ||||
|         script = parsed.script?.content || "", | ||||
|         label = script.match(/label:[^,]+/)?.[0]?.replace(/.+["']([^"']+).+/, '$1') | ||||
|     const paths = file.split(/[\\\/]/) | ||||
|     apps.push({ | ||||
|       id: file.replace(/\.vue$/, '').replace(/[\\\/]/g, '_'), | ||||
|       label: label || name, | ||||
|       path: `/${file.replace(/\.vue$/, '').replace(/[\\\/]/g, '/')}`, | ||||
|       workspace: paths.at(0), | ||||
|       esm: ['.', paths.slice(1)].flat().join("/"), | ||||
|       name | ||||
|     }) | ||||
|   } | ||||
| } | ||||
|  | ||||
| const start = () => { | ||||
|   chalkTag.info("开始扫描库工程...") | ||||
|   const list = [] | ||||
|   Promise.all([ | ||||
|     findApp('packages', app => getAppInfo(app, list)), | ||||
|     findApp('project', app => getAppInfo(app, list)), | ||||
|   ]).then(() => { | ||||
|     fsExtra.outputJson('examples/modules.json', {apps: list}) | ||||
|     chalkTag.done("扫描完毕") | ||||
|   }) | ||||
| } | ||||
| start() | ||||
							
								
								
									
										37
									
								
								bin/scanApps.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								bin/scanApps.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| const {chalkTag, findApp, fs, fsExtra} = require("./tools"); | ||||
| const compiler = require('vue-template-compiler') | ||||
| const getAppInfo = (file, apps) => { | ||||
|   if (/[\\\/](App[A-Z][^\\\/]+)\.vue$/g.test(file)) { | ||||
|     const name = file.replace(/.+[\\\/](App[^\\\/]+)\.vue$/, '$1'), | ||||
|       source = fs.readFileSync(file).toString(), | ||||
|       parsed = compiler.parseComponent(source), | ||||
|       script = parsed.script?.content || "", | ||||
|       label = script.match(/label:[^,]+/)?.[0]?.replace(/.+["']([^"']+).+/, '$1') | ||||
|     const paths = file.split(/[\\\/]/) | ||||
|     apps.push({ | ||||
|       id: file.replace(/\.vue$/, '').replace(/[\\\/]/g, '_'), | ||||
|       label: label || name, | ||||
|       path: `/${file.replace(/\.vue$/, '').replace(/[\\\/]/g, '/')}`, | ||||
|       workspace: paths.at(0), | ||||
|       esm: file.replace(/[\\\/]/g, '/'), | ||||
|       name | ||||
|     }) | ||||
|   } | ||||
| } | ||||
|  | ||||
| const start = () => { | ||||
|   chalkTag.info("开始扫描库工程...") | ||||
|   const {VUE_APP_SCOPE, VUE_APP_CORE} = process.env | ||||
|   const list = [] | ||||
|   let scanScope = ['packages', 'project'] | ||||
|   if (VUE_APP_SCOPE) scanScope = [`project/${VUE_APP_SCOPE}`] | ||||
|   if (VUE_APP_CORE) scanScope.push('packages/core') | ||||
|   Promise.all(scanScope.map(e => findApp(e, app => getAppInfo(app, list)))).then(() => { | ||||
|     fsExtra.outputFile('examples/router/apps.js', `export default [${list.map(e => { | ||||
|       const {name, label, path, esm} = e | ||||
|       return `{name:"${name}",label:"${label}",path:"${path}",component:()=>import("@${esm}")}` | ||||
|     }).join(',\n')}]`) | ||||
|     chalkTag.done("扫描完毕") | ||||
|   }) | ||||
| } | ||||
| start() | ||||
| @@ -9,13 +9,13 @@ | ||||
|       </template> | ||||
|     </header-nav> | ||||
|     <ai-dv-wrapper class="fill" v-if="dvDev"> | ||||
|       <router-view/> | ||||
|       <router-view v-bind="commonAttrs"/> | ||||
|     </ai-dv-wrapper> | ||||
|     <el-row v-else-if="showTools" class="fill mar-t48" type="flex"> | ||||
|       <slider-nav/> | ||||
|       <main-content class="fill"/> | ||||
|       <main-content class="fill" :commonAttrs="commonAttrs"/> | ||||
|     </el-row> | ||||
|     <router-view class="fill" v-else/> | ||||
|     <router-view class="fill" v-else v-bind="commonAttrs"/> | ||||
|     <div v-if="dialog" class="sign-box"> | ||||
|       <ai-sign style="margin: auto" :instance="$request" :action="{login}" | ||||
|                visible @login="getToken" :showScanLogin="false"/> | ||||
| @@ -25,15 +25,16 @@ | ||||
| </template> | ||||
| 
 | ||||
| <script> | ||||
| import SliderNav from "../components/sliderNav"; | ||||
| import MainContent from "../components/mainContent"; | ||||
| import HeaderNav from "../components/headerNav"; | ||||
| import SliderNav from "./components/sliderNav"; | ||||
| import MainContent from "./components/mainContent"; | ||||
| import HeaderNav from "./components/headerNav"; | ||||
| import {mapActions, mapMutations, mapState} from "vuex"; | ||||
| import Mock from "../components/mock"; | ||||
| import Mock from "./components/mock"; | ||||
| import AiDvWrapper from "dui/dv/layout/AiDvWrapper/AiDvWrapper.vue"; | ||||
| 
 | ||||
| export default { | ||||
|   name: 'app', | ||||
|   components: {Mock, HeaderNav, MainContent, SliderNav}, | ||||
|   components: {AiDvWrapper, Mock, HeaderNav, MainContent, SliderNav}, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     login() { | ||||
| @@ -41,6 +42,13 @@ export default { | ||||
|       /project\/sass/g.test(location.pathname) && (url += "?corpId=ww596787bb70f08288") | ||||
|       return url | ||||
|     }, | ||||
|     commonAttrs() { | ||||
|       return { | ||||
|         instance: this.$request, | ||||
|         dict: this.$dict, | ||||
|         permissions: this.$permissions | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
| @@ -74,7 +82,7 @@ export default { | ||||
|     handleMock() { | ||||
|     } | ||||
|   }, | ||||
|   mounted() { | ||||
|   created() { | ||||
|     const {jWeixin} = window | ||||
|     window.wx = jWeixin | ||||
|     if (this.user.token) this.getUserInfo().finally(() => { | ||||
| @@ -1,8 +1,8 @@ | ||||
| <template> | ||||
|   <section class="mainContent"> | ||||
|     <ai-nav-tab :routes="apps"/> | ||||
|     <ai-nav-tab :routes="$apps"/> | ||||
|     <div class="fill"> | ||||
|       <router-view/> | ||||
|       <router-view v-bind="$attrs.commonAttrs"/> | ||||
|       <ai-empty v-if="isHome">欢迎使用村微产品库</ai-empty> | ||||
|     </div> | ||||
|   </section> | ||||
| @@ -10,13 +10,11 @@ | ||||
|  | ||||
| <script> | ||||
| import AiNavTab from "dui/packages/basic/AiNavTab"; | ||||
| import {mapState} from "vuex" | ||||
|  | ||||
| export default { | ||||
|   name: "mainContent", | ||||
|   components: {AiNavTab}, | ||||
|   computed: { | ||||
|     ...mapState(['apps']), | ||||
|     isHome: v => v.$route.path == '/', | ||||
|   }, | ||||
| } | ||||
|   | ||||
| @@ -39,10 +39,10 @@ export default { | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user', 'apps']), | ||||
|     ...mapState(['user']), | ||||
|     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)).map(e => { | ||||
|       return (this.$apps || []).filter(e => !this.searchApp || reg?.test(e.name) || reg?.test(e.label)).map(e => { | ||||
|         if (/\/project\//.test(e.path)) { | ||||
|           e.project = process.env.VUE_APP_SCOPE || e.path.replace(/.*project\/([^\/]+)\/.+/, '$1') | ||||
|         } else if (/\/core\//.test(e.path)) { | ||||
| @@ -52,9 +52,9 @@ export default { | ||||
|       }) | ||||
|     }, | ||||
|     menuPath() { | ||||
|       let paths = [], current = this.apps?.find(e => e.name == this.$route.name) | ||||
|       let paths = [], current = this.$apps?.find(e => e.name == this.$route.name) | ||||
|       const findParent = name => { | ||||
|         let menu = this.apps?.find(e => e.name == name) | ||||
|         let menu = this.$apps?.find(e => e.name == name) | ||||
|         if (menu) { | ||||
|           paths.push(menu.name) | ||||
|           if (!!menu.parentId) findParent(menu.parentId) | ||||
| @@ -102,7 +102,7 @@ export default { | ||||
|       localStorage.setItem("searchApp", this.searchApp) | ||||
|     }, | ||||
|   }, | ||||
|   mounted() { | ||||
|   created() { | ||||
|     this.searchApp = localStorage.getItem("searchApp") || "" | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -1,14 +1,18 @@ | ||||
| import Vue from 'vue'; | ||||
| import App from './App.vue'; | ||||
| import router from './router/router'; | ||||
| import ui from 'element-ui'; | ||||
| import router from './router'; | ||||
| import axios from './router/axios'; | ||||
| import utils from './utils'; | ||||
| import dui from 'dui'; | ||||
| import dui from 'dui/packages'; | ||||
| import store from './store'; | ||||
| import dataV from '@jiaminghi/data-view'; | ||||
| import dvui from 'dui/dv' | ||||
|  | ||||
| Vue.use(dataV) | ||||
| Vue.use(ui); | ||||
| Vue.use(dui); | ||||
| Vue.use(dvui); | ||||
| //富文本编辑器配置 | ||||
| Vue.config.productionTip = false; | ||||
| Object.keys(utils).map((e) => (Vue.prototype[e] = utils[e])); | ||||
| @@ -18,12 +22,14 @@ const app = new Vue({ | ||||
|   store, | ||||
|   render: h => h(App) | ||||
| }); | ||||
|  | ||||
| let theme = null | ||||
| store.dispatch('getSystem').then(res => { | ||||
|   theme = JSON.parse(res?.colorScheme || null) | ||||
|   Vue.prototype.$theme = theme?.web || "blue" | ||||
|   return import(`dui/lib/styles/theme.${theme?.web}.scss`).catch(() => 0) | ||||
| }).finally(() => { | ||||
|   Vue.prototype.$vm = app | ||||
|   import(`dui/lib/styles/common.scss`).finally(() => app.$mount('#app')) | ||||
| }) | ||||
|  | ||||
|   | ||||
| @@ -1,21 +0,0 @@ | ||||
| import {resolve} from 'path' | ||||
|  | ||||
| export default { | ||||
|   css: ['ui/lib/styles/common.scss'], | ||||
|   dev: process.env.NODE_ENV !== 'production', | ||||
|   alias: { | ||||
|     'style': resolve(__dirname, './assets/style'), | ||||
|     'dui': resolve(__dirname, '../ui') | ||||
|   }, | ||||
|   srcDir: "examples", | ||||
|   dir: { | ||||
|     pages: 'views', | ||||
|   }, | ||||
|   build: { | ||||
|     postcss: null, | ||||
|     transpile: [/^ui/] | ||||
|   }, | ||||
|   plugins: [ | ||||
|     '~plugins/ui.js' | ||||
|   ], | ||||
| } | ||||
| @@ -1,7 +0,0 @@ | ||||
| import Vue from 'vue'; | ||||
| import ElementUI from 'element-ui'; | ||||
| import dui from 'dui/packages'; | ||||
| import 'dui/lib/styles/common.scss'; | ||||
|  | ||||
| Vue.use(ElementUI); | ||||
| Vue.use(dui) | ||||
| @@ -1,81 +0,0 @@ | ||||
| import store from "../store"; | ||||
| import {waiting} from "../utils"; | ||||
| import appEntry from "../views/appEntry"; | ||||
| import router from "./router"; | ||||
|  | ||||
| export default { | ||||
|   routes: () => store.state.apps, | ||||
|   init() { | ||||
|     //约束正则式 | ||||
|     store.commit("cleanApps") | ||||
|     // 自动化本工程应用 | ||||
|     waiting.init({innerHTML: '应用加载中..'}) | ||||
|     let startTime = new Date().getTime() | ||||
|     /** | ||||
|      * require.context 的路径变量范式只能为静态字符串 | ||||
|      */ | ||||
|     switch (process.env.VUE_APP_SCOPE) { | ||||
|       case 'dv': | ||||
|         this.esm = { | ||||
|           packages: require.context('../../packages/bigscreen', true, /\.(\/.+)\/App[A-Z][^\/]+\.vue$/, 'lazy') | ||||
|         } | ||||
|         break | ||||
|       case 'fengdu': | ||||
|         this.esm = { | ||||
|           project: require.context('../../project/fengdu', true, /\.(\/.+)\/App[A-Z][^\/]+\.vue$/, 'lazy') | ||||
|         } | ||||
|         break | ||||
|       case 'ai': | ||||
|         this.esm = { | ||||
|           biaopin: require.context('../../project/biaopin/AppCopilotConfig', true, /\.\/App[A-Z][^\/]+\.vue$/, 'lazy'), | ||||
|           project: require.context('../../project/ai', true, /\.(\/.+)\/App[A-Z][^\/]+\.vue$/, 'lazy') | ||||
|         } | ||||
|         break | ||||
|       case 'oms': | ||||
|         this.esm = { | ||||
|           project: require.context('../../project/oms', true, /\.(\/.+)\/App[A-Z][^\/]+\.vue$/, 'lazy') | ||||
|         } | ||||
|         break | ||||
|       default: | ||||
|         this.esm = { | ||||
|           packages: require.context('../../packages/', true, /\.(\/.+)\/App[A-Z][^\/]+\.vue$/, 'lazy'), | ||||
|           project: require.context('../../project/', true, /\.(\/.+)\/App[A-Z][^\/]+\.vue$/, 'lazy') | ||||
|         } | ||||
|     } | ||||
|     console.log('模块引用用了%s秒', (new Date().getTime() - startTime) / 1000) | ||||
|     startTime = new Date().getTime() | ||||
|     this.loadApps().finally(() => { | ||||
|       console.log('模块加载用了%s秒', (new Date().getTime() - startTime) / 1000) | ||||
|       waiting.close() | ||||
|     }) | ||||
|   }, | ||||
|   loadMods() { | ||||
|     // return Promise.all(mods.apps.map(e => { | ||||
|     //   Vue.component(e.name, this.esm[e.workspace](e.esm)) | ||||
|     //   const addApp = {...e, component: appEntry} | ||||
|     //   waiting.setContent(`加载${e.name}...`) | ||||
|     //   //命名规范入口文件必须以App开头 | ||||
|     //   return store.commit("addApp", addApp) | ||||
|     // })) | ||||
|   }, | ||||
|   loadApps() { | ||||
|     //新App的自动化格式 | ||||
|     const promise = (mods, base) => Promise.all(mods.keys().map(path => mods(path).then(file => { | ||||
|       if (file.default) { | ||||
|         const {name, label} = file.default | ||||
|         const addApp = { | ||||
|           name: [base, path.replace(/\.\/?(vue)?/g, '')?.split("/")].flat().join("_"), | ||||
|           label: label || name, | ||||
|           path: `/${base}${path.replace(/\.(\/.+\/App.+)\.vue$/, '$1')}`, | ||||
|           component: appEntry, | ||||
|           esm: file.default | ||||
|         } | ||||
|         waiting.setContent(`加载${name}...`) | ||||
|         router.addRoute(addApp) | ||||
|         //命名规范入口文件必须以App开头 | ||||
|         return store.commit("addApp", addApp) | ||||
|       } else return 0 | ||||
|     }).catch(err => console.log(err)))) | ||||
|     return Promise.all(Object.entries(this.esm).map(([root, mods]) => promise(mods, root))).catch(console.error) | ||||
|   } | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| import { Message } from 'element-ui' | ||||
| import instance from '../../ui/lib/js/request' | ||||
| import instance from 'dui/lib/js/request' | ||||
|  | ||||
| let baseURLs = { | ||||
|   production: "/", | ||||
| @@ -8,34 +8,10 @@ let baseURLs = { | ||||
| instance.defaults.baseURL = baseURLs[process.env.NODE_ENV] | ||||
| instance.interceptors.request.use(config => { | ||||
|   if (config.url.startsWith("/node")) { | ||||
|     config.baseURL = "/ns" | ||||
|   } else if (config.url.startsWith("/sse")) { | ||||
|     config.baseURL = "/" | ||||
|   } else if (/\/project\/activeAnalysis/.test(location.pathname)) { | ||||
|     config.baseURL = "/analysis" | ||||
|   } else if (/\/project\/beta/.test(location.pathname)) { | ||||
|     config.baseURL = "/wg" | ||||
|   } else if (/\/project\/sass/.test(location.pathname)) { | ||||
|     config.baseURL = "/saas" | ||||
|   } else if (/\/tianfuxing/.test(location.pathname)) { | ||||
|     config.baseURL = "/tfx" | ||||
|   } else if (/\/qianxinan/.test(location.pathname)) { | ||||
|     // config.baseURL = "/qxn" | ||||
|   } else if (/\/xiushan/.test(location.pathname)) { | ||||
|     config.baseURL = "/xsjr" | ||||
|   } else if (/project\/oms/.test(location.pathname)) { | ||||
|     config.baseURL = "/omsapi" | ||||
|   } else if (/#url-/.test(location.hash)) { | ||||
|     config.baseURL = location.hash.replace(/#url-/, '/') | ||||
|   } | ||||
|   if (["/xsjr", "/tfx", "/omsapi"].includes(config.baseURL)) { | ||||
|     config.url = config.url.replace(/(app|auth|admin|api)\//, "api/") | ||||
|   } | ||||
|   if (['/qxn', '/analysis'].includes(config.baseURL)) { | ||||
|     config.url = config.url.replace(/(app|auth|admin)\//, "api/") | ||||
|     config.url = "/ns" + config.url | ||||
|   } | ||||
|   if (process.env.VUE_APP_IS_SIMPLE_SERVER == 1) { | ||||
|     config.url = config.url.replace(/(app|auth|admin)\//, "api/") | ||||
|     config.url = config.url.replace(/^\/(app|auth|admin)\//, "/api/") | ||||
|   } | ||||
|   return config | ||||
| }, error => Message.error(error)) | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| import Vue from 'vue' | ||||
| import VueRouter from 'vue-router' | ||||
| import autoRoutes from './autoRoutes' | ||||
| import apps from "./apps"; | ||||
| 
 | ||||
| Vue.use(VueRouter) | ||||
| autoRoutes.init() | ||||
| Vue.prototype.$apps = apps | ||||
| export default new VueRouter({ | ||||
|   mode: 'history', | ||||
|   hashbang: false, | ||||
|   routes: autoRoutes.routes(), | ||||
|   routes: apps, | ||||
|   scrollBehavior(to) { | ||||
|     if (to.hash) { | ||||
|       return { | ||||
| @@ -1,26 +1,12 @@ | ||||
| import Vue from 'vue' | ||||
| import Vuex from 'vuex' | ||||
| import preState from 'vuex-persistedstate' | ||||
| import * as modules from "dui/lib/js/modules" | ||||
| import xsActions from "../../project/xiushan/actions" | ||||
|  | ||||
| Vue.use(Vuex) | ||||
| export const state = () => ({ | ||||
|   apps: [] | ||||
| }) | ||||
| export const mutations = { | ||||
|   addApp(state, app) { | ||||
|     state.apps.push(app) | ||||
|   }, | ||||
|   cleanApps(state) { | ||||
|     state.apps = [] | ||||
|   } | ||||
| } | ||||
| const actions = { | ||||
|   ...xsActions | ||||
| } | ||||
| export default { | ||||
|   state, | ||||
|   mutations, | ||||
|   actions, | ||||
| export default new Vuex.Store({ | ||||
|   actions: {...xsActions}, | ||||
|   modules, | ||||
| } | ||||
|   plugins: [preState()] | ||||
| }) | ||||
|   | ||||
| @@ -1,36 +0,0 @@ | ||||
| <template> | ||||
|   <section class="appEntry"> | ||||
|     <component v-if="app" :is="app" ref="currentPage" :instance="$request" :dict="$dict" :permissions="$permissions"/> | ||||
|     <ai-empty v-else>无法找到应用文件</ai-empty> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
|  | ||||
| export default { | ||||
|   name: "appEntry", | ||||
|   label: "应用库-应用", | ||||
|   computed: { | ||||
|     ...mapState(['apps']), | ||||
|     app() { | ||||
|       const app = this.apps.find(e => e.name == this.$route.name) | ||||
|       return app.esm ?? "" | ||||
|     } | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .appEntry { | ||||
|   width: 100%; | ||||
|   flex: 1; | ||||
|   min-width: 0; | ||||
|   min-height: 0; | ||||
|   height: 100%; | ||||
|  | ||||
|   & > * { | ||||
|     height: 100%; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										33
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,19 +1,20 @@ | ||||
| { | ||||
|   "name": "dvcp-web", | ||||
|   "name": "dvcp-web-apps", | ||||
|   "version": "4.0.0", | ||||
|   "private": false, | ||||
|   "author": "kubbo", | ||||
|   "scripts": { | ||||
|     "dev": "nuxt -c examples/nuxt.config.js", | ||||
|     "dev": "vue-cli-service serve examples/main.js", | ||||
|     "build": "vue-cli-service build", | ||||
|     "dev:ai": "vue-cli-service serve examples/main.js --mode ai", | ||||
|     "dev:oms": "vue-cli-service serve examples/main.js --mode oms", | ||||
|     "dev:biaopin": "vue-cli-service serve examples/main.js --mode biaopin", | ||||
|     "dev:dv": "vue-cli-service serve examples/main.js --mode dv", | ||||
|     "dev:fengdu": "vue-cli-service serve examples/main.js --mode fengdu", | ||||
|     "oms": "vue-cli-service serve examples/main.js --mode oms", | ||||
|     "xumu": "vue-cli-service serve examples/main.js --mode xumu", | ||||
|     "sync": "node bin/appsSync.js", | ||||
|     "preview": "vue-cli-service serve", | ||||
|     "prebuild": "" | ||||
|     "preview": "node bin/build.js && vue-cli-service serve", | ||||
|     "predev": "node bin/scanApps.js", | ||||
|     "preoms": "dotenv -e .env.oms node bin/scanApps.js", | ||||
|     "prexumu": "dotenv -e .env.xumu node bin/scanApps.js", | ||||
|     "view:xumu": "vue-cli-service serve --mode xumu", | ||||
|     "preview:xumu": "dotenv -e .env.xumu node bin/build.js" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "@amap/amap-jsapi-loader": "^1.0.1", | ||||
| @@ -21,11 +22,13 @@ | ||||
|     "@jiaminghi/data-view": "^2.10.0", | ||||
|     "@logicflow/core": "^1.2.1", | ||||
|     "bin-ace-editor": "^3.2.0", | ||||
|     "crypto-js": "^4.1.1", | ||||
|     "crypto-js": "^4.2.0", | ||||
|     "dayjs": "^1.8.35", | ||||
|     "echarts": "^5.5.1", | ||||
|     "echarts-wordcloud": "^2.0.0", | ||||
|     "hash.js": "^1.1.7", | ||||
|     "html2canvas": "^1.4.1", | ||||
|     "jspdf": "^2.5.2", | ||||
|     "mp4box": "^0.4.1", | ||||
|     "print-js": "^1.0.63", | ||||
|     "serialize-javascript": "^6.0.0", | ||||
| @@ -48,6 +51,7 @@ | ||||
|     "axios": "^0.19.2", | ||||
|     "babel-eslint": "^10.1.0", | ||||
|     "core-js": "^2.6.11", | ||||
|     "dotenv-cli": "^7.4.2", | ||||
|     "element-ui": "^2.15.9", | ||||
|     "eslint": "^5.16.0", | ||||
|     "eslint-plugin-vue": "^5.0.0", | ||||
| @@ -55,7 +59,6 @@ | ||||
|     "inquirer": "^6.5.2", | ||||
|     "mockjs": "^1.1.0", | ||||
|     "node-ipc": "^9.2.1", | ||||
|     "nuxt": "^2.18.1", | ||||
|     "readline": "^1.3.0", | ||||
|     "sass": "~1.32.6", | ||||
|     "sass-loader": "^7.3.1", | ||||
| @@ -66,6 +69,14 @@ | ||||
|     "vuex": "^3.5.1", | ||||
|     "vuex-persistedstate": "^2.7.1" | ||||
|   }, | ||||
|   "vetur": { | ||||
|     "attributes": "./attributes.json" | ||||
|   }, | ||||
|   "postcss": { | ||||
|     "plugins": { | ||||
|       "autoprefixer": {} | ||||
|     } | ||||
|   }, | ||||
|   "browserslist": [ | ||||
|     "> 1%", | ||||
|     "last 2 versions", | ||||
|   | ||||
| @@ -168,7 +168,7 @@ import {monitorTypes} from "../config"; | ||||
| import ConfigItem from "./configItem.vue"; | ||||
| import DatasourcePicker from "./datasourcePicker.vue"; | ||||
| import AiSelect from "dui/packages/basic/AiSelect.vue"; | ||||
| import {DvCompData} from "@dui/dv"; | ||||
| import {DvCompData} from "dui/dv"; | ||||
|  | ||||
| export default { | ||||
|   name: 'dataConfig', | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import ConfigItem from "./configItem"; | ||||
| import ChartPicker from "./chartPicker"; | ||||
| import JsonEditor from "./jsonEditor"; | ||||
| import {layers, monitorTypes} from "../config"; | ||||
| import AiDvSummary from "@dui/dv/layout/AiDvSummary/AiDvSummary"; | ||||
| import AiDvSummary from "dui/dv/layout/AiDvSummary/AiDvSummary"; | ||||
|  | ||||
| export default { | ||||
|   name: "configExtra", | ||||
|   | ||||
| @@ -34,7 +34,7 @@ import 'brace/snippets/json'; | ||||
| import 'brace/theme/github'; | ||||
| import 'brace/theme/monokai'; | ||||
| import JsonEditor from "./jsonEditor.vue"; | ||||
| import {DvCompData} from "@dui/dv"; | ||||
| import {DvCompData} from "dui/dv"; | ||||
|  | ||||
| export default { | ||||
|   name: "datasourcePicker", | ||||
|   | ||||
							
								
								
									
										62
									
								
								packages/conv/AppHealthReport/AppHealthReport.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								packages/conv/AppHealthReport/AppHealthReport.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| <template> | ||||
|   <div class="AppHealthReport"> | ||||
|     <keep-alive :include="['List']"> | ||||
|       <component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component> | ||||
|     </keep-alive> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import List from './components/List.vue' | ||||
|   import Detail from './components/Detail.vue' | ||||
|  | ||||
|   export default { | ||||
|     name: 'AppHealthReport', | ||||
|     label: '健康上报', | ||||
|  | ||||
|     components: { | ||||
|       List, | ||||
|       Detail | ||||
|     }, | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       permissions: Function | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         component: 'List', | ||||
|         params: {} | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       onChange (data) { | ||||
|         if (data.type === 'Detail') { | ||||
|           this.component = 'Detail' | ||||
|           this.isShowDetail = true | ||||
|           this.params = data.params | ||||
|         } | ||||
|  | ||||
|         if (data.type === 'list') { | ||||
|           this.component = 'List' | ||||
|           this.params = data.params | ||||
|  | ||||
|           this.$nextTick(() => { | ||||
|             if (data.isRefresh) { | ||||
|               this.$refs.component.getList() | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .AppHealthReport { | ||||
|     height: 100%; | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										316
									
								
								packages/conv/AppHealthReport/components/Detail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										316
									
								
								packages/conv/AppHealthReport/components/Detail.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,316 @@ | ||||
|  <template> | ||||
|   <ai-detail isHasSidebar> | ||||
|     <template slot="title"> | ||||
|       <ai-title title="详情" isShowBack isShowBottomBorder @onBackClick="cancel(true)"> | ||||
|       </ai-title> | ||||
|     </template> | ||||
|     <template slot="content"> | ||||
|       <AiSidebar :tabTitle="tabList" v-model="currIndex"></AiSidebar> | ||||
|       <div v-show="currIndex === 0"> | ||||
|         <ai-card title="基本信息" v-show="currIndex === 0"> | ||||
|           <template #content> | ||||
|             <ai-wrapper | ||||
|               label-width="120px"> | ||||
|               <ai-info-item label="姓名" :value="info.name"></ai-info-item> | ||||
|               <ai-info-item label="上报时间" :value="info.createTime"></ai-info-item> | ||||
|               <ai-info-item label="身份证号" :value="info.idNumber"></ai-info-item> | ||||
|               <ai-info-item label="所属地区" :value="info.areaName"></ai-info-item> | ||||
|               <ai-info-item label="详细地址" isLine :value="info.address"></ai-info-item> | ||||
|             </ai-wrapper> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|       </div> | ||||
|       <ai-card title="每日上报" v-show="currIndex === 1"> | ||||
|         <template #content> | ||||
|           <ai-table | ||||
|             class="detail-table__table" | ||||
|             :tableData="tableData" | ||||
|             :col-configs="colConfigs" | ||||
|             :total="total" | ||||
|             :current.sync="search.current" | ||||
|             :size.sync="search.size" | ||||
|             @getList="getList"> | ||||
|             <el-table-column slot="options" width="140px" fixed="right" label="操作" align="center"> | ||||
|               <template slot-scope="{ row }"> | ||||
|                 <div class="table-options"> | ||||
|                   <el-button type="text" @click="toDetail(row.id)">详情</el-button> | ||||
|                 </div> | ||||
|               </template> | ||||
|             </el-table-column> | ||||
|           </ai-table> | ||||
|           <ai-dialog | ||||
|             :visible.sync="isShow" | ||||
|             width="890px" | ||||
|             customFooter | ||||
|             title="上报详情"> | ||||
|             <ai-bar title="健康状况"></ai-bar> | ||||
|             <ai-wrapper | ||||
|               label-width="120px"> | ||||
|               <ai-info-item label="当前体温"> | ||||
|                 <span :style="{color: reportInfo.temperature > 37.3 ? '#FF4466' : '#42D784'}">{{ reportInfo.temperature }}℃</span> | ||||
|               </ai-info-item> | ||||
|               <ai-info-item label="14天内是否接触新冠确诊或疑似患者"> | ||||
|                 <span :style="{color: reportInfo.touchInFourteen === '0' ? '#42D784' : '#FF4466'}">{{ $dict.getLabel('epidemicTouchInFourteen', reportInfo.touchInFourteen) }}</span> | ||||
|               </ai-info-item> | ||||
|               <ai-info-item label="当前健康状况" isLine> | ||||
|                 <span :style="{color: !reportInfo.isHealth ? '#42D784' : '#FF4466'}">{{ reportInfo.healthName }}</span> | ||||
|               </ai-info-item> | ||||
|             </ai-wrapper> | ||||
|             <ai-bar title="核酸检测信息"></ai-bar> | ||||
|             <ai-wrapper | ||||
|               label-width="120px"> | ||||
|               <ai-info-item label="检测日期"> | ||||
|                 <span>{{ reportInfo.checkTime && reportInfo.checkTime.split(' ')[0] }}</span> | ||||
|               </ai-info-item> | ||||
|               <ai-info-item label="检测结果"> | ||||
|                 <span :style="{color: reportInfo.checkResult === '0' ? '#42D784' : '#FF4466'}">{{ $dict.getLabel('epidemicRecentTestResult', reportInfo.checkResult) }}</span> | ||||
|               </ai-info-item> | ||||
|               <ai-info-item label="健康码状态"> | ||||
|                 <span :style="{color: (reportInfo.healthCode === '0' || reportInfo.healthCode === '1') ? '#42D784' : '#FF4466'}">{{ $dict.getLabel('epidemicHealthCode', reportInfo.healthCode) }}</span> | ||||
|               </ai-info-item> | ||||
|               <ai-info-item label="已接种疫苗次数"> | ||||
|                 <span>{{ $dict.getLabel('epidemicVaccineTime', reportInfo.vaccine) }}</span> | ||||
|               </ai-info-item> | ||||
|               <ai-info-item label="本人健康码截图" isLine> | ||||
|                 <ai-uploader | ||||
|                   :instance="instance" | ||||
|                   v-model="reportInfo.checkPhoto" | ||||
|                   disabled | ||||
|                   :limit="9"> | ||||
|                 </ai-uploader> | ||||
|               </ai-info-item> | ||||
|             </ai-wrapper> | ||||
|             <div class="dialog-footer" slot="footer"> | ||||
|               <el-button @click="isShow = false">关闭</el-button> | ||||
|             </div> | ||||
|           </ai-dialog> | ||||
|         </template> | ||||
|       </ai-card> | ||||
|       <div v-show="currIndex === 2"> | ||||
|         <ai-card title="异常处理"> | ||||
|           <template #right> | ||||
|             <el-button type="primary" v-if="info.status === '0'" @click="release">解除异常</el-button> | ||||
|           </template> | ||||
|           <template #content> | ||||
|             <ai-wrapper | ||||
|               label-width="120px"> | ||||
|               <ai-info-item label="姓名" :value="info.name"></ai-info-item> | ||||
|               <ai-info-item label="填报时间" :value="info.createTime"></ai-info-item> | ||||
|               <ai-info-item label="身份证号" :value="info.idNumber"></ai-info-item> | ||||
|               <ai-info-item label="手机号码" :value="info.phone"></ai-info-item> | ||||
|               <ai-info-item label="异常状况" isLine> | ||||
|                 <span :style="{color: info.unusual ? 'red' : '#333'}">{{ info.unusual || '-' }}</span> | ||||
|               </ai-info-item> | ||||
|               <ai-info-item label="异常解除人" v-if="info.releaseName && info.status === '1'" :value="info.releaseName"></ai-info-item> | ||||
|               <ai-info-item label="异常解除时间" v-if="info.releaseTime && info.status === '1'" :value="info.releaseTime"></ai-info-item> | ||||
|             </ai-wrapper> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|         <ai-card title="异常情况记录"> | ||||
|           <template #right> | ||||
|             <el-button type="primary" v-if="info.status === '0'" @click="isShowAdd = true">添加记录</el-button> | ||||
|           </template> | ||||
|           <template #content> | ||||
|             <ai-table | ||||
|               :tableData="recordList" | ||||
|               :col-configs="recordConfigs" | ||||
|               :total="recordTotal" | ||||
|               :current.sync="recordSerch.current" | ||||
|               :size.sync="recordSerch.size" | ||||
|               @getList="getRecordList"> | ||||
|               <el-table-column slot="options" width="120px" fixed="right" label="操作" align="center"> | ||||
|                 <template slot-scope="{ row }"> | ||||
|                   <div class="table-options"> | ||||
|                     <el-button type="text" @click="remove(row.id)">删除</el-button> | ||||
|                   </div> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|             </ai-table> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|         <ai-dialog | ||||
|           :visible.sync="isShowAdd" | ||||
|           width="800px" | ||||
|           @close="form.content = ''" | ||||
|           title="添加异常记录" | ||||
|           @onConfirm="onConfirm"> | ||||
|           <el-form class="ai-form" label-width="120px" :model="form" ref="form"> | ||||
|             <el-form-item label="异常记录" prop="content" style="width: 100%;" :rules="[{ required: true, message: '请输入异常记录' }]"> | ||||
|               <el-input type="textarea" :rows="5" :maxlength="500" v-model="form.content" clearable placeholder="请输入异常记录" show-word-limit></el-input> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </ai-dialog> | ||||
|       </div> | ||||
|     </template> | ||||
|   </ai-detail> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     name: 'Detail', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       params: Object | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         total: 0, | ||||
|         info: {}, | ||||
|         id: '', | ||||
|         isShowAdd: false, | ||||
|         recordTotal: 0, | ||||
|         recordSerch: { | ||||
|           current: 1, | ||||
|           size: 10 | ||||
|         }, | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10 | ||||
|         }, | ||||
|         form: { | ||||
|           content: '' | ||||
|         }, | ||||
|         recordConfigs: [ | ||||
|           {prop: 'content', label: '异常记录', align: 'center' }, | ||||
|           {prop: 'createTime', label: '创建时间', align: 'center'}, | ||||
|           {prop: 'createUserName', label: '记录人', align: 'center' } | ||||
|         ], | ||||
|         reportInfo: {}, | ||||
|         isShow: false, | ||||
|         currIndex: 0, | ||||
|         tableData: [], | ||||
|         recordList: [], | ||||
|         colConfigs: [ | ||||
|           {prop: 'createTime', label: '上报日期', align: 'center', dateFormat: 'YYYY-MM-DD'}, | ||||
|           {prop: 'status', label: '健康状态', align: 'center', format: v => v === '0' ? '异常' : '正常' } | ||||
|         ], | ||||
|         tabList: ['基本信息', '每日上报', '异常处理'] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created () { | ||||
|       if (this.params && this.params.id) { | ||||
|         this.id = this.params.id | ||||
|         this.dict.load(['epidemicRecentHealth', 'epidemicRecentTravel', 'epidemicTouchInFourteen', 'epidemicMemberType', 'epidemicRecentTestResult']).then(() => { | ||||
|           this.getInfo(this.params.id) | ||||
|           this.getList() | ||||
|           this.getRecordList() | ||||
|         }) | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getInfo (id) { | ||||
|         this.instance.post(`/app/appepidemicreportmember/queryDetailById?id=${id}`).then(res => { | ||||
|           if (res.code === 0) { | ||||
|             this.info = res.data | ||||
|             this.currIndex = 0 | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       getRecordList () { | ||||
|         this.instance.post(`/app/appepidemicunusuallog/list`, null, { | ||||
|           params: { | ||||
|             ...this.search, | ||||
|             recordId: this.params.id | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.recordList = res.data.records | ||||
|             this.recordTotal = res.data.total | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       onConfirm() { | ||||
|         this.$refs.form.validate(v => { | ||||
|           if (v) { | ||||
|             this.instance.post('/app/appepidemicunusuallog/addOrUpdate', { | ||||
|               ...this.form, | ||||
|               recordId: this.params.id | ||||
|             }).then(res => { | ||||
|               if (res?.code == 0) { | ||||
|                 this.isShowAdd = false | ||||
|                 this.getRecordList(this.params.id) | ||||
|                 this.$message.success('添加成功!') | ||||
|               } | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       release () { | ||||
|         this.$confirm('确定解除异常?').then(() => { | ||||
|           this.instance.post(`/app/appepidemicreportmember/release`, { | ||||
|             id: this.params.id | ||||
|           }).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('解除异常成功!') | ||||
|               this.currIndex = 0 | ||||
|               this.getInfo(this.params.id) | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       remove(id) { | ||||
|         this.$confirm('确定删除该数据?').then(() => { | ||||
|           this.instance.post(`/app/appepidemicunusuallog/delete?ids=${id}`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('删除成功!') | ||||
|               this.getRecordList(this.params.id) | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       toDetail (id) { | ||||
|         this.instance.post(`/app/appepidemichealthreport/queryDetailById?id=${id}`).then(res => { | ||||
|           if (res.code === 0) { | ||||
|             this.reportInfo = res.data | ||||
|             this.reportInfo.checkPhoto = JSON.parse(res.data.checkPhoto) | ||||
|             let healthName = '' | ||||
|             this.reportInfo.isHealth = false | ||||
|             res.data.health.split(',').forEach(v => { | ||||
|               if (v > 0) { | ||||
|                 this.reportInfo.isHealth = true | ||||
|               } | ||||
|               healthName = healthName + this.dict.getLabel('epidemicRecentHealth', v) | ||||
|             }) | ||||
|             this.reportInfo.healthName = healthName | ||||
|  | ||||
|             this.isShow = true | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       getList () { | ||||
|         this.instance.post(`/app/appepidemichealthreport/list`, null, { | ||||
|           params: { | ||||
|             ...this.search, | ||||
|             memberId: this.params.id | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       cancel (isRefresh) { | ||||
|         this.$emit('change', { | ||||
|           type: 'list', | ||||
|           isRefresh: !!isRefresh | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| </style> | ||||
							
								
								
									
										293
									
								
								packages/conv/AppHealthReport/components/List.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								packages/conv/AppHealthReport/components/List.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,293 @@ | ||||
| <template> | ||||
|   <ai-list class="list"> | ||||
|     <ai-title slot="title" title="健康上报" v-if="search.areaId" isShowBottomBorder :instance="instance" :disabledLevel="disabledLevel" isShowArea v-model="search.areaId" @change="changeArea"></ai-title> | ||||
|     <template slot="content"> | ||||
|       <div class="statistics-top"> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>上报人数</span> | ||||
|           <h2 style="color: #2266FF;">{{ info.total }}</h2> | ||||
|         </div> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>今日上报</span> | ||||
|           <h2 style="color: #22AA99;">{{ info.today }}</h2> | ||||
|         </div> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>今日未报</span> | ||||
|           <h2 style="color: #F8B425">{{ info.unReport }}</h2> | ||||
|         </div> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>今日异常</span> | ||||
|           <h2 style="color: red">{{ info.unusual }}</h2> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="content"> | ||||
|         <ai-search-bar bottomBorder> | ||||
|           <template #left> | ||||
|             <ai-select | ||||
|               v-model="search.checkResult" | ||||
|               clearable | ||||
|               placeholder="请选择检查结果" | ||||
|               :selectList="dict.getDict('epidemicRecentTestResult')" | ||||
|               @change="search.current = 1, getList()"> | ||||
|             </ai-select> | ||||
|             <ai-select | ||||
|               v-model="search.today" | ||||
|               clearable | ||||
|               placeholder="今日是否上报" | ||||
|               :selectList="dictList" | ||||
|               @change="search.current = 1, getList()"> | ||||
|             </ai-select> | ||||
|             <ai-download :instance="instance" url="/app/appepidemicreportmember/export" :params="search" fileName="健康上报" :disabled="tableData.length == 0"> | ||||
|               <el-button icon="iconfont iconExported" :disabled="tableData.length == 0">导出</el-button> | ||||
|             </ai-download> | ||||
|           </template> | ||||
|           <template #right> | ||||
|             <el-input | ||||
|               v-model="search.name" | ||||
|               size="small" | ||||
|               placeholder="请输入姓名" | ||||
|               clearable | ||||
|               v-throttle="() => {search.current = 1, getList()}" | ||||
|               @clear="search.current = 1, search.name = '', getList()" | ||||
|               suffix-icon="iconfont iconSearch"> | ||||
|             </el-input> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <ai-table | ||||
|           :tableData="tableData" | ||||
|           :col-configs="colConfigs" | ||||
|           :total="total" | ||||
|           v-loading="loading" | ||||
|           style="margin-top: 16px;" | ||||
|           :current.sync="search.current" | ||||
|           :size.sync="search.size" | ||||
|           @getList="getList"> | ||||
|           <el-table-column slot="healthCode" align="center" label="健康码"> | ||||
|             <template slot-scope="{ row }"> | ||||
|               <ai-uploader | ||||
|                 v-if="row.healthCode" | ||||
|                 :instance="instance" | ||||
|                 :value="JSON.parse(row.healthCode)" | ||||
|                 disabled | ||||
|                 :limit="1"> | ||||
|               </ai-uploader> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|           <el-table-column slot="options" width="140px" fixed="right" label="操作" align="center"> | ||||
|             <template slot-scope="{ row }"> | ||||
|               <div class="table-options"> | ||||
|                 <el-button type="text" @click="toDetail(row.id)">详情</el-button> | ||||
|                 <el-button type="text" @click="remove(row.id)">删除</el-button> | ||||
|               </div> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|         </ai-table> | ||||
|       </div> | ||||
|     </template> | ||||
|   </ai-list> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import { mapState } from 'vuex' | ||||
|   export default { | ||||
|     name: 'List', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10, | ||||
|           name: '', | ||||
|           checkResult: '', | ||||
|           areaId: '', | ||||
|           today: '' | ||||
|         }, | ||||
|         dictList: [{ | ||||
|           dictName: '否', | ||||
|           dictValue: '0' | ||||
|         }, { | ||||
|           dictName: '是', | ||||
|           dictValue: '1' | ||||
|         }], | ||||
|         info: {}, | ||||
|         colConfigs: [ | ||||
|           { prop: 'name', label: '姓名' }, | ||||
|           { prop: 'phone', align: 'center', label: '手机号码' }, | ||||
|           { prop: 'areaName', align: 'center', label: '所属地区', width: '200px' }, | ||||
|           { prop: 'reportTime', align: 'center', label: '上报时间', width: '200px' }, | ||||
|           { | ||||
|             prop: 'vaccine', | ||||
|             align: 'center', | ||||
|             label: '已接种情况', | ||||
|             render: (h, {row}) => { | ||||
|               return h('span', { | ||||
|                 style: { | ||||
|                 } | ||||
|               }, row.today === '0' ? '-' : (row.vaccine || 0 + '次')) | ||||
|             } | ||||
|           }, | ||||
|           { prop: 'healthCode', align: 'center', label: '健康码', format: v => v ? this.dict.getLabel('epidemicHealthCode', v) : '-' }, | ||||
|           { prop: 'checkTime', align: 'center', label: '核酸日期', format: v => v ? v.split(' ')[0] : '-' }, | ||||
|           { prop: 'checkResult', align: 'center', label: '检测结果', format: v => v ? this.dict.getLabel('epidemicRecentTestResult', v) : '-' }, | ||||
|           { | ||||
|             prop: 'status', | ||||
|             align: 'center', | ||||
|             label: '健康状态', | ||||
|             render: (h, {row}) => { | ||||
|               return h('span', { | ||||
|                 style: { | ||||
|                   color: row.status === '0' ? 'red' : '#333' | ||||
|                 } | ||||
|               }, row.today === '0' ? '-' : (row.status === '0' ? '异常' : '正常')) | ||||
|             } | ||||
|           }, | ||||
|           { prop: 'today', align: 'center', label: '今日上报', format: v => v === '0' ? '未上报' : '已上报' }, | ||||
|         ], | ||||
|         tableData: [], | ||||
|         total: 0, | ||||
|         loading: false, | ||||
|         disabledLevel: 0 | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       ...mapState(['user']), | ||||
|  | ||||
|       param () { | ||||
|         return { | ||||
|  | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created () { | ||||
|       this.disabledLevel = this.user.info.areaList.length - 1 | ||||
|       this.search.areaId = this.user.info.areaId | ||||
|       this.loading = true | ||||
|       this.dict.load(['epidemicTouchInFourteen', 'epidemicRecentHealth', 'epidemicRecentTestResult', 'epidemicHealthCode', 'epidemicVaccineTime']).then(() => { | ||||
|         this.getList() | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getList () { | ||||
|         this.instance.post(`/app/appepidemicreportmember/list`, null, { | ||||
|           params: { | ||||
|             ...this.search | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|             this.loading = false | ||||
|           } else { | ||||
|             this.loading = false | ||||
|           } | ||||
|         }).catch(() => { | ||||
|           this.loading = false | ||||
|         }) | ||||
|  | ||||
|         this.getTotalInfo() | ||||
|       }, | ||||
|  | ||||
|       remove(id) { | ||||
|         this.$confirm('确定删除该数据?').then(() => { | ||||
|           this.instance.post(`/app/appepidemicreportmember/delete?ids=${id}`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('删除成功!') | ||||
|               this.getTotalInfo() | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       toDetail (id) { | ||||
|         this.$emit('change', { | ||||
|           type: 'Detail', | ||||
|           params: { | ||||
|             id: id || '' | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       changeArea () { | ||||
|         this.search.current = 1 | ||||
|  | ||||
|         this.$nextTick(() => { | ||||
|           this.getList() | ||||
|           this.getTotalInfo() | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       getTotalInfo () { | ||||
|         this.instance.post(`/app/appepidemicreportmember/statistic`, null, { | ||||
|           params: { | ||||
|             areaId: this.search.areaId | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.info = res.data | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
|   .list { | ||||
|     :deep( .ai-list__content ){ | ||||
|       padding: 0!important; | ||||
|  | ||||
|       .ai-list__content--right-wrapper { | ||||
|         background: transparent!important; | ||||
|         box-shadow: none!important; | ||||
|         margin: 0!important; | ||||
|         padding: 12px 16px 12px!important; | ||||
|       } | ||||
|     } | ||||
|     .statistics-top { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       margin-bottom: 20px; | ||||
|  | ||||
|       & > div { | ||||
|         flex: 1; | ||||
|         height: 96px; | ||||
|         line-height: 1; | ||||
|         margin-right: 20px; | ||||
|         padding: 16px 24px; | ||||
|         background: #FFFFFF; | ||||
|         box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15); | ||||
|         border-radius: 4px; | ||||
|  | ||||
|         &:last-child { | ||||
|           margin-right: 0; | ||||
|         } | ||||
|  | ||||
|         h3 { | ||||
|           font-size: 24px; | ||||
|         } | ||||
|  | ||||
|         span { | ||||
|           display: block; | ||||
|           margin-bottom: 16px; | ||||
|           color: #888888; | ||||
|           font-size: 16px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .content { | ||||
|       padding: 16px; | ||||
|       background: #FFFFFF; | ||||
|       box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15); | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										105
									
								
								packages/conv/AppReturnHomeRegister/AppReturnHomeRegister.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								packages/conv/AppReturnHomeRegister/AppReturnHomeRegister.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | ||||
| <template> | ||||
|   <ai-list class="AppReturnHomeRegister" v-if="!isShowDetail"> | ||||
|     <template slot="title"> | ||||
|       <ai-title title="返乡登记" :isShowBottomBorder="false" :fullname.sync="areaName" v-model="areaId" :instance="instance" @change="onAreaChange"></ai-title> | ||||
|     </template> | ||||
|     <template slot="tabs"> | ||||
|       <el-tabs v-model="currIndex"> | ||||
|         <el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label"> | ||||
|           <component :areaId="areaId" :ref="String(i)" v-if="currIndex == i" :is="tab.comp" @change="onChange" lazy :instance="instance" :dict="dict" :permissions="permissions"/> | ||||
|         </el-tab-pane> | ||||
|       </el-tabs> | ||||
|     </template> | ||||
|   </ai-list> | ||||
|   <Detail v-else-if="component === 'Detail'" :params="params" :instance="instance" :dict="dict" :permissions="permissions" @change="onChange"></Detail> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import List from './components/List.vue' | ||||
|   import Detail from './components/Detail.vue' | ||||
|   import AbnormalList from './components/AbnormalList.vue' | ||||
|   import { mapState } from 'vuex' | ||||
|  | ||||
|   export default { | ||||
|     name: 'AppReturnHomeRegister', | ||||
|     label: '返乡登记', | ||||
|  | ||||
|     components: { | ||||
|       List, | ||||
|       Detail, | ||||
|       AbnormalList | ||||
|     }, | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       permissions: Function | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       ...mapState(['user']), | ||||
|  | ||||
|       tabs () { | ||||
|         const tabList = [ | ||||
|           {label: '返乡登记', name: 'List', comp: List, permission: ''}, | ||||
|           // {label: '历史异常人员', name: 'AbnormalList', comp: AbnormalList, permission: ''} | ||||
|         ] | ||||
|  | ||||
|         return tabList | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         activeName: 'JoinEvent', | ||||
|         currIndex: '0', | ||||
|         component: 'List', | ||||
|         params: {}, | ||||
|         areaId: '', | ||||
|         isShowDetail: false, | ||||
|         areaName: '' | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created () { | ||||
|       this.areaId = this.user.info.areaId | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       onChange (data) { | ||||
|         if (data.type === 'Detail') { | ||||
|           this.component = 'Detail' | ||||
|           this.isShowDetail = true | ||||
|           this.params = data.params | ||||
|         } | ||||
|         if (data.type === 'AbnormalList') { | ||||
|           this.component = 'AbnormalList' | ||||
|           this.isShowDetail = false | ||||
|           this.params = data.params | ||||
|         } | ||||
|  | ||||
|         if (data.type === 'List') { | ||||
|           this.component = 'List' | ||||
|           this.isShowDetail = false | ||||
|           this.params = data.params | ||||
|  | ||||
|           this.$nextTick(() => { | ||||
|             if (data.isRefresh) { | ||||
|               this.$refs.component.getList() | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }, | ||||
|  | ||||
|       onAreaChange () { | ||||
|         this.$refs[this.currIndex][0].changeArea() | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .AppReturnHomeRegister { | ||||
|     height: 100%; | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										200
									
								
								packages/conv/AppReturnHomeRegister/components/AbnormalList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								packages/conv/AppReturnHomeRegister/components/AbnormalList.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,200 @@ | ||||
| <template> | ||||
|   <ai-list isTabs> | ||||
|     <template slot="content"> | ||||
|       <ai-search-bar bottomBorder> | ||||
|         <template #left> | ||||
|           <ai-select | ||||
|             v-model="search.status" | ||||
|             clearable | ||||
|             placeholder="请选择健康状态" | ||||
|             :selectList="dictList" | ||||
|             @change="search.current = 1, getList()"> | ||||
|           </ai-select> | ||||
|           <ai-download :instance="instance" url="/app/appepidemicbackhomerecord/export" :params="param" fileName="返乡登记" :disabled="tableData.length == 0"> | ||||
|             <el-button icon="iconfont iconExported" :disabled="tableData.length == 0">导出</el-button> | ||||
|           </ai-download> | ||||
|         </template> | ||||
|         <template #right> | ||||
|           <el-input | ||||
|             v-model="search.name" | ||||
|             size="small" | ||||
|             placeholder="请输入姓名" | ||||
|             clearable | ||||
|             v-throttle="() => {search.current = 1, getList()}" | ||||
|             @clear="search.current = 1, search.name = '', getList()" | ||||
|             suffix-icon="iconfont iconSearch"> | ||||
|           </el-input> | ||||
|         </template> | ||||
|       </ai-search-bar> | ||||
|       <ai-table | ||||
|         :tableData="tableData" | ||||
|         :col-configs="colConfigs" | ||||
|         :total="total" | ||||
|         v-loading="loading" | ||||
|         style="margin-top: 16px;" | ||||
|         :current.sync="search.current" | ||||
|         :size.sync="search.size" | ||||
|         @getList="getList"> | ||||
|         <el-table-column slot="options" width="140px" fixed="right" label="操作" align="center"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="table-options"> | ||||
|               <el-button type="text" @click="toDetail(row.id)">详情</el-button> | ||||
|               <el-button type="text" @click="remove(row.id)">删除</el-button> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </ai-table> | ||||
|     </template> | ||||
|   </ai-list> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import { mapState } from 'vuex' | ||||
|   export default { | ||||
|     name: 'AbnormalList', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10, | ||||
|           name: '', | ||||
|           arriveAreaId: '', | ||||
|           status: '' | ||||
|         }, | ||||
|         dictList: [{ | ||||
|           dictName: '异常', | ||||
|           dictValue: '0' | ||||
|         }, { | ||||
|           dictName: '正常', | ||||
|           dictValue: '1' | ||||
|         }], | ||||
|         info: {}, | ||||
|         colConfigs: [ | ||||
|           { prop: 'name', label: '姓名' }, | ||||
|           { prop: 'phone', align: 'center', label: '手机号码' }, | ||||
|           { prop: 'startTime', align: 'center', label: '出发时间', format: v => v.substr(0, v.length - 3) }, | ||||
|           { | ||||
|             prop: 'startAreaName', | ||||
|             align: 'center', | ||||
|             label: '出发地区' | ||||
|           }, | ||||
|           { prop: 'arriveTime', align: 'center', label: '到达时间', format: v => v.substr(0, v.length - 3) }, | ||||
|           { | ||||
|             prop: 'arriveAreaName', | ||||
|             align: 'center', | ||||
|             label: '到达地区' | ||||
|           }, | ||||
|           { prop: 'checkTime', align: 'center', label: '核酸日期', format: v => v.split(' ')[0] }, | ||||
|           { | ||||
|             prop: 'status', | ||||
|             align: 'center', | ||||
|             label: '健康状态', | ||||
|             render: (h, {row}) => { | ||||
|               return h('span', { | ||||
|                 style: { | ||||
|                   color: row.status === '0' ? 'red' : '#333' | ||||
|                 } | ||||
|               }, row.status === '0' ? '异常' : '正常') | ||||
|             } | ||||
|           } | ||||
|         ], | ||||
|         ids: [], | ||||
|         tableData: [], | ||||
|         total: 0, | ||||
|         loading: false, | ||||
|         disabledLevel: 0 | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       ...mapState(['user']), | ||||
|  | ||||
|       param () { | ||||
|         return this.search | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created () { | ||||
|       this.disabledLevel = this.user.info.areaList.length - 1 | ||||
|       this.search.arriveAreaId = this.user.info.areaId | ||||
|       this.loading = true | ||||
|       this.dict.load(['marriageType', 'marriagePersonType', 'modeType']).then(() => { | ||||
|         this.getList() | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getList () { | ||||
|         this.instance.post(`/app/appepidemicbackhomerecord/list`, null, { | ||||
|           params: { | ||||
|             ...this.search | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|             this.loading = false | ||||
|           } else { | ||||
|             this.loading = false | ||||
|           } | ||||
|         }).catch(() => { | ||||
|           this.loading = false | ||||
|         }) | ||||
|  | ||||
|         this.getTotalInfo() | ||||
|       }, | ||||
|  | ||||
|       toDetail (id) { | ||||
|         this.$emit('change', { | ||||
|           type: 'Detail', | ||||
|           params: { | ||||
|             id: id || '' | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       changeArea () { | ||||
|         this.search.current = 1 | ||||
|  | ||||
|         this.$nextTick(() => { | ||||
|           this.getList() | ||||
|           this.getTotalInfo() | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       remove(id) { | ||||
|         this.$confirm('确定删除该数据?').then(() => { | ||||
|           this.instance.post(`/app/appepidemicbackhomerecord/delete?ids=${id}`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('删除成功!') | ||||
|               this.getTotalInfo() | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|  | ||||
|       getTotalInfo () { | ||||
|         this.instance.post(`/app/appepidemicbackhomerecord/statistic`, null, { | ||||
|           params: { | ||||
|             areaId: this.search.arriveAreaId | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.info = res.data | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| </style> | ||||
							
								
								
									
										279
									
								
								packages/conv/AppReturnHomeRegister/components/Detail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										279
									
								
								packages/conv/AppReturnHomeRegister/components/Detail.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,279 @@ | ||||
|  <template> | ||||
|   <ai-detail isHasSidebar> | ||||
|     <template slot="title"> | ||||
|       <ai-title title="返乡登记详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)"> | ||||
|       </ai-title> | ||||
|     </template> | ||||
|     <template slot="content"> | ||||
|       <AiSidebar :tabTitle="tabList" v-model="currIndex"></AiSidebar> | ||||
|       <div v-show="currIndex === 0"> | ||||
|         <ai-card title="基本信息" v-show="currIndex === 0"> | ||||
|           <template #content> | ||||
|             <ai-wrapper | ||||
|               label-width="120px"> | ||||
|               <ai-info-item label="姓名" :value="info.name"></ai-info-item> | ||||
|               <ai-info-item label="填报时间" :value="info.createTime"></ai-info-item> | ||||
|               <ai-info-item label="身份证号" :value="info.idNumber"></ai-info-item> | ||||
|               <ai-info-item label="手机号码" :value="info.phone"></ai-info-item> | ||||
|               <ai-info-item label="人员类别" isLine> | ||||
|                 <span :style="(info.type == 0 || info.type == 3 || info.type ==6 || info.type == 9)? 'color:#42D784;' : 'color:#f46;'">{{dict.getLabel('epidemicRecentPersonType', info.type)}}</span> | ||||
|               </ai-info-item> | ||||
|             </ai-wrapper> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|         <ai-card title="行程信息"> | ||||
|           <template #content> | ||||
|             <ai-wrapper | ||||
|               label-width="120px"> | ||||
|               <ai-info-item label="出发时间" :value="info.startTime"></ai-info-item> | ||||
|               <ai-info-item label="出发地区" > | ||||
|                 <span  :style="{color: info.denger == 1 ? '#FF4466' : '#333'}">{{info.startAreaName}} </span> | ||||
|               </ai-info-item> | ||||
|               <ai-info-item label="出发地址" isLine :value="info.startAddress"></ai-info-item> | ||||
|               <ai-info-item label="出行方式" :value="dict.getLabel('epidemicRecentTravel', info.travelType)"></ai-info-item> | ||||
|               <ai-info-item label="行程描述" isLine :value="info.description"></ai-info-item> | ||||
|               <ai-info-item label="到达时间" :value="info.arriveTime"></ai-info-item> | ||||
|               <ai-info-item label="到达地区" :value="info.arriveAreaName"></ai-info-item> | ||||
|               <ai-info-item label="返乡地址" isLine :value="info.arriveAddress"></ai-info-item> | ||||
|             </ai-wrapper> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|         <ai-card title="健康状况"> | ||||
|           <template #content> | ||||
|             <ai-wrapper | ||||
|               label-width="120px"> | ||||
|               <ai-info-item label="当前体温"> | ||||
|                 <span :style="info.temperature >= 37.3 ? 'color:#f46;' : ''">{{ info.temperature + '℃' }}</span> | ||||
|               </ai-info-item> | ||||
|               <ai-info-item label="14天内是否接触新冠确诊或疑似患者"> | ||||
|                 <span :class="'color-'+info.touchInFourteen">{{$dict.getLabel('epidemicTouchInFourteen', info.touchInFourteen)}}</span>  | ||||
|               </ai-info-item> | ||||
|               <ai-info-item label="当前健康状况">  | ||||
|                 <span></span> | ||||
|                 <span v-for="(item, index) in info.health" :key="index" :style="item != 0 ? 'color:#FF4466;' : ''"><span v-if="index>0">;</span>{{$dict.getLabel('epidemicRecentHealth', item)}}</span> | ||||
|               </ai-info-item> | ||||
|             </ai-wrapper> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|         <ai-card title="核酸检测"> | ||||
|           <template #content> | ||||
|             <ai-wrapper | ||||
|               label-width="120px"> | ||||
|               <ai-info-item label="检测日期" :value="info.checkTime && info.checkTime.split(' ')[0]"></ai-info-item> | ||||
|               <ai-info-item label="检测结果"> | ||||
|                 <span :style="info.checkResult == 1 ? 'color:#f46;' : 'color:#42D784;'">{{$dict.getLabel('epidemicRecentTestResult', info.checkResult)}}</span> | ||||
|               </ai-info-item> | ||||
|               <ai-info-item label="本人健康码截图" isLine> | ||||
|                 <ai-uploader | ||||
|                   :instance="instance" | ||||
|                   v-model="info.checkPhoto" | ||||
|                   disabled | ||||
|                   :limit="9"> | ||||
|                 </ai-uploader> | ||||
|               </ai-info-item> | ||||
|             </ai-wrapper> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|       </div> | ||||
|       <div v-show="currIndex === 1"> | ||||
|         <ai-card title="异常处理"> | ||||
|           <template #right> | ||||
|             <el-button type="primary" v-if="info.status === '0'" @click="release">解除异常</el-button> | ||||
|           </template> | ||||
|           <template #content> | ||||
|             <ai-wrapper | ||||
|               label-width="120px"> | ||||
|               <ai-info-item label="姓名" :value="info.name"></ai-info-item> | ||||
|               <ai-info-item label="填报时间" :value="info.createTime"></ai-info-item> | ||||
|               <ai-info-item label="身份证号" :value="info.idNumber"></ai-info-item> | ||||
|               <ai-info-item label="手机号码" :value="info.phone"></ai-info-item> | ||||
|               <ai-info-item label="人员类别" isLine :value="dict.getLabel('epidemicRecentPersonType', info.type)"></ai-info-item> | ||||
|               <ai-info-item label="异常状况" isLine> | ||||
|                 <span :style="{color: info.unusual ? 'red' : '#333'}">{{ info.unusual || '-' }}</span> | ||||
|               </ai-info-item> | ||||
|               <ai-info-item label="异常解除人" v-if="info.releaseName && info.status === '1'" :value="info.releaseName"></ai-info-item> | ||||
|               <ai-info-item label="异常解除时间" v-if="info.releaseTime && info.status === '1'" :value="info.releaseTime"></ai-info-item> | ||||
|             </ai-wrapper> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|         <ai-card title="异常情况记录"> | ||||
|           <template #right> | ||||
|             <el-button type="primary" v-if="info.status === '0'" @click="isShow = true">添加记录</el-button> | ||||
|           </template> | ||||
|           <template #content> | ||||
|             <ai-table | ||||
|               :tableData="tableData" | ||||
|               :col-configs="colConfigs" | ||||
|               :total="total" | ||||
|               :current.sync="search.current" | ||||
|               :size.sync="search.size" | ||||
|               @getList="getList"> | ||||
|               <el-table-column slot="options" width="120px" fixed="right" label="操作" align="center"> | ||||
|                 <template slot-scope="{ row }"> | ||||
|                   <div class="table-options"> | ||||
|                     <el-button type="text" @click="remove(row.id)">删除</el-button> | ||||
|                   </div> | ||||
|                 </template> | ||||
|               </el-table-column> | ||||
|             </ai-table> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|         <ai-dialog | ||||
|           :visible.sync="isShow" | ||||
|           width="800px" | ||||
|           @close="form.content = ''" | ||||
|           title="添加异常记录" | ||||
|           @onConfirm="onConfirm"> | ||||
|           <el-form class="ai-form" label-width="120px" :model="form" ref="form"> | ||||
|             <el-form-item label="异常记录" prop="content" style="width: 100%;" :rules="[{ required: true, message: '请输入异常记录' }]"> | ||||
|               <el-input type="textarea" :rows="5" :maxlength="500" v-model="form.content" clearable placeholder="请输入异常记录" show-word-limit></el-input> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </ai-dialog> | ||||
|       </div> | ||||
|     </template> | ||||
|   </ai-detail> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     name: 'Detail', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       params: Object | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         total: 0, | ||||
|         info: {}, | ||||
|         id: '', | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10 | ||||
|         }, | ||||
|         form: { | ||||
|           content: '' | ||||
|         }, | ||||
|         isShow: false, | ||||
|         currIndex: 0, | ||||
|         tableData: [], | ||||
|         colConfigs: [ | ||||
|           {prop: 'content', label: '异常记录', align: 'center' }, | ||||
|           {prop: 'createTime', label: '创建时间', align: 'center'}, | ||||
|           {prop: 'createUserName', label: '记录人', align: 'center' } | ||||
|         ], | ||||
|         tabList: ['基本信息', '异常处理'] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created () { | ||||
|       if (this.params && this.params.id) { | ||||
|         this.id = this.params.id | ||||
|         this.$dict.load(['epidemicRecentHealth', 'epidemicRecentTravel', 'epidemicTouchInFourteen', 'epidemicRecentPersonType', 'epidemicRecentTestResult']).then(() => { | ||||
|           this.getInfo(this.params.id) | ||||
|         }) | ||||
|  | ||||
|         this.getList() | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getInfo (id) { | ||||
|         this.instance.post(`/app/appepidemicbackhomerecord/queryDetailById?id=${id}`).then(res => { | ||||
|           if (res.code === 0) { | ||||
|             this.info = res.data | ||||
|             this.info.checkPhoto = res.data.checkPhoto ? JSON.parse(res.data.checkPhoto) : [] | ||||
|             let healthName = '' | ||||
|             this.info.isHealth = false | ||||
|             res.data.health.split(',').forEach(v => { | ||||
|               if (v > 0) { | ||||
|                 this.info.isHealth = true | ||||
|               } | ||||
|               healthName = healthName + this.$dict.getLabel('epidemicRecentHealth', v) | ||||
|             }) | ||||
|             this.info.healthName = healthName | ||||
|             this.info.health = this.info.health.split(',') | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       release () { | ||||
|         this.$confirm('确定解除异常?').then(() => { | ||||
|           this.instance.post(`/app/appepidemicbackhomerecord/release?recordId=${this.params.id}`, { | ||||
|             id: this.params.id | ||||
|           }).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('解除异常成功!') | ||||
|               this.currIndex = 0 | ||||
|               this.getInfo(this.params.id) | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       remove(id) { | ||||
|         this.$confirm('确定删除该数据?').then(() => { | ||||
|           this.instance.post(`/app/appepidemicunusuallog/delete?ids=${id}`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('删除成功!') | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       onConfirm() { | ||||
|         this.$refs.form.validate(v => { | ||||
|           if (v) { | ||||
|             this.instance.post('/app/appepidemicunusuallog/addOrUpdate', { | ||||
|               ...this.form, | ||||
|               recordId: this.params.id | ||||
|             }).then(res => { | ||||
|               if (res?.code == 0) { | ||||
|                 this.isShow = false | ||||
|                 this.getList() | ||||
|                 this.$message.success('添加成功!') | ||||
|               } | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       getList () { | ||||
|         this.instance.post(`/app/appepidemicunusuallog/list`, null, { | ||||
|           params: { | ||||
|             ...this.search, | ||||
|             recordId: this.params.id | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       cancel () { | ||||
|         this.$emit('change', { | ||||
|           type: 'List', | ||||
|           isRefresh: true | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
|   .color-0{ | ||||
|     color: #42D784; | ||||
|   } | ||||
|   .color-1{ | ||||
|     color: #f46; | ||||
|   } | ||||
|   .color-2{ | ||||
|     color: #1365DD; | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										273
									
								
								packages/conv/AppReturnHomeRegister/components/List.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								packages/conv/AppReturnHomeRegister/components/List.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,273 @@ | ||||
| <template> | ||||
|   <ai-list class="list" isTabs> | ||||
|     <template slot="content"> | ||||
|       <div class="statistics-top"> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>返乡人数</span> | ||||
|           <h2 style="color: #2266FF;">{{ info.total }}</h2> | ||||
|         </div> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>今日新增返乡</span> | ||||
|           <h2 style="color: #22AA99;">{{ info.today }}</h2> | ||||
|         </div> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>异常人数</span> | ||||
|           <h2 style="color: #F8B425">{{ info.unusual }}</h2> | ||||
|         </div> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>今日异常人数</span> | ||||
|           <h2 style="color: red">{{ info.todayUnusual }}</h2> | ||||
|         </div> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>异常处理</span> | ||||
|           <h2 style="color: red">{{ info.release }}</h2> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="content"> | ||||
|         <ai-search-bar bottomBorder> | ||||
|           <template #left> | ||||
|             <ai-select | ||||
|               v-model="search.status" | ||||
|               clearable | ||||
|               placeholder="请选择健康状态" | ||||
|               :selectList="dictList" | ||||
|               @change="search.current = 1, getList()"> | ||||
|             </ai-select> | ||||
|             <ai-download :instance="instance" url="/app/appepidemicbackhomerecord/export" :params="param" fileName="返乡登记" :disabled="tableData.length == 0"> | ||||
|               <el-button icon="iconfont iconExported" :disabled="tableData.length == 0">导出</el-button> | ||||
|             </ai-download> | ||||
|           </template> | ||||
|           <template #right> | ||||
|             <el-input | ||||
|               v-model="search.name" | ||||
|               size="small" | ||||
|               placeholder="请输入姓名" | ||||
|               clearable | ||||
|               v-throttle="() => {search.current = 1, getList()}" | ||||
|               @clear="search.current = 1, search.name = '', getList()" | ||||
|               suffix-icon="iconfont iconSearch"> | ||||
|             </el-input> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <ai-table | ||||
|           :tableData="tableData" | ||||
|           :col-configs="colConfigs" | ||||
|           :total="total" | ||||
|           v-loading="loading" | ||||
|           style="margin-top: 16px;" | ||||
|           :current.sync="search.current" | ||||
|           :size.sync="search.size" | ||||
|           @getList="getList"> | ||||
|           <el-table-column slot="options" width="140px" fixed="right" label="操作" align="center"> | ||||
|             <template slot-scope="{ row }"> | ||||
|               <div class="table-options"> | ||||
|                 <el-button type="text" @click="toDetail(row.id)">详情</el-button> | ||||
|                 <el-button type="text" @click="remove(row.id)">删除</el-button> | ||||
|               </div> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|         </ai-table> | ||||
|       </div> | ||||
|     </template> | ||||
|   </ai-list> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import { mapState } from 'vuex' | ||||
|   export default { | ||||
|     name: 'List', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       areaId: String | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10, | ||||
|           name: '', | ||||
|           status: '' | ||||
|         }, | ||||
|         dictList: [{ | ||||
|           dictName: '异常', | ||||
|           dictValue: '0' | ||||
|         }, { | ||||
|           dictName: '正常', | ||||
|           dictValue: '1' | ||||
|         }], | ||||
|         info: {}, | ||||
|         colConfigs: [ | ||||
|           { prop: 'name', label: '姓名' }, | ||||
|           { prop: 'phone', align: 'center', label: '手机号码' }, | ||||
|           { prop: 'startTime', align: 'center', label: '出发时间', format: v => v.substr(0, v.length - 3) }, | ||||
|           { | ||||
|             prop: 'startAreaName', | ||||
|             align: 'center', | ||||
|             label: '出发地区' | ||||
|           }, | ||||
|           { prop: 'arriveTime', align: 'center', label: '到达时间', format: v => v.substr(0, v.length - 3) }, | ||||
|           { | ||||
|             prop: 'arriveAreaName', | ||||
|             align: 'center', | ||||
|             label: '到达地区' | ||||
|           }, | ||||
|           { prop: 'checkTime', align: 'center', label: '核酸日期', format: v => v.split(' ')[0] }, | ||||
|           { | ||||
|             prop: 'status', | ||||
|             align: 'center', | ||||
|             label: '健康状态', | ||||
|             render: (h, {row}) => { | ||||
|               return h('span', { | ||||
|                 style: { | ||||
|                   color: row.status === '0' ? 'red' : '#333' | ||||
|                 } | ||||
|               }, row.status === '0' ? '异常' : '正常') | ||||
|             } | ||||
|           } | ||||
|         ], | ||||
|         ids: [], | ||||
|         tableData: [], | ||||
|         total: 0, | ||||
|         loading: false, | ||||
|         disabledLevel: 0 | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       ...mapState(['user']), | ||||
|  | ||||
|       param () { | ||||
|         return this.search | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created () { | ||||
|       this.disabledLevel = this.user.info.areaList.length - 1 | ||||
|       this.loading = true | ||||
|       this.dict.load(['marriageType', 'marriagePersonType', 'modeType']).then(() => { | ||||
|         this.getList() | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getList () { | ||||
|         this.instance.post(`/app/appepidemicbackhomerecord/list`, null, { | ||||
|           params: { | ||||
|             ...this.search, | ||||
|             arriveAreaId: this.areaId | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|             this.loading = false | ||||
|           } else { | ||||
|             this.loading = false | ||||
|           } | ||||
|         }).catch(() => { | ||||
|           this.loading = false | ||||
|         }) | ||||
|  | ||||
|         this.getTotalInfo() | ||||
|       }, | ||||
|  | ||||
|       toDetail (id) { | ||||
|         this.$emit('change', { | ||||
|           type: 'Detail', | ||||
|           params: { | ||||
|             id: id || '' | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       changeArea () { | ||||
|         this.search.current = 1 | ||||
|  | ||||
|         this.$nextTick(() => { | ||||
|           this.getList() | ||||
|           this.getTotalInfo() | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       remove(id) { | ||||
|         this.$confirm('确定删除该数据?').then(() => { | ||||
|           this.instance.post(`/app/appepidemicbackhomerecord/delete?ids=${id}`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('删除成功!') | ||||
|               this.getTotalInfo() | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|  | ||||
|       getTotalInfo () { | ||||
|         this.instance.post(`/app/appepidemicbackhomerecord/statistic`, null, { | ||||
|           params: { | ||||
|             areaId: this.search.arriveAreaId | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.info = res.data | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
|   .list { | ||||
|     :deep( .ai-list__content ){ | ||||
|       padding: 0!important; | ||||
|  | ||||
|       .ai-list__content--right-wrapper { | ||||
|         background: transparent!important; | ||||
|         box-shadow: none!important; | ||||
|         margin: 0!important; | ||||
|         padding: 0 0 0!important; | ||||
|       } | ||||
|     } | ||||
|     .statistics-top { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       margin-bottom: 20px; | ||||
|  | ||||
|       & > div { | ||||
|         flex: 1; | ||||
|         height: 96px; | ||||
|         line-height: 1; | ||||
|         margin-right: 20px; | ||||
|         padding: 16px 24px; | ||||
|         background: #FFFFFF; | ||||
|         box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15); | ||||
|         border-radius: 4px; | ||||
|  | ||||
|         &:last-child { | ||||
|           margin-right: 0; | ||||
|         } | ||||
|  | ||||
|         h3 { | ||||
|           font-size: 24px; | ||||
|         } | ||||
|  | ||||
|         span { | ||||
|           display: block; | ||||
|           margin-bottom: 16px; | ||||
|           color: #888888; | ||||
|           font-size: 16px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .content { | ||||
|       padding: 16px; | ||||
|       background: #FFFFFF; | ||||
|       box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15); | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										65
									
								
								packages/conv/AppRiskArea/AppRiskArea.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								packages/conv/AppRiskArea/AppRiskArea.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | ||||
| <template> | ||||
|   <div class="doc-circulation ailist-wrapper"> | ||||
|     <keep-alive :include="['List']"> | ||||
|       <component ref="component" :moduleName="moduleName" :moduleId="moduleId" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component> | ||||
|     </keep-alive> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import List from './components/List' | ||||
|   import Add from './components/Add' | ||||
|  | ||||
|   export default { | ||||
|     name: 'AppRiskArea', | ||||
|     label: '风险配置', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         component: 'List', | ||||
|         params: {}, | ||||
|         moduleId: '', | ||||
|         include: [], | ||||
|         moduleName: '' | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     components: { | ||||
|       Add, | ||||
|       List | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       onChange (data) { | ||||
|         if (data.type === 'Add') { | ||||
|           this.component = 'Add' | ||||
|           this.params = data.params | ||||
|         } | ||||
|  | ||||
|         if (data.type === 'list') { | ||||
|           this.component = 'List' | ||||
|           this.params = data.params | ||||
|  | ||||
|           this.$nextTick(() => { | ||||
|             if (data.isRefresh) { | ||||
|               this.$refs.component.getList() | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
|   .doc-circulation { | ||||
|     height: 100%; | ||||
|     background: #F3F6F9; | ||||
|     overflow: auto; | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										154
									
								
								packages/conv/AppRiskArea/components/Add.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								packages/conv/AppRiskArea/components/Add.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
| <template> | ||||
|   <ai-detail class="content-add"> | ||||
|     <template slot="title"> | ||||
|       <ai-title :title="params.id ? '编辑风险区域' : '添加风险区域'" isShowBack isShowBottomBorder @onBackClick="cancel(false)"> | ||||
|       </ai-title> | ||||
|     </template> | ||||
|     <template slot="content"> | ||||
|       <ai-card title="基本信息"> | ||||
|         <template #content> | ||||
|           <el-form class="ai-form" :model="form" label-width="120px" ref="form"> | ||||
|             <el-form-item prop="areaId" style="width: 100%;" label="选择地区" :rules="[{required: true, message: '请选择地区', trigger: 'change'}]"> | ||||
|               <ai-area-select clearable @fullname="v => form.areaName = v" always-show :instance="instance" v-model="form.areaId"></ai-area-select> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="风险等级" style="width: 100%;" prop="level" :rules="[{required: true, message: '请选择风险等级', trigger: 'change'}]"> | ||||
|               <ai-select | ||||
|                 v-model="form.level" | ||||
|                 clearable | ||||
|                 placeholder="请选择风险等级" | ||||
|                 :selectList="dict.getDict('epidemicDangerousAreaLevel')"> | ||||
|               </ai-select> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </template> | ||||
|       </ai-card> | ||||
|     </template> | ||||
|     <template #footer> | ||||
|       <el-button @click="cancel">取消</el-button> | ||||
|       <el-button type="primary" @click="confirm">提交</el-button> | ||||
|     </template> | ||||
|   </ai-detail> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import { mapState } from 'vuex' | ||||
|   export default { | ||||
|     name: 'Add', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       params: Object, | ||||
|       moduleName: String | ||||
|     }, | ||||
|     data () { | ||||
|       return { | ||||
|         info: {}, | ||||
|         form: { | ||||
|           level: '', | ||||
|           areaId: '', | ||||
|           areaName: '' | ||||
|         }, | ||||
|         id: '' | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       ...mapState(['user']) | ||||
|     }, | ||||
|  | ||||
|     created () { | ||||
|       this.dict.load('epidemicDangerousAreaLevel').then(() => { | ||||
|         if (this.params && this.params.id) { | ||||
|           this.id = this.params.id | ||||
|           this.getInfo(this.params.id) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getInfo (id) { | ||||
|         this.instance.post(`/app/appepidemicdangerousarea/queryDetailById?id=${id}`).then(res => { | ||||
|           if (res.code === 0) { | ||||
|             this.form = res.data | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       confirm () { | ||||
|         this.$refs.form.validate((valid) => { | ||||
|           if (valid) { | ||||
|             this.instance.post(`/app/appepidemicdangerousarea/addOrUpdate`, { | ||||
|               ...this.form | ||||
|             }).then(res => { | ||||
|               if (res.code == 0) { | ||||
|                 this.$message.success('提交成功') | ||||
|                 setTimeout(() => { | ||||
|                   this.cancel(true) | ||||
|                 }, 600) | ||||
|               } | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       cancel (isRefresh) { | ||||
|         this.$emit('change', { | ||||
|           type: 'list', | ||||
|           isRefresh: !!isRefresh | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
|   .content-add { | ||||
|     .video { | ||||
|       width: 640px; | ||||
|       height: 360px; | ||||
|       border-radius: 4px; | ||||
|       border: 1px dashed #D0D4DC; | ||||
|       display: flex; | ||||
|       flex-direction: column; | ||||
|       align-items: center; | ||||
|       justify-content: center; | ||||
|  | ||||
|       .icon { | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         align-items: center; | ||||
|         justify-content: center; | ||||
|  | ||||
|         span:nth-child(2) { | ||||
|           display: inline-block; | ||||
|           font-size: 16px; | ||||
|           color: #333333; | ||||
|           line-height: 30px; | ||||
|         } | ||||
|  | ||||
|         .iconfont { | ||||
|           display: inline-block; | ||||
|           font-size: 40px; | ||||
|           color: #2266FF; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .tips { | ||||
|         display: inline-block; | ||||
|         font-size: 12px; | ||||
|         color: #999999; | ||||
|         line-height: 26px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .video-com { | ||||
|       width: 640px; | ||||
|       height: 360px; | ||||
|       background: rgba(0, 0, 0, 0.5); | ||||
|       border-radius: 2px; | ||||
|       border: 1px solid #D0D4DC; | ||||
|       margin-top: -40px; | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										141
									
								
								packages/conv/AppRiskArea/components/List.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										141
									
								
								packages/conv/AppRiskArea/components/List.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,141 @@ | ||||
| <template> | ||||
|   <ai-list class="notice"> | ||||
|     <template slot="title"> | ||||
|       <ai-title title="风险区域配置" isShowBottomBorder></ai-title> | ||||
|     </template> | ||||
|     <template slot="content"> | ||||
|       <ai-search-bar class="search-bar"> | ||||
|         <template #left> | ||||
|           <ai-select | ||||
|             v-model="search.level" | ||||
|             clearable | ||||
|             placeholder="请选择风险等级" | ||||
|             :selectList="dict.getDict('epidemicDangerousAreaLevel')" | ||||
|             @change="search.current = 1, getList()"> | ||||
|           </ai-select> | ||||
|           <el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd('')">添加</el-button> | ||||
|         </template> | ||||
|         <template #right> | ||||
|           <el-input | ||||
|             v-model="search.province" | ||||
|             class="search-input" | ||||
|             size="small" | ||||
|             v-throttle="() => {search.current = 1, getList()}" | ||||
|             placeholder="省级名称/市级名称/区级名称" | ||||
|             clearable | ||||
|             @clear="search.current = 1, search.province = '', getList()" | ||||
|             suffix-icon="iconfont iconSearch"> | ||||
|           </el-input> | ||||
|         </template> | ||||
|       </ai-search-bar> | ||||
|       <ai-table | ||||
|         :tableData="tableData" | ||||
|         :col-configs="colConfigs" | ||||
|         :total="total" | ||||
|         style="margin-top: 6px;" | ||||
|         :current.sync="search.current" | ||||
|         :size.sync="search.size" | ||||
|         @getList="getList"> | ||||
|         <el-table-column slot="options" width="140px" fixed="right" label="操作" align="center"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="table-options"> | ||||
|               <el-button type="text" @click="toAdd(row.id)">编辑</el-button> | ||||
|               <el-button type="text" @click="remove(row.id)">删除</el-button> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </ai-table> | ||||
|     </template> | ||||
|   </ai-list> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import { mapState } from 'vuex' | ||||
|   export default { | ||||
|     name: 'List', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       moduleName: String | ||||
|     }, | ||||
|  | ||||
|     data() { | ||||
|       return { | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10, | ||||
|           level: '', | ||||
|           province: '' | ||||
|         }, | ||||
|         currIndex: -1, | ||||
|         areaList: [], | ||||
|         total: 10, | ||||
|         colConfigs: [ | ||||
|           { prop: 'province',  label: '省级', align: 'left', width: '200px' }, | ||||
|           { prop: 'city', label: '市级', align: 'center' }, | ||||
|           { prop: 'district', label: '区级', align: 'center' }, | ||||
|           { prop: 'town', label: '镇级', align: 'center' }, | ||||
|           { prop: 'village', label: '村级', align: 'center' }, | ||||
|           { prop: 'level', label: '等级', align: 'center', format: v => this.dict.getLabel('epidemicDangerousAreaLevel', v) }, | ||||
|           { prop: 'createTime', label: '设置时间', align: 'center' }, | ||||
|           { prop: 'createUserName', label: '添加人', align: 'center' }, | ||||
|           { slot: 'options', label: '操作', align: 'center' } | ||||
|         ], | ||||
|         areaName: '', | ||||
|         unitName: '', | ||||
|         tableData: [] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       ...mapState(['user']) | ||||
|     }, | ||||
|  | ||||
|     created() { | ||||
|       this.dict.load('epidemicDangerousAreaLevel').then(() => { | ||||
|         this.getList() | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getList() { | ||||
|         this.instance.post(`/app/appepidemicdangerousarea/list`, null, { | ||||
|           params: { | ||||
|             ...this.search | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       remove(id) { | ||||
|         this.$confirm('确定删除该数据?').then(() => { | ||||
|           this.instance.post(`/app/appepidemicdangerousarea/delete?ids=${id}`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('删除成功!') | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       toAdd(id) { | ||||
|         this.$emit('change', { | ||||
|           type: 'Add', | ||||
|           params: { | ||||
|             id: id || '' | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .notice { | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										206
									
								
								packages/conv/AppVaccination/AppVaccination.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								packages/conv/AppVaccination/AppVaccination.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,206 @@ | ||||
| <template> | ||||
|   <section class="AppVaccination"> | ||||
|     <ai-list v-if="!showDetail"> | ||||
|       <ai-title slot="title" title="疫苗接种" isShowBottomBorder isShowArea v-model="areaId" :instance="instance" | ||||
|                 @change="page.current=1,getTableData()"/> | ||||
|       <template #blank> | ||||
|         <el-row type="flex"> | ||||
|           <div class="dataPane" v-for="(op,i) in dataPanes" :key="i"> | ||||
|             {{ [op.label, op.v].join(" ") }} | ||||
|           </div> | ||||
|         </el-row> | ||||
|         <div class="mainPane"> | ||||
|           <ai-search-bar> | ||||
|             <template #left> | ||||
|               <ai-select placeholder="接种状况" v-model="search.inoculationType" @change="page.current=1,getTableData()" | ||||
|                          :selectList="dict.getDict('vaccineInoculationType')"/> | ||||
|             </template> | ||||
|             <template #right> | ||||
|               <el-input placeholder="姓名/身份证/联系方式" | ||||
|                         v-model="search.name" | ||||
|                         size="small" | ||||
|                         clearable | ||||
|                         @clear="page.current = 1,search.name = '', getTableData()" | ||||
|                         v-throttle="() => {page.current = 1, getTableData()}" | ||||
|                         suffix-icon="iconfont iconSearch"/> | ||||
|             </template> | ||||
|           </ai-search-bar> | ||||
|           <ai-search-bar> | ||||
|             <template #left> | ||||
|               <el-button type="primary" icon="iconfont iconAdd" @click="$router.push({hash:'#add'})">添加</el-button> | ||||
|               <el-button icon="iconfont iconDelete" :disabled="!ids.length" @click="handleDelete(ids)">删除</el-button> | ||||
|             </template> | ||||
|             <template #right> | ||||
|               <ai-import :instance="instance" :dict="dict" name="疫苗接种" suffixName="xlsx" | ||||
|                          type="appvaccineinoculationuser" @onSuccess="resetSearch"/> | ||||
|               <ai-download url="/app/appvaccineinoculationuser/export" :params="{...search,areaId,ids:ids.toString()}" | ||||
|                            :instance="instance" fileName="疫苗接种导出文件"/> | ||||
|             </template> | ||||
|           </ai-search-bar> | ||||
|           <ai-table :tableData="tableData" :colConfigs="colConfigs" :total="page.total" :current.sync="page.current" | ||||
|                     :size.sync="page.size" @getList="getTableData" :dict="dict" | ||||
|                     @selection-change="v=>ids=v.map(e=>e.id)"> | ||||
|             <el-table-column slot="vaccinationDate" label="接种日期" align="center" class-name="vaccinationDate"> | ||||
|               <el-table-column label="第一次" align="center" prop="firstDate"/> | ||||
|               <el-table-column label="第二次" align="center" prop="secondDate"/> | ||||
|               <el-table-column label="第三次" align="center" prop="thirdDate"/> | ||||
|             </el-table-column> | ||||
|             <el-table-column slot="options" label="操作" align="center" fixed="right"> | ||||
|               <template slot-scope="{row:{id}}"> | ||||
|                 <el-button type="text" @click="$router.push({hash:'#add',query:{id}})">编辑</el-button> | ||||
|                 <el-button type="text" @click="handleDelete(id)">删除</el-button> | ||||
|               </template> | ||||
|             </el-table-column> | ||||
|           </ai-table> | ||||
|         </div> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|     <add-vaccination v-else :dict="dict" :instance="instance"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
| import AddVaccination from "./addVaccination"; | ||||
| import {ID} from "dui/lib/js/utils"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppVaccination", | ||||
|   components: {AddVaccination}, | ||||
|   label: "疫苗接种", | ||||
|   provide() { | ||||
|     return { | ||||
|       top: this | ||||
|     } | ||||
|   }, | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       areaId: "", | ||||
|       page: {current: 1, size: 10, total: 0}, | ||||
|       search: {inoculationType: "", name: ""}, | ||||
|       ids: [], | ||||
|       tableData: [], | ||||
|       staData: {} | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     showDetail() { | ||||
|       return this.$route.hash == "#add" | ||||
|     }, | ||||
|     dataPanes() { | ||||
|       return [ | ||||
|         {label: "总接种人数", v: this.staData.zjzrs || 0}, | ||||
|         {label: "已接种第一针人数", v: this.staData.yjzdyzrs || 0}, | ||||
|         {label: "已接种第二针人数", v: this.staData.yjzdezrs || 0}, | ||||
|         {label: "已接种第三针人数", v: this.staData.yjzdszrs || 0}, | ||||
|       ] | ||||
|     }, | ||||
|     colConfigs() { | ||||
|       return [ | ||||
|         {type: "selection", align: 'center'}, | ||||
|         {label: "姓名", prop: "name", align: 'center'}, | ||||
|         {label: "性别", prop: "sex", dict: 'sex', align: 'center'}, | ||||
|         {label: "出生日期", prop: "birthday", align: 'center'}, | ||||
|         { | ||||
|           label: "身份证号", width: "160px", align: 'center', | ||||
|           render: (h, {row}) => h('span', null, ID.hideId(row.idNumber)) | ||||
|         }, | ||||
|         {label: "所属地区", prop: "areaName", align: 'center'}, | ||||
|         {label: "住址", prop: "address", width: "200px", align: 'center'}, | ||||
|         {label: "联系方式", prop: "phone", align: 'center'}, | ||||
|         {slot: 'vaccinationDate'}, | ||||
|         {slot: "options"}, | ||||
|       ] | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.areaId = JSON.parse(JSON.stringify(this.user.info.areaId)) | ||||
|     this.dict.load('sex', 'vaccineInoculationType') | ||||
|     this.getTableData() | ||||
|   }, | ||||
|   methods: { | ||||
|     getStaData() { | ||||
|       this.instance.post(`/app/appvaccineinoculationuser/countByAreaId`, null, { | ||||
|         params: {areaId: this.areaId} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.staData = res.data | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getTableData() { | ||||
|       this.page.current == 1 && this.getStaData() | ||||
|       this.instance.post(`/app/appvaccineinoculationuser/list`, null, { | ||||
|         params: {...this.search, ...this.page, areaId: this.areaId} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.tableData = res.data.records | ||||
|           this.page.total = res.data.total | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     handleDelete(ids) { | ||||
|       ids = ids?.toString() | ||||
|       this.$confirm("确定要删除该条数据吗?").then(() => { | ||||
|         this.instance.post(`/app/appvaccineinoculationuser/delete`, null, { | ||||
|           params: {ids} | ||||
|         }).then(res => { | ||||
|           if (res?.code == 0) { | ||||
|             this.$message.success("删除成功!"); | ||||
|             this.getTableData(); | ||||
|           } | ||||
|         }) | ||||
|       }).catch(() => 0) | ||||
|     }, | ||||
|     resetSearch() { | ||||
|       this.page.current = 1 | ||||
|       this.search = {} | ||||
|       this.getTableData() | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AppVaccination { | ||||
|   height: 100%; | ||||
|  | ||||
|   :deep( .dataPane ){ | ||||
|     flex: 1; | ||||
|     min-width: 0; | ||||
|     background: #FFFFFF; | ||||
|     box-shadow: 0 4px 6px -2px rgba(15, 15, 21, 0.15); | ||||
|     border-radius: 2px; | ||||
|     margin-bottom: 16px; | ||||
|     margin-right: 16px; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: center; | ||||
|     height: 60px; | ||||
|  | ||||
|     &:last-of-type { | ||||
|       margin-right: 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   :deep( .mainPane ){ | ||||
|     background: #fff; | ||||
|     padding: 12px 16px; | ||||
|     box-shadow: 0 4px 6px -2px rgba(15, 15, 21, 0.15); | ||||
|  | ||||
|     .vaccinationDate { | ||||
|       border-bottom: 1px solid #D0D4DC; | ||||
|     } | ||||
|  | ||||
|     .ai-table__header { | ||||
|       padding: 2px 0; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										236
									
								
								packages/conv/AppVaccination/addVaccination.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										236
									
								
								packages/conv/AppVaccination/addVaccination.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,236 @@ | ||||
| <template> | ||||
|   <section class="addVaccination"> | ||||
|     <ai-detail> | ||||
|       <ai-title slot="title" :title="addTitle" isShowBottomBorder | ||||
|                 isShowBack @onBackClick="back"/> | ||||
|       <template #content> | ||||
|         <el-form size="small" :model="form" ref="vaccinationForm" :rules="rules" label-width="100px"> | ||||
|           <ai-card title="基本信息"> | ||||
|             <template #content> | ||||
|               <el-form-item label="受种人姓名" prop="name"> | ||||
|                 <el-row type="flex" align="middle"> | ||||
|                   <el-input placeholder="请输入" v-model="form.name" :disabled="isEdit" clearable | ||||
|                             style="margin-right: 8px"/> | ||||
|                   <ai-person-select v-if="!isEdit" :instance="instance" @selectPerson="handleSelectPerson"/> | ||||
|                 </el-row> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="身份证号码" prop="idNumber"> | ||||
|                 <ai-id v-model="form.idNumber" @change="getInfoByIdNumber" :disabled="isEdit"/> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="性别" prop="sex"> | ||||
|                 <ai-select disabled v-model="form.sex" :selectList="dict.getDict('sex')"/> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="出生日期" prop="birthday"> | ||||
|                 <el-date-picker v-model="form.birthday" type="date" disabled/> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="联系方式" prop="phone"> | ||||
|                 <el-input v-model="form.phone" placeholder="请输入"/> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="所属地区" isLine prop="areaId"> | ||||
|                 <ai-area-select :instance="instance" v-model="form.areaId" always-show @name="v=>form.areaName=v"/> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="住址" isLine prop="address"> | ||||
|                 <el-input v-model="form.address" placeholder="请输入"/> | ||||
|               </el-form-item> | ||||
|             </template> | ||||
|           </ai-card> | ||||
|           <ai-card title="接种情况"> | ||||
|             <template #right> | ||||
|               <el-button icon="iconfont iconAdd" type="text" @click="dialog=true">添加</el-button> | ||||
|             </template> | ||||
|             <template #content> | ||||
|               <el-form-item isLine label-width="0"> | ||||
|                 <ai-table :tableData="form.detailList" :colConfigs="colConfigs" :isShowPagination="false" :dict="dict"> | ||||
|                   <el-table-column slot="options" label="操作" align="center" fixed="right"> | ||||
|                     <template v-slot="{row,$index}"> | ||||
|                       <el-button type="text" @click="handleEdit(row,$index)">编辑</el-button> | ||||
|                       <el-button type="text" @click="handleDelete($index)">删除</el-button> | ||||
|                     </template> | ||||
|                   </el-table-column> | ||||
|                 </ai-table> | ||||
|               </el-form-item> | ||||
|             </template> | ||||
|           </ai-card> | ||||
|         </el-form> | ||||
|       </template> | ||||
|       <template #footer> | ||||
|         <el-button @click="back">取消</el-button> | ||||
|         <el-button type="primary" @click="handleSubmit">提交</el-button> | ||||
|       </template> | ||||
|     </ai-detail> | ||||
|     <ai-dialog :visible.sync="dialog" title="接种情况" @closed="dialogForm={}" @onConfirm="handleConfirm"> | ||||
|       <el-form ref="appvaccineinoculationuser" size="small" :model="dialogForm" label-width="100px" :rules="rules"> | ||||
|         <el-form-item label="接种次数" prop="type"> | ||||
|           <ai-select v-model="dialogForm.type" :selectList="dict.getDict('vaccineType')"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="接种日期" prop="vaccinateDate"> | ||||
|           <el-date-picker v-model="dialogForm.vaccinateDate" value-format="yyyy-MM-dd"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="接种人员" prop="vaccinatePerson"> | ||||
|           <el-input v-model="dialogForm.vaccinatePerson"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="生产企业" prop="createCompany"> | ||||
|           <el-input v-model="dialogForm.createCompany"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="接种单位" prop="vaccinateUnit"> | ||||
|           <el-input v-model="dialogForm.vaccinateUnit"/> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|     </ai-dialog> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
| import {ID} from "dui/lib/js/utils"; | ||||
|  | ||||
| export default { | ||||
|   name: "addVaccination", | ||||
|   inject: ['top'], | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       form: {detailList: []}, | ||||
|       dialog: false, | ||||
|       dialogForm: {} | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     isEdit() { | ||||
|       return !!this.$route.query.id | ||||
|     }, | ||||
|     addTitle() { | ||||
|       return this.isEdit ? '编辑疫苗接种人员' : '新增疫苗接种人员' | ||||
|     }, | ||||
|     rules() { | ||||
|       return { | ||||
|         vaccinateDate: {required: true, message: "请选择 接种日期"}, | ||||
|         type: {required: true, message: "请选择 接种次数",}, | ||||
|         areaId: [ | ||||
|           {required: true, message: "请选择 所属地区"}, | ||||
|           {trigger:'blur',validator: (r, v, cb) => /0{3}$/g.test(v) ? cb('请选择到村/社区') : cb()} | ||||
|         ], | ||||
|         name: {required: true, message: "请填写 受种人姓名"}, | ||||
|         idNumber: {required: true, message: "请填写 身份号码"}, | ||||
|         sex: {required: true, message: "请填写 性别"}, | ||||
|         birthday: {required: true, message: "请填写 出生日期"}, | ||||
|         phone: {required: true, message: "请填写 联系方式"}, | ||||
|       } | ||||
|     }, | ||||
|     colConfigs() { | ||||
|       return [ | ||||
|         {label: "类型", align: 'center', prop: "type", dict: 'vaccineType'}, | ||||
|         {label: "接种日期", align: 'center', prop: "vaccinateDate"}, | ||||
|         {label: "接种人员", align: 'center', prop: "vaccinatePerson"}, | ||||
|         {label: "生产企业", align: 'center', prop: "createCompany"}, | ||||
|         {label: "接种单位", align: 'center', prop: "vaccinateUnit"}, | ||||
|         {slot: "options"} | ||||
|       ] | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     back() { | ||||
|       this.$router.push({}) | ||||
|     }, | ||||
|     getDetail() { | ||||
|       let {id} = this.$route.query | ||||
|       if (id) { | ||||
|         this.instance.post("/app/appvaccineinoculationuser/queryDetailById", null, { | ||||
|           params: {id} | ||||
|         }).then(res => { | ||||
|           if (res?.data) { | ||||
|             this.form = res.data | ||||
|           } | ||||
|         }) | ||||
|       } else { | ||||
|         this.$set(this.form,'areaId',JSON.parse(JSON.stringify(this.top.areaId))) | ||||
|       } | ||||
|     }, | ||||
|     handleSubmit() { | ||||
|       this.$refs.vaccinationForm?.validate(v => { | ||||
|         if (v) { | ||||
|           this.instance.post("/app/appvaccineinoculationuser/addOrUpdate", this.form).then(res => { | ||||
|             if (res?.code == 0) { | ||||
|               this.$message.success("提交成功!") | ||||
|               this.top.resetSearch() | ||||
|               this.back() | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     handleEdit(row, index) { | ||||
|       this.dialogForm = JSON.parse(JSON.stringify({...row, index})) | ||||
|       this.dialog = true | ||||
|     }, | ||||
|     handleConfirm() { | ||||
|       this.$refs.appvaccineinoculationuser.validate(v => { | ||||
|         if (v) { | ||||
|           if (this.dialogForm.index > -1) { | ||||
|             this.form.detailList.splice(this.dialogForm.index, 1, this.dialogForm) | ||||
|           } else { | ||||
|             this.form.detailList.push(this.dialogForm) | ||||
|           } | ||||
|           this.dialog = false | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     handleSelectPerson(v) { | ||||
|       let {name, idNumber, phone, currentAreaId:areaId, currentAddress:address} = v | ||||
|       this.form = {...this.form, name, idNumber, phone, areaId, address} | ||||
|     }, | ||||
|     getInfoByIdNumber(code) { | ||||
|       if (ID.check(code)) { | ||||
|         let info = new ID(code) | ||||
|         this.form.sex = info.sex | ||||
|         this.form.birthday = info.birthday | ||||
|         this.$forceUpdate() | ||||
|       } | ||||
|     }, | ||||
|     handleDelete(index) { | ||||
|       this.$confirm("是否要删除该条数据?").then(() => this.form.detailList.splice(index, 1)).catch(() => 0) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load('vaccineType') | ||||
|     this.getDetail() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .addVaccination { | ||||
|   height: 100%; | ||||
|  | ||||
|   :deep( .ai-card__body), .el-form { | ||||
|     display: flex; | ||||
|     flex-wrap: wrap; | ||||
|   } | ||||
|  | ||||
|   .ai-card { | ||||
|     width: 100%; | ||||
|   } | ||||
|  | ||||
|   .el-form-item { | ||||
|     width: 50%; | ||||
|  | ||||
|     &[isLine] { | ||||
|       width: 100%; | ||||
|     } | ||||
|  | ||||
|     .el-date-editor { | ||||
|       width: 100%; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   :deep( .el-button ){ | ||||
|     .iconfont { | ||||
|       color: inherit | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @@ -49,6 +49,7 @@ | ||||
|               <el-button type="text" @click="toDetail(row.id)">详情</el-button> | ||||
|               <el-button type="text" @click="remove(row.id)">删除</el-button> | ||||
|               <el-button type="text" @click="gag(row.createUserId, row.blacklist)">{{ row.blacklist ? '解除禁言' : '禁言' }}</el-button> | ||||
|               <el-button type="text" v-if="row.status<1" @click="admin(row)">审核</el-button> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
| @@ -77,7 +78,7 @@ | ||||
|         }, | ||||
|         total: 0, | ||||
|         colConfigs: [ | ||||
|           { prop: 'content',  label: '内容', align: 'left' }, | ||||
|           { prop: 'content',  label: '帖子内容', align: 'left' }, | ||||
|           { prop: 'createUserName',  label: '发帖人', align: 'center', width: '120' }, | ||||
|           { prop: 'createUserAreaName',  label: '所属地区', align: 'center' }, | ||||
|           { prop: 'createTime',  label: '创建时间', align: 'center' }, | ||||
| @@ -85,6 +86,7 @@ | ||||
|           { prop: 'appreciateCount',  label: '点赞数', align: 'center', width: '120' }, | ||||
|           { prop: 'sharedCount',  label: '分享数', align: 'center', width: '120' }, | ||||
|           { prop: 'blacklist',  label: '状态', align: 'center', format: v => v ? '禁言' : '正常' }, | ||||
|           { prop: 'status',  label: '审核状态', align: 'center', width: '120', dict: 'auditStatus' }, | ||||
|           { slot: 'options'}, | ||||
|         ], | ||||
|         tableData: [], | ||||
| @@ -100,7 +102,9 @@ | ||||
|  | ||||
|     created() { | ||||
|       this.search.areaId = this.user.info.areaId | ||||
|       this.dict.load('auditStatus').then(() => { | ||||
|         this.getList() | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
| @@ -172,6 +176,34 @@ | ||||
|             id: id || '' | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       admin(row) { | ||||
|         console.log(row) | ||||
|         this.$confirm('是否审核通过该条帖子?', { | ||||
|           distinguishCancelAndClose: true, | ||||
|           confirmButtonText: '通过', | ||||
|           closeOnClickModal: true, | ||||
|           cancelButtonText: '拒绝' | ||||
|         }).then((e) => { | ||||
|           this.instance.post(`/app/appneighborhoodassistance/examine?id=${row.id}&pass=1`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('审核成功!') | ||||
|               this.search.current = 1 | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         }).catch((e) => { | ||||
|           if(e == 'cancel') { | ||||
|             this.instance.post(`/app/appneighborhoodassistance/examine?id=${row.id}&pass=0`).then(res => { | ||||
|               if (res.code == 0) { | ||||
|                 this.$message.success('审核成功!') | ||||
|                 this.search.current = 1 | ||||
|                 this.getList() | ||||
|               } | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   | ||||
| @@ -1,151 +1,27 @@ | ||||
| <template> | ||||
|   <section class="AppDictionary"> | ||||
|     <ai-list v-if="!showDetail"> | ||||
|       <ai-title slot="title" title="数据字典" isShowBottomBorder/> | ||||
|       <template #content> | ||||
|         <ai-search-bar> | ||||
|           <template #left> | ||||
|             <el-button type="primary" size="small" icon="iconfont iconAdd" @click="addDict" | ||||
|                        v-if="$permissions('admin_sysdictionary_add')">添加 | ||||
|             </el-button> | ||||
|           </template> | ||||
|           <template #right> | ||||
|             <el-input size="small" v-model="search.condition" placeholder="数据项" clearable | ||||
|                       @change="page.current=1,getDicts()" prefix-icon="iconfont iconSearch"/> | ||||
|             <el-button type="primary" size="small" icon="iconfont iconSearch" | ||||
|                        @click="page.current=1,getDicts()">查询 | ||||
|             </el-button> | ||||
|             <el-button size="small" icon="el-icon-refresh-right" @click="resetSearch">重置</el-button> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <el-table size="mini" :data="dictList" header-cell-class-name="table-header" tooltip-effect="light" | ||||
|                   row-class-name="table-row" cell-class-name="table-cell" @expand-change="getDictInfo"> | ||||
|           <el-table-column type="expand"> | ||||
|             <el-row slot-scope="{row}" type="flex" align="middle" style="flex-wrap: wrap"> | ||||
|               <el-tag v-for="(op,i) in row.detail||[]" :key="i" style="margin: 4px">{{ op.dictValue }}|{{ op.dictName }} | ||||
|                 {{ op.dictColor ? '| ' + op.dictColor : '' }} | ||||
|               </el-tag> | ||||
|             </el-row> | ||||
|           </el-table-column> | ||||
|           <el-table-column align="center" label="数据项" prop="code"/> | ||||
|           <el-table-column align="center" label="数据项名称" prop="name"/> | ||||
|           <el-table-column align="center" label="操作"> | ||||
|             <div slot-scope="{row}"> | ||||
|               <el-button type="text" @click="openDetail(row.id)" v-text="'编辑'" | ||||
|                          v-if="$permissions('admin_sysdictionary_edit')"/> | ||||
|               <el-button type="text" @click="handleDelete(row.id)" v-text="'删除'" | ||||
|                          v-if="$permissions('admin_sysdictionary_del')"/> | ||||
|             </div> | ||||
|           </el-table-column> | ||||
|           <div slot="empty" class="no-data"></div> | ||||
|         </el-table> | ||||
|         <div class="pagination"> | ||||
|           <el-pagination background :current-page.sync="page.current" :total="page.total" | ||||
|                          layout="total,prev, pager, next,sizes, jumper" | ||||
|                          @size-change="handleSizeChange" | ||||
|                          :page-size="page.size" | ||||
|                          :page-sizes="[10, 20, 50, 100,200]" | ||||
|                          @current-change="getDicts"/> | ||||
|         </div> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|     <dict-detail v-else :instance="instance" :permissions="permissions"/> | ||||
|     <component :is="currentPage" v-bind="$props"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import DictDetail from "./dictDetail"; | ||||
| import DictList from "@project/xumu/AppDictionary/dictList.vue"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppDictionary", | ||||
|   components: {DictDetail}, | ||||
|   label: "数据字典", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     showDetail() { | ||||
|       return this.$route.hash == "#add" | ||||
|     currentPage() { | ||||
|       let {hash} = this.$route | ||||
|       return hash == "#add" ? DictDetail : DictList | ||||
|     } | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       page: { | ||||
|         current: 1, | ||||
|         total: 0, | ||||
|         size: 10 | ||||
|       }, | ||||
|       search: { | ||||
|         condition: "" | ||||
|       }, | ||||
|       dictList: [], | ||||
|       id: '' | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     resetSearch() { | ||||
|       this.page.current = 1; | ||||
|       this.search.condition = ''; | ||||
|       this.getDicts(); | ||||
|     }, | ||||
|     getDicts() { | ||||
|       this.instance.post("/admin/dictionary/queryDictList", null, { | ||||
|         params: { | ||||
|           ...this.page, | ||||
|           name: this.search.condition | ||||
|         } | ||||
|       }).then(res => { | ||||
|         this.dictList = res.data.records.map(e => { | ||||
|           return {...e, detail: []} | ||||
|         }) | ||||
|         this.page.total = res.data.total | ||||
|       }) | ||||
|     }, | ||||
|     addDict() { | ||||
|       this.$router.push({hash: "#add"}) | ||||
|     }, | ||||
|     handleDelete(id) { | ||||
|       this.$confirm("确定要删除该数据项吗?", { | ||||
|         type: "error" | ||||
|       }).then(() => { | ||||
|         this.instance.post("/admin/dictionary/deleteDict", null, { | ||||
|           params: {id} | ||||
|         }).then(res => { | ||||
|           if (res?.code == 0) { | ||||
|             this.getDicts(); | ||||
|             this.$message.success("删除成功!") | ||||
|           } | ||||
|         }) | ||||
|       }).catch(() => 0) | ||||
|     }, | ||||
|     openDetail(id) { | ||||
|       this.$router.push({query: {id}, hash: "#add"}) | ||||
|     }, | ||||
|     handleSizeChange(val) { | ||||
|       this.page.size = val; | ||||
|       this.getDicts(); | ||||
|     }, | ||||
|     getDictInfo(row) { | ||||
|       if (row.detail.length) { | ||||
|         row.detail = [] | ||||
|       } else { | ||||
|         this.getDict(row.id).then(res => { | ||||
|           if (res && res.data) { | ||||
|             row.detail = res.data.dictionaryDetails || [] | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     }, | ||||
|     getDict(dictionaryId) { | ||||
|       return this.instance.post("/admin/dictionary/queryDictDetail", null, { | ||||
|         params: {dictionaryId} | ||||
|       }) | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.getDicts() | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
|   | ||||
							
								
								
									
										142
									
								
								packages/core/AppDictionary/dictList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								packages/core/AppDictionary/dictList.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| <script> | ||||
| const columns = [ | ||||
|   {slot: "expand"}, | ||||
|   {label: "数据项", prop: "code"}, | ||||
|   {label: "数据项名称", prop: "name"}, | ||||
| ] | ||||
| export default { | ||||
|   name: "dictList", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       columns, | ||||
|       page: { | ||||
|         current: 1, | ||||
|         total: 0, | ||||
|         size: 10 | ||||
|       }, | ||||
|       search: { | ||||
|         condition: "" | ||||
|       }, | ||||
|       dictList: [], | ||||
|       id: '' | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     resetSearch() { | ||||
|       this.page.current = 1; | ||||
|       this.search.condition = ''; | ||||
|       this.getDicts(); | ||||
|     }, | ||||
|     getDicts() { | ||||
|       this.instance.post("/admin/dictionary/queryDictList", null, { | ||||
|         params: { | ||||
|           ...this.page, | ||||
|           name: this.search.condition | ||||
|         } | ||||
|       }).then(res => { | ||||
|         this.dictList = res.data.records.map(e => { | ||||
|           return {...e, detail: []} | ||||
|         }) | ||||
|         this.page.total = res.data.total | ||||
|       }) | ||||
|     }, | ||||
|     addDict() { | ||||
|       this.$router.push({hash: "#add"}) | ||||
|     }, | ||||
|     handleDelete(id) { | ||||
|       this.$confirm("确定要删除该数据项吗?", { | ||||
|         type: "error" | ||||
|       }).then(() => { | ||||
|         this.instance.post("/admin/dictionary/deleteDict", null, { | ||||
|           params: {id} | ||||
|         }).then(res => { | ||||
|           if (res?.code == 0) { | ||||
|             this.getDicts(); | ||||
|             this.$message.success("删除成功!") | ||||
|           } | ||||
|         }) | ||||
|       }).catch(() => 0) | ||||
|     }, | ||||
|     openDetail(id) { | ||||
|       this.$router.push({query: {id}, hash: "#add"}) | ||||
|     }, | ||||
|     handleSizeChange(val) { | ||||
|       this.page.size = val; | ||||
|       this.getDicts(); | ||||
|     }, | ||||
|     getDictInfo(row) { | ||||
|       if (row.detail.length) { | ||||
|         row.detail = [] | ||||
|       } else { | ||||
|         this.getDict(row.id).then(res => { | ||||
|           if (res && res.data) { | ||||
|             row.detail = res.data.dictionaryDetails || [] | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     }, | ||||
|     getDict(dictionaryId) { | ||||
|       return this.instance.post("/admin/dictionary/queryDictDetail", null, { | ||||
|         params: {dictionaryId} | ||||
|       }) | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.getDicts() | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| <template> | ||||
|   <section class="dictList"> | ||||
|     <ai-list> | ||||
|       <ai-title slot="title" title="数据字典" isShowBottomBorder/> | ||||
|       <template #content> | ||||
|         <ai-search-bar> | ||||
|           <template #left> | ||||
|             <el-button type="primary" size="small" icon="iconfont iconAdd" @click="addDict" | ||||
|                        v-if="$permissions('admin_sysdictionary_add')">添加 | ||||
|             </el-button> | ||||
|           </template> | ||||
|           <template #right> | ||||
|             <el-input size="small" v-model="search.condition" placeholder="数据项" clearable | ||||
|                       @change="page.current=1,getDicts()" prefix-icon="iconfont iconSearch"/> | ||||
|             <el-button type="primary" size="small" icon="iconfont iconSearch" | ||||
|                        @click="page.current=1,getDicts()">查询 | ||||
|             </el-button> | ||||
|             <el-button size="small" icon="el-icon-refresh-right" @click="resetSearch">重置</el-button> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <ai-table :tableData="dictList" :colConfigs="columns" :dict="dict" @getList="getDicts" | ||||
|                   :total="page.total" :current.sync="page.current" :size.sync="page.size" :page-sizes="[10, 20, 50, 100,200]" | ||||
|                   @expand-change="getDictInfo"> | ||||
|           <el-table-column slot="expand" type="expand"> | ||||
|             <template slot-scope="{row}"> | ||||
|               <div class="flex" style="gap:4px"> | ||||
|                 <el-tag v-for="(op,i) in row.detail||[]" :key="i">{{ [op.dictValue, op.dictName, op.dictColor].filter(Boolean).join("|") }}</el-tag> | ||||
|               </div> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|           <el-table-column slot="options" label="操作" fixed="right" align="center"> | ||||
|             <template slot-scope="{row}"> | ||||
|               <div class="table-options"> | ||||
|                 <el-button type="text" @click="openDetail(row.id)" v-if="$permissions('admin_sysdictionary_edit')">编辑</el-button> | ||||
|                 <el-button type="text" @click="handleDelete(row.id)" v-if="$permissions('admin_sysdictionary_del')">删除</el-button> | ||||
|               </div> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|         </ai-table> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .dictList { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
| @@ -40,7 +40,7 @@ | ||||
|                 <div v-if="node.isLeaf" class="opBtn del" v-text="`删除`" @click="handleDelete(data)"/> | ||||
|                 <div v-if="permissions('guide_page_config')&&data.component&&data.type==1" class="opBtn" v-text="`引导页`" | ||||
|                      @click="$router.push({hash:'#intro',query:{id:data.id}})"/> | ||||
|                 <div v-if="data.type<2" class="opBtn" v-text="`添加下级`" @click="addMenu(data)"/> | ||||
|                 <div v-if="!data.component" class="opBtn" v-text="`添加下级`" @click="addMenu(data)"/> | ||||
|                 <div class="opBtn" v-text="`编辑`" @click="handleEdit(data)"/> | ||||
|               </el-row> | ||||
|             </el-row> | ||||
| @@ -54,29 +54,16 @@ | ||||
|         <el-form-item label="菜单名称" prop="name"> | ||||
|           <el-input v-model="form.name" placeholder="请输入" clearable/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="菜单类型" prop="type"> | ||||
|           <ai-select v-model="form.type" clearable :selectList="dict.getDict('menuType')"/> | ||||
|         </el-form-item> | ||||
|         <template v-if="form.type==0"> | ||||
|         <el-form-item label="菜单图标" prop="style"> | ||||
|           <el-input v-model="form.style" placeholder="请输入" clearable/> | ||||
|         </el-form-item> | ||||
|         </template> | ||||
|         <template v-if="form.type==1"> | ||||
|           <el-form-item label="菜单图标" prop="style"> | ||||
|             <el-input v-model="form.style" placeholder="请输入" clearable/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="路由名" prop="route"> | ||||
|             <span v-text="form.route||'提交保存后会自动生成'"/> | ||||
|           </el-form-item> | ||||
|         <el-form-item label="菜单应用" prop="component"> | ||||
|           <el-input v-model="form.component" placeholder="请输入" clearable/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="路径(path)" prop="path"> | ||||
|           <el-input v-model="form.path" placeholder="请输入" clearable/> | ||||
|         </el-form-item> | ||||
|         </template> | ||||
|         <template v-if="form.type==2"> | ||||
|         <template v-if="form.component"> | ||||
|           <el-form-item label="权限码" prop="permission"> | ||||
|             <el-input v-model="form.permission" placeholder="请输入" clearable/> | ||||
|           </el-form-item> | ||||
| @@ -84,7 +71,7 @@ | ||||
|         <el-form-item label="显示菜单" prop="status"> | ||||
|           <ai-select v-model="form.status" clearable :selectList="dict.getDict('yesOrNo')"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item v-if="form.type<2" label="排序" prop="showIndex"> | ||||
|         <el-form-item label="排序" prop="showIndex"> | ||||
|           <el-input v-model="form.showIndex" placeholder="请输入" clearable/> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|   | ||||
							
								
								
									
										66
									
								
								packages/extra/AppAddressBook/AppAddressBook.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								packages/extra/AppAddressBook/AppAddressBook.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| <template> | ||||
|   <div class="doc-circulation ailist-wrapper"> | ||||
|     <keep-alive :include="['List']"> | ||||
|       <component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component> | ||||
|     </keep-alive> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import List from './components/List' | ||||
|   import Add from './components/Add' | ||||
|  | ||||
|   export default { | ||||
|     name: 'AppAddressBook', | ||||
|     label: '通讯录管理', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         component: 'List', | ||||
|         params: {}, | ||||
|         include: [] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     components: { | ||||
|       Add, | ||||
|       List | ||||
|     }, | ||||
|  | ||||
|     mounted () { | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       onChange (data) { | ||||
|         if (data.type === 'Add') { | ||||
|           this.component = 'Add' | ||||
|           this.params = data.params | ||||
|         } | ||||
|  | ||||
|         if (data.type === 'list') { | ||||
|           this.component = 'List' | ||||
|           this.params = data.params | ||||
|  | ||||
|           this.$nextTick(() => { | ||||
|             if (data.isRefresh) { | ||||
|               this.$refs.component.getList() | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
|   .doc-circulation { | ||||
|     height: 100%; | ||||
|     background: #F3F6F9; | ||||
|     overflow: auto; | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										203
									
								
								packages/extra/AppAddressBook/components/Add.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								packages/extra/AppAddressBook/components/Add.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,203 @@ | ||||
| <template> | ||||
|   <ai-detail> | ||||
|     <template slot="title"> | ||||
|       <ai-title :title="id ? '编辑成员' : '添加成员'" isShowBack isShowBottomBorder @onBackClick="cancel(false)"> | ||||
|       </ai-title> | ||||
|     </template> | ||||
|     <template slot="content">   | ||||
|       <el-form ref="form" :model="form" label-width="110px" label-position="right"> | ||||
|       <ai-card title="个人信息"> | ||||
|         <template #content> | ||||
|           <div class="ai-form"> | ||||
|             <el-form-item label="姓名" prop="name" :rules="[{ required: true, message: '请输入姓名', trigger: 'blur' }]"> | ||||
|               <el-input size="small" placeholder="请输入姓名" show-word-limit v-model="form.name" :maxlength="10"></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="账号" prop="id" :rules="[{ required: true, message: '请输入账号', trigger: 'blur' }]"> | ||||
|               <el-input size="small" :disabled="!!id" show-word-limit :maxlength="30" placeholder="成员唯一标识,设定以后不支持修改" v-model="form.id"></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="手机号" prop="mobile" :rules="[{ required: true, validator: validatorPhone, trigger: 'blur' }]"> | ||||
|               <el-input size="small" placeholder="请输入手机号" show-word-limit :maxlength="11" v-model="form.mobile"></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="性别" prop="gender"> | ||||
|               <el-radio-group v-model="form.gender"> | ||||
|                 <el-radio label="1">男</el-radio> | ||||
|                 <el-radio label="2">女</el-radio> | ||||
|               </el-radio-group> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="座机" prop="telephone"> | ||||
|               <el-input size="small" placeholder="请输入座机" v-model="form.telephone"></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="邮箱" prop="email"> | ||||
|               <el-input size="small" placeholder="请输入邮箱" v-model="form.email"></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="地址" style="width: 100%;" prop="address"> | ||||
|               <el-input size="small" style="width: 100%;" show-word-limit :maxlength="30" placeholder="请输入地址" v-model="form.address"></el-input> | ||||
|             </el-form-item> | ||||
|           </div> | ||||
|         </template> | ||||
|       </ai-card> | ||||
|       <ai-card title="组织信息"> | ||||
|         <template #content> | ||||
|           <el-form-item label="部门" prop="departmentName" style="width: 100%;" :rules="[{ required: true, message: '请选择部门', trigger: 'change' }]"> | ||||
|             <el-input size="small" placeholder="请选择..." disabled v-model="form.departmentName"> | ||||
|               <ai-wechat-selecter slot="append" isStrictly :instance="instance" @change="onChange" v-model="department" isChooseUnit> | ||||
|                 <el-button type="info">选择</el-button> | ||||
|               </ai-wechat-selecter> | ||||
|             </el-input> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="标签" style="width: 100%;" prop="tags"> | ||||
|             <el-select size="small" v-model="form.tagIds" multiple placeholder="请选择标签"> | ||||
|               <el-option | ||||
|                 v-for="item in tagsList" | ||||
|                 :key="item.id" | ||||
|                 :label="item.tagname" | ||||
|                 :value="item.id"> | ||||
|               </el-option> | ||||
|             </el-select> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="职务" prop="position"> | ||||
|             <el-input size="small" placeholder="请输入职务" v-model="form.position"></el-input> | ||||
|           </el-form-item> | ||||
|         </template> | ||||
|       </ai-card> | ||||
|       </el-form> | ||||
|     </template> | ||||
|     <template #footer> | ||||
|       <el-button @click="cancel">取消</el-button> | ||||
|       <el-button type="primary" @click="confirm">提交</el-button> | ||||
|     </template> | ||||
|   </ai-detail> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     name: 'Add', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       params: Object | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       const validatorPhone = function (rule, value, callback) { | ||||
|         if (value === '') { | ||||
|           callback(new Error('请输入手机号')) | ||||
|         } else if (!/^1\d{10}$/.test(value)) { | ||||
|           callback(new Error('手机号格式错误')) | ||||
|         } else { | ||||
|           callback() | ||||
|         } | ||||
|       } | ||||
|       return { | ||||
|         info: {}, | ||||
|         department: [], | ||||
|         validatorPhone: validatorPhone, | ||||
|         form: { | ||||
|           position: '', | ||||
|           name: '', | ||||
|           email: '', | ||||
|           telephone: '', | ||||
|           gender: '', | ||||
|           mobile: '', | ||||
|           departmentName: '', | ||||
|           departmentIds: [], | ||||
|           tagIds: [], | ||||
|           id: '' | ||||
|         }, | ||||
|         id: '', | ||||
|         tagsList: [] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created () { | ||||
|       this.getTags() | ||||
|  | ||||
|       if (this.params && this.params.departmentId && !this.params.id) { | ||||
|         this.department = [{ | ||||
|           id: String(this.params.departmentId), | ||||
|           name: this.params.departmentName | ||||
|         }] | ||||
|         this.form.departmentIds = [this.params.departmentId] | ||||
|         this.form.departmentName = this.params.departmentName | ||||
|       } | ||||
|  | ||||
|       if (this.params && this.params.id) { | ||||
|         this.id = this.params.id | ||||
|         this.getInfo(this.params.id) | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getInfo (id) { | ||||
|         this.instance.post(`/app/wxcp/wxuser/queryDetailById?id=${id}`).then(res => { | ||||
|           if (res.code === 0) { | ||||
|             const departmentNames = res.data.departmentNames.split(',') | ||||
|             this.department = res.data.departmentIdsStr.split(',').map((item, index) => { | ||||
|               return { | ||||
|                 name: departmentNames[index], | ||||
|                 id: item | ||||
|               } | ||||
|             }) | ||||
|             this.form = { | ||||
|               ...res.data, | ||||
|               departmentName: res.data.departmentNames, | ||||
|               tagIds: res.data.tags.map(v => v.id), | ||||
|               departmentIds: res.data.departmentIdsStr.split(',') | ||||
|             } | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       onChange (e) { | ||||
|         if (e.length) { | ||||
|           this.form.departmentIds = e.map(v => v.id) | ||||
|           this.form.departmentName = e.map(v => v.name).join(',') | ||||
|         } else { | ||||
|           this.form.departmentIds = '' | ||||
|           this.form.departmentName = '' | ||||
|         } | ||||
|       }, | ||||
|  | ||||
|       getTags () { | ||||
|         this.instance.post(`/app/wxcp/wxtag/listAll`).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.tagsList = res.data | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       onClose () { | ||||
|         this.form.explain = '' | ||||
|       }, | ||||
|  | ||||
|       confirm () { | ||||
|         this.$refs.form.validate((valid) => { | ||||
|           if (valid) { | ||||
|             const api = this.id ? '/app/wxcp/wxuser/update' : '/app/wxcp/wxuser/add' | ||||
|             this.instance.post(api, { | ||||
|               ...this.form | ||||
|             }).then(res => { | ||||
|               if (res.code == 0) { | ||||
|                 this.$message.success('提交成功') | ||||
|                 setTimeout(() => { | ||||
|                   this.cancel(true) | ||||
|                 }, 600) | ||||
|               } | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       cancel (isRefresh) { | ||||
|         this.$emit('change', { | ||||
|           type: 'list', | ||||
|           isRefresh: !!isRefresh | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| </style> | ||||
							
								
								
									
										995
									
								
								packages/extra/AppAddressBook/components/List.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										995
									
								
								packages/extra/AppAddressBook/components/List.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,995 @@ | ||||
| <template> | ||||
|   <ai-list class="addressBook"> | ||||
|     <template slot="title"> | ||||
|       <ai-title title="内部通讯录" isShowBottomBorder></ai-title> | ||||
|     </template> | ||||
|     <template #left> | ||||
|       <div class="addressBook-left"> | ||||
|         <div class="addressBook-left__title"> | ||||
|           <h2 @click="tabIndex = 0, search.current = 1, getList()" :class="[tabIndex === 0 ? 'tab-active' : '']"> | ||||
|             组织架构</h2> | ||||
|           <h2 @click="tabIndex = 1, search.current = 1, getList()" :class="[tabIndex === 1 ? 'tab-active' : '']">标签</h2> | ||||
|         </div> | ||||
|         <div class="addressBook-left__list--title" v-if="tabIndex === 0"> | ||||
|           <el-input | ||||
|               size="mini" | ||||
|               placeholder="请输入部门名称" | ||||
|               v-model="unitName" | ||||
|               clearable | ||||
|               suffix-icon="iconfont iconSearch"> | ||||
|           </el-input> | ||||
|         </div> | ||||
|         <div class="addressBook-left__list--title" v-if="tabIndex === 1"> | ||||
|           <el-button size="mini" icon="iconfont iconAdd" @click="isShowTags = true">添加标签</el-button> | ||||
|           <el-input | ||||
|               class="addressBook-left__list--search" | ||||
|               size="mini" | ||||
|               clearable | ||||
|               style="width: 154px;" | ||||
|               placeholder="请输入标签名称" | ||||
|               v-model="tagName" | ||||
|               suffix-icon="iconfont iconSearch"> | ||||
|           </el-input> | ||||
|         </div> | ||||
|         <div class="addressBook-left__list--wrapper"> | ||||
|           <div class="addressBook-left__list" v-show="tabIndex === 0"> | ||||
|             <el-tree | ||||
|               :filter-node-method="filterNode" | ||||
|               ref="tree" | ||||
|               :props="defaultProps" | ||||
|               node-key="id" | ||||
|               :data="unitList" | ||||
|               highlight-current | ||||
|               @node-contextmenu="nodeContextmenu" | ||||
|               :current-node-key="search.departmentId" | ||||
|               :default-expanded-keys="defaultExpanded" | ||||
|               :default-checked-keys="defaultChecked" | ||||
|               @current-change="onTreeChange"> | ||||
|             </el-tree> | ||||
|             <ul | ||||
|                 v-if="isShowMenu" | ||||
|                 class="el-dropdown-menu el-popper" | ||||
|                 :style="{top: menuInfo.y + 'px', left: menuInfo.x + 'px', position: 'fixed', zIndex: 2023}" | ||||
|                 x-placement="top-end"> | ||||
|               <li class="el-dropdown-menu__item" @click="handleTreeCommand('add', menuInfo.node)">添加子部门</li> | ||||
|               <li class="el-dropdown-menu__item" @click="handleTreeCommand('edit', menuInfo.node)">修改名称</li> | ||||
|               <li class="el-dropdown-menu__item" @click="handleTreeCommand('remove', menuInfo.node)">删除</li> | ||||
|               <li class="el-dropdown-menu__item" :class="[!menuInfo.node.i ? 'is-disabled' : '']" | ||||
|                   @click="handleTreeCommand('top', menuInfo.node)">上移 | ||||
|               </li> | ||||
|               <li | ||||
|                   class="el-dropdown-menu__item" | ||||
|                   :class="[(menuInfo.node.i === menuInfo.node.len - 1) || (!menuInfo.node.i && menuInfo.node.i !== 0) ? 'is-disabled' : '']" | ||||
|                   @click="handleTreeCommand('bottom', menuInfo.node)">下移 | ||||
|               </li> | ||||
|             </ul> | ||||
|           </div> | ||||
|           <div class="addressBook-left__list" v-show="tabIndex === 1"> | ||||
|             <div class="addressBook-left__tags"> | ||||
|               <div | ||||
|                   @click="changeTag(index)" | ||||
|                   class="addressBook-left__tags--item" | ||||
|                   :class="[currIndex === index ? 'addressBook-left__tags--item-active' : '']" | ||||
|                   v-for="(item, index) in tagsList" :key="index"> | ||||
|                 <span>{{ item.tagname }}</span> | ||||
|                 <el-dropdown @command="e => handleCommand(e, item)"> | ||||
|                   <i class="iconfont iconmore"></i> | ||||
|                   <el-dropdown-menu slot="dropdown"> | ||||
|                     <el-dropdown-item command="edit">编辑</el-dropdown-item> | ||||
|                     <el-dropdown-item command="remove">删除</el-dropdown-item> | ||||
|                   </el-dropdown-menu> | ||||
|                 </el-dropdown> | ||||
|               </div> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </template> | ||||
|     <template slot="content"> | ||||
|       <ai-search-bar class="search-bar"> | ||||
|         <template #left> | ||||
|           <el-button size="small" type="primary" icon="iconfont iconAdd" v-if="tabIndex === 0" @click="toAdd('')">添加成员 | ||||
|           </el-button> | ||||
|           <ai-import :instance="instance" :dict="dict" v-if="tabIndex === 0" type="wxcp/wxuser" name="内部通讯录" | ||||
|                      :importParams="{departmentId:search.departmentId}" @success="getList"/> | ||||
|           <el-button size="small" icon="iconfont iconUpdate_Files" v-if="tabIndex === 0" :loading="btnLoading" @click="syncMembers">同步部门</el-button> | ||||
|           <el-button size="small" icon="iconfont iconUpdate_Files" v-if="tabIndex === 0" :loading="btnLoading" @click="syncUser">同步成员</el-button> | ||||
|           <ai-wechat-selecter refs="addTags" :instance="instance" v-model="users" @change="onChooseUser" | ||||
|                               :disabled="currIndex < 0" v-if="tabIndex === 1"> | ||||
|             <el-button size="small" :disabled="currIndex < 0" type="primary" icon="iconfont iconAdd">添加成员</el-button> | ||||
|           </ai-wechat-selecter> | ||||
|         </template> | ||||
|         <template slot="right"> | ||||
|           <el-input | ||||
|               v-model="search.name" | ||||
|               size="small" | ||||
|               v-throttle="() => {search.current = 1, getList()}" | ||||
|               placeholder="请输入成员姓名、手机号或标签名称" | ||||
|               clearable | ||||
|               @clear="search.current = 1, search.name = '', getList()" | ||||
|               suffix-icon="iconfont iconSearch"> | ||||
|           </el-input> | ||||
|         </template> | ||||
|       </ai-search-bar> | ||||
|       <ai-table | ||||
|           :tableData="tableData" | ||||
|           :col-configs="colConfigs" | ||||
|           :total="total" | ||||
|           v-loading="loading" | ||||
|           style="margin-top: 6px;" | ||||
|           :current.sync="search.current" | ||||
|           :size.sync="search.size" | ||||
|           @handleSelectionChange="handleSelectionChange" | ||||
|           @getList="getList"> | ||||
|         <el-table-column slot="avatar" label="" align="right" width="100px"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <img class="table-avatar" :src="row.avatar || 'https://cdn.cunwuyun.cn/dvcp/h5/defaultAvatar.png'"> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column slot="tags" label="标签" align="left"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="table-tags" v-if="row.tagNames"> | ||||
|               <el-tag type="info" v-for="(item, index) in row.tagNames.split('、')" size="small" :key="index">{{ | ||||
|                   item | ||||
|                 }} | ||||
|               </el-tag> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column slot="options" width="140px" fixed="right" label="操作" align="center"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="table-options"> | ||||
|               <el-button type="text" @click="toAdd(row.id)" v-show="tabIndex === 0">编辑</el-button> | ||||
|               <el-button type="text" @click="remove(row.id)" v-show="tabIndex === 0">删除</el-button> | ||||
|               <el-button type="text" @click="removeTags(row.id)" v-show="tabIndex === 1">移除</el-button> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <div slot="paginationBtns" class="addressBook-table__btns"> | ||||
|           <span style="margin-right: 8px;" @click="removeAll">{{ tabIndex === 0 ? '批量删除' : '批量移除' }}</span> | ||||
|           <ai-wechat-selecter :instance="instance" v-model="department" isChooseUnit @change="onDepartment" | ||||
|                               v-if="tabIndex === 0"> | ||||
|             <span>批量导出</span> | ||||
|           </ai-wechat-selecter> | ||||
|         </div> | ||||
|       </ai-table> | ||||
|       <ai-dialog | ||||
|           :visible.sync="isShowTags" | ||||
|           width="590px" | ||||
|           :title="tagId ? '编辑标签' : '添加标签'" | ||||
|           @close="onClose" | ||||
|           @onConfirm="onFormConfirm"> | ||||
|         <el-form ref="tagForm" :model="tagForm" label-width="110px" label-position="right"> | ||||
|           <el-form-item label="标签名称" prop="tagname" :rules="[{ required: true, message: '请输入标签名称', trigger: 'blur' }]"> | ||||
|             <el-input size="small" placeholder="请输入标签名称" show-word-limit :maxlength="10" v-model="tagForm.tagname"></el-input> | ||||
|           </el-form-item> | ||||
|         </el-form> | ||||
|       </ai-dialog> | ||||
|       <ai-dialog | ||||
|           :visible.sync="isShowDepart" | ||||
|           width="590px" | ||||
|           :title="departId ? '修改名称' : '添加部门'" | ||||
|           @close="onClose" | ||||
|           @onConfirm="onDepartConfirm"> | ||||
|         <el-form ref="departForm" :model="departForm" label-width="110px" label-position="right"> | ||||
|           <el-form-item label="部门名称" prop="name" :rules="[{ required: true, message: '请输入部门名称', trigger: 'blur' }]"> | ||||
|             <el-input size="small" placeholder="请输入部门名称" show-word-limit :maxlength="30" v-model="departForm.name"></el-input> | ||||
|           </el-form-item> | ||||
|         </el-form> | ||||
|       </ai-dialog> | ||||
|     </template> | ||||
|   </ai-list> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   name: 'List', | ||||
|  | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object | ||||
|   }, | ||||
|  | ||||
|   data() { | ||||
|     return { | ||||
|       users: [], | ||||
|       isShowMenu: false, | ||||
|       department: [], | ||||
|       btnLoading: false, | ||||
|       menuInfo: { | ||||
|         x: '', | ||||
|         y: '', | ||||
|         node: {} | ||||
|       }, | ||||
|       search: { | ||||
|         current: 1, | ||||
|         size: 10, | ||||
|         title: '', | ||||
|         tagname: '', | ||||
|         name: '', | ||||
|         tagIds: '', | ||||
|         departmentId: '' | ||||
|       }, | ||||
|       tagForm: { | ||||
|         tagname: '' | ||||
|       }, | ||||
|       isShowDepart: false, | ||||
|       departForm: { | ||||
|         name: '' | ||||
|       }, | ||||
|       loading: false, | ||||
|       isShowTags: false, | ||||
|       defaultChecked: [], | ||||
|       defaultExpanded: [], | ||||
|       tabIndex: 0, | ||||
|       currIndex: -1, | ||||
|       areaList: [], | ||||
|       total: 0, | ||||
|       colConfigs: [ | ||||
|         {type: 'selection', label: ''}, | ||||
|         {slot: 'avatar', label: ''}, | ||||
|         {prop: 'name', label: '姓名'}, | ||||
|         {prop: 'position', label: '职务'}, | ||||
|         {prop: 'departmentNames', label: '部门'}, | ||||
|         {prop: 'mobile', label: '手机号'}, | ||||
|         {slot: 'tags', label: '标签'}, | ||||
|         {prop: 'status', label: '账号状态', align: 'center', format: v => v == 1 ? '已激活' : '未激活'} | ||||
|       ], | ||||
|       defaultProps: { | ||||
|         children: 'children', | ||||
|         label: 'name' | ||||
|       }, | ||||
|       unitName: '', | ||||
|       rootId: '', | ||||
|       unitList: [], | ||||
|       tagsList: [], | ||||
|       tagName: '', | ||||
|       sourceTagList: [], | ||||
|       tableData: [], | ||||
|       tagId: '', | ||||
|       departmentName: '', | ||||
|       departId: '', | ||||
|       ids: '' | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapState(['user']) | ||||
|   }, | ||||
|  | ||||
|   watch: { | ||||
|     unitName(val) { | ||||
|       this.$refs.tree.filter(val) | ||||
|     }, | ||||
|  | ||||
|     tagName(val) { | ||||
|       if (!val) { | ||||
|         this.tagsList = this.sourceTagList | ||||
|       } | ||||
|  | ||||
|       this.tagsList = this.sourceTagList.filter(v => v.tagname.indexOf(val) > -1) | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   mounted() { | ||||
|     this.getTree() | ||||
|     this.getList() | ||||
|     this.getTags() | ||||
|     document.querySelector('html').addEventListener('click', this.bindEvent) | ||||
|  | ||||
|     this.$nextTick(() => { | ||||
|     }) | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     changeTag(index) { | ||||
|       this.currIndex = index | ||||
|       this.search.current = 1 | ||||
|  | ||||
|       this.$nextTick(() => { | ||||
|         this.getList() | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     bindEvent() { | ||||
|       this.isShowMenu = false | ||||
|     }, | ||||
|  | ||||
|     nodeContextmenu(e, node) { | ||||
|       this.isShowMenu = true | ||||
|       let y = e.y + 6 | ||||
|       if (y + 202 > document.body.clientHeight) { | ||||
|         y = y - 202 | ||||
|       } | ||||
|       this.menuInfo = { | ||||
|         x: e.x + 16, y, | ||||
|         node | ||||
|       } | ||||
|     }, | ||||
|     removeTags(id) { | ||||
|       if (this.currIndex < 0) { | ||||
|         return this.$message.error('请选择标签') | ||||
|       } | ||||
|  | ||||
|       this.$confirm('确定移除该成员?').then(() => { | ||||
|         this.instance.post(`/app/wxcp/wxtag/removeTag?userIds=${id}&tagId=${this.tagsList[this.currIndex].id}`).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.$message.success('移除成功!') | ||||
|             this.search.current = 1 | ||||
|  | ||||
|             this.getList() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     onDepartment(e) { | ||||
|       if (!e.length) { | ||||
|         return this.$message.error('请选择部门') | ||||
|       } | ||||
|       const ids = e.map(v => v.id).join(',') | ||||
|  | ||||
|       this.department = [] | ||||
|       this.instance.post(`/app/wxcp/wxuser/export?departmentId=${ids}`, null, { | ||||
|         responseType: 'blob' | ||||
|       }).then(res => { | ||||
|         if (res?.type == "application/json") { | ||||
|           let reader = new FileReader() | ||||
|           reader.readAsText(res, "utf-8") | ||||
|           reader.onload = e => { | ||||
|             if (e.target.readyState === 2) { | ||||
|               let ret = JSON.parse(e.target.result) | ||||
|               if (ret?.code == 0) { | ||||
|                 this.$message.success(ret.msg) | ||||
|               } else this.$message.error(ret.msg) | ||||
|             } | ||||
|           } | ||||
|         } else { | ||||
|           const link = document.createElement('a') | ||||
|           let blob = new Blob([res], {type: res.type}) | ||||
|           link.style.display = 'none' | ||||
|           link.href = URL.createObjectURL(blob) | ||||
|           link.setAttribute('download', `${e[0].name}.xls`) | ||||
|           document.body.appendChild(link) | ||||
|           link.click() | ||||
|           document.body.removeChild(link) | ||||
|           this.$message.success('导出成功!') | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     onChooseUser(e) { | ||||
|       if (!e.length) { | ||||
|         return this.$message.error('请选择成员') | ||||
|       } | ||||
|  | ||||
|       this.instance.post(`/app/wxcp/wxtag/markTag`, null, { | ||||
|         params: { | ||||
|           tagId: this.tagsList[this.currIndex].id, | ||||
|           userIds: e.map(v => v.id).join(',') | ||||
|         } | ||||
|       }).then(res => { | ||||
|         if (res.code == 0) { | ||||
|           this.getList() | ||||
|           this.users = [] | ||||
|           this.search.current = 1 | ||||
|           this.$refs.addTags.reset() | ||||
|         } else { | ||||
|           this.users = [] | ||||
|         } | ||||
|       }).catch(() => { | ||||
|         this.users = [] | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     handleTreeCommand(e, item) { | ||||
|       this.isShowMenu = false | ||||
|  | ||||
|       if (e === 'add') { | ||||
|         this.departForm.id = '' | ||||
|         this.departForm.parentid = item.id | ||||
|         this.departId = '' | ||||
|         this.isShowDepart = true | ||||
|       } else if (e === 'edit') { | ||||
|         this.departForm = { | ||||
|           ...item | ||||
|         } | ||||
|  | ||||
|         this.departId = item.id | ||||
|         this.isShowDepart = true | ||||
|       } else if (e === 'top') { | ||||
|         if (!item.i) { | ||||
|           return false | ||||
|         } | ||||
|  | ||||
|         this.moveDepart(item.id, 0) | ||||
|       } else if (e === 'bottom') { | ||||
|         if ((item.i === item.len - 1) || (!item.i && item.i !== 0)) { | ||||
|           return false | ||||
|         } | ||||
|  | ||||
|         this.moveDepart(item.id, 1) | ||||
|       } else if (e === 'remove') { | ||||
|         this.removeDepart(item.id, item.parentid) | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     removeDepart(id, parentid) { | ||||
|       this.$confirm('确定删除该数据?').then(() => { | ||||
|         this.instance.post(`/app/wxcp/wxdepartment/delete?id=${id}`).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.defaultChecked = [parentid] | ||||
|             this.$message.success('删除成功!') | ||||
|             this.getTree() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     moveDepart(id, type) { | ||||
|       this.instance.post(`/app/wxcp/wxdepartment/move?id=${id}&type=${type}`).then(res => { | ||||
|         if (res.code == 0) { | ||||
|           this.defaultChecked = [id] | ||||
|           this.getTree() | ||||
|           this.$message.success(type === 0 ? '上移成功' : '下移成功') | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     onDepartConfirm() { | ||||
|       this.$refs.departForm.validate((valid) => { | ||||
|         if (valid) { | ||||
|           this.instance.post(`/app/wxcp/wxdepartment/addOrUpdate`, { | ||||
|             ...this.departForm, | ||||
|             departId: this.departId | ||||
|           }).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.defaultChecked = [this.departForm.parentid] | ||||
|               this.isShowDepart = false | ||||
|               this.getTree() | ||||
|               this.$message.success(this.departId ? '编辑成功' : '新增成功') | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     onFormConfirm() { | ||||
|       this.$refs.tagForm.validate((valid) => { | ||||
|         if (valid) { | ||||
|           this.instance.post(`/app/wxcp/wxtag/addOrUpdate`, { | ||||
|             ...this.tagForm | ||||
|           }).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.isShowTags = false | ||||
|               this.getTags() | ||||
|               this.$message.success(this.tagId ? '编辑成功' : '新增成功') | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     handleCommand(e, item) { | ||||
|       if (e === 'edit') { | ||||
|         this.tagId = item.id | ||||
|         this.tagForm = { | ||||
|           ...item | ||||
|         } | ||||
|  | ||||
|         this.isShowTags = true | ||||
|       } else { | ||||
|         this.$confirm('确定删除该数据?').then(() => { | ||||
|           this.instance.post(`/app/wxcp/wxtag/delete?id=${item.id}`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('删除成功!') | ||||
|               this.getTags() | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     onClose() { | ||||
|       this.tagId = '' | ||||
|       this.tagForm.tagname = '' | ||||
|       this.departForm.name = '' | ||||
|       this.departId = '' | ||||
|       this.departForm.nameEn = '' | ||||
|       this.departForm.parentid = '' | ||||
|       this.departForm.showIndex = '' | ||||
|     }, | ||||
|  | ||||
|     syncMembers() { | ||||
|       this.btnLoading = true | ||||
|  | ||||
|       this.instance.post(`/app/wxcp/wxdepartment/syncDepart`).then(res => { | ||||
|         if (res.code == 0) { | ||||
|           this.$message.success('同步成功') | ||||
|           this.getList() | ||||
|           this.getTree() | ||||
|         } | ||||
|  | ||||
|         this.btnLoading = false | ||||
|       }).catch(() => { | ||||
|         this.btnLoading = false | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     syncUser() { | ||||
|       let departId = this.search.departmentId; | ||||
|       if (!departId) departId = 1; | ||||
|       this.btnLoading = true | ||||
|  | ||||
|       this.instance.post(`/app/wxcp/wxdepartment/syncUser?departmentId=${departId}`, null, { | ||||
|         timeout: 1000000 | ||||
|       }).then(res => { | ||||
|         if (res.code == 0) { | ||||
|           this.$message.success('同步成功') | ||||
|           this.getList() | ||||
|           this.getTree() | ||||
|         } | ||||
|  | ||||
|         this.btnLoading = false | ||||
|       }).catch(() => { | ||||
|         this.btnLoading = false | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     getTags() { | ||||
|       this.instance.post(`/app/wxcp/wxtag/listAll`).then(res => { | ||||
|         if (res.code == 0) { | ||||
|           this.sourceTagList = res.data.length ? JSON.parse(JSON.stringify(res.data)) : [] | ||||
|           this.tagsList = res.data | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     onSwitchChange(id) { | ||||
|       this.instance.post(`/app/wxcp/wxuser/enable?id=${id}`).then(res => { | ||||
|         if (res.code == 0) { | ||||
|           this.getList() | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     onTreeChange(e) { | ||||
|       this.departmentName = e.name | ||||
|       this.search.departmentId = e.id || '' | ||||
|       this.search.current = 1 | ||||
|       this.isShowMenu = false | ||||
|  | ||||
|       this.$nextTick(() => { | ||||
|         this.getList() | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     getList() { | ||||
|       this.loading = true | ||||
|       this.instance.post(`/app/wxcp/wxuser/list`, null, { | ||||
|         params: { | ||||
|           ...this.search, | ||||
|           departmentId: this.tabIndex === 0 ? this.search.departmentId : '', | ||||
|           tagIds: this.tabIndex === 1 ? (this.currIndex >= 0 ? this.tagsList[this.currIndex].id : '') : '', | ||||
|           listType: this.tabIndex | ||||
|         } | ||||
|       }).then(res => { | ||||
|         if (res.code == 0) { | ||||
|           this.tableData = res.data.records | ||||
|           this.total = res.data.total | ||||
|  | ||||
|           this.$nextTick(() => { | ||||
|             this.loading = false | ||||
|           }) | ||||
|         } else { | ||||
|           this.loading = false | ||||
|         } | ||||
|       }).catch(() => { | ||||
|         this.loading = false | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     removeAll() { | ||||
|       if (!this.ids) return | ||||
|  | ||||
|       if (this.tabIndex === 1) { | ||||
|         this.removeTags(this.ids) | ||||
|       } else { | ||||
|         this.remove(this.ids) | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     handleSelectionChange(e) { | ||||
|       this.ids = e.map(v => v.id).join(',') | ||||
|     }, | ||||
|  | ||||
|     filterNode(value, data) { | ||||
|       if (!value) return true | ||||
|       return data.name.indexOf(value) !== -1 | ||||
|     }, | ||||
|  | ||||
|     changeTab(id, index) { | ||||
|       this.currIndex = index | ||||
|       this.search.areaId = id | ||||
|  | ||||
|       this.$nextTick(() => { | ||||
|         this.getList() | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     getTree() { | ||||
|       this.instance.post(`/app/wxcp/wxdepartment/listAll?unitName=${this.unitName}`).then(res => { | ||||
|         if (res.code === 0) { | ||||
|           let parent = res.data.map(v => { | ||||
|             v.label = v.name | ||||
|             v.children = [] | ||||
|  | ||||
|             return v | ||||
|           }).filter(e => !e.parentid)[0] | ||||
|           this.defaultExpanded = [parent.id] | ||||
|           this.defaultChecked = [parent.id] | ||||
|           this.search.departmentId = parent.id | ||||
|           this.departmentName = parent.name | ||||
|           this.addChild(parent, res.data) | ||||
|           this.unitList = [parent] | ||||
|  | ||||
|           this.$nextTick(() => { | ||||
|             this.$refs.tree.setCurrentKey(parent.id) | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     addChild(parent, list) { | ||||
|       for (let i = 0; i < list.length; i++) { | ||||
|         if (list[i].parentid === parent.id) { | ||||
|           list[i].i = parent.children.length | ||||
|           parent.children.push(list[i]) | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       if (parent.children.length) { | ||||
|         parent.children.forEach(v => { | ||||
|           v.len = parent.children.length | ||||
|         }) | ||||
|       } | ||||
|  | ||||
|       if (list.length > 0) { | ||||
|         parent['children'].map(v => this.addChild(v, list)) | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     formatList(list) { | ||||
|       var arr = [] | ||||
|       for (let item of list) { | ||||
|         if (item.childrenUser && item.childrenUser.length) { | ||||
|           delete item.childrenUser | ||||
|         } | ||||
|  | ||||
|         if (item.childrenDept && item.childrenDept.length) { | ||||
|           this.formatList(item.childrenDept) | ||||
|         } | ||||
|  | ||||
|         arr.push(item) | ||||
|       } | ||||
|  | ||||
|       return arr | ||||
|     }, | ||||
|  | ||||
|     remove(id) { | ||||
|       this.$confirm('确定删除该数据?').then(() => { | ||||
|         this.instance.post(`/app/wxcp/wxuser/delete?id=${id}`).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.$message.success('删除成功!') | ||||
|             this.getList() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     toAdd(id) { | ||||
|       this.$emit('change', { | ||||
|         type: 'Add', | ||||
|         params: { | ||||
|           id: id || '', | ||||
|           departmentId: this.search.departmentId || '', | ||||
|           departmentName: this.departmentName || '' | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .addressBook { | ||||
|   .addressBook-table__btns { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   .table-tags { | ||||
|     .el-tag { | ||||
|       margin-right: 8px; | ||||
|       margin-bottom: 8px; | ||||
|  | ||||
|       &:last-child { | ||||
|         margin-right: 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .import-wrapper { | ||||
|     & > h2 { | ||||
|       margin-bottom: 8px; | ||||
|       font-size: 16px; | ||||
|       color: #222222; | ||||
|       font-weight: Bold; | ||||
|     } | ||||
|  | ||||
|     .import-wrapper__tips { | ||||
|       line-height: 1; | ||||
|       margin-bottom: 24px; | ||||
|  | ||||
|       div { | ||||
|         display: flex; | ||||
|         margin-bottom: 8px; | ||||
|         color: #222222; | ||||
|         font-size: 14px; | ||||
|  | ||||
|         span { | ||||
|           cursor: pointer; | ||||
|           color: #2266FF; | ||||
|  | ||||
|           &:hover { | ||||
|             opacity: 0.8; | ||||
|             text-decoration: underline; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .import-files { | ||||
|       i { | ||||
|         display: block; | ||||
|         margin-top: 8px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     i { | ||||
|       color: #999999; | ||||
|       font-size: 12px; | ||||
|       font-style: normal; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .tree-container { | ||||
|     position: relative; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
|     width: 100%; | ||||
|     height: 100%; | ||||
|  | ||||
|     .tree-name { | ||||
|       padding-right: 30px; | ||||
|     } | ||||
|  | ||||
|     i { | ||||
|       position: absolute; | ||||
|       top: 50%; | ||||
|       right: 8px; | ||||
|       transform: translateY(-50%); | ||||
|       padding-right: 8px; | ||||
|       font-weight: normal; | ||||
|       color: #fff; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .el-tag { | ||||
|     margin-right: 8px; | ||||
|     border: 1px solid #D0D4DC; | ||||
|     background: #F3F4F7; | ||||
|     border-radius: 4px; | ||||
|     font-size: 13px; | ||||
|     color: #222222; | ||||
|  | ||||
|     &:last-child { | ||||
|       margin-right: 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .table-avatar { | ||||
|     width: 40px; | ||||
|     height: 40px; | ||||
|     margin-top: 3px; | ||||
|     border-radius: 2px; | ||||
|     border: 1px solid #CCCCCC; | ||||
|   } | ||||
|  | ||||
|   .el-button--mini, .el-button--mini.is-round { | ||||
|     height: 28px; | ||||
|     line-height: 28px; | ||||
|     padding: 0; | ||||
|     font-size: 12px; | ||||
|  | ||||
|     :deep( span ){ | ||||
|       margin-left: 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .addressBook-left__list--title { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     margin: 8px 8px 0; | ||||
|  | ||||
|     .addressBook-left__list--search { | ||||
|       flex: 1; | ||||
|  | ||||
|       :deep( input ){ | ||||
|         width: 100%; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .el-button { | ||||
|       width: 84px; | ||||
|       flex-shrink: 1; | ||||
|       margin-right: 8px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .addressBook-left { | ||||
|     width: 100%; | ||||
|     height: auto; | ||||
|     background: #FAFAFB; | ||||
|  | ||||
|     .addressBook-left__title { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       width: 100%; | ||||
|       height: 40px; | ||||
|       background: #ffffff; | ||||
|  | ||||
|       h2 { | ||||
|         flex: 1; | ||||
|         height: 100%; | ||||
|         line-height: 40px; | ||||
|         color: #222; | ||||
|         font-size: 14px; | ||||
|         text-align: center; | ||||
|         cursor: pointer; | ||||
|         border-bottom: 2px solid transparent; | ||||
|  | ||||
|         &.tab-active { | ||||
|           color: #2266FF; | ||||
|           border-bottom: 2px solid #2266FF; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // ::-webkit-scrollbar { | ||||
|     //   width: 1px; | ||||
|     // } | ||||
|  | ||||
|     .addressBook-left__list--wrapper { | ||||
|       height: calc(100% - 68px); | ||||
|       padding: 8px; | ||||
|     } | ||||
|  | ||||
|     .addressBook-left__list { | ||||
|       width: 100%; | ||||
|       height: 100%; | ||||
|       overflow: auto; | ||||
|  | ||||
|       :deep( .el-tree ){ | ||||
|         width: fit-content; | ||||
|         min-width: 100%; | ||||
|       } | ||||
|  | ||||
|       :deep( .el-scrollbar__wrap ){ | ||||
|         margin-bottom: 0 !important; | ||||
|         overflow-x: hidden; | ||||
|  | ||||
|         .el-scrollbar__view { | ||||
|           width: fit-content; | ||||
|           min-width: 100%; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .addressBook-left__tags--item { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         justify-content: space-between; | ||||
|         height: 40px; | ||||
|         padding: 0 8px 0 16px; | ||||
|         cursor: pointer; | ||||
|         color: #222222; | ||||
|  | ||||
|         &.addressBook-left__tags--item-active, &:hover { | ||||
|           background: #E8EFFF; | ||||
|           color: #2266FF; | ||||
|  | ||||
|           i, span { | ||||
|             color: #2266FF; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         span { | ||||
|           font-size: 14px; | ||||
|         } | ||||
|  | ||||
|         i { | ||||
|           cursor: pointer; | ||||
|           color: #8e9ebf; | ||||
|           font-size: 16px; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       span { | ||||
|         color: #222222; | ||||
|         font-size: 14px; | ||||
|       } | ||||
|  | ||||
|       :deep( .el-tree ){ | ||||
|         background: transparent; | ||||
|  | ||||
|         .el-tree-node__expand-icon.is-leaf { | ||||
|           color: transparent !important; | ||||
|         } | ||||
|  | ||||
|         .el-tree-node__content > .el-tree-node__expand-icon { | ||||
|           padding: 4px; | ||||
|         } | ||||
|  | ||||
|         .el-tree-node__content { | ||||
|           height: 32px; | ||||
|         } | ||||
|  | ||||
|         .el-tree__empty-text { | ||||
|           color: #222; | ||||
|           font-size: 14px; | ||||
|         } | ||||
|  | ||||
|         .el-tree-node__children .el-tree-node__content { | ||||
|           height: 32px; | ||||
|         } | ||||
|  | ||||
|         .el-tree-node__content:hover { | ||||
|           background: #E8EFFF; | ||||
|           color: #222222; | ||||
|           border-radius: 2px; | ||||
|         } | ||||
|  | ||||
|         .is-current > .el-tree-node__content { | ||||
|           &:hover { | ||||
|             background: #2266FF; | ||||
|             color: #fff; | ||||
|           } | ||||
|  | ||||
|           background: #2266FF; | ||||
|  | ||||
|           span { | ||||
|             color: #fff; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   :deep( .ai-list__content--right ){ | ||||
|     flex: 1; | ||||
|     min-width: 0; | ||||
|     margin-left: 1px; | ||||
|     box-shadow: none; | ||||
|  | ||||
|     .ai-list__content--right-wrapper { | ||||
|       width: 100%; | ||||
|     } | ||||
|   } | ||||
|  | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										164
									
								
								packages/extra/AppLicence/AppLicence.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								packages/extra/AppLicence/AppLicence.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,164 @@ | ||||
| <template> | ||||
|   <section class="AppLicence"> | ||||
|     <ai-list> | ||||
|       <ai-title slot="title" title="产品许可" isShowBottomBorder  :instance="instance"></ai-title> | ||||
|       <template #content> | ||||
|         <div class="licence-content"> | ||||
|           <img class="left-img" src="https://cdn.cunwuyun.cn/dvcp/key.png" alt="" /> | ||||
|           <div class="content-right"> | ||||
|             <h3 class="title">产品许可信息</h3> | ||||
|             <p class="mini-title">您当前的版本为Saas专业版,非常感谢您对我们产品的认可与支持!</p> | ||||
|             <div class="info"> | ||||
|               <span class="label">过期时间</span> | ||||
|               <span class="value color-f46" v-if="info.isExpired == 1">{{info.expireDate ? info.expireDate+'(已过期)' : '未激活'}}</span> | ||||
|               <span class="value color-26f" v-else>{{info.expireDate}}</span> | ||||
|             </div> | ||||
|             <div class="info"> | ||||
|               <span class="label">主板序列号</span> | ||||
|               <span class="value">{{info.mainBoard}}</span> | ||||
|             </div> | ||||
|             <div class="info"> | ||||
|               <span class="label">CPU</span> | ||||
|               <span class="value">{{info.cpu}}</span> | ||||
|             </div> | ||||
|             <div class="info"> | ||||
|               <span class="label">MAC地址</span> | ||||
|               <span class="value">{{info.mac}}</span> | ||||
|             </div> | ||||
|             <div class="info mar-b32"> | ||||
|               <span class="label">IP地址</span> | ||||
|               <span class="value">{{info.ip}}</span> | ||||
|             </div> | ||||
|             <el-upload | ||||
|               class="upload-demo" | ||||
|               action | ||||
|               multiple | ||||
|               accept=".lic" | ||||
|               :http-request="uploadFile"> | ||||
|               <div class="btn">上传许可</div> | ||||
|             </el-upload> | ||||
|           </div> | ||||
|         </div> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|   </section> | ||||
| </template> | ||||
| <script> | ||||
|  | ||||
| export default { | ||||
|   name: "AppLicence", | ||||
|   label: "产品许可", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       files: [], | ||||
|       info: {} | ||||
|     } | ||||
|   }, | ||||
|   mounted() { | ||||
|     this.getDetail() | ||||
|   }, | ||||
|   methods: { | ||||
|     getDetail() { | ||||
|       this.instance.post(`/admin/license/detail`).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.info = res.data | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     uploadFile: function (file) { | ||||
|       let formData = new FormData(); | ||||
|       formData.append("file", file.file); | ||||
|       this.instance.post(`/admin/license/save`, formData, {withoutToken: false}).then(res => { | ||||
|         if (res && res.code == 0) { | ||||
|           this.$message.success("证书上传成功!"); | ||||
|           this.getDetail() | ||||
|         } | ||||
|       }); | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
| }; | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .AppLicence { | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   :deep( .ai-list){ | ||||
|     background-color: #F5F6F9; | ||||
|   } | ||||
|   :deep( .ai-list .ai-list__content--right .ai-list__content--right-wrapper){ | ||||
|     background-color: #F5F6F9; | ||||
|     box-shadow: 0 0 0 0; | ||||
|     margin: 0!important; | ||||
|     padding: 0!important; | ||||
|   } | ||||
|   :deep( .el-upload-list){ | ||||
|     display: none; | ||||
|   } | ||||
|   .licence-content{ | ||||
|     display: flex; | ||||
|     margin-top: 30px; | ||||
|     .left-img{ | ||||
|       width: 200px; | ||||
|       height: 200px; | ||||
|     } | ||||
|     .content-right{ | ||||
|       width: 800px; | ||||
|       .title{ | ||||
|         font-size: 24px; | ||||
|         font-family: MicrosoftYaHei-Bold, MicrosoftYaHei; | ||||
|         font-weight: bold; | ||||
|         color: #222; | ||||
|         line-height: 24px; | ||||
|         margin-bottom: 8px; | ||||
|       } | ||||
|       .mini-title{ | ||||
|         font-size: 14px; | ||||
|         font-family: MicrosoftYaHei; | ||||
|         color: #555; | ||||
|         line-height: 22px; | ||||
|         margin-bottom: 20px; | ||||
|       } | ||||
|       .info{ | ||||
|         font-size: 14px; | ||||
|         font-family: MicrosoftYaHei; | ||||
|         line-height: 22px; | ||||
|         margin-bottom: 8px; | ||||
|         display: flex; | ||||
|         color: #222; | ||||
|         .label{ | ||||
|           width: 164px; | ||||
|         } | ||||
|         .value{ | ||||
|           width: calc(100% - 164px); | ||||
|         } | ||||
|         .color-26f{ | ||||
|           color: #26f; | ||||
|         } | ||||
|         .color-f46{ | ||||
|           color: #f46; | ||||
|         } | ||||
|       } | ||||
|       .mar-b32{ | ||||
|         margin-bottom: 32px; | ||||
|       } | ||||
|       .btn{ | ||||
|         width: 88px; | ||||
|         height: 32px; | ||||
|         line-height: 32px; | ||||
|         text-align: center; | ||||
|         background: linear-gradient(90deg, #299FFF 0%, #0C61FF 100%); | ||||
|         border-radius: 2px; | ||||
|         cursor: pointer; | ||||
|         color: #fff; | ||||
|         font-size: 14px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										354
									
								
								packages/party/AppPartyPayment/AppPartyPayment.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								packages/party/AppPartyPayment/AppPartyPayment.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,354 @@ | ||||
| <template> | ||||
|   <ai-list class="AppPartyPayment"> | ||||
|     <template slot="title"> | ||||
|       <ai-title title="党费缴纳" isShowBottomBorder :instance="instance"></ai-title> | ||||
|     </template> | ||||
|     <template #content> | ||||
|       <div class="statistics-top"> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>本月已缴纳党费金额</span> | ||||
|           <h2 style="color: #2266FF;">{{ topTotal['本月缴纳党费'] || 0 }}</h2> | ||||
|         </div> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>本月已缴纳人数</span> | ||||
|           <h2 style="color: #22AA99;">{{ topTotal['本月已缴纳人数'] || 0  }}</h2> | ||||
|         </div> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>本月未缴纳党费金额</span> | ||||
|           <h2 style="color: #F8B425">{{ topTotal['本月未缴纳党费'] || 0 }}</h2> | ||||
|         </div> | ||||
|         <div class="statistics-top__item"> | ||||
|           <span>本月未缴纳人数</span> | ||||
|           <h2 style="color: #999;">{{ topTotal['本月未缴纳人数'] || 0 }}</h2> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div class="content"> | ||||
|         <ai-search-bar> | ||||
|           <template #left> | ||||
|             <ai-party :instance="instance" v-model="search.partyOrgId" :topOrgId="topOrgId" :name.sync="search.partyOrgName" | ||||
|                     style="display:inline-block" @origin="handlePartyOrgSelect" customClicker | ||||
|                     url="/app/partyOrganization/queryAllChildren"> | ||||
|               <el-input size="small" v-model="search.partyOrgName" readonly placeholder="选择党组织"></el-input> | ||||
|             </ai-party> | ||||
|             <el-date-picker v-model="search.ymd" type="month" placeholder="选择日期" size="small" value-format="yyyy-MM" @change="getListInit"></el-date-picker> | ||||
|             <ai-select | ||||
|               v-model="search.status" | ||||
|               @change="getListInit()" | ||||
|               placeholder="状态" | ||||
|               :selectList="dict.getDict('zhishengPartyFeeRecordStatus')"> | ||||
|             </ai-select> | ||||
|           </template> | ||||
|           <template #right> | ||||
|             <el-input size="small" v-model="search.name" placeholder="姓名/身份证" | ||||
|               suffix-icon="iconfont iconSearch" v-throttle="() => {getListInit()}" clearable @clear="search.name = '', getListInit()"/> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <ai-search-bar> | ||||
|           <template #left> | ||||
|             <el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd('')">新增</el-button> | ||||
|           </template> | ||||
|           <template #right> | ||||
|             <ai-import :instance="instance" :dict="dict" type="appconvenientaddressbook" name="党费缴纳" | ||||
|               @success="getListInit()" importUrl="/app/appdfjnzhisheng/import" url="/app/appdfjnzhisheng/downloadTemplate"> | ||||
|               <el-button icon="iconfont iconImport">导入</el-button> | ||||
|             </ai-import> | ||||
|             <ai-download :instance="instance" url="/app/appdfjnzhisheng/export" :params="search" fileName="党费缴纳" | ||||
|               :disabled="tableData.length == 0"> | ||||
|               <el-button icon="iconfont iconExported" :disabled="tableData.length == 0">导出</el-button> | ||||
|             </ai-download> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <ai-table | ||||
|           :tableData="tableData" | ||||
|           :col-configs="colConfigs" | ||||
|           :total="total" | ||||
|           :current.sync="search.current" | ||||
|           :size.sync="search.size" | ||||
|           @getList="getList"> | ||||
|           <el-table-column slot="option" label="操作" align="center" width="160px" fixed="right"> | ||||
|             <template slot-scope="{ row }"> | ||||
|               <div class="table-options"> | ||||
|                 <el-button type="text" title="编辑" @click="edit(row)">编辑</el-button> | ||||
|                 <el-button type="text" title="删除" @click="remove(row)">删除</el-button> | ||||
|               </div> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|         </ai-table> | ||||
|       </div> | ||||
|       <ai-dialog :visible.sync="dialog" :title="dialogTitle" @closed="$refs.form.resetFields()" @onConfirm="handlePayment"> | ||||
|         <el-form ref="form" :rules="rules" size="small" :model="form" label-width="80px"> | ||||
|           <el-form-item label="党员姓名" prop="name"> | ||||
|             <el-autocomplete ref="poiInput" v-model="form.name" size="small" clearable :fetch-suggestions="handleSearch" | ||||
|               placeholder="请输入党员姓名" @select="handleSelect" :trigger-on-focus="false" style="width:100%;"> | ||||
|               <template slot-scope="{item}"> | ||||
|                 <span style="direction: rtl" v-text="`${item.name}-${item.partyOrgName}(${item.idNumber})`"/> | ||||
|               </template> | ||||
|             </el-autocomplete>  | ||||
|           </el-form-item> | ||||
|           <el-form-item label="身份证号" prop="idNumber"> | ||||
|             <el-input placeholder="自动带入" v-model="form.idNumber" :disabled="true" size="small"></el-input> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="缴纳状态" prop="status"> | ||||
|             <el-radio-group v-model="form.status"> | ||||
|               <el-radio label="1">已缴纳</el-radio> | ||||
|               <el-radio label="0">未缴纳</el-radio> | ||||
|             </el-radio-group> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="缴纳月份" prop="ymd"> | ||||
|             <el-date-picker v-model="form.ymd" type="month" placeholder="选择年月" size="small" value-format="yyyy-MM"></el-date-picker> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="金额(元)" prop="amount"> | ||||
|             <el-input-number :precision="2" size="small" type="input" v-model="form.amount" clearable placeholder="2位小数"></el-input-number> | ||||
|           </el-form-item> | ||||
|         </el-form> | ||||
|       </ai-dialog> | ||||
|     </template> | ||||
|   </ai-list> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import {mapState} from 'vuex' | ||||
|   export default { | ||||
|     name: 'AppPartyPayment', | ||||
|     label: '党费缴纳', | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object | ||||
|     }, | ||||
|     data () { | ||||
|       return { | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10, | ||||
|           partyOrgId: '', | ||||
|           partyOrgName: '', | ||||
|           name: '', | ||||
|           status: '', | ||||
|           ymd: '' | ||||
|         }, | ||||
|         total: 0, | ||||
|         tableData: [], | ||||
|         colConfigs: [ | ||||
|           { prop: 'orgName', label: '党组织' }, | ||||
|           { prop: 'name', label: '党员姓名', align: 'center',  }, | ||||
|           { prop: 'idNumber', label: '身份证', align: 'center' }, | ||||
|           { prop: 'ymd', label: '缴纳月份', align: 'center' }, | ||||
|           { prop: 'amount', label: '缴纳党费', align: 'center' }, | ||||
|           { prop: 'status', label: '状态', align: 'center',format: v => this.dict.getLabel('zhishengPartyFeeRecordStatus', v)}, | ||||
|           { slot: 'option'} | ||||
|         ], | ||||
|         topOrgId: '', | ||||
|         dialog: false, | ||||
|         dialogTitle: '', | ||||
|         form: { | ||||
|           name: '', | ||||
|           idNumber: '', | ||||
|           status: '0', | ||||
|           ymd: '', | ||||
|           amount: '', | ||||
|           orgId: '', | ||||
|           orgName: '', | ||||
|           partyId: '' | ||||
|         }, | ||||
|         topTotal: {} | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       params () { | ||||
|         return { | ||||
|           ...this.search, | ||||
|           startTime: this.search.type === '3' ? this.date[0] : '', | ||||
|           endTime: this.search.type === '3' ? this.date[1] : '' | ||||
|         } | ||||
|       }, | ||||
|       rules() { | ||||
|         return { | ||||
|           name: [{ required: true, message: '请输入党员姓名', trigger: 'change'}], | ||||
|           idNumber: [{ required: true, message: '请选择党员', trigger: 'change'}], | ||||
|           status: [{ required: true, message: '请选择缴费状态', trigger: 'change'}], | ||||
|           ymd: [{ required: true, message: '请选择缴纳月份', trigger: 'change'}], | ||||
|           amount: [{ required: true, message: '请输入金额', trigger: 'blur'}], | ||||
|         } | ||||
|       }, | ||||
|       ...mapState(['user']), | ||||
|     }, | ||||
|  | ||||
|     created () { | ||||
|       this.topOrgId = this.user.info.organizationId | ||||
|       this.dict.load('zhishengPartyFeeRecordStatus').then(() => { | ||||
|         this.getList() | ||||
|       }) | ||||
|       this.getTotal() | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       toAdd() { | ||||
|         this.form =  { | ||||
|           name: '', | ||||
|           idNumber: '', | ||||
|           status: '0', | ||||
|           ymd: '', | ||||
|           amount: '', | ||||
|           orgId: '', | ||||
|           orgName: '', | ||||
|           partyId: '' | ||||
|         } | ||||
|         this.dialogTitle = '新增党费信息' | ||||
|         this.dialog = true | ||||
|       }, | ||||
|       edit(row) { | ||||
|         this.form = row | ||||
|         this.dialog = true | ||||
|         this.dialogTitle = '编辑党费信息' | ||||
|       }, | ||||
|       handleSearch(e, cb) { | ||||
|         this.instance.post(`/app/appparty/fuzzyList?name=${e}&size=50`).then((res) => { | ||||
|           if (res.code == 0) { | ||||
|             cb(res.data) | ||||
|           } | ||||
|         }); | ||||
|       }, | ||||
|       handleSelect(e) { | ||||
|         this.form.name = e.name | ||||
|         this.form.idNumber = e.idNumber | ||||
|         this.form.orgId = e.partyOrgId | ||||
|         this.form.orgName = e.partyOrgName | ||||
|         this.form.partyId = e.id | ||||
|       }, | ||||
|       handlePayment() { | ||||
|         this.$refs.form.validate((valid) => { | ||||
|           if (valid) { | ||||
|             this.instance.post(`/app/appdfjnzhisheng/addOrUpdate`, {...this.form}).then((res) => { | ||||
|               if (res.code == 0) { | ||||
|                 this.$message.success(this.dialogTitle == '编辑党费信息' ? "编辑成功" : "新增成功"); | ||||
|                 this.$refs.form.resetFields() | ||||
|                 this.dialog = false | ||||
|                 this.getListInit() | ||||
|                 this.getTotal() | ||||
|               } | ||||
|             }); | ||||
|           } | ||||
|         }); | ||||
|       }, | ||||
|       handlePartyOrgSelect(e) { | ||||
|         let {isLeaf, name, id} = e?.[0] || {}; | ||||
|         if (isLeaf == 1) { | ||||
|           this.search.partyOrgName = name; | ||||
|           this.search.partyOrgId = id; | ||||
|         } | ||||
|         this.getListInit() | ||||
|       }, | ||||
|       getListInit() { | ||||
|         this.search.current = 1 | ||||
|         this.getList() | ||||
|       }, | ||||
|       getList () { | ||||
|         this.instance.post(`/app/appdfjnzhisheng/list`, null, { | ||||
|           params: { | ||||
|             ...this.search, | ||||
|             orgId: this.search.partyOrgId | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             res.data.records.map((item) => { | ||||
|               item.ymd = item.ymd.substring(0, 7) | ||||
|             }) | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|       remove(row) { | ||||
|         this.$confirm('确定删除该数据?').then(() => { | ||||
|           this.instance.post(`/app/appdfjnzhisheng/delete?ids=${row.id}`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('删除成功!') | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|       getTotal() { | ||||
|         this.instance.post(`/app/appdfjnzhisheng/statistics`).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.topTotal = res.data | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .AppPartyPayment { | ||||
|  | ||||
|     .bottom { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|  | ||||
|       & > .ai-card { | ||||
|         flex: 1; | ||||
|  | ||||
|         &:last-child { | ||||
|           margin-left: 20px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     :deep( .ai-list__content ){ | ||||
|       padding: 0!important; | ||||
|  | ||||
|       .ai-list__content--right-wrapper { | ||||
|         background: transparent!important; | ||||
|         box-shadow: none!important; | ||||
|         margin: 0!important; | ||||
|         padding: 12px 16px 12px!important; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     :deep( .ai-card) { | ||||
|       .ai-card__body { | ||||
|         padding: 12px 16px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .statistics-top { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       margin-bottom: 20px; | ||||
|  | ||||
|       & > div { | ||||
|         flex: 1; | ||||
|         height: 96px; | ||||
|         line-height: 1; | ||||
|         margin-right: 20px; | ||||
|         padding: 16px 24px; | ||||
|         background: #FFFFFF; | ||||
|         box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15); | ||||
|         border-radius: 4px; | ||||
|  | ||||
|         &:last-child { | ||||
|           margin-right: 0; | ||||
|         } | ||||
|  | ||||
|         h3 { | ||||
|           font-size: 24px; | ||||
|         } | ||||
|  | ||||
|         span { | ||||
|           display: block; | ||||
|           margin-bottom: 16px; | ||||
|           color: #888888; | ||||
|           font-size: 16px; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .content { | ||||
|       padding: 16px; | ||||
|       background: #FFFFFF; | ||||
|       box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15); | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										35
									
								
								packages/party/AppPartyScore/AppPartyScore.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								packages/party/AppPartyScore/AppPartyScore.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| <template> | ||||
|   <section class="AppPartyScore"> | ||||
|     <component :is="currentPage" v-bind="$props"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import PsList from "./psList"; | ||||
| import PsDetail from "./psDetail"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppPartyScore", | ||||
|   components: {PsDetail, PsList}, | ||||
|   label: "党员积分", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     currentPage() { | ||||
|       return this.$route.query.id ? PsDetail : PsList | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load("partyIntegralType") | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AppPartyScore { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										154
									
								
								packages/party/AppPartyScore/psDetail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								packages/party/AppPartyScore/psDetail.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
| <template> | ||||
|   <section class="psDetail"> | ||||
|     <ai-detail> | ||||
|       <ai-title slot="title" title="积分详情" isShowBottomBorder isShowBack @onBackClick="back"/> | ||||
|       <template #content> | ||||
|         <el-row type="flex"> | ||||
|           <ai-card hideTitle class="staCard fill"> | ||||
|             <template #content> | ||||
|               <div class="color-999" v-text="`姓名`"/> | ||||
|               <b v-text="detail.name"/> | ||||
|             </template> | ||||
|           </ai-card> | ||||
|           <ai-card hideTitle class="staCard fill"> | ||||
|             <template #content> | ||||
|               <div class="color-999" v-text="`学习强国`"/> | ||||
|               <el-button type="text" @click="handleEditLearningIntergral(detail.id)">编辑</el-button> | ||||
|               <b class="color-26f" v-text="detail.learningIntegral||0"/> | ||||
|             </template> | ||||
|           </ai-card> | ||||
|           <ai-card hideTitle class="staCard fill"> | ||||
|             <template slot="content"> | ||||
|               <div class="color-999" v-text="`个人积分`"/> | ||||
|               <b class="color-26f" v-text="detail.integral||0"/> | ||||
|             </template> | ||||
|           </ai-card> | ||||
|           <ai-card hideTitle class="staCard fill"> | ||||
|             <template #content> | ||||
|               <div class="color-999" v-text="`家庭积分`"/> | ||||
|               <b class="color-26f" v-text="detail.familySurplusIntegral||0"/> | ||||
|             </template> | ||||
|           </ai-card> | ||||
|         </el-row> | ||||
|         <ai-card title="余额变动明细"> | ||||
|           <template #content> | ||||
|             <ai-table :tableData="detail.integralInfoList" :isShowPagination="false" :col-configs="colConfigs" | ||||
|                       :dict="dict"/> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|       </template> | ||||
|     </ai-detail> | ||||
|     <ai-dialog :visible.sync="dialog" title="学习强国设置" width="500px" @close="form={}" @onConfirm="submit"> | ||||
|       <el-form :model="form" size="small" ref="DialogForm" :rules="rules" label-width="110px"> | ||||
|         <el-form-item label="学习强国积分" prop="learningIntegral"> | ||||
|           <el-input v-model.number="form.learningIntegral" placeholder="请输入正整数" clearable/> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|     </ai-dialog> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "psDetail", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       detail: {}, | ||||
|       colConfigs: [ | ||||
|         {label: "时间", prop: "createTime"}, | ||||
|         {label: "类型", prop: "integralType", align: 'center', dict: "partyIntegralType"}, | ||||
|         {label: "变动积分", prop: "integral", align: 'center'}, | ||||
|         {label: "剩余积分", prop: "residualIntegral", align: 'center'}, | ||||
|         {label: "调整说明", prop: "remark"}, | ||||
|       ], | ||||
|       dialog: false, | ||||
|       form: {}, | ||||
|       rules: { | ||||
|         learningIntegral: [ | ||||
|           {required: true, message: "请输入学习强国积分"}, | ||||
|           {pattern: /^\d+$/g, message: "请输入正整数"} | ||||
|         ] | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     getDetail() { | ||||
|       let {id} = this.$route.query | ||||
|       this.instance.post("/app/appparty/getPartyIntegralDetail", null, { | ||||
|         params: {id} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.detail = res.data | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     back() { | ||||
|       this.$router.push({}) | ||||
|     }, | ||||
|     submit() { | ||||
|       this.$refs.DialogForm.validate(v => { | ||||
|         if (v) { | ||||
|           this.instance.post("/app/appparty/editLearningIntegral", null,{ | ||||
|             params:this.form | ||||
|           }).then(res => { | ||||
|             if (res?.code == 0) { | ||||
|               this.$message.success("提交成功!") | ||||
|               this.dialog = false | ||||
|               this.getDetail() | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     handleEditLearningIntergral(partyMemberId) { | ||||
|       this.dialog = true | ||||
|       this.form = {partyMemberId} | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.getDetail() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .psDetail { | ||||
|   height: 100%; | ||||
|  | ||||
|   .color-999 { | ||||
|     color: #999; | ||||
|   } | ||||
|  | ||||
|   .color-26f { | ||||
|     color: #26f; | ||||
|   } | ||||
|  | ||||
|   :deep(.staCard ){ | ||||
|     font-size: 14px; | ||||
|  | ||||
|     b { | ||||
|       font-size: 24px; | ||||
|       line-height: 40px; | ||||
|     } | ||||
|  | ||||
|     & + .staCard { | ||||
|       margin-left: 16px; | ||||
|     } | ||||
|  | ||||
|     .ai-card__body { | ||||
|       position: relative; | ||||
|  | ||||
|       .el-button { | ||||
|         position: absolute; | ||||
|         right: 32px; | ||||
|         top: 6px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										116
									
								
								packages/party/AppPartyScore/psList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								packages/party/AppPartyScore/psList.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | ||||
| <template> | ||||
|   <section class="psList"> | ||||
|     <ai-list> | ||||
|       <ai-title slot="title" title="党员积分" isShowBottomBorder/> | ||||
|       <template #content> | ||||
|         <ai-search-bar> | ||||
|           <template #right> | ||||
|             <ai-import :instance="instance" name="党员积分" title="导入党员积分" | ||||
|                        suffixName="xlsx" | ||||
|                        url="/app/apppartyintegralinfo/downloadTemplate" | ||||
|                        importUrl="/app/apppartyintegralinfo/import" | ||||
|                        @onSuccess="page.current=1,getTableData()"/> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size" | ||||
|                   @getList="getTableData" :col-configs="colConfigs" :dict="dict"> | ||||
|           <el-table-column slot="options" label="操作" fixed="right" align="center"> | ||||
|             <template slot-scope="{row}"> | ||||
|               <el-button type="text" @click="getFamilyByPartyId(row.idNumber)">家庭成员</el-button> | ||||
|               <el-button type="text" @click="showDetail(row.id)">详情</el-button> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|         </ai-table> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|     <ai-dialog :visible.sync="dialog" title="家庭成员" :customFooter="true" width="780px" @close="familyList=[]"> | ||||
|       <ai-table :tableData="familyList" :isShowPagination="false" :col-configs="familyCols" :dict="dict"/> | ||||
|       <div class="dialog-footer" slot="footer"> | ||||
|         <el-button @click="dialog=false">关 闭</el-button> | ||||
|       </div> | ||||
|     </ai-dialog> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
| import {ID} from "dui/lib/js/utils"; | ||||
|  | ||||
| export default { | ||||
|   name: "psList", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     colConfigs() { | ||||
|       return [ | ||||
|         {label: "姓名", prop: "name"}, | ||||
|         {label: "个人积分", prop: "integral", align: "center"}, | ||||
|         {label: "家庭积分", prop: "familySurplusIntegral", align: "center"}, | ||||
|         {label: "学习强国", prop: "learningIntegral", align: "center"}, | ||||
|         {slot: "options"} | ||||
|       ] | ||||
|     }, | ||||
|     familyCols() { | ||||
|       return [ | ||||
|         { | ||||
|           label: '与户主关系', prop: 'householdRelation', align: 'center', width: 165, | ||||
|           render: (h, {row}) => h('p', this.dict.getLabel('householdRelation', row.householdRelation || "户主")) | ||||
|         }, | ||||
|         {label: '类型', prop: 'residentType', align: 'center', dict: "residentType"}, | ||||
|         {label: '姓名', prop: 'name', align: 'center'}, | ||||
|         {label: '身份证号', render: (h, {row}) => h('p', ID.hideId(row.idNumber)), width: 165}, | ||||
|         {label: '联系电话', prop: 'phone', align: 'center', width: 120} | ||||
|       ] | ||||
|     } | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       search: {}, | ||||
|       page: {current: 1, size: 10, total: 0}, | ||||
|       tableData: [], | ||||
|       dialog: false, | ||||
|       familyList: [], | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     back() { | ||||
|       this.$router.push({}) | ||||
|     }, | ||||
|     getTableData() { | ||||
|       this.instance.post("/app/appparty/listByPartyIntegral", null, { | ||||
|         params: {...this.page, ...this.search} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.tableData = res.data?.records | ||||
|           this.page.total = res.data.total | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     showDetail(id) { | ||||
|       this.$router.push({query: {id}}) | ||||
|     }, | ||||
|     getFamilyByPartyId(idNumber) { | ||||
|       this.instance.post("/app/appresident/queryHomeMember", null, { | ||||
|         params: {idNumber} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.familyList = res.data?.family || [] | ||||
|           this.dialog = true | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.getTableData() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .psList { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										34
									
								
								packages/party/AppPartyScoreFlow/AppPartyScoreFlow.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								packages/party/AppPartyScoreFlow/AppPartyScoreFlow.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| <template> | ||||
|   <section class="AppPartyScoreFlow"> | ||||
|     <component :is="currentPage" v-bind="$props"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import PsfList from "./psfList"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppPartyScoreFlow", | ||||
|   components: {PsfList}, | ||||
|   label: "党员积分明细", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     currentPage() { | ||||
|       return PsfList | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load("partyIntegralType") | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AppPartyScoreFlow { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										150
									
								
								packages/party/AppPartyScoreFlow/psfList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								packages/party/AppPartyScoreFlow/psfList.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,150 @@ | ||||
| <template> | ||||
|   <section class="psfList"> | ||||
|     <ai-list> | ||||
|       <ai-title slot="title" title="党员积分明细" isShowBottomBorder/> | ||||
|       <template #content> | ||||
|         <ai-search-bar> | ||||
|           <template #left> | ||||
|             <el-button type="primary" icon="iconfont iconAdd" @click="dialog=true">添加</el-button> | ||||
|             <el-date-picker type="daterange" placeholder="日期" size="small" clearable v-model="createTime" | ||||
|                             @change="handleSearchTime" start-placeholder="开始时间" end-placeholder="结束时间" | ||||
|                             value-format="yyyy-MM-dd HH:mm:ss" :default-time="['00:00:00','23:59:59']"/> | ||||
|           </template> | ||||
|           <template #right> | ||||
|             <el-input size="small" placeholder="搜索党员" v-model="search.partyName" clearable | ||||
|                       @change="page.current=1,getTableData()" suffix-icon="iconfont iconSearch"/> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size" | ||||
|                   @getList="getTableData" :col-configs="colConfigs" :dict="dict"> | ||||
|           <el-table-column slot="options" label="操作" fixed="right" align="center"> | ||||
|             <template slot-scope="{row}"> | ||||
|               <el-button type="text" @click="showDetail(row)">详情</el-button> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|         </ai-table> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|     <ai-dialog :visible.sync="dialog" title="积分对象" width="600px" @close="form={}" @onConfirm="submit" | ||||
|                :customFooter="!isAdd"> | ||||
|       <el-form v-if="isAdd" :model="form" size="small" ref="DialogForm" :rules="rules" label-width="80px"> | ||||
|         <el-form-item label="选择人员" prop="partyId"> | ||||
|           <ai-select v-model="form.partyId" action="/app/appparty/list" :instance="instance" | ||||
|                      :prop="{label:'name'}"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="调整说明" prop="remark"> | ||||
|           <el-input type="textarea" placeholder="请输入" v-model="form.remark" maxlength="100" show-word-limit rows="3" | ||||
|                     clearable/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="类型" prop="integralType"> | ||||
|           <ai-select v-model="form.integralType" :selectList="dict.getDict('partyIntegralType')"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="积分" prop="integral"> | ||||
|           <el-input v-model.number="form.integral" placeholder="请输入正整数" clearable/> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|       <ai-wrapper v-else> | ||||
|         <ai-info-item label="对象" :value="form.partyName"/> | ||||
|         <ai-info-item label="调整说明" :value="form.remark" isLine/> | ||||
|         <ai-info-item label="类型" :value="dict.getLabel('partyIntegralType',form.integralType)"/> | ||||
|         <ai-info-item label="积分" :value="form.integral"/> | ||||
|       </ai-wrapper> | ||||
|     </ai-dialog> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
|  | ||||
| export default { | ||||
|   name: "psfList", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     colConfigs() { | ||||
|       return [ | ||||
|         {label: "对象", prop: "partyName"}, | ||||
|         {label: "调整说明", prop: "remark", align: "center"}, | ||||
|         {label: "时间", prop: "createTime"}, | ||||
|         {label: "类型", prop: "integralType", align: "center", dict: "partyIntegralType"}, | ||||
|         {label: "积分", prop: "integral", align: "center"}, | ||||
|         {slot: "options"} | ||||
|       ] | ||||
|     }, | ||||
|     isAdd() { | ||||
|       return !this.form.id | ||||
|     } | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       search: {}, | ||||
|       page: {current: 1, size: 10, total: 0}, | ||||
|       tableData: [], | ||||
|       dialog: false, | ||||
|       form: {}, | ||||
|       rules: { | ||||
|         partyId: {required: true, message: "请选择人员"}, | ||||
|         remark: {required: true, message: "请输入调整说明"}, | ||||
|         integralType: {required: true, message: "请选择类型"}, | ||||
|         integral: [ | ||||
|           {required: true, message: "请输入分数"}, | ||||
|           {pattern: /^\d+$/g, message: "请输入正整数"} | ||||
|         ], | ||||
|       }, | ||||
|       createTime: "" | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     getTableData() { | ||||
|       this.instance.post("/app/apppartyintegralinfo/list", null, { | ||||
|         params: {...this.page, ...this.search} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.tableData = res.data?.records?.map(e => ({ | ||||
|             ...e, | ||||
|             integral: (e.integralType == 0 ? "-" : '+') + e.integral | ||||
|           })) | ||||
|           this.page.total = res.data.total | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     showDetail(row) { | ||||
|       this.form = JSON.parse(JSON.stringify(row)) | ||||
|       this.dialog = true | ||||
|     }, | ||||
|     submit() { | ||||
|       this.$refs.DialogForm.validate(v => { | ||||
|         if (v) { | ||||
|           let loading = this.$loading({text: "提交中..."}) | ||||
|           this.instance.post("/app/apppartyintegralinfo/addOrUpdate", this.form).then(res => { | ||||
|             loading.close() | ||||
|             if (res?.code == 0) { | ||||
|               this.$message.success("提交成功!") | ||||
|               this.dialog = false | ||||
|               this.getTableData() | ||||
|             } | ||||
|           }).catch(() => loading.close()) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     handleSearchTime(v) { | ||||
|       this.page.current = 1 | ||||
|       this.search.startTime = v?.[0] | ||||
|       this.search.endTime = v?.[1] | ||||
|       this.getTableData() | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.getTableData() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .psfList { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										101
									
								
								packages/work/AppConference/AppConference.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								packages/work/AppConference/AppConference.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| <template> | ||||
|   <section class="conference"> | ||||
|     <ai-list v-if="!showDetail"> | ||||
|       <template slot="title"> | ||||
|         <ai-title title="会议管理"></ai-title> | ||||
|       </template> | ||||
|       <template slot="tabs"> | ||||
|         <el-tabs v-model="currIndex" @tab-click="handleClick"> | ||||
|           <el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label" :name="String(i)"> | ||||
|             <component :is="tab.comp" v-if="currIndex==i" :ref="currIndex" :instance="instance" :dict="dict" | ||||
|                        :permissions="permissions" @goPage="goPage" :listType="listType" /> | ||||
|           </el-tab-pane> | ||||
|         </el-tabs> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|  | ||||
|     <component v-else :is="currentComp" :instance="instance" :dict="dict" :detail="detailRow" :listType="listType" @gotoEdit="gotoAdd" ></component> | ||||
|  | ||||
|   </section> | ||||
| </template> | ||||
| <script> | ||||
| import addMeeting from './addMeeting'; | ||||
| import detail from './detail' | ||||
| import list from './list' | ||||
|  | ||||
| export default { | ||||
|   name: 'AppConference', | ||||
|   label: "会议管理", | ||||
|   components: {addMeeting, detail, list}, | ||||
|   provide() { | ||||
|     return { | ||||
|       top: this | ||||
|     } | ||||
|   }, | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       //会议状态,0、草稿;1、未开始;2、进行中;3、已取消;4、已结束 | ||||
|       //参会状态,0、未确认;1、已确认;2、缺席 | ||||
|       currIndex: "0", | ||||
|       currentComp: "", | ||||
|       showDetail: false, | ||||
|       detailRow: {}, | ||||
|       listType: '1', | ||||
|     } | ||||
|   }, | ||||
|   computed:{ | ||||
|     tabs() { | ||||
|       return [ | ||||
|         {label: "我参与的会议", name: "addMeeting", comp: list, detail: detail, permission: ""}, | ||||
|         {label: "我发起的会议", name: "addMeeting",  comp: list, detail: detail, permission: ""}, | ||||
|       ] | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     goPage(params) { | ||||
|       this.detailRow = params.row | ||||
|       this.currentComp = params.comp | ||||
|  | ||||
|       if(params.comp == 'detail' || params.comp == 'addMeeting') { | ||||
|         this.showDetail = true | ||||
|       } | ||||
|     }, | ||||
|     handleClick() { | ||||
|       if (this.currIndex == 0) { | ||||
|         this.listType = '1' | ||||
|       } else { | ||||
|         this.listType = '0' | ||||
|       } | ||||
|     }, | ||||
|     goBack() { | ||||
|       this.showDetail = false; | ||||
|       if (this.currIndex == '0') { | ||||
|         this.listType = '1' | ||||
|       } else { | ||||
|         this.listType = '0' | ||||
|       } | ||||
|     }, | ||||
|     gotoAdd(obj) { | ||||
|       this.showDetail = true | ||||
|       this.detailRow = obj | ||||
|       this.currentComp = 'addMeeting' | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
|   .conference { | ||||
|     height: 100%; | ||||
|  | ||||
|     :deep( .ai-list__content--right-wrapper ){ | ||||
|       background-color: transparent !important; | ||||
|       box-shadow: none !important; | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										244
									
								
								packages/work/AppConference/addMeeting.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								packages/work/AppConference/addMeeting.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,244 @@ | ||||
| <template> | ||||
|   <ai-detail class="addMeeting"> | ||||
|     <ai-title slot="title" title="发起会议" isShowBack isShowBottomBorder @onBackClick="$parent.goBack"/> | ||||
|     <template #content> | ||||
|       <ai-card title="会议信息"> | ||||
|         <template #content> | ||||
|           <el-form :model="saveData" status-icon ref="ruleForm" :rules="rules" label-width="100px" | ||||
|                    label-position="right"> | ||||
|             <el-form-item label="会议标题:" prop="title"> | ||||
|               <el-input v-model="saveData.title" size="small" placeholder="请输入..." | ||||
|                         :maxlength="30" show-word-limit></el-input> | ||||
|             </el-form-item> | ||||
|             <el-row type="flex" justify="space-between"> | ||||
|               <el-form-item label="开始时间:" prop="startTime"> | ||||
|                 <el-date-picker | ||||
|                     :editable="false" | ||||
|                     value-format="yyyy-MM-dd HH:mm:ss" | ||||
|                     v-model="saveData.startTime" | ||||
|                     :picker-options="pickerOptions" | ||||
|                     type="datetime" | ||||
|                     size="small" | ||||
|                     placeholder="选择开始时间"> | ||||
|                 </el-date-picker> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="结束时间:" prop="endTime"> | ||||
|                 <el-date-picker | ||||
|                     :editable="false" | ||||
|                     value-format="yyyy-MM-dd HH:mm:ss" | ||||
|                     v-model="saveData.endTime" | ||||
|                     :picker-options="pickerOptions" | ||||
|                     type="datetime" | ||||
|                     :disabled="!Boolean(saveData.startTime)" | ||||
|                     size="small" | ||||
|                     placeholder="选择结束时间"> | ||||
|                 </el-date-picker> | ||||
|               </el-form-item> | ||||
|             </el-row> | ||||
|             <el-form-item label="会议地点:" prop="address"> | ||||
|               <el-input v-model="saveData.address" size="small" placeholder="请输入..." | ||||
|                         :maxlength="30" show-word-limit></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="会议内容:" prop="content"> | ||||
|               <el-input v-model="saveData.content" size="small" placeholder="请输入..." | ||||
|                         type="textarea" :rows="8" :maxlength="500" show-word-limit></el-input> | ||||
|             </el-form-item> | ||||
|             <el-row type="flex" justify="space-between"> | ||||
|               <el-form-item label="参会提醒:" prop="noticeBefore"> | ||||
|                 <ai-select v-model="saveData.noticeBefore" | ||||
|                            placeholder="请选择" | ||||
|                            :selectList="dict.getDict('meetingNoticeBefore')" | ||||
|                 ></ai-select> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="确认提醒:" prop="noticeAfter"> | ||||
|                 <ai-select v-model="saveData.noticeAfter" | ||||
|                            placeholder="请选择" | ||||
|                            :selectList="dict.getDict('meetingNoticeAfter')" | ||||
|                 ></ai-select> | ||||
|               </el-form-item> | ||||
|             </el-row> | ||||
|             <el-form-item label="会议资料:" prop="files"> | ||||
|               <ai-uploader :instance="instance" @change="handleChange" isShowTip fileType="file" | ||||
|                            v-model="saveData.fileList" | ||||
|                            acceptType=".zip,.rar,.doc,.docx,.xls,.ppt,.pptx,.pdf,.txt,.jpg,.png,.xlsx" | ||||
|                            :limit="9"></ai-uploader> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </template> | ||||
|       </ai-card> | ||||
|       <ai-card title="参会人员信息"> | ||||
|         <template #right> | ||||
|           <ai-wechat-selecter slot="append" :instance="instance" v-model="saveData.attendees"> | ||||
|             <el-button type="text" icon="iconfont iconAdd">选择参会人员</el-button> | ||||
|           </ai-wechat-selecter> | ||||
|         </template> | ||||
|         <template #content> | ||||
|           <ai-table | ||||
|               border | ||||
|               :tableData="saveData.attendees" | ||||
|               :colConfigs="colConfigs" | ||||
|               :isShowPagination="false"> | ||||
|             <el-table-column label="操作" slot="option" align="center"> | ||||
|               <template v-slot="{row}"> | ||||
|                 <el-button type="text" title="删除" @click="deletePer(row)">删除</el-button> | ||||
|               </template> | ||||
|             </el-table-column> | ||||
|           </ai-table> | ||||
|         </template> | ||||
|       </ai-card> | ||||
|     </template> | ||||
|     <template #footer> | ||||
|       <el-button @click="$parent.goBack">取消</el-button> | ||||
|       <el-button type="primary" @click="saveFrom(0)">保存草稿</el-button> | ||||
|       <el-button type="primary" @click="saveFrom(1)">保存并发布</el-button> | ||||
|     </template> | ||||
|   </ai-detail> | ||||
| </template> | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
| import moment from 'dayjs' | ||||
|  | ||||
| export default { | ||||
|   name: "addMeeting", | ||||
|   inject: ['top'], | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function, | ||||
|     detail: Object | ||||
|   }, | ||||
|   data() { | ||||
|     let endTimePass = (rule, value, callback) => { | ||||
|       if (value) { | ||||
|         if (moment(value).unix() - moment(this.saveData.startTime).unix() > 0) { | ||||
|           callback() | ||||
|         } else { | ||||
|           callback(new Error('结束时间要大于开始时间')); | ||||
|         } | ||||
|       } else { | ||||
|         callback(new Error('请选择结束时间')); | ||||
|       } | ||||
|     } | ||||
|     return { | ||||
|       saveData: { | ||||
|         noticeBefore: '4', | ||||
|         noticeAfter: '0', | ||||
|         attendees: [], | ||||
|         fileList: [] | ||||
|       }, | ||||
|       rules: { | ||||
|         title: [{required: true, message: '请填写会议标题', trigger: 'blur'}], | ||||
|         startTime: [{required: true, message: '请选择开始时间', trigger: 'blur'}], | ||||
|         endTime: [{required: true, validator: endTimePass, trigger: 'change'}], | ||||
|         address: [{required: true, message: '请填写会议地点', trigger: 'blur'}], | ||||
|         // content: [{required: true, message: '请填写会议内容', trigger: 'blur'}], | ||||
|         noticeBefore: [{required: true, message: '请选择参会提醒', trigger: 'blur'}], | ||||
|         noticeAfter: [{required: true, message: '请选择确认提醒', trigger: 'blur'}], | ||||
|       }, | ||||
|       pickerOptions: { | ||||
|         disabledDate(time) { | ||||
|           return time.getTime() < Date.now() - 8.64e7; | ||||
|         } | ||||
|       }, | ||||
|       showEdit: false, | ||||
|       total: 0, | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     handleChange(e) { | ||||
|       this.saveData.fileList = e | ||||
|     }, | ||||
|     deletePer(scope) { | ||||
|       this.$confirm('确认删除此参会人?') | ||||
|       .then(_ => { | ||||
|         if (this.detail.id) { //编辑 | ||||
|  | ||||
|         } else { //新增 | ||||
|           this.saveData.attendees.map((item, index) => { | ||||
|             if (item.id == scope.id) { | ||||
|               this.saveData.attendees.splice(index, 1) | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     saveFrom(status) { | ||||
|       this.$refs["ruleForm"].validate((valid) => { | ||||
|         if (this.saveData.attendees.length == 0) { | ||||
|           return this.$message.error("参会人不能为空!") | ||||
|         } | ||||
|         if (moment(this.saveData.startTime).unix() - moment(Date.now()).unix() < 0) { | ||||
|           return this.$message.error("会议开始时间已过期,请重新选择!"); | ||||
|         } | ||||
|         if (valid) { | ||||
|  | ||||
|           this.saveData.files = [] | ||||
|           this.saveData.fileList.map((item) => { | ||||
|             this.saveData.files.push(item.id) | ||||
|           }) | ||||
|           this.instance.post(`/app/appmeetinginfo/add-update`, { | ||||
|             ...this.saveData, | ||||
|             status: status, | ||||
|           }).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               if (status != 1) { | ||||
|                 this.$message.success("保存草稿成功") | ||||
|               } else { | ||||
|                 this.$message.success("发布成功") | ||||
|               } | ||||
|               this.$parent.goBack(); | ||||
|             } | ||||
|           }); | ||||
|         } | ||||
|       }); | ||||
|     }, | ||||
|     getDetail() { | ||||
|       this.instance.post(`/app/appmeetinginfo/info-id?id=${this.detail.id}`).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.saveData = { | ||||
|             ...res.data, | ||||
|           }; | ||||
|           this.saveData.fileList = res.data.files || [] | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load("meetingNoticeAfter", "meetingNoticeBefore").then( | ||||
|         this.$nextTick(() => { | ||||
|           if (JSON.stringify(this.detail) == '{}') { | ||||
|             this.showEdit = false; | ||||
|           } else { | ||||
|             this.showEdit = true; | ||||
|             // this.saveData = {...this.detail}; | ||||
|             // this.compereList = this.saveData.hosts; | ||||
|             // this.saveData.attendees = this.saveData.attendees || []; | ||||
|             this.getDetail() | ||||
|           } | ||||
|         }) | ||||
|     ) | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     headerTitle() { | ||||
|       return this.showEdit ? '修改会议' : '发起会议' | ||||
|     }, | ||||
|     colConfigs() { | ||||
|       return [ | ||||
|         {prop: 'name', align: 'center', label: '姓名'}, | ||||
|         {prop: 'departName', align: 'center', label: '所属单位'}, | ||||
|         {slot: 'option'} | ||||
|       ] | ||||
|     }, | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .addMeeting { | ||||
|   :deep( .el-button--text ){ | ||||
|     .iconfont { | ||||
|       color: inherit; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										595
									
								
								packages/work/AppConference/detail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										595
									
								
								packages/work/AppConference/detail.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,595 @@ | ||||
| <template> | ||||
|   <section class="meetingDetail detail-content"> | ||||
|     <ai-detail> | ||||
|       <template #title> | ||||
|         <ai-title title="会议详情" isShowBottomBorder isShowBack @onBackClick="$parent.goBack"> | ||||
|           <template #rightBtn> | ||||
|             <p class="conference_top_area" v-if="listType==0"> | ||||
|               <!-- <el-button type="primary" v-if="detail.status==0" @click="changeMeeting('是否立即发布会议?')">立即发布</el-button> --> | ||||
|               <el-button type="primary" v-if="detail.status==1" @click="noticeMetting()">参会提醒</el-button> | ||||
|               <el-button type="primary" v-if="detail.status==0" @click="editMeeting()">修改会议</el-button> | ||||
|               <el-button class="del-btn-list" v-if="detail.status==1" @click="changeMeeting('是否取消会议?')">取消会议</el-button> | ||||
|               <el-button class="iconfont iconDelete del-btn-list" v-if="detail.status==0||detail.status==3" | ||||
|                          @click="changeMeeting('是否删除会议?')">删除会议 | ||||
|               </el-button> | ||||
|             </p> | ||||
|             <!-- v-if="detail.status==0||detail.status==3" --> | ||||
|             <p class="conference_top_area" v-if="listType==1&&info.status==1"> | ||||
|               <el-button @click="toDo" style="width:80px;" class="del-btn-list">待定</el-button> | ||||
|               <el-button @click="innerVisible=true" v-if="info.joinStatus!=2" style="width:80px;" class="del-btn-list"> | ||||
|                 请假 | ||||
|               </el-button> | ||||
|               <el-button type="primary" @click="changeMeeting('是否确认参会?')" v-if="info.joinStatus!=1" style="width:80px;"> | ||||
|                 确认参会 | ||||
|               </el-button> | ||||
|             </p> | ||||
|           </template> | ||||
|         </ai-title> | ||||
|       </template> | ||||
|       <template #content> | ||||
|         <ai-dialog | ||||
|             title="确认请假" | ||||
|             :visible.sync="innerVisible" | ||||
|             @onConfirm="queMeeting('writeInfo')" | ||||
|             @onCancel="innerVisible=false;" @close="$refs.writeInfo.resetFields()" | ||||
|             width="520px"> | ||||
|           <div class="addother_main" style="width:400px;margin:auto;"> | ||||
|             <el-form :model="writeInfo" status-icon ref="writeInfo" label-width="100px" class="demo-ruleForm"> | ||||
|               <el-form-item label="请假原因:" prop="reason" autocomplete="off" | ||||
|                             :rules="{ | ||||
|                                         required: true, message: '请假原因不能为空', trigger: 'blur' | ||||
|                                     }" | ||||
|               > | ||||
|                 <el-input v-model.trim="writeInfo.reason" autocomplete="off" size="mini" placeholder="请输入..." | ||||
|                           type="textarea" :rows="4" :maxlength="100" show-word-limit></el-input> | ||||
|               </el-form-item> | ||||
|  | ||||
|             </el-form> | ||||
|           </div> | ||||
|         </ai-dialog> | ||||
|         <ai-card title="会议说明"> | ||||
|           <template slot="content"> | ||||
|             <ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="1"> | ||||
|               <ai-info-item label="会议标题:"><span>{{ info.title }}</span></ai-info-item> | ||||
|             </ai-wrapper> | ||||
|             <ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="2"> | ||||
|               <ai-info-item label="发起单位:" :value="info.unitName"> | ||||
|               </ai-info-item> | ||||
|               <ai-info-item label="发起人:" :value="info.userName"> | ||||
|               </ai-info-item> | ||||
|             </ai-wrapper> | ||||
|             <ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="1"> | ||||
|               <!-- <ai-info-item label="会议状态:" v-if="xq.joinStatus==1&&listType==1"><span>{{ xq.joinStatus }}</span> | ||||
|               </ai-info-item> --> | ||||
|               <ai-info-item label="发起时间:"><span>{{ info.createTime }}</span></ai-info-item> | ||||
|             </ai-wrapper> | ||||
|             <ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="2"> | ||||
|               <ai-info-item label="开始时间:"><span>{{ info.startTime }}</span></ai-info-item> | ||||
|               <ai-info-item label="结束时间:"><span>{{ info.endTime }}</span></ai-info-item> | ||||
|             </ai-wrapper> | ||||
|             <ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="2"> | ||||
|               <ai-info-item label="参会提醒:"><span>{{ | ||||
|                   dict.getLabel("meetingNoticeBefore", info.noticeBefore) || "-" | ||||
|                 }}</span></ai-info-item> | ||||
|               <ai-info-item label="确认提醒:"><span>{{ | ||||
|                   dict.getLabel("meetingNoticeAfter", info.noticeAfter) || "-" | ||||
|                 }}</span> | ||||
|               </ai-info-item> | ||||
|             </ai-wrapper> | ||||
|             <ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="1"> | ||||
|               <ai-info-item label="会议地点:"><span>{{ info.address }}</span></ai-info-item> | ||||
|             </ai-wrapper> | ||||
|             <ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="1"> | ||||
|               <ai-info-item label="会议内容:"><span v-html="info.content"></span></ai-info-item> | ||||
|             </ai-wrapper> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|         <ai-card title="会议资料"> | ||||
|           <template slot="content"> | ||||
|             <ai-file-list :fileList="info.files" :fileOps="{name: 'name', size: 'fileSizeStr'}"></ai-file-list> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|         <ai-card title="参会名单"> | ||||
|           <template slot="content"> | ||||
|             <ai-search-bar bottomBorder> | ||||
|               <template #left> | ||||
|                 <el-select v-model="search.joinStatus" placeholder="确认状态" size="small" clearable class="vc-input-160" @change="searchMeetinguser"> | ||||
|                   <el-option | ||||
|                       v-for="(item,k) in confirmStatus" | ||||
|                       :key="k" | ||||
|                       :label="item.label" | ||||
|                       :value="k"> | ||||
|                   </el-option> | ||||
|                 </el-select> | ||||
|               </template> | ||||
|               <template #right> | ||||
|                 <!-- <ai-download :instance="instance" url="/app/appepidemicbackhomerecord/export" fileName="参会名单"> | ||||
|                   <el-button icon="iconfont iconExported">导出</el-button> | ||||
|                 </ai-download> --> | ||||
|               </template> | ||||
|             </ai-search-bar> | ||||
|             <ai-table | ||||
|                 :tableData="info.attendees" | ||||
|                 :colConfigs="colConfigs" | ||||
|                 style="margin-top: 12px;" | ||||
|                 :isShowPagination="false"> | ||||
|               <el-table-column slot="meetingUserName" | ||||
|                                label="姓名" | ||||
|                                align="center" | ||||
|                                show-overflow-tooltip> | ||||
|                 <div slot-scope="{row}"> | ||||
|                   <span>{{ row.meetingUserName }}</span> | ||||
|                 </div> | ||||
|               </el-table-column> | ||||
|  | ||||
|               <el-table-column slot="meetingUnitName" | ||||
|                                label="所属部门" | ||||
|                                align="center" | ||||
|                                show-overflow-tooltip> | ||||
|                 <div slot-scope="{row}"> | ||||
|                   <span>{{ row.meetingUnitName }}</span> | ||||
|                 </div> | ||||
|               </el-table-column> | ||||
|  | ||||
|               <el-table-column slot="joinStatus" | ||||
|                                prop="joinStatus" | ||||
|                                label="确认状态" | ||||
|                                align="center" | ||||
|                                show-overflow-tooltip> | ||||
|                 <div slot-scope="{row}"> | ||||
|                   <p style="color:rgba(255,68,102,1);display:flex;justify-content:center;" v-if="row.joinStatus==2"> | ||||
|                     请假<i class="el-icon-warning" :title="row.absence" style="cursor: pointer;"></i> | ||||
|                   </p> | ||||
|                   <span v-else :style="{color:confirmStatus[row.joinStatus].color}" | ||||
|                         v-text="confirmStatus[row.joinStatus].label"/> | ||||
|                 </div> | ||||
|               </el-table-column> | ||||
|               <el-table-column slot="option" | ||||
|                                label="操作" | ||||
|                                align="center" | ||||
|                                v-if="listType==0" | ||||
|                                show-overflow-tooltip> | ||||
|                 <div slot-scope="{row}" v-if="row.joinStatus==0"> | ||||
|                   <span class="el-icon-message-solid" style="cursor: pointer;" title="参会提醒" | ||||
|                         @click="noticeMetting(row.meetingUserId)" v-if="detail.status==1"></span> | ||||
|                 </div> | ||||
|               </el-table-column> | ||||
|             </ai-table> | ||||
|           </template> | ||||
|         </ai-card> | ||||
|       </template> | ||||
|     </ai-detail> | ||||
|   </section> | ||||
| </template> | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
|  | ||||
| export default { | ||||
|   name: 'meetingDetail', | ||||
|   inject: ['top'], | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function, | ||||
|     detail: Object, | ||||
|     listType: String | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       navId: '1', | ||||
|       info: {}, | ||||
|       total: 0, | ||||
|       writeInfo: {reason: ''}, | ||||
|       meetingUserList: [], | ||||
|       innerVisible: false, | ||||
|       search: {joinStatus: ''} | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load("meetingNoticeAfter", "meetingNoticeBefore").then(() => this.searchDetail(this.detail.id)) | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     colConfigs() { | ||||
|       return [ | ||||
|         { | ||||
|           slot: 'meetingUserName' | ||||
|         }, | ||||
|         { | ||||
|           slot: 'meetingUnitName' | ||||
|         }, | ||||
|         { | ||||
|           slot: 'joinStatus', | ||||
|         }, | ||||
|         {prop: 'signInStatus', align: 'center', label: '签到', format: v => v === '1' ? '已签到' : '未签到'}, | ||||
|         { | ||||
|           slot: 'option', | ||||
|         } | ||||
|       ] | ||||
|     }, | ||||
|     confirmStatus() { | ||||
|       return { | ||||
|         0: {label: '未确认', color: "rgba(255,136,34,1)"}, | ||||
|         1: {label: '已确认', color: "rgba(34,102,255,1)"}, | ||||
|         2: {label: '请假', color: "rgba(255,68,102,1)"}, | ||||
|         3: {label: '待定', color: "rgba(255,136,34,1)"}, | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     toDo() { | ||||
|       this.$confirm("是否确认待定会议?").then(_ => { | ||||
|         this.instance.post("/app/appmeetinginfo/tobeConfirm", null, { | ||||
|           params: { | ||||
|             meetingId: this.detail.id, | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.$message.success("会议待定"); | ||||
|             setTimeout(_ => { | ||||
|               this.$parent.goBack(); | ||||
|             }, 800) | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|     searchMeetinguser() { | ||||
|       this.instance.post(`/app/appmeetinguser/list`, null, { | ||||
|         params: {...this.search, size: 999, meetingId: this.info.id} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.info.attendees = res.data.records; | ||||
|           this.total = res.data.total; | ||||
|  | ||||
|         } | ||||
|       }); | ||||
|     }, | ||||
|     searchDetail(id) { | ||||
|       this.instance.post(`/app/appmeetinginfo/info-id`, null, { | ||||
|         params: {id} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           let {files = [], content} = res.data | ||||
|           content = content.replace(/(\r\n)|(\n)/g, "<br>") | ||||
|           this.info = {...res.data, content, files}; | ||||
|           this.searchMeetinguser() | ||||
|         } | ||||
|       }); | ||||
|     }, | ||||
|     changeMeeting(title, id) { | ||||
|       this.$confirm(title, { | ||||
|         type: 'warning' | ||||
|       }).then(() => { | ||||
|         if (title == '是否立即发布会议?') { | ||||
|           this.fbMeeting(); | ||||
|         } else if (title == '是否删除会议?') { | ||||
|           this.sdMeeting(); | ||||
|         } else if (title == '是否取消会议?') { | ||||
|           this.qxMeeting(); | ||||
|         } else if (title == '是否确认参会?') { | ||||
|           this.qrMeeting(); | ||||
|         } else if (title == '是否删除此参会人员?') { | ||||
|           this.deleteMeetingPer(id) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     deleteMeetingPer(id) { | ||||
|       this.instance.post(`/app/appmeetinguser/delete`, null, | ||||
|           { | ||||
|             params: { | ||||
|               id | ||||
|             } | ||||
|           } | ||||
|       ).then(res => { | ||||
|  | ||||
|         if (res && res.code == 0) { | ||||
|           this.$message.success("删除成功!"); | ||||
|           this.searchMeetinguser(); | ||||
|         } | ||||
|  | ||||
|       }); | ||||
|     }, | ||||
|     queMeeting(formName) { | ||||
|       this.$refs[formName].validate((valid) => { | ||||
|         if (valid) { | ||||
|           this.instance.post(`/app/appmeetinginfo/absent`, null, | ||||
|               { | ||||
|                 params: { | ||||
|                   meetingId: this.detail.id, | ||||
|                   reason: this.writeInfo.reason | ||||
|                 } | ||||
|               } | ||||
|           ).then(res => { | ||||
|  | ||||
|             if (res && res.code == 0) { | ||||
|               this.innerVisible = false; | ||||
|               this.$parent.goBack(); | ||||
|             } | ||||
|  | ||||
|           }); | ||||
|         } else { | ||||
|           return false; | ||||
|         } | ||||
|       }); | ||||
|  | ||||
|     }, | ||||
|     qrMeeting() { | ||||
|       this.instance.post(`/app/appmeetinginfo/confirm`, null, | ||||
|           { | ||||
|             params: { | ||||
|               meetingId: this.detail.id | ||||
|  | ||||
|             } | ||||
|           } | ||||
|       ).then(res => { | ||||
|  | ||||
|         if (res && res.code == 0) { | ||||
|           this.$message.success("确认参会成功!") | ||||
|           this.$parent.goBack(); | ||||
|         } | ||||
|  | ||||
|       }); | ||||
|     }, | ||||
|     noticeMetting(meetingUserId) { | ||||
|       this.instance.post(`/app/appmeetinginfo/notice`, null, { | ||||
|         params: { | ||||
|           meetingId: this.detail.id, noticeALL: !meetingUserId, meetingUserId | ||||
|         } | ||||
|       }).then(res => { | ||||
|         if (res && res.code == 0) { | ||||
|           this.$message.success("提醒成功!") | ||||
|         } | ||||
|  | ||||
|       }); | ||||
|     }, | ||||
|     fbMeeting() { | ||||
|       this.instance.post(`/app/appmeetinginfo/release`, null, | ||||
|           { | ||||
|             params: { | ||||
|               meetingId: this.detail.id | ||||
|             } | ||||
|           } | ||||
|       ).then(res => { | ||||
|  | ||||
|         if (res && res.code == 0) { | ||||
|           this.$message.success("发布成功!") | ||||
|           this.$parent.goBack(); | ||||
|         } | ||||
|  | ||||
|       }); | ||||
|  | ||||
|     }, | ||||
|     sdMeeting() { | ||||
|       this.instance.post(`/app/appmeetinginfo/delete`, null, | ||||
|           { | ||||
|             params: { | ||||
|               meetingId: this.detail.id | ||||
|             } | ||||
|           } | ||||
|       ).then(res => { | ||||
|  | ||||
|         if (res && res.code == 0) { | ||||
|           this.$message.success("删除成功!"); | ||||
|           this.$parent.goBack(); | ||||
|         } | ||||
|  | ||||
|       }); | ||||
|     }, | ||||
|     qxMeeting() { | ||||
|       this.instance.post(`/app/appmeetinginfo/cancel`, null, | ||||
|           { | ||||
|             params: { | ||||
|               meetingId: this.detail.id | ||||
|             } | ||||
|           } | ||||
|       ).then(res => { | ||||
|  | ||||
|         if (res && res.code == 0) { | ||||
|           this.$message.success("取消会议成功!"); | ||||
|           this.$parent.goBack(); | ||||
|         } | ||||
|  | ||||
|       }); | ||||
|     }, | ||||
|     editMeeting() { | ||||
|       this.$parent.goBack(); | ||||
|       this.$emit('gotoEdit', this.info) | ||||
|     }, | ||||
|   } | ||||
| } | ||||
| </script> | ||||
| <style lang="scss" scoped> | ||||
| .meetingDetail { | ||||
|   width: 100%; | ||||
|   height: 100%; | ||||
|   background: rgba(255, 255, 255, 1); | ||||
|  | ||||
|   .conference_top_area { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|   } | ||||
|  | ||||
|   .user-search { | ||||
|     width: 100%; | ||||
|     height: 48px; | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|     align-items: center; | ||||
|  | ||||
|     .float-right { | ||||
|       width: calc(100% - 200px); | ||||
|       text-align: right; | ||||
|     } | ||||
|  | ||||
|     .input-162 { | ||||
|       display: inline-block; | ||||
|       width: 162px; | ||||
|     } | ||||
|  | ||||
|   } | ||||
|  | ||||
|   .content { | ||||
|     width: 1000px; | ||||
|     height: calc(100% - 50px); | ||||
|     overflow: hidden; | ||||
|     margin: auto; | ||||
|     display: flex; | ||||
|     justify-content: space-around; | ||||
|  | ||||
|     .content-left { | ||||
|       width: 160px; | ||||
|       height: 100%; | ||||
|  | ||||
|       .content-left-nav { | ||||
|         width: 158px; | ||||
|         background-color: #ffffff; | ||||
|         border-radius: 4px; | ||||
|         border: solid 1px #eeeeee; | ||||
|         margin-top: 56px; | ||||
|         overflow: hidden; | ||||
|  | ||||
|         li { | ||||
|           height: 48px; | ||||
|           line-height: 48px; | ||||
|           padding-left: 24px; | ||||
|           font-size: 14px; | ||||
|           font-weight: normal; | ||||
|           font-stretch: normal; | ||||
|           letter-spacing: 0; | ||||
|           color: #666666; | ||||
|           cursor: pointer; | ||||
|           border-left: 3px solid transparent; | ||||
|  | ||||
|           &:hover { | ||||
|             border-left: 3px solid #5088ff; | ||||
|           } | ||||
|  | ||||
|           a { | ||||
|             display: block; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         .navActive { | ||||
|           border-left: 3px solid #5088ff; | ||||
|           color: #5088ff; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|     } | ||||
|  | ||||
|     .content-right { | ||||
|       width: 780px; | ||||
|       height: calc(100% - 80px); | ||||
|       overflow-y: auto; | ||||
|       margin-left: 40px; | ||||
|       box-sizing: border-box; | ||||
|       overflow-x: hidden; | ||||
|  | ||||
|       .content-right-title { | ||||
|         width: 780px; | ||||
|         height: 56px; | ||||
|         margin-bottom: 16px; | ||||
|         box-shadow: inset 0px -1px 0px 0px #dad5d5; | ||||
|         display: flex; | ||||
|         justify-content: space-between; | ||||
|         align-items: center; | ||||
|  | ||||
|         span { | ||||
|           display: block; | ||||
|           width: 150px; | ||||
|           height: 56px; | ||||
|           line-height: 56px; | ||||
|           color: #333333; | ||||
|           font-weight: bold; | ||||
|  | ||||
|           &:nth-of-type(2) { | ||||
|             text-align: right; | ||||
|             width: 200px; | ||||
|           } | ||||
|  | ||||
|         } | ||||
|  | ||||
|  | ||||
|       } | ||||
|  | ||||
|       .flie { | ||||
|         width: 100%; | ||||
|         height: 40px; | ||||
|         line-height: 40px; | ||||
|         padding: 0 8px; | ||||
|         box-sizing: border-box; | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         justify-content: space-between; | ||||
|         font-size: 14px; | ||||
|         color: rgba(51, 51, 51, 1); | ||||
|         background: rgba(255, 255, 255, 1); | ||||
|         border-radius: 4px; | ||||
|         border: 1px solid rgba(208, 212, 220, 1); | ||||
|         margin-bottom: 16px; | ||||
|         cursor: pointer; | ||||
|  | ||||
|         p { | ||||
|           display: flex; | ||||
|           justify-content: flex-start; | ||||
|           align-items: center | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .meeting_name { | ||||
|         width: 100%; | ||||
|         padding-bottom: 25px; | ||||
|         font-size: 16px; | ||||
|         box-shadow: inset 0px -1px 0px 0px #dad5d5; | ||||
|         position: relative; | ||||
|         overflow: hidden; | ||||
|  | ||||
|         .title { | ||||
|           color: #333333; | ||||
|           height: 28px; | ||||
|           line-height: 28px; | ||||
|           margin-left: 0; | ||||
|           font-weight: bold; | ||||
|           margin-top: 14px; | ||||
|         } | ||||
|  | ||||
|         ul { | ||||
|           overflow: hidden; | ||||
|  | ||||
|           li { | ||||
|             width: 33.3%; | ||||
|             float: left; | ||||
|             line-height: 28px; | ||||
|             font-size: 14px; | ||||
|  | ||||
|             span { | ||||
|               width: 70px; | ||||
|               display: block; | ||||
|               float: left; | ||||
|               color: rgba(153, 153, 153, 1) | ||||
|             } | ||||
|  | ||||
|             p { | ||||
|               width: calc(100% - 70px); | ||||
|               float: left; | ||||
|               color: rgba(51, 51, 51, 1); | ||||
|             } | ||||
|           ; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         .svg { | ||||
|           width: 88px; | ||||
|           height: 88px; | ||||
|           position: absolute; | ||||
|           right: -20px; | ||||
|           bottom: -20px; | ||||
|         } | ||||
|  | ||||
|       } | ||||
|  | ||||
|  | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										259
									
								
								packages/work/AppConference/list.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								packages/work/AppConference/list.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,259 @@ | ||||
| <template> | ||||
|   <ai-list isTabs> | ||||
|     <template #content> | ||||
|       <ai-search-bar> | ||||
|         <template #left> | ||||
|           <el-button type="primary" @click="addMetting()">发起会议</el-button> | ||||
|           <ai-select | ||||
|               v-model="search.meetingStatus" | ||||
|               @change="getTableData()" | ||||
|               placeholder="会议状态" | ||||
|               :selectList="dict.getDict($parent.name==0 ? 'meetingStatusSelect' : 'meetingStatus')" | ||||
|           ></ai-select> | ||||
|           <ai-select | ||||
|               v-if="$parent.name==0" | ||||
|               v-model="search.confirmStatus" | ||||
|               @change="getTableData()" | ||||
|               placeholder="确认状态" | ||||
|               :selectList="dict.getDict('confirmStatus')" | ||||
|           ></ai-select> | ||||
|         </template> | ||||
|         <template #right> | ||||
|           <el-input | ||||
|             v-model="search.param" | ||||
|             v-throttle="() => {search.current=1,getTableData()}" | ||||
|             @keyup.enter.native="search.current=1,getTableData()" | ||||
|             placeholder="会议标题/地点" | ||||
|             size="small" suffix-icon="iconfont iconSearch" clearable @clear="getTableData()"></el-input> | ||||
|         </template> | ||||
|       </ai-search-bar> | ||||
|       <div class="list_main"> | ||||
|         <div class="no-data" style="height:160px;" v-if="tableData.length==0"></div> | ||||
|         <ul v-if="tableData.length>0"> | ||||
|           <li v-for="(item,index) in tableData" :key="index" @click="goDetail(item)"> | ||||
|             <p> | ||||
|               <span class="conference_title">{{ item.title }}</span> | ||||
|               <span class="time" v-if="item.status==1">{{ item.expirationTime }}</span> | ||||
|             </p> | ||||
|             <p style="width:80%;"> | ||||
|               <el-row type="flex" align="middle" class="unit">发起人:{{ item.userName }} | ||||
|               </el-row> | ||||
|               <el-row type="flex" align="middle" class="unit">发起单位:{{ item.unitName }} | ||||
|               </el-row> | ||||
|             </p> | ||||
|             <p style="width:80%;"> | ||||
|               <span class="unit">会议时间:{{ item.startTime.substring(0, 16) + '至' + item.endTime.substring(0, 16) }}</span> | ||||
|               <el-tooltip :content="item.address" placement="top-start" effect="light"> | ||||
|                 <span class="unit" v-if="item.address.length>12">会议地点:{{ | ||||
|                     item.address.substring(0, 12) + '....' | ||||
|                   }}</span> | ||||
|                 <span class="unit" v-else>会议地点:{{ item.address }}</span> | ||||
|               </el-tooltip> | ||||
|             </p> | ||||
|             <!-- <p style="width:80%;"> | ||||
|                   <span | ||||
|                     class="unit">会议时间:{{ | ||||
|                       item.startTime.substring(0, 16) + '至' + item.endTime.substring(0, 16) | ||||
|                     }}</span> | ||||
|               <el-tooltip :content="item.address" placement="top-start" effect="light"> | ||||
|                     <span class="unit address" | ||||
|                           v-if="item.address.length>12">会议地点:{{ item.address.substring(0, 12) + '....' }}</span> | ||||
|                 <span class="unit address" v-else>会议地点:{{ item.address }}</span> | ||||
|               </el-tooltip> | ||||
|             </p> --> | ||||
|             <h5 :class="{color0:item.status==0,color1:item.status==1,color2:item.status==2,color3:item.status==3,color4:item.status==4}"> | ||||
|               <span v-if="item.status==0">草稿箱</span> | ||||
|               <span v-if="item.status==1">未开始</span> | ||||
|               <span v-if="item.status==2">进行中</span> | ||||
|               <span v-if="item.status==3">已取消</span> | ||||
|               <span v-if="item.status==4">已结束</span> | ||||
|             </h5> | ||||
|             <ai-icon class="svg" v-if="item.joinStatus==0" type="svg" icon="iconunidentified"/> | ||||
|             <ai-icon class="svg" v-else-if="item.joinStatus==1" type="svg" icon="iconidentified"/> | ||||
|             <ai-icon class="svg" v-else-if="item.joinStatus==2" type="svg" icon="iconyiqingjia"/> | ||||
|             <ai-icon class="svg" v-else-if="item.joinStatus==3" type="svg" icon="icondaiding"/> | ||||
|           </li> | ||||
|         </ul> | ||||
|       </div> | ||||
|       <div class="pagination" v-if="tableData.length>0"> | ||||
|         <el-pagination | ||||
|             @current-change="handleCurrentChange" | ||||
|             @size-change="handleSizeChange" | ||||
|             background | ||||
|             :current-page.sync="search.current" | ||||
|             :page-sizes="[5, 10, 50, 100,200]" | ||||
|             :page-size="search.size" | ||||
|             layout="total,prev, pager, next,sizes,jumper" | ||||
|             :total="total"> | ||||
|         </el-pagination> | ||||
|       </div> | ||||
|     </template> | ||||
|   </ai-list> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "list", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function, | ||||
|     listType: String | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       search: { | ||||
|         meetingStatus: '', | ||||
|         confirmStatus: '', | ||||
|         param: '', | ||||
|         current: 1, | ||||
|         size: 10, | ||||
|         listType: '' | ||||
|       }, | ||||
|       tableData: [], | ||||
|       total: 0, | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     goDetail(item) { | ||||
|       this.$emit('goPage', { | ||||
|         row: item, | ||||
|         comp: 'detail' | ||||
|       }); | ||||
|     }, | ||||
|     addMetting() { | ||||
|       this.$emit('goPage', { | ||||
|         row: {}, | ||||
|         comp: 'addMeeting' | ||||
|       }); | ||||
|     }, | ||||
|  | ||||
|     getTableData() { | ||||
|       this.instance.post(`/app/appmeetinginfo/list`, null, { | ||||
|         params: { | ||||
|           ...this.search, | ||||
|           listType: this.listType | ||||
|         } | ||||
|       }).then(res => { | ||||
|         if (res && res.data) { | ||||
|           this.tableData = res.data.records; | ||||
|           this.total = res.data.total; | ||||
|  | ||||
|         } | ||||
|       }); | ||||
|     }, | ||||
|     handleCurrentChange(val) { | ||||
|       this.search.current = val; | ||||
|       this.getTableData(); | ||||
|     }, | ||||
|     handleSizeChange(val) { | ||||
|       this.search.size = val; | ||||
|       this.getTableData(); | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load("confirmStatus", "meetingStatus", "meetingStatusSelect").then(_ => this.getTableData()) | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .list_main { | ||||
|   width: 100%; | ||||
|  | ||||
|   ul { | ||||
|     overflow: hidden; | ||||
|     padding: 0; | ||||
|     margin: 0; | ||||
|  | ||||
|     li { | ||||
|       width: 100%; | ||||
|       height: 107px; | ||||
|       background: rgba(255, 255, 255, 1); | ||||
|       border-radius: 4px; | ||||
|       border: 1px solid rgba(216, 224, 232, 1); | ||||
|       box-sizing: border-box; | ||||
|       padding: 16px 16px 16px 50px; | ||||
|       margin-top: 8px; | ||||
|       cursor: pointer; | ||||
|       position: relative; | ||||
|       overflow: hidden; | ||||
|  | ||||
|       p { | ||||
|         width: 100%; | ||||
|         height: 25px; | ||||
|         display: flex; | ||||
|         justify-content: space-between; | ||||
|         align-items: center; | ||||
|  | ||||
|         .conference_title { | ||||
|           color: rgba(51, 51, 51, 1); | ||||
|           font-size: 16px; | ||||
|           font-weight: bold; | ||||
|         } | ||||
|  | ||||
|         .time { | ||||
|           font-size: 14px; | ||||
|           color: #2266FF; | ||||
|         } | ||||
|  | ||||
|         .unit { | ||||
|           font-size: 14px; | ||||
|           width: 50%; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       h5 { | ||||
|         width: 100px; | ||||
|         height: 20px; | ||||
|         line-height: 20px; | ||||
|         text-align: center; | ||||
|         position: absolute; | ||||
|         left: -22px; | ||||
|         top: 10px; | ||||
|         box-sizing: border-box; | ||||
|         padding-right: 8px; | ||||
|         font-size: 12px; | ||||
|         transform: rotate(-45deg); | ||||
|         background: #FFF3E8; | ||||
|         color: rgba(255, 136, 34, 1); | ||||
|         box-shadow: -1px 1px 0px 0px rgba(216, 224, 232, 1), 1px -1px 0px 0px rgba(216, 224, 232, 1); | ||||
|         margin: 0; | ||||
|       } | ||||
|  | ||||
|       .color0 { | ||||
|         color: #2244FF; | ||||
|         background: #EFF6FF; | ||||
|       } | ||||
|  | ||||
|       .color1 { | ||||
|         background: #FFF3E8; | ||||
|         color: rgba(255, 136, 34, 1); | ||||
|       } | ||||
|  | ||||
|       .color2 { | ||||
|         background: #EFF6FF; | ||||
|         color: #2266FF; | ||||
|       } | ||||
|  | ||||
|       .color3 { | ||||
|         background-color: #D8E0E8; | ||||
|         color: #999999; | ||||
|       } | ||||
|  | ||||
|       .color4 { | ||||
|         color: #2EA222; | ||||
|         background-color: #D8E0E8; | ||||
|       } | ||||
|  | ||||
|       .svg { | ||||
|         width: 88px; | ||||
|         height: 88px; | ||||
|         position: absolute; | ||||
|         right: -20px; | ||||
|         bottom: -20px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @@ -0,0 +1,186 @@ | ||||
| <template> | ||||
|   <section class="AppCorporateSeal"> | ||||
|       <ai-list v-if="showList"> | ||||
|         <template slot="title"> | ||||
|           <ai-title title="企业印章" :isShowBottomBorder="true"></ai-title> | ||||
|         </template> | ||||
|         <template slot="content"> | ||||
|           <div class="signaturePane"> | ||||
|             <div class="signatureCard" v-for="(op,i) in signatures" :key="i"> | ||||
|               <div class="default" v-if="op.isDefault==1">默认</div> | ||||
|               <div class="body"> | ||||
|                 <el-image :src="`data:image/png;base64,${op.signSealData}`"/> | ||||
|               </div> | ||||
|               <div class="footer"> | ||||
|                 <el-button type="text" :disabled="op.isDefault==1" @click.stop="handleSetDefault(op.id)">设为默认</el-button> | ||||
|                 <hr/> | ||||
|                 <el-button type="text" :disabled="op.isDefault==1||op.signType==1" @click.stop="handleDelete(op.id)">删除 | ||||
|                 </el-button> | ||||
|               </div> | ||||
|             </div> | ||||
|             <div class="signatureCard add" @click="showList=false"> | ||||
|               <ai-icon icon="iconAdd" size="32px"/> | ||||
|               <span>点击添加印章</span> | ||||
|             </div> | ||||
|           </div> | ||||
|         </template> | ||||
|       </ai-list> | ||||
|     <seal-detail v-else/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import SealDetail from "./sealDetail"; | ||||
|  | ||||
|   export default { | ||||
|     name: "AppCorporateSeal", | ||||
|     label: "企业印章", | ||||
|     components: {SealDetail}, | ||||
|     provide() { | ||||
|       return { | ||||
|         seal: this | ||||
|       } | ||||
|     }, | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       permissions: Function | ||||
|     }, | ||||
|     data() { | ||||
|       return { | ||||
|         signatures: [], | ||||
|         showList: true | ||||
|       } | ||||
|     }, | ||||
|     created() { | ||||
|       this.getSignatures() | ||||
|     }, | ||||
|     methods: { | ||||
|       getSignatures() { | ||||
|         this.instance.post("/app/syssignaccount/list", null, { | ||||
|           params: { | ||||
|             signType: 2, | ||||
|             size: 999 | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res?.data) { | ||||
|             this.signatures = res.data.records | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|       handleSetDefault(id) { | ||||
|         this.$confirm("是否设置该印章为默认印章?").then(() => { | ||||
|           this.instance.post("/app/syssignaccount/default", null, {params: {id, listType: 1}}).then(res => { | ||||
|             if (res?.code == 0) { | ||||
|               this.$message.success("设置成功!") | ||||
|               this.getSignatures() | ||||
|             } | ||||
|           }).catch(() => 0) | ||||
|         }) | ||||
|       }, | ||||
|       handleDelete(ids) { | ||||
|         this.$confirm("是否删除该印章?").then(() => { | ||||
|           this.instance.post("/app/syssignaccount/delete", null, {params: {ids}}).then(res => { | ||||
|             if (res?.code == 0) { | ||||
|               this.$message.success("删除成功!") | ||||
|               this.getSignatures() | ||||
|             } | ||||
|           }).catch(() => 0) | ||||
|         }) | ||||
|       }, | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .AppCorporateSeal { | ||||
|     height: 100%; | ||||
|     background: #f3f6f9; | ||||
|  | ||||
|     :deep( .signaturePane ){ | ||||
|       display: flex; | ||||
|       gap: 16px; | ||||
|       flex-wrap: wrap; | ||||
|       padding: 16px; | ||||
|  | ||||
|       .signatureCard { | ||||
|         width: 290px; | ||||
|         height: 258px; | ||||
|         background: #FFFFFF; | ||||
|         border-radius: 4px; | ||||
|         position: relative; | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         overflow: hidden; | ||||
|  | ||||
|         &.add { | ||||
|           justify-content: center; | ||||
|           align-items: center; | ||||
|           color: #666666; | ||||
|           cursor: pointer; | ||||
|  | ||||
|           .AiIcon { | ||||
|             width: 32px; | ||||
|             height: 32px; | ||||
|             font-size: 32px; | ||||
|           } | ||||
|  | ||||
|           & > span { | ||||
|             font-size: 12px; | ||||
|             line-height: 16px; | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         .default { | ||||
|           position: absolute; | ||||
|           width: 56px; | ||||
|           height: 24px; | ||||
|           background: #3573FF; | ||||
|           border-radius: 0 0 4px 0; | ||||
|           top: 0; | ||||
|           left: 0; | ||||
|           text-align: center; | ||||
|           line-height: 24px; | ||||
|           font-size: 12px; | ||||
|           color: #FFF; | ||||
|         } | ||||
|  | ||||
|         .body { | ||||
|           min-height: 0; | ||||
|           flex: 1; | ||||
|           display: flex; | ||||
|           justify-content: center; | ||||
|           align-items: center; | ||||
|           padding: 50px; | ||||
|           cursor: pointer; | ||||
|  | ||||
|         } | ||||
|  | ||||
|         .footer { | ||||
|           flex-shrink: 0; | ||||
|           height: 40px; | ||||
|           background: rgba(#30426F, .5); | ||||
|           display: flex; | ||||
|           align-items: center; | ||||
|           padding: 8px 0; | ||||
|           box-sizing: border-box; | ||||
|  | ||||
|           hr { | ||||
|             height: 100%; | ||||
|             border-color: rgba(#fff, .5); | ||||
|           } | ||||
|  | ||||
|           & > .el-button { | ||||
|             flex: 1; | ||||
|             color: #fff; | ||||
|  | ||||
|             &[disabled] { | ||||
|               color: rgba(#fff, .5); | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
| </style> | ||||
							
								
								
									
										235
									
								
								packages/work/processManagement/corporateSeal/sealDetail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								packages/work/processManagement/corporateSeal/sealDetail.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,235 @@ | ||||
| <template> | ||||
|   <section class="sealDetail"> | ||||
|     <ai-detail> | ||||
|       <template #title> | ||||
|         <ai-title title="添加企业印章" isShowBack isShowBottomBorder @onBackClick="back"/> | ||||
|       </template> | ||||
|       <template #content> | ||||
|         <el-form size="small" ref="SealForm" :model="form" :rules="rules" label-suffix=":" label-width="160px"> | ||||
|           <ai-title title="单位信息" isShowBottomBorder/> | ||||
|           <el-form-item label="单位名称" prop="organizeName"> | ||||
|             <el-input clearable v-model="form.organizeName" placeholder="请输入..." maxlength="25" show-word-limit/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="单位类型" prop="organizeType"> | ||||
|             <el-select clearable v-model="form.organizeType" placeholder="请输入..."> | ||||
|               <el-option v-for="(op,i) in $dict.getDict('organizeType')" :key="i" :value="op.dictValue" | ||||
|                          :label="op.dictName"/> | ||||
|             </el-select> | ||||
|           </el-form-item> | ||||
|           <div class="flexFillRow"> | ||||
|             <el-form-item label="企业注册类型" prop="organRegType"> | ||||
|               <el-select clearable v-model="form.organRegType" placeholder="请输入..."> | ||||
|                 <el-option v-for="(op,i) in $dict.getDict('organRegType')" :key="i" :value="op.dictValue" | ||||
|                            :label="op.dictName"/> | ||||
|               </el-select> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="!!form.organRegType" :label="$dict.getLabel('organRegType',form.organRegType)" | ||||
|                           prop="organCode"> | ||||
|               <el-input clearable v-model="form.organCode" placeholder="请输入..."/> | ||||
|             </el-form-item> | ||||
|             <div v-else/> | ||||
|           </div> | ||||
|           <div class="flexFillRow"> | ||||
|             <el-form-item label="注册类型" prop="registerType"> | ||||
|               <el-select clearable v-model="form.registerType" placeholder="请输入..."> | ||||
|                 <el-option v-for="(op,i) in $dict.getDict('registerType')" :key="i" :value="op.dictValue" | ||||
|                            :label="op.dictName"/> | ||||
|               </el-select> | ||||
|             </el-form-item> | ||||
|             <div/> | ||||
|           </div> | ||||
|           <template v-if="form.registerType==1"> | ||||
|             <div class="flexFillRow"> | ||||
|               <el-form-item label="代理人姓名" prop="agentName"> | ||||
|                 <el-input clearable v-model="form.agentName" placeholder="请输入..."/> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="代理人身份证号" prop="agentIdNumber"> | ||||
|                 <el-input clearable v-model="form.agentIdNumber" placeholder="请输入..."/> | ||||
|               </el-form-item> | ||||
|             </div> | ||||
|             <div class="flexFillRow"> | ||||
|               <el-form-item label="代理人手机号" prop="signPhone"> | ||||
|                 <el-input clearable v-model="form.signPhone" placeholder="请输入..."/> | ||||
|               </el-form-item> | ||||
|               <div/> | ||||
|             </div> | ||||
|           </template> | ||||
|           <template v-if="form.registerType==2"> | ||||
|             <div class="flexFillRow"> | ||||
|               <el-form-item label="法人姓名" prop="legalName"> | ||||
|                 <el-input clearable v-model="form.legalName" placeholder="请输入..."/> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="法人身份证号" prop="legalIdNumber"> | ||||
|                 <el-input clearable v-model="form.legalIdNumber" placeholder="请输入..."/> | ||||
|               </el-form-item> | ||||
|             </div> | ||||
|             <div class="flexFillRow"> | ||||
|               <el-form-item label="法人手机号" prop="signPhone"> | ||||
|                 <el-input clearable v-model="form.signPhone" placeholder="请输入..."/> | ||||
|               </el-form-item> | ||||
|               <div/> | ||||
|             </div> | ||||
|           </template> | ||||
|           <ai-title title="印章信息" isShowBottomBorder/> | ||||
|           <el-form-item class="sealImageTypes" label="生成印章类型" prop="organizeTemplateType"> | ||||
|             <div v-for="(op,i) in sealImageTypes" :key="i" class="item" @click="form.organizeTemplateType=op.value"> | ||||
|               <el-image :src="op.image" fit="contain"/> | ||||
|               <el-radio :label="op.value" v-model="form.organizeTemplateType">{{ op.name }}</el-radio> | ||||
|             </div> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="横向文内容" prop="htext"> | ||||
|             <el-input clearable v-model="form.htext" placeholder="0-8个字,如合同专用章,财务专用章等" maxlength="8" show-word-limit/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="下弦文内容" prop="qtext"> | ||||
|             <el-input clearable v-model="form.qtext" placeholder="0-20个字,下弦文是指的贵司公章底部一串防伪数字" maxlength="20" | ||||
|                       show-word-limit/> | ||||
|           </el-form-item> | ||||
|         </el-form> | ||||
|       </template> | ||||
|       <template #footer> | ||||
|         <el-button @click="back">取消</el-button> | ||||
|         <el-button type="primary" @click="handleSubmit" v-loading="loading">提交</el-button> | ||||
|       </template> | ||||
|     </ai-detail> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {ID} from "dui/lib/js/utils"; | ||||
|  | ||||
| export default { | ||||
|   name: "sealDetail", | ||||
|   inject: ['seal'], | ||||
|   data() { | ||||
|     return { | ||||
|       form: { | ||||
|         organizeTemplateType: "STAR", | ||||
|         organizeType: "4", | ||||
|         organRegType: "NORMAL", | ||||
|         registerType: "1" | ||||
|       }, | ||||
|       loading: false | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     sealImageTypes() { | ||||
|       return this.$dict.getDict("organizeTemplateType")?.map(e => ({ | ||||
|         image: e.dictColor, | ||||
|         value: e.dictValue, | ||||
|         name: e.dictName | ||||
|       })) || [] | ||||
|     }, | ||||
|     rules() { | ||||
|       return { | ||||
|         organizeName: [{required: true, message: "请填写单位名称"}], | ||||
|         organCode: [{required: true, message: `请填写${this.$dict.getLabel('organRegType', this.form.organRegType)}`}], | ||||
|         legalName: [{required: true, message: "请填写法人姓名"}], | ||||
|         agentName: [{required: true, message: "请填写代理人姓名"}], | ||||
|         organizeTemplateType: [{required: true}], | ||||
|         htext: [{required: true, message: "请填写横向文内容"}], | ||||
|         qtext: [{required: true, message: "请填写下弦文内容"}], | ||||
|         organizeType: [{required: true, message: "请选择单位类型"}], | ||||
|         organRegType: [{required: true, message: "请选择企业注册类型"}], | ||||
|         registerType: [{required: true, message: "请选择注册类型"}], | ||||
|         signPhone: [ | ||||
|           {required: true, message: "请填写手机号码"}, | ||||
|           {pattern: /^1[3456789]\d{9}$/, message: "手机号码格式有误"} | ||||
|         ], | ||||
|         legalIdNumber: [ | ||||
|           {required: true, message: "请填写法人身份证号码"}, | ||||
|           {validator: (r, v, cb) => cb(ID.check(v) ? undefined : "身份证号码格式有误")} | ||||
|         ], | ||||
|         agentIdNumber: [ | ||||
|           {required: true, message: "请填写代理人身份证号码"}, | ||||
|           {validator: (r, v, cb) => cb(ID.check(v) ? undefined : "身份证号码格式有误")} | ||||
|         ], | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.$dict.load("registerType", "organRegType", "organizeType", "organizeTemplateType") | ||||
|   }, | ||||
|   methods: { | ||||
|     back() { | ||||
|       this.seal.showList = true | ||||
|       this.seal.getSignatures() | ||||
|     }, | ||||
|     handleSubmit() { | ||||
|       this.$refs.SealForm.validate(v => { | ||||
|         if (v) { | ||||
|           this.loading = true | ||||
|           this.seal.instance.post("/app/syssignaccount/register", { | ||||
|             userType: 0, | ||||
|             signType: 2, | ||||
|             signPhone: this.form.signPhone, | ||||
|             registerInfo: {...this.form, legalArea: 0}, | ||||
|             style: {...this.form, sealColor: "RED"} | ||||
|           }).then(res => { | ||||
|             this.loading = false | ||||
|             if (res?.code == 0) { | ||||
|               this.$message.success("添加成功!") | ||||
|               this.back() | ||||
|             } | ||||
|           }).catch(() => this.loading = false) | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .sealDetail { | ||||
|   height: inherit; | ||||
|  | ||||
|   :deep( .ai-detail__content--wrapper ){ | ||||
|     .el-form { | ||||
|       display: flex; | ||||
|       flex-direction: column; | ||||
|       gap: 24px; | ||||
|     } | ||||
|  | ||||
|     .el-form-item { | ||||
|       margin-bottom: 0; | ||||
|  | ||||
|       .el-select { | ||||
|         width: 100%; | ||||
|       } | ||||
|  | ||||
|       &.sealImageTypes > .el-form-item__content { | ||||
|         display: flex; | ||||
|         gap: 40px; | ||||
|  | ||||
|         .item { | ||||
|           display: flex; | ||||
|           flex-direction: column; | ||||
|           align-items: center; | ||||
|           justify-content: center; | ||||
|           gap: 8px; | ||||
|           cursor: pointer; | ||||
|  | ||||
|           .el-image { | ||||
|             width: 80px; | ||||
|             height: 80px; | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .flexFillRow { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|  | ||||
|       & > * { | ||||
|         flex: 1; | ||||
|         min-width: 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   :deep( .ai-detail__footer > .el-button ){ | ||||
|     width: 92px; | ||||
|     height: 32px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @@ -0,0 +1,365 @@ | ||||
| <template> | ||||
|   <section class="personal-signature"> | ||||
|     <ai-list v-if="!showPhonePage"> | ||||
|       <ai-title slot="title" title="个人签名" :isShowBottomBorder="false"/> | ||||
|       <template #custom> | ||||
|         <div class="signaturePane"> | ||||
|           <div class="signatureCard" v-for="(op,i) in signatures" :key="i"> | ||||
|             <div class="default" v-if="op.isDefault==1">默认</div> | ||||
|             <div class="body"> | ||||
|               <el-image :src="`data:image/png;base64,${op.signSealData}`"/> | ||||
|             </div> | ||||
|             <div class="footer"> | ||||
|               <el-button type="text" :disabled="op.isDefault==1" @click.stop="handleSetDefault(op.id)">设为默认</el-button> | ||||
|               <hr/> | ||||
|               <el-button type="text" :disabled="op.isDefault==1||op.signType>0" @click.stop="handleDelete(op.id)">删除 | ||||
|               </el-button> | ||||
|             </div> | ||||
|           </div> | ||||
|           <div class="signatureCard add" @click="dialog=true"> | ||||
|             <ai-icon icon="iconAdd" size="32px"/> | ||||
|             <span>点击添加签名</span> | ||||
|           </div> | ||||
|         </div> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|     <ai-dialog :visible.sync="dialog" v-bind="dialogConf" @onConfirm="handleSubmit" | ||||
|                @closed="form={},drawPlaceholder=true,qrCode=null,showQRCode=false,getSignatures()"> | ||||
|       <ai-drawer v-if="hasAuthed" :seal.sync="sealData" ref="aiDrawer"> | ||||
|         <template #tools> | ||||
|           <el-popover trigger="manual" v-model="showQRCode"> | ||||
|             <el-image :src="qrCode"/> | ||||
|             <div class="writeInPhone" slot="reference" @click.stop="showQR"> | ||||
|               <ai-icon icon="iconEwm"/> | ||||
|               <span>手机签名</span> | ||||
|             </div> | ||||
|           </el-popover> | ||||
|         </template> | ||||
|       </ai-drawer> | ||||
|       <el-form size="small" :model="form" ref="authForm" :rules="rules" class="authZone" v-else label-suffix=":" | ||||
|                label-width="100px"> | ||||
|         <el-alert type="warning" title="第一次添加个人签名,需先进行实名认证" show-icon :closable="false"/> | ||||
|         <el-form-item label="姓名" prop="personName"> | ||||
|           <el-input v-model="form.personName" clearable placeholder="姓名"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="身份证号" prop="idNumber"> | ||||
|           <el-input v-model="form.idNumber" clearable placeholder="身份证号"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="手机号码" prop="signPhone"> | ||||
|           <el-input v-model="form.signPhone" clearable placeholder="手机号码"/> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|     </ai-dialog> | ||||
|     <draw-in-phone v-if="showPhonePage"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
| import DrawInPhone from "./drawInPhone"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppPersonalSignature", | ||||
|   label: "个人签名", | ||||
|   components: {DrawInPhone}, | ||||
|   provide() { | ||||
|     return { | ||||
|       signature: this | ||||
|     } | ||||
|   }, | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     hasAuthed() { | ||||
|       return this.signatures.length > 0 | ||||
|     }, | ||||
|     dialogConf() { | ||||
|       return this.hasAuthed ? { | ||||
|         title: "手写签名", | ||||
|         width: '720px' | ||||
|       } : { | ||||
|         title: "实名认证", | ||||
|         width: '520px' | ||||
|       } | ||||
|     }, | ||||
|     rules() { | ||||
|       return { | ||||
|         personName: [{required: true, message: "请填写姓名"}], | ||||
|         signPhone: [ | ||||
|           {required: true, message: "请填写手机号码"}, | ||||
|           {pattern: /^1[3456789]\d{9}$/, message: "手机号码格式有误"} | ||||
|         ], | ||||
|         idNumber: [ | ||||
|           {required: true, message: "请填写身份证号码"}, | ||||
|           {validator: (r, v, cb) => cb(ID.check(v) ? undefined : "身份证号码格式有误")} | ||||
|         ], | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       signatures: [], | ||||
|       dialog: false, | ||||
|       form: {}, | ||||
|       sealData: null, | ||||
|       qrCode: null, | ||||
|       showQRCode: false, | ||||
|       showPhonePage: false, | ||||
|       loading: false, | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     if (this.$route.query.userId && this.$route.hash == "#phone") { | ||||
|       this.showPhonePage = true | ||||
|     } else { | ||||
|       this.getSignatures() | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     getSignatures() { | ||||
|       this.instance.post("/app/syssignaccount/list", null, { | ||||
|         params: { | ||||
|           size: 999 | ||||
|         } | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.signatures = res.data.records | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     handleSubmit() { | ||||
|       if (this.loading) return | ||||
|       if (this.hasAuthed && this.$refs['aiDrawer'].drawPlaceholder) return this.$message.error("请签名") | ||||
|       this.loading = true | ||||
|       if (this.hasAuthed) { | ||||
|         let sealData = this.sealData?.replace(/data:image\/png;base64,/, '') | ||||
|         sealData && this.instance({ | ||||
|           url: '/app/syssignaccount/upload-sealdata', | ||||
|           headers: {"Content-Type": "application/json"}, | ||||
|           method: 'post', | ||||
|           params: {userId: this.user.info.id}, | ||||
|           data: sealData | ||||
|         }).then(res => { | ||||
|           this.loading = false | ||||
|           if (res?.code == 0) { | ||||
|             this.dialog = false | ||||
|             this.$message.success("添加成功!") | ||||
|             this.getSignatures() | ||||
|           } | ||||
|         }).catch(() => { | ||||
|           this.loading = false | ||||
|         }) | ||||
|       } else { | ||||
|         this.$refs.authForm.validate(v => { | ||||
|           if (v) { | ||||
|             this.instance.post("/app/syssignaccount/register", { | ||||
|               signPhone: this.form.signPhone, | ||||
|               signType: 1, | ||||
|               userType: 0, | ||||
|               registerInfo: {...this.form}, | ||||
|               style: {personTemplateType: 'RECTANGLE', sealColor: 'RED'} | ||||
|             }).then(res => { | ||||
|               this.loading = false | ||||
|               if (res?.code == 0) { | ||||
|                 this.dialog = false | ||||
|                 this.$message.success("认证成功!") | ||||
|                 this.getSignatures() | ||||
|               } | ||||
|             }).catch(() => { | ||||
|               this.loading = false | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     }, | ||||
|     handleSetDefault(id) { | ||||
|       this.$confirm("是否设置该签名为默认签名?").then(() => { | ||||
|         this.instance.post("/app/syssignaccount/default", null, {params: {id, listType: 0}}).then(res => { | ||||
|           if (res?.code == 0) { | ||||
|             this.$message.success("设置成功!") | ||||
|             this.getSignatures() | ||||
|           } | ||||
|         }).catch(() => 0) | ||||
|       }) | ||||
|     }, | ||||
|     handleDelete(ids) { | ||||
|       this.$confirm("是否删除该签名?").then(() => { | ||||
|         this.instance.post("/app/syssignaccount/delete", null, {params: {ids}}).then(res => { | ||||
|           if (res?.code == 0) { | ||||
|             this.$message.success("删除成功!") | ||||
|             this.getSignatures() | ||||
|           } | ||||
|         }).catch(() => 0) | ||||
|       }) | ||||
|     }, | ||||
|     showQR() { | ||||
|       if (!this.qrCode) { | ||||
|         let url = `${location.href}?userId=${this.user.info.id}#phone` | ||||
|         this.instance.post("/app/syssignaccount/draw-qrcode", null, { | ||||
|           params: {url} | ||||
|         }).then(res => { | ||||
|           if (res?.data) { | ||||
|             this.showQRCode = true | ||||
|             this.qrCode = res.data | ||||
|           } | ||||
|         }) | ||||
|       } else { | ||||
|         this.showQRCode = !this.showQRCode | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .personal-signature { | ||||
|   height: 100%; | ||||
|   background: #f3f6f9; | ||||
|   overflow: auto; | ||||
|  | ||||
|   :deep( .signaturePane ){ | ||||
|     display: flex; | ||||
|     gap: 16px; | ||||
|     flex-wrap: wrap; | ||||
|     padding: 16px; | ||||
|  | ||||
|     .signatureCard { | ||||
|       width: 290px; | ||||
|       height: 258px; | ||||
|       background: #FFFFFF; | ||||
|       border-radius: 4px; | ||||
|       position: relative; | ||||
|       display: flex; | ||||
|       flex-direction: column; | ||||
|       overflow: hidden; | ||||
|  | ||||
|       &.add { | ||||
|         justify-content: center; | ||||
|         align-items: center; | ||||
|         color: #666666; | ||||
|         cursor: pointer; | ||||
|  | ||||
|         .AiIcon { | ||||
|           width: 32px; | ||||
|           height: 32px; | ||||
|           font-size: 32px; | ||||
|         } | ||||
|  | ||||
|         & > span { | ||||
|           font-size: 12px; | ||||
|           line-height: 16px; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .default { | ||||
|         position: absolute; | ||||
|         width: 56px; | ||||
|         height: 24px; | ||||
|         background: #3573FF; | ||||
|         border-radius: 0 0 4px 0; | ||||
|         top: 0; | ||||
|         left: 0; | ||||
|         text-align: center; | ||||
|         line-height: 24px; | ||||
|         font-size: 12px; | ||||
|         color: #FFF; | ||||
|       } | ||||
|  | ||||
|       .body { | ||||
|         min-height: 0; | ||||
|         flex: 1; | ||||
|         display: flex; | ||||
|         justify-content: center; | ||||
|         align-items: center; | ||||
|         padding: 25px; | ||||
|         pointer-events: none; | ||||
|  | ||||
|         .el-image { | ||||
|           width: 100%; | ||||
|           height: 100% | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .footer { | ||||
|         flex-shrink: 0; | ||||
|         height: 40px; | ||||
|         background: rgba(#30426F, .5); | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         padding: 8px 0; | ||||
|         box-sizing: border-box; | ||||
|  | ||||
|         hr { | ||||
|           height: 100%; | ||||
|           border-color: rgba(#fff, .5); | ||||
|         } | ||||
|  | ||||
|         & > .el-button { | ||||
|           flex: 1; | ||||
|           color: #fff; | ||||
|  | ||||
|           &[disabled] { | ||||
|             color: rgba(#fff, .5); | ||||
|           } | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   :deep( .writeInPhone ){ | ||||
|     position: absolute; | ||||
|     width: 100px; | ||||
|     height: 32px; | ||||
|     background: rgba(#000, .5); | ||||
|     border-radius: 16px; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: center; | ||||
|     gap: 4px; | ||||
|     color: rgba(#fff, .6); | ||||
|     cursor: pointer; | ||||
|     left: 16px; | ||||
|     top: 16px; | ||||
|  | ||||
|     .AiIcon { | ||||
|       width: auto; | ||||
|       height: auto; | ||||
|     } | ||||
|  | ||||
|     &:hover { | ||||
|       color: #fff; | ||||
|     } | ||||
|   } | ||||
|   :deep( .ai-dialog__wrapper ){ | ||||
|     .ai-dialog__content--wrapper { | ||||
|       padding-right: 0 !important; | ||||
|     } | ||||
|  | ||||
|     .el-dialog__body { | ||||
|       padding: 24px 0; | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
|     .authZone { | ||||
|       padding: 0 16px 24px; | ||||
|       width: 100%; | ||||
|       box-sizing: border-box; | ||||
|       display: flex; | ||||
|       flex-direction: column; | ||||
|       gap: 24px; | ||||
|  | ||||
|       .el-alert { | ||||
|         border: 1px solid #FF8822; | ||||
|       } | ||||
|  | ||||
|       .el-form-item { | ||||
|         margin-bottom: 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
| @@ -0,0 +1,110 @@ | ||||
| <template> | ||||
|   <section class="drawInPhone" @touchmove.prevent> | ||||
|     <div class="endPage" v-if="finished">操作结束请关闭页面</div> | ||||
|     <ai-drawer :seal.sync="sealData" placeholder="请签名" :width="device.width" :height="device.height"> | ||||
|       <template #tools> | ||||
|         <div class="writeInPhone" slot="reference" @click.stop="handleSubmit"> | ||||
|           <ai-icon icon="iconPublish"/> | ||||
|           <span>提交</span> | ||||
|         </div> | ||||
|       </template> | ||||
|     </ai-drawer> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| export default { | ||||
|   name: "drawInPhone", | ||||
|   inject: ['signature'], | ||||
|   data() { | ||||
|     return { | ||||
|       sealData: null, | ||||
|       device: {width: 0, height: 0}, | ||||
|       finished: false | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.device.width = document.body.clientWidth | ||||
|     this.device.height = document.body.clientHeight | ||||
|     window.onresize = () => { | ||||
|       this.device.width = document.body.clientWidth | ||||
|       this.device.height = document.body.clientHeight | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     handleSubmit() { | ||||
|       let sealData = this.sealData?.replace(/data:image\/png;base64,/, ''), | ||||
|           {userId} = this.$route.query | ||||
|       if (!userId) return alert("缺少必要参数") | ||||
|       sealData && this.signature.instance({ | ||||
|         url: '/app/syssignaccount/upload-sealdata', | ||||
|         headers: {"Content-Type": "application/json"}, | ||||
|         method: 'post', | ||||
|         params: {userId}, | ||||
|         data: sealData, | ||||
|         withoutToken: true | ||||
|       }).then(res => { | ||||
|         if (res?.code == 0) { | ||||
|           alert("添加成功!") | ||||
|           this.finished = true | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .drawInPhone { | ||||
|   position: fixed; | ||||
|   left: 0; | ||||
|   right: 0; | ||||
|   top: 0; | ||||
|   bottom: 0; | ||||
|   z-index: 20210205932; | ||||
|  | ||||
|   .endPage { | ||||
|     position: fixed; | ||||
|     left: 0; | ||||
|     right: 0; | ||||
|     top: 0; | ||||
|     bottom: 0; | ||||
|     z-index: 20210205933; | ||||
|     background: rgba(#000, .8); | ||||
|     color: #999; | ||||
|     display: flex; | ||||
|     justify-content: center; | ||||
|     align-items: center; | ||||
|     font-size: 32px; | ||||
|   } | ||||
|  | ||||
|   .AiDrawer { | ||||
|     margin: 0; | ||||
|   } | ||||
|  | ||||
|   .writeInPhone { | ||||
|     position: absolute; | ||||
|     width: 72px; | ||||
|     height: 32px; | ||||
|     background: rgba(#000, .5); | ||||
|     border-radius: 16px; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: center; | ||||
|     gap: 4px; | ||||
|     color: rgba(#fff, .6); | ||||
|     cursor: pointer; | ||||
|     left: 16px; | ||||
|     top: 16px; | ||||
|  | ||||
|     .AiIcon { | ||||
|       width: auto; | ||||
|       height: auto; | ||||
|     } | ||||
|  | ||||
|     &:hover { | ||||
|       color: #fff; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										66
									
								
								packages/wxwork/AppBuddyMessage/AppBuddyMessage.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								packages/wxwork/AppBuddyMessage/AppBuddyMessage.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| <template> | ||||
|   <div class="doc-circulation ailist-wrapper"> | ||||
|     <keep-alive :include="['List']"> | ||||
|       <component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component> | ||||
|     </keep-alive> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import List from './components/List' | ||||
|   import Add from './components/Add' | ||||
|  | ||||
|   export default { | ||||
|     name: 'AppBuddyMessage', | ||||
|     label: '好友欢迎语', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         component: 'List', | ||||
|         params: {}, | ||||
|         include: [] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     components: { | ||||
|       Add, | ||||
|       List | ||||
|     }, | ||||
|  | ||||
|     mounted () { | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       onChange (data) { | ||||
|         if (data.type === 'Add') { | ||||
|           this.component = 'Add' | ||||
|           this.params = data.params | ||||
|         } | ||||
|  | ||||
|         if (data.type === 'list') { | ||||
|           this.component = 'List' | ||||
|           this.params = data.params | ||||
|  | ||||
|           this.$nextTick(() => { | ||||
|             if (data.isRefresh) { | ||||
|               this.$refs.component.getList() | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
|   .doc-circulation { | ||||
|     height: 100%; | ||||
|     background: #F3F6F9; | ||||
|     overflow: auto; | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										380
									
								
								packages/wxwork/AppBuddyMessage/components/Add.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										380
									
								
								packages/wxwork/AppBuddyMessage/components/Add.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,380 @@ | ||||
| <template> | ||||
|   <ai-detail> | ||||
|     <template slot="title"> | ||||
|       <ai-title title="新建欢迎语" isShowBack isShowBottomBorder @onBackClick="cancel(false)"></ai-title> | ||||
|     </template> | ||||
|  | ||||
|     <template slot="content"> | ||||
|       <ai-card> | ||||
|         <template #title> | ||||
|           <div class="ai-card__title"> | ||||
|             <h2>基本信息</h2> | ||||
|             <span>*一个成员如果被设置了多个欢迎语,将会使用最新设置或修改的欢迎语</span> | ||||
|           </div> | ||||
|         </template> | ||||
|  | ||||
|         <template #content> | ||||
|           <el-form class="ai-form" :rules="rules" ref="userForm" :model="form" label-width="100px" label-position="right"> | ||||
|             <el-form-item label="使用成员" prop="users" style="width: 100%"> | ||||
|               <el-input v-model="users" placeholder="请选择使用成员" disabled style="width: 100%"> | ||||
|                 <template #append> | ||||
|                   <ai-user-selecter refs="addTags" :instance="instance" v-model="form.users"> | ||||
|                     <el-button size="small">选择</el-button> | ||||
|                   </ai-user-selecter> | ||||
|                 </template> | ||||
|               </el-input> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </template> | ||||
|       </ai-card> | ||||
|  | ||||
|       <ai-card title="发送欢迎语"> | ||||
|         <template #content> | ||||
|           <el-form class="ai-form" ref="form" :model="form" label-width="110px" label-position="right"> | ||||
|             <el-form-item class="el-form-item__textarea" label="文本内容" prop="explain" style="width: 100%"> | ||||
|               <span @click="insertNickname" class="el-form-item__btn" type="text">[插入居民昵称]</span> | ||||
|               <el-input type="textarea" placeholder="请输入…" v-model="form.content" maxlength="1000" :rows="5" show-word-limit></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="其他类型" prop="explain" style="width: 100%"> | ||||
|               <el-radio-group v-model="form.type" @change="onTypeChange"> | ||||
|                 <el-radio label="image">图片</el-radio> | ||||
|                 <el-radio label="link">链接</el-radio> | ||||
|                 <el-radio label="video">视频</el-radio> | ||||
|                 <el-radio label="miniapp">小程序</el-radio> | ||||
|               </el-radio-group> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="图片" prop="files" style="width: 100%" v-if="form.type === 'image'"> | ||||
|               <ai-uploader :instance="instance" isWechat v-model="form.files" :limit="1" url="/app/wxcp/upload/uploadFile?type=image"></ai-uploader> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="链接" prop="linkUrl" style="width: 100%" v-if="form.type === 'link'"> | ||||
|               <el-input placeholder="链接地址请以http或https开头" :rows="2" type="textarea" v-model="form.linkUrl"></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="链接图片地址" prop="picUrl" style="width: 100%" v-if="form.type === 'link'"> | ||||
|               <ai-uploader :instance="instance" v-model="form.picUrl" :limit="1"></ai-uploader> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="链接标题" prop="title" style="width: 100%" v-if="form.type === 'link'"> | ||||
|               <el-input placeholder="请输入链接标题" v-model="form.title"></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="视频" prop="files" style="width: 100%" v-if="form.type === 'video'"> | ||||
|               <ai-uploader :instance="instance" fileType="file" isWechat acceptType=".mp4" v-model="form.files" :limit="1" url="/app/wxcp/upload/uploadFile?type=video"></ai-uploader> | ||||
|             </el-form-item> | ||||
|             <!-- <el-form-item label="小程序" prop="applets" style="width: 100%" v-if="form.type === 'miniapp'"> | ||||
|               <el-radio-group v-model="form.applets"> | ||||
|                 <div class="appletss"> | ||||
|                   <div class="applets-item" @click="form.applets = '0'" :class="[form.applets === '0' ? 'applets-active' : '']"> | ||||
|                     <el-radio label="0"></el-radio> | ||||
|                     <img src="http://www.9665.com/uploadfile/2018/0607/20180607042142312.png"> | ||||
|                     <span>小程序</span> | ||||
|                   </div> | ||||
|                   <div class="applets-item" @click="form.applets = '1'" :class="[form.applets === '1' ? 'applets-active' : '']"> | ||||
|                     <el-radio label="1"></el-radio> | ||||
|                     <img src="http://www.9665.com/uploadfile/2018/0607/20180607042142312.png"> | ||||
|                     <span>小程序</span> | ||||
|                   </div> | ||||
|                   <div class="applets-item" @click="form.applets = '2'" :class="[form.applets === '2' ? 'applets-active' : '']"> | ||||
|                     <el-radio label="2"></el-radio> | ||||
|                     <img src="http://www.9665.com/uploadfile/2018/0607/20180607042142312.png"> | ||||
|                     <span>小程序</span> | ||||
|                   </div> | ||||
|                 </div> | ||||
|               </el-radio-group> | ||||
|             </el-form-item> --> | ||||
|             <el-form-item label="小程序标题" prop="title" style="width: 100%" v-if="form.type === 'miniapp'"> | ||||
|               <el-input placeholder="请输入小程序标题" v-model="form.title"></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="小程序APPID" prop="appid" style="width: 100%" v-if="form.type === 'miniapp'"> | ||||
|               <el-input placeholder="请输入小程序APPID" v-model="form.appid"></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="小程序跳转页面" prop="page" style="width: 100%" v-if="form.type === 'miniapp'"> | ||||
|               <el-input placeholder="如pages/home/Home" v-model="form.page"></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="小程序图片" prop="files" style="width: 100%" v-if="form.type === 'miniapp'"> | ||||
|               <ai-uploader :instance="instance" v-model="form.files" isWechat :limit="1" url="/app/wxcp/upload/uploadFile?type=image"></ai-uploader> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </template> | ||||
|       </ai-card> | ||||
|     </template> | ||||
|  | ||||
|     <template #footer> | ||||
|       <el-button @click="cancel">取消</el-button> | ||||
|       <el-button type="primary" @click="confirm">提交</el-button> | ||||
|     </template> | ||||
|   </ai-detail> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   const validateUser = (rule, value, callback) => { | ||||
|     if (!value.length) { | ||||
|       callback(new Error('请选择使用成员')) | ||||
|     } else { | ||||
|       callback() | ||||
|     } | ||||
|   } | ||||
|   export default { | ||||
|     name: 'Add', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       params: Object | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         isShow: false, | ||||
|         info: {}, | ||||
|         form: { | ||||
|           users: [], | ||||
|           appId: '', | ||||
|           page: '', | ||||
|           title: '', | ||||
|           miniappImg: [], | ||||
|           picUrl: [], | ||||
|           content: '', | ||||
|           files: [], | ||||
|           linkUrl: '', | ||||
|           isRemind: true, | ||||
|           type: 'text' | ||||
|         }, | ||||
|         rules: { | ||||
|           users: [ | ||||
|             { required: true, message: '请选择使用成员', trigger: 'change' }, | ||||
|             { validator: validateUser, trigger: 'change' } | ||||
|           ] | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       users () { | ||||
|         return this.form.users.map(v => v.name).join(',') | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created () { | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getInfo (id) { | ||||
|         this.instance.post(`/app/appleavemessage/queryDetailById?id=${id}`).then(res => { | ||||
|           if (res.code === 0) { | ||||
|             this.info = res.data | ||||
|             this.info.appLeaveMessageReplyList = res.data.appLeaveMessageReplyList.map(item => { | ||||
|               item.images = JSON.parse(item.images).map(item => { | ||||
|                 return { | ||||
|                   ...item, | ||||
|                   url: item.accessUrl | ||||
|                 } | ||||
|               }) | ||||
|  | ||||
|               return item | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       validateUser (rule, value, callback) { | ||||
|         if (!value.length) { | ||||
|           callback(new Error('请选择使用成员')) | ||||
|         } else { | ||||
|           callback() | ||||
|         } | ||||
|       }, | ||||
|  | ||||
|       onClose () { | ||||
|         this.form.explain = '' | ||||
|       }, | ||||
|  | ||||
|       onTypeChange () { | ||||
|         this.form.files = [] | ||||
|         this.form.picUrl = [] | ||||
|         this.form.appId = '' | ||||
|         this.form.page = '' | ||||
|         this.form.title = '' | ||||
|         this.form.miniappImg = [] | ||||
|         this.form.linkUrl = '' | ||||
|       }, | ||||
|  | ||||
|       insertNickname () { | ||||
|         this.form.content = this.form.content + '[用户昵称]' | ||||
|       }, | ||||
|  | ||||
|       onChange () { | ||||
|  | ||||
|       }, | ||||
|  | ||||
|       confirm () { | ||||
|         this.$refs.userForm.validate((valid) => { | ||||
|           if (valid) { | ||||
|             if (this.form.type === 'text' && !this.form.content) { | ||||
|               return this.$message.error('请输入消息内容') | ||||
|             } | ||||
|  | ||||
|             if (this.form.type === 'image' && !this.form.files.length) { | ||||
|               return this.$message.error('请上传图片') | ||||
|             } | ||||
|             // if (this.form.type === 'file' && !this.form.files.length) { | ||||
|             //   return this.$message.error('请上传附件') | ||||
|             // } | ||||
|             if (this.form.type === 'video' && !this.form.files.length) { | ||||
|               return this.$message.error('请上传视频') | ||||
|             } | ||||
|             if (this.form.type === 'link' && !this.form.linkUrl) { | ||||
|               return this.$message.error('请输入链接') | ||||
|             } | ||||
|             if (this.form.type === 'link' && !this.form.picUrl.length) { | ||||
|               return this.$message.error('请输入链接图片') | ||||
|             } | ||||
|             if (this.form.type === 'link' && !this.form.title) { | ||||
|               return this.$message.error('请输入链接标题') | ||||
|             } | ||||
|             if (this.form.type === 'miniapp' && !this.form.title) { | ||||
|               return this.$message.error('请输入小程序标题') | ||||
|             } | ||||
|             if (this.form.type === 'miniapp' && !this.form.appid) { | ||||
|               return this.$message.error('请输入小程序appid') | ||||
|             } | ||||
|             if (this.form.type === 'miniapp' && !this.form.page) { | ||||
|               return this.$message.error('请输入小程序page') | ||||
|             } | ||||
|             if (this.form.type === 'miniapp' && !this.form.files.length) { | ||||
|               return this.$message.error('请上传小程序图片') | ||||
|             } | ||||
|  | ||||
|             this.instance.post(`/app/wxcp/wxwelcomeword/add`, { | ||||
|               type: '1', | ||||
|               content: this.form.content || '', | ||||
|               isNotify: '0', | ||||
|               media: { | ||||
|                 createdAt: this.form.files.length ? this.form.files[0].media.createdAt : '', | ||||
|                 file: this.form.files.length ? this.form.files[0] : {}, | ||||
|                 mediaId: this.form.files.length ? this.form.files[0].media.mediaId : '', | ||||
|                 sysFileId: this.form.files.length ? this.form.files[0].id : '', | ||||
|                 type: this.form.type, | ||||
|                 linkUrl: this.form.type === 'link' && this.form.linkUrl ? this.form.linkUrl : '', | ||||
|                 title: this.form.title, | ||||
|                 appId: this.form.appid, | ||||
|                 page: this.form.page, | ||||
|                 picUrl: this.form.type === 'link' ? this.form.picUrl[0].url : '' | ||||
|               }, | ||||
|               users: this.form.users.map(item => { | ||||
|                 return { | ||||
|                   type: 0, | ||||
|                   objectId: item.id, | ||||
|                   objectName: item.name | ||||
|                 } | ||||
|               }) | ||||
|             }).then(res => { | ||||
|               if (res.code == 0) { | ||||
|                 this.$message.success('提交成功') | ||||
|                 setTimeout(() => { | ||||
|                   this.cancel(true) | ||||
|                 }, 600) | ||||
|               } | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       cancel (isRefresh) { | ||||
|         this.$emit('change', { | ||||
|           type: 'list', | ||||
|           isRefresh: isRefresh ? true : false | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
|   .ai-card__title { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|  | ||||
|     h2 { | ||||
|       margin-right: 20px; | ||||
|       color: #222222; | ||||
|       font-size: 16px; | ||||
|       font-weight: 700; | ||||
|     } | ||||
|  | ||||
|     span { | ||||
|       color: #888888; | ||||
|       font-size: 14px; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .appletss { | ||||
|     display: flex; | ||||
|     flex-wrap: wrap; | ||||
|  | ||||
|     .applets-item { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       width: 400px; | ||||
|       height: 60px; | ||||
|       margin-right: 8px; | ||||
|       margin-bottom: 8px; | ||||
|       padding: 0 17px; | ||||
|       background: #FFFFFF; | ||||
|       border-radius: 2px; | ||||
|       border: 1px solid #D0D4DC; | ||||
|       cursor: pointer; | ||||
|  | ||||
|       &:hover { | ||||
|         border-color: #2266FF; | ||||
|       } | ||||
|  | ||||
|       :deep( ){ | ||||
|         .el-radio__label { | ||||
|           display: none; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       img { | ||||
|         width: 40px; | ||||
|         height: 40px; | ||||
|         margin: 0 8px 0 13px; | ||||
|       } | ||||
|  | ||||
|       span { | ||||
|         color: #222222; | ||||
|         font-size: 12px; | ||||
|       } | ||||
|  | ||||
|       .el-radio { | ||||
|         margin: 0; | ||||
|       } | ||||
|  | ||||
|       &.applets-active { | ||||
|         border-color: #2266FF; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .tips { | ||||
|     position: relative; | ||||
|     top: 2px; | ||||
|     padding-left: 8px; | ||||
|     color: #222222; | ||||
|     font-size: 14px; | ||||
|   } | ||||
|  | ||||
|   .el-form-item-item__textarea  { | ||||
|     position: relative; | ||||
|   } | ||||
|  | ||||
|     .el-form-item__btn { | ||||
|       position: absolute; | ||||
|       bottom: 12px; | ||||
|       left: 12px; | ||||
|       line-height: 1; | ||||
|       z-index: 1; | ||||
|       color: #2266FF; | ||||
|       font-size: 14px; | ||||
|       user-select: none; | ||||
|       background: #fff; | ||||
|       cursor: pointer; | ||||
|     } | ||||
| </style> | ||||
							
								
								
									
										235
									
								
								packages/wxwork/AppBuddyMessage/components/List.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								packages/wxwork/AppBuddyMessage/components/List.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,235 @@ | ||||
| <template> | ||||
|   <ai-list class="message"> | ||||
|     <template slot="title"> | ||||
|       <ai-title title="好友欢迎语" isShowBottomBorder></ai-title> | ||||
|     </template> | ||||
|     <template slot="content"> | ||||
|       <ai-search-bar class="search-bar"> | ||||
|         <template #left> | ||||
|           <el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd">添加好友欢迎语</el-button> | ||||
|         </template> | ||||
|         <template slot="right"> | ||||
|         </template> | ||||
|       </ai-search-bar> | ||||
|       <ai-table | ||||
|         :tableData="tableData" | ||||
|         :col-configs="colConfigs" | ||||
|         :total="total" | ||||
|         style="margin-top: 6px;" | ||||
|         :current.sync="search.current" | ||||
|         :size.sync="search.size" | ||||
|         @getList="getList"> | ||||
|         <el-table-column slot="type" width="240px" label="消息内容" align="center"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <el-popover | ||||
|               placement="bottom" | ||||
|               width="400" | ||||
|               :visible-arrow="false" | ||||
|               popper-class="wechat-message__container" | ||||
|               trigger="hover"> | ||||
|               <div class="count" slot="reference">共{{ row.count }}条</div> | ||||
|               <div class="message-info"> | ||||
|                 <h2 v-if="row.content" :style="{marginBottom: row.media ? '16px' : '0'}">{{ row.content }}</h2> | ||||
|                 <div class="message-info__wrapper" v-if="row.media && (row.media.file || row.media.type === 'link')"> | ||||
|                   <img v-if="row.media.type === 'image' || row.media.type === 'miniapp'" :src="row.media.file.url"> | ||||
|                   <video v-if="row.media.type === 'video'" :src="row.media.file.url"></video> | ||||
|                   <img v-if="row.media.type === 'link'" :src="row.media.picUrl"> | ||||
|                   <div class="message-info__wrapper--right"> | ||||
|                     <h3 v-if="row.media.type === 'miniapp'">{{ row.media.title }}</h3> | ||||
|                     <h3 v-if="row.media.type === 'image'">{{ row.media.file.name }}</h3> | ||||
|                     <h3 v-if="row.media.type === 'link'">{{ row.media.linkUrl }}</h3> | ||||
|                     <h3 v-if="row.media.type === 'video'">{{ row.media.file.name }}</h3> | ||||
|                     <p v-if="row.media.type === 'image'">{{ row.media.file.fileSizeStr }}</p> | ||||
|                     <p v-if="row.media.type === 'link'">{{ row.media.title }}</p> | ||||
|                     <p v-if="row.media.type === 'video'">{{ row.media.file.fileSizeStr }}</p> | ||||
|                   </div> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </el-popover> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column slot="options" width="120px" fixed="right" label="操作" align="center"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="table-options"> | ||||
|               <!-- <el-button type="text" disabled @click="toAdd(row.id)" title="编辑">编辑</el-button> --> | ||||
|               <el-button type="text" @click="remove(row.id)" title="删除">删除</el-button> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </ai-table> | ||||
|     </template> | ||||
|   </ai-list> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     name: 'List', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10, | ||||
|           content: '' | ||||
|         }, | ||||
|         currIndex: 0, | ||||
|         total: 10, | ||||
|         colConfigs: [ | ||||
|           { prop: 'type',  label: '类型', align: 'left', width: '160', | ||||
|             render: (h, params) => { | ||||
|               let str = '' | ||||
|  | ||||
|               if (params.row.content) { | ||||
|                 str = '文字' | ||||
|               } | ||||
|  | ||||
|               if (params.row.media && params.row.media.type === 'link') { | ||||
|                 str += this.dict.getLabel('wxMsgType', params.row.media.type) ? (params.row.content ? '+' : '') + this.dict.getLabel('wxMsgType', params.row.media.type) : '' | ||||
|               } | ||||
|  | ||||
|               if (params.row.media && params.row.media.file) { | ||||
|                 str += this.dict.getLabel('wxMsgType', params.row.media.type) ? (params.row.content ? '+' : '') + this.dict.getLabel('wxMsgType', params.row.media.type) : '' | ||||
|               } | ||||
|  | ||||
|               return h('span', { | ||||
|                 style: { | ||||
|                 } | ||||
|               }, str) | ||||
|             } | ||||
|           }, | ||||
|           { slot: 'type' }, | ||||
|           { prop: 'users', label: '使用成员', align: 'left', format: v => v.join(';') }, | ||||
|           { prop: 'createUser', label: '创建人' }, | ||||
|           { prop: 'createTime', label: '编辑时间' }, | ||||
|           { slot: 'options', label: '操作' } | ||||
|         ], | ||||
|         tableData: [] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     mounted () { | ||||
|       this.dict.load(['wxMsgType']).then(() => { | ||||
|         this.getList() | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getList() { | ||||
|         this.instance.post(`/app/wxcp/wxwelcomeword/list`, null, { | ||||
|           params: { | ||||
|             ...this.search | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.tableData = res.data.records.map(item => { | ||||
|               let count = 0 | ||||
|  | ||||
|               if (item.content) { | ||||
|                 count = count + 1 | ||||
|               } | ||||
|  | ||||
|               if (item.media && item.media.type !== 'text') { | ||||
|                 count = count + 1 | ||||
|               } | ||||
|  | ||||
|               item.count = count | ||||
|               return item | ||||
|             }) | ||||
|             this.total = res.data.total | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       remove (id) { | ||||
|         this.$confirm('确定删除该数据?').then(() => { | ||||
|           this.instance.post(`/app/wxcp/wxwelcomeword/delete?id=${id}`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('删除成功!') | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       toAdd (id) { | ||||
|         this.$emit('change', { | ||||
|           type: 'Add', | ||||
|           params: { | ||||
|             id | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .message { | ||||
|     .count { | ||||
|       cursor: pointer; | ||||
|       color: #2266FF; | ||||
|       font-size: 14px; | ||||
|  | ||||
|       &:hover { | ||||
|         opacity: 0.6; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .message-info { | ||||
|     padding: 8px; | ||||
|     min-height: 116px; | ||||
|  | ||||
|     h2 { | ||||
|       color: #222222; | ||||
|       font-weight: 500; | ||||
|       font-size: 14px; | ||||
|     } | ||||
|  | ||||
|     .message-info__wrapper { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       width: 368px; | ||||
|       height: 60px; | ||||
|       padding: 10px; | ||||
|       background: #FFFFFF; | ||||
|       border-radius: 2px; | ||||
|       border: 1px solid #D0D4DC; | ||||
|  | ||||
|       .message-info__wrapper--right { | ||||
|         flex: 1; | ||||
|         overflow: hidden; | ||||
|         text-overflow:ellipsis; | ||||
|         white-space: nowrap; | ||||
|       } | ||||
|  | ||||
|       h3 { | ||||
|         width: 100%; | ||||
|         color: #222222; | ||||
|         font-size: 14px; | ||||
|         overflow: hidden; | ||||
|         text-overflow:ellipsis; | ||||
|         white-space: nowrap; | ||||
|         font-weight: normal; | ||||
|       } | ||||
|  | ||||
|       img, video { | ||||
|         width: 40px; | ||||
|         height: 40px; | ||||
|         margin-right: 10px; | ||||
|         object-fit: cover; | ||||
|       } | ||||
|  | ||||
|       p { | ||||
|         margin-top: 6px; | ||||
|         font-size: 14px; | ||||
|         color: #888888; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										47
									
								
								packages/wxwork/AppMaterialLibrary/AppMaterialLibrary.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								packages/wxwork/AppMaterialLibrary/AppMaterialLibrary.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| <template> | ||||
|   <div class="doc-circulation ailist-wrapper"> | ||||
|     <keep-alive :include="['List']"> | ||||
|       <component ref="component" :is="component" :instance="instance" :dict="dict"></component> | ||||
|     </keep-alive> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import List from './components/List' | ||||
|  | ||||
|   export default { | ||||
|     name: 'AppMaterialLibrary', | ||||
|     label: '素材库', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         component: 'List', | ||||
|         params: {}, | ||||
|         include: [] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     components: { | ||||
|       List | ||||
|     }, | ||||
|  | ||||
|     mounted () { | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
|   .doc-circulation { | ||||
|     height: 100%; | ||||
|     background: #F3F6F9; | ||||
|     overflow: auto; | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										212
									
								
								packages/wxwork/AppMaterialLibrary/components/ChooseMaterial.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										212
									
								
								packages/wxwork/AppMaterialLibrary/components/ChooseMaterial.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,212 @@ | ||||
| <template> | ||||
|   <div id="ChooseMaterial"> | ||||
|     <ai-dialog | ||||
|       :visible.sync="isShow" | ||||
|       width="890px" | ||||
|       @onConfirm="onConfirm" | ||||
|       title="选择素材"> | ||||
|       <div class="AppMaterialLibrary-title"> | ||||
|         <span | ||||
|           v-for="(item, index) in typeList" | ||||
|           :key="index" | ||||
|           :class="[currIndex === index ? 'active' : '']" @click="currIndex = index, search.current = 1, getList()"> | ||||
|           {{ item }} | ||||
|         </span> | ||||
|       </div> | ||||
|       <ai-search-bar class="search-bar"> | ||||
|         <template #left> | ||||
|         </template> | ||||
|         <template slot="right"> | ||||
|           <el-input | ||||
|             v-model="search.title" | ||||
|             size="small" | ||||
|             v-throttle="() => { search.current = 1, getList() }" | ||||
|             placeholder="请输入标题、话术内容、添加人" | ||||
|             clearable | ||||
|             @clear="search.current = 1, search.title = '', getList()" | ||||
|             suffix-icon="iconfont iconSearch"> | ||||
|           </el-input> | ||||
|         </template> | ||||
|       </ai-search-bar> | ||||
|       <ai-table | ||||
|         :tableData="tableData" | ||||
|         :col-configs="colConfigs" | ||||
|         :total="total" | ||||
|         style="margin-top: 6px; width: 100%;" | ||||
|         :current.sync="search.current" | ||||
|         :size.sync="search.size" | ||||
|         @selection-change="v=> ids = v.map((e) => e.id)" | ||||
|         @getList="getList"> | ||||
|       </ai-table> | ||||
|     </ai-dialog> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     name: 'ChooseMaterial', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function | ||||
|     }, | ||||
|  | ||||
|     data() { | ||||
|       return { | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10, | ||||
|           title: '', | ||||
|         }, | ||||
|         ids: [], | ||||
|         isShow: false, | ||||
|         id: '', | ||||
|         typeList: ['话术', '图片', '小程序', '文件', '视频', '网页'], | ||||
|         currIndex: 0, | ||||
|         tableData: [], | ||||
|         total: 0 | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       mpTitle () { | ||||
|         return { | ||||
|           '0': '话术标题', | ||||
|           '1': '图片名称', | ||||
|           '2': '小程序标题', | ||||
|           '3': '文件名称', | ||||
|           '4': '视频名称', | ||||
|           '5': '网页名称' | ||||
|         }[this.currIndex] | ||||
|       }, | ||||
|  | ||||
|       colConfigs () { | ||||
|         if (this.currIndex === 0) { | ||||
|           return [ | ||||
|             { type: 'selection' }, | ||||
|             { prop: 'title', label: this.mpTitle }, | ||||
|             { prop: 'content', label: '话术内容', align: 'center' }, | ||||
|             { prop: 'createUserName', label: '添加人', align: 'center' }, | ||||
|             { prop: 'createTime', label: '添加时间', align: 'center' } | ||||
|           ] | ||||
|         } | ||||
|  | ||||
|         if (this.currIndex === 2) { | ||||
|           return [ | ||||
|             { type: 'selection' }, | ||||
|             { prop: 'title', label: this.mpTitle }, | ||||
|             { prop: 'appId', label: '小程序APPID', align: 'center' }, | ||||
|             { prop: 'createUserName', label: '添加人', align: 'center' }, | ||||
|             { prop: 'createTime', label: '添加时间', align: 'center' } | ||||
|           ] | ||||
|         } | ||||
|  | ||||
|         if (this.currIndex === 5) { | ||||
|           return [ | ||||
|             { type: 'selection' }, | ||||
|             { prop: 'title', label: this.mpTitle }, | ||||
|             { prop: 'pagePath', label: '外链网页', align: 'center' }, | ||||
|             { prop: 'createUserName', label: '添加人', align: 'center' }, | ||||
|             { prop: 'createTime', label: '添加时间', align: 'center' } | ||||
|           ] | ||||
|         } | ||||
|  | ||||
|         return [ | ||||
|           { type: 'selection' }, | ||||
|           { prop: 'title', label: this.mpTitle }, | ||||
|           { prop: 'fileSizeStr', label: '文件大小', align: 'center' }, | ||||
|           { prop: 'createUserName', label: '添加人', align: 'center' }, | ||||
|           { prop: 'createTime', label: '添加时间', align: 'center' } | ||||
|         ] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created () { | ||||
|       this.getList() | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getList() { | ||||
|         this.instance.post(`/app/appmaterialinfo/list`, null, { | ||||
|           params: { | ||||
|             ...this.search, | ||||
|             type: this.currIndex | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       onConfirm () { | ||||
|         if (!this.ids.length) { | ||||
|           return this.$message.error('请选择素材') | ||||
|         } | ||||
|  | ||||
|         if (this.ids.length > 1) { | ||||
|           return this.$message.error('素材不能多选') | ||||
|         } | ||||
|  | ||||
|  | ||||
|       }, | ||||
|  | ||||
|       open () { | ||||
|         this.isShow = true | ||||
|       }, | ||||
|  | ||||
|       close () { | ||||
|         this.isShow = false | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   #ChooseMaterial { | ||||
|     :deep( .ai-list__content--right-wrapper ) { | ||||
|       padding: 0 20px!important; | ||||
|     } | ||||
|  | ||||
|     :deep( .el-dialog__header ) { | ||||
|       display: none; | ||||
|     } | ||||
|  | ||||
|     :deep( .el-dialog__body ) { | ||||
|       padding-top: 0!important; | ||||
|     } | ||||
|  | ||||
|     .AppMaterialLibrary-title { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       margin-bottom: 20px; | ||||
|       border-bottom: 1px solid #eee; | ||||
|  | ||||
|       span { | ||||
|         height: 100%; | ||||
|         line-height: 56px; | ||||
|         margin-right: 32px; | ||||
|         color: #888888; | ||||
|         font-size: 16px; | ||||
|         font-weight: 600; | ||||
|         transition: all ease 0.3s; | ||||
|         border-bottom: 3px solid transparent; | ||||
|         cursor: pointer; | ||||
|         user-select: none; | ||||
|  | ||||
|         &:hover { | ||||
|           color: #222; | ||||
|         } | ||||
|  | ||||
|         &:last-child { | ||||
|           margin-right: 0; | ||||
|         } | ||||
|  | ||||
|         &.active { | ||||
|           color: #222222; | ||||
|           border-bottom: 3px solid #2266FF; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										394
									
								
								packages/wxwork/AppMaterialLibrary/components/List.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										394
									
								
								packages/wxwork/AppMaterialLibrary/components/List.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,394 @@ | ||||
| <template> | ||||
|   <ai-list id="AppMaterialLibrary"> | ||||
|     <template slot="title"> | ||||
|       <ai-title title="素材管理" isShowBottomBorder> | ||||
|         <template #sub> | ||||
|           <span>可在聊天素材、宣发工具中选择素材发送给居民,提升服务效率;其中文件、视频和网页素材支持记录居民查看行为</span> | ||||
|         </template> | ||||
|       </ai-title> | ||||
|     </template> | ||||
|     <template slot="content"> | ||||
|       <div class="AppMaterialLibrary-title"> | ||||
|         <span | ||||
|           v-for="(item, index) in typeList" | ||||
|           :key="index" | ||||
|           :class="[currIndex === index ? 'active' : '']" @click="currIndex = index, search.current = 1, getList()"> | ||||
|           {{ item }} | ||||
|         </span> | ||||
|       </div> | ||||
|       <ai-search-bar class="search-bar"> | ||||
|         <template #left> | ||||
|           <el-button size="small" type="primary" icon="iconfont iconAdd" @click="isShow = true">添加{{ typeList[currIndex] }}</el-button> | ||||
|         </template> | ||||
|         <template slot="right"> | ||||
|           <el-input | ||||
|             v-model="search.title" | ||||
|             size="small" | ||||
|             v-throttle="() => { search.current = 1, getList() }" | ||||
|             placeholder="请输入标题、话术内容、添加人" | ||||
|             clearable | ||||
|             @clear="search.current = 1, search.title = '', getList()" | ||||
|             suffix-icon="iconfont iconSearch"> | ||||
|           </el-input> | ||||
|         </template> | ||||
|       </ai-search-bar> | ||||
|       <ai-table | ||||
|         :tableData="tableData" | ||||
|         :col-configs="colConfigs" | ||||
|         :total="total" | ||||
|         style="margin-top: 6px; width: 100%;" | ||||
|         :current.sync="search.current" | ||||
|         :size.sync="search.size" | ||||
|         @getList="getList"> | ||||
|         <el-table-column slot="options" width="120px" fixed="right" label="操作" align="center"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="table-options"> | ||||
|               <el-button type="text" @click="id = row.id, toAdd(row)">编辑</el-button> | ||||
|               <el-button type="text" @click="remove(row.id)">删除</el-button> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </ai-table> | ||||
|       <ai-dialog | ||||
|         :visible.sync="isShow" | ||||
|         width="920px" | ||||
|         :title="(id ? '编辑' : '添加') + typeList[currIndex]" | ||||
|         @close="onClose" | ||||
|         :close-on-click-modal="false" | ||||
|         destroy-on-close | ||||
|         @onConfirm="confirm"> | ||||
|         <el-form ref="form" v-if="isShow" :model="form" label-width="130px" label-position="right"> | ||||
|           <div class="ai-form"> | ||||
|             <el-form-item v-if="currIndex === 0" label="话术标题" style="width: 100%;" prop="title" :rules="[{ required: true, message: '请输入话术标题', trigger: 'blur' }]"> | ||||
|               <el-input | ||||
|                 size="small" | ||||
|                 placeholder="请输入话术标题" | ||||
|                 maxlength="42" | ||||
|                 show-word-limit | ||||
|                 v-model="form.title"> | ||||
|               </el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 0" label="话术内容" style="width: 100%;" prop="content" :rules="[{ required: true, message: '请输入话术内容', trigger: 'blur' }]"> | ||||
|               <el-input | ||||
|                 size="small" | ||||
|                 placeholder="请输入话术内容" | ||||
|                 maxlength="682" | ||||
|                 show-word-limit | ||||
|                 v-model="form.content"> | ||||
|               </el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 1" label="图片名称" style="width: 100%;" prop="title" :rules="[{ required: true, message: '请输入图片名称', trigger: 'blur' }]"> | ||||
|               <el-input | ||||
|                 size="small" | ||||
|                 placeholder="请输入图片名称" | ||||
|                 maxlength="42" | ||||
|                 show-word-limit | ||||
|                 v-model="form.title"> | ||||
|               </el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 1" label="上传图片" style="width: 100%;" prop="fileUrl" :rules="[{ required: true, message: '请上传', trigger: 'change' }]"> | ||||
|               <ai-uploader :instance="instance" url="/admin/file/add3?type=image" v-model="form.fileUrl" :limit="1"></ai-uploader> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 3" label="文件名称" style="width: 100%;" prop="title" :rules="[{ required: true, message: '请输入文件名称', trigger: 'blur' }]"> | ||||
|               <el-input | ||||
|                 size="small" | ||||
|                 placeholder="请输入图片名称" | ||||
|                 maxlength="42" | ||||
|                 show-word-limit | ||||
|                 v-model="form.title"> | ||||
|               </el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 3" label="上传文件" style="width: 100%;" prop="fileUrl" :rules="[{ required: true, message: '请上传', trigger: 'change' }]"> | ||||
|               <ai-uploader fileType="file" url="/admin/file/add3?type=file" :instance="instance" v-model="form.fileUrl" :limit="1"></ai-uploader> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 4" label="视频标题" style="width: 100%;" prop="title" :rules="[{ required: true, message: '请输入视频标题', trigger: 'blur' }]"> | ||||
|               <el-input | ||||
|                 size="small" | ||||
|                 placeholder="请输入视频标题" | ||||
|                 maxlength="42" | ||||
|                 show-word-limit | ||||
|                 v-model="form.title"> | ||||
|               </el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 4" label="上传视频" style="width: 100%;" prop="fileUrl" :rules="[{ required: true, message: '请上传', trigger: 'change' }]"> | ||||
|               <ai-uploader :instance="instance" url="/admin/file/add3?type=video" fileType="file" v-model="form.fileUrl" :limit="1"></ai-uploader> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 4" label="视频封面图" prop="pictureUrl" style="width: 100%;" :rules="[{ required: true, message: '请上传视频封面图', trigger: 'change' }]"> | ||||
|               <ai-uploader :instance="instance" url="/admin/file/add3?type=image" v-model="form.pictureUrl" :limit="1"></ai-uploader> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 4" label="视频描述" style="width: 100%;" prop="content" :rules="[{ required: true, message: '请输入视频描述', trigger: 'blur' }]"> | ||||
|               <el-input | ||||
|                 size="small" | ||||
|                 placeholder="请输入视频描述" | ||||
|                 maxlength="682" | ||||
|                 show-word-limit | ||||
|                 v-model="form.content"> | ||||
|               </el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 5" label="网页标题" style="width: 100%;" prop="title" :rules="[{ required: true, message: '请输入网页标题', trigger: 'blur' }]"> | ||||
|               <el-input | ||||
|                 size="small" | ||||
|                 placeholder="请输入网页标题" | ||||
|                 maxlength="42" | ||||
|                 show-word-limit | ||||
|                 v-model="form.title"> | ||||
|               </el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 5" label="网页链接" style="width: 100%;" prop="pagePath" :rules="[{ required: true, message: '请输入网页链接链接', trigger: 'blur' }]"> | ||||
|               <el-input | ||||
|                 size="small" | ||||
|                 placeholder="请输入网页链接链接" | ||||
|                 maxlength="682" | ||||
|                 show-word-limit | ||||
|                 v-model="form.pagePath"> | ||||
|               </el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="form.currIndex === 5" label="网页描述" style="width: 100%;" prop="content"> | ||||
|               <el-input | ||||
|                 size="small" | ||||
|                 placeholder="请输入网页描述" | ||||
|                 maxlength="170" | ||||
|                 show-word-limit | ||||
|                 v-model="form.content"> | ||||
|               </el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 5" label="网页封面图" prop="pictureUrl" style="width: 100%;" :rules="[{ required: true, message: '请上传封面图', trigger: 'change' }]"> | ||||
|               <ai-uploader :instance="instance" url="/admin/file/add3?type=image" v-model="form.pictureUrl" :limit="1"></ai-uploader> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 2" label="小程序标题" style="width: 100%;" prop="title" :rules="[{ required: true, message: '请输入小程序标题', trigger: 'blur' }]"> | ||||
|               <el-input | ||||
|                 size="small" | ||||
|                 placeholder="请输入小程序标题" | ||||
|                 maxlength="20" | ||||
|                 show-word-limit | ||||
|                 v-model="form.title"> | ||||
|               </el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 2" label="小程序appid" style="width: 100%;" prop="appId" :rules="[{ required: true, message: '小程序appid', trigger: 'blur' }]"> | ||||
|               <el-input | ||||
|                 size="small" | ||||
|                 placeholder="小程序appid" | ||||
|                 v-model="form.appId"> | ||||
|               </el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 2" label="小程序路径" style="width: 100%;" prop="pagePath" :rules="[{ required: true, message: '请输入小程序路径', trigger: 'blur' }]"> | ||||
|               <el-input | ||||
|                 size="small" | ||||
|                 placeholder="请输入小程序page路径" | ||||
|                 v-model="form.pagePath"> | ||||
|               </el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item v-if="currIndex === 2" label="小程序封面图" prop="pictureUrl" style="width: 100%;" :rules="[{ required: true, message: '请上传封面图', trigger: 'change' }]"> | ||||
|               <ai-uploader :instance="instance" url="/admin/file/add3?type=image" v-model="form.pictureUrl" :limit="1"></ai-uploader> | ||||
|             </el-form-item> | ||||
|           </div> | ||||
|         </el-form> | ||||
|       </ai-dialog> | ||||
|     </template> | ||||
|   </ai-list> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     name: 'List', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object | ||||
|     }, | ||||
|  | ||||
|     data() { | ||||
|       return { | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10, | ||||
|           title: '', | ||||
|         }, | ||||
|         isShow: false, | ||||
|         form: { | ||||
|           appId: '', | ||||
|           content: '', | ||||
|           fileUrl: [], | ||||
|           pagePath: '', | ||||
|           pictureUrl: [], | ||||
|           title: '' | ||||
|         }, | ||||
|         id: '', | ||||
|         typeList: ['话术', '图片', '小程序', '文件', '视频', '网页'], | ||||
|         currIndex: 0, | ||||
|         tableData: [], | ||||
|         total: 0 | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       mpTitle () { | ||||
|         return { | ||||
|           '0': '话术标题', | ||||
|           '1': '图片名称', | ||||
|           '2': '小程序标题', | ||||
|           '3': '文件名称', | ||||
|           '4': '视频名称', | ||||
|           '5': '网页名称' | ||||
|         }[this.currIndex] | ||||
|       }, | ||||
|  | ||||
|       colConfigs () { | ||||
|         if (this.currIndex === 0) { | ||||
|           return [ | ||||
|             { prop: 'title', label: this.mpTitle }, | ||||
|             { prop: 'content', label: '话术内容', align: 'center' }, | ||||
|             { prop: 'createUserName', label: '添加人', align: 'center' }, | ||||
|             { prop: 'createTime', label: '添加时间', align: 'center' } | ||||
|           ] | ||||
|         } | ||||
|  | ||||
|         if (this.currIndex === 2) { | ||||
|           return [ | ||||
|             { prop: 'title', label: this.mpTitle }, | ||||
|             { prop: 'appId', label: '小程序APPID', align: 'center' }, | ||||
|             { prop: 'createUserName', label: '添加人', align: 'center' }, | ||||
|             { prop: 'createTime', label: '添加时间', align: 'center' } | ||||
|           ] | ||||
|         } | ||||
|  | ||||
|         if (this.currIndex === 5) { | ||||
|           return [ | ||||
|             { prop: 'title', label: this.mpTitle }, | ||||
|             { prop: 'pagePath', label: '外链网页', align: 'center' }, | ||||
|             { prop: 'createUserName', label: '添加人', align: 'center' }, | ||||
|             { prop: 'createTime', label: '添加时间', align: 'center' } | ||||
|           ] | ||||
|         } | ||||
|  | ||||
|         return [ | ||||
|           { prop: 'title', label: this.mpTitle }, | ||||
|           { prop: 'fileSizeStr', label: '文件大小', align: 'center' }, | ||||
|           { prop: 'createUserName', label: '添加人', align: 'center' }, | ||||
|           { prop: 'createTime', label: '添加时间', align: 'center' } | ||||
|         ] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created () { | ||||
|       this.getList() | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getList() { | ||||
|         this.instance.post(`/app/appmaterialinfo/list`, null, { | ||||
|           params: { | ||||
|             ...this.search, | ||||
|             type: this.currIndex | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       toAdd (e) { | ||||
|         this.form = { | ||||
|           ...this.form, | ||||
|           ...e, | ||||
|           fileUrl: e.fileUrl ? [{ | ||||
|             url: e.fileUrl | ||||
|           }] : '', | ||||
|           pictureUrl: e.pictureUrl ? [{ | ||||
|             url: e.pictureUrl | ||||
|           }] : '' | ||||
|         } | ||||
|  | ||||
|         this.isShow = true | ||||
|       }, | ||||
|  | ||||
|       onClose () { | ||||
|         this.form.content = '' | ||||
|         this.form.appId = '' | ||||
|         this.form.fileUrl = [] | ||||
|         this.form.pagePath = '' | ||||
|         this.form.pictureUrl = [] | ||||
|         this.form.title = '' | ||||
|  | ||||
|         this.id = '' | ||||
|       }, | ||||
|  | ||||
|       confirm () { | ||||
|         this.$refs.form.validate((valid) => { | ||||
|           if (valid) { | ||||
|             this.instance.post(`/app/appmaterialinfo/addOrUpdate`, { | ||||
|               ...this.form, | ||||
|               type: this.currIndex, | ||||
|               fileUrl: this.form.fileUrl.length ? this.form.fileUrl[0].url : '', | ||||
|               fileId: this.form.fileUrl.length ? this.form.fileUrl[0].id : '', | ||||
|               pictureId: this.form.pictureUrl.length ? this.form.pictureUrl[0].id : '', | ||||
|               pictureUrl: this.form.pictureUrl.length ? this.form.pictureUrl[0].url : '', | ||||
|               fileSize: this.form.fileUrl.length ? this.form.fileUrl[0].fileSize : '', | ||||
|             }).then(res => { | ||||
|               if (res.code == 0) { | ||||
|                 this.$message.success('提交成功') | ||||
|                 this.isShow = false | ||||
|  | ||||
|                 this.getList() | ||||
|               } | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       remove (id) { | ||||
|         this.$confirm('确定删除该数据?').then(() => { | ||||
|           this.instance.post(`/app/appmaterialinfo/delete?ids=${id}`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('删除成功!') | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   #AppMaterialLibrary { | ||||
|     :deep( .ai-list__content--right-wrapper ) { | ||||
|       padding: 0 20px!important; | ||||
|     } | ||||
|  | ||||
|     .AppMaterialLibrary-title { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       margin-bottom: 20px; | ||||
|       border-bottom: 1px solid #eee; | ||||
|  | ||||
|       span { | ||||
|         height: 100%; | ||||
|         line-height: 56px; | ||||
|         margin-right: 32px; | ||||
|         color: #888888; | ||||
|         font-size: 16px; | ||||
|         font-weight: 600; | ||||
|         transition: all ease 0.3s; | ||||
|         border-bottom: 3px solid transparent; | ||||
|         cursor: pointer; | ||||
|         user-select: none; | ||||
|  | ||||
|         &:hover { | ||||
|           color: #222; | ||||
|         } | ||||
|  | ||||
|         &:last-child { | ||||
|           margin-right: 0; | ||||
|         } | ||||
|  | ||||
|         &.active { | ||||
|           color: #222222; | ||||
|           border-bottom: 3px solid #2266FF; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										617
									
								
								packages/wxwork/AppVerbalTrick/AppVerbalTrick.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										617
									
								
								packages/wxwork/AppVerbalTrick/AppVerbalTrick.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,617 @@ | ||||
| <template> | ||||
|   <section style="height: 100%;"> | ||||
|     <ai-list> | ||||
|       <template slot="title"> | ||||
|         <ai-title title="话术库" :isShowBottomBorder="true"></ai-title> | ||||
|       </template> | ||||
|       <template #left> | ||||
|         <div class="left-tree"> | ||||
|           <div class="tree-title"> | ||||
|             <label>分组</label> | ||||
|             <el-button icon="iconfont iconAdd" style="height: 28px;line-height: 0;" @click="groupDialog = true">添加分组 | ||||
|             </el-button> | ||||
|           </div> | ||||
|           <el-scrollbar style="height: calc(100% - 40px)"> | ||||
|             <el-menu style="height: 100%;" default-active="0" active-text-color="#26f" text-color="#222" | ||||
|                      mode="vertical"> | ||||
|               <el-menu-item v-for="(item, index) in sortList" :key="index" class="menu-item" @click="currentMenu(item)" | ||||
|                             :index="index.toString()"> | ||||
|                 <label class="item-title">{{ item.name }}</label> | ||||
|                 <el-popover style="width: 30px" placement="left" trigger="click"> | ||||
|                   <div style="display: flex;flex-direction: column;align-items: center;"> | ||||
|                     <div style="cursor: pointer;" @click="editGroup(item, index)">编辑</div> | ||||
|                     <div style="cursor: pointer;" @click="delteGroup(item, index)">删除</div> | ||||
|                   </div> | ||||
|                   <span class="iconfont iconMore" slot="reference"></span> | ||||
|                 </el-popover> | ||||
|               </el-menu-item> | ||||
|             </el-menu> | ||||
|           </el-scrollbar> | ||||
|         </div> | ||||
|       </template> | ||||
|       <template slot="content"> | ||||
|         <ai-search-bar> | ||||
|           <template slot="left"> | ||||
|             <el-select v-model="search.contentType" placeholder="类型" size="small" clearable @change="getList()"> | ||||
|               <el-option v-for="(item, index) in types" :key="index" :label="item.name" :value="item.value"></el-option> | ||||
|             </el-select> | ||||
|           </template> | ||||
|           <template slot="right"> | ||||
|             <el-input v-model="search.title" class="search-input" size="small" | ||||
|                       @keyup.enter.native=";(search.current = 1), getList()" placeholder="请输入标题或话术内容或创建人" clearable | ||||
|                       @clear=";(search.current = 1), (search.title = ''), getList()" suffix-icon="iconfont iconSearch"/> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <ai-search-bar> | ||||
|           <template slot="left"> | ||||
|             <el-button icon="iconfont iconAdd" type="primary" @click="add">添加话术</el-button> | ||||
|           </template> | ||||
|         </ai-search-bar> | ||||
|         <ai-table :tableData="tableData" :col-configs="colConfigs" :stripe="true" :total="total" ref="aitableex" | ||||
|                   style="margin-top: 8px;" :current.sync="search.current" :size.sync="search.size" @getList="getList">\ | ||||
|  | ||||
|           <el-table-column slot="content" label="话术内容" align="left" width="280"> | ||||
|             <template slot-scope="{ row }"> | ||||
|               <div class="table-left__wrapper"> | ||||
|                 <video :src="row.file && row.file.url" v-if="row.file && row.contentType == 'video'" | ||||
|                        class="media"></video> | ||||
|                 <img :src="row.file && row.file.url" v-if="row.file && row.contentType == 'image'" class="media"/> | ||||
|                 <audio :src="row.file && row.file.url" v-if="row.file && row.contentType == 'voice'" | ||||
|                        class="media"></audio> | ||||
|                 <div class="table-left__wrapper--right"> | ||||
|                   <el-tooltip class="item" effect="dark" :content="row.content" placement="top"> | ||||
|                     <div class="table-left__wrapper--text" v-if="row.contentType == 'text'">{{ row.content }}</div> | ||||
|                   </el-tooltip> | ||||
|                   <div class="ellipsis" v-if="row.contentType !== 'text' && row.file && row.file.name">{{ row.file.name }}</div> | ||||
|                   <div v-if="row.contentType !== 'text' && row.file && row.file.size">{{ row.file.size | size }}KB</div> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|  | ||||
|  | ||||
|           <el-table-column slot="options" label="操作" width="160px" align="center" fixed="right"> | ||||
|             <template slot-scope="{ row }"> | ||||
|               <span class="table-btn" title="编辑" @click="editTrick(row)">编辑</span> | ||||
|               <span class="table-btn" title="删除" @click="deleteTrick(row)">删除</span> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|         </ai-table> | ||||
|       </template> | ||||
|     </ai-list> | ||||
|     <ai-dialog :visible.sync="groupDialog" @closed="sortForm = {},sortForm.type=1" width="800px" title="添加分组" | ||||
|                @onConfirm="onConfirm"> | ||||
|       <el-form size="small" label-width="100px" ref="groupForm" :model="sortForm" :rules="sortRules"> | ||||
|         <el-form-item label="分组名称" prop="name"> | ||||
|           <el-input clearable v-model.trim="sortForm.name" placeholder="请输入..." :maxlength="10" show-word-limit/> | ||||
|         </el-form-item> | ||||
|         <!--        <el-form-item label="可见范围" prop="type">--> | ||||
|         <!--          <el-radio-group v-model="sortForm.type">--> | ||||
|         <!--            <el-radio label="0">个人话术</el-radio>--> | ||||
|         <!--            <el-radio label="1">公共话术</el-radio>--> | ||||
|         <!--          </el-radio-group>--> | ||||
|         <!--        </el-form-item>--> | ||||
|         <!--        <el-form-item label="可用部门" prop="documentName">--> | ||||
|         <!--          <el-row type="flex">--> | ||||
|         <!--            <div class="input"></div>--> | ||||
|         <!--            <ai-person-select :instance="instance" url="/app/appvillagecadres/list" :isMultiple="true"--> | ||||
|         <!--                              btnText="选择" dialogTitle="选择">--> | ||||
|         <!--              <template name="option" v-slot:option="{ item }">--> | ||||
|         <!--                <span class="iconfont iconProlife">{{ item.name }}</span>--> | ||||
|         <!--                <ai-id mode="show" :show-eyes="false" :value="item.idNumber"/>--> | ||||
|         <!--              </template>--> | ||||
|         <!--            </ai-person-select>--> | ||||
|         <!--          </el-row>--> | ||||
|         <!--        </el-form-item>--> | ||||
|       </el-form> | ||||
|     </ai-dialog> | ||||
|  | ||||
|     <ai-dialog :visible.sync="trickDialog" @close="onClose" @onConfirm="trickConfirm" width="800px" title="添加话术"> | ||||
|       <el-form size="small" label-width="100px" ref="trickFom" :model="trickForm" :rules="trickRules"> | ||||
|         <!--        <el-form-item label="分组" prop="handleResult">--> | ||||
|         <!--          <ai-select--> | ||||
|         <!--            v-model="search.type"--> | ||||
|         <!--            @change="search.current = 1, getList()"--> | ||||
|         <!--            placeholder="类型"--> | ||||
|         <!--            :selectList="sortList"--> | ||||
|         <!--          ></ai-select>--> | ||||
|         <!--        </el-form-item>--> | ||||
|         <el-form-item label="标题" prop="title"> | ||||
|           <el-input clearable placeholder="请输入..." v-model="trickForm.title" show-word-limit :maxlength="20"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="话术类型" prop="contentType"> | ||||
|           <el-radio-group v-model="trickForm.contentType" @change="onChange"> | ||||
|             <el-radio :label="item.value" v-for="(item, index) in types" :key="index">{{ item.name }}</el-radio> | ||||
|           </el-radio-group> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="文本内容" class="el-form-item__textarea" prop="content" v-if="trickForm.contentType == 'text'"> | ||||
|           <span @click="insertNickname" class="el-form-item__btn" type="text">[插入用户昵称]</span> | ||||
|           <span @click="insertRemark" class="el-form-item__remark" type="text">[插入备注名]</span> | ||||
|           <el-input type="textarea" v-model="trickForm.content" placeholder="请输入..." :rows="5" show-word-limit | ||||
|                     :maxlength="255"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item :label="compLabel" prop="fileId" v-else> | ||||
|           <ai-uploader :instance="instance" v-model="fileList" :acceptType="acceptType" | ||||
|                        :url="'/app/wxcp/upload/uploadFile?type=' + trickForm.contentType" isWechat :fileType="fileType" | ||||
|                        :limit="1" @change="change"></ai-uploader> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|     </ai-dialog> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from 'vuex' | ||||
|  | ||||
| export default { | ||||
|   name: 'AppVerbalTrick', | ||||
|   label: '话术库', | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       groupDialog: false, | ||||
|       trickDialog: false, | ||||
|       search: { | ||||
|         current: 1, | ||||
|         size: 10, | ||||
|         contentType: '', | ||||
|       }, | ||||
|       sortForm: { | ||||
|         name: '', | ||||
|         type: '1', | ||||
|       }, | ||||
|       trickForm: { | ||||
|         title: '', | ||||
|         contentType: 'text', | ||||
|         content: '', | ||||
|         fileId: '', | ||||
|         mediaId: '', | ||||
|       }, | ||||
|       row: {}, | ||||
|       current: {}, | ||||
|       sortList: [], | ||||
|       total: 0, | ||||
|       tableData: [], | ||||
|       fileList: [], | ||||
|     } | ||||
|   }, | ||||
|  | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     acceptType() { | ||||
|       return { | ||||
|         "image": ".jpg,.png,.jpeg", | ||||
|         "video": ".mp4" | ||||
|       }[this.trickForm.contentType] | ||||
|     }, | ||||
|     compLabel() { | ||||
|       return this.types.find((e) => e.value == this.trickForm.contentType)?.name | ||||
|     }, | ||||
|     fileType() { | ||||
|       return this.trickForm.contentType == 'image' ? 'img' : 'file' | ||||
|     }, | ||||
|     types() { | ||||
|       return [ | ||||
|         {name: '文本', value: 'text'}, | ||||
|         {name: '图片', value: 'image'}, | ||||
|         {name: '视频', value: 'video'}, | ||||
|         // // {name: "附件", value: "file"}, | ||||
|         // {name: "音频", value: "voice"}, | ||||
|       ] | ||||
|     }, | ||||
|     trickRules() { | ||||
|       return { | ||||
|         title: [{required: true, message: '请输入标题', trigger: 'blur'}], | ||||
|         contentType: [{required: true, message: '请选择话术类型', trigger: 'change'}], | ||||
|         content: [{required: true, validator: (rule, value, callback)=>{ | ||||
|             if(this.trickForm.contentType == 'text' && !value){ | ||||
|               return callback("请输入文本内容") | ||||
|             }else { | ||||
|               callback() | ||||
|             } | ||||
|           }}], | ||||
|         fileId: [{required: true, validator: (rule, value, callback)=>{ | ||||
|             if(this.trickForm.contentType != 'text' && !value){ | ||||
|               return callback("请上传文件") | ||||
|             }else { | ||||
|               callback() | ||||
|             } | ||||
|           }}], | ||||
|       } | ||||
|     }, | ||||
|     // message() { | ||||
|     //   return (() => { | ||||
|     //     if (this.trickForm.contentType == 'text') { | ||||
|     //       return '请输入文本内容' | ||||
|     //     } else if (this.trickForm.contentType == 'image') { | ||||
|     //       return '请上传图片' | ||||
|     //     } else if (this.trickForm.contentType == 'file') { | ||||
|     //       return '请上传文件' | ||||
|     //     } else if (this.trickForm.contentType == 'video') { | ||||
|     //       return '请上传视频' | ||||
|     //     } else if (this.trickForm.contentType == 'voice') { | ||||
|     //       return '请上传音频' | ||||
|     //     } | ||||
|     //   })() | ||||
|     // }, | ||||
|     sortRules() { | ||||
|       return { | ||||
|         name: [{required: true, message: '请输入分组名称', trigger: 'blur'}], | ||||
|         type: [{required: true, message: '请选择可见范围', trigger: 'change'}], | ||||
|       } | ||||
|     }, | ||||
|     colConfigs() { | ||||
|       return [ | ||||
|         {slot: 'type'}, | ||||
|         {slot: 'content'}, | ||||
|         {prop: 'title', label: '标题'}, | ||||
|         { | ||||
|           prop: 'contentType', | ||||
|           label: '类型', | ||||
|           align: 'center', | ||||
|           render: (h, {row}) => { | ||||
|             return h('span', {}, this.types.find((e) => row.contentType == e.value)?.name) | ||||
|           }, | ||||
|         }, | ||||
|         {prop: 'userName', label: '创建人', align: 'center'}, | ||||
|         {prop: 'createTime', label: '创建时间', align: 'center'}, | ||||
|         {slot: 'options', label: '操作', align: 'center'}, | ||||
|       ] | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   created() { | ||||
|     this.getSortList() | ||||
|   }, | ||||
|  | ||||
|   filters: { | ||||
|     size(size) { | ||||
|       return (size / 1024).toFixed(1) | ||||
|     }, | ||||
|   }, | ||||
|  | ||||
|   methods: { | ||||
|     insertNickname() { | ||||
|       this.trickForm.content += '[用户昵称]' | ||||
|     }, | ||||
|     insertRemark() { | ||||
|       this.trickForm.content += '[备注名]' | ||||
|     }, | ||||
|     onClose() { | ||||
|       this.trickForm.title = '' | ||||
|       this.trickForm.content = '' | ||||
|       this.trickForm.fileId = '' | ||||
|       this.trickForm.mediaId = '' | ||||
|       this.trickForm.createdAt = '' | ||||
|       this.trickForm.contentType = 'text' | ||||
|       this.fileList = [] | ||||
|     }, | ||||
|     onChange() { | ||||
|       this.trickForm.fileId = '' | ||||
|       this.trickForm.content = '' | ||||
|       this.trickForm.mediaId = '' | ||||
|       this.trickForm.createdAt = '' | ||||
|       this.fileList = [] | ||||
|     }, | ||||
|     add() { | ||||
|       if (this.sortList.length == 0) return this.$message.error('请先添加分组') | ||||
|       this.$nextTick(() => { | ||||
|         this.trickDialog = true | ||||
|       }) | ||||
|     }, | ||||
|     change(e) { | ||||
|       if(e.length){ | ||||
|         this.trickForm.fileId = e[0].id | ||||
|         this.trickForm.mediaId = e[0].media.mediaId | ||||
|         this.trickForm.createdAt = e[0].media.createdAt | ||||
|       }else { | ||||
|         this.trickForm.fileId ="" | ||||
|         this.trickForm.mediaId = "" | ||||
|         this.trickForm.createdAt = "" | ||||
|       } | ||||
|     }, | ||||
|     editTrick(row) { | ||||
|       this.row = row | ||||
|       this.trickForm = {...row} | ||||
|       row.file && (this.trickForm.fileId = row.file.id) | ||||
|       this.$nextTick(() => { | ||||
|         this.trickDialog = true | ||||
|       }) | ||||
|       this.fileList.push(row.file) | ||||
|     }, | ||||
|     deleteTrick(row) { | ||||
|       this.$confirm('确认要删除吗?').then(() => { | ||||
|         this.instance | ||||
|         .post(`/app/wxcp/wxspeechtechnique/delete`, null, { | ||||
|           params: { | ||||
|             id: row.id, | ||||
|           }, | ||||
|         }) | ||||
|         .then((res) => { | ||||
|           if (res.code == 0) { | ||||
|             this.$message.success('删除成功') | ||||
|             this.getList() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|     trickConfirm() { | ||||
|       this.$refs['trickFom'].validate((valid) => { | ||||
|         if (valid) { | ||||
|           this.instance | ||||
|           .post(`/app/wxcp/wxspeechtechnique/addOrUpdate`, { | ||||
|             ...this.trickForm, | ||||
|             category: this.current.id, | ||||
|             userId: this.user.info.id, | ||||
|           }) | ||||
|           .then((res) => { | ||||
|             if (res.code == 0) { | ||||
|               this.trickDialog = false | ||||
|               this.$message.success(this.trickForm.id ? '编辑成功' : '添加成功') | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     currentMenu(item) { | ||||
|       this.current = item | ||||
|       this.getList() | ||||
|     }, | ||||
|     delteGroup(item, index) { | ||||
|       this.$confirm('是否要删除?').then(() => { | ||||
|         this.instance | ||||
|         .post(`/app/wxcp/wxspeechtechniquecategory/delete`, null, { | ||||
|           params: { | ||||
|             id: item.id, | ||||
|           }, | ||||
|         }) | ||||
|         .then((res) => { | ||||
|           if (res.code == 0) { | ||||
|             this.$message.success('删除成功') | ||||
|             this.getSortList() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|     editGroup(item, index) { | ||||
|       this.sortForm = {...item} | ||||
|       this.groupDialog = true | ||||
|     }, | ||||
|     onConfirm() { | ||||
|       this.$refs['groupForm'].validate((valid) => { | ||||
|         if (valid) { | ||||
|           this.instance | ||||
|           .post(`/app/wxcp/wxspeechtechniquecategory/addOrUpdate`, { | ||||
|             ...this.sortForm, | ||||
|           }) | ||||
|           .then((res) => { | ||||
|             if (res.code == 0) { | ||||
|               this.groupDialog = false | ||||
|               this.$message.success(this.sortForm.id ? '编辑成功' : '添加成功') | ||||
|               this.getSortList() | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     getSortList() { | ||||
|       this.instance | ||||
|       .post(`/app/wxcp/wxspeechtechniquecategory/listAll`, null, { | ||||
|         params: { | ||||
|           // type: 1, | ||||
|         }, | ||||
|       }) | ||||
|       .then((res) => { | ||||
|         if (res && res.data.length) { | ||||
|           this.sortList = res.data | ||||
|           this.current = res.data[0] | ||||
|           this.getList() | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getList(item) { | ||||
|       this.instance | ||||
|       .post(`/app/wxcp/wxspeechtechnique/list`, null, { | ||||
|         params: { | ||||
|           category: this.current.id, | ||||
|           ...this.search, | ||||
|           status: 1, | ||||
|         }, | ||||
|       }) | ||||
|       .then((res) => { | ||||
|         if (res.code == 0) { | ||||
|           this.tableData = res.data.records | ||||
|           this.total = res.data.total | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .left-tree { | ||||
|   width: 264px; | ||||
|   background: #fafafb; | ||||
|   box-shadow: -1px 0px 0px 0px #e5e5e5; | ||||
|   border-radius: 2px 0px 0px 2px; | ||||
|  | ||||
|   .tree-title { | ||||
|     height: 40px; | ||||
|     box-sizing: border-box; | ||||
|     padding: 0 8px 0 16px; | ||||
|     background: #eeeff1; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
|  | ||||
|     & > label { | ||||
|       font-size: 14px; | ||||
|       font-weight: bold; | ||||
|       color: #222222; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .tree-item { | ||||
|     box-sizing: border-box; | ||||
|     padding: 8px 16px 8px 24px; | ||||
|     height: 40px; | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
|     border-right: 2px solid transparent; | ||||
|   } | ||||
|  | ||||
|   .menu-item { | ||||
|     height: 40px; | ||||
|     align-items: center; | ||||
|     display: flex; | ||||
|     justify-content: space-between; | ||||
|  | ||||
|     .item-title { | ||||
|       display: inline-block; | ||||
|       width: 160px; | ||||
|       overflow: hidden; | ||||
|       text-overflow: ellipsis; | ||||
|       white-space: nowrap; | ||||
|       font-size: 14px; | ||||
|       color: #222222; | ||||
|     } | ||||
|  | ||||
|     .iconMore { | ||||
|       cursor: pointer; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   :deep( .el-scrollbar__wrap ){ | ||||
|     overflow-x: hidden; | ||||
|   } | ||||
| } | ||||
|  | ||||
| :deep( .ai-list__content--right ){ | ||||
|  | ||||
|   .ai-list__content--right-wrapper { | ||||
|     min-height: 100%; | ||||
|   } | ||||
| } | ||||
|  | ||||
| :deep( .has-gutter tr ){ | ||||
|   height: 40px; | ||||
| } | ||||
|  | ||||
| :deep( .el-table__row td ){ | ||||
|   height: 68px; | ||||
| } | ||||
|  | ||||
| // :deep( .el-table__row td .cell ){ | ||||
| //   width: 240px; | ||||
| //   height: 44px; | ||||
| // } | ||||
|  | ||||
| .table-btn { | ||||
|   font-size: 14px; | ||||
|   color: #2266ff; | ||||
|   cursor: pointer; | ||||
|  | ||||
|   &:nth-child(1) { | ||||
|     margin-right: 16px; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .input { | ||||
|   width: 100%; | ||||
|   min-height: 32px; | ||||
|   line-height: 32px; | ||||
|   border-radius: 4px; | ||||
|   border: 1px solid #d0d4dc; | ||||
|   color: #666; | ||||
|   display: inline-block; | ||||
|   font-size: inherit; | ||||
|   cursor: pointer; | ||||
|  | ||||
|   &:after { | ||||
|     content: '请选择...'; | ||||
|     color: #888888; | ||||
|     padding-left: 10px; | ||||
|   } | ||||
| } | ||||
|  | ||||
| :deep( .media ){ | ||||
|   object-fit: fill; | ||||
|   width: 40px; | ||||
|   height: 40px; | ||||
|   vertical-align: middle; | ||||
|   box-sizing: content-box; | ||||
| } | ||||
|  | ||||
| :deep( .AiPersonSelect ){ | ||||
|   & > button { | ||||
|     background: #f5f5f5; | ||||
|     border-radius: 0px 2px 2px 0px; | ||||
|     border: 1px solid #d0d4dc; | ||||
|     color: #222222; | ||||
|   } | ||||
| } | ||||
|  | ||||
| :deep( .is-active ){ | ||||
|   border-right: 2px solid #2266ff; | ||||
| } | ||||
| </style> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .el-popper { | ||||
|   min-width: 76px !important; | ||||
| } | ||||
|  | ||||
| .table-left__wrapper { | ||||
|   display: flex; | ||||
|   align-items: center; | ||||
|  | ||||
|   .table-left__wrapper--text { | ||||
|     display: -webkit-box; | ||||
|     -webkit-box-orient: vertical; | ||||
|     -webkit-line-clamp: 2; | ||||
|     overflow: hidden; | ||||
|   } | ||||
|  | ||||
|   .ellipsis { | ||||
|     width: 170px; | ||||
|     height: 24px; | ||||
|     overflow: hidden; | ||||
|     text-overflow: ellipsis; | ||||
|     white-space: nowrap; | ||||
|   } | ||||
|  | ||||
|   img, | ||||
|   video { | ||||
|     margin-right: 8px; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .el-form-item__textarea { | ||||
|   position: relative; | ||||
|  | ||||
|   .el-form-item__btn, .el-form-item__remark { | ||||
|     position: absolute; | ||||
|     bottom: 12px; | ||||
|     left: 12px; | ||||
|     line-height: 1; | ||||
|     z-index: 1; | ||||
|     color: #2266FF; | ||||
|     font-size: 14px; | ||||
|     user-select: none; | ||||
|     background: #fff; | ||||
|     cursor: pointer; | ||||
|   } | ||||
|  | ||||
|   .el-form-item__remark { | ||||
|     left: 108px; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										66
									
								
								packages/wxwork/AppVillageCode/AppVillageCode.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								packages/wxwork/AppVillageCode/AppVillageCode.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| <template> | ||||
|   <div class="doc-circulation ailist-wrapper"> | ||||
|     <keep-alive :include="['List']"> | ||||
|       <component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component> | ||||
|     </keep-alive> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import List from './components/List' | ||||
|   import Add from './components/Add' | ||||
|  | ||||
|   export default { | ||||
|     name: 'AppVillageCode', | ||||
|     label: '一村一码', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         component: 'List', | ||||
|         params: {}, | ||||
|         include: [] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     components: { | ||||
|       Add, | ||||
|       List | ||||
|     }, | ||||
|  | ||||
|     mounted () { | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       onChange (data) { | ||||
|         if (data.type === 'Add') { | ||||
|           this.component = 'Add' | ||||
|           this.params = data.params | ||||
|         } | ||||
|  | ||||
|         if (data.type === 'list') { | ||||
|           this.component = 'List' | ||||
|           this.params = data.params | ||||
|  | ||||
|           this.$nextTick(() => { | ||||
|             if (data.isRefresh) { | ||||
|               this.$refs.component.getList() | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
|   .doc-circulation { | ||||
|     height: 100%; | ||||
|     background: #F3F6F9; | ||||
|     overflow: auto; | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										119
									
								
								packages/wxwork/AppVillageCode/components/Add.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								packages/wxwork/AppVillageCode/components/Add.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | ||||
| <template> | ||||
|   <ai-detail> | ||||
|     <template slot="title"> | ||||
|       <ai-title title="添加二维码" isShowBack isShowBottomBorder @onBackClick="cancel(false)"> | ||||
|       </ai-title> | ||||
|     </template> | ||||
|     <template slot="content"> | ||||
|       <ai-card title="基本信息"> | ||||
|         <template #content> | ||||
|           <el-form class="ai-form" ref="form" :model="form" label-width="110px" label-position="right"> | ||||
|             <el-form-item label="地区" style="width: 100%;" prop="codeName"> | ||||
|               <span style="color: #666;">{{ form.areaName }}</span> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="二维码名称" prop="codeName" :rules="[{ required: true, message: '请输入二维码名称', trigger: 'blur' }]"> | ||||
|               <el-input size="small" maxlength="30" show-word-limit placeholder="请输入二维码名称" style="width: 328px;" v-model="form.codeName"></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item style="width: 100%;" label="二维码类型" prop="type" :rules="[{ required: true, message: '请选择二维码类型', trigger: 'change' }]"> | ||||
|               <el-radio-group v-model="form.type"> | ||||
|                 <el-radio label="0">群二维码</el-radio> | ||||
|                 <el-radio label="1">个人二维码</el-radio> | ||||
|               </el-radio-group> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="上传二维码" prop="codeUrl" style="width: 100%;" :rules="[{ required: true, message: '请上传二维码', trigger: 'change' }]"> | ||||
|               <ai-uploader :instance="instance" v-model="form.codeUrl" :limit="1"></ai-uploader> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </template> | ||||
|       </ai-card> | ||||
|     </template> | ||||
|     <template #footer> | ||||
|       <el-button @click="cancel">取消</el-button> | ||||
|       <el-button type="primary" @click="confirm">提交</el-button> | ||||
|     </template> | ||||
|   </ai-detail> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     name: 'Add', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       params: Object | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         info: {}, | ||||
|         form: { | ||||
|           areaId: '', | ||||
|           codeName: '', | ||||
|           areaName: '', | ||||
|           code: '', | ||||
|           codeUrl: [], | ||||
|           type: '', | ||||
|         }, | ||||
|         id: '' | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created () { | ||||
|       if (this.params && this.params.areaId && !this.params.id) { | ||||
|         this.form.areaId = this.params.areaId | ||||
|         this.form.areaName = this.params.areaName | ||||
|       } | ||||
|  | ||||
|       if (this.params && this.params.id) { | ||||
|         this.id = this.params.id | ||||
|         this.getInfo(this.params.id) | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getInfo (id) { | ||||
|         this.instance.post(`/app/appeveryvillagecode/queryDetailById?id=${id}`).then(res => { | ||||
|           if (res.code === 0) { | ||||
|             this.form = res.data | ||||
|             this.form.codeUrl = [{ | ||||
|               url: res.data.codeUrl | ||||
|             }] | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       onClose () { | ||||
|         this.form.explain = '' | ||||
|       }, | ||||
|  | ||||
|       confirm () { | ||||
|         this.$refs.form.validate((valid) => { | ||||
|           if (valid) { | ||||
|             this.instance.post(`/app/appeveryvillagecode/addOrUpdate`, { | ||||
|               ...this.form, | ||||
|               codeUrl: this.form.codeUrl[0].url | ||||
|             }).then(res => { | ||||
|               if (res.code == 0) { | ||||
|                 this.$message.success('提交成功') | ||||
|                 setTimeout(() => { | ||||
|                   this.cancel(true) | ||||
|                 }, 600) | ||||
|               } | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       cancel (isRefresh) { | ||||
|         this.$emit('change', { | ||||
|           type: 'list', | ||||
|           isRefresh: !!isRefresh | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| </style> | ||||
							
								
								
									
										413
									
								
								packages/wxwork/AppVillageCode/components/List.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										413
									
								
								packages/wxwork/AppVillageCode/components/List.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,413 @@ | ||||
| <template> | ||||
|   <ai-list class="villagecode"> | ||||
|     <template slot="title"> | ||||
|       <ai-title title="一村一码" isShowBottomBorder></ai-title> | ||||
|     </template> | ||||
|     <template #left> | ||||
|       <div class="villagecode-left"> | ||||
|         <div class="villagecode-left__title"> | ||||
|           <h2>村列表</h2> | ||||
|         </div> | ||||
|         <div class="addressBook-left__list"> | ||||
|           <div class="addressBook-left__list--title"> | ||||
|             <el-input | ||||
|               class="addressBook-left__list--search" | ||||
|               size="mini" | ||||
|               clearable | ||||
|               placeholder="请输入地区名称" | ||||
|               v-model="unitName" | ||||
|               suffix-icon="iconfont iconSearch"> | ||||
|             </el-input> | ||||
|           </div> | ||||
|           <el-tree | ||||
|             :filter-node-method="filterNode" | ||||
|             ref="tree" | ||||
|             :props="defaultProps" | ||||
|             node-key="id" | ||||
|             :data="areaTree" | ||||
|             highlight-current | ||||
|             :current-node-key="search.areaId" | ||||
|             :default-expanded-keys="defaultExpanded" | ||||
|             :default-checked-keys="defaultChecked" | ||||
|             @current-change="onTreeChange"> | ||||
|           </el-tree> | ||||
|         </div> | ||||
|       </div> | ||||
|     </template> | ||||
|     <template slot="content"> | ||||
|       <ai-search-bar class="search-bar"> | ||||
|         <template #left> | ||||
|           <el-button size="small" type="primary" :disabled="isShowAdd" icon="iconfont iconAdd" @click="toAdd('')">添加活码</el-button> | ||||
|         </template> | ||||
|       </ai-search-bar> | ||||
|       <ai-table | ||||
|         :tableData="tableData" | ||||
|         :col-configs="colConfigs" | ||||
|         :total="total" | ||||
|         style="margin-top: 6px;" | ||||
|         :current.sync="search.current" | ||||
|         :size.sync="search.size" | ||||
|         @getList="getList"> | ||||
|         <el-table-column slot="tags" label="标签"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="table-tags"> | ||||
|               <el-tag type="info" v-for="(item, index) in row.tags" size="small" :key="index">{{ item }}</el-tag> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|         <el-table-column slot="options" width="180px" fixed="right" label="操作" align="center"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="table-options"> | ||||
|               <el-popover | ||||
|                   placement="bottom" | ||||
|                   width="160" | ||||
|                   :visible-arrow="false" | ||||
|                   popper-class="wechat-message__container" | ||||
|                   trigger="hover"> | ||||
|                 <el-button type="text" slot="reference">二维码</el-button> | ||||
|                 <div style="font-size: 0;"> | ||||
|                   <img class="message-info__img" :src="row.codeUrl"> | ||||
|                 </div> | ||||
|               </el-popover> | ||||
|               <el-button type="text" @click="toAdd(row.id)">编辑</el-button> | ||||
|               <el-button type="text" @click="remove(row.id)">删除</el-button> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </ai-table> | ||||
|     </template> | ||||
|   </ai-list> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import { mapState } from 'vuex' | ||||
|   export default { | ||||
|     name: 'List', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object | ||||
|     }, | ||||
|  | ||||
|     data() { | ||||
|       return { | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10, | ||||
|           status: 0, | ||||
|           title: '', | ||||
|           areaId: '' | ||||
|         }, | ||||
|         defaultExpanded: [], | ||||
|         defaultChecked: [], | ||||
|         areaTree: [], | ||||
|         defaultProps: { | ||||
|           children: 'children', | ||||
|           label: 'name' | ||||
|         }, | ||||
|         currIndex: -1, | ||||
|         total: 10, | ||||
|         colConfigs: [ | ||||
|           {prop: 'codeName', label: '名称', align: 'left'}, | ||||
|           {prop: 'type', label: '二维码类型', align: 'left', format: v => v === '0' ? '群二维码' : '个人二维码'}, | ||||
|           {prop: 'createUserName', label: '创建人'}, | ||||
|           {prop: 'createTime', label: '创建时间'}, | ||||
|           {slot: 'options', label: '操作'} | ||||
|         ], | ||||
|         areaName: '', | ||||
|         unitName: '', | ||||
|         tableData: [] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       ...mapState(['user']), | ||||
|  | ||||
|       isShowAdd () { | ||||
|         const str = this.search.areaId.substr(this.search.areaId.length - 3) | ||||
|  | ||||
|         return str === '000' | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     watch: { | ||||
|       unitName (val) { | ||||
|         this.$refs.tree.filter(val) | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     mounted() { | ||||
|       this.search.areaId = this.user.info.areaId | ||||
|       this.areaName = this.user.info.areaName | ||||
|       this.getTree() | ||||
|       this.getList() | ||||
|  | ||||
|       this.$nextTick(() => { | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getList() { | ||||
|         this.instance.post(`/app/appeveryvillagecode/list`, null, { | ||||
|           params: { | ||||
|             ...this.search | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       filterNode(value, data) { | ||||
|         if (!value) return true | ||||
|         return data.name.indexOf(value) !== -1 | ||||
|       }, | ||||
|  | ||||
|       onTreeChange (e) { | ||||
|         this.search.areaId = e.id | ||||
|         this.areaName = e.name | ||||
|         this.search.current = 1 | ||||
|  | ||||
|         this.$nextTick(() => { | ||||
|           this.getList() | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       getTree () { | ||||
|         this.instance.post(`/admin/area/queryAllArea?id=${this.user.info.areaId}`).then(res => { | ||||
|           if (res.code === 0) { | ||||
|             let parent = res.data.map(v => { | ||||
|               v.label = v.name | ||||
|               v.children = [] | ||||
|  | ||||
|               return v | ||||
|             }).filter(e => !e.parentid)[0] | ||||
|             this.defaultExpanded = [parent.id] | ||||
|             this.defaultChecked = [parent.id] | ||||
|             this.search.areaId = parent.id | ||||
|             this.addChild(parent, res.data) | ||||
|             this.areaTree = [parent] | ||||
|  | ||||
|             this.$nextTick(() => { | ||||
|               this.$refs.tree.setCurrentKey(parent.id) | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       addChild (parent, list) { | ||||
|         for (let i = 0; i < list.length; i++) { | ||||
|           if (list[i].parentId === parent.id) { | ||||
|             parent.children.push(list[i]) | ||||
|           } | ||||
|         } | ||||
|  | ||||
|         if (list.length > 0) { | ||||
|           parent['children'].map(v => this.addChild(v, list)) | ||||
|         } | ||||
|       }, | ||||
|  | ||||
|       remove(id) { | ||||
|         this.$confirm('确定删除该数据?').then(() => { | ||||
|           this.instance.post(`/app/appeveryvillagecode/delete?ids=${id}`).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.$message.success('删除成功!') | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       toAdd(id) { | ||||
|         this.$emit('change', { | ||||
|           type: 'Add', | ||||
|           params: { | ||||
|             areaName: this.areaName, | ||||
|             id: id || '', | ||||
|             areaId: this.search.areaId | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .villagecode { | ||||
|   .table-tags { | ||||
|     .el-tag { | ||||
|       margin-right: 8px; | ||||
|  | ||||
|       &:last-child { | ||||
|         margin-right: 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .addressBook-left__list { | ||||
|     height: calc(100% - 40px); | ||||
|     padding: 8px 8px; | ||||
|     overflow: auto; | ||||
|  | ||||
|     .addressBook-left__tags--item { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: space-between; | ||||
|       height: 40px; | ||||
|       padding: 0 8px 0 16px; | ||||
|       color: #222222; | ||||
|  | ||||
|       &.addressBook-left__tags--item-active, &:hover { | ||||
|         background: #E8EFFF; | ||||
|         color: #2266FF; | ||||
|  | ||||
|         i, span { | ||||
|           color: #2266FF; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       span { | ||||
|         font-size: 14px; | ||||
|       } | ||||
|  | ||||
|       i { | ||||
|         cursor: pointer; | ||||
|         color: #8e9ebf; | ||||
|         font-size: 16px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .addressBook-left__list--title { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       margin-bottom: 8px; | ||||
|  | ||||
|       .addressBook-left__list--search { | ||||
|         flex: 1; | ||||
|         :deep( input ){ | ||||
|           width: 100%; | ||||
|         } | ||||
|       } | ||||
|  | ||||
|       .el-button { | ||||
|         width: 84px; | ||||
|         flex-shrink: 1; | ||||
|         margin-right: 8px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     span { | ||||
|       color: #222222; | ||||
|       font-size: 14px; | ||||
|     } | ||||
|  | ||||
|     :deep( .el-tree ){ | ||||
|       background: transparent; | ||||
|  | ||||
|       .el-tree-node__expand-icon.is-leaf { | ||||
|         color: transparent!important; | ||||
|       } | ||||
|  | ||||
|       .el-tree-node__content > .el-tree-node__expand-icon { | ||||
|         padding: 4px; | ||||
|       } | ||||
|  | ||||
|       .el-tree-node__content { | ||||
|         height: 32px; | ||||
|       } | ||||
|  | ||||
|       .el-tree__empty-text { | ||||
|         color: #222; | ||||
|         font-size: 14px; | ||||
|       } | ||||
|  | ||||
|       .el-tree-node__children .el-tree-node__content { | ||||
|         height: 32px; | ||||
|       } | ||||
|  | ||||
|       .el-tree-node__content:hover { | ||||
|         background: #E8EFFF; | ||||
|         color: #222222; | ||||
|         border-radius: 2px; | ||||
|       } | ||||
|  | ||||
|       .is-current > .el-tree-node__content { | ||||
|         &:hover { | ||||
|           background: #2266FF; | ||||
|           color: #fff; | ||||
|         } | ||||
|  | ||||
|         background: #2266FF; | ||||
|  | ||||
|         span { | ||||
|           color: #fff; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   .villagecode-left { | ||||
|     width: 100%; | ||||
|     height: auto; | ||||
|     background: #FAFAFB; | ||||
|  | ||||
|     .villagecode-left__title { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       height: 40px; | ||||
|       padding: 0 16px; | ||||
|       background: #E5E5E5; | ||||
|  | ||||
|       h2 { | ||||
|         color: #222; | ||||
|         font-size: 14px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .villagecode-left__list { | ||||
|       height: calc(100% - 40px); | ||||
|       padding: 8px 0; | ||||
|       overflow: auto; | ||||
|  | ||||
|       span { | ||||
|         display: block; | ||||
|         height: 40px; | ||||
|         line-height: 40px; | ||||
|         padding: 0 24px; | ||||
|         color: #222222; | ||||
|         font-size: 14px; | ||||
|         cursor: pointer; | ||||
|         border-right: 2px solid transparent; | ||||
|         background: transparent; | ||||
|  | ||||
|         &:hover { | ||||
|           color: #2266FF; | ||||
|           background: #E8EFFF; | ||||
|         } | ||||
|  | ||||
|         &.left-active { | ||||
|           color: #2266FF; | ||||
|           border-color: #2266FF; | ||||
|           background: #E8EFFF; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   :deep( .ai-list__content--right ){ | ||||
|  | ||||
|     .ai-list__content--right-wrapper { | ||||
|       min-height: 100%; | ||||
|     } | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
| .message-info__img { | ||||
|   font-size: 0; | ||||
|   width: 144px; | ||||
|   height: 144px; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										64
									
								
								project/biaopin/AppFormReview/AppFormReview.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								project/biaopin/AppFormReview/AppFormReview.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| <template> | ||||
|   <div class="AppFormReview"> | ||||
|     <keep-alive :include="['List']"> | ||||
|       <component ref="component" :is="component" :permissions="permissions " @change="onChange" :params="params" :instance="instance" :dict="dict"></component> | ||||
|     </keep-alive> | ||||
|   </div> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import List from './components/List' | ||||
|   import Detail from './components/Detail' | ||||
|  | ||||
|   export default { | ||||
|     name: 'AppFormReview', | ||||
|     label: '网格动态', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       permissions: Function | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         component: 'List', | ||||
|         params: {}, | ||||
|         include: [] | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     components: { | ||||
|       List, | ||||
|       Detail | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       onChange (data) { | ||||
|         if (data.type === 'Detail') { | ||||
|           this.component = 'Detail' | ||||
|           this.params = data.params | ||||
|         } | ||||
|  | ||||
|         if (data.type === 'List') { | ||||
|           this.component = 'List' | ||||
|           this.params = data.params | ||||
|  | ||||
|           this.$nextTick(() => { | ||||
|             if (data.isRefresh) { | ||||
|               this.$refs.component.getList() | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss"> | ||||
| .AppFormReview { | ||||
|   height: 100%; | ||||
|   background: #F3F6F9; | ||||
|   overflow: auto; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										154
									
								
								project/biaopin/AppFormReview/components/Detail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								project/biaopin/AppFormReview/components/Detail.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,154 @@ | ||||
| <template> | ||||
|   <ai-detail class="AppDynamicDetail"> | ||||
|     <template slot="title"> | ||||
|       <ai-title title="详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)"> | ||||
|         <template #rightBtn> | ||||
|           <div class="title-btns"> | ||||
|             <el-button type="primary" icon="iconfont iconRegister" @click="isShowExamine = true" v-if="info.status == 0">审核</el-button> | ||||
|           </div> | ||||
|         </template> | ||||
|       </ai-title> | ||||
|     </template> | ||||
|     <template slot="content"> | ||||
|       <ai-card title="基本信息"> | ||||
|         <template #content> | ||||
|           <ai-wrapper label-width="120px"> | ||||
|             <ai-info-item label="内容" isLine :value="info.content"></ai-info-item> | ||||
|             <ai-info-item label="所属网格" isLine :value="info.girdName"></ai-info-item> | ||||
|             <ai-info-item label="类型" >{{dict.getLabel("wyGirdNewsType", info.type)}}</ai-info-item> | ||||
|             <ai-info-item label="地址" >{{info.address}}</ai-info-item> | ||||
|             <ai-info-item label="网格员姓名" :value="info.name"></ai-info-item> | ||||
|             <ai-info-item label="状态" >{{dict.getLabel("auditStatus", info.status)}}</ai-info-item> | ||||
|             <ai-info-item label="发布时间"  :value="info.createTime"></ai-info-item> | ||||
|             <ai-info-item label="图片" isLine> | ||||
|               <div class="files"> | ||||
|                 <div class="file-item" v-for="(item, index) in info.files" :key="index"> | ||||
|                   <img :src="item.url" v-viewer="{movable: true}"> | ||||
|                 </div> | ||||
|               </div> | ||||
|             </ai-info-item> | ||||
|           </ai-wrapper> | ||||
|         </template> | ||||
|       </ai-card> | ||||
|       <ai-card title="审核信息" v-if="info.status != 0"> | ||||
|         <template #content> | ||||
|           <ai-wrapper label-width="120px"> | ||||
|             <ai-info-item label="审批意见" isLine :value="info.examineOpinion"></ai-info-item> | ||||
|             <ai-info-item label="审批人" :value="info.examineUserName"></ai-info-item> | ||||
|             <ai-info-item label="审批时间" :value="info.examineTime"></ai-info-item> | ||||
|           </ai-wrapper> | ||||
|         </template> | ||||
|       </ai-card> | ||||
|        <ai-dialog | ||||
|         :visible.sync="isShowExamine" | ||||
|         width="800px" | ||||
|         title="审核" | ||||
|         @closed="isShowExamine=false" | ||||
|         @onConfirm="handleEvent"> | ||||
|         <el-form class="ai-form" label-width="120px" :model="form" ref="form"> | ||||
|           <el-form-item label="是否通过" prop="status" style="width: 100%;" :rules="[{ required: true, message: '请选择是否通过' }]"> | ||||
|             <el-radio-group v-model="form.status"> | ||||
|               <el-radio label="1">是</el-radio> | ||||
|               <el-radio label="0">否</el-radio> | ||||
|             </el-radio-group> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="审批意见" prop="opinion" style="width: 100%;" > | ||||
|             <el-input type="textarea" :rows="5" :maxlength="500" v-model="form.opinion" clearable placeholder="请输入审批意见" show-word-limit></el-input> | ||||
|           </el-form-item> | ||||
|           <!-- <el-form-item label="图片" prop="files" style="width: 100%;"> | ||||
|             <ai-uploader | ||||
|                 :instance="instance" | ||||
|                 isShowTip | ||||
|                 v-model="form.files" | ||||
|                 :limit="9"> | ||||
|             </ai-uploader> | ||||
|           </el-form-item> --> | ||||
|         </el-form> | ||||
|       </ai-dialog> | ||||
|     </template> | ||||
|   </ai-detail> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   export default { | ||||
|     name: 'Detail', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object, | ||||
|       params: Object, | ||||
|       moduleId: String | ||||
|     }, | ||||
|  | ||||
|     data () { | ||||
|       return { | ||||
|         info: {}, | ||||
|         id: '', | ||||
|         isShowExamine: false, | ||||
|         form: {status: '', opinion: ''} | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created () { | ||||
|       this.dict.load('wyGirdNewsType', 'auditStatus').then(() => { | ||||
|         this.getDetail() | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getDetail () { | ||||
|         this.instance.post(`/app/appgirdnews/queryDetailById?id=${this.params.id}`).then(res => { | ||||
|           if (res.code === 0) { | ||||
|             this.info = res.data | ||||
|             this | ||||
|             this.info = { | ||||
|               ...res.data | ||||
|             } | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       handleEvent() { | ||||
|         this.$refs.form.validate(v => { | ||||
|           if (v) { | ||||
|             this.instance.post(`/app/appgirdnews/examine?id=${this.params.id}&pass=${this.form.status}&opinion=${this.form.opinion}`).then(res => { | ||||
|               if (res?.code == 0) { | ||||
|                 this.isShowExamine = false | ||||
|                 this.$message.success('审核成功!') | ||||
|                 this.cancel(true) | ||||
|               } | ||||
|             }) | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       cancel (isRefresh) { | ||||
|         this.$emit('change', { | ||||
|           type: 'List', | ||||
|           isRefresh: !!isRefresh | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
|   .AppDynamicDetail { | ||||
|     .files { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       flex-wrap: wrap; | ||||
|       .file-item { | ||||
|         width: 150px; | ||||
|         height: 150px; | ||||
|         margin: 0 20px 20px 0; | ||||
|  | ||||
|         img, video { | ||||
|           width: 100%; | ||||
|           height: 100%; | ||||
|           object-fit: cover; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
							
								
								
									
										194
									
								
								project/biaopin/AppFormReview/components/List.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								project/biaopin/AppFormReview/components/List.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,194 @@ | ||||
| <template> | ||||
|   <ai-list class="notice"> | ||||
|     <ai-title slot="title" title="网格动态" isShowBottomBorder></ai-title> | ||||
|     <template slot="content"> | ||||
|       <ai-search-bar class="search-bar"> | ||||
|         <template #left> | ||||
|           <ai-select | ||||
|             v-model="search.type" | ||||
|             @change="(search.current = 1), getList()" | ||||
|             placeholder="请选择类型" | ||||
|             :selectList="dict.getDict('wyGirdNewsType')"> | ||||
|           </ai-select> | ||||
|           <ai-picker | ||||
|             :instance="instance" | ||||
|             :multiple="false" | ||||
|             dialogTitle="选择网格" | ||||
|             :ops="{ label: 'girdName' }" | ||||
|             pageTitle="网格" | ||||
|             action="/app/appgirdinfo/girdList" | ||||
|             @pick="onGridChange"> | ||||
|             <div class="userSelcet"> | ||||
|               <span style="color: #606266;" v-if="search.girdId">{{ search.girdName }}</span> | ||||
|               <span v-else>请选择网格</span> | ||||
|               <i class="el-icon-arrow-up"  v-if="!search.girdId"></i> | ||||
|               <i class="el-icon-circle-close" v-if="search.girdId" @click.stop="search.girdId = '', search.girdName = '', search.current = 1, getList()"></i> | ||||
|             </div> | ||||
|           </ai-picker> | ||||
|         </template> | ||||
|         <template #right> | ||||
|           <el-input | ||||
|             v-model="search.content" | ||||
|             class="search-input" | ||||
|             size="small" | ||||
|             v-throttle="() => {search.current = 1, getList()}" | ||||
|             placeholder="内容" | ||||
|             clearable | ||||
|             @clear="search.current = 1, search.content = '', getList()" | ||||
|             suffix-icon="iconfont iconSearch"> | ||||
|           </el-input> | ||||
|         </template> | ||||
|       </ai-search-bar> | ||||
|       <ai-table | ||||
|         :tableData="tableData" | ||||
|         :col-configs="colConfigs" | ||||
|         :total="total" | ||||
|         style="margin-top: 6px;" | ||||
|         :current.sync="search.current" | ||||
|         :size.sync="search.size" | ||||
|         @getList="getList"> | ||||
|         <el-table-column slot="options" width="120px" fixed="right" label="操作" align="center"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="table-options"> | ||||
|               <el-button type="text" @click="toDetail(row.id)">详情</el-button> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </ai-table> | ||||
|     </template> | ||||
|   </ai-list> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
|   import { mapState } from 'vuex' | ||||
|   export default { | ||||
|     name: 'List', | ||||
|  | ||||
|     props: { | ||||
|       instance: Function, | ||||
|       dict: Object | ||||
|     }, | ||||
|  | ||||
|     data() { | ||||
|       return { | ||||
|         search: { | ||||
|           current: 1, | ||||
|           size: 10, | ||||
|           content: '', | ||||
|           areaId: '', | ||||
|           girdId: '', | ||||
|           girdName: '' | ||||
|         }, | ||||
|         total: 0, | ||||
|         colConfigs: [ | ||||
|           { prop: 'content',  label: '内容', align: 'left', width: '200px' }, | ||||
|           { prop: 'girdName', label: '所属网格', align: 'center' }, | ||||
|           { prop: 'type', align: 'center', label: '类型', dict:"wyGirdNewsType"}, | ||||
|           { prop: 'address', label: '地址', align: 'center' }, | ||||
|           { prop: 'name',  label: '网格员姓名', align: 'center' }, | ||||
|           { prop: 'status', align: 'center', label: '状态', dict:"auditStatus"}, | ||||
|           { prop: 'createTime', label: '发布时间', align: 'center' } | ||||
|         ], | ||||
|         tableData: [], | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     computed: { | ||||
|       ...mapState(['user']), | ||||
|  | ||||
|       hideLevel () { | ||||
|         return this.user.info.areaList.length || 0 | ||||
|       }, | ||||
|  | ||||
|       params () { | ||||
|         return { | ||||
|           ...this.search | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|  | ||||
|     created() { | ||||
|       this.dict.load('wyGirdNewsType', 'auditStatus').then(() => { | ||||
|         this.getList() | ||||
|       }) | ||||
|     }, | ||||
|  | ||||
|     methods: { | ||||
|       getList () { | ||||
|         this.instance.post(`/app/appgirdnews/list`, null, { | ||||
|           params: { | ||||
|             ...this.search | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res.code == 0) { | ||||
|             this.tableData = res.data.records | ||||
|             this.total = res.data.total | ||||
|           } | ||||
|         }) | ||||
|       }, | ||||
|  | ||||
|       onGridChange (e) { | ||||
|         if (e.length) { | ||||
|           this.search.girdId = e[0].id | ||||
|           this.search.girdName = e[0].girdName | ||||
|           this.search.current = 1 | ||||
|           this.getList() | ||||
|         } | ||||
|       }, | ||||
|  | ||||
|       toDetail(id) { | ||||
|         this.$emit('change', { | ||||
|           type: 'Detail', | ||||
|           params: { | ||||
|             id: id || '' | ||||
|           } | ||||
|         }) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
|   .userSelcet { | ||||
|     display: flex; | ||||
|     align-items: center; | ||||
|     justify-content: space-between; | ||||
|     width: 215px; | ||||
|     height: 32px; | ||||
|     line-height: 32px; | ||||
|     border-radius: 4px; | ||||
|     border: 1px solid #d0d4dc; | ||||
|     overflow: hidden; | ||||
|     cursor: pointer; | ||||
|     transition: border-color 0.2s cubic-bezier(0.645, 0.045, 0.355, 1); | ||||
|  | ||||
|     &:hover { | ||||
|       border-color: $placeholderColor; | ||||
|     } | ||||
|  | ||||
|     i { | ||||
|       display: flex; | ||||
|       position: relative; | ||||
|       align-items: center; | ||||
|       justify-content: center; | ||||
|       width: 30px; | ||||
|       height: 100%; | ||||
|       line-height: 32px; | ||||
|       font-size: 14px; | ||||
|       text-align: center; | ||||
|       color: #d0d4dc; | ||||
|       transform: rotateZ(180deg); | ||||
|     } | ||||
|  | ||||
|     .el-icon-circle-close:hover { | ||||
|       opacity: 0.6; | ||||
|     } | ||||
|  | ||||
|     span { | ||||
|       flex: 1; | ||||
|       padding: 0 15px; | ||||
|       font-size: 12px; | ||||
|       color: $placeholderColor; | ||||
|     } | ||||
|   } | ||||
| </style> | ||||
| @@ -17,8 +17,9 @@ | ||||
|           <el-table-column slot="scoringCycle" label="周期范围" align="center"> | ||||
|             <template slot-scope="{ row }"> | ||||
|               <span v-if="row.parentRuleName == '工单处理'">-</span> | ||||
|               <span v-else>{{row.numberLimit.length ? $dict.getLabel("integralRuleScoringCycle", row.scoringCycle) | ||||
|               <span v-if="row.parentRuleName != '工单处理' && row.numberLimit">{{row.numberLimit.length ? $dict.getLabel("integralRuleScoringCycle", row.scoringCycle) | ||||
|                     : $dict.getLabel("integralRuleScoringCycle", row.scoringCycle) + row.numberLimit + "次"}}</span> | ||||
|               <span v-if="row.parentRuleName != '工单处理' && !row.numberLimit">{{$dict.getLabel("integralRuleScoringCycle", row.scoringCycle) + "不限次"}}</span> | ||||
|             </template> | ||||
|           </el-table-column> | ||||
|           <el-table-column slot="integral" label="分值" align="center"> | ||||
|   | ||||
| @@ -10,6 +10,10 @@ | ||||
|               <el-input v-model="form.title" placeholder="请输入" show-word-limit maxlength="64"></el-input> | ||||
|             </el-form-item> | ||||
|  | ||||
|             <el-form-item label="名额" prop="quota" style="width: 100%"> | ||||
|               <el-input-number v-model="form.quota" :min="1" :max="1000" label="请输入"></el-input-number> | ||||
|             </el-form-item> | ||||
|  | ||||
|             <el-form-item label="活动说明" style="width: 100%"> | ||||
|               <el-input type="textarea" :rows="5" v-model="form.detail" placeholder="请输入" show-word-limit maxlength="500"></el-input> | ||||
|             </el-form-item> | ||||
| @@ -124,6 +128,7 @@ export default { | ||||
|     return { | ||||
|       form: { | ||||
|         title: '', | ||||
|         quota: 1, | ||||
|         detail: '', | ||||
|         lng: '', | ||||
|         lat: '', | ||||
| @@ -144,6 +149,7 @@ export default { | ||||
|       }, | ||||
|       formRules: { | ||||
|         title: [{required: true, message: "请输入活动名称", trigger: "blur"}], | ||||
|         quota: [{required: true, message: "请输入名额", trigger: "blur"}], | ||||
|         location: [{required: true, validator: validLocation, trigger: "blur"}], | ||||
|         clockRange: [{required: true, message: "请输入打卡范围", trigger: "blur"}], | ||||
|         intoTime: [{required: true, message: "请选择进场打卡时间", trigger: "blur"}], | ||||
| @@ -185,17 +191,17 @@ export default { | ||||
|   watch: { | ||||
|     'form.intoTime': { | ||||
|       handler(val) { | ||||
|         if(val) { | ||||
|           this.form.intoBegintime = val[0] | ||||
|           this.form.intoEndtime = val[1] | ||||
|         if (Array.isArray(val) && val.length >= 2) { | ||||
|           this.form.intoBegintime = val[0]; | ||||
|           this.form.intoEndtime = val[1]; | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     'form.exitTime': { | ||||
|       handler(val) { | ||||
|         if(val) { | ||||
|           this.form.exitBegintime = val[0] | ||||
|           this.form.exitEndtime = val[1] | ||||
|         if (Array.isArray(val) && val.length >= 2) { | ||||
|           this.form.exitBegintime = val[0]; | ||||
|           this.form.exitEndtime = val[1]; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
|         <template #content> | ||||
|           <ai-wrapper> | ||||
|             <ai-info-item label="活动名称" :value="info.title"></ai-info-item> | ||||
|             <ai-info-item label="名额" :value="info.quota"></ai-info-item> | ||||
|             <ai-info-item label="创建人" :value="info.createUserName"></ai-info-item> | ||||
|             <ai-info-item label="活动说明" isLine :value="info.detail"></ai-info-item> | ||||
|             <ai-info-item label="活动图片" isLine> | ||||
|   | ||||
| @@ -7,29 +7,26 @@ | ||||
|           <el-tab-pane label="方案设置"> | ||||
|             <el-form ref="AddForm" :model="form" size="small" label-width="120px" :rules="rules"> | ||||
|               <ai-card title="基本信息"> | ||||
|                 <template #content> | ||||
|                   <el-form-item label="项目/系统名称" prop="name"> | ||||
|                     <el-input v-model="form.name" placeholder="请输入" clearable/> | ||||
|                 <div class="grid"> | ||||
|                   <el-form-item label="项目/系统名称" prop="name" class="row"> | ||||
|                     <ai-input v-model="form.name"/> | ||||
|                   </el-form-item> | ||||
|                   <el-row type="flex"> | ||||
|                     <div class="fill"> | ||||
|                   <el-form-item label="系统类型" prop="type"> | ||||
|                         <ai-select v-model="form.type" :selectList="dict.getDict('systemType')" @change="form.apps = [],handleSysTypeChange(form.type)"/> | ||||
|                     <ai-select v-model="form.type" dict="systemType" @change="form.apps = []"/> | ||||
|                   </el-form-item> | ||||
|                   <el-form-item label="库项目根路径" prop="customPath"> | ||||
|                     <ai-input v-model="form.customPath"/> | ||||
|                   </el-form-item> | ||||
|                   <el-form-item label="更新项目路径" prop="dist"> | ||||
|                         <el-input v-model="form.dist" placeholder="常填写nginx路径,下载包从这里取" clearable/> | ||||
|                       </el-form-item> | ||||
|                     </div> | ||||
|                     <div class="fill mar-l16"> | ||||
|                       <el-form-item label="库项目根路径" prop="customPath"> | ||||
|                         <el-input v-model="form.customPath" placeholder="请输入" clearable/> | ||||
|                     <ai-input v-model="form.dist" placeholder="常填写nginx路径,下载包从这里取"/> | ||||
|                   </el-form-item> | ||||
|                   <el-form-item label="版本号" prop="version"> | ||||
|                         <el-input v-model="form.version" placeholder="请输入" clearable/> | ||||
|                     <ai-input v-model="form.version"/> | ||||
|                   </el-form-item> | ||||
|                   <el-form-item label="微信机器人" prop="webhook"> | ||||
|                     <ai-input v-model="form.webhook"/> | ||||
|                   </el-form-item> | ||||
|                 </div> | ||||
|                   </el-row> | ||||
|                 </template> | ||||
|               </ai-card> | ||||
|               <ai-card title="主库应用"> | ||||
|                 <template #content> | ||||
| @@ -38,179 +35,15 @@ | ||||
|                   <ai-empty v-else>请先选择系统类型</ai-empty> | ||||
|                 </template> | ||||
|               </ai-card> | ||||
|               <ai-card title="扩展设置"> | ||||
|                 <template #right> | ||||
|                   <template v-if="form.type=='web'"> | ||||
|                     <ai-dialog-btn text="设置系统信息" dialogTitle="系统信息"> | ||||
|                       <el-form size="small" label-width="140px"> | ||||
|                         <el-form-item label="系统标题"> | ||||
|                           <el-input v-model="form.sysInfo.fullTitle" placeholder="请输入..." clearable/> | ||||
|                         </el-form-item> | ||||
|                         <el-form-item label="favicon"> | ||||
|                           <el-input v-model="form.sysInfo.favicon" placeholder="请输入..." clearable/> | ||||
|                         </el-form-item> | ||||
|                         <el-form-item label="logo"> | ||||
|                           <el-row type="flex"> | ||||
|                             <el-input v-model="form.sysInfo.logo" placeholder="请输入..." clearable/> | ||||
|                             <el-input class="mar-l10" v-model="form.sysInfo.logoText" placeholder="logo文字"> | ||||
|                               <template #prepend>logo文字</template> | ||||
|                             </el-input> | ||||
|                           </el-row> | ||||
|                         </el-form-item> | ||||
|                         <el-form-item label="登录页"> | ||||
|                           <el-row type="flex" class="mar-b10"> | ||||
|                             <el-input v-model="form.sysInfo.loginLogo" placeholder="登录页左上角logo,带/代表图片" clearable> | ||||
|                               <template #prepend>左页首logo</template> | ||||
|                             </el-input> | ||||
|                             <el-input class="mar-l10" v-model="form.sysInfo.loginLogoText" placeholder="logo文字" clearable> | ||||
|                               <template #prepend>logo文字</template> | ||||
|                             </el-input> | ||||
|                           </el-row> | ||||
|                           <el-row type="flex"> | ||||
|                             <el-input v-model="form.sysInfo.name" placeholder="左上角标题" clearable> | ||||
|                               <template #prepend>左上角标题</template> | ||||
|                             </el-input> | ||||
|                             <el-input class="mar-l10" v-model="form.sysInfo.title" placeholder="左上角副标题" clearable> | ||||
|                               <template #prepend>左上角副标题</template> | ||||
|                             </el-input> | ||||
|                           </el-row> | ||||
|                           <el-input class="mar-t10" type="textarea" rows="5" v-model="form.sysInfo.desc" placeholder="副标题" clearable/> | ||||
|                         </el-form-item> | ||||
|                         <el-row type="flex"> | ||||
|                           <div class="fill"> | ||||
|                             <el-form-item label="版权所有"> | ||||
|                               <el-input v-model="form.sysInfo.recordDesc" placeholder="请输入..." clearable/> | ||||
|                             </el-form-item> | ||||
|                             <el-form-item label="备案号"> | ||||
|                               <el-input v-model="form.sysInfo.recordNo" placeholder="请输入..." clearable/> | ||||
|                             </el-form-item> | ||||
|                           </div> | ||||
|                           <div class="fill"> | ||||
|                             <el-form-item label="框架版本"> | ||||
|                               <!--edition :版本,标准版:standard、上架版:saas 简易版(不带扫码):simple --> | ||||
|                               <el-input v-model="form.sysInfo.edition" placeholder="请输入..." clearable/> | ||||
|                             </el-form-item> | ||||
|                             <el-form-item label="备案跳转链接"> | ||||
|                               <el-input v-model="form.sysInfo.recordURL" placeholder="请输入..." clearable/> | ||||
|                             </el-form-item> | ||||
|                           </div> | ||||
|                         </el-row> | ||||
|                         <el-form-item label="可信证书"> | ||||
|                           <el-input type="textarea" v-model="form.sysInfo.ssl" placeholder="请输入可信证书的html代码" clearable rows="5"/> | ||||
|                         </el-form-item> | ||||
|                       </el-form> | ||||
|                     </ai-dialog-btn> | ||||
|                   </template> | ||||
|                 </template> | ||||
|                 <template #content> | ||||
|                   <template v-if="form.type=='mp'"> | ||||
|                     <el-form-item label="小程序AppId"> | ||||
|                       <el-input v-model="form.appId" clearable placeholder="小程序appId"/> | ||||
|                     </el-form-item> | ||||
|                     <el-form-item label="半屏小程序"> | ||||
|                       <el-input v-model="form.embeddedAppIdList" clearable placeholder="如果有多个,请用英文','分割"/> | ||||
|                     </el-form-item> | ||||
|                     <el-form-item label="接口是否单服务"> | ||||
|                       <el-checkbox v-model="form.isSingleService"/> | ||||
|                     </el-form-item> | ||||
|                     <el-form-item label="引导页"> | ||||
|                       <el-input v-model="form.guide" placeholder="带'/'会被认为是输入的页面路径" clearable/> | ||||
|                     </el-form-item> | ||||
|                     <ai-title title="底部导航栏"> | ||||
|                       <el-button type="text" slot="rightBtn" icon="iconfont iconAdd" @click="tabBar.list.push({})">添加</el-button> | ||||
|                     </ai-title> | ||||
|                     <ai-table :tableData="tabBar.list" :colConfigs="colConfigs" tableSize="mini" :isShowPagination="false" border ref="TabBar"> | ||||
|                       <el-table-column slot="options" label="操作" width="260" align="center"> | ||||
|                         <template slot-scope="{row,$index}"> | ||||
|                           <el-row type="flex" class="tabBarOptions"> | ||||
|                             <ai-dialog-btn text="更换" dialogTitle="选择应用"> | ||||
|                               <ai-lib-table :meta="appList" v-model="row.id" @select="v=>handleTabbarChange(row,v)" :isShowPagination="false" v-bind="$props" | ||||
|                                             :border="false"/> | ||||
|                             </ai-dialog-btn> | ||||
|                             <ai-dialog-btn text="编辑" dialogTitle="编辑导航栏" width="600px"> | ||||
|                               <el-form-item label="名称"> | ||||
|                                 <el-input v-model="row.text" placeholder="请输入" clearable/> | ||||
|                               </el-form-item> | ||||
|                               <el-form-item label="默认图标"> | ||||
|                                 <el-input v-model="row.iconPath" placeholder="请输入" clearable/> | ||||
|                               </el-form-item> | ||||
|                               <el-form-item label="选中图标"> | ||||
|                                 <el-input v-model="row.selectedIconPath" placeholder="请输入" clearable/> | ||||
|                               </el-form-item> | ||||
|                             </ai-dialog-btn> | ||||
|                             <el-button type="text" @click="handleTabbarDelete($index)">删除</el-button> | ||||
|                             <el-button type="text" @click="handleTabbarPosition($index,-1)" v-if="$index>0">上移</el-button> | ||||
|                             <el-button type="text" @click="handleTabbarPosition($index,1)" v-if="$index<tabBar.list.length-1">下移</el-button> | ||||
|                           </el-row> | ||||
|                         </template> | ||||
|                       </el-table-column> | ||||
|                     </ai-table> | ||||
|                   </template> | ||||
|                   <template v-else-if="form.type=='wxwork'"> | ||||
|                     <el-row type="flex"> | ||||
|                       <div class="fill"> | ||||
|                         <el-form-item label="接口是否单服务"> | ||||
|                           <el-checkbox v-model="form.isSingleService"/> | ||||
|                         </el-form-item> | ||||
|                         <el-form-item label="是否启用水印"> | ||||
|                           <el-checkbox v-model="form.waterMarker"/> | ||||
|                         </el-form-item> | ||||
|                         <el-form-item label="自定义登录"> | ||||
|                           <el-checkbox v-model="form.customLogin"/> | ||||
|                         </el-form-item> | ||||
|                       </div> | ||||
|                       <div class="fill"> | ||||
|                         <el-form-item label="域名根目录(baseURL)"> | ||||
|                           <el-input v-model="form.base" clearable placeholder="域名根目录"/> | ||||
|                         </el-form-item> | ||||
|                         <el-form-item label="默认首页"> | ||||
|                           <el-input v-model="form.homePage" clearable placeholder="填写应用的文件名"/> | ||||
|                         </el-form-item> | ||||
|                         <el-form-item label="开启百度流量"> | ||||
|                           <el-checkbox v-model="form.hmt"/> | ||||
|                         </el-form-item> | ||||
|                       </div> | ||||
|                     </el-row> | ||||
|                   </template> | ||||
|                   <template v-else-if="form.type=='web'"> | ||||
|                     <el-form-item label="头部导航工具栏"> | ||||
|                       <el-checkbox v-model="form.downloadCenter">下载中心</el-checkbox> | ||||
|                       <el-checkbox v-model="form.dv">数据大屏</el-checkbox> | ||||
|                       <el-checkbox v-model="form.showTool">显示/隐藏导航栏</el-checkbox> | ||||
|                       <el-checkbox v-model="form.helpDoc">帮助文档</el-checkbox> | ||||
|                       <el-checkbox v-model="form.customerService">智能客服</el-checkbox> | ||||
|                       <el-checkbox v-model="form.appQRCode">手机APP</el-checkbox> | ||||
|                     </el-form-item> | ||||
|                     <el-row type="flex"> | ||||
|                       <div class="fill"> | ||||
|                         <el-form-item label="接口是否单服务"> | ||||
|                           <el-checkbox v-model="form.isSingleService"/> | ||||
|                         </el-form-item> | ||||
|                         <el-form-item label="默认首页"> | ||||
|                           <el-input v-model="form.homePage" clearable placeholder="填写应用的文件名"/> | ||||
|                         </el-form-item> | ||||
|                         <el-form-item label="是否加载AI助手"> | ||||
|                           <el-checkbox v-model="form.copilot"/> | ||||
|                         </el-form-item> | ||||
|                       </div> | ||||
|                       <div class="fill"> | ||||
|                         <el-form-item label="域名根目录"> | ||||
|                           <el-input v-model="form.base" clearable placeholder="填写域名根目录(baseURL)"/> | ||||
|                         </el-form-item> | ||||
|                         <el-form-item label="开启百度流量"> | ||||
|                           <el-checkbox v-model="form.hmt"/> | ||||
|                         </el-form-item> | ||||
|                       </div> | ||||
|                     </el-row> | ||||
|                   </template> | ||||
|                 </template> | ||||
|               </ai-card> | ||||
|               <component class="extraConfig" title="扩展设置" :is="extraConfig" v-model="form.extra" :appList="appList"/> | ||||
|             </el-form> | ||||
|           </el-tab-pane> | ||||
|           <el-tab-pane label="方案应用" lazy> | ||||
|             <ai-lib-table :meta="appList" customData :isShowPagination="false" v-bind="$props" disabled :colConfigs="appListConfigs"> | ||||
|             <ai-lib-table :meta="appList" customData :isShowPagination="false" v-bind="$props" disabled | ||||
|                           :colConfigs="appListConfigs"> | ||||
|               <template slot="options" slot-scope="{row}"> | ||||
|                 <ai-dialog-btn text="编辑" :customFooter="false" dialogTitle="应用配置" width="500px" @onConfirm="handleAppEdit(row)"> | ||||
|                 <ai-dialog-btn text="编辑" :customFooter="false" dialogTitle="应用配置" width="500px" | ||||
|                                @onConfirm="handleAppEdit(row)"> | ||||
|                   <el-form size="small" label-width="80px"> | ||||
|                     <el-form-item label="应用名称"> | ||||
|                       <el-input v-model="row.label" clearable placeholder="请输入应用名称"/> | ||||
| @@ -233,6 +66,9 @@ | ||||
| <script> | ||||
| import {mapActions} from "vuex" | ||||
| import AiLibTable from "./AiLibTable"; | ||||
| import webConfig from "./config/webConfig.vue"; | ||||
| import wxcpConfig from "./config/wxcpConfig.vue"; | ||||
| import wxmpConfig from "./config/wxmpConfig.vue"; | ||||
|  | ||||
| export default { | ||||
|   name: "add", | ||||
| @@ -256,41 +92,26 @@ export default { | ||||
|         return e | ||||
|       }).filter(e => e.project != "core") || [] | ||||
|     }, | ||||
|     extraConfig: v => ({ | ||||
|       web: webConfig, | ||||
|       wxwork: wxcpConfig, | ||||
|       mp: wxmpConfig | ||||
|     }[v.form.type]) | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       form: {apps: [], type: null, sysInfo: {}, customPath: ""}, | ||||
|       form: {apps: [], type: null, customPath: "", extra: {sysInfo: {}}}, | ||||
|       rules: { | ||||
|         name: {required: true, message: "请输入"}, | ||||
|         type: {required: true, message: "请选择"}, | ||||
|         // customPath: {required: true, message: "请输入"}, | ||||
|       }, | ||||
|       colConfigs: [ | ||||
|         {prop: 'text', label: "名称", width: 120}, | ||||
|         {prop: 'pagePath', label: "应用路径"}, | ||||
|         {prop: 'iconPath', label: "默认图标"}, | ||||
|         {prop: 'selectedIconPath', label: "选中图标"}, | ||||
|       ], | ||||
|       appListConfigs: [ | ||||
|         {prop: 'label', label: "应用名称", render: (h, {row}) => h(row.tabbar ? 'b' : 'p', row.label + `  ${row.tabbar ? '(底部导航栏)' : ''}`)}, | ||||
|         {prop: 'project', label: "项目/框架"}, | ||||
|         {prop: 'category', label: "分类", dict: "appsCategory"}, | ||||
|         {prop: 'name', label: "模块名"} | ||||
|       ], | ||||
|       tabBar: { | ||||
|         color: "#666666", | ||||
|         selectedColor: "#197DF0", | ||||
|         backgroundColor: "#ffffff", | ||||
|         list: [ | ||||
|           {pagePath: "pages/AppHome/AppHome", text: "首页", iconPath: "static/TabBar/home.png", selectedIconPath: "static/TabBar/home_selected.png"}, | ||||
|           {pagePath: "pages/AppModules/AppModules", text: "应用", iconPath: "static/TabBar/service.png", selectedIconPath: "static/TabBar/service_selected.png"}, | ||||
|           { | ||||
|             pagePath: "pages/AppEnteringVillage/AppEnteringVillage", text: "进村", | ||||
|             iconPath: "static/TabBar/custom.png", selectedIconPath: "static/TabBar/custom_selected.png" | ||||
|           }, | ||||
|           {pagePath: "pages/AppMine/AppMine", text: "我的", iconPath: "static/TabBar/me.png", selectedIconPath: "static/TabBar/me_selected.png"} | ||||
|         ] | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
| @@ -302,7 +123,6 @@ export default { | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.form = {...this.form, ...res.data} | ||||
|           this.handleSysTypeChange(this.form.type, this.form.extra) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
| @@ -313,37 +133,9 @@ export default { | ||||
|     submit() { | ||||
|       this.$refs.AddForm.validate(v => { | ||||
|         if (v) { | ||||
|           const { | ||||
|             tabBar, | ||||
|             form: { | ||||
|               type, | ||||
|               appId, | ||||
|               embeddedAppIdList, | ||||
|               isSingleService, | ||||
|               homePage, | ||||
|               hmt, | ||||
|               dv, | ||||
|               downloadCenter, | ||||
|               showTool, | ||||
|               helpDoc, | ||||
|               customerService, | ||||
|               sysInfo, | ||||
|               appQRCode, | ||||
|               customLogin, | ||||
|               base, | ||||
|               guide, | ||||
|               copilot | ||||
|             } | ||||
|           } = this | ||||
|           if (type == 'mp') { | ||||
|             this.form.extra = {tabBar, appId, embeddedAppIdList, isSingleService, guide} | ||||
|           } else if (type == 'web') { | ||||
|             const {desc} = sysInfo | ||||
|             sysInfo.desc = JSON.parse(desc || null) | ||||
|             sysInfo.ssl = sysInfo.ssl?.replace(/"/g, "'") | ||||
|             this.form.extra = {isSingleService, homePage, hmt, dv, downloadCenter, showTool, helpDoc, customerService, sysInfo, appQRCode, base, copilot} | ||||
|           } else if (type == 'wxwork') { | ||||
|             this.form.extra = {isSingleService, homePage, hmt, customLogin, base} | ||||
|           if (this.form.type == 'web') { | ||||
|             this.form.extra.sysInfo.desc = JSON.parse(this.form.extra.sysInfo.desc || null) | ||||
|             this.form.extra.sysInfo.ssl = this.form.extra.sysInfo.ssl?.replace(/"/g, "'") | ||||
|           } | ||||
|           this.instance.post("/node/custom/addOrUpdate", this.form).then(res => { | ||||
|             if (res?.code == 0) { | ||||
| @@ -354,34 +146,11 @@ export default { | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     handleSysTypeChange(v, data = {}) { | ||||
|       let values = this.$copy(data) | ||||
|       if (v == 'mp') { | ||||
|         if (values?.tabBar) { | ||||
|           this.tabBar = values.tabBar || this.tabBar | ||||
|           delete values.tabBar | ||||
|         } | ||||
|       } else if (v == 'web') { | ||||
|         if (values?.sysInfo?.desc) values.sysInfo.desc = JSON.stringify(values.sysInfo.desc) | ||||
|       } | ||||
|       Object.keys(values).map(e => this.$set(this.form, e, values[e])) | ||||
|     }, | ||||
|     handleTabbarChange(row, {name, label}) { | ||||
|       row.text = label | ||||
|       row.pagePath = `pages/${name}/${name}` | ||||
|     }, | ||||
|     handleTabbarDelete(i) { | ||||
|       this.tabBar.list?.splice(i, 1) | ||||
|     }, | ||||
|     handleAppEdit(row) { | ||||
|       const i = this.form.appList.findIndex(e => e.id == row.id) | ||||
|       this.form.appList.splice(i, 1, row) | ||||
|     }, | ||||
|     handleTabbarPosition(i, offset) { | ||||
|       const row = this.tabBar.list[i] | ||||
|       this.tabBar.list.splice(i, 1, this.tabBar.list[i + offset]) | ||||
|       this.tabBar.list.splice(i + offset, 1, row) | ||||
|     } | ||||
|  | ||||
|   }, | ||||
|   created() { | ||||
|     this.getDetail() | ||||
| @@ -404,5 +173,16 @@ export default { | ||||
|       margin-left: 0; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   :deep(.extraConfig) { | ||||
|     .ai-card__body { | ||||
|       display: grid; | ||||
|       grid-template-columns: 1fr 1fr; | ||||
|  | ||||
|       .row { | ||||
|         grid-column: span 2; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
|   | ||||
							
								
								
									
										116
									
								
								project/oms/apps/develop/AppDeployCustom/config/webConfig.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								project/oms/apps/develop/AppDeployCustom/config/webConfig.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | ||||
| <script> | ||||
| export default { | ||||
|   name: "webConfig", | ||||
|   model: { | ||||
|     prop: "form", | ||||
|     event: "input" | ||||
|   }, | ||||
|   props: { | ||||
|     form: { default: () => ({ sysInfo: {} }) }, | ||||
|     title: String | ||||
|   }, | ||||
|   watch: { | ||||
|     form: { | ||||
|       handler(v) { | ||||
|         this.$emit("input", v) | ||||
|       }, | ||||
|       deep: true | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-card :title="title" class="webConfig"> | ||||
|     <template #right> | ||||
|       <ai-dialog-btn text="设置系统信息" dialogTitle="系统信息"> | ||||
|         <el-form size="small" label-width="140px"> | ||||
|           <el-form-item label="系统标题"> | ||||
|             <el-input v-model="form.sysInfo.fullTitle" placeholder="请输入..." clearable /> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="favicon"> | ||||
|             <el-input v-model="form.sysInfo.favicon" placeholder="请输入..." clearable /> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="logo"> | ||||
|             <el-row type="flex"> | ||||
|               <el-input v-model="form.sysInfo.logo" placeholder="请输入..." clearable /> | ||||
|               <el-input class="mar-l10" v-model="form.sysInfo.logoText" placeholder="logo文字"> | ||||
|                 <template #prepend>logo文字</template> | ||||
|               </el-input> | ||||
|             </el-row> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="登录页"> | ||||
|             <el-row type="flex" class="mar-b10"> | ||||
|               <el-input v-model="form.sysInfo.loginLogo" placeholder="登录页左上角logo,带/代表图片" clearable> | ||||
|                 <template #prepend>左页首logo</template> | ||||
|               </el-input> | ||||
|               <el-input class="mar-l10" v-model="form.sysInfo.loginLogoText" placeholder="logo文字" clearable> | ||||
|                 <template #prepend>logo文字</template> | ||||
|               </el-input> | ||||
|             </el-row> | ||||
|             <el-row type="flex"> | ||||
|               <el-input v-model="form.sysInfo.name" placeholder="左上角标题" clearable> | ||||
|                 <template #prepend>左上角标题</template> | ||||
|               </el-input> | ||||
|               <el-input class="mar-l10" v-model="form.sysInfo.title" placeholder="左上角副标题" clearable> | ||||
|                 <template #prepend>左上角副标题</template> | ||||
|               </el-input> | ||||
|             </el-row> | ||||
|             <el-input class="mar-t10" type="textarea" rows="5" v-model="form.sysInfo.desc" placeholder="副标题" | ||||
|               clearable /> | ||||
|           </el-form-item> | ||||
|           <el-row type="flex"> | ||||
|             <div class="fill"> | ||||
|               <el-form-item label="版权所有"> | ||||
|                 <el-input v-model="form.sysInfo.recordDesc" placeholder="请输入..." clearable /> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="备案号"> | ||||
|                 <el-input v-model="form.sysInfo.recordNo" placeholder="请输入..." clearable /> | ||||
|               </el-form-item> | ||||
|             </div> | ||||
|             <div class="fill"> | ||||
|               <el-form-item label="框架版本"> | ||||
|                 <!--edition :版本,标准版:standard、上架版:saas 简易版(不带扫码):simple --> | ||||
|                 <el-input v-model="form.sysInfo.edition" placeholder="请输入..." clearable /> | ||||
|               </el-form-item> | ||||
|               <el-form-item label="备案跳转链接"> | ||||
|                 <el-input v-model="form.sysInfo.recordURL" placeholder="请输入..." clearable /> | ||||
|               </el-form-item> | ||||
|             </div> | ||||
|           </el-row> | ||||
|           <el-form-item label="可信证书"> | ||||
|             <el-input type="textarea" v-model="form.sysInfo.ssl" placeholder="请输入可信证书的html代码" clearable rows="5" /> | ||||
|           </el-form-item> | ||||
|         </el-form> | ||||
|       </ai-dialog-btn> | ||||
|     </template> | ||||
|     <template #content> | ||||
|       <el-form-item label="头部导航工具栏" class="row"> | ||||
|         <el-checkbox v-model="form.downloadCenter">下载中心</el-checkbox> | ||||
|         <el-checkbox v-model="form.dv">数据大屏</el-checkbox> | ||||
|         <el-checkbox v-model="form.showTool">显示/隐藏导航栏</el-checkbox> | ||||
|         <el-checkbox v-model="form.helpDoc">帮助文档</el-checkbox> | ||||
|         <el-checkbox v-model="form.customerService">智能客服</el-checkbox> | ||||
|         <el-checkbox v-model="form.appQRCode">手机APP</el-checkbox> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="接口是否单服务"> | ||||
|         <el-checkbox v-model="form.isSingleService" /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="域名根目录"> | ||||
|         <el-input v-model="form.base" clearable placeholder="填写域名根目录(baseURL)" /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="默认首页"> | ||||
|         <el-input v-model="form.homePage" clearable placeholder="填写应用的文件名" /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="登录页"> | ||||
|         <el-input v-model="form.signPage" clearable placeholder="填写应用的文件名" /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="开启百度流量"> | ||||
|         <el-checkbox v-model="form.hmt" /> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="是否加载AI助手"> | ||||
|         <el-checkbox v-model="form.copilot" /> | ||||
|       </el-form-item> | ||||
|     </template> | ||||
|   </ai-card> | ||||
| </template> | ||||
| @@ -0,0 +1,51 @@ | ||||
| <script> | ||||
| export default { | ||||
|   name: "wxcpConfig", | ||||
|   model: { | ||||
|     prop: "form", | ||||
|     event: "input" | ||||
|   }, | ||||
|   props: { | ||||
|     form: Object, | ||||
|     title: String | ||||
|   }, | ||||
|   watch: { | ||||
|     form: { | ||||
|       handler() { | ||||
|         this.$emit("input", this.form) | ||||
|       }, | ||||
|       deep: true | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-card :title="title" class="wxcpConfig"> | ||||
|     <template #content> | ||||
|       <el-form-item label="默认首页"> | ||||
|         <el-input v-model="form.homePage" clearable placeholder="填写应用的文件名"/> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="域名根目录(baseURL)"> | ||||
|         <el-input v-model="form.base" clearable placeholder="域名根目录"/> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="是否启用水印"> | ||||
|         <el-checkbox v-model="form.waterMarker"/> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="接口是否单服务"> | ||||
|         <el-checkbox v-model="form.isSingleService"/> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="自定义登录"> | ||||
|         <el-checkbox v-model="form.customLogin"/> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="开启百度流量"> | ||||
|         <el-checkbox v-model="form.hmt"/> | ||||
|       </el-form-item> | ||||
|     </template> | ||||
|   </ai-card> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .wxcpConfig { | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										126
									
								
								project/oms/apps/develop/AppDeployCustom/config/wxmpConfig.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										126
									
								
								project/oms/apps/develop/AppDeployCustom/config/wxmpConfig.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,126 @@ | ||||
| <script> | ||||
| import AiLibTable from "../AiLibTable.vue"; | ||||
|  | ||||
| export default { | ||||
|   name: "wxmpConfig", | ||||
|   components: {AiLibTable}, | ||||
|   model: { | ||||
|     prop: "form", | ||||
|     event: "input" | ||||
|   }, | ||||
|   props: { | ||||
|     form: Object, | ||||
|     title: String, | ||||
|     appList: {default: () => []} | ||||
|   }, | ||||
|   watch: { | ||||
|     form: { | ||||
|       handler(v) { | ||||
|         this.$emit("input", v) | ||||
|       }, | ||||
|       deep: true | ||||
|     }, | ||||
|     tabBar: { | ||||
|       deep: true, handler(v) { | ||||
|         this.$emit("input", {...this.form, tabBar: {...v, list: v.list.filter(e => !!e.pagePath) || []}}) | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       colConfigs: [ | ||||
|         {prop: 'text', label: "名称", width: 120}, | ||||
|         {prop: 'pagePath', label: "应用路径"}, | ||||
|         {prop: 'iconPath', label: "默认图标"}, | ||||
|         {prop: 'selectedIconPath', label: "选中图标"}, | ||||
|       ], | ||||
|       tabBar: { | ||||
|         color: "#666666", | ||||
|         selectedColor: "#197DF0", | ||||
|         backgroundColor: "#ffffff", | ||||
|         list: [ | ||||
|           {pagePath: "pages/AppHome/AppHome", text: "首页", iconPath: "static/TabBar/home.png", selectedIconPath: "static/TabBar/home_selected.png"}, | ||||
|           {pagePath: "pages/AppModules/AppModules", text: "应用", iconPath: "static/TabBar/service.png", selectedIconPath: "static/TabBar/service_selected.png"}, | ||||
|           { | ||||
|             pagePath: "pages/AppEnteringVillage/AppEnteringVillage", text: "进村", | ||||
|             iconPath: "static/TabBar/custom.png", selectedIconPath: "static/TabBar/custom_selected.png" | ||||
|           }, | ||||
|           {pagePath: "pages/AppMine/AppMine", text: "我的", iconPath: "static/TabBar/me.png", selectedIconPath: "static/TabBar/me_selected.png"} | ||||
|         ] | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     handleTabbarChange(row, {name, label}) { | ||||
|       row.text = label | ||||
|       row.pagePath = `pages/${name}/${name}` | ||||
|     }, | ||||
|     handleTabbarDelete(i) { | ||||
|       this.tabBar.list?.splice(i, 1) | ||||
|     }, | ||||
|     handleTabbarPosition(i, offset) { | ||||
|       const row = this.tabBar.list[i] | ||||
|       this.tabBar.list.splice(i, 1, this.tabBar.list[i + offset]) | ||||
|       this.tabBar.list.splice(i + offset, 1, row) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     if (this.form.tabBar?.list?.length > 0) { | ||||
|       this.tabBar = this.form.tabBar | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-card :title="title" class="wxmpConfig"> | ||||
|     <template #content> | ||||
|       <el-form-item label="小程序AppId"> | ||||
|         <el-input v-model="form.appId" clearable placeholder="小程序appId"/> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="半屏小程序"> | ||||
|         <el-input v-model="form.embeddedAppIdList" clearable placeholder="如果有多个,请用英文','分割"/> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="接口是否单服务"> | ||||
|         <el-checkbox v-model="form.isSingleService"/> | ||||
|       </el-form-item> | ||||
|       <el-form-item label="引导页"> | ||||
|         <el-input v-model="form.guide" placeholder="带'/'会被认为是输入的页面路径" clearable/> | ||||
|       </el-form-item> | ||||
|       <ai-title class="row" title="底部导航栏"> | ||||
|         <el-button type="text" slot="rightBtn" icon="iconfont iconAdd" @click="tabBar.list.push({})">添加</el-button> | ||||
|       </ai-title> | ||||
|       <ai-table class="row" :tableData="tabBar.list" :colConfigs="colConfigs" tableSize="mini" :isShowPagination="false" border ref="TabBar"> | ||||
|         <el-table-column slot="options" label="操作" width="260" align="center"> | ||||
|           <template slot-scope="{row,$index}"> | ||||
|             <el-row type="flex" class="tabBarOptions"> | ||||
|               <ai-dialog-btn text="更换" dialogTitle="选择应用"> | ||||
|                 <ai-lib-table :meta="appList" v-model="row.id" @select="v=>handleTabbarChange(row,v)" :isShowPagination="false" v-bind="$props" | ||||
|                               :border="false"/> | ||||
|               </ai-dialog-btn> | ||||
|               <ai-dialog-btn text="编辑" dialogTitle="编辑导航栏" width="600px"> | ||||
|                 <el-form-item label="名称"> | ||||
|                   <el-input v-model="row.text" placeholder="请输入" clearable/> | ||||
|                 </el-form-item> | ||||
|                 <el-form-item label="默认图标"> | ||||
|                   <el-input v-model="row.iconPath" placeholder="请输入" clearable/> | ||||
|                 </el-form-item> | ||||
|                 <el-form-item label="选中图标"> | ||||
|                   <el-input v-model="row.selectedIconPath" placeholder="请输入" clearable/> | ||||
|                 </el-form-item> | ||||
|               </ai-dialog-btn> | ||||
|               <el-button type="text" @click="handleTabbarDelete($index)">删除</el-button> | ||||
|               <el-button type="text" @click="handleTabbarPosition($index,-1)" v-if="$index>0">上移</el-button> | ||||
|               <el-button type="text" @click="handleTabbarPosition($index,1)" v-if="$index<tabBar.list.length-1">下移</el-button> | ||||
|             </el-row> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </ai-table> | ||||
|     </template> | ||||
|   </ai-card> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .wxmpConfig { | ||||
| } | ||||
| </style> | ||||
| @@ -11,6 +11,12 @@ | ||||
|             <el-form-item style="width: 100%" label="店铺名称" prop="title" :rules="[{required: true, message: '请输入店铺名称', trigger: 'blur'}]"> | ||||
|               <el-input type="input" size="small" v-model="form.title" clearable placeholder="请输入店铺名称" :maxlength="50" show-word-limit></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item style="width: 50%" label="店家" prop="shopkeeper"> | ||||
|               <el-input type="input" size="small" v-model="form.shopkeeper" clearable placeholder="请输入店家名字" :maxlength="10" show-word-limit></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item style="width: 50%" label="联系电话" prop="phone" :rules="[{required: true, message: '请输入联系电话', trigger: 'blur'}]"> | ||||
|               <el-input type="number" size="small" v-model="form.phone" clearable placeholder="请输入联系电话" :maxlength="11" show-word-limit></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item style="width: 100%" label="店铺类型" prop="type" :rules="[{required: true, message: '请选择店铺类型', trigger: 'change'}]"> | ||||
|               <ai-select | ||||
|                 v-model="form.type" | ||||
| @@ -227,6 +233,8 @@ | ||||
|         isShow: false, | ||||
|         form: { | ||||
|           title: '', | ||||
|           shopkeeper: '', | ||||
|           phone: '', | ||||
|           type: '', | ||||
|           serviceType: '0', | ||||
|           visibleNames: '', | ||||
|   | ||||
							
								
								
									
										128
									
								
								project/xumu/AppAccountConfigManage/AppAccountConfigManage.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								project/xumu/AppAccountConfigManage/AppAccountConfigManage.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,128 @@ | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppAccountConfigManage", | ||||
|   label: "配置管理", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       columns: [ | ||||
|         {label: "序号", type: "index"}, | ||||
|         {label: "账号", prop: "userName"}, | ||||
|         {label: "姓名", prop: "name"}, | ||||
|         {label: "角色", prop: "roleName"}, | ||||
|         {label: "所属端", prop: "type", dict: "roleType", width: 120, align: 'center'}, | ||||
|         {label: "状态", prop: "configStatus", dict: "configStatus", width: 120, align: 'center'}, | ||||
|       ], | ||||
|       tableData: [], | ||||
|       page: {pageNum: 1, pageSize: 10, total: 0}, | ||||
|       search: {name: ""}, | ||||
|       dialog: false, | ||||
|       userId: "", | ||||
|       treeData: [] | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']) | ||||
|   }, | ||||
|   methods: { | ||||
|     getTableData() { | ||||
|       this.instance.post("/api/user/config/page", null, { | ||||
|         params: {...this.page, ...this.search} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.tableData = res.data?.records | ||||
|           this.page.total = res.data.total | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getTreeData() { | ||||
|       const {userId} = this | ||||
|       this.instance.post("/api/siteUser/querySiteByUserId", null, {params: {userId}}).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.treeData = res.data | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     handleDelete(node) { | ||||
|       this.$confirm("是否要删除该节点?").then(() => { | ||||
|         this.instance.post("/api/siteUser/del", null, {params: {ids: node.id}}).then(res => { | ||||
|           if (res?.code == '0' && res?.data != 1) { | ||||
|             this.$message.success("删除成功!") | ||||
|             this.getTreeData() | ||||
|           } else { | ||||
|             this.$message.error(res.msg) | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|     createNode(data) { | ||||
|       this.$prompt("请输入名称").then(({value}) => { | ||||
|         const {userId} = this | ||||
|         this.instance.post("/api/siteUser/add", null, {params: {name: value, parentId: data.id, userId}}).then(res => { | ||||
|           if (res?.code == '0' && res?.data != 1) { | ||||
|             this.$message.success("新增成功!") | ||||
|             this.getTreeData() | ||||
|           } else { | ||||
|             this.$message.error(res.msg) | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load("roleType", "configStatus") | ||||
|     this.getTableData() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-page class="AppAccountConfigManage" :title="$options.label"> | ||||
|     <ai-search-bar> | ||||
|       <template #right> | ||||
|         <el-input size="small" placeholder="搜索账号" v-model="search.name" clearable | ||||
|                   @change="page.pageNum=1, getTableData()" @getList="getTableData"/> | ||||
|       </template> | ||||
|     </ai-search-bar> | ||||
|     <ai-table :tableData="tableData" :colConfigs="columns" :dict="dict" @getList="getTableData" | ||||
|               :total="page.total" :current.sync="page.pageNum" :size.sync="page.pageSize"> | ||||
|       <el-table-column slot="options" label="操作" fixed="right" align="center"> | ||||
|         <template slot-scope="{row}"> | ||||
|           <div class="table-options"> | ||||
|             <el-button type="text" @click="dialog=true,userId=row.id">配置</el-button> | ||||
|           </div> | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|     </ai-table> | ||||
|     <ai-dialog v-model="dialog" title="场地配置" width="50vw" @close="userId='',getTableData()" | ||||
|                @open="getTreeData" customFooter> | ||||
|       <el-button class="mar-b8" type="primary" @click="createNode(treeData)">新增根节点</el-button> | ||||
|       <el-tree :data="treeData" :props="{label:'name'}" default-expand-all> | ||||
|         <template slot-scope="{node,data}"> | ||||
|           <div class="flex" style="width: 100%"> | ||||
|             <span class="fill" v-text="node.label"/> | ||||
|             <el-button size="mini" type="text" @click="createNode(data)">增加子节点</el-button> | ||||
|             <el-button size="mini" type="text" @click="handleDelete(data)" v-if="$isEmpty(data.children)" class="del">删除</el-button> | ||||
|           </div> | ||||
|         </template> | ||||
|       </el-tree> | ||||
|       <el-button slot="footer" @click="dialog=false,getTableData()">关闭</el-button> | ||||
|     </ai-dialog> | ||||
|   </ai-page> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .AppAccountConfigManage { | ||||
|   height: 100%; | ||||
|  | ||||
|   .el-button .del { | ||||
|     color: #f46; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										263
									
								
								project/xumu/AppAccountManage/AppAccountManage.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								project/xumu/AppAccountManage/AppAccountManage.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,263 @@ | ||||
| <template> | ||||
|   <section class="AppAccountManage"> | ||||
|     <ai-page title="账号管理"> | ||||
|       <ai-area-tree :root-id="rootArea" slot="left" v-model="search.areaId" range="3" @input="page.pageNum=1,getTableData()"/> | ||||
|       <ai-search-bar> | ||||
|         <template #left> | ||||
|           <el-button type="primary" icon="iconfont iconAdd" @click="dialog = true">添加</el-button> | ||||
|           <!--            <el-button type="primary" :disabled="!ids.toString()" @click="batchAllot">功能分配</el-button>--> | ||||
|         </template> | ||||
|         <template #right> | ||||
|           <el-input size="small" placeholder="搜索姓名、手机号" v-model="search.condition" clearable | ||||
|                     @change="page.pageNum=1, getTableData()"/> | ||||
|         </template> | ||||
|       </ai-search-bar> | ||||
|       <ai-table :tableData="tableData" :total="page.total" :current.sync="page.pageNum" :size.sync="page.pageSize" | ||||
|                 @getList="getTableData" :col-configs="colConfigs" :dict="dict" @selection-change="v => ids = v.map(e => e.id)"> | ||||
|         <el-table-column slot="name" label="姓名" width="180px"> | ||||
|           <el-row type="flex" align="middle" slot-scope="{row}"> | ||||
|             <el-image class="avatar" :src="row.avatar" :preview-src-list="[row.avatar]"> | ||||
|               <el-image slot="error" src="https://cdn.cunwuyun.cn/dvcp/h5/defaultAvatar.png" alt=""/> | ||||
|             </el-image> | ||||
|             <div>{{ row.name }}</div> | ||||
|           </el-row> | ||||
|         </el-table-column> | ||||
|         <el-table-column slot="options" align="center" label="操作" fixed="right" width="220px"> | ||||
|           <template slot-scope="{ row }"> | ||||
|             <div class="table-options"> | ||||
|               <el-button type="text" @click="changeEnable(row)">{{ row.status == 1 ? '禁用' : '启用' }}</el-button> | ||||
|               <el-button type="text" @click="appAllot(row)">编辑</el-button> | ||||
|               <el-button type="text" @click="resetPassword(row.id)">重置密码</el-button> | ||||
|               <el-button type="text" @click="handleDelete(row)">删除</el-button> | ||||
|             </div> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </ai-table> | ||||
|     </ai-page> | ||||
|     <!--添加账号、功能分配--> | ||||
|     <ai-dialog :title="dialogTitle" :visible.sync="dialog" width="60vw" @open="initDialogData" | ||||
|                @onConfirm="updateAccount" @closed="dialogForm = {}"> | ||||
|       <el-form ref="updateAccountForm" :model="dialogForm" :rules="rules" size="small" label-width="120px" class="grid"> | ||||
|         <el-form-item required label="行政区划" prop="areaId"> | ||||
|           <ai-area-get v-model.trim="dialogForm.areaId" placeholder="请选择" :instance="instance"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item required label="账号" prop="userName"> | ||||
|           <el-input v-model.trim="dialogForm.userName" placeholder="请输入..." clearable :maxLength="15"/> | ||||
|         </el-form-item> | ||||
|         <!--        <el-form-item required label="账号密码" prop="password" v-if="!isEdit" :rules="[{ required: true, message: '请输入密码' }]">--> | ||||
|         <!--          <el-input v-model.trim="dialogForm.password" placeholder="请输入密码" clearable :minlength="6"/>--> | ||||
|         <!--        </el-form-item>--> | ||||
|         <el-form-item required label="角色" prop="roleId"> | ||||
|           <el-select placeholder="请选择角色" :value="dialogForm.roleId" filterable v-model="dialogForm.roleId" clearable> | ||||
|             <el-option v-for="(op, i) in accountRoles" :key="i" :label="op.name" :value="op.id"/> | ||||
|           </el-select> | ||||
|         </el-form-item> | ||||
|         <el-form-item required label="姓名" prop="name"> | ||||
|           <el-input v-model.trim="dialogForm.name" placeholder="请输入..." clearable :maxLength="15"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="手机号码" prop="phone"> | ||||
|           <el-input v-model.trim="dialogForm.phone" placeholder="请输入..." clearable :maxLength="11"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="身份证号" prop="idCard" :rules="[{required:true,message:'请输入身份证号'}]"> | ||||
|           <ai-input v-model.trim="dialogForm.idCard" :maxLength="18"/> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|     </ai-dialog> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import {mapState} from "vuex"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppAccountManage", | ||||
|   label: "账号管理", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     cascaderProps() { | ||||
|       return { | ||||
|         value: 'id', | ||||
|         checkStrictly: true, | ||||
|         emitPath: false | ||||
|       } | ||||
|     }, | ||||
|     isEdit() { | ||||
|       return !!this.dialogForm.id | ||||
|     }, | ||||
|     dialogTitle() { | ||||
|       return this.isEdit ? '编辑账号' : '添加账号' | ||||
|     }, | ||||
|     colConfigs() { | ||||
|       return [ | ||||
|         // {type: 'selection', align: 'center'}, | ||||
|         {label: "账号", prop: "userName"}, | ||||
|         {label: "姓名", slot: "name"}, | ||||
|         {label: "联系方式", prop: "phone", align: 'center'}, | ||||
|         {label: "角色", prop: "roleName", align: 'center'}, | ||||
|         {label: "状态", prop: "status", align: 'center', dict: "enable"}, | ||||
|         {label: "认证状态", prop: "authStatus", align: 'center', dict: "authStatus"}, | ||||
|         {label: "配置状态", prop: "configStatus", align: 'center', dict: "configStatus"}, | ||||
|       ] | ||||
|     }, | ||||
|     rules() { | ||||
|       return { | ||||
|         userName: [{required: true, message: "请输入账号"}], | ||||
|         name: [{required: true, message: "请输入姓名"}], | ||||
|         password: [{required: true, message: '请输入密码'}], | ||||
|         areaId: [{required: true, message: "请选择行政区划"}], | ||||
|         roleId: [{required: true, message: "请选择角色"}], | ||||
|         // phone: [{required: true, message: "请输入手机号码"}] | ||||
|       } | ||||
|     }, | ||||
|     rootArea: v => v.user.info.areaId | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       accountRoles: [], | ||||
|       page: {pageNum: 1, pageSize: 10, total: 0}, | ||||
|       dialog: false, | ||||
|       dialogForm: {}, | ||||
|       tableData: [], | ||||
|       search: {condition: ""}, | ||||
|       ids: [], | ||||
|       form: { | ||||
|         appids: [], | ||||
|         userId: '' | ||||
|       }, | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     getTableData() { | ||||
|       this.instance.post("/admin/user/page", null, { | ||||
|         params: {...this.page, ...this.search} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.tableData = res.data?.records | ||||
|           this.page.total = res.data.total | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     onConfirm() { | ||||
|       this.$refs.form.validate((valid) => { | ||||
|         if (valid) { | ||||
|           this.instance.post(`/api/sysuserwxmp/addOrUpdate`, { | ||||
|             ...this.form | ||||
|           }).then(res => { | ||||
|             if (res.code == 0) { | ||||
|               this.getTableData() | ||||
|               this.$message.success('提交成功!') | ||||
|  | ||||
|               this.getList() | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     initDialogData() { | ||||
|       //用于优化初始化数据 | ||||
|       this.getAccountRoles() | ||||
|     }, | ||||
|     getAccountRoles() { | ||||
|       this.accountRoles.length == 0 && this.instance.post("/admin/role/list-all").then(res => { | ||||
|         if (res?.data) { | ||||
|           this.accountRoles = res.data | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     batchAllot() { | ||||
|       this.dialog = true | ||||
|       this.dialogForm = {areaId: this.user.info.areaId, ids: this.ids} | ||||
|     }, | ||||
|     appAllot(row) { | ||||
|       this.dialog = true | ||||
|       this.dialogForm = JSON.parse(JSON.stringify({ | ||||
|         ...row, | ||||
|         areaId: row.areaId || this.user.info.areaId | ||||
|       })); | ||||
|     }, | ||||
|     // 修改 | ||||
|     updateAccount() { | ||||
|       this.$refs.updateAccountForm.validate(v => { | ||||
|         if (v) { | ||||
|           this.instance.post("/admin/user/addOrEdit", this.dialogForm).then(res => { | ||||
|             if (res?.code == 0) { | ||||
|               this.dialog = false; | ||||
|               this.$message.success("提交成功") | ||||
|               this.getTableData(); | ||||
|             } else { | ||||
|               this.$message.error(res?.msg) | ||||
|             } | ||||
|           }) | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     handleDelete(row) { | ||||
|       const {id: ids, authStatus, configStatus} = row | ||||
|       let text = "是否要删除该账号?" | ||||
|       if (authStatus == 1) { | ||||
|         text = configStatus == 1 ? "该账户已经认证,是否确认删除该账户?" : "该账户已经认证及配置,是否确认删除该账户?" | ||||
|       } | ||||
|       this.$confirm(text).then(() => { | ||||
|         this.instance.post("/admin/user/del", null, { | ||||
|           params: {ids} | ||||
|         }).then(res => { | ||||
|           if (res?.code == 0) { | ||||
|             this.getTableData(); | ||||
|             this.$message.success("删除成功!"); | ||||
|           } | ||||
|         }) | ||||
|       }).catch(() => 0) | ||||
|     }, | ||||
|     changeEnable(row) { | ||||
|       const {status, id} = row | ||||
|       this.$confirm(`是否要${status == 1 ? '禁用' : '启用'}该账号?`).then(() => { | ||||
|         this.instance.post("/api/user/update-status", null, {params: {id}}).then(res => { | ||||
|           if (res?.code == 0) { | ||||
|             this.$message.success(`${status == 1 ? '禁用' : '启用'}成功!`) | ||||
|             this.getTableData() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|     resetPassword(id) { | ||||
|       this.$confirm("是否要重置密码?").then(() => { | ||||
|         this.instance.post("/api/user/resetPwd", null, {params: {id}}).then(res => { | ||||
|           if (res?.code == 0) { | ||||
|             this.$message.success("重置成功!") | ||||
|             this.getTableData() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load("enable", "authStatus", "configStatus") | ||||
|     this.getTableData() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AppAccountManage { | ||||
|   height: 100%; | ||||
|  | ||||
|   :deep(.avatar) { | ||||
|     width: 40px; | ||||
|     height: 40px; | ||||
|     margin-right: 10px; | ||||
|   } | ||||
|  | ||||
|   :deep(.el-form) { | ||||
|  | ||||
|     .el-cascader, | ||||
|     .el-select { | ||||
|       width: 100%; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										43
									
								
								project/xumu/AppAuthManage/AppAuthManage.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								project/xumu/AppAuthManage/AppAuthManage.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| <script> | ||||
| import authAdd from "./authAdd.vue"; | ||||
| import authList from "./authList.vue"; | ||||
| export default { | ||||
|   name: "AppAuthManage", | ||||
|   label: "认证审核", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     currentPage() { | ||||
|       let {hash} = this.$route | ||||
|       return hash == "#add" ? authAdd : authList | ||||
|     } | ||||
|   }, | ||||
|   data(){ | ||||
|     return { | ||||
|       certificates:[ | ||||
|         {label: "身份证(正面)", prop: "frontCard"}, | ||||
|         {label: "身份证(反面)", prop: "reverseCard"}, | ||||
|         {label: "营业执照", prop: "businessPic", permit: ["breed"]}, | ||||
|         {label: "畜禽经营许可证", prop: "breedPic", permit: ["breed"]}, | ||||
|         {label: "动物防疫条件许可证", prop: "prevention", permit: ["breed"]}, | ||||
|         {label: "组织机构证明", prop: "orgPic", permit: ["bank", "insurance"]}, | ||||
|       ] | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <section class="AppAuthManage"> | ||||
|     <component :is="currentPage" v-bind="$props"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .AppAuthManage { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										85
									
								
								project/xumu/AppAuthManage/authAdd.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								project/xumu/AppAuthManage/authAdd.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | ||||
| <script> | ||||
|  | ||||
| export default { | ||||
|   name: "authAdd", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     permissions: Function, | ||||
|     dict: Object | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       detail: {}, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     isAuditing: v => v.detail.auditStatus == 1 | ||||
|   }, | ||||
|   methods: { | ||||
|     back(params = {}) { | ||||
|       this.$router.push(params) | ||||
|     }, | ||||
|     getDetail() { | ||||
|       const {id} = this.$route.query | ||||
|       this.instance.post("/api/user/auth/page", null, {params: {id}}).then(res => { | ||||
|         if (res?.data?.records) { | ||||
|           const detail = res.data.records[0] || {} | ||||
|           let {picture = "{}"} = detail | ||||
|           picture = JSON.parse(picture) | ||||
|           this.detail = {...detail, ...picture} | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getNeedCerts(type) { | ||||
|       return this.$parent.certificates.filter(e => !e.permit || e.permit.includes(type)) | ||||
|     }, | ||||
|     handleAudit(auditStatus) { | ||||
|       const auditLabels = { | ||||
|         2: "同意通过", 3: "驳回" | ||||
|       } | ||||
|       this.$confirm(`是否要${auditLabels[auditStatus]}认证?`).then(() => { | ||||
|         this.instance.post("/api/user/audit", null, {params:{ | ||||
|             id: this.detail.id, auditStatus | ||||
|           }}).then(res => { | ||||
|           if (res?.code == 0) { | ||||
|             this.$confirm("是否要返回列表?","提交成功").then(() => this.back()) | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load("auditStatus") | ||||
|     this.getDetail() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-page title="认证材料" class="authAdd" showBack content-string="detail"> | ||||
|     <el-form size="small" label-position="top" :model="detail" ref="detail"> | ||||
|       <ai-card title="认证材料"> | ||||
|         <div class="grid"> | ||||
|           <el-form-item v-for="(op,i) in getNeedCerts(detail.type)" :key="i" v-bind="op" :rules="{required:true,message:`请上传${op.label}`,trigger:'change'}"> | ||||
|             <el-image :src="detail[op.prop]" :preview-src-list="[detail[op.prop]]"/> | ||||
|           </el-form-item> | ||||
|         </div> | ||||
|       </ai-card> | ||||
|       <ai-card title="备注说明"> | ||||
|         <div v-text="detail.remark"/> | ||||
|       </ai-card> | ||||
|     </el-form> | ||||
|     <div slot="footer"> | ||||
|       <template v-if="isAuditing"> | ||||
|         <el-button type="primary" @click="handleAudit(2)">同意</el-button> | ||||
|         <el-button type="danger" @click="handleAudit(3)">拒绝</el-button> | ||||
|       </template> | ||||
|       <el-button @click="back">关闭</el-button> | ||||
|     </div> | ||||
|   </ai-page> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .authAdd { | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										135
									
								
								project/xumu/AppAuthManage/authList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								project/xumu/AppAuthManage/authList.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,135 @@ | ||||
| <script> | ||||
| const columns = [ | ||||
|   {label: "序号", type: "index"}, | ||||
|   {label: "账号", prop: "userName"}, | ||||
|   {label: "姓名", prop: "name"}, | ||||
|   {label: "角色", prop: "roleName"}, | ||||
|   {label: "所属端", prop: "type", dict: "roleType", width: 120, align: 'center'}, | ||||
|   {label: "状态", prop: "authStatus", dict: "authStatus", width: 120, align: 'center'}, | ||||
|   {label: "审核状态", prop: "auditStatus", dict: "auditStatus", width: 120, align: 'center'}, | ||||
| ] | ||||
| export default { | ||||
|   name: "authList", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       columns, | ||||
|       tableData: [], | ||||
|       page: {pageNum: 1, pageSize: 10, total: 0}, | ||||
|       search: {name: ""}, | ||||
|       dialog: false, | ||||
|       form: {} | ||||
|     } | ||||
|   }, | ||||
|   watch: { | ||||
|     search: { | ||||
|       deep: true, | ||||
|       handler() { | ||||
|         this.page.pageNum = 1 | ||||
|         this.getTableData() | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     getTableData() { | ||||
|       this.instance.post("/api/user/auth/page", null, { | ||||
|         params: {...this.page, ...this.search} | ||||
|       }).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.tableData = res.data?.records.map(e => ({...e, permit: `${e.authStatus}` + e.auditStatus})) | ||||
|           this.page.total = res.data.total | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     getNeedCerts(type) { | ||||
|       return this.$parent.certificates.filter(e => !e.permit || e.permit.includes(type)) | ||||
|     }, | ||||
|     handleConfirm() { | ||||
|       this.$refs.form.validate().then(() => { | ||||
|         const {id, remark} = this.form, picture = {} | ||||
|         this.$parent.certificates.forEach(e => { | ||||
|           picture[e.prop] = this.form[e.prop] | ||||
|         }) | ||||
|         this.instance.post("/api/user/savePicture", null, { | ||||
|           params: { | ||||
|             id, remark, picture: JSON.stringify(picture) | ||||
|           } | ||||
|         }).then(res => { | ||||
|           if (res?.code == '0' && res?.data != 1) { | ||||
|             this.dialog = false | ||||
|             this.$message.success("提交成功!") | ||||
|             this.getTableData() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|     handleUploadPics(row = {}) { | ||||
|       let {id, type, remark, picture = "{}"} = row | ||||
|       picture = JSON.parse(picture) | ||||
|       this.form = {id, type, remark, ...picture} | ||||
|       this.dialog = true | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load("roleType", "authStatus", "auditStatus") | ||||
|     this.getTableData() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-page class="authList" title="认证审核"> | ||||
|     <ai-search-bar> | ||||
|       <template #left> | ||||
|         <ai-select v-model="search.authStatus" dict="authStatus" placeholder="状态"/> | ||||
|         <ai-select v-model="search.auditStatus" dict="auditStatus" placeholder="审核状态"/> | ||||
|       </template> | ||||
|       <template #right> | ||||
|         <el-input size="small" placeholder="搜索账号" v-model="search.name" clearable | ||||
|                   @change="page.pageNum=1, getTableData()" @getList="getTableData"/> | ||||
|       </template> | ||||
|     </ai-search-bar> | ||||
|     <ai-table :tableData="tableData" :colConfigs="columns" :dict="dict" @getList="getTableData" | ||||
|               :total="page.total" :current.sync="page.pageNum" :size.sync="page.pageSize"> | ||||
|       <el-table-column slot="options" label="操作" fixed="right" align="center"> | ||||
|         <template slot-scope="{row}"> | ||||
|           <div class="table-options"> | ||||
|             <el-button type="text" v-if="'12'.includes(row.permit)" | ||||
|                        @click="$router.push({query:{id:row.id},hash:'#add'})">查看 | ||||
|             </el-button> | ||||
|             <el-button class="deleteBtn" type="text" v-if="'11'.includes(row.permit)" | ||||
|                        @click="$router.push({query:{id:row.id},hash:'#add'})">审核 | ||||
|             </el-button> | ||||
|             <el-button type="text" v-if="'00|13'.includes(row.permit)" | ||||
|                        @click="handleUploadPics(row)">认证材料 | ||||
|             </el-button> | ||||
|           </div> | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|     </ai-table> | ||||
|     <ai-dialog v-model="dialog" title="认证材料" width="60%" @close="form={}" @confirm="handleConfirm"> | ||||
|       <el-form class="grid c-3" :model="form" ref="form" label-width="160px"> | ||||
|         <el-form-item v-for="(op,i) in getNeedCerts(form.type)" :key="i" v-bind="op" :rules="{required:true,message:`请上传${op.label}`,trigger:'change'}"> | ||||
|           <ai-uploader v-model="form[op.prop]" valueIsUrl :limit="1" :instance="instance"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item class="row" label="备注说明" prop="remark"> | ||||
|           <el-input type="textarea" :rows="2" v-model="form.remark" placeholder="备注说明具体情况"/> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|     </ai-dialog> | ||||
|   </ai-page> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .authList { | ||||
|   height: 100%; | ||||
|  | ||||
|   .deleteBtn { | ||||
|     color: $errorColor; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										35
									
								
								project/xumu/AppBreedArchive/AppBreedArchive.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								project/xumu/AppBreedArchive/AppBreedArchive.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| <script> | ||||
| import add from "./add.vue"; | ||||
| import list from "./list.vue"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppBreedArchive", | ||||
|   label: "电子档案", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     currentPage() { | ||||
|       let {hash} = this.$route | ||||
|       return hash == "#add" ? add : list | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load("archiveStatus", "category", "variety", "insuranceType", "deathReason", "dataSources", "yesOrNo") | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <section class="AppBreedArchive"> | ||||
|     <component :is="currentPage" v-bind="$props"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .AppBreedArchive { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										182
									
								
								project/xumu/AppBreedArchive/add.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								project/xumu/AppBreedArchive/add.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,182 @@ | ||||
| <script> | ||||
| import {mapState} from "vuex" | ||||
|  | ||||
| const columns = { | ||||
|   weightList: [ | ||||
|     {label: "序号", type: "index"}, | ||||
|     {label: "重量", prop: "weight"}, | ||||
|     {label: "称重时间", prop: "createTime"}, | ||||
|     {label: "数据来源", prop: "source", dict: "dataSources"}, | ||||
|     {label: "是否变更过", prop: "isUpdate", dict: "yesOrNo"}, | ||||
|   ], | ||||
|   immunityList: [ | ||||
|     {label: "序号", type: "index"}, | ||||
|     {label: "疫苗名称", prop: "vaccineName"}, | ||||
|     {label: "用药方式", prop: "method"}, | ||||
|     {label: "药量(ml)", prop: "dosage"}, | ||||
|     {label: "生产厂家", prop: "factory"}, | ||||
|     {label: "厂家批号", prop: "batchNumber"}, | ||||
|     {label: "免疫时间", prop: "immunityTime"}, | ||||
|     {label: "登记时间", prop: "createTime"}, | ||||
|     {label: "防疫员", prop: "userName"}, | ||||
|   ], | ||||
|   treatmentList: [ | ||||
|     {label: "序号", type: "index"}, | ||||
|     {label: "药品名称", prop: "drugName"}, | ||||
|     {label: "药量(ml)", prop: "dosage"}, | ||||
|     {label: "生产厂家", prop: "factory"}, | ||||
|     {label: "厂家批号", prop: "batchNumber"}, | ||||
|     {label: "疾病名称", prop: "diseaseName"}, | ||||
|     {label: "症状", prop: "symptom"}, | ||||
|     {label: "兽医", prop: "userName"}, | ||||
|     {label: "治疗时间", prop: "immunityTime"}, | ||||
|     {label: "登记时间", prop: "createTime"}, | ||||
|   ], | ||||
|   outList: [ | ||||
|     {label: "序号", type: "index"}, | ||||
|     {label: "养殖场", prop: "userName", format: (v, row) => `${[row.farmName, row.houseName, row.penName].join("-")}`}, | ||||
|     {label: "生物芯片耳标号", prop: "biochipEarNumber"}, | ||||
|     {label: "类别", prop: "category", dict: "category", width: 120}, | ||||
|     {label: "品种", prop: "variety", dict: "variety", width: 120}, | ||||
|     {label: "日龄(天)", prop: "age", width: 80}, | ||||
|     {label: "淘汰时间", prop: "outTime"}, | ||||
|     {label: "淘汰原因", prop: "reason"} | ||||
|   ], | ||||
|   deathList: [ | ||||
|     {label: "序号", type: "index"}, | ||||
|     {label: "养殖场", prop: "userName", format: (v, row) => `${[row.farmName, row.houseName, row.penName].join("-")}`}, | ||||
|     {label: "生物芯片耳标号", prop: "biochipEarNumber"}, | ||||
|     {label: "类别", prop: "category", dict: "category", width: 120}, | ||||
|     {label: "品种", prop: "variety", dict: "variety", width: 120}, | ||||
|     {label: "日龄(天)", prop: "age", width: 80}, | ||||
|     {label: "死亡时间", prop: "deathTime"}, | ||||
|     {label: "死亡原因", prop: "reason", dict: "deathReason", width: 80}, | ||||
|     {label: "登记时间", prop: "createTime"}, | ||||
|     {label: "操作人", prop: "userName", width: 100}, | ||||
|   ], | ||||
|   insuranceList: [ | ||||
|     {label: "序号", type: "index"}, | ||||
|     {label: "保险类型", prop: "insuranceType", dict: "insuranceType"}, | ||||
|     {label: "保单编号", prop: "orderNo"}, | ||||
|   ] | ||||
| } | ||||
| const forms = { | ||||
|   device: [ | ||||
|     {label: "当前温度", prop: "temperature"}, | ||||
|     {label: "温度状态", prop: "temperatureStatus", dict: "temperatureStatus"}, | ||||
|     {label: "运动状态", prop: "sportsSituation", dict: "sportsSituation"}, | ||||
|     {label: "在栏状态", prop: "status", dict: "archiveStatus"}, | ||||
|   ], | ||||
|   loan: [ | ||||
|     {label: "贷款合同编号", prop: "contractNo"}, | ||||
|   ] | ||||
| } | ||||
| const navs = [ | ||||
|   {label: "体重记录", value: "weightList"}, | ||||
|   {label: "免疫记录", value: "immunityList"}, | ||||
|   {label: "治疗记录", value: "treatmentList"}, | ||||
|   {label: "淘汰记录", value: "outList"}, | ||||
|   {label: "死亡记录", value: "deathList"}, | ||||
|   {label: "设备检测", value: "device"}, | ||||
|   {label: "贷款信息", value: "loan"}, | ||||
|   {label: "保险信息", value: "insuranceList"}, | ||||
| ] | ||||
| export default { | ||||
|   name: "baAdd", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     permissions: Function, | ||||
|     dict: Object | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       detail: {detailList: []}, | ||||
|       active: "weightList", | ||||
|       columns, navs, forms | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(["user"]), | ||||
|     userinfo: v => v.user.info || {}, | ||||
|     isAdd: v => !v.$route.query.id, | ||||
|     isEdit: v => v.$route.query.edit == 1, | ||||
|     pageTitle: v => { | ||||
|       const appName = v.$parent.menuName || v.$parent.$options.label | ||||
|       return v.$route.query.id ? v.isEdit ? `编辑${appName}` : `${appName}详情` : `新增${appName}` | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|     back(params = {}) { | ||||
|       this.$router.push(params) | ||||
|     }, | ||||
|     getDetail() { | ||||
|       const {id} = this.$route.query | ||||
|       return id && this.instance.post("/api/report/getInfo", null, {params: {biochipEarNumber: id}}).then(res => { | ||||
|         if (res?.data) { | ||||
|           const detail = res.data | ||||
|           Object.keys(columns).forEach(key => { | ||||
|             detail[key] = detail[key] || [] | ||||
|           }) | ||||
|           return this.detail = {...detail} | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load("auditStatus", "category", "variety") | ||||
|     this.getDetail() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-page :title="pageTitle" class="baAdd" showBack content-string="blank"> | ||||
|     <el-form size="small" label-width="120px" :model="detail" ref="detail"> | ||||
|       <ai-card title="基础信息"> | ||||
|         <div class="grid c-3"> | ||||
|           <el-form-item label="养殖户" prop="userName" class="row"> | ||||
|             <b v-text="detail.userName"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="养殖场" prop="farmId"> | ||||
|             <b v-text="detail.farmName"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="养殖舍" prop="houseId"> | ||||
|             <b v-text="detail.houseName"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="养殖栏" prop="penId"> | ||||
|             <b v-text="detail.penName"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="生物芯片耳标号" prop="penId"> | ||||
|             <b v-text="detail.biochipEarNumber"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="电子耳标号" prop="penId"> | ||||
|             <b v-text="detail.electronicEarNumber"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="原厂耳标号" prop="penId"> | ||||
|             <b v-text="detail.originalEarNumber"/> | ||||
|           </el-form-item> | ||||
|         </div> | ||||
|       </ai-card> | ||||
|       <el-tabs type="border-card" v-model="active"> | ||||
|         <el-tab-pane v-for="(nav,i) in navs" :key="i" :label="nav.label" :name="nav.value" lazy> | ||||
|           <template v-if="active==nav.value"> | ||||
|             <ai-table v-if="columns[nav.value]" :colConfigs="columns[nav.value]" :table-data="detail[nav.value]" :isShowPagination="!1"/> | ||||
|             <el-form v-if="forms[nav.value]" size="small" class="grid" label-width="120px"> | ||||
|               <el-form-item v-for="(item,i) in forms[nav.value]" :key="i" :label="item.label" :prop="item.prop"> | ||||
|                 <b v-text="dict.getLabel(item.dict||'yesOrNo',detail[item.prop])"/> | ||||
|               </el-form-item> | ||||
|             </el-form> | ||||
|           </template> | ||||
|         </el-tab-pane> | ||||
|       </el-tabs> | ||||
|     </el-form> | ||||
|     <div slot="footer"> | ||||
|       <el-button @click="back">返回</el-button> | ||||
|     </div> | ||||
|   </ai-page> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .baAdd { | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										110
									
								
								project/xumu/AppBreedArchive/list.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								project/xumu/AppBreedArchive/list.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| <script> | ||||
| import {mapState} from "vuex" | ||||
|  | ||||
| const columns = [ | ||||
|   {label: "序号", type: "index"}, | ||||
|   {label: "养殖户", prop: "userName", width: 100}, | ||||
|   {label: "养殖场", format: (v, row) => `${[row.farmName, row.houseName, row.penName].join("-")}`, minWidth: 200}, | ||||
|   {label: "生物芯片耳标号", prop: "biochipEarNumber"}, | ||||
|   {label: "电子耳标号", prop: "biochipEarNumber"}, | ||||
|   {label: "原厂耳标号", prop: "biochipEarNumber"}, | ||||
|   {label: "入栏日期", prop: "createTime", width: 160}, | ||||
|   {label: "饲养时长(天)", prop: "days", width: 100, align: 'right', headerAlign: 'center'}, | ||||
|   {label: "最新体重(公斤)", prop: "weight", width: 120, align: 'right', headerAlign: 'center'}, | ||||
|   // {label: "当前体温", prop: "temperatureStatus", dict: 'temperatureStatus'}, | ||||
|   // {label: "运动情况", prop: "sportsSituation", dict: "sportsSituation"}, | ||||
| ] | ||||
| export default { | ||||
|   name: "baList", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       columns, | ||||
|       tableData: [], | ||||
|       page: {pageNum: 1, pageSize: 10, total: 0}, | ||||
|       search: {}, | ||||
|       dialog: false, | ||||
|       form: {} | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     userinfo: v => v.user.info || {}, | ||||
|     pageTitle: v => v.$parent.menuName || v.$parent.$options.label | ||||
|   }, | ||||
|   watch: { | ||||
|     search: { | ||||
|       deep: true, | ||||
|       handler() { | ||||
|         this.page.pageNum = 1 | ||||
|         this.getTableData() | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     getTableData() { | ||||
|       this.instance.post("/api/report/getArchivePage", {...this.page, ...this.search}).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.tableData = res.data?.records | ||||
|           this.page.total = res.data.total | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.getTableData() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-page class="baList" :title="pageTitle"> | ||||
|     <ai-search-bar> | ||||
|       <template #left> | ||||
|         <ai-select placeholder="全部养殖户" v-model="search.userId" :instance="instance" :action="`/api/report/getOrgList`" :prop="{label:'name'}" readonly/> | ||||
|         <ai-select placeholder="全部养殖场" v-model="search.farmId" :instance="instance" :action="`/api/siteUser/querySiteByUserId?userId=${search.userId||''}`" :prop="{label:'name'}"/> | ||||
|         <ai-select placeholder="全部养殖舍" v-model="search.houseId" :instance="instance" :action="`/api/siteUser/querySiteById?id=${search.farmId||-1}`" :prop="{label:'name'}"/> | ||||
|         <ai-select placeholder="全部养殖栏" v-model="search.penId" :instance="instance" :action="`/api/siteUser/querySiteById?id=${search.houseId||-1}`" :prop="{label:'name'}"/> | ||||
|         <ai-input placeholder="生物芯片耳标号" v-model="search.biochipEarNumber"/> | ||||
|         <ai-input placeholder="电子耳标号" v-model="search.electronicEarNumber"/> | ||||
|         <ai-input placeholder="原厂耳标号" v-model="search.originalEarNumber"/> | ||||
|         <ai-select placeholder="全部状态" v-model="search.status" dict="archiveStatus"/> | ||||
|         <ai-select placeholder="全部类别" v-model="search.category" dict="category"/> | ||||
|         <ai-select placeholder="全部品种" v-model="search.variety" dict="variety"/> | ||||
|         <ai-search label="入栏日期"> | ||||
|           <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.beginDate" type="datetime" placeholder="开始日期" size="small"/> | ||||
|           <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.endDate" type="datetime" placeholder="结束日期" size="small"/> | ||||
|         </ai-search> | ||||
|       </template> | ||||
|     </ai-search-bar> | ||||
|     <ai-search-bar> | ||||
|       <template #left> | ||||
|         <ai-download :instance="instance" url="/api/report/exportArchive" :params="{...search,...page}" :fileName="`${pageTitle}导出表-${Date.now()}`"/> | ||||
|       </template> | ||||
|     </ai-search-bar> | ||||
|     <ai-table :tableData="tableData" :colConfigs="columns" :dict="dict" @getList="getTableData" | ||||
|               :total="page.total" :current.sync="page.pageNum" :size.sync="page.pageSize"> | ||||
|       <el-table-column slot="options" label="操作" fixed="right" align="center"> | ||||
|         <template slot-scope="{row}"> | ||||
|           <div class="table-options"> | ||||
|             <el-button type="text" @click="$router.push({hash:'#add',query:{id:row.biochipEarNumber}})">查看</el-button> | ||||
|           </div> | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|     </ai-table> | ||||
|   </ai-page> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .baList { | ||||
|   height: 100%; | ||||
|  | ||||
|   .deleteBtn { | ||||
|     color: $errorColor; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										35
									
								
								project/xumu/AppClaimApply/AppClaimApply.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								project/xumu/AppClaimApply/AppClaimApply.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| <script> | ||||
| import add from "./add.vue"; | ||||
| import list from "./list.vue"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppClaimApply", | ||||
|   label: "理赔申请", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     currentPage() { | ||||
|       let {hash} = this.$route | ||||
|       return ["#claim", "#add"].includes(hash) ? add : list | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load("auditStatus", "insureType", "insureStatus", "category", "variety") | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <section class="AppClaimApply"> | ||||
|     <component :is="currentPage" v-bind="$props"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .AppClaimApply { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										147
									
								
								project/xumu/AppClaimApply/add.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								project/xumu/AppClaimApply/add.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | ||||
| <script> | ||||
| import { mapState } from "vuex" | ||||
| import AiEartagPicker from "@project/xumu/components/AiEartagPicker.vue"; | ||||
|  | ||||
| const records = [ | ||||
|   { label: "序号", type: "index" }, | ||||
|   { label: "报案号", prop: "reportNo" }, | ||||
|   { label: "审批状态", prop: "auditStatus", dict: "auditStatus" }, | ||||
|   { label: "审批时间", prop: "auditTime" }, | ||||
|   { label: "审批人", prop: "auditName" }, | ||||
| ] | ||||
| export default { | ||||
|   name: "claimAdd", | ||||
|   components: { AiEartagPicker }, | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     permissions: Function, | ||||
|     dict: Object | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       detail: { detailList: [], list: [] }, | ||||
|       records | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(["user"]), | ||||
|     userinfo: v => v.user.info || {}, | ||||
|     pageTitle: v => { | ||||
|       const appName = v.$parent.menuName || v.$parent.$options.label | ||||
|       return v.isClaim ? `新增${appName}` : `${appName}详情` | ||||
|     }, | ||||
|     isClaim: v => v.$route.hash == "#claim", | ||||
|     formImages: v => [ | ||||
|       { label: "勘察报告书", prop: "surveyPicture", rules: { required: v.isClaim, message: '请上传 勘察报告书' } }, | ||||
|       { label: "无害化回执单", prop: "receiptPicture", rules: { required: v.isClaim, message: '请上传 无害化回执单' } }, | ||||
|     ], | ||||
|     columns: v => [ | ||||
|       { label: "序号", type: "index" }, | ||||
|       { label: "生物芯片耳标号", prop: "biochipEarNumber" }, | ||||
|       { label: "身长测量照片", prop: "heightPicture", upload: { instance: v.instance, readonly: !v.isClaim, valueIsUrl: !0, limit: 1 } }, | ||||
|       { label: "电子耳标照片", prop: "earNumberPicture", upload: { instance: v.instance, readonly: !v.isClaim, valueIsUrl: !0, limit: 1 } }, | ||||
|       { label: "防疫耳标照片", prop: "preventionPicture", upload: { instance: v.instance, readonly: !v.isClaim, valueIsUrl: !0, limit: 1 } }, | ||||
|       { label: "无害化处理照片", prop: "harmlessPicture", upload: { instance: v.instance, readonly: !v.isClaim, valueIsUrl: !0, limit: 1 } }, | ||||
|       { label: "报案号", prop: "reportNo", hide: v.isClaim }, | ||||
|     ].filter(e => !e.hide), | ||||
|     selectedEartags: v => v.detail.list?.length || 0, | ||||
|   }, | ||||
|   methods: { | ||||
|     back(params = {}) { | ||||
|       this.$router.push(params) | ||||
|     }, | ||||
|     getDetail() { | ||||
|       const { id } = this.$route.query | ||||
|       return id && this.instance.post("/api/insurance/claim/apply/getInfo", null, { params: { orderNo: id } }).then(res => { | ||||
|         if (res?.data) { | ||||
|           const detail = res.data | ||||
|           detail.detailList = detail.detailList || [] | ||||
|           return this.detail = { ...detail } | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     submit() { | ||||
|       this.$refs.detail.validate().then(() => { | ||||
|         this.instance.post("/api/insurance/claim/apply/add", { ...this.detail }).then(res => { | ||||
|           if (res?.code == '0') { | ||||
|             this.$message.success("提交成功!") | ||||
|             this.back() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.getDetail() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-page :title="pageTitle" class="claimAdd" showBack content-string="blank"> | ||||
|     <el-form size="small" label-width="120px" :model="detail" ref="detail"> | ||||
|       <ai-card title="基础信息"> | ||||
|         <div class="grid"> | ||||
|           <el-form-item label="养殖场" prop="farmId"> | ||||
|             <b v-text="detail.farmName" /> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="承保公司" prop="companyId"> | ||||
|             <b v-text="detail.companyName" /> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="投保类型"> | ||||
|             <ai-input :value="dict.getLabel('insureType', detail.insureType)" :edit="!1" /> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="保险产品" prop="productType"> | ||||
|             <b v-text="detail.productType" /> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="联系人"> | ||||
|             <ai-input v-model="detail.contacts" :edit="!1" /> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="联系电话"> | ||||
|             <ai-input v-model="detail.phone" :edit="!1" /> | ||||
|           </el-form-item> | ||||
|         </div> | ||||
|       </ai-card> | ||||
|       <ai-card title="投保对象"> | ||||
|         <template #right v-if="isClaim"> | ||||
|           <ai-eartag-picker @select="v => detail.detailList = v.map(e=>({biochipEarNumber:e}))" :instance="instance" | ||||
|             :action="`/api/insurance/claim/apply/getClaimEarNumberList?orderNo=${detail.orderNo}`"> | ||||
|             <el-button type="text">选择</el-button> | ||||
|           </ai-eartag-picker> | ||||
|         </template> | ||||
|         <ai-highlight class="mar-b8 font-14" :content="`投保标的共${detail.insureNumber || 0}只,已理赔标的共 @v 只`" color="red" | ||||
|           :value="selectedEartags" /> | ||||
|         <ai-table :tableData="detail.detailList" :colConfigs="columns" :isShowPagination="!1" hideOptions /> | ||||
|       </ai-card> | ||||
|       <ai-card title="理赔材料" v-if="isClaim"> | ||||
|         <div class="font-12 mar-b8">只能上传JPG/PNG文件,且不超过2M,一次最多5张</div> | ||||
|         <el-form-item v-for="(img, i) in formImages" :key="i" v-bind="img"> | ||||
|           <ai-uploader v-model="detail[img.prop]" :instance="instance" value-is-url :limit="5" /> | ||||
|         </el-form-item> | ||||
|       </ai-card> | ||||
|       <ai-card title="理赔记录" v-else> | ||||
|         <ai-table :tableData="detail.list" :colConfigs="records" :isShowPagination="!1" hideOptions /> | ||||
|       </ai-card> | ||||
|     </el-form> | ||||
|     <div slot="footer"> | ||||
|       <template v-if="isClaim"> | ||||
|         <el-button type="primary" @click="submit(1)">提交</el-button> | ||||
|       </template> | ||||
|       <el-button @click="back">返回</el-button> | ||||
|     </div> | ||||
|   </ai-page> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .claimAdd { | ||||
|   :deep(.el-form--label-top) { | ||||
|     .el-form-item__label { | ||||
|       width: 100% !important; | ||||
|     } | ||||
|  | ||||
|     .el-form-item__content { | ||||
|       margin-left: unset !important; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										123
									
								
								project/xumu/AppClaimApply/list.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										123
									
								
								project/xumu/AppClaimApply/list.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,123 @@ | ||||
| <script> | ||||
| import {mapState} from "vuex" | ||||
|  | ||||
| const columns = [ | ||||
|   {label: "序号", type: "index"}, | ||||
|   {label: "投保单号", prop: "orderNo"}, | ||||
|   {label: "所属养殖户", prop: "applyName"}, | ||||
|   {label: "所属养殖场", prop: "farmName"}, | ||||
|   {label: "投保数量(头)", prop: "insureNumber", width: 120}, | ||||
|   {label: "投保状态", prop: "status", width: 160, dict: "insureStatus"}, | ||||
|   {label: "投保类型", prop: "insureType", dict: "insureType"}, | ||||
|   {label: "投保时间", prop: "createTime"}, | ||||
|   {label: "可理赔数量", prop: "unpaidClaimNumber", width: 120}, | ||||
|   {label: "说明", prop: "remarks"}, | ||||
| ] | ||||
| export default { | ||||
|   name: "claimList", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       columns, | ||||
|       tableData: [], | ||||
|       page: {pageNum: 1, pageSize: 10, total: 0}, | ||||
|       search: {}, | ||||
|       dialog: false, | ||||
|       form: {} | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     userinfo: v => v.user.info || {}, | ||||
|     pageTitle: v => v.$parent.menuName || v.$parent.$options.label | ||||
|   }, | ||||
|   watch: { | ||||
|     search: { | ||||
|       deep: true, | ||||
|       handler() { | ||||
|         this.page.pageNum = 1 | ||||
|         this.getTableData() | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     getTableData() { | ||||
|       this.instance.post("/api/insurance/claim/apply/page", {...this.page, ...this.search}).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.tableData = res.data?.records.map(e => ({...e, permit: e.remarks == "可申请理赔"})) | ||||
|           this.page.total = res.data.total | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.getTableData() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-page class="claimList" :title="pageTitle"> | ||||
|     <ai-search-bar> | ||||
|       <template #left> | ||||
|         <ai-input placeholder="投保订单号" v-model="search.orderNo"/> | ||||
|         <ai-select placeholder="全部投保类型" v-model="search.insureType" dict="insureType"/> | ||||
|         <ai-search label="投保日期"> | ||||
|           <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.beginDate" type="datetime" placeholder="开始日期" size="small"/> | ||||
|           <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.endDate" type="datetime" placeholder="结束日期" size="small"/> | ||||
|         </ai-search> | ||||
|         <ai-input placeholder="养殖户" v-model="search.applyName"/> | ||||
|         <ai-input placeholder="养殖场" v-model="search.farmName"/> | ||||
|       </template> | ||||
|     </ai-search-bar> | ||||
|     <ai-search-bar> | ||||
|       <template #left> | ||||
|         <ai-download :instance="instance" url="/api/insurance/claim/apply/export" :params="{...search,...page}" :fileName="`${pageTitle}导出表-${Date.now()}`"/> | ||||
|       </template> | ||||
|     </ai-search-bar> | ||||
|     <ai-table :tableData="tableData" :colConfigs="columns" :dict="dict" @getList="getTableData" | ||||
|               :total="page.total" :current.sync="page.pageNum" :size.sync="page.pageSize"> | ||||
|       <el-table-column slot="options" label="操作" fixed="right" align="center"> | ||||
|         <template slot-scope="{row}"> | ||||
|           <div class="table-options"> | ||||
|             <template v-if="row.permit"> | ||||
|               <el-button type="text" @click="dialog=true,$set(form,'id',row.orderNo)">理赔</el-button> | ||||
|             </template> | ||||
|             <el-button v-else type="text" @click="$router.push({hash:'#add',query:{id:row.orderNo}})">查看</el-button> | ||||
|           </div> | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|     </ai-table> | ||||
|     <ai-dialog v-model="dialog" title="理赔须知" @closed="form={}"> | ||||
|       <el-form size="small" label-position="top" :mode="form" ref="form"> | ||||
|         <el-form-item label="如遇一下情况进行赔付:"> | ||||
|           1、自然灾害:如暴雨、洪水、台风、冰雹、雷击、暴风雪等导致的肉牛死亡或伤残;<br/> | ||||
|           2、疾病与疫病:包括但不限于口蹄疫、布鲁氏菌病、炭疽、牛结核病等对肉牛生命安全造成威胁的疾病;<br/> | ||||
|           3、意外事故:如火灾、爆炸、触电、盗窃、走失等;<br/> | ||||
|           4、强制扑杀:由于政府政策或疫情控制需要,对肉牛进行的强制扑杀。 | ||||
|         </el-form-item> | ||||
|         <el-form-item class="flex center"> | ||||
|           <el-checkbox v-model="form.agree">本人阅读并知晓理赔须知,承认上传资料的真实性</el-checkbox> | ||||
|         </el-form-item> | ||||
|       </el-form> | ||||
|       <template #foot> | ||||
|         <el-button @click="$router.push({hash:'#claim',query:{id:form.id}})" type="primary" :disabled="!form.agree">符合要求,立即申请</el-button> | ||||
|         <el-button @click="dialog=false">取消</el-button> | ||||
|       </template> | ||||
|     </ai-dialog> | ||||
|   </ai-page> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .claimList { | ||||
|   height: 100%; | ||||
|  | ||||
|   .deleteBtn { | ||||
|     color: $errorColor; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										35
									
								
								project/xumu/AppClaimAudit/AppClaimAudit.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								project/xumu/AppClaimAudit/AppClaimAudit.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| <script> | ||||
| import add from "./add.vue"; | ||||
| import list from "./list.vue"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppClaimAudit", | ||||
|   label: "理赔审核", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     currentPage() { | ||||
|       let {hash} = this.$route | ||||
|       return ["#audit", "#add"].includes(hash) ? add : list | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load("auditStatus", "insureType", "insureStatus", "category", "variety") | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <section class="AppClaimAudit"> | ||||
|     <component :is="currentPage" v-bind="$props"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .AppClaimAudit { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										160
									
								
								project/xumu/AppClaimAudit/add.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								project/xumu/AppClaimAudit/add.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,160 @@ | ||||
| <script> | ||||
| import {mapState} from "vuex" | ||||
| import AiEartagPicker from "@project/xumu/components/AiEartagPicker.vue"; | ||||
| import AiSelect from "dui/packages/basic/AiSelect.vue"; | ||||
|  | ||||
| const records = [ | ||||
|   {label: "序号", type: "index"}, | ||||
|   {label: "报案号", prop: "reportNo"}, | ||||
|   {label: "审批状态", prop: "auditStatus", dict: "auditStatus"}, | ||||
|   {label: "审批时间", prop: "auditTime"}, | ||||
|   {label: "审批人", prop: "auditName"}, | ||||
| ] | ||||
| export default { | ||||
|   name: "claimAdd", | ||||
|   components: {AiSelect, AiEartagPicker}, | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     permissions: Function, | ||||
|     dict: Object | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       detail: {detailList: []}, | ||||
|       records | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(["user"]), | ||||
|     userinfo: v => v.user.info || {}, | ||||
|     pageTitle: v => { | ||||
|       const appName = v.$parent.menuName || v.$parent.$options.label | ||||
|       return v.isAudit ? `${appName}审批` : `${appName}详情` | ||||
|     }, | ||||
|     isAudit: v => v.$route.hash == "#audit", | ||||
|     formImages: v => [ | ||||
|       {label: "勘察报告书", prop: "surveyPicture"}, | ||||
|       {label: "无害化回执单", prop: "receiptPicture"}, | ||||
|     ], | ||||
|     columns: v => [ | ||||
|       {label: "序号", type: "index"}, | ||||
|       {label: "生物芯片耳标号", prop: "biochipEarNumber"}, | ||||
|       {label: "身长测量照片", prop: "heightPicture", upload: {instance: v.instance, readonly: !0, valueIsUrl: !0, limit: 1}}, | ||||
|       {label: "电子耳标照片", prop: "earNumberPicture", upload: {instance: v.instance, readonly: !0, valueIsUrl: !0, limit: 1}}, | ||||
|       {label: "防疫耳标照片", prop: "preventionPicture", upload: {instance: v.instance, readonly: !0, valueIsUrl: !0, limit: 1}}, | ||||
|       {label: "无害化处理照片", prop: "harmlessPicture", upload: {instance: v.instance, readonly: !0, valueIsUrl: !0, limit: 1}}, | ||||
|     ].filter(e => !e.hide), | ||||
|   }, | ||||
|   methods: { | ||||
|     back(params = {}) { | ||||
|       this.$router.push(params) | ||||
|     }, | ||||
|     getDetail() { | ||||
|       const {id} = this.$route.query | ||||
|       return id && this.instance.post("/api/insurance/claim/apply/getAuditInfo", null, {params: {id}}).then(res => { | ||||
|         if (res?.data) { | ||||
|           const detail = res.data | ||||
|           return this.detail = {...detail} | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     submit() { | ||||
|       this.$refs.detail.validate().then(() => { | ||||
|         this.instance.post("/api/insurance/claim/apply/audit", {...this.detail}).then(res => { | ||||
|           if (res?.code == '0') { | ||||
|             this.$message.success("提交成功!") | ||||
|             this.back() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.getDetail() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-page :title="pageTitle" class="claimAdd" showBack content-string="blank"> | ||||
|     <el-form size="small" label-width="120px" :model="detail" ref="detail"> | ||||
|       <ai-card title="基础信息"> | ||||
|         <div class="grid"> | ||||
|           <el-form-item label="养殖场" prop="farmId"> | ||||
|             <b v-text="detail.farmName"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="承保公司" prop="companyId"> | ||||
|             <b v-text="detail.companyName"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="投保类型"> | ||||
|             <ai-input :value="dict.getLabel('insureType',detail.insureType)" :edit="!1"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="保险产品" prop="productType"> | ||||
|             <b v-text="detail.productType"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="联系人"> | ||||
|             <ai-input v-model="detail.contacts" :edit="!1"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="联系电话"> | ||||
|             <ai-input v-model="detail.phone" :edit="!1"/> | ||||
|           </el-form-item> | ||||
|         </div> | ||||
|       </ai-card> | ||||
|       <ai-card title="投保对象"> | ||||
|         <ai-table :tableData="detail.detailList" :colConfigs="columns" :isShowPagination="!1" hideOptions/> | ||||
|       </ai-card> | ||||
|       <ai-card title="理赔材料"> | ||||
|         <el-form-item v-for="(img,i) in formImages" :key="i" v-bind="img"> | ||||
|           <ai-uploader v-model="detail[img.prop]" value-is-url readonly/> | ||||
|         </el-form-item> | ||||
|       </ai-card> | ||||
|       <ai-card title="审核信息"> | ||||
|         <div class="grid"> | ||||
|           <template v-if="isAudit"> | ||||
|             <el-form-item label="审批状态" prop="auditStatus" :rules="{required:true,message:'请选择审批状态'}"> | ||||
|               <ai-select v-model="detail.auditStatus" dict="auditStatus"/> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="理赔资料" class="sc-3"> | ||||
|               <ai-uploader v-model="detail.picture" value-is-url :instance="instance" :limit="1"/> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="报案号" prop="reportNo" :rules="{required:true,message:'请输入 报案号'}"> | ||||
|               <ai-input v-model="detail.reportNo"/> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="说明"> | ||||
|               <ai-input type="textarea" :rows="3" v-model="detail.remarks"/> | ||||
|             </el-form-item> | ||||
|           </template> | ||||
|           <template v-else> | ||||
|             <el-form-item label="审核状态">{{ dict.getLabel('auditStatus', detail.auditStatus) }}</el-form-item> | ||||
|             <el-form-item label="理赔资料" class="sc-3"> | ||||
|               <el-image :src="detail.picture" :preview-src-list="[detail.picture]"/> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="审核时间">{{ detail.auditTime }}</el-form-item> | ||||
|             <el-form-item label="审核人">{{ detail.auditName }}</el-form-item> | ||||
|             <el-form-item label="说明">{{ detail.remarks }}</el-form-item> | ||||
|           </template> | ||||
|         </div> | ||||
|       </ai-card> | ||||
|     </el-form> | ||||
|     <div slot="footer"> | ||||
|       <template v-if="isAudit"> | ||||
|         <el-button type="primary" @click="submit">提交</el-button> | ||||
|       </template> | ||||
|       <el-button @click="back">返回</el-button> | ||||
|     </div> | ||||
|   </ai-page> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .claimAdd { | ||||
|   :deep(.el-form--label-top) { | ||||
|     .el-form-item__label { | ||||
|       width: 100% !important; | ||||
|     } | ||||
|  | ||||
|     .el-form-item__content { | ||||
|       margin-left: unset !important; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										107
									
								
								project/xumu/AppClaimAudit/list.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								project/xumu/AppClaimAudit/list.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | ||||
| <script> | ||||
| import {mapState} from "vuex" | ||||
|  | ||||
| const columns = [ | ||||
|   {label: "序号", type: "index"}, | ||||
|   {label: "报案号", prop: "reportNo"}, | ||||
|   {label: "投保单号", prop: "orderNo"}, | ||||
|   {label: "所属养殖户", prop: "applyName"}, | ||||
|   {label: "投保类型", prop: "insureType", dict: "insureType"}, | ||||
|   {label: "理赔数量", prop: "claimNumber"}, | ||||
|   {label: "审批状态", prop: "auditStatus", dict: "auditStatus"}, | ||||
|   {label: "审批时间", prop: "auditTime"}, | ||||
|   {label: "审批人", prop: "auditName"}, | ||||
| ] | ||||
| export default { | ||||
|   name: "claimList", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       columns, | ||||
|       tableData: [], | ||||
|       page: {pageNum: 1, pageSize: 10, total: 0}, | ||||
|       search: {}, | ||||
|       dialog: false, | ||||
|       form: {} | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     userinfo: v => v.user.info || {}, | ||||
|     pageTitle: v => v.$parent.menuName || v.$parent.$options.label | ||||
|   }, | ||||
|   watch: { | ||||
|     search: { | ||||
|       deep: true, | ||||
|       handler() { | ||||
|         this.page.pageNum = 1 | ||||
|         this.getTableData() | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     getTableData() { | ||||
|       this.instance.post("/api/insurance/claim/apply/getAuditPage", {...this.page, ...this.search}).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.tableData = res.data?.records.map(e => ({...e, permit: `${e.status}` + e.auditStatus})) | ||||
|           this.page.total = res.data.total | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.getTableData() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-page class="claimList" :title="pageTitle"> | ||||
|     <ai-search-bar> | ||||
|       <template #left> | ||||
|         <ai-input placeholder="投保订单号" v-model="search.orderNo"/> | ||||
|         <ai-select placeholder="全部投保类型" v-model="search.insureType" dict="insureType"/> | ||||
|         <ai-select placeholder="全部审批状态" v-model="search.auditStatus" dict="auditStatus"/> | ||||
|         <ai-select placeholder="全部投保状态" v-model="search.status" dict="insureStatus"/> | ||||
|         <ai-search label="投保日期"> | ||||
|           <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.beginDate" type="datetime" placeholder="开始日期" size="small"/> | ||||
|           <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.endDate" type="datetime" placeholder="结束日期" size="small"/> | ||||
|         </ai-search> | ||||
|         <ai-input placeholder="养殖户" v-model="search.applyName"/> | ||||
|         <ai-input placeholder="养殖场" v-model="search.farmName"/> | ||||
|       </template> | ||||
|     </ai-search-bar> | ||||
|     <ai-search-bar> | ||||
|       <template #left> | ||||
|         <ai-download :instance="instance" url="/api/insurance/claim/apply/exportAudit" :params="{...search,...page}" :fileName="`${pageTitle}导出表-${Date.now()}`"/> | ||||
|       </template> | ||||
|     </ai-search-bar> | ||||
|     <ai-table :tableData="tableData" :colConfigs="columns" :dict="dict" @getList="getTableData" | ||||
|               :total="page.total" :current.sync="page.pageNum" :size.sync="page.pageSize"> | ||||
|       <el-table-column slot="options" label="操作" fixed="right" align="center"> | ||||
|         <template slot-scope="{row}"> | ||||
|           <div class="table-options"> | ||||
|             <template v-if="['1'].includes(row.auditStatus)"> | ||||
|               <el-button type="text" @click="$router.push({hash:'#audit',query:{id:row.id}})">审核</el-button> | ||||
|             </template> | ||||
|             <el-button v-else type="text" @click="$router.push({hash:'#add',query:{id:row.id}})">查看</el-button> | ||||
|           </div> | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|     </ai-table> | ||||
|   </ai-page> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .claimList { | ||||
|   height: 100%; | ||||
|  | ||||
|   .deleteBtn { | ||||
|     color: $errorColor; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										35
									
								
								project/xumu/AppDeathAudit/AppDeathAudit.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								project/xumu/AppDeathAudit/AppDeathAudit.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| <script> | ||||
| import add from "./add.vue"; | ||||
| import list from "./list.vue"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppDeathAudit", | ||||
|   label: "死亡审核", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     currentPage() { | ||||
|       let {hash} = this.$route | ||||
|       return ["#audit", "#add"].includes(hash) ? add : list | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load("auditStatus", "deathReason", "category", "variety") | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <section class="AppDeathAudit"> | ||||
|     <component :is="currentPage" v-bind="$props"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .AppDeathAudit { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										153
									
								
								project/xumu/AppDeathAudit/add.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								project/xumu/AppDeathAudit/add.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,153 @@ | ||||
| <script> | ||||
| import {mapState} from "vuex" | ||||
|  | ||||
| export default { | ||||
|   name: "deathAdd", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     permissions: Function, | ||||
|     dict: Object | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       detail: {detailList: []} | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(["user"]), | ||||
|     userinfo: v => v.user.info || {}, | ||||
|     pageTitle: v => { | ||||
|       const appName = v.$parent.menuName || v.$parent.$options.label | ||||
|       return v.isAudit ? `${appName}审批` : `${appName}详情` | ||||
|     }, | ||||
|     isAudit: v => v.$route.hash == "#audit", | ||||
|     formImages: v => [ | ||||
|       {label: "身长测量照片", prop: "heightPic"}, | ||||
|       {label: "生物芯片照片", prop: "biochipPic"}, | ||||
|       {label: "防疫耳标照片", prop: "preventionPic"}, | ||||
|       {label: "其他说明照片", prop: "otherPic"}, | ||||
|     ], | ||||
|   }, | ||||
|   methods: { | ||||
|     back(params = {}) { | ||||
|       this.$router.push(params) | ||||
|     }, | ||||
|     getDetail() { | ||||
|       const {id} = this.$route.query | ||||
|       return id && this.instance.post("/api/breed/death/page", null, {params: {id}}).then(res => { | ||||
|         if (res?.data?.records) { | ||||
|           const detail = res.data.records[0] || {} | ||||
|           if (detail.picture) { | ||||
|             Object.entries(JSON.parse(detail.picture)).forEach(([key, value]) => { | ||||
|               detail[key] = value | ||||
|             }) | ||||
|           } | ||||
|           return this.detail = {...detail} | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     submit() { | ||||
|       this.$refs.detail.validate().then(() => { | ||||
|         this.instance.post("/api/breed/death/audit", {...this.detail}).then(res => { | ||||
|           if (res?.code == '0') { | ||||
|             this.$message.success("提交成功!") | ||||
|             this.back() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.getDetail() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-page :title="pageTitle" class="deathAdd" showBack content-string="blank"> | ||||
|     <el-form size="small" label-width="120px" :model="detail" ref="detail"> | ||||
|       <ai-card title="基础信息"> | ||||
|         <div class="grid c-4"> | ||||
|           <el-form-item label="生物芯片耳标号" class="row"> | ||||
|             <b v-text="detail.biochipEarNumber"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="养殖场" prop="farmId"> | ||||
|             <b v-text="detail.farmName"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="养殖舍" prop="houseId"> | ||||
|             <b v-text="detail.houseName"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="养殖栏" prop="penId"> | ||||
|             <b v-text="detail.penName"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="电子耳标号" prop="electronicEarNumber"> | ||||
|             <b v-text="detail.electronicEarNumber"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="原厂耳标号" prop="category"> | ||||
|             <b v-text="detail.originalEarNumber"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="类别" prop="category"> | ||||
|             <b v-text="detail.category"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="品种" prop="variety"> | ||||
|             <b v-text="detail.variety"/> | ||||
|           </el-form-item> | ||||
|           <div class="row flex"> | ||||
|             <el-form-item v-for="(img,i) in formImages" :key="i" v-bind="img"> | ||||
|               <ai-uploader v-model="detail[img.prop]" value-is-url readonly/> | ||||
|             </el-form-item> | ||||
|           </div> | ||||
|         </div> | ||||
|       </ai-card> | ||||
|       <ai-card title="死亡信息"> | ||||
|         <el-form-item label="死亡原因"> | ||||
|           <b v-text="dict.getLabel('deathReason',detail.reason)"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="死亡日期"> | ||||
|           <b v-text="detail.deathTime"/> | ||||
|         </el-form-item> | ||||
|         <el-form-item label="备注"> | ||||
|           <b v-text="detail.remark"/> | ||||
|         </el-form-item> | ||||
|       </ai-card> | ||||
|       <ai-card title="审核信息"> | ||||
|         <div class="grid"> | ||||
|           <template v-if="isAudit"> | ||||
|             <el-form-item label="审批状态" prop="auditStatus" :rules="{required:true,message:'请选择审批状态'}"> | ||||
|               <ai-select v-model="detail.auditStatus" dict="auditStatus"/> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="意见"> | ||||
|               <ai-input type="textarea" :rows="3" v-model="detail.remark"/> | ||||
|             </el-form-item> | ||||
|           </template> | ||||
|           <template v-else> | ||||
|             <el-form-item label="审核状态">{{ dict.getLabel('auditStatus', detail.auditStatus) }}</el-form-item> | ||||
|             <el-form-item label="审核时间">{{ detail.auditTime }}</el-form-item> | ||||
|             <el-form-item label="审核人">{{ detail.auditName }}</el-form-item> | ||||
|             <el-form-item label="意见">{{ detail.remarks }}</el-form-item> | ||||
|           </template> | ||||
|         </div> | ||||
|       </ai-card> | ||||
|     </el-form> | ||||
|     <div slot="footer"> | ||||
|       <template v-if="isAudit"> | ||||
|         <el-button type="primary" @click="submit">提交</el-button> | ||||
|       </template> | ||||
|       <el-button @click="back">返回</el-button> | ||||
|     </div> | ||||
|   </ai-page> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .deathAdd { | ||||
|   :deep(.el-form--label-top) { | ||||
|     .el-form-item__label { | ||||
|       width: 100% !important; | ||||
|     } | ||||
|  | ||||
|     .el-form-item__content { | ||||
|       margin-left: unset !important; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										112
									
								
								project/xumu/AppDeathAudit/list.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								project/xumu/AppDeathAudit/list.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | ||||
| <script> | ||||
| import {mapState} from "vuex" | ||||
|  | ||||
| const columns = [ | ||||
|   {label: "序号", type: "index"}, | ||||
|   {label: "养殖场", format: (v, row) => `${[row.farmName, row.houseName, row.penName].join("-")}`}, | ||||
|   {label: "生物芯片耳标号", prop: "biochipEarNumber"}, | ||||
|   {label: "类别", prop: "category", dict: "category", width: 120}, | ||||
|   {label: "品种", prop: "variety", dict: "variety", width: 120}, | ||||
|   {label: "日龄(天)", prop: "age", width: 80}, | ||||
|   {label: "死亡时间", prop: "deathTime"}, | ||||
|   {label: "死亡原因", prop: "reason", dict: "deathReason", width: 80}, | ||||
|   {label: "登记时间", prop: "createTime"}, | ||||
|   {label: "操作人", prop: "userName", width: 100}, | ||||
|   {label: "审核状态", prop: "auditStatus", dict: "auditStatus", width: 80}, | ||||
| ] | ||||
| export default { | ||||
|   name: "deathList", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       columns, | ||||
|       tableData: [], | ||||
|       page: {pageNum: 1, pageSize: 10, total: 0}, | ||||
|       search: {}, | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     userinfo: v => v.user.info || {}, | ||||
|     pageTitle: v => v.$parent.menuName || v.$parent.$options.label | ||||
|   }, | ||||
|   watch: { | ||||
|     search: { | ||||
|       deep: true, | ||||
|       handler() { | ||||
|         this.page.pageNum = 1 | ||||
|         this.getTableData() | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     getTableData() { | ||||
|       this.instance.post("/api/breed/death/getAuditPage", {...this.page, ...this.search}).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.tableData = res.data?.records.map(e => ({...e, permit: `${e.status}` + e.auditStatus})) | ||||
|           this.page.total = res.data.total | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.getTableData() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-page class="deathList" :title="pageTitle"> | ||||
|     <ai-search-bar> | ||||
|       <template #left> | ||||
|         <ai-select placeholder="全部养殖场" v-model="search.farmId" :instance="instance" :action="`/api/siteUser/querySiteByUserId?userId=${userinfo.id}`" :prop="{label:'name'}"/> | ||||
|         <ai-select placeholder="全部养殖舍" v-model="search.houseId" :instance="instance" :action="`/api/siteUser/querySiteById?id=${search.farmId||-1}`" :prop="{label:'name'}"/> | ||||
|         <ai-select placeholder="全部养殖栏" v-model="search.penId" :instance="instance" :action="`/api/siteUser/querySiteById?id=${search.houseId||-1}`" :prop="{label:'name'}"/> | ||||
|         <ai-select placeholder="全部审核状态" v-model="search.auditStatus" dict="auditStatus"/> | ||||
|         <ai-search label="死亡日期"> | ||||
|           <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.deathBeginDate" type="datetime" placeholder="开始日期" size="small"/> | ||||
|           <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.deathEndDate" type="datetime" placeholder="结束日期" size="small"/> | ||||
|         </ai-search> | ||||
|         <ai-search label="登记日期"> | ||||
|           <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.beginDate" type="datetime" placeholder="开始日期" size="small"/> | ||||
|           <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.endDate" type="datetime" placeholder="结束日期" size="small"/> | ||||
|         </ai-search> | ||||
|         <ai-input placeholder="原场耳标号" v-model="search.originalEarNumber"/> | ||||
|         <ai-input placeholder="生物芯片耳标号" v-model="search.biochipEarNumber"/> | ||||
|         <ai-input placeholder="电子耳标号" v-model="search.electronicEarNumber"/> | ||||
|       </template> | ||||
|     </ai-search-bar> | ||||
|     <ai-search-bar> | ||||
|       <template #left> | ||||
|         <ai-download :instance="instance" url="/api/breed/death/export" :params="{...search,...page}" :fileName="`${pageTitle}导出表-${Date.now()}`"/> | ||||
|       </template> | ||||
|     </ai-search-bar> | ||||
|     <ai-table :tableData="tableData" :colConfigs="columns" :dict="dict" @getList="getTableData" | ||||
|               :total="page.total" :current.sync="page.pageNum" :size.sync="page.pageSize"> | ||||
|       <el-table-column slot="options" label="操作" fixed="right" align="center"> | ||||
|         <template slot-scope="{row}"> | ||||
|           <div class="table-options"> | ||||
|             <template v-if="['1'].includes(row.auditStatus)"> | ||||
|               <el-button type="text" @click="$router.push({hash:'#audit',query:{id:row.id}})">审核</el-button> | ||||
|             </template> | ||||
|             <el-button v-else type="text" @click="$router.push({hash:'#add',query:{id:row.id}})">查看</el-button> | ||||
|           </div> | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|     </ai-table> | ||||
|   </ai-page> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .deathList { | ||||
|   height: 100%; | ||||
|  | ||||
|   .deleteBtn { | ||||
|     color: $errorColor; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										35
									
								
								project/xumu/AppDeathManage/AppDeathManage.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								project/xumu/AppDeathManage/AppDeathManage.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | ||||
| <script> | ||||
| import add from "./add.vue"; | ||||
| import list from "./list.vue"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppDeathManage", | ||||
|   label: "死亡登记", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     currentPage() { | ||||
|       let { hash } = this.$route | ||||
|       return hash == "#add" ? add : list | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.dict.load("yesOrNo", "category", "variety", "deathReason", "auditStatus") | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <section class="AppDeathManage"> | ||||
|     <component :is="currentPage" v-bind="$props" /> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .AppDeathManage { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										167
									
								
								project/xumu/AppDeathManage/add.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								project/xumu/AppDeathManage/add.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,167 @@ | ||||
| <script> | ||||
| import {mapState} from "vuex" | ||||
| import AiEartagRemote from "@project/xumu/components/AiEartagRemote.vue"; | ||||
|  | ||||
| const formImages = [ | ||||
|   {label: "身长测量照片", prop: "heightPic",}, | ||||
|   {label: "生物芯片照片", prop: "biochipPic",}, | ||||
|   {label: "防疫耳标照片", prop: "preventionPic",}, | ||||
|   {label: "其他说明照片", prop: "otherPic",}, | ||||
| ] | ||||
| export default { | ||||
|   name: "deathAdd", | ||||
|   components: {AiEartagRemote}, | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     permissions: Function, | ||||
|     dict: Object | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       formImages, | ||||
|       detail: {}, | ||||
|       form: {} | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(["user"]), | ||||
|     userinfo: v => v.user.info || {}, | ||||
|     isAdd: v => !v.$route.query.id, | ||||
|     isEdit: v => v.$route.query.edit == 1, | ||||
|     isAuthing: v => v.detail.auditStatus == 1, | ||||
|     pageTitle: v => { | ||||
|       const appName = v.$parent.menuName || v.$parent.$options.label | ||||
|       return v.$route.query.id ? v.isEdit ? `编辑${appName}` : `${appName}详情` : `新增${appName}` | ||||
|     }, | ||||
|   }, | ||||
|   methods: { | ||||
|     back(params = {}) { | ||||
|       this.$router.push(params) | ||||
|     }, | ||||
|     getDetail(id) { | ||||
|       return id && this.instance.post("/api/breed/death/page", {biochipEarNumber: id}).then(res => { | ||||
|         if (res?.data?.records) { | ||||
|           const detail = res.data.records[0] || {} | ||||
|           if (detail.picture) { | ||||
|             Object.entries(JSON.parse(detail.picture)).forEach(([key, value]) => { | ||||
|               detail[key] = value | ||||
|             }) | ||||
|           } | ||||
|           return this.detail = {...detail} | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     submit() { | ||||
|       this.$refs.detail.validate().then(() => { | ||||
|         const {biochipEarNumber, id, deathTime, heightPic, biochipPic, preventionPic, otherPic, reason, remarks} = this.detail | ||||
|         this.instance.post("/api/breed/death/addOrEdit", { | ||||
|           biochipEarNumber, id, deathTime, picture: JSON.stringify({heightPic, biochipPic, preventionPic, otherPic}), reason, remarks | ||||
|         }).then(res => { | ||||
|           if (res?.code == 0 && res?.data != 1) { | ||||
|             this.$confirm("是否返回列表页?", "提交成功").then(() => this.back()).catch(() => this.getDetail(biochipEarNumber)) | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|     handleAudit() { | ||||
|       this.$refs.form.validate().then(() => { | ||||
|         const {id} = this.detail | ||||
|         this.instance.post("/api/breed/death/audit", null, {params: {id, ...this.form}}).then(res => { | ||||
|           if (res?.code == 0) { | ||||
|             this.$message.success("操作成功") | ||||
|             this.back() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|     handlerAutocomplete(value) { | ||||
|       'biochipEarNumber|farmId|houseId|penId|electronicEarNumber|originalEarNumber|category|variety'.split("|").forEach(prop => this.$set(this.detail, prop, value[prop])) | ||||
|     }, | ||||
|   }, | ||||
|   created() { | ||||
|     this.getDetail(this.$route.query.id) | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-page :title="pageTitle" class="deathAdd" showBack content-string="blank"> | ||||
|     <el-form size="small" label-width="120px" :model="detail" ref="detail"> | ||||
|       <ai-card title="基础信息"> | ||||
|         <div class="grid c-4"> | ||||
|           <ai-eartag-remote :instance="instance" @enter="handlerAutocomplete" class="row"/> | ||||
|           <el-form-item label="生物芯片耳标号"> | ||||
|             <b v-text="detail.biochipEarNumber"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="养殖场" prop="farmId"> | ||||
|             <b v-text="detail.farmName"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="养殖舍" prop="houseId"> | ||||
|             <b v-text="detail.houseName"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="养殖栏" prop="penId"> | ||||
|             <b v-text="detail.penName"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="电子耳标号" prop="electronicEarNumber"> | ||||
|             <b v-text="detail.electronicEarNumber"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="原厂耳标号" prop="originalEarNumber"> | ||||
|             <b v-text="detail.originalEarNumber"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="类别" prop="category"> | ||||
|             <b v-text="detail.category"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="品种" prop="variety"> | ||||
|             <b v-text="detail.variety"/> | ||||
|           </el-form-item> | ||||
|         </div> | ||||
|       </ai-card> | ||||
|       <ai-card title="上传照片"> | ||||
|         <div class="grid c-4"> | ||||
|           <el-form-item v-for="(img,i) in formImages" :key="i" v-bind="img"> | ||||
|             <ai-uploader v-if="isAdd||isEdit" v-model="detail[img.prop]" :instance="instance" :limit="1" value-is-url/> | ||||
|             <el-image :src="detail[img.prop]" :preview-src-list="[detail[img.prop]]" v-else/> | ||||
|           </el-form-item> | ||||
|         </div> | ||||
|       </ai-card> | ||||
|       <ai-card title="死亡录入"> | ||||
|         <div class="grid"> | ||||
|           <el-form-item label="死亡日期" prop="deathTime" :rules="[{required:isAdd||isEdit,message:'请选择死亡日期'}]"> | ||||
|             <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-if="isAdd||isEdit" v-model="detail.deathTime"/> | ||||
|             <b v-else v-text="detail.deathTime"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="死亡原因" prop="reason" :rules="[{required:isAdd||isEdit,message:'请选择死亡原因'}]"> | ||||
|             <ai-select v-if="isAdd||isEdit" v-model="detail.reason" dict="deathReason"/> | ||||
|             <b v-else v-text="dict.getLabel('deathReason',detail.reason)"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="备注" prop="remark" class="row"> | ||||
|             <ai-input type="textarea" :row="3" v-model="detail.remark" :edit="isAdd||isEdit"/> | ||||
|           </el-form-item> | ||||
|         </div> | ||||
|       </ai-card> | ||||
|       <ai-card title="审批信息" v-if="isAuthing"> | ||||
|         <el-form :model="form" size="small" ref="form" label-width="120px"> | ||||
|           <el-form-item label="是否同意" prop="auditStatus" :rules="[{required:true,message:'请选择是否同意'}]"> | ||||
|             <ai-select v-model="form.auditStatus" :select-list="[{dictValue: 2, dictName: '同意'}, {dictValue: 3, dictName: '不同意'}]"/> | ||||
|           </el-form-item> | ||||
|           <el-form-item label="审批意见" prop="auditReason"> | ||||
|             <el-input type="textarea" :row="3" v-model="form.auditReason" clearable placeholder="请输入"/> | ||||
|           </el-form-item> | ||||
|         </el-form> | ||||
|       </ai-card> | ||||
|     </el-form> | ||||
|     <div slot="footer"> | ||||
|       <el-button type="primary" @click="submit" v-if="isAdd||isEdit">提交</el-button> | ||||
|       <el-button type="primary" @click="handleAudit" v-if="isAuthing">提交</el-button> | ||||
|       <el-button @click="back">返回</el-button> | ||||
|     </div> | ||||
|   </ai-page> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .deathAdd { | ||||
|   .el-date-editor { | ||||
|     width: 100%; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										142
									
								
								project/xumu/AppDeathManage/list.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								project/xumu/AppDeathManage/list.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | ||||
| <script> | ||||
| import {mapState} from "vuex" | ||||
|  | ||||
| const columns = [ | ||||
|   {label: "序号", type: "index"}, | ||||
|   {label: "养殖场",format: (v, row) => `${[row.farmName, row.houseName, row.penName].join("-")}`}, | ||||
|   {label: "生物芯片耳标号", prop: "biochipEarNumber"}, | ||||
|   {label: "类别", prop: "category", dict: "category", width: 120}, | ||||
|   {label: "品种", prop: "variety", dict: "variety", width: 120}, | ||||
|   {label: "日龄(天)", prop: "age", width: 80}, | ||||
|   {label: "死亡时间", prop: "deathTime"}, | ||||
|   {label: "死亡原因", prop: "reason", dict: "deathReason", width: 80}, | ||||
|   {label: "登记时间", prop: "createTime"}, | ||||
|   {label: "操作人", prop: "userName", width: 100}, | ||||
|   {label: "审核状态", prop: "auditStatus", dict: "auditStatus", width: 80}, | ||||
| ] | ||||
| export default { | ||||
|   name: "deathList", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       columns, | ||||
|       tableData: [], | ||||
|       page: {pageNum: 1, pageSize: 10, total: 0}, | ||||
|       search: {}, | ||||
|       dialog: false, | ||||
|       form: {} | ||||
|     } | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['user']), | ||||
|     userinfo: v => v.user.info || {}, | ||||
|     pageTitle: v => v.$parent.menuName || v.$parent.$options.label | ||||
|   }, | ||||
|   watch: { | ||||
|     search: { | ||||
|       deep: true, | ||||
|       handler() { | ||||
|         this.page.pageNum = 1 | ||||
|         this.getTableData() | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     getTableData() { | ||||
|       this.instance.post("/api/breed/death/page", {...this.page, ...this.search}).then(res => { | ||||
|         if (res?.data) { | ||||
|           this.tableData = res.data?.records | ||||
|           this.page.total = res.data.total | ||||
|         } | ||||
|       }) | ||||
|     }, | ||||
|     handleDelete(id) { | ||||
|       this.$confirm("确定删除该条数据?").then(() => { | ||||
|         this.instance.post("/api/breed/weight/del", null, { | ||||
|           params: {id} | ||||
|         }).then(res => { | ||||
|           if (res?.code == 0) { | ||||
|             this.getTableData() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     }, | ||||
|     handleAuditAgain(id) { | ||||
|       this.$confirm("是否要再次提交审批?").then(() => { | ||||
|         this.instance.post("/api/breed/death/audit", null, { | ||||
|           params: {id, auditStatus: 1} | ||||
|         }).then(res => { | ||||
|           if (res?.code == '0') { | ||||
|             this.$message.success("提交成功") | ||||
|             this.getTableData() | ||||
|           } | ||||
|         }) | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|   created() { | ||||
|     this.getTableData() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <template> | ||||
|   <ai-page class="deathList" :title="pageTitle"> | ||||
|     <ai-search-bar> | ||||
|       <template #left> | ||||
|         <ai-select placeholder="全部养殖场" v-model="search.farmId" :instance="instance" :action="`/api/siteUser/querySiteByUserId?userId=${userinfo.id}`" :prop="{label:'name'}"/> | ||||
|         <ai-select placeholder="全部养殖舍" v-model="search.houseId" :instance="instance" :action="`/api/siteUser/querySiteById?id=${search.farmId||-1}`" :prop="{label:'name'}"/> | ||||
|         <ai-select placeholder="全部养殖栏" v-model="search.penId" :instance="instance" :action="`/api/siteUser/querySiteById?id=${search.houseId||-1}`" :prop="{label:'name'}"/> | ||||
|         <ai-select placeholder="全部审核状态" v-model="search.auditStatus" dict="auditStatus"/> | ||||
|         <ai-search label="死亡日期"> | ||||
|           <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.deathBeginDate" type="datetime" placeholder="开始日期" size="small"/> | ||||
|           <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.deathEndDate" type="datetime" placeholder="结束日期" size="small"/> | ||||
|         </ai-search> | ||||
|         <ai-search label="登记日期"> | ||||
|           <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.beginDate" type="datetime" placeholder="开始日期" size="small"/> | ||||
|           <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="search.endDate" type="datetime" placeholder="结束日期" size="small"/> | ||||
|         </ai-search> | ||||
|         <ai-input placeholder="原场耳标号" v-model="search.originalEarNumber"/> | ||||
|         <ai-input placeholder="生物芯片耳标号" v-model="search.biochipEarNumber"/> | ||||
|         <ai-input placeholder="电子耳标号" v-model="search.electronicEarNumber"/> | ||||
|       </template> | ||||
|     </ai-search-bar> | ||||
|     <ai-search-bar> | ||||
|       <template #left> | ||||
|         <el-button type="primary" icon="iconfont iconAdd" @click="$router.push({hash:'#add'})">新增</el-button> | ||||
|         <ai-download :instance="instance" url="/api/breed/death/export" :params="{...search,...page}" :fileName="`死亡导出表-${Date.now()}`"/> | ||||
|       </template> | ||||
|     </ai-search-bar> | ||||
|     <ai-table :tableData="tableData" :colConfigs="columns" :dict="dict" @getList="getTableData" | ||||
|               :total="page.total" :current.sync="page.pageNum" :size.sync="page.pageSize"> | ||||
|       <el-table-column slot="options" label="操作" fixed="right" align="center"> | ||||
|         <template slot-scope="{row}"> | ||||
|           <div class="table-options"> | ||||
|  | ||||
|             <el-button v-if="row.auditStatus==1" type="text" @click="$router.push({hash:'#add',query:{id:row.biochipEarNumber}})">查看</el-button> | ||||
|             <template v-else> | ||||
|               <el-button v-if="row.auditStatus==2" type="text" @click="$router.push({hash:'#add',query:{id:row.biochipEarNumber}})">查看</el-button> | ||||
|               <el-button v-if="row.auditStatus==2" type="text" @click="$router.push({hash:'#add',query:{id:row.biochipEarNumber,edit:1}})">编辑</el-button> | ||||
|               <el-button v-if="row.auditStatus==3" type="text" @click="handleAuditAgain(row.id)">再次提交</el-button> | ||||
|               <el-button type="text" @click="handleDelete(row.id)">删除</el-button> | ||||
|             </template> | ||||
|           </div> | ||||
|         </template> | ||||
|       </el-table-column> | ||||
|     </ai-table> | ||||
|   </ai-page> | ||||
| </template> | ||||
|  | ||||
| <style scoped lang="scss"> | ||||
| .deathList { | ||||
|   height: 100%; | ||||
|  | ||||
|   .deleteBtn { | ||||
|     color: $errorColor; | ||||
|   } | ||||
| } | ||||
| </style> | ||||
							
								
								
									
										32
									
								
								project/xumu/AppDictionary/AppDictionary.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								project/xumu/AppDictionary/AppDictionary.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| <template> | ||||
|   <section class="AppDictionary"> | ||||
|     <component :is="currentPage" v-bind="$props"/> | ||||
|   </section> | ||||
| </template> | ||||
|  | ||||
| <script> | ||||
| import DictDetail from "./dictDetail"; | ||||
| import DictList from "@project/xumu/AppDictionary/dictList.vue"; | ||||
|  | ||||
| export default { | ||||
|   name: "AppDictionary", | ||||
|   label: "数据字典", | ||||
|   props: { | ||||
|     instance: Function, | ||||
|     dict: Object, | ||||
|     permissions: Function | ||||
|   }, | ||||
|   computed: { | ||||
|     currentPage() { | ||||
|       let {hash} = this.$route | ||||
|       return hash == "#add" ? DictDetail : DictList | ||||
|     } | ||||
|   }, | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" scoped> | ||||
| .AppDictionary { | ||||
|   height: 100%; | ||||
| } | ||||
| </style> | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user