初始化产品库
							
								
								
									
										25
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,25 @@ | |||||||
|  | .DS_Store | ||||||
|  | node_modules/ | ||||||
|  | unpackage/ | ||||||
|  | dist/ | ||||||
|  |  | ||||||
|  | # local env files | ||||||
|  | .env.local | ||||||
|  | .env.*.local | ||||||
|  |  | ||||||
|  | # Log files | ||||||
|  | npm-debug.log* | ||||||
|  | yarn-debug.log* | ||||||
|  | yarn-error.log* | ||||||
|  |  | ||||||
|  | # Editor directories and files | ||||||
|  | .project | ||||||
|  | .idea | ||||||
|  | .vscode | ||||||
|  | *.suo | ||||||
|  | *.ntvs* | ||||||
|  | *.njsproj | ||||||
|  | *.sln | ||||||
|  | *.sw* | ||||||
|  | /package-lock.json | ||||||
|  | /.hbuilderx/launch.json | ||||||
							
								
								
									
										64
									
								
								babel.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,64 @@ | |||||||
|  | const plugins = [] | ||||||
|  |  | ||||||
|  | if (process.env.UNI_OPT_TREESHAKINGNG) { | ||||||
|  |   plugins.push(require('@dcloudio/vue-cli-plugin-uni-optimize/packages/babel-plugin-uni-api/index.js')) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | if ( | ||||||
|  |     ( | ||||||
|  |         process.env.UNI_PLATFORM === 'app-plus' && | ||||||
|  |         process.env.UNI_USING_V8 | ||||||
|  |     ) || | ||||||
|  |     ( | ||||||
|  |         process.env.UNI_PLATFORM === 'h5' && | ||||||
|  |         process.env.UNI_H5_BROWSER === 'builtin' | ||||||
|  |     ) | ||||||
|  | ) { | ||||||
|  |   const path = require('path') | ||||||
|  |  | ||||||
|  |   const isWin = /^win/.test(process.platform) | ||||||
|  |  | ||||||
|  |   const normalizePath = path => (isWin ? path.replace(/\\/g, '/') : path) | ||||||
|  |  | ||||||
|  |   const input = normalizePath(process.env.UNI_INPUT_DIR) | ||||||
|  |   try { | ||||||
|  |     plugins.push([ | ||||||
|  |       require('@dcloudio/vue-cli-plugin-hbuilderx/packages/babel-plugin-console'), | ||||||
|  |       { | ||||||
|  |         file(file) { | ||||||
|  |           file = normalizePath(file) | ||||||
|  |           if (file.indexOf(input) === 0) { | ||||||
|  |             return path.relative(input, file) | ||||||
|  |           } | ||||||
|  |           return false | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     ]) | ||||||
|  |   } catch (e) { | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | process.UNI_LIBRARIES = process.UNI_LIBRARIES || ['@dcloudio/uni-ui'] | ||||||
|  | process.UNI_LIBRARIES.forEach(libraryName => { | ||||||
|  |   plugins.push([ | ||||||
|  |     'import', | ||||||
|  |     { | ||||||
|  |       'libraryName': libraryName, | ||||||
|  |       'customName': (name) => { | ||||||
|  |         return `${libraryName}/lib/${name}/${name}` | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   ]) | ||||||
|  | }) | ||||||
|  | module.exports = { | ||||||
|  |   presets: [ | ||||||
|  |     [ | ||||||
|  |       '@vue/app', | ||||||
|  |       { | ||||||
|  |         modules: 'commonjs', | ||||||
|  |         useBuiltIns: process.env.UNI_PLATFORM === 'h5' ? 'usage' : 'entry' | ||||||
|  |       } | ||||||
|  |     ] | ||||||
|  |   ], | ||||||
|  |   plugins | ||||||
|  | } | ||||||
							
								
								
									
										84
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,84 @@ | |||||||
|  | { | ||||||
|  |   "name": "dv_cp_wechat", | ||||||
|  |   "version": "0.1.0", | ||||||
|  |   "private": true, | ||||||
|  |   "scripts": { | ||||||
|  |     "dev": "cross-env NODE_ENV=development UNI_PLATFORM=h5 vue-cli-service uni-serve --minimize", | ||||||
|  |     "build": "cross-env NODE_ENV=production UNI_PLATFORM=h5 vue-cli-service uni-build", | ||||||
|  |     "build:mp-weixin": "cross-env NODE_ENV=production UNI_PLATFORM=mp-weixin vue-cli-service uni-build", | ||||||
|  |     "dev:mp-weixin": "cross-env NODE_ENV=development UNI_PLATFORM=mp-weixin vue-cli-service uni-build --watch", | ||||||
|  |     "info": "node node_modules/@dcloudio/vue-cli-plugin-uni/commands/info.js", | ||||||
|  |     "test:mp-weixin": "cross-env UNI_PLATFORM=mp-weixin jest -i" | ||||||
|  |   }, | ||||||
|  |   "dependencies": { | ||||||
|  |     "@amap/amap-jsapi-loader": "^1.0.1", | ||||||
|  |     "@dcloudio/uni-app-plus": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/uni-h5": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/uni-helper-json": "*", | ||||||
|  |     "@dcloudio/uni-mp-360": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/uni-mp-alipay": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/uni-mp-baidu": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/uni-mp-kuaishou": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/uni-mp-qq": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/uni-mp-toutiao": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/uni-mp-vue": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/uni-mp-weixin": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/uni-quickapp-native": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/uni-quickapp-webview": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/uni-stat": "^2.0.0-31820210406002", | ||||||
|  |     "@vue/shared": "^3.0.0", | ||||||
|  |     "axios": "^0.21.1", | ||||||
|  |     "core-js": "^3.11.0", | ||||||
|  |     "dayjs": "^1.10.6", | ||||||
|  |     "echarts": "^4.9.0", | ||||||
|  |     "recorder-core": "^1.1.21080800", | ||||||
|  |     "regenerator-runtime": "^0.12.1", | ||||||
|  |     "vue": "^2.6.11", | ||||||
|  |     "vuedraggable": "^2.24.3", | ||||||
|  |     "vuex": "^3.2.0", | ||||||
|  |     "vuex-persistedstate": "^4.0.0-beta.3" | ||||||
|  |   }, | ||||||
|  |   "devDependencies": { | ||||||
|  |     "@babel/runtime": "~7.12.0", | ||||||
|  |     "@dcloudio/types": "^2.2.1", | ||||||
|  |     "@dcloudio/uni-automator": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/uni-cli-i18n": "^2.0.0-32920211029001", | ||||||
|  |     "@dcloudio/uni-cli-shared": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/uni-i18n": "^2.0.0-32920211029001", | ||||||
|  |     "@dcloudio/uni-migration": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/uni-template-compiler": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/vue-cli-plugin-hbuilderx": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/vue-cli-plugin-uni": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/vue-cli-plugin-uni-optimize": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/webpack-uni-mp-loader": "^2.0.0-31820210406002", | ||||||
|  |     "@dcloudio/webpack-uni-pages-loader": "^2.0.0-31820210406002", | ||||||
|  |     "@vue/cli-plugin-babel": "^4.5.12", | ||||||
|  |     "@vue/cli-service": "~4.5.0", | ||||||
|  |     "babel-plugin-import": "^1.11.0", | ||||||
|  |     "cross-env": "^7.0.2", | ||||||
|  |     "jest": "^25.4.0", | ||||||
|  |     "mini-types": "*", | ||||||
|  |     "miniprogram-api-typings": "^3.3.2", | ||||||
|  |     "node-sass": "npm:dart-sass@^1.25.0", | ||||||
|  |     "postcss-comment": "^2.0.0", | ||||||
|  |     "sass-loader": "^7.1.0", | ||||||
|  |     "vue-template-compiler": "^2.6.11" | ||||||
|  |   }, | ||||||
|  |   "browserslist": [ | ||||||
|  |     "Android >= 4", | ||||||
|  |     "ios >= 8" | ||||||
|  |   ], | ||||||
|  |   "uni-app": { | ||||||
|  |     "scripts": { | ||||||
|  |       "cp-weixin": { | ||||||
|  |         "title": "企业微信端", | ||||||
|  |         "env": { | ||||||
|  |           "UNI_PLATFORM": "mp-weixin" | ||||||
|  |         }, | ||||||
|  |         "define": { | ||||||
|  |           "CP-WEIXIN": true | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								postcss.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,22 @@ | |||||||
|  | const path = require('path') | ||||||
|  | module.exports = { | ||||||
|  |   parser: require('postcss-comment'), | ||||||
|  |   plugins: [ | ||||||
|  |     require('postcss-import')({ | ||||||
|  |       resolve (id, basedir, importOptions) { | ||||||
|  |         if (id.startsWith('~@/')) { | ||||||
|  |           return path.resolve(process.env.UNI_INPUT_DIR, id.substr(3)) | ||||||
|  |         } else if (id.startsWith('@/')) { | ||||||
|  |           return path.resolve(process.env.UNI_INPUT_DIR, id.substr(2)) | ||||||
|  |         } else if (id.startsWith('/') && !id.startsWith('//')) { | ||||||
|  |           return path.resolve(process.env.UNI_INPUT_DIR, id.substr(1)) | ||||||
|  |         } | ||||||
|  |         return id | ||||||
|  |       } | ||||||
|  |     }), | ||||||
|  |     require('autoprefixer')({ | ||||||
|  |       remove: process.env.UNI_PLATFORM !== 'h5' | ||||||
|  |     }), | ||||||
|  |     require('@dcloudio/vue-cli-plugin-uni/packages/postcss') | ||||||
|  |   ] | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								public/WW_verify_BeLokK3oa5SpR9ER.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | |||||||
|  | BeLokK3oa5SpR9ER | ||||||
							
								
								
									
										1
									
								
								public/WW_verify_mSayjTrg7ZGXGC2D.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | |||||||
|  | mSayjTrg7ZGXGC2D | ||||||
							
								
								
									
										1
									
								
								public/WW_verify_ual6jgcTCMb4cdLb.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1 @@ | |||||||
|  | ual6jgcTCMb4cdLb | ||||||
							
								
								
									
										28
									
								
								public/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,28 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html lang="zh-CN"> | ||||||
|  |  | ||||||
|  | <head> | ||||||
|  |   <meta charset="utf-8"> | ||||||
|  |   <meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||||||
|  |   <title> | ||||||
|  |     <%= htmlWebpackPlugin.options.title %> | ||||||
|  |   </title> | ||||||
|  |   <script> | ||||||
|  |     document.addEventListener('DOMContentLoaded', function () { | ||||||
|  |       document.documentElement.style.fontSize = document.documentElement.clientWidth / 20 + 'px' | ||||||
|  |     }) | ||||||
|  |     var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') || CSS.supports('top: constant(a)')) | ||||||
|  |     document.write('<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' + (coverSupport ? ', viewport-fit=cover' : '') + '" />') | ||||||
|  |   </script> | ||||||
|  |   <link rel="stylesheet" href="<%= BASE_URL %>static/index.<%= VUE_APP_INDEX_CSS_HASH %>.css"/> | ||||||
|  | </head> | ||||||
|  |  | ||||||
|  | <body> | ||||||
|  | <noscript> | ||||||
|  |   <strong>Please enable JavaScript to continue.</strong> | ||||||
|  | </noscript> | ||||||
|  | <div id="app"></div> | ||||||
|  | <!-- built files will be auto injected --> | ||||||
|  | </body> | ||||||
|  |  | ||||||
|  | </html> | ||||||
							
								
								
									
										164
									
								
								src/App.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,164 @@ | |||||||
|  | <script> | ||||||
|  | import {mapMutations, mapState} from 'vuex' | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   provide() { | ||||||
|  |     return { | ||||||
|  |       root: this, | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   onLaunch: function () { | ||||||
|  |     this.initConfig() | ||||||
|  |   }, | ||||||
|  |   onShow: function () { | ||||||
|  |     this.initWaterMarker() | ||||||
|  |   }, | ||||||
|  |   onPageNotFound() { | ||||||
|  |     this.logout() | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['token', 'user']), | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     ...mapMutations(['initWaterMarker', 'logout', 'getConfig']), | ||||||
|  |     initDev() { | ||||||
|  |       let baseURL = 'http://192.168.1.87:9000' | ||||||
|  |       this.getConfig({baseURL}) | ||||||
|  |        | ||||||
|  |       // this.$store.commit('login', 'bearer 88dd207a-dfe3-4f81-b9bd-e379de427d0b') | ||||||
|  |     }, | ||||||
|  |     initConfig() { | ||||||
|  |       if (process.env.NODE_ENV == 'development') this.initDev() | ||||||
|  |       else { | ||||||
|  |         let baseURL = location.origin | ||||||
|  |         this.getConfig({baseURL}) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss"> | ||||||
|  | @import 'uview/index.scss'; | ||||||
|  | @import './common/iconfont.css'; | ||||||
|  |  | ||||||
|  | body { | ||||||
|  |   font-family: 'Microsoft YaHei', serif; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uni-page-body { | ||||||
|  |   min-height: 100%; | ||||||
|  |   background: #f5f5f5; | ||||||
|  |   position: relative; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | div[bottom] { | ||||||
|  |   position: fixed; | ||||||
|  |   left: 0; | ||||||
|  |   bottom: 0; | ||||||
|  |   width: 100%; | ||||||
|  |   height: 128px; | ||||||
|  |   padding: 24px 32px; | ||||||
|  |   box-sizing: border-box; | ||||||
|  |   background: #ffffff; | ||||||
|  |   border-top: 1px solid #d4d4d4; | ||||||
|  |   display: flex; | ||||||
|  |   gap: 32px; | ||||||
|  |  | ||||||
|  |   & > * { | ||||||
|  |     flex: 1; | ||||||
|  |     min-width: 0; | ||||||
|  |  | ||||||
|  |     & + * { | ||||||
|  |       margin-left: 32px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | div[flex] { | ||||||
|  |   display: flex; | ||||||
|  |   align-items: center; | ||||||
|  |  | ||||||
|  |   &.spb { | ||||||
|  |     justify-content: space-between; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   &.wrap { | ||||||
|  |     flex-wrap: wrap; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   &.column { | ||||||
|  |     flex-direction: column; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   &.start { | ||||||
|  |     align-items: flex-start; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | div[shrink] { | ||||||
|  |   flex-shrink: 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uni-button { | ||||||
|  |   border-radius: 4px; | ||||||
|  |  | ||||||
|  |   &.u-btn--primary { | ||||||
|  |     background-color: $uni-color-primary !important; | ||||||
|  |     border-color: $uni-color-primary !important; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   &:after { | ||||||
|  |     border-radius: 4px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .fill { | ||||||
|  |   flex: 1; | ||||||
|  |   min-width: 0; | ||||||
|  |   min-height: 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .u-form-item { | ||||||
|  |   width: 100%; | ||||||
|  |   min-height: 100px; | ||||||
|  |   background: #ffffff; | ||||||
|  |   padding: 0 32px !important; | ||||||
|  |   box-sizing: border-box; | ||||||
|  |   display: flex; | ||||||
|  |   line-height: normal !important; | ||||||
|  |  | ||||||
|  |   .u-form-item__body { | ||||||
|  |     height: inherit; | ||||||
|  |     flex: 1; | ||||||
|  |  | ||||||
|  |     .u-form-item--left { | ||||||
|  |       min-height: 100px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .u-form-item--right__content__slot { | ||||||
|  |       padding-bottom: 10px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .u-form-item__message { | ||||||
|  |     margin: 15px 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @keyframes mapWarn { | ||||||
|  |   0% { | ||||||
|  |     transform: scale(.5); | ||||||
|  |     opacity: 1 | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   30% { | ||||||
|  |     opacity: .5 | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   to { | ||||||
|  |     transform: scale(1.4); | ||||||
|  |     opacity: 0 | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										61
									
								
								src/common/axios.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,61 @@ | |||||||
|  | import axios from 'axios' | ||||||
|  | import store from '../store' | ||||||
|  | import util from "./util"; | ||||||
|  |  | ||||||
|  | let instance = axios.create({ | ||||||
|  |   timeout: 600000, | ||||||
|  |   withCredentials: true, | ||||||
|  | }) | ||||||
|  | instance.interceptors.request.use(config => { | ||||||
|  |   store.commit('initWaterMarker') | ||||||
|  |   if (!config.withoutToken && store.state.token) { | ||||||
|  |     config.headers["Authorization"] = store.state.token | ||||||
|  |   } | ||||||
|  |   return config | ||||||
|  | }, err => { | ||||||
|  |   console.error(err) | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | instance.interceptors.response.use(res => { | ||||||
|  |   if (res.data) { | ||||||
|  |     if (res.data.code) { | ||||||
|  |       if (res.data.code == 0) { | ||||||
|  |         return res.data | ||||||
|  |       } else if (res.data.code == 401) { | ||||||
|  |         store.commit("logout"); | ||||||
|  |         let reg = new RegExp('.*code=(.+$)', "g") | ||||||
|  |         if (reg.test(location.search)) { | ||||||
|  |           let code = location.search.replace(reg, '$1') | ||||||
|  |           store.commit('bindAccount', { | ||||||
|  |             code, then: res => { | ||||||
|  |               store.commit("login", [res?.token_type, res?.access_token].join(" ").trim()) | ||||||
|  |               location.href = location.href.replace('code=' + code, '') | ||||||
|  |             } | ||||||
|  |           }) | ||||||
|  |         } else util.confirm("用户信息验证失效,是否要重新登录?").then(() => { | ||||||
|  |           store.commit('redirectCode') | ||||||
|  |           // let app = store.state.apps?.find(e => location.href.indexOf(e.path) > -1) | ||||||
|  |           // const goto = path => { | ||||||
|  |           //   location.href = location.origin + "/pages/loading?" + path | ||||||
|  |           // } | ||||||
|  |           // if (app) { | ||||||
|  |           //   goto(location.search + `&app=${app.key}`) | ||||||
|  |           // } else { | ||||||
|  |           //   goto(location.search + `#error`) | ||||||
|  |           // } | ||||||
|  |         }).catch(() => 0) | ||||||
|  |       } else { | ||||||
|  |         console.error(res.data.msg || "请求失败!") | ||||||
|  |         return Promise.reject(res.data.msg) | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       return res.data | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     console.error("服务器异常,请联系管理员!") | ||||||
|  |   } | ||||||
|  | }, err => { | ||||||
|  |   console.error(err) | ||||||
|  | }) | ||||||
|  |  | ||||||
|  | export default instance | ||||||
							
								
								
									
										50
									
								
								src/common/dict.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,50 @@ | |||||||
|  | import request from "./axios"; | ||||||
|  | import store from "../store"; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 封装字典工具类 | ||||||
|  |  */ | ||||||
|  | const $dict = { | ||||||
|  |   vueStore: null, | ||||||
|  |   url: "/admin/dictionary/queryValsByCodeList", | ||||||
|  |   setUrl(v) { | ||||||
|  |     this.url = v | ||||||
|  |   }, | ||||||
|  |   load(...code) { | ||||||
|  |     if (!this.vueStore) this.vueStore = store | ||||||
|  |     return request.post(this.url, null, { | ||||||
|  |       params: { | ||||||
|  |         codeList: code.join(',') | ||||||
|  |       } | ||||||
|  |     }).then((res) => { | ||||||
|  |       this.vueStore.commit("setDicts", res.data) | ||||||
|  |     }) | ||||||
|  |   }, | ||||||
|  |   getDict(key) { | ||||||
|  |     let dict = this.vueStore.getters.getDict(key) | ||||||
|  |     return dict ? dict.values : [] | ||||||
|  |   }, | ||||||
|  |   getValue(key, label) { | ||||||
|  |     let dict = this.vueStore.getters.getDict(key) | ||||||
|  |     if (dict) { | ||||||
|  |       let item = dict.values.find(v => v.dictName == label) | ||||||
|  |       return item ? item.dictValue : label | ||||||
|  |     } else return label | ||||||
|  |   }, | ||||||
|  |   getLabel(key, value) { | ||||||
|  |     let dict = this.vueStore.getters.getDict(key) | ||||||
|  |     if (dict) { | ||||||
|  |       let item = dict.values.find(v => v.dictValue == value) | ||||||
|  |       return item ? item.dictName : value | ||||||
|  |     } else return value | ||||||
|  |   }, | ||||||
|  |   getColor(key, value) { | ||||||
|  |     let dict = this.vueStore.getters.getDict(key) | ||||||
|  |     if (dict) { | ||||||
|  |       let item = dict.values.find(v => v.dictValue == value) | ||||||
|  |       return item ? item.dictColor : value | ||||||
|  |     } else return value | ||||||
|  |   }, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export default $dict | ||||||
							
								
								
									
										712
									
								
								src/common/iconfont.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										245
									
								
								src/common/permission.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,245 @@ | |||||||
|  | /// null = 未请求,1 = 已允许,0 = 拒绝|受限, 2 = 系统未开启 | ||||||
|  |  | ||||||
|  | var isIOS | ||||||
|  |  | ||||||
|  | function album() { | ||||||
|  |     var result = 0; | ||||||
|  |     var PHPhotoLibrary = plus.ios.import("PHPhotoLibrary"); | ||||||
|  |     var authStatus = PHPhotoLibrary.authorizationStatus(); | ||||||
|  |     if (authStatus === 0) { | ||||||
|  |         result = null; | ||||||
|  |     } else if (authStatus == 3) { | ||||||
|  |         result = 1; | ||||||
|  |     } else { | ||||||
|  |         result = 0; | ||||||
|  |     } | ||||||
|  |     plus.ios.deleteObject(PHPhotoLibrary); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function camera() { | ||||||
|  |     var result = 0; | ||||||
|  |     var AVCaptureDevice = plus.ios.import("AVCaptureDevice"); | ||||||
|  |     var authStatus = AVCaptureDevice.authorizationStatusForMediaType('vide'); | ||||||
|  |     if (authStatus === 0) { | ||||||
|  |         result = null; | ||||||
|  |     } else if (authStatus == 3) { | ||||||
|  |         result = 1; | ||||||
|  |     } else { | ||||||
|  |         result = 0; | ||||||
|  |     } | ||||||
|  |     plus.ios.deleteObject(AVCaptureDevice); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function location() { | ||||||
|  |     var result = 0; | ||||||
|  |     var cllocationManger = plus.ios.import("CLLocationManager"); | ||||||
|  |     var enable = cllocationManger.locationServicesEnabled(); | ||||||
|  |     var status = cllocationManger.authorizationStatus(); | ||||||
|  |     if (!enable) { | ||||||
|  |         result = 2; | ||||||
|  |     } else if (status === 0) { | ||||||
|  |         result = null; | ||||||
|  |     } else if (status === 3 || status === 4) { | ||||||
|  |         result = 1; | ||||||
|  |     } else { | ||||||
|  |         result = 0; | ||||||
|  |     } | ||||||
|  |     plus.ios.deleteObject(cllocationManger); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function push() { | ||||||
|  |     var result = 0; | ||||||
|  |     var UIApplication = plus.ios.import("UIApplication"); | ||||||
|  |     var app = UIApplication.sharedApplication(); | ||||||
|  |     var enabledTypes = 0; | ||||||
|  |     if (app.currentUserNotificationSettings) { | ||||||
|  |         var settings = app.currentUserNotificationSettings(); | ||||||
|  |         enabledTypes = settings.plusGetAttribute("types"); | ||||||
|  |         if (enabledTypes == 0) { | ||||||
|  |             result = 0; | ||||||
|  |             console.log("推送权限没有开启"); | ||||||
|  |         } else { | ||||||
|  |             result = 1; | ||||||
|  |             console.log("已经开启推送功能!") | ||||||
|  |         } | ||||||
|  |         plus.ios.deleteObject(settings); | ||||||
|  |     } else { | ||||||
|  |         enabledTypes = app.enabledRemoteNotificationTypes(); | ||||||
|  |         if (enabledTypes == 0) { | ||||||
|  |             result = 3; | ||||||
|  |             console.log("推送权限没有开启!"); | ||||||
|  |         } else { | ||||||
|  |             result = 4; | ||||||
|  |             console.log("已经开启推送功能!") | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     plus.ios.deleteObject(app); | ||||||
|  |     plus.ios.deleteObject(UIApplication); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function contact() { | ||||||
|  |     var result = 0; | ||||||
|  |     var CNContactStore = plus.ios.import("CNContactStore"); | ||||||
|  |     var cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0); | ||||||
|  |     if (cnAuthStatus === 0) { | ||||||
|  |         result = null; | ||||||
|  |     } else if (cnAuthStatus == 3) { | ||||||
|  |         result = 1; | ||||||
|  |     } else { | ||||||
|  |         result = 0; | ||||||
|  |     } | ||||||
|  |     plus.ios.deleteObject(CNContactStore); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function record() { | ||||||
|  |     var result = null; | ||||||
|  |     var avaudiosession = plus.ios.import("AVAudioSession"); | ||||||
|  |     var avaudio = avaudiosession.sharedInstance(); | ||||||
|  |     var status = avaudio.recordPermission(); | ||||||
|  |     console.log("permissionStatus:" + status); | ||||||
|  |     if (status === 1970168948) { | ||||||
|  |         result = null; | ||||||
|  |     } else if (status === 1735552628) { | ||||||
|  |         result = 1; | ||||||
|  |     } else { | ||||||
|  |         result = 0; | ||||||
|  |     } | ||||||
|  |     plus.ios.deleteObject(avaudiosession); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function calendar() { | ||||||
|  |     var result = null; | ||||||
|  |     var EKEventStore = plus.ios.import("EKEventStore"); | ||||||
|  |     var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(0); | ||||||
|  |     if (ekAuthStatus == 3) { | ||||||
|  |         result = 1; | ||||||
|  |         console.log("日历权限已经开启"); | ||||||
|  |     } else { | ||||||
|  |         console.log("日历权限没有开启"); | ||||||
|  |     } | ||||||
|  |     plus.ios.deleteObject(EKEventStore); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function memo() { | ||||||
|  |     var result = null; | ||||||
|  |     var EKEventStore = plus.ios.import("EKEventStore"); | ||||||
|  |     var ekAuthStatus = EKEventStore.authorizationStatusForEntityType(1); | ||||||
|  |     if (ekAuthStatus == 3) { | ||||||
|  |         result = 1; | ||||||
|  |         console.log("备忘录权限已经开启"); | ||||||
|  |     } else { | ||||||
|  |         console.log("备忘录权限没有开启"); | ||||||
|  |     } | ||||||
|  |     plus.ios.deleteObject(EKEventStore); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function requestIOS(permissionID) { | ||||||
|  |     return new Promise((resolve, reject) => { | ||||||
|  |         switch (permissionID) { | ||||||
|  |             case "push": | ||||||
|  |                 resolve(push()); | ||||||
|  |                 break; | ||||||
|  |             case "location": | ||||||
|  |                 resolve(location()); | ||||||
|  |                 break; | ||||||
|  |             case "record": | ||||||
|  |                 resolve(record()); | ||||||
|  |                 break; | ||||||
|  |             case "camera": | ||||||
|  |                 resolve(camera()); | ||||||
|  |                 break; | ||||||
|  |             case "album": | ||||||
|  |                 resolve(album()); | ||||||
|  |                 break; | ||||||
|  |             case "contact": | ||||||
|  |                 resolve(contact()); | ||||||
|  |                 break; | ||||||
|  |             case "calendar": | ||||||
|  |                 resolve(calendar()); | ||||||
|  |                 break; | ||||||
|  |             case "memo": | ||||||
|  |                 resolve(memo()); | ||||||
|  |                 break; | ||||||
|  |             default: | ||||||
|  |                 resolve(0); | ||||||
|  |                 break; | ||||||
|  |         } | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function requestAndroid(permissionID) { | ||||||
|  |     return new Promise((resolve, reject) => { | ||||||
|  |         plus.android.requestPermissions( | ||||||
|  |             [permissionID], | ||||||
|  |             function(resultObj) { | ||||||
|  |                 var result = 0; | ||||||
|  |                 for (var i = 0; i < resultObj.granted.length; i++) { | ||||||
|  |                     var grantedPermission = resultObj.granted[i]; | ||||||
|  |                     console.log('已获取的权限:' + grantedPermission); | ||||||
|  |                     result = 1 | ||||||
|  |                 } | ||||||
|  |                 for (var i = 0; i < resultObj.deniedPresent.length; i++) { | ||||||
|  |                     var deniedPresentPermission = resultObj.deniedPresent[i]; | ||||||
|  |                     console.log('拒绝本次申请的权限:' + deniedPresentPermission); | ||||||
|  |                     result = 0 | ||||||
|  |                 } | ||||||
|  |                 for (var i = 0; i < resultObj.deniedAlways.length; i++) { | ||||||
|  |                     var deniedAlwaysPermission = resultObj.deniedAlways[i]; | ||||||
|  |                     console.log('永久拒绝申请的权限:' + deniedAlwaysPermission); | ||||||
|  |                     result = -1 | ||||||
|  |                 } | ||||||
|  |                 resolve(result); | ||||||
|  |             }, | ||||||
|  |             function(error) { | ||||||
|  |                 console.log('result error: ' + error.message) | ||||||
|  |                 resolve({ | ||||||
|  |                     code: error.code, | ||||||
|  |                     message: error.message | ||||||
|  |                 }); | ||||||
|  |             } | ||||||
|  |         ); | ||||||
|  |     }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function gotoAppPermissionSetting() { | ||||||
|  |     if (permission.isIOS) { | ||||||
|  |         var UIApplication = plus.ios.import("UIApplication"); | ||||||
|  |         var application2 = UIApplication.sharedApplication(); | ||||||
|  |         var NSURL2 = plus.ios.import("NSURL"); | ||||||
|  |         var setting2 = NSURL2.URLWithString("app-settings:"); | ||||||
|  |         application2.openURL(setting2); | ||||||
|  |         plus.ios.deleteObject(setting2); | ||||||
|  |         plus.ios.deleteObject(NSURL2); | ||||||
|  |         plus.ios.deleteObject(application2); | ||||||
|  |     } else { | ||||||
|  |         var Intent = plus.android.importClass("android.content.Intent"); | ||||||
|  |         var Settings = plus.android.importClass("android.provider.Settings"); | ||||||
|  |         var Uri = plus.android.importClass("android.net.Uri"); | ||||||
|  |         var mainActivity = plus.android.runtimeMainActivity(); | ||||||
|  |         var intent = new Intent(); | ||||||
|  |         intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); | ||||||
|  |         var uri = Uri.fromParts("package", mainActivity.getPackageName(), null); | ||||||
|  |         intent.setData(uri); | ||||||
|  |         mainActivity.startActivity(intent); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const permission = { | ||||||
|  |     get isIOS(){ | ||||||
|  |         return typeof isIOS === 'boolean' ? isIOS : (isIOS = uni.getSystemInfoSync().platform === 'ios') | ||||||
|  |     }, | ||||||
|  |     requestIOS: requestIOS, | ||||||
|  |     requestAndroid: requestAndroid, | ||||||
|  |     gotoAppSetting: gotoAppPermissionSetting | ||||||
|  | } | ||||||
|  |  | ||||||
|  | module.exports = permission | ||||||
							
								
								
									
										59
									
								
								src/common/util.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,59 @@ | |||||||
|  | import dict from "./dict"; | ||||||
|  | import toast from '../uview/libs/function/toast' | ||||||
|  | import addUnit from '../uview/libs/function/addUnit' | ||||||
|  | import $parent from '../uview/libs/function/$parent' | ||||||
|  | import guid from '../uview/libs/function/guid' | ||||||
|  | import deepClone from '../uview/libs/function/deepClone' | ||||||
|  | import debounce from '../uview/libs/function/debounce' | ||||||
|  | import throttle from '../uview/libs/function/throttle' | ||||||
|  | import trim from '../uview/libs/function/trim' | ||||||
|  | import {sys} from '../uview/libs/function/sys' | ||||||
|  | import test from '../uview/libs/function/test' | ||||||
|  | import config from '../uview/libs/config/config' | ||||||
|  | import zIndex from '../uview/libs/config/zIndex' | ||||||
|  | import $moment from 'dayjs' | ||||||
|  |  | ||||||
|  | const confirm = (content, title, config) => { | ||||||
|  |   let ops = {content} | ||||||
|  |   if (typeof title == 'object') { | ||||||
|  |     ops = {...ops, ...title} | ||||||
|  |   } else ops = {...ops, title: title || "提示"} | ||||||
|  |   return new Promise((resolve, reject) => { | ||||||
|  |     uni.showModal({ | ||||||
|  |       ...ops, ...config, success: res => { | ||||||
|  |         if (res?.confirm) { | ||||||
|  |           resolve() | ||||||
|  |         } else if (res?.cancel) { | ||||||
|  |           reject() | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 获取年龄 | ||||||
|  |  * @param code | ||||||
|  |  */ | ||||||
|  | const calcAge = (code) => { | ||||||
|  |   let birthday | ||||||
|  |   if (typeof code == 'string' && code.length == 18) { | ||||||
|  |     birthday = $moment(code.substring(6, 14), 'YYYYMMDD') | ||||||
|  |   } else if (typeof code == 'object') { | ||||||
|  |     birthday = code | ||||||
|  |   } | ||||||
|  |   return Math.ceil($moment().year() - $moment(birthday).year()) | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | const u = {toast, $parent, addUnit, guid, config, zIndex, deepClone, throttle, debounce, trim, test, sys} | ||||||
|  | export default { | ||||||
|  |   dict, | ||||||
|  |   confirm, | ||||||
|  |   calcAge, | ||||||
|  |   u, | ||||||
|  |   dateFormat: (time, format) => { | ||||||
|  |     return $moment(time).format(format || 'YYYY-MM-DD').replace("Invalid Date", "") | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										69
									
								
								src/components/AiAdd.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,69 @@ | |||||||
|  | <template> | ||||||
|  |   <movable-area class="movableArea"> | ||||||
|  |     <movable-view direction="all" x="300" y="500"> | ||||||
|  |       <div class="AiAdd" @click.stop="add"></div> | ||||||
|  |     </movable-view> | ||||||
|  |   </movable-area> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  |   export default { | ||||||
|  |     name: "AiAdd", | ||||||
|  |     props: { | ||||||
|  |  | ||||||
|  |     }, | ||||||
|  |     data() { | ||||||
|  |       return {} | ||||||
|  |     }, | ||||||
|  |     methods: { | ||||||
|  |       add() { | ||||||
|  |         this.$emit("add") | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  |   .movableArea { | ||||||
|  |     position: fixed; | ||||||
|  |     left: 0; | ||||||
|  |     top: 0; | ||||||
|  |     width: 100%; | ||||||
|  |     height: 100%; | ||||||
|  |     pointer-events: none; | ||||||
|  |     z-index: 999; | ||||||
|  |  | ||||||
|  |     uni-movable-view { | ||||||
|  |       pointer-events: auto; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .AiAdd { | ||||||
|  |     width: 96px; | ||||||
|  |     height: 96px; | ||||||
|  |     background: #1365DD; | ||||||
|  |     box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); | ||||||
|  |     border-radius: 50%; | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     flex-direction: column; | ||||||
|  |     justify-content: center; | ||||||
|  |     &:before , &:after{ | ||||||
|  |       content: ""; | ||||||
|  |       background: #FFFFFF; | ||||||
|  |       display: block; | ||||||
|  |       position: absolute; | ||||||
|  |       border-radius: 4px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     &:before{ | ||||||
|  |       height: 48px; | ||||||
|  |       width: 4px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     &:after{ | ||||||
|  |       height: 4px; | ||||||
|  |       width: 48px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										87
									
								
								src/components/AiBack.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,87 @@ | |||||||
|  | <template> | ||||||
|  |   <ai-fixed-btn v-if="!isTopPage||custom"> | ||||||
|  |     <div class="AiBack" @click.stop="back"> | ||||||
|  |       <img :src="imgHomeUrl + 'back.png'" alt=""> | ||||||
|  |       <text>返回</text> | ||||||
|  |     </div> | ||||||
|  |   </ai-fixed-btn> | ||||||
|  | </template> | ||||||
|  | <script> | ||||||
|  | import AiFixedBtn from "./AiFixedBtn"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "AiBack", | ||||||
|  |   components: {AiFixedBtn}, | ||||||
|  |   props: { | ||||||
|  |     delta: { | ||||||
|  |       type: Number, | ||||||
|  |       default: 1 | ||||||
|  |     }, | ||||||
|  |     eventName: { | ||||||
|  |       type: String, | ||||||
|  |       default: '' | ||||||
|  |     }, | ||||||
|  |     data: { | ||||||
|  |       type: Object | Boolean, | ||||||
|  |       default: () => { | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     custom: Boolean, | ||||||
|  |     visible: Boolean, | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       isTopPage: false | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     back() { | ||||||
|  |       if (this.visible) | ||||||
|  |         return this.$parent.$emit(this.eventName, this.data) | ||||||
|  |  | ||||||
|  |       if (this.custom) { | ||||||
|  |         this.$emit("back") | ||||||
|  |       } else uni.navigateBack({ | ||||||
|  |         delta: this.delta, | ||||||
|  |         success: () => { | ||||||
|  |           if (this.eventName != '') { | ||||||
|  |             uni.$emit(this.eventName, this.data) | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |         fail: (err) => { | ||||||
|  |           console.error(err) | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   mounted() { | ||||||
|  |     this.isTopPage = window.history.length <= 1 | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiBack { | ||||||
|  |   width: 108px; | ||||||
|  |   height: 108px; | ||||||
|  |   background: #6BA1F9; | ||||||
|  |   box-shadow: 0 0 12px 0 rgba(0, 0, 0, 0.12); | ||||||
|  |   border-radius: 50%; | ||||||
|  |   display: flex; | ||||||
|  |   align-items: center; | ||||||
|  |   flex-direction: column; | ||||||
|  |   justify-content: center; | ||||||
|  |  | ||||||
|  |   img { | ||||||
|  |     width: 40px; | ||||||
|  |     height: 40px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   text { | ||||||
|  |     font-size: 26px; | ||||||
|  |     font-weight: 800; | ||||||
|  |     color: #FFFFFF; | ||||||
|  |     line-height: 40px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										115
									
								
								src/components/AiCard.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,115 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiCard"> | ||||||
|  |     <div flex v-if="$slots.custom" class="start"> | ||||||
|  |       <div class="fill"> | ||||||
|  |         <slot name="custom"/> | ||||||
|  |       </div> | ||||||
|  |       <div v-if="$slots.menu" class="iconfont iconfont-iconMore" @tap.stop="handleMore"/> | ||||||
|  |     </div> | ||||||
|  |     <template v-else> | ||||||
|  |       <u-row> | ||||||
|  |         <div class="content"> | ||||||
|  |           <slot/> | ||||||
|  |         </div> | ||||||
|  |         <div btn @tap="$emit('send')">发送</div> | ||||||
|  |       </u-row> | ||||||
|  |       <u-row justify="space-between"> | ||||||
|  |         <slot v-if="$slots.title" name="title"/> | ||||||
|  |         <div v-else>{{ cardTitle }}</div> | ||||||
|  |         <div v-if="$slots.menu" class="iconfont iconfont-iconMore" @tap.stop="handleMore"/> | ||||||
|  |       </u-row> | ||||||
|  |     </template> | ||||||
|  |     <div v-if="menu" class="mask" @click="menu=false"> | ||||||
|  |       <div class="moreMenu" :style="menuPos"> | ||||||
|  |         <slot name="menu"/> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: "AiCard", | ||||||
|  |   props: { | ||||||
|  |     cardTitle: String | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       menuPos: {}, | ||||||
|  |       menu: false | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     handleMore({detail}) { | ||||||
|  |       this.menuPos = { | ||||||
|  |         left: detail.x - 10 + 'px', | ||||||
|  |         top: detail.y + 'px' | ||||||
|  |       } | ||||||
|  |       this.menu = !this.menu | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiCard { | ||||||
|  |   width: 100%; | ||||||
|  |   background: #FFFFFF; | ||||||
|  |   box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.02); | ||||||
|  |   border-radius: 8px; | ||||||
|  |   padding: 20px; | ||||||
|  |   box-sizing: border-box; | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   color: #999; | ||||||
|  |   font-size: 26px; | ||||||
|  |   flex-shrink: 0; | ||||||
|  |  | ||||||
|  |   .content { | ||||||
|  |     background: #F9F9F9; | ||||||
|  |     border-radius: 4px; | ||||||
|  |     min-height: 120px; | ||||||
|  |     flex: 1; | ||||||
|  |     min-width: 0; | ||||||
|  |     margin-bottom: 26px; | ||||||
|  |     padding: 20px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     color: #333; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .u-row { | ||||||
|  |     flex-wrap: nowrap; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   div[btn] { | ||||||
|  |     color: #1365DD; | ||||||
|  |     padding: 0 0 0 18px; | ||||||
|  |     cursor: pointer; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .iconfont-iconMore { | ||||||
|  |     font-size: 38px; | ||||||
|  |     transform: rotate(90deg); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .moreMenu { | ||||||
|  |     position: fixed; | ||||||
|  |     background: #FFFFFF; | ||||||
|  |     box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.1); | ||||||
|  |     border-radius: 4px; | ||||||
|  |     transform: translate(-100%, -100%); | ||||||
|  |     min-width: 100px; | ||||||
|  |     min-height: 100px; | ||||||
|  |     z-index: 9; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .mask { | ||||||
|  |     position: fixed; | ||||||
|  |     top: 0; | ||||||
|  |     bottom: 0; | ||||||
|  |     left: 0; | ||||||
|  |     right: 0; | ||||||
|  |     z-index: 11; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										76
									
								
								src/components/AiCell.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,76 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiCell" :class="{bottomBorder,alignCenter,topLabel}"> | ||||||
|  |     <div class="label" :class="{title}"> | ||||||
|  |       <slot v-if="$slots.label" name="label"/> | ||||||
|  |       <span v-else>{{ label }}</span> | ||||||
|  |     </div> | ||||||
|  |     <div class="content" :class="{topLabel}"> | ||||||
|  |       <slot/> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: "AiCell", | ||||||
|  |   props: { | ||||||
|  |     label: {default: ""}, | ||||||
|  |     bottomBorder: Boolean, | ||||||
|  |     topLabel: Boolean, | ||||||
|  |     title: Boolean, | ||||||
|  |     alignCenter: Boolean | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiCell { | ||||||
|  |   display: flex; | ||||||
|  |   min-height: 72px; | ||||||
|  |   font-size: 30px; | ||||||
|  |   color: #333; | ||||||
|  |   padding: 14px 0; | ||||||
|  |   box-sizing: border-box; | ||||||
|  |   justify-content: space-between; | ||||||
|  |  | ||||||
|  |   &.bottomBorder { | ||||||
|  |     border-bottom: 1px solid #eee; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   &.alignCenter { | ||||||
|  |     align-items: center; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   &.topLabel { | ||||||
|  |     flex-direction: column; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .label { | ||||||
|  |     min-width: 60px; | ||||||
|  |     flex-shrink: 0; | ||||||
|  |     width: auto; | ||||||
|  |     color: #999; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     &.title { | ||||||
|  |       color: #333; | ||||||
|  |       font-weight: bold; | ||||||
|  |       font-size: 34px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .content { | ||||||
|  |     flex: 1; | ||||||
|  |     min-width: 100px; | ||||||
|  |     min-height: 40px; | ||||||
|  |     max-width: 500px; | ||||||
|  |     text-align: right; | ||||||
|  |  | ||||||
|  |     &.topLabel { | ||||||
|  |       text-align: start; | ||||||
|  |       margin-top: 16px; | ||||||
|  |       max-width: 100%; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										60
									
								
								src/components/AiDate.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,60 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiDate"> | ||||||
|  |     <u-calendar v-model="show" @change="handleSelect" :mode="mode"/> | ||||||
|  |     <div flex @click="show=true"> | ||||||
|  |       <div v-if="label" v-html="label"/> | ||||||
|  |       <div v-else v-html="placeholder"/> | ||||||
|  |       <i class="iconfont iconfont-iconArrow_Down"/> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import UCalendar from "../uview/components/u-calendar/u-calendar"; | ||||||
|  | import dayjs from 'dayjs' | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "AiDate", | ||||||
|  |   components: {UCalendar}, | ||||||
|  |   computed: { | ||||||
|  |     label() { | ||||||
|  |       let arr = (this.selected || this.value)?.toString()?.split(",") || [] | ||||||
|  |       arr = arr.map(e => dayjs(e).format("MM-DD").replace("Invalid Date", '')) | ||||||
|  |       return arr.join('至') | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       show: false, | ||||||
|  |       selected: "" | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   props: { | ||||||
|  |     value: {default: ""}, | ||||||
|  |     placeholder: {default: "请选择"}, | ||||||
|  |     mode: {default: "date"},//date 单个日期|range 日期范围 | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     handleSelect(v) { | ||||||
|  |       if (this.mode == 'date') { | ||||||
|  |         this.selected = v.result | ||||||
|  |         this.$emit('change', v.result) | ||||||
|  |       } else if (this.mode == 'range') { | ||||||
|  |         this.selected = [v.startDate, v.endDate] | ||||||
|  |         this.$emit('change', v) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiDate { | ||||||
|  |   color: #333333; | ||||||
|  |  | ||||||
|  |   .iconfont-iconArrow_Down { | ||||||
|  |     margin-left: 4px; | ||||||
|  |     font-size: 32px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										39
									
								
								src/components/AiEmpty/AiEmpty.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,39 @@ | |||||||
|  | <template> | ||||||
|  |     <div class="emptyWrap"> | ||||||
|  |         <img class="emptyImg" src="./static/Empty.png"> | ||||||
|  |         <div class="emptyText">{{description}}</div> | ||||||
|  |     </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  |   export default { | ||||||
|  |     name:"emptyData", | ||||||
|  |     props:{ | ||||||
|  |       description:{ | ||||||
|  |         default:'暂无相关信息', | ||||||
|  |         type:String | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  |     .emptyWrap { | ||||||
|  |         width: 100%; | ||||||
|  |         display: flex; | ||||||
|  |         flex-direction: column; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: center; | ||||||
|  |         .emptyImg{ | ||||||
|  |             width: 400rpx; | ||||||
|  |             height: 240rpx; | ||||||
|  |             margin-top: 112px; | ||||||
|  |         } | ||||||
|  |         .emptyText{ | ||||||
|  |             font-size:29rpx; | ||||||
|  |             font-family:PingFangSC-Regular,PingFang SC; | ||||||
|  |             font-weight:400; | ||||||
|  |             color:rgba(183,183,183,1); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | </style> | ||||||
							
								
								
									
										
											BIN
										
									
								
								src/components/AiEmpty/static/1/Icon/Fields/bianhao@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 806 B | 
							
								
								
									
										
											BIN
										
									
								
								src/components/AiEmpty/static/1/Icon/Fields/time@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/components/AiEmpty/static/Empty.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.1 KiB | 
							
								
								
									
										36
									
								
								src/components/AiFixedBtn.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,36 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiFixedBtn"> | ||||||
|  |     <movable-area class="movableArea"> | ||||||
|  |       <movable-view direction="all" x="300" y="500" @tap.stop> | ||||||
|  |         <slot/> | ||||||
|  |       </movable-view> | ||||||
|  |     </movable-area> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: "AiFixedBtn" | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiFixedBtn { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .movableArea { | ||||||
|  |   position: fixed; | ||||||
|  |   left: 0; | ||||||
|  |   top: 0; | ||||||
|  |   width: 100%; | ||||||
|  |   height: 100%; | ||||||
|  |   pointer-events: none; | ||||||
|  |   z-index: 999; | ||||||
|  |  | ||||||
|  |   uni-movable-view { | ||||||
|  |     pointer-events: auto; | ||||||
|  |     width: auto; | ||||||
|  |     height: auto; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										72
									
								
								src/components/AiImage.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,72 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiImage"> | ||||||
|  |     <div v-if="$slots.default" @tap="prev"> | ||||||
|  |       <slot/> | ||||||
|  |     </div> | ||||||
|  |     <u-image v-else :src="src" @tap="prev"> | ||||||
|  |       <image v-if="link" class="errorImage" slot="error" :src="$cdn+'link.png'"/> | ||||||
|  |       <image v-else-if="miniapp" class="errorImage" slot="error" :src="$cdn+'miniwxmp.jpg'"/> | ||||||
|  |       <image v-else class="errorImage" slot="error" :src="$cdn+'file.png'"/> | ||||||
|  |     </u-image> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import UImage from "../uview/components/u-image/u-image"; | ||||||
|  | import UModal from "../uview/components/u-modal/u-modal"; | ||||||
|  | import {mapActions} from "vuex"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "AiImage", | ||||||
|  |   components: {UModal, UImage}, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       dialog: false | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   props: { | ||||||
|  |     src: String, | ||||||
|  |     preview: Boolean, | ||||||
|  |     link: Boolean, | ||||||
|  |     miniapp: Boolean, | ||||||
|  |     file: { | ||||||
|  |       default: () => { | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     ...mapActions(['previewFile', 'injectJWeixin']), | ||||||
|  |     prev() { | ||||||
|  |       if (this.preview) { | ||||||
|  |         if (!!this.src) { | ||||||
|  |           uni.previewImage({ | ||||||
|  |             current: this.src, | ||||||
|  |             urls: [this.src] | ||||||
|  |           }) | ||||||
|  |         } else { | ||||||
|  |           this.previewFile({size: 1, ...this.file}) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiImage { | ||||||
|  |   ::v-deep image { | ||||||
|  |     width: 160px; | ||||||
|  |     height: 160px; | ||||||
|  |     object-fit: cover; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .u-image__error { | ||||||
|  |     position: relative; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .errorImage { | ||||||
|  |     width: 80px; | ||||||
|  |     height: 80px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										28
									
								
								src/components/AiLoading.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,28 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiLoading"> | ||||||
|  |     <image :src="image"/> | ||||||
|  |     <span>{{ tips }}</span> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: "AiLoading", | ||||||
|  |   props: { | ||||||
|  |     tips: {default: "应用加载中"}, | ||||||
|  |     image: {default: "https://cdn.cunwuyun.cn/wxAdmin/img/message.png"} | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiLoading { | ||||||
|  |   font-size: 32px; | ||||||
|  |   color: #666; | ||||||
|  |   text-align: center; | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   align-items: center; | ||||||
|  |   justify-content: center; | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										68
									
								
								src/components/AiMap.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,68 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiMap"> | ||||||
|  |     <div ref="amap" class="map"/> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import AMapLoader from "@amap/amap-jsapi-loader"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "AiMap", | ||||||
|  |   props: { | ||||||
|  |     plugins: {default: () => ['AMap.DistrictSearch']}, | ||||||
|  |     map: Object, | ||||||
|  |     lib: Object | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       amap: null | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     initMap() { | ||||||
|  |       let {plugins} = this | ||||||
|  |       AMapLoader.load({ | ||||||
|  |         key: '54a02a43d9828a8f9cd4f26fe281e74e', | ||||||
|  |         version: '2.0', | ||||||
|  |         plugins | ||||||
|  |       }).then(AMap => { | ||||||
|  |         this.amap = new AMap.Map(this.$refs.amap, { | ||||||
|  |           resizeEnable: true, | ||||||
|  |           zoom: 14, | ||||||
|  |         }) | ||||||
|  |         this.$emit('update:lib', AMap) | ||||||
|  |         this.$emit('update:map', this.amap) | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   mounted() { | ||||||
|  |     this.initMap() | ||||||
|  |   }, | ||||||
|  |   destroyed() { | ||||||
|  |     this.amap?.destroy() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiMap { | ||||||
|  |   .map { | ||||||
|  |     height: 100%; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .amap-logo, ::v-deep .amap-copyright { | ||||||
|  |     display: none !important; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .amap-icon { | ||||||
|  |     width: 40px !important; | ||||||
|  |     height: 40px !important; | ||||||
|  |  | ||||||
|  |     img { | ||||||
|  |       width: 100%; | ||||||
|  |       height: 100%; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										85
									
								
								src/components/AiResult.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,85 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiResult"> | ||||||
|  |     <slot v-if="$slots.default"/> | ||||||
|  |     <template v-else> | ||||||
|  |       <image :src="result.image"/> | ||||||
|  |       <span class="tips">{{ result.tips }}</span> | ||||||
|  |       <slot name="extra" class="extra" v-if="$slots.extra"/> | ||||||
|  |       <div v-if="result.btn" class="btn" @tap="handleTap">{{ result.btn }}</div> | ||||||
|  |     </template> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: "AiResult", | ||||||
|  |   props: { | ||||||
|  |     tips: {default: "提交成功!"}, | ||||||
|  |     image: {default: "https://cdn.cunwuyun.cn/dvcp/h5/result/success.png"}, | ||||||
|  |     btn: {default: ""}, | ||||||
|  |     status: {default: "success"}, | ||||||
|  |     btnTap: Function | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     result() { | ||||||
|  |       let obj = { | ||||||
|  |         image: this.image, | ||||||
|  |         tips: this.tips, | ||||||
|  |         btn: this.btn | ||||||
|  |       } | ||||||
|  |       if (this.status == "error") { | ||||||
|  |         obj.image = this.$cdn + "result/fail.png" | ||||||
|  |         obj.tips = this.tips || "提交失败!" | ||||||
|  |       } | ||||||
|  |       return obj | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     handleTap() { | ||||||
|  |       this.btnTap && this.btnTap() | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiResult { | ||||||
|  |   padding-top: 96px; | ||||||
|  |   width: 100%; | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   align-items: center; | ||||||
|  |   justify-content: center; | ||||||
|  |   font-size: 36px; | ||||||
|  |   font-weight: bold; | ||||||
|  |  | ||||||
|  |   & > image { | ||||||
|  |     width: 192px; | ||||||
|  |     height: 192px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .tips { | ||||||
|  |     margin: 16px auto 0; | ||||||
|  |     color: #333; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .extra { | ||||||
|  |     margin-top: 48px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .btn { | ||||||
|  |     cursor: pointer; | ||||||
|  |     margin-top: 80px; | ||||||
|  |     width: calc(100% - 192px); | ||||||
|  |     height: 88px; | ||||||
|  |     background: #197DF0; | ||||||
|  |     box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.02); | ||||||
|  |     border-radius: 8px; | ||||||
|  |     color: #FFF; | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: center; | ||||||
|  |     align-items: center; | ||||||
|  |     font-weight: 500; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										87
									
								
								src/components/AiSearchPopup.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,87 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiSearchPopup"> | ||||||
|  |     <u-popup v-model="show" length="100%" closeable :mode="mode"> | ||||||
|  |       <slot v-if="$slots.default"/> | ||||||
|  |       <div class="searchPane" v-else> | ||||||
|  |         <div class="title">{{ title }}</div> | ||||||
|  |         <u-search v-model="search" :placeholder="placeholder" :show-action="false" @search="getList()" :focus="show"/> | ||||||
|  |         <div class="result"> | ||||||
|  |           <div class="option" v-for="(op,i) in list" :key="i" @tap="handleSelect(op)">{{ op[ops.label] }}</div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </u-popup> | ||||||
|  |     <div @tap="show=true"> | ||||||
|  |       <slot name="btn"/> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: "AiSearchPopup", | ||||||
|  |   props: { | ||||||
|  |     title: {default: "搜索"}, | ||||||
|  |     placeholder: {default: "请搜索"}, | ||||||
|  |     ops: {default: () => ({label: 'label', search: 'name'})}, | ||||||
|  |     url: String, | ||||||
|  |     mode: {default: "right"} | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       show: false, | ||||||
|  |       search: "", | ||||||
|  |       list: [] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getList() { | ||||||
|  |       this.url && this.$instance.post(this.url, null, { | ||||||
|  |         params: {[this.ops.search]: this.search} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.list = res.data | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     handleSelect(op) { | ||||||
|  |       this.$emit('select', op) | ||||||
|  |       this.show = false | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiSearchPopup { | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ::v-deep .searchPane { | ||||||
|  |     padding: 0 16px; | ||||||
|  |     display: flex; | ||||||
|  |     flex-direction: column; | ||||||
|  |     height: 100%; | ||||||
|  |  | ||||||
|  |     .title { | ||||||
|  |       width: 100%; | ||||||
|  |       height: 100px; | ||||||
|  |       text-align: center; | ||||||
|  |       line-height: 100px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .result { | ||||||
|  |       flex: 1; | ||||||
|  |       min-height: 0; | ||||||
|  |       overflow-y: auto; | ||||||
|  |       padding-bottom: 30px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .option { | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |       height: 80px; | ||||||
|  |       border-bottom: 1px solid #eee; | ||||||
|  |       font-size: 32px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										83
									
								
								src/components/AiSelect.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,83 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiSelect"> | ||||||
|  |     <div class="display" v-if="$slots.default" @tap="handleShowOptions"> | ||||||
|  |       <slot/> | ||||||
|  |     </div> | ||||||
|  |     <div v-else class="display" @tap="handleShowOptions"> | ||||||
|  |       <div class="selectedLabel" v-if="selectedLabel">{{ selectedLabel }}</div> | ||||||
|  |       <i v-else>{{ placeholder }}</i> | ||||||
|  |       <u-icon name="arrow-right" color="#ddd"/> | ||||||
|  |     </div> | ||||||
|  |     <u-select v-model="show" :list="options" :mode="mode" @confirm="handleConfirm"/> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: "AiSelect", | ||||||
|  |   props: { | ||||||
|  |     value: String, | ||||||
|  |     placeholder: {default: "请选择"}, | ||||||
|  |     list: {default: () => []}, | ||||||
|  |     mode: {default: "single-column"}, | ||||||
|  |     dict: {default: ""}, | ||||||
|  |     disabled: Boolean | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     selectedLabel() { | ||||||
|  |       let label = this.options.find(e => e.value == this.value)?.label | ||||||
|  |       return this.selected?.map(e => e.label)?.join(",") || label | ||||||
|  |     }, | ||||||
|  |     options() { | ||||||
|  |       return this.dict ? this.$dict.getDict(this.dict).map(e => ({ | ||||||
|  |         value: e.dictValue, | ||||||
|  |         label: e.dictName | ||||||
|  |       })) : this.list | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       show: false, | ||||||
|  |       selected: [] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     handleConfirm(v) { | ||||||
|  |       this.selected = v | ||||||
|  |       this.$emit("data", this.selected) | ||||||
|  |       this.$forceUpdate() | ||||||
|  |     }, | ||||||
|  |     handleShowOptions() { | ||||||
|  |       if (!this.disabled) this.show = true | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiSelect { | ||||||
|  |   max-width: 100%; | ||||||
|  |  | ||||||
|  |   ::v-deep .u-icon { | ||||||
|  |     margin-left: 8px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .display { | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |  | ||||||
|  |     .selectedLabel { | ||||||
|  |       flex: 1; | ||||||
|  |       min-width: 0; | ||||||
|  |       overflow: hidden; | ||||||
|  |       text-overflow: ellipsis; | ||||||
|  |       white-space: nowrap; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   i { | ||||||
|  |     font-style: normal; | ||||||
|  |     color: $uni-text-color-grey; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										148
									
								
								src/components/AiSelectEnterprise/AiSelectEnterprise.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,148 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="AiSelectEnterprise"> | ||||||
|  |     <tree :checkList="checkList" :props="prop" @sendValue="(val)=>checkList = val" :multiple="multiple" :isCheck="true" | ||||||
|  |           :rootId="rootId"/> | ||||||
|  |     <div class="footer"> | ||||||
|  |       <scroll-view scroll-x class="scroll" style="width: 100%;"> | ||||||
|  |       </scroll-view> | ||||||
|  |       <div class="btn" @click="confirm">确定选择</div> | ||||||
|  |       <AiBack :visible="true" eventName="update:visible" :data="false" @click.native="confirm"></AiBack> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  |   import tree from "./tree"; | ||||||
|  |   import AiBack from "../AiBack"; | ||||||
|  |  | ||||||
|  |   export default { | ||||||
|  |     name: "AiSelectEnterprise", | ||||||
|  |     components: {tree, AiBack}, | ||||||
|  |     props: { | ||||||
|  |       value: { | ||||||
|  |         type: Array, | ||||||
|  |         default: () => [] | ||||||
|  |       }, | ||||||
|  |       multiple: { | ||||||
|  |         type: Boolean, | ||||||
|  |         default: true | ||||||
|  |       }, | ||||||
|  |       rootId: Object, | ||||||
|  |     }, | ||||||
|  |     data() { | ||||||
|  |       return { | ||||||
|  |         tree: [], | ||||||
|  |         checkList: this.value, | ||||||
|  |         prop: { | ||||||
|  |           label: 'name', | ||||||
|  |           multiple: this.multiple, | ||||||
|  |         }, | ||||||
|  |         map: {}, | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     created() { | ||||||
|  |       uni.pageScrollTo({ | ||||||
|  |         duration: 0, | ||||||
|  |         scrollTop: 0 | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     methods: { | ||||||
|  |       confirm() { | ||||||
|  |         let filter = [] | ||||||
|  |         this.map = {} | ||||||
|  |         this.recursion(this.checkList) | ||||||
|  |         Object.keys(this.map).map(e => filter.push(this.map[e])) | ||||||
|  |         this.$emit("change", filter) | ||||||
|  |         this.$emit('update:visible', false) | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       recursion(arr) { | ||||||
|  |         if (arr?.length) { | ||||||
|  |           arr.map(e => { | ||||||
|  |             if ((e.type == 0 || e.openId) && e.checked && !this.map[e.id]) { | ||||||
|  |               this.map[e.id] = e | ||||||
|  |               this.recursion(e.childrenUser) | ||||||
|  |             } | ||||||
|  |             if (e.childrenDept?.length) { | ||||||
|  |               this.recursion(e.childrenDept) | ||||||
|  |             } | ||||||
|  |           }) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  |   .AiSelectEnterprise { | ||||||
|  |     min-height: 100%; | ||||||
|  |     background-color: #F5F5F5; | ||||||
|  |     position: relative; | ||||||
|  |  | ||||||
|  |     .footer { | ||||||
|  |       width: 100%; | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |       z-index: 10; | ||||||
|  |       background: #F4F8FB; | ||||||
|  |       position: fixed; | ||||||
|  |       left: 0; | ||||||
|  |       bottom: 0; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       padding: 0 32px; | ||||||
|  |  | ||||||
|  |       .scroll { | ||||||
|  |         height: 118px; | ||||||
|  |  | ||||||
|  |         ::v-deep .uni-scroll-view-content { | ||||||
|  |           display: flex; | ||||||
|  |           align-items: center; | ||||||
|  |  | ||||||
|  |           .tag { | ||||||
|  |             width: 236px; | ||||||
|  |             height: 72px; | ||||||
|  |             background: #EAEEF1; | ||||||
|  |             border-radius: 8px; | ||||||
|  |             display: flex; | ||||||
|  |             align-items: center; | ||||||
|  |             margin-right: 16px; | ||||||
|  |  | ||||||
|  |             & > img { | ||||||
|  |               width: 48px; | ||||||
|  |               height: 45px; | ||||||
|  |               margin-right: 8px; | ||||||
|  |               flex-shrink: 0; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             & > label { | ||||||
|  |               width: 148px; | ||||||
|  |               height: 42px; | ||||||
|  |               font-size: 30px; | ||||||
|  |               font-weight: 600; | ||||||
|  |               color: #333333; | ||||||
|  |               overflow: hidden; | ||||||
|  |               text-overflow: ellipsis; | ||||||
|  |               white-space: nowrap; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .btn { | ||||||
|  |         width: 192px; | ||||||
|  |         height: 80px; | ||||||
|  |         background: #1365DD; | ||||||
|  |         border-radius: 4px; | ||||||
|  |         z-index: 10; | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: center; | ||||||
|  |         font-size: 32px; | ||||||
|  |         color: #FFFFFF; | ||||||
|  |         margin-left: 8px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										481
									
								
								src/components/AiSelectEnterprise/tree.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,481 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="tree"> | ||||||
|  |     <ai-top-fixed> | ||||||
|  |       <div class="top pad"> | ||||||
|  |         <u-search v-if="searchIf" placeholder="搜索" @change="confirmSearch" @search="confirmSearch" :clearabled="true" | ||||||
|  |                   v-model="keyword" :show-action="false" @clear="clear"></u-search> | ||||||
|  |         <u-tabs :list="list" :current="current" item-width="50%" height="96" bar-width="192" | ||||||
|  |                 @change="tabChange"></u-tabs> | ||||||
|  |       </div> | ||||||
|  |     </ai-top-fixed> | ||||||
|  |  | ||||||
|  |     <div class="tree-list"> | ||||||
|  |       <scroll-view scroll-x class="scroll pad" style="width:100%" :scroll-left="scrollLeft"> | ||||||
|  |         <div v-for="(item,index) in parent" class="inline-item" :key="index"> | ||||||
|  |           <div class="inline-item" v-if="index==0" @click.stop="backTree(item,-1)"> | ||||||
|  |             <text v-if="index==parent.length-1&&!isSear" class="none">可选范围</text> | ||||||
|  |             <text v-else class="active">可选范围</text> | ||||||
|  |           </div> | ||||||
|  |           <div v-if="index==0 && isSear" @click.stop="backTree(item,-2)" | ||||||
|  |                :class="[index==parent.length-1 && isSear] ? 'none inline-item':'active inline-item'"> | ||||||
|  |             <span style="margin: 0 8px">/</span> | ||||||
|  |             搜索结果 | ||||||
|  |           </div> | ||||||
|  |           <div class="inline-item" @click.stop="backTree(item,index)" v-if="index!=0"> | ||||||
|  |             <span style="margin: 0 8px">/</span> | ||||||
|  |             <text v-if="index==parent.length-1" class="none inline-item"> | ||||||
|  |               {{item[tag]}} | ||||||
|  |             </text> | ||||||
|  |             <text v-else class="active"> | ||||||
|  |               {{item[tag]}} | ||||||
|  |             </text> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </scroll-view> | ||||||
|  |       <div class="container-list"> | ||||||
|  |         <div class="common" v-for="(item, index) in tree" @click.stop="toNext(item)" :key="index"> | ||||||
|  |           <label class="content"> | ||||||
|  |             <div class="checkbox" v-if="multiple" @click.stop="checkboxChange(item,index)"> | ||||||
|  |               <img :src="$cdn + 'common/xzh.png'" v-if="item.checked" alt=""> | ||||||
|  |               <img :src="$cdn + 'common/xzn.png'" v-else alt=""> | ||||||
|  |             </div> | ||||||
|  |             <div class="checkbox" v-if="!multiple && (item.type==0 || item.openId)" @click.stop="checkbox(item,index)"> | ||||||
|  |               <img :src="$cdn + 'common/xzh.png'" v-if="item.checked" alt=""> | ||||||
|  |               <img :src="$cdn + 'common/xzn.png'" v-else alt=""> | ||||||
|  |             </div> | ||||||
|  |             <div class="person" v-if="item.type==0"> | ||||||
|  |               <u-avatar :src="item.avatar || ($cdn + 'common/xztx.png')" mode="square" :size="74"></u-avatar> | ||||||
|  |             </div> | ||||||
|  |  | ||||||
|  |             <u-row justify="between" style="width: 100%;"> | ||||||
|  |               <div class="word" v-if="tag=='name'"> | ||||||
|  |                 <img :src="$cdn + 'common/xzbq.png'" v-if="item.type==1" alt=""> | ||||||
|  |                 <span class="ellipsis">{{item[tag]}}</span> | ||||||
|  |               </div> | ||||||
|  |               <div class="word" v-else-if="tag=='tagname'"> | ||||||
|  |                 <template v-if="!item.openId"> | ||||||
|  |                   <img :src="$cdn + 'common/xzbqbottom.png'" alt=""> | ||||||
|  |                   <span class="ellipsis">{{item[tag]}}</span> | ||||||
|  |                 </template> | ||||||
|  |                 <template v-else> | ||||||
|  |                   <u-avatar :src="item.avatar || ($cdn + 'common/xztx.png')" mode="square" :size="74" | ||||||
|  |                             style="margin: 0 17px;"></u-avatar> | ||||||
|  |                   <span class="ellipsis">{{item["name"]}}</span> | ||||||
|  |                 </template> | ||||||
|  |               </div> | ||||||
|  |               <div class="right" | ||||||
|  |                    v-if="item.type==1 && (item.childrenDept.length || item.childrenUser.length) && tag=='name'"></div> | ||||||
|  |               <div class="right" v-if="tag=='tagname' && !item.openId"></div> | ||||||
|  |             </u-row> | ||||||
|  |           </label> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  |   import AiTopFixed from "../AiTopFixed"; | ||||||
|  |  | ||||||
|  |   export default { | ||||||
|  |     name: "tree", | ||||||
|  |     components: {AiTopFixed}, | ||||||
|  |     props: { | ||||||
|  |       checkList: { | ||||||
|  |         type: Array, | ||||||
|  |         default: () => [] | ||||||
|  |       }, | ||||||
|  |       searchIf: { | ||||||
|  |         type: Boolean, | ||||||
|  |         default: () => true | ||||||
|  |       }, | ||||||
|  |       multiple: { | ||||||
|  |         type: Boolean, | ||||||
|  |         default: true | ||||||
|  |       }, | ||||||
|  |       rootId: Object, | ||||||
|  |     }, | ||||||
|  |     data() { | ||||||
|  |       return { | ||||||
|  |         isSear: false, | ||||||
|  |         tree: [], | ||||||
|  |         parent: [1], | ||||||
|  |         searchResult: [], | ||||||
|  |         allData: [], | ||||||
|  |         newCheckList: this.checkList, | ||||||
|  |         scrollLeft: Infinity, | ||||||
|  |         keyword: "", | ||||||
|  |         current: 0, | ||||||
|  |         tag: "name", | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     methods: { | ||||||
|  |       tabChange(e) { | ||||||
|  |         this.tag = e == 0 ? "name" : "tagname" | ||||||
|  |         this.current = e | ||||||
|  |         this.parent = [1] | ||||||
|  |         // this.newCheckList = [] | ||||||
|  |         this.getTree() | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       clear() { | ||||||
|  |         this.keyword = "" | ||||||
|  |         this.tree = this.allData | ||||||
|  |         this.parent = [1] | ||||||
|  |         this.isSear = false | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       checkboxChange(item, index) { | ||||||
|  |         if (item.checked) { | ||||||
|  |           this.$set(this.tree[index], 'checked', false) | ||||||
|  |           this.delChild(item) | ||||||
|  |           for (let index = 0, n = this.newCheckList.length; index < n; index++) { | ||||||
|  |             let temp = this.newCheckList[index]; | ||||||
|  |             if (temp.id == item.id) { | ||||||
|  |               this.newCheckList.splice(index, 1) | ||||||
|  |               break | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } else { | ||||||
|  |           (item.type == 0 || item.openId) && this.newCheckList.push(item) | ||||||
|  |           this.$set(this.tree[index], 'checked', true) | ||||||
|  |           this.chooseChild(item) | ||||||
|  |         } | ||||||
|  |         this.$emit('sendValue', this.newCheckList) | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       delUser(id) { | ||||||
|  |         for (let i = 0, len = this.newCheckList.length; i < len; i++) { | ||||||
|  |           if (this.newCheckList[i].id === id) { | ||||||
|  |             return this.newCheckList.splice(i, 1) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       chooseChild(arr) { | ||||||
|  |         if (arr.childrenDept?.length) { | ||||||
|  |           for (let i = 0, len = arr.childrenDept.length; i < len; i++) { | ||||||
|  |             let item = arr.childrenDept[i] | ||||||
|  |             item.checked = true | ||||||
|  |             this.newCheckList.push(item) | ||||||
|  |             this.chooseChild(item) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (arr.childrenUser?.length) { | ||||||
|  |           for (let i = 0, len = arr.childrenUser.length; i < len; i++) { | ||||||
|  |             let item = arr.childrenUser[i] | ||||||
|  |             item.checked = true | ||||||
|  |             this.newCheckList.push(item) | ||||||
|  |             this.chooseChild(item) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (arr.users?.length) { | ||||||
|  |           for (let i = 0, len = arr.users.length; i < len; i++) { | ||||||
|  |             let item = arr.users[i] | ||||||
|  |             item.checked = true | ||||||
|  |             this.newCheckList.push(item) | ||||||
|  |             this.chooseChild(item) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         this.newCheckList = Array.from(new Set(this.newCheckList)) | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       delChild(arr) { | ||||||
|  |         if (arr.childrenDept?.length) { | ||||||
|  |           for (let i = 0, len = arr.childrenDept.length; i < len; i++) { | ||||||
|  |             let item = arr.childrenDept[i]; | ||||||
|  |             item.checked = false | ||||||
|  |             for (let index = 0, n = this.newCheckList.length; index < n; index++) { | ||||||
|  |               let temp = this.newCheckList[index]; | ||||||
|  |               if (temp.id == item.id) { | ||||||
|  |                 this.newCheckList.splice(index, 1) | ||||||
|  |                 break | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |             this.delChild(item) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (arr.childrenUser?.length) { | ||||||
|  |           for (let i = 0, len = arr.childrenUser.length; i < len; i++) { | ||||||
|  |             let item = arr.childrenUser[i]; | ||||||
|  |             item.checked = false | ||||||
|  |             for (let index = 0, n = this.newCheckList.length; index < n; index++) { | ||||||
|  |               let temp = this.newCheckList[index]; | ||||||
|  |               if (temp.id == item.id) { | ||||||
|  |                 this.newCheckList.splice(index, 1) | ||||||
|  |                 break | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |             this.delChild(item) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       //单选 | ||||||
|  |       checkbox(item, index) { | ||||||
|  |         let status = !this.tree[index].checked | ||||||
|  |         this.$set(this.tree[index], 'checked', status) | ||||||
|  |         if (this.newCheckList.length <= 0) { | ||||||
|  |           this.newCheckList = [this.tree[index]] | ||||||
|  |         } else if (this.newCheckList.length == 1) { | ||||||
|  |           this.tree.forEach(item => { | ||||||
|  |             if (item.id != this.tree[index].id) { | ||||||
|  |               item.checked = false | ||||||
|  |             } | ||||||
|  |           }) | ||||||
|  |           this.newCheckList = [] | ||||||
|  |           if (this.tree[index].checked) { | ||||||
|  |             this.newCheckList.push(this.tree[index]) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         this.$emit('sendValue', this.newCheckList) | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       toNext(item) { | ||||||
|  |         if (this.tag == "name") { | ||||||
|  |           if (item.type == 1 && (item["childrenDept"].length || item["childrenUser"].length)) { | ||||||
|  |             this.tree = [] | ||||||
|  |             if (item["childrenDept"].length) { | ||||||
|  |               this.tree = item["childrenDept"] | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (item["childrenUser"].length) { | ||||||
|  |               this.tree = [...this.tree, ...item["childrenUser"]] | ||||||
|  |             } | ||||||
|  |             this.checkIf() | ||||||
|  |             if (this.parent[0].id !== item.id) { | ||||||
|  |               this.parent.push(item) | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } else if (this.tag == "tagname" && !item.openId) { | ||||||
|  |           this.tree = item.users | ||||||
|  |           if (this.parent[0].id !== item.id) { | ||||||
|  |             this.parent.push(item) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.$nextTick(() => { | ||||||
|  |           this.scrollLeft += 200 | ||||||
|  |         }) | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       checkIf() { | ||||||
|  |         for (let i = 0, len = this.tree.length; i < len; i++) { | ||||||
|  |           for (let j = 0, lens = this.newCheckList.length; j < lens; j++) { | ||||||
|  |             if (this.newCheckList[j].id == this.tree[i].id) { | ||||||
|  |               this.$set(this.tree[i], 'checked', true) | ||||||
|  |               break | ||||||
|  |             } else { | ||||||
|  |               this.$set(this.tree[i], 'checked', false) | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       confirmSearch(val) { | ||||||
|  |         this.searchResult = [] | ||||||
|  |         this.search(this.tree, val) | ||||||
|  |         this.isSear = true | ||||||
|  |         this.parent.splice(1, Infinity) | ||||||
|  |         this.tree = this.searchResult | ||||||
|  |         if(!val) this.clear() | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       search(data, keyword) { | ||||||
|  |         if (data.length) { | ||||||
|  |           for (let i = 0, len = data.length; i < len; i++) { | ||||||
|  |             if (data[i].name?.indexOf(keyword) != -1) { | ||||||
|  |               this.searchResult.push(data[i]) | ||||||
|  |             } | ||||||
|  |             if (data[i]["childrenDept"]?.length || data[i]["childrenUser"]?.length) { | ||||||
|  |               this.search(data[i]["childrenDept"].concat(data[i]["childrenUser"]), keyword) | ||||||
|  |             } | ||||||
|  |             if (data[i]["users"]?.length) { | ||||||
|  |               this.search(data[i]["users"], keyword) | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       backTree(item, index) { | ||||||
|  |         if (index == -1) { | ||||||
|  |           this.tree = this.allData | ||||||
|  |           this.parent.splice(1, Infinity) | ||||||
|  |           this.isSear = false | ||||||
|  |           this.keyword = "" | ||||||
|  |         } else if (index == -2) { | ||||||
|  |           this.tree = this.searchResult | ||||||
|  |           this.parent.splice(1, Infinity) | ||||||
|  |         } else { | ||||||
|  |           if (this.parent.length - index > 2) { | ||||||
|  |             this.parent.forEach((item, i) => { | ||||||
|  |               if (i > index) { | ||||||
|  |                 this.parent.splice(i, Infinity) | ||||||
|  |               } | ||||||
|  |             }) | ||||||
|  |           } else if (index != this.parent.length - 1) { | ||||||
|  |             this.parent.splice(this.parent.length - 1, 1) | ||||||
|  |           } | ||||||
|  |           this.tree = item["childrenDept"].concat(item["childrenUser"] || []) | ||||||
|  |         } | ||||||
|  |         if (this.multiple) return | ||||||
|  |         this.checkIf() | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       getTree() { | ||||||
|  |         this.$http.post(this.current == 0 ? "/app/wxcp/wxuser/tree" : "/app/wxcp/wxtag/tree", null, { | ||||||
|  |           params: { | ||||||
|  |             rootId: this.rootId | ||||||
|  |           } | ||||||
|  |         }).then(res => { | ||||||
|  |           if (res && res.data) { | ||||||
|  |             let result = this.tag == 'name' ? [res.data] : res.data | ||||||
|  |             this.tree = result | ||||||
|  |             this.allData = result | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       }, | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     computed: { | ||||||
|  |       list() { | ||||||
|  |         return [ | ||||||
|  |           {name: "组织架构"}, | ||||||
|  |           {name: "标签"} | ||||||
|  |         ] | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     created() { | ||||||
|  |       this.getTree() | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  |  | ||||||
|  |   .tree { | ||||||
|  |     min-height: 100%; | ||||||
|  |     background-color: #F5F5F5; | ||||||
|  |  | ||||||
|  |     .top { | ||||||
|  |       background-color: #FFFFFF; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .tree-list { | ||||||
|  |       margin-top: 24px; | ||||||
|  |       background-color: #FFFFFF; | ||||||
|  |  | ||||||
|  |       .scroll { | ||||||
|  |         white-space: nowrap; | ||||||
|  |         border-bottom: 1px solid #f4f4f4; | ||||||
|  |  | ||||||
|  |         .inline-item { | ||||||
|  |           height: 112px; | ||||||
|  |           font-size: 30px; | ||||||
|  |           display: inline-block; | ||||||
|  |           line-height: 112px; | ||||||
|  |  | ||||||
|  |           .active { | ||||||
|  |             color: #4297ED !important; | ||||||
|  |             font-weight: 600; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           .none { | ||||||
|  |             color: #666666; | ||||||
|  |             font-weight: 600; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .container-list { | ||||||
|  |         min-height: 1000px; | ||||||
|  |         overflow-y: scroll; | ||||||
|  |         overflow-x: hidden; | ||||||
|  |  | ||||||
|  |         .common { | ||||||
|  |           background-color: #fff; | ||||||
|  |           border-bottom: 1px solid #f4f4f4; | ||||||
|  |           box-sizing: border-box; | ||||||
|  |           padding: 0 30px; | ||||||
|  |  | ||||||
|  |           .content { | ||||||
|  |             display: flex; | ||||||
|  |             align-items: center; | ||||||
|  |             height: 100px; | ||||||
|  |             width: 100%; | ||||||
|  |             line-height: 100px; | ||||||
|  |             position: relative; | ||||||
|  |             font-size: 32px; | ||||||
|  |  | ||||||
|  |             .right { | ||||||
|  |               width: 16px; | ||||||
|  |               height: 16px; | ||||||
|  |               border-right: 4px solid #CCCCCC; | ||||||
|  |               border-top: 4px solid #CCCCCC; | ||||||
|  |               transform: rotate(45deg); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             .word { | ||||||
|  |               display: flex; | ||||||
|  |               align-items: center; | ||||||
|  |  | ||||||
|  |               & > img { | ||||||
|  |                 width: 74px; | ||||||
|  |                 height: 74px; | ||||||
|  |                 margin: 0 34px; | ||||||
|  |               } | ||||||
|  |  | ||||||
|  |               .ellipsis{ | ||||||
|  |                 width: 450px; | ||||||
|  |                 overflow: hidden; | ||||||
|  |                 text-overflow: ellipsis; | ||||||
|  |                 white-space: nowrap; | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             .checkbox { | ||||||
|  |               position: relative; | ||||||
|  |               display: flex; | ||||||
|  |               align-items: center; | ||||||
|  |  | ||||||
|  |               & > img { | ||||||
|  |                 width: 48px; | ||||||
|  |                 height: 48px; | ||||||
|  |                 border-radius: 50%; | ||||||
|  |               } | ||||||
|  |  | ||||||
|  |               .color { | ||||||
|  |                 color: #00aaff; | ||||||
|  |                 background-color: #00aaff; | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             .person { | ||||||
|  |               display: flex; | ||||||
|  |               align-items: center; | ||||||
|  |               color: #f57a00; | ||||||
|  |               font-size: 36px; | ||||||
|  |               text-align: center; | ||||||
|  |               margin: 0 34px; | ||||||
|  |               flex-shrink: 0; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ::v-deep .content { | ||||||
|  |       padding: 0 !important; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .pad { | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       padding: 20px 32px 0; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										63
									
								
								src/components/AiTabbar.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,63 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiTabbar"> | ||||||
|  |     <div class="tabPane" v-for="(op,i) in tabbars" :key="i" | ||||||
|  |          @click="$emit('update:active',i)"> | ||||||
|  |       <img :src="op.icon" alt=""/> | ||||||
|  |       <span :class="{active:i==active}">{{ op.text }}</span> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: "AiTabbar", | ||||||
|  |   props: { | ||||||
|  |     active: {default: 0}, | ||||||
|  |     list: {default: () => []}, | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     tabbars() { | ||||||
|  |       return this.list.map((e, i) => ({ | ||||||
|  |         ...e, | ||||||
|  |         icon: i == this.active ? e.selectedIconPath : e.iconPath | ||||||
|  |       })) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiTabbar { | ||||||
|  |   height: 98px; | ||||||
|  |   width: 100%; | ||||||
|  |   position: fixed; | ||||||
|  |   bottom: 0; | ||||||
|  |   background: #FFFFFF; | ||||||
|  |   border-top: 1px solid #ddd; | ||||||
|  |   display: flex; | ||||||
|  |   z-index: 9; | ||||||
|  |  | ||||||
|  |   .tabPane { | ||||||
|  |     flex: 1; | ||||||
|  |     min-width: 0; | ||||||
|  |     display: flex; | ||||||
|  |     flex-direction: column; | ||||||
|  |     align-items: center; | ||||||
|  |     justify-content: center; | ||||||
|  |     font-size: 22px; | ||||||
|  |     cursor: pointer; | ||||||
|  |  | ||||||
|  |     & > img { | ||||||
|  |       height: 44px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     & > span { | ||||||
|  |       color: #C4CAD4; | ||||||
|  |  | ||||||
|  |       &.active { | ||||||
|  |         color: #3267F0; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										53
									
								
								src/components/AiTable.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,53 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiTable"> | ||||||
|  |     <u-table color="#333"> | ||||||
|  |       <u-tr> | ||||||
|  |         <u-th v-for="(col,i) in colConfigs" :key="i" :width="col.width">{{ col.label }}</u-th> | ||||||
|  |       </u-tr> | ||||||
|  |       <u-tr v-for="(row,j) in data" :key="j"> | ||||||
|  |         <u-td v-for="(col,i) in colConfigs" :key="i" :width="col.width"> | ||||||
|  |           <slot v-if="col.slot" :name="col.slot"/> | ||||||
|  |           <p v-else-if="col.dict">{{ $dict.getLabel(col.dict, row[col.prop]) }}</p> | ||||||
|  |           <p v-else>{{ row[col.prop] || "-" }}</p> | ||||||
|  |         </u-td> | ||||||
|  |       </u-tr> | ||||||
|  |     </u-table> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import UTable from "../uview/components/u-table/u-table"; | ||||||
|  | import UTd from "../uview/components/u-td/u-td"; | ||||||
|  | import UTh from "../uview/components/u-th/u-th"; | ||||||
|  | import UTr from "../uview/components/u-tr/u-tr"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "AiTable", | ||||||
|  |   components: {UTr, UTh, UTd, UTable}, | ||||||
|  |   props: { | ||||||
|  |     data: {default: () => []}, | ||||||
|  |     colConfigs: {default: () => []}, | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiTable { | ||||||
|  |   border-radius: 8px; | ||||||
|  |   min-height: 100px; | ||||||
|  |   overflow: hidden; | ||||||
|  |  | ||||||
|  |   .u-table, .u-th { | ||||||
|  |     border-color: #D0D4DC !important; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .u-th { | ||||||
|  |     background-color: #DFE6F4; | ||||||
|  |     color: #646D7F; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .u-tr { | ||||||
|  |     height: 80px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										81
									
								
								src/components/AiTabs.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,81 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiTabs" :class="{wrap}"> | ||||||
|  |     <div class="tabItem" v-for="(op,i) in ops" :key="i" | ||||||
|  |          :class="{active:value==op.value,plain}" | ||||||
|  |          :style="{width:itemWidth}" | ||||||
|  |          @tap="$emit('change',op.value)"> | ||||||
|  |       {{ op.name }} | ||||||
|  |     </div> | ||||||
|  |     <div class="end"> | ||||||
|  |       <slot name="end"/> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: "AiTabs", | ||||||
|  |   model: { | ||||||
|  |     prop: "value", | ||||||
|  |     event: "change" | ||||||
|  |   }, | ||||||
|  |   props: { | ||||||
|  |     value: {default: ""}, | ||||||
|  |     ops: {default: () => []}, | ||||||
|  |     wrap: Boolean, | ||||||
|  |     plain: Boolean, | ||||||
|  |     itemWidth: String | ||||||
|  |   }, | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiTabs { | ||||||
|  |   display: flex; | ||||||
|  |   flex: 1; | ||||||
|  |   min-width: 0; | ||||||
|  |   max-height: 240px; | ||||||
|  |   overflow-y: auto; | ||||||
|  |  | ||||||
|  |   &.wrap { | ||||||
|  |     flex-wrap: wrap; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .tabItem { | ||||||
|  |     flex-shrink: 0; | ||||||
|  |     min-width: 144px; | ||||||
|  |     max-width: 100%; | ||||||
|  |     min-height: 64px; | ||||||
|  |     font-size: 28px; | ||||||
|  |     font-weight: 400; | ||||||
|  |     color: #666; | ||||||
|  |     background: #FFFFFF; | ||||||
|  |     border-radius: 4px; | ||||||
|  |     border: 1px solid #CCC; | ||||||
|  |     text-align: center; | ||||||
|  |     line-height: 64px; | ||||||
|  |     margin-bottom: 16px; | ||||||
|  |     margin-right: 16px; | ||||||
|  |     padding: 0 16px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |  | ||||||
|  |     &.active { | ||||||
|  |       border-color: $uni-color-primary; | ||||||
|  |       color: $uni-color-primary; | ||||||
|  |  | ||||||
|  |       &.plain { | ||||||
|  |         color: #fff; | ||||||
|  |         border-color: transparent; | ||||||
|  |         background: $uni-color-primary; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .end { | ||||||
|  |     flex: 1; | ||||||
|  |     min-width: 0; | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: flex-end; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										82
									
								
								src/components/AiTextarea.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,82 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiTextarea" :class="{border}"> | ||||||
|  |     <u-input type="textarea" v-bind="$attrs" :value="value" :maxlength="maxlength" | ||||||
|  |              @input="handleInput" :disabled="disabled"/> | ||||||
|  |     <div class="bottomBar"> | ||||||
|  |       <div class="leftPane"> | ||||||
|  |         <slot name="bar"/> | ||||||
|  |       </div> | ||||||
|  |       <div v-if="!!maxlength">{{ value.length }}/{{ maxlength }}</div> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import UInput from "../uview/components/u-input/u-input"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "AiTextarea", | ||||||
|  |   components: {UInput}, | ||||||
|  |   model: { | ||||||
|  |     prop: "value", | ||||||
|  |     event: "change" | ||||||
|  |   }, | ||||||
|  |   props: { | ||||||
|  |     value: {default: ""}, | ||||||
|  |     maxlength: {default: 0}, | ||||||
|  |     border: Boolean, | ||||||
|  |     disabled: Boolean | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     handleInput(v) { | ||||||
|  |       this.$emit('change', v) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiTextarea { | ||||||
|  |   width: 100%; | ||||||
|  |   position: relative; | ||||||
|  |  | ||||||
|  |   &.border { | ||||||
|  |     ::v-deep textarea { | ||||||
|  |       border-radius: 4px; | ||||||
|  |       border: 1px solid #e2e1e1; | ||||||
|  |       padding: 16px 16px 36px; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .bottomBar { | ||||||
|  |       position: absolute; | ||||||
|  |       bottom: 8px; | ||||||
|  |       right: 16px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ::v-deep .u-input__right-icon { | ||||||
|  |       position: absolute; | ||||||
|  |       top: 50%; | ||||||
|  |       right: 16px; | ||||||
|  |       transform: translateY(-50%); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .bottomBar { | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     justify-content: space-between; | ||||||
|  |     min-height: 36px; | ||||||
|  |     color: #999999; | ||||||
|  |  | ||||||
|  |     .leftPane { | ||||||
|  |       display: flex; | ||||||
|  |  | ||||||
|  |       & > * + * { | ||||||
|  |         margin-left: 32px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										63
									
								
								src/components/AiTopFixed.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,63 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiTopFixed" :style="{background}"> | ||||||
|  |     <!--占位区--> | ||||||
|  |     <div class="placeholder"> | ||||||
|  |       <div v-if="$slots.tabs"> | ||||||
|  |         <slot name="tabs"/> | ||||||
|  |       </div> | ||||||
|  |       <div class="content" v-if="$slots.default"> | ||||||
|  |         <slot/> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <!--悬浮区--> | ||||||
|  |     <div class="fixed" :style="{background}"> | ||||||
|  |       <div v-if="$slots.tabs"> | ||||||
|  |         <slot name="tabs"/> | ||||||
|  |       </div> | ||||||
|  |       <div class="content" v-if="$slots.default"> | ||||||
|  |         <slot/> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: "AiTopFixed", | ||||||
|  |   props: { | ||||||
|  |     background: {default: "#fff"} | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiTopFixed { | ||||||
|  |   width: 100%; | ||||||
|  |  | ||||||
|  |   & > div { | ||||||
|  |     width: 100%; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .fixed { | ||||||
|  |     width: 100%; | ||||||
|  |     top: 0; | ||||||
|  |     position: fixed; | ||||||
|  |     z-index: 9; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .placeholder { | ||||||
|  |     visibility: hidden; | ||||||
|  |     opacity: 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .content { | ||||||
|  |     padding: 20px 32px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .u-search { | ||||||
|  |     box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.02); | ||||||
|  |     margin-bottom: 32px !important; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										229
									
								
								src/components/AiUploader.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,229 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="ai-uploader"> | ||||||
|  |     <div class="fileList"> | ||||||
|  |       <div class="item" v-for="(item, i) in fileList" :key="i"> | ||||||
|  |         <template v-if="type == 'image'"> | ||||||
|  |           <ai-image :src="item.url" :preview="preview"/> | ||||||
|  |           <div class="info"> | ||||||
|  |             <i>{{ item.fileSizeStr }}</i> | ||||||
|  |           </div> | ||||||
|  |         </template> | ||||||
|  |         <template v-else> | ||||||
|  |           <ai-image :preview="preview" :file="item"/> | ||||||
|  |           <div class="info"> | ||||||
|  |             <span>{{ item.name }} </span> | ||||||
|  |             <i>{{ item.fileSizeStr }}</i> | ||||||
|  |           </div> | ||||||
|  |         </template> | ||||||
|  |         <template v-if="!disabled"> | ||||||
|  |           <div btn @tap="handleReUpload(i)"> | ||||||
|  |             重新上传 | ||||||
|  |           </div> | ||||||
|  |           <div btn @tap="remove(i)"> | ||||||
|  |             删除 | ||||||
|  |           </div> | ||||||
|  |         </template> | ||||||
|  |       </div> | ||||||
|  |       <div v-if="!disabled&&(fileList.length == 0 || (multiple && fileList.length < limit))" class="default" | ||||||
|  |            @click="upload"> | ||||||
|  |         <i class="iconfont iconfont-iconAdd"/> | ||||||
|  |         <span>{{ placeholder }}</span> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import {mapState} from 'vuex' | ||||||
|  | import AiImage from './AiImage' | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: 'AiUploader', | ||||||
|  |   components: {AiImage}, | ||||||
|  |   props: { | ||||||
|  |     limit: {default: 1}, //数量 | ||||||
|  |     placeholder: {default: '添加图片'}, // 文字提示 | ||||||
|  |     type: {default: 'image'}, // 文件类型,image还是file | ||||||
|  |     multiple: { | ||||||
|  |       type: Boolean, | ||||||
|  |       default: false, | ||||||
|  |     }, | ||||||
|  |     fileId: String, | ||||||
|  |     mediaId: String, | ||||||
|  |     def: {default: () => []}, | ||||||
|  |     action: {default: '/app/wxcp/upload/uploadFile'}, | ||||||
|  |     preview: Boolean, | ||||||
|  |     size: {default: 0}, | ||||||
|  |     disabled: Boolean | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['baseURL', 'token']), | ||||||
|  |     errorImage() { | ||||||
|  |       return this.$cdn + 'file.png' | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   watch: { | ||||||
|  |     def: { | ||||||
|  |       handler(v) { | ||||||
|  |         if (!!v?.toString() && v?.url) { | ||||||
|  |           if (this.multiple) { | ||||||
|  |             this.fileList = v | ||||||
|  |           } else { | ||||||
|  |             this.fileList = [v] | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       immediate: true, | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       fileList: [], | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     remove(index) { | ||||||
|  |       this.fileList.splice(index, 1) | ||||||
|  |       this.$emit('list', this.fileList) | ||||||
|  |     }, | ||||||
|  |     upload(wait) { | ||||||
|  |       let params = { | ||||||
|  |         count: this.limit, | ||||||
|  |         sizeType: ['compressed'], | ||||||
|  |         sourceType: ['album', 'camera'], | ||||||
|  |         success: (res) => { | ||||||
|  |           let count = this.fileList?.length + (res.tempFiles?.length || res.tempFile ? 1 : 0) | ||||||
|  |           if (count > this.limit && this.limit !== 1) { | ||||||
|  |             return this.$u.toast(`不能超过${this.limit}个`) | ||||||
|  |           } | ||||||
|  |           if (res.tempFiles) { | ||||||
|  |             res.tempFiles?.map((item) => { | ||||||
|  |               this.uploadFile(item) | ||||||
|  |             }) | ||||||
|  |           } else if (res?.tempFile) { | ||||||
|  |             this.uploadFile(res.tempFile) | ||||||
|  |           } | ||||||
|  |         }, | ||||||
|  |       } | ||||||
|  |       typeof wait == 'function' && wait() | ||||||
|  |       if (this.type == 'image') { | ||||||
|  |         uni.chooseImage(params) | ||||||
|  |       } else if (this.type == 'video') { | ||||||
|  |         uni.chooseVideo(params) | ||||||
|  |       } else { | ||||||
|  |         uni.chooseFile(params) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     uploadFile(img) { | ||||||
|  |       if (this.size > 0 && img.size > this.size) { | ||||||
|  |         return this.$u.toast(`不能超过${Math.ceil(this.size / 1024 / 1024)}MB`) | ||||||
|  |       } | ||||||
|  |       uni.showLoading({title: '上传中'}) | ||||||
|  |       let formData = new FormData() | ||||||
|  |       formData.append('file', img) | ||||||
|  |       this.$http | ||||||
|  |       .post(this.action, formData, { | ||||||
|  |         params: {type: this.type}, | ||||||
|  |       }) | ||||||
|  |       .then((res) => { | ||||||
|  |         uni.hideLoading() | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.$emit('data', res.data) | ||||||
|  |           this.$u.toast('上传成功!') | ||||||
|  |           if (this.action == '/app/wxcp/upload/uploadFile') { | ||||||
|  |             this.$emit('update:mediaId', res.data?.media?.mediaId) | ||||||
|  |             this.$emit('update:fileId', res.data.file.id) | ||||||
|  |             this.fileList.push(res.data.file) | ||||||
|  |           } else if (this.action == '/admin/file/add2') { | ||||||
|  |             let info = res.data | ||||||
|  |             this.$emit('update:fileId', info?.id) | ||||||
|  |             this.fileList.push(res.data) | ||||||
|  |           } | ||||||
|  |           this.$emit("update:def", this.fileList) | ||||||
|  |           this.$emit("list", this.fileList) | ||||||
|  |         } else { | ||||||
|  |           this.$u.toast(res.msg) | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |       .catch(() => uni.hideLoading()) | ||||||
|  |     }, | ||||||
|  |     handleReUpload(i) { | ||||||
|  |       this.upload(() => this.remove(i)) | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .ai-uploader { | ||||||
|  |   width: 100%; | ||||||
|  |   line-height: normal; | ||||||
|  |   margin-bottom: 16px; | ||||||
|  |  | ||||||
|  |   .fileList { | ||||||
|  |     .item { | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |       margin-bottom: 10px; | ||||||
|  |  | ||||||
|  |       image { | ||||||
|  |         width: 160px; | ||||||
|  |         height: 160px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       i { | ||||||
|  |         font-style: normal; | ||||||
|  |         color: #9b9b9b; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .info { | ||||||
|  |         flex: 1; | ||||||
|  |         min-width: 0; | ||||||
|  |         display: flex; | ||||||
|  |         flex-direction: column; | ||||||
|  |         align-items: flex-start; | ||||||
|  |  | ||||||
|  |         & > span { | ||||||
|  |           overflow: hidden; | ||||||
|  |           text-overflow: ellipsis; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       div[btn] { | ||||||
|  |         color: $uni-color-primary; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       div:nth-child(4) { | ||||||
|  |         color: #f72c27; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       & > * + * { | ||||||
|  |         margin-left: 20px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .default { | ||||||
|  |       width: 240px; | ||||||
|  |       height: 240px; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       border-radius: 8px; | ||||||
|  |       background: #f3f4f7; | ||||||
|  |       color: #89b; | ||||||
|  |       display: flex; | ||||||
|  |       flex-direction: column; | ||||||
|  |       justify-content: center; | ||||||
|  |       align-items: center; | ||||||
|  |  | ||||||
|  |       .iconfont-iconAdd { | ||||||
|  |         font-size: 64px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         display: block; | ||||||
|  |         text-align: center; | ||||||
|  |         font-size: 28px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										185
									
								
								src/components/AiVideo.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,185 @@ | |||||||
|  | <template> | ||||||
|  | 	<view class="imt-audio"> | ||||||
|  | 		<view class="audio-wrapper"> | ||||||
|  | 			<view class="audio-number">{{format(current)}}</view> | ||||||
|  | 			<slider class="audio-slider" :activeColor="color" block-size="16" :value="current" :max="duration || 10" @changing="seek=true,current=$event.detail.value" @change="audio.seek($event.detail.value)"></slider> | ||||||
|  | 			<view class="audio-number">{{format(duration)}}</view> | ||||||
|  | 		</view> | ||||||
|  | 		<view class="audio-control-wrapper" :style="{color}"> | ||||||
|  |       <image | ||||||
|  |         class="audio-control audio-control-switch" | ||||||
|  |         @click="audio.paused?play():audio.pause()" | ||||||
|  |         :src="paused ? playImg : stopImg" /> | ||||||
|  |       <p>{{ paused ? '点击播放' : '点击停止播放' }}</p> | ||||||
|  | 		</view> | ||||||
|  | 	</view> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  |   import stopImg from '../pages/resourcesManage/img/stop-img.png' | ||||||
|  |   import playImg from '../pages/resourcesManage/img/play-icon.png' | ||||||
|  | 	export default { | ||||||
|  | 		data() { | ||||||
|  | 			return { | ||||||
|  | 				audio: uni.createInnerAudioContext(), | ||||||
|  | 				current: 0, //当前进度(s) | ||||||
|  | 				duration: 0, //总时长(s) | ||||||
|  | 				paused: true, //是否处于暂停状态 | ||||||
|  | 				loading: false, //是否处于读取状态 | ||||||
|  | 				seek: false, | ||||||
|  |         stopImg, | ||||||
|  |         playImg | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
|  | 		props: { | ||||||
|  | 			src: String, //音频链接 | ||||||
|  | 			autoplay: Boolean, //是否自动播放 | ||||||
|  | 			continue: Boolean, //播放完成后是否继续播放下一首,需定义@next事件 | ||||||
|  | 			control: { | ||||||
|  | 				type: Boolean, | ||||||
|  | 				default: true | ||||||
|  | 			}, //是否需要上一曲/下一曲按钮 | ||||||
|  | 			color: { | ||||||
|  | 				type: String, | ||||||
|  | 				default: '#007BFF' | ||||||
|  | 			} //主色调 | ||||||
|  | 		}, | ||||||
|  | 		methods: { | ||||||
|  | 			//返回prev事件 | ||||||
|  | 			prev() { | ||||||
|  | 				this.$emit('prev') | ||||||
|  | 			}, | ||||||
|  | 			//返回next事件 | ||||||
|  | 			next() { | ||||||
|  | 				this.$emit('next') | ||||||
|  | 			}, | ||||||
|  | 			//格式化时长 | ||||||
|  | 			format(num) { | ||||||
|  | 				return '0'.repeat(2 - String(Math.floor(num / 60)).length) + Math.floor(num / 60) + ':' + '0'.repeat(2 - String(Math.floor(num % 60)).length) + Math.floor(num % 60) | ||||||
|  | 			}, | ||||||
|  | 			//点击播放按钮 | ||||||
|  | 			play() { | ||||||
|  | 				this.audio.play() | ||||||
|  | 				this.loading = true | ||||||
|  | 			} | ||||||
|  | 		}, | ||||||
|  | 		created() { | ||||||
|  | 			if (this.src) { | ||||||
|  | 				this.audio.src = this.src | ||||||
|  | 				this.autoplay && this.play() | ||||||
|  | 			} | ||||||
|  | 			this.audio.obeyMuteSwitch = false | ||||||
|  | 			//音频进度更新事件 | ||||||
|  | 			this.audio.onTimeUpdate(() => { | ||||||
|  | 				if (!this.seek) { | ||||||
|  | 					this.current = this.audio.currentTime | ||||||
|  | 				} | ||||||
|  | 				if (!this.duration) { | ||||||
|  | 					this.duration = this.audio.duration | ||||||
|  | 				} | ||||||
|  | 			}) | ||||||
|  | 			//音频播放事件 | ||||||
|  | 			this.audio.onPlay(() => { | ||||||
|  | 				this.paused = false | ||||||
|  | 				this.loading = false | ||||||
|  | 			}) | ||||||
|  | 			//音频暂停事件 | ||||||
|  | 			this.audio.onPause(() => { | ||||||
|  | 				this.paused = true | ||||||
|  | 			}) | ||||||
|  | 			//音频结束事件 | ||||||
|  | 			this.audio.onEnded(() => { | ||||||
|  | 				if (this.continue) { | ||||||
|  | 					this.next() | ||||||
|  | 				} else { | ||||||
|  | 					this.paused = true | ||||||
|  | 					this.current = 0 | ||||||
|  | 				} | ||||||
|  | 			}) | ||||||
|  | 			//音频完成更改进度事件 | ||||||
|  | 			this.audio.onSeeked(() => { | ||||||
|  | 				this.seek = false | ||||||
|  | 			}) | ||||||
|  | 		}, | ||||||
|  | 		beforeDestroy(){ | ||||||
|  | 			this.audio.destroy() | ||||||
|  | 		}, | ||||||
|  | 		watch: { | ||||||
|  | 			src(src, old) { | ||||||
|  | 				this.audio.src = src | ||||||
|  | 				this.current = 0 | ||||||
|  | 				this.duration = 0 | ||||||
|  | 				if (old || this.autoplay) { | ||||||
|  | 					this.play() | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style> | ||||||
|  | 	.imt-audio { | ||||||
|  | 		background: #fff; | ||||||
|  | 		border-radius: 20upx; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	.audio-wrapper { | ||||||
|  | 		display: flex; | ||||||
|  | 		align-items: center; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	.audio-number { | ||||||
|  | 		width: 120upx; | ||||||
|  | 		font-size: 24upx; | ||||||
|  | 		line-height: 1; | ||||||
|  | 		color: #999999; | ||||||
|  | 		text-align: center; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	.audio-slider { | ||||||
|  | 		flex: 1; | ||||||
|  | 		margin: 0; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	.audio-control-wrapper { | ||||||
|  | 		margin-top: 40upx; | ||||||
|  |     text-align: center; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  |   .audio-control-wrapper p { | ||||||
|  |     color: #999999; | ||||||
|  |     font-size: 26rpx; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .audio-control-wrapper image { | ||||||
|  |     width: 128rpx; | ||||||
|  |     height: 128rpx; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | 	.audio-control { | ||||||
|  | 		font-size: 32upx; | ||||||
|  | 		line-height: 1; | ||||||
|  | 		border-radius: 50%; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	.audio-control-next { | ||||||
|  | 		transform: rotate(180deg); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	.audio-control-switch { | ||||||
|  | 		font-size: 40upx; | ||||||
|  | 		margin: 0 100upx; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	.audioLoading { | ||||||
|  | 		animation: loading 2s; | ||||||
|  | 		animation-iteration-count: infinite; | ||||||
|  | 		animation-timing-function: linear; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@keyframes loading { | ||||||
|  | 		to { | ||||||
|  | 			transform: rotate(360deg); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | </style> | ||||||
							
								
								
									
										29
									
								
								src/components/VDrag.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,29 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="VDrag"> | ||||||
|  |     <vuedraggable v-bind="$attrs" @change="handleChange"> | ||||||
|  |       <slot/> | ||||||
|  |     </vuedraggable> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import vuedraggable from 'vuedraggable' | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "VDrag", | ||||||
|  |   components: {vuedraggable}, | ||||||
|  |   data: () => ({ | ||||||
|  |     moveEvt: null | ||||||
|  |   }), | ||||||
|  |   methods: { | ||||||
|  |     handleChange(moved) { | ||||||
|  |       this.$emit('move', moved) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .VDrag { | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										39
									
								
								src/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,39 @@ | |||||||
|  | import Vue from 'vue'; | ||||||
|  | import App from './App'; | ||||||
|  | import store from './store'; | ||||||
|  | import axios from './common/axios'; | ||||||
|  | import utils from './common/util'; | ||||||
|  | import dayjs from 'dayjs'; | ||||||
|  | import mixin from './uview/libs/mixin/mixin'; | ||||||
|  |  | ||||||
|  | Vue.config.productionTip = false; | ||||||
|  | Vue.prototype.$store = store; | ||||||
|  | //初始化接口工具类 | ||||||
|  | axios.defaults.baseURL = store.state.baseURL; | ||||||
|  | Vue.prototype.$http = axios; | ||||||
|  | Vue.prototype.$cdn = 'https://cdn.cunwuyun.cn/dvcp/h5/'; | ||||||
|  | Vue.prototype.imgHomeUrl = 'https://cdn.cunwuyun.cn/dvcp/h5/home/'; | ||||||
|  | Vue.prototype.imgOtherUrl = 'https://cdn.cunwuyun.cn/dvcp/h5/other/'; | ||||||
|  | Vue.prototype.$formatName = (name) => { | ||||||
|  | 	if (name == undefined) { | ||||||
|  | 		return; | ||||||
|  | 	} | ||||||
|  | 	return name.substr(name.length - 2, name.length > 2 ? name.length - 1 : name.length); | ||||||
|  | }; | ||||||
|  | Object.keys(utils).map((e) => (Vue.prototype['$' + e] = utils[e])); | ||||||
|  | let relativeTime = require('dayjs/plugin/relativeTime'); | ||||||
|  | require('dayjs/locale/zh-cn'); | ||||||
|  | let dayjs_plugin_duration = require('dayjs/plugin/duration'); | ||||||
|  | dayjs.extend(dayjs_plugin_duration); | ||||||
|  | dayjs.extend(relativeTime); | ||||||
|  | Vue.prototype.$dayjs = dayjs; | ||||||
|  | Vue.mixin(mixin); | ||||||
|  |  | ||||||
|  | App.mpType = 'app'; | ||||||
|  | process.env.NODE_ENV == 'development' && new VConsole(); | ||||||
|  | const app = new Vue({ | ||||||
|  | 	store, | ||||||
|  | 	...App | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | app.$mount(); | ||||||
							
								
								
									
										37
									
								
								src/manifest.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,37 @@ | |||||||
|  | { | ||||||
|  |   "name": "dv_cp_weixin", | ||||||
|  |   "description": "企业微信应用", | ||||||
|  |   "versionName": "1.0.0", | ||||||
|  |   "versionCode": "100", | ||||||
|  |   "transformPx": true, | ||||||
|  |   "mp-weixin": { | ||||||
|  |     "appid": "", | ||||||
|  |     "setting": { | ||||||
|  |       "urlCheck": false | ||||||
|  |     }, | ||||||
|  |     "usingComponents": true, | ||||||
|  |     "permission": { | ||||||
|  |       "scope.userLocation": { | ||||||
|  |         "desc": "演示定位能力" | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   "h5": { | ||||||
|  |     "title": "数字乡村", | ||||||
|  |     "template": "template.h5.html", | ||||||
|  |     "router": { | ||||||
|  |       "mode": "history", | ||||||
|  |       "base": "" | ||||||
|  |     }, | ||||||
|  |     "devServer": { | ||||||
|  |       "disableHostCheck": true, | ||||||
|  |       "port": "10323" | ||||||
|  |     }, | ||||||
|  |     "optimization": { | ||||||
|  |       "preload": true, | ||||||
|  |       "treeShaking": { | ||||||
|  |         "enable": true | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										411
									
								
								src/pages.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,411 @@ | |||||||
|  | { | ||||||
|  |   "easycom": { | ||||||
|  |     "^u-(.*)": "@/uview/components/u-$1/u-$1.vue" | ||||||
|  |   }, | ||||||
|  |   "pages": [ | ||||||
|  |     { | ||||||
|  |       "path": "pages/loading", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "欢迎使用村微..." | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/app", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "应用" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/login" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/notification/notification", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "通知公告" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/notification/components/read", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "接收情况" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/notification/components/detail", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "公告详情" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/notification/components/add", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "新增公告" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/workTask/workTask", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "工作任务" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/workTask/components/create", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "创建任务" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/workTask/components/detail", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "任务详情" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/workTask/components/subDetail", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "任务详情" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/workTask/components/finishDetail", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "完成详情" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/workTask/components/finish", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "完成任务" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/documentFlow/documentFlow", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "公文流转" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/documentFlow/components/detail", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "公文详情" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/documentFlow/components/approval", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "批示" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/meetingNotice/meetingNotice", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "会议通知" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/meetingNotice/components/addMeeting", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "发起会议" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/meetingNotice/components/belongToMe", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "我发起的" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/meetingNotice/components/detail", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "会议详情" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/meetingNotice/components/meetingList" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/askForm/askForm" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/askForm/index", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "问卷表单" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/askForm/formSetting", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "设置" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/askForm/filedConfig", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "组件设置" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/askForm/previewForm", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "表单预览" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/askForm/addForm", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "新建调查表单" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/resident/resident" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/resident/comp", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "居民管理" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/resident/groupResident" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/whereabouts/whereabouts" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/interview/interview", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "调查走访" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/interview/detail", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "新增走访" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/quickReply/quickReply" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/quickReply/typeManage" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/quickReply/replyDetail" | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/supermarket/supermarket", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "信用好超市" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/supermarket/balance", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "结算" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/supermarket/search", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "搜索" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/supermarket/components/resultPage/resultPage", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "结算提交" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/casuallyask/casuallyask", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "随心问" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/casuallyask/casuallyaskDetail", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "随心问(详情页)" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/casuallyask/closemsg", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "关闭留言" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/casuallyask/truemsg", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "提交留言" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/casuallyask/reply", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "发表回复" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/workonline/workonline", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "网上办事" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/workonline/detail", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "进度详情" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/workonline/approvalopinion", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "进度详情" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/workonline/truemsg", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "进度详情" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/snapshot/snapshot", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "随手拍" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/snapshot/snapshotDetail", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "随手拍详情" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/snapshot/handleResult", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "处理结果" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/snapshot/components/handlePage/handlePage", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "处理结果" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/villageQRCode/villageQRCode", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "一村一码" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/guardianship/guardianship", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "智慧监护" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/guardianship/userDetail", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "个人详情" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/guardianship/historyList", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "历史记录" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/guardianship/warningDetail", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "预警" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/bigHorn/bigHorn", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "广播通知" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/bigHorn/playList", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "播放记录" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/bigHorn/onlineList", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "在线设备" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/bigHorn/onlinePlayList", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "在播设备" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/bigHorn/addPlay", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "音频播放" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/bigHorn/selectMp3", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "选择内容" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/bigHorn/selectEquipment", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "选择设备" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/resourcesManage/resourcesManage", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "媒资管理" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/resourcesManage/addPlay", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "媒资管理" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/resourcesManage/talking", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "实时喊话" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/resourcesManage/recording", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "音频录制" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/videoSurveillance/videoSurveillance", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "视频监控" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     { | ||||||
|  |       "path": "pages/videoSurveillance/monitorDetail", | ||||||
|  |       "style": { | ||||||
|  |         "navigationBarTitleText": "实时监控", | ||||||
|  |         "pageOrientation": "landscape" | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   ], | ||||||
|  |   "globalStyle": { | ||||||
|  |     "pageOrientation": "auto", | ||||||
|  |     "navigationStyle": "custom" | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										174
									
								
								src/pages/app.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,174 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="app"> | ||||||
|  |     <u-swiper :list="list" height="240" bg-color="#408CFF"></u-swiper> | ||||||
|  |     <label class="useful-app">常用应用</label> | ||||||
|  |     <u-grid | ||||||
|  |       :col="o.length" | ||||||
|  |       :border="false" | ||||||
|  |       v-for="(o, i) in gridGroup" | ||||||
|  |       :key="i" | ||||||
|  |     > | ||||||
|  |       <u-grid-item v-for="(i, j) in o" :key="j" @click="linkTo(i)"> | ||||||
|  |         <u-icon :name="i.icon" :size="100"></u-icon> | ||||||
|  |         <view class="grid-text">{{ i.label }}</view> | ||||||
|  |       </u-grid-item> | ||||||
|  |     </u-grid> | ||||||
|  |     <label class="useful-app notice">通知公告</label> | ||||||
|  |     <section class="list"> | ||||||
|  |       <div class="item" v-for="(item, index) in dataList" :key="index"> | ||||||
|  |         <label class="title hidden">{{ item.title }}</label> | ||||||
|  |         <div class="content hidden">{{ item.content }}</div> | ||||||
|  |         <div class="date">{{ item.createTime }}</div> | ||||||
|  |       </div> | ||||||
|  |       <u-loadmore :status="status" /> | ||||||
|  |     </section> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: 'app', | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       list: [this.imgHomeUrl + 'banner.png'], | ||||||
|  |       gridGroup: [ | ||||||
|  |         [ | ||||||
|  |           { | ||||||
|  |             icon: `${this.imgHomeUrl}icon1.png`, | ||||||
|  |             label: '随心问', | ||||||
|  |             link: '/pages/casuallyask/casuallyask' | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             icon: `${this.imgHomeUrl}icon2.png`, | ||||||
|  |             label: '随手拍', | ||||||
|  |             link: '/pages/snapshot/snapshot' | ||||||
|  |           }, | ||||||
|  |           { | ||||||
|  |             icon: `${this.imgHomeUrl}icon3.png`, | ||||||
|  |             label: '网上办事', | ||||||
|  |             link: '/pages/workonline/workonline' | ||||||
|  |           }, | ||||||
|  |           { icon: `${this.imgHomeUrl}icon4.png`, label: '调查走访' } | ||||||
|  |         ], | ||||||
|  |         [ | ||||||
|  |           { | ||||||
|  |             icon: `${this.imgHomeUrl}icon5.png`, | ||||||
|  |             label: '信用好超市', | ||||||
|  |             link: '/pages/supermarket/supermarket' | ||||||
|  |           }, | ||||||
|  |           { icon: `${this.imgHomeUrl}icon6.png`, label: '中心工作' }, | ||||||
|  |           { icon: `${this.imgHomeUrl}icon7.png`, label: '会务通知' }, | ||||||
|  |           { icon: `${this.imgHomeUrl}icon8.png`, label: '工作去向' }, | ||||||
|  |           { icon: `${this.imgHomeUrl}icon8.png`, label: '大喇叭' } | ||||||
|  |         ] | ||||||
|  |       ], | ||||||
|  |       status: 'nomore', | ||||||
|  |       dataList: [], | ||||||
|  |       current: 0 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   onLoad() { | ||||||
|  |     this.getList() | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getList() { | ||||||
|  |       if (this.loadingStatus == 'nomore') return | ||||||
|  |       this.$http | ||||||
|  |         .post(`/app/appworkcenternotice/list`, null, { | ||||||
|  |           params: { | ||||||
|  |             withoutToken: true, | ||||||
|  |             current: this.current + 1, | ||||||
|  |             size: 10 | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |         .then(res => { | ||||||
|  |           if (res && res.data) { | ||||||
|  |             this.dataList = res.data.records | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |     }, | ||||||
|  |     linkTo(val) { | ||||||
|  |       if (val.link) { | ||||||
|  |         uni.navigateTo({ url: val.link }) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   onReachBottom() { | ||||||
|  |     this.getList() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .app { | ||||||
|  |   min-height: 100%; | ||||||
|  |   background-color: #ffffff; | ||||||
|  |   box-sizing: border-box; | ||||||
|  |   padding: 32px; | ||||||
|  |   position: relative; | ||||||
|  |  | ||||||
|  |   .grid-text { | ||||||
|  |     font-size: 28px; | ||||||
|  |     color: #333333; | ||||||
|  |     line-height: 46px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .useful-app { | ||||||
|  |     margin-top: 80px; | ||||||
|  |     display: inherit; | ||||||
|  |     font-size: 36px; | ||||||
|  |     font-weight: bold; | ||||||
|  |     color: #333333; | ||||||
|  |     line-height: 50px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .notice { | ||||||
|  |     margin-top: 56px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .list { | ||||||
|  |     margin-top: 38px; | ||||||
|  |  | ||||||
|  |     .item { | ||||||
|  |       height: 192px; | ||||||
|  |       background: #f7f9ff; | ||||||
|  |       border-radius: 8px; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       padding: 20px; | ||||||
|  |       margin-bottom: 32px; | ||||||
|  |  | ||||||
|  |       .title { | ||||||
|  |         font-size: 32px; | ||||||
|  |         font-weight: 800; | ||||||
|  |         color: #343d65; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .content { | ||||||
|  |         font-size: 28px; | ||||||
|  |         color: #333333; | ||||||
|  |         font-weight: 500; | ||||||
|  |         margin: 20px 0 8px 0; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .date { | ||||||
|  |         font-size: 28px; | ||||||
|  |         color: #666666; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .hidden { | ||||||
|  |     overflow: hidden; | ||||||
|  |     text-overflow: ellipsis; | ||||||
|  |     white-space: nowrap; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .u-indicator-item-round { | ||||||
|  |     background-color: #d8dde6; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .u-indicator-item-round-active { | ||||||
|  |     background-color: #408cff !important; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										700
									
								
								src/pages/askForm/addForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,700 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="add-form" v-if="pageShow"> | ||||||
|  |     <div class="header-pic"> | ||||||
|  |       <image v-if="form.headPicture" :src="form.headPicture" /> | ||||||
|  |       <span @click="upload">更换图片</span> | ||||||
|  |     </div> | ||||||
|  |     <div class="form-info"> | ||||||
|  |       <h2>文本选项</h2> | ||||||
|  |       <div class="form-info__wrapper"> | ||||||
|  |         <textarea class="title" placeholder="请输入标题 (必填)" :maxlength="30" :auto-height="true" v-model="form.title"></textarea> | ||||||
|  |         <u-input class="content" :clearable="false" type="textarea" v-model="form.tableExplain" placeholder="请输入表单描述 (选填)" :height="80" :auto-height="true" :maxlength="255"></u-input> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <draggable | ||||||
|  |       class="components-list" | ||||||
|  |       v-model="targetList" | ||||||
|  |       :animation="340" | ||||||
|  |       scroll | ||||||
|  |       element="div" | ||||||
|  |       :options="{ | ||||||
|  |         animation: 340, | ||||||
|  |         handle: '.components-item__title' | ||||||
|  |       }" | ||||||
|  |       draggable=".components-item" | ||||||
|  |       :sort="true"> | ||||||
|  |       <div class="components-item" v-for="(item, index) in targetList" :key="index" @click="toFiledSetting(item, index)"> | ||||||
|  |         <div class="components-item__title"> | ||||||
|  |           <div class="components-item__title--left"> | ||||||
|  |             <em :style="{opacity: item.required ? 1 : 0}">*</em> | ||||||
|  |             <i>{{ index + 1 }}.</i> | ||||||
|  |             <h2>{{ item.label }}</h2> | ||||||
|  |           </div> | ||||||
|  |           <image :src="`${$cdn}askform/sc1.png`" @click.stop="removeComponent(index)" @touchstart.stop="removeComponent(index)" /> | ||||||
|  |         </div> | ||||||
|  |         <div class="components-item__filed"> | ||||||
|  |           <template v-if="(item.type === 'radio')"> | ||||||
|  |             <u-radio-group v-model="item.value" wrap> | ||||||
|  |               <u-radio disabled :name="field.label" v-for="(field, i) in item.options" :key="i"> | ||||||
|  |                 <image :src="field.img[0].url" v-if="field.img.length"/> | ||||||
|  |                 <span>{{ field.label }}</span> | ||||||
|  |               </u-radio> | ||||||
|  |             </u-radio-group> | ||||||
|  |           </template> | ||||||
|  |           <template v-if="(item.type === 'checkbox')"> | ||||||
|  |             <u-checkbox-group v-model="item.value" wrap> | ||||||
|  |               <u-checkbox  disabled :name="field.label" v-for="(field, i) in item.options" :key="i"> | ||||||
|  |                 <image :src="field.img[0].url" v-if="field.img.length"/> | ||||||
|  |                 <span>{{ field.label }}</span> | ||||||
|  |               </u-checkbox> | ||||||
|  |             </u-checkbox-group> | ||||||
|  |           </template> | ||||||
|  |           <template v-if="(item.type === 'select')"> | ||||||
|  |             <div class="components-item__select"> | ||||||
|  |               <span>{{ item.placeholder }}</span> | ||||||
|  |               <u-icon name="arrow-down" color="#DEDFDF" /> | ||||||
|  |             </div> | ||||||
|  |           </template> | ||||||
|  |           <template v-if="(item.type === 'upload')"> | ||||||
|  |             <div class="components-item__select components-item__textarea components-item__upload"> | ||||||
|  |               <image :src="`${$cdn}askform/upload.png`" /> | ||||||
|  |               <span>选择图片(2M以内)</span> | ||||||
|  |             </div> | ||||||
|  |           </template> | ||||||
|  |           <template v-if="(item.type === 'input')"> | ||||||
|  |             <div class="components-item__select"> | ||||||
|  |               <span>{{ item.placeholder }}</span> | ||||||
|  |             </div> | ||||||
|  |           </template> | ||||||
|  |           <template v-if="(item.type === 'textarea')"> | ||||||
|  |             <div class="components-item__select components-item__textarea"> | ||||||
|  |               <span>{{ item.placeholder }}</span> | ||||||
|  |             </div> | ||||||
|  |           </template> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </draggable> | ||||||
|  |     <div class="add-form__btn" @click="isShow = true"> | ||||||
|  |       <image :src="`${$cdn}askform/add.png`" /> | ||||||
|  |       <span>添加问题</span> | ||||||
|  |     </div> | ||||||
|  |     <div class="add-form__footer"> | ||||||
|  |       <div> | ||||||
|  |         <span @click="toPreview">预览</span> | ||||||
|  |         <span @click="toSetting">设置</span> | ||||||
|  |       </div> | ||||||
|  |       <div @click="onConfirm">立即发布</div> | ||||||
|  |     </div> | ||||||
|  |     <u-popup v-model="isShow" :closeable="false" mode="bottom"> | ||||||
|  |       <div class="add-popup"> | ||||||
|  |         <div class="add-popup__title"> | ||||||
|  |           <h2>添加问题</h2> | ||||||
|  |           <image :src="`${$cdn}askform/zk.png`" mode="aspectFit" @click="isShow = false" /> | ||||||
|  |         </div> | ||||||
|  |         <div class="add-popup__list"> | ||||||
|  |           <span @click="toFiledSetting('radio')">单选题</span> | ||||||
|  |           <span @click="toFiledSetting('checkbox')">多选题</span> | ||||||
|  |           <span @click="toFiledSetting('select')">单下拉框</span> | ||||||
|  |           <span @click="toFiledSetting('input')">单行填空</span> | ||||||
|  |           <span @click="toFiledSetting('textarea')">多行填空</span> | ||||||
|  |           <span @click="toFiledSetting('upload')">上传图片</span> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </u-popup> | ||||||
|  |     <AiBack></AiBack> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  |   import AiBack from "@/components/AiBack"; | ||||||
|  |   import draggable from 'vuedraggable' | ||||||
|  |   export default { | ||||||
|  |     data () { | ||||||
|  |       return { | ||||||
|  |         pageShow: false, | ||||||
|  |         form: { | ||||||
|  |           tableExplain: '详细描述', | ||||||
|  |           title: '问卷调查', | ||||||
|  |           isShowheadPicture: true, | ||||||
|  |           isShowTableExplain: true, | ||||||
|  |           isShowBtn: true, | ||||||
|  |           headPicture: '', | ||||||
|  |           commitType: '1', | ||||||
|  |           periodValidityType: '0', | ||||||
|  |           actionNotice: '1', | ||||||
|  |           dynamicNotice: '1', | ||||||
|  |           periodValidityEndTime: '', | ||||||
|  |           shareStatus: '0', | ||||||
|  |           count: 0, | ||||||
|  |           wechatId: '0', | ||||||
|  |           type: 0, | ||||||
|  |           buttonExplain: '提交', | ||||||
|  |           tips: true | ||||||
|  |         }, | ||||||
|  |         templateType: 0, | ||||||
|  |         targetList: [], | ||||||
|  |         isShow: false, | ||||||
|  |         type: 0, | ||||||
|  |         id: '', | ||||||
|  |         isQuote: false, | ||||||
|  |         touchStart: 0, | ||||||
|  |         formConfig: {} | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     components: { | ||||||
|  |       AiBack, | ||||||
|  |       draggable | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onLoad (query) { | ||||||
|  |       this.type = Number(query.type) | ||||||
|  |  | ||||||
|  |       if (query.isQuote) { | ||||||
|  |         this.isQuote = true | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if (query.id) { | ||||||
|  |         this.id = query.id | ||||||
|  |         this.getInfo(query.id) | ||||||
|  |       } else { | ||||||
|  |         this.pageShow = true | ||||||
|  |       } | ||||||
|  |       this.init() | ||||||
|  |  | ||||||
|  |       uni.$on('setting', res => { | ||||||
|  |         this.form = { | ||||||
|  |           ...this.form, | ||||||
|  |           ...res | ||||||
|  |         } | ||||||
|  |         this.formConfig = res | ||||||
|  |       }) | ||||||
|  |  | ||||||
|  |       uni.$on('filedConfig', res => { | ||||||
|  |         if (res.index === '-1') { | ||||||
|  |           this.targetList.push(res.config) | ||||||
|  |         } else { | ||||||
|  |           this.$set(this.targetList, [res.index], res.config) | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     methods: { | ||||||
|  |       toSetting () { | ||||||
|  |         uni.navigateTo({ | ||||||
|  |           url: `/pages/askForm/formSetting?id=${this.id}&formConfig=${JSON.stringify(this.formConfig)}` | ||||||
|  |         }) | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       removeComponent (index) { | ||||||
|  |         this.targetList.splice(index, 1) | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       toPreview () { | ||||||
|  |         uni.navigateTo({ | ||||||
|  |           url: `/pages/askForm/previewForm?targetList=${JSON.stringify(this.targetList)}&form=${JSON.stringify(this.form)}` | ||||||
|  |         }) | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       upload() { | ||||||
|  |         let params = { | ||||||
|  |           count: 1, | ||||||
|  |           sizeType: ['compressed'], | ||||||
|  |           sourceType: ['album', 'camera'], | ||||||
|  |           success: (res) => { | ||||||
|  |             let count = this.fileList?.length + (res.tempFiles?.length || res.tempFile ? 1 : 0) | ||||||
|  |             if (count > 1) { | ||||||
|  |               return this.$u.toast(`不能超过1个`) | ||||||
|  |             } | ||||||
|  |             if (res.tempFiles) { | ||||||
|  |               res.tempFiles.map((item) => { | ||||||
|  |                 this.uploadFile(item) | ||||||
|  |               }) | ||||||
|  |             } else if (res?.tempFile) { | ||||||
|  |               this.uploadFile(res.tempFile) | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         uni.chooseImage(params) | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       uploadFile (img) { | ||||||
|  |         uni.showLoading({title: '上传中'}) | ||||||
|  |         let formData = new FormData() | ||||||
|  |         formData.append('file', img) | ||||||
|  |         this.$http.post('/admin/file/add2', formData).then((res) => { | ||||||
|  |           uni.hideLoading() | ||||||
|  |           if (res?.data) { | ||||||
|  |             this.$u.toast('上传成功!') | ||||||
|  |             this.form.headPicture = res.data.url | ||||||
|  |           } | ||||||
|  |         }).catch(res => { | ||||||
|  |           this.$u.toast(res) | ||||||
|  |           uni.hideLoading() | ||||||
|  |         }) | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       onConfirm () { | ||||||
|  |         for (let item of this.targetList) { | ||||||
|  |           if (item.isShowPoints) { | ||||||
|  |             if (item.pointType === '0') { | ||||||
|  |               if (!item.answer || JSON.stringify(item.answer) === '[]') { | ||||||
|  |                 return this.$u.toast(`请输入${item.label}正确答案`) | ||||||
|  |               } | ||||||
|  |  | ||||||
|  |               if (!item.points) { | ||||||
|  |                 return this.$u.toast(`请输入${item.label}的分值`) | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (item.pointType === '1') { | ||||||
|  |               for (let option of item.options) { | ||||||
|  |                 if (!option.point) { | ||||||
|  |                   return this.$u.toast(`请输入${item.label}${option.label}的分值`) | ||||||
|  |                 } | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             if (item.pointType === '2') { | ||||||
|  |               for (let option of item.options) { | ||||||
|  |                 if (!option.point) { | ||||||
|  |                   return this.$u.toast(`请输入${item.label}${option.label}的分值`) | ||||||
|  |                 } | ||||||
|  |               } | ||||||
|  |  | ||||||
|  |               if (!item.points) { | ||||||
|  |                 return this.$u.toast(`请输入${item.label}全部答对分值`) | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         const fields = this.targetList.map(item => { | ||||||
|  |           return { | ||||||
|  |             fieldType: item.type, | ||||||
|  |             fieldName: item.label, | ||||||
|  |             fieldInfo: JSON.stringify(item) | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |  | ||||||
|  |         this.$http.post(`/app/appquestionnairetemplate/addOrUpdate`, { | ||||||
|  |           ...this.form, | ||||||
|  |           fields, | ||||||
|  |           status: 1, | ||||||
|  |           id: this.isQuote ? '' : this.id, | ||||||
|  |           headPicture: this.form.headPicture, | ||||||
|  |           type: this.type, | ||||||
|  |           templateType: 0 | ||||||
|  |         }).then(res => { | ||||||
|  |           if (res.code == 0) { | ||||||
|  |             this.$u.toast('提交成功') | ||||||
|  |  | ||||||
|  |             setTimeout(() => { | ||||||
|  |               uni.$emit('reload') | ||||||
|  |               uni.navigateBack({ | ||||||
|  |                 delta: 1 | ||||||
|  |               }) | ||||||
|  |             }, 600) | ||||||
|  |           } | ||||||
|  |         }).catch(e => { | ||||||
|  |           this.$u.toast(e) | ||||||
|  |         }) | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       getInfo (id) { | ||||||
|  |         uni.showLoading() | ||||||
|  |         this.$http.post(`/app/appquestionnairetemplate/queryDetailById?id=${id}`).then(res => { | ||||||
|  |           if (res.code == 0) { | ||||||
|  |             this.form = { | ||||||
|  |               ...res.data, | ||||||
|  |               headPicture: res.data.headPicture | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             this.type = res.data.type | ||||||
|  |  | ||||||
|  |             this.targetList = res.data.fields.map(item => { | ||||||
|  |               return JSON.parse(item.fieldInfo) | ||||||
|  |             }) | ||||||
|  |  | ||||||
|  |             this.pageShow = true | ||||||
|  |           } else { | ||||||
|  |             this.$u.toast(res.msg) | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           uni.hideLoading() | ||||||
|  |         }).catch(() => { | ||||||
|  |           uni.hideLoading() | ||||||
|  |         }) | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       toFiledSetting (type, index) { | ||||||
|  |         if (index != undefined) { | ||||||
|  |           uni.navigateTo({ | ||||||
|  |             url: `/pages/askForm/filedConfig?config=${JSON.stringify(type)}&index=${index}` | ||||||
|  |           }) | ||||||
|  |  | ||||||
|  |           return false | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         this.isShow = false | ||||||
|  |         uni.navigateTo({ | ||||||
|  |           url: `/pages/askForm/filedConfig?type=${type}` | ||||||
|  |         }) | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       init () { | ||||||
|  |         if (this.type == 0) { | ||||||
|  |           this.form.headPicture = 'https://cdn.cunwuyun.cn/dvcp/h5/form/interview.png' | ||||||
|  |         } | ||||||
|  |         if (this.type == 1) { | ||||||
|  |           this.form.title = '考试测评' | ||||||
|  |           this.form.headPicture = 'https://cdn.cunwuyun.cn/dvcp/h5/form/exam.png' | ||||||
|  |         } | ||||||
|  |         if (this.type == 2) { | ||||||
|  |           this.form.title = '报名登记' | ||||||
|  |           this.form.headPicture = 'https://cdn.cunwuyun.cn/dvcp/h5/form/apply.png' | ||||||
|  |         } | ||||||
|  |         if (this.type == 3) { | ||||||
|  |           this.form.title = '满意调查' | ||||||
|  |           this.form.headPicture = 'https://cdn.cunwuyun.cn/dvcp/h5/form/satisfaction.png' | ||||||
|  |         } | ||||||
|  |         if (this.type == 4) { | ||||||
|  |           this.form.title = '投票评选' | ||||||
|  |           this.form.headPicture = 'https://cdn.cunwuyun.cn/dvcp/h5/form/vote.png' | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  |   .add-form { | ||||||
|  |     min-height: 100vh; | ||||||
|  |     padding-bottom: 140px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     background: #F3F6F9; | ||||||
|  |  | ||||||
|  |     * { | ||||||
|  |       box-sizing: border-box; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ::v-deep .u-drawer-bottom { | ||||||
|  |       background-color: transparent; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .components-list { | ||||||
|  |       padding: 0 20px; | ||||||
|  |  | ||||||
|  |       .components-item { | ||||||
|  |         margin-top: 24px; | ||||||
|  |         padding: 32px; | ||||||
|  |         box-shadow: 0 4px 8px 4px rgba(233, 233, 233, 0.39); | ||||||
|  |         border-radius: 8px; | ||||||
|  |         overflow: hidden; | ||||||
|  |         border: 1px solid #EEEFF0; | ||||||
|  |         background: #fff; | ||||||
|  |  | ||||||
|  |         ::v-deep .u-radio, ::v-deep .u-checkbox { | ||||||
|  |           position: relative; | ||||||
|  |           margin-bottom: 20px; | ||||||
|  |  | ||||||
|  |           &:last-child { | ||||||
|  |             margin-bottom: 0; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           .u-checkbox__icon-wrap, .u-radio__icon-wrap { | ||||||
|  |             position: absolute; | ||||||
|  |             top: 4rpx; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           .u-radio__label, .u-checkbox__label { | ||||||
|  |             display: flex; | ||||||
|  |             align-items: center; | ||||||
|  |             margin-right: 0; | ||||||
|  |             margin-left: 40px; | ||||||
|  |             text-align: justify; | ||||||
|  |  | ||||||
|  |             span { | ||||||
|  |               line-height: 1.5; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             image { | ||||||
|  |               width: 100px; | ||||||
|  |               height: 100px; | ||||||
|  |               margin: 0 10px; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         span { | ||||||
|  |           flex: 1; | ||||||
|  |           color: #666; | ||||||
|  |           font-size: 26px; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .components-item__select { | ||||||
|  |           display: flex; | ||||||
|  |           align-items: center; | ||||||
|  |           justify-content: space-between; | ||||||
|  |           width: 100%; | ||||||
|  |           height: 80px; | ||||||
|  |           margin-bottom: 8px; | ||||||
|  |           padding: 0 26px; | ||||||
|  |           border: 1px solid #DEDFDF; | ||||||
|  |  | ||||||
|  |           &.components-item__textarea { | ||||||
|  |             align-items: flex-start; | ||||||
|  |             height: 160px; | ||||||
|  |             padding-top: 20px; | ||||||
|  |  | ||||||
|  |             image { | ||||||
|  |               width: 46px; | ||||||
|  |               height: 34px; | ||||||
|  |               margin-right: 16px; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             span { | ||||||
|  |               color: #666; | ||||||
|  |               font-size: 26px; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           &.components-item__upload { | ||||||
|  |             justify-content: center; | ||||||
|  |             align-items: center; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .components-item__title { | ||||||
|  |           display: flex; | ||||||
|  |           align-items: center; | ||||||
|  |           justify-content: space-between; | ||||||
|  |           margin-bottom: 32px; | ||||||
|  |  | ||||||
|  |           em { | ||||||
|  |             margin-right: 4px; | ||||||
|  |             font-style: normal; | ||||||
|  |             color: rgb(226, 33, 32);; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           image { | ||||||
|  |             position: relative; | ||||||
|  |             flex-shrink: 1; | ||||||
|  |             right: -20px; | ||||||
|  |             width: 32px; | ||||||
|  |             height: 32px; | ||||||
|  |             box-sizing: content-box; | ||||||
|  |             padding: 30px 20px 30px 20px; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           div { | ||||||
|  |             display: flex; | ||||||
|  |             align-items: baseline; | ||||||
|  |             max-width: 550px; | ||||||
|  |             color: #333333; | ||||||
|  |             font-size: 32px; | ||||||
|  |  | ||||||
|  |             i { | ||||||
|  |               font-style: normal; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             h2 { | ||||||
|  |               font-weight: 600; | ||||||
|  |               font-size: 32px; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .add-popup { | ||||||
|  |       height: 440px; | ||||||
|  |       border-radius: 20px 20px 0 0; | ||||||
|  |       background: #fff; | ||||||
|  |  | ||||||
|  |       .add-popup__title { | ||||||
|  |         display: flex; | ||||||
|  |         position: relative; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: center; | ||||||
|  |         height: 96px; | ||||||
|  |         border-bottom: 1px solid #E4E5E6; | ||||||
|  |  | ||||||
|  |         h2 { | ||||||
|  |           color: #333333; | ||||||
|  |           font-size: 32px; | ||||||
|  |           font-weight: 600; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         image { | ||||||
|  |           position: absolute; | ||||||
|  |           right: 32px; | ||||||
|  |           top: 50%; | ||||||
|  |           width: 30px; | ||||||
|  |           height: 20px; | ||||||
|  |           transform: translateY(-50%); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .add-popup__list { | ||||||
|  |         display: flex; | ||||||
|  |         flex-wrap: wrap; | ||||||
|  |         padding: 0 34px; | ||||||
|  |  | ||||||
|  |         span { | ||||||
|  |           width: calc((100% - 64px) / 3); | ||||||
|  |           height: 78px; | ||||||
|  |           line-height: 78px; | ||||||
|  |           margin-top: 32px; | ||||||
|  |           margin-right: 32px; | ||||||
|  |           text-align: center; | ||||||
|  |           color: #333333; | ||||||
|  |           font-size: 28px; | ||||||
|  |           border-radius: 8px; | ||||||
|  |           border: 1px solid #E4E5E6; | ||||||
|  |  | ||||||
|  |           &:nth-of-type(3n) { | ||||||
|  |             margin-right: 0; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .add-form__footer { | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |       position: fixed; | ||||||
|  |       left: 0; | ||||||
|  |       bottom: 0; | ||||||
|  |       z-index: 1; | ||||||
|  |       width: 100%; | ||||||
|  |       height: 112px; | ||||||
|  |       text-align: center; | ||||||
|  |  | ||||||
|  |       div { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: center; | ||||||
|  |         flex: 1; | ||||||
|  |         height: 100%; | ||||||
|  |         text-align: center; | ||||||
|  |         background: #fff; | ||||||
|  |  | ||||||
|  |         &:last-child { | ||||||
|  |           color: #fff; | ||||||
|  |           font-size: 36px; | ||||||
|  |           background: #3192F4; | ||||||
|  |  | ||||||
|  |           &:active { | ||||||
|  |             opacity: 0.8; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         span { | ||||||
|  |           flex: 1; | ||||||
|  |           height: 100%; | ||||||
|  |           line-height: 112px; | ||||||
|  |           color: #333333; | ||||||
|  |           font-size: 32px; | ||||||
|  |  | ||||||
|  |           &:active { | ||||||
|  |             background: #eee; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .add-form__btn { | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |       justify-content: center; | ||||||
|  |       width: 214px; | ||||||
|  |       height: 66px; | ||||||
|  |       line-height: 66px; | ||||||
|  |       margin: 64px auto 0; | ||||||
|  |       background: #FFFFFF; | ||||||
|  |       border-radius: 34px; | ||||||
|  |  | ||||||
|  |       &:active { | ||||||
|  |         opacity: 0.8; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       image { | ||||||
|  |         width: 28px; | ||||||
|  |         height: 28px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         margin-left: 16px; | ||||||
|  |         color: #4392E6; | ||||||
|  |         font-size: 28px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     * { | ||||||
|  |       box-sizing: border-box; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .form-info { | ||||||
|  |       padding: 0 20px; | ||||||
|  |  | ||||||
|  |       & > h2 { | ||||||
|  |         height: 76px; | ||||||
|  |         line-height: 76px; | ||||||
|  |         color: #999999; | ||||||
|  |         font-weight: normal; | ||||||
|  |         font-size: 28px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .form-info__wrapper { | ||||||
|  |         padding: 0 18px; | ||||||
|  |         background: #fff; | ||||||
|  |  | ||||||
|  |         .title { | ||||||
|  |           width: 100%; | ||||||
|  |           padding: 22px 0; | ||||||
|  |           font-size: 36px; | ||||||
|  |           border-bottom: 1px solid #F1F2F3; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .content { | ||||||
|  |           padding: 30px 0!important; | ||||||
|  |           font-size: 28px; | ||||||
|  |  | ||||||
|  |           ::v-deep textarea { | ||||||
|  |             color: #333; | ||||||
|  |             font-size: 28px!important; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .header-pic { | ||||||
|  |       position: relative; | ||||||
|  |       font-size: 0; | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         position: absolute; | ||||||
|  |         bottom: 16px; | ||||||
|  |         right: 16px; | ||||||
|  |         z-index: 1; | ||||||
|  |         width: 148px; | ||||||
|  |         height: 56px; | ||||||
|  |         line-height: 56px; | ||||||
|  |         text-align: center; | ||||||
|  |         color: #fff; | ||||||
|  |         font-size: 26px; | ||||||
|  |         background: rgba(0, 0, 0, 0.16); | ||||||
|  |         border-radius: 28px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       image { | ||||||
|  |         width: 100%; | ||||||
|  |         height: 320px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ::v-deep .u-radio, ::v-deep .u-checkbox { | ||||||
|  |       align-items: baseline; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										52
									
								
								src/pages/askForm/askForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,52 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="askForm"> | ||||||
|  |     <template v-if="showDetail&&!isManager"> | ||||||
|  |       <form-detail/> | ||||||
|  |     </template> | ||||||
|  |     <template v-else-if="isManager"> | ||||||
|  |       <form-list ref="FormList"/> | ||||||
|  |     </template> | ||||||
|  |     <ai-loading v-else :tips="errMsg"/> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import AiLoading from "../../components/AiLoading"; | ||||||
|  | import {mapState} from "vuex"; | ||||||
|  | import FormDetail from "./formDetail"; | ||||||
|  | import FormList from "./formList"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "askForm", | ||||||
|  |   components: {FormList, FormDetail, AiLoading}, | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['openUser', 'user']), | ||||||
|  |     showDetail() { | ||||||
|  |       return !!this.$route.query?.id | ||||||
|  |     }, | ||||||
|  |     isManager() { | ||||||
|  |       let {hash, query: {preview}} = this.$route | ||||||
|  |       if (preview) return false | ||||||
|  |       else if (hash == "#dev") return true | ||||||
|  |       else return hash != '#form' && !!this.user.id | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       errMsg: "加载表单中..." | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   onReachBottom() { | ||||||
|  |     this.$refs?.FormList?.reachBottom() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .askForm { | ||||||
|  |   position: absolute; | ||||||
|  |   width: 100%; | ||||||
|  |   height: 100%; | ||||||
|  |   background: #fff; | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										182
									
								
								src/pages/askForm/components/addList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,182 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="form"> | ||||||
|  |     <div class="form-list"> | ||||||
|  |       <div | ||||||
|  |         class="form-list__item" | ||||||
|  |         @click="toAdd(`/pages/askForm/addForm?type=${index}`)" | ||||||
|  |         :style="{'background-image': `url(${$cdn}askform/${index + 1}.png)`}" | ||||||
|  |         v-for="(item, index) in itemList" | ||||||
|  |         :key="index"> | ||||||
|  |         <h2>{{ item.name }}</h2> | ||||||
|  |         <div>立即创建</div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="template" v-if="list.length"> | ||||||
|  |       <h2>共享模板</h2> | ||||||
|  |       <div class="template-list"> | ||||||
|  |         <div class="template-item" v-for="(item, index) in list" :key="index" hover-class="bg-hover" @click="quote(item.id)"> | ||||||
|  |           <image :src="`${$cdn}askform/6.png`" /> | ||||||
|  |           <h2>{{ item.title }}</h2> | ||||||
|  |           <u-icon name="arrow-right" color="#E1E2E3" /> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: 'addList', | ||||||
|  |   label: '新建项目', | ||||||
|  |  | ||||||
|  |   data () { | ||||||
|  |     return { | ||||||
|  |       itemList: [{ | ||||||
|  |         name: '调查问卷' | ||||||
|  |       }, { | ||||||
|  |         name: '考试测评' | ||||||
|  |       }, { | ||||||
|  |         name: '报名登记' | ||||||
|  |       }, { | ||||||
|  |         name: '满意调查' | ||||||
|  |       }, { | ||||||
|  |         name: '投票评选' | ||||||
|  |       }], | ||||||
|  |       list: [] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   mounted () { | ||||||
|  |     this.getList() | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   methods: { | ||||||
|  |     toAdd (url) { | ||||||
|  |       uni.navigateTo({ | ||||||
|  |         url | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     quote (id) { | ||||||
|  |       uni.navigateTo({ | ||||||
|  |         url: `/pages/askForm/addForm?isQuote=1&id=${id}` | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     getList () { | ||||||
|  |       this.$http.post(`/app/appquestionnairetemplate/list`, null, { | ||||||
|  |         params: { | ||||||
|  |           current: 1, | ||||||
|  |           templateType: 1, | ||||||
|  |           size: 10000 | ||||||
|  |         } | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res.code == 0) { | ||||||
|  |           this.list = res.data.records | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  |   .template { | ||||||
|  |     margin: 32px 32px 0; | ||||||
|  |     background: #fff; | ||||||
|  |     border-radius: 8px; | ||||||
|  |     overflow: hidden; | ||||||
|  |  | ||||||
|  |     & > h2 { | ||||||
|  |       height: 88px; | ||||||
|  |       line-height: 88px; | ||||||
|  |       padding: 0 24px; | ||||||
|  |       color: #333333; | ||||||
|  |       font-size: 30px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .template-item { | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |       height: 104px; | ||||||
|  |       padding: 0 24px; | ||||||
|  |       border-bottom: 1px solid #D8DDE6; | ||||||
|  |  | ||||||
|  |       &:active { | ||||||
|  |         background-color: #eee; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       &:last-child { | ||||||
|  |         border: none; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       image { | ||||||
|  |         width: 36px; | ||||||
|  |         height: 42px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       i { | ||||||
|  |         font-size: 30px; | ||||||
|  |         color: #E1E2E3; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       h2 { | ||||||
|  |         flex: 1; | ||||||
|  |         padding: 0 18px; | ||||||
|  |         color: #333333; | ||||||
|  |         font-size: 28px; | ||||||
|  |         font-weight: normal; | ||||||
|  |         overflow: hidden; | ||||||
|  |         text-overflow:ellipsis; | ||||||
|  |         white-space: nowrap; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .form-list { | ||||||
|  |     display: flex; | ||||||
|  |     flex-wrap: wrap; | ||||||
|  |     padding: 0 32px 0; | ||||||
|  |  | ||||||
|  |     div { | ||||||
|  |       box-sizing: border-box; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .form-list__item { | ||||||
|  |       width: calc(50% - 13px); | ||||||
|  |       height: 216px; | ||||||
|  |       margin: 32px 24px 0 0; | ||||||
|  |       padding: 40px 20px 52px; | ||||||
|  |       background-color: #FFFFFF; | ||||||
|  |       border-radius: 8px; | ||||||
|  |       background-size: 100% 100%; | ||||||
|  |  | ||||||
|  |       &:active { | ||||||
|  |         background-color: #eee; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       &:nth-of-type(2n) { | ||||||
|  |         margin-right: 0; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       div { | ||||||
|  |         width: 148px; | ||||||
|  |         height: 48px; | ||||||
|  |         line-height: 48px; | ||||||
|  |         text-align: center; | ||||||
|  |         color: #fff; | ||||||
|  |         font-size: 28px; | ||||||
|  |         background: #6BA1F9; | ||||||
|  |         border-radius: 24px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       h2 { | ||||||
|  |         margin-bottom: 32px; | ||||||
|  |         padding-left: 10px; | ||||||
|  |         color: #333333; | ||||||
|  |         font-weight: 700; | ||||||
|  |         font-size: 32px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										497
									
								
								src/pages/askForm/components/list.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,497 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="form"> | ||||||
|  |     <ai-top-fixed> | ||||||
|  |       <u-search placeholder="请输入标题" :show-action="false" search-icon-color="#ccc" v-model="search.title" | ||||||
|  |                 @search="isMore = false, search.current = 1, getList()"/> | ||||||
|  |     </ai-top-fixed> | ||||||
|  |     <div class="form-list"> | ||||||
|  |       <div class="form-item" v-for="(item, index) in list" :key="index" | ||||||
|  |            @click="info = item, id = item.id, isShow = true"> | ||||||
|  |         <div class="form-item__top"> | ||||||
|  |           <div class="form-item__left"> | ||||||
|  |             <h2>{{ item.title }}</h2> | ||||||
|  |             <div class="form-item__left--info"> | ||||||
|  |               <span>{{ item.createUserName }}</span> | ||||||
|  |               <span>{{ item.createUnitName }}</span> | ||||||
|  |               <span>{{ item.createTime.substr(0, item.createTime.length - 3) }}</span> | ||||||
|  |               <span>{{ $dict.getLabel('questionnaireType', item.type) }}</span> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |           <div class="form-item__right"> | ||||||
|  |             <h2>{{ item.dataCount }}</h2> | ||||||
|  |             <span>答卷数量</span> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="form-item__bottom form-item__bottom--active"> | ||||||
|  |           <i :style="{background: $dict.getColor('questionnaireStatus', item.status)}"></i> | ||||||
|  |           <span>{{ $dict.getLabel('questionnaireStatus', item.status) }}</span> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <ai-empty v-if="!list.length && isMore"></ai-empty> | ||||||
|  |     </div> | ||||||
|  |     <u-popup v-model="isShow" :closeable="false" mode="bottom" :z-index="11"> | ||||||
|  |       <div class="popup"> | ||||||
|  |         <h2>{{ info.title }}</h2> | ||||||
|  |         <div class="operate-list"> | ||||||
|  |           <div class="operate-item" @click="toEdit"> | ||||||
|  |             <div> | ||||||
|  |               <image :src="`${$cdn}askform/bj.png`"/> | ||||||
|  |             </div> | ||||||
|  |             <h3>编辑</h3> | ||||||
|  |           </div> | ||||||
|  |           <div class="operate-item" @click="linkTo('/pages/askForm/askForm?preview=1&id=' + id)"> | ||||||
|  |             <div> | ||||||
|  |               <image :src="`${$cdn}askform/yl.png`"/> | ||||||
|  |             </div> | ||||||
|  |             <h3>预览</h3> | ||||||
|  |           </div> | ||||||
|  |           <div class="operate-item" @click="publish" v-if="info.status !== '1'"> | ||||||
|  |             <div> | ||||||
|  |               <image :src="`${$cdn}askform/fb.png`"/> | ||||||
|  |             </div> | ||||||
|  |             <h3>发布</h3> | ||||||
|  |           </div> | ||||||
|  |           <div class="operate-item" @click="toStop" v-if="info.status === '1'"> | ||||||
|  |             <div> | ||||||
|  |               <image :src="`${$cdn}askform/stop.png`"/> | ||||||
|  |             </div> | ||||||
|  |             <h3>停止</h3> | ||||||
|  |           </div> | ||||||
|  |           <div class="operate-item" @click="showShare"> | ||||||
|  |             <div> | ||||||
|  |               <image :src="`${$cdn}askform/fx.png`"/> | ||||||
|  |             </div> | ||||||
|  |             <h3>分享</h3> | ||||||
|  |           </div> | ||||||
|  |           <div class="operate-item" @click="share(id)"> | ||||||
|  |             <div> | ||||||
|  |               <image :src="`${$cdn}askform/mb.png`"/> | ||||||
|  |             </div> | ||||||
|  |             <h3>共享为模板</h3> | ||||||
|  |           </div> | ||||||
|  |           <div class="operate-item" @click="remove(id)"> | ||||||
|  |             <div> | ||||||
|  |               <image :src="`${$cdn}askform/sc.png`"/> | ||||||
|  |             </div> | ||||||
|  |             <h3>删除</h3> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="popup-btn" @click="isShow = false">关闭</div> | ||||||
|  |       </div> | ||||||
|  |     </u-popup> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import AiTopFixed from '@/components/AiTopFixed' | ||||||
|  | import AiEmpty from '@/components/AiEmpty/AiEmpty' | ||||||
|  | import {mapActions} from 'vuex' | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: 'formList', | ||||||
|  |   label: '表单列表', | ||||||
|  |  | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       search: { | ||||||
|  |         current: 1, | ||||||
|  |         templateType: 0, | ||||||
|  |         title: '' | ||||||
|  |       }, | ||||||
|  |       id: '', | ||||||
|  |       info: {}, | ||||||
|  |       isMore: false, | ||||||
|  |       list: [], | ||||||
|  |       isShow: false | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   components: { | ||||||
|  |     AiEmpty, | ||||||
|  |     AiTopFixed | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   mounted() { | ||||||
|  |     this.injectJWeixin(['sendChatMessage', 'selectEnterpriseContact']) | ||||||
|  |     this.$dict.load(['questionnaireStatus', 'questionnaireType', 'questionnaireFieldType']).then(() => { | ||||||
|  |       this.getList() | ||||||
|  |     }) | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   methods: { | ||||||
|  |     ...mapActions(['injectJWeixin', 'wxInvoke']), | ||||||
|  |  | ||||||
|  |     linkTo(url) { | ||||||
|  |       this.isShow = false | ||||||
|  |  | ||||||
|  |       uni.navigateTo({ | ||||||
|  |         url | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     toStop() { | ||||||
|  |       this.$http.post(`/app/appquestionnairetemplate/stopRelease?id=${this.info.id}`).then(res => { | ||||||
|  |         if (res.code === 0) { | ||||||
|  |           this.$u.toast('停止成功') | ||||||
|  |           this.search.current = 1 | ||||||
|  |           this.isShow = false | ||||||
|  |           this.isMore = false | ||||||
|  |           this.getList() | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     showShare() { | ||||||
|  |       if (this.info.status !== '1') { | ||||||
|  |         this.isShow = false | ||||||
|  |         return this.$u.toast(`该表单${this.info.status === '0' ? '未发布' : '已截止'},无法分享!`) | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       uni.showActionSheet({ | ||||||
|  |         itemList: ['分享', '微信分享', '获取链接'], | ||||||
|  |         success: data => { | ||||||
|  |           this.$http.post(`/app/appquestionnairetemplate/queryQrCode?id=${this.info.id}`).then(res => { | ||||||
|  |             if (res.code == 0) { | ||||||
|  |               if (data.tapIndex === 2) { | ||||||
|  |                 this.copy(res.data.linkUrl) | ||||||
|  |                 this.isShow = false | ||||||
|  |               } | ||||||
|  |               if (data.tapIndex === 0 || data.tapIndex === 1) { | ||||||
|  |                 this.injectJWeixin(['shareAppMessage', 'shareWechatMessage']).then(() => { | ||||||
|  |                   if (data.tapIndex === 0) { | ||||||
|  |                     this.wxInvoke(['shareAppMessage', { | ||||||
|  |                       title: this.info.title, | ||||||
|  |                       desc: this.info.tableExplain, | ||||||
|  |                       link: res.data.linkUrl, | ||||||
|  |                       imgUrl: this.info.headPicture | ||||||
|  |                     }, () => { | ||||||
|  |                       this.isShow = false | ||||||
|  |                     }]) | ||||||
|  |                   } else { | ||||||
|  |                     this.wxInvoke(['shareWechatMessage', { | ||||||
|  |                       title: this.info.title, | ||||||
|  |                       desc: this.info.tableExplain, | ||||||
|  |                       link: res.data.linkUrl, | ||||||
|  |                       imgUrl: this.info.headPicture | ||||||
|  |                     }, () => { | ||||||
|  |                       this.isShow = false | ||||||
|  |                     }]) | ||||||
|  |                   } | ||||||
|  |                 }) | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           }) | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     copy(link) { | ||||||
|  |       let oInput = document.createElement('input') | ||||||
|  |       oInput.value = link | ||||||
|  |       document.body.appendChild(oInput) | ||||||
|  |       oInput.select() | ||||||
|  |       document.execCommand('Copy') | ||||||
|  |       this.$u.toast('已复制') | ||||||
|  |       oInput.remove() | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     publish() { | ||||||
|  |       if (this.info.status === '1') { | ||||||
|  |         return this.$u.toast('该表单已发布') | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       this.linkTo(`/pages/askForm/formSetting?id=${this.info.id}&type=edit`) | ||||||
|  |       this.isShow = false | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     toEdit() { | ||||||
|  |       if (this.info.dataCount !== 0) { | ||||||
|  |         return this.$u.toast('该表单已有数据,无法编辑!') | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       uni.navigateTo({ | ||||||
|  |         url: `/pages/askForm/addForm?id=${this.id}` | ||||||
|  |       }) | ||||||
|  |  | ||||||
|  |       this.isShow = false | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     share(id) { | ||||||
|  |       this.$http.post(`/app/appquestionnairetemplate/share?id=${id}`).then(res => { | ||||||
|  |         if (res.code === 0) { | ||||||
|  |           this.$confirm('调查表单共享成功,其他成员可在新建项目时直接使用!', '', { | ||||||
|  |             showCancel: false | ||||||
|  |           }) | ||||||
|  |           this.isShow = false | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     remove(id) { | ||||||
|  |       if (this.info.dataCount !== 0) { | ||||||
|  |         return this.$u.toast('该表单已有数据,无法删除!') | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       this.$confirm('确定删除该数据?').then(() => { | ||||||
|  |         this.$http.post(`/app/appquestionnairetemplate/delete?id=${id}`).then(res => { | ||||||
|  |           if (res.code == 0) { | ||||||
|  |             this.$u.toast('删除成功') | ||||||
|  |             this.isShow = false | ||||||
|  |             this.search.current = 1 | ||||||
|  |             this.isMore = false | ||||||
|  |  | ||||||
|  |             this.getList() | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       }).catch(() => { | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     reload() { | ||||||
|  |       this.isMore = false | ||||||
|  |       this.search.current = 1 | ||||||
|  |  | ||||||
|  |       this.getList() | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     getList() { | ||||||
|  |       if (this.isMore) return | ||||||
|  |  | ||||||
|  |       this.$http.post(`/app/appquestionnairetemplate/list`, null, { | ||||||
|  |         params: { | ||||||
|  |           ...this.search, | ||||||
|  |           size: 10 | ||||||
|  |         } | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res.code == 0) { | ||||||
|  |           if (this.search.current > 1) { | ||||||
|  |             this.list = [...this.list, ...res.data.records] | ||||||
|  |           } else { | ||||||
|  |             this.list = res.data.records | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           uni.hideLoading() | ||||||
|  |  | ||||||
|  |           if (res.data.records.length < 10) { | ||||||
|  |             this.isMore = true | ||||||
|  |  | ||||||
|  |             return false | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           this.search.current = this.search.current + 1 | ||||||
|  |         } else { | ||||||
|  |           uni.hideLoading() | ||||||
|  |         } | ||||||
|  |       }).catch(() => { | ||||||
|  |         uni.hideLoading() | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .form { | ||||||
|  |   ::v-deep .u-search { | ||||||
|  |     margin-bottom: 0 !important; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .popup { | ||||||
|  |     background: #F7F7F7; | ||||||
|  |  | ||||||
|  |     & > h2 { | ||||||
|  |       height: 72px; | ||||||
|  |       line-height: 72px; | ||||||
|  |       padding: 0 20px; | ||||||
|  |       color: #999999; | ||||||
|  |       font-size: 22px; | ||||||
|  |       text-align: center; | ||||||
|  |       border-bottom: 2px solid #D7D8DA; | ||||||
|  |       overflow: hidden; | ||||||
|  |       text-overflow: ellipsis; | ||||||
|  |       white-space: nowrap; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .popup-btn { | ||||||
|  |       height: 96px; | ||||||
|  |       line-height: 96px; | ||||||
|  |       text-align: center; | ||||||
|  |       color: #333333; | ||||||
|  |       font-size: 30px; | ||||||
|  |       background: #fff; | ||||||
|  |  | ||||||
|  |       &:active { | ||||||
|  |         background: #eee; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .operate-list { | ||||||
|  |       display: flex; | ||||||
|  |       flex-wrap: wrap; | ||||||
|  |       text-align: center; | ||||||
|  |       padding-bottom: 26px; | ||||||
|  |  | ||||||
|  |       .operate-item { | ||||||
|  |         width: 25%; | ||||||
|  |         font-size: 0; | ||||||
|  |         margin-top: 28px; | ||||||
|  |  | ||||||
|  |         &:active { | ||||||
|  |           opacity: 0.7; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         h3 { | ||||||
|  |           margin-top: 20px; | ||||||
|  |           color: #666666; | ||||||
|  |           font-size: 26px; | ||||||
|  |           font-weight: normal; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       image { | ||||||
|  |         width: 100px; | ||||||
|  |         height: 100px; | ||||||
|  |         border-radius: 16px; | ||||||
|  |         background: #fff; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   div { | ||||||
|  |     box-sizing: border-box; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .form-item { | ||||||
|  |     margin: 24px 25px 0; | ||||||
|  |     padding: 32px; | ||||||
|  |     background: #FFFFFF; | ||||||
|  |     border-radius: 16px; | ||||||
|  |  | ||||||
|  |     .form-item__bottom { | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |       margin-top: 28px; | ||||||
|  |       color: #999999; | ||||||
|  |  | ||||||
|  |       i { | ||||||
|  |         width: 12px; | ||||||
|  |         height: 12px; | ||||||
|  |         margin-right: 6px; | ||||||
|  |         border-radius: 50%; | ||||||
|  |         background: #999999; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         font-size: 26px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       &.form-item__bottom--active i { | ||||||
|  |         background: #3CB300; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .form-item__top { | ||||||
|  |       display: flex; | ||||||
|  |       justify-content: space-between; | ||||||
|  |       align-items: center; | ||||||
|  |  | ||||||
|  |       .form-item__right { | ||||||
|  |         text-align: center; | ||||||
|  |  | ||||||
|  |         h2 { | ||||||
|  |           line-height: 40px; | ||||||
|  |           margin-bottom: 16px; | ||||||
|  |           font-size: 32px; | ||||||
|  |           font-weight: 600; | ||||||
|  |           color: #1EA0FA; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         span { | ||||||
|  |           color: #999999; | ||||||
|  |           font-size: 22px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .form-item__left { | ||||||
|  |         flex: 1; | ||||||
|  |         max-width: 80%; | ||||||
|  |         position: relative; | ||||||
|  |  | ||||||
|  |         &::after { | ||||||
|  |           position: absolute; | ||||||
|  |           right: -15px; | ||||||
|  |           top: 50%; | ||||||
|  |           width: 2px; | ||||||
|  |           height: 96px; | ||||||
|  |           background: #F5F5F5; | ||||||
|  |           content: ''; | ||||||
|  |           transform: translateY(-50%); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         h2 { | ||||||
|  |           line-height: 44px; | ||||||
|  |           margin-bottom: 16px; | ||||||
|  |           color: #333; | ||||||
|  |           font-size: 32px; | ||||||
|  |           font-weight: 700; | ||||||
|  |           overflow: hidden; | ||||||
|  |           text-overflow: ellipsis; | ||||||
|  |           white-space: nowrap; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .form-item__left--info { | ||||||
|  |           display: flex; | ||||||
|  |           align-items: center; | ||||||
|  |           flex-wrap: wrap; | ||||||
|  |           color: #999; | ||||||
|  |           font-size: 20px; | ||||||
|  |  | ||||||
|  |           span { | ||||||
|  |             position: relative; | ||||||
|  |             margin-right: 24px; | ||||||
|  |  | ||||||
|  |             &::after { | ||||||
|  |               position: absolute; | ||||||
|  |               right: -12px; | ||||||
|  |               top: 50%; | ||||||
|  |               width: 2px; | ||||||
|  |               height: 20px; | ||||||
|  |               background: #D1D2D5; | ||||||
|  |               content: ''; | ||||||
|  |               transform: translateY(-50%); | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             &:last-child { | ||||||
|  |               margin-right: 0; | ||||||
|  |  | ||||||
|  |               &::after { | ||||||
|  |                 display: none; | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .type-0 { | ||||||
|  |     background: #2266FF !important; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .type-1 { | ||||||
|  |     background: rgba(34, 170, 153, 1) !important; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .type-2 { | ||||||
|  |     background: rgba(248, 180, 37, 1) !important; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .type-3 { | ||||||
|  |     background: rgba(102, 119, 187, 1) !important; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .type-4 { | ||||||
|  |     background: rgba(236, 68, 97, 1) !important; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										163
									
								
								src/pages/askForm/config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,163 @@ | |||||||
|  | export const components = [ | ||||||
|  | 	{ | ||||||
|  | 		type: 'radio', | ||||||
|  | 		label: '单选', | ||||||
|  | 		fixedLabel: '单选', | ||||||
|  | 		value: '', | ||||||
|  | 		points: '', | ||||||
|  | 		icon: 'iconradio', | ||||||
|  | 		isShowPoints: false, | ||||||
|  | 		required: true, | ||||||
|  | 		hasAnswer: false, | ||||||
|  | 		answer: '', | ||||||
|  | 		pointType: '0', | ||||||
|  | 		pointDict: [ | ||||||
|  | 			{ | ||||||
|  | 				dictName: '此题有唯一答案和分值', | ||||||
|  | 				dictValue: '0' | ||||||
|  | 			}, | ||||||
|  | 			{ | ||||||
|  | 				dictName: '每个选项都有对应分值', | ||||||
|  | 				dictValue: '1' | ||||||
|  | 			} | ||||||
|  | 		], | ||||||
|  | 		options: [ | ||||||
|  | 			{ | ||||||
|  | 				label: '选项1', | ||||||
|  | 				value: '', | ||||||
|  | 				point: '', | ||||||
|  | 				img: [] | ||||||
|  | 			}, | ||||||
|  | 			{ | ||||||
|  | 				label: '选项2', | ||||||
|  | 				value: '', | ||||||
|  | 				point: '', | ||||||
|  | 				img: [] | ||||||
|  | 			} | ||||||
|  | 		], | ||||||
|  | 		title: '' | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		type: 'checkbox', | ||||||
|  | 		label: '多选', | ||||||
|  | 		fixedLabel: '多选', | ||||||
|  | 		points: '', | ||||||
|  | 		icon: 'iconcheck_box', | ||||||
|  | 		isShowPoints: false, | ||||||
|  | 		required: true, | ||||||
|  | 		hasAnswer: false, | ||||||
|  | 		answer: [], | ||||||
|  | 		value: [], | ||||||
|  | 		pointType: '0', | ||||||
|  | 		pointDict: [ | ||||||
|  | 			{ | ||||||
|  | 				dictName: '此题有唯一答案和分值', | ||||||
|  | 				dictValue: '0' | ||||||
|  | 			}, | ||||||
|  | 			{ | ||||||
|  | 				dictName: '每个选项都有对应分值', | ||||||
|  | 				dictValue: '1' | ||||||
|  | 			}, | ||||||
|  | 			{ | ||||||
|  | 				dictName: '答对几项得几分,答错不得分', | ||||||
|  | 				dictValue: '2' | ||||||
|  | 			} | ||||||
|  | 		], | ||||||
|  | 		options: [ | ||||||
|  | 			{ | ||||||
|  | 				label: '选项1', | ||||||
|  | 				value: '', | ||||||
|  | 				point: '', | ||||||
|  | 				img: [], | ||||||
|  | 				checked: false | ||||||
|  | 			}, | ||||||
|  | 			{ | ||||||
|  | 				label: '选项2', | ||||||
|  | 				point: '', | ||||||
|  | 				value: '', | ||||||
|  | 				img: [], | ||||||
|  | 				checked: false | ||||||
|  | 			} | ||||||
|  | 		], | ||||||
|  | 		title: '' | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		type: 'select', | ||||||
|  | 		label: '单下拉框', | ||||||
|  | 		fixedLabel: '单下拉框', | ||||||
|  | 		value: '', | ||||||
|  | 		points: '', | ||||||
|  | 		icon: 'iconSelect', | ||||||
|  | 		isShowPoints: false, | ||||||
|  | 		required: true, | ||||||
|  | 		hasAnswer: false, | ||||||
|  | 		answer: '', | ||||||
|  | 		pointType: '0', | ||||||
|  | 		placeholder: '请选择', | ||||||
|  | 		pointDict: [ | ||||||
|  | 			{ | ||||||
|  | 				dictName: '此题有唯一答案和分值', | ||||||
|  | 				dictValue: '0' | ||||||
|  | 			}, | ||||||
|  | 			{ | ||||||
|  | 				dictName: '每个选项都有对应分值', | ||||||
|  | 				dictValue: '1' | ||||||
|  | 			} | ||||||
|  | 		], | ||||||
|  | 		options: [ | ||||||
|  | 			{ | ||||||
|  | 				label: '选项1', | ||||||
|  | 				value: '', | ||||||
|  | 				point: '', | ||||||
|  | 				img: [] | ||||||
|  | 			}, | ||||||
|  | 			{ | ||||||
|  | 				label: '选项2', | ||||||
|  | 				value: '', | ||||||
|  | 				point: '', | ||||||
|  | 				img: [] | ||||||
|  | 			} | ||||||
|  | 		], | ||||||
|  | 		title: '' | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		type: 'input', | ||||||
|  | 		label: '单行填空', | ||||||
|  | 		fixedLabel: '单行填空', | ||||||
|  | 		value: '', | ||||||
|  | 		pointType: '0', | ||||||
|  | 		icon: 'icontext_box', | ||||||
|  | 		isShowPoints: false, | ||||||
|  | 		points: '', | ||||||
|  | 		required: true, | ||||||
|  | 		hasAnswer: false, | ||||||
|  | 		placeholder: '请输入...', | ||||||
|  | 		answer: '' | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		type: 'textarea', | ||||||
|  | 		label: '多行填空', | ||||||
|  | 		fixedLabel: '多行填空', | ||||||
|  | 		pointType: '0', | ||||||
|  | 		icon: 'icontext_area', | ||||||
|  | 		points: '', | ||||||
|  | 		isShowPoints: false, | ||||||
|  | 		required: true, | ||||||
|  | 		hasAnswer: false, | ||||||
|  | 		answer: '', | ||||||
|  | 		placeholder: '请输入...', | ||||||
|  | 		value: '' | ||||||
|  | 	}, | ||||||
|  | 	{ | ||||||
|  | 		type: 'upload', | ||||||
|  | 		label: '上传图片', | ||||||
|  | 		fixedLabel: '上传图片', | ||||||
|  | 		value: '', | ||||||
|  | 		icon: 'iconpic', | ||||||
|  | 		isShowPoints: false, | ||||||
|  | 		points: '', | ||||||
|  | 		required: true, | ||||||
|  | 		hasAnswer: false, | ||||||
|  | 		answer: '' | ||||||
|  | 	} | ||||||
|  | ]; | ||||||
							
								
								
									
										535
									
								
								src/pages/askForm/filedConfig.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,535 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="form-config"> | ||||||
|  |     <div class="config-group"> | ||||||
|  |       <div class="config-item"> | ||||||
|  |         <u-input class="form-maintitle" :maxlength="200" v-model="config.label" :placeholder="`请输入${config.fixedLabel}标题 ${config.required ? '(必填)' : ''}`"  placeholder-style="color: #999999; font-weight: 600" /> | ||||||
|  |       </div> | ||||||
|  |       <div class="config-item__select--wrapper" v-if="['radio', 'select', 'checkbox'].includes(config.type)"> | ||||||
|  |         <div class="config-item__select" v-for="(item, index) in config.options" :key="index"> | ||||||
|  |           <image class="config-icon" :src="`${$cdn}askform/del.png`" @click="removeOptions(index)" /> | ||||||
|  |           <div class="config-item__upload" v-if="config.type !== 'select'" @click="upload(index)"> | ||||||
|  |             <u-icon color="#8c9dc3" name="plus" v-if="!item.img.length"></u-icon> | ||||||
|  |             <image v-else :src="item.img[0].url" /> | ||||||
|  |           </div> | ||||||
|  |           <div class="textarea"> | ||||||
|  |            <textarea type="textarea" placeholder-style="color: #CDCDCF" :auto-height="true" v-model="item.label" :maxlength="100" placeholder="请输入选项" /> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="config-item__select config-item__select--add" @click="addOptions"> | ||||||
|  |           <image class="config-icon" :src="`${$cdn}askform/zj.png`" /> | ||||||
|  |           <span>添加选项</span> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="config-group"> | ||||||
|  |       <div class="config-item" v-if="!['radio', 'upload', 'checkbox', 'select'].includes(config.type)"> | ||||||
|  |         <div class="config-item__left"> | ||||||
|  |           <span>说明文字</span> | ||||||
|  |         </div> | ||||||
|  |         <div class="config-item__right"> | ||||||
|  |           <u-input v-model="config.placeholder" placeholder="请输入说明文字" input-align="right" /> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="config-item"> | ||||||
|  |         <div class="config-item__left"> | ||||||
|  |           <span>是否必填</span> | ||||||
|  |         </div> | ||||||
|  |         <div class="config-item__right"> | ||||||
|  |           <u-switch v-model="config.required" active-value="1" inactive-value="0" :size="40" active-color="#1088F9"></u-switch> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="config-item" v-if="!['upload'].includes(config.type)"> | ||||||
|  |         <div class="config-item__left"> | ||||||
|  |           <span>答案与分值</span> | ||||||
|  |         </div> | ||||||
|  |         <div class="config-item__right"> | ||||||
|  |           <u-switch v-model="config.isShowPoints" :size="40" active-color="#1088F9"></u-switch> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="config-item" v-if="['input', 'textarea'].includes(config.type) && config.isShowPoints"> | ||||||
|  |         <div class="config-item__left"> | ||||||
|  |           <span>正确答案</span> | ||||||
|  |         </div> | ||||||
|  |         <div class="config-item__right"> | ||||||
|  |           <u-input v-model="config.answer" placeholder="请输入正确答案" input-align="right" /> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="config-item" v-if="['radio', 'select'].includes(config.type) && config.isShowPoints && config.pointType === '0'"> | ||||||
|  |         <div class="config-item__left"> | ||||||
|  |           <span>正确答案</span> | ||||||
|  |         </div> | ||||||
|  |         <div class="config-item__right config-item__text" @click="isShowAnswer = true"> | ||||||
|  |           <span>{{ config.answer ? config.answer : '请选择正确答案' }}</span> | ||||||
|  |           <u-icon name="arrow-down-fill" color="#c0c4cc" size="24"></u-icon> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="config-item config-item__checkbox" v-if="config.isShowPoints && ['radio', 'select', 'checkbox'].includes(config.type)"> | ||||||
|  |         <div class="config-item__left"> | ||||||
|  |           <span>计分方式</span> | ||||||
|  |         </div> | ||||||
|  |         <div class="config-item__right" @click="isShowType = true"> | ||||||
|  |           <span>{{ pointTypeName ? pointTypeName : '请选择' }}</span> | ||||||
|  |           <u-icon name="arrow-right" color="#E1E2E3" /> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="config-item config-item__answer config-item__checkbox" v-if="['checkbox'].includes(config.type) && config.isShowPoints && config.pointType === '0'"> | ||||||
|  |         <div class="config-item__left"> | ||||||
|  |           <span>正确答案</span> | ||||||
|  |         </div> | ||||||
|  |         <div class="config-item__right"> | ||||||
|  |           <u-checkbox-group wrap @change="onCheckboxChange"> | ||||||
|  |             <u-checkbox v-model="field.checked" :name="field.label"  v-if="field.label" v-for="(field, i) in config.options" :key="i"> | ||||||
|  |               <span>{{ field.label }}</span> | ||||||
|  |             </u-checkbox> | ||||||
|  |           </u-checkbox-group> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="config-item" v-if="config.isShowPoints && config.pointType === '0'"> | ||||||
|  |         <div class="config-item__left"> | ||||||
|  |           <span>本题分值</span> | ||||||
|  |         </div> | ||||||
|  |         <div class="config-item__right"> | ||||||
|  |           <u-input v-model="config.points" type="number" placeholder="请输入本题分值" input-align="right" /> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div v-if="config.isShowPoints && config.pointType === '1'"> | ||||||
|  |         <div class="config-item" v-for="(item, index) in config.options" :key="index"> | ||||||
|  |           <div class="config-item__left"> | ||||||
|  |             <span>{{ item.label }}</span> | ||||||
|  |           </div> | ||||||
|  |           <div class="config-item__right"> | ||||||
|  |             <u-input v-model="item.point" placeholder="请输入分值" input-align="right" /> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="config-item config-item__point" v-if="config.isShowPoints && config.pointType === '2'"> | ||||||
|  |         <u-checkbox-group wrap @change="onCheckboxChange"> | ||||||
|  |           <u-checkbox v-model="field.checked" :name="field.label" v-if="field.label" v-for="(field, i) in config.options" :key="i"> | ||||||
|  |             <span>{{ field.label }}</span> | ||||||
|  |             <u-input v-model="field.point" type="number" placeholder="请输入分值" input-align="right" /> | ||||||
|  |           </u-checkbox> | ||||||
|  |         </u-checkbox-group> | ||||||
|  |       </div> | ||||||
|  |       <div class="config-item" v-if="config.isShowPoints && config.pointType === '2'"> | ||||||
|  |         <div class="config-item__left" style="padding-left: 20px"> | ||||||
|  |           <span>全部答对</span> | ||||||
|  |         </div> | ||||||
|  |         <div class="config-item__right"> | ||||||
|  |           <u-input v-model="config.points" type="number" placeholder="请输入全部答对分值" input-align="right" /> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <u-select :list="config.options" :default-value="defaultAnswer" value-name="value" label-name="label" v-model="isShowAnswer" @confirm="answerChange"></u-select> | ||||||
|  |     <u-select :list="config.pointDict" :default-value="defaultType" value-name="dictValue" label-name="dictName" v-model="isShowType" @confirm="pointTypeChange"></u-select> | ||||||
|  |     <div class="add-form__footer"> | ||||||
|  |       <div @click="back"> | ||||||
|  |         <span>取消</span> | ||||||
|  |       </div> | ||||||
|  |       <div @click="confirm">确定</div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import { components } from './config' | ||||||
|  | export default { | ||||||
|  |   data () { | ||||||
|  |     return { | ||||||
|  |       index: '', | ||||||
|  |       isShowType: false, | ||||||
|  |       isShowAnswer: false, | ||||||
|  |       config: { | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   onLoad (query) { | ||||||
|  |     if (query.type) { | ||||||
|  |       this.config = JSON.parse(JSON.stringify(components.filter(v => v.type === query.type)[0])) | ||||||
|  |     } else { | ||||||
|  |       this.config = JSON.parse(query.config) | ||||||
|  |       this.index = query.index | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   computed: { | ||||||
|  |     pointTypeName () { | ||||||
|  |       if (!this.config.pointDict) return '' | ||||||
|  |  | ||||||
|  |       return this.config.pointDict.filter(v => v.dictValue === this.config.pointType)[0].dictName | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     defaultType () { | ||||||
|  |       if (!this.config.pointType) return [0] | ||||||
|  |  | ||||||
|  |       return [Number(this.config.pointType)] | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     defaultAnswer () { | ||||||
|  |       if (!this.config.answer) return [0] | ||||||
|  |  | ||||||
|  |       let index = 0 | ||||||
|  |       if (this.config.answer) { | ||||||
|  |         this.config.options.forEach((v, i) => { | ||||||
|  |           if (v.label === this.config.answer) { | ||||||
|  |             index = i | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       return [index] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   methods: { | ||||||
|  |     answerChange (e) { | ||||||
|  |       this.config.answer = e[0].label | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     pointTypeChange (e) { | ||||||
|  |       console.log(e) | ||||||
|  |       this.config.pointType = e[0].value | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onCheckboxChange (e) { | ||||||
|  |       this.config.answer = e | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     upload (index) { | ||||||
|  |       let params = { | ||||||
|  |         count: 1, | ||||||
|  |         sizeType: ['compressed'], | ||||||
|  |         sourceType: ['album', 'camera'], | ||||||
|  |         success: (res) => { | ||||||
|  |           let count = this.fileList?.length + (res.tempFiles?.length || res.tempFile ? 1 : 0) | ||||||
|  |           if (count > 1) { | ||||||
|  |             return this.$u.toast(`不能超过1个`) | ||||||
|  |           } | ||||||
|  |           if (res.tempFiles) { | ||||||
|  |             res.tempFiles.map((item) => { | ||||||
|  |               this.uploadFile(item, index) | ||||||
|  |             }) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       uni.chooseImage(params) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     uploadFile (img, index) { | ||||||
|  |       uni.showLoading({title: '上传中'}) | ||||||
|  |       let formData = new FormData() | ||||||
|  |       formData.append('file', img) | ||||||
|  |       this.$http.post('/admin/file/add2', formData).then((res) => { | ||||||
|  |         uni.hideLoading() | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.$u.toast('上传成功!') | ||||||
|  |           this.$set(this.config.options[index], 'img', [res.data]) | ||||||
|  |         } | ||||||
|  |       }).catch(res => { | ||||||
|  |         this.$u.toast(res) | ||||||
|  |         uni.hideLoading() | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     removeOptions (index) { | ||||||
|  |       const len = this.config.options.length | ||||||
|  |       const label = this.config.options[index].label | ||||||
|  |       if (len === 2) { | ||||||
|  |         return this.$u.toast('选项不能少于2个') | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if (this.config.type === 'checkbox') { | ||||||
|  |         const answerIndex = this.config.answer.indexOf(label) | ||||||
|  |         if (answerIndex > -1) { | ||||||
|  |           this.config.answer.splice(answerIndex, 1) | ||||||
|  |         } | ||||||
|  |       } else { | ||||||
|  |         if (label === this.config.answer) { | ||||||
|  |           this.config.answer = '' | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       this.config.options.splice(index, 1) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     back () { | ||||||
|  |       uni.navigateBack({ | ||||||
|  |         delta: 1 | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     confirm () { | ||||||
|  |       uni.$emit('filedConfig', { | ||||||
|  |         config: this.config, | ||||||
|  |         index: this.index === '' ? '-1' : this.index | ||||||
|  |       }) | ||||||
|  |       uni.navigateBack({ | ||||||
|  |         delta: 1 | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     addOptions () { | ||||||
|  |       const len = this.config.options.length | ||||||
|  |       let label = `选项${len + 1}` | ||||||
|  |  | ||||||
|  |       const index= this.config.options.findIndex(v => label === v.label) | ||||||
|  |       if (index > -1) { | ||||||
|  |         label = `新选项${len + 1}` | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       this.config.options.push({ | ||||||
|  |         label: label, | ||||||
|  |         value: '', | ||||||
|  |         point: '', | ||||||
|  |         img: '', | ||||||
|  |         checked: false | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  |   .form-config { | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     padding-bottom: 130px; | ||||||
|  |  | ||||||
|  |     .form-maintitle { | ||||||
|  |       ::v-deep .uni-input-input { | ||||||
|  |         font-size: 36px; | ||||||
|  |         font-weight: 600; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .config-item__select--wrapper { | ||||||
|  |       .config-item__select { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |  | ||||||
|  |         ::v-deep .u-input__input { | ||||||
|  |           height: 100%; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .textarea { | ||||||
|  |           flex: 1; | ||||||
|  |           display: flex; | ||||||
|  |           align-items: center; | ||||||
|  |           min-height: 104px; | ||||||
|  |           padding: 16px 0; | ||||||
|  |           font-size: 28px; | ||||||
|  |           border-bottom: 1px solid #dfe8f8; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         textarea { | ||||||
|  |           width: 100%; | ||||||
|  |           font-size: 28px; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .config-icon { | ||||||
|  |           width: 36px; | ||||||
|  |           height: 36px; | ||||||
|  |           margin-right: 12px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .config-item__select--add { | ||||||
|  |         height: 120px; | ||||||
|  |  | ||||||
|  |         .config-icon { | ||||||
|  |           margin-right: 18px; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         span { | ||||||
|  |           color: #1D74F4; | ||||||
|  |           font-size: 30px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .config-group { | ||||||
|  |       margin-bottom: 32px; | ||||||
|  |       padding: 0 32px; | ||||||
|  |       background: #fff; | ||||||
|  |  | ||||||
|  |       .config-item__upload { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: center; | ||||||
|  |         width: 60px; | ||||||
|  |         height: 60px; | ||||||
|  |         margin-right: 20px; | ||||||
|  |         border: 1px solid rgb(208, 212, 220); | ||||||
|  |         background-color: #fbfdff; | ||||||
|  |  | ||||||
|  |         image { | ||||||
|  |           width: 100%; | ||||||
|  |           height: 100%; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .config-item { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: space-between; | ||||||
|  |         min-height: 100px; | ||||||
|  |         padding: 16px 0; | ||||||
|  |         border-bottom: 1px solid #dfe8f8; | ||||||
|  |  | ||||||
|  |         &:last-child { | ||||||
|  |           border: none; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         ::v-deep .u-radio__label, ::v-deep .u-checkbox__label { | ||||||
|  |           margin-right: 0; | ||||||
|  |           font-size: 28px; | ||||||
|  |  | ||||||
|  |           span { | ||||||
|  |             max-width: 400rpx; | ||||||
|  |             line-height: 1.2; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .config-item__left { | ||||||
|  |           max-width: 400px; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .config-item__right { | ||||||
|  |           flex: 1; | ||||||
|  |           text-align: right; | ||||||
|  |           padding-left: 30px; | ||||||
|  |  | ||||||
|  |           &.config-item__text { | ||||||
|  |             display: flex; | ||||||
|  |             align-items: center; | ||||||
|  |             justify-content: flex-end; | ||||||
|  |  | ||||||
|  |             span { | ||||||
|  |               max-width: 400px; | ||||||
|  |               margin-right: 10px; | ||||||
|  |               overflow: hidden; | ||||||
|  |               text-overflow: ellipsis; | ||||||
|  |               white-space: nowrap; | ||||||
|  |               word-break: keep-all; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           .text { | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         &.config-item__answer { | ||||||
|  |           display: block; | ||||||
|  |           padding: 20px 0; | ||||||
|  |  | ||||||
|  |           .config-item__left { | ||||||
|  |             margin-bottom: 32rpx; | ||||||
|  |             span { | ||||||
|  |               word-break: break-all; | ||||||
|  |               color: #333; | ||||||
|  |               font-size: 30px; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           .config-item__right { | ||||||
|  |             width: 100%; | ||||||
|  |             padding-left: 0; | ||||||
|  |             text-align: left; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       ::v-deep .u-checkbox { | ||||||
|  |         align-items: baseline; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .config-item__checkbox { | ||||||
|  |         height: auto; | ||||||
|  |         padding: 14px 0; | ||||||
|  |  | ||||||
|  |         ::v-deep .u-checkbox, ::v-deep .u-radio { | ||||||
|  |           // justify-content: flex-end; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       .config-item__point { | ||||||
|  |         height: auto; | ||||||
|  |         padding: 0; | ||||||
|  |  | ||||||
|  |         ::v-deep .u-checkbox { | ||||||
|  |           justify-content: inherit; | ||||||
|  |           min-height: 100px; | ||||||
|  |           padding: 14px 0; | ||||||
|  |           border-bottom: 1px solid #eee; | ||||||
|  |  | ||||||
|  |           &:last-child { | ||||||
|  |             border: none; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           .u-checkbox__label { | ||||||
|  |             display: flex; | ||||||
|  |             align-items: center; | ||||||
|  |             justify-content: space-between; | ||||||
|  |             flex: 1; | ||||||
|  |             margin-right: 0; | ||||||
|  |  | ||||||
|  |             .u-input { | ||||||
|  |               flex: 1; | ||||||
|  |               max-width: 400px; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     * { | ||||||
|  |       box-sizing: border-box; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .add-form__footer { | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |       position: fixed; | ||||||
|  |       left: 0; | ||||||
|  |       bottom: 0; | ||||||
|  |       z-index: 1; | ||||||
|  |       width: 100%; | ||||||
|  |       height: 112px; | ||||||
|  |       text-align: center; | ||||||
|  |  | ||||||
|  |       div { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: center; | ||||||
|  |         flex: 1; | ||||||
|  |         height: 100%; | ||||||
|  |         text-align: center; | ||||||
|  |         background: #fff; | ||||||
|  |  | ||||||
|  |         &:first-child:active { | ||||||
|  |           background: #eee; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         &:last-child { | ||||||
|  |           color: #fff; | ||||||
|  |           font-size: 36px; | ||||||
|  |           background: #3192F4; | ||||||
|  |  | ||||||
|  |           &:active { | ||||||
|  |             opacity: 0.8; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         span { | ||||||
|  |           flex: 1; | ||||||
|  |           height: 100%; | ||||||
|  |           line-height: 112px; | ||||||
|  |           color: #333333; | ||||||
|  |           font-size: 32px; | ||||||
|  |  | ||||||
|  |           &:active { | ||||||
|  |             background: #eee; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										405
									
								
								src/pages/askForm/formDetail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,405 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="formDetail"> | ||||||
|  |     <ai-result v-if="result.tips" v-bind="result"> | ||||||
|  |       <template v-if="isExam" #extra> | ||||||
|  |         <div flex class="scorePane"> | ||||||
|  |           <div>成绩</div> | ||||||
|  |           <div class="fill"><em v-html="score"/> 分</div> | ||||||
|  |         </div> | ||||||
|  |       </template> | ||||||
|  |     </ai-result> | ||||||
|  |     <template v-else-if="form.id"> | ||||||
|  |       <image v-if="form.headPicture" class="headPicture" :src="form.headPicture"/> | ||||||
|  |       <b class="title">{{ form.title || "标题" }}</b> | ||||||
|  |       <div class="tableExplain">{{ form.tableExplain }}</div> | ||||||
|  |       <u-form class="content" label-position="top"> | ||||||
|  |         <u-form-item class="item" v-for="(op,i) in fields" :key="i" :label="(i+1)+'.'+op.fieldName" | ||||||
|  |                      :required="op.fieldInfo.required==1"> | ||||||
|  |           <template v-if="op.fieldType=='input'"> | ||||||
|  |             <input v-model="op.fieldValue" :placeholder="op.fieldInfo.placeholder" :disabled="isResult"/> | ||||||
|  |           </template> | ||||||
|  |           <template v-else-if="op.fieldType=='textarea'"> | ||||||
|  |             <textarea v-model="op.fieldValue" :disabled="isResult" :placeholder="op.fieldInfo.placeholder"/> | ||||||
|  |           </template> | ||||||
|  |           <template v-else-if="op.fieldType=='upload'"> | ||||||
|  |             <ai-uploader @list="v=>op.fieldValue=v.map(e=>e.url)" :def="op.fieldValue" :disabled="isResult" | ||||||
|  |                          preview/> | ||||||
|  |           </template> | ||||||
|  |           <u-row v-else-if="op.fieldType=='radio'"> | ||||||
|  |             <radio-group @change="({detail})=>op.fieldValue=detail.value"> | ||||||
|  |               <div class="option" flex v-for="option in op.fieldInfo.options" :key="option.label"> | ||||||
|  |                 <radio :value="option.label" :disabled="isResult" :checked="op.fieldValue==option.label"/> | ||||||
|  |                 <ai-image v-if="option.img" :src="option.img" preview/> | ||||||
|  |                 <div class="label fill">{{ option.label }}</div> | ||||||
|  |               </div> | ||||||
|  |             </radio-group> | ||||||
|  |           </u-row> | ||||||
|  |           <u-row v-else-if="op.fieldType=='checkbox'"> | ||||||
|  |             <checkbox-group @change="({detail})=>op.fieldValue=detail.value"> | ||||||
|  |               <div class="option" flex v-for="option in op.fieldInfo.options" :key="option.label"> | ||||||
|  |                 <checkbox :value="option.label" :disabled="isResult" | ||||||
|  |                           :checked="option.checked"/> | ||||||
|  |                 <ai-image v-if="option.img" :src="option.img" preview/> | ||||||
|  |                 <div class="label fill">{{ option.label }}</div> | ||||||
|  |               </div> | ||||||
|  |             </checkbox-group> | ||||||
|  |           </u-row> | ||||||
|  |           <template v-else-if="op.fieldType=='select'"> | ||||||
|  |             <ai-select @data="v=>op.fieldValue=v.map(e=>e.value)" :list="op.fieldInfo.options" :disabled="isResult"> | ||||||
|  |               <div class="option" flex> | ||||||
|  |                 <div class="label fill" v-if="op.fieldValue">{{ op.fieldValue.toString() }}</div> | ||||||
|  |                 <i class="fill" v-else>请选择</i> | ||||||
|  |                 <u-icon name="arrow-right" color="#ddd"/> | ||||||
|  |               </div> | ||||||
|  |             </ai-select> | ||||||
|  |           </template> | ||||||
|  |         </u-form-item> | ||||||
|  |       </u-form> | ||||||
|  |       <div class="bottom" v-if="!(isPreview||isResult)"> | ||||||
|  |         <div class="bottomBtn" @tap="handleSubmit">提交</div> | ||||||
|  |       </div> | ||||||
|  |     </template> | ||||||
|  |     <ai-loading v-else tips="调查问卷加载中..."/> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  |  | ||||||
|  | import UForm from "../../uview/components/u-form/u-form"; | ||||||
|  | import UFormItem from "../../uview/components/u-form-item/u-form-item"; | ||||||
|  | import {mapActions, mapState} from "vuex"; | ||||||
|  | import UInput from "../../uview/components/u-input/u-input"; | ||||||
|  | import AiTextarea from "../../components/AiTextarea"; | ||||||
|  | import AiUploader from "../../components/AiUploader"; | ||||||
|  | import AiSelect from "../../components/AiSelect"; | ||||||
|  | import URadio from "../../uview/components/u-radio/u-radio"; | ||||||
|  | import AiLoading from "../../components/AiLoading"; | ||||||
|  | import AiResult from "../../components/AiResult"; | ||||||
|  | import AiImage from "../../components/AiImage"; | ||||||
|  | import AiBack from "../../components/AiBack"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "formDetail", | ||||||
|  |   components: { | ||||||
|  |     AiBack, | ||||||
|  |     AiImage, | ||||||
|  |     AiResult, | ||||||
|  |     AiLoading, | ||||||
|  |     URadio, | ||||||
|  |     AiSelect, | ||||||
|  |     AiUploader, | ||||||
|  |     AiTextarea, | ||||||
|  |     UInput, | ||||||
|  |     UFormItem, | ||||||
|  |     UForm | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['openUser', 'token']), | ||||||
|  |     isExam() { | ||||||
|  |       return this.form?.type == 1 | ||||||
|  |     }, | ||||||
|  |     isPreview() { | ||||||
|  |       return !!this.$route.query?.preview | ||||||
|  |     }, | ||||||
|  |     isResult() { | ||||||
|  |       return !!this.$route.query?.result | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       form: {}, | ||||||
|  |       fields: [], | ||||||
|  |       checkUser: false, | ||||||
|  |       result: {}, | ||||||
|  |       score: 0 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   watch: { | ||||||
|  |     form: { | ||||||
|  |       deep: true, | ||||||
|  |       handler(v) { | ||||||
|  |         this.fields = v?.fields?.map(e => { | ||||||
|  |           let fieldInfo = JSON.parse(e.fieldInfo) | ||||||
|  |           fieldInfo?.options?.map(op => { | ||||||
|  |             op.img = op?.img?.[0]?.url | ||||||
|  |             op.checked = !!e.fieldValue?.split(",")?.includes(op.label) | ||||||
|  |           }) | ||||||
|  |           if (e.fieldType == 'select') { | ||||||
|  |             fieldInfo.options = fieldInfo.options.map(e => ({...e, value: e.label, label: e.label})) | ||||||
|  |           } | ||||||
|  |           return {...e, fieldInfo} | ||||||
|  |         }) || [] | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     ...mapActions(['getUserInfo']), | ||||||
|  |     getForm() { | ||||||
|  |       let {id} = this.$route.query | ||||||
|  |       this.$http.post("/app/appquestionnairetemplate/queryDetailById", null, { | ||||||
|  |         params: {id} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.form = res.data | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     validateForm() { | ||||||
|  |       return !this.fields.some(e => { | ||||||
|  |         if (!!e?.fieldInfo?.required && !e.fieldValue?.toString()) { | ||||||
|  |           this.$u.toast(e.fieldName + "不能为空!") | ||||||
|  |           return true | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     handleSubmit() { | ||||||
|  |       if (this.validateForm()) { | ||||||
|  |         this.handleScore() | ||||||
|  |         let {avatar: avatarUrl, openId, name: nickName, type: userType, unionId, corpName} = this.openUser | ||||||
|  |         this.$http.post("/app/appquestionnairetemplate/commit", { | ||||||
|  |           fields: this.fields.map(e => ({ | ||||||
|  |             ...e, | ||||||
|  |             fieldInfo: JSON.stringify(e.fieldInfo), | ||||||
|  |             fieldValue: e.fieldValue?.toString() | ||||||
|  |           })), | ||||||
|  |           avatarUrl, openId, nickName, userType, unionId, corpName, | ||||||
|  |           totalScore: this.score, | ||||||
|  |           questionnaireTemplateId: this.$route.query.id | ||||||
|  |         }).then(res => { | ||||||
|  |           if (res?.code == 0) { | ||||||
|  |             this.result = { | ||||||
|  |               tips: "提交成功!感谢参与", | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     handleScore() { | ||||||
|  |       this.score = 0 | ||||||
|  |       this.isExam && this.fields.map(field => { | ||||||
|  |         let item = field?.fieldInfo || {} | ||||||
|  |         let current = 0 | ||||||
|  |         const calcScore = point => (current += (Number(point) || 0)) | ||||||
|  |         if (item?.pointType == 0) {//此题有唯一答案和分值 | ||||||
|  |           field.fieldValue?.toString() == item.answer?.toString() && calcScore(item?.points) | ||||||
|  |         } else if (item?.pointType == 1) {//每个选项都有对应分值 | ||||||
|  |           item?.options?.map(op => { | ||||||
|  |             if (typeof field.fieldValue == "object") { | ||||||
|  |               if (field.fieldValue?.includes(op.label)) { | ||||||
|  |                 calcScore(op.point) | ||||||
|  |               } | ||||||
|  |             } else { | ||||||
|  |               op.label == field.fieldValue && calcScore(op.point) | ||||||
|  |             } | ||||||
|  |           }) | ||||||
|  |         } else if (item?.pointType == 2) {//答对几项得几分,答错不得分 | ||||||
|  |           item?.options?.some(op => { | ||||||
|  |             if (typeof field.fieldValue == "object") { | ||||||
|  |               if (field.fieldValue?.includes(op.label)) { | ||||||
|  |                 if (item.answer?.includes(op.label)) calcScore(op.point) | ||||||
|  |                 else return current = 0 | ||||||
|  |               } | ||||||
|  |             } else { | ||||||
|  |               op.label == field.fieldValue && calcScore(op.point) | ||||||
|  |             } | ||||||
|  |           }) | ||||||
|  |         } | ||||||
|  |         this.score += current | ||||||
|  |         //打印每题打分 | ||||||
|  |         if (!!field.fieldValue) { | ||||||
|  |           const typeResult = (reply, answer) => { | ||||||
|  |             console.log("题目:%s,回答:%s,得分:%s,总分:%s \n 答案:%s", field.fieldName, | ||||||
|  |                 reply, current, this.score, answer) | ||||||
|  |           } | ||||||
|  |           typeResult(field.fieldValue?.toString(), item.answer?.toString()) | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     checkForm() { | ||||||
|  |       if (this.isPreview) { | ||||||
|  |         this.checkUser = true | ||||||
|  |         return Promise.resolve() | ||||||
|  |       } | ||||||
|  |       let {query: {id}, hash} = this.$route, | ||||||
|  |           {openId} = this.openUser | ||||||
|  |       if (hash != "#form") { | ||||||
|  |         this.result = { | ||||||
|  |           tips: "非法的调查问卷链接", | ||||||
|  |           status: "error" | ||||||
|  |         } | ||||||
|  |       } else if (openId) { | ||||||
|  |         return new Promise(resolve => { | ||||||
|  |           this.$http.post("/app/appquestionnairetemplate/commitCheck", null, { | ||||||
|  |             params: {id, openId} | ||||||
|  |           }).then(res => { | ||||||
|  |             if (res?.code == 0) { | ||||||
|  |               this.checkUser = true | ||||||
|  |               if (this.isResult && res?.data) { | ||||||
|  |                 this.form = res?.data | ||||||
|  |               } else resolve() | ||||||
|  |             } else this.result = { | ||||||
|  |               tips: "调查问卷加载失败", | ||||||
|  |               status: "error", | ||||||
|  |               btn: "重新加载", | ||||||
|  |               btnTap() { | ||||||
|  |                 location.reload() | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           }).catch(err => { | ||||||
|  |             this.result = { | ||||||
|  |               tips: err || "调查问卷加载失败", | ||||||
|  |             } | ||||||
|  |           }) | ||||||
|  |         }) | ||||||
|  |       } else { | ||||||
|  |         this.getUserInfo().then(() => { | ||||||
|  |           if (!!this.openUser?.openId) { | ||||||
|  |             this.checkForm()?.then(() => this.checkUser && this.getForm()) | ||||||
|  |           } else { | ||||||
|  |             this.result = { | ||||||
|  |               tips: "您的信息获取失败", | ||||||
|  |               status: "error", | ||||||
|  |               btn: "重新加载", | ||||||
|  |               btnTap() { | ||||||
|  |                 location.reload() | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.checkForm()?.then(() => this.checkUser && this.getForm()) | ||||||
|  |   }, | ||||||
|  |   mounted() { | ||||||
|  |     document.title = this.form.title || "调查问卷" | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .formDetail { | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   background: #fff; | ||||||
|  |  | ||||||
|  |   .headPicture { | ||||||
|  |     width: 100%; | ||||||
|  |     height: 320px; | ||||||
|  |  | ||||||
|  |     .img { | ||||||
|  |       width: 100%; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .title { | ||||||
|  |     width: 100%; | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: center; | ||||||
|  |     align-items: center; | ||||||
|  |     flex-wrap: wrap; | ||||||
|  |     padding: 32px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     font-size: 34px; | ||||||
|  |     font-weight: bold; | ||||||
|  |     color: #333; | ||||||
|  |     line-height: 48px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .bottom { | ||||||
|  |     position: fixed; | ||||||
|  |     bottom: 0; | ||||||
|  |     width: 100%; | ||||||
|  |     padding: 32px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     background: #fff; | ||||||
|  |     z-index: 99; | ||||||
|  |  | ||||||
|  |     .bottomBtn { | ||||||
|  |       width: 100%; | ||||||
|  |       line-height: 96px; | ||||||
|  |       background: #287DE1; | ||||||
|  |       color: #fff; | ||||||
|  |       text-align: center; | ||||||
|  |       height: 96px; | ||||||
|  |       font-size: 32px; | ||||||
|  |       font-weight: bold; | ||||||
|  |       border-radius: 8px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .tableExplain { | ||||||
|  |     font-size: 28px; | ||||||
|  |     font-weight: 400; | ||||||
|  |     color: #666; | ||||||
|  |     padding: 32px 24px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .u-form-item { | ||||||
|  |     .u-form-item--left { | ||||||
|  |       font-size: 30px; | ||||||
|  |       font-weight: bold; | ||||||
|  |       color: #333; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .u-form-item--right__content__slot > * { | ||||||
|  |       width: 100%; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .display { | ||||||
|  |       justify-content: space-between; | ||||||
|  |       min-height: 58px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .uni-radio-input, .uni-checkbox-input { | ||||||
|  |       height: 32px; | ||||||
|  |       width: 32px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .label { | ||||||
|  |       flex-shrink: 0; | ||||||
|  |  | ||||||
|  |       * + & { | ||||||
|  |         margin-left: 16px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .option { | ||||||
|  |       width: 100%; | ||||||
|  |       margin-right: 16px; | ||||||
|  |       margin-bottom: 16px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .content { | ||||||
|  |     padding: 64px 32px 200px; | ||||||
|  |     background: #fff; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .scorePane { | ||||||
|  |     width: calc(100% - 40px); | ||||||
|  |     padding: 0 32px; | ||||||
|  |     height: 124px; | ||||||
|  |     background: #E9F2FF; | ||||||
|  |     border-radius: 16px; | ||||||
|  |     font-size: 30px; | ||||||
|  |     font-weight: 500; | ||||||
|  |     color: #333333; | ||||||
|  |     margin-top: 48px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |  | ||||||
|  |     .fill { | ||||||
|  |       text-align: center; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     em { | ||||||
|  |       font-size: 48px; | ||||||
|  |       font-weight: bold; | ||||||
|  |       color: #2C72FE; | ||||||
|  |       font-style: normal; | ||||||
|  |       margin-right: 8px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										164
									
								
								src/pages/askForm/formList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,164 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="formList"> | ||||||
|  |     <ai-top-fixed> | ||||||
|  |       <u-search placeholder="请输入标题" :show-action="false" search-icon-color="#ccc" | ||||||
|  |                 v-model="search.title" @search="page.current=1,getList()"/> | ||||||
|  |  | ||||||
|  |     </ai-top-fixed> | ||||||
|  |     <div class="mainPane"> | ||||||
|  |       <div class="formBox column" flex v-for="op in list" :key="op.id"> | ||||||
|  |         <div flex> | ||||||
|  |           <div class="fill column" flex> | ||||||
|  |             <b class="title">{{ op.title }}</b> | ||||||
|  |             <div class="info wrap" flex> | ||||||
|  |               <span v-html="op.createUserName"/> | ||||||
|  |               <span v-html="op.createUnitName"/> | ||||||
|  |               <span v-html="op.createTime"/> | ||||||
|  |               <span v-html="$dict.getLabel('questionnaireType',op.type)"/> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |           <div class="split"/> | ||||||
|  |           <div flex class="column submitCount"> | ||||||
|  |             <b>{{ op.dataCount }}</b> | ||||||
|  |             <div>答卷数量</div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |         <div flex class="bottom"> | ||||||
|  |           <div class="dot" :style="{background:$dict.getColor('questionnaireStatus',op.status)}"/> | ||||||
|  |           <div>{{ $dict.getLabel("questionnaireStatus", op.status) }}</div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import AiTopFixed from "../../components/AiTopFixed"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "formList", | ||||||
|  |   components: {AiTopFixed}, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       page: {current: 1, size: 10, total: 0}, | ||||||
|  |       search: {title: ""}, | ||||||
|  |       list: [] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getList() { | ||||||
|  |       this.$http.post("/app/appquestionnairetemplate/list", null, { | ||||||
|  |         params: {...this.page, ...this.search} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           if (this.page.current > 1) { | ||||||
|  |             this.list = [...this.list, ...res.data.records] | ||||||
|  |           } else this.list = res.data.records | ||||||
|  |           this.page.total = res.data.total | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     reachBottom() { | ||||||
|  |       if (this.page.total > this.list.length) { | ||||||
|  |         this.page.current++ | ||||||
|  |         this.getList() | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.$dict.load("questionnaireStatus", 'questionnaireType') | ||||||
|  |     this.getList() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .formList { | ||||||
|  |   min-height: 100%; | ||||||
|  |   background: #F3F6F9; | ||||||
|  |  | ||||||
|  |   ::v-deep .mainPane { | ||||||
|  |     padding: 24px 24px 126px; | ||||||
|  |  | ||||||
|  |     .formBox { | ||||||
|  |       width: 100%; | ||||||
|  |       min-height: 220px; | ||||||
|  |       background: #FFFFFF; | ||||||
|  |       border-radius: 16px; | ||||||
|  |       padding: 24px; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       text-align: center; | ||||||
|  |       color: #999; | ||||||
|  |       font-size: 20px; | ||||||
|  |       margin-bottom: 24px; | ||||||
|  |  | ||||||
|  |       & > div { | ||||||
|  |         width: 100%; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       b { | ||||||
|  |         width: 100%; | ||||||
|  |         white-space: nowrap; | ||||||
|  |         overflow: hidden; | ||||||
|  |         text-overflow: ellipsis; | ||||||
|  |         font-size: 32px; | ||||||
|  |         color: #333; | ||||||
|  |         margin-bottom: 16px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .title { | ||||||
|  |         text-align: start; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .info { | ||||||
|  |         width: 100%; | ||||||
|  |  | ||||||
|  |         span { | ||||||
|  |           white-space: nowrap; | ||||||
|  |           padding: 0 16px; | ||||||
|  |           box-sizing: border-box; | ||||||
|  |           border-left: 1px solid #D1D2D5; | ||||||
|  |           margin-bottom: 4px; | ||||||
|  |  | ||||||
|  |           &:first-of-type { | ||||||
|  |             border-left: none; | ||||||
|  |             padding-left: 0; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .bottom { | ||||||
|  |         margin-top: 30px; | ||||||
|  |         font-size: 26px; | ||||||
|  |  | ||||||
|  |         .dot { | ||||||
|  |           width: 11px; | ||||||
|  |           height: 11px; | ||||||
|  |           background: #3CB300; | ||||||
|  |           border-radius: 50%; | ||||||
|  |           margin-right: 8px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .submitCount { | ||||||
|  |         width: 118px; | ||||||
|  |  | ||||||
|  |         b { | ||||||
|  |           color: #1EA0FA; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         & > div { | ||||||
|  |           font-size: 22px; | ||||||
|  |           white-space: nowrap; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .split { | ||||||
|  |         width: 2px; | ||||||
|  |         background: #f5f5f5; | ||||||
|  |         margin: 0 24px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										314
									
								
								src/pages/askForm/formSetting.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,314 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="form-setting"> | ||||||
|  |     <h2>表单设置</h2> | ||||||
|  |     <div class="form-setting__list"> | ||||||
|  |       <div class="setting-item"> | ||||||
|  |         <div class="setting-item__left"> | ||||||
|  |           <span>截止时间</span> | ||||||
|  |           <image :src="`${$cdn}askform/bz.png`" @click="tips = '表单截止后,用户打开表单会提示此表单已结束' , isShowModal = true" /> | ||||||
|  |         </div> | ||||||
|  |         <div class="setting-item__right"> | ||||||
|  |           <u-radio-group v-model="periodValidityType" active-color="#1088F9"> | ||||||
|  |             <u-radio name="0">永久有效</u-radio> | ||||||
|  |             <u-radio name="1">自定义时间</u-radio> | ||||||
|  |           </u-radio-group> | ||||||
|  |           <u-icon name="arrow-right" color="#E1E2E3" /> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="setting-item" v-if="periodValidityType === '1'" @click="isShowTime = true"> | ||||||
|  |         <div class="setting-item__left"> | ||||||
|  |           <span>截至时间</span> | ||||||
|  |         </div> | ||||||
|  |         <div class="setting-item__right"> | ||||||
|  |           <span>{{ periodValidityEndTime }}</span> | ||||||
|  |           <u-icon name="arrow-right" color="#E1E2E3" /> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="setting-item"> | ||||||
|  |         <div class="setting-item__left"> | ||||||
|  |           <span>匹配客户方式</span> | ||||||
|  |           <image :src="`${$cdn}askform/bz.png`" @click="tips = '将参与活动的微信客户和企业微信客户匹配' , isShowModal = true" /> | ||||||
|  |         </div> | ||||||
|  |         <div class="setting-item__right"> | ||||||
|  |           <span>客户微信ID匹配</span> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="setting-item"> | ||||||
|  |         <div class="setting-item__left"> | ||||||
|  |           <span>提交次数</span> | ||||||
|  |           <image :src="`${$cdn}askform/bz.png`" @click="tips = '此功能发布后不可修改' , isShowModal = true" /> | ||||||
|  |         </div> | ||||||
|  |         <div class="setting-item__right"> | ||||||
|  |           <u-radio-group v-model="commitType" active-color="#1088F9"> | ||||||
|  |             <u-radio name="0">不限次数</u-radio> | ||||||
|  |             <u-radio name="1">限提交一次</u-radio> | ||||||
|  |           </u-radio-group> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="setting-item"> | ||||||
|  |         <div class="setting-item__left"> | ||||||
|  |           <span>行为通知</span> | ||||||
|  |           <image :src="`${$cdn}askform/bz.png`" @click="tips = '当客户点击或者发布表单时,发送表单的员工将会受到消息提醒' , isShowModal = true" /> | ||||||
|  |         </div> | ||||||
|  |         <div class="setting-item__right"> | ||||||
|  |           <u-switch v-model="actionNotice" active-value="1" inactive-value="0" :size="40" active-color="#1088F9"></u-switch> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="setting-item"> | ||||||
|  |         <div class="setting-item__left"> | ||||||
|  |           <span>动态通知</span> | ||||||
|  |           <image :src="`${$cdn}askform/bz.png`" @click="tips = '当客户点击或者发布表单时,会将客户的打开行为记录在客户动态里' , isShowModal = true" /> | ||||||
|  |         </div> | ||||||
|  |         <div class="setting-item__right"> | ||||||
|  |           <u-switch v-model="dynamicNotice" active-value="1" inactive-value="0" :size="40" active-color="#1088F9"></u-switch> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="add-form__footer"> | ||||||
|  |       <div @click="back"> | ||||||
|  |         <span>取消</span> | ||||||
|  |       </div> | ||||||
|  |       <div @click="confirm">{{ type === 'edit' ? '发布' : '确定' }}</div> | ||||||
|  |     </div> | ||||||
|  |     <u-modal v-model="isShowModal" :content="tips"></u-modal> | ||||||
|  |     <u-picker mode="time" v-model="isShowTime" :show-time-tag="true" @confirm="onTimeChange" :params="params"></u-picker> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   data () { | ||||||
|  |     return { | ||||||
|  |       params: { | ||||||
|  |         year: true, | ||||||
|  |         month: true, | ||||||
|  |         day: true, | ||||||
|  |         hour: true, | ||||||
|  |         minute: true, | ||||||
|  |         second: true | ||||||
|  |       }, | ||||||
|  |       tips: '', | ||||||
|  |       isShowModal: false, | ||||||
|  |       actionNotice: true, | ||||||
|  |       dynamicNotice: true, | ||||||
|  |       commitType: '1', | ||||||
|  |       wechatId: '0', | ||||||
|  |       periodValidityEndTime: '', | ||||||
|  |       isShowTime: false, | ||||||
|  |       periodValidityType: '0', | ||||||
|  |       type: '', | ||||||
|  |       id: '' | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   onLoad (query) { | ||||||
|  |     if (query.id) { | ||||||
|  |       this.id = query.id | ||||||
|  |       this.getInfo(query.id) | ||||||
|  |       this.type = query.type | ||||||
|  |     } else if (query.formConfig && query.formConfig !== '{}') { | ||||||
|  |       const res = JSON.parse(query.formConfig) | ||||||
|  |       this.periodValidityType = res.periodValidityType | ||||||
|  |       this.commitType = res.commitType | ||||||
|  |       this.actionNotice = res.actionNotice === '1' | ||||||
|  |       this.dynamicNotice = res.dynamicNotice === '1' | ||||||
|  |  | ||||||
|  |       if (res.periodValidityType === '1') { | ||||||
|  |         this.periodValidityEndTime = res.periodValidityEndTime | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   methods: { | ||||||
|  |     onTimeChange (e) { | ||||||
|  |       this.periodValidityEndTime = `${e.year}-${e.month}-${e.day} ${e.hour}:${e.minute}:${e.second}` | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     back () { | ||||||
|  |       uni.navigateBack({ | ||||||
|  |         delta: 1 | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     getInfo (id) { | ||||||
|  |       this.$http.post(`/app/appquestionnairetemplate/queryDetailById?id=${id}`).then(res => { | ||||||
|  |         if (res.code == 0) { | ||||||
|  |           this.periodValidityType = res.data.periodValidityType | ||||||
|  |           this.commitType = res.data.commitType | ||||||
|  |           this.actionNotice = res.data.actionNotice === '1' | ||||||
|  |           this.dynamicNotice = res.data.dynamicNotice === '1' | ||||||
|  |  | ||||||
|  |           if (res.data.periodValidityType === '1') { | ||||||
|  |             this.periodValidityEndTime = res.data.periodValidityEndTime | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }).catch(msg => { | ||||||
|  |         this.$u.toast(msg) | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     publish () { | ||||||
|  |       this.$http.post(`/app/appquestionnairetemplate/release`, null, { | ||||||
|  |         params: { | ||||||
|  |           commitType: this.commitType, | ||||||
|  |           periodValidityType: this.periodValidityType, | ||||||
|  |           actionNotice: this.actionNotice ? '1' : '0', | ||||||
|  |           dynamicNotice: this.dynamicNotice ? '1' : '0', | ||||||
|  |           shareStatus: '0', | ||||||
|  |           wechatId: '0', | ||||||
|  |           id: this.id, | ||||||
|  |           periodValidityEndTime: this.periodValidityType === '1' ? this.periodValidityEndTime : '' | ||||||
|  |         } | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res.code == 0) { | ||||||
|  |           uni.$emit('reload') | ||||||
|  |           this.$u.toast('发布成功') | ||||||
|  |  | ||||||
|  |           this.back() | ||||||
|  |         } | ||||||
|  |       }).catch(e => { | ||||||
|  |         this.$u.toast(e) | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     confirm () { | ||||||
|  |       if (this.type === 'edit') { | ||||||
|  |         this.publish() | ||||||
|  |  | ||||||
|  |         return false | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       uni.$emit('setting', { | ||||||
|  |         periodValidityType: this.periodValidityType, | ||||||
|  |         commitType: this.commitType, | ||||||
|  |         actionNotice: this.actionNotice ? '1' : '0', | ||||||
|  |         dynamicNotice: this.dynamicNotice ? '1' : '0', | ||||||
|  |         periodValidityEndTime: this.periodValidityEndTime ? this.periodValidityEndTime : '' | ||||||
|  |       }) | ||||||
|  |  | ||||||
|  |       this.back() | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  |   .form-setting { | ||||||
|  |     padding: 0 20px; | ||||||
|  |  | ||||||
|  |     .add-form__footer { | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |       position: fixed; | ||||||
|  |       left: 0; | ||||||
|  |       bottom: 0; | ||||||
|  |       z-index: 1; | ||||||
|  |       width: 100%; | ||||||
|  |       height: 112px; | ||||||
|  |       text-align: center; | ||||||
|  |  | ||||||
|  |       div { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: center; | ||||||
|  |         flex: 1; | ||||||
|  |         height: 100%; | ||||||
|  |         text-align: center; | ||||||
|  |         background: #fff; | ||||||
|  |  | ||||||
|  |         &:first-child:active { | ||||||
|  |           background: #eee; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         &:last-child { | ||||||
|  |           color: #fff; | ||||||
|  |           font-size: 36px; | ||||||
|  |           background: #3192F4; | ||||||
|  |  | ||||||
|  |           &:active { | ||||||
|  |             opacity: 0.8; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         span { | ||||||
|  |           flex: 1; | ||||||
|  |           height: 100%; | ||||||
|  |           line-height: 112px; | ||||||
|  |           color: #333333; | ||||||
|  |           font-size: 32px; | ||||||
|  |  | ||||||
|  |           &:active { | ||||||
|  |             background: #eee; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     * { | ||||||
|  |       box-sizing: border-box; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     & > h2 { | ||||||
|  |       height: 80px; | ||||||
|  |       padding-top: 24px; | ||||||
|  |       font-size: 28px; | ||||||
|  |       color: #999999; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .form-setting__list { | ||||||
|  |       padding: 0 20px; | ||||||
|  |       background: #fff; | ||||||
|  |       border-radius: 8px; | ||||||
|  |  | ||||||
|  |       .setting-item { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: space-between; | ||||||
|  |         height: 104px; | ||||||
|  |         border-bottom: 1px solid #D8DDE6; | ||||||
|  |  | ||||||
|  |         .setting-item__right { | ||||||
|  |           color: #999; | ||||||
|  |           font-size: 28px; | ||||||
|  |  | ||||||
|  |           span { | ||||||
|  |             margin-right: 6px; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           ::v-deep .u-radio__label { | ||||||
|  |             color: #999; | ||||||
|  |             font-size: 28px; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           ::v-deep .u-radio { | ||||||
|  |             &:last-child { | ||||||
|  |               .u-radio__label { | ||||||
|  |                 margin-right: 6px; | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         &:last-child { | ||||||
|  |           border: none; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         & > div { | ||||||
|  |           display: flex; | ||||||
|  |           align-items: center; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .setting-item__left { | ||||||
|  |           color: #666666; | ||||||
|  |           font-size: 30px; | ||||||
|  |  | ||||||
|  |           image { | ||||||
|  |             width: 30px; | ||||||
|  |             height: 30px; | ||||||
|  |             margin-left: 16px; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										69
									
								
								src/pages/askForm/index.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,69 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="form"> | ||||||
|  |     <div class="form-content"> | ||||||
|  |       <add-list ref="addList" v-if="currIndex === 1"></add-list> | ||||||
|  |       <list ref="list" v-if="currIndex === 0"></list> | ||||||
|  |     </div> | ||||||
|  |     <ai-tabbar :active.sync="currIndex" :list="tabBar"/> | ||||||
|  |     <div class="form-footer"></div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import addList from './components/addList.vue' | ||||||
|  | import list from './components/list.vue' | ||||||
|  | import AiTabbar from '../../components/AiTabbar' | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: 'formIndex', | ||||||
|  |   label: '问卷表单', | ||||||
|  |  | ||||||
|  |   data () { | ||||||
|  |     return { | ||||||
|  |       currIndex: 0 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   components: { | ||||||
|  |     addList, | ||||||
|  |     AiTabbar, | ||||||
|  |     list | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   computed: { | ||||||
|  |     tabBar () { | ||||||
|  |       const link = icon => `${this.$cdn}askform/${icon}.png` | ||||||
|  |       return [ | ||||||
|  |         {text: "表单列表", iconPath: "bdlb1", selectedIconPath: "bdlb2" }, | ||||||
|  |         {text: "新建项目", iconPath: "xjxm1", selectedIconPath: "xjxm2" } | ||||||
|  |       ].map(e => ({ | ||||||
|  |         ...e, | ||||||
|  |         iconPath: link(e.iconPath), | ||||||
|  |         selectedIconPath: link(e.selectedIconPath) | ||||||
|  |       })) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   onLoad () { | ||||||
|  |     uni.$on('reload', () => { | ||||||
|  |       if (this.currIndex === 0) { | ||||||
|  |         this.$refs.list.reload() | ||||||
|  |       } else { | ||||||
|  |         this.$refs.addList.getList() | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   onReachBottom() { | ||||||
|  |     if (this.currIndex === 0) { | ||||||
|  |       this.$refs.list.getList() | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  |   .form { | ||||||
|  |     padding-bottom: 98px; | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										457
									
								
								src/pages/askForm/previewForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,457 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="add-form"> | ||||||
|  |     <div class="header-pic"> | ||||||
|  |       <image v-if="form.headPicture" :src="form.headPicture" /> | ||||||
|  |     </div> | ||||||
|  |     <div class="form-info"> | ||||||
|  |       <div class="form-info__wrapper"> | ||||||
|  |         <textarea class="title" :auto-height="true" disabled placeholder="请输入标题 (必填)" v-model="form.title"></textarea> | ||||||
|  |         <u-input class="content" disabled :clearable="false" type="textarea" v-model="form.tableExplain" placeholder="请输入表单描述 (选填)" :height="80" :auto-height="true" :maxlength="255"></u-input> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="components-list"> | ||||||
|  |       <div class="components-item" v-for="(item, index) in targetList" :key="index"> | ||||||
|  |         <div class="components-item__title"> | ||||||
|  |           <div class="components-item__title--left"> | ||||||
|  |             <em :style="{opacity: item.required ? 1 : 0}">*</em> | ||||||
|  |             <i>{{ index + 1 }}.</i> | ||||||
|  |             <h2>{{ item.label }}</h2> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="components-item__filed"> | ||||||
|  |           <template v-if="(item.type === 'radio')"> | ||||||
|  |             <u-radio-group v-model="item.value" wrap> | ||||||
|  |               <u-radio :name="field.label" v-for="(field, i) in item.options" :key="i"> | ||||||
|  |                 <image :src="field.img[0].url" v-if="field.img.length"/> | ||||||
|  |                 <span>{{ field.label }}</span> | ||||||
|  |               </u-radio> | ||||||
|  |             </u-radio-group> | ||||||
|  |           </template> | ||||||
|  |           <template v-if="(item.type === 'checkbox')"> | ||||||
|  |             <u-checkbox-group wrap> | ||||||
|  |               <u-checkbox :name="field.label" v-model="field.checked1" v-for="(field, i) in item.options" :key="i"> | ||||||
|  |                 <image :src="field.img[0].url" v-if="field.img.length"/> | ||||||
|  |                 <span>{{ field.label }}</span> | ||||||
|  |               </u-checkbox> | ||||||
|  |             </u-checkbox-group> | ||||||
|  |           </template> | ||||||
|  |           <template v-if="(item.type === 'select')"> | ||||||
|  |             <div class="components-item__select"> | ||||||
|  |               <span>{{ item.placeholder }}</span> | ||||||
|  |               <u-icon name="arrow-down" color="#DEDFDF" /> | ||||||
|  |             </div> | ||||||
|  |           </template> | ||||||
|  |           <template v-if="(item.type === 'upload')"> | ||||||
|  |             <div class="components-item__select components-item__textarea components-item__upload"> | ||||||
|  |               <image :src="`${$cdn}askform/upload.png`" /> | ||||||
|  |               <span>选择图片(2M以内)</span> | ||||||
|  |             </div> | ||||||
|  |           </template> | ||||||
|  |           <template v-if="(item.type === 'input')"> | ||||||
|  |             <div class="components-item__select"> | ||||||
|  |               <span>{{ item.placeholder }}</span> | ||||||
|  |             </div> | ||||||
|  |           </template> | ||||||
|  |           <template v-if="(item.type === 'textarea')"> | ||||||
|  |             <div class="components-item__select components-item__textarea"> | ||||||
|  |               <span>{{ item.placeholder }}</span> | ||||||
|  |             </div> | ||||||
|  |           </template> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <AiBack></AiBack> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  |   import AiBack from "@/components/AiBack"; | ||||||
|  |   export default { | ||||||
|  |     data () { | ||||||
|  |       return { | ||||||
|  |         form: { | ||||||
|  |           tableExplain: '详细描述', | ||||||
|  |           title: '问卷调查', | ||||||
|  |           isShowheadPicture: true, | ||||||
|  |           isShowTableExplain: true, | ||||||
|  |           isShowBtn: true, | ||||||
|  |           headPicture: '', | ||||||
|  |           commitType: '1', | ||||||
|  |           periodValidityType: '0', | ||||||
|  |           actionNotice: '1', | ||||||
|  |           dynamicNotice: '1', | ||||||
|  |           periodValidityEndTime: '', | ||||||
|  |           shareStatus: '0', | ||||||
|  |           count: 0, | ||||||
|  |           wechatId: '0', | ||||||
|  |           type: 0, | ||||||
|  |           buttonExplain: '提交', | ||||||
|  |           tips: true | ||||||
|  |         }, | ||||||
|  |         templateType: 0, | ||||||
|  |         targetList: [], | ||||||
|  |         isShow: false, | ||||||
|  |         type: 0, | ||||||
|  |         id: '', | ||||||
|  |         touchStart: 0 | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     onLoad (query) { | ||||||
|  |       this.form = JSON.parse(query.form) | ||||||
|  |       this.targetList = JSON.parse(query.targetList) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     components: { | ||||||
|  |       AiBack | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     methods: { | ||||||
|  |       getInfo (id) { | ||||||
|  |         uni.showLoading() | ||||||
|  |         this.$http.post(`/app/appquestionnairetemplate/queryDetailById?id=${id}`).then(res => { | ||||||
|  |           if (res.code == 0) { | ||||||
|  |             this.form = { | ||||||
|  |               ...res.data, | ||||||
|  |               headPicture: res.data.headPicture | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             this.type = res.data.type | ||||||
|  |  | ||||||
|  |             this.targetList = res.data.fields.map(item => { | ||||||
|  |               return JSON.parse(item.fieldInfo) | ||||||
|  |             }) | ||||||
|  |  | ||||||
|  |             this.pageShow = true | ||||||
|  |           } else { | ||||||
|  |             this.$u.toast(res.msg) | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           uni.hideLoading() | ||||||
|  |         }).catch(() => { | ||||||
|  |           uni.hideLoading() | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  |   .add-form { | ||||||
|  |     min-height: 100vh; | ||||||
|  |     padding-bottom: 60px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     background: #F3F6F9; | ||||||
|  |  | ||||||
|  |     * { | ||||||
|  |       box-sizing: border-box; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ::v-deep .u-drawer-bottom { | ||||||
|  |       background-color: transparent; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .components-list { | ||||||
|  |       padding: 0 20px; | ||||||
|  |  | ||||||
|  |       .components-item { | ||||||
|  |         margin-top: 24px; | ||||||
|  |         padding: 32px; | ||||||
|  |         box-shadow: 0 4px 8px 4px rgba(233, 233, 233, 0.39); | ||||||
|  |         border-radius: 8px; | ||||||
|  |         overflow: hidden; | ||||||
|  |         border: 1px solid #EEEFF0; | ||||||
|  |         background: #fff; | ||||||
|  |  | ||||||
|  |         ::v-deep .u-radio, ::v-deep .u-checkbox { | ||||||
|  |           position: relative; | ||||||
|  |           margin-bottom: 20px; | ||||||
|  |  | ||||||
|  |           &:last-child { | ||||||
|  |             margin-bottom: 0; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           .u-checkbox__icon-wrap, .u-radio__icon-wrap { | ||||||
|  |             position: absolute; | ||||||
|  |             top: 4px; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           .u-radio__label, .u-checkbox__label { | ||||||
|  |             display: flex; | ||||||
|  |             align-items: center; | ||||||
|  |             margin-right: 0; | ||||||
|  |             margin-left: 40px; | ||||||
|  |             line-height: 1.5; | ||||||
|  |             text-align: justify; | ||||||
|  |  | ||||||
|  |             image { | ||||||
|  |               width: 100px; | ||||||
|  |               height: 100px; | ||||||
|  |               margin: 0 10px; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         span { | ||||||
|  |           flex: 1; | ||||||
|  |           color: #666; | ||||||
|  |           font-size: 26px; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .components-item__select { | ||||||
|  |           display: flex; | ||||||
|  |           align-items: center; | ||||||
|  |           justify-content: space-between; | ||||||
|  |           width: 100%; | ||||||
|  |           height: 80px; | ||||||
|  |           margin-bottom: 8px; | ||||||
|  |           padding: 0 26px; | ||||||
|  |           border: 1px solid #DEDFDF; | ||||||
|  |  | ||||||
|  |           &.components-item__textarea { | ||||||
|  |             align-items: flex-start; | ||||||
|  |             height: 160px; | ||||||
|  |             padding-top: 20px; | ||||||
|  |  | ||||||
|  |             image { | ||||||
|  |               width: 46px; | ||||||
|  |               height: 34px; | ||||||
|  |               margin-right: 16px; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             span { | ||||||
|  |               color: #666; | ||||||
|  |               font-size: 26px; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           &.components-item__upload { | ||||||
|  |             justify-content: center; | ||||||
|  |             align-items: center; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .components-item__title { | ||||||
|  |           display: flex; | ||||||
|  |           justify-content: space-between; | ||||||
|  |           margin-bottom: 32px; | ||||||
|  |  | ||||||
|  |           em { | ||||||
|  |             margin-right: 4px; | ||||||
|  |             font-style: normal; | ||||||
|  |             color: rgb(226, 33, 32);; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           image { | ||||||
|  |             width: 32px; | ||||||
|  |             height: 32px; | ||||||
|  |             box-sizing: content-box; | ||||||
|  |             padding: 20px 0 20px 20px; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           div { | ||||||
|  |             display: flex; | ||||||
|  |             align-items: baseline; | ||||||
|  |             color: #333333; | ||||||
|  |             font-size: 32px; | ||||||
|  |  | ||||||
|  |             i { | ||||||
|  |               font-style: normal; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             h2 { | ||||||
|  |               font-weight: 600; | ||||||
|  |               font-size: 32px; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .add-popup { | ||||||
|  |       height: 440px; | ||||||
|  |       border-radius: 20px 20px 0 0; | ||||||
|  |       background: #fff; | ||||||
|  |  | ||||||
|  |       .add-popup__title { | ||||||
|  |         display: flex; | ||||||
|  |         position: relative; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: center; | ||||||
|  |         height: 96px; | ||||||
|  |         border-bottom: 1px solid #E4E5E6; | ||||||
|  |  | ||||||
|  |         h2 { | ||||||
|  |           color: #333333; | ||||||
|  |           font-size: 32px; | ||||||
|  |           font-weight: 600; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         image { | ||||||
|  |           position: absolute; | ||||||
|  |           right: 32px; | ||||||
|  |           top: 50%; | ||||||
|  |           width: 30px; | ||||||
|  |           height: 20px; | ||||||
|  |           transform: translateY(-50%); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .add-popup__list { | ||||||
|  |         display: flex; | ||||||
|  |         flex-wrap: wrap; | ||||||
|  |         padding: 0 34px; | ||||||
|  |  | ||||||
|  |         span { | ||||||
|  |           width: calc((100% - 64px) / 3); | ||||||
|  |           height: 78px; | ||||||
|  |           line-height: 78px; | ||||||
|  |           margin-top: 32px; | ||||||
|  |           margin-right: 32px; | ||||||
|  |           text-align: center; | ||||||
|  |           color: #333333; | ||||||
|  |           font-size: 28px; | ||||||
|  |           border-radius: 8px; | ||||||
|  |           border: 1px solid #E4E5E6; | ||||||
|  |  | ||||||
|  |           &:nth-of-type(3n) { | ||||||
|  |             margin-right: 0; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .add-form__footer { | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |       position: fixed; | ||||||
|  |       left: 0; | ||||||
|  |       bottom: 0; | ||||||
|  |       z-index: 1; | ||||||
|  |       width: 100%; | ||||||
|  |       height: 112px; | ||||||
|  |       text-align: center; | ||||||
|  |  | ||||||
|  |       div { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: center; | ||||||
|  |         flex: 1; | ||||||
|  |         height: 100%; | ||||||
|  |         text-align: center; | ||||||
|  |         background: #fff; | ||||||
|  |  | ||||||
|  |         &:last-child { | ||||||
|  |           color: #fff; | ||||||
|  |           font-size: 36px; | ||||||
|  |           background: #3192F4; | ||||||
|  |  | ||||||
|  |           &:active { | ||||||
|  |             opacity: 0.8; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         span { | ||||||
|  |           flex: 1; | ||||||
|  |           height: 100%; | ||||||
|  |           line-height: 112px; | ||||||
|  |           color: #333333; | ||||||
|  |           font-size: 32px; | ||||||
|  |  | ||||||
|  |           &:active { | ||||||
|  |             background: #eee; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .add-form__btn { | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |       justify-content: center; | ||||||
|  |       width: 214px; | ||||||
|  |       height: 66px; | ||||||
|  |       line-height: 66px; | ||||||
|  |       margin: 64px auto 0; | ||||||
|  |       background: #FFFFFF; | ||||||
|  |       border-radius: 34px; | ||||||
|  |  | ||||||
|  |       &:active { | ||||||
|  |         opacity: 0.8; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       image { | ||||||
|  |         width: 28px; | ||||||
|  |         height: 28px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         margin-left: 16px; | ||||||
|  |         color: #4392E6; | ||||||
|  |         font-size: 28px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     * { | ||||||
|  |       box-sizing: border-box; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .form-info { | ||||||
|  |       margin-top: 26px; | ||||||
|  |       padding: 0 20px; | ||||||
|  |  | ||||||
|  |       & > h2 { | ||||||
|  |         height: 76px; | ||||||
|  |         line-height: 76px; | ||||||
|  |         color: #999999; | ||||||
|  |         font-weight: normal; | ||||||
|  |         font-size: 28px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .form-info__wrapper { | ||||||
|  |         padding: 0 18px; | ||||||
|  |         background: #fff; | ||||||
|  |  | ||||||
|  |         .title { | ||||||
|  |           width: 100%; | ||||||
|  |           padding: 22px 0; | ||||||
|  |           font-size: 36px; | ||||||
|  |           border-bottom: 1px solid #F1F2F3; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .content { | ||||||
|  |           padding: 30px 0!important; | ||||||
|  |           font-size: 28px; | ||||||
|  |  | ||||||
|  |           ::v-deep textarea { | ||||||
|  |             color: #333; | ||||||
|  |             font-size: 28px!important; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .header-pic { | ||||||
|  |       position: relative; | ||||||
|  |       font-size: 0; | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         position: absolute; | ||||||
|  |         bottom: 16px; | ||||||
|  |         right: 16px; | ||||||
|  |         z-index: 1; | ||||||
|  |         width: 148px; | ||||||
|  |         height: 56px; | ||||||
|  |         line-height: 56px; | ||||||
|  |         text-align: center; | ||||||
|  |         color: #fff; | ||||||
|  |         font-size: 26px; | ||||||
|  |         background: rgba(0, 0, 0, 0.16); | ||||||
|  |         border-radius: 28px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       image { | ||||||
|  |         width: 100%; | ||||||
|  |         height: 320px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										501
									
								
								src/pages/bigHorn/addPlay.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,501 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="addPlay"> | ||||||
|  |     <div class="content"> | ||||||
|  |       <div class="item"> | ||||||
|  |         <div class="label">播发内容</div> | ||||||
|  |         <div class="value" @click="linkTo('/pages/resourcesManage/resourcesManage?isChoose=1')"> | ||||||
|  |           <span :class="formData.mediaName == '请选择' ? 'color-999' : ''">{{formData.mediaName}}</span> | ||||||
|  |           <img src="./img/right-icon.png" alt=""> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="item"> | ||||||
|  |         <div class="label">播放设备</div> | ||||||
|  |         <div class="value" @click="selectClick('showEquipment', equipmentList)"> | ||||||
|  |           <span :class="formData.serialName == '请选择' ? 'color-999' : ''">{{formData.serialName}}</span> | ||||||
|  |           <img src="./img/right-icon.png" alt=""> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="item"> | ||||||
|  |         <div class="label">播发级别</div> | ||||||
|  |         <div class="value" @click="selectClick('showMessageLevel', messageLevelList)"> | ||||||
|  |           <span :class="formData.messageLevelName == '请选择' ? 'color-999' : ''">{{formData.messageLevelName}}</span> | ||||||
|  |           <img src="./img/right-icon.png" alt=""> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="radio-content"> | ||||||
|  |       <div class="title">播放方式</div> | ||||||
|  |       <div class="item mar-r50" :class="formData.taskType == 0 ? 'active' : ''"  @click="formData.taskType = 0">立即播放<img src="./img/bigHorn-xz.png" alt=""></div> | ||||||
|  |       <div class="item" :class="formData.taskType == 1 ? 'active' : ''" @click="formData.taskType = 1"><img src="./img/bigHorn-xz.png" alt="">定时播放</div> | ||||||
|  |     </div> | ||||||
|  |     <div class="content" v-if="formData.taskType != 0"> | ||||||
|  |       <div class="item"> | ||||||
|  |         <div class="label">定时策略</div> | ||||||
|  |         <div class="value" @click="selectClick('showCyclingType', cyclingTypeList)"> | ||||||
|  |           <span :class="formData.cyclingTypeName == '请选择' ? 'color-999' : ''">{{formData.cyclingTypeName}}</span> | ||||||
|  |           <img src="./img/right-icon.png" alt=""> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="radio-content" v-if="formData.taskType != 0 && formData.cyclingType == 2"> | ||||||
|  |       <div class="title">播放天数</div> | ||||||
|  |       <div class="mini-item" :class="item.isCheck ? 'mini-active' : ''" v-for="(item, index) in dayList" :key="index" @click="checkClick(index)">{{item.label}}</div> | ||||||
|  |     </div> | ||||||
|  |     <div class="content" v-if="formData.taskType != 0 && formData.cyclingType == 3"> | ||||||
|  |       <div class="item"> | ||||||
|  |         <div class="label">播放天数</div> | ||||||
|  |         <div class="value"> | ||||||
|  |           <u-input type="text" placeholder="请输入" height="18" input-align="right" v-model="formData.broadcastDay" maxlength="4" /> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="content" v-if="formData.taskType != 0"> | ||||||
|  |       <div class="item"> | ||||||
|  |         <div class="label">开始日期</div> | ||||||
|  |         <div class="value" @click="timeClick(true, 'showDate')"> | ||||||
|  |           <span :class="formData.startDate ? 'color-999' : ''">{{formData.startDate || '请选择'}}</span> | ||||||
|  |           <img src="./img/right-icon.png" alt=""> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="item"> | ||||||
|  |         <div class="label">开始时间</div> | ||||||
|  |         <div class="value" @click="timeClick(false, 'showSatrt')"> | ||||||
|  |           <span :class="formData.startTime ? 'color-999' : ''">{{formData.startTime || '请选择'}}</span> | ||||||
|  |           <img src="./img/right-icon.png" alt=""> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="item"> | ||||||
|  |         <div class="label">结束时间</div> | ||||||
|  |         <div class="value" @click="timeClick(false, 'showEnd')"> | ||||||
|  |           <span :class="formData.endTime ? 'color-999' : ''">{{formData.endTime || '请选择'}}</span> | ||||||
|  |           <img src="./img/right-icon.png" alt=""> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="btn" @click="addConfirm">确认</div> | ||||||
|  |     <u-select v-model="showSelect" :list="selectList" @confirm="confirm" label-name="dictName" value-name="dictValue"></u-select> | ||||||
|  |     <u-picker v-model="showDateTime" mode="time" :params="params" @confirm="confirm"></u-picker> | ||||||
|  |     <AiBack></AiBack> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | <script>  | ||||||
|  |   import AiBack from "@/components/AiBack"; | ||||||
|  | export default { | ||||||
|  |   name: "addPlay", | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       showSelect: false, | ||||||
|  |       selectList: [], | ||||||
|  |       showMedia: false, | ||||||
|  |       mediaList: [], | ||||||
|  |       showEquipment: false, | ||||||
|  |       equipmentList: [], | ||||||
|  |       showMessageLevel: false, | ||||||
|  |       messageLevelList: [], | ||||||
|  |       showCyclingType: false, | ||||||
|  |       cyclingTypeList: [], | ||||||
|  |       formData: { | ||||||
|  |         mediaId: '', | ||||||
|  |         mediaName: '请选择', | ||||||
|  |         serialNo: '', | ||||||
|  |         serialName: '请选择', | ||||||
|  |         messageLevel: '', | ||||||
|  |         messageLevelName: '请选择', | ||||||
|  |         taskType: '0', | ||||||
|  |         cyclingTypeName: '请选择', | ||||||
|  |         cyclingType: '', | ||||||
|  |         startDate: '', | ||||||
|  |         startTime: '', | ||||||
|  |         endTime: '', | ||||||
|  |         broadcastDay: '', | ||||||
|  |         cyclingDate: '' | ||||||
|  |       }, | ||||||
|  |       dayList: [ | ||||||
|  |         { | ||||||
|  |           isCheck: false, | ||||||
|  |           value: 1, | ||||||
|  |           label: '每周一' | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           isCheck: false, | ||||||
|  |           value: 2, | ||||||
|  |           label: '每周二' | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           isCheck: false, | ||||||
|  |           value: 3, | ||||||
|  |           label: '每周三' | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           isCheck: false, | ||||||
|  |           value: 4, | ||||||
|  |           label: '每周四' | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           isCheck: false, | ||||||
|  |           value: 5, | ||||||
|  |           label: '每周五' | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           isCheck: false, | ||||||
|  |           value: 6, | ||||||
|  |           label: '每周六' | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           isCheck: false, | ||||||
|  |           value: 7, | ||||||
|  |           label: '每周日' | ||||||
|  |         } | ||||||
|  |       ], | ||||||
|  |       showDateTime: false, | ||||||
|  |       showDate: false, | ||||||
|  |       showSatrt: false, | ||||||
|  |       showEnd: false, | ||||||
|  |       params: { | ||||||
|  |         year: true, | ||||||
|  |         month: true, | ||||||
|  |         day: true, | ||||||
|  |         hour: false, | ||||||
|  |         minute: false, | ||||||
|  |         second: false | ||||||
|  |       }, | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   components: { | ||||||
|  |     AiBack | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   onLoad () { | ||||||
|  |     uni.$on('choose', e => { | ||||||
|  |       console.log(e) | ||||||
|  |       this.formData.mediaId = e.mediaId | ||||||
|  |       this.formData.mediaName = e.mediaName | ||||||
|  |     }) | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   methods: { | ||||||
|  |     addConfirm() { | ||||||
|  |       var cyclingDateList = [] | ||||||
|  |       this.dayList.map((item) => { | ||||||
|  |         if(item.isCheck) { | ||||||
|  |           cyclingDateList.push(item.value) | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |  | ||||||
|  |       if(!this.formData.mediaId) { | ||||||
|  |         return this.$u.toast('请选择播发内容') | ||||||
|  |       } | ||||||
|  |       if(!this.formData.serialNo) { | ||||||
|  |         return this.$u.toast('请选择播放设备') | ||||||
|  |       } | ||||||
|  |       if(!this.formData.messageLevel) { | ||||||
|  |         return this.$u.toast('播发级别') | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       //播放方式(定时播放) | ||||||
|  |       if(this.formData.taskType != 0 && this.formData.startDate == '请选择') { | ||||||
|  |         return this.$u.toast('请选择开始日期') | ||||||
|  |       } | ||||||
|  |       if(this.formData.taskType != 0 && this.formData.startTime == '请选择') { | ||||||
|  |         return this.$u.toast('请选择开始时间') | ||||||
|  |       } | ||||||
|  |       if(this.formData.taskType != 0 && this.formData.endTime == '请选择') { | ||||||
|  |         return this.$u.toast('请选择结束时间') | ||||||
|  |       } | ||||||
|  |       //播放方式(定时播放)定时策略(时长) | ||||||
|  |       if(this.formData.taskType != 0 && this.formData.cyclingType == 3 && !this.formData.broadcastDay) { | ||||||
|  |         return this.$u.toast('请输入播放天数') | ||||||
|  |       } | ||||||
|  |       //播放方式(定时播放)定时策略(自定义) | ||||||
|  |       if(this.formData.taskType != 0 && this.formData.cyclingType == 2 && !cyclingDateList.length) { | ||||||
|  |         return this.$u.toast('请选择播放天数') | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       if(this.formData.taskType != 0 && this.formData.cyclingType == 2) { | ||||||
|  |         this.formData.cyclingDate = cyclingDateList.join(',') | ||||||
|  |       } | ||||||
|  |       this.formData.coverageType = '4' | ||||||
|  |       this.$http.post(`/app/appzyvideobroadcast/play`, {...this.formData,}).then((res) => { | ||||||
|  |         if (res.code == 0) { | ||||||
|  |           this.$u.toast('提交成功') | ||||||
|  |           setTimeout(() => { | ||||||
|  |             uni.navigateBack() | ||||||
|  |           }, 1000) | ||||||
|  |         } | ||||||
|  |       })  | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     linkTo (path) { | ||||||
|  |       uni.navigateTo({ | ||||||
|  |         url: path | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     confirm(e) { | ||||||
|  |       if(this.showMedia) { | ||||||
|  |         this.formData.mediaId = e[0].value | ||||||
|  |         this.formData.mediaName = e[0].label | ||||||
|  |       } | ||||||
|  |       if(this.showEquipment) { | ||||||
|  |         this.formData.serialNo = e[0].value | ||||||
|  |         this.formData.serialName = e[0].label | ||||||
|  |       } | ||||||
|  |       if(this.showMessageLevel) { | ||||||
|  |         this.formData.messageLevel = e[0].value | ||||||
|  |         this.formData.messageLevelName = e[0].label | ||||||
|  |       } | ||||||
|  |       if(this.showCyclingType) { | ||||||
|  |         this.formData.cyclingType = e[0].value | ||||||
|  |         this.formData.cyclingTypeName = e[0].label | ||||||
|  |       } | ||||||
|  |       if(this.showDate) { | ||||||
|  |         this.formData.startDate = e.year + '-' + e.month + '-' + e.day | ||||||
|  |       } | ||||||
|  |       if(this.showSatrt) { | ||||||
|  |         var startTime = e.hour + ':' + e.minute + ':' + e.second | ||||||
|  |         var myDate = new Date(); | ||||||
|  |         var time = myDate.getHours() + ':' +  myDate.getMinutes() + ':' + myDate.getSeconds() | ||||||
|  |         if (this.timeToSec(startTime) - this.timeToSec(time) > 0) { | ||||||
|  |           this.formData.startTime = startTime | ||||||
|  |         }else { | ||||||
|  |           this.$u.toast('开始时间要大于当前时间') | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       if(this.showEnd) { | ||||||
|  |         var endTime = e.hour + ':' + e.minute + ':' + e.second | ||||||
|  |         console.log(this.timeToSec(endTime), this.timeToSec(this.formData.startTime)) | ||||||
|  |         if (this.timeToSec(endTime) - this.timeToSec(this.formData.startTime) > 0) { | ||||||
|  |           this.formData.endTime = endTime | ||||||
|  |         } else { | ||||||
|  |           this.$u.toast('结束时间要大于开始时间') | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       this.init() | ||||||
|  |     }, | ||||||
|  |     init() { | ||||||
|  |       this.showMedia = false | ||||||
|  |       this.showEquipment = false | ||||||
|  |       this.showMessageLevel = false | ||||||
|  |       this.showCyclingType = false | ||||||
|  |       this.showDate = false | ||||||
|  |       this.showSatrt = false | ||||||
|  |       this.showEnd = false | ||||||
|  |     }, | ||||||
|  |     selectClick(showType, list) { | ||||||
|  |       this.showSelect = true | ||||||
|  |       this[showType] = true | ||||||
|  |       this.selectList = list | ||||||
|  |     }, | ||||||
|  |     getMediaList() { | ||||||
|  |       this.$http.post(`/app/appdlbresource/list?current=1&size=10000`).then((res) => { | ||||||
|  |         if (res.code == 0) { | ||||||
|  |           this.mediaList = [] | ||||||
|  |           if(res.data && res.data.records.length) { | ||||||
|  |             res.data.records.map((item) => { | ||||||
|  |               let info = { | ||||||
|  |                 dictName: item.name, | ||||||
|  |                 dictValue: item.id | ||||||
|  |               } | ||||||
|  |               this.mediaList.push(info) | ||||||
|  |             }) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     getEquipmentList() { | ||||||
|  |       this.$http.post(`/app/appdlbquipment/getDlbDeviceList?current=1&size=10000&devStatus=5&keyword=`).then((res) => { | ||||||
|  |         if (res.code == 0) { | ||||||
|  |           this.equipmentList = [] | ||||||
|  |           if(res.data && res.data.records.length) { | ||||||
|  |             res.data.records.map((item) => { | ||||||
|  |               let info = { | ||||||
|  |                 dictName: item.deviceName, | ||||||
|  |                 dictValue: item.serialNo | ||||||
|  |               } | ||||||
|  |               this.equipmentList.push(info) | ||||||
|  |             }) | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     checkClick(index) { | ||||||
|  |       this.dayList[index].isCheck = !this.dayList[index].isCheck | ||||||
|  |     }, | ||||||
|  |     timeClick(showYear, showType) { | ||||||
|  |       this[showType] = true | ||||||
|  |       this.showDateTime = true | ||||||
|  |       if(showYear) { | ||||||
|  |         this.params = { | ||||||
|  |           year: true, | ||||||
|  |           month: true, | ||||||
|  |           day: true, | ||||||
|  |           hour: false, | ||||||
|  |           minute: false, | ||||||
|  |           second: false | ||||||
|  |         } | ||||||
|  |       }else { | ||||||
|  |         this.params = { | ||||||
|  |           year: false, | ||||||
|  |           month: false, | ||||||
|  |           day: false, | ||||||
|  |           hour: true, | ||||||
|  |           minute: true, | ||||||
|  |           second: true | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     timeToSec(time) { | ||||||
|  |       var s = ""; | ||||||
|  |       var hour = time.split(":")[0]; | ||||||
|  |       var min = time.split(":")[1]; | ||||||
|  |       var second =  time.split(":")[2]; | ||||||
|  |       s = Number(hour * 3600) + Number(min * 60) + Number(second) | ||||||
|  |       return s; | ||||||
|  |     },  | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.$dict.load('dlbMessageUrgency', 'dlbBroadTaskType', 'dlbDyclingType').then(() => { | ||||||
|  |       this.getMediaList() | ||||||
|  |       this.getEquipmentList() | ||||||
|  |       this.messageLevelList = this.$dict.getDict('dlbMessageUrgency') | ||||||
|  |       this.cyclingTypeList = this.$dict.getDict('dlbDyclingType') | ||||||
|  |     }) | ||||||
|  |   }, | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .addPlay { | ||||||
|  |   padding-bottom: 128px; | ||||||
|  |   .content{ | ||||||
|  |     padding-left: 32px; | ||||||
|  |     background-color: #fff; | ||||||
|  |     .item{ | ||||||
|  |       width: 100%; | ||||||
|  |       padding: 34px 0; | ||||||
|  |       font-size: 32px; | ||||||
|  |       font-family: PingFangSC-Regular, PingFang SC; | ||||||
|  |       font-weight: 400; | ||||||
|  |       line-height: 44px; | ||||||
|  |       border-bottom: 1px solid #ddd; | ||||||
|  |       display: flex; | ||||||
|  |       color: #333; | ||||||
|  |       justify-content: space-between; | ||||||
|  |       .label{ | ||||||
|  |         width: 198px; | ||||||
|  |         font-size: 32px; | ||||||
|  |       } | ||||||
|  |       .value{ | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: flex-end; | ||||||
|  |         font-size: 28px; | ||||||
|  |         flex: 1; | ||||||
|  |         padding-right: 32px; | ||||||
|  |         max-width: calc(100% - 198px); | ||||||
|  |         box-sizing: border-box; | ||||||
|  |         text-align: right; | ||||||
|  |  | ||||||
|  |         span { | ||||||
|  |           overflow: hidden; | ||||||
|  |           text-overflow: ellipsis; | ||||||
|  |           white-space: nowrap; | ||||||
|  |         } | ||||||
|  |         img{ | ||||||
|  |           width: 32px; | ||||||
|  |           height: 32px; | ||||||
|  |           vertical-align: middle; | ||||||
|  |           margin-left: 6px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       .color-999{ | ||||||
|  |         color: #999; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   .radio-content{ | ||||||
|  |     padding: 34px 32px 38px; | ||||||
|  |     border-bottom: 1px solid #ddd; | ||||||
|  |     background-color: #fff; | ||||||
|  |     .title{ | ||||||
|  |       font-size: 32px; | ||||||
|  |       font-family: PingFangSC-Regular, PingFang SC; | ||||||
|  |       font-weight: 400; | ||||||
|  |       color: #333; | ||||||
|  |       line-height: 44px; | ||||||
|  |       margin-bottom: 54px; | ||||||
|  |       span{ | ||||||
|  |         font-size: 24px; | ||||||
|  |         font-weight: 400; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     .item{ | ||||||
|  |       display: inline-block; | ||||||
|  |       width: 320px; | ||||||
|  |       height: 112px; | ||||||
|  |       line-height: 112px; | ||||||
|  |       text-align: center; | ||||||
|  |       background: #F5F5F5; | ||||||
|  |       border-radius: 4px; | ||||||
|  |       font-size: 30px; | ||||||
|  |       font-family: PingFangSC-Medium, PingFang SC; | ||||||
|  |       font-weight: 500; | ||||||
|  |       color: #333; | ||||||
|  |       img{ | ||||||
|  |         display: none; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     .active{ | ||||||
|  |       background: #E7F1FE; | ||||||
|  |       color: #1174FE; | ||||||
|  |       position: relative; | ||||||
|  |       img{ | ||||||
|  |         display: inline-block; | ||||||
|  |         position: absolute; | ||||||
|  |         bottom: 0; | ||||||
|  |         right: 0; | ||||||
|  |         width: 46px; | ||||||
|  |         height: 46px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     .mar-r50 { | ||||||
|  |       margin-right: 50px; | ||||||
|  |     } | ||||||
|  |     .mini-item{ | ||||||
|  |       display: inline-block; | ||||||
|  |       width: 128px; | ||||||
|  |       height: 72px; | ||||||
|  |       line-height: 72px; | ||||||
|  |       text-align: center; | ||||||
|  |       background: #F9F9F9; | ||||||
|  |       border-radius: 16px; | ||||||
|  |       color: #333; | ||||||
|  |       font-size: 28px; | ||||||
|  |       margin-right: 58px; | ||||||
|  |       margin-bottom: 32px; | ||||||
|  |     } | ||||||
|  |     .mini-item:nth-of-type(5) { | ||||||
|  |       margin-right: 0; | ||||||
|  |     } | ||||||
|  |     .mini-active{ | ||||||
|  |       background: #F2F8FE; | ||||||
|  |       border: 1px solid #89B2EE; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   .btn{ | ||||||
|  |     position: fixed; | ||||||
|  |     bottom: 0; | ||||||
|  |     left: 0; | ||||||
|  |     width: 100%; | ||||||
|  |     height: 112px; | ||||||
|  |     line-height: 112px; | ||||||
|  |     text-align: center; | ||||||
|  |     background: #3975C6; | ||||||
|  |     font-size: 32px; | ||||||
|  |     font-family: PingFangSC-Medium, PingFang SC; | ||||||
|  |     font-weight: 500; | ||||||
|  |     color: #FFFFFF; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										167
									
								
								src/pages/bigHorn/bigHorn.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,167 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="bigHorn"> | ||||||
|  |     <div class="header"> | ||||||
|  |       <img src="./img/bigHorn-bg.png" alt=""> | ||||||
|  |       <div class="content"> | ||||||
|  |         <div class="item" @click="linkTo('./onlineList')"> | ||||||
|  |           <img src="./img/bigHorn-icon1@2x.png" alt=""> | ||||||
|  |           <div>在线设备</div> | ||||||
|  |           <!-- <h2>1</h2> --> | ||||||
|  |         </div> | ||||||
|  |         <div class="item" @click="linkTo('./playList')"> | ||||||
|  |           <img src="./img/bigHorn-icon2@2x.png" alt=""> | ||||||
|  |           <div>播放记录</div> | ||||||
|  |         </div> | ||||||
|  |         <div class="item" @click="linkTo('./onlinePlayList')"> | ||||||
|  |           <img src="./img/bigHorn-icon3@2x.png" alt=""> | ||||||
|  |           <div>在播设备</div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="banner"> | ||||||
|  |       <div class="item" :class="item.bgClass" v-for="(item, index) in bannerList" :key="index" @click="linkTo(item.path)"> | ||||||
|  |         <h2>{{item.title}}</h2> | ||||||
|  |         <div>{{item.text}}</div> | ||||||
|  |         <img :src="item.imgUrl" alt=""> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | <script>  | ||||||
|  | export default { | ||||||
|  |   name: "bigHorn", | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       bannerList: [ | ||||||
|  |         { | ||||||
|  |           title: '素材播放', | ||||||
|  |           text: '支持音频立即播发和定时播发', | ||||||
|  |           imgUrl: require('./img/bigHorn-icon11@2x.png'), | ||||||
|  |           path: '/pages/bigHorn/addPlay', | ||||||
|  |           bgClass: 'bg-67A3F4' | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           title: '实时喊话', | ||||||
|  |           text: '实时在线喊话,远程广播通知', | ||||||
|  |           imgUrl: require('./img/bigHorn-icon22@2x.png'), | ||||||
|  |           bgClass: 'bg-4ED5BB' | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           title: '音频录制', | ||||||
|  |           text: '音频文件的录制', | ||||||
|  |           path: '/pages/resourcesManage/addPlay?type=1', | ||||||
|  |           imgUrl: require('./img/bigHorn-icon33@2x.png'), | ||||||
|  |           bgClass: 'bg-E5B565' | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |           title: '媒资管理', | ||||||
|  |           path: '/pages/resourcesManage/resourcesManage', | ||||||
|  |           text: '支持音频文件和录音内容添加', | ||||||
|  |           imgUrl: require('./img/bigHorn-icon44@2x.png'), | ||||||
|  |           bgClass: 'bg-F19661' | ||||||
|  |         } | ||||||
|  |       ] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     linkTo(url) { | ||||||
|  |       uni.navigateTo({url}) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   mounted() { | ||||||
|  |  | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .bigHorn { | ||||||
|  |   .header{ | ||||||
|  |     position: relative; | ||||||
|  |     img{ | ||||||
|  |       width: 100%; | ||||||
|  |       height: 306px; | ||||||
|  |     } | ||||||
|  |     .content{ | ||||||
|  |       width: 686px; | ||||||
|  |       padding: 40px 0; | ||||||
|  |       background: #FFFFFF; | ||||||
|  |       box-shadow: 0px 4px 8px 4px rgba(0, 0, 0, 0.06); | ||||||
|  |       border-radius: 12px; | ||||||
|  |       position: absolute; | ||||||
|  |       top: 210px; | ||||||
|  |       left: 50%; | ||||||
|  |       transform: translateX(-50%); | ||||||
|  |       display: flex; | ||||||
|  |       .item{ | ||||||
|  |         text-align: center; | ||||||
|  |         flex: 1; | ||||||
|  |         img{ | ||||||
|  |           width: 64px; | ||||||
|  |           height: 64px; | ||||||
|  |           margin-bottom: 18px; | ||||||
|  |         } | ||||||
|  |         div{ | ||||||
|  |           font-size: 30px; | ||||||
|  |           font-family: PingFang-SC-Medium, PingFang-SC; | ||||||
|  |           font-weight: 500; | ||||||
|  |           color: #333; | ||||||
|  |           line-height: 42px; | ||||||
|  |           margin-bottom: 10px; | ||||||
|  |         } | ||||||
|  |         h2{ | ||||||
|  |           font-size: 40px; | ||||||
|  |           font-family: DINAlternate-Bold, DINAlternate; | ||||||
|  |           font-weight: bold; | ||||||
|  |           color: #333; | ||||||
|  |           line-height: 48px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   .banner{ | ||||||
|  |     margin-top: 150px; | ||||||
|  |     .item{ | ||||||
|  |       width: 686px; | ||||||
|  |       height: 190px; | ||||||
|  |       border-radius: 12px; | ||||||
|  |       margin: 0 auto 24px auto; | ||||||
|  |       padding: 40px 46px 0 80px; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       color: #FFF; | ||||||
|  |       position: relative; | ||||||
|  |       h2{ | ||||||
|  |         font-size: 42px; | ||||||
|  |         font-family: PingFangSC-Medium, PingFang SC; | ||||||
|  |         font-weight: 500; | ||||||
|  |         line-height: 60px; | ||||||
|  |         margin-bottom: 16px; | ||||||
|  |       } | ||||||
|  |       div{ | ||||||
|  |         font-size: 26px; | ||||||
|  |         font-family: PingFangSC-Regular, PingFang SC; | ||||||
|  |         font-weight: 400; | ||||||
|  |         color: #FFF; | ||||||
|  |         line-height: 32px; | ||||||
|  |       } | ||||||
|  |       img{ | ||||||
|  |         width: 160px; | ||||||
|  |         position: absolute; | ||||||
|  |         top: 10px; | ||||||
|  |         right: 30px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     .bg-67A3F4{ | ||||||
|  |       background: #67A3F4; | ||||||
|  |     } | ||||||
|  |     .bg-4ED5BB{ | ||||||
|  |       background: #4ED5BB; | ||||||
|  |     } | ||||||
|  |     .bg-E5B565{ | ||||||
|  |       background: #E5B565; | ||||||
|  |     } | ||||||
|  |     .bg-F19661{ | ||||||
|  |       background: #F19661; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-bg.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 64 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-icon11@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-icon1@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.4 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-icon22@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.9 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-icon2@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-icon33@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 6.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-icon3@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-icon44@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-lb@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/bigHorn-xz.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.3 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/cir.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 795 B | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/lb@2x.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.1 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/right-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 269 B | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/search-icon.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 766 B | 
							
								
								
									
										
											BIN
										
									
								
								src/pages/bigHorn/img/select-blue.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 1.1 KiB | 
							
								
								
									
										93
									
								
								src/pages/bigHorn/onlineList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,93 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="onlineList"> | ||||||
|  |     <div class="record"> | ||||||
|  |       <div class="item"  v-for="(item, index) in list" :key="index"> | ||||||
|  |         <img src="./img/bigHorn-lb@2x.png" alt=""> | ||||||
|  |         <div class="info"> | ||||||
|  |           <p>{{item.deviceName}}</p> | ||||||
|  |           <span>{{item.areaName}}</span> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <ai-empty v-if="!list.length"></ai-empty> | ||||||
|  |     <AiBack></AiBack> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | <script>  | ||||||
|  | import AiEmpty from '@/components/AiEmpty/AiEmpty' | ||||||
|  | import AiBack from "@/components/AiBack"; | ||||||
|  | export default { | ||||||
|  |   name: "onlineList", | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       page: {current: 1, size: 10, total: 0}, | ||||||
|  |       list: [] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   components: { | ||||||
|  |     AiEmpty, | ||||||
|  |     AiBack | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getList() { | ||||||
|  |       this.$http.post("/app/appdlbquipment/getDlbDeviceList", null, { | ||||||
|  |         params: {...this.page, devStatus: 5} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           if (this.page.current > 1) { | ||||||
|  |             this.list = [...this.list, ...res.data.records] | ||||||
|  |           } else this.list = res.data.records | ||||||
|  |           this.page.total = res.data.total | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     reachBottom() { | ||||||
|  |       if (this.page.total > this.list.length) { | ||||||
|  |         this.page.current++ | ||||||
|  |         this.getList() | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.getList() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .onlineList { | ||||||
|  |   .record{ | ||||||
|  |     padding-left: 32px; | ||||||
|  |     background-color: #fff; | ||||||
|  |     .item{ | ||||||
|  |       width: 100%; | ||||||
|  |       border-bottom: 1px solid #ddd; | ||||||
|  |       display: flex; | ||||||
|  |       padding: 12px 40px 16px 0; | ||||||
|  |       img{ | ||||||
|  |         width: 48px; | ||||||
|  |         height: 48px; | ||||||
|  |         margin: 12px 16px 0 0; | ||||||
|  |       } | ||||||
|  |       .info{ | ||||||
|  |         width: calc(100% - 100px); | ||||||
|  |         p{ | ||||||
|  |           font-size: 34px; | ||||||
|  |           font-family: PingFang-SC-Medium, PingFang-SC; | ||||||
|  |           font-weight: 500; | ||||||
|  |           color: #333; | ||||||
|  |           line-height: 48px; | ||||||
|  |           margin-bottom: 12px; | ||||||
|  |         } | ||||||
|  |         span{ | ||||||
|  |           font-size: 22px; | ||||||
|  |           font-family: PingFang-SC-Medium, PingFang-SC; | ||||||
|  |           font-weight: 500; | ||||||
|  |           color: #999; | ||||||
|  |           line-height: 32px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										95
									
								
								src/pages/bigHorn/onlinePlayList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,95 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="onlinePlayList"> | ||||||
|  |     <div class="record"> | ||||||
|  |       <div class="item" v-for="(item, index) in list" :key="index"> | ||||||
|  |         <img src="./img/bigHorn-lb@2x.png" alt=""> | ||||||
|  |         <div class="info"> | ||||||
|  |           <p>{{item.deviceName}}</p> | ||||||
|  |           <span>{{item.createTime}}</span><br /> | ||||||
|  |           <span>{{item.name}}</span> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <ai-empty v-if="!list.length"></ai-empty> | ||||||
|  |     <AiBack></AiBack> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | <script>  | ||||||
|  | import AiEmpty from '@/components/AiEmpty/AiEmpty' | ||||||
|  | import AiBack from "@/components/AiBack"; | ||||||
|  | export default { | ||||||
|  |   name: "onlinePlayList", | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       page: {current: 1, size: 10, total: 0}, | ||||||
|  |       list: [] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   components: { | ||||||
|  |     AiEmpty, | ||||||
|  |     AiBack | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   methods: { | ||||||
|  |     getList() { | ||||||
|  |       this.$http.post("/app/appdlbquipment/getDlbDeviceList", null, { | ||||||
|  |         params: {...this.page, devStatus: 1} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           if (this.page.current > 1) { | ||||||
|  |             this.list = [...this.list, ...res.data.records] | ||||||
|  |           } else this.list = res.data.records | ||||||
|  |           this.page.total = res.data.total | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     reachBottom() { | ||||||
|  |       if (this.page.total > this.list.length) { | ||||||
|  |         this.page.current++ | ||||||
|  |         this.getList() | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.getList() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .onlinePlayList { | ||||||
|  |   .record{ | ||||||
|  |     padding-left: 32px; | ||||||
|  |     background-color: #fff; | ||||||
|  |     .item{ | ||||||
|  |       width: 100%; | ||||||
|  |       border-bottom: 1px solid #ddd; | ||||||
|  |       display: flex; | ||||||
|  |       padding: 12px 40px 16px 0; | ||||||
|  |       img{ | ||||||
|  |         width: 48px; | ||||||
|  |         height: 48px; | ||||||
|  |         margin: 12px 16px 0 0; | ||||||
|  |       } | ||||||
|  |       .info{ | ||||||
|  |         width: calc(100% - 100px); | ||||||
|  |         p{ | ||||||
|  |           font-size: 34px; | ||||||
|  |           font-family: PingFang-SC-Medium, PingFang-SC; | ||||||
|  |           font-weight: 500; | ||||||
|  |           color: #333; | ||||||
|  |           line-height: 48px; | ||||||
|  |           margin-bottom: 12px; | ||||||
|  |         } | ||||||
|  |         span{ | ||||||
|  |           font-size: 22px; | ||||||
|  |           font-family: PingFang-SC-Medium, PingFang-SC; | ||||||
|  |           font-weight: 500; | ||||||
|  |           color: #999; | ||||||
|  |           line-height: 32px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										138
									
								
								src/pages/bigHorn/playList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,138 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="playList"> | ||||||
|  |     <div class="title"> | ||||||
|  |       <span>播放记录</span> | ||||||
|  |       <span>操作</span> | ||||||
|  |     </div> | ||||||
|  |     <div class="record"> | ||||||
|  |       <div class="item" v-for="(item, index) in list" :key="index">  | ||||||
|  |         <div class="info"> | ||||||
|  |           <p>{{item.messageName}}</p> | ||||||
|  |           <span>{{item.createTime}}</span><br /> | ||||||
|  |           <span>{{item.deviceName}}</span> | ||||||
|  |         </div> | ||||||
|  |         <div class="btn bg-3975C6" v-if="item.broadcastStatus == 0 || item.broadcastStatus == 1 || item.broadcastStatus == 2" @click="cancel(item.broadcastId)">撤销</div> | ||||||
|  |         <div class="btn bg-AFD0FC" v-if="item.broadcastStatus == 6">已取消</div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <AiBack></AiBack> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | <script>  | ||||||
|  |   import AiBack from "@/components/AiBack"; | ||||||
|  | export default { | ||||||
|  |   name: "playList", | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       page: {current: 1, size: 10, total: 0}, | ||||||
|  |       list: [] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |  | ||||||
|  |   components: { | ||||||
|  |     AiBack | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getList() { | ||||||
|  |       this.$http.post("/app/appzyvideobroadcast/getBroadcastRecords", null, { | ||||||
|  |         params: {...this.page} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           if (this.page.current > 1) { | ||||||
|  |             this.list = [...this.list, ...res.data.records] | ||||||
|  |           } else this.list = res.data.records | ||||||
|  |           this.page.total = res.data.total | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     reachBottom() { | ||||||
|  |       if (this.page.total > this.list.length) { | ||||||
|  |         this.page.current++ | ||||||
|  |         this.getList() | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     cancel(id) { | ||||||
|  |       this.$confirm('确定撤回该广播?').then(() => { | ||||||
|  |         this.$http.post(`/app/appzyvideobroadcast/getBroadcastRecall?broadcastId=${id}`).then((res) => { | ||||||
|  |           if (res.code == 0) { | ||||||
|  |             this.$u.toast('撤回成功!') | ||||||
|  |             this.getList() | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.$dict.load('dlbBroadcastStatus').then(() => { | ||||||
|  |       this.getList() | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .playList { | ||||||
|  |   .title{ | ||||||
|  |     width: 100%; | ||||||
|  |     height: 88px; | ||||||
|  |     line-height: 88px; | ||||||
|  |     background: #FFF; | ||||||
|  |     padding: 0 80px; | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: space-between; | ||||||
|  |     color: #333; | ||||||
|  |     font-size: 34px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     border-bottom: 1px solid #ddd; | ||||||
|  |   } | ||||||
|  |   .record{ | ||||||
|  |     padding-left: 32px; | ||||||
|  |     background-color: #fff; | ||||||
|  |     .item{ | ||||||
|  |       width: 100%; | ||||||
|  |       border-bottom: 1px solid #ddd; | ||||||
|  |       display: flex; | ||||||
|  |       justify-content: space-between; | ||||||
|  |       padding: 12px 40px 16px 0; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       .info{ | ||||||
|  |         width: 480px; | ||||||
|  |         margin-right: 40px; | ||||||
|  |         word-break: break-all; | ||||||
|  |         p{ | ||||||
|  |           font-size: 34px; | ||||||
|  |           font-family: PingFang-SC-Medium, PingFang-SC; | ||||||
|  |           font-weight: 500; | ||||||
|  |           color: #333; | ||||||
|  |           line-height: 48px; | ||||||
|  |           margin-bottom: 12px; | ||||||
|  |         } | ||||||
|  |         span{ | ||||||
|  |           font-size: 22px; | ||||||
|  |           font-family: PingFang-SC-Medium, PingFang-SC; | ||||||
|  |           font-weight: 500; | ||||||
|  |           color: #999; | ||||||
|  |           line-height: 32px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       .btn{ | ||||||
|  |         width: 154px; | ||||||
|  |         height: 60px; | ||||||
|  |         border-radius: 8px; | ||||||
|  |         text-align: center; | ||||||
|  |         line-height: 60px; | ||||||
|  |         font-size: 30px; | ||||||
|  |         font-family: PingFang-SC-Medium, PingFang-SC; | ||||||
|  |         font-weight: 500; | ||||||
|  |         color: #FFF; | ||||||
|  |         margin-top: 18px; | ||||||
|  |       } | ||||||
|  |       .bg-3975C6{ | ||||||
|  |         background: #3975C6; | ||||||
|  |       } | ||||||
|  |       .bg-AFD0FC{ | ||||||
|  |         background: #AFD0FC; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										160
									
								
								src/pages/bigHorn/selectEquipment.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,160 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="selectEquipment"> | ||||||
|  |     <div class="search"> | ||||||
|  |       <div class="search-bg"> | ||||||
|  |         <img src="./img/search-icon.png" alt=""> | ||||||
|  |         <u-input v-model="value" type="text" placeholder="搜索设备名称" class="search-input" height="18" /> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="record"> | ||||||
|  |       <div class="item"> | ||||||
|  |         <img src="./img/cir.png" alt="" class="check-img"> | ||||||
|  |         <img src="./img/lb@2x.png" alt="" class="voice-img"> | ||||||
|  |         <div class="info"> | ||||||
|  |           <div class="text"> | ||||||
|  |             <p>村头大喇叭</p> | ||||||
|  |             <span>刘家河居委会</span> | ||||||
|  |           </div> | ||||||
|  |           <div class="status">在线</div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="item"> | ||||||
|  |         <img src="./img/cir.png" alt="" class="check-img"> | ||||||
|  |         <img src="./img/lb@2x.png" alt="" class="voice-img"> | ||||||
|  |         <div class="info"> | ||||||
|  |           <div class="text"> | ||||||
|  |             <p>村头大喇叭</p> | ||||||
|  |             <span>刘家河居委会</span> | ||||||
|  |           </div> | ||||||
|  |           <div class="status">在线</div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="btn"> | ||||||
|  |       <div>确定选择</div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | <script>  | ||||||
|  | export default { | ||||||
|  |   name: "selectEquipment", | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       value: '' | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |      | ||||||
|  |   }, | ||||||
|  |   mounted() { | ||||||
|  |  | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .selectEquipment { | ||||||
|  |   padding-bottom: 128px; | ||||||
|  |   .search{ | ||||||
|  |     width: 100%; | ||||||
|  |     height: 104px; | ||||||
|  |     background: #FFF; | ||||||
|  |     margin-bottom: 4px; | ||||||
|  |     padding: 20px 32px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     .search-bg{ | ||||||
|  |       width: 686px; | ||||||
|  |       height: 64px; | ||||||
|  |       padding: 14px 0; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       background: #F5F5F5; | ||||||
|  |       border-radius: 32px; | ||||||
|  |       position: relative; | ||||||
|  |       img{ | ||||||
|  |         width: 32px; | ||||||
|  |         height: 32px; | ||||||
|  |         position: absolute; | ||||||
|  |         top: 16px; | ||||||
|  |         left: 32px; | ||||||
|  |       } | ||||||
|  |       .search-input{ | ||||||
|  |         width: 590px; | ||||||
|  |         height: 36px; | ||||||
|  |         line-height: 36px; | ||||||
|  |         font-size: 28px; | ||||||
|  |         margin-left: 70px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   .record{ | ||||||
|  |     padding-left: 32px; | ||||||
|  |     background-color: #fff; | ||||||
|  |     .item{ | ||||||
|  |       width: 100%; | ||||||
|  |       display: flex; | ||||||
|  |       border-bottom: 1px solid #ddd; | ||||||
|  |       .check-img{ | ||||||
|  |         width: 32px; | ||||||
|  |         height: 32px; | ||||||
|  |         margin: 32px 32px 0 0; | ||||||
|  |       } | ||||||
|  |       .voice-img{ | ||||||
|  |         width: 48px; | ||||||
|  |         height: 48px; | ||||||
|  |         margin: 28px 16px 0 0; | ||||||
|  |       } | ||||||
|  |       .info{ | ||||||
|  |         width: calc(100% - 148px); | ||||||
|  |         padding: 18px 0; | ||||||
|  |         line-height: 44px; | ||||||
|  |         font-size: 34px; | ||||||
|  |         display: flex; | ||||||
|  |         justify-content: space-between; | ||||||
|  |         .text{ | ||||||
|  |           p{ | ||||||
|  |             font-family: PingFang-SC-Medium, PingFang-SC; | ||||||
|  |             font-weight: 500; | ||||||
|  |             color: #333; | ||||||
|  |             margin-bottom: 8px; | ||||||
|  |           } | ||||||
|  |           span{ | ||||||
|  |             font-size: 26px; | ||||||
|  |             font-family: PingFang-SC-Medium, PingFang-SC; | ||||||
|  |             font-weight: 500; | ||||||
|  |             color: #999; | ||||||
|  |             line-height: 36px; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         .status{ | ||||||
|  |           font-size: 34px; | ||||||
|  |           font-family: PingFang-SC-Medium, PingFang-SC; | ||||||
|  |           font-weight: 500; | ||||||
|  |           color: #4E8EEE; | ||||||
|  |           line-height: 48px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   .btn{ | ||||||
|  |     position: fixed; | ||||||
|  |     bottom: 0; | ||||||
|  |     left: 0; | ||||||
|  |     width: 100%; | ||||||
|  |     height: 128px; | ||||||
|  |     background: #FFF; | ||||||
|  |     border-top: 1px solid #ddd; | ||||||
|  |     padding: 24px 32px 24px 0; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     div{ | ||||||
|  |       width: 192px; | ||||||
|  |       height: 80px; | ||||||
|  |       line-height: 80px; | ||||||
|  |       text-align: center; | ||||||
|  |       background: #3975C6; | ||||||
|  |       border-radius: 4px; | ||||||
|  |       color: #fff; | ||||||
|  |       font-size: 32px; | ||||||
|  |       float: right; | ||||||
|  |     }  | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										83
									
								
								src/pages/bigHorn/selectMp3.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,83 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="selectMp3"> | ||||||
|  |     <div class="record"> | ||||||
|  |       <div class="item"> | ||||||
|  |         <img src="./img/cir.png" alt=""> | ||||||
|  |         <div class="info"> | ||||||
|  |           <p>村头大喇叭</p> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="btn"> | ||||||
|  |       <div>确定选择</div> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  | <script>  | ||||||
|  | export default { | ||||||
|  |   name: "selectMp3", | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |        | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |      | ||||||
|  |   }, | ||||||
|  |   mounted() { | ||||||
|  |  | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .selectMp3 { | ||||||
|  |   padding-bottom: 128px; | ||||||
|  |   .record{ | ||||||
|  |     padding-left: 32px; | ||||||
|  |     background-color: #fff; | ||||||
|  |     .item{ | ||||||
|  |       width: 100%; | ||||||
|  |       display: flex; | ||||||
|  |       img{ | ||||||
|  |         width: 32px; | ||||||
|  |         height: 32px; | ||||||
|  |         margin: 40px 16px 0 0; | ||||||
|  |       } | ||||||
|  |       .info{ | ||||||
|  |         width: calc(100% - 60px); | ||||||
|  |         padding-bottom: 16px; | ||||||
|  |         padding: 34px 0; | ||||||
|  |         line-height: 44px; | ||||||
|  |         border-bottom: 1px solid #ddd; | ||||||
|  |         font-size: 34px; | ||||||
|  |         font-family: PingFang-SC-Medium, PingFang-SC; | ||||||
|  |         font-weight: 500; | ||||||
|  |         color: #333; | ||||||
|  |         margin-left: 16px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   .btn{ | ||||||
|  |     position: fixed; | ||||||
|  |     bottom: 0; | ||||||
|  |     left: 0; | ||||||
|  |     width: 100%; | ||||||
|  |     height: 128px; | ||||||
|  |     background: #FFF; | ||||||
|  |     border-top: 1px solid #ddd; | ||||||
|  |     padding: 24px 32px 24px 0; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     div{ | ||||||
|  |       width: 192px; | ||||||
|  |       height: 80px; | ||||||
|  |       line-height: 80px; | ||||||
|  |       text-align: center; | ||||||
|  |       background: #3975C6; | ||||||
|  |       border-radius: 4px; | ||||||
|  |       color: #fff; | ||||||
|  |       font-size: 32px; | ||||||
|  |       float: right; | ||||||
|  |     }  | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										268
									
								
								src/pages/casuallyask/casuallyask.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,268 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="casuallyask"> | ||||||
|  |     <div class="banner"> | ||||||
|  |       <picker :range="dictList" @change="bindPickerChange" range-key="dictName"> | ||||||
|  |         <div class="picker"> | ||||||
|  |           {{ askType }} | ||||||
|  |           <u-icon | ||||||
|  |               name="arrow-down" | ||||||
|  |               :custom-style="{ margin: '0 5px' }" | ||||||
|  |           ></u-icon> | ||||||
|  |         </div> | ||||||
|  |       </picker> | ||||||
|  |       <u-search | ||||||
|  |           placeholder="请输入标题" | ||||||
|  |           :show-action="false" | ||||||
|  |           v-model="keyword" | ||||||
|  |           @search="onSearch" | ||||||
|  |       /> | ||||||
|  |     </div> | ||||||
|  |     <u-tabs | ||||||
|  |         class="nav" | ||||||
|  |         :list="tabs" | ||||||
|  |         :is-scroll="false" | ||||||
|  |         :current="currentType" | ||||||
|  |         font-size="32" | ||||||
|  |         bar-width="192" | ||||||
|  |         height="96" | ||||||
|  |         @change="handleTabClick" | ||||||
|  |     ></u-tabs> | ||||||
|  |     <div class="body" v-if="eventList.length !== 0"> | ||||||
|  |       <div | ||||||
|  |           class="content" | ||||||
|  |           v-for="(item, index) in eventList" | ||||||
|  |           :key="index" | ||||||
|  |           @click="detail(item)" | ||||||
|  |       > | ||||||
|  |         <u-row> | ||||||
|  |           <div> | ||||||
|  |             <div class="top"> | ||||||
|  |  | ||||||
|  |               <text :class="item.type == '0' ? 'active' : 'noactive'"> | ||||||
|  |                 {{ $dict.getLabel('leaveMessageType', item.type) }} | ||||||
|  |               </text> | ||||||
|  |               <!-- 村 --> | ||||||
|  |               <text class="areaName" v-if="item.areaName">{{ item.areaName }}:</text> | ||||||
|  |               <!-- 问题 --> | ||||||
|  |               <text class="title">{{ item.title }}</text> | ||||||
|  |             </div> | ||||||
|  |  | ||||||
|  |             <div class="cont"> | ||||||
|  |               <span class="name_time">留言人:</span> | ||||||
|  |               <text class="text_c"> {{ item.leaveName }}</text> | ||||||
|  |             </div> | ||||||
|  |             <div class="cont"> | ||||||
|  |               <text class="name_time">留言时间:</text> | ||||||
|  |               <text class="text_c"> {{ item.createTime }}</text> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </u-row> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <AiEmpty v-else/> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import AiEmpty from '../../components/AiEmpty/AiEmpty' | ||||||
|  | import URow from '../../uview/components/u-row/u-row.vue' | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: 'casuallyAsk', | ||||||
|  |   // 组件 | ||||||
|  |   components: {URow, AiEmpty}, | ||||||
|  |   props: {}, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       page: {current: 1, size: 10, total: 0}, | ||||||
|  |       dictList: [], // 字典 | ||||||
|  |       index: 0, // 留言类型 0投诉 1咨询 2建议 | ||||||
|  |       keyword: '', | ||||||
|  |       askType: '提问类型', | ||||||
|  |       askIndex: '', | ||||||
|  |       currentType: 0, // 默认value的值(0待我回复)(1已回复)(2处理完成) | ||||||
|  |       eventList: [] // 数据列表 | ||||||
|  |       // temp: { '0': '投诉', '1': '建议', '2': '咨询' } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   // 计算 | ||||||
|  |   computed: { | ||||||
|  |     tabs() { | ||||||
|  |       return [ | ||||||
|  |         {name: '待我回复', value: 0}, | ||||||
|  |         {name: '我已回复', value: 1}, | ||||||
|  |         {name: '处理完成', value: 2} | ||||||
|  |       ] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   // 实例创建后 | ||||||
|  |   onShow() { | ||||||
|  |     this.$dict.load('leaveMessageType').then(() => { | ||||||
|  |       this.dictList = this.$dict.getDict('leaveMessageType') | ||||||
|  |       this.getList() | ||||||
|  |     }) | ||||||
|  |   }, | ||||||
|  |   // 方法 | ||||||
|  |   methods: { | ||||||
|  |     // 点击 value的值(0待我回复)(1已回复)(2处理完成) | ||||||
|  |     handleTabClick(i) { | ||||||
|  |       this.currentType = i | ||||||
|  |       this.getList() | ||||||
|  |     }, | ||||||
|  |     getList() { | ||||||
|  |       this.$http.post(`/app/appleavemessage/list`, null, { | ||||||
|  |         params: { | ||||||
|  |           ...this.page, | ||||||
|  |           title: this.keyword, | ||||||
|  |           status: this.currentType, | ||||||
|  |           type: this.askIndex | ||||||
|  |         } | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.page.total = res.data.total | ||||||
|  |           if (this.page.current > 1) | ||||||
|  |             this.eventList = [...this.eventList, res.data.records] | ||||||
|  |           else this.eventList = res.data.records | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     detail(item) { | ||||||
|  |       uni.navigateTo({ | ||||||
|  |         url: `/pages/casuallyask/casuallyaskDetail?id=${item.id}&type=${item.type}` | ||||||
|  |         //  url: `/pages/casuallyask/casuallyaskDetail?id=${item.id}` | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     // 提问类型 | ||||||
|  |     bindPickerChange(e) { | ||||||
|  |       let index = e.detail.value | ||||||
|  |       this.askType = this.dictList[index].dictName | ||||||
|  |       this.askIndex = index | ||||||
|  |       this.getList() | ||||||
|  |     }, | ||||||
|  |     onSearch(e) { | ||||||
|  |       this.keyword = e | ||||||
|  |       this.getList() | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   onReachBottom() { | ||||||
|  |     if (this.eventList.length < this.page.total) { | ||||||
|  |       this.page.current++ | ||||||
|  |       this.getList() | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style scoped lang="scss"> | ||||||
|  | .casuallyask { | ||||||
|  |   min-height: 100%; | ||||||
|  |   background: #f5f5f5; | ||||||
|  |   padding-top: 64px; | ||||||
|  |  | ||||||
|  |   .banner { | ||||||
|  |     position: fixed; | ||||||
|  |     top: 0; | ||||||
|  |     width: 100%; | ||||||
|  |     background-color: #fff; | ||||||
|  |     height: 80px; | ||||||
|  |     line-height: 80px; | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     justify-content: space-between; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     padding: 0 30px 0 30px; | ||||||
|  |  | ||||||
|  |     .picker { | ||||||
|  |       font-size: 30px; | ||||||
|  |       font-weight: 500; | ||||||
|  |       color: #333333; | ||||||
|  |       margin-right: 8px; | ||||||
|  |  | ||||||
|  |       .u-icon-wrap { | ||||||
|  |         margin-left: 25px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .nav { | ||||||
|  |     position: fixed; | ||||||
|  |     top: 80px; | ||||||
|  |     background-color: #ffffff; | ||||||
|  |     height: 96px; | ||||||
|  |     padding-top: 8px; | ||||||
|  |     width: 100%; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .body { | ||||||
|  |     padding: 114px 0 0 0; | ||||||
|  |  | ||||||
|  |     .content { | ||||||
|  |       background-color: #ffffff; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       padding: 34px 32px; | ||||||
|  |       margin: 32px 20px; | ||||||
|  |  | ||||||
|  |       .top { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         width: 100%; | ||||||
|  |  | ||||||
|  |         .typeBox { | ||||||
|  |  | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .noactive { | ||||||
|  |           text-align: center; | ||||||
|  |           color: #2266ff; | ||||||
|  |           width: 70px; | ||||||
|  |           height: 44px; | ||||||
|  |           line-height: 44px; | ||||||
|  |           border-radius: 8px; | ||||||
|  |           background-color: #e8efff; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .active { | ||||||
|  |           text-align: center; | ||||||
|  |           color: #ff4466; | ||||||
|  |           line-height: 44px; | ||||||
|  |           width: 70px; | ||||||
|  |           height: 44px; | ||||||
|  |           border-radius: 8px; | ||||||
|  |           background-color: #ffebef; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .areaName { | ||||||
|  |           display: inline-block; | ||||||
|  |           color: #333; | ||||||
|  |           font-size: 32px; | ||||||
|  |           margin-left: 15px; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .title { | ||||||
|  |           color: #333; | ||||||
|  |           font-size: 32px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .cont { | ||||||
|  |         margin: 10px 0; | ||||||
|  |  | ||||||
|  |         .name_time { | ||||||
|  |           display: inline-block; | ||||||
|  |           width: 150px; | ||||||
|  |           height: 24px; | ||||||
|  |           color: #999; | ||||||
|  |           font-size: 30px; | ||||||
|  |           // font-weight: 800; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .text_c { | ||||||
|  |           color: #343d65; | ||||||
|  |           font-size: 30px; | ||||||
|  |           // font-weight: 800; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										442
									
								
								src/pages/casuallyask/casuallyaskDetail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,442 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="casuallyaskDetail"> | ||||||
|  |     <div class="detail"> | ||||||
|  |       <div class="headerTitle" flex> | ||||||
|  |         <div class="temp"> | ||||||
|  |           [{{ $dict.getLabel('leaveMessageType', detail.type) }}] | ||||||
|  |         </div> | ||||||
|  |         <span class="areaName">{{ detail.areaName }}</span> | ||||||
|  |         <span>{{ detail.title }}</span> | ||||||
|  |       </div> | ||||||
|  |       <div class="leaveName_leavePhone"> | ||||||
|  |         <!-- 顶部圆形头像 --> | ||||||
|  |         <span class="icon">{{ detail.headPortrait || $formatName(detail.leaveName) }}</span> | ||||||
|  |         <span class="leaveName">{{ detail.leaveName }}</span> | ||||||
|  |         <span class="leavePhone" v-if="detail.leavePhone">({{ detail.leavePhone }})</span> | ||||||
|  |       </div> | ||||||
|  |       <!-- 编号 --> | ||||||
|  |       <div class="info-item"> | ||||||
|  |         <span class="label"> | ||||||
|  |           <u-icon name="order"></u-icon> | ||||||
|  |         </span> | ||||||
|  |         <span class="value">{{ detail.msgCode }}</span> | ||||||
|  |       </div> | ||||||
|  |       <!-- 日期 --> | ||||||
|  |       <div class="info-item"> | ||||||
|  |         <span class="label"> | ||||||
|  |           <u-icon name="clock"></u-icon> | ||||||
|  |         </span> | ||||||
|  |         <span class="value">{{ detail.createTime }}</span> | ||||||
|  |       </div> | ||||||
|  |       <!-- 进度--> | ||||||
|  |       <div class="info-item"> | ||||||
|  |         <span class="label"><u-icon name="tags"/></span> | ||||||
|  |         <text class="status">{{ | ||||||
|  |             $dict.getLabel('leaveMessageStatus', detail.status) | ||||||
|  |           }} | ||||||
|  |         </text> | ||||||
|  |       </div> | ||||||
|  |       <div class="content_text_img"> | ||||||
|  |         <!-- 提问内容 --> | ||||||
|  |         <div class="content_text"> | ||||||
|  |           {{ detail.content }} | ||||||
|  |         </div> | ||||||
|  |         <!-- 提问内容的图片 --> | ||||||
|  |         <div class="imageList"> | ||||||
|  |           <ai-image preview :src="items.url" alt="" v-for="(items, i) in imgList" :key="i"/> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="reply_content" v-if="detail.status == 1 || detail.status == 2"> | ||||||
|  |         <div class="reply_title"> | ||||||
|  |           <img src="https://cdn.cunwuyun.cn/img/dialogue.svg" alt=""/> | ||||||
|  |           <p>沟通记录</p> | ||||||
|  |         </div> | ||||||
|  |         <div class="reply_list"> | ||||||
|  |           <div class="item" v-for="(item, index) in appLeaveMessageReplyList" :key="index"> | ||||||
|  |             <div class="item_top"> | ||||||
|  |               <div class="item_left"> | ||||||
|  |                 <div class="icon"> | ||||||
|  |                   {{ detail.headPortrait || $formatName(item.createUserName) }} | ||||||
|  |                 </div> | ||||||
|  |                 <div class="name fill"> | ||||||
|  |                   <div class="createUserName_createUnitName"> | ||||||
|  |                     <span v-if="item.createUserId == user.id" class="reply_font">我的回复</span> | ||||||
|  |                     <template v-else> | ||||||
|  |                       <span class="createUserName">{{ item.createUserName }} </span> | ||||||
|  |                       <span class="createUserName" v-if="item.createUserPhone">({{ item.createUserPhone }})</span> | ||||||
|  |                     </template> | ||||||
|  |                   </div> | ||||||
|  |                   <div flex v-if="item.createUserId != user.id"> | ||||||
|  |                     <!-- 回复单位 --> | ||||||
|  |                     <span class="createUnitName">{{ item.createUnitName }}</span> | ||||||
|  |                     <span class="reply">回复</span> | ||||||
|  |                   </div> | ||||||
|  |                 </div> | ||||||
|  |               </div> | ||||||
|  |               <div class="item_right">{{ item.createTime }}</div> | ||||||
|  |             </div> | ||||||
|  |             <!-- 回复内容 --> | ||||||
|  |             <div class="myreply_con"> | ||||||
|  |               <div class="myreply_text"> | ||||||
|  |                 {{ item.content }} | ||||||
|  |               </div> | ||||||
|  |               <!-- 回复图片 --> | ||||||
|  |               <div class="imageList"> | ||||||
|  |                 <ai-image v-for="img in item.images" :key="img.id" preview :src="img.url"/> | ||||||
|  |               </div> | ||||||
|  |               <!--  --> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="close_reply" v-if="detail.status == 0 || detail.status == 1"> | ||||||
|  |       <div class="btn" @click="close">关闭留言</div> | ||||||
|  |       <div class="btn reply" @click="reply">回复</div> | ||||||
|  |     </div> | ||||||
|  |     <u-modal | ||||||
|  |         v-model="show" | ||||||
|  |         :content="content" | ||||||
|  |         cancel-color="#2979ff" | ||||||
|  |         title="" | ||||||
|  |         :async-close="true" | ||||||
|  |         :show-cancel-button="true" | ||||||
|  |         @confirm="handleCloseMessage" | ||||||
|  |         @cancel="show = false"/> | ||||||
|  |     <back/> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import back from '../../components/AiBack' | ||||||
|  | import {mapState} from 'vuex' | ||||||
|  | import AiImage from "../../components/AiImage"; | ||||||
|  | import UImage from "../../uview/components/u-image/u-image"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: 'casuallyaskDetail', | ||||||
|  |   components: {UImage, AiImage, back}, | ||||||
|  |   props: {}, | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['user']) | ||||||
|  |   }, | ||||||
|  |   onLoad(options) { | ||||||
|  |     this.getDetail(options.id) | ||||||
|  |   }, | ||||||
|  |   onShow() { | ||||||
|  |     this.$dict.load('leaveMessageStatus', 'leaveMessageType') | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       objdie: '', // id | ||||||
|  |       appLeaveMessageReplyList: [], //遍历得到的数据 | ||||||
|  |       show: false, // 默认关闭模态框 | ||||||
|  |       content: '关闭留言后,双方都无法再进行回复,是否确定关闭本次留言?', | ||||||
|  |       msgCode: null, | ||||||
|  |       imgList: [], | ||||||
|  |       detail: {} | ||||||
|  |       // images:[] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getDetail(id = this.detail.id) { | ||||||
|  |       this.$http.post(`/app/appleavemessage/queryDetailById?id=${id}`,).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.detail = res.data | ||||||
|  |           this.imgList = JSON.parse(this.detail.images) | ||||||
|  |           this.appLeaveMessageReplyList = res.data.appLeaveMessageReplyList.map(item => ({ | ||||||
|  |             ...item, | ||||||
|  |             images: JSON.parse(item.images).map(e => ({url: e.url || e?.file?.accessUrl, id: e.file?.id})) | ||||||
|  |           })) | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     // 关闭留言 | ||||||
|  |     close() { | ||||||
|  |       this.show = true | ||||||
|  |       this.getDetail() | ||||||
|  |     }, | ||||||
|  |     // 确定关闭留言 | ||||||
|  |     handleCloseMessage() { | ||||||
|  |       this.$http.post(`/app/appleavemessage/release?id=${this.objdie}&status=2`).then(res => { | ||||||
|  |         if (res?.code == 0) { | ||||||
|  |           this.getDetail() | ||||||
|  |           uni.navigateTo({url: `./closemsg?flag=true`}) | ||||||
|  |         } | ||||||
|  |       }).catch(() => { | ||||||
|  |         uni.navigateTo({url: `./closemsg?flag=false`}) | ||||||
|  |       }) | ||||||
|  |       this.show = false | ||||||
|  |     }, | ||||||
|  |     // 去回复 | ||||||
|  |     reply() { | ||||||
|  |       uni.navigateTo({url: `./reply?msgCode=${this.detail.msgCode}`}) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .casuallyaskDetail { | ||||||
|  |   padding-bottom: 80px; | ||||||
|  |  | ||||||
|  |   .detail { | ||||||
|  |     padding: 15px 32px 112px 32px; | ||||||
|  |     background-color: #fff; | ||||||
|  |     font-size: 30px; | ||||||
|  |     font-weight: 400; | ||||||
|  |     color: #343D65; | ||||||
|  |  | ||||||
|  |     .headerTitle { | ||||||
|  |       font-size: 40px; | ||||||
|  |       font-weight: bold; | ||||||
|  |       color: #333; | ||||||
|  |       line-height: 64px; | ||||||
|  |       letter-spacing: 2px; | ||||||
|  |       flex-wrap: wrap; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .leaveName_leavePhone { | ||||||
|  |       height: 56px; | ||||||
|  |       margin: 20px 0 36px 0; | ||||||
|  |  | ||||||
|  |       .icon { | ||||||
|  |         display: inline-block; | ||||||
|  |         width: 56px; | ||||||
|  |         height: 56px; | ||||||
|  |         line-height: 56px; | ||||||
|  |         border-radius: 50%; | ||||||
|  |         background-color: #2266ff; | ||||||
|  |         color: #fff; | ||||||
|  |         font-size: 22px; | ||||||
|  |         vertical-align: middle; | ||||||
|  |         text-align: center; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .leaveName { | ||||||
|  |         // display: block; | ||||||
|  |         margin-left: 20px; | ||||||
|  |         color: #343d65; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // .leavePhone { | ||||||
|  |       // } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .info-item { | ||||||
|  |       height: 40px; | ||||||
|  |       line-height: 40px; | ||||||
|  |       font-size: 28px; | ||||||
|  |       margin-bottom: 8px; | ||||||
|  |  | ||||||
|  |       .label { | ||||||
|  |         display: inline-block; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .value { | ||||||
|  |         display: inline-block; | ||||||
|  |         margin-left: 20px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .status { | ||||||
|  |         display: inline-block; | ||||||
|  |         margin-left: 20px; | ||||||
|  |         // color: #999; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .content_text_img { | ||||||
|  |       margin-top: 64px; | ||||||
|  |       max-height: 700px; | ||||||
|  |       color: #000; | ||||||
|  |       font-size: 32px; | ||||||
|  |       // font-weight: 800; | ||||||
|  |       overflow: hidden; | ||||||
|  |  | ||||||
|  |       .content_text { | ||||||
|  |         width: 100%; | ||||||
|  |         margin-bottom: 12px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .reply_content { | ||||||
|  |       margin-top: 25px; | ||||||
|  |  | ||||||
|  |       .reply_title { | ||||||
|  |         margin-top: 25px; | ||||||
|  |         width: 225px; | ||||||
|  |         height: 45px; | ||||||
|  |         line-height: 45px; | ||||||
|  |  | ||||||
|  |         img { | ||||||
|  |           vertical-align: middle; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         p { | ||||||
|  |           display: inline-block; | ||||||
|  |           color: #333; | ||||||
|  |           // font-weight: 800; | ||||||
|  |           margin-left: 10px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .reply_list { | ||||||
|  |         .item { | ||||||
|  |           .item_top { | ||||||
|  |             display: flex; | ||||||
|  |             justify-content: space-between; | ||||||
|  |             margin-top: 10px; | ||||||
|  |  | ||||||
|  |             .item_left { | ||||||
|  |               display: flex; | ||||||
|  |               align-items: center; | ||||||
|  |               flex: 1; | ||||||
|  |               min-width: 0; | ||||||
|  |  | ||||||
|  |               .icon { | ||||||
|  |                 display: block; | ||||||
|  |                 flex-shrink: 0; | ||||||
|  |                 width: 64px; | ||||||
|  |                 height: 64px; | ||||||
|  |                 line-height: 64px; | ||||||
|  |                 border-radius: 50%; | ||||||
|  |                 background-color: #2266ff; | ||||||
|  |                 color: #fff; | ||||||
|  |                 font-size: 23px; | ||||||
|  |                 text-align: center; | ||||||
|  |                 margin-right: 10px; | ||||||
|  |               } | ||||||
|  |  | ||||||
|  |               .name { | ||||||
|  |                 display: flex; | ||||||
|  |                 flex-direction: column; | ||||||
|  |  | ||||||
|  |                 .createUnitName { | ||||||
|  |                   color: #135ab8; | ||||||
|  |                   margin-right: 8px; | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 .createUserName_createUnitName { | ||||||
|  |                   width: 100%; | ||||||
|  |                   display: flex; | ||||||
|  |  | ||||||
|  |                   .reply_font { | ||||||
|  |                     width: 120px; | ||||||
|  |                     color: #333333; | ||||||
|  |                     font-size: 28px; | ||||||
|  |                   } | ||||||
|  |  | ||||||
|  |                   .createUserName { | ||||||
|  |                     margin-bottom: 5px; | ||||||
|  |                     color: #135ab8; | ||||||
|  |                   } | ||||||
|  |                 } | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             .item_right { | ||||||
|  |               font-size: 26px; | ||||||
|  |               color: #999; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           .myreply_con { | ||||||
|  |             width: 570px; | ||||||
|  |             background-color: #f3f6f9; | ||||||
|  |             margin: 24px 0 0 80px; | ||||||
|  |             padding: 14px; | ||||||
|  |  | ||||||
|  |             .myreply_text { | ||||||
|  |               overflow: auto; | ||||||
|  |               word-wrap: break-word; | ||||||
|  |               word-break: break-all; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             .imageList { | ||||||
|  |               display: flex; | ||||||
|  |               flex-wrap: wrap; | ||||||
|  |  | ||||||
|  |               .AiImage { | ||||||
|  |                 margin: 0 12px 12px 0; | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .no_yes_reply { | ||||||
|  |           .con_title { | ||||||
|  |             display: flex; | ||||||
|  |             flex-direction: row; | ||||||
|  |             justify-content: space-between; | ||||||
|  |             margin-top: 16px; | ||||||
|  |             height: 64px; | ||||||
|  |             line-height: 64px; | ||||||
|  |  | ||||||
|  |             .icon { | ||||||
|  |               display: inline-block; | ||||||
|  |               width: 60px; | ||||||
|  |               height: 60px; | ||||||
|  |               line-height: 60px; | ||||||
|  |               border-radius: 50%; | ||||||
|  |               background-color: #2266ff; | ||||||
|  |               color: #fff; | ||||||
|  |               font-size: 23px; | ||||||
|  |               vertical-align: middle; | ||||||
|  |               text-align: center; | ||||||
|  |               // font-weight: 800; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             .my_reply { | ||||||
|  |               width: 370px; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             .right { | ||||||
|  |               color: #999; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           .myreply_content { | ||||||
|  |             width: 606px; | ||||||
|  |             height: 460px; | ||||||
|  |             background-color: #f3f6f9; | ||||||
|  |             margin: 24px 0 0 62px; | ||||||
|  |             padding: 16px; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .no_more { | ||||||
|  |       padding: 44px 0; | ||||||
|  |       color: #999; | ||||||
|  |       font-size: 24px; | ||||||
|  |       text-align: center; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .close_reply { | ||||||
|  |     position: fixed; | ||||||
|  |     bottom: 0; | ||||||
|  |     display: flex; | ||||||
|  |     height: 112px; | ||||||
|  |     width: 100%; | ||||||
|  |     border-top: 1px solid #ddd; | ||||||
|  |     z-index: 999; | ||||||
|  |     background: #fff; | ||||||
|  |  | ||||||
|  |     .btn { | ||||||
|  |       flex: 1; | ||||||
|  |       min-width: 0; | ||||||
|  |       background-color: #fff; | ||||||
|  |       display: flex; | ||||||
|  |       justify-content: center; | ||||||
|  |       align-items: center; | ||||||
|  |  | ||||||
|  |       &.reply { | ||||||
|  |         background-color: #1365dd; | ||||||
|  |         color: #fff; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										78
									
								
								src/pages/casuallyask/closemsg.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,78 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="closemsg"> | ||||||
|  |     <img :src="imgSrc" alt="" /> | ||||||
|  |     <text>{{ text }}</text> | ||||||
|  |     <u-button | ||||||
|  |       type="primary" | ||||||
|  |       :custom-style="{ width: '100%', borderRadius: '4px', marginTop: '48px' }" | ||||||
|  |       @click="goBack" | ||||||
|  |       >{{ btnText }}</u-button | ||||||
|  |     > | ||||||
|  |     <back></back> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import back from '../../components/AiBack' | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: 'CloseMsg', | ||||||
|  |   components: { back }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       flag: true | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   onLoad(val) { | ||||||
|  |     if (val.flag) { | ||||||
|  |       this.flag = val.flag | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     goBack() { | ||||||
|  |       uni.navigateBack({ | ||||||
|  |         // url: `/pages/casuallyask/casuallyask` | ||||||
|  |         delta: 1 | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     text() { | ||||||
|  |       return this.flag ? '关闭留言成功!' : '关闭留言失败' | ||||||
|  |     }, | ||||||
|  |     btnText() { | ||||||
|  |       return this.flag ? '确定' : '查看详情' | ||||||
|  |     }, | ||||||
|  |     imgSrc() { | ||||||
|  |       return this.flag | ||||||
|  |         ? this.imgOtherUrl + 'kztcg.png' | ||||||
|  |         : this.imgOtherUrl + 'kztsb.png' | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .closemsg { | ||||||
|  |   min-height: 100%; | ||||||
|  |   background-color: #ffffff; | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   align-items: center; | ||||||
|  |   padding: 96px; | ||||||
|  |  | ||||||
|  |   img { | ||||||
|  |     width: 192px; | ||||||
|  |     height: 192px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   text { | ||||||
|  |     font-size: 36px; | ||||||
|  |     font-weight: 800; | ||||||
|  |     color: #333333; | ||||||
|  |     line-height: 50px; | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: center; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										197
									
								
								src/pages/casuallyask/reply.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,197 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="reply"> | ||||||
|  |     <div class="reply_content"> | ||||||
|  |       <span class="icon">*</span> | ||||||
|  |       <text class="msgfont">回复内容</text> | ||||||
|  |       <textarea :maxlength="500" placeholder="请输入内容(500字以内)" v-model="msg" class="textarea"></textarea> | ||||||
|  |       <!-- <u-input | ||||||
|  |         type="textarea" | ||||||
|  |         height="50" | ||||||
|  |         :auto-height="false" | ||||||
|  |         placeholder="请输入内容(500字以内)" | ||||||
|  |         placeholder-style="color:#999;" | ||||||
|  |         maxlength="500" | ||||||
|  |         v-model="msg" | ||||||
|  |         class="textarea" | ||||||
|  |       /> --> | ||||||
|  |     </div> | ||||||
|  |     <div class="reply_img"> | ||||||
|  |       <text class="img">图片资料</text> | ||||||
|  |       <text class="img_text">(最多9张)</text> | ||||||
|  |       <div class="upload"> | ||||||
|  |         <div class="info"> | ||||||
|  |           <ai-uploader multiple @data="data" @change="change" :limit="9" action="/admin/file/add2"></ai-uploader> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <ai-back/> | ||||||
|  |     <div class="submit"> | ||||||
|  |       <button class="btn" @click="btn">提交</button> | ||||||
|  |     </div> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import AiUploader from '../../components/AiUploader' | ||||||
|  | import AiBack from "../../components/AiBack"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   // name: '', | ||||||
|  |   // 组件 | ||||||
|  |   components: {AiBack, AiUploader}, | ||||||
|  |   props: {}, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       msg: '', | ||||||
|  |       files: [], | ||||||
|  |       msgCode: '', | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   onLoad(options) { | ||||||
|  |     this.msgCode = options.msgCode | ||||||
|  |   }, | ||||||
|  |   // 计算 | ||||||
|  |   computed: {}, | ||||||
|  |   // 监听 | ||||||
|  |   watch: {}, | ||||||
|  |   // 实例创建后 | ||||||
|  |   onShow() { | ||||||
|  |     this.$dict.load('leaveMessageType').then(() => { | ||||||
|  |       this.dictList = this.$dict.getDict('leaveMessageType') | ||||||
|  |     }) | ||||||
|  |   }, | ||||||
|  |   // 实例渲染后 | ||||||
|  |   mounted() { | ||||||
|  |   }, | ||||||
|  |   // 方法 | ||||||
|  |   methods: { | ||||||
|  |     data(e) { | ||||||
|  |       this.files.push(e) | ||||||
|  |     }, | ||||||
|  |     // selectEventType(selecteds) { | ||||||
|  |     //   this.eventType = selecteds?.[0]?.value | ||||||
|  |     // }, | ||||||
|  |     change(e) { | ||||||
|  |       this.files = e | ||||||
|  |     }, | ||||||
|  |     btn() { | ||||||
|  |       if (this.msg == '') { | ||||||
|  |         return uni.showToast({ | ||||||
|  |           title: '请输入留言内容', | ||||||
|  |           icon: 'none', | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  |       this.$http | ||||||
|  |       .post(`/app/appleavemessagereply/addOrUpdate`, { | ||||||
|  |         images: JSON.stringify(this.files), | ||||||
|  |         content: this.msg, | ||||||
|  |         msgCode: this.msgCode, | ||||||
|  |         userType: '1', | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.code == 0) { | ||||||
|  |           uni.navigateTo({ | ||||||
|  |             url: `/pages/casuallyask/truemsg?flag=1`, | ||||||
|  |           }) | ||||||
|  |         } | ||||||
|  |       }).catch(err => { | ||||||
|  |         uni.navigateTo({ | ||||||
|  |           url: `/pages/casuallyask/truemsg?flag=0`, | ||||||
|  |         }) | ||||||
|  |         this.$u.toast(err || '网络异常') | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style scoped lang="scss"> | ||||||
|  | .reply { | ||||||
|  |   width: 100%; | ||||||
|  |   // height: 100%; | ||||||
|  |   .reply_content { | ||||||
|  |     height: 288px; | ||||||
|  |     padding: 0 20px 0 20px; | ||||||
|  |     background-color: #fff; | ||||||
|  |  | ||||||
|  |     .icon { | ||||||
|  |       display: inline-block; | ||||||
|  |       width: 16px; | ||||||
|  |       height: 44px; | ||||||
|  |       line-height: 44px; | ||||||
|  |       font-size: 42px; | ||||||
|  |       vertical-align: middle; | ||||||
|  |       color: red; | ||||||
|  |       margin-top: 10px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .msgfont { | ||||||
|  |       // overflow: auto; | ||||||
|  |       // word-wrap: break-word; | ||||||
|  |       // word-break: break-all; | ||||||
|  |       display: inline-block; | ||||||
|  |       width: 226px; | ||||||
|  |       height: 44px; | ||||||
|  |       margin-top: 34px; | ||||||
|  |       line-height: 44px; | ||||||
|  |       font-size: 32px; | ||||||
|  |       // font-weight: 800; | ||||||
|  |       margin-left: 10px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .textarea { | ||||||
|  |       height: 190px; | ||||||
|  |       width: 700px; | ||||||
|  |       // overflow: auto; | ||||||
|  |       // word-wrap: break-word; | ||||||
|  |       // word-break: break-all; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .reply_img { | ||||||
|  |     margin-top: 20px; | ||||||
|  |     background-color: #fff; | ||||||
|  |     padding: 0 20px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |  | ||||||
|  |     .img { | ||||||
|  |       display: inline-block; | ||||||
|  |       margin-top: 20px; | ||||||
|  |       font-size: 32px; | ||||||
|  |       // font-weight: 800; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .img_text { | ||||||
|  |       font-size: 32px; | ||||||
|  |       color: #999; | ||||||
|  |       margin-left: 10px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .upload { | ||||||
|  |       width: 100%; | ||||||
|  |       margin-top: 10px; | ||||||
|  |       padding: 12px 12px 12px 0; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |  | ||||||
|  |       .info { | ||||||
|  |         width: 100%; | ||||||
|  |         text-align: center; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       ::v-deep .ai-uploader .fileList .default { | ||||||
|  |         width: 160px; | ||||||
|  |         height: 160px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .submit { | ||||||
|  |     padding: 50px 32px; | ||||||
|  |  | ||||||
|  |     .btn { | ||||||
|  |       background-color: #1365dd; | ||||||
|  |       color: #fff; | ||||||
|  |       font-size: 36px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										75
									
								
								src/pages/casuallyask/truemsg.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,75 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="closemsg"> | ||||||
|  |     <img :src="imgSrc" alt=""/> | ||||||
|  |     <text>{{ text }}</text> | ||||||
|  |     <u-button | ||||||
|  |         type="primary" | ||||||
|  |         :custom-style="{ width: '100%', borderRadius: '4px', marginTop: '48px' }" | ||||||
|  |         @click="goBack" | ||||||
|  |     >{{ btnText }} | ||||||
|  |     </u-button> | ||||||
|  |     <back></back> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import back from '../../components/AiBack' | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: 'CloseMsg', | ||||||
|  |   components: {back}, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       flag: true | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   onLoad(val) { | ||||||
|  |     this.flag = val?.flag == 1 | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     goBack() { | ||||||
|  |       uni.navigateBack({ | ||||||
|  |         delta: 2 | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     text() { | ||||||
|  |       return this.flag ? '提交成功!' : '处理失败' | ||||||
|  |     }, | ||||||
|  |     btnText() { | ||||||
|  |       return this.flag ? '查看详情' : '我知道了' | ||||||
|  |     }, | ||||||
|  |     imgSrc() { | ||||||
|  |       return this.flag | ||||||
|  |           ? this.imgOtherUrl + 'kztcg.png' | ||||||
|  |           : this.imgOtherUrl + 'kztsb.png' | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .closemsg { | ||||||
|  |   min-height: 100%; | ||||||
|  |   background-color: #ffffff; | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   align-items: center; | ||||||
|  |   padding: 96px; | ||||||
|  |  | ||||||
|  |   img { | ||||||
|  |     width: 192px; | ||||||
|  |     height: 192px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   text { | ||||||
|  |     font-size: 36px; | ||||||
|  |     font-weight: 800; | ||||||
|  |     color: #333333; | ||||||
|  |     line-height: 50px; | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: center; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										91
									
								
								src/pages/documentFlow/components/approval.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,91 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="approval"> | ||||||
|  |     <div class="card"> | ||||||
|  |       <header>批示意见</header> | ||||||
|  |       <textarea placeholder="请输入批示意见" v-model.trim="description" maxlength="200"></textarea> | ||||||
|  |       <u-row justify="between"> | ||||||
|  |         <span @click="description=''">清空内容</span> | ||||||
|  |         <span>{{description.length || 0}}/200</span> | ||||||
|  |       </u-row> | ||||||
|  |     </div> | ||||||
|  |     <ai-back/> | ||||||
|  |     <u-button type="primary" @click="submit">提交</u-button> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  |   import AiBack from "../../../components/AiBack"; | ||||||
|  |  | ||||||
|  |   export default { | ||||||
|  |     name: "approval", | ||||||
|  |     components: {AiBack}, | ||||||
|  |     data() { | ||||||
|  |       return { | ||||||
|  |         id: null, | ||||||
|  |         description: "" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     onLoad(opt) { | ||||||
|  |       this.id = opt.id | ||||||
|  |     }, | ||||||
|  |     methods: { | ||||||
|  |       submit() { | ||||||
|  |         this.$http.post("/app/appofficialdocumentinfo/instructionById", null, { | ||||||
|  |           params: { | ||||||
|  |             id: this.id, | ||||||
|  |             description: this.description | ||||||
|  |           } | ||||||
|  |         }).then(res => { | ||||||
|  |           if (res.code == 0) { | ||||||
|  |             this.$u.toast("批示成功") | ||||||
|  |             uni.navigateBack() | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  |   .approval { | ||||||
|  |     background: #F5F5F5; | ||||||
|  |  | ||||||
|  |     .card { | ||||||
|  |       background-color: #FFFFFF; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       padding: 32px; | ||||||
|  |  | ||||||
|  |       header { | ||||||
|  |         font-size: 32px; | ||||||
|  |         color: #333333; | ||||||
|  |         margin-bottom: 16px; | ||||||
|  |         font-weight: bold; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       textarea { | ||||||
|  |         width: 100%; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       span:first-child { | ||||||
|  |         font-size: 28px; | ||||||
|  |         color: #1365DD; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       span:last-child { | ||||||
|  |         font-size: 24px; | ||||||
|  |         color: #999999; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .u-btn { | ||||||
|  |       width: 100%; | ||||||
|  |       height: 112px !important; | ||||||
|  |       font-size: 32px; | ||||||
|  |       color: #FFFFFF; | ||||||
|  |       position: fixed; | ||||||
|  |       left: 0; | ||||||
|  |       bottom: 0; | ||||||
|  |       background: #197DF0 !important; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										432
									
								
								src/pages/documentFlow/components/detail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,432 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="detail"> | ||||||
|  |     <template v-if="!userSelect"> | ||||||
|  |       <div class="card"> | ||||||
|  |         <header>{{detail.documentName}}</header> | ||||||
|  |         <u-gap height="16"></u-gap> | ||||||
|  |         <u-row> | ||||||
|  |           <span>公文编号:</span> | ||||||
|  |           <span>{{detail.documentCode}}</span> | ||||||
|  |         </u-row> | ||||||
|  |         <u-gap height="8"></u-gap> | ||||||
|  |         <u-row> | ||||||
|  |           <span>公文类型:</span> | ||||||
|  |           <span>{{$dict.getLabel("officialDocumentName",detail.documentType)}}</span> | ||||||
|  |         </u-row> | ||||||
|  |         <u-gap height="8"></u-gap> | ||||||
|  |         <u-row> | ||||||
|  |           <span>紧急程度:</span> | ||||||
|  |           <span :style="{color:$dict.getColor('documentEmergencyLevel',detail.emergencyLevel)}">{{$dict.getLabel("documentEmergencyLevel",detail.emergencyLevel)}}</span> | ||||||
|  |         </u-row> | ||||||
|  |         <u-gap height="8"></u-gap> | ||||||
|  |         <u-row> | ||||||
|  |           <span>发文机关:</span> | ||||||
|  |           <span>{{detail.issuingUnit}}</span> | ||||||
|  |         </u-row> | ||||||
|  |         <u-gap height="8"></u-gap> | ||||||
|  |         <u-row> | ||||||
|  |           <span>发文字号:</span> | ||||||
|  |           <span>{{detail.issuingFont}}</span> | ||||||
|  |         </u-row> | ||||||
|  |         <u-gap height="8"></u-gap> | ||||||
|  |         <u-row> | ||||||
|  |           <span>签发人:</span> | ||||||
|  |           <span>{{detail.signer}}</span> | ||||||
|  |         </u-row> | ||||||
|  |         <u-gap height="16"></u-gap> | ||||||
|  |         <img v-if="detail.confidentialityLevel" :src="$cdn + tag(detail.confidentialityLevel)" alt=""> | ||||||
|  |       </div> | ||||||
|  |       <div class="card" style="margin-bottom: 0;padding-top: 0"> | ||||||
|  |         <div class="label">备注</div> | ||||||
|  |         <span>{{detail.remark}}</span> | ||||||
|  |       </div> | ||||||
|  |       <div class="card" style="padding-top: 0" v-if="detail.files && detail.files.length"> | ||||||
|  |         <div class="label">相关附件</div> | ||||||
|  |         <div class="file" v-for="(item,index) in detail.files" :key="index" @click="preFile(item)"> | ||||||
|  |           <u-row justify="between"> | ||||||
|  |             <label class="left"> | ||||||
|  |               <img :src="$cdn + 'common/appendix.png'" alt=""> | ||||||
|  |               <span>{{item.fileName}}.{{item.postfix}}</span> | ||||||
|  |             </label> | ||||||
|  |             <span>{{(item.size/1024).toFixed(2)}}KB</span> | ||||||
|  |           </u-row> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="card"> | ||||||
|  |         <div class="label" style="96px;">{{detail.readType ==0 ? "流转信息" : "传阅情况"}} | ||||||
|  |           <em>({{$dict.getLabel("documentStatus",detail.status)}})</em></div> | ||||||
|  |         <div class="progress"> | ||||||
|  |           <div class="item" v-for="(item,index) in detail.flowUsers" :key="index"> | ||||||
|  |             <div class="avatar">{{item.flowUserName && item.flowUserName.substr(-2)}}</div> | ||||||
|  |             <div class="right"> | ||||||
|  |               <u-row justify="between"> | ||||||
|  |                 <text class="status" :style="{color:item.readStatus==1?'#FF8822':'#1365DD'}">{{$dict.getLabel(detail.readType ==1 ? "readingStatus" : | ||||||
|  |                   "documentFlowStatus",detail.readType ==0 ? item.flowStatus : item.readStatus)}} | ||||||
|  |                 </text> | ||||||
|  |                 <text class="date">{{item.flowTime}}</text> | ||||||
|  |               </u-row> | ||||||
|  |               <u-row justify="between"> | ||||||
|  |                 <text class="name">{{item.flowUserName}}</text> | ||||||
|  |               </u-row> | ||||||
|  |               <u-row justify="between"> | ||||||
|  |                 <text class="note">{{item.description}}</text> | ||||||
|  |               </u-row> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |  | ||||||
|  |       <div class="footer" v-if="detail.flowRight==1 && detail.readType==0"> | ||||||
|  |         <div @click="handleClick(0)">批示</div> | ||||||
|  |         <div @click="handleClick(1)">流转</div> | ||||||
|  |       </div> | ||||||
|  |  | ||||||
|  |       <div class="footer" v-if="detail.readType==1 && detail.flowRight==1" @click="read" style="background-color: #1365DD;color: #FFFFFF">我已阅完</div> | ||||||
|  |  | ||||||
|  |     </template> | ||||||
|  |  | ||||||
|  |     <AiSelectEnterprise :visible.sync="userSelect" v-if="userSelect" :multiple="false" | ||||||
|  |                         @change="change"></AiSelectEnterprise> | ||||||
|  |  | ||||||
|  |     <AiBack v-if="!userSelect"/> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  |   import AiBack from "../../../components/AiBack"; | ||||||
|  |   import AiSelectEnterprise from "../../../components/AiSelectEnterprise/AiSelectEnterprise"; | ||||||
|  |   import {mapActions} from "vuex"; | ||||||
|  |  | ||||||
|  |   export default { | ||||||
|  |     name: "detail", | ||||||
|  |     components: {AiBack, AiSelectEnterprise}, | ||||||
|  |     data() { | ||||||
|  |       return { | ||||||
|  |         id: null, | ||||||
|  |         detail: {}, | ||||||
|  |         userSelect: false, | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     onLoad(opt) { | ||||||
|  |       this.$dict.load("officialDocumentName", "documentEmergencyLevel", "documentStatus", "readingStatus", "documentFlowStatus") | ||||||
|  |       this.id = opt.id | ||||||
|  |     }, | ||||||
|  |  | ||||||
|  |     methods: { | ||||||
|  |       ...mapActions(['previewFile', 'injectJWeixin']), | ||||||
|  |       read() { | ||||||
|  |         this.$http.post("/app/appofficialdocumentinfo/readById", null, { | ||||||
|  |           params: { | ||||||
|  |             id: this.id | ||||||
|  |           } | ||||||
|  |         }).then(res => { | ||||||
|  |           if (res.code == 0) { | ||||||
|  |             this.$u.toast("已阅读") | ||||||
|  |             this.getDetail() | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       }, | ||||||
|  |       preFile(e) { | ||||||
|  |         if([".jpg",".png",".gif"].includes(e.postfix.toLowerCase())){ | ||||||
|  |           uni.previewImage({ | ||||||
|  |             current: e.url, | ||||||
|  |             urls: [e.url] | ||||||
|  |           }) | ||||||
|  |         }else { | ||||||
|  |           this.previewFile({...e}) | ||||||
|  |         } | ||||||
|  |       }, | ||||||
|  |       change(e) { | ||||||
|  |         this.$http.post("/app/appofficialdocumentinfo/flowById", null, { | ||||||
|  |           params: { | ||||||
|  |             flowUserId: e[0].id, | ||||||
|  |             flowUserName: e[0].name, | ||||||
|  |             id: this.id, | ||||||
|  |             avatar: e[0].avatar, | ||||||
|  |             flag: 0 | ||||||
|  |           } | ||||||
|  |         }).then(res => { | ||||||
|  |           if (res.code == 0) { | ||||||
|  |             this.$u.toast("流转成功") | ||||||
|  |             this.getDetail() | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       }, | ||||||
|  |  | ||||||
|  |       tag(status) { | ||||||
|  |         return { | ||||||
|  |           "0": "common/mm.png", | ||||||
|  |           "1": "common/jm.png", | ||||||
|  |           "2": "common/tm.png" | ||||||
|  |         }[status] | ||||||
|  |       }, | ||||||
|  |       getDetail() { | ||||||
|  |         this.$http.post("/app/appofficialdocumentinfo/queryDetailById", null, { | ||||||
|  |           params: { | ||||||
|  |             id: this.id, | ||||||
|  |             flag: 1 | ||||||
|  |           } | ||||||
|  |         }).then(res => { | ||||||
|  |           if (res && res.data) { | ||||||
|  |             this.detail = res.data | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       }, | ||||||
|  |       handleClick(status) { | ||||||
|  |         if (status == 0) { | ||||||
|  |           uni.navigateTo({ | ||||||
|  |             url: "/pages/documentFlow/components/approval?id=" + this.id | ||||||
|  |           }) | ||||||
|  |         } else { | ||||||
|  |           this.userSelect = true | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     onShow() { | ||||||
|  |       this.getDetail() | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  |   .detail { | ||||||
|  |     min-height: 100%; | ||||||
|  |     background-color: #F5F5F5; | ||||||
|  |     padding-bottom: 140px; | ||||||
|  |     position: relative; | ||||||
|  |  | ||||||
|  |     .card { | ||||||
|  |       background-color: #FFFFFF; | ||||||
|  |       margin-bottom: 8px; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       padding: 16px 32px; | ||||||
|  |       position: relative; | ||||||
|  |  | ||||||
|  |       header { | ||||||
|  |         font-size: 40px; | ||||||
|  |         font-weight: 600; | ||||||
|  |         color: #333333; | ||||||
|  |         line-height: 64px; | ||||||
|  |         letter-spacing: 1px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .u-row { | ||||||
|  |         & > div { | ||||||
|  |           background-color: #2266FF; | ||||||
|  |           border-radius: 50%; | ||||||
|  |           text-align: center; | ||||||
|  |           font-size: 22px; | ||||||
|  |           font-weight: bold; | ||||||
|  |           color: #FFFFFF; | ||||||
|  |           display: flex; | ||||||
|  |           align-items: center; | ||||||
|  |           justify-content: center; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         & > span:first-child { | ||||||
|  |           font-size: 30px; | ||||||
|  |           color: #999999;; | ||||||
|  |           line-height: 48px; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         & > span:last-child { | ||||||
|  |           font-size: 30px; | ||||||
|  |           color: #343D65; | ||||||
|  |           margin-left: 16px; | ||||||
|  |           line-height: 48px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       & > img { | ||||||
|  |         width: 190px; | ||||||
|  |         height: 190px; | ||||||
|  |         position: absolute; | ||||||
|  |         right: 0; | ||||||
|  |         top: 74px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       & > span { | ||||||
|  |         font-size: 32px; | ||||||
|  |         color: #333333; | ||||||
|  |         line-height: 48px; | ||||||
|  |         letter-spacing: 1px; | ||||||
|  |         display: inline-block; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .label { | ||||||
|  |         height: 80px; | ||||||
|  |         font-size: 32px; | ||||||
|  |         color: #333333; | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         margin-bottom: 16px; | ||||||
|  |  | ||||||
|  |         & > em { | ||||||
|  |           font-style: normal; | ||||||
|  |           font-size: 32px; | ||||||
|  |           color: #1365DD; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .file { | ||||||
|  |         height: 128px; | ||||||
|  |         background: #FFFFFF; | ||||||
|  |         border-radius: 8px; | ||||||
|  |         border: 1px solid #CCCCCC; | ||||||
|  |         box-sizing: border-box; | ||||||
|  |         padding: 0 16px; | ||||||
|  |         margin-bottom: 32px; | ||||||
|  |  | ||||||
|  |         & > .u-row { | ||||||
|  |           height: 100%; | ||||||
|  |  | ||||||
|  |           .left { | ||||||
|  |             width: 500px; | ||||||
|  |             display: flex; | ||||||
|  |             align-items: center; | ||||||
|  |  | ||||||
|  |             & > img { | ||||||
|  |               flex-shrink: 0; | ||||||
|  |               width: 96px; | ||||||
|  |               height: 96px; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             & > span { | ||||||
|  |               font-size: 32px; | ||||||
|  |               color: #333333; | ||||||
|  |               display: inline-block; | ||||||
|  |               line-height: 44px; | ||||||
|  |               overflow: hidden; | ||||||
|  |               text-overflow: ellipsis; | ||||||
|  |               display:-webkit-box; | ||||||
|  |               -webkit-box-orient:vertical; | ||||||
|  |               -webkit-line-clamp:2; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           & > span { | ||||||
|  |             font-size: 28px; | ||||||
|  |             color: #999999; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .active { | ||||||
|  |         background-color: #F3F6F9; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .progress { | ||||||
|  |         margin-top: 8px; | ||||||
|  |  | ||||||
|  |         .item { | ||||||
|  |           display: flex; | ||||||
|  |           align-items: center; | ||||||
|  |           position: relative; | ||||||
|  |           min-height: 136px; | ||||||
|  |           margin-bottom: 80px; | ||||||
|  |  | ||||||
|  |           .avatar { | ||||||
|  |             width: 80px; | ||||||
|  |             height: 80px; | ||||||
|  |             border-radius: 50%; | ||||||
|  |             background-color: #2266FF; | ||||||
|  |             font-size: 28px; | ||||||
|  |             color: #FFFFFF; | ||||||
|  |             display: flex; | ||||||
|  |             align-items: center; | ||||||
|  |             justify-content: center; | ||||||
|  |             flex-shrink: 0; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           .right { | ||||||
|  |             width: 100%; | ||||||
|  |             display: flex; | ||||||
|  |             flex-direction: column; | ||||||
|  |  | ||||||
|  |             & > .u-row { | ||||||
|  |               margin-left: 40px; | ||||||
|  |  | ||||||
|  |               .status { | ||||||
|  |                 font-size: 32px; | ||||||
|  |                 color: #333333; | ||||||
|  |               } | ||||||
|  |  | ||||||
|  |               .date { | ||||||
|  |                 font-size: 28px; | ||||||
|  |                 color: #999999; | ||||||
|  |               } | ||||||
|  |  | ||||||
|  |               .name { | ||||||
|  |                 font-size: 28px; | ||||||
|  |                 color: #666666; | ||||||
|  |                 margin: 8px 0; | ||||||
|  |               } | ||||||
|  |  | ||||||
|  |               .note { | ||||||
|  |                 font-size: 28px; | ||||||
|  |                 color: #343D65; | ||||||
|  |               } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           &:after { | ||||||
|  |             content: ""; | ||||||
|  |             width: 4px; | ||||||
|  |             height: 100%; | ||||||
|  |             background-color: #EEEEEE; | ||||||
|  |             position: absolute; | ||||||
|  |             left: 40px; | ||||||
|  |             top: 112px; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           &:last-child:after { | ||||||
|  |             display: none; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .footer { | ||||||
|  |       height: 112px; | ||||||
|  |       width: 100%; | ||||||
|  |       position: fixed; | ||||||
|  |       left: 0; | ||||||
|  |       bottom: 0; | ||||||
|  |       background-color: #FFFFFF; | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |       justify-content: center; | ||||||
|  |       font-size: 36px; | ||||||
|  |  | ||||||
|  |       & > div { | ||||||
|  |         color: #333333; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       & > div:first-child { | ||||||
|  |         width: 50%; | ||||||
|  |         height: 100%; | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: center; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       & > div:last-child { | ||||||
|  |         width: 50%; | ||||||
|  |         height: 100%; | ||||||
|  |         color: #FFFFFF; | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: center; | ||||||
|  |         background-color: #1365DD; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       & > label { | ||||||
|  |         display: flex; | ||||||
|  |         align-items: center; | ||||||
|  |         justify-content: center; | ||||||
|  |         background-color: #1365DD; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										166
									
								
								src/pages/documentFlow/documentFlow.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,166 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="document-flow"> | ||||||
|  |     <ai-top-fixed> | ||||||
|  |       <header class="pad"> | ||||||
|  |         <u-search placeholder="请输入公文名称" v-model="documentName" @clear="documentName='',getList()" @search="getList" clearabled :show-action="false" height="64"></u-search> | ||||||
|  |       </header> | ||||||
|  |     </ai-top-fixed> | ||||||
|  |     <div class="list pad" v-if="list.length"> | ||||||
|  |       <div class="card" v-for="(item,index) in list" :key="index" @click="handleClick(item)"> | ||||||
|  |         <u-row> | ||||||
|  |           <em v-if="item.redStatus==0"></em> | ||||||
|  |           <span>{{item.documentName}}</span> | ||||||
|  |         </u-row> | ||||||
|  |         <u-gap height="16"></u-gap> | ||||||
|  |         <u-row> | ||||||
|  |           <label>公文类型:</label> | ||||||
|  |           <text style="color: #1365DD;">{{$dict.getLabel("officialDocumentName",item.documentType)}}</text> | ||||||
|  |         </u-row> | ||||||
|  |         <u-gap height="8"></u-gap> | ||||||
|  |         <u-row> | ||||||
|  |           <label>登记人:</label> | ||||||
|  |           <text>{{item.createUserName}}</text> | ||||||
|  |         </u-row> | ||||||
|  |         <u-gap height="8"></u-gap> | ||||||
|  |         <u-row> | ||||||
|  |           <label>登记日期:</label> | ||||||
|  |           <text>{{item.createTime}}</text> | ||||||
|  |         </u-row> | ||||||
|  |         <img :src=" $cdn + tag(item.readType)" alt=""> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <AiEmpty v-else></AiEmpty> | ||||||
|  |     <u-loadmore :status="status" v-if="list.length"/> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  |   import AiTopFixed from "../../components/AiTopFixed"; | ||||||
|  |   import AiEmpty from "../../components/AiEmpty/AiEmpty"; | ||||||
|  |  | ||||||
|  |   export default { | ||||||
|  |     name: "documentFlow", | ||||||
|  |     components: {AiTopFixed,AiEmpty}, | ||||||
|  |     data() { | ||||||
|  |       return { | ||||||
|  |         documentName: "", | ||||||
|  |         current: 1, | ||||||
|  |         list: [], | ||||||
|  |         status: "加载更多" | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     onLoad(){ | ||||||
|  |       this.$dict.load("officialDocumentName") | ||||||
|  |     }, | ||||||
|  |     methods: { | ||||||
|  |       tag(status){ | ||||||
|  |         return { | ||||||
|  |           "0": 'common/1ps.png', | ||||||
|  |           "1": 'common/2cy.png' | ||||||
|  |         }[status] | ||||||
|  |       }, | ||||||
|  |       getList() { | ||||||
|  |         this.$http.post("/app/appofficialdocumentinfo/appList", null, { | ||||||
|  |           params:{ | ||||||
|  |             documentName: this.documentName, | ||||||
|  |             size: 10, | ||||||
|  |             current: this.current | ||||||
|  |           } | ||||||
|  |         }).then(res => { | ||||||
|  |           if (res && res.data) { | ||||||
|  |             if (this.current > 1 && this.current > res.data.pages) { | ||||||
|  |               this.status = "已经到底啦" | ||||||
|  |             } | ||||||
|  |             this.list = this.current > 1 ? [...this.list, ...res.data.records] : res.data.records | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       }, | ||||||
|  |       handleClick({id}) { | ||||||
|  |         uni.navigateTo({ | ||||||
|  |           url: "/pages/documentFlow/components/detail?id=" + id | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     onShow(){ | ||||||
|  |       this.getList() | ||||||
|  |     }, | ||||||
|  |     onReachBottom() { | ||||||
|  |       this.current = this.current + 1; | ||||||
|  |       this.getList() | ||||||
|  |     }, | ||||||
|  |   } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  |   .document-flow { | ||||||
|  |     min-height: 100%; | ||||||
|  |     background: #F5F5F5; | ||||||
|  |  | ||||||
|  |     ::v-deep .content { | ||||||
|  |       padding: 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     header { | ||||||
|  |       height: 112px; | ||||||
|  |       background-color: #FFFFFF; | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .list { | ||||||
|  |       margin: 32px 0; | ||||||
|  |  | ||||||
|  |       .card { | ||||||
|  |         background: #FFFFFF; | ||||||
|  |         border-radius: 8px; | ||||||
|  |         box-sizing: border-box; | ||||||
|  |         padding: 32px; | ||||||
|  |         position: relative; | ||||||
|  |         margin-bottom: 32px; | ||||||
|  |  | ||||||
|  |         .u-row{ | ||||||
|  |           flex-wrap: nowrap !important; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         em { | ||||||
|  |           width: 16px; | ||||||
|  |           height: 16px; | ||||||
|  |           border-radius: 50%; | ||||||
|  |           background-color: #FF4466; | ||||||
|  |           font-style: normal; | ||||||
|  |           margin-right: 8px; | ||||||
|  |           flex-shrink: 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         span { | ||||||
|  |           font-size: 32px; | ||||||
|  |           font-weight: 600; | ||||||
|  |           color: #333333; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         label { | ||||||
|  |           font-size: 30px; | ||||||
|  |           color: #999999; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         text { | ||||||
|  |           font-size: 30px; | ||||||
|  |           color: #343D65; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         img { | ||||||
|  |           width: 160px; | ||||||
|  |           height: 160px; | ||||||
|  |           position: absolute; | ||||||
|  |           right: 0; | ||||||
|  |           bottom: 0; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .pad { | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       padding: 32px 32px 0 32px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | </style> | ||||||
							
								
								
									
										146
									
								
								src/pages/guardianship/component/areaSelector.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,146 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="areaSelector"> | ||||||
|  |     <ai-search-popup mode="bottom" ref="areaSelector"> | ||||||
|  |       <template #btn> | ||||||
|  |         <div class="areaSelector"> | ||||||
|  |           <span v-for="area in fullArea" :key="area.id" v-text="area.name" | ||||||
|  |                 :class="{current:area.id==areaId}"  @tap="index=area.id,getChildAreas(area.id)"/> | ||||||
|  |         </div> | ||||||
|  |       </template> | ||||||
|  |       <div class="areaSelector"> | ||||||
|  |         <span v-for="area in fullArea" :key="area.id" v-text="area.name" | ||||||
|  |               :class="{current:area.id==index}" | ||||||
|  |               @click="index=area.id,getChildAreas(area.id)"/> | ||||||
|  |       </div> | ||||||
|  |       <div class="pendingItem" flex v-for="op in list" :key="op.id" @tap="handleSelect(op)"> | ||||||
|  |         <div class="fill" :class="{self:index==op.id}" v-html="op.name"/> | ||||||
|  |         <u-icon name="arrow-right" color="#ddd"/> | ||||||
|  |       </div> | ||||||
|  |     </ai-search-popup> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import AiSearchPopup from "../../../components/AiSearchPopup"; | ||||||
|  | import AiCell from "../../../components/AiCell"; | ||||||
|  | import {mapState} from "vuex"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "areaSelector", | ||||||
|  |   components: {AiCell, AiSearchPopup}, | ||||||
|  |   props: { | ||||||
|  |     areaId: {default: ""} | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['user']), | ||||||
|  |     dataRange() { | ||||||
|  |       let rules = [10, 8, 6, 3, 0], level = 2 | ||||||
|  |       rules.some((e, i) => { | ||||||
|  |         let reg = new RegExp(`0{${e}}`, 'g') | ||||||
|  |         if (reg.test(this.user.areaId)) { | ||||||
|  |           return level = i | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |       return level | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       fullArea: [], | ||||||
|  |       index: "", | ||||||
|  |       list: [] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   watch: { | ||||||
|  |     areaId(v) { | ||||||
|  |       v && this.getFullArea() | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getFullArea() { | ||||||
|  |       let {areaId} = this | ||||||
|  |       return areaId && this.$http.post("/admin/area/getAllParentAreaId", null, { | ||||||
|  |         params: {areaId} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.fullArea = res.data.reverse().slice(this.dataRange) | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     getChildAreas(id) { | ||||||
|  |       id && this.$http.post("/admin/area/queryAreaByParentId", null, { | ||||||
|  |         params: {id} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.list = res.data | ||||||
|  |           let self = this.fullArea.find(e => e.id == this.index) | ||||||
|  |           this.list.unshift(self) | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     handleSelect(op) { | ||||||
|  |       this.$emit('select', op) | ||||||
|  |       this.$refs.areaSelector?.handleSelect() | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.index = this.areaId | ||||||
|  |     this.getFullArea() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .areaSelector { | ||||||
|  |   ::v-deep .AiSearchPopup { | ||||||
|  |     .areaSelector { | ||||||
|  |       display: flex; | ||||||
|  |       align-items: center; | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         cursor: pointer; | ||||||
|  |  | ||||||
|  |         &:first-of-type:before { | ||||||
|  |           content: ""; | ||||||
|  |           padding: 0; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         &:before { | ||||||
|  |           color: #333; | ||||||
|  |           content: "/"; | ||||||
|  |           padding: 0 16px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .current { | ||||||
|  |         color: #3F8DF5; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .u-drawer-content { | ||||||
|  |       position: fixed; | ||||||
|  |  | ||||||
|  |       .areaSelector { | ||||||
|  |         padding: 0 16px; | ||||||
|  |         box-sizing: border-box; | ||||||
|  |         border-bottom: 16px solid #f5f5f5; | ||||||
|  |  | ||||||
|  |         span { | ||||||
|  |           line-height: 100px; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .pendingItem { | ||||||
|  |       margin-left: 32px; | ||||||
|  |       padding-right: 32px; | ||||||
|  |       height: 104px; | ||||||
|  |       border-bottom: 1px solid #ddd; | ||||||
|  |  | ||||||
|  |       .self { | ||||||
|  |         font-weight: bold; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										73
									
								
								src/pages/guardianship/component/makeCalls.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,73 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="makeCalls"> | ||||||
|  |     <div v-if="$slots.default" @tap="calls=true"> | ||||||
|  |       <slot/> | ||||||
|  |     </div> | ||||||
|  |     <div v-else flex class="column" @tap="calls=true"> | ||||||
|  |       <img :src="`${$cdn}guardianship/dh.png`"/> | ||||||
|  |       <span v-html="label"/> | ||||||
|  |     </div> | ||||||
|  |     <u-popup v-model="calls" mode="bottom"> | ||||||
|  |       <div flex class="column option" v-for="item in list" @click="handleCall(item.guardianPhone)"> | ||||||
|  |         {{ [item.guardianName, item.guardianPhone].join('   ') }} | ||||||
|  |       </div> | ||||||
|  |       <div class="option" @tap="calls=false">取消</div> | ||||||
|  |     </u-popup> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: "makeCalls", | ||||||
|  |   props: { | ||||||
|  |     label: {default: "联系ta"}, | ||||||
|  |     list: {default: () => []} | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       calls: false | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     handleCall(phone) { | ||||||
|  |       location.href = "tel:" + phone | ||||||
|  |     }, | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .makeCalls { | ||||||
|  |   img { | ||||||
|  |     width: 40px; | ||||||
|  |     height: 40px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep span { | ||||||
|  |     margin-left: 0; | ||||||
|  |     color: #999; | ||||||
|  |     font-size: 20px; | ||||||
|  |  | ||||||
|  |     p { | ||||||
|  |       color: #3D94FB; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .u-drawer { | ||||||
|  |     text-align: center; | ||||||
|  |     .uni-scroll-view-content{ | ||||||
|  |       max-height: 672px; | ||||||
|  |     } | ||||||
|  |     .option { | ||||||
|  |       font-size: 32px; | ||||||
|  |       cursor: pointer; | ||||||
|  |       line-height: 112px; | ||||||
|  |       border-bottom: 1px solid #D8DDE6; | ||||||
|  |  | ||||||
|  |       &:first-of-type { | ||||||
|  |         border-radius: 16px 16px 0 0; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										40
									
								
								src/pages/guardianship/component/openMap.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,40 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="openMap"> | ||||||
|  |     <div flex class="column" shrink @tap="handleOpenMap"> | ||||||
|  |       <img :src="`${$cdn}guardianship/seat.png`"/> | ||||||
|  |       <span v-text="'地图/导航'"/> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: "openMap", | ||||||
|  |   props: { | ||||||
|  |     data: {default: () => ({})} | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     handleOpenMap() { | ||||||
|  |       let {lng, lat, gpsDesc} = this.data | ||||||
|  |       location.href = `https://uri.amap.com/marker?callnative=1&position=${[lng, lat].toString()}&name=${gpsDesc}` | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .openMap { | ||||||
|  |   flex-shrink: 0; | ||||||
|  |  | ||||||
|  |   img { | ||||||
|  |     width: 40px; | ||||||
|  |     height: 40px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   span { | ||||||
|  |     margin-left: 0; | ||||||
|  |     color: #999; | ||||||
|  |     font-size: 20px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										169
									
								
								src/pages/guardianship/earlyWarning.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,169 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="earlyWarning"> | ||||||
|  |     <ai-top-fixed> | ||||||
|  |       <u-search v-model="search.name" placeholder="请输入姓名" :show-action="false" | ||||||
|  |                 search-icon-color="#ccc" placeholder-color="#999" | ||||||
|  |                 @change="page.current=1,getList()"/> | ||||||
|  |       <div flex> | ||||||
|  |         <ai-date class="fill" placeholder="日期选择" mode="range" @change="handleDateSearch"/> | ||||||
|  |         <ai-select class="fill" dict="intelligentGuardianshipItem2" @data="handleTypeSearch"> | ||||||
|  |           <div>{{ $dict.getLabel('intelligentGuardianshipItem2', search.item) || '全部预警' }}</div> | ||||||
|  |           <i class="iconfont iconfont-iconArrow_Down"/> | ||||||
|  |         </ai-select> | ||||||
|  |       </div> | ||||||
|  |     </ai-top-fixed> | ||||||
|  |     <div class="card" v-for="row in list" :key="row.id" @tap="handleShow(row)"> | ||||||
|  |       <div class="header" flex> | ||||||
|  |         <img :src="top.cdn(typeIcons[row.item])"/> | ||||||
|  |         <b v-text="row.desc"/> | ||||||
|  |       </div> | ||||||
|  |       <div class="wrapper"> | ||||||
|  |         <div class="start" flex> | ||||||
|  |           <span v-text="`上报时间:`"/> | ||||||
|  |           <div v-text="row.createTime"/> | ||||||
|  |         </div> | ||||||
|  |         <div class="start" flex> | ||||||
|  |           <span v-text="`上报地点:`"/> | ||||||
|  |           <div v-text="row.gpsDesc"/> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import AiTopFixed from "../../components/AiTopFixed"; | ||||||
|  | import {mapState} from "vuex"; | ||||||
|  | import AiDate from "../../components/AiDate"; | ||||||
|  | import AiSelect from "../../components/AiSelect"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "earlyWarning", | ||||||
|  |   components: {AiSelect, AiDate, AiTopFixed}, | ||||||
|  |   inject: ['top'], | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['user']), | ||||||
|  |     typeIcons() { | ||||||
|  |       return { | ||||||
|  |         0: "icon4", | ||||||
|  |         1: "icon2", | ||||||
|  |         2: "icon5", | ||||||
|  |         3: "icon6", | ||||||
|  |         4: "icon3", | ||||||
|  |         5: "icon1", | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       search: {name: "", createTimeRange: ",", item: ""}, | ||||||
|  |       areaId: "", | ||||||
|  |       page: {current: 1, size: 10, total: 0}, | ||||||
|  |       list: [] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getList() { | ||||||
|  |       let {areaId} = this | ||||||
|  |       this.$http.post("/app/appintelligentguardianshipalarm/list", null, { | ||||||
|  |         params: {areaId, ...this.search, ...this.page} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           let data = res.data.records.map(e => { | ||||||
|  |             return {...e, desc: [e.name, this.$dict.getLabel('intelligentGuardianshipItem2', e.item)].join('的')} | ||||||
|  |           }) | ||||||
|  |           if (this.page.current > 1) { | ||||||
|  |             this.list = [...this.list, ...data] | ||||||
|  |           } else this.list = data | ||||||
|  |           this.page.total = res.data.total | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     reachBottom() { | ||||||
|  |       if (this.page.total > this.list.length) { | ||||||
|  |         this.page.current++ | ||||||
|  |         this.getList() | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     handleDateSearch(v) { | ||||||
|  |       let {startDate: start, endDate: end} = v | ||||||
|  |       start = this.$dateFormat(start) | ||||||
|  |       end = this.$dateFormat(end) | ||||||
|  |       this.search.createTimeRange = [start, end || start].toString() | ||||||
|  |       this.page.current = 1 | ||||||
|  |       this.getList() | ||||||
|  |     }, | ||||||
|  |     handleTypeSearch(v) { | ||||||
|  |       this.search.item = v?.[0]?.value | ||||||
|  |       this.page.current = 1 | ||||||
|  |       this.getList() | ||||||
|  |     }, | ||||||
|  |     handleShow(row) { | ||||||
|  |       uni.navigateTo({url: `./warningDetail?id=${row.id}`}) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.areaId = JSON.parse(JSON.stringify(this.user.areaId)) | ||||||
|  |     this.getList() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .earlyWarning { | ||||||
|  |   padding-bottom: 130px; | ||||||
|  |   background: #f5f5f5; | ||||||
|  |  | ||||||
|  |   ::v-deep .AiDate > div { | ||||||
|  |     justify-content: center; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .u-drawer-content { | ||||||
|  |     padding-bottom: 100px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .display { | ||||||
|  |     justify-content: center; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .iconfont-iconArrow_Down { | ||||||
|  |     margin-left: 4px; | ||||||
|  |     font-size: 32px; | ||||||
|  |     color: inherit; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .card { | ||||||
|  |     margin: 32px 32px 0; | ||||||
|  |     background: #FFFFFF; | ||||||
|  |     box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.02); | ||||||
|  |     border-radius: 8px; | ||||||
|  |  | ||||||
|  |     .header { | ||||||
|  |       padding: 0 32px; | ||||||
|  |       height: 104px; | ||||||
|  |       border-bottom: 2px solid #EFEFF4; | ||||||
|  |       font-size: 36px; | ||||||
|  |  | ||||||
|  |       img { | ||||||
|  |         width: 64px; | ||||||
|  |         height: 64px; | ||||||
|  |         margin-right: 16px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .wrapper { | ||||||
|  |       color: #343D65; | ||||||
|  |       font-size: 30px; | ||||||
|  |       margin-bottom: 8px; | ||||||
|  |       padding: 18px 32px; | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         white-space: nowrap; | ||||||
|  |         flex-shrink: 0; | ||||||
|  |         color: #999; | ||||||
|  |         margin-right: 20px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										461
									
								
								src/pages/guardianship/gsLocation.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,461 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="gsLocation"> | ||||||
|  |     <ai-map class="fill" :map.sync="amap" :lib.sync="mapLib"/> | ||||||
|  |     <div class="searchZone"> | ||||||
|  |       <u-search v-model="search" placeholder="请输入姓名" shape="square" bg-color="#fff" | ||||||
|  |                 :show-action="false" @search="getList()"/> | ||||||
|  |       <div class="searchResult" v-if="searchResult"> | ||||||
|  |         <div class="item" v-for="row in list" :key="row.id" @tap="handleSelect(row)"> | ||||||
|  |           <img :src="cdn(row.onlineStatus==1?'zxtx':'lxtx')"/> | ||||||
|  |           <div flex class="column fill"> | ||||||
|  |             <b v-html="searchName(row.name)"/> | ||||||
|  |             <div v-text="row.gpsDesc"/> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <u-popup v-model="popup" mode="bottom" :mask="false"> | ||||||
|  |         <div class="headerIcon" flex @touchstart="handleTouchStart" @touchmove="handleTouchmoveClose"/> | ||||||
|  |         <div class="selectedInfo"> | ||||||
|  |           <div class="header" flex> | ||||||
|  |             <img :src="`${$cdn}guardianship/tx.png`" @tap="handleShowDetail(selected)"/> | ||||||
|  |             <b v-text="selected.name" @tap="handleShowDetail(selected)"/> | ||||||
|  |             <div v-if="selected.abnormalStatus==1" class="abnormal" @tap="handleShowDetail(selected)">异常</div> | ||||||
|  |             <u-icon name="arrow-right" color="#ddd" class="fill" @tap="handleShowDetail(selected)"/> | ||||||
|  |             <make-calls :list="phoneList"/> | ||||||
|  |           </div> | ||||||
|  |           <div flex class="spb wrap"> | ||||||
|  |             <div class="detail" v-for="(op,i) in quotas" :key="i" flex> | ||||||
|  |               <img :src="op.icon"/> | ||||||
|  |               <div class="fill" v-text="op.label"/> | ||||||
|  |               <div :class="{abnormal:op.abnormal}" v-text="op.value"/> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |         <div class="navigation"> | ||||||
|  |           <div class="content" flex> | ||||||
|  |             <div flex class="spb wrap"> | ||||||
|  |               <div class="fill" v-text="selected.gpsDesc"/> | ||||||
|  |               <span>最后更新:{{ selected.lastUpdateTime }}</span> | ||||||
|  |               <div class="battery" flex> | ||||||
|  |                 <img :src="batteryIcon"/> | ||||||
|  |                 <div v-text="`剩余${selected.electricQuantity}%`"/> | ||||||
|  |               </div> | ||||||
|  |             </div> | ||||||
|  |             <open-map :data="selected"/> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </u-popup> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import AiSearchPopup from "../../components/AiSearchPopup"; | ||||||
|  | import {mapState} from "vuex"; | ||||||
|  | import UPopup from "../../uview/components/u-popup/u-popup"; | ||||||
|  | import MakeCalls from "./component/makeCalls"; | ||||||
|  | import OpenMap from "./component/openMap"; | ||||||
|  | import AiMap from "../../components/AiMap"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "gsLocation", | ||||||
|  |   components: {AiMap, OpenMap, MakeCalls, UPopup, AiSearchPopup}, | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['user']), | ||||||
|  |     markers() { | ||||||
|  |       return this.list.filter(e => e.lng).map(e => { | ||||||
|  |         let abnormal = 'offline' | ||||||
|  |         if (e.onlineStatus == 1) { | ||||||
|  |           switch (e.abnormalStatus) { | ||||||
|  |             case '1': | ||||||
|  |               abnormal = 'warning'; | ||||||
|  |               break; | ||||||
|  |             case '2': | ||||||
|  |               abnormal = 'abnormal'; | ||||||
|  |               break; | ||||||
|  |             default: | ||||||
|  |               abnormal = '' | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         return new this.mapLib.Marker({ | ||||||
|  |           position: new this.mapLib.LngLat(e.lng, e.lat), | ||||||
|  |           anchor: 'bottom-center', | ||||||
|  |           content: `<div class="marker ${abnormal}">${e.name}</div>`, | ||||||
|  |           extData: e, | ||||||
|  |           topWhenClick: true | ||||||
|  |         }).on('click', () => { | ||||||
|  |           this.handleSelect(e) | ||||||
|  |         }) | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     quotas() { | ||||||
|  |       let quota = [ | ||||||
|  |         {key: "0", icon: "1"}, | ||||||
|  |         {key: "1", icon: "2"}, | ||||||
|  |         {key: "2", icon: "3"}, | ||||||
|  |         {key: "3", icon: "4"}, | ||||||
|  |       ] | ||||||
|  |       return quota.map(e => { | ||||||
|  |         let item = this.detail.find(d => d.item == e.key) | ||||||
|  |         let label = this.$dict.getLabel('intelligentGuardianshipItem', e.key) | ||||||
|  |         return { | ||||||
|  |           label, icon: this.cdn(e.icon), | ||||||
|  |           value: item?.itemValue || "-", | ||||||
|  |           abnormal: item?.abnormalStatus == 1 | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     batteryIcon() { | ||||||
|  |       return this.cdn(this.selected.electricQuantity == 100 ? 'dcm' : 'dcq') | ||||||
|  |     }, | ||||||
|  |     phoneList() { | ||||||
|  |       let {name: guardianName, phone: guardianPhone} = this.selected | ||||||
|  |       return [{guardianName, guardianPhone}, ...(this.selected.guardians || [])] | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       mapLib: null, | ||||||
|  |       amap: null, | ||||||
|  |       search: "", | ||||||
|  |       selected: {}, | ||||||
|  |       list: [], | ||||||
|  |       popup: false,//被监护人信息弹窗 | ||||||
|  |       detail: [], | ||||||
|  |       moveDistance: 0, | ||||||
|  |       searchResult: false //搜索下拉弹窗 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   watch: { | ||||||
|  |     amap(v) { | ||||||
|  |       v && this.getList().then(() => { | ||||||
|  |         this.amap?.add(this.markers) | ||||||
|  |         this.getMapArea() | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     cdn(icon) { | ||||||
|  |       return `${this.$cdn}guardianship/${icon}.png` | ||||||
|  |     }, | ||||||
|  |     getMapArea() { | ||||||
|  |       if (this.mapLib) { | ||||||
|  |         new this.mapLib.DistrictSearch({ | ||||||
|  |           subdistrict: 0,   //获取边界不需要返回下级行政区 | ||||||
|  |           extensions: 'all',  //返回行政区边界坐标组等具体信息 | ||||||
|  |           level: 'district'  //查询行政级别为 市 | ||||||
|  |         }).search(this.user.areaId.substring(0, 6), (status, result) => { | ||||||
|  |           let bounds = result?.districtList?.[0]?.boundaries; | ||||||
|  |           let polygons = [] | ||||||
|  |           bounds?.forEach(path => polygons.push(new this.mapLib.Polygon({ | ||||||
|  |             strokeWeight: 1, | ||||||
|  |             path, | ||||||
|  |             strokeStyle: 'dashed', | ||||||
|  |             fillOpacity: 0.1, | ||||||
|  |             fillColor: '#80d8ff', | ||||||
|  |             strokeColor: '#0091ea' | ||||||
|  |           }))) | ||||||
|  |           this.amap.add(polygons) | ||||||
|  |           this.amap.setFitView();//视口自适应 | ||||||
|  |         }) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     getList() { | ||||||
|  |       this.searchResult = !!this.search | ||||||
|  |       return this.$http.post("/app/appintelligentguardianshipdevice/list", null, { | ||||||
|  |         params: {name: this.search, size: 999, areaId: this.user.areaId} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.list = res.data.records | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     getDetail(deviceId) { | ||||||
|  |       this.$http.post("/app/appintelligentguardianshipdevice/queryMonitorList", null, { | ||||||
|  |         params: {type: 1, deviceId} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.detail = res.data.records | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |       this.$http.post("/app/appintelligentguardianshipdevice/queryDetailById", null, { | ||||||
|  |         params: {id: deviceId} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.selected = {...this.selected, ...res.data} | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     searchName(name) { | ||||||
|  |       return name?.replace(this.search, `<span>${this.search}</span>`) | ||||||
|  |     }, | ||||||
|  |     handleSelect(e) { | ||||||
|  |       this.amap.setCenter(new this.mapLib.LngLat(e.lng, e.lat)) | ||||||
|  |       this.selected = e | ||||||
|  |       this.popup = true | ||||||
|  |       this.searchResult = false | ||||||
|  |       this.getDetail(e.id) | ||||||
|  |     }, | ||||||
|  |     handleShowDetail(user) { | ||||||
|  |       uni.navigateTo({url: `./userDetail?id=${user.id}`}) | ||||||
|  |     }, | ||||||
|  |     handleTouchmoveClose(e) { | ||||||
|  |       if (e.touches?.[0]?.clientY > this.moveDistance + 10) { | ||||||
|  |         this.popup = false | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     handleTouchStart(e) { | ||||||
|  |       this.moveDistance = e.touches?.[0]?.clientY | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .gsLocation { | ||||||
|  |   height: 100%; | ||||||
|  |  | ||||||
|  |   a { | ||||||
|  |     color: inherit; | ||||||
|  |     text-decoration: none; | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     justify-content: center; | ||||||
|  |     height: 112px; | ||||||
|  |     border-top: 1px solid #d8dde6; | ||||||
|  |  | ||||||
|  |     &:first-of-type { | ||||||
|  |       border-top: none; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .headerIcon { | ||||||
|  |     width: 100%; | ||||||
|  |     height: 60px; | ||||||
|  |     justify-content: center; | ||||||
|  |  | ||||||
|  |     &:before { | ||||||
|  |       content: " "; | ||||||
|  |       display: block; | ||||||
|  |       width: 64px; | ||||||
|  |       height: 10px; | ||||||
|  |       background: #CCCCCC; | ||||||
|  |       border-radius: 5px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .makeCalls { | ||||||
|  |     .option:last-of-type { | ||||||
|  |       margin-bottom: 120px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .selectedInfo { | ||||||
|  |     width: 100%; | ||||||
|  |     border-radius: 20px 20px 0 0; | ||||||
|  |     padding: 0 32px; | ||||||
|  |     background: #fff; | ||||||
|  |     overflow: hidden; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |  | ||||||
|  |     .header { | ||||||
|  |       margin-bottom: 40px; | ||||||
|  |       font-size: 40px; | ||||||
|  |  | ||||||
|  |       & > img { | ||||||
|  |         width: 82px; | ||||||
|  |         height: 82px; | ||||||
|  |         margin-right: 16px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .abnormal { | ||||||
|  |         color: #FF4466; | ||||||
|  |         font-size: 24px; | ||||||
|  |         padding: 12px; | ||||||
|  |         background: rgba(#EC4461, .1); | ||||||
|  |         border-radius: 8px; | ||||||
|  |         margin: 0 16px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         margin-left: 0; | ||||||
|  |         color: #999; | ||||||
|  |         font-size: 20px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .detail { | ||||||
|  |       width: 318px; | ||||||
|  |       height: 84px; | ||||||
|  |       background: #F4F5F6; | ||||||
|  |       border-radius: 8px; | ||||||
|  |       padding: 0 24px; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       margin-bottom: 36px; | ||||||
|  |  | ||||||
|  |       img { | ||||||
|  |         margin-right: 16px; | ||||||
|  |         width: 56px; | ||||||
|  |         height: 56px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .abnormal { | ||||||
|  |         color: #FF4466; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .navigation { | ||||||
|  |     padding-bottom: 100px; | ||||||
|  |  | ||||||
|  |     .content { | ||||||
|  |       padding: 32px 40px; | ||||||
|  |       font-size: 26px; | ||||||
|  |  | ||||||
|  |       & > .spb { | ||||||
|  |         margin-right: 40px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .fill { | ||||||
|  |         min-width: 100%; | ||||||
|  |         flex-shrink: 0; | ||||||
|  |         margin-bottom: 10px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         margin-left: 0; | ||||||
|  |         color: #999; | ||||||
|  |         font-size: 22px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .battery > img { | ||||||
|  |         margin-right: 14px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     &:before { | ||||||
|  |       content: " "; | ||||||
|  |       display: block; | ||||||
|  |       width: 100%; | ||||||
|  |       height: 8px; | ||||||
|  |       background: #F4F5F6; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .searchZone { | ||||||
|  |     position: absolute; | ||||||
|  |     top: 0; | ||||||
|  |     z-index: 2; | ||||||
|  |     width: 100%; | ||||||
|  |     background: transparent; | ||||||
|  |     padding: 24px 16px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |  | ||||||
|  |     .u-search { | ||||||
|  |       box-shadow: 0 4px 8px 0 rgba(192, 185, 185, 0.5); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .searchResult { | ||||||
|  |       margin-top: 16px; | ||||||
|  |       padding: 0 28px; | ||||||
|  |       background: #fff; | ||||||
|  |  | ||||||
|  |       .item { | ||||||
|  |         font-size: 24px; | ||||||
|  |         display: flex; | ||||||
|  |         line-height: 36px; | ||||||
|  |         padding: 24px 0; | ||||||
|  |         border-bottom: 3px solid #DEDFE1; | ||||||
|  |  | ||||||
|  |         &:last-of-type { | ||||||
|  |           border-bottom: none; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         img { | ||||||
|  |           width: 36px; | ||||||
|  |           height: 36px; | ||||||
|  |           margin-right: 16px; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         & > .fill { | ||||||
|  |           align-items: unset; | ||||||
|  |  | ||||||
|  |           b > span { | ||||||
|  |             color: #1365DD; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           & > div { | ||||||
|  |             width: 100%; | ||||||
|  |             overflow: hidden; | ||||||
|  |             text-overflow: ellipsis; | ||||||
|  |             white-space: nowrap; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .marker { | ||||||
|  |     color: #fff; | ||||||
|  |     font-size: 30px; | ||||||
|  |     display: flex; | ||||||
|  |     justify-content: center; | ||||||
|  |     align-items: center; | ||||||
|  |     padding: 0 32px; | ||||||
|  |     height: 56px; | ||||||
|  |     white-space: nowrap; | ||||||
|  |     background: #5088FF; | ||||||
|  |     border-color: #5088FF; | ||||||
|  |     border-radius: 52px; | ||||||
|  |     position: relative; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     &:after { | ||||||
|  |       position: absolute; | ||||||
|  |       display: block; | ||||||
|  |       content: " "; | ||||||
|  |       bottom: -12px; | ||||||
|  |       left: 50%; | ||||||
|  |       transform: translateX(-50%); | ||||||
|  |       border: 12px solid transparent; | ||||||
|  |       border-bottom: none; | ||||||
|  |       height: 0; | ||||||
|  |       width: 0; | ||||||
|  |       border-top-color: inherit; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     &.offline { | ||||||
|  |       background: #C4CAD4; | ||||||
|  |       border-color: #C4CAD4; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     &.warning { | ||||||
|  |       background: #FFAA44; | ||||||
|  |       border-color: #FFAA44; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     &.abnormal { | ||||||
|  |       background: #F46159; | ||||||
|  |       border-color: #F46159; | ||||||
|  |  | ||||||
|  |       &:before { | ||||||
|  |         position: absolute; | ||||||
|  |         z-index: -1; | ||||||
|  |         bottom: -40px; | ||||||
|  |         width: 80px; | ||||||
|  |         height: 80px; | ||||||
|  |         border-radius: 50%; | ||||||
|  |         background-color: #F46159; | ||||||
|  |         transform: translate(-50%, -50%); | ||||||
|  |         animation: mapWarn 1s ease-out 0s infinite; | ||||||
|  |         content: " "; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .AiMap { | ||||||
|  |     width: 100%; | ||||||
|  |     height: 100%; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										65
									
								
								src/pages/guardianship/guardianship.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,65 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="guardianship"> | ||||||
|  |     <component ref="currentTab" :is="currentTab.comp"/> | ||||||
|  |     <ai-tabbar :active.sync="active" :list="bottomBar"/> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import AiLoading from "../../components/AiLoading"; | ||||||
|  | import GsLocation from "./gsLocation"; | ||||||
|  | import AiTabbar from "../../components/AiTabbar"; | ||||||
|  | import WardList from "./wardList"; | ||||||
|  | import EarlyWarning from "./earlyWarning"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "guardianship", | ||||||
|  |   components: {AiTabbar, AiLoading}, | ||||||
|  |   provide() { | ||||||
|  |     return { | ||||||
|  |       top: this | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     bottomBar() { | ||||||
|  |       return [ | ||||||
|  |         {text: "定位", iconPath: "bardwn", selectedIconPath: "bardwh", comp: GsLocation}, | ||||||
|  |         {text: "人员", iconPath: "barryn", selectedIconPath: "barryh", comp: WardList}, | ||||||
|  |         {text: "预警", iconPath: "baryjn", selectedIconPath: "baryjh", comp: EarlyWarning}, | ||||||
|  |       ].map(e => ({ | ||||||
|  |         ...e, | ||||||
|  |         iconPath: this.cdn(e.iconPath), | ||||||
|  |         selectedIconPath: this.cdn(e.selectedIconPath) | ||||||
|  |       })) | ||||||
|  |     }, | ||||||
|  |     currentTab() { | ||||||
|  |       return this.bottomBar?.[this.active] || {} | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     cdn(icon) { | ||||||
|  |       return `${this.$cdn}guardianship/${icon}.png` | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       active: 0 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.$dict.load("intelligentGuardianshipItem", 'intelligentGuardianshipItem2', 'intelligentGuardianshipAbnormalStatus') | ||||||
|  |   }, | ||||||
|  |   onReachBottom() { | ||||||
|  |     if (typeof this.$refs?.currentTab?.reachBottom == 'function') this.$refs?.currentTab.reachBottom() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .guardianship { | ||||||
|  |   position: absolute; | ||||||
|  |   width: 100%; | ||||||
|  |   top: 0; | ||||||
|  |   bottom: 0; | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										75
									
								
								src/pages/guardianship/historyList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,75 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="historyList"> | ||||||
|  |     <div flex> | ||||||
|  |       <b class="header" v-text="itemLabel"/> | ||||||
|  |     </div> | ||||||
|  |     <div v-for="row in list" :key="row.id" flex class="spb row"> | ||||||
|  |       <div :class="{abnormal:row.abnormalStatus==1}" v-text="row.itemValue"/> | ||||||
|  |       <span v-text="row.sampleTime"/> | ||||||
|  |     </div> | ||||||
|  |     <ai-back/> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import AiBack from "../../components/AiBack"; | ||||||
|  | export default { | ||||||
|  |   name: "historyList", | ||||||
|  |   components: {AiBack}, | ||||||
|  |   computed: { | ||||||
|  |     itemLabel() { | ||||||
|  |       return '历史'+this.$dict.getLabel('intelligentGuardianshipItem', this.$route.query.type)+`(${this.$dict.getLabel('intelligentGuardianshipItemUnit',this.$route.query.type)})` | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       list: [] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getHistory() { | ||||||
|  |       let {type: item, id: deviceId} = this.$route.query | ||||||
|  |       this.$http.post("/app/appintelligentguardianshipdevice/queryMonitorList", null, { | ||||||
|  |         params: {deviceId, size: 999, item} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.list = res.data.records | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.$dict.load("intelligentGuardianshipItem",'intelligentGuardianshipItemUnit') | ||||||
|  |     this.getHistory() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .historyList { | ||||||
|  |   font-size: 30px; | ||||||
|  |  | ||||||
|  |   & > div { | ||||||
|  |     padding: 0 32px; | ||||||
|  |     border-bottom: 1px solid #ddd; | ||||||
|  |     height: 96px; | ||||||
|  |     background: #FFFFFF; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .header { | ||||||
|  |     font-size: 32px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .row { | ||||||
|  |     color: #5AAD6A; | ||||||
|  |  | ||||||
|  |     .abnormal { | ||||||
|  |       color: #CD413A; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     & > span { | ||||||
|  |       color: #999; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										279
									
								
								src/pages/guardianship/userDetail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,279 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="userDetail"> | ||||||
|  |     <div class="selectedInfo"> | ||||||
|  |       <div class="header" flex> | ||||||
|  |         <img :src="`${$cdn}guardianship/tx.png`"/> | ||||||
|  |         <b v-text="detail.name"/> | ||||||
|  |         <div v-if="detail.abnormalStatus==1" class="abnormal">异常</div> | ||||||
|  |         <div class="fill"/> | ||||||
|  |         <make-calls :list="phoneList" :label="`<p>拨打电话</p>`"/> | ||||||
|  |       </div> | ||||||
|  |       <div class="content"> | ||||||
|  |         <ai-cell label="所属地区">{{ detail.areaName }}</ai-cell> | ||||||
|  |         <ai-cell label="联系电话">{{ detail.phone }}</ai-cell> | ||||||
|  |         <ai-cell label="性别">{{ $dict.getLabel('sex', detail.sex) }}</ai-cell> | ||||||
|  |         <ai-cell label="年龄">{{ $calcAge(detail.idNumber) }}</ai-cell> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="card"> | ||||||
|  |       <div flex class="spb header"> | ||||||
|  |         <b v-text="`设备状况`"/> | ||||||
|  |         <span class="onlineStatus" v-html="detail.onlineStatus==1?'设备在线':'<p>设备离线</p>'"/> | ||||||
|  |       </div> | ||||||
|  |       <div flex class="spb wrap quotas"> | ||||||
|  |         <div class="quota" v-for="(op,i) in quotas" :key="i" flex @tap="handleShowHistory(op)"> | ||||||
|  |           <img :src="op.icon"/> | ||||||
|  |           <div class="fill" v-text="op.label"/> | ||||||
|  |           <div :class="{abnormal:op.abnormal}" v-text="op.value"/> | ||||||
|  |           <u-icon name="arrow-right" color="#ddd"/> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="navigation"> | ||||||
|  |         <div class="content spb" flex> | ||||||
|  |           <div flex class="spb wrap"> | ||||||
|  |             <div class="fill" v-text="detail.gpsDesc"/> | ||||||
|  |             <span>最后更新:{{ detail.lastUpdateTime }}</span> | ||||||
|  |             <div class="battery" flex> | ||||||
|  |               <img :src="batteryIcon"/> | ||||||
|  |               <div v-text="`剩余${detail.electricQuantity||0}%`"/> | ||||||
|  |             </div> | ||||||
|  |           </div> | ||||||
|  |           <open-map :data="detail"/> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="card"> | ||||||
|  |       <div flex class="spb header"> | ||||||
|  |         <b v-text="`监护人信息`"/> | ||||||
|  |       </div> | ||||||
|  |       <div flex class="spb guardian" v-for="row in detail.guardians" :key="row.id"> | ||||||
|  |         <span v-text="row.guardianName"/> | ||||||
|  |         <div v-text="row.guardianPhone"/> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <ai-back/> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import MakeCalls from "./component/makeCalls"; | ||||||
|  | import OpenMap from "./component/openMap"; | ||||||
|  | import AiCell from "../../components/AiCell"; | ||||||
|  | import AiBack from "../../components/AiBack"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "userDetail", | ||||||
|  |   components: {AiBack, AiCell, OpenMap, MakeCalls}, | ||||||
|  |   computed: { | ||||||
|  |     batteryIcon() { | ||||||
|  |       return this.cdn(this.detail.electricQuantity == 100 ? 'dcm' : 'dcq') | ||||||
|  |     }, | ||||||
|  |     quotas() { | ||||||
|  |       let quota = [ | ||||||
|  |         {key: "0", icon: "1"}, | ||||||
|  |         {key: "1", icon: "2"}, | ||||||
|  |         {key: "2", icon: "3"}, | ||||||
|  |         {key: "3", icon: "4"}, | ||||||
|  |       ] | ||||||
|  |       return quota.map(e => { | ||||||
|  |         let item = this.detail.quota?.find(d => d.item == e.key) | ||||||
|  |         let label = this.$dict.getLabel('intelligentGuardianshipItem', e.key) | ||||||
|  |         return { | ||||||
|  |           label, icon: this.cdn(e.icon), type: e.key, | ||||||
|  |           value: item?.itemValue || "-", | ||||||
|  |           abnormal: item?.abnormalStatus == 1 | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     phoneList() { | ||||||
|  |       let {name: guardianName, phone: guardianPhone} = this.detail | ||||||
|  |       return [{guardianName, guardianPhone}, ...this.detail.guardians] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       detail: { | ||||||
|  |         guardians: [] | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     cdn(icon) { | ||||||
|  |       return `${this.$cdn}guardianship/${icon}.png` | ||||||
|  |     }, | ||||||
|  |     getDetail(deviceId) { | ||||||
|  |       this.$http.post("/app/appintelligentguardianshipdevice/queryMonitorList", null, { | ||||||
|  |         params: {type: 1, deviceId} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.$set(this.detail, 'quota', res.data.records) | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |       this.$http.post("/app/appintelligentguardianshipdevice/queryDetailById", null, { | ||||||
|  |         params: {id: deviceId} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.detail = {...this.detail, ...res.data} | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     handleShowHistory(item) { | ||||||
|  |       uni.navigateTo({url: `./historyList?type=${item.type}&id=${this.$route.query.id}`}) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.$dict.load("intelligentGuardianshipItem", 'sex') | ||||||
|  |     this.getDetail(this.$route.query.id) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .userDetail { | ||||||
|  |   padding-bottom: 60px; | ||||||
|  |  | ||||||
|  |   & > * { | ||||||
|  |     margin-bottom: 16px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .card { | ||||||
|  |     background: #fff; | ||||||
|  |     font-size: 32px; | ||||||
|  |     box-shadow: 0 1px 1px 0 rgba(221, 221, 221, 1); | ||||||
|  |  | ||||||
|  |     .header { | ||||||
|  |       height: 96px; | ||||||
|  |       background: #FFFFFF; | ||||||
|  |       border-bottom: 1px solid #ddd; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     & > .spb { | ||||||
|  |       padding: 0 32px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .selectedInfo { | ||||||
|  |     width: 100%; | ||||||
|  |     background: #fff; | ||||||
|  |     overflow: hidden; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |  | ||||||
|  |     .header { | ||||||
|  |       height: 136px; | ||||||
|  |       font-size: 40px; | ||||||
|  |       padding: 0 32px; | ||||||
|  |       border-bottom: 1px solid #D8DDE6; | ||||||
|  |  | ||||||
|  |       & > img { | ||||||
|  |         width: 82px; | ||||||
|  |         height: 82px; | ||||||
|  |         margin-right: 16px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .abnormal { | ||||||
|  |         color: #FF4466; | ||||||
|  |         font-size: 24px; | ||||||
|  |         padding: 12px; | ||||||
|  |         background: rgba(#EC4461, .1); | ||||||
|  |         border-radius: 8px; | ||||||
|  |         margin-left: 16px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         margin-left: 0; | ||||||
|  |         color: #999; | ||||||
|  |         font-size: 20px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     & > .content { | ||||||
|  |       padding: 32px; | ||||||
|  |       font-size: 30px; | ||||||
|  |  | ||||||
|  |       ::v-deep .AiCell { | ||||||
|  |         padding: 0; | ||||||
|  |         min-height: 58px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .quotas { | ||||||
|  |     margin-top: 24px; | ||||||
|  |  | ||||||
|  |     .quota { | ||||||
|  |       cursor: pointer; | ||||||
|  |       width: 318px; | ||||||
|  |       height: 84px; | ||||||
|  |       background: #F4F5F6; | ||||||
|  |       border-radius: 8px; | ||||||
|  |       padding: 0 8px 0 24px; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       margin-bottom: 36px; | ||||||
|  |       font-size: 28px; | ||||||
|  |  | ||||||
|  |       img { | ||||||
|  |         margin-right: 16px; | ||||||
|  |         width: 56px; | ||||||
|  |         height: 56px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .abnormal { | ||||||
|  |         color: #FF4466; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   .navigation { | ||||||
|  |     .content { | ||||||
|  |       padding: 10px 40px 32px; | ||||||
|  |       font-size: 26px; | ||||||
|  |  | ||||||
|  |       & > .spb { | ||||||
|  |         margin-right: 40px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .fill { | ||||||
|  |         min-width: 100%; | ||||||
|  |         flex-shrink: 0; | ||||||
|  |         margin-bottom: 10px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         margin-left: 0; | ||||||
|  |         color: #999; | ||||||
|  |         font-size: 22px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .battery > img { | ||||||
|  |         margin-left: 32px; | ||||||
|  |         margin-right: 14px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .onlineStatus { | ||||||
|  |     font-size: 30px; | ||||||
|  |     color: #5AAD6A; | ||||||
|  |  | ||||||
|  |     p { | ||||||
|  |       color: #F5A319; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .guardian { | ||||||
|  |     height: 96px; | ||||||
|  |     border-bottom: 1px solid #ddd; | ||||||
|  |     font-size: 28px; | ||||||
|  |     color: #222; | ||||||
|  |  | ||||||
|  |     &:last-of-type { | ||||||
|  |       border-bottom: none; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     span { | ||||||
|  |       color: #666666; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										106
									
								
								src/pages/guardianship/wardList.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,106 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="wardList"> | ||||||
|  |     <ai-top-fixed> | ||||||
|  |       <u-search v-model="search" placeholder="请输入姓名" :show-action="false" | ||||||
|  |                 search-icon-color="#ccc" placeholder-color="#999" | ||||||
|  |                 @change="page.current=1,getUser()"/> | ||||||
|  |       <area-selector :areaId="areaId" @select="handleSelectArea"/> | ||||||
|  |     </ai-top-fixed> | ||||||
|  |     <div class="userList"> | ||||||
|  |       <div v-for="row in list" :key="row.id" flex class="row" @tap="handleShowDetail(row)"> | ||||||
|  |         <img :src="top.cdn(row.onlineStatus==1?'zxtx':'lxtx')"/> | ||||||
|  |         <b class="fill" v-text="row.name"/> | ||||||
|  |         <div class="status" :style="{color:$dict.getColor('intelligentGuardianshipAbnormalStatus',row.abnormalStatus)}" | ||||||
|  |              v-text="$dict.getLabel('intelligentGuardianshipAbnormalStatus',row.abnormalStatus)"/> | ||||||
|  |         <u-icon name="arrow-right" color="#ddd"/> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import AiTopFixed from "../../components/AiTopFixed"; | ||||||
|  | import {mapState} from "vuex"; | ||||||
|  | import AreaSelector from "./component/areaSelector"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "wardList", | ||||||
|  |   components: {AreaSelector, AiTopFixed}, | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['user']), | ||||||
|  |   }, | ||||||
|  |   inject: ['top'], | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       search: "", | ||||||
|  |       areaId: "", | ||||||
|  |       page: {current: 1, size: 20, total: 0}, | ||||||
|  |       list: [] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getUser() { | ||||||
|  |       let {areaId, search: name} = this | ||||||
|  |       this.$http.post("/app/appintelligentguardianshipdevice/list", null, { | ||||||
|  |         params: {areaId, name, ...this.page} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           let data = res.data.records.reverse() | ||||||
|  |           if (this.page.current > 1) { | ||||||
|  |             this.list = [...this.list, ...data] | ||||||
|  |           } else this.list = data | ||||||
|  |           this.page.total = res.data.total | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     handleSelectArea({id}) { | ||||||
|  |       this.areaId = id | ||||||
|  |       this.getUser() | ||||||
|  |     }, | ||||||
|  |     reachBottom() { | ||||||
|  |       if (this.page.total > this.list.length) { | ||||||
|  |         this.page.current++ | ||||||
|  |         this.getUser() | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     handleShowDetail(user) { | ||||||
|  |       uni.navigateTo({url: `./userDetail?id=${user.id}`}) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.areaId = JSON.parse(JSON.stringify(this.user.areaId)) | ||||||
|  |     this.getUser() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .wardList { | ||||||
|  |   background: #f5f5f5; | ||||||
|  |   padding-bottom: 130px; | ||||||
|  |   font-size: 30px; | ||||||
|  |  | ||||||
|  |   ::v-deep .userList { | ||||||
|  |     margin-top: 16px; | ||||||
|  |     background: #fff; | ||||||
|  |  | ||||||
|  |     .row { | ||||||
|  |       font-size: 36px; | ||||||
|  |       margin-left: 32px; | ||||||
|  |       padding-right: 32px; | ||||||
|  |       height: 104px; | ||||||
|  |       border-bottom: 1px solid #ddd; | ||||||
|  |  | ||||||
|  |       img { | ||||||
|  |         width: 72px; | ||||||
|  |         height: 72px; | ||||||
|  |         margin-right: 38px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .status { | ||||||
|  |         margin-right: 12px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										185
									
								
								src/pages/guardianship/warningDetail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,185 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="warningDetail"> | ||||||
|  |     <div flex class="header"> | ||||||
|  |       <b v-text="detail.name"/> | ||||||
|  |       <div> | ||||||
|  |         {{ $dict.getLabel('intelligentGuardianshipItem2', detail.item) }} | ||||||
|  |         {{ detail.itemValue }} | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <ai-map class="fill" :map.sync="amap" :lib.sync="mapLib"/> | ||||||
|  |     <div class="navigation"> | ||||||
|  |       <div class="content spb" flex> | ||||||
|  |         <div flex class="spb wrap"> | ||||||
|  |           <div class="fill" v-text="detail.gpsDesc"/> | ||||||
|  |           <span>最后更新:{{ detail.createTime }}</span> | ||||||
|  |         </div> | ||||||
|  |         <open-map :data="detail"/> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <make-calls :list="phoneList"> | ||||||
|  |       <div class="bottomBtn">拨打电话</div> | ||||||
|  |     </make-calls> | ||||||
|  |     <ai-back/> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import OpenMap from "./component/openMap"; | ||||||
|  | import MakeCalls from "./component/makeCalls"; | ||||||
|  | import AiBack from "../../components/AiBack"; | ||||||
|  | import AiMap from "../../components/AiMap"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "warningDetail", | ||||||
|  |   components: {AiMap, AiBack, MakeCalls, OpenMap}, | ||||||
|  |   computed: { | ||||||
|  |     phoneList() { | ||||||
|  |       let {name: guardianName, phone: guardianPhone} = this.detail | ||||||
|  |       return [{guardianName, guardianPhone}, ...this.detail.guardians] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       detail: {guardians: []}, | ||||||
|  |       mapLib: null, | ||||||
|  |       amap: null, | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getDetail(id) { | ||||||
|  |       return this.$http.post("/app/appintelligentguardianshipalarm/queryDetailById", null, { | ||||||
|  |         params: {id}, | ||||||
|  |         withoutToken: true | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.detail = res.data | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     initMap() { | ||||||
|  |       if (this.mapLib) { | ||||||
|  |         let pos = new this.mapLib.LngLat(this.detail.lng, this.detail.lat) | ||||||
|  |         this.amap.add(new this.mapLib.Marker({ | ||||||
|  |           position: pos, | ||||||
|  |           anchor: 'bottom-center', | ||||||
|  |           content: `<div class="marker">${this.detail.name}</div>`, | ||||||
|  |         })) | ||||||
|  |         this.amap.setFitView() | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   watch: { | ||||||
|  |     mapLib(v) { | ||||||
|  |       this.detail.id && v && this.initMap() | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.$dict.load("intelligentGuardianshipItem",'intelligentGuardianshipItem2', 'sex') | ||||||
|  |   }, | ||||||
|  |   mounted() { | ||||||
|  |     this.getDetail(this.$route.query.id).then(() => this.initMap()) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .warningDetail { | ||||||
|  |   padding: 48px 48px 112px; | ||||||
|  |   width: 100%; | ||||||
|  |   height: 100%; | ||||||
|  |   box-sizing: border-box; | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   position: absolute; | ||||||
|  |  | ||||||
|  |   .header { | ||||||
|  |     font-size: 40px; | ||||||
|  |     font-weight: bold; | ||||||
|  |     color: #333333; | ||||||
|  |     justify-content: center; | ||||||
|  |     margin-bottom: 48px; | ||||||
|  |  | ||||||
|  |     & > div { | ||||||
|  |       color: #EC4461; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .navigation { | ||||||
|  |     .content { | ||||||
|  |       padding: 10px 0 32px; | ||||||
|  |       font-size: 28px; | ||||||
|  |       color: #555; | ||||||
|  |  | ||||||
|  |       & > .spb { | ||||||
|  |         margin-right: 40px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .fill { | ||||||
|  |         min-width: 100%; | ||||||
|  |         flex-shrink: 0; | ||||||
|  |         margin-bottom: 10px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         margin-left: 0; | ||||||
|  |         color: #999; | ||||||
|  |         font-size: 22px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .bottomBtn { | ||||||
|  |     position: fixed; | ||||||
|  |     left: 0; | ||||||
|  |     bottom: 0; | ||||||
|  |     width: 100%; | ||||||
|  |     text-align: center; | ||||||
|  |     color: #fff; | ||||||
|  |     background: #1365DD; | ||||||
|  |     line-height: 112px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .AiMap { | ||||||
|  |     margin-bottom: 72px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   ::v-deep .marker { | ||||||
|  |     border-radius: 52px; | ||||||
|  |     background: #F46159; | ||||||
|  |     color: #fff; | ||||||
|  |     font-size: 22px; | ||||||
|  |     padding: 4px 16px; | ||||||
|  |     white-space: nowrap; | ||||||
|  |     position: relative; | ||||||
|  |  | ||||||
|  |     &:before { | ||||||
|  |       position: absolute; | ||||||
|  |       left: calc(50% - 30px); | ||||||
|  |       bottom: -34px; | ||||||
|  |       z-index: -1; | ||||||
|  |       width: 60px; | ||||||
|  |       height: 60px; | ||||||
|  |       border-radius: 50%; | ||||||
|  |       background-color: #F46159; | ||||||
|  |       animation: mapWarn 1s ease-out 0s infinite; | ||||||
|  |       content: " "; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     &:after { | ||||||
|  |       position: absolute; | ||||||
|  |       display: block; | ||||||
|  |       content: " "; | ||||||
|  |       bottom: -8px; | ||||||
|  |       left: 50%; | ||||||
|  |       transform: translateX(-50%); | ||||||
|  |       border: 8px solid transparent; | ||||||
|  |       border-bottom: none; | ||||||
|  |       border-top-color: #F46159; | ||||||
|  |       height: 0; | ||||||
|  |       width: 0; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										184
									
								
								src/pages/interview/detail.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,184 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="interviewDetail"> | ||||||
|  |     <template v-if="isEdit"> | ||||||
|  |       <u-form ref="interviewForm" label-position="top" :rules="rules" :model="form"> | ||||||
|  |         <u-form-item label="调查走访事项" prop="title" required> | ||||||
|  |           <u-input v-model="form.title" placeholder="请输入,最多30字" maxlength="30"/> | ||||||
|  |         </u-form-item> | ||||||
|  |         <u-form-item label="调查走访内容" prop="content"> | ||||||
|  |           <ai-textarea v-model="form.content" placeholder="请输入,最多500字" :maxlength="500"/> | ||||||
|  |         </u-form-item> | ||||||
|  |         <u-form-item label="图片(最多9张)"> | ||||||
|  |           <ai-uploader multiple :limit="9" :def.sync="form.fileList" action="/admin/file/add2"/> | ||||||
|  |         </u-form-item> | ||||||
|  |       </u-form> | ||||||
|  |       <div bottom> | ||||||
|  |         <u-button type="primary" @tap="submitForm">保存</u-button> | ||||||
|  |       </div> | ||||||
|  |     </template> | ||||||
|  |     <template v-else> | ||||||
|  |       <div class="headerPane"> | ||||||
|  |         <b>{{ form.title }}</b> | ||||||
|  |         <div>记录时间:{{ form.createTime }}</div> | ||||||
|  |       </div> | ||||||
|  |       <div class="contentPane"> | ||||||
|  |         <div v-html="form.content"/> | ||||||
|  |         <div flex class="wrap"> | ||||||
|  |           <ai-image v-for="(op,i) in form.fileList" :src="op.accessUrl" preview :key="i"/> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |     </template> | ||||||
|  |     <ai-back/> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import UButton from "../../uview/components/u-button/u-button"; | ||||||
|  | import AiUploader from "../../components/AiUploader"; | ||||||
|  | import UInput from "../../uview/components/u-input/u-input"; | ||||||
|  | import AiImage from "../../components/AiImage"; | ||||||
|  | import AiTextarea from "../../components/AiTextarea"; | ||||||
|  | import UFormItem from "../../uview/components/u-form-item/u-form-item"; | ||||||
|  | import AiBack from "../../components/AiBack"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: 'interviewDetail', | ||||||
|  |   components: {AiBack, UFormItem, AiTextarea, AiImage, UInput, AiUploader, UButton}, | ||||||
|  |   computed: { | ||||||
|  |     isEdit() { | ||||||
|  |       let flag = this.$route.query?.detail != 1 | ||||||
|  |       !flag && uni.setNavigationBarTitle({title: "走访详情"}) | ||||||
|  |       return flag | ||||||
|  |     }, | ||||||
|  |     rules() { | ||||||
|  |       return { | ||||||
|  |         title: [{required: true, message: '请输入 调查走访事项'}], | ||||||
|  |         // content: [{required: true, message: '请输入 调查走访内容'}], | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       form: { | ||||||
|  |         fileList: [] | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.searchDetail(); | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     submitForm() { | ||||||
|  |       this.$refs.interviewForm?.validate(v => { | ||||||
|  |         if (v) { | ||||||
|  |           this.$http.post(`/app/appinterview/add-xcx`, { | ||||||
|  |             ...this.form | ||||||
|  |           }).then(res => { | ||||||
|  |             if (res?.code == 0) { | ||||||
|  |               this.$u.toast("提交成功!") | ||||||
|  |               uni.navigateBack() | ||||||
|  |             } | ||||||
|  |           }) | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     searchDetail() { | ||||||
|  |       let {id} = this.$route.query | ||||||
|  |       id && this.$http.post(`/app/appinterview/queryDetailById`, null, { | ||||||
|  |         params: {id} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.form = {...res.data}; | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .interviewDetail { | ||||||
|  |   background: #F3F6F9; | ||||||
|  |   min-height: 100%; | ||||||
|  |  | ||||||
|  |   .u-form { | ||||||
|  |     width: 100%; | ||||||
|  |     height: 100%; | ||||||
|  |     overflow-y: auto; | ||||||
|  |     background-color: #f3f6f9; | ||||||
|  |     position: relative; | ||||||
|  |     padding: 0 0 188px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     font-size: 30px; | ||||||
|  |  | ||||||
|  |     ::v-deep textarea { | ||||||
|  |       width: 100%; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ::v-deep .u-form-item { | ||||||
|  |       margin-bottom: 16px; | ||||||
|  |  | ||||||
|  |       .u-form-item--left__content__label { | ||||||
|  |         font-weight: 400; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       div[flex] { | ||||||
|  |         width: 100%; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   div[bottom] { | ||||||
|  |     z-index: 99; | ||||||
|  |     padding: 0; | ||||||
|  |     height: 112px; | ||||||
|  |  | ||||||
|  |     .u-btn { | ||||||
|  |       height: 100%; | ||||||
|  |       border-radius: 0; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .headerPane { | ||||||
|  |     width: 100%; | ||||||
|  |     background: #3975C6; | ||||||
|  |     color: #fff; | ||||||
|  |     padding: 24px 32px 32px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     font-size: 28px; | ||||||
|  |  | ||||||
|  |     b { | ||||||
|  |       display: block; | ||||||
|  |       font-size: 40px; | ||||||
|  |       line-height: 64px; | ||||||
|  |       letter-spacing: 2px; | ||||||
|  |       margin-bottom: 16px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .contentPane { | ||||||
|  |     padding: 32px; | ||||||
|  |     width: 100%; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     font-size: 32px; | ||||||
|  |     font-weight: 400; | ||||||
|  |     color: #666; | ||||||
|  |     line-height: 56px; | ||||||
|  |  | ||||||
|  |     .wrap { | ||||||
|  |       margin-top: 32px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .AiImage { | ||||||
|  |       width: 31%; | ||||||
|  |       margin-bottom: 16px; | ||||||
|  |       margin-right: 16px; | ||||||
|  |  | ||||||
|  |       image { | ||||||
|  |         width: 100%; | ||||||
|  |         height: 218px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										224
									
								
								src/pages/interview/interview.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,224 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="interview"> | ||||||
|  |     <ai-top-fixed> | ||||||
|  |       <div flex> | ||||||
|  |         <ai-date placeholder="日期选择" mode="range" @change="handleDateSearch"/> | ||||||
|  |         <u-search placeholder="请输入标题" :show-action="false" v-model="search.title" @search="current=1,getList()"/> | ||||||
|  |       </div> | ||||||
|  |     </ai-top-fixed> | ||||||
|  |     <template v-if="list.length>0"> | ||||||
|  |       <ai-card v-for="(e,index) in list" :key="index" @click.native="goDetail(e.id,1)"> | ||||||
|  |         <template #custom> | ||||||
|  |           <div flex> | ||||||
|  |             <b class="fill">{{ e.title }}</b> | ||||||
|  |           </div> | ||||||
|  |           <div flex v-if="!!e.fileList" class="wrap"> | ||||||
|  |             <ai-image v-for="(op,i) in e.fileList.slice(0,3)" :src="op.accessUrl" preview :key="i"/> | ||||||
|  |           </div> | ||||||
|  |           <div class="bottom">{{ e.createTime }}</div> | ||||||
|  |         </template> | ||||||
|  |         <template #menu> | ||||||
|  |           <div class="menu" @tap.stop="goDetail(e.id)">编辑</div> | ||||||
|  |           <div class="menu" @tap.stop="handleDelete(e.id)">删除</div> | ||||||
|  |         </template> | ||||||
|  |       </ai-card> | ||||||
|  |       <u-loadmore :status="loadmore" color="#999" font-size="24" | ||||||
|  |                   margin-top="32" margin-bottom="80"/> | ||||||
|  |     </template> | ||||||
|  |     <div class="no-message" v-else> | ||||||
|  |       <image src="https://cdn.cunwuyun.cn/wxAdmin/img/message.png"/> | ||||||
|  |       <p>您还未添加过入户调查走访<br>点击<b>新增按钮</b>试试吧~</p> | ||||||
|  |     </div> | ||||||
|  |     <ai-fixed-btn> | ||||||
|  |       <div class="addBtn iconfont iconfont-iconfangda" @tap="gotoAdd()"/> | ||||||
|  |     </ai-fixed-btn> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import AiSelect from "../../components/AiSelect"; | ||||||
|  | import AiTopFixed from "../../components/AiTopFixed"; | ||||||
|  | import AiCard from "../../components/AiCard"; | ||||||
|  | import AiImage from "../../components/AiImage"; | ||||||
|  | import AiDate from "../../components/AiDate"; | ||||||
|  | import AiFixedBtn from "../../components/AiFixedBtn"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "interview", | ||||||
|  |   components: {AiFixedBtn, AiDate, AiImage, AiCard, AiTopFixed, AiSelect}, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       search: {title: ""}, | ||||||
|  |       list: [], | ||||||
|  |       current: 1, | ||||||
|  |       pages: 0 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     loadmore() { | ||||||
|  |       return this.pages <= this.current ? 'loading ' : 'nomore' | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   onShow() { | ||||||
|  |     this.current = 1; | ||||||
|  |     this.getList() | ||||||
|  |   }, | ||||||
|  |   onReachBottom() { | ||||||
|  |     this.current++; | ||||||
|  |     this.getList() | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getList() { | ||||||
|  |       this.$http.post('/app/appinterview/list-xcx', null, { | ||||||
|  |         params: { | ||||||
|  |           current: this.current, | ||||||
|  |           size: 10, | ||||||
|  |           ...this.search | ||||||
|  |         } | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.list = this.current > 1 ? [...this.list, ...res.data.records] : res.data.records | ||||||
|  |           this.pages = res.data.pages | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     goDetail(id, readonly) { | ||||||
|  |       let url = `./detail?id=${id}` | ||||||
|  |       readonly && (url += "&detail=1") | ||||||
|  |       uni.navigateTo({url}) | ||||||
|  |     }, | ||||||
|  |     gotoAdd() { | ||||||
|  |       uni.navigateTo({url: `./detail`}) | ||||||
|  |     }, | ||||||
|  |     handleDelete(ids) { | ||||||
|  |       this.$confirm("是否要删除该调查走访").then(() => { | ||||||
|  |         this.$http.post("/app/appinterview/delete", null, { | ||||||
|  |           params: {ids} | ||||||
|  |         }).then(res => { | ||||||
|  |           if (res?.code == 0) { | ||||||
|  |             this.$u.toast("删除成功!") | ||||||
|  |             this.getList() | ||||||
|  |           } | ||||||
|  |         }) | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     handleDateSearch(v) { | ||||||
|  |       this.search.startTime = v.startDate | ||||||
|  |       this.search.endTime = v.endDate || v.startDate | ||||||
|  |       this.current = 1 | ||||||
|  |       this.getList() | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .interview { | ||||||
|  |   width: 100%; | ||||||
|  |   min-height: 100%; | ||||||
|  |   box-sizing: border-box; | ||||||
|  |   position: absolute; | ||||||
|  |   background: #fff; | ||||||
|  |  | ||||||
|  |   .no-message { | ||||||
|  |     margin-top: 140px; | ||||||
|  |     text-align: center; | ||||||
|  |     color: #888; | ||||||
|  |     font-size: 30px; | ||||||
|  |  | ||||||
|  |     b { | ||||||
|  |       font-size: 32px; | ||||||
|  |       color: $uni-color-primary; | ||||||
|  |       padding: 0 8px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     image { | ||||||
|  |       width: 320px; | ||||||
|  |       height: 240px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .AiCard { | ||||||
|  |     width: 100%; | ||||||
|  |     min-height: 160px; | ||||||
|  |     background: #FFFFFF; | ||||||
|  |     padding: 32px 32px 0; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     display: flex; | ||||||
|  |     flex-direction: column; | ||||||
|  |     position: relative; | ||||||
|  |  | ||||||
|  |     b { | ||||||
|  |       display: block; | ||||||
|  |       width: 100%; | ||||||
|  |       font-size: 30px; | ||||||
|  |       white-space: nowrap; | ||||||
|  |       overflow: hidden; | ||||||
|  |       text-overflow: ellipsis; | ||||||
|  |       color: #333; | ||||||
|  |       margin-right: 60px; | ||||||
|  |       margin-bottom: 20px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .iconfont-iconMore { | ||||||
|  |       color: #666; | ||||||
|  |       position: absolute; | ||||||
|  |       right: 32px; | ||||||
|  |       top: 32px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .bottom { | ||||||
|  |       font-size: 24px; | ||||||
|  |       color: #999999; | ||||||
|  |       padding: 24px 0; | ||||||
|  |       border-bottom: 1px solid rgba(221, 221, 221, .4); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .AiImage { | ||||||
|  |       width: 30%; | ||||||
|  |       margin-bottom: 8px; | ||||||
|  |       margin-right: 8px; | ||||||
|  |  | ||||||
|  |       image { | ||||||
|  |         width: 100%; | ||||||
|  |         height: 218px; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .addBtn { | ||||||
|  |     width: 96px; | ||||||
|  |     height: 96px; | ||||||
|  |     flex-shrink: 0; | ||||||
|  |     background: $uni-color-primary; | ||||||
|  |     box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2); | ||||||
|  |     font-size: 48px; | ||||||
|  |     color: #fff; | ||||||
|  |     border-radius: 50%; | ||||||
|  |     justify-content: center; | ||||||
|  |     align-items: center; | ||||||
|  |     display: flex; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .menu { | ||||||
|  |     text-align: center; | ||||||
|  |     line-height: 80px; | ||||||
|  |     width: 192px; | ||||||
|  |     height: 80px; | ||||||
|  |     font-size: 28px; | ||||||
|  |     font-weight: 400; | ||||||
|  |     color: #333333; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ::v-deep .u-search { | ||||||
|  |     margin-bottom: 0 !important; | ||||||
|  |     padding-left: 146px; | ||||||
|  |     box-shadow: none; | ||||||
|  |  | ||||||
|  |     .u-content { | ||||||
|  |       padding-left: 50px; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										174
									
								
								src/pages/loading.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,174 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="loading"> | ||||||
|  |     <!--    <div class="iconfont iconfont-iconWeChat"/>--> | ||||||
|  |     <!--    <div class="iconfont iconfont-iconjuminxinxi"/>--> | ||||||
|  |     <!--    <div class="iconfont iconfont-iconLogo"/>--> | ||||||
|  |     <ai-result v-if="result.tips" v-bind="result"/> | ||||||
|  |     <template v-if="isDev"> | ||||||
|  |       <input v-if="!!$route.query.code" class="codeText" :value="$route.query.code"/> | ||||||
|  |       <div class="codeBtn" @click="devGetCode">获取code</div> | ||||||
|  |       <div flex class="appsPane wrap"> | ||||||
|  |         <b v-for="app in apps" :key="app.key" @tap="gotoApp(app.key)">{{ app.name }}</b> | ||||||
|  |       </div> | ||||||
|  |     </template> | ||||||
|  |  | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import {mapActions, mapState} from 'vuex' | ||||||
|  | import AiResult from "../components/AiResult"; | ||||||
|  | import UTag from "../uview/components/u-tag/u-tag"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: 'loading', | ||||||
|  |   components: {UTag, AiResult}, | ||||||
|  |   inject: ['root'], | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['token', 'apps', 'openUser', 'user']), | ||||||
|  |     currentApp() { | ||||||
|  |       return this.apps.find(e => e.key == this.$route.query.app) || {} | ||||||
|  |     }, | ||||||
|  |     isDev() { | ||||||
|  |       return this.$route.hash == "#dev" | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       result: {} | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     ...mapActions(['getToken', 'getAccount', 'agentSign', 'getUserInfo', 'getCode', 'closeAgent']), | ||||||
|  |     initAccess() { | ||||||
|  |       if (this.$route.hash == "#error" || this.isDev) { | ||||||
|  |         return Promise.resolve() | ||||||
|  |       } else if (this.$route.hash == "#form") { | ||||||
|  |         if (this.openUser?.openId || !!this.$route.query.preview) { | ||||||
|  |           this.openForm() | ||||||
|  |         } else if (this.$route.query?.code) { | ||||||
|  |           this.getToken(this.$route.query?.code) | ||||||
|  |           .then(() => this.getUserInfo()) | ||||||
|  |           .then(() => this.openForm()) | ||||||
|  |         } else this.getCode(location.href) | ||||||
|  |       } else if (this.token) {//获取账号信息 | ||||||
|  |         return this.getAccount() | ||||||
|  |       } else if (this.$route.query?.code) {//获取token | ||||||
|  |         return this.getToken(this.$route.query?.code) | ||||||
|  |       } else {//获取应用配置 | ||||||
|  |         this.getCode(location.href) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     openForm() { | ||||||
|  |       this.redirectTo("/askForm/askForm") | ||||||
|  |     }, | ||||||
|  |     redirectTo(path) { | ||||||
|  |       let {query, hash} = this.$route | ||||||
|  |       delete query.app | ||||||
|  |       uni.redirectTo({ | ||||||
|  |         url: `/pages${path}`, success: () => { | ||||||
|  |           this.$router.push({query, hash}) | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     gotoApp(app) { | ||||||
|  |       uni.reLaunch({url: '/pages/loading?app=' + app}) | ||||||
|  |     }, | ||||||
|  |     devGetCode() { | ||||||
|  |       this.getCode(location.origin + '/pages/loading#dev') | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     uni.showLoading({ | ||||||
|  |       title: "加载中" | ||||||
|  |     }) | ||||||
|  |     this.initAccess()?.then(() => { | ||||||
|  |       uni.hideLoading() | ||||||
|  |       if (this.token) { | ||||||
|  |         if (this.currentApp.name) { | ||||||
|  |           this.redirectTo(this.currentApp.path) | ||||||
|  |         } else if (this.$route.query.url) { | ||||||
|  |           this.redirectTo(this.$route.query.url) | ||||||
|  |         } else { | ||||||
|  |           this.result = { | ||||||
|  |             status: "error", | ||||||
|  |             tips: "应用加载失败", | ||||||
|  |             btn: "重新加载", | ||||||
|  |             btnTap() { | ||||||
|  |               location.href = location.href?.replace("#error", '') | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } else if (this.isDev) { | ||||||
|  |         this.result = { | ||||||
|  |           tips: "欢迎进入开发应用", | ||||||
|  |         } | ||||||
|  |       } else { | ||||||
|  |         this.result = { | ||||||
|  |           status: "error", | ||||||
|  |           tips: "应用加载失败", | ||||||
|  |           btn: "重新加载", | ||||||
|  |           btnTap() { | ||||||
|  |             location.href = location.href?.replace("#error", '') | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     })?.catch(() => { | ||||||
|  |       uni.navigateTo({url: './login'}) | ||||||
|  |     }) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .loading { | ||||||
|  |   height: 100%; | ||||||
|  |   position: relative; | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   align-items: center; | ||||||
|  |  | ||||||
|  |   & > span { | ||||||
|  |     font-size: 36px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .codeText { | ||||||
|  |     font-size: 24px; | ||||||
|  |     margin-top: 16px; | ||||||
|  |     padding: 4px 0; | ||||||
|  |     width: 100%; | ||||||
|  |     text-align: center; | ||||||
|  |     background: #ccc; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .codeBtn { | ||||||
|  |     width: 180px; | ||||||
|  |     text-align: center; | ||||||
|  |     cursor: pointer; | ||||||
|  |     font-size: 24px; | ||||||
|  |     background: $uni-color-warning; | ||||||
|  |     color: #fff; | ||||||
|  |     padding: 8px; | ||||||
|  |     margin-top: 16px; | ||||||
|  |     border-radius: 8px; | ||||||
|  |     font-weight: normal; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .appsPane { | ||||||
|  |     justify-content: center; | ||||||
|  |     margin-top: 16px; | ||||||
|  |     padding: 0 16px; | ||||||
|  |  | ||||||
|  |     b { | ||||||
|  |       cursor: pointer; | ||||||
|  |       font-size: 24px; | ||||||
|  |       background: $uni-color-primary; | ||||||
|  |       color: #fff; | ||||||
|  |       padding: 8px; | ||||||
|  |       margin: 4px; | ||||||
|  |       border-radius: 8px; | ||||||
|  |       font-weight: normal; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										96
									
								
								src/pages/login.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,96 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="login"> | ||||||
|  |     <u-form :model="form" ref="loginForm" label-width="140"> | ||||||
|  |       <u-form-item label="账号" prop="phone" :errory-type="['message']"> | ||||||
|  |         <u-input v-model="form.phone" placeholder="请输入手机号"/> | ||||||
|  |       </u-form-item> | ||||||
|  |       <u-form-item label="验证码" prop="vcode"> | ||||||
|  |         <u-input v-model="form.vcode" placeholder="请输入短信验证码"/> | ||||||
|  |         <u-verification-code ref="vcode" secords="60" @change="v=>tips=v"/> | ||||||
|  |         <div class="vcode" @tap="$u.debounce(getVCode)">{{ tips }}</div> | ||||||
|  |       </u-form-item> | ||||||
|  |     </u-form> | ||||||
|  |     <div bottom> | ||||||
|  |       <u-button type="primary" @tap="handleLogin">绑定并登录</u-button> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import {mapActions, mapState} from "vuex"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "login", | ||||||
|  |   inject: ['root'], | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['lastPage']), | ||||||
|  |     rules() { | ||||||
|  |       return { | ||||||
|  |         phone: [{required: true, message: "请选择分组"}], | ||||||
|  |         vcode: [{required: true, message: "请选择快捷回复类型"}], | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       form: {}, | ||||||
|  |       tips: '' | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     ...mapActions(['getCode']), | ||||||
|  |     getVCode() { | ||||||
|  |       if (this.form.phone) { | ||||||
|  |         this.$http.post("/admin/user/sendCode", null, { | ||||||
|  |           withoutToken: 1, | ||||||
|  |           params: {phone: this.form.phone} | ||||||
|  |         }).then(() => { | ||||||
|  |           this.$u.toast("验证已发送!") | ||||||
|  |           this.$refs.vcode?.start() | ||||||
|  |         }) | ||||||
|  |       } else { | ||||||
|  |         this.$u.toast("请先填写手机号!") | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     handleLogin() { | ||||||
|  |       this.$refs.loginForm.validate(v => { | ||||||
|  |         if (v) { | ||||||
|  |           let params = { | ||||||
|  |             ...this.form, code: this.$route.query?.code, then: res => { | ||||||
|  |               let last = uni.getStorageSync("lastApp") | ||||||
|  |               if (last) { | ||||||
|  |                 this.$store.commit("login", [res?.token_type, res?.access_token].join(" ").trim()) | ||||||
|  |                 uni.removeStorageSync("lastApp") | ||||||
|  |                 // this.root.getCode(location.origin + last) | ||||||
|  |                 uni.reLaunch({url: "./loading?app=" + last}) | ||||||
|  |               } else this.$u.toast("绑定成功,请重新打开应用页面!") | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |           this.$store.commit("bindAccount", params) | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     !this.$route.query?.code && this.getCode() | ||||||
|  |   }, | ||||||
|  |   mounted() { | ||||||
|  |     this.$nextTick(() => this.$refs.loginForm?.setRules(this.rules)) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .login { | ||||||
|  |   border-top: 1px solid #D4D4D4; | ||||||
|  |   padding: 0 0 208px; | ||||||
|  |   background: #F5F5F5; | ||||||
|  |   box-sizing: border-box; | ||||||
|  |   height: 100%; | ||||||
|  |  | ||||||
|  |   .vcode { | ||||||
|  |     color: $uni-color-primary; | ||||||
|  |     cursor: pointer; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||