整合工程
This commit is contained in:
		
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -27,3 +27,7 @@ yarn-error.log* | |||||||
| /project/*/dist | /project/*/dist | ||||||
| /ui/package-lock.json | /ui/package-lock.json | ||||||
| /examples/modules.json | /examples/modules.json | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /src/apps/ | ||||||
|  | /src/config.json | ||||||
|   | |||||||
							
								
								
									
										26
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "dvcp-web-apps", |   "name": "dvcp-web", | ||||||
|   "version": "3.0.0", |   "version": "4.0.0", | ||||||
|   "private": false, |   "private": false, | ||||||
|   "author": "kubbo", |   "author": "kubbo", | ||||||
|   "scripts": { |   "scripts": { | ||||||
| @@ -11,20 +11,10 @@ | |||||||
|     "dev:biaopin": "vue-cli-service serve examples/main.js --mode biaopin", |     "dev:biaopin": "vue-cli-service serve examples/main.js --mode biaopin", | ||||||
|     "dev:dv": "vue-cli-service serve examples/main.js --mode dv", |     "dev:dv": "vue-cli-service serve examples/main.js --mode dv", | ||||||
|     "dev:fengdu": "vue-cli-service serve examples/main.js --mode fengdu", |     "dev:fengdu": "vue-cli-service serve examples/main.js --mode fengdu", | ||||||
|     "lib": "npm publish||(npm unpublish -f&&npm publish)", |  | ||||||
|     "preui": "npm publish -ws||(npm unpublish -f -ws&&npm publish -ws)", |  | ||||||
|     "ui": "npm i dui@latest @dui/dv@latest", |  | ||||||
|     "sync": "node bin/appsSync.js", |     "sync": "node bin/appsSync.js", | ||||||
|     "preview": "vue-cli-service serve" |     "preview": "vue-cli-service serve", | ||||||
|  |     "prebuild": "" | ||||||
|   }, |   }, | ||||||
|   "workspaces": [ |  | ||||||
|     "ui", |  | ||||||
|     "ui/dv" |  | ||||||
|   ], |  | ||||||
|   "files": [ |  | ||||||
|     "packages", |  | ||||||
|     "project" |  | ||||||
|   ], |  | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "@amap/amap-jsapi-loader": "^1.0.1", |     "@amap/amap-jsapi-loader": "^1.0.1", | ||||||
|     "@dui/dv": "^1.0.0", |     "@dui/dv": "^1.0.0", | ||||||
| @@ -73,14 +63,6 @@ | |||||||
|     "vuex": "^3.5.1", |     "vuex": "^3.5.1", | ||||||
|     "vuex-persistedstate": "^2.7.1" |     "vuex-persistedstate": "^2.7.1" | ||||||
|   }, |   }, | ||||||
|   "vetur": { |  | ||||||
|     "attributes": "./attributes.json" |  | ||||||
|   }, |  | ||||||
|   "postcss": { |  | ||||||
|     "plugins": { |  | ||||||
|       "autoprefixer": {} |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   "browserslist": [ |   "browserslist": [ | ||||||
|     "> 1%", |     "> 1%", | ||||||
|     "last 2 versions", |     "last 2 versions", | ||||||
|   | |||||||
| @@ -1,105 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <ai-list class="AppReturnHomeRegister" v-if="!isShowDetail"> |  | ||||||
|     <template slot="title"> |  | ||||||
|       <ai-title title="返乡登记" :isShowBottomBorder="false" :fullname.sync="areaName" v-model="areaId" :instance="instance" @change="onAreaChange"></ai-title> |  | ||||||
|     </template> |  | ||||||
|     <template slot="tabs"> |  | ||||||
|       <el-tabs v-model="currIndex"> |  | ||||||
|         <el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label"> |  | ||||||
|           <component :areaId="areaId" :ref="String(i)" v-if="currIndex == i" :is="tab.comp" @change="onChange" lazy :instance="instance" :dict="dict" :permissions="permissions"/> |  | ||||||
|         </el-tab-pane> |  | ||||||
|       </el-tabs> |  | ||||||
|     </template> |  | ||||||
|   </ai-list> |  | ||||||
|   <Detail v-else-if="component === 'Detail'" :params="params" :instance="instance" :dict="dict" :permissions="permissions" @change="onChange"></Detail> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   import List from './components/List.vue' |  | ||||||
|   import Detail from './components/Detail.vue' |  | ||||||
|   import AbnormalList from './components/AbnormalList.vue' |  | ||||||
|   import { mapState } from 'vuex' |  | ||||||
|  |  | ||||||
|   export default { |  | ||||||
|     name: 'AppReturnHomeRegister', |  | ||||||
|     label: '返乡登记', |  | ||||||
|  |  | ||||||
|     components: { |  | ||||||
|       List, |  | ||||||
|       Detail, |  | ||||||
|       AbnormalList |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object, |  | ||||||
|       permissions: Function |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     computed: { |  | ||||||
|       ...mapState(['user']), |  | ||||||
|  |  | ||||||
|       tabs () { |  | ||||||
|         const tabList = [ |  | ||||||
|           {label: '返乡登记', name: 'List', comp: List, permission: ''}, |  | ||||||
|           // {label: '历史异常人员', name: 'AbnormalList', comp: AbnormalList, permission: ''} |  | ||||||
|         ] |  | ||||||
|  |  | ||||||
|         return tabList |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data () { |  | ||||||
|       return { |  | ||||||
|         activeName: 'JoinEvent', |  | ||||||
|         currIndex: '0', |  | ||||||
|         component: 'List', |  | ||||||
|         params: {}, |  | ||||||
|         areaId: '', |  | ||||||
|         isShowDetail: false, |  | ||||||
|         areaName: '' |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     created () { |  | ||||||
|       this.areaId = this.user.info.areaId |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       onChange (data) { |  | ||||||
|         if (data.type === 'Detail') { |  | ||||||
|           this.component = 'Detail' |  | ||||||
|           this.isShowDetail = true |  | ||||||
|           this.params = data.params |  | ||||||
|         } |  | ||||||
|         if (data.type === 'AbnormalList') { |  | ||||||
|           this.component = 'AbnormalList' |  | ||||||
|           this.isShowDetail = false |  | ||||||
|           this.params = data.params |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (data.type === 'List') { |  | ||||||
|           this.component = 'List' |  | ||||||
|           this.isShowDetail = false |  | ||||||
|           this.params = data.params |  | ||||||
|  |  | ||||||
|           this.$nextTick(() => { |  | ||||||
|             if (data.isRefresh) { |  | ||||||
|               this.$refs.component.getList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       onAreaChange () { |  | ||||||
|         this.$refs[this.currIndex][0].changeArea() |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
|   .AppReturnHomeRegister { |  | ||||||
|     height: 100%; |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -1,200 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <ai-list isTabs> |  | ||||||
|     <template slot="content"> |  | ||||||
|       <ai-search-bar bottomBorder> |  | ||||||
|         <template #left> |  | ||||||
|           <ai-select |  | ||||||
|             v-model="search.status" |  | ||||||
|             clearable |  | ||||||
|             placeholder="请选择健康状态" |  | ||||||
|             :selectList="dictList" |  | ||||||
|             @change="search.current = 1, getList()"> |  | ||||||
|           </ai-select> |  | ||||||
|           <ai-download :instance="instance" url="/app/appepidemicbackhomerecord/export" :params="param" fileName="返乡登记" :disabled="tableData.length == 0"> |  | ||||||
|             <el-button icon="iconfont iconExported" :disabled="tableData.length == 0">导出</el-button> |  | ||||||
|           </ai-download> |  | ||||||
|         </template> |  | ||||||
|         <template #right> |  | ||||||
|           <el-input |  | ||||||
|             v-model="search.name" |  | ||||||
|             size="small" |  | ||||||
|             placeholder="请输入姓名" |  | ||||||
|             clearable |  | ||||||
|             v-throttle="() => {search.current = 1, getList()}" |  | ||||||
|             @clear="search.current = 1, search.name = '', getList()" |  | ||||||
|             suffix-icon="iconfont iconSearch"> |  | ||||||
|           </el-input> |  | ||||||
|         </template> |  | ||||||
|       </ai-search-bar> |  | ||||||
|       <ai-table |  | ||||||
|         :tableData="tableData" |  | ||||||
|         :col-configs="colConfigs" |  | ||||||
|         :total="total" |  | ||||||
|         v-loading="loading" |  | ||||||
|         style="margin-top: 16px;" |  | ||||||
|         :current.sync="search.current" |  | ||||||
|         :size.sync="search.size" |  | ||||||
|         @getList="getList"> |  | ||||||
|         <el-table-column slot="options" width="140px" fixed="right" label="操作" align="center"> |  | ||||||
|           <template slot-scope="{ row }"> |  | ||||||
|             <div class="table-options"> |  | ||||||
|               <el-button type="text" @click="toDetail(row.id)">详情</el-button> |  | ||||||
|               <el-button type="text" @click="remove(row.id)">删除</el-button> |  | ||||||
|             </div> |  | ||||||
|           </template> |  | ||||||
|         </el-table-column> |  | ||||||
|       </ai-table> |  | ||||||
|     </template> |  | ||||||
|   </ai-list> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   import { mapState } from 'vuex' |  | ||||||
|   export default { |  | ||||||
|     name: 'AbnormalList', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data () { |  | ||||||
|       return { |  | ||||||
|         search: { |  | ||||||
|           current: 1, |  | ||||||
|           size: 10, |  | ||||||
|           name: '', |  | ||||||
|           arriveAreaId: '', |  | ||||||
|           status: '' |  | ||||||
|         }, |  | ||||||
|         dictList: [{ |  | ||||||
|           dictName: '异常', |  | ||||||
|           dictValue: '0' |  | ||||||
|         }, { |  | ||||||
|           dictName: '正常', |  | ||||||
|           dictValue: '1' |  | ||||||
|         }], |  | ||||||
|         info: {}, |  | ||||||
|         colConfigs: [ |  | ||||||
|           { prop: 'name', label: '姓名' }, |  | ||||||
|           { prop: 'phone', align: 'center', label: '手机号码' }, |  | ||||||
|           { prop: 'startTime', align: 'center', label: '出发时间', format: v => v.substr(0, v.length - 3) }, |  | ||||||
|           { |  | ||||||
|             prop: 'startAreaName', |  | ||||||
|             align: 'center', |  | ||||||
|             label: '出发地区' |  | ||||||
|           }, |  | ||||||
|           { prop: 'arriveTime', align: 'center', label: '到达时间', format: v => v.substr(0, v.length - 3) }, |  | ||||||
|           { |  | ||||||
|             prop: 'arriveAreaName', |  | ||||||
|             align: 'center', |  | ||||||
|             label: '到达地区' |  | ||||||
|           }, |  | ||||||
|           { prop: 'checkTime', align: 'center', label: '核酸日期', format: v => v.split(' ')[0] }, |  | ||||||
|           { |  | ||||||
|             prop: 'status', |  | ||||||
|             align: 'center', |  | ||||||
|             label: '健康状态', |  | ||||||
|             render: (h, {row}) => { |  | ||||||
|               return h('span', { |  | ||||||
|                 style: { |  | ||||||
|                   color: row.status === '0' ? 'red' : '#333' |  | ||||||
|                 } |  | ||||||
|               }, row.status === '0' ? '异常' : '正常') |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|         ], |  | ||||||
|         ids: [], |  | ||||||
|         tableData: [], |  | ||||||
|         total: 0, |  | ||||||
|         loading: false, |  | ||||||
|         disabledLevel: 0 |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     computed: { |  | ||||||
|       ...mapState(['user']), |  | ||||||
|  |  | ||||||
|       param () { |  | ||||||
|         return this.search |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     created () { |  | ||||||
|       this.disabledLevel = this.user.info.areaList.length - 1 |  | ||||||
|       this.search.arriveAreaId = this.user.info.areaId |  | ||||||
|       this.loading = true |  | ||||||
|       this.dict.load(['marriageType', 'marriagePersonType', 'modeType']).then(() => { |  | ||||||
|         this.getList() |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       getList () { |  | ||||||
|         this.instance.post(`/app/appepidemicbackhomerecord/list`, null, { |  | ||||||
|           params: { |  | ||||||
|             ...this.search |  | ||||||
|           } |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.tableData = res.data.records |  | ||||||
|             this.total = res.data.total |  | ||||||
|             this.loading = false |  | ||||||
|           } else { |  | ||||||
|             this.loading = false |  | ||||||
|           } |  | ||||||
|         }).catch(() => { |  | ||||||
|           this.loading = false |  | ||||||
|         }) |  | ||||||
|  |  | ||||||
|         this.getTotalInfo() |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       toDetail (id) { |  | ||||||
|         this.$emit('change', { |  | ||||||
|           type: 'Detail', |  | ||||||
|           params: { |  | ||||||
|             id: id || '' |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       changeArea () { |  | ||||||
|         this.search.current = 1 |  | ||||||
|  |  | ||||||
|         this.$nextTick(() => { |  | ||||||
|           this.getList() |  | ||||||
|           this.getTotalInfo() |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       remove(id) { |  | ||||||
|         this.$confirm('确定删除该数据?').then(() => { |  | ||||||
|           this.instance.post(`/app/appepidemicbackhomerecord/delete?ids=${id}`).then(res => { |  | ||||||
|             if (res.code == 0) { |  | ||||||
|               this.$message.success('删除成功!') |  | ||||||
|               this.getTotalInfo() |  | ||||||
|               this.getList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|  |  | ||||||
|       getTotalInfo () { |  | ||||||
|         this.instance.post(`/app/appepidemicbackhomerecord/statistic`, null, { |  | ||||||
|           params: { |  | ||||||
|             areaId: this.search.arriveAreaId |  | ||||||
|           } |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.info = res.data |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style scoped lang="scss"> |  | ||||||
| </style> |  | ||||||
| @@ -1,279 +0,0 @@ | |||||||
|  <template> |  | ||||||
|   <ai-detail isHasSidebar> |  | ||||||
|     <template slot="title"> |  | ||||||
|       <ai-title title="返乡登记详情" isShowBack isShowBottomBorder @onBackClick="cancel(false)"> |  | ||||||
|       </ai-title> |  | ||||||
|     </template> |  | ||||||
|     <template slot="content"> |  | ||||||
|       <AiSidebar :tabTitle="tabList" v-model="currIndex"></AiSidebar> |  | ||||||
|       <div v-show="currIndex === 0"> |  | ||||||
|         <ai-card title="基本信息" v-show="currIndex === 0"> |  | ||||||
|           <template #content> |  | ||||||
|             <ai-wrapper |  | ||||||
|               label-width="120px"> |  | ||||||
|               <ai-info-item label="姓名" :value="info.name"></ai-info-item> |  | ||||||
|               <ai-info-item label="填报时间" :value="info.createTime"></ai-info-item> |  | ||||||
|               <ai-info-item label="身份证号" :value="info.idNumber"></ai-info-item> |  | ||||||
|               <ai-info-item label="手机号码" :value="info.phone"></ai-info-item> |  | ||||||
|               <ai-info-item label="人员类别" isLine> |  | ||||||
|                 <span :style="(info.type == 0 || info.type == 3 || info.type ==6 || info.type == 9)? 'color:#42D784;' : 'color:#f46;'">{{dict.getLabel('epidemicRecentPersonType', info.type)}}</span> |  | ||||||
|               </ai-info-item> |  | ||||||
|             </ai-wrapper> |  | ||||||
|           </template> |  | ||||||
|         </ai-card> |  | ||||||
|         <ai-card title="行程信息"> |  | ||||||
|           <template #content> |  | ||||||
|             <ai-wrapper |  | ||||||
|               label-width="120px"> |  | ||||||
|               <ai-info-item label="出发时间" :value="info.startTime"></ai-info-item> |  | ||||||
|               <ai-info-item label="出发地区" > |  | ||||||
|                 <span  :style="{color: info.denger == 1 ? '#FF4466' : '#333'}">{{info.startAreaName}} </span> |  | ||||||
|               </ai-info-item> |  | ||||||
|               <ai-info-item label="出发地址" isLine :value="info.startAddress"></ai-info-item> |  | ||||||
|               <ai-info-item label="出行方式" :value="dict.getLabel('epidemicRecentTravel', info.travelType)"></ai-info-item> |  | ||||||
|               <ai-info-item label="行程描述" isLine :value="info.description"></ai-info-item> |  | ||||||
|               <ai-info-item label="到达时间" :value="info.arriveTime"></ai-info-item> |  | ||||||
|               <ai-info-item label="到达地区" :value="info.arriveAreaName"></ai-info-item> |  | ||||||
|               <ai-info-item label="返乡地址" isLine :value="info.arriveAddress"></ai-info-item> |  | ||||||
|             </ai-wrapper> |  | ||||||
|           </template> |  | ||||||
|         </ai-card> |  | ||||||
|         <ai-card title="健康状况"> |  | ||||||
|           <template #content> |  | ||||||
|             <ai-wrapper |  | ||||||
|               label-width="120px"> |  | ||||||
|               <ai-info-item label="当前体温"> |  | ||||||
|                 <span :style="info.temperature >= 37.3 ? 'color:#f46;' : ''">{{ info.temperature + '℃' }}</span> |  | ||||||
|               </ai-info-item> |  | ||||||
|               <ai-info-item label="14天内是否接触新冠确诊或疑似患者"> |  | ||||||
|                 <span :class="'color-'+info.touchInFourteen">{{$dict.getLabel('epidemicTouchInFourteen', info.touchInFourteen)}}</span>  |  | ||||||
|               </ai-info-item> |  | ||||||
|               <ai-info-item label="当前健康状况">  |  | ||||||
|                 <span></span> |  | ||||||
|                 <span v-for="(item, index) in info.health" :key="index" :style="item != 0 ? 'color:#FF4466;' : ''"><span v-if="index>0">;</span>{{$dict.getLabel('epidemicRecentHealth', item)}}</span> |  | ||||||
|               </ai-info-item> |  | ||||||
|             </ai-wrapper> |  | ||||||
|           </template> |  | ||||||
|         </ai-card> |  | ||||||
|         <ai-card title="核酸检测"> |  | ||||||
|           <template #content> |  | ||||||
|             <ai-wrapper |  | ||||||
|               label-width="120px"> |  | ||||||
|               <ai-info-item label="检测日期" :value="info.checkTime && info.checkTime.split(' ')[0]"></ai-info-item> |  | ||||||
|               <ai-info-item label="检测结果"> |  | ||||||
|                 <span :style="info.checkResult == 1 ? 'color:#f46;' : 'color:#42D784;'">{{$dict.getLabel('epidemicRecentTestResult', info.checkResult)}}</span> |  | ||||||
|               </ai-info-item> |  | ||||||
|               <ai-info-item label="本人健康码截图" isLine> |  | ||||||
|                 <ai-uploader |  | ||||||
|                   :instance="instance" |  | ||||||
|                   v-model="info.checkPhoto" |  | ||||||
|                   disabled |  | ||||||
|                   :limit="9"> |  | ||||||
|                 </ai-uploader> |  | ||||||
|               </ai-info-item> |  | ||||||
|             </ai-wrapper> |  | ||||||
|           </template> |  | ||||||
|         </ai-card> |  | ||||||
|       </div> |  | ||||||
|       <div v-show="currIndex === 1"> |  | ||||||
|         <ai-card title="异常处理"> |  | ||||||
|           <template #right> |  | ||||||
|             <el-button type="primary" v-if="info.status === '0'" @click="release">解除异常</el-button> |  | ||||||
|           </template> |  | ||||||
|           <template #content> |  | ||||||
|             <ai-wrapper |  | ||||||
|               label-width="120px"> |  | ||||||
|               <ai-info-item label="姓名" :value="info.name"></ai-info-item> |  | ||||||
|               <ai-info-item label="填报时间" :value="info.createTime"></ai-info-item> |  | ||||||
|               <ai-info-item label="身份证号" :value="info.idNumber"></ai-info-item> |  | ||||||
|               <ai-info-item label="手机号码" :value="info.phone"></ai-info-item> |  | ||||||
|               <ai-info-item label="人员类别" isLine :value="dict.getLabel('epidemicRecentPersonType', info.type)"></ai-info-item> |  | ||||||
|               <ai-info-item label="异常状况" isLine> |  | ||||||
|                 <span :style="{color: info.unusual ? 'red' : '#333'}">{{ info.unusual || '-' }}</span> |  | ||||||
|               </ai-info-item> |  | ||||||
|               <ai-info-item label="异常解除人" v-if="info.releaseName && info.status === '1'" :value="info.releaseName"></ai-info-item> |  | ||||||
|               <ai-info-item label="异常解除时间" v-if="info.releaseTime && info.status === '1'" :value="info.releaseTime"></ai-info-item> |  | ||||||
|             </ai-wrapper> |  | ||||||
|           </template> |  | ||||||
|         </ai-card> |  | ||||||
|         <ai-card title="异常情况记录"> |  | ||||||
|           <template #right> |  | ||||||
|             <el-button type="primary" v-if="info.status === '0'" @click="isShow = true">添加记录</el-button> |  | ||||||
|           </template> |  | ||||||
|           <template #content> |  | ||||||
|             <ai-table |  | ||||||
|               :tableData="tableData" |  | ||||||
|               :col-configs="colConfigs" |  | ||||||
|               :total="total" |  | ||||||
|               :current.sync="search.current" |  | ||||||
|               :size.sync="search.size" |  | ||||||
|               @getList="getList"> |  | ||||||
|               <el-table-column slot="options" width="120px" fixed="right" label="操作" align="center"> |  | ||||||
|                 <template slot-scope="{ row }"> |  | ||||||
|                   <div class="table-options"> |  | ||||||
|                     <el-button type="text" @click="remove(row.id)">删除</el-button> |  | ||||||
|                   </div> |  | ||||||
|                 </template> |  | ||||||
|               </el-table-column> |  | ||||||
|             </ai-table> |  | ||||||
|           </template> |  | ||||||
|         </ai-card> |  | ||||||
|         <ai-dialog |  | ||||||
|           :visible.sync="isShow" |  | ||||||
|           width="800px" |  | ||||||
|           @close="form.content = ''" |  | ||||||
|           title="添加异常记录" |  | ||||||
|           @onConfirm="onConfirm"> |  | ||||||
|           <el-form class="ai-form" label-width="120px" :model="form" ref="form"> |  | ||||||
|             <el-form-item label="异常记录" prop="content" style="width: 100%;" :rules="[{ required: true, message: '请输入异常记录' }]"> |  | ||||||
|               <el-input type="textarea" :rows="5" :maxlength="500" v-model="form.content" clearable placeholder="请输入异常记录" show-word-limit></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-form> |  | ||||||
|         </ai-dialog> |  | ||||||
|       </div> |  | ||||||
|     </template> |  | ||||||
|   </ai-detail> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   export default { |  | ||||||
|     name: 'Detail', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object, |  | ||||||
|       params: Object |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data () { |  | ||||||
|       return { |  | ||||||
|         total: 0, |  | ||||||
|         info: {}, |  | ||||||
|         id: '', |  | ||||||
|         search: { |  | ||||||
|           current: 1, |  | ||||||
|           size: 10 |  | ||||||
|         }, |  | ||||||
|         form: { |  | ||||||
|           content: '' |  | ||||||
|         }, |  | ||||||
|         isShow: false, |  | ||||||
|         currIndex: 0, |  | ||||||
|         tableData: [], |  | ||||||
|         colConfigs: [ |  | ||||||
|           {prop: 'content', label: '异常记录', align: 'center' }, |  | ||||||
|           {prop: 'createTime', label: '创建时间', align: 'center'}, |  | ||||||
|           {prop: 'createUserName', label: '记录人', align: 'center' } |  | ||||||
|         ], |  | ||||||
|         tabList: ['基本信息', '异常处理'] |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     created () { |  | ||||||
|       if (this.params && this.params.id) { |  | ||||||
|         this.id = this.params.id |  | ||||||
|         this.$dict.load(['epidemicRecentHealth', 'epidemicRecentTravel', 'epidemicTouchInFourteen', 'epidemicRecentPersonType', 'epidemicRecentTestResult']).then(() => { |  | ||||||
|           this.getInfo(this.params.id) |  | ||||||
|         }) |  | ||||||
|  |  | ||||||
|         this.getList() |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       getInfo (id) { |  | ||||||
|         this.instance.post(`/app/appepidemicbackhomerecord/queryDetailById?id=${id}`).then(res => { |  | ||||||
|           if (res.code === 0) { |  | ||||||
|             this.info = res.data |  | ||||||
|             this.info.checkPhoto = res.data.checkPhoto ? JSON.parse(res.data.checkPhoto) : [] |  | ||||||
|             let healthName = '' |  | ||||||
|             this.info.isHealth = false |  | ||||||
|             res.data.health.split(',').forEach(v => { |  | ||||||
|               if (v > 0) { |  | ||||||
|                 this.info.isHealth = true |  | ||||||
|               } |  | ||||||
|               healthName = healthName + this.$dict.getLabel('epidemicRecentHealth', v) |  | ||||||
|             }) |  | ||||||
|             this.info.healthName = healthName |  | ||||||
|             this.info.health = this.info.health.split(',') |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       release () { |  | ||||||
|         this.$confirm('确定解除异常?').then(() => { |  | ||||||
|           this.instance.post(`/app/appepidemicbackhomerecord/release?recordId=${this.params.id}`, { |  | ||||||
|             id: this.params.id |  | ||||||
|           }).then(res => { |  | ||||||
|             if (res.code == 0) { |  | ||||||
|               this.$message.success('解除异常成功!') |  | ||||||
|               this.currIndex = 0 |  | ||||||
|               this.getInfo(this.params.id) |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       remove(id) { |  | ||||||
|         this.$confirm('确定删除该数据?').then(() => { |  | ||||||
|           this.instance.post(`/app/appepidemicunusuallog/delete?ids=${id}`).then(res => { |  | ||||||
|             if (res.code == 0) { |  | ||||||
|               this.$message.success('删除成功!') |  | ||||||
|               this.getList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       onConfirm() { |  | ||||||
|         this.$refs.form.validate(v => { |  | ||||||
|           if (v) { |  | ||||||
|             this.instance.post('/app/appepidemicunusuallog/addOrUpdate', { |  | ||||||
|               ...this.form, |  | ||||||
|               recordId: this.params.id |  | ||||||
|             }).then(res => { |  | ||||||
|               if (res?.code == 0) { |  | ||||||
|                 this.isShow = false |  | ||||||
|                 this.getList() |  | ||||||
|                 this.$message.success('添加成功!') |  | ||||||
|               } |  | ||||||
|             }) |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       getList () { |  | ||||||
|         this.instance.post(`/app/appepidemicunusuallog/list`, null, { |  | ||||||
|           params: { |  | ||||||
|             ...this.search, |  | ||||||
|             recordId: this.params.id |  | ||||||
|           } |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.tableData = res.data.records |  | ||||||
|             this.total = res.data.total |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       cancel () { |  | ||||||
|         this.$emit('change', { |  | ||||||
|           type: 'List', |  | ||||||
|           isRefresh: true |  | ||||||
|         }) |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style scoped lang="scss"> |  | ||||||
|   .color-0{ |  | ||||||
|     color: #42D784; |  | ||||||
|   } |  | ||||||
|   .color-1{ |  | ||||||
|     color: #f46; |  | ||||||
|   } |  | ||||||
|   .color-2{ |  | ||||||
|     color: #1365DD; |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -1,273 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <ai-list class="list" isTabs> |  | ||||||
|     <template slot="content"> |  | ||||||
|       <div class="statistics-top"> |  | ||||||
|         <div class="statistics-top__item"> |  | ||||||
|           <span>返乡人数</span> |  | ||||||
|           <h2 style="color: #2266FF;">{{ info.total }}</h2> |  | ||||||
|         </div> |  | ||||||
|         <div class="statistics-top__item"> |  | ||||||
|           <span>今日新增返乡</span> |  | ||||||
|           <h2 style="color: #22AA99;">{{ info.today }}</h2> |  | ||||||
|         </div> |  | ||||||
|         <div class="statistics-top__item"> |  | ||||||
|           <span>异常人数</span> |  | ||||||
|           <h2 style="color: #F8B425">{{ info.unusual }}</h2> |  | ||||||
|         </div> |  | ||||||
|         <div class="statistics-top__item"> |  | ||||||
|           <span>今日异常人数</span> |  | ||||||
|           <h2 style="color: red">{{ info.todayUnusual }}</h2> |  | ||||||
|         </div> |  | ||||||
|         <div class="statistics-top__item"> |  | ||||||
|           <span>异常处理</span> |  | ||||||
|           <h2 style="color: red">{{ info.release }}</h2> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|       <div class="content"> |  | ||||||
|         <ai-search-bar bottomBorder> |  | ||||||
|           <template #left> |  | ||||||
|             <ai-select |  | ||||||
|               v-model="search.status" |  | ||||||
|               clearable |  | ||||||
|               placeholder="请选择健康状态" |  | ||||||
|               :selectList="dictList" |  | ||||||
|               @change="search.current = 1, getList()"> |  | ||||||
|             </ai-select> |  | ||||||
|             <ai-download :instance="instance" url="/app/appepidemicbackhomerecord/export" :params="param" fileName="返乡登记" :disabled="tableData.length == 0"> |  | ||||||
|               <el-button icon="iconfont iconExported" :disabled="tableData.length == 0">导出</el-button> |  | ||||||
|             </ai-download> |  | ||||||
|           </template> |  | ||||||
|           <template #right> |  | ||||||
|             <el-input |  | ||||||
|               v-model="search.name" |  | ||||||
|               size="small" |  | ||||||
|               placeholder="请输入姓名" |  | ||||||
|               clearable |  | ||||||
|               v-throttle="() => {search.current = 1, getList()}" |  | ||||||
|               @clear="search.current = 1, search.name = '', getList()" |  | ||||||
|               suffix-icon="iconfont iconSearch"> |  | ||||||
|             </el-input> |  | ||||||
|           </template> |  | ||||||
|         </ai-search-bar> |  | ||||||
|         <ai-table |  | ||||||
|           :tableData="tableData" |  | ||||||
|           :col-configs="colConfigs" |  | ||||||
|           :total="total" |  | ||||||
|           v-loading="loading" |  | ||||||
|           style="margin-top: 16px;" |  | ||||||
|           :current.sync="search.current" |  | ||||||
|           :size.sync="search.size" |  | ||||||
|           @getList="getList"> |  | ||||||
|           <el-table-column slot="options" width="140px" fixed="right" label="操作" align="center"> |  | ||||||
|             <template slot-scope="{ row }"> |  | ||||||
|               <div class="table-options"> |  | ||||||
|                 <el-button type="text" @click="toDetail(row.id)">详情</el-button> |  | ||||||
|                 <el-button type="text" @click="remove(row.id)">删除</el-button> |  | ||||||
|               </div> |  | ||||||
|             </template> |  | ||||||
|           </el-table-column> |  | ||||||
|         </ai-table> |  | ||||||
|       </div> |  | ||||||
|     </template> |  | ||||||
|   </ai-list> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   import { mapState } from 'vuex' |  | ||||||
|   export default { |  | ||||||
|     name: 'List', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object, |  | ||||||
|       areaId: String |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data () { |  | ||||||
|       return { |  | ||||||
|         search: { |  | ||||||
|           current: 1, |  | ||||||
|           size: 10, |  | ||||||
|           name: '', |  | ||||||
|           status: '' |  | ||||||
|         }, |  | ||||||
|         dictList: [{ |  | ||||||
|           dictName: '异常', |  | ||||||
|           dictValue: '0' |  | ||||||
|         }, { |  | ||||||
|           dictName: '正常', |  | ||||||
|           dictValue: '1' |  | ||||||
|         }], |  | ||||||
|         info: {}, |  | ||||||
|         colConfigs: [ |  | ||||||
|           { prop: 'name', label: '姓名' }, |  | ||||||
|           { prop: 'phone', align: 'center', label: '手机号码' }, |  | ||||||
|           { prop: 'startTime', align: 'center', label: '出发时间', format: v => v.substr(0, v.length - 3) }, |  | ||||||
|           { |  | ||||||
|             prop: 'startAreaName', |  | ||||||
|             align: 'center', |  | ||||||
|             label: '出发地区' |  | ||||||
|           }, |  | ||||||
|           { prop: 'arriveTime', align: 'center', label: '到达时间', format: v => v.substr(0, v.length - 3) }, |  | ||||||
|           { |  | ||||||
|             prop: 'arriveAreaName', |  | ||||||
|             align: 'center', |  | ||||||
|             label: '到达地区' |  | ||||||
|           }, |  | ||||||
|           { prop: 'checkTime', align: 'center', label: '核酸日期', format: v => v.split(' ')[0] }, |  | ||||||
|           { |  | ||||||
|             prop: 'status', |  | ||||||
|             align: 'center', |  | ||||||
|             label: '健康状态', |  | ||||||
|             render: (h, {row}) => { |  | ||||||
|               return h('span', { |  | ||||||
|                 style: { |  | ||||||
|                   color: row.status === '0' ? 'red' : '#333' |  | ||||||
|                 } |  | ||||||
|               }, row.status === '0' ? '异常' : '正常') |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|         ], |  | ||||||
|         ids: [], |  | ||||||
|         tableData: [], |  | ||||||
|         total: 0, |  | ||||||
|         loading: false, |  | ||||||
|         disabledLevel: 0 |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     computed: { |  | ||||||
|       ...mapState(['user']), |  | ||||||
|  |  | ||||||
|       param () { |  | ||||||
|         return this.search |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     created () { |  | ||||||
|       this.disabledLevel = this.user.info.areaList.length - 1 |  | ||||||
|       this.loading = true |  | ||||||
|       this.dict.load(['marriageType', 'marriagePersonType', 'modeType']).then(() => { |  | ||||||
|         this.getList() |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       getList () { |  | ||||||
|         this.instance.post(`/app/appepidemicbackhomerecord/list`, null, { |  | ||||||
|           params: { |  | ||||||
|             ...this.search, |  | ||||||
|             arriveAreaId: this.areaId |  | ||||||
|           } |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.tableData = res.data.records |  | ||||||
|             this.total = res.data.total |  | ||||||
|             this.loading = false |  | ||||||
|           } else { |  | ||||||
|             this.loading = false |  | ||||||
|           } |  | ||||||
|         }).catch(() => { |  | ||||||
|           this.loading = false |  | ||||||
|         }) |  | ||||||
|  |  | ||||||
|         this.getTotalInfo() |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       toDetail (id) { |  | ||||||
|         this.$emit('change', { |  | ||||||
|           type: 'Detail', |  | ||||||
|           params: { |  | ||||||
|             id: id || '' |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       changeArea () { |  | ||||||
|         this.search.current = 1 |  | ||||||
|  |  | ||||||
|         this.$nextTick(() => { |  | ||||||
|           this.getList() |  | ||||||
|           this.getTotalInfo() |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       remove(id) { |  | ||||||
|         this.$confirm('确定删除该数据?').then(() => { |  | ||||||
|           this.instance.post(`/app/appepidemicbackhomerecord/delete?ids=${id}`).then(res => { |  | ||||||
|             if (res.code == 0) { |  | ||||||
|               this.$message.success('删除成功!') |  | ||||||
|               this.getTotalInfo() |  | ||||||
|               this.getList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|  |  | ||||||
|       getTotalInfo () { |  | ||||||
|         this.instance.post(`/app/appepidemicbackhomerecord/statistic`, null, { |  | ||||||
|           params: { |  | ||||||
|             areaId: this.search.arriveAreaId |  | ||||||
|           } |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.info = res.data |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style scoped lang="scss"> |  | ||||||
|   .list { |  | ||||||
|     :deep( .ai-list__content ){ |  | ||||||
|       padding: 0!important; |  | ||||||
|  |  | ||||||
|       .ai-list__content--right-wrapper { |  | ||||||
|         background: transparent!important; |  | ||||||
|         box-shadow: none!important; |  | ||||||
|         margin: 0!important; |  | ||||||
|         padding: 0 0 0!important; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     .statistics-top { |  | ||||||
|       display: flex; |  | ||||||
|       align-items: center; |  | ||||||
|       margin-bottom: 20px; |  | ||||||
|  |  | ||||||
|       & > div { |  | ||||||
|         flex: 1; |  | ||||||
|         height: 96px; |  | ||||||
|         line-height: 1; |  | ||||||
|         margin-right: 20px; |  | ||||||
|         padding: 16px 24px; |  | ||||||
|         background: #FFFFFF; |  | ||||||
|         box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15); |  | ||||||
|         border-radius: 4px; |  | ||||||
|  |  | ||||||
|         &:last-child { |  | ||||||
|           margin-right: 0; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         h3 { |  | ||||||
|           font-size: 24px; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         span { |  | ||||||
|           display: block; |  | ||||||
|           margin-bottom: 16px; |  | ||||||
|           color: #888888; |  | ||||||
|           font-size: 16px; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .content { |  | ||||||
|       padding: 16px; |  | ||||||
|       background: #FFFFFF; |  | ||||||
|       box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -1,65 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <div class="doc-circulation ailist-wrapper"> |  | ||||||
|     <keep-alive :include="['List']"> |  | ||||||
|       <component ref="component" :moduleName="moduleName" :moduleId="moduleId" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component> |  | ||||||
|     </keep-alive> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   import List from './components/List' |  | ||||||
|   import Add from './components/Add' |  | ||||||
|  |  | ||||||
|   export default { |  | ||||||
|     name: 'AppRiskArea', |  | ||||||
|     label: '风险配置', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data () { |  | ||||||
|       return { |  | ||||||
|         component: 'List', |  | ||||||
|         params: {}, |  | ||||||
|         moduleId: '', |  | ||||||
|         include: [], |  | ||||||
|         moduleName: '' |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     components: { |  | ||||||
|       Add, |  | ||||||
|       List |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       onChange (data) { |  | ||||||
|         if (data.type === 'Add') { |  | ||||||
|           this.component = 'Add' |  | ||||||
|           this.params = data.params |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (data.type === 'list') { |  | ||||||
|           this.component = 'List' |  | ||||||
|           this.params = data.params |  | ||||||
|  |  | ||||||
|           this.$nextTick(() => { |  | ||||||
|             if (data.isRefresh) { |  | ||||||
|               this.$refs.component.getList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss"> |  | ||||||
|   .doc-circulation { |  | ||||||
|     height: 100%; |  | ||||||
|     background: #F3F6F9; |  | ||||||
|     overflow: auto; |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -1,154 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <ai-detail class="content-add"> |  | ||||||
|     <template slot="title"> |  | ||||||
|       <ai-title :title="params.id ? '编辑风险区域' : '添加风险区域'" isShowBack isShowBottomBorder @onBackClick="cancel(false)"> |  | ||||||
|       </ai-title> |  | ||||||
|     </template> |  | ||||||
|     <template slot="content"> |  | ||||||
|       <ai-card title="基本信息"> |  | ||||||
|         <template #content> |  | ||||||
|           <el-form class="ai-form" :model="form" label-width="120px" ref="form"> |  | ||||||
|             <el-form-item prop="areaId" style="width: 100%;" label="选择地区" :rules="[{required: true, message: '请选择地区', trigger: 'change'}]"> |  | ||||||
|               <ai-area-select clearable @fullname="v => form.areaName = v" always-show :instance="instance" v-model="form.areaId"></ai-area-select> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="风险等级" style="width: 100%;" prop="level" :rules="[{required: true, message: '请选择风险等级', trigger: 'change'}]"> |  | ||||||
|               <ai-select |  | ||||||
|                 v-model="form.level" |  | ||||||
|                 clearable |  | ||||||
|                 placeholder="请选择风险等级" |  | ||||||
|                 :selectList="dict.getDict('epidemicDangerousAreaLevel')"> |  | ||||||
|               </ai-select> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-form> |  | ||||||
|         </template> |  | ||||||
|       </ai-card> |  | ||||||
|     </template> |  | ||||||
|     <template #footer> |  | ||||||
|       <el-button @click="cancel">取消</el-button> |  | ||||||
|       <el-button type="primary" @click="confirm">提交</el-button> |  | ||||||
|     </template> |  | ||||||
|   </ai-detail> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   import { mapState } from 'vuex' |  | ||||||
|   export default { |  | ||||||
|     name: 'Add', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object, |  | ||||||
|       params: Object, |  | ||||||
|       moduleName: String |  | ||||||
|     }, |  | ||||||
|     data () { |  | ||||||
|       return { |  | ||||||
|         info: {}, |  | ||||||
|         form: { |  | ||||||
|           level: '', |  | ||||||
|           areaId: '', |  | ||||||
|           areaName: '' |  | ||||||
|         }, |  | ||||||
|         id: '' |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     computed: { |  | ||||||
|       ...mapState(['user']) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     created () { |  | ||||||
|       this.dict.load('epidemicDangerousAreaLevel').then(() => { |  | ||||||
|         if (this.params && this.params.id) { |  | ||||||
|           this.id = this.params.id |  | ||||||
|           this.getInfo(this.params.id) |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       getInfo (id) { |  | ||||||
|         this.instance.post(`/app/appepidemicdangerousarea/queryDetailById?id=${id}`).then(res => { |  | ||||||
|           if (res.code === 0) { |  | ||||||
|             this.form = res.data |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       confirm () { |  | ||||||
|         this.$refs.form.validate((valid) => { |  | ||||||
|           if (valid) { |  | ||||||
|             this.instance.post(`/app/appepidemicdangerousarea/addOrUpdate`, { |  | ||||||
|               ...this.form |  | ||||||
|             }).then(res => { |  | ||||||
|               if (res.code == 0) { |  | ||||||
|                 this.$message.success('提交成功') |  | ||||||
|                 setTimeout(() => { |  | ||||||
|                   this.cancel(true) |  | ||||||
|                 }, 600) |  | ||||||
|               } |  | ||||||
|             }) |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       cancel (isRefresh) { |  | ||||||
|         this.$emit('change', { |  | ||||||
|           type: 'list', |  | ||||||
|           isRefresh: !!isRefresh |  | ||||||
|         }) |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style scoped lang="scss"> |  | ||||||
|   .content-add { |  | ||||||
|     .video { |  | ||||||
|       width: 640px; |  | ||||||
|       height: 360px; |  | ||||||
|       border-radius: 4px; |  | ||||||
|       border: 1px dashed #D0D4DC; |  | ||||||
|       display: flex; |  | ||||||
|       flex-direction: column; |  | ||||||
|       align-items: center; |  | ||||||
|       justify-content: center; |  | ||||||
|  |  | ||||||
|       .icon { |  | ||||||
|         display: flex; |  | ||||||
|         flex-direction: column; |  | ||||||
|         align-items: center; |  | ||||||
|         justify-content: center; |  | ||||||
|  |  | ||||||
|         span:nth-child(2) { |  | ||||||
|           display: inline-block; |  | ||||||
|           font-size: 16px; |  | ||||||
|           color: #333333; |  | ||||||
|           line-height: 30px; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .iconfont { |  | ||||||
|           display: inline-block; |  | ||||||
|           font-size: 40px; |  | ||||||
|           color: #2266FF; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .tips { |  | ||||||
|         display: inline-block; |  | ||||||
|         font-size: 12px; |  | ||||||
|         color: #999999; |  | ||||||
|         line-height: 26px; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .video-com { |  | ||||||
|       width: 640px; |  | ||||||
|       height: 360px; |  | ||||||
|       background: rgba(0, 0, 0, 0.5); |  | ||||||
|       border-radius: 2px; |  | ||||||
|       border: 1px solid #D0D4DC; |  | ||||||
|       margin-top: -40px; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -1,141 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <ai-list class="notice"> |  | ||||||
|     <template slot="title"> |  | ||||||
|       <ai-title title="风险区域配置" isShowBottomBorder></ai-title> |  | ||||||
|     </template> |  | ||||||
|     <template slot="content"> |  | ||||||
|       <ai-search-bar class="search-bar"> |  | ||||||
|         <template #left> |  | ||||||
|           <ai-select |  | ||||||
|             v-model="search.level" |  | ||||||
|             clearable |  | ||||||
|             placeholder="请选择风险等级" |  | ||||||
|             :selectList="dict.getDict('epidemicDangerousAreaLevel')" |  | ||||||
|             @change="search.current = 1, getList()"> |  | ||||||
|           </ai-select> |  | ||||||
|           <el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd('')">添加</el-button> |  | ||||||
|         </template> |  | ||||||
|         <template #right> |  | ||||||
|           <el-input |  | ||||||
|             v-model="search.province" |  | ||||||
|             class="search-input" |  | ||||||
|             size="small" |  | ||||||
|             v-throttle="() => {search.current = 1, getList()}" |  | ||||||
|             placeholder="省级名称/市级名称/区级名称" |  | ||||||
|             clearable |  | ||||||
|             @clear="search.current = 1, search.province = '', getList()" |  | ||||||
|             suffix-icon="iconfont iconSearch"> |  | ||||||
|           </el-input> |  | ||||||
|         </template> |  | ||||||
|       </ai-search-bar> |  | ||||||
|       <ai-table |  | ||||||
|         :tableData="tableData" |  | ||||||
|         :col-configs="colConfigs" |  | ||||||
|         :total="total" |  | ||||||
|         style="margin-top: 6px;" |  | ||||||
|         :current.sync="search.current" |  | ||||||
|         :size.sync="search.size" |  | ||||||
|         @getList="getList"> |  | ||||||
|         <el-table-column slot="options" width="140px" fixed="right" label="操作" align="center"> |  | ||||||
|           <template slot-scope="{ row }"> |  | ||||||
|             <div class="table-options"> |  | ||||||
|               <el-button type="text" @click="toAdd(row.id)">编辑</el-button> |  | ||||||
|               <el-button type="text" @click="remove(row.id)">删除</el-button> |  | ||||||
|             </div> |  | ||||||
|           </template> |  | ||||||
|         </el-table-column> |  | ||||||
|       </ai-table> |  | ||||||
|     </template> |  | ||||||
|   </ai-list> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   import { mapState } from 'vuex' |  | ||||||
|   export default { |  | ||||||
|     name: 'List', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object, |  | ||||||
|       moduleName: String |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data() { |  | ||||||
|       return { |  | ||||||
|         search: { |  | ||||||
|           current: 1, |  | ||||||
|           size: 10, |  | ||||||
|           level: '', |  | ||||||
|           province: '' |  | ||||||
|         }, |  | ||||||
|         currIndex: -1, |  | ||||||
|         areaList: [], |  | ||||||
|         total: 10, |  | ||||||
|         colConfigs: [ |  | ||||||
|           { prop: 'province',  label: '省级', align: 'left', width: '200px' }, |  | ||||||
|           { prop: 'city', label: '市级', align: 'center' }, |  | ||||||
|           { prop: 'district', label: '区级', align: 'center' }, |  | ||||||
|           { prop: 'town', label: '镇级', align: 'center' }, |  | ||||||
|           { prop: 'village', label: '村级', align: 'center' }, |  | ||||||
|           { prop: 'level', label: '等级', align: 'center', format: v => this.dict.getLabel('epidemicDangerousAreaLevel', v) }, |  | ||||||
|           { prop: 'createTime', label: '设置时间', align: 'center' }, |  | ||||||
|           { prop: 'createUserName', label: '添加人', align: 'center' }, |  | ||||||
|           { slot: 'options', label: '操作', align: 'center' } |  | ||||||
|         ], |  | ||||||
|         areaName: '', |  | ||||||
|         unitName: '', |  | ||||||
|         tableData: [] |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     computed: { |  | ||||||
|       ...mapState(['user']) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     created() { |  | ||||||
|       this.dict.load('epidemicDangerousAreaLevel').then(() => { |  | ||||||
|         this.getList() |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       getList() { |  | ||||||
|         this.instance.post(`/app/appepidemicdangerousarea/list`, null, { |  | ||||||
|           params: { |  | ||||||
|             ...this.search |  | ||||||
|           } |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.tableData = res.data.records |  | ||||||
|             this.total = res.data.total |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       remove(id) { |  | ||||||
|         this.$confirm('确定删除该数据?').then(() => { |  | ||||||
|           this.instance.post(`/app/appepidemicdangerousarea/delete?ids=${id}`).then(res => { |  | ||||||
|             if (res.code == 0) { |  | ||||||
|               this.$message.success('删除成功!') |  | ||||||
|               this.getList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       toAdd(id) { |  | ||||||
|         this.$emit('change', { |  | ||||||
|           type: 'Add', |  | ||||||
|           params: { |  | ||||||
|             id: id || '' |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
|   .notice { |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -1,206 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <section class="AppVaccination"> |  | ||||||
|     <ai-list v-if="!showDetail"> |  | ||||||
|       <ai-title slot="title" title="疫苗接种" isShowBottomBorder isShowArea v-model="areaId" :instance="instance" |  | ||||||
|                 @change="page.current=1,getTableData()"/> |  | ||||||
|       <template #blank> |  | ||||||
|         <el-row type="flex"> |  | ||||||
|           <div class="dataPane" v-for="(op,i) in dataPanes" :key="i"> |  | ||||||
|             {{ [op.label, op.v].join(" ") }} |  | ||||||
|           </div> |  | ||||||
|         </el-row> |  | ||||||
|         <div class="mainPane"> |  | ||||||
|           <ai-search-bar> |  | ||||||
|             <template #left> |  | ||||||
|               <ai-select placeholder="接种状况" v-model="search.inoculationType" @change="page.current=1,getTableData()" |  | ||||||
|                          :selectList="dict.getDict('vaccineInoculationType')"/> |  | ||||||
|             </template> |  | ||||||
|             <template #right> |  | ||||||
|               <el-input placeholder="姓名/身份证/联系方式" |  | ||||||
|                         v-model="search.name" |  | ||||||
|                         size="small" |  | ||||||
|                         clearable |  | ||||||
|                         @clear="page.current = 1,search.name = '', getTableData()" |  | ||||||
|                         v-throttle="() => {page.current = 1, getTableData()}" |  | ||||||
|                         suffix-icon="iconfont iconSearch"/> |  | ||||||
|             </template> |  | ||||||
|           </ai-search-bar> |  | ||||||
|           <ai-search-bar> |  | ||||||
|             <template #left> |  | ||||||
|               <el-button type="primary" icon="iconfont iconAdd" @click="$router.push({hash:'#add'})">添加</el-button> |  | ||||||
|               <el-button icon="iconfont iconDelete" :disabled="!ids.length" @click="handleDelete(ids)">删除</el-button> |  | ||||||
|             </template> |  | ||||||
|             <template #right> |  | ||||||
|               <ai-import :instance="instance" :dict="dict" name="疫苗接种" suffixName="xlsx" |  | ||||||
|                          type="appvaccineinoculationuser" @onSuccess="resetSearch"/> |  | ||||||
|               <ai-download url="/app/appvaccineinoculationuser/export" :params="{...search,areaId,ids:ids.toString()}" |  | ||||||
|                            :instance="instance" fileName="疫苗接种导出文件"/> |  | ||||||
|             </template> |  | ||||||
|           </ai-search-bar> |  | ||||||
|           <ai-table :tableData="tableData" :colConfigs="colConfigs" :total="page.total" :current.sync="page.current" |  | ||||||
|                     :size.sync="page.size" @getList="getTableData" :dict="dict" |  | ||||||
|                     @selection-change="v=>ids=v.map(e=>e.id)"> |  | ||||||
|             <el-table-column slot="vaccinationDate" label="接种日期" align="center" class-name="vaccinationDate"> |  | ||||||
|               <el-table-column label="第一次" align="center" prop="firstDate"/> |  | ||||||
|               <el-table-column label="第二次" align="center" prop="secondDate"/> |  | ||||||
|               <el-table-column label="第三次" align="center" prop="thirdDate"/> |  | ||||||
|             </el-table-column> |  | ||||||
|             <el-table-column slot="options" label="操作" align="center" fixed="right"> |  | ||||||
|               <template slot-scope="{row:{id}}"> |  | ||||||
|                 <el-button type="text" @click="$router.push({hash:'#add',query:{id}})">编辑</el-button> |  | ||||||
|                 <el-button type="text" @click="handleDelete(id)">删除</el-button> |  | ||||||
|               </template> |  | ||||||
|             </el-table-column> |  | ||||||
|           </ai-table> |  | ||||||
|         </div> |  | ||||||
|       </template> |  | ||||||
|     </ai-list> |  | ||||||
|     <add-vaccination v-else :dict="dict" :instance="instance"/> |  | ||||||
|   </section> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
| import {mapState} from "vuex"; |  | ||||||
| import AddVaccination from "./addVaccination"; |  | ||||||
| import {ID} from "dui/lib/js/utils"; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   name: "AppVaccination", |  | ||||||
|   components: {AddVaccination}, |  | ||||||
|   label: "疫苗接种", |  | ||||||
|   provide() { |  | ||||||
|     return { |  | ||||||
|       top: this |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   props: { |  | ||||||
|     instance: Function, |  | ||||||
|     dict: Object, |  | ||||||
|     permissions: Function, |  | ||||||
|   }, |  | ||||||
|   data() { |  | ||||||
|     return { |  | ||||||
|       areaId: "", |  | ||||||
|       page: {current: 1, size: 10, total: 0}, |  | ||||||
|       search: {inoculationType: "", name: ""}, |  | ||||||
|       ids: [], |  | ||||||
|       tableData: [], |  | ||||||
|       staData: {} |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   computed: { |  | ||||||
|     ...mapState(['user']), |  | ||||||
|     showDetail() { |  | ||||||
|       return this.$route.hash == "#add" |  | ||||||
|     }, |  | ||||||
|     dataPanes() { |  | ||||||
|       return [ |  | ||||||
|         {label: "总接种人数", v: this.staData.zjzrs || 0}, |  | ||||||
|         {label: "已接种第一针人数", v: this.staData.yjzdyzrs || 0}, |  | ||||||
|         {label: "已接种第二针人数", v: this.staData.yjzdezrs || 0}, |  | ||||||
|         {label: "已接种第三针人数", v: this.staData.yjzdszrs || 0}, |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     colConfigs() { |  | ||||||
|       return [ |  | ||||||
|         {type: "selection", align: 'center'}, |  | ||||||
|         {label: "姓名", prop: "name", align: 'center'}, |  | ||||||
|         {label: "性别", prop: "sex", dict: 'sex', align: 'center'}, |  | ||||||
|         {label: "出生日期", prop: "birthday", align: 'center'}, |  | ||||||
|         { |  | ||||||
|           label: "身份证号", width: "160px", align: 'center', |  | ||||||
|           render: (h, {row}) => h('span', null, ID.hideId(row.idNumber)) |  | ||||||
|         }, |  | ||||||
|         {label: "所属地区", prop: "areaName", align: 'center'}, |  | ||||||
|         {label: "住址", prop: "address", width: "200px", align: 'center'}, |  | ||||||
|         {label: "联系方式", prop: "phone", align: 'center'}, |  | ||||||
|         {slot: 'vaccinationDate'}, |  | ||||||
|         {slot: "options"}, |  | ||||||
|       ] |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   created() { |  | ||||||
|     this.areaId = JSON.parse(JSON.stringify(this.user.info.areaId)) |  | ||||||
|     this.dict.load('sex', 'vaccineInoculationType') |  | ||||||
|     this.getTableData() |  | ||||||
|   }, |  | ||||||
|   methods: { |  | ||||||
|     getStaData() { |  | ||||||
|       this.instance.post(`/app/appvaccineinoculationuser/countByAreaId`, null, { |  | ||||||
|         params: {areaId: this.areaId} |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res?.data) { |  | ||||||
|           this.staData = res.data |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     getTableData() { |  | ||||||
|       this.page.current == 1 && this.getStaData() |  | ||||||
|       this.instance.post(`/app/appvaccineinoculationuser/list`, null, { |  | ||||||
|         params: {...this.search, ...this.page, areaId: this.areaId} |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res?.data) { |  | ||||||
|           this.tableData = res.data.records |  | ||||||
|           this.page.total = res.data.total |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     handleDelete(ids) { |  | ||||||
|       ids = ids?.toString() |  | ||||||
|       this.$confirm("确定要删除该条数据吗?").then(() => { |  | ||||||
|         this.instance.post(`/app/appvaccineinoculationuser/delete`, null, { |  | ||||||
|           params: {ids} |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res?.code == 0) { |  | ||||||
|             this.$message.success("删除成功!"); |  | ||||||
|             this.getTableData(); |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }).catch(() => 0) |  | ||||||
|     }, |  | ||||||
|     resetSearch() { |  | ||||||
|       this.page.current = 1 |  | ||||||
|       this.search = {} |  | ||||||
|       this.getTableData() |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .AppVaccination { |  | ||||||
|   height: 100%; |  | ||||||
|  |  | ||||||
|   :deep( .dataPane ){ |  | ||||||
|     flex: 1; |  | ||||||
|     min-width: 0; |  | ||||||
|     background: #FFFFFF; |  | ||||||
|     box-shadow: 0 4px 6px -2px rgba(15, 15, 21, 0.15); |  | ||||||
|     border-radius: 2px; |  | ||||||
|     margin-bottom: 16px; |  | ||||||
|     margin-right: 16px; |  | ||||||
|     display: flex; |  | ||||||
|     align-items: center; |  | ||||||
|     justify-content: center; |  | ||||||
|     height: 60px; |  | ||||||
|  |  | ||||||
|     &:last-of-type { |  | ||||||
|       margin-right: 0; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   :deep( .mainPane ){ |  | ||||||
|     background: #fff; |  | ||||||
|     padding: 12px 16px; |  | ||||||
|     box-shadow: 0 4px 6px -2px rgba(15, 15, 21, 0.15); |  | ||||||
|  |  | ||||||
|     .vaccinationDate { |  | ||||||
|       border-bottom: 1px solid #D0D4DC; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .ai-table__header { |  | ||||||
|       padding: 2px 0; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,236 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <section class="addVaccination"> |  | ||||||
|     <ai-detail> |  | ||||||
|       <ai-title slot="title" :title="addTitle" isShowBottomBorder |  | ||||||
|                 isShowBack @onBackClick="back"/> |  | ||||||
|       <template #content> |  | ||||||
|         <el-form size="small" :model="form" ref="vaccinationForm" :rules="rules" label-width="100px"> |  | ||||||
|           <ai-card title="基本信息"> |  | ||||||
|             <template #content> |  | ||||||
|               <el-form-item label="受种人姓名" prop="name"> |  | ||||||
|                 <el-row type="flex" align="middle"> |  | ||||||
|                   <el-input placeholder="请输入" v-model="form.name" :disabled="isEdit" clearable |  | ||||||
|                             style="margin-right: 8px"/> |  | ||||||
|                   <ai-person-select v-if="!isEdit" :instance="instance" @selectPerson="handleSelectPerson"/> |  | ||||||
|                 </el-row> |  | ||||||
|               </el-form-item> |  | ||||||
|               <el-form-item label="身份证号码" prop="idNumber"> |  | ||||||
|                 <ai-id v-model="form.idNumber" @change="getInfoByIdNumber" :disabled="isEdit"/> |  | ||||||
|               </el-form-item> |  | ||||||
|               <el-form-item label="性别" prop="sex"> |  | ||||||
|                 <ai-select disabled v-model="form.sex" :selectList="dict.getDict('sex')"/> |  | ||||||
|               </el-form-item> |  | ||||||
|               <el-form-item label="出生日期" prop="birthday"> |  | ||||||
|                 <el-date-picker v-model="form.birthday" type="date" disabled/> |  | ||||||
|               </el-form-item> |  | ||||||
|               <el-form-item label="联系方式" prop="phone"> |  | ||||||
|                 <el-input v-model="form.phone" placeholder="请输入"/> |  | ||||||
|               </el-form-item> |  | ||||||
|               <el-form-item label="所属地区" isLine prop="areaId"> |  | ||||||
|                 <ai-area-select :instance="instance" v-model="form.areaId" always-show @name="v=>form.areaName=v"/> |  | ||||||
|               </el-form-item> |  | ||||||
|               <el-form-item label="住址" isLine prop="address"> |  | ||||||
|                 <el-input v-model="form.address" placeholder="请输入"/> |  | ||||||
|               </el-form-item> |  | ||||||
|             </template> |  | ||||||
|           </ai-card> |  | ||||||
|           <ai-card title="接种情况"> |  | ||||||
|             <template #right> |  | ||||||
|               <el-button icon="iconfont iconAdd" type="text" @click="dialog=true">添加</el-button> |  | ||||||
|             </template> |  | ||||||
|             <template #content> |  | ||||||
|               <el-form-item isLine label-width="0"> |  | ||||||
|                 <ai-table :tableData="form.detailList" :colConfigs="colConfigs" :isShowPagination="false" :dict="dict"> |  | ||||||
|                   <el-table-column slot="options" label="操作" align="center" fixed="right"> |  | ||||||
|                     <template v-slot="{row,$index}"> |  | ||||||
|                       <el-button type="text" @click="handleEdit(row,$index)">编辑</el-button> |  | ||||||
|                       <el-button type="text" @click="handleDelete($index)">删除</el-button> |  | ||||||
|                     </template> |  | ||||||
|                   </el-table-column> |  | ||||||
|                 </ai-table> |  | ||||||
|               </el-form-item> |  | ||||||
|             </template> |  | ||||||
|           </ai-card> |  | ||||||
|         </el-form> |  | ||||||
|       </template> |  | ||||||
|       <template #footer> |  | ||||||
|         <el-button @click="back">取消</el-button> |  | ||||||
|         <el-button type="primary" @click="handleSubmit">提交</el-button> |  | ||||||
|       </template> |  | ||||||
|     </ai-detail> |  | ||||||
|     <ai-dialog :visible.sync="dialog" title="接种情况" @closed="dialogForm={}" @onConfirm="handleConfirm"> |  | ||||||
|       <el-form ref="appvaccineinoculationuser" size="small" :model="dialogForm" label-width="100px" :rules="rules"> |  | ||||||
|         <el-form-item label="接种次数" prop="type"> |  | ||||||
|           <ai-select v-model="dialogForm.type" :selectList="dict.getDict('vaccineType')"/> |  | ||||||
|         </el-form-item> |  | ||||||
|         <el-form-item label="接种日期" prop="vaccinateDate"> |  | ||||||
|           <el-date-picker v-model="dialogForm.vaccinateDate" value-format="yyyy-MM-dd"/> |  | ||||||
|         </el-form-item> |  | ||||||
|         <el-form-item label="接种人员" prop="vaccinatePerson"> |  | ||||||
|           <el-input v-model="dialogForm.vaccinatePerson"/> |  | ||||||
|         </el-form-item> |  | ||||||
|         <el-form-item label="生产企业" prop="createCompany"> |  | ||||||
|           <el-input v-model="dialogForm.createCompany"/> |  | ||||||
|         </el-form-item> |  | ||||||
|         <el-form-item label="接种单位" prop="vaccinateUnit"> |  | ||||||
|           <el-input v-model="dialogForm.vaccinateUnit"/> |  | ||||||
|         </el-form-item> |  | ||||||
|       </el-form> |  | ||||||
|     </ai-dialog> |  | ||||||
|   </section> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
| import {mapState} from "vuex"; |  | ||||||
| import {ID} from "dui/lib/js/utils"; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   name: "addVaccination", |  | ||||||
|   inject: ['top'], |  | ||||||
|   props: { |  | ||||||
|     instance: Function, |  | ||||||
|     dict: Object, |  | ||||||
|   }, |  | ||||||
|   data() { |  | ||||||
|     return { |  | ||||||
|       form: {detailList: []}, |  | ||||||
|       dialog: false, |  | ||||||
|       dialogForm: {} |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   computed: { |  | ||||||
|     ...mapState(['user']), |  | ||||||
|     isEdit() { |  | ||||||
|       return !!this.$route.query.id |  | ||||||
|     }, |  | ||||||
|     addTitle() { |  | ||||||
|       return this.isEdit ? '编辑疫苗接种人员' : '新增疫苗接种人员' |  | ||||||
|     }, |  | ||||||
|     rules() { |  | ||||||
|       return { |  | ||||||
|         vaccinateDate: {required: true, message: "请选择 接种日期"}, |  | ||||||
|         type: {required: true, message: "请选择 接种次数",}, |  | ||||||
|         areaId: [ |  | ||||||
|           {required: true, message: "请选择 所属地区"}, |  | ||||||
|           {trigger:'blur',validator: (r, v, cb) => /0{3}$/g.test(v) ? cb('请选择到村/社区') : cb()} |  | ||||||
|         ], |  | ||||||
|         name: {required: true, message: "请填写 受种人姓名"}, |  | ||||||
|         idNumber: {required: true, message: "请填写 身份号码"}, |  | ||||||
|         sex: {required: true, message: "请填写 性别"}, |  | ||||||
|         birthday: {required: true, message: "请填写 出生日期"}, |  | ||||||
|         phone: {required: true, message: "请填写 联系方式"}, |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     colConfigs() { |  | ||||||
|       return [ |  | ||||||
|         {label: "类型", align: 'center', prop: "type", dict: 'vaccineType'}, |  | ||||||
|         {label: "接种日期", align: 'center', prop: "vaccinateDate"}, |  | ||||||
|         {label: "接种人员", align: 'center', prop: "vaccinatePerson"}, |  | ||||||
|         {label: "生产企业", align: 'center', prop: "createCompany"}, |  | ||||||
|         {label: "接种单位", align: 'center', prop: "vaccinateUnit"}, |  | ||||||
|         {slot: "options"} |  | ||||||
|       ] |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   methods: { |  | ||||||
|     back() { |  | ||||||
|       this.$router.push({}) |  | ||||||
|     }, |  | ||||||
|     getDetail() { |  | ||||||
|       let {id} = this.$route.query |  | ||||||
|       if (id) { |  | ||||||
|         this.instance.post("/app/appvaccineinoculationuser/queryDetailById", null, { |  | ||||||
|           params: {id} |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res?.data) { |  | ||||||
|             this.form = res.data |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       } else { |  | ||||||
|         this.$set(this.form,'areaId',JSON.parse(JSON.stringify(this.top.areaId))) |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     handleSubmit() { |  | ||||||
|       this.$refs.vaccinationForm?.validate(v => { |  | ||||||
|         if (v) { |  | ||||||
|           this.instance.post("/app/appvaccineinoculationuser/addOrUpdate", this.form).then(res => { |  | ||||||
|             if (res?.code == 0) { |  | ||||||
|               this.$message.success("提交成功!") |  | ||||||
|               this.top.resetSearch() |  | ||||||
|               this.back() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     handleEdit(row, index) { |  | ||||||
|       this.dialogForm = JSON.parse(JSON.stringify({...row, index})) |  | ||||||
|       this.dialog = true |  | ||||||
|     }, |  | ||||||
|     handleConfirm() { |  | ||||||
|       this.$refs.appvaccineinoculationuser.validate(v => { |  | ||||||
|         if (v) { |  | ||||||
|           if (this.dialogForm.index > -1) { |  | ||||||
|             this.form.detailList.splice(this.dialogForm.index, 1, this.dialogForm) |  | ||||||
|           } else { |  | ||||||
|             this.form.detailList.push(this.dialogForm) |  | ||||||
|           } |  | ||||||
|           this.dialog = false |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     handleSelectPerson(v) { |  | ||||||
|       let {name, idNumber, phone, currentAreaId:areaId, currentAddress:address} = v |  | ||||||
|       this.form = {...this.form, name, idNumber, phone, areaId, address} |  | ||||||
|     }, |  | ||||||
|     getInfoByIdNumber(code) { |  | ||||||
|       if (ID.check(code)) { |  | ||||||
|         let info = new ID(code) |  | ||||||
|         this.form.sex = info.sex |  | ||||||
|         this.form.birthday = info.birthday |  | ||||||
|         this.$forceUpdate() |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     handleDelete(index) { |  | ||||||
|       this.$confirm("是否要删除该条数据?").then(() => this.form.detailList.splice(index, 1)).catch(() => 0) |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   created() { |  | ||||||
|     this.dict.load('vaccineType') |  | ||||||
|     this.getDetail() |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .addVaccination { |  | ||||||
|   height: 100%; |  | ||||||
|  |  | ||||||
|   :deep( .ai-card__body), .el-form { |  | ||||||
|     display: flex; |  | ||||||
|     flex-wrap: wrap; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .ai-card { |  | ||||||
|     width: 100%; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .el-form-item { |  | ||||||
|     width: 50%; |  | ||||||
|  |  | ||||||
|     &[isLine] { |  | ||||||
|       width: 100%; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .el-date-editor { |  | ||||||
|       width: 100%; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   :deep( .el-button ){ |  | ||||||
|     .iconfont { |  | ||||||
|       color: inherit |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,66 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <div class="doc-circulation ailist-wrapper"> |  | ||||||
|     <keep-alive :include="['List']"> |  | ||||||
|       <component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component> |  | ||||||
|     </keep-alive> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   import List from './components/List' |  | ||||||
|   import Add from './components/Add' |  | ||||||
|  |  | ||||||
|   export default { |  | ||||||
|     name: 'AppAddressBook', |  | ||||||
|     label: '通讯录管理', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data () { |  | ||||||
|       return { |  | ||||||
|         component: 'List', |  | ||||||
|         params: {}, |  | ||||||
|         include: [] |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     components: { |  | ||||||
|       Add, |  | ||||||
|       List |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     mounted () { |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       onChange (data) { |  | ||||||
|         if (data.type === 'Add') { |  | ||||||
|           this.component = 'Add' |  | ||||||
|           this.params = data.params |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (data.type === 'list') { |  | ||||||
|           this.component = 'List' |  | ||||||
|           this.params = data.params |  | ||||||
|  |  | ||||||
|           this.$nextTick(() => { |  | ||||||
|             if (data.isRefresh) { |  | ||||||
|               this.$refs.component.getList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss"> |  | ||||||
|   .doc-circulation { |  | ||||||
|     height: 100%; |  | ||||||
|     background: #F3F6F9; |  | ||||||
|     overflow: auto; |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -1,203 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <ai-detail> |  | ||||||
|     <template slot="title"> |  | ||||||
|       <ai-title :title="id ? '编辑成员' : '添加成员'" isShowBack isShowBottomBorder @onBackClick="cancel(false)"> |  | ||||||
|       </ai-title> |  | ||||||
|     </template> |  | ||||||
|     <template slot="content">   |  | ||||||
|       <el-form ref="form" :model="form" label-width="110px" label-position="right"> |  | ||||||
|       <ai-card title="个人信息"> |  | ||||||
|         <template #content> |  | ||||||
|           <div class="ai-form"> |  | ||||||
|             <el-form-item label="姓名" prop="name" :rules="[{ required: true, message: '请输入姓名', trigger: 'blur' }]"> |  | ||||||
|               <el-input size="small" placeholder="请输入姓名" show-word-limit v-model="form.name" :maxlength="10"></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="账号" prop="id" :rules="[{ required: true, message: '请输入账号', trigger: 'blur' }]"> |  | ||||||
|               <el-input size="small" :disabled="!!id" show-word-limit :maxlength="30" placeholder="成员唯一标识,设定以后不支持修改" v-model="form.id"></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="手机号" prop="mobile" :rules="[{ required: true, validator: validatorPhone, trigger: 'blur' }]"> |  | ||||||
|               <el-input size="small" placeholder="请输入手机号" show-word-limit :maxlength="11" v-model="form.mobile"></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="性别" prop="gender"> |  | ||||||
|               <el-radio-group v-model="form.gender"> |  | ||||||
|                 <el-radio label="1">男</el-radio> |  | ||||||
|                 <el-radio label="2">女</el-radio> |  | ||||||
|               </el-radio-group> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="座机" prop="telephone"> |  | ||||||
|               <el-input size="small" placeholder="请输入座机" v-model="form.telephone"></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="邮箱" prop="email"> |  | ||||||
|               <el-input size="small" placeholder="请输入邮箱" v-model="form.email"></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="地址" style="width: 100%;" prop="address"> |  | ||||||
|               <el-input size="small" style="width: 100%;" show-word-limit :maxlength="30" placeholder="请输入地址" v-model="form.address"></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|           </div> |  | ||||||
|         </template> |  | ||||||
|       </ai-card> |  | ||||||
|       <ai-card title="组织信息"> |  | ||||||
|         <template #content> |  | ||||||
|           <el-form-item label="部门" prop="departmentName" style="width: 100%;" :rules="[{ required: true, message: '请选择部门', trigger: 'change' }]"> |  | ||||||
|             <el-input size="small" placeholder="请选择..." disabled v-model="form.departmentName"> |  | ||||||
|               <ai-wechat-selecter slot="append" isStrictly :instance="instance" @change="onChange" v-model="department" isChooseUnit> |  | ||||||
|                 <el-button type="info">选择</el-button> |  | ||||||
|               </ai-wechat-selecter> |  | ||||||
|             </el-input> |  | ||||||
|           </el-form-item> |  | ||||||
|           <el-form-item label="标签" style="width: 100%;" prop="tags"> |  | ||||||
|             <el-select size="small" v-model="form.tagIds" multiple placeholder="请选择标签"> |  | ||||||
|               <el-option |  | ||||||
|                 v-for="item in tagsList" |  | ||||||
|                 :key="item.id" |  | ||||||
|                 :label="item.tagname" |  | ||||||
|                 :value="item.id"> |  | ||||||
|               </el-option> |  | ||||||
|             </el-select> |  | ||||||
|           </el-form-item> |  | ||||||
|           <el-form-item label="职务" prop="position"> |  | ||||||
|             <el-input size="small" placeholder="请输入职务" v-model="form.position"></el-input> |  | ||||||
|           </el-form-item> |  | ||||||
|         </template> |  | ||||||
|       </ai-card> |  | ||||||
|       </el-form> |  | ||||||
|     </template> |  | ||||||
|     <template #footer> |  | ||||||
|       <el-button @click="cancel">取消</el-button> |  | ||||||
|       <el-button type="primary" @click="confirm">提交</el-button> |  | ||||||
|     </template> |  | ||||||
|   </ai-detail> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   export default { |  | ||||||
|     name: 'Add', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object, |  | ||||||
|       params: Object |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data () { |  | ||||||
|       const validatorPhone = function (rule, value, callback) { |  | ||||||
|         if (value === '') { |  | ||||||
|           callback(new Error('请输入手机号')) |  | ||||||
|         } else if (!/^1\d{10}$/.test(value)) { |  | ||||||
|           callback(new Error('手机号格式错误')) |  | ||||||
|         } else { |  | ||||||
|           callback() |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|       return { |  | ||||||
|         info: {}, |  | ||||||
|         department: [], |  | ||||||
|         validatorPhone: validatorPhone, |  | ||||||
|         form: { |  | ||||||
|           position: '', |  | ||||||
|           name: '', |  | ||||||
|           email: '', |  | ||||||
|           telephone: '', |  | ||||||
|           gender: '', |  | ||||||
|           mobile: '', |  | ||||||
|           departmentName: '', |  | ||||||
|           departmentIds: [], |  | ||||||
|           tagIds: [], |  | ||||||
|           id: '' |  | ||||||
|         }, |  | ||||||
|         id: '', |  | ||||||
|         tagsList: [] |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     created () { |  | ||||||
|       this.getTags() |  | ||||||
|  |  | ||||||
|       if (this.params && this.params.departmentId && !this.params.id) { |  | ||||||
|         this.department = [{ |  | ||||||
|           id: String(this.params.departmentId), |  | ||||||
|           name: this.params.departmentName |  | ||||||
|         }] |  | ||||||
|         this.form.departmentIds = [this.params.departmentId] |  | ||||||
|         this.form.departmentName = this.params.departmentName |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       if (this.params && this.params.id) { |  | ||||||
|         this.id = this.params.id |  | ||||||
|         this.getInfo(this.params.id) |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       getInfo (id) { |  | ||||||
|         this.instance.post(`/app/wxcp/wxuser/queryDetailById?id=${id}`).then(res => { |  | ||||||
|           if (res.code === 0) { |  | ||||||
|             const departmentNames = res.data.departmentNames.split(',') |  | ||||||
|             this.department = res.data.departmentIdsStr.split(',').map((item, index) => { |  | ||||||
|               return { |  | ||||||
|                 name: departmentNames[index], |  | ||||||
|                 id: item |  | ||||||
|               } |  | ||||||
|             }) |  | ||||||
|             this.form = { |  | ||||||
|               ...res.data, |  | ||||||
|               departmentName: res.data.departmentNames, |  | ||||||
|               tagIds: res.data.tags.map(v => v.id), |  | ||||||
|               departmentIds: res.data.departmentIdsStr.split(',') |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       onChange (e) { |  | ||||||
|         if (e.length) { |  | ||||||
|           this.form.departmentIds = e.map(v => v.id) |  | ||||||
|           this.form.departmentName = e.map(v => v.name).join(',') |  | ||||||
|         } else { |  | ||||||
|           this.form.departmentIds = '' |  | ||||||
|           this.form.departmentName = '' |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       getTags () { |  | ||||||
|         this.instance.post(`/app/wxcp/wxtag/listAll`).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.tagsList = res.data |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       onClose () { |  | ||||||
|         this.form.explain = '' |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       confirm () { |  | ||||||
|         this.$refs.form.validate((valid) => { |  | ||||||
|           if (valid) { |  | ||||||
|             const api = this.id ? '/app/wxcp/wxuser/update' : '/app/wxcp/wxuser/add' |  | ||||||
|             this.instance.post(api, { |  | ||||||
|               ...this.form |  | ||||||
|             }).then(res => { |  | ||||||
|               if (res.code == 0) { |  | ||||||
|                 this.$message.success('提交成功') |  | ||||||
|                 setTimeout(() => { |  | ||||||
|                   this.cancel(true) |  | ||||||
|                 }, 600) |  | ||||||
|               } |  | ||||||
|             }) |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       cancel (isRefresh) { |  | ||||||
|         this.$emit('change', { |  | ||||||
|           type: 'list', |  | ||||||
|           isRefresh: !!isRefresh |  | ||||||
|         }) |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style scoped lang="scss"> |  | ||||||
| </style> |  | ||||||
| @@ -1,995 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <ai-list class="addressBook"> |  | ||||||
|     <template slot="title"> |  | ||||||
|       <ai-title title="内部通讯录" isShowBottomBorder></ai-title> |  | ||||||
|     </template> |  | ||||||
|     <template #left> |  | ||||||
|       <div class="addressBook-left"> |  | ||||||
|         <div class="addressBook-left__title"> |  | ||||||
|           <h2 @click="tabIndex = 0, search.current = 1, getList()" :class="[tabIndex === 0 ? 'tab-active' : '']"> |  | ||||||
|             组织架构</h2> |  | ||||||
|           <h2 @click="tabIndex = 1, search.current = 1, getList()" :class="[tabIndex === 1 ? 'tab-active' : '']">标签</h2> |  | ||||||
|         </div> |  | ||||||
|         <div class="addressBook-left__list--title" v-if="tabIndex === 0"> |  | ||||||
|           <el-input |  | ||||||
|               size="mini" |  | ||||||
|               placeholder="请输入部门名称" |  | ||||||
|               v-model="unitName" |  | ||||||
|               clearable |  | ||||||
|               suffix-icon="iconfont iconSearch"> |  | ||||||
|           </el-input> |  | ||||||
|         </div> |  | ||||||
|         <div class="addressBook-left__list--title" v-if="tabIndex === 1"> |  | ||||||
|           <el-button size="mini" icon="iconfont iconAdd" @click="isShowTags = true">添加标签</el-button> |  | ||||||
|           <el-input |  | ||||||
|               class="addressBook-left__list--search" |  | ||||||
|               size="mini" |  | ||||||
|               clearable |  | ||||||
|               style="width: 154px;" |  | ||||||
|               placeholder="请输入标签名称" |  | ||||||
|               v-model="tagName" |  | ||||||
|               suffix-icon="iconfont iconSearch"> |  | ||||||
|           </el-input> |  | ||||||
|         </div> |  | ||||||
|         <div class="addressBook-left__list--wrapper"> |  | ||||||
|           <div class="addressBook-left__list" v-show="tabIndex === 0"> |  | ||||||
|             <el-tree |  | ||||||
|               :filter-node-method="filterNode" |  | ||||||
|               ref="tree" |  | ||||||
|               :props="defaultProps" |  | ||||||
|               node-key="id" |  | ||||||
|               :data="unitList" |  | ||||||
|               highlight-current |  | ||||||
|               @node-contextmenu="nodeContextmenu" |  | ||||||
|               :current-node-key="search.departmentId" |  | ||||||
|               :default-expanded-keys="defaultExpanded" |  | ||||||
|               :default-checked-keys="defaultChecked" |  | ||||||
|               @current-change="onTreeChange"> |  | ||||||
|             </el-tree> |  | ||||||
|             <ul |  | ||||||
|                 v-if="isShowMenu" |  | ||||||
|                 class="el-dropdown-menu el-popper" |  | ||||||
|                 :style="{top: menuInfo.y + 'px', left: menuInfo.x + 'px', position: 'fixed', zIndex: 2023}" |  | ||||||
|                 x-placement="top-end"> |  | ||||||
|               <li class="el-dropdown-menu__item" @click="handleTreeCommand('add', menuInfo.node)">添加子部门</li> |  | ||||||
|               <li class="el-dropdown-menu__item" @click="handleTreeCommand('edit', menuInfo.node)">修改名称</li> |  | ||||||
|               <li class="el-dropdown-menu__item" @click="handleTreeCommand('remove', menuInfo.node)">删除</li> |  | ||||||
|               <li class="el-dropdown-menu__item" :class="[!menuInfo.node.i ? 'is-disabled' : '']" |  | ||||||
|                   @click="handleTreeCommand('top', menuInfo.node)">上移 |  | ||||||
|               </li> |  | ||||||
|               <li |  | ||||||
|                   class="el-dropdown-menu__item" |  | ||||||
|                   :class="[(menuInfo.node.i === menuInfo.node.len - 1) || (!menuInfo.node.i && menuInfo.node.i !== 0) ? 'is-disabled' : '']" |  | ||||||
|                   @click="handleTreeCommand('bottom', menuInfo.node)">下移 |  | ||||||
|               </li> |  | ||||||
|             </ul> |  | ||||||
|           </div> |  | ||||||
|           <div class="addressBook-left__list" v-show="tabIndex === 1"> |  | ||||||
|             <div class="addressBook-left__tags"> |  | ||||||
|               <div |  | ||||||
|                   @click="changeTag(index)" |  | ||||||
|                   class="addressBook-left__tags--item" |  | ||||||
|                   :class="[currIndex === index ? 'addressBook-left__tags--item-active' : '']" |  | ||||||
|                   v-for="(item, index) in tagsList" :key="index"> |  | ||||||
|                 <span>{{ item.tagname }}</span> |  | ||||||
|                 <el-dropdown @command="e => handleCommand(e, item)"> |  | ||||||
|                   <i class="iconfont iconmore"></i> |  | ||||||
|                   <el-dropdown-menu slot="dropdown"> |  | ||||||
|                     <el-dropdown-item command="edit">编辑</el-dropdown-item> |  | ||||||
|                     <el-dropdown-item command="remove">删除</el-dropdown-item> |  | ||||||
|                   </el-dropdown-menu> |  | ||||||
|                 </el-dropdown> |  | ||||||
|               </div> |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|     </template> |  | ||||||
|     <template slot="content"> |  | ||||||
|       <ai-search-bar class="search-bar"> |  | ||||||
|         <template #left> |  | ||||||
|           <el-button size="small" type="primary" icon="iconfont iconAdd" v-if="tabIndex === 0" @click="toAdd('')">添加成员 |  | ||||||
|           </el-button> |  | ||||||
|           <ai-import :instance="instance" :dict="dict" v-if="tabIndex === 0" type="wxcp/wxuser" name="内部通讯录" |  | ||||||
|                      :importParams="{departmentId:search.departmentId}" @success="getList"/> |  | ||||||
|           <el-button size="small" icon="iconfont iconUpdate_Files" v-if="tabIndex === 0" :loading="btnLoading" @click="syncMembers">同步部门</el-button> |  | ||||||
|           <el-button size="small" icon="iconfont iconUpdate_Files" v-if="tabIndex === 0" :loading="btnLoading" @click="syncUser">同步成员</el-button> |  | ||||||
|           <ai-wechat-selecter refs="addTags" :instance="instance" v-model="users" @change="onChooseUser" |  | ||||||
|                               :disabled="currIndex < 0" v-if="tabIndex === 1"> |  | ||||||
|             <el-button size="small" :disabled="currIndex < 0" type="primary" icon="iconfont iconAdd">添加成员</el-button> |  | ||||||
|           </ai-wechat-selecter> |  | ||||||
|         </template> |  | ||||||
|         <template slot="right"> |  | ||||||
|           <el-input |  | ||||||
|               v-model="search.name" |  | ||||||
|               size="small" |  | ||||||
|               v-throttle="() => {search.current = 1, getList()}" |  | ||||||
|               placeholder="请输入成员姓名、手机号或标签名称" |  | ||||||
|               clearable |  | ||||||
|               @clear="search.current = 1, search.name = '', getList()" |  | ||||||
|               suffix-icon="iconfont iconSearch"> |  | ||||||
|           </el-input> |  | ||||||
|         </template> |  | ||||||
|       </ai-search-bar> |  | ||||||
|       <ai-table |  | ||||||
|           :tableData="tableData" |  | ||||||
|           :col-configs="colConfigs" |  | ||||||
|           :total="total" |  | ||||||
|           v-loading="loading" |  | ||||||
|           style="margin-top: 6px;" |  | ||||||
|           :current.sync="search.current" |  | ||||||
|           :size.sync="search.size" |  | ||||||
|           @handleSelectionChange="handleSelectionChange" |  | ||||||
|           @getList="getList"> |  | ||||||
|         <el-table-column slot="avatar" label="" align="right" width="100px"> |  | ||||||
|           <template slot-scope="{ row }"> |  | ||||||
|             <img class="table-avatar" :src="row.avatar || 'https://cdn.cunwuyun.cn/dvcp/h5/defaultAvatar.png'"> |  | ||||||
|           </template> |  | ||||||
|         </el-table-column> |  | ||||||
|         <el-table-column slot="tags" label="标签" align="left"> |  | ||||||
|           <template slot-scope="{ row }"> |  | ||||||
|             <div class="table-tags" v-if="row.tagNames"> |  | ||||||
|               <el-tag type="info" v-for="(item, index) in row.tagNames.split('、')" size="small" :key="index">{{ |  | ||||||
|                   item |  | ||||||
|                 }} |  | ||||||
|               </el-tag> |  | ||||||
|             </div> |  | ||||||
|           </template> |  | ||||||
|         </el-table-column> |  | ||||||
|         <el-table-column slot="options" width="140px" fixed="right" label="操作" align="center"> |  | ||||||
|           <template slot-scope="{ row }"> |  | ||||||
|             <div class="table-options"> |  | ||||||
|               <el-button type="text" @click="toAdd(row.id)" v-show="tabIndex === 0">编辑</el-button> |  | ||||||
|               <el-button type="text" @click="remove(row.id)" v-show="tabIndex === 0">删除</el-button> |  | ||||||
|               <el-button type="text" @click="removeTags(row.id)" v-show="tabIndex === 1">移除</el-button> |  | ||||||
|             </div> |  | ||||||
|           </template> |  | ||||||
|         </el-table-column> |  | ||||||
|         <div slot="paginationBtns" class="addressBook-table__btns"> |  | ||||||
|           <span style="margin-right: 8px;" @click="removeAll">{{ tabIndex === 0 ? '批量删除' : '批量移除' }}</span> |  | ||||||
|           <ai-wechat-selecter :instance="instance" v-model="department" isChooseUnit @change="onDepartment" |  | ||||||
|                               v-if="tabIndex === 0"> |  | ||||||
|             <span>批量导出</span> |  | ||||||
|           </ai-wechat-selecter> |  | ||||||
|         </div> |  | ||||||
|       </ai-table> |  | ||||||
|       <ai-dialog |  | ||||||
|           :visible.sync="isShowTags" |  | ||||||
|           width="590px" |  | ||||||
|           :title="tagId ? '编辑标签' : '添加标签'" |  | ||||||
|           @close="onClose" |  | ||||||
|           @onConfirm="onFormConfirm"> |  | ||||||
|         <el-form ref="tagForm" :model="tagForm" label-width="110px" label-position="right"> |  | ||||||
|           <el-form-item label="标签名称" prop="tagname" :rules="[{ required: true, message: '请输入标签名称', trigger: 'blur' }]"> |  | ||||||
|             <el-input size="small" placeholder="请输入标签名称" show-word-limit :maxlength="10" v-model="tagForm.tagname"></el-input> |  | ||||||
|           </el-form-item> |  | ||||||
|         </el-form> |  | ||||||
|       </ai-dialog> |  | ||||||
|       <ai-dialog |  | ||||||
|           :visible.sync="isShowDepart" |  | ||||||
|           width="590px" |  | ||||||
|           :title="departId ? '修改名称' : '添加部门'" |  | ||||||
|           @close="onClose" |  | ||||||
|           @onConfirm="onDepartConfirm"> |  | ||||||
|         <el-form ref="departForm" :model="departForm" label-width="110px" label-position="right"> |  | ||||||
|           <el-form-item label="部门名称" prop="name" :rules="[{ required: true, message: '请输入部门名称', trigger: 'blur' }]"> |  | ||||||
|             <el-input size="small" placeholder="请输入部门名称" show-word-limit :maxlength="30" v-model="departForm.name"></el-input> |  | ||||||
|           </el-form-item> |  | ||||||
|         </el-form> |  | ||||||
|       </ai-dialog> |  | ||||||
|     </template> |  | ||||||
|   </ai-list> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
| import {mapState} from 'vuex' |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   name: 'List', |  | ||||||
|  |  | ||||||
|   props: { |  | ||||||
|     instance: Function, |  | ||||||
|     dict: Object |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   data() { |  | ||||||
|     return { |  | ||||||
|       users: [], |  | ||||||
|       isShowMenu: false, |  | ||||||
|       department: [], |  | ||||||
|       btnLoading: false, |  | ||||||
|       menuInfo: { |  | ||||||
|         x: '', |  | ||||||
|         y: '', |  | ||||||
|         node: {} |  | ||||||
|       }, |  | ||||||
|       search: { |  | ||||||
|         current: 1, |  | ||||||
|         size: 10, |  | ||||||
|         title: '', |  | ||||||
|         tagname: '', |  | ||||||
|         name: '', |  | ||||||
|         tagIds: '', |  | ||||||
|         departmentId: '' |  | ||||||
|       }, |  | ||||||
|       tagForm: { |  | ||||||
|         tagname: '' |  | ||||||
|       }, |  | ||||||
|       isShowDepart: false, |  | ||||||
|       departForm: { |  | ||||||
|         name: '' |  | ||||||
|       }, |  | ||||||
|       loading: false, |  | ||||||
|       isShowTags: false, |  | ||||||
|       defaultChecked: [], |  | ||||||
|       defaultExpanded: [], |  | ||||||
|       tabIndex: 0, |  | ||||||
|       currIndex: -1, |  | ||||||
|       areaList: [], |  | ||||||
|       total: 0, |  | ||||||
|       colConfigs: [ |  | ||||||
|         {type: 'selection', label: ''}, |  | ||||||
|         {slot: 'avatar', label: ''}, |  | ||||||
|         {prop: 'name', label: '姓名'}, |  | ||||||
|         {prop: 'position', label: '职务'}, |  | ||||||
|         {prop: 'departmentNames', label: '部门'}, |  | ||||||
|         {prop: 'mobile', label: '手机号'}, |  | ||||||
|         {slot: 'tags', label: '标签'}, |  | ||||||
|         {prop: 'status', label: '账号状态', align: 'center', format: v => v == 1 ? '已激活' : '未激活'} |  | ||||||
|       ], |  | ||||||
|       defaultProps: { |  | ||||||
|         children: 'children', |  | ||||||
|         label: 'name' |  | ||||||
|       }, |  | ||||||
|       unitName: '', |  | ||||||
|       rootId: '', |  | ||||||
|       unitList: [], |  | ||||||
|       tagsList: [], |  | ||||||
|       tagName: '', |  | ||||||
|       sourceTagList: [], |  | ||||||
|       tableData: [], |  | ||||||
|       tagId: '', |  | ||||||
|       departmentName: '', |  | ||||||
|       departId: '', |  | ||||||
|       ids: '' |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   computed: { |  | ||||||
|     ...mapState(['user']) |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   watch: { |  | ||||||
|     unitName(val) { |  | ||||||
|       this.$refs.tree.filter(val) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     tagName(val) { |  | ||||||
|       if (!val) { |  | ||||||
|         this.tagsList = this.sourceTagList |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       this.tagsList = this.sourceTagList.filter(v => v.tagname.indexOf(val) > -1) |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   mounted() { |  | ||||||
|     this.getTree() |  | ||||||
|     this.getList() |  | ||||||
|     this.getTags() |  | ||||||
|     document.querySelector('html').addEventListener('click', this.bindEvent) |  | ||||||
|  |  | ||||||
|     this.$nextTick(() => { |  | ||||||
|     }) |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   methods: { |  | ||||||
|     changeTag(index) { |  | ||||||
|       this.currIndex = index |  | ||||||
|       this.search.current = 1 |  | ||||||
|  |  | ||||||
|       this.$nextTick(() => { |  | ||||||
|         this.getList() |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     bindEvent() { |  | ||||||
|       this.isShowMenu = false |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     nodeContextmenu(e, node) { |  | ||||||
|       this.isShowMenu = true |  | ||||||
|       let y = e.y + 6 |  | ||||||
|       if (y + 202 > document.body.clientHeight) { |  | ||||||
|         y = y - 202 |  | ||||||
|       } |  | ||||||
|       this.menuInfo = { |  | ||||||
|         x: e.x + 16, y, |  | ||||||
|         node |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     removeTags(id) { |  | ||||||
|       if (this.currIndex < 0) { |  | ||||||
|         return this.$message.error('请选择标签') |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       this.$confirm('确定移除该成员?').then(() => { |  | ||||||
|         this.instance.post(`/app/wxcp/wxtag/removeTag?userIds=${id}&tagId=${this.tagsList[this.currIndex].id}`).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.$message.success('移除成功!') |  | ||||||
|             this.search.current = 1 |  | ||||||
|  |  | ||||||
|             this.getList() |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     onDepartment(e) { |  | ||||||
|       if (!e.length) { |  | ||||||
|         return this.$message.error('请选择部门') |  | ||||||
|       } |  | ||||||
|       const ids = e.map(v => v.id).join(',') |  | ||||||
|  |  | ||||||
|       this.department = [] |  | ||||||
|       this.instance.post(`/app/wxcp/wxuser/export?departmentId=${ids}`, null, { |  | ||||||
|         responseType: 'blob' |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res?.type == "application/json") { |  | ||||||
|           let reader = new FileReader() |  | ||||||
|           reader.readAsText(res, "utf-8") |  | ||||||
|           reader.onload = e => { |  | ||||||
|             if (e.target.readyState === 2) { |  | ||||||
|               let ret = JSON.parse(e.target.result) |  | ||||||
|               if (ret?.code == 0) { |  | ||||||
|                 this.$message.success(ret.msg) |  | ||||||
|               } else this.$message.error(ret.msg) |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|         } else { |  | ||||||
|           const link = document.createElement('a') |  | ||||||
|           let blob = new Blob([res], {type: res.type}) |  | ||||||
|           link.style.display = 'none' |  | ||||||
|           link.href = URL.createObjectURL(blob) |  | ||||||
|           link.setAttribute('download', `${e[0].name}.xls`) |  | ||||||
|           document.body.appendChild(link) |  | ||||||
|           link.click() |  | ||||||
|           document.body.removeChild(link) |  | ||||||
|           this.$message.success('导出成功!') |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     onChooseUser(e) { |  | ||||||
|       if (!e.length) { |  | ||||||
|         return this.$message.error('请选择成员') |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       this.instance.post(`/app/wxcp/wxtag/markTag`, null, { |  | ||||||
|         params: { |  | ||||||
|           tagId: this.tagsList[this.currIndex].id, |  | ||||||
|           userIds: e.map(v => v.id).join(',') |  | ||||||
|         } |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res.code == 0) { |  | ||||||
|           this.getList() |  | ||||||
|           this.users = [] |  | ||||||
|           this.search.current = 1 |  | ||||||
|           this.$refs.addTags.reset() |  | ||||||
|         } else { |  | ||||||
|           this.users = [] |  | ||||||
|         } |  | ||||||
|       }).catch(() => { |  | ||||||
|         this.users = [] |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     handleTreeCommand(e, item) { |  | ||||||
|       this.isShowMenu = false |  | ||||||
|  |  | ||||||
|       if (e === 'add') { |  | ||||||
|         this.departForm.id = '' |  | ||||||
|         this.departForm.parentid = item.id |  | ||||||
|         this.departId = '' |  | ||||||
|         this.isShowDepart = true |  | ||||||
|       } else if (e === 'edit') { |  | ||||||
|         this.departForm = { |  | ||||||
|           ...item |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         this.departId = item.id |  | ||||||
|         this.isShowDepart = true |  | ||||||
|       } else if (e === 'top') { |  | ||||||
|         if (!item.i) { |  | ||||||
|           return false |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         this.moveDepart(item.id, 0) |  | ||||||
|       } else if (e === 'bottom') { |  | ||||||
|         if ((item.i === item.len - 1) || (!item.i && item.i !== 0)) { |  | ||||||
|           return false |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         this.moveDepart(item.id, 1) |  | ||||||
|       } else if (e === 'remove') { |  | ||||||
|         this.removeDepart(item.id, item.parentid) |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     removeDepart(id, parentid) { |  | ||||||
|       this.$confirm('确定删除该数据?').then(() => { |  | ||||||
|         this.instance.post(`/app/wxcp/wxdepartment/delete?id=${id}`).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.defaultChecked = [parentid] |  | ||||||
|             this.$message.success('删除成功!') |  | ||||||
|             this.getTree() |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     moveDepart(id, type) { |  | ||||||
|       this.instance.post(`/app/wxcp/wxdepartment/move?id=${id}&type=${type}`).then(res => { |  | ||||||
|         if (res.code == 0) { |  | ||||||
|           this.defaultChecked = [id] |  | ||||||
|           this.getTree() |  | ||||||
|           this.$message.success(type === 0 ? '上移成功' : '下移成功') |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     onDepartConfirm() { |  | ||||||
|       this.$refs.departForm.validate((valid) => { |  | ||||||
|         if (valid) { |  | ||||||
|           this.instance.post(`/app/wxcp/wxdepartment/addOrUpdate`, { |  | ||||||
|             ...this.departForm, |  | ||||||
|             departId: this.departId |  | ||||||
|           }).then(res => { |  | ||||||
|             if (res.code == 0) { |  | ||||||
|               this.defaultChecked = [this.departForm.parentid] |  | ||||||
|               this.isShowDepart = false |  | ||||||
|               this.getTree() |  | ||||||
|               this.$message.success(this.departId ? '编辑成功' : '新增成功') |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     onFormConfirm() { |  | ||||||
|       this.$refs.tagForm.validate((valid) => { |  | ||||||
|         if (valid) { |  | ||||||
|           this.instance.post(`/app/wxcp/wxtag/addOrUpdate`, { |  | ||||||
|             ...this.tagForm |  | ||||||
|           }).then(res => { |  | ||||||
|             if (res.code == 0) { |  | ||||||
|               this.isShowTags = false |  | ||||||
|               this.getTags() |  | ||||||
|               this.$message.success(this.tagId ? '编辑成功' : '新增成功') |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     handleCommand(e, item) { |  | ||||||
|       if (e === 'edit') { |  | ||||||
|         this.tagId = item.id |  | ||||||
|         this.tagForm = { |  | ||||||
|           ...item |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         this.isShowTags = true |  | ||||||
|       } else { |  | ||||||
|         this.$confirm('确定删除该数据?').then(() => { |  | ||||||
|           this.instance.post(`/app/wxcp/wxtag/delete?id=${item.id}`).then(res => { |  | ||||||
|             if (res.code == 0) { |  | ||||||
|               this.$message.success('删除成功!') |  | ||||||
|               this.getTags() |  | ||||||
|               this.getList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         }) |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     onClose() { |  | ||||||
|       this.tagId = '' |  | ||||||
|       this.tagForm.tagname = '' |  | ||||||
|       this.departForm.name = '' |  | ||||||
|       this.departId = '' |  | ||||||
|       this.departForm.nameEn = '' |  | ||||||
|       this.departForm.parentid = '' |  | ||||||
|       this.departForm.showIndex = '' |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     syncMembers() { |  | ||||||
|       this.btnLoading = true |  | ||||||
|  |  | ||||||
|       this.instance.post(`/app/wxcp/wxdepartment/syncDepart`).then(res => { |  | ||||||
|         if (res.code == 0) { |  | ||||||
|           this.$message.success('同步成功') |  | ||||||
|           this.getList() |  | ||||||
|           this.getTree() |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         this.btnLoading = false |  | ||||||
|       }).catch(() => { |  | ||||||
|         this.btnLoading = false |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     syncUser() { |  | ||||||
|       let departId = this.search.departmentId; |  | ||||||
|       if (!departId) departId = 1; |  | ||||||
|       this.btnLoading = true |  | ||||||
|  |  | ||||||
|       this.instance.post(`/app/wxcp/wxdepartment/syncUser?departmentId=${departId}`, null, { |  | ||||||
|         timeout: 1000000 |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res.code == 0) { |  | ||||||
|           this.$message.success('同步成功') |  | ||||||
|           this.getList() |  | ||||||
|           this.getTree() |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         this.btnLoading = false |  | ||||||
|       }).catch(() => { |  | ||||||
|         this.btnLoading = false |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     getTags() { |  | ||||||
|       this.instance.post(`/app/wxcp/wxtag/listAll`).then(res => { |  | ||||||
|         if (res.code == 0) { |  | ||||||
|           this.sourceTagList = res.data.length ? JSON.parse(JSON.stringify(res.data)) : [] |  | ||||||
|           this.tagsList = res.data |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     onSwitchChange(id) { |  | ||||||
|       this.instance.post(`/app/wxcp/wxuser/enable?id=${id}`).then(res => { |  | ||||||
|         if (res.code == 0) { |  | ||||||
|           this.getList() |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     onTreeChange(e) { |  | ||||||
|       this.departmentName = e.name |  | ||||||
|       this.search.departmentId = e.id || '' |  | ||||||
|       this.search.current = 1 |  | ||||||
|       this.isShowMenu = false |  | ||||||
|  |  | ||||||
|       this.$nextTick(() => { |  | ||||||
|         this.getList() |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     getList() { |  | ||||||
|       this.loading = true |  | ||||||
|       this.instance.post(`/app/wxcp/wxuser/list`, null, { |  | ||||||
|         params: { |  | ||||||
|           ...this.search, |  | ||||||
|           departmentId: this.tabIndex === 0 ? this.search.departmentId : '', |  | ||||||
|           tagIds: this.tabIndex === 1 ? (this.currIndex >= 0 ? this.tagsList[this.currIndex].id : '') : '', |  | ||||||
|           listType: this.tabIndex |  | ||||||
|         } |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res.code == 0) { |  | ||||||
|           this.tableData = res.data.records |  | ||||||
|           this.total = res.data.total |  | ||||||
|  |  | ||||||
|           this.$nextTick(() => { |  | ||||||
|             this.loading = false |  | ||||||
|           }) |  | ||||||
|         } else { |  | ||||||
|           this.loading = false |  | ||||||
|         } |  | ||||||
|       }).catch(() => { |  | ||||||
|         this.loading = false |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     removeAll() { |  | ||||||
|       if (!this.ids) return |  | ||||||
|  |  | ||||||
|       if (this.tabIndex === 1) { |  | ||||||
|         this.removeTags(this.ids) |  | ||||||
|       } else { |  | ||||||
|         this.remove(this.ids) |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     handleSelectionChange(e) { |  | ||||||
|       this.ids = e.map(v => v.id).join(',') |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     filterNode(value, data) { |  | ||||||
|       if (!value) return true |  | ||||||
|       return data.name.indexOf(value) !== -1 |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     changeTab(id, index) { |  | ||||||
|       this.currIndex = index |  | ||||||
|       this.search.areaId = id |  | ||||||
|  |  | ||||||
|       this.$nextTick(() => { |  | ||||||
|         this.getList() |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     getTree() { |  | ||||||
|       this.instance.post(`/app/wxcp/wxdepartment/listAll?unitName=${this.unitName}`).then(res => { |  | ||||||
|         if (res.code === 0) { |  | ||||||
|           let parent = res.data.map(v => { |  | ||||||
|             v.label = v.name |  | ||||||
|             v.children = [] |  | ||||||
|  |  | ||||||
|             return v |  | ||||||
|           }).filter(e => !e.parentid)[0] |  | ||||||
|           this.defaultExpanded = [parent.id] |  | ||||||
|           this.defaultChecked = [parent.id] |  | ||||||
|           this.search.departmentId = parent.id |  | ||||||
|           this.departmentName = parent.name |  | ||||||
|           this.addChild(parent, res.data) |  | ||||||
|           this.unitList = [parent] |  | ||||||
|  |  | ||||||
|           this.$nextTick(() => { |  | ||||||
|             this.$refs.tree.setCurrentKey(parent.id) |  | ||||||
|           }) |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     addChild(parent, list) { |  | ||||||
|       for (let i = 0; i < list.length; i++) { |  | ||||||
|         if (list[i].parentid === parent.id) { |  | ||||||
|           list[i].i = parent.children.length |  | ||||||
|           parent.children.push(list[i]) |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       if (parent.children.length) { |  | ||||||
|         parent.children.forEach(v => { |  | ||||||
|           v.len = parent.children.length |  | ||||||
|         }) |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       if (list.length > 0) { |  | ||||||
|         parent['children'].map(v => this.addChild(v, list)) |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     formatList(list) { |  | ||||||
|       var arr = [] |  | ||||||
|       for (let item of list) { |  | ||||||
|         if (item.childrenUser && item.childrenUser.length) { |  | ||||||
|           delete item.childrenUser |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (item.childrenDept && item.childrenDept.length) { |  | ||||||
|           this.formatList(item.childrenDept) |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         arr.push(item) |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       return arr |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     remove(id) { |  | ||||||
|       this.$confirm('确定删除该数据?').then(() => { |  | ||||||
|         this.instance.post(`/app/wxcp/wxuser/delete?id=${id}`).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.$message.success('删除成功!') |  | ||||||
|             this.getList() |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     toAdd(id) { |  | ||||||
|       this.$emit('change', { |  | ||||||
|         type: 'Add', |  | ||||||
|         params: { |  | ||||||
|           id: id || '', |  | ||||||
|           departmentId: this.search.departmentId || '', |  | ||||||
|           departmentName: this.departmentName || '' |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .addressBook { |  | ||||||
|   .addressBook-table__btns { |  | ||||||
|     display: flex; |  | ||||||
|     align-items: center; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   .table-tags { |  | ||||||
|     .el-tag { |  | ||||||
|       margin-right: 8px; |  | ||||||
|       margin-bottom: 8px; |  | ||||||
|  |  | ||||||
|       &:last-child { |  | ||||||
|         margin-right: 0; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .import-wrapper { |  | ||||||
|     & > h2 { |  | ||||||
|       margin-bottom: 8px; |  | ||||||
|       font-size: 16px; |  | ||||||
|       color: #222222; |  | ||||||
|       font-weight: Bold; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .import-wrapper__tips { |  | ||||||
|       line-height: 1; |  | ||||||
|       margin-bottom: 24px; |  | ||||||
|  |  | ||||||
|       div { |  | ||||||
|         display: flex; |  | ||||||
|         margin-bottom: 8px; |  | ||||||
|         color: #222222; |  | ||||||
|         font-size: 14px; |  | ||||||
|  |  | ||||||
|         span { |  | ||||||
|           cursor: pointer; |  | ||||||
|           color: #2266FF; |  | ||||||
|  |  | ||||||
|           &:hover { |  | ||||||
|             opacity: 0.8; |  | ||||||
|             text-decoration: underline; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .import-files { |  | ||||||
|       i { |  | ||||||
|         display: block; |  | ||||||
|         margin-top: 8px; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     i { |  | ||||||
|       color: #999999; |  | ||||||
|       font-size: 12px; |  | ||||||
|       font-style: normal; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .tree-container { |  | ||||||
|     position: relative; |  | ||||||
|     display: flex; |  | ||||||
|     align-items: center; |  | ||||||
|     justify-content: space-between; |  | ||||||
|     width: 100%; |  | ||||||
|     height: 100%; |  | ||||||
|  |  | ||||||
|     .tree-name { |  | ||||||
|       padding-right: 30px; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     i { |  | ||||||
|       position: absolute; |  | ||||||
|       top: 50%; |  | ||||||
|       right: 8px; |  | ||||||
|       transform: translateY(-50%); |  | ||||||
|       padding-right: 8px; |  | ||||||
|       font-weight: normal; |  | ||||||
|       color: #fff; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .el-tag { |  | ||||||
|     margin-right: 8px; |  | ||||||
|     border: 1px solid #D0D4DC; |  | ||||||
|     background: #F3F4F7; |  | ||||||
|     border-radius: 4px; |  | ||||||
|     font-size: 13px; |  | ||||||
|     color: #222222; |  | ||||||
|  |  | ||||||
|     &:last-child { |  | ||||||
|       margin-right: 0; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .table-avatar { |  | ||||||
|     width: 40px; |  | ||||||
|     height: 40px; |  | ||||||
|     margin-top: 3px; |  | ||||||
|     border-radius: 2px; |  | ||||||
|     border: 1px solid #CCCCCC; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .el-button--mini, .el-button--mini.is-round { |  | ||||||
|     height: 28px; |  | ||||||
|     line-height: 28px; |  | ||||||
|     padding: 0; |  | ||||||
|     font-size: 12px; |  | ||||||
|  |  | ||||||
|     :deep( span ){ |  | ||||||
|       margin-left: 0; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .addressBook-left__list--title { |  | ||||||
|     display: flex; |  | ||||||
|     align-items: center; |  | ||||||
|     margin: 8px 8px 0; |  | ||||||
|  |  | ||||||
|     .addressBook-left__list--search { |  | ||||||
|       flex: 1; |  | ||||||
|  |  | ||||||
|       :deep( input ){ |  | ||||||
|         width: 100%; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .el-button { |  | ||||||
|       width: 84px; |  | ||||||
|       flex-shrink: 1; |  | ||||||
|       margin-right: 8px; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .addressBook-left { |  | ||||||
|     width: 100%; |  | ||||||
|     height: auto; |  | ||||||
|     background: #FAFAFB; |  | ||||||
|  |  | ||||||
|     .addressBook-left__title { |  | ||||||
|       display: flex; |  | ||||||
|       align-items: center; |  | ||||||
|       width: 100%; |  | ||||||
|       height: 40px; |  | ||||||
|       background: #ffffff; |  | ||||||
|  |  | ||||||
|       h2 { |  | ||||||
|         flex: 1; |  | ||||||
|         height: 100%; |  | ||||||
|         line-height: 40px; |  | ||||||
|         color: #222; |  | ||||||
|         font-size: 14px; |  | ||||||
|         text-align: center; |  | ||||||
|         cursor: pointer; |  | ||||||
|         border-bottom: 2px solid transparent; |  | ||||||
|  |  | ||||||
|         &.tab-active { |  | ||||||
|           color: #2266FF; |  | ||||||
|           border-bottom: 2px solid #2266FF; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // ::-webkit-scrollbar { |  | ||||||
|     //   width: 1px; |  | ||||||
|     // } |  | ||||||
|  |  | ||||||
|     .addressBook-left__list--wrapper { |  | ||||||
|       height: calc(100% - 68px); |  | ||||||
|       padding: 8px; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .addressBook-left__list { |  | ||||||
|       width: 100%; |  | ||||||
|       height: 100%; |  | ||||||
|       overflow: auto; |  | ||||||
|  |  | ||||||
|       :deep( .el-tree ){ |  | ||||||
|         width: fit-content; |  | ||||||
|         min-width: 100%; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       :deep( .el-scrollbar__wrap ){ |  | ||||||
|         margin-bottom: 0 !important; |  | ||||||
|         overflow-x: hidden; |  | ||||||
|  |  | ||||||
|         .el-scrollbar__view { |  | ||||||
|           width: fit-content; |  | ||||||
|           min-width: 100%; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .addressBook-left__tags--item { |  | ||||||
|         display: flex; |  | ||||||
|         align-items: center; |  | ||||||
|         justify-content: space-between; |  | ||||||
|         height: 40px; |  | ||||||
|         padding: 0 8px 0 16px; |  | ||||||
|         cursor: pointer; |  | ||||||
|         color: #222222; |  | ||||||
|  |  | ||||||
|         &.addressBook-left__tags--item-active, &:hover { |  | ||||||
|           background: #E8EFFF; |  | ||||||
|           color: #2266FF; |  | ||||||
|  |  | ||||||
|           i, span { |  | ||||||
|             color: #2266FF; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         span { |  | ||||||
|           font-size: 14px; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         i { |  | ||||||
|           cursor: pointer; |  | ||||||
|           color: #8e9ebf; |  | ||||||
|           font-size: 16px; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       span { |  | ||||||
|         color: #222222; |  | ||||||
|         font-size: 14px; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       :deep( .el-tree ){ |  | ||||||
|         background: transparent; |  | ||||||
|  |  | ||||||
|         .el-tree-node__expand-icon.is-leaf { |  | ||||||
|           color: transparent !important; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .el-tree-node__content > .el-tree-node__expand-icon { |  | ||||||
|           padding: 4px; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .el-tree-node__content { |  | ||||||
|           height: 32px; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .el-tree__empty-text { |  | ||||||
|           color: #222; |  | ||||||
|           font-size: 14px; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .el-tree-node__children .el-tree-node__content { |  | ||||||
|           height: 32px; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .el-tree-node__content:hover { |  | ||||||
|           background: #E8EFFF; |  | ||||||
|           color: #222222; |  | ||||||
|           border-radius: 2px; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .is-current > .el-tree-node__content { |  | ||||||
|           &:hover { |  | ||||||
|             background: #2266FF; |  | ||||||
|             color: #fff; |  | ||||||
|           } |  | ||||||
|  |  | ||||||
|           background: #2266FF; |  | ||||||
|  |  | ||||||
|           span { |  | ||||||
|             color: #fff; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   :deep( .ai-list__content--right ){ |  | ||||||
|     flex: 1; |  | ||||||
|     min-width: 0; |  | ||||||
|     margin-left: 1px; |  | ||||||
|     box-shadow: none; |  | ||||||
|  |  | ||||||
|     .ai-list__content--right-wrapper { |  | ||||||
|       width: 100%; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,354 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <ai-list class="AppPartyPayment"> |  | ||||||
|     <template slot="title"> |  | ||||||
|       <ai-title title="党费缴纳" isShowBottomBorder :instance="instance"></ai-title> |  | ||||||
|     </template> |  | ||||||
|     <template #content> |  | ||||||
|       <div class="statistics-top"> |  | ||||||
|         <div class="statistics-top__item"> |  | ||||||
|           <span>本月已缴纳党费金额</span> |  | ||||||
|           <h2 style="color: #2266FF;">{{ topTotal['本月缴纳党费'] || 0 }}</h2> |  | ||||||
|         </div> |  | ||||||
|         <div class="statistics-top__item"> |  | ||||||
|           <span>本月已缴纳人数</span> |  | ||||||
|           <h2 style="color: #22AA99;">{{ topTotal['本月已缴纳人数'] || 0  }}</h2> |  | ||||||
|         </div> |  | ||||||
|         <div class="statistics-top__item"> |  | ||||||
|           <span>本月未缴纳党费金额</span> |  | ||||||
|           <h2 style="color: #F8B425">{{ topTotal['本月未缴纳党费'] || 0 }}</h2> |  | ||||||
|         </div> |  | ||||||
|         <div class="statistics-top__item"> |  | ||||||
|           <span>本月未缴纳人数</span> |  | ||||||
|           <h2 style="color: #999;">{{ topTotal['本月未缴纳人数'] || 0 }}</h2> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|       <div class="content"> |  | ||||||
|         <ai-search-bar> |  | ||||||
|           <template #left> |  | ||||||
|             <ai-party :instance="instance" v-model="search.partyOrgId" :topOrgId="topOrgId" :name.sync="search.partyOrgName" |  | ||||||
|                     style="display:inline-block" @origin="handlePartyOrgSelect" customClicker |  | ||||||
|                     url="/app/partyOrganization/queryAllChildren"> |  | ||||||
|               <el-input size="small" v-model="search.partyOrgName" readonly placeholder="选择党组织"></el-input> |  | ||||||
|             </ai-party> |  | ||||||
|             <el-date-picker v-model="search.ymd" type="month" placeholder="选择日期" size="small" value-format="yyyy-MM" @change="getListInit"></el-date-picker> |  | ||||||
|             <ai-select |  | ||||||
|               v-model="search.status" |  | ||||||
|               @change="getListInit()" |  | ||||||
|               placeholder="状态" |  | ||||||
|               :selectList="dict.getDict('zhishengPartyFeeRecordStatus')"> |  | ||||||
|             </ai-select> |  | ||||||
|           </template> |  | ||||||
|           <template #right> |  | ||||||
|             <el-input size="small" v-model="search.name" placeholder="姓名/身份证" |  | ||||||
|               suffix-icon="iconfont iconSearch" v-throttle="() => {getListInit()}" clearable @clear="search.name = '', getListInit()"/> |  | ||||||
|           </template> |  | ||||||
|         </ai-search-bar> |  | ||||||
|         <ai-search-bar> |  | ||||||
|           <template #left> |  | ||||||
|             <el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd('')">新增</el-button> |  | ||||||
|           </template> |  | ||||||
|           <template #right> |  | ||||||
|             <ai-import :instance="instance" :dict="dict" type="appconvenientaddressbook" name="党费缴纳" |  | ||||||
|               @success="getListInit()" importUrl="/app/appdfjnzhisheng/import" url="/app/appdfjnzhisheng/downloadTemplate"> |  | ||||||
|               <el-button icon="iconfont iconImport">导入</el-button> |  | ||||||
|             </ai-import> |  | ||||||
|             <ai-download :instance="instance" url="/app/appdfjnzhisheng/export" :params="search" fileName="党费缴纳" |  | ||||||
|               :disabled="tableData.length == 0"> |  | ||||||
|               <el-button icon="iconfont iconExported" :disabled="tableData.length == 0">导出</el-button> |  | ||||||
|             </ai-download> |  | ||||||
|           </template> |  | ||||||
|         </ai-search-bar> |  | ||||||
|         <ai-table |  | ||||||
|           :tableData="tableData" |  | ||||||
|           :col-configs="colConfigs" |  | ||||||
|           :total="total" |  | ||||||
|           :current.sync="search.current" |  | ||||||
|           :size.sync="search.size" |  | ||||||
|           @getList="getList"> |  | ||||||
|           <el-table-column slot="option" label="操作" align="center" width="160px" fixed="right"> |  | ||||||
|             <template slot-scope="{ row }"> |  | ||||||
|               <div class="table-options"> |  | ||||||
|                 <el-button type="text" title="编辑" @click="edit(row)">编辑</el-button> |  | ||||||
|                 <el-button type="text" title="删除" @click="remove(row)">删除</el-button> |  | ||||||
|               </div> |  | ||||||
|             </template> |  | ||||||
|           </el-table-column> |  | ||||||
|         </ai-table> |  | ||||||
|       </div> |  | ||||||
|       <ai-dialog :visible.sync="dialog" :title="dialogTitle" @closed="$refs.form.resetFields()" @onConfirm="handlePayment"> |  | ||||||
|         <el-form ref="form" :rules="rules" size="small" :model="form" label-width="80px"> |  | ||||||
|           <el-form-item label="党员姓名" prop="name"> |  | ||||||
|             <el-autocomplete ref="poiInput" v-model="form.name" size="small" clearable :fetch-suggestions="handleSearch" |  | ||||||
|               placeholder="请输入党员姓名" @select="handleSelect" :trigger-on-focus="false" style="width:100%;"> |  | ||||||
|               <template slot-scope="{item}"> |  | ||||||
|                 <span style="direction: rtl" v-text="`${item.name}-${item.partyOrgName}(${item.idNumber})`"/> |  | ||||||
|               </template> |  | ||||||
|             </el-autocomplete>  |  | ||||||
|           </el-form-item> |  | ||||||
|           <el-form-item label="身份证号" prop="idNumber"> |  | ||||||
|             <el-input placeholder="自动带入" v-model="form.idNumber" :disabled="true" size="small"></el-input> |  | ||||||
|           </el-form-item> |  | ||||||
|           <el-form-item label="缴纳状态" prop="status"> |  | ||||||
|             <el-radio-group v-model="form.status"> |  | ||||||
|               <el-radio label="1">已缴纳</el-radio> |  | ||||||
|               <el-radio label="0">未缴纳</el-radio> |  | ||||||
|             </el-radio-group> |  | ||||||
|           </el-form-item> |  | ||||||
|           <el-form-item label="缴纳月份" prop="ymd"> |  | ||||||
|             <el-date-picker v-model="form.ymd" type="month" placeholder="选择年月" size="small" value-format="yyyy-MM"></el-date-picker> |  | ||||||
|           </el-form-item> |  | ||||||
|           <el-form-item label="金额(元)" prop="amount"> |  | ||||||
|             <el-input-number :precision="2" size="small" type="input" v-model="form.amount" clearable placeholder="2位小数"></el-input-number> |  | ||||||
|           </el-form-item> |  | ||||||
|         </el-form> |  | ||||||
|       </ai-dialog> |  | ||||||
|     </template> |  | ||||||
|   </ai-list> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   import {mapState} from 'vuex' |  | ||||||
|   export default { |  | ||||||
|     name: 'AppPartyPayment', |  | ||||||
|     label: '党费缴纳', |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object |  | ||||||
|     }, |  | ||||||
|     data () { |  | ||||||
|       return { |  | ||||||
|         search: { |  | ||||||
|           current: 1, |  | ||||||
|           size: 10, |  | ||||||
|           partyOrgId: '', |  | ||||||
|           partyOrgName: '', |  | ||||||
|           name: '', |  | ||||||
|           status: '', |  | ||||||
|           ymd: '' |  | ||||||
|         }, |  | ||||||
|         total: 0, |  | ||||||
|         tableData: [], |  | ||||||
|         colConfigs: [ |  | ||||||
|           { prop: 'orgName', label: '党组织' }, |  | ||||||
|           { prop: 'name', label: '党员姓名', align: 'center',  }, |  | ||||||
|           { prop: 'idNumber', label: '身份证', align: 'center' }, |  | ||||||
|           { prop: 'ymd', label: '缴纳月份', align: 'center' }, |  | ||||||
|           { prop: 'amount', label: '缴纳党费', align: 'center' }, |  | ||||||
|           { prop: 'status', label: '状态', align: 'center',format: v => this.dict.getLabel('zhishengPartyFeeRecordStatus', v)}, |  | ||||||
|           { slot: 'option'} |  | ||||||
|         ], |  | ||||||
|         topOrgId: '', |  | ||||||
|         dialog: false, |  | ||||||
|         dialogTitle: '', |  | ||||||
|         form: { |  | ||||||
|           name: '', |  | ||||||
|           idNumber: '', |  | ||||||
|           status: '0', |  | ||||||
|           ymd: '', |  | ||||||
|           amount: '', |  | ||||||
|           orgId: '', |  | ||||||
|           orgName: '', |  | ||||||
|           partyId: '' |  | ||||||
|         }, |  | ||||||
|         topTotal: {} |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     computed: { |  | ||||||
|       params () { |  | ||||||
|         return { |  | ||||||
|           ...this.search, |  | ||||||
|           startTime: this.search.type === '3' ? this.date[0] : '', |  | ||||||
|           endTime: this.search.type === '3' ? this.date[1] : '' |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|       rules() { |  | ||||||
|         return { |  | ||||||
|           name: [{ required: true, message: '请输入党员姓名', trigger: 'change'}], |  | ||||||
|           idNumber: [{ required: true, message: '请选择党员', trigger: 'change'}], |  | ||||||
|           status: [{ required: true, message: '请选择缴费状态', trigger: 'change'}], |  | ||||||
|           ymd: [{ required: true, message: '请选择缴纳月份', trigger: 'change'}], |  | ||||||
|           amount: [{ required: true, message: '请输入金额', trigger: 'blur'}], |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|       ...mapState(['user']), |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     created () { |  | ||||||
|       this.topOrgId = this.user.info.organizationId |  | ||||||
|       this.dict.load('zhishengPartyFeeRecordStatus').then(() => { |  | ||||||
|         this.getList() |  | ||||||
|       }) |  | ||||||
|       this.getTotal() |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       toAdd() { |  | ||||||
|         this.form =  { |  | ||||||
|           name: '', |  | ||||||
|           idNumber: '', |  | ||||||
|           status: '0', |  | ||||||
|           ymd: '', |  | ||||||
|           amount: '', |  | ||||||
|           orgId: '', |  | ||||||
|           orgName: '', |  | ||||||
|           partyId: '' |  | ||||||
|         } |  | ||||||
|         this.dialogTitle = '新增党费信息' |  | ||||||
|         this.dialog = true |  | ||||||
|       }, |  | ||||||
|       edit(row) { |  | ||||||
|         this.form = row |  | ||||||
|         this.dialog = true |  | ||||||
|         this.dialogTitle = '编辑党费信息' |  | ||||||
|       }, |  | ||||||
|       handleSearch(e, cb) { |  | ||||||
|         this.instance.post(`/app/appparty/fuzzyList?name=${e}&size=50`).then((res) => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             cb(res.data) |  | ||||||
|           } |  | ||||||
|         }); |  | ||||||
|       }, |  | ||||||
|       handleSelect(e) { |  | ||||||
|         this.form.name = e.name |  | ||||||
|         this.form.idNumber = e.idNumber |  | ||||||
|         this.form.orgId = e.partyOrgId |  | ||||||
|         this.form.orgName = e.partyOrgName |  | ||||||
|         this.form.partyId = e.id |  | ||||||
|       }, |  | ||||||
|       handlePayment() { |  | ||||||
|         this.$refs.form.validate((valid) => { |  | ||||||
|           if (valid) { |  | ||||||
|             this.instance.post(`/app/appdfjnzhisheng/addOrUpdate`, {...this.form}).then((res) => { |  | ||||||
|               if (res.code == 0) { |  | ||||||
|                 this.$message.success(this.dialogTitle == '编辑党费信息' ? "编辑成功" : "新增成功"); |  | ||||||
|                 this.$refs.form.resetFields() |  | ||||||
|                 this.dialog = false |  | ||||||
|                 this.getListInit() |  | ||||||
|                 this.getTotal() |  | ||||||
|               } |  | ||||||
|             }); |  | ||||||
|           } |  | ||||||
|         }); |  | ||||||
|       }, |  | ||||||
|       handlePartyOrgSelect(e) { |  | ||||||
|         let {isLeaf, name, id} = e?.[0] || {}; |  | ||||||
|         if (isLeaf == 1) { |  | ||||||
|           this.search.partyOrgName = name; |  | ||||||
|           this.search.partyOrgId = id; |  | ||||||
|         } |  | ||||||
|         this.getListInit() |  | ||||||
|       }, |  | ||||||
|       getListInit() { |  | ||||||
|         this.search.current = 1 |  | ||||||
|         this.getList() |  | ||||||
|       }, |  | ||||||
|       getList () { |  | ||||||
|         this.instance.post(`/app/appdfjnzhisheng/list`, null, { |  | ||||||
|           params: { |  | ||||||
|             ...this.search, |  | ||||||
|             orgId: this.search.partyOrgId |  | ||||||
|           } |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             res.data.records.map((item) => { |  | ||||||
|               item.ymd = item.ymd.substring(0, 7) |  | ||||||
|             }) |  | ||||||
|             this.tableData = res.data.records |  | ||||||
|             this.total = res.data.total |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|       remove(row) { |  | ||||||
|         this.$confirm('确定删除该数据?').then(() => { |  | ||||||
|           this.instance.post(`/app/appdfjnzhisheng/delete?ids=${row.id}`).then(res => { |  | ||||||
|             if (res.code == 0) { |  | ||||||
|               this.$message.success('删除成功!') |  | ||||||
|               this.getList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|       getTotal() { |  | ||||||
|         this.instance.post(`/app/appdfjnzhisheng/statistics`).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.topTotal = res.data |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
|   .AppPartyPayment { |  | ||||||
|  |  | ||||||
|     .bottom { |  | ||||||
|       display: flex; |  | ||||||
|       align-items: center; |  | ||||||
|  |  | ||||||
|       & > .ai-card { |  | ||||||
|         flex: 1; |  | ||||||
|  |  | ||||||
|         &:last-child { |  | ||||||
|           margin-left: 20px; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     :deep( .ai-list__content ){ |  | ||||||
|       padding: 0!important; |  | ||||||
|  |  | ||||||
|       .ai-list__content--right-wrapper { |  | ||||||
|         background: transparent!important; |  | ||||||
|         box-shadow: none!important; |  | ||||||
|         margin: 0!important; |  | ||||||
|         padding: 12px 16px 12px!important; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     :deep( .ai-card) { |  | ||||||
|       .ai-card__body { |  | ||||||
|         padding: 12px 16px; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .statistics-top { |  | ||||||
|       display: flex; |  | ||||||
|       align-items: center; |  | ||||||
|       margin-bottom: 20px; |  | ||||||
|  |  | ||||||
|       & > div { |  | ||||||
|         flex: 1; |  | ||||||
|         height: 96px; |  | ||||||
|         line-height: 1; |  | ||||||
|         margin-right: 20px; |  | ||||||
|         padding: 16px 24px; |  | ||||||
|         background: #FFFFFF; |  | ||||||
|         box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15); |  | ||||||
|         border-radius: 4px; |  | ||||||
|  |  | ||||||
|         &:last-child { |  | ||||||
|           margin-right: 0; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         h3 { |  | ||||||
|           font-size: 24px; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         span { |  | ||||||
|           display: block; |  | ||||||
|           margin-bottom: 16px; |  | ||||||
|           color: #888888; |  | ||||||
|           font-size: 16px; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .content { |  | ||||||
|       padding: 16px; |  | ||||||
|       background: #FFFFFF; |  | ||||||
|       box-shadow: 0px 4px 6px -2px rgba(15, 15, 21, 0.15); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -1,35 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <section class="AppPartyScore"> |  | ||||||
|     <component :is="currentPage" v-bind="$props"/> |  | ||||||
|   </section> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
| import PsList from "./psList"; |  | ||||||
| import PsDetail from "./psDetail"; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   name: "AppPartyScore", |  | ||||||
|   components: {PsDetail, PsList}, |  | ||||||
|   label: "党员积分", |  | ||||||
|   props: { |  | ||||||
|     instance: Function, |  | ||||||
|     dict: Object, |  | ||||||
|     permissions: Function |  | ||||||
|   }, |  | ||||||
|   computed: { |  | ||||||
|     currentPage() { |  | ||||||
|       return this.$route.query.id ? PsDetail : PsList |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   created() { |  | ||||||
|     this.dict.load("partyIntegralType") |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .AppPartyScore { |  | ||||||
|   height: 100%; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,154 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <section class="psDetail"> |  | ||||||
|     <ai-detail> |  | ||||||
|       <ai-title slot="title" title="积分详情" isShowBottomBorder isShowBack @onBackClick="back"/> |  | ||||||
|       <template #content> |  | ||||||
|         <el-row type="flex"> |  | ||||||
|           <ai-card hideTitle class="staCard fill"> |  | ||||||
|             <template #content> |  | ||||||
|               <div class="color-999" v-text="`姓名`"/> |  | ||||||
|               <b v-text="detail.name"/> |  | ||||||
|             </template> |  | ||||||
|           </ai-card> |  | ||||||
|           <ai-card hideTitle class="staCard fill"> |  | ||||||
|             <template #content> |  | ||||||
|               <div class="color-999" v-text="`学习强国`"/> |  | ||||||
|               <el-button type="text" @click="handleEditLearningIntergral(detail.id)">编辑</el-button> |  | ||||||
|               <b class="color-26f" v-text="detail.learningIntegral||0"/> |  | ||||||
|             </template> |  | ||||||
|           </ai-card> |  | ||||||
|           <ai-card hideTitle class="staCard fill"> |  | ||||||
|             <template slot="content"> |  | ||||||
|               <div class="color-999" v-text="`个人积分`"/> |  | ||||||
|               <b class="color-26f" v-text="detail.integral||0"/> |  | ||||||
|             </template> |  | ||||||
|           </ai-card> |  | ||||||
|           <ai-card hideTitle class="staCard fill"> |  | ||||||
|             <template #content> |  | ||||||
|               <div class="color-999" v-text="`家庭积分`"/> |  | ||||||
|               <b class="color-26f" v-text="detail.familySurplusIntegral||0"/> |  | ||||||
|             </template> |  | ||||||
|           </ai-card> |  | ||||||
|         </el-row> |  | ||||||
|         <ai-card title="余额变动明细"> |  | ||||||
|           <template #content> |  | ||||||
|             <ai-table :tableData="detail.integralInfoList" :isShowPagination="false" :col-configs="colConfigs" |  | ||||||
|                       :dict="dict"/> |  | ||||||
|           </template> |  | ||||||
|         </ai-card> |  | ||||||
|       </template> |  | ||||||
|     </ai-detail> |  | ||||||
|     <ai-dialog :visible.sync="dialog" title="学习强国设置" width="500px" @close="form={}" @onConfirm="submit"> |  | ||||||
|       <el-form :model="form" size="small" ref="DialogForm" :rules="rules" label-width="110px"> |  | ||||||
|         <el-form-item label="学习强国积分" prop="learningIntegral"> |  | ||||||
|           <el-input v-model.number="form.learningIntegral" placeholder="请输入正整数" clearable/> |  | ||||||
|         </el-form-item> |  | ||||||
|       </el-form> |  | ||||||
|     </ai-dialog> |  | ||||||
|   </section> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
| export default { |  | ||||||
|   name: "psDetail", |  | ||||||
|   props: { |  | ||||||
|     instance: Function, |  | ||||||
|     dict: Object, |  | ||||||
|   }, |  | ||||||
|   data() { |  | ||||||
|     return { |  | ||||||
|       detail: {}, |  | ||||||
|       colConfigs: [ |  | ||||||
|         {label: "时间", prop: "createTime"}, |  | ||||||
|         {label: "类型", prop: "integralType", align: 'center', dict: "partyIntegralType"}, |  | ||||||
|         {label: "变动积分", prop: "integral", align: 'center'}, |  | ||||||
|         {label: "剩余积分", prop: "residualIntegral", align: 'center'}, |  | ||||||
|         {label: "调整说明", prop: "remark"}, |  | ||||||
|       ], |  | ||||||
|       dialog: false, |  | ||||||
|       form: {}, |  | ||||||
|       rules: { |  | ||||||
|         learningIntegral: [ |  | ||||||
|           {required: true, message: "请输入学习强国积分"}, |  | ||||||
|           {pattern: /^\d+$/g, message: "请输入正整数"} |  | ||||||
|         ] |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   methods: { |  | ||||||
|     getDetail() { |  | ||||||
|       let {id} = this.$route.query |  | ||||||
|       this.instance.post("/app/appparty/getPartyIntegralDetail", null, { |  | ||||||
|         params: {id} |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res?.data) { |  | ||||||
|           this.detail = res.data |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     back() { |  | ||||||
|       this.$router.push({}) |  | ||||||
|     }, |  | ||||||
|     submit() { |  | ||||||
|       this.$refs.DialogForm.validate(v => { |  | ||||||
|         if (v) { |  | ||||||
|           this.instance.post("/app/appparty/editLearningIntegral", null,{ |  | ||||||
|             params:this.form |  | ||||||
|           }).then(res => { |  | ||||||
|             if (res?.code == 0) { |  | ||||||
|               this.$message.success("提交成功!") |  | ||||||
|               this.dialog = false |  | ||||||
|               this.getDetail() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     handleEditLearningIntergral(partyMemberId) { |  | ||||||
|       this.dialog = true |  | ||||||
|       this.form = {partyMemberId} |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   created() { |  | ||||||
|     this.getDetail() |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .psDetail { |  | ||||||
|   height: 100%; |  | ||||||
|  |  | ||||||
|   .color-999 { |  | ||||||
|     color: #999; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .color-26f { |  | ||||||
|     color: #26f; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   :deep(.staCard ){ |  | ||||||
|     font-size: 14px; |  | ||||||
|  |  | ||||||
|     b { |  | ||||||
|       font-size: 24px; |  | ||||||
|       line-height: 40px; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     & + .staCard { |  | ||||||
|       margin-left: 16px; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .ai-card__body { |  | ||||||
|       position: relative; |  | ||||||
|  |  | ||||||
|       .el-button { |  | ||||||
|         position: absolute; |  | ||||||
|         right: 32px; |  | ||||||
|         top: 6px; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,116 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <section class="psList"> |  | ||||||
|     <ai-list> |  | ||||||
|       <ai-title slot="title" title="党员积分" isShowBottomBorder/> |  | ||||||
|       <template #content> |  | ||||||
|         <ai-search-bar> |  | ||||||
|           <template #right> |  | ||||||
|             <ai-import :instance="instance" name="党员积分" title="导入党员积分" |  | ||||||
|                        suffixName="xlsx" |  | ||||||
|                        url="/app/apppartyintegralinfo/downloadTemplate" |  | ||||||
|                        importUrl="/app/apppartyintegralinfo/import" |  | ||||||
|                        @onSuccess="page.current=1,getTableData()"/> |  | ||||||
|           </template> |  | ||||||
|         </ai-search-bar> |  | ||||||
|         <ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size" |  | ||||||
|                   @getList="getTableData" :col-configs="colConfigs" :dict="dict"> |  | ||||||
|           <el-table-column slot="options" label="操作" fixed="right" align="center"> |  | ||||||
|             <template slot-scope="{row}"> |  | ||||||
|               <el-button type="text" @click="getFamilyByPartyId(row.idNumber)">家庭成员</el-button> |  | ||||||
|               <el-button type="text" @click="showDetail(row.id)">详情</el-button> |  | ||||||
|             </template> |  | ||||||
|           </el-table-column> |  | ||||||
|         </ai-table> |  | ||||||
|       </template> |  | ||||||
|     </ai-list> |  | ||||||
|     <ai-dialog :visible.sync="dialog" title="家庭成员" :customFooter="true" width="780px" @close="familyList=[]"> |  | ||||||
|       <ai-table :tableData="familyList" :isShowPagination="false" :col-configs="familyCols" :dict="dict"/> |  | ||||||
|       <div class="dialog-footer" slot="footer"> |  | ||||||
|         <el-button @click="dialog=false">关 闭</el-button> |  | ||||||
|       </div> |  | ||||||
|     </ai-dialog> |  | ||||||
|   </section> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
| import {mapState} from "vuex"; |  | ||||||
| import {ID} from "dui/lib/js/utils"; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   name: "psList", |  | ||||||
|   props: { |  | ||||||
|     instance: Function, |  | ||||||
|     dict: Object, |  | ||||||
|   }, |  | ||||||
|   computed: { |  | ||||||
|     ...mapState(['user']), |  | ||||||
|     colConfigs() { |  | ||||||
|       return [ |  | ||||||
|         {label: "姓名", prop: "name"}, |  | ||||||
|         {label: "个人积分", prop: "integral", align: "center"}, |  | ||||||
|         {label: "家庭积分", prop: "familySurplusIntegral", align: "center"}, |  | ||||||
|         {label: "学习强国", prop: "learningIntegral", align: "center"}, |  | ||||||
|         {slot: "options"} |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     familyCols() { |  | ||||||
|       return [ |  | ||||||
|         { |  | ||||||
|           label: '与户主关系', prop: 'householdRelation', align: 'center', width: 165, |  | ||||||
|           render: (h, {row}) => h('p', this.dict.getLabel('householdRelation', row.householdRelation || "户主")) |  | ||||||
|         }, |  | ||||||
|         {label: '类型', prop: 'residentType', align: 'center', dict: "residentType"}, |  | ||||||
|         {label: '姓名', prop: 'name', align: 'center'}, |  | ||||||
|         {label: '身份证号', render: (h, {row}) => h('p', ID.hideId(row.idNumber)), width: 165}, |  | ||||||
|         {label: '联系电话', prop: 'phone', align: 'center', width: 120} |  | ||||||
|       ] |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   data() { |  | ||||||
|     return { |  | ||||||
|       search: {}, |  | ||||||
|       page: {current: 1, size: 10, total: 0}, |  | ||||||
|       tableData: [], |  | ||||||
|       dialog: false, |  | ||||||
|       familyList: [], |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   methods: { |  | ||||||
|     back() { |  | ||||||
|       this.$router.push({}) |  | ||||||
|     }, |  | ||||||
|     getTableData() { |  | ||||||
|       this.instance.post("/app/appparty/listByPartyIntegral", null, { |  | ||||||
|         params: {...this.page, ...this.search} |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res?.data) { |  | ||||||
|           this.tableData = res.data?.records |  | ||||||
|           this.page.total = res.data.total |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     showDetail(id) { |  | ||||||
|       this.$router.push({query: {id}}) |  | ||||||
|     }, |  | ||||||
|     getFamilyByPartyId(idNumber) { |  | ||||||
|       this.instance.post("/app/appresident/queryHomeMember", null, { |  | ||||||
|         params: {idNumber} |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res?.data) { |  | ||||||
|           this.familyList = res.data?.family || [] |  | ||||||
|           this.dialog = true |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   created() { |  | ||||||
|     this.getTableData() |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .psList { |  | ||||||
|   height: 100%; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,34 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <section class="AppPartyScoreFlow"> |  | ||||||
|     <component :is="currentPage" v-bind="$props"/> |  | ||||||
|   </section> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
| import PsfList from "./psfList"; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   name: "AppPartyScoreFlow", |  | ||||||
|   components: {PsfList}, |  | ||||||
|   label: "党员积分明细", |  | ||||||
|   props: { |  | ||||||
|     instance: Function, |  | ||||||
|     dict: Object, |  | ||||||
|     permissions: Function |  | ||||||
|   }, |  | ||||||
|   computed: { |  | ||||||
|     currentPage() { |  | ||||||
|       return PsfList |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   created() { |  | ||||||
|     this.dict.load("partyIntegralType") |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .AppPartyScoreFlow { |  | ||||||
|   height: 100%; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,150 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <section class="psfList"> |  | ||||||
|     <ai-list> |  | ||||||
|       <ai-title slot="title" title="党员积分明细" isShowBottomBorder/> |  | ||||||
|       <template #content> |  | ||||||
|         <ai-search-bar> |  | ||||||
|           <template #left> |  | ||||||
|             <el-button type="primary" icon="iconfont iconAdd" @click="dialog=true">添加</el-button> |  | ||||||
|             <el-date-picker type="daterange" placeholder="日期" size="small" clearable v-model="createTime" |  | ||||||
|                             @change="handleSearchTime" start-placeholder="开始时间" end-placeholder="结束时间" |  | ||||||
|                             value-format="yyyy-MM-dd HH:mm:ss" :default-time="['00:00:00','23:59:59']"/> |  | ||||||
|           </template> |  | ||||||
|           <template #right> |  | ||||||
|             <el-input size="small" placeholder="搜索党员" v-model="search.partyName" clearable |  | ||||||
|                       @change="page.current=1,getTableData()" suffix-icon="iconfont iconSearch"/> |  | ||||||
|           </template> |  | ||||||
|         </ai-search-bar> |  | ||||||
|         <ai-table :tableData="tableData" :total="page.total" :current.sync="page.current" :size.sync="page.size" |  | ||||||
|                   @getList="getTableData" :col-configs="colConfigs" :dict="dict"> |  | ||||||
|           <el-table-column slot="options" label="操作" fixed="right" align="center"> |  | ||||||
|             <template slot-scope="{row}"> |  | ||||||
|               <el-button type="text" @click="showDetail(row)">详情</el-button> |  | ||||||
|             </template> |  | ||||||
|           </el-table-column> |  | ||||||
|         </ai-table> |  | ||||||
|       </template> |  | ||||||
|     </ai-list> |  | ||||||
|     <ai-dialog :visible.sync="dialog" title="积分对象" width="600px" @close="form={}" @onConfirm="submit" |  | ||||||
|                :customFooter="!isAdd"> |  | ||||||
|       <el-form v-if="isAdd" :model="form" size="small" ref="DialogForm" :rules="rules" label-width="80px"> |  | ||||||
|         <el-form-item label="选择人员" prop="partyId"> |  | ||||||
|           <ai-select v-model="form.partyId" action="/app/appparty/list" :instance="instance" |  | ||||||
|                      :prop="{label:'name'}"/> |  | ||||||
|         </el-form-item> |  | ||||||
|         <el-form-item label="调整说明" prop="remark"> |  | ||||||
|           <el-input type="textarea" placeholder="请输入" v-model="form.remark" maxlength="100" show-word-limit rows="3" |  | ||||||
|                     clearable/> |  | ||||||
|         </el-form-item> |  | ||||||
|         <el-form-item label="类型" prop="integralType"> |  | ||||||
|           <ai-select v-model="form.integralType" :selectList="dict.getDict('partyIntegralType')"/> |  | ||||||
|         </el-form-item> |  | ||||||
|         <el-form-item label="积分" prop="integral"> |  | ||||||
|           <el-input v-model.number="form.integral" placeholder="请输入正整数" clearable/> |  | ||||||
|         </el-form-item> |  | ||||||
|       </el-form> |  | ||||||
|       <ai-wrapper v-else> |  | ||||||
|         <ai-info-item label="对象" :value="form.partyName"/> |  | ||||||
|         <ai-info-item label="调整说明" :value="form.remark" isLine/> |  | ||||||
|         <ai-info-item label="类型" :value="dict.getLabel('partyIntegralType',form.integralType)"/> |  | ||||||
|         <ai-info-item label="积分" :value="form.integral"/> |  | ||||||
|       </ai-wrapper> |  | ||||||
|     </ai-dialog> |  | ||||||
|   </section> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
| import {mapState} from "vuex"; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   name: "psfList", |  | ||||||
|   props: { |  | ||||||
|     instance: Function, |  | ||||||
|     dict: Object, |  | ||||||
|   }, |  | ||||||
|   computed: { |  | ||||||
|     ...mapState(['user']), |  | ||||||
|     colConfigs() { |  | ||||||
|       return [ |  | ||||||
|         {label: "对象", prop: "partyName"}, |  | ||||||
|         {label: "调整说明", prop: "remark", align: "center"}, |  | ||||||
|         {label: "时间", prop: "createTime"}, |  | ||||||
|         {label: "类型", prop: "integralType", align: "center", dict: "partyIntegralType"}, |  | ||||||
|         {label: "积分", prop: "integral", align: "center"}, |  | ||||||
|         {slot: "options"} |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     isAdd() { |  | ||||||
|       return !this.form.id |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   data() { |  | ||||||
|     return { |  | ||||||
|       search: {}, |  | ||||||
|       page: {current: 1, size: 10, total: 0}, |  | ||||||
|       tableData: [], |  | ||||||
|       dialog: false, |  | ||||||
|       form: {}, |  | ||||||
|       rules: { |  | ||||||
|         partyId: {required: true, message: "请选择人员"}, |  | ||||||
|         remark: {required: true, message: "请输入调整说明"}, |  | ||||||
|         integralType: {required: true, message: "请选择类型"}, |  | ||||||
|         integral: [ |  | ||||||
|           {required: true, message: "请输入分数"}, |  | ||||||
|           {pattern: /^\d+$/g, message: "请输入正整数"} |  | ||||||
|         ], |  | ||||||
|       }, |  | ||||||
|       createTime: "" |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   methods: { |  | ||||||
|     getTableData() { |  | ||||||
|       this.instance.post("/app/apppartyintegralinfo/list", null, { |  | ||||||
|         params: {...this.page, ...this.search} |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res?.data) { |  | ||||||
|           this.tableData = res.data?.records?.map(e => ({ |  | ||||||
|             ...e, |  | ||||||
|             integral: (e.integralType == 0 ? "-" : '+') + e.integral |  | ||||||
|           })) |  | ||||||
|           this.page.total = res.data.total |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     showDetail(row) { |  | ||||||
|       this.form = JSON.parse(JSON.stringify(row)) |  | ||||||
|       this.dialog = true |  | ||||||
|     }, |  | ||||||
|     submit() { |  | ||||||
|       this.$refs.DialogForm.validate(v => { |  | ||||||
|         if (v) { |  | ||||||
|           let loading = this.$loading({text: "提交中..."}) |  | ||||||
|           this.instance.post("/app/apppartyintegralinfo/addOrUpdate", this.form).then(res => { |  | ||||||
|             loading.close() |  | ||||||
|             if (res?.code == 0) { |  | ||||||
|               this.$message.success("提交成功!") |  | ||||||
|               this.dialog = false |  | ||||||
|               this.getTableData() |  | ||||||
|             } |  | ||||||
|           }).catch(() => loading.close()) |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     handleSearchTime(v) { |  | ||||||
|       this.page.current = 1 |  | ||||||
|       this.search.startTime = v?.[0] |  | ||||||
|       this.search.endTime = v?.[1] |  | ||||||
|       this.getTableData() |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   created() { |  | ||||||
|     this.getTableData() |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .psfList { |  | ||||||
|   height: 100%; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,101 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <section class="conference"> |  | ||||||
|     <ai-list v-if="!showDetail"> |  | ||||||
|       <template slot="title"> |  | ||||||
|         <ai-title title="会议管理"></ai-title> |  | ||||||
|       </template> |  | ||||||
|       <template slot="tabs"> |  | ||||||
|         <el-tabs v-model="currIndex" @tab-click="handleClick"> |  | ||||||
|           <el-tab-pane v-for="(tab,i) in tabs" :key="i" :label="tab.label" :name="String(i)"> |  | ||||||
|             <component :is="tab.comp" v-if="currIndex==i" :ref="currIndex" :instance="instance" :dict="dict" |  | ||||||
|                        :permissions="permissions" @goPage="goPage" :listType="listType" /> |  | ||||||
|           </el-tab-pane> |  | ||||||
|         </el-tabs> |  | ||||||
|       </template> |  | ||||||
|     </ai-list> |  | ||||||
|  |  | ||||||
|     <component v-else :is="currentComp" :instance="instance" :dict="dict" :detail="detailRow" :listType="listType" @gotoEdit="gotoAdd" ></component> |  | ||||||
|  |  | ||||||
|   </section> |  | ||||||
| </template> |  | ||||||
| <script> |  | ||||||
| import addMeeting from './addMeeting'; |  | ||||||
| import detail from './detail' |  | ||||||
| import list from './list' |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   name: 'AppConference', |  | ||||||
|   label: "会议管理", |  | ||||||
|   components: {addMeeting, detail, list}, |  | ||||||
|   provide() { |  | ||||||
|     return { |  | ||||||
|       top: this |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   props: { |  | ||||||
|     instance: Function, |  | ||||||
|     dict: Object, |  | ||||||
|     permissions: Function, |  | ||||||
|   }, |  | ||||||
|   data() { |  | ||||||
|     return { |  | ||||||
|       //会议状态,0、草稿;1、未开始;2、进行中;3、已取消;4、已结束 |  | ||||||
|       //参会状态,0、未确认;1、已确认;2、缺席 |  | ||||||
|       currIndex: "0", |  | ||||||
|       currentComp: "", |  | ||||||
|       showDetail: false, |  | ||||||
|       detailRow: {}, |  | ||||||
|       listType: '1', |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   computed:{ |  | ||||||
|     tabs() { |  | ||||||
|       return [ |  | ||||||
|         {label: "我参与的会议", name: "addMeeting", comp: list, detail: detail, permission: ""}, |  | ||||||
|         {label: "我发起的会议", name: "addMeeting",  comp: list, detail: detail, permission: ""}, |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   methods: { |  | ||||||
|     goPage(params) { |  | ||||||
|       this.detailRow = params.row |  | ||||||
|       this.currentComp = params.comp |  | ||||||
|  |  | ||||||
|       if(params.comp == 'detail' || params.comp == 'addMeeting') { |  | ||||||
|         this.showDetail = true |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     handleClick() { |  | ||||||
|       if (this.currIndex == 0) { |  | ||||||
|         this.listType = '1' |  | ||||||
|       } else { |  | ||||||
|         this.listType = '0' |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     goBack() { |  | ||||||
|       this.showDetail = false; |  | ||||||
|       if (this.currIndex == '0') { |  | ||||||
|         this.listType = '1' |  | ||||||
|       } else { |  | ||||||
|         this.listType = '0' |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     gotoAdd(obj) { |  | ||||||
|       this.showDetail = true |  | ||||||
|       this.detailRow = obj |  | ||||||
|       this.currentComp = 'addMeeting' |  | ||||||
|     }, |  | ||||||
|   }, |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
| <style lang="scss" scoped> |  | ||||||
|   .conference { |  | ||||||
|     height: 100%; |  | ||||||
|  |  | ||||||
|     :deep( .ai-list__content--right-wrapper ){ |  | ||||||
|       background-color: transparent !important; |  | ||||||
|       box-shadow: none !important; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -1,244 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <ai-detail class="addMeeting"> |  | ||||||
|     <ai-title slot="title" title="发起会议" isShowBack isShowBottomBorder @onBackClick="$parent.goBack"/> |  | ||||||
|     <template #content> |  | ||||||
|       <ai-card title="会议信息"> |  | ||||||
|         <template #content> |  | ||||||
|           <el-form :model="saveData" status-icon ref="ruleForm" :rules="rules" label-width="100px" |  | ||||||
|                    label-position="right"> |  | ||||||
|             <el-form-item label="会议标题:" prop="title"> |  | ||||||
|               <el-input v-model="saveData.title" size="small" placeholder="请输入..." |  | ||||||
|                         :maxlength="30" show-word-limit></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-row type="flex" justify="space-between"> |  | ||||||
|               <el-form-item label="开始时间:" prop="startTime"> |  | ||||||
|                 <el-date-picker |  | ||||||
|                     :editable="false" |  | ||||||
|                     value-format="yyyy-MM-dd HH:mm:ss" |  | ||||||
|                     v-model="saveData.startTime" |  | ||||||
|                     :picker-options="pickerOptions" |  | ||||||
|                     type="datetime" |  | ||||||
|                     size="small" |  | ||||||
|                     placeholder="选择开始时间"> |  | ||||||
|                 </el-date-picker> |  | ||||||
|               </el-form-item> |  | ||||||
|               <el-form-item label="结束时间:" prop="endTime"> |  | ||||||
|                 <el-date-picker |  | ||||||
|                     :editable="false" |  | ||||||
|                     value-format="yyyy-MM-dd HH:mm:ss" |  | ||||||
|                     v-model="saveData.endTime" |  | ||||||
|                     :picker-options="pickerOptions" |  | ||||||
|                     type="datetime" |  | ||||||
|                     :disabled="!Boolean(saveData.startTime)" |  | ||||||
|                     size="small" |  | ||||||
|                     placeholder="选择结束时间"> |  | ||||||
|                 </el-date-picker> |  | ||||||
|               </el-form-item> |  | ||||||
|             </el-row> |  | ||||||
|             <el-form-item label="会议地点:" prop="address"> |  | ||||||
|               <el-input v-model="saveData.address" size="small" placeholder="请输入..." |  | ||||||
|                         :maxlength="30" show-word-limit></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="会议内容:" prop="content"> |  | ||||||
|               <el-input v-model="saveData.content" size="small" placeholder="请输入..." |  | ||||||
|                         type="textarea" :rows="8" :maxlength="500" show-word-limit></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-row type="flex" justify="space-between"> |  | ||||||
|               <el-form-item label="参会提醒:" prop="noticeBefore"> |  | ||||||
|                 <ai-select v-model="saveData.noticeBefore" |  | ||||||
|                            placeholder="请选择" |  | ||||||
|                            :selectList="dict.getDict('meetingNoticeBefore')" |  | ||||||
|                 ></ai-select> |  | ||||||
|               </el-form-item> |  | ||||||
|               <el-form-item label="确认提醒:" prop="noticeAfter"> |  | ||||||
|                 <ai-select v-model="saveData.noticeAfter" |  | ||||||
|                            placeholder="请选择" |  | ||||||
|                            :selectList="dict.getDict('meetingNoticeAfter')" |  | ||||||
|                 ></ai-select> |  | ||||||
|               </el-form-item> |  | ||||||
|             </el-row> |  | ||||||
|             <el-form-item label="会议资料:" prop="files"> |  | ||||||
|               <ai-uploader :instance="instance" @change="handleChange" isShowTip fileType="file" |  | ||||||
|                            v-model="saveData.fileList" |  | ||||||
|                            acceptType=".zip,.rar,.doc,.docx,.xls,.ppt,.pptx,.pdf,.txt,.jpg,.png,.xlsx" |  | ||||||
|                            :limit="9"></ai-uploader> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-form> |  | ||||||
|         </template> |  | ||||||
|       </ai-card> |  | ||||||
|       <ai-card title="参会人员信息"> |  | ||||||
|         <template #right> |  | ||||||
|           <ai-wechat-selecter slot="append" :instance="instance" v-model="saveData.attendees"> |  | ||||||
|             <el-button type="text" icon="iconfont iconAdd">选择参会人员</el-button> |  | ||||||
|           </ai-wechat-selecter> |  | ||||||
|         </template> |  | ||||||
|         <template #content> |  | ||||||
|           <ai-table |  | ||||||
|               border |  | ||||||
|               :tableData="saveData.attendees" |  | ||||||
|               :colConfigs="colConfigs" |  | ||||||
|               :isShowPagination="false"> |  | ||||||
|             <el-table-column label="操作" slot="option" align="center"> |  | ||||||
|               <template v-slot="{row}"> |  | ||||||
|                 <el-button type="text" title="删除" @click="deletePer(row)">删除</el-button> |  | ||||||
|               </template> |  | ||||||
|             </el-table-column> |  | ||||||
|           </ai-table> |  | ||||||
|         </template> |  | ||||||
|       </ai-card> |  | ||||||
|     </template> |  | ||||||
|     <template #footer> |  | ||||||
|       <el-button @click="$parent.goBack">取消</el-button> |  | ||||||
|       <el-button type="primary" @click="saveFrom(0)">保存草稿</el-button> |  | ||||||
|       <el-button type="primary" @click="saveFrom(1)">保存并发布</el-button> |  | ||||||
|     </template> |  | ||||||
|   </ai-detail> |  | ||||||
| </template> |  | ||||||
| <script> |  | ||||||
| import {mapState} from "vuex"; |  | ||||||
| import moment from 'dayjs' |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   name: "addMeeting", |  | ||||||
|   inject: ['top'], |  | ||||||
|   props: { |  | ||||||
|     instance: Function, |  | ||||||
|     dict: Object, |  | ||||||
|     permissions: Function, |  | ||||||
|     detail: Object |  | ||||||
|   }, |  | ||||||
|   data() { |  | ||||||
|     let endTimePass = (rule, value, callback) => { |  | ||||||
|       if (value) { |  | ||||||
|         if (moment(value).unix() - moment(this.saveData.startTime).unix() > 0) { |  | ||||||
|           callback() |  | ||||||
|         } else { |  | ||||||
|           callback(new Error('结束时间要大于开始时间')); |  | ||||||
|         } |  | ||||||
|       } else { |  | ||||||
|         callback(new Error('请选择结束时间')); |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     return { |  | ||||||
|       saveData: { |  | ||||||
|         noticeBefore: '4', |  | ||||||
|         noticeAfter: '0', |  | ||||||
|         attendees: [], |  | ||||||
|         fileList: [] |  | ||||||
|       }, |  | ||||||
|       rules: { |  | ||||||
|         title: [{required: true, message: '请填写会议标题', trigger: 'blur'}], |  | ||||||
|         startTime: [{required: true, message: '请选择开始时间', trigger: 'blur'}], |  | ||||||
|         endTime: [{required: true, validator: endTimePass, trigger: 'change'}], |  | ||||||
|         address: [{required: true, message: '请填写会议地点', trigger: 'blur'}], |  | ||||||
|         // content: [{required: true, message: '请填写会议内容', trigger: 'blur'}], |  | ||||||
|         noticeBefore: [{required: true, message: '请选择参会提醒', trigger: 'blur'}], |  | ||||||
|         noticeAfter: [{required: true, message: '请选择确认提醒', trigger: 'blur'}], |  | ||||||
|       }, |  | ||||||
|       pickerOptions: { |  | ||||||
|         disabledDate(time) { |  | ||||||
|           return time.getTime() < Date.now() - 8.64e7; |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|       showEdit: false, |  | ||||||
|       total: 0, |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   methods: { |  | ||||||
|     handleChange(e) { |  | ||||||
|       this.saveData.fileList = e |  | ||||||
|     }, |  | ||||||
|     deletePer(scope) { |  | ||||||
|       this.$confirm('确认删除此参会人?') |  | ||||||
|       .then(_ => { |  | ||||||
|         if (this.detail.id) { //编辑 |  | ||||||
|  |  | ||||||
|         } else { //新增 |  | ||||||
|           this.saveData.attendees.map((item, index) => { |  | ||||||
|             if (item.id == scope.id) { |  | ||||||
|               this.saveData.attendees.splice(index, 1) |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     saveFrom(status) { |  | ||||||
|       this.$refs["ruleForm"].validate((valid) => { |  | ||||||
|         if (this.saveData.attendees.length == 0) { |  | ||||||
|           return this.$message.error("参会人不能为空!") |  | ||||||
|         } |  | ||||||
|         if (moment(this.saveData.startTime).unix() - moment(Date.now()).unix() < 0) { |  | ||||||
|           return this.$message.error("会议开始时间已过期,请重新选择!"); |  | ||||||
|         } |  | ||||||
|         if (valid) { |  | ||||||
|  |  | ||||||
|           this.saveData.files = [] |  | ||||||
|           this.saveData.fileList.map((item) => { |  | ||||||
|             this.saveData.files.push(item.id) |  | ||||||
|           }) |  | ||||||
|           this.instance.post(`/app/appmeetinginfo/add-update`, { |  | ||||||
|             ...this.saveData, |  | ||||||
|             status: status, |  | ||||||
|           }).then(res => { |  | ||||||
|             if (res.code == 0) { |  | ||||||
|               if (status != 1) { |  | ||||||
|                 this.$message.success("保存草稿成功") |  | ||||||
|               } else { |  | ||||||
|                 this.$message.success("发布成功") |  | ||||||
|               } |  | ||||||
|               this.$parent.goBack(); |  | ||||||
|             } |  | ||||||
|           }); |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|     }, |  | ||||||
|     getDetail() { |  | ||||||
|       this.instance.post(`/app/appmeetinginfo/info-id?id=${this.detail.id}`).then(res => { |  | ||||||
|         if (res?.data) { |  | ||||||
|           this.saveData = { |  | ||||||
|             ...res.data, |  | ||||||
|           }; |  | ||||||
|           this.saveData.fileList = res.data.files || [] |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   created() { |  | ||||||
|     this.dict.load("meetingNoticeAfter", "meetingNoticeBefore").then( |  | ||||||
|         this.$nextTick(() => { |  | ||||||
|           if (JSON.stringify(this.detail) == '{}') { |  | ||||||
|             this.showEdit = false; |  | ||||||
|           } else { |  | ||||||
|             this.showEdit = true; |  | ||||||
|             // this.saveData = {...this.detail}; |  | ||||||
|             // this.compereList = this.saveData.hosts; |  | ||||||
|             // this.saveData.attendees = this.saveData.attendees || []; |  | ||||||
|             this.getDetail() |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|     ) |  | ||||||
|   }, |  | ||||||
|   computed: { |  | ||||||
|     ...mapState(['user']), |  | ||||||
|     headerTitle() { |  | ||||||
|       return this.showEdit ? '修改会议' : '发起会议' |  | ||||||
|     }, |  | ||||||
|     colConfigs() { |  | ||||||
|       return [ |  | ||||||
|         {prop: 'name', align: 'center', label: '姓名'}, |  | ||||||
|         {prop: 'departName', align: 'center', label: '所属单位'}, |  | ||||||
|         {slot: 'option'} |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .addMeeting { |  | ||||||
|   :deep( .el-button--text ){ |  | ||||||
|     .iconfont { |  | ||||||
|       color: inherit; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,595 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <section class="meetingDetail detail-content"> |  | ||||||
|     <ai-detail> |  | ||||||
|       <template #title> |  | ||||||
|         <ai-title title="会议详情" isShowBottomBorder isShowBack @onBackClick="$parent.goBack"> |  | ||||||
|           <template #rightBtn> |  | ||||||
|             <p class="conference_top_area" v-if="listType==0"> |  | ||||||
|               <!-- <el-button type="primary" v-if="detail.status==0" @click="changeMeeting('是否立即发布会议?')">立即发布</el-button> --> |  | ||||||
|               <el-button type="primary" v-if="detail.status==1" @click="noticeMetting()">参会提醒</el-button> |  | ||||||
|               <el-button type="primary" v-if="detail.status==0" @click="editMeeting()">修改会议</el-button> |  | ||||||
|               <el-button class="del-btn-list" v-if="detail.status==1" @click="changeMeeting('是否取消会议?')">取消会议</el-button> |  | ||||||
|               <el-button class="iconfont iconDelete del-btn-list" v-if="detail.status==0||detail.status==3" |  | ||||||
|                          @click="changeMeeting('是否删除会议?')">删除会议 |  | ||||||
|               </el-button> |  | ||||||
|             </p> |  | ||||||
|             <!-- v-if="detail.status==0||detail.status==3" --> |  | ||||||
|             <p class="conference_top_area" v-if="listType==1&&info.status==1"> |  | ||||||
|               <el-button @click="toDo" style="width:80px;" class="del-btn-list">待定</el-button> |  | ||||||
|               <el-button @click="innerVisible=true" v-if="info.joinStatus!=2" style="width:80px;" class="del-btn-list"> |  | ||||||
|                 请假 |  | ||||||
|               </el-button> |  | ||||||
|               <el-button type="primary" @click="changeMeeting('是否确认参会?')" v-if="info.joinStatus!=1" style="width:80px;"> |  | ||||||
|                 确认参会 |  | ||||||
|               </el-button> |  | ||||||
|             </p> |  | ||||||
|           </template> |  | ||||||
|         </ai-title> |  | ||||||
|       </template> |  | ||||||
|       <template #content> |  | ||||||
|         <ai-dialog |  | ||||||
|             title="确认请假" |  | ||||||
|             :visible.sync="innerVisible" |  | ||||||
|             @onConfirm="queMeeting('writeInfo')" |  | ||||||
|             @onCancel="innerVisible=false;" @close="$refs.writeInfo.resetFields()" |  | ||||||
|             width="520px"> |  | ||||||
|           <div class="addother_main" style="width:400px;margin:auto;"> |  | ||||||
|             <el-form :model="writeInfo" status-icon ref="writeInfo" label-width="100px" class="demo-ruleForm"> |  | ||||||
|               <el-form-item label="请假原因:" prop="reason" autocomplete="off" |  | ||||||
|                             :rules="{ |  | ||||||
|                                         required: true, message: '请假原因不能为空', trigger: 'blur' |  | ||||||
|                                     }" |  | ||||||
|               > |  | ||||||
|                 <el-input v-model.trim="writeInfo.reason" autocomplete="off" size="mini" placeholder="请输入..." |  | ||||||
|                           type="textarea" :rows="4" :maxlength="100" show-word-limit></el-input> |  | ||||||
|               </el-form-item> |  | ||||||
|  |  | ||||||
|             </el-form> |  | ||||||
|           </div> |  | ||||||
|         </ai-dialog> |  | ||||||
|         <ai-card title="会议说明"> |  | ||||||
|           <template slot="content"> |  | ||||||
|             <ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="1"> |  | ||||||
|               <ai-info-item label="会议标题:"><span>{{ info.title }}</span></ai-info-item> |  | ||||||
|             </ai-wrapper> |  | ||||||
|             <ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="2"> |  | ||||||
|               <ai-info-item label="发起单位:" :value="info.unitName"> |  | ||||||
|               </ai-info-item> |  | ||||||
|               <ai-info-item label="发起人:" :value="info.userName"> |  | ||||||
|               </ai-info-item> |  | ||||||
|             </ai-wrapper> |  | ||||||
|             <ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="1"> |  | ||||||
|               <!-- <ai-info-item label="会议状态:" v-if="xq.joinStatus==1&&listType==1"><span>{{ xq.joinStatus }}</span> |  | ||||||
|               </ai-info-item> --> |  | ||||||
|               <ai-info-item label="发起时间:"><span>{{ info.createTime }}</span></ai-info-item> |  | ||||||
|             </ai-wrapper> |  | ||||||
|             <ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="2"> |  | ||||||
|               <ai-info-item label="开始时间:"><span>{{ info.startTime }}</span></ai-info-item> |  | ||||||
|               <ai-info-item label="结束时间:"><span>{{ info.endTime }}</span></ai-info-item> |  | ||||||
|             </ai-wrapper> |  | ||||||
|             <ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="2"> |  | ||||||
|               <ai-info-item label="参会提醒:"><span>{{ |  | ||||||
|                   dict.getLabel("meetingNoticeBefore", info.noticeBefore) || "-" |  | ||||||
|                 }}</span></ai-info-item> |  | ||||||
|               <ai-info-item label="确认提醒:"><span>{{ |  | ||||||
|                   dict.getLabel("meetingNoticeAfter", info.noticeAfter) || "-" |  | ||||||
|                 }}</span> |  | ||||||
|               </ai-info-item> |  | ||||||
|             </ai-wrapper> |  | ||||||
|             <ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="1"> |  | ||||||
|               <ai-info-item label="会议地点:"><span>{{ info.address }}</span></ai-info-item> |  | ||||||
|             </ai-wrapper> |  | ||||||
|             <ai-wrapper class="mar-t16" label-width="70px" :columnsNumber="1"> |  | ||||||
|               <ai-info-item label="会议内容:"><span v-html="info.content"></span></ai-info-item> |  | ||||||
|             </ai-wrapper> |  | ||||||
|           </template> |  | ||||||
|         </ai-card> |  | ||||||
|         <ai-card title="会议资料"> |  | ||||||
|           <template slot="content"> |  | ||||||
|             <ai-file-list :fileList="info.files" :fileOps="{name: 'name', size: 'fileSizeStr'}"></ai-file-list> |  | ||||||
|           </template> |  | ||||||
|         </ai-card> |  | ||||||
|         <ai-card title="参会名单"> |  | ||||||
|           <template slot="content"> |  | ||||||
|             <ai-search-bar bottomBorder> |  | ||||||
|               <template #left> |  | ||||||
|                 <el-select v-model="search.joinStatus" placeholder="确认状态" size="small" clearable class="vc-input-160" @change="searchMeetinguser"> |  | ||||||
|                   <el-option |  | ||||||
|                       v-for="(item,k) in confirmStatus" |  | ||||||
|                       :key="k" |  | ||||||
|                       :label="item.label" |  | ||||||
|                       :value="k"> |  | ||||||
|                   </el-option> |  | ||||||
|                 </el-select> |  | ||||||
|               </template> |  | ||||||
|               <template #right> |  | ||||||
|                 <!-- <ai-download :instance="instance" url="/app/appepidemicbackhomerecord/export" fileName="参会名单"> |  | ||||||
|                   <el-button icon="iconfont iconExported">导出</el-button> |  | ||||||
|                 </ai-download> --> |  | ||||||
|               </template> |  | ||||||
|             </ai-search-bar> |  | ||||||
|             <ai-table |  | ||||||
|                 :tableData="info.attendees" |  | ||||||
|                 :colConfigs="colConfigs" |  | ||||||
|                 style="margin-top: 12px;" |  | ||||||
|                 :isShowPagination="false"> |  | ||||||
|               <el-table-column slot="meetingUserName" |  | ||||||
|                                label="姓名" |  | ||||||
|                                align="center" |  | ||||||
|                                show-overflow-tooltip> |  | ||||||
|                 <div slot-scope="{row}"> |  | ||||||
|                   <span>{{ row.meetingUserName }}</span> |  | ||||||
|                 </div> |  | ||||||
|               </el-table-column> |  | ||||||
|  |  | ||||||
|               <el-table-column slot="meetingUnitName" |  | ||||||
|                                label="所属部门" |  | ||||||
|                                align="center" |  | ||||||
|                                show-overflow-tooltip> |  | ||||||
|                 <div slot-scope="{row}"> |  | ||||||
|                   <span>{{ row.meetingUnitName }}</span> |  | ||||||
|                 </div> |  | ||||||
|               </el-table-column> |  | ||||||
|  |  | ||||||
|               <el-table-column slot="joinStatus" |  | ||||||
|                                prop="joinStatus" |  | ||||||
|                                label="确认状态" |  | ||||||
|                                align="center" |  | ||||||
|                                show-overflow-tooltip> |  | ||||||
|                 <div slot-scope="{row}"> |  | ||||||
|                   <p style="color:rgba(255,68,102,1);display:flex;justify-content:center;" v-if="row.joinStatus==2"> |  | ||||||
|                     请假<i class="el-icon-warning" :title="row.absence" style="cursor: pointer;"></i> |  | ||||||
|                   </p> |  | ||||||
|                   <span v-else :style="{color:confirmStatus[row.joinStatus].color}" |  | ||||||
|                         v-text="confirmStatus[row.joinStatus].label"/> |  | ||||||
|                 </div> |  | ||||||
|               </el-table-column> |  | ||||||
|               <el-table-column slot="option" |  | ||||||
|                                label="操作" |  | ||||||
|                                align="center" |  | ||||||
|                                v-if="listType==0" |  | ||||||
|                                show-overflow-tooltip> |  | ||||||
|                 <div slot-scope="{row}" v-if="row.joinStatus==0"> |  | ||||||
|                   <span class="el-icon-message-solid" style="cursor: pointer;" title="参会提醒" |  | ||||||
|                         @click="noticeMetting(row.meetingUserId)" v-if="detail.status==1"></span> |  | ||||||
|                 </div> |  | ||||||
|               </el-table-column> |  | ||||||
|             </ai-table> |  | ||||||
|           </template> |  | ||||||
|         </ai-card> |  | ||||||
|       </template> |  | ||||||
|     </ai-detail> |  | ||||||
|   </section> |  | ||||||
| </template> |  | ||||||
| <script> |  | ||||||
| import {mapState} from "vuex"; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   name: 'meetingDetail', |  | ||||||
|   inject: ['top'], |  | ||||||
|   props: { |  | ||||||
|     instance: Function, |  | ||||||
|     dict: Object, |  | ||||||
|     permissions: Function, |  | ||||||
|     detail: Object, |  | ||||||
|     listType: String |  | ||||||
|   }, |  | ||||||
|   data() { |  | ||||||
|     return { |  | ||||||
|       navId: '1', |  | ||||||
|       info: {}, |  | ||||||
|       total: 0, |  | ||||||
|       writeInfo: {reason: ''}, |  | ||||||
|       meetingUserList: [], |  | ||||||
|       innerVisible: false, |  | ||||||
|       search: {joinStatus: ''} |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   created() { |  | ||||||
|     this.dict.load("meetingNoticeAfter", "meetingNoticeBefore").then(() => this.searchDetail(this.detail.id)) |  | ||||||
|   }, |  | ||||||
|   computed: { |  | ||||||
|     ...mapState(['user']), |  | ||||||
|     colConfigs() { |  | ||||||
|       return [ |  | ||||||
|         { |  | ||||||
|           slot: 'meetingUserName' |  | ||||||
|         }, |  | ||||||
|         { |  | ||||||
|           slot: 'meetingUnitName' |  | ||||||
|         }, |  | ||||||
|         { |  | ||||||
|           slot: 'joinStatus', |  | ||||||
|         }, |  | ||||||
|         {prop: 'signInStatus', align: 'center', label: '签到', format: v => v === '1' ? '已签到' : '未签到'}, |  | ||||||
|         { |  | ||||||
|           slot: 'option', |  | ||||||
|         } |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     confirmStatus() { |  | ||||||
|       return { |  | ||||||
|         0: {label: '未确认', color: "rgba(255,136,34,1)"}, |  | ||||||
|         1: {label: '已确认', color: "rgba(34,102,255,1)"}, |  | ||||||
|         2: {label: '请假', color: "rgba(255,68,102,1)"}, |  | ||||||
|         3: {label: '待定', color: "rgba(255,136,34,1)"}, |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   methods: { |  | ||||||
|     toDo() { |  | ||||||
|       this.$confirm("是否确认待定会议?").then(_ => { |  | ||||||
|         this.instance.post("/app/appmeetinginfo/tobeConfirm", null, { |  | ||||||
|           params: { |  | ||||||
|             meetingId: this.detail.id, |  | ||||||
|           } |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.$message.success("会议待定"); |  | ||||||
|             setTimeout(_ => { |  | ||||||
|               this.$parent.goBack(); |  | ||||||
|             }, 800) |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     searchMeetinguser() { |  | ||||||
|       this.instance.post(`/app/appmeetinguser/list`, null, { |  | ||||||
|         params: {...this.search, size: 999, meetingId: this.info.id} |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res?.data) { |  | ||||||
|           this.info.attendees = res.data.records; |  | ||||||
|           this.total = res.data.total; |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|     }, |  | ||||||
|     searchDetail(id) { |  | ||||||
|       this.instance.post(`/app/appmeetinginfo/info-id`, null, { |  | ||||||
|         params: {id} |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res?.data) { |  | ||||||
|           let {files = [], content} = res.data |  | ||||||
|           content = content.replace(/(\r\n)|(\n)/g, "<br>") |  | ||||||
|           this.info = {...res.data, content, files}; |  | ||||||
|           this.searchMeetinguser() |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|     }, |  | ||||||
|     changeMeeting(title, id) { |  | ||||||
|       this.$confirm(title, { |  | ||||||
|         type: 'warning' |  | ||||||
|       }).then(() => { |  | ||||||
|         if (title == '是否立即发布会议?') { |  | ||||||
|           this.fbMeeting(); |  | ||||||
|         } else if (title == '是否删除会议?') { |  | ||||||
|           this.sdMeeting(); |  | ||||||
|         } else if (title == '是否取消会议?') { |  | ||||||
|           this.qxMeeting(); |  | ||||||
|         } else if (title == '是否确认参会?') { |  | ||||||
|           this.qrMeeting(); |  | ||||||
|         } else if (title == '是否删除此参会人员?') { |  | ||||||
|           this.deleteMeetingPer(id) |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     deleteMeetingPer(id) { |  | ||||||
|       this.instance.post(`/app/appmeetinguser/delete`, null, |  | ||||||
|           { |  | ||||||
|             params: { |  | ||||||
|               id |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|       ).then(res => { |  | ||||||
|  |  | ||||||
|         if (res && res.code == 0) { |  | ||||||
|           this.$message.success("删除成功!"); |  | ||||||
|           this.searchMeetinguser(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|       }); |  | ||||||
|     }, |  | ||||||
|     queMeeting(formName) { |  | ||||||
|       this.$refs[formName].validate((valid) => { |  | ||||||
|         if (valid) { |  | ||||||
|           this.instance.post(`/app/appmeetinginfo/absent`, null, |  | ||||||
|               { |  | ||||||
|                 params: { |  | ||||||
|                   meetingId: this.detail.id, |  | ||||||
|                   reason: this.writeInfo.reason |  | ||||||
|                 } |  | ||||||
|               } |  | ||||||
|           ).then(res => { |  | ||||||
|  |  | ||||||
|             if (res && res.code == 0) { |  | ||||||
|               this.innerVisible = false; |  | ||||||
|               this.$parent.goBack(); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|           }); |  | ||||||
|         } else { |  | ||||||
|           return false; |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|  |  | ||||||
|     }, |  | ||||||
|     qrMeeting() { |  | ||||||
|       this.instance.post(`/app/appmeetinginfo/confirm`, null, |  | ||||||
|           { |  | ||||||
|             params: { |  | ||||||
|               meetingId: this.detail.id |  | ||||||
|  |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|       ).then(res => { |  | ||||||
|  |  | ||||||
|         if (res && res.code == 0) { |  | ||||||
|           this.$message.success("确认参会成功!") |  | ||||||
|           this.$parent.goBack(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|       }); |  | ||||||
|     }, |  | ||||||
|     noticeMetting(meetingUserId) { |  | ||||||
|       this.instance.post(`/app/appmeetinginfo/notice`, null, { |  | ||||||
|         params: { |  | ||||||
|           meetingId: this.detail.id, noticeALL: !meetingUserId, meetingUserId |  | ||||||
|         } |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res && res.code == 0) { |  | ||||||
|           this.$message.success("提醒成功!") |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|       }); |  | ||||||
|     }, |  | ||||||
|     fbMeeting() { |  | ||||||
|       this.instance.post(`/app/appmeetinginfo/release`, null, |  | ||||||
|           { |  | ||||||
|             params: { |  | ||||||
|               meetingId: this.detail.id |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|       ).then(res => { |  | ||||||
|  |  | ||||||
|         if (res && res.code == 0) { |  | ||||||
|           this.$message.success("发布成功!") |  | ||||||
|           this.$parent.goBack(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|       }); |  | ||||||
|  |  | ||||||
|     }, |  | ||||||
|     sdMeeting() { |  | ||||||
|       this.instance.post(`/app/appmeetinginfo/delete`, null, |  | ||||||
|           { |  | ||||||
|             params: { |  | ||||||
|               meetingId: this.detail.id |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|       ).then(res => { |  | ||||||
|  |  | ||||||
|         if (res && res.code == 0) { |  | ||||||
|           this.$message.success("删除成功!"); |  | ||||||
|           this.$parent.goBack(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|       }); |  | ||||||
|     }, |  | ||||||
|     qxMeeting() { |  | ||||||
|       this.instance.post(`/app/appmeetinginfo/cancel`, null, |  | ||||||
|           { |  | ||||||
|             params: { |  | ||||||
|               meetingId: this.detail.id |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|       ).then(res => { |  | ||||||
|  |  | ||||||
|         if (res && res.code == 0) { |  | ||||||
|           this.$message.success("取消会议成功!"); |  | ||||||
|           this.$parent.goBack(); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|       }); |  | ||||||
|     }, |  | ||||||
|     editMeeting() { |  | ||||||
|       this.$parent.goBack(); |  | ||||||
|       this.$emit('gotoEdit', this.info) |  | ||||||
|     }, |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .meetingDetail { |  | ||||||
|   width: 100%; |  | ||||||
|   height: 100%; |  | ||||||
|   background: rgba(255, 255, 255, 1); |  | ||||||
|  |  | ||||||
|   .conference_top_area { |  | ||||||
|     display: flex; |  | ||||||
|     align-items: center; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .user-search { |  | ||||||
|     width: 100%; |  | ||||||
|     height: 48px; |  | ||||||
|     display: flex; |  | ||||||
|     justify-content: space-between; |  | ||||||
|     align-items: center; |  | ||||||
|  |  | ||||||
|     .float-right { |  | ||||||
|       width: calc(100% - 200px); |  | ||||||
|       text-align: right; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .input-162 { |  | ||||||
|       display: inline-block; |  | ||||||
|       width: 162px; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .content { |  | ||||||
|     width: 1000px; |  | ||||||
|     height: calc(100% - 50px); |  | ||||||
|     overflow: hidden; |  | ||||||
|     margin: auto; |  | ||||||
|     display: flex; |  | ||||||
|     justify-content: space-around; |  | ||||||
|  |  | ||||||
|     .content-left { |  | ||||||
|       width: 160px; |  | ||||||
|       height: 100%; |  | ||||||
|  |  | ||||||
|       .content-left-nav { |  | ||||||
|         width: 158px; |  | ||||||
|         background-color: #ffffff; |  | ||||||
|         border-radius: 4px; |  | ||||||
|         border: solid 1px #eeeeee; |  | ||||||
|         margin-top: 56px; |  | ||||||
|         overflow: hidden; |  | ||||||
|  |  | ||||||
|         li { |  | ||||||
|           height: 48px; |  | ||||||
|           line-height: 48px; |  | ||||||
|           padding-left: 24px; |  | ||||||
|           font-size: 14px; |  | ||||||
|           font-weight: normal; |  | ||||||
|           font-stretch: normal; |  | ||||||
|           letter-spacing: 0; |  | ||||||
|           color: #666666; |  | ||||||
|           cursor: pointer; |  | ||||||
|           border-left: 3px solid transparent; |  | ||||||
|  |  | ||||||
|           &:hover { |  | ||||||
|             border-left: 3px solid #5088ff; |  | ||||||
|           } |  | ||||||
|  |  | ||||||
|           a { |  | ||||||
|             display: block; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .navActive { |  | ||||||
|           border-left: 3px solid #5088ff; |  | ||||||
|           color: #5088ff; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .content-right { |  | ||||||
|       width: 780px; |  | ||||||
|       height: calc(100% - 80px); |  | ||||||
|       overflow-y: auto; |  | ||||||
|       margin-left: 40px; |  | ||||||
|       box-sizing: border-box; |  | ||||||
|       overflow-x: hidden; |  | ||||||
|  |  | ||||||
|       .content-right-title { |  | ||||||
|         width: 780px; |  | ||||||
|         height: 56px; |  | ||||||
|         margin-bottom: 16px; |  | ||||||
|         box-shadow: inset 0px -1px 0px 0px #dad5d5; |  | ||||||
|         display: flex; |  | ||||||
|         justify-content: space-between; |  | ||||||
|         align-items: center; |  | ||||||
|  |  | ||||||
|         span { |  | ||||||
|           display: block; |  | ||||||
|           width: 150px; |  | ||||||
|           height: 56px; |  | ||||||
|           line-height: 56px; |  | ||||||
|           color: #333333; |  | ||||||
|           font-weight: bold; |  | ||||||
|  |  | ||||||
|           &:nth-of-type(2) { |  | ||||||
|             text-align: right; |  | ||||||
|             width: 200px; |  | ||||||
|           } |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .flie { |  | ||||||
|         width: 100%; |  | ||||||
|         height: 40px; |  | ||||||
|         line-height: 40px; |  | ||||||
|         padding: 0 8px; |  | ||||||
|         box-sizing: border-box; |  | ||||||
|         display: flex; |  | ||||||
|         align-items: center; |  | ||||||
|         justify-content: space-between; |  | ||||||
|         font-size: 14px; |  | ||||||
|         color: rgba(51, 51, 51, 1); |  | ||||||
|         background: rgba(255, 255, 255, 1); |  | ||||||
|         border-radius: 4px; |  | ||||||
|         border: 1px solid rgba(208, 212, 220, 1); |  | ||||||
|         margin-bottom: 16px; |  | ||||||
|         cursor: pointer; |  | ||||||
|  |  | ||||||
|         p { |  | ||||||
|           display: flex; |  | ||||||
|           justify-content: flex-start; |  | ||||||
|           align-items: center |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .meeting_name { |  | ||||||
|         width: 100%; |  | ||||||
|         padding-bottom: 25px; |  | ||||||
|         font-size: 16px; |  | ||||||
|         box-shadow: inset 0px -1px 0px 0px #dad5d5; |  | ||||||
|         position: relative; |  | ||||||
|         overflow: hidden; |  | ||||||
|  |  | ||||||
|         .title { |  | ||||||
|           color: #333333; |  | ||||||
|           height: 28px; |  | ||||||
|           line-height: 28px; |  | ||||||
|           margin-left: 0; |  | ||||||
|           font-weight: bold; |  | ||||||
|           margin-top: 14px; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         ul { |  | ||||||
|           overflow: hidden; |  | ||||||
|  |  | ||||||
|           li { |  | ||||||
|             width: 33.3%; |  | ||||||
|             float: left; |  | ||||||
|             line-height: 28px; |  | ||||||
|             font-size: 14px; |  | ||||||
|  |  | ||||||
|             span { |  | ||||||
|               width: 70px; |  | ||||||
|               display: block; |  | ||||||
|               float: left; |  | ||||||
|               color: rgba(153, 153, 153, 1) |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             p { |  | ||||||
|               width: calc(100% - 70px); |  | ||||||
|               float: left; |  | ||||||
|               color: rgba(51, 51, 51, 1); |  | ||||||
|             } |  | ||||||
|           ; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .svg { |  | ||||||
|           width: 88px; |  | ||||||
|           height: 88px; |  | ||||||
|           position: absolute; |  | ||||||
|           right: -20px; |  | ||||||
|           bottom: -20px; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,259 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <ai-list isTabs> |  | ||||||
|     <template #content> |  | ||||||
|       <ai-search-bar> |  | ||||||
|         <template #left> |  | ||||||
|           <el-button type="primary" @click="addMetting()">发起会议</el-button> |  | ||||||
|           <ai-select |  | ||||||
|               v-model="search.meetingStatus" |  | ||||||
|               @change="getTableData()" |  | ||||||
|               placeholder="会议状态" |  | ||||||
|               :selectList="dict.getDict($parent.name==0 ? 'meetingStatusSelect' : 'meetingStatus')" |  | ||||||
|           ></ai-select> |  | ||||||
|           <ai-select |  | ||||||
|               v-if="$parent.name==0" |  | ||||||
|               v-model="search.confirmStatus" |  | ||||||
|               @change="getTableData()" |  | ||||||
|               placeholder="确认状态" |  | ||||||
|               :selectList="dict.getDict('confirmStatus')" |  | ||||||
|           ></ai-select> |  | ||||||
|         </template> |  | ||||||
|         <template #right> |  | ||||||
|           <el-input |  | ||||||
|             v-model="search.param" |  | ||||||
|             v-throttle="() => {search.current=1,getTableData()}" |  | ||||||
|             @keyup.enter.native="search.current=1,getTableData()" |  | ||||||
|             placeholder="会议标题/地点" |  | ||||||
|             size="small" suffix-icon="iconfont iconSearch" clearable @clear="getTableData()"></el-input> |  | ||||||
|         </template> |  | ||||||
|       </ai-search-bar> |  | ||||||
|       <div class="list_main"> |  | ||||||
|         <div class="no-data" style="height:160px;" v-if="tableData.length==0"></div> |  | ||||||
|         <ul v-if="tableData.length>0"> |  | ||||||
|           <li v-for="(item,index) in tableData" :key="index" @click="goDetail(item)"> |  | ||||||
|             <p> |  | ||||||
|               <span class="conference_title">{{ item.title }}</span> |  | ||||||
|               <span class="time" v-if="item.status==1">{{ item.expirationTime }}</span> |  | ||||||
|             </p> |  | ||||||
|             <p style="width:80%;"> |  | ||||||
|               <el-row type="flex" align="middle" class="unit">发起人:{{ item.userName }} |  | ||||||
|               </el-row> |  | ||||||
|               <el-row type="flex" align="middle" class="unit">发起单位:{{ item.unitName }} |  | ||||||
|               </el-row> |  | ||||||
|             </p> |  | ||||||
|             <p style="width:80%;"> |  | ||||||
|               <span class="unit">会议时间:{{ item.startTime.substring(0, 16) + '至' + item.endTime.substring(0, 16) }}</span> |  | ||||||
|               <el-tooltip :content="item.address" placement="top-start" effect="light"> |  | ||||||
|                 <span class="unit" v-if="item.address.length>12">会议地点:{{ |  | ||||||
|                     item.address.substring(0, 12) + '....' |  | ||||||
|                   }}</span> |  | ||||||
|                 <span class="unit" v-else>会议地点:{{ item.address }}</span> |  | ||||||
|               </el-tooltip> |  | ||||||
|             </p> |  | ||||||
|             <!-- <p style="width:80%;"> |  | ||||||
|                   <span |  | ||||||
|                     class="unit">会议时间:{{ |  | ||||||
|                       item.startTime.substring(0, 16) + '至' + item.endTime.substring(0, 16) |  | ||||||
|                     }}</span> |  | ||||||
|               <el-tooltip :content="item.address" placement="top-start" effect="light"> |  | ||||||
|                     <span class="unit address" |  | ||||||
|                           v-if="item.address.length>12">会议地点:{{ item.address.substring(0, 12) + '....' }}</span> |  | ||||||
|                 <span class="unit address" v-else>会议地点:{{ item.address }}</span> |  | ||||||
|               </el-tooltip> |  | ||||||
|             </p> --> |  | ||||||
|             <h5 :class="{color0:item.status==0,color1:item.status==1,color2:item.status==2,color3:item.status==3,color4:item.status==4}"> |  | ||||||
|               <span v-if="item.status==0">草稿箱</span> |  | ||||||
|               <span v-if="item.status==1">未开始</span> |  | ||||||
|               <span v-if="item.status==2">进行中</span> |  | ||||||
|               <span v-if="item.status==3">已取消</span> |  | ||||||
|               <span v-if="item.status==4">已结束</span> |  | ||||||
|             </h5> |  | ||||||
|             <ai-icon class="svg" v-if="item.joinStatus==0" type="svg" icon="iconunidentified"/> |  | ||||||
|             <ai-icon class="svg" v-else-if="item.joinStatus==1" type="svg" icon="iconidentified"/> |  | ||||||
|             <ai-icon class="svg" v-else-if="item.joinStatus==2" type="svg" icon="iconyiqingjia"/> |  | ||||||
|             <ai-icon class="svg" v-else-if="item.joinStatus==3" type="svg" icon="icondaiding"/> |  | ||||||
|           </li> |  | ||||||
|         </ul> |  | ||||||
|       </div> |  | ||||||
|       <div class="pagination" v-if="tableData.length>0"> |  | ||||||
|         <el-pagination |  | ||||||
|             @current-change="handleCurrentChange" |  | ||||||
|             @size-change="handleSizeChange" |  | ||||||
|             background |  | ||||||
|             :current-page.sync="search.current" |  | ||||||
|             :page-sizes="[5, 10, 50, 100,200]" |  | ||||||
|             :page-size="search.size" |  | ||||||
|             layout="total,prev, pager, next,sizes,jumper" |  | ||||||
|             :total="total"> |  | ||||||
|         </el-pagination> |  | ||||||
|       </div> |  | ||||||
|     </template> |  | ||||||
|   </ai-list> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
| export default { |  | ||||||
|   name: "list", |  | ||||||
|   props: { |  | ||||||
|     instance: Function, |  | ||||||
|     dict: Object, |  | ||||||
|     permissions: Function, |  | ||||||
|     listType: String |  | ||||||
|   }, |  | ||||||
|   data() { |  | ||||||
|     return { |  | ||||||
|       search: { |  | ||||||
|         meetingStatus: '', |  | ||||||
|         confirmStatus: '', |  | ||||||
|         param: '', |  | ||||||
|         current: 1, |  | ||||||
|         size: 10, |  | ||||||
|         listType: '' |  | ||||||
|       }, |  | ||||||
|       tableData: [], |  | ||||||
|       total: 0, |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   methods: { |  | ||||||
|     goDetail(item) { |  | ||||||
|       this.$emit('goPage', { |  | ||||||
|         row: item, |  | ||||||
|         comp: 'detail' |  | ||||||
|       }); |  | ||||||
|     }, |  | ||||||
|     addMetting() { |  | ||||||
|       this.$emit('goPage', { |  | ||||||
|         row: {}, |  | ||||||
|         comp: 'addMeeting' |  | ||||||
|       }); |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     getTableData() { |  | ||||||
|       this.instance.post(`/app/appmeetinginfo/list`, null, { |  | ||||||
|         params: { |  | ||||||
|           ...this.search, |  | ||||||
|           listType: this.listType |  | ||||||
|         } |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res && res.data) { |  | ||||||
|           this.tableData = res.data.records; |  | ||||||
|           this.total = res.data.total; |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|       }); |  | ||||||
|     }, |  | ||||||
|     handleCurrentChange(val) { |  | ||||||
|       this.search.current = val; |  | ||||||
|       this.getTableData(); |  | ||||||
|     }, |  | ||||||
|     handleSizeChange(val) { |  | ||||||
|       this.search.size = val; |  | ||||||
|       this.getTableData(); |  | ||||||
|     }, |  | ||||||
|   }, |  | ||||||
|   created() { |  | ||||||
|     this.dict.load("confirmStatus", "meetingStatus", "meetingStatusSelect").then(_ => this.getTableData()) |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .list_main { |  | ||||||
|   width: 100%; |  | ||||||
|  |  | ||||||
|   ul { |  | ||||||
|     overflow: hidden; |  | ||||||
|     padding: 0; |  | ||||||
|     margin: 0; |  | ||||||
|  |  | ||||||
|     li { |  | ||||||
|       width: 100%; |  | ||||||
|       height: 107px; |  | ||||||
|       background: rgba(255, 255, 255, 1); |  | ||||||
|       border-radius: 4px; |  | ||||||
|       border: 1px solid rgba(216, 224, 232, 1); |  | ||||||
|       box-sizing: border-box; |  | ||||||
|       padding: 16px 16px 16px 50px; |  | ||||||
|       margin-top: 8px; |  | ||||||
|       cursor: pointer; |  | ||||||
|       position: relative; |  | ||||||
|       overflow: hidden; |  | ||||||
|  |  | ||||||
|       p { |  | ||||||
|         width: 100%; |  | ||||||
|         height: 25px; |  | ||||||
|         display: flex; |  | ||||||
|         justify-content: space-between; |  | ||||||
|         align-items: center; |  | ||||||
|  |  | ||||||
|         .conference_title { |  | ||||||
|           color: rgba(51, 51, 51, 1); |  | ||||||
|           font-size: 16px; |  | ||||||
|           font-weight: bold; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .time { |  | ||||||
|           font-size: 14px; |  | ||||||
|           color: #2266FF; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .unit { |  | ||||||
|           font-size: 14px; |  | ||||||
|           width: 50%; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       h5 { |  | ||||||
|         width: 100px; |  | ||||||
|         height: 20px; |  | ||||||
|         line-height: 20px; |  | ||||||
|         text-align: center; |  | ||||||
|         position: absolute; |  | ||||||
|         left: -22px; |  | ||||||
|         top: 10px; |  | ||||||
|         box-sizing: border-box; |  | ||||||
|         padding-right: 8px; |  | ||||||
|         font-size: 12px; |  | ||||||
|         transform: rotate(-45deg); |  | ||||||
|         background: #FFF3E8; |  | ||||||
|         color: rgba(255, 136, 34, 1); |  | ||||||
|         box-shadow: -1px 1px 0px 0px rgba(216, 224, 232, 1), 1px -1px 0px 0px rgba(216, 224, 232, 1); |  | ||||||
|         margin: 0; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .color0 { |  | ||||||
|         color: #2244FF; |  | ||||||
|         background: #EFF6FF; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .color1 { |  | ||||||
|         background: #FFF3E8; |  | ||||||
|         color: rgba(255, 136, 34, 1); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .color2 { |  | ||||||
|         background: #EFF6FF; |  | ||||||
|         color: #2266FF; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .color3 { |  | ||||||
|         background-color: #D8E0E8; |  | ||||||
|         color: #999999; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .color4 { |  | ||||||
|         color: #2EA222; |  | ||||||
|         background-color: #D8E0E8; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .svg { |  | ||||||
|         width: 88px; |  | ||||||
|         height: 88px; |  | ||||||
|         position: absolute; |  | ||||||
|         right: -20px; |  | ||||||
|         bottom: -20px; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,186 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <section class="AppCorporateSeal"> |  | ||||||
|       <ai-list v-if="showList"> |  | ||||||
|         <template slot="title"> |  | ||||||
|           <ai-title title="企业印章" :isShowBottomBorder="true"></ai-title> |  | ||||||
|         </template> |  | ||||||
|         <template slot="content"> |  | ||||||
|           <div class="signaturePane"> |  | ||||||
|             <div class="signatureCard" v-for="(op,i) in signatures" :key="i"> |  | ||||||
|               <div class="default" v-if="op.isDefault==1">默认</div> |  | ||||||
|               <div class="body"> |  | ||||||
|                 <el-image :src="`data:image/png;base64,${op.signSealData}`"/> |  | ||||||
|               </div> |  | ||||||
|               <div class="footer"> |  | ||||||
|                 <el-button type="text" :disabled="op.isDefault==1" @click.stop="handleSetDefault(op.id)">设为默认</el-button> |  | ||||||
|                 <hr/> |  | ||||||
|                 <el-button type="text" :disabled="op.isDefault==1||op.signType==1" @click.stop="handleDelete(op.id)">删除 |  | ||||||
|                 </el-button> |  | ||||||
|               </div> |  | ||||||
|             </div> |  | ||||||
|             <div class="signatureCard add" @click="showList=false"> |  | ||||||
|               <ai-icon icon="iconAdd" size="32px"/> |  | ||||||
|               <span>点击添加印章</span> |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|         </template> |  | ||||||
|       </ai-list> |  | ||||||
|     <seal-detail v-else/> |  | ||||||
|   </section> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   import SealDetail from "./sealDetail"; |  | ||||||
|  |  | ||||||
|   export default { |  | ||||||
|     name: "AppCorporateSeal", |  | ||||||
|     label: "企业印章", |  | ||||||
|     components: {SealDetail}, |  | ||||||
|     provide() { |  | ||||||
|       return { |  | ||||||
|         seal: this |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object, |  | ||||||
|       permissions: Function |  | ||||||
|     }, |  | ||||||
|     data() { |  | ||||||
|       return { |  | ||||||
|         signatures: [], |  | ||||||
|         showList: true |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     created() { |  | ||||||
|       this.getSignatures() |  | ||||||
|     }, |  | ||||||
|     methods: { |  | ||||||
|       getSignatures() { |  | ||||||
|         this.instance.post("/app/syssignaccount/list", null, { |  | ||||||
|           params: { |  | ||||||
|             signType: 2, |  | ||||||
|             size: 999 |  | ||||||
|           } |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res?.data) { |  | ||||||
|             this.signatures = res.data.records |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|       handleSetDefault(id) { |  | ||||||
|         this.$confirm("是否设置该印章为默认印章?").then(() => { |  | ||||||
|           this.instance.post("/app/syssignaccount/default", null, {params: {id, listType: 1}}).then(res => { |  | ||||||
|             if (res?.code == 0) { |  | ||||||
|               this.$message.success("设置成功!") |  | ||||||
|               this.getSignatures() |  | ||||||
|             } |  | ||||||
|           }).catch(() => 0) |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|       handleDelete(ids) { |  | ||||||
|         this.$confirm("是否删除该印章?").then(() => { |  | ||||||
|           this.instance.post("/app/syssignaccount/delete", null, {params: {ids}}).then(res => { |  | ||||||
|             if (res?.code == 0) { |  | ||||||
|               this.$message.success("删除成功!") |  | ||||||
|               this.getSignatures() |  | ||||||
|             } |  | ||||||
|           }).catch(() => 0) |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
|   .AppCorporateSeal { |  | ||||||
|     height: 100%; |  | ||||||
|     background: #f3f6f9; |  | ||||||
|  |  | ||||||
|     :deep( .signaturePane ){ |  | ||||||
|       display: flex; |  | ||||||
|       gap: 16px; |  | ||||||
|       flex-wrap: wrap; |  | ||||||
|       padding: 16px; |  | ||||||
|  |  | ||||||
|       .signatureCard { |  | ||||||
|         width: 290px; |  | ||||||
|         height: 258px; |  | ||||||
|         background: #FFFFFF; |  | ||||||
|         border-radius: 4px; |  | ||||||
|         position: relative; |  | ||||||
|         display: flex; |  | ||||||
|         flex-direction: column; |  | ||||||
|         overflow: hidden; |  | ||||||
|  |  | ||||||
|         &.add { |  | ||||||
|           justify-content: center; |  | ||||||
|           align-items: center; |  | ||||||
|           color: #666666; |  | ||||||
|           cursor: pointer; |  | ||||||
|  |  | ||||||
|           .AiIcon { |  | ||||||
|             width: 32px; |  | ||||||
|             height: 32px; |  | ||||||
|             font-size: 32px; |  | ||||||
|           } |  | ||||||
|  |  | ||||||
|           & > span { |  | ||||||
|             font-size: 12px; |  | ||||||
|             line-height: 16px; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .default { |  | ||||||
|           position: absolute; |  | ||||||
|           width: 56px; |  | ||||||
|           height: 24px; |  | ||||||
|           background: #3573FF; |  | ||||||
|           border-radius: 0 0 4px 0; |  | ||||||
|           top: 0; |  | ||||||
|           left: 0; |  | ||||||
|           text-align: center; |  | ||||||
|           line-height: 24px; |  | ||||||
|           font-size: 12px; |  | ||||||
|           color: #FFF; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .body { |  | ||||||
|           min-height: 0; |  | ||||||
|           flex: 1; |  | ||||||
|           display: flex; |  | ||||||
|           justify-content: center; |  | ||||||
|           align-items: center; |  | ||||||
|           padding: 50px; |  | ||||||
|           cursor: pointer; |  | ||||||
|  |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         .footer { |  | ||||||
|           flex-shrink: 0; |  | ||||||
|           height: 40px; |  | ||||||
|           background: rgba(#30426F, .5); |  | ||||||
|           display: flex; |  | ||||||
|           align-items: center; |  | ||||||
|           padding: 8px 0; |  | ||||||
|           box-sizing: border-box; |  | ||||||
|  |  | ||||||
|           hr { |  | ||||||
|             height: 100%; |  | ||||||
|             border-color: rgba(#fff, .5); |  | ||||||
|           } |  | ||||||
|  |  | ||||||
|           & > .el-button { |  | ||||||
|             flex: 1; |  | ||||||
|             color: #fff; |  | ||||||
|  |  | ||||||
|             &[disabled] { |  | ||||||
|               color: rgba(#fff, .5); |  | ||||||
|             } |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
| </style> |  | ||||||
| @@ -1,235 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <section class="sealDetail"> |  | ||||||
|     <ai-detail> |  | ||||||
|       <template #title> |  | ||||||
|         <ai-title title="添加企业印章" isShowBack isShowBottomBorder @onBackClick="back"/> |  | ||||||
|       </template> |  | ||||||
|       <template #content> |  | ||||||
|         <el-form size="small" ref="SealForm" :model="form" :rules="rules" label-suffix=":" label-width="160px"> |  | ||||||
|           <ai-title title="单位信息" isShowBottomBorder/> |  | ||||||
|           <el-form-item label="单位名称" prop="organizeName"> |  | ||||||
|             <el-input clearable v-model="form.organizeName" placeholder="请输入..." maxlength="25" show-word-limit/> |  | ||||||
|           </el-form-item> |  | ||||||
|           <el-form-item label="单位类型" prop="organizeType"> |  | ||||||
|             <el-select clearable v-model="form.organizeType" placeholder="请输入..."> |  | ||||||
|               <el-option v-for="(op,i) in $dict.getDict('organizeType')" :key="i" :value="op.dictValue" |  | ||||||
|                          :label="op.dictName"/> |  | ||||||
|             </el-select> |  | ||||||
|           </el-form-item> |  | ||||||
|           <div class="flexFillRow"> |  | ||||||
|             <el-form-item label="企业注册类型" prop="organRegType"> |  | ||||||
|               <el-select clearable v-model="form.organRegType" placeholder="请输入..."> |  | ||||||
|                 <el-option v-for="(op,i) in $dict.getDict('organRegType')" :key="i" :value="op.dictValue" |  | ||||||
|                            :label="op.dictName"/> |  | ||||||
|               </el-select> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="!!form.organRegType" :label="$dict.getLabel('organRegType',form.organRegType)" |  | ||||||
|                           prop="organCode"> |  | ||||||
|               <el-input clearable v-model="form.organCode" placeholder="请输入..."/> |  | ||||||
|             </el-form-item> |  | ||||||
|             <div v-else/> |  | ||||||
|           </div> |  | ||||||
|           <div class="flexFillRow"> |  | ||||||
|             <el-form-item label="注册类型" prop="registerType"> |  | ||||||
|               <el-select clearable v-model="form.registerType" placeholder="请输入..."> |  | ||||||
|                 <el-option v-for="(op,i) in $dict.getDict('registerType')" :key="i" :value="op.dictValue" |  | ||||||
|                            :label="op.dictName"/> |  | ||||||
|               </el-select> |  | ||||||
|             </el-form-item> |  | ||||||
|             <div/> |  | ||||||
|           </div> |  | ||||||
|           <template v-if="form.registerType==1"> |  | ||||||
|             <div class="flexFillRow"> |  | ||||||
|               <el-form-item label="代理人姓名" prop="agentName"> |  | ||||||
|                 <el-input clearable v-model="form.agentName" placeholder="请输入..."/> |  | ||||||
|               </el-form-item> |  | ||||||
|               <el-form-item label="代理人身份证号" prop="agentIdNumber"> |  | ||||||
|                 <el-input clearable v-model="form.agentIdNumber" placeholder="请输入..."/> |  | ||||||
|               </el-form-item> |  | ||||||
|             </div> |  | ||||||
|             <div class="flexFillRow"> |  | ||||||
|               <el-form-item label="代理人手机号" prop="signPhone"> |  | ||||||
|                 <el-input clearable v-model="form.signPhone" placeholder="请输入..."/> |  | ||||||
|               </el-form-item> |  | ||||||
|               <div/> |  | ||||||
|             </div> |  | ||||||
|           </template> |  | ||||||
|           <template v-if="form.registerType==2"> |  | ||||||
|             <div class="flexFillRow"> |  | ||||||
|               <el-form-item label="法人姓名" prop="legalName"> |  | ||||||
|                 <el-input clearable v-model="form.legalName" placeholder="请输入..."/> |  | ||||||
|               </el-form-item> |  | ||||||
|               <el-form-item label="法人身份证号" prop="legalIdNumber"> |  | ||||||
|                 <el-input clearable v-model="form.legalIdNumber" placeholder="请输入..."/> |  | ||||||
|               </el-form-item> |  | ||||||
|             </div> |  | ||||||
|             <div class="flexFillRow"> |  | ||||||
|               <el-form-item label="法人手机号" prop="signPhone"> |  | ||||||
|                 <el-input clearable v-model="form.signPhone" placeholder="请输入..."/> |  | ||||||
|               </el-form-item> |  | ||||||
|               <div/> |  | ||||||
|             </div> |  | ||||||
|           </template> |  | ||||||
|           <ai-title title="印章信息" isShowBottomBorder/> |  | ||||||
|           <el-form-item class="sealImageTypes" label="生成印章类型" prop="organizeTemplateType"> |  | ||||||
|             <div v-for="(op,i) in sealImageTypes" :key="i" class="item" @click="form.organizeTemplateType=op.value"> |  | ||||||
|               <el-image :src="op.image" fit="contain"/> |  | ||||||
|               <el-radio :label="op.value" v-model="form.organizeTemplateType">{{ op.name }}</el-radio> |  | ||||||
|             </div> |  | ||||||
|           </el-form-item> |  | ||||||
|           <el-form-item label="横向文内容" prop="htext"> |  | ||||||
|             <el-input clearable v-model="form.htext" placeholder="0-8个字,如合同专用章,财务专用章等" maxlength="8" show-word-limit/> |  | ||||||
|           </el-form-item> |  | ||||||
|           <el-form-item label="下弦文内容" prop="qtext"> |  | ||||||
|             <el-input clearable v-model="form.qtext" placeholder="0-20个字,下弦文是指的贵司公章底部一串防伪数字" maxlength="20" |  | ||||||
|                       show-word-limit/> |  | ||||||
|           </el-form-item> |  | ||||||
|         </el-form> |  | ||||||
|       </template> |  | ||||||
|       <template #footer> |  | ||||||
|         <el-button @click="back">取消</el-button> |  | ||||||
|         <el-button type="primary" @click="handleSubmit" v-loading="loading">提交</el-button> |  | ||||||
|       </template> |  | ||||||
|     </ai-detail> |  | ||||||
|   </section> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
| import {ID} from "dui/lib/js/utils"; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   name: "sealDetail", |  | ||||||
|   inject: ['seal'], |  | ||||||
|   data() { |  | ||||||
|     return { |  | ||||||
|       form: { |  | ||||||
|         organizeTemplateType: "STAR", |  | ||||||
|         organizeType: "4", |  | ||||||
|         organRegType: "NORMAL", |  | ||||||
|         registerType: "1" |  | ||||||
|       }, |  | ||||||
|       loading: false |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   computed: { |  | ||||||
|     sealImageTypes() { |  | ||||||
|       return this.$dict.getDict("organizeTemplateType")?.map(e => ({ |  | ||||||
|         image: e.dictColor, |  | ||||||
|         value: e.dictValue, |  | ||||||
|         name: e.dictName |  | ||||||
|       })) || [] |  | ||||||
|     }, |  | ||||||
|     rules() { |  | ||||||
|       return { |  | ||||||
|         organizeName: [{required: true, message: "请填写单位名称"}], |  | ||||||
|         organCode: [{required: true, message: `请填写${this.$dict.getLabel('organRegType', this.form.organRegType)}`}], |  | ||||||
|         legalName: [{required: true, message: "请填写法人姓名"}], |  | ||||||
|         agentName: [{required: true, message: "请填写代理人姓名"}], |  | ||||||
|         organizeTemplateType: [{required: true}], |  | ||||||
|         htext: [{required: true, message: "请填写横向文内容"}], |  | ||||||
|         qtext: [{required: true, message: "请填写下弦文内容"}], |  | ||||||
|         organizeType: [{required: true, message: "请选择单位类型"}], |  | ||||||
|         organRegType: [{required: true, message: "请选择企业注册类型"}], |  | ||||||
|         registerType: [{required: true, message: "请选择注册类型"}], |  | ||||||
|         signPhone: [ |  | ||||||
|           {required: true, message: "请填写手机号码"}, |  | ||||||
|           {pattern: /^1[3456789]\d{9}$/, message: "手机号码格式有误"} |  | ||||||
|         ], |  | ||||||
|         legalIdNumber: [ |  | ||||||
|           {required: true, message: "请填写法人身份证号码"}, |  | ||||||
|           {validator: (r, v, cb) => cb(ID.check(v) ? undefined : "身份证号码格式有误")} |  | ||||||
|         ], |  | ||||||
|         agentIdNumber: [ |  | ||||||
|           {required: true, message: "请填写代理人身份证号码"}, |  | ||||||
|           {validator: (r, v, cb) => cb(ID.check(v) ? undefined : "身份证号码格式有误")} |  | ||||||
|         ], |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   created() { |  | ||||||
|     this.$dict.load("registerType", "organRegType", "organizeType", "organizeTemplateType") |  | ||||||
|   }, |  | ||||||
|   methods: { |  | ||||||
|     back() { |  | ||||||
|       this.seal.showList = true |  | ||||||
|       this.seal.getSignatures() |  | ||||||
|     }, |  | ||||||
|     handleSubmit() { |  | ||||||
|       this.$refs.SealForm.validate(v => { |  | ||||||
|         if (v) { |  | ||||||
|           this.loading = true |  | ||||||
|           this.seal.instance.post("/app/syssignaccount/register", { |  | ||||||
|             userType: 0, |  | ||||||
|             signType: 2, |  | ||||||
|             signPhone: this.form.signPhone, |  | ||||||
|             registerInfo: {...this.form, legalArea: 0}, |  | ||||||
|             style: {...this.form, sealColor: "RED"} |  | ||||||
|           }).then(res => { |  | ||||||
|             this.loading = false |  | ||||||
|             if (res?.code == 0) { |  | ||||||
|               this.$message.success("添加成功!") |  | ||||||
|               this.back() |  | ||||||
|             } |  | ||||||
|           }).catch(() => this.loading = false) |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .sealDetail { |  | ||||||
|   height: inherit; |  | ||||||
|  |  | ||||||
|   :deep( .ai-detail__content--wrapper ){ |  | ||||||
|     .el-form { |  | ||||||
|       display: flex; |  | ||||||
|       flex-direction: column; |  | ||||||
|       gap: 24px; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .el-form-item { |  | ||||||
|       margin-bottom: 0; |  | ||||||
|  |  | ||||||
|       .el-select { |  | ||||||
|         width: 100%; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       &.sealImageTypes > .el-form-item__content { |  | ||||||
|         display: flex; |  | ||||||
|         gap: 40px; |  | ||||||
|  |  | ||||||
|         .item { |  | ||||||
|           display: flex; |  | ||||||
|           flex-direction: column; |  | ||||||
|           align-items: center; |  | ||||||
|           justify-content: center; |  | ||||||
|           gap: 8px; |  | ||||||
|           cursor: pointer; |  | ||||||
|  |  | ||||||
|           .el-image { |  | ||||||
|             width: 80px; |  | ||||||
|             height: 80px; |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .flexFillRow { |  | ||||||
|       display: flex; |  | ||||||
|       align-items: center; |  | ||||||
|  |  | ||||||
|       & > * { |  | ||||||
|         flex: 1; |  | ||||||
|         min-width: 0; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   :deep( .ai-detail__footer > .el-button ){ |  | ||||||
|     width: 92px; |  | ||||||
|     height: 32px; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,365 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <section class="personal-signature"> |  | ||||||
|     <ai-list v-if="!showPhonePage"> |  | ||||||
|       <ai-title slot="title" title="个人签名" :isShowBottomBorder="false"/> |  | ||||||
|       <template #custom> |  | ||||||
|         <div class="signaturePane"> |  | ||||||
|           <div class="signatureCard" v-for="(op,i) in signatures" :key="i"> |  | ||||||
|             <div class="default" v-if="op.isDefault==1">默认</div> |  | ||||||
|             <div class="body"> |  | ||||||
|               <el-image :src="`data:image/png;base64,${op.signSealData}`"/> |  | ||||||
|             </div> |  | ||||||
|             <div class="footer"> |  | ||||||
|               <el-button type="text" :disabled="op.isDefault==1" @click.stop="handleSetDefault(op.id)">设为默认</el-button> |  | ||||||
|               <hr/> |  | ||||||
|               <el-button type="text" :disabled="op.isDefault==1||op.signType>0" @click.stop="handleDelete(op.id)">删除 |  | ||||||
|               </el-button> |  | ||||||
|             </div> |  | ||||||
|           </div> |  | ||||||
|           <div class="signatureCard add" @click="dialog=true"> |  | ||||||
|             <ai-icon icon="iconAdd" size="32px"/> |  | ||||||
|             <span>点击添加签名</span> |  | ||||||
|           </div> |  | ||||||
|         </div> |  | ||||||
|       </template> |  | ||||||
|     </ai-list> |  | ||||||
|     <ai-dialog :visible.sync="dialog" v-bind="dialogConf" @onConfirm="handleSubmit" |  | ||||||
|                @closed="form={},drawPlaceholder=true,qrCode=null,showQRCode=false,getSignatures()"> |  | ||||||
|       <ai-drawer v-if="hasAuthed" :seal.sync="sealData" ref="aiDrawer"> |  | ||||||
|         <template #tools> |  | ||||||
|           <el-popover trigger="manual" v-model="showQRCode"> |  | ||||||
|             <el-image :src="qrCode"/> |  | ||||||
|             <div class="writeInPhone" slot="reference" @click.stop="showQR"> |  | ||||||
|               <ai-icon icon="iconEwm"/> |  | ||||||
|               <span>手机签名</span> |  | ||||||
|             </div> |  | ||||||
|           </el-popover> |  | ||||||
|         </template> |  | ||||||
|       </ai-drawer> |  | ||||||
|       <el-form size="small" :model="form" ref="authForm" :rules="rules" class="authZone" v-else label-suffix=":" |  | ||||||
|                label-width="100px"> |  | ||||||
|         <el-alert type="warning" title="第一次添加个人签名,需先进行实名认证" show-icon :closable="false"/> |  | ||||||
|         <el-form-item label="姓名" prop="personName"> |  | ||||||
|           <el-input v-model="form.personName" clearable placeholder="姓名"/> |  | ||||||
|         </el-form-item> |  | ||||||
|         <el-form-item label="身份证号" prop="idNumber"> |  | ||||||
|           <el-input v-model="form.idNumber" clearable placeholder="身份证号"/> |  | ||||||
|         </el-form-item> |  | ||||||
|         <el-form-item label="手机号码" prop="signPhone"> |  | ||||||
|           <el-input v-model="form.signPhone" clearable placeholder="手机号码"/> |  | ||||||
|         </el-form-item> |  | ||||||
|       </el-form> |  | ||||||
|     </ai-dialog> |  | ||||||
|     <draw-in-phone v-if="showPhonePage"/> |  | ||||||
|   </section> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
| import {mapState} from "vuex"; |  | ||||||
| import DrawInPhone from "./drawInPhone"; |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   name: "AppPersonalSignature", |  | ||||||
|   label: "个人签名", |  | ||||||
|   components: {DrawInPhone}, |  | ||||||
|   provide() { |  | ||||||
|     return { |  | ||||||
|       signature: this |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   props: { |  | ||||||
|     instance: Function, |  | ||||||
|     dict: Object, |  | ||||||
|     permissions: Function |  | ||||||
|   }, |  | ||||||
|   computed: { |  | ||||||
|     ...mapState(['user']), |  | ||||||
|     hasAuthed() { |  | ||||||
|       return this.signatures.length > 0 |  | ||||||
|     }, |  | ||||||
|     dialogConf() { |  | ||||||
|       return this.hasAuthed ? { |  | ||||||
|         title: "手写签名", |  | ||||||
|         width: '720px' |  | ||||||
|       } : { |  | ||||||
|         title: "实名认证", |  | ||||||
|         width: '520px' |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     rules() { |  | ||||||
|       return { |  | ||||||
|         personName: [{required: true, message: "请填写姓名"}], |  | ||||||
|         signPhone: [ |  | ||||||
|           {required: true, message: "请填写手机号码"}, |  | ||||||
|           {pattern: /^1[3456789]\d{9}$/, message: "手机号码格式有误"} |  | ||||||
|         ], |  | ||||||
|         idNumber: [ |  | ||||||
|           {required: true, message: "请填写身份证号码"}, |  | ||||||
|           {validator: (r, v, cb) => cb(ID.check(v) ? undefined : "身份证号码格式有误")} |  | ||||||
|         ], |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   data() { |  | ||||||
|     return { |  | ||||||
|       signatures: [], |  | ||||||
|       dialog: false, |  | ||||||
|       form: {}, |  | ||||||
|       sealData: null, |  | ||||||
|       qrCode: null, |  | ||||||
|       showQRCode: false, |  | ||||||
|       showPhonePage: false, |  | ||||||
|       loading: false, |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   created() { |  | ||||||
|     if (this.$route.query.userId && this.$route.hash == "#phone") { |  | ||||||
|       this.showPhonePage = true |  | ||||||
|     } else { |  | ||||||
|       this.getSignatures() |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   methods: { |  | ||||||
|     getSignatures() { |  | ||||||
|       this.instance.post("/app/syssignaccount/list", null, { |  | ||||||
|         params: { |  | ||||||
|           size: 999 |  | ||||||
|         } |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res?.data) { |  | ||||||
|           this.signatures = res.data.records |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     handleSubmit() { |  | ||||||
|       if (this.loading) return |  | ||||||
|       if (this.hasAuthed && this.$refs['aiDrawer'].drawPlaceholder) return this.$message.error("请签名") |  | ||||||
|       this.loading = true |  | ||||||
|       if (this.hasAuthed) { |  | ||||||
|         let sealData = this.sealData?.replace(/data:image\/png;base64,/, '') |  | ||||||
|         sealData && this.instance({ |  | ||||||
|           url: '/app/syssignaccount/upload-sealdata', |  | ||||||
|           headers: {"Content-Type": "application/json"}, |  | ||||||
|           method: 'post', |  | ||||||
|           params: {userId: this.user.info.id}, |  | ||||||
|           data: sealData |  | ||||||
|         }).then(res => { |  | ||||||
|           this.loading = false |  | ||||||
|           if (res?.code == 0) { |  | ||||||
|             this.dialog = false |  | ||||||
|             this.$message.success("添加成功!") |  | ||||||
|             this.getSignatures() |  | ||||||
|           } |  | ||||||
|         }).catch(() => { |  | ||||||
|           this.loading = false |  | ||||||
|         }) |  | ||||||
|       } else { |  | ||||||
|         this.$refs.authForm.validate(v => { |  | ||||||
|           if (v) { |  | ||||||
|             this.instance.post("/app/syssignaccount/register", { |  | ||||||
|               signPhone: this.form.signPhone, |  | ||||||
|               signType: 1, |  | ||||||
|               userType: 0, |  | ||||||
|               registerInfo: {...this.form}, |  | ||||||
|               style: {personTemplateType: 'RECTANGLE', sealColor: 'RED'} |  | ||||||
|             }).then(res => { |  | ||||||
|               this.loading = false |  | ||||||
|               if (res?.code == 0) { |  | ||||||
|                 this.dialog = false |  | ||||||
|                 this.$message.success("认证成功!") |  | ||||||
|                 this.getSignatures() |  | ||||||
|               } |  | ||||||
|             }).catch(() => { |  | ||||||
|               this.loading = false |  | ||||||
|             }) |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     handleSetDefault(id) { |  | ||||||
|       this.$confirm("是否设置该签名为默认签名?").then(() => { |  | ||||||
|         this.instance.post("/app/syssignaccount/default", null, {params: {id, listType: 0}}).then(res => { |  | ||||||
|           if (res?.code == 0) { |  | ||||||
|             this.$message.success("设置成功!") |  | ||||||
|             this.getSignatures() |  | ||||||
|           } |  | ||||||
|         }).catch(() => 0) |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     handleDelete(ids) { |  | ||||||
|       this.$confirm("是否删除该签名?").then(() => { |  | ||||||
|         this.instance.post("/app/syssignaccount/delete", null, {params: {ids}}).then(res => { |  | ||||||
|           if (res?.code == 0) { |  | ||||||
|             this.$message.success("删除成功!") |  | ||||||
|             this.getSignatures() |  | ||||||
|           } |  | ||||||
|         }).catch(() => 0) |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     showQR() { |  | ||||||
|       if (!this.qrCode) { |  | ||||||
|         let url = `${location.href}?userId=${this.user.info.id}#phone` |  | ||||||
|         this.instance.post("/app/syssignaccount/draw-qrcode", null, { |  | ||||||
|           params: {url} |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res?.data) { |  | ||||||
|             this.showQRCode = true |  | ||||||
|             this.qrCode = res.data |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       } else { |  | ||||||
|         this.showQRCode = !this.showQRCode |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .personal-signature { |  | ||||||
|   height: 100%; |  | ||||||
|   background: #f3f6f9; |  | ||||||
|   overflow: auto; |  | ||||||
|  |  | ||||||
|   :deep( .signaturePane ){ |  | ||||||
|     display: flex; |  | ||||||
|     gap: 16px; |  | ||||||
|     flex-wrap: wrap; |  | ||||||
|     padding: 16px; |  | ||||||
|  |  | ||||||
|     .signatureCard { |  | ||||||
|       width: 290px; |  | ||||||
|       height: 258px; |  | ||||||
|       background: #FFFFFF; |  | ||||||
|       border-radius: 4px; |  | ||||||
|       position: relative; |  | ||||||
|       display: flex; |  | ||||||
|       flex-direction: column; |  | ||||||
|       overflow: hidden; |  | ||||||
|  |  | ||||||
|       &.add { |  | ||||||
|         justify-content: center; |  | ||||||
|         align-items: center; |  | ||||||
|         color: #666666; |  | ||||||
|         cursor: pointer; |  | ||||||
|  |  | ||||||
|         .AiIcon { |  | ||||||
|           width: 32px; |  | ||||||
|           height: 32px; |  | ||||||
|           font-size: 32px; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         & > span { |  | ||||||
|           font-size: 12px; |  | ||||||
|           line-height: 16px; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .default { |  | ||||||
|         position: absolute; |  | ||||||
|         width: 56px; |  | ||||||
|         height: 24px; |  | ||||||
|         background: #3573FF; |  | ||||||
|         border-radius: 0 0 4px 0; |  | ||||||
|         top: 0; |  | ||||||
|         left: 0; |  | ||||||
|         text-align: center; |  | ||||||
|         line-height: 24px; |  | ||||||
|         font-size: 12px; |  | ||||||
|         color: #FFF; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .body { |  | ||||||
|         min-height: 0; |  | ||||||
|         flex: 1; |  | ||||||
|         display: flex; |  | ||||||
|         justify-content: center; |  | ||||||
|         align-items: center; |  | ||||||
|         padding: 25px; |  | ||||||
|         pointer-events: none; |  | ||||||
|  |  | ||||||
|         .el-image { |  | ||||||
|           width: 100%; |  | ||||||
|           height: 100% |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .footer { |  | ||||||
|         flex-shrink: 0; |  | ||||||
|         height: 40px; |  | ||||||
|         background: rgba(#30426F, .5); |  | ||||||
|         display: flex; |  | ||||||
|         align-items: center; |  | ||||||
|         padding: 8px 0; |  | ||||||
|         box-sizing: border-box; |  | ||||||
|  |  | ||||||
|         hr { |  | ||||||
|           height: 100%; |  | ||||||
|           border-color: rgba(#fff, .5); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         & > .el-button { |  | ||||||
|           flex: 1; |  | ||||||
|           color: #fff; |  | ||||||
|  |  | ||||||
|           &[disabled] { |  | ||||||
|             color: rgba(#fff, .5); |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   :deep( .writeInPhone ){ |  | ||||||
|     position: absolute; |  | ||||||
|     width: 100px; |  | ||||||
|     height: 32px; |  | ||||||
|     background: rgba(#000, .5); |  | ||||||
|     border-radius: 16px; |  | ||||||
|     display: flex; |  | ||||||
|     align-items: center; |  | ||||||
|     justify-content: center; |  | ||||||
|     gap: 4px; |  | ||||||
|     color: rgba(#fff, .6); |  | ||||||
|     cursor: pointer; |  | ||||||
|     left: 16px; |  | ||||||
|     top: 16px; |  | ||||||
|  |  | ||||||
|     .AiIcon { |  | ||||||
|       width: auto; |  | ||||||
|       height: auto; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     &:hover { |  | ||||||
|       color: #fff; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   :deep( .ai-dialog__wrapper ){ |  | ||||||
|     .ai-dialog__content--wrapper { |  | ||||||
|       padding-right: 0 !important; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .el-dialog__body { |  | ||||||
|       padding: 24px 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     .authZone { |  | ||||||
|       padding: 0 16px 24px; |  | ||||||
|       width: 100%; |  | ||||||
|       box-sizing: border-box; |  | ||||||
|       display: flex; |  | ||||||
|       flex-direction: column; |  | ||||||
|       gap: 24px; |  | ||||||
|  |  | ||||||
|       .el-alert { |  | ||||||
|         border: 1px solid #FF8822; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .el-form-item { |  | ||||||
|         margin-bottom: 0; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,110 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <section class="drawInPhone" @touchmove.prevent> |  | ||||||
|     <div class="endPage" v-if="finished">操作结束请关闭页面</div> |  | ||||||
|     <ai-drawer :seal.sync="sealData" placeholder="请签名" :width="device.width" :height="device.height"> |  | ||||||
|       <template #tools> |  | ||||||
|         <div class="writeInPhone" slot="reference" @click.stop="handleSubmit"> |  | ||||||
|           <ai-icon icon="iconPublish"/> |  | ||||||
|           <span>提交</span> |  | ||||||
|         </div> |  | ||||||
|       </template> |  | ||||||
|     </ai-drawer> |  | ||||||
|   </section> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
| export default { |  | ||||||
|   name: "drawInPhone", |  | ||||||
|   inject: ['signature'], |  | ||||||
|   data() { |  | ||||||
|     return { |  | ||||||
|       sealData: null, |  | ||||||
|       device: {width: 0, height: 0}, |  | ||||||
|       finished: false |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   created() { |  | ||||||
|     this.device.width = document.body.clientWidth |  | ||||||
|     this.device.height = document.body.clientHeight |  | ||||||
|     window.onresize = () => { |  | ||||||
|       this.device.width = document.body.clientWidth |  | ||||||
|       this.device.height = document.body.clientHeight |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|   methods: { |  | ||||||
|     handleSubmit() { |  | ||||||
|       let sealData = this.sealData?.replace(/data:image\/png;base64,/, ''), |  | ||||||
|           {userId} = this.$route.query |  | ||||||
|       if (!userId) return alert("缺少必要参数") |  | ||||||
|       sealData && this.signature.instance({ |  | ||||||
|         url: '/app/syssignaccount/upload-sealdata', |  | ||||||
|         headers: {"Content-Type": "application/json"}, |  | ||||||
|         method: 'post', |  | ||||||
|         params: {userId}, |  | ||||||
|         data: sealData, |  | ||||||
|         withoutToken: true |  | ||||||
|       }).then(res => { |  | ||||||
|         if (res?.code == 0) { |  | ||||||
|           alert("添加成功!") |  | ||||||
|           this.finished = true |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .drawInPhone { |  | ||||||
|   position: fixed; |  | ||||||
|   left: 0; |  | ||||||
|   right: 0; |  | ||||||
|   top: 0; |  | ||||||
|   bottom: 0; |  | ||||||
|   z-index: 20210205932; |  | ||||||
|  |  | ||||||
|   .endPage { |  | ||||||
|     position: fixed; |  | ||||||
|     left: 0; |  | ||||||
|     right: 0; |  | ||||||
|     top: 0; |  | ||||||
|     bottom: 0; |  | ||||||
|     z-index: 20210205933; |  | ||||||
|     background: rgba(#000, .8); |  | ||||||
|     color: #999; |  | ||||||
|     display: flex; |  | ||||||
|     justify-content: center; |  | ||||||
|     align-items: center; |  | ||||||
|     font-size: 32px; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .AiDrawer { |  | ||||||
|     margin: 0; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .writeInPhone { |  | ||||||
|     position: absolute; |  | ||||||
|     width: 72px; |  | ||||||
|     height: 32px; |  | ||||||
|     background: rgba(#000, .5); |  | ||||||
|     border-radius: 16px; |  | ||||||
|     display: flex; |  | ||||||
|     align-items: center; |  | ||||||
|     justify-content: center; |  | ||||||
|     gap: 4px; |  | ||||||
|     color: rgba(#fff, .6); |  | ||||||
|     cursor: pointer; |  | ||||||
|     left: 16px; |  | ||||||
|     top: 16px; |  | ||||||
|  |  | ||||||
|     .AiIcon { |  | ||||||
|       width: auto; |  | ||||||
|       height: auto; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     &:hover { |  | ||||||
|       color: #fff; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,66 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <div class="doc-circulation ailist-wrapper"> |  | ||||||
|     <keep-alive :include="['List']"> |  | ||||||
|       <component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component> |  | ||||||
|     </keep-alive> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   import List from './components/List' |  | ||||||
|   import Add from './components/Add' |  | ||||||
|  |  | ||||||
|   export default { |  | ||||||
|     name: 'AppBuddyMessage', |  | ||||||
|     label: '好友欢迎语', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data () { |  | ||||||
|       return { |  | ||||||
|         component: 'List', |  | ||||||
|         params: {}, |  | ||||||
|         include: [] |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     components: { |  | ||||||
|       Add, |  | ||||||
|       List |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     mounted () { |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       onChange (data) { |  | ||||||
|         if (data.type === 'Add') { |  | ||||||
|           this.component = 'Add' |  | ||||||
|           this.params = data.params |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (data.type === 'list') { |  | ||||||
|           this.component = 'List' |  | ||||||
|           this.params = data.params |  | ||||||
|  |  | ||||||
|           this.$nextTick(() => { |  | ||||||
|             if (data.isRefresh) { |  | ||||||
|               this.$refs.component.getList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss"> |  | ||||||
|   .doc-circulation { |  | ||||||
|     height: 100%; |  | ||||||
|     background: #F3F6F9; |  | ||||||
|     overflow: auto; |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -1,380 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <ai-detail> |  | ||||||
|     <template slot="title"> |  | ||||||
|       <ai-title title="新建欢迎语" isShowBack isShowBottomBorder @onBackClick="cancel(false)"></ai-title> |  | ||||||
|     </template> |  | ||||||
|  |  | ||||||
|     <template slot="content"> |  | ||||||
|       <ai-card> |  | ||||||
|         <template #title> |  | ||||||
|           <div class="ai-card__title"> |  | ||||||
|             <h2>基本信息</h2> |  | ||||||
|             <span>*一个成员如果被设置了多个欢迎语,将会使用最新设置或修改的欢迎语</span> |  | ||||||
|           </div> |  | ||||||
|         </template> |  | ||||||
|  |  | ||||||
|         <template #content> |  | ||||||
|           <el-form class="ai-form" :rules="rules" ref="userForm" :model="form" label-width="100px" label-position="right"> |  | ||||||
|             <el-form-item label="使用成员" prop="users" style="width: 100%"> |  | ||||||
|               <el-input v-model="users" placeholder="请选择使用成员" disabled style="width: 100%"> |  | ||||||
|                 <template #append> |  | ||||||
|                   <ai-user-selecter refs="addTags" :instance="instance" v-model="form.users"> |  | ||||||
|                     <el-button size="small">选择</el-button> |  | ||||||
|                   </ai-user-selecter> |  | ||||||
|                 </template> |  | ||||||
|               </el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-form> |  | ||||||
|         </template> |  | ||||||
|       </ai-card> |  | ||||||
|  |  | ||||||
|       <ai-card title="发送欢迎语"> |  | ||||||
|         <template #content> |  | ||||||
|           <el-form class="ai-form" ref="form" :model="form" label-width="110px" label-position="right"> |  | ||||||
|             <el-form-item class="el-form-item__textarea" label="文本内容" prop="explain" style="width: 100%"> |  | ||||||
|               <span @click="insertNickname" class="el-form-item__btn" type="text">[插入居民昵称]</span> |  | ||||||
|               <el-input type="textarea" placeholder="请输入…" v-model="form.content" maxlength="1000" :rows="5" show-word-limit></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="其他类型" prop="explain" style="width: 100%"> |  | ||||||
|               <el-radio-group v-model="form.type" @change="onTypeChange"> |  | ||||||
|                 <el-radio label="image">图片</el-radio> |  | ||||||
|                 <el-radio label="link">链接</el-radio> |  | ||||||
|                 <el-radio label="video">视频</el-radio> |  | ||||||
|                 <el-radio label="miniapp">小程序</el-radio> |  | ||||||
|               </el-radio-group> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="图片" prop="files" style="width: 100%" v-if="form.type === 'image'"> |  | ||||||
|               <ai-uploader :instance="instance" isWechat v-model="form.files" :limit="1" url="/app/wxcp/upload/uploadFile?type=image"></ai-uploader> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="链接" prop="linkUrl" style="width: 100%" v-if="form.type === 'link'"> |  | ||||||
|               <el-input placeholder="链接地址请以http或https开头" :rows="2" type="textarea" v-model="form.linkUrl"></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="链接图片地址" prop="picUrl" style="width: 100%" v-if="form.type === 'link'"> |  | ||||||
|               <ai-uploader :instance="instance" v-model="form.picUrl" :limit="1"></ai-uploader> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="链接标题" prop="title" style="width: 100%" v-if="form.type === 'link'"> |  | ||||||
|               <el-input placeholder="请输入链接标题" v-model="form.title"></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="视频" prop="files" style="width: 100%" v-if="form.type === 'video'"> |  | ||||||
|               <ai-uploader :instance="instance" fileType="file" isWechat acceptType=".mp4" v-model="form.files" :limit="1" url="/app/wxcp/upload/uploadFile?type=video"></ai-uploader> |  | ||||||
|             </el-form-item> |  | ||||||
|             <!-- <el-form-item label="小程序" prop="applets" style="width: 100%" v-if="form.type === 'miniapp'"> |  | ||||||
|               <el-radio-group v-model="form.applets"> |  | ||||||
|                 <div class="appletss"> |  | ||||||
|                   <div class="applets-item" @click="form.applets = '0'" :class="[form.applets === '0' ? 'applets-active' : '']"> |  | ||||||
|                     <el-radio label="0"></el-radio> |  | ||||||
|                     <img src="http://www.9665.com/uploadfile/2018/0607/20180607042142312.png"> |  | ||||||
|                     <span>小程序</span> |  | ||||||
|                   </div> |  | ||||||
|                   <div class="applets-item" @click="form.applets = '1'" :class="[form.applets === '1' ? 'applets-active' : '']"> |  | ||||||
|                     <el-radio label="1"></el-radio> |  | ||||||
|                     <img src="http://www.9665.com/uploadfile/2018/0607/20180607042142312.png"> |  | ||||||
|                     <span>小程序</span> |  | ||||||
|                   </div> |  | ||||||
|                   <div class="applets-item" @click="form.applets = '2'" :class="[form.applets === '2' ? 'applets-active' : '']"> |  | ||||||
|                     <el-radio label="2"></el-radio> |  | ||||||
|                     <img src="http://www.9665.com/uploadfile/2018/0607/20180607042142312.png"> |  | ||||||
|                     <span>小程序</span> |  | ||||||
|                   </div> |  | ||||||
|                 </div> |  | ||||||
|               </el-radio-group> |  | ||||||
|             </el-form-item> --> |  | ||||||
|             <el-form-item label="小程序标题" prop="title" style="width: 100%" v-if="form.type === 'miniapp'"> |  | ||||||
|               <el-input placeholder="请输入小程序标题" v-model="form.title"></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="小程序APPID" prop="appid" style="width: 100%" v-if="form.type === 'miniapp'"> |  | ||||||
|               <el-input placeholder="请输入小程序APPID" v-model="form.appid"></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="小程序跳转页面" prop="page" style="width: 100%" v-if="form.type === 'miniapp'"> |  | ||||||
|               <el-input placeholder="如pages/home/Home" v-model="form.page"></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="小程序图片" prop="files" style="width: 100%" v-if="form.type === 'miniapp'"> |  | ||||||
|               <ai-uploader :instance="instance" v-model="form.files" isWechat :limit="1" url="/app/wxcp/upload/uploadFile?type=image"></ai-uploader> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-form> |  | ||||||
|         </template> |  | ||||||
|       </ai-card> |  | ||||||
|     </template> |  | ||||||
|  |  | ||||||
|     <template #footer> |  | ||||||
|       <el-button @click="cancel">取消</el-button> |  | ||||||
|       <el-button type="primary" @click="confirm">提交</el-button> |  | ||||||
|     </template> |  | ||||||
|   </ai-detail> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   const validateUser = (rule, value, callback) => { |  | ||||||
|     if (!value.length) { |  | ||||||
|       callback(new Error('请选择使用成员')) |  | ||||||
|     } else { |  | ||||||
|       callback() |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|   export default { |  | ||||||
|     name: 'Add', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object, |  | ||||||
|       params: Object |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data () { |  | ||||||
|       return { |  | ||||||
|         isShow: false, |  | ||||||
|         info: {}, |  | ||||||
|         form: { |  | ||||||
|           users: [], |  | ||||||
|           appId: '', |  | ||||||
|           page: '', |  | ||||||
|           title: '', |  | ||||||
|           miniappImg: [], |  | ||||||
|           picUrl: [], |  | ||||||
|           content: '', |  | ||||||
|           files: [], |  | ||||||
|           linkUrl: '', |  | ||||||
|           isRemind: true, |  | ||||||
|           type: 'text' |  | ||||||
|         }, |  | ||||||
|         rules: { |  | ||||||
|           users: [ |  | ||||||
|             { required: true, message: '请选择使用成员', trigger: 'change' }, |  | ||||||
|             { validator: validateUser, trigger: 'change' } |  | ||||||
|           ] |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     computed: { |  | ||||||
|       users () { |  | ||||||
|         return this.form.users.map(v => v.name).join(',') |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     created () { |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       getInfo (id) { |  | ||||||
|         this.instance.post(`/app/appleavemessage/queryDetailById?id=${id}`).then(res => { |  | ||||||
|           if (res.code === 0) { |  | ||||||
|             this.info = res.data |  | ||||||
|             this.info.appLeaveMessageReplyList = res.data.appLeaveMessageReplyList.map(item => { |  | ||||||
|               item.images = JSON.parse(item.images).map(item => { |  | ||||||
|                 return { |  | ||||||
|                   ...item, |  | ||||||
|                   url: item.accessUrl |  | ||||||
|                 } |  | ||||||
|               }) |  | ||||||
|  |  | ||||||
|               return item |  | ||||||
|             }) |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       validateUser (rule, value, callback) { |  | ||||||
|         if (!value.length) { |  | ||||||
|           callback(new Error('请选择使用成员')) |  | ||||||
|         } else { |  | ||||||
|           callback() |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       onClose () { |  | ||||||
|         this.form.explain = '' |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       onTypeChange () { |  | ||||||
|         this.form.files = [] |  | ||||||
|         this.form.picUrl = [] |  | ||||||
|         this.form.appId = '' |  | ||||||
|         this.form.page = '' |  | ||||||
|         this.form.title = '' |  | ||||||
|         this.form.miniappImg = [] |  | ||||||
|         this.form.linkUrl = '' |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       insertNickname () { |  | ||||||
|         this.form.content = this.form.content + '[用户昵称]' |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       onChange () { |  | ||||||
|  |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       confirm () { |  | ||||||
|         this.$refs.userForm.validate((valid) => { |  | ||||||
|           if (valid) { |  | ||||||
|             if (this.form.type === 'text' && !this.form.content) { |  | ||||||
|               return this.$message.error('请输入消息内容') |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (this.form.type === 'image' && !this.form.files.length) { |  | ||||||
|               return this.$message.error('请上传图片') |  | ||||||
|             } |  | ||||||
|             // if (this.form.type === 'file' && !this.form.files.length) { |  | ||||||
|             //   return this.$message.error('请上传附件') |  | ||||||
|             // } |  | ||||||
|             if (this.form.type === 'video' && !this.form.files.length) { |  | ||||||
|               return this.$message.error('请上传视频') |  | ||||||
|             } |  | ||||||
|             if (this.form.type === 'link' && !this.form.linkUrl) { |  | ||||||
|               return this.$message.error('请输入链接') |  | ||||||
|             } |  | ||||||
|             if (this.form.type === 'link' && !this.form.picUrl.length) { |  | ||||||
|               return this.$message.error('请输入链接图片') |  | ||||||
|             } |  | ||||||
|             if (this.form.type === 'link' && !this.form.title) { |  | ||||||
|               return this.$message.error('请输入链接标题') |  | ||||||
|             } |  | ||||||
|             if (this.form.type === 'miniapp' && !this.form.title) { |  | ||||||
|               return this.$message.error('请输入小程序标题') |  | ||||||
|             } |  | ||||||
|             if (this.form.type === 'miniapp' && !this.form.appid) { |  | ||||||
|               return this.$message.error('请输入小程序appid') |  | ||||||
|             } |  | ||||||
|             if (this.form.type === 'miniapp' && !this.form.page) { |  | ||||||
|               return this.$message.error('请输入小程序page') |  | ||||||
|             } |  | ||||||
|             if (this.form.type === 'miniapp' && !this.form.files.length) { |  | ||||||
|               return this.$message.error('请上传小程序图片') |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             this.instance.post(`/app/wxcp/wxwelcomeword/add`, { |  | ||||||
|               type: '1', |  | ||||||
|               content: this.form.content || '', |  | ||||||
|               isNotify: '0', |  | ||||||
|               media: { |  | ||||||
|                 createdAt: this.form.files.length ? this.form.files[0].media.createdAt : '', |  | ||||||
|                 file: this.form.files.length ? this.form.files[0] : {}, |  | ||||||
|                 mediaId: this.form.files.length ? this.form.files[0].media.mediaId : '', |  | ||||||
|                 sysFileId: this.form.files.length ? this.form.files[0].id : '', |  | ||||||
|                 type: this.form.type, |  | ||||||
|                 linkUrl: this.form.type === 'link' && this.form.linkUrl ? this.form.linkUrl : '', |  | ||||||
|                 title: this.form.title, |  | ||||||
|                 appId: this.form.appid, |  | ||||||
|                 page: this.form.page, |  | ||||||
|                 picUrl: this.form.type === 'link' ? this.form.picUrl[0].url : '' |  | ||||||
|               }, |  | ||||||
|               users: this.form.users.map(item => { |  | ||||||
|                 return { |  | ||||||
|                   type: 0, |  | ||||||
|                   objectId: item.id, |  | ||||||
|                   objectName: item.name |  | ||||||
|                 } |  | ||||||
|               }) |  | ||||||
|             }).then(res => { |  | ||||||
|               if (res.code == 0) { |  | ||||||
|                 this.$message.success('提交成功') |  | ||||||
|                 setTimeout(() => { |  | ||||||
|                   this.cancel(true) |  | ||||||
|                 }, 600) |  | ||||||
|               } |  | ||||||
|             }) |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       cancel (isRefresh) { |  | ||||||
|         this.$emit('change', { |  | ||||||
|           type: 'list', |  | ||||||
|           isRefresh: isRefresh ? true : false |  | ||||||
|         }) |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style scoped lang="scss"> |  | ||||||
|   .ai-card__title { |  | ||||||
|     display: flex; |  | ||||||
|     align-items: center; |  | ||||||
|  |  | ||||||
|     h2 { |  | ||||||
|       margin-right: 20px; |  | ||||||
|       color: #222222; |  | ||||||
|       font-size: 16px; |  | ||||||
|       font-weight: 700; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     span { |  | ||||||
|       color: #888888; |  | ||||||
|       font-size: 14px; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .appletss { |  | ||||||
|     display: flex; |  | ||||||
|     flex-wrap: wrap; |  | ||||||
|  |  | ||||||
|     .applets-item { |  | ||||||
|       display: flex; |  | ||||||
|       align-items: center; |  | ||||||
|       width: 400px; |  | ||||||
|       height: 60px; |  | ||||||
|       margin-right: 8px; |  | ||||||
|       margin-bottom: 8px; |  | ||||||
|       padding: 0 17px; |  | ||||||
|       background: #FFFFFF; |  | ||||||
|       border-radius: 2px; |  | ||||||
|       border: 1px solid #D0D4DC; |  | ||||||
|       cursor: pointer; |  | ||||||
|  |  | ||||||
|       &:hover { |  | ||||||
|         border-color: #2266FF; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       :deep( ){ |  | ||||||
|         .el-radio__label { |  | ||||||
|           display: none; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       img { |  | ||||||
|         width: 40px; |  | ||||||
|         height: 40px; |  | ||||||
|         margin: 0 8px 0 13px; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       span { |  | ||||||
|         color: #222222; |  | ||||||
|         font-size: 12px; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .el-radio { |  | ||||||
|         margin: 0; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       &.applets-active { |  | ||||||
|         border-color: #2266FF; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .tips { |  | ||||||
|     position: relative; |  | ||||||
|     top: 2px; |  | ||||||
|     padding-left: 8px; |  | ||||||
|     color: #222222; |  | ||||||
|     font-size: 14px; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .el-form-item-item__textarea  { |  | ||||||
|     position: relative; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|     .el-form-item__btn { |  | ||||||
|       position: absolute; |  | ||||||
|       bottom: 12px; |  | ||||||
|       left: 12px; |  | ||||||
|       line-height: 1; |  | ||||||
|       z-index: 1; |  | ||||||
|       color: #2266FF; |  | ||||||
|       font-size: 14px; |  | ||||||
|       user-select: none; |  | ||||||
|       background: #fff; |  | ||||||
|       cursor: pointer; |  | ||||||
|     } |  | ||||||
| </style> |  | ||||||
| @@ -1,235 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <ai-list class="message"> |  | ||||||
|     <template slot="title"> |  | ||||||
|       <ai-title title="好友欢迎语" isShowBottomBorder></ai-title> |  | ||||||
|     </template> |  | ||||||
|     <template slot="content"> |  | ||||||
|       <ai-search-bar class="search-bar"> |  | ||||||
|         <template #left> |  | ||||||
|           <el-button size="small" type="primary" icon="iconfont iconAdd" @click="toAdd">添加好友欢迎语</el-button> |  | ||||||
|         </template> |  | ||||||
|         <template slot="right"> |  | ||||||
|         </template> |  | ||||||
|       </ai-search-bar> |  | ||||||
|       <ai-table |  | ||||||
|         :tableData="tableData" |  | ||||||
|         :col-configs="colConfigs" |  | ||||||
|         :total="total" |  | ||||||
|         style="margin-top: 6px;" |  | ||||||
|         :current.sync="search.current" |  | ||||||
|         :size.sync="search.size" |  | ||||||
|         @getList="getList"> |  | ||||||
|         <el-table-column slot="type" width="240px" label="消息内容" align="center"> |  | ||||||
|           <template slot-scope="{ row }"> |  | ||||||
|             <el-popover |  | ||||||
|               placement="bottom" |  | ||||||
|               width="400" |  | ||||||
|               :visible-arrow="false" |  | ||||||
|               popper-class="wechat-message__container" |  | ||||||
|               trigger="hover"> |  | ||||||
|               <div class="count" slot="reference">共{{ row.count }}条</div> |  | ||||||
|               <div class="message-info"> |  | ||||||
|                 <h2 v-if="row.content" :style="{marginBottom: row.media ? '16px' : '0'}">{{ row.content }}</h2> |  | ||||||
|                 <div class="message-info__wrapper" v-if="row.media && (row.media.file || row.media.type === 'link')"> |  | ||||||
|                   <img v-if="row.media.type === 'image' || row.media.type === 'miniapp'" :src="row.media.file.url"> |  | ||||||
|                   <video v-if="row.media.type === 'video'" :src="row.media.file.url"></video> |  | ||||||
|                   <img v-if="row.media.type === 'link'" :src="row.media.picUrl"> |  | ||||||
|                   <div class="message-info__wrapper--right"> |  | ||||||
|                     <h3 v-if="row.media.type === 'miniapp'">{{ row.media.title }}</h3> |  | ||||||
|                     <h3 v-if="row.media.type === 'image'">{{ row.media.file.name }}</h3> |  | ||||||
|                     <h3 v-if="row.media.type === 'link'">{{ row.media.linkUrl }}</h3> |  | ||||||
|                     <h3 v-if="row.media.type === 'video'">{{ row.media.file.name }}</h3> |  | ||||||
|                     <p v-if="row.media.type === 'image'">{{ row.media.file.fileSizeStr }}</p> |  | ||||||
|                     <p v-if="row.media.type === 'link'">{{ row.media.title }}</p> |  | ||||||
|                     <p v-if="row.media.type === 'video'">{{ row.media.file.fileSizeStr }}</p> |  | ||||||
|                   </div> |  | ||||||
|                 </div> |  | ||||||
|               </div> |  | ||||||
|             </el-popover> |  | ||||||
|           </template> |  | ||||||
|         </el-table-column> |  | ||||||
|         <el-table-column slot="options" width="120px" fixed="right" label="操作" align="center"> |  | ||||||
|           <template slot-scope="{ row }"> |  | ||||||
|             <div class="table-options"> |  | ||||||
|               <!-- <el-button type="text" disabled @click="toAdd(row.id)" title="编辑">编辑</el-button> --> |  | ||||||
|               <el-button type="text" @click="remove(row.id)" title="删除">删除</el-button> |  | ||||||
|             </div> |  | ||||||
|           </template> |  | ||||||
|         </el-table-column> |  | ||||||
|       </ai-table> |  | ||||||
|     </template> |  | ||||||
|   </ai-list> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   export default { |  | ||||||
|     name: 'List', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data () { |  | ||||||
|       return { |  | ||||||
|         search: { |  | ||||||
|           current: 1, |  | ||||||
|           size: 10, |  | ||||||
|           content: '' |  | ||||||
|         }, |  | ||||||
|         currIndex: 0, |  | ||||||
|         total: 10, |  | ||||||
|         colConfigs: [ |  | ||||||
|           { prop: 'type',  label: '类型', align: 'left', width: '160', |  | ||||||
|             render: (h, params) => { |  | ||||||
|               let str = '' |  | ||||||
|  |  | ||||||
|               if (params.row.content) { |  | ||||||
|                 str = '文字' |  | ||||||
|               } |  | ||||||
|  |  | ||||||
|               if (params.row.media && params.row.media.type === 'link') { |  | ||||||
|                 str += this.dict.getLabel('wxMsgType', params.row.media.type) ? (params.row.content ? '+' : '') + this.dict.getLabel('wxMsgType', params.row.media.type) : '' |  | ||||||
|               } |  | ||||||
|  |  | ||||||
|               if (params.row.media && params.row.media.file) { |  | ||||||
|                 str += this.dict.getLabel('wxMsgType', params.row.media.type) ? (params.row.content ? '+' : '') + this.dict.getLabel('wxMsgType', params.row.media.type) : '' |  | ||||||
|               } |  | ||||||
|  |  | ||||||
|               return h('span', { |  | ||||||
|                 style: { |  | ||||||
|                 } |  | ||||||
|               }, str) |  | ||||||
|             } |  | ||||||
|           }, |  | ||||||
|           { slot: 'type' }, |  | ||||||
|           { prop: 'users', label: '使用成员', align: 'left', format: v => v.join(';') }, |  | ||||||
|           { prop: 'createUser', label: '创建人' }, |  | ||||||
|           { prop: 'createTime', label: '编辑时间' }, |  | ||||||
|           { slot: 'options', label: '操作' } |  | ||||||
|         ], |  | ||||||
|         tableData: [] |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     mounted () { |  | ||||||
|       this.dict.load(['wxMsgType']).then(() => { |  | ||||||
|         this.getList() |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       getList() { |  | ||||||
|         this.instance.post(`/app/wxcp/wxwelcomeword/list`, null, { |  | ||||||
|           params: { |  | ||||||
|             ...this.search |  | ||||||
|           } |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.tableData = res.data.records.map(item => { |  | ||||||
|               let count = 0 |  | ||||||
|  |  | ||||||
|               if (item.content) { |  | ||||||
|                 count = count + 1 |  | ||||||
|               } |  | ||||||
|  |  | ||||||
|               if (item.media && item.media.type !== 'text') { |  | ||||||
|                 count = count + 1 |  | ||||||
|               } |  | ||||||
|  |  | ||||||
|               item.count = count |  | ||||||
|               return item |  | ||||||
|             }) |  | ||||||
|             this.total = res.data.total |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       remove (id) { |  | ||||||
|         this.$confirm('确定删除该数据?').then(() => { |  | ||||||
|           this.instance.post(`/app/wxcp/wxwelcomeword/delete?id=${id}`).then(res => { |  | ||||||
|             if (res.code == 0) { |  | ||||||
|               this.$message.success('删除成功!') |  | ||||||
|               this.getList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       toAdd (id) { |  | ||||||
|         this.$emit('change', { |  | ||||||
|           type: 'Add', |  | ||||||
|           params: { |  | ||||||
|             id |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
|   .message { |  | ||||||
|     .count { |  | ||||||
|       cursor: pointer; |  | ||||||
|       color: #2266FF; |  | ||||||
|       font-size: 14px; |  | ||||||
|  |  | ||||||
|       &:hover { |  | ||||||
|         opacity: 0.6; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .message-info { |  | ||||||
|     padding: 8px; |  | ||||||
|     min-height: 116px; |  | ||||||
|  |  | ||||||
|     h2 { |  | ||||||
|       color: #222222; |  | ||||||
|       font-weight: 500; |  | ||||||
|       font-size: 14px; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .message-info__wrapper { |  | ||||||
|       display: flex; |  | ||||||
|       align-items: center; |  | ||||||
|       width: 368px; |  | ||||||
|       height: 60px; |  | ||||||
|       padding: 10px; |  | ||||||
|       background: #FFFFFF; |  | ||||||
|       border-radius: 2px; |  | ||||||
|       border: 1px solid #D0D4DC; |  | ||||||
|  |  | ||||||
|       .message-info__wrapper--right { |  | ||||||
|         flex: 1; |  | ||||||
|         overflow: hidden; |  | ||||||
|         text-overflow:ellipsis; |  | ||||||
|         white-space: nowrap; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       h3 { |  | ||||||
|         width: 100%; |  | ||||||
|         color: #222222; |  | ||||||
|         font-size: 14px; |  | ||||||
|         overflow: hidden; |  | ||||||
|         text-overflow:ellipsis; |  | ||||||
|         white-space: nowrap; |  | ||||||
|         font-weight: normal; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       img, video { |  | ||||||
|         width: 40px; |  | ||||||
|         height: 40px; |  | ||||||
|         margin-right: 10px; |  | ||||||
|         object-fit: cover; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       p { |  | ||||||
|         margin-top: 6px; |  | ||||||
|         font-size: 14px; |  | ||||||
|         color: #888888; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -1,47 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <div class="doc-circulation ailist-wrapper"> |  | ||||||
|     <keep-alive :include="['List']"> |  | ||||||
|       <component ref="component" :is="component" :instance="instance" :dict="dict"></component> |  | ||||||
|     </keep-alive> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   import List from './components/List' |  | ||||||
|  |  | ||||||
|   export default { |  | ||||||
|     name: 'AppMaterialLibrary', |  | ||||||
|     label: '素材库', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data () { |  | ||||||
|       return { |  | ||||||
|         component: 'List', |  | ||||||
|         params: {}, |  | ||||||
|         include: [] |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     components: { |  | ||||||
|       List |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     mounted () { |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss"> |  | ||||||
|   .doc-circulation { |  | ||||||
|     height: 100%; |  | ||||||
|     background: #F3F6F9; |  | ||||||
|     overflow: auto; |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -1,212 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <div id="ChooseMaterial"> |  | ||||||
|     <ai-dialog |  | ||||||
|       :visible.sync="isShow" |  | ||||||
|       width="890px" |  | ||||||
|       @onConfirm="onConfirm" |  | ||||||
|       title="选择素材"> |  | ||||||
|       <div class="AppMaterialLibrary-title"> |  | ||||||
|         <span |  | ||||||
|           v-for="(item, index) in typeList" |  | ||||||
|           :key="index" |  | ||||||
|           :class="[currIndex === index ? 'active' : '']" @click="currIndex = index, search.current = 1, getList()"> |  | ||||||
|           {{ item }} |  | ||||||
|         </span> |  | ||||||
|       </div> |  | ||||||
|       <ai-search-bar class="search-bar"> |  | ||||||
|         <template #left> |  | ||||||
|         </template> |  | ||||||
|         <template slot="right"> |  | ||||||
|           <el-input |  | ||||||
|             v-model="search.title" |  | ||||||
|             size="small" |  | ||||||
|             v-throttle="() => { search.current = 1, getList() }" |  | ||||||
|             placeholder="请输入标题、话术内容、添加人" |  | ||||||
|             clearable |  | ||||||
|             @clear="search.current = 1, search.title = '', getList()" |  | ||||||
|             suffix-icon="iconfont iconSearch"> |  | ||||||
|           </el-input> |  | ||||||
|         </template> |  | ||||||
|       </ai-search-bar> |  | ||||||
|       <ai-table |  | ||||||
|         :tableData="tableData" |  | ||||||
|         :col-configs="colConfigs" |  | ||||||
|         :total="total" |  | ||||||
|         style="margin-top: 6px; width: 100%;" |  | ||||||
|         :current.sync="search.current" |  | ||||||
|         :size.sync="search.size" |  | ||||||
|         @selection-change="v=> ids = v.map((e) => e.id)" |  | ||||||
|         @getList="getList"> |  | ||||||
|       </ai-table> |  | ||||||
|     </ai-dialog> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   export default { |  | ||||||
|     name: 'ChooseMaterial', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data() { |  | ||||||
|       return { |  | ||||||
|         search: { |  | ||||||
|           current: 1, |  | ||||||
|           size: 10, |  | ||||||
|           title: '', |  | ||||||
|         }, |  | ||||||
|         ids: [], |  | ||||||
|         isShow: false, |  | ||||||
|         id: '', |  | ||||||
|         typeList: ['话术', '图片', '小程序', '文件', '视频', '网页'], |  | ||||||
|         currIndex: 0, |  | ||||||
|         tableData: [], |  | ||||||
|         total: 0 |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     computed: { |  | ||||||
|       mpTitle () { |  | ||||||
|         return { |  | ||||||
|           '0': '话术标题', |  | ||||||
|           '1': '图片名称', |  | ||||||
|           '2': '小程序标题', |  | ||||||
|           '3': '文件名称', |  | ||||||
|           '4': '视频名称', |  | ||||||
|           '5': '网页名称' |  | ||||||
|         }[this.currIndex] |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       colConfigs () { |  | ||||||
|         if (this.currIndex === 0) { |  | ||||||
|           return [ |  | ||||||
|             { type: 'selection' }, |  | ||||||
|             { prop: 'title', label: this.mpTitle }, |  | ||||||
|             { prop: 'content', label: '话术内容', align: 'center' }, |  | ||||||
|             { prop: 'createUserName', label: '添加人', align: 'center' }, |  | ||||||
|             { prop: 'createTime', label: '添加时间', align: 'center' } |  | ||||||
|           ] |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (this.currIndex === 2) { |  | ||||||
|           return [ |  | ||||||
|             { type: 'selection' }, |  | ||||||
|             { prop: 'title', label: this.mpTitle }, |  | ||||||
|             { prop: 'appId', label: '小程序APPID', align: 'center' }, |  | ||||||
|             { prop: 'createUserName', label: '添加人', align: 'center' }, |  | ||||||
|             { prop: 'createTime', label: '添加时间', align: 'center' } |  | ||||||
|           ] |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (this.currIndex === 5) { |  | ||||||
|           return [ |  | ||||||
|             { type: 'selection' }, |  | ||||||
|             { prop: 'title', label: this.mpTitle }, |  | ||||||
|             { prop: 'pagePath', label: '外链网页', align: 'center' }, |  | ||||||
|             { prop: 'createUserName', label: '添加人', align: 'center' }, |  | ||||||
|             { prop: 'createTime', label: '添加时间', align: 'center' } |  | ||||||
|           ] |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return [ |  | ||||||
|           { type: 'selection' }, |  | ||||||
|           { prop: 'title', label: this.mpTitle }, |  | ||||||
|           { prop: 'fileSizeStr', label: '文件大小', align: 'center' }, |  | ||||||
|           { prop: 'createUserName', label: '添加人', align: 'center' }, |  | ||||||
|           { prop: 'createTime', label: '添加时间', align: 'center' } |  | ||||||
|         ] |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     created () { |  | ||||||
|       this.getList() |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       getList() { |  | ||||||
|         this.instance.post(`/app/appmaterialinfo/list`, null, { |  | ||||||
|           params: { |  | ||||||
|             ...this.search, |  | ||||||
|             type: this.currIndex |  | ||||||
|           } |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.tableData = res.data.records |  | ||||||
|             this.total = res.data.total |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       onConfirm () { |  | ||||||
|         if (!this.ids.length) { |  | ||||||
|           return this.$message.error('请选择素材') |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (this.ids.length > 1) { |  | ||||||
|           return this.$message.error('素材不能多选') |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       open () { |  | ||||||
|         this.isShow = true |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       close () { |  | ||||||
|         this.isShow = false |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
|   #ChooseMaterial { |  | ||||||
|     :deep( .ai-list__content--right-wrapper ) { |  | ||||||
|       padding: 0 20px!important; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     :deep( .el-dialog__header ) { |  | ||||||
|       display: none; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     :deep( .el-dialog__body ) { |  | ||||||
|       padding-top: 0!important; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .AppMaterialLibrary-title { |  | ||||||
|       display: flex; |  | ||||||
|       align-items: center; |  | ||||||
|       margin-bottom: 20px; |  | ||||||
|       border-bottom: 1px solid #eee; |  | ||||||
|  |  | ||||||
|       span { |  | ||||||
|         height: 100%; |  | ||||||
|         line-height: 56px; |  | ||||||
|         margin-right: 32px; |  | ||||||
|         color: #888888; |  | ||||||
|         font-size: 16px; |  | ||||||
|         font-weight: 600; |  | ||||||
|         transition: all ease 0.3s; |  | ||||||
|         border-bottom: 3px solid transparent; |  | ||||||
|         cursor: pointer; |  | ||||||
|         user-select: none; |  | ||||||
|  |  | ||||||
|         &:hover { |  | ||||||
|           color: #222; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         &:last-child { |  | ||||||
|           margin-right: 0; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         &.active { |  | ||||||
|           color: #222222; |  | ||||||
|           border-bottom: 3px solid #2266FF; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -1,394 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <ai-list id="AppMaterialLibrary"> |  | ||||||
|     <template slot="title"> |  | ||||||
|       <ai-title title="素材管理" isShowBottomBorder> |  | ||||||
|         <template #sub> |  | ||||||
|           <span>可在聊天素材、宣发工具中选择素材发送给居民,提升服务效率;其中文件、视频和网页素材支持记录居民查看行为</span> |  | ||||||
|         </template> |  | ||||||
|       </ai-title> |  | ||||||
|     </template> |  | ||||||
|     <template slot="content"> |  | ||||||
|       <div class="AppMaterialLibrary-title"> |  | ||||||
|         <span |  | ||||||
|           v-for="(item, index) in typeList" |  | ||||||
|           :key="index" |  | ||||||
|           :class="[currIndex === index ? 'active' : '']" @click="currIndex = index, search.current = 1, getList()"> |  | ||||||
|           {{ item }} |  | ||||||
|         </span> |  | ||||||
|       </div> |  | ||||||
|       <ai-search-bar class="search-bar"> |  | ||||||
|         <template #left> |  | ||||||
|           <el-button size="small" type="primary" icon="iconfont iconAdd" @click="isShow = true">添加{{ typeList[currIndex] }}</el-button> |  | ||||||
|         </template> |  | ||||||
|         <template slot="right"> |  | ||||||
|           <el-input |  | ||||||
|             v-model="search.title" |  | ||||||
|             size="small" |  | ||||||
|             v-throttle="() => { search.current = 1, getList() }" |  | ||||||
|             placeholder="请输入标题、话术内容、添加人" |  | ||||||
|             clearable |  | ||||||
|             @clear="search.current = 1, search.title = '', getList()" |  | ||||||
|             suffix-icon="iconfont iconSearch"> |  | ||||||
|           </el-input> |  | ||||||
|         </template> |  | ||||||
|       </ai-search-bar> |  | ||||||
|       <ai-table |  | ||||||
|         :tableData="tableData" |  | ||||||
|         :col-configs="colConfigs" |  | ||||||
|         :total="total" |  | ||||||
|         style="margin-top: 6px; width: 100%;" |  | ||||||
|         :current.sync="search.current" |  | ||||||
|         :size.sync="search.size" |  | ||||||
|         @getList="getList"> |  | ||||||
|         <el-table-column slot="options" width="120px" fixed="right" label="操作" align="center"> |  | ||||||
|           <template slot-scope="{ row }"> |  | ||||||
|             <div class="table-options"> |  | ||||||
|               <el-button type="text" @click="id = row.id, toAdd(row)">编辑</el-button> |  | ||||||
|               <el-button type="text" @click="remove(row.id)">删除</el-button> |  | ||||||
|             </div> |  | ||||||
|           </template> |  | ||||||
|         </el-table-column> |  | ||||||
|       </ai-table> |  | ||||||
|       <ai-dialog |  | ||||||
|         :visible.sync="isShow" |  | ||||||
|         width="920px" |  | ||||||
|         :title="(id ? '编辑' : '添加') + typeList[currIndex]" |  | ||||||
|         @close="onClose" |  | ||||||
|         :close-on-click-modal="false" |  | ||||||
|         destroy-on-close |  | ||||||
|         @onConfirm="confirm"> |  | ||||||
|         <el-form ref="form" v-if="isShow" :model="form" label-width="130px" label-position="right"> |  | ||||||
|           <div class="ai-form"> |  | ||||||
|             <el-form-item v-if="currIndex === 0" label="话术标题" style="width: 100%;" prop="title" :rules="[{ required: true, message: '请输入话术标题', trigger: 'blur' }]"> |  | ||||||
|               <el-input |  | ||||||
|                 size="small" |  | ||||||
|                 placeholder="请输入话术标题" |  | ||||||
|                 maxlength="42" |  | ||||||
|                 show-word-limit |  | ||||||
|                 v-model="form.title"> |  | ||||||
|               </el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 0" label="话术内容" style="width: 100%;" prop="content" :rules="[{ required: true, message: '请输入话术内容', trigger: 'blur' }]"> |  | ||||||
|               <el-input |  | ||||||
|                 size="small" |  | ||||||
|                 placeholder="请输入话术内容" |  | ||||||
|                 maxlength="682" |  | ||||||
|                 show-word-limit |  | ||||||
|                 v-model="form.content"> |  | ||||||
|               </el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 1" label="图片名称" style="width: 100%;" prop="title" :rules="[{ required: true, message: '请输入图片名称', trigger: 'blur' }]"> |  | ||||||
|               <el-input |  | ||||||
|                 size="small" |  | ||||||
|                 placeholder="请输入图片名称" |  | ||||||
|                 maxlength="42" |  | ||||||
|                 show-word-limit |  | ||||||
|                 v-model="form.title"> |  | ||||||
|               </el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 1" label="上传图片" style="width: 100%;" prop="fileUrl" :rules="[{ required: true, message: '请上传', trigger: 'change' }]"> |  | ||||||
|               <ai-uploader :instance="instance" url="/admin/file/add3?type=image" v-model="form.fileUrl" :limit="1"></ai-uploader> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 3" label="文件名称" style="width: 100%;" prop="title" :rules="[{ required: true, message: '请输入文件名称', trigger: 'blur' }]"> |  | ||||||
|               <el-input |  | ||||||
|                 size="small" |  | ||||||
|                 placeholder="请输入图片名称" |  | ||||||
|                 maxlength="42" |  | ||||||
|                 show-word-limit |  | ||||||
|                 v-model="form.title"> |  | ||||||
|               </el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 3" label="上传文件" style="width: 100%;" prop="fileUrl" :rules="[{ required: true, message: '请上传', trigger: 'change' }]"> |  | ||||||
|               <ai-uploader fileType="file" url="/admin/file/add3?type=file" :instance="instance" v-model="form.fileUrl" :limit="1"></ai-uploader> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 4" label="视频标题" style="width: 100%;" prop="title" :rules="[{ required: true, message: '请输入视频标题', trigger: 'blur' }]"> |  | ||||||
|               <el-input |  | ||||||
|                 size="small" |  | ||||||
|                 placeholder="请输入视频标题" |  | ||||||
|                 maxlength="42" |  | ||||||
|                 show-word-limit |  | ||||||
|                 v-model="form.title"> |  | ||||||
|               </el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 4" label="上传视频" style="width: 100%;" prop="fileUrl" :rules="[{ required: true, message: '请上传', trigger: 'change' }]"> |  | ||||||
|               <ai-uploader :instance="instance" url="/admin/file/add3?type=video" fileType="file" v-model="form.fileUrl" :limit="1"></ai-uploader> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 4" label="视频封面图" prop="pictureUrl" style="width: 100%;" :rules="[{ required: true, message: '请上传视频封面图', trigger: 'change' }]"> |  | ||||||
|               <ai-uploader :instance="instance" url="/admin/file/add3?type=image" v-model="form.pictureUrl" :limit="1"></ai-uploader> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 4" label="视频描述" style="width: 100%;" prop="content" :rules="[{ required: true, message: '请输入视频描述', trigger: 'blur' }]"> |  | ||||||
|               <el-input |  | ||||||
|                 size="small" |  | ||||||
|                 placeholder="请输入视频描述" |  | ||||||
|                 maxlength="682" |  | ||||||
|                 show-word-limit |  | ||||||
|                 v-model="form.content"> |  | ||||||
|               </el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 5" label="网页标题" style="width: 100%;" prop="title" :rules="[{ required: true, message: '请输入网页标题', trigger: 'blur' }]"> |  | ||||||
|               <el-input |  | ||||||
|                 size="small" |  | ||||||
|                 placeholder="请输入网页标题" |  | ||||||
|                 maxlength="42" |  | ||||||
|                 show-word-limit |  | ||||||
|                 v-model="form.title"> |  | ||||||
|               </el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 5" label="网页链接" style="width: 100%;" prop="pagePath" :rules="[{ required: true, message: '请输入网页链接链接', trigger: 'blur' }]"> |  | ||||||
|               <el-input |  | ||||||
|                 size="small" |  | ||||||
|                 placeholder="请输入网页链接链接" |  | ||||||
|                 maxlength="682" |  | ||||||
|                 show-word-limit |  | ||||||
|                 v-model="form.pagePath"> |  | ||||||
|               </el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="form.currIndex === 5" label="网页描述" style="width: 100%;" prop="content"> |  | ||||||
|               <el-input |  | ||||||
|                 size="small" |  | ||||||
|                 placeholder="请输入网页描述" |  | ||||||
|                 maxlength="170" |  | ||||||
|                 show-word-limit |  | ||||||
|                 v-model="form.content"> |  | ||||||
|               </el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 5" label="网页封面图" prop="pictureUrl" style="width: 100%;" :rules="[{ required: true, message: '请上传封面图', trigger: 'change' }]"> |  | ||||||
|               <ai-uploader :instance="instance" url="/admin/file/add3?type=image" v-model="form.pictureUrl" :limit="1"></ai-uploader> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 2" label="小程序标题" style="width: 100%;" prop="title" :rules="[{ required: true, message: '请输入小程序标题', trigger: 'blur' }]"> |  | ||||||
|               <el-input |  | ||||||
|                 size="small" |  | ||||||
|                 placeholder="请输入小程序标题" |  | ||||||
|                 maxlength="20" |  | ||||||
|                 show-word-limit |  | ||||||
|                 v-model="form.title"> |  | ||||||
|               </el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 2" label="小程序appid" style="width: 100%;" prop="appId" :rules="[{ required: true, message: '小程序appid', trigger: 'blur' }]"> |  | ||||||
|               <el-input |  | ||||||
|                 size="small" |  | ||||||
|                 placeholder="小程序appid" |  | ||||||
|                 v-model="form.appId"> |  | ||||||
|               </el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 2" label="小程序路径" style="width: 100%;" prop="pagePath" :rules="[{ required: true, message: '请输入小程序路径', trigger: 'blur' }]"> |  | ||||||
|               <el-input |  | ||||||
|                 size="small" |  | ||||||
|                 placeholder="请输入小程序page路径" |  | ||||||
|                 v-model="form.pagePath"> |  | ||||||
|               </el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item v-if="currIndex === 2" label="小程序封面图" prop="pictureUrl" style="width: 100%;" :rules="[{ required: true, message: '请上传封面图', trigger: 'change' }]"> |  | ||||||
|               <ai-uploader :instance="instance" url="/admin/file/add3?type=image" v-model="form.pictureUrl" :limit="1"></ai-uploader> |  | ||||||
|             </el-form-item> |  | ||||||
|           </div> |  | ||||||
|         </el-form> |  | ||||||
|       </ai-dialog> |  | ||||||
|     </template> |  | ||||||
|   </ai-list> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   export default { |  | ||||||
|     name: 'List', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data() { |  | ||||||
|       return { |  | ||||||
|         search: { |  | ||||||
|           current: 1, |  | ||||||
|           size: 10, |  | ||||||
|           title: '', |  | ||||||
|         }, |  | ||||||
|         isShow: false, |  | ||||||
|         form: { |  | ||||||
|           appId: '', |  | ||||||
|           content: '', |  | ||||||
|           fileUrl: [], |  | ||||||
|           pagePath: '', |  | ||||||
|           pictureUrl: [], |  | ||||||
|           title: '' |  | ||||||
|         }, |  | ||||||
|         id: '', |  | ||||||
|         typeList: ['话术', '图片', '小程序', '文件', '视频', '网页'], |  | ||||||
|         currIndex: 0, |  | ||||||
|         tableData: [], |  | ||||||
|         total: 0 |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     computed: { |  | ||||||
|       mpTitle () { |  | ||||||
|         return { |  | ||||||
|           '0': '话术标题', |  | ||||||
|           '1': '图片名称', |  | ||||||
|           '2': '小程序标题', |  | ||||||
|           '3': '文件名称', |  | ||||||
|           '4': '视频名称', |  | ||||||
|           '5': '网页名称' |  | ||||||
|         }[this.currIndex] |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       colConfigs () { |  | ||||||
|         if (this.currIndex === 0) { |  | ||||||
|           return [ |  | ||||||
|             { prop: 'title', label: this.mpTitle }, |  | ||||||
|             { prop: 'content', label: '话术内容', align: 'center' }, |  | ||||||
|             { prop: 'createUserName', label: '添加人', align: 'center' }, |  | ||||||
|             { prop: 'createTime', label: '添加时间', align: 'center' } |  | ||||||
|           ] |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (this.currIndex === 2) { |  | ||||||
|           return [ |  | ||||||
|             { prop: 'title', label: this.mpTitle }, |  | ||||||
|             { prop: 'appId', label: '小程序APPID', align: 'center' }, |  | ||||||
|             { prop: 'createUserName', label: '添加人', align: 'center' }, |  | ||||||
|             { prop: 'createTime', label: '添加时间', align: 'center' } |  | ||||||
|           ] |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (this.currIndex === 5) { |  | ||||||
|           return [ |  | ||||||
|             { prop: 'title', label: this.mpTitle }, |  | ||||||
|             { prop: 'pagePath', label: '外链网页', align: 'center' }, |  | ||||||
|             { prop: 'createUserName', label: '添加人', align: 'center' }, |  | ||||||
|             { prop: 'createTime', label: '添加时间', align: 'center' } |  | ||||||
|           ] |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return [ |  | ||||||
|           { prop: 'title', label: this.mpTitle }, |  | ||||||
|           { prop: 'fileSizeStr', label: '文件大小', align: 'center' }, |  | ||||||
|           { prop: 'createUserName', label: '添加人', align: 'center' }, |  | ||||||
|           { prop: 'createTime', label: '添加时间', align: 'center' } |  | ||||||
|         ] |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     created () { |  | ||||||
|       this.getList() |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       getList() { |  | ||||||
|         this.instance.post(`/app/appmaterialinfo/list`, null, { |  | ||||||
|           params: { |  | ||||||
|             ...this.search, |  | ||||||
|             type: this.currIndex |  | ||||||
|           } |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.tableData = res.data.records |  | ||||||
|             this.total = res.data.total |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       toAdd (e) { |  | ||||||
|         this.form = { |  | ||||||
|           ...this.form, |  | ||||||
|           ...e, |  | ||||||
|           fileUrl: e.fileUrl ? [{ |  | ||||||
|             url: e.fileUrl |  | ||||||
|           }] : '', |  | ||||||
|           pictureUrl: e.pictureUrl ? [{ |  | ||||||
|             url: e.pictureUrl |  | ||||||
|           }] : '' |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         this.isShow = true |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       onClose () { |  | ||||||
|         this.form.content = '' |  | ||||||
|         this.form.appId = '' |  | ||||||
|         this.form.fileUrl = [] |  | ||||||
|         this.form.pagePath = '' |  | ||||||
|         this.form.pictureUrl = [] |  | ||||||
|         this.form.title = '' |  | ||||||
|  |  | ||||||
|         this.id = '' |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       confirm () { |  | ||||||
|         this.$refs.form.validate((valid) => { |  | ||||||
|           if (valid) { |  | ||||||
|             this.instance.post(`/app/appmaterialinfo/addOrUpdate`, { |  | ||||||
|               ...this.form, |  | ||||||
|               type: this.currIndex, |  | ||||||
|               fileUrl: this.form.fileUrl.length ? this.form.fileUrl[0].url : '', |  | ||||||
|               fileId: this.form.fileUrl.length ? this.form.fileUrl[0].id : '', |  | ||||||
|               pictureId: this.form.pictureUrl.length ? this.form.pictureUrl[0].id : '', |  | ||||||
|               pictureUrl: this.form.pictureUrl.length ? this.form.pictureUrl[0].url : '', |  | ||||||
|               fileSize: this.form.fileUrl.length ? this.form.fileUrl[0].fileSize : '', |  | ||||||
|             }).then(res => { |  | ||||||
|               if (res.code == 0) { |  | ||||||
|                 this.$message.success('提交成功') |  | ||||||
|                 this.isShow = false |  | ||||||
|  |  | ||||||
|                 this.getList() |  | ||||||
|               } |  | ||||||
|             }) |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       remove (id) { |  | ||||||
|         this.$confirm('确定删除该数据?').then(() => { |  | ||||||
|           this.instance.post(`/app/appmaterialinfo/delete?ids=${id}`).then(res => { |  | ||||||
|             if (res.code == 0) { |  | ||||||
|               this.$message.success('删除成功!') |  | ||||||
|               this.getList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         }) |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
|   #AppMaterialLibrary { |  | ||||||
|     :deep( .ai-list__content--right-wrapper ) { |  | ||||||
|       padding: 0 20px!important; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .AppMaterialLibrary-title { |  | ||||||
|       display: flex; |  | ||||||
|       align-items: center; |  | ||||||
|       margin-bottom: 20px; |  | ||||||
|       border-bottom: 1px solid #eee; |  | ||||||
|  |  | ||||||
|       span { |  | ||||||
|         height: 100%; |  | ||||||
|         line-height: 56px; |  | ||||||
|         margin-right: 32px; |  | ||||||
|         color: #888888; |  | ||||||
|         font-size: 16px; |  | ||||||
|         font-weight: 600; |  | ||||||
|         transition: all ease 0.3s; |  | ||||||
|         border-bottom: 3px solid transparent; |  | ||||||
|         cursor: pointer; |  | ||||||
|         user-select: none; |  | ||||||
|  |  | ||||||
|         &:hover { |  | ||||||
|           color: #222; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         &:last-child { |  | ||||||
|           margin-right: 0; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         &.active { |  | ||||||
|           color: #222222; |  | ||||||
|           border-bottom: 3px solid #2266FF; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -1,617 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <section style="height: 100%;"> |  | ||||||
|     <ai-list> |  | ||||||
|       <template slot="title"> |  | ||||||
|         <ai-title title="话术库" :isShowBottomBorder="true"></ai-title> |  | ||||||
|       </template> |  | ||||||
|       <template #left> |  | ||||||
|         <div class="left-tree"> |  | ||||||
|           <div class="tree-title"> |  | ||||||
|             <label>分组</label> |  | ||||||
|             <el-button icon="iconfont iconAdd" style="height: 28px;line-height: 0;" @click="groupDialog = true">添加分组 |  | ||||||
|             </el-button> |  | ||||||
|           </div> |  | ||||||
|           <el-scrollbar style="height: calc(100% - 40px)"> |  | ||||||
|             <el-menu style="height: 100%;" default-active="0" active-text-color="#26f" text-color="#222" |  | ||||||
|                      mode="vertical"> |  | ||||||
|               <el-menu-item v-for="(item, index) in sortList" :key="index" class="menu-item" @click="currentMenu(item)" |  | ||||||
|                             :index="index.toString()"> |  | ||||||
|                 <label class="item-title">{{ item.name }}</label> |  | ||||||
|                 <el-popover style="width: 30px" placement="left" trigger="click"> |  | ||||||
|                   <div style="display: flex;flex-direction: column;align-items: center;"> |  | ||||||
|                     <div style="cursor: pointer;" @click="editGroup(item, index)">编辑</div> |  | ||||||
|                     <div style="cursor: pointer;" @click="delteGroup(item, index)">删除</div> |  | ||||||
|                   </div> |  | ||||||
|                   <span class="iconfont iconMore" slot="reference"></span> |  | ||||||
|                 </el-popover> |  | ||||||
|               </el-menu-item> |  | ||||||
|             </el-menu> |  | ||||||
|           </el-scrollbar> |  | ||||||
|         </div> |  | ||||||
|       </template> |  | ||||||
|       <template slot="content"> |  | ||||||
|         <ai-search-bar> |  | ||||||
|           <template slot="left"> |  | ||||||
|             <el-select v-model="search.contentType" placeholder="类型" size="small" clearable @change="getList()"> |  | ||||||
|               <el-option v-for="(item, index) in types" :key="index" :label="item.name" :value="item.value"></el-option> |  | ||||||
|             </el-select> |  | ||||||
|           </template> |  | ||||||
|           <template slot="right"> |  | ||||||
|             <el-input v-model="search.title" class="search-input" size="small" |  | ||||||
|                       @keyup.enter.native=";(search.current = 1), getList()" placeholder="请输入标题或话术内容或创建人" clearable |  | ||||||
|                       @clear=";(search.current = 1), (search.title = ''), getList()" suffix-icon="iconfont iconSearch"/> |  | ||||||
|           </template> |  | ||||||
|         </ai-search-bar> |  | ||||||
|         <ai-search-bar> |  | ||||||
|           <template slot="left"> |  | ||||||
|             <el-button icon="iconfont iconAdd" type="primary" @click="add">添加话术</el-button> |  | ||||||
|           </template> |  | ||||||
|         </ai-search-bar> |  | ||||||
|         <ai-table :tableData="tableData" :col-configs="colConfigs" :stripe="true" :total="total" ref="aitableex" |  | ||||||
|                   style="margin-top: 8px;" :current.sync="search.current" :size.sync="search.size" @getList="getList">\ |  | ||||||
|  |  | ||||||
|           <el-table-column slot="content" label="话术内容" align="left" width="280"> |  | ||||||
|             <template slot-scope="{ row }"> |  | ||||||
|               <div class="table-left__wrapper"> |  | ||||||
|                 <video :src="row.file && row.file.url" v-if="row.file && row.contentType == 'video'" |  | ||||||
|                        class="media"></video> |  | ||||||
|                 <img :src="row.file && row.file.url" v-if="row.file && row.contentType == 'image'" class="media"/> |  | ||||||
|                 <audio :src="row.file && row.file.url" v-if="row.file && row.contentType == 'voice'" |  | ||||||
|                        class="media"></audio> |  | ||||||
|                 <div class="table-left__wrapper--right"> |  | ||||||
|                   <el-tooltip class="item" effect="dark" :content="row.content" placement="top"> |  | ||||||
|                     <div class="table-left__wrapper--text" v-if="row.contentType == 'text'">{{ row.content }}</div> |  | ||||||
|                   </el-tooltip> |  | ||||||
|                   <div class="ellipsis" v-if="row.contentType !== 'text' && row.file && row.file.name">{{ row.file.name }}</div> |  | ||||||
|                   <div v-if="row.contentType !== 'text' && row.file && row.file.size">{{ row.file.size | size }}KB</div> |  | ||||||
|                 </div> |  | ||||||
|               </div> |  | ||||||
|             </template> |  | ||||||
|           </el-table-column> |  | ||||||
|  |  | ||||||
|  |  | ||||||
|           <el-table-column slot="options" label="操作" width="160px" align="center" fixed="right"> |  | ||||||
|             <template slot-scope="{ row }"> |  | ||||||
|               <span class="table-btn" title="编辑" @click="editTrick(row)">编辑</span> |  | ||||||
|               <span class="table-btn" title="删除" @click="deleteTrick(row)">删除</span> |  | ||||||
|             </template> |  | ||||||
|           </el-table-column> |  | ||||||
|         </ai-table> |  | ||||||
|       </template> |  | ||||||
|     </ai-list> |  | ||||||
|     <ai-dialog :visible.sync="groupDialog" @closed="sortForm = {},sortForm.type=1" width="800px" title="添加分组" |  | ||||||
|                @onConfirm="onConfirm"> |  | ||||||
|       <el-form size="small" label-width="100px" ref="groupForm" :model="sortForm" :rules="sortRules"> |  | ||||||
|         <el-form-item label="分组名称" prop="name"> |  | ||||||
|           <el-input clearable v-model.trim="sortForm.name" placeholder="请输入..." :maxlength="10" show-word-limit/> |  | ||||||
|         </el-form-item> |  | ||||||
|         <!--        <el-form-item label="可见范围" prop="type">--> |  | ||||||
|         <!--          <el-radio-group v-model="sortForm.type">--> |  | ||||||
|         <!--            <el-radio label="0">个人话术</el-radio>--> |  | ||||||
|         <!--            <el-radio label="1">公共话术</el-radio>--> |  | ||||||
|         <!--          </el-radio-group>--> |  | ||||||
|         <!--        </el-form-item>--> |  | ||||||
|         <!--        <el-form-item label="可用部门" prop="documentName">--> |  | ||||||
|         <!--          <el-row type="flex">--> |  | ||||||
|         <!--            <div class="input"></div>--> |  | ||||||
|         <!--            <ai-person-select :instance="instance" url="/app/appvillagecadres/list" :isMultiple="true"--> |  | ||||||
|         <!--                              btnText="选择" dialogTitle="选择">--> |  | ||||||
|         <!--              <template name="option" v-slot:option="{ item }">--> |  | ||||||
|         <!--                <span class="iconfont iconProlife">{{ item.name }}</span>--> |  | ||||||
|         <!--                <ai-id mode="show" :show-eyes="false" :value="item.idNumber"/>--> |  | ||||||
|         <!--              </template>--> |  | ||||||
|         <!--            </ai-person-select>--> |  | ||||||
|         <!--          </el-row>--> |  | ||||||
|         <!--        </el-form-item>--> |  | ||||||
|       </el-form> |  | ||||||
|     </ai-dialog> |  | ||||||
|  |  | ||||||
|     <ai-dialog :visible.sync="trickDialog" @close="onClose" @onConfirm="trickConfirm" width="800px" title="添加话术"> |  | ||||||
|       <el-form size="small" label-width="100px" ref="trickFom" :model="trickForm" :rules="trickRules"> |  | ||||||
|         <!--        <el-form-item label="分组" prop="handleResult">--> |  | ||||||
|         <!--          <ai-select--> |  | ||||||
|         <!--            v-model="search.type"--> |  | ||||||
|         <!--            @change="search.current = 1, getList()"--> |  | ||||||
|         <!--            placeholder="类型"--> |  | ||||||
|         <!--            :selectList="sortList"--> |  | ||||||
|         <!--          ></ai-select>--> |  | ||||||
|         <!--        </el-form-item>--> |  | ||||||
|         <el-form-item label="标题" prop="title"> |  | ||||||
|           <el-input clearable placeholder="请输入..." v-model="trickForm.title" show-word-limit :maxlength="20"/> |  | ||||||
|         </el-form-item> |  | ||||||
|         <el-form-item label="话术类型" prop="contentType"> |  | ||||||
|           <el-radio-group v-model="trickForm.contentType" @change="onChange"> |  | ||||||
|             <el-radio :label="item.value" v-for="(item, index) in types" :key="index">{{ item.name }}</el-radio> |  | ||||||
|           </el-radio-group> |  | ||||||
|         </el-form-item> |  | ||||||
|         <el-form-item label="文本内容" class="el-form-item__textarea" prop="content" v-if="trickForm.contentType == 'text'"> |  | ||||||
|           <span @click="insertNickname" class="el-form-item__btn" type="text">[插入用户昵称]</span> |  | ||||||
|           <span @click="insertRemark" class="el-form-item__remark" type="text">[插入备注名]</span> |  | ||||||
|           <el-input type="textarea" v-model="trickForm.content" placeholder="请输入..." :rows="5" show-word-limit |  | ||||||
|                     :maxlength="255"/> |  | ||||||
|         </el-form-item> |  | ||||||
|         <el-form-item :label="compLabel" prop="fileId" v-else> |  | ||||||
|           <ai-uploader :instance="instance" v-model="fileList" :acceptType="acceptType" |  | ||||||
|                        :url="'/app/wxcp/upload/uploadFile?type=' + trickForm.contentType" isWechat :fileType="fileType" |  | ||||||
|                        :limit="1" @change="change"></ai-uploader> |  | ||||||
|         </el-form-item> |  | ||||||
|       </el-form> |  | ||||||
|     </ai-dialog> |  | ||||||
|   </section> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
| import {mapState} from 'vuex' |  | ||||||
|  |  | ||||||
| export default { |  | ||||||
|   name: 'AppVerbalTrick', |  | ||||||
|   label: '话术库', |  | ||||||
|   props: { |  | ||||||
|     instance: Function, |  | ||||||
|     dict: Object, |  | ||||||
|     permissions: Function, |  | ||||||
|   }, |  | ||||||
|   data() { |  | ||||||
|     return { |  | ||||||
|       groupDialog: false, |  | ||||||
|       trickDialog: false, |  | ||||||
|       search: { |  | ||||||
|         current: 1, |  | ||||||
|         size: 10, |  | ||||||
|         contentType: '', |  | ||||||
|       }, |  | ||||||
|       sortForm: { |  | ||||||
|         name: '', |  | ||||||
|         type: '1', |  | ||||||
|       }, |  | ||||||
|       trickForm: { |  | ||||||
|         title: '', |  | ||||||
|         contentType: 'text', |  | ||||||
|         content: '', |  | ||||||
|         fileId: '', |  | ||||||
|         mediaId: '', |  | ||||||
|       }, |  | ||||||
|       row: {}, |  | ||||||
|       current: {}, |  | ||||||
|       sortList: [], |  | ||||||
|       total: 0, |  | ||||||
|       tableData: [], |  | ||||||
|       fileList: [], |  | ||||||
|     } |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   computed: { |  | ||||||
|     ...mapState(['user']), |  | ||||||
|     acceptType() { |  | ||||||
|       return { |  | ||||||
|         "image": ".jpg,.png,.jpeg", |  | ||||||
|         "video": ".mp4" |  | ||||||
|       }[this.trickForm.contentType] |  | ||||||
|     }, |  | ||||||
|     compLabel() { |  | ||||||
|       return this.types.find((e) => e.value == this.trickForm.contentType)?.name |  | ||||||
|     }, |  | ||||||
|     fileType() { |  | ||||||
|       return this.trickForm.contentType == 'image' ? 'img' : 'file' |  | ||||||
|     }, |  | ||||||
|     types() { |  | ||||||
|       return [ |  | ||||||
|         {name: '文本', value: 'text'}, |  | ||||||
|         {name: '图片', value: 'image'}, |  | ||||||
|         {name: '视频', value: 'video'}, |  | ||||||
|         // // {name: "附件", value: "file"}, |  | ||||||
|         // {name: "音频", value: "voice"}, |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|     trickRules() { |  | ||||||
|       return { |  | ||||||
|         title: [{required: true, message: '请输入标题', trigger: 'blur'}], |  | ||||||
|         contentType: [{required: true, message: '请选择话术类型', trigger: 'change'}], |  | ||||||
|         content: [{required: true, validator: (rule, value, callback)=>{ |  | ||||||
|             if(this.trickForm.contentType == 'text' && !value){ |  | ||||||
|               return callback("请输入文本内容") |  | ||||||
|             }else { |  | ||||||
|               callback() |  | ||||||
|             } |  | ||||||
|           }}], |  | ||||||
|         fileId: [{required: true, validator: (rule, value, callback)=>{ |  | ||||||
|             if(this.trickForm.contentType != 'text' && !value){ |  | ||||||
|               return callback("请上传文件") |  | ||||||
|             }else { |  | ||||||
|               callback() |  | ||||||
|             } |  | ||||||
|           }}], |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     // message() { |  | ||||||
|     //   return (() => { |  | ||||||
|     //     if (this.trickForm.contentType == 'text') { |  | ||||||
|     //       return '请输入文本内容' |  | ||||||
|     //     } else if (this.trickForm.contentType == 'image') { |  | ||||||
|     //       return '请上传图片' |  | ||||||
|     //     } else if (this.trickForm.contentType == 'file') { |  | ||||||
|     //       return '请上传文件' |  | ||||||
|     //     } else if (this.trickForm.contentType == 'video') { |  | ||||||
|     //       return '请上传视频' |  | ||||||
|     //     } else if (this.trickForm.contentType == 'voice') { |  | ||||||
|     //       return '请上传音频' |  | ||||||
|     //     } |  | ||||||
|     //   })() |  | ||||||
|     // }, |  | ||||||
|     sortRules() { |  | ||||||
|       return { |  | ||||||
|         name: [{required: true, message: '请输入分组名称', trigger: 'blur'}], |  | ||||||
|         type: [{required: true, message: '请选择可见范围', trigger: 'change'}], |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     colConfigs() { |  | ||||||
|       return [ |  | ||||||
|         {slot: 'type'}, |  | ||||||
|         {slot: 'content'}, |  | ||||||
|         {prop: 'title', label: '标题'}, |  | ||||||
|         { |  | ||||||
|           prop: 'contentType', |  | ||||||
|           label: '类型', |  | ||||||
|           align: 'center', |  | ||||||
|           render: (h, {row}) => { |  | ||||||
|             return h('span', {}, this.types.find((e) => row.contentType == e.value)?.name) |  | ||||||
|           }, |  | ||||||
|         }, |  | ||||||
|         {prop: 'userName', label: '创建人', align: 'center'}, |  | ||||||
|         {prop: 'createTime', label: '创建时间', align: 'center'}, |  | ||||||
|         {slot: 'options', label: '操作', align: 'center'}, |  | ||||||
|       ] |  | ||||||
|     }, |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   created() { |  | ||||||
|     this.getSortList() |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   filters: { |  | ||||||
|     size(size) { |  | ||||||
|       return (size / 1024).toFixed(1) |  | ||||||
|     }, |  | ||||||
|   }, |  | ||||||
|  |  | ||||||
|   methods: { |  | ||||||
|     insertNickname() { |  | ||||||
|       this.trickForm.content += '[用户昵称]' |  | ||||||
|     }, |  | ||||||
|     insertRemark() { |  | ||||||
|       this.trickForm.content += '[备注名]' |  | ||||||
|     }, |  | ||||||
|     onClose() { |  | ||||||
|       this.trickForm.title = '' |  | ||||||
|       this.trickForm.content = '' |  | ||||||
|       this.trickForm.fileId = '' |  | ||||||
|       this.trickForm.mediaId = '' |  | ||||||
|       this.trickForm.createdAt = '' |  | ||||||
|       this.trickForm.contentType = 'text' |  | ||||||
|       this.fileList = [] |  | ||||||
|     }, |  | ||||||
|     onChange() { |  | ||||||
|       this.trickForm.fileId = '' |  | ||||||
|       this.trickForm.content = '' |  | ||||||
|       this.trickForm.mediaId = '' |  | ||||||
|       this.trickForm.createdAt = '' |  | ||||||
|       this.fileList = [] |  | ||||||
|     }, |  | ||||||
|     add() { |  | ||||||
|       if (this.sortList.length == 0) return this.$message.error('请先添加分组') |  | ||||||
|       this.$nextTick(() => { |  | ||||||
|         this.trickDialog = true |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     change(e) { |  | ||||||
|       if(e.length){ |  | ||||||
|         this.trickForm.fileId = e[0].id |  | ||||||
|         this.trickForm.mediaId = e[0].media.mediaId |  | ||||||
|         this.trickForm.createdAt = e[0].media.createdAt |  | ||||||
|       }else { |  | ||||||
|         this.trickForm.fileId ="" |  | ||||||
|         this.trickForm.mediaId = "" |  | ||||||
|         this.trickForm.createdAt = "" |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|     editTrick(row) { |  | ||||||
|       this.row = row |  | ||||||
|       this.trickForm = {...row} |  | ||||||
|       row.file && (this.trickForm.fileId = row.file.id) |  | ||||||
|       this.$nextTick(() => { |  | ||||||
|         this.trickDialog = true |  | ||||||
|       }) |  | ||||||
|       this.fileList.push(row.file) |  | ||||||
|     }, |  | ||||||
|     deleteTrick(row) { |  | ||||||
|       this.$confirm('确认要删除吗?').then(() => { |  | ||||||
|         this.instance |  | ||||||
|         .post(`/app/wxcp/wxspeechtechnique/delete`, null, { |  | ||||||
|           params: { |  | ||||||
|             id: row.id, |  | ||||||
|           }, |  | ||||||
|         }) |  | ||||||
|         .then((res) => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.$message.success('删除成功') |  | ||||||
|             this.getList() |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     trickConfirm() { |  | ||||||
|       this.$refs['trickFom'].validate((valid) => { |  | ||||||
|         if (valid) { |  | ||||||
|           this.instance |  | ||||||
|           .post(`/app/wxcp/wxspeechtechnique/addOrUpdate`, { |  | ||||||
|             ...this.trickForm, |  | ||||||
|             category: this.current.id, |  | ||||||
|             userId: this.user.info.id, |  | ||||||
|           }) |  | ||||||
|           .then((res) => { |  | ||||||
|             if (res.code == 0) { |  | ||||||
|               this.trickDialog = false |  | ||||||
|               this.$message.success(this.trickForm.id ? '编辑成功' : '添加成功') |  | ||||||
|               this.getList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     currentMenu(item) { |  | ||||||
|       this.current = item |  | ||||||
|       this.getList() |  | ||||||
|     }, |  | ||||||
|     delteGroup(item, index) { |  | ||||||
|       this.$confirm('是否要删除?').then(() => { |  | ||||||
|         this.instance |  | ||||||
|         .post(`/app/wxcp/wxspeechtechniquecategory/delete`, null, { |  | ||||||
|           params: { |  | ||||||
|             id: item.id, |  | ||||||
|           }, |  | ||||||
|         }) |  | ||||||
|         .then((res) => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.$message.success('删除成功') |  | ||||||
|             this.getSortList() |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     editGroup(item, index) { |  | ||||||
|       this.sortForm = {...item} |  | ||||||
|       this.groupDialog = true |  | ||||||
|     }, |  | ||||||
|     onConfirm() { |  | ||||||
|       this.$refs['groupForm'].validate((valid) => { |  | ||||||
|         if (valid) { |  | ||||||
|           this.instance |  | ||||||
|           .post(`/app/wxcp/wxspeechtechniquecategory/addOrUpdate`, { |  | ||||||
|             ...this.sortForm, |  | ||||||
|           }) |  | ||||||
|           .then((res) => { |  | ||||||
|             if (res.code == 0) { |  | ||||||
|               this.groupDialog = false |  | ||||||
|               this.$message.success(this.sortForm.id ? '编辑成功' : '添加成功') |  | ||||||
|               this.getSortList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     getSortList() { |  | ||||||
|       this.instance |  | ||||||
|       .post(`/app/wxcp/wxspeechtechniquecategory/listAll`, null, { |  | ||||||
|         params: { |  | ||||||
|           // type: 1, |  | ||||||
|         }, |  | ||||||
|       }) |  | ||||||
|       .then((res) => { |  | ||||||
|         if (res && res.data.length) { |  | ||||||
|           this.sortList = res.data |  | ||||||
|           this.current = res.data[0] |  | ||||||
|           this.getList() |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|     getList(item) { |  | ||||||
|       this.instance |  | ||||||
|       .post(`/app/wxcp/wxspeechtechnique/list`, null, { |  | ||||||
|         params: { |  | ||||||
|           category: this.current.id, |  | ||||||
|           ...this.search, |  | ||||||
|           status: 1, |  | ||||||
|         }, |  | ||||||
|       }) |  | ||||||
|       .then((res) => { |  | ||||||
|         if (res.code == 0) { |  | ||||||
|           this.tableData = res.data.records |  | ||||||
|           this.total = res.data.total |  | ||||||
|         } |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|   }, |  | ||||||
| } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .left-tree { |  | ||||||
|   width: 264px; |  | ||||||
|   background: #fafafb; |  | ||||||
|   box-shadow: -1px 0px 0px 0px #e5e5e5; |  | ||||||
|   border-radius: 2px 0px 0px 2px; |  | ||||||
|  |  | ||||||
|   .tree-title { |  | ||||||
|     height: 40px; |  | ||||||
|     box-sizing: border-box; |  | ||||||
|     padding: 0 8px 0 16px; |  | ||||||
|     background: #eeeff1; |  | ||||||
|     display: flex; |  | ||||||
|     align-items: center; |  | ||||||
|     justify-content: space-between; |  | ||||||
|  |  | ||||||
|     & > label { |  | ||||||
|       font-size: 14px; |  | ||||||
|       font-weight: bold; |  | ||||||
|       color: #222222; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .tree-item { |  | ||||||
|     box-sizing: border-box; |  | ||||||
|     padding: 8px 16px 8px 24px; |  | ||||||
|     height: 40px; |  | ||||||
|     display: flex; |  | ||||||
|     align-items: center; |  | ||||||
|     justify-content: space-between; |  | ||||||
|     border-right: 2px solid transparent; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .menu-item { |  | ||||||
|     height: 40px; |  | ||||||
|     align-items: center; |  | ||||||
|     display: flex; |  | ||||||
|     justify-content: space-between; |  | ||||||
|  |  | ||||||
|     .item-title { |  | ||||||
|       display: inline-block; |  | ||||||
|       width: 160px; |  | ||||||
|       overflow: hidden; |  | ||||||
|       text-overflow: ellipsis; |  | ||||||
|       white-space: nowrap; |  | ||||||
|       font-size: 14px; |  | ||||||
|       color: #222222; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .iconMore { |  | ||||||
|       cursor: pointer; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   :deep( .el-scrollbar__wrap ){ |  | ||||||
|     overflow-x: hidden; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| :deep( .ai-list__content--right ){ |  | ||||||
|  |  | ||||||
|   .ai-list__content--right-wrapper { |  | ||||||
|     min-height: 100%; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| :deep( .has-gutter tr ){ |  | ||||||
|   height: 40px; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| :deep( .el-table__row td ){ |  | ||||||
|   height: 68px; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| // :deep( .el-table__row td .cell ){ |  | ||||||
| //   width: 240px; |  | ||||||
| //   height: 44px; |  | ||||||
| // } |  | ||||||
|  |  | ||||||
| .table-btn { |  | ||||||
|   font-size: 14px; |  | ||||||
|   color: #2266ff; |  | ||||||
|   cursor: pointer; |  | ||||||
|  |  | ||||||
|   &:nth-child(1) { |  | ||||||
|     margin-right: 16px; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .input { |  | ||||||
|   width: 100%; |  | ||||||
|   min-height: 32px; |  | ||||||
|   line-height: 32px; |  | ||||||
|   border-radius: 4px; |  | ||||||
|   border: 1px solid #d0d4dc; |  | ||||||
|   color: #666; |  | ||||||
|   display: inline-block; |  | ||||||
|   font-size: inherit; |  | ||||||
|   cursor: pointer; |  | ||||||
|  |  | ||||||
|   &:after { |  | ||||||
|     content: '请选择...'; |  | ||||||
|     color: #888888; |  | ||||||
|     padding-left: 10px; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| :deep( .media ){ |  | ||||||
|   object-fit: fill; |  | ||||||
|   width: 40px; |  | ||||||
|   height: 40px; |  | ||||||
|   vertical-align: middle; |  | ||||||
|   box-sizing: content-box; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| :deep( .AiPersonSelect ){ |  | ||||||
|   & > button { |  | ||||||
|     background: #f5f5f5; |  | ||||||
|     border-radius: 0px 2px 2px 0px; |  | ||||||
|     border: 1px solid #d0d4dc; |  | ||||||
|     color: #222222; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| :deep( .is-active ){ |  | ||||||
|   border-right: 2px solid #2266ff; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
|  |  | ||||||
| <style scoped lang="scss"> |  | ||||||
| .el-popper { |  | ||||||
|   min-width: 76px !important; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .table-left__wrapper { |  | ||||||
|   display: flex; |  | ||||||
|   align-items: center; |  | ||||||
|  |  | ||||||
|   .table-left__wrapper--text { |  | ||||||
|     display: -webkit-box; |  | ||||||
|     -webkit-box-orient: vertical; |  | ||||||
|     -webkit-line-clamp: 2; |  | ||||||
|     overflow: hidden; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .ellipsis { |  | ||||||
|     width: 170px; |  | ||||||
|     height: 24px; |  | ||||||
|     overflow: hidden; |  | ||||||
|     text-overflow: ellipsis; |  | ||||||
|     white-space: nowrap; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   img, |  | ||||||
|   video { |  | ||||||
|     margin-right: 8px; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .el-form-item__textarea { |  | ||||||
|   position: relative; |  | ||||||
|  |  | ||||||
|   .el-form-item__btn, .el-form-item__remark { |  | ||||||
|     position: absolute; |  | ||||||
|     bottom: 12px; |  | ||||||
|     left: 12px; |  | ||||||
|     line-height: 1; |  | ||||||
|     z-index: 1; |  | ||||||
|     color: #2266FF; |  | ||||||
|     font-size: 14px; |  | ||||||
|     user-select: none; |  | ||||||
|     background: #fff; |  | ||||||
|     cursor: pointer; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .el-form-item__remark { |  | ||||||
|     left: 108px; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
| @@ -1,66 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <div class="doc-circulation ailist-wrapper"> |  | ||||||
|     <keep-alive :include="['List']"> |  | ||||||
|       <component ref="component" :is="component" @change="onChange" :params="params" :instance="instance" :dict="dict"></component> |  | ||||||
|     </keep-alive> |  | ||||||
|   </div> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   import List from './components/List' |  | ||||||
|   import Add from './components/Add' |  | ||||||
|  |  | ||||||
|   export default { |  | ||||||
|     name: 'AppVillageCode', |  | ||||||
|     label: '一村一码', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data () { |  | ||||||
|       return { |  | ||||||
|         component: 'List', |  | ||||||
|         params: {}, |  | ||||||
|         include: [] |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     components: { |  | ||||||
|       Add, |  | ||||||
|       List |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     mounted () { |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       onChange (data) { |  | ||||||
|         if (data.type === 'Add') { |  | ||||||
|           this.component = 'Add' |  | ||||||
|           this.params = data.params |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (data.type === 'list') { |  | ||||||
|           this.component = 'List' |  | ||||||
|           this.params = data.params |  | ||||||
|  |  | ||||||
|           this.$nextTick(() => { |  | ||||||
|             if (data.isRefresh) { |  | ||||||
|               this.$refs.component.getList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss"> |  | ||||||
|   .doc-circulation { |  | ||||||
|     height: 100%; |  | ||||||
|     background: #F3F6F9; |  | ||||||
|     overflow: auto; |  | ||||||
|   } |  | ||||||
| </style> |  | ||||||
| @@ -1,119 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <ai-detail> |  | ||||||
|     <template slot="title"> |  | ||||||
|       <ai-title title="添加二维码" isShowBack isShowBottomBorder @onBackClick="cancel(false)"> |  | ||||||
|       </ai-title> |  | ||||||
|     </template> |  | ||||||
|     <template slot="content"> |  | ||||||
|       <ai-card title="基本信息"> |  | ||||||
|         <template #content> |  | ||||||
|           <el-form class="ai-form" ref="form" :model="form" label-width="110px" label-position="right"> |  | ||||||
|             <el-form-item label="地区" style="width: 100%;" prop="codeName"> |  | ||||||
|               <span style="color: #666;">{{ form.areaName }}</span> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="二维码名称" prop="codeName" :rules="[{ required: true, message: '请输入二维码名称', trigger: 'blur' }]"> |  | ||||||
|               <el-input size="small" maxlength="30" show-word-limit placeholder="请输入二维码名称" style="width: 328px;" v-model="form.codeName"></el-input> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item style="width: 100%;" label="二维码类型" prop="type" :rules="[{ required: true, message: '请选择二维码类型', trigger: 'change' }]"> |  | ||||||
|               <el-radio-group v-model="form.type"> |  | ||||||
|                 <el-radio label="0">群二维码</el-radio> |  | ||||||
|                 <el-radio label="1">个人二维码</el-radio> |  | ||||||
|               </el-radio-group> |  | ||||||
|             </el-form-item> |  | ||||||
|             <el-form-item label="上传二维码" prop="codeUrl" style="width: 100%;" :rules="[{ required: true, message: '请上传二维码', trigger: 'change' }]"> |  | ||||||
|               <ai-uploader :instance="instance" v-model="form.codeUrl" :limit="1"></ai-uploader> |  | ||||||
|             </el-form-item> |  | ||||||
|           </el-form> |  | ||||||
|         </template> |  | ||||||
|       </ai-card> |  | ||||||
|     </template> |  | ||||||
|     <template #footer> |  | ||||||
|       <el-button @click="cancel">取消</el-button> |  | ||||||
|       <el-button type="primary" @click="confirm">提交</el-button> |  | ||||||
|     </template> |  | ||||||
|   </ai-detail> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   export default { |  | ||||||
|     name: 'Add', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object, |  | ||||||
|       params: Object |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data () { |  | ||||||
|       return { |  | ||||||
|         info: {}, |  | ||||||
|         form: { |  | ||||||
|           areaId: '', |  | ||||||
|           codeName: '', |  | ||||||
|           areaName: '', |  | ||||||
|           code: '', |  | ||||||
|           codeUrl: [], |  | ||||||
|           type: '', |  | ||||||
|         }, |  | ||||||
|         id: '' |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     created () { |  | ||||||
|       if (this.params && this.params.areaId && !this.params.id) { |  | ||||||
|         this.form.areaId = this.params.areaId |  | ||||||
|         this.form.areaName = this.params.areaName |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       if (this.params && this.params.id) { |  | ||||||
|         this.id = this.params.id |  | ||||||
|         this.getInfo(this.params.id) |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       getInfo (id) { |  | ||||||
|         this.instance.post(`/app/appeveryvillagecode/queryDetailById?id=${id}`).then(res => { |  | ||||||
|           if (res.code === 0) { |  | ||||||
|             this.form = res.data |  | ||||||
|             this.form.codeUrl = [{ |  | ||||||
|               url: res.data.codeUrl |  | ||||||
|             }] |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       onClose () { |  | ||||||
|         this.form.explain = '' |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       confirm () { |  | ||||||
|         this.$refs.form.validate((valid) => { |  | ||||||
|           if (valid) { |  | ||||||
|             this.instance.post(`/app/appeveryvillagecode/addOrUpdate`, { |  | ||||||
|               ...this.form, |  | ||||||
|               codeUrl: this.form.codeUrl[0].url |  | ||||||
|             }).then(res => { |  | ||||||
|               if (res.code == 0) { |  | ||||||
|                 this.$message.success('提交成功') |  | ||||||
|                 setTimeout(() => { |  | ||||||
|                   this.cancel(true) |  | ||||||
|                 }, 600) |  | ||||||
|               } |  | ||||||
|             }) |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       cancel (isRefresh) { |  | ||||||
|         this.$emit('change', { |  | ||||||
|           type: 'list', |  | ||||||
|           isRefresh: !!isRefresh |  | ||||||
|         }) |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style scoped lang="scss"> |  | ||||||
| </style> |  | ||||||
| @@ -1,413 +0,0 @@ | |||||||
| <template> |  | ||||||
|   <ai-list class="villagecode"> |  | ||||||
|     <template slot="title"> |  | ||||||
|       <ai-title title="一村一码" isShowBottomBorder></ai-title> |  | ||||||
|     </template> |  | ||||||
|     <template #left> |  | ||||||
|       <div class="villagecode-left"> |  | ||||||
|         <div class="villagecode-left__title"> |  | ||||||
|           <h2>村列表</h2> |  | ||||||
|         </div> |  | ||||||
|         <div class="addressBook-left__list"> |  | ||||||
|           <div class="addressBook-left__list--title"> |  | ||||||
|             <el-input |  | ||||||
|               class="addressBook-left__list--search" |  | ||||||
|               size="mini" |  | ||||||
|               clearable |  | ||||||
|               placeholder="请输入地区名称" |  | ||||||
|               v-model="unitName" |  | ||||||
|               suffix-icon="iconfont iconSearch"> |  | ||||||
|             </el-input> |  | ||||||
|           </div> |  | ||||||
|           <el-tree |  | ||||||
|             :filter-node-method="filterNode" |  | ||||||
|             ref="tree" |  | ||||||
|             :props="defaultProps" |  | ||||||
|             node-key="id" |  | ||||||
|             :data="areaTree" |  | ||||||
|             highlight-current |  | ||||||
|             :current-node-key="search.areaId" |  | ||||||
|             :default-expanded-keys="defaultExpanded" |  | ||||||
|             :default-checked-keys="defaultChecked" |  | ||||||
|             @current-change="onTreeChange"> |  | ||||||
|           </el-tree> |  | ||||||
|         </div> |  | ||||||
|       </div> |  | ||||||
|     </template> |  | ||||||
|     <template slot="content"> |  | ||||||
|       <ai-search-bar class="search-bar"> |  | ||||||
|         <template #left> |  | ||||||
|           <el-button size="small" type="primary" :disabled="isShowAdd" icon="iconfont iconAdd" @click="toAdd('')">添加活码</el-button> |  | ||||||
|         </template> |  | ||||||
|       </ai-search-bar> |  | ||||||
|       <ai-table |  | ||||||
|         :tableData="tableData" |  | ||||||
|         :col-configs="colConfigs" |  | ||||||
|         :total="total" |  | ||||||
|         style="margin-top: 6px;" |  | ||||||
|         :current.sync="search.current" |  | ||||||
|         :size.sync="search.size" |  | ||||||
|         @getList="getList"> |  | ||||||
|         <el-table-column slot="tags" label="标签"> |  | ||||||
|           <template slot-scope="{ row }"> |  | ||||||
|             <div class="table-tags"> |  | ||||||
|               <el-tag type="info" v-for="(item, index) in row.tags" size="small" :key="index">{{ item }}</el-tag> |  | ||||||
|             </div> |  | ||||||
|           </template> |  | ||||||
|         </el-table-column> |  | ||||||
|         <el-table-column slot="options" width="180px" fixed="right" label="操作" align="center"> |  | ||||||
|           <template slot-scope="{ row }"> |  | ||||||
|             <div class="table-options"> |  | ||||||
|               <el-popover |  | ||||||
|                   placement="bottom" |  | ||||||
|                   width="160" |  | ||||||
|                   :visible-arrow="false" |  | ||||||
|                   popper-class="wechat-message__container" |  | ||||||
|                   trigger="hover"> |  | ||||||
|                 <el-button type="text" slot="reference">二维码</el-button> |  | ||||||
|                 <div style="font-size: 0;"> |  | ||||||
|                   <img class="message-info__img" :src="row.codeUrl"> |  | ||||||
|                 </div> |  | ||||||
|               </el-popover> |  | ||||||
|               <el-button type="text" @click="toAdd(row.id)">编辑</el-button> |  | ||||||
|               <el-button type="text" @click="remove(row.id)">删除</el-button> |  | ||||||
|             </div> |  | ||||||
|           </template> |  | ||||||
|         </el-table-column> |  | ||||||
|       </ai-table> |  | ||||||
|     </template> |  | ||||||
|   </ai-list> |  | ||||||
| </template> |  | ||||||
|  |  | ||||||
| <script> |  | ||||||
|   import { mapState } from 'vuex' |  | ||||||
|   export default { |  | ||||||
|     name: 'List', |  | ||||||
|  |  | ||||||
|     props: { |  | ||||||
|       instance: Function, |  | ||||||
|       dict: Object |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     data() { |  | ||||||
|       return { |  | ||||||
|         search: { |  | ||||||
|           current: 1, |  | ||||||
|           size: 10, |  | ||||||
|           status: 0, |  | ||||||
|           title: '', |  | ||||||
|           areaId: '' |  | ||||||
|         }, |  | ||||||
|         defaultExpanded: [], |  | ||||||
|         defaultChecked: [], |  | ||||||
|         areaTree: [], |  | ||||||
|         defaultProps: { |  | ||||||
|           children: 'children', |  | ||||||
|           label: 'name' |  | ||||||
|         }, |  | ||||||
|         currIndex: -1, |  | ||||||
|         total: 10, |  | ||||||
|         colConfigs: [ |  | ||||||
|           {prop: 'codeName', label: '名称', align: 'left'}, |  | ||||||
|           {prop: 'type', label: '二维码类型', align: 'left', format: v => v === '0' ? '群二维码' : '个人二维码'}, |  | ||||||
|           {prop: 'createUserName', label: '创建人'}, |  | ||||||
|           {prop: 'createTime', label: '创建时间'}, |  | ||||||
|           {slot: 'options', label: '操作'} |  | ||||||
|         ], |  | ||||||
|         areaName: '', |  | ||||||
|         unitName: '', |  | ||||||
|         tableData: [] |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     computed: { |  | ||||||
|       ...mapState(['user']), |  | ||||||
|  |  | ||||||
|       isShowAdd () { |  | ||||||
|         const str = this.search.areaId.substr(this.search.areaId.length - 3) |  | ||||||
|  |  | ||||||
|         return str === '000' |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     watch: { |  | ||||||
|       unitName (val) { |  | ||||||
|         this.$refs.tree.filter(val) |  | ||||||
|       } |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     mounted() { |  | ||||||
|       this.search.areaId = this.user.info.areaId |  | ||||||
|       this.areaName = this.user.info.areaName |  | ||||||
|       this.getTree() |  | ||||||
|       this.getList() |  | ||||||
|  |  | ||||||
|       this.$nextTick(() => { |  | ||||||
|       }) |  | ||||||
|     }, |  | ||||||
|  |  | ||||||
|     methods: { |  | ||||||
|       getList() { |  | ||||||
|         this.instance.post(`/app/appeveryvillagecode/list`, null, { |  | ||||||
|           params: { |  | ||||||
|             ...this.search |  | ||||||
|           } |  | ||||||
|         }).then(res => { |  | ||||||
|           if (res.code == 0) { |  | ||||||
|             this.tableData = res.data.records |  | ||||||
|             this.total = res.data.total |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       filterNode(value, data) { |  | ||||||
|         if (!value) return true |  | ||||||
|         return data.name.indexOf(value) !== -1 |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       onTreeChange (e) { |  | ||||||
|         this.search.areaId = e.id |  | ||||||
|         this.areaName = e.name |  | ||||||
|         this.search.current = 1 |  | ||||||
|  |  | ||||||
|         this.$nextTick(() => { |  | ||||||
|           this.getList() |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       getTree () { |  | ||||||
|         this.instance.post(`/admin/area/queryAllArea?id=${this.user.info.areaId}`).then(res => { |  | ||||||
|           if (res.code === 0) { |  | ||||||
|             let parent = res.data.map(v => { |  | ||||||
|               v.label = v.name |  | ||||||
|               v.children = [] |  | ||||||
|  |  | ||||||
|               return v |  | ||||||
|             }).filter(e => !e.parentid)[0] |  | ||||||
|             this.defaultExpanded = [parent.id] |  | ||||||
|             this.defaultChecked = [parent.id] |  | ||||||
|             this.search.areaId = parent.id |  | ||||||
|             this.addChild(parent, res.data) |  | ||||||
|             this.areaTree = [parent] |  | ||||||
|  |  | ||||||
|             this.$nextTick(() => { |  | ||||||
|               this.$refs.tree.setCurrentKey(parent.id) |  | ||||||
|             }) |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       addChild (parent, list) { |  | ||||||
|         for (let i = 0; i < list.length; i++) { |  | ||||||
|           if (list[i].parentId === parent.id) { |  | ||||||
|             parent.children.push(list[i]) |  | ||||||
|           } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if (list.length > 0) { |  | ||||||
|           parent['children'].map(v => this.addChild(v, list)) |  | ||||||
|         } |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       remove(id) { |  | ||||||
|         this.$confirm('确定删除该数据?').then(() => { |  | ||||||
|           this.instance.post(`/app/appeveryvillagecode/delete?ids=${id}`).then(res => { |  | ||||||
|             if (res.code == 0) { |  | ||||||
|               this.$message.success('删除成功!') |  | ||||||
|               this.getList() |  | ||||||
|             } |  | ||||||
|           }) |  | ||||||
|         }) |  | ||||||
|       }, |  | ||||||
|  |  | ||||||
|       toAdd(id) { |  | ||||||
|         this.$emit('change', { |  | ||||||
|           type: 'Add', |  | ||||||
|           params: { |  | ||||||
|             areaName: this.areaName, |  | ||||||
|             id: id || '', |  | ||||||
|             areaId: this.search.areaId |  | ||||||
|           } |  | ||||||
|         }) |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| </script> |  | ||||||
|  |  | ||||||
| <style lang="scss" scoped> |  | ||||||
| .villagecode { |  | ||||||
|   .table-tags { |  | ||||||
|     .el-tag { |  | ||||||
|       margin-right: 8px; |  | ||||||
|  |  | ||||||
|       &:last-child { |  | ||||||
|         margin-right: 0; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .addressBook-left__list { |  | ||||||
|     height: calc(100% - 40px); |  | ||||||
|     padding: 8px 8px; |  | ||||||
|     overflow: auto; |  | ||||||
|  |  | ||||||
|     .addressBook-left__tags--item { |  | ||||||
|       display: flex; |  | ||||||
|       align-items: center; |  | ||||||
|       justify-content: space-between; |  | ||||||
|       height: 40px; |  | ||||||
|       padding: 0 8px 0 16px; |  | ||||||
|       color: #222222; |  | ||||||
|  |  | ||||||
|       &.addressBook-left__tags--item-active, &:hover { |  | ||||||
|         background: #E8EFFF; |  | ||||||
|         color: #2266FF; |  | ||||||
|  |  | ||||||
|         i, span { |  | ||||||
|           color: #2266FF; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       span { |  | ||||||
|         font-size: 14px; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       i { |  | ||||||
|         cursor: pointer; |  | ||||||
|         color: #8e9ebf; |  | ||||||
|         font-size: 16px; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .addressBook-left__list--title { |  | ||||||
|       display: flex; |  | ||||||
|       align-items: center; |  | ||||||
|       margin-bottom: 8px; |  | ||||||
|  |  | ||||||
|       .addressBook-left__list--search { |  | ||||||
|         flex: 1; |  | ||||||
|         :deep( input ){ |  | ||||||
|           width: 100%; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .el-button { |  | ||||||
|         width: 84px; |  | ||||||
|         flex-shrink: 1; |  | ||||||
|         margin-right: 8px; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     span { |  | ||||||
|       color: #222222; |  | ||||||
|       font-size: 14px; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     :deep( .el-tree ){ |  | ||||||
|       background: transparent; |  | ||||||
|  |  | ||||||
|       .el-tree-node__expand-icon.is-leaf { |  | ||||||
|         color: transparent!important; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .el-tree-node__content > .el-tree-node__expand-icon { |  | ||||||
|         padding: 4px; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .el-tree-node__content { |  | ||||||
|         height: 32px; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .el-tree__empty-text { |  | ||||||
|         color: #222; |  | ||||||
|         font-size: 14px; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .el-tree-node__children .el-tree-node__content { |  | ||||||
|         height: 32px; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .el-tree-node__content:hover { |  | ||||||
|         background: #E8EFFF; |  | ||||||
|         color: #222222; |  | ||||||
|         border-radius: 2px; |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       .is-current > .el-tree-node__content { |  | ||||||
|         &:hover { |  | ||||||
|           background: #2266FF; |  | ||||||
|           color: #fff; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         background: #2266FF; |  | ||||||
|  |  | ||||||
|         span { |  | ||||||
|           color: #fff; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   .villagecode-left { |  | ||||||
|     width: 100%; |  | ||||||
|     height: auto; |  | ||||||
|     background: #FAFAFB; |  | ||||||
|  |  | ||||||
|     .villagecode-left__title { |  | ||||||
|       display: flex; |  | ||||||
|       align-items: center; |  | ||||||
|       height: 40px; |  | ||||||
|       padding: 0 16px; |  | ||||||
|       background: #E5E5E5; |  | ||||||
|  |  | ||||||
|       h2 { |  | ||||||
|         color: #222; |  | ||||||
|         font-size: 14px; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     .villagecode-left__list { |  | ||||||
|       height: calc(100% - 40px); |  | ||||||
|       padding: 8px 0; |  | ||||||
|       overflow: auto; |  | ||||||
|  |  | ||||||
|       span { |  | ||||||
|         display: block; |  | ||||||
|         height: 40px; |  | ||||||
|         line-height: 40px; |  | ||||||
|         padding: 0 24px; |  | ||||||
|         color: #222222; |  | ||||||
|         font-size: 14px; |  | ||||||
|         cursor: pointer; |  | ||||||
|         border-right: 2px solid transparent; |  | ||||||
|         background: transparent; |  | ||||||
|  |  | ||||||
|         &:hover { |  | ||||||
|           color: #2266FF; |  | ||||||
|           background: #E8EFFF; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         &.left-active { |  | ||||||
|           color: #2266FF; |  | ||||||
|           border-color: #2266FF; |  | ||||||
|           background: #E8EFFF; |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   :deep( .ai-list__content--right ){ |  | ||||||
|  |  | ||||||
|     .ai-list__content--right-wrapper { |  | ||||||
|       min-height: 100%; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
|  |  | ||||||
| } |  | ||||||
|  |  | ||||||
| .message-info__img { |  | ||||||
|   font-size: 0; |  | ||||||
|   width: 144px; |  | ||||||
|   height: 144px; |  | ||||||
| } |  | ||||||
| </style> |  | ||||||
							
								
								
									
										70
									
								
								src/App.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								src/App.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | |||||||
|  | <template> | ||||||
|  |   <div id="app" :class="{greyFilter,[`theme-${$theme}`]:true}"> | ||||||
|  |     <router-view/> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import {mapState} from "vuex"; | ||||||
|  | import customConfig from "./config.json"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: 'app', | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['sys']), | ||||||
|  |     greyFilter: v => v.sys?.theme?.enableGreyFilter == 1, | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     initFavicon(icon) { | ||||||
|  |       const linkList = document.head.querySelectorAll('link') || {}, | ||||||
|  |           url = `${this.$cdn}/favicon/${icon || "favicon"}.ico` | ||||||
|  |       if (Object.values(linkList).findIndex(e => e.href == url) == -1) { | ||||||
|  |         let favicon = document.createElement("link") | ||||||
|  |         favicon.rel = "icon" | ||||||
|  |         favicon.href = url | ||||||
|  |         document.head.appendChild(favicon) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.initFavicon(customConfig.sysInfo?.favicon) | ||||||
|  |     document.title = this.sys.info.fullTitle | ||||||
|  |     customConfig?.hmt && this.$injectLib("https://hm.baidu.com/hm.js?4e5dd7c5512e5da68c025c3b956fbd5d") | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss"> | ||||||
|  | html, body { | ||||||
|  |   height: 100%; | ||||||
|  |   width: 100%; | ||||||
|  |   padding: 0; | ||||||
|  |   margin: 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, fieldset, input, p, blockquote, th, td { | ||||||
|  |   margin: 0; | ||||||
|  |   padding: 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #app { | ||||||
|  |   font-family: Helvetica, Arial, sans-serif; | ||||||
|  |   -webkit-font-smoothing: antialiased; | ||||||
|  |   -moz-osx-font-smoothing: grayscale; | ||||||
|  |   overflow: hidden; | ||||||
|  |   width: 100%; | ||||||
|  |   height: 100%; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | li { | ||||||
|  |   list-style-type: none; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .greyFilter { | ||||||
|  |   filter: grayscale(100%); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .amap-logo, .amap-copyright { | ||||||
|  |   display: none !important; | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										
											BIN
										
									
								
								src/assets/bg_prolife.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/assets/bg_prolife.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 94 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/building.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/assets/building.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 22 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/loginLeft.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/assets/loginLeft.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 616 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/loginRightBottom.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/assets/loginRightBottom.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 23 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/loginRightTop.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/assets/loginRightTop.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 15 KiB | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/nav_bg.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/assets/nav_bg.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 75 KiB | 
							
								
								
									
										125
									
								
								src/components/AiAreaPicker.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								src/components/AiAreaPicker.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="AiAreaPicker"> | ||||||
|  |     <div @click="handleOpenDialog"> | ||||||
|  |       <slot v-if="$scopedSlots.default" :selected="selected"/> | ||||||
|  |       <el-button v-else type="text">选择地区</el-button> | ||||||
|  |     </div> | ||||||
|  |     <ai-dialog :visible.sync="dialog" title="选择地区" @onConfirm="submit" @close="selecting=[],init()" destroy-on-close> | ||||||
|  |       <el-breadcrumb separator-class="el-icon-arrow-right"> | ||||||
|  |         <el-breadcrumb-item v-for="(item,i) in path" :key="item.id"> | ||||||
|  |           <el-button type="text" @click.native="handlePathClick(i)">{{ item.name }}</el-button> | ||||||
|  |         </el-breadcrumb-item> | ||||||
|  |       </el-breadcrumb> | ||||||
|  |       <ai-table-select class="mar-t16" v-model="selecting" :instance="instance" :action="action" :isShowPagination="false" extra="hidden" search-key="name" | ||||||
|  |                        multiple valueObj> | ||||||
|  |         <template slot="extra" slot-scope="{row}"> | ||||||
|  |           <el-button v-if="row.id!=root" type="text" icon="el-icon-arrow-right" @click.stop="getChildren(row)"/> | ||||||
|  |         </template> | ||||||
|  |       </ai-table-select> | ||||||
|  |     </ai-dialog> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "AiAreaPicker", | ||||||
|  |   model: { | ||||||
|  |     prop: "value", | ||||||
|  |     event: "change" | ||||||
|  |   }, | ||||||
|  |   props: { | ||||||
|  |     value: {default: ""}, | ||||||
|  |     meta: {default: null}, | ||||||
|  |     root: {default: ""}, | ||||||
|  |     instance: {type: Function, required: true}, | ||||||
|  |     multiple: Boolean | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     action() { | ||||||
|  |       let currentParent = this.path.slice(-1)?.[0]?.id | ||||||
|  |       return !!currentParent && /[^0]0{0,2}$/.test(currentParent) ? `/admin/appresident/queryAreaIdGroup?currentAreaId=${currentParent}` : | ||||||
|  |           `/admin/area/queryAreaByParentIdSelf?self=${currentParent == this.root ? 1 : ''}&id=${currentParent}` | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   watch: { | ||||||
|  |     value(v) { | ||||||
|  |       this.dispatch('ElFormItem', 'el.form.change', [v]); | ||||||
|  |     }, | ||||||
|  |     selected(v) { | ||||||
|  |       this.$emit("update:meta", v) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       dialog: false, | ||||||
|  |       options: [], | ||||||
|  |       selecting: [], | ||||||
|  |       path: [], | ||||||
|  |       selected: [] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     dispatch(componentName, eventName, params) { | ||||||
|  |       let parent = this.$parent || this.$root; | ||||||
|  |       let name = parent.$options.componentName; | ||||||
|  |       while (parent && (!name || name !== componentName)) { | ||||||
|  |         parent = parent.$parent; | ||||||
|  |         if (parent) { | ||||||
|  |           name = parent.$options.componentName; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       if (parent) { | ||||||
|  |         parent.$emit.apply(parent, [eventName].concat(params)); | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     getChildren(row) { | ||||||
|  |       let area = this.path.find(e => e.id == row.id) | ||||||
|  |       if (!area) this.path.push(row) | ||||||
|  |     }, | ||||||
|  |     handlePathClick(index) { | ||||||
|  |       this.path.splice(index + 1, 10) | ||||||
|  |     }, | ||||||
|  |     submit() { | ||||||
|  |       this.$emit("change", this.selecting.map(e => e.id)) | ||||||
|  |       this.selected = this.$copy(this.selecting) | ||||||
|  |       this.$emit("select", this.selecting) | ||||||
|  |       this.dialog = false | ||||||
|  |     }, | ||||||
|  |     init() { | ||||||
|  |       this.path = [{id: this.root, name: "可选范围"}] | ||||||
|  |     }, | ||||||
|  |     handleOpenDialog() { | ||||||
|  |       let areas = this.value.filter(e => /^\d{12}$/.test(e)) | ||||||
|  |       this.instance.post("/admin/area/getAreaNameByids", null, { | ||||||
|  |         params: {ids: areas?.toString()} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.selecting = this.value.map(id => ({id, name: res.data?.[id] || id})) | ||||||
|  |           this.dialog = true | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     getAreaById(id) { | ||||||
|  |       return this.instance.post("/admin/area/queryAreaByAreaid", null, { | ||||||
|  |         params: {id} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           return res.data | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.init() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .AiAreaPicker { | ||||||
|  |   .mar-t16 { | ||||||
|  |     margin-top: 16px; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
| @@ -1,7 +1,6 @@ | |||||||
| <template> | <template> | ||||||
|   <section class="AppLicence"> |   <section class="AppLicence" v-if="showLicence"> | ||||||
|     <ai-list> |     <ai-list> | ||||||
|       <ai-title slot="title" title="产品许可" isShowBottomBorder  :instance="instance"></ai-title> |  | ||||||
|       <template #content> |       <template #content> | ||||||
|         <div class="licence-content"> |         <div class="licence-content"> | ||||||
|           <img class="left-img" src="https://cdn.cunwuyun.cn/dvcp/key.png" alt="" /> |           <img class="left-img" src="https://cdn.cunwuyun.cn/dvcp/key.png" alt="" /> | ||||||
| @@ -30,13 +29,14 @@ | |||||||
|               <span class="value">{{info.ip}}</span> |               <span class="value">{{info.ip}}</span> | ||||||
|             </div> |             </div> | ||||||
|             <el-upload |             <el-upload | ||||||
|               class="upload-demo" |               class="upload-demo mar-r16" | ||||||
|               action |               action | ||||||
|               multiple |               multiple | ||||||
|               accept=".lic" |               accept=".lic" | ||||||
|               :http-request="uploadFile"> |               :http-request="uploadFile"> | ||||||
|               <div class="btn">上传许可</div> |               <div class="btn">上传许可</div> | ||||||
|             </el-upload> |             </el-upload> | ||||||
|  |             <div class="btn" @click="showLicence = false">返回登录</div> | ||||||
|           </div> |           </div> | ||||||
|         </div> |         </div> | ||||||
|       </template> |       </template> | ||||||
| @@ -50,19 +50,25 @@ export default { | |||||||
|   label: "产品许可", |   label: "产品许可", | ||||||
|   props: { |   props: { | ||||||
|     instance: Function, |     instance: Function, | ||||||
|     dict: Object, |  | ||||||
|     permissions: Function |  | ||||||
|   }, |   }, | ||||||
|   data() { |   data() { | ||||||
|     return { |     return { | ||||||
|       files: [], |       files: [], | ||||||
|       info: {} |       info: {}, | ||||||
|  |       showLicence: false | ||||||
|     } |     } | ||||||
|   }, |   }, | ||||||
|   mounted() { |   mounted() { | ||||||
|     this.getDetail() | 
 | ||||||
|   }, |   }, | ||||||
|   methods: { |   methods: { | ||||||
|  |     show() { | ||||||
|  |       this.showLicence = true | ||||||
|  |       this.getDetail() | ||||||
|  |     }, | ||||||
|  |     hide() { | ||||||
|  |       this.showLicence = false | ||||||
|  |     }, | ||||||
|     getDetail() { |     getDetail() { | ||||||
|       this.instance.post(`/admin/license/detail`).then(res => { |       this.instance.post(`/admin/license/detail`).then(res => { | ||||||
|         if (res?.data) { |         if (res?.data) { | ||||||
| @@ -78,7 +84,9 @@ export default { | |||||||
|           this.$message.success("证书上传成功!"); |           this.$message.success("证书上传成功!"); | ||||||
|           this.getDetail() |           this.getDetail() | ||||||
|         } |         } | ||||||
|       }); |       }).catch((err) => { | ||||||
|  |         this.$message.error(err); | ||||||
|  |       }) | ||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
| 
 | 
 | ||||||
| @@ -88,6 +96,10 @@ export default { | |||||||
| .AppLicence { | .AppLicence { | ||||||
|   width: 100%; |   width: 100%; | ||||||
|   height: 100%; |   height: 100%; | ||||||
|  |   position: fixed; | ||||||
|  |   top: 0; | ||||||
|  |   left: 0; | ||||||
|  |   z-index: 99; | ||||||
|   :deep( .ai-list){ |   :deep( .ai-list){ | ||||||
|     background-color: #F5F6F9; |     background-color: #F5F6F9; | ||||||
|   } |   } | ||||||
| @@ -102,7 +114,8 @@ export default { | |||||||
|   } |   } | ||||||
|   .licence-content{ |   .licence-content{ | ||||||
|     display: flex; |     display: flex; | ||||||
|     margin-top: 30px; |     width: 1000px; | ||||||
|  |     margin: 200px auto 0; | ||||||
|     .left-img{ |     .left-img{ | ||||||
|       width: 200px; |       width: 200px; | ||||||
|       height: 200px; |       height: 200px; | ||||||
| @@ -111,7 +124,6 @@ export default { | |||||||
|       width: 800px; |       width: 800px; | ||||||
|       .title{ |       .title{ | ||||||
|         font-size: 24px; |         font-size: 24px; | ||||||
|         font-family: MicrosoftYaHei-Bold, MicrosoftYaHei; |  | ||||||
|         font-weight: bold; |         font-weight: bold; | ||||||
|         color: #222; |         color: #222; | ||||||
|         line-height: 24px; |         line-height: 24px; | ||||||
| @@ -119,14 +131,12 @@ export default { | |||||||
|       } |       } | ||||||
|       .mini-title{ |       .mini-title{ | ||||||
|         font-size: 14px; |         font-size: 14px; | ||||||
|         font-family: MicrosoftYaHei; |  | ||||||
|         color: #555; |         color: #555; | ||||||
|         line-height: 22px; |         line-height: 22px; | ||||||
|         margin-bottom: 20px; |         margin-bottom: 20px; | ||||||
|       } |       } | ||||||
|       .info{ |       .info{ | ||||||
|         font-size: 14px; |         font-size: 14px; | ||||||
|         font-family: MicrosoftYaHei; |  | ||||||
|         line-height: 22px; |         line-height: 22px; | ||||||
|         margin-bottom: 8px; |         margin-bottom: 8px; | ||||||
|         display: flex; |         display: flex; | ||||||
| @@ -147,7 +157,11 @@ export default { | |||||||
|       .mar-b32{ |       .mar-b32{ | ||||||
|         margin-bottom: 32px; |         margin-bottom: 32px; | ||||||
|       } |       } | ||||||
|  |       .upload-demo{ | ||||||
|  |         display: inline-block; | ||||||
|  |       } | ||||||
|       .btn{ |       .btn{ | ||||||
|  |         display: inline-block; | ||||||
|         width: 88px; |         width: 88px; | ||||||
|         height: 32px; |         height: 32px; | ||||||
|         line-height: 32px; |         line-height: 32px; | ||||||
| @@ -158,6 +172,9 @@ export default { | |||||||
|         color: #fff; |         color: #fff; | ||||||
|         font-size: 14px; |         font-size: 14px; | ||||||
|       } |       } | ||||||
|  |       .mar-r16{ | ||||||
|  |         margin-right: 16px; | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
							
								
								
									
										255
									
								
								src/components/headerNav.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								src/components/headerNav.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,255 @@ | |||||||
|  | <template> | ||||||
|  |   <div class="headerNav navBg"> | ||||||
|  |     <div style="position: relative"> | ||||||
|  |       <ai-icon type="logo" :icon="system.logo||'iconcunwei'"/> | ||||||
|  |       <ai-icon type="logo" :icon="system.logo||'iconcunwei'" class="textShadow"/> | ||||||
|  |     </div> | ||||||
|  |     <span class="headerTitle">{{ system.fullTitle }}<div class="textShadow" v-html="system.fullTitle"/></span> | ||||||
|  |     <el-row type="flex" align="middle" class="toolbar"> | ||||||
|  |       <!--下载中心--> | ||||||
|  |       <downloan-center-btn v-if="extra.downloadCenter"/> | ||||||
|  |       <!--大屏按钮--> | ||||||
|  |       <dv-btn v-if="extra.dv"/> | ||||||
|  |       <div class="btn" v-if="extra.showTool" @click="home.showTool=false">隐藏工具栏</div> | ||||||
|  |       <div class="btn" v-if="extra.helpDoc" @click="openHelp">帮助文档</div> | ||||||
|  |       <app-qrcode v-if="extra.appQRCode"/> | ||||||
|  |       <div class="btn" v-if="extra.customerService" @click.native="openAiService"> | ||||||
|  |         <div class="iconfont iconCustomer_Service"></div> | ||||||
|  |         <div>智能客服</div> | ||||||
|  |       </div> | ||||||
|  |       <!--推荐链接--> | ||||||
|  |       <link-btn/> | ||||||
|  |     </el-row> | ||||||
|  |     <el-dropdown @visible-change="v=>isClick=v" @command="doMenu" class="rightDropdown"> | ||||||
|  |       <el-row type="flex" align="middle"> | ||||||
|  |         <el-avatar :src="user.info.avatar"> | ||||||
|  |           {{ defaultAvatar }} | ||||||
|  |         </el-avatar> | ||||||
|  |         <span>{{ [user.info.name, user.info.roleName].join(" - ") }}</span> | ||||||
|  |         <i :class="dropdownIcon"/> | ||||||
|  |       </el-row> | ||||||
|  |       <el-dropdown-menu> | ||||||
|  |         <el-dropdown-item command="user">用户中心</el-dropdown-item> | ||||||
|  |         <el-dropdown-item command="signOut">退出</el-dropdown-item> | ||||||
|  |       </el-dropdown-menu> | ||||||
|  |     </el-dropdown> | ||||||
|  |   </div> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import {mapState} from "vuex"; | ||||||
|  | import DvBtn from "./headerTools/dvBtn"; | ||||||
|  | import DownloanCenterBtn from "./headerTools/downloanCenterBtn"; | ||||||
|  | import extra from "../config.json" | ||||||
|  | import AppQrcode from "./headerTools/appQrcode"; | ||||||
|  | import LinkBtn from "./headerTools/linkBtn"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: 'headerNav', | ||||||
|  |   components: {LinkBtn, AppQrcode, DownloanCenterBtn, DvBtn}, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       extra, | ||||||
|  |       isClick: false, | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['user', 'sys']), | ||||||
|  |     dropdownIcon() { | ||||||
|  |       return this.isClick ? 'el-icon-caret-top' : 'el-icon-caret-bottom' | ||||||
|  |     }, | ||||||
|  |     defaultAvatar() { | ||||||
|  |       return this.user.info.name?.slice(-2) || "游客" | ||||||
|  |     }, | ||||||
|  |     system: v => v.sys?.info || {} | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.$dict.load('fileFrom'); | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     // 获取最新的安卓、ios下载二维码 | ||||||
|  |     doMenu(comm) { | ||||||
|  |       switch (comm) { | ||||||
|  |         case 'signOut': | ||||||
|  |           //登出 | ||||||
|  |           this.$confirm("是否要登出?", {type: "warning"}).then(() => { | ||||||
|  |             this.$store.commit("signOut") | ||||||
|  |           }).catch(() => { | ||||||
|  |           }) | ||||||
|  |           break; | ||||||
|  |         case 'user': | ||||||
|  |           this.$router.push({name: "个人中心"}) | ||||||
|  |           break; | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     openAiService() { | ||||||
|  |       window.open('http://v3.faqrobot.org/robot/chat1.html?sysNum=153543696570625098') | ||||||
|  |     }, | ||||||
|  |     openHelp() { | ||||||
|  |       window.open('https://www.yuque.com/books/share/eeaaa5e3-a528-42eb-872e-20d661f3d0e2') | ||||||
|  |     }, | ||||||
|  |     changeStatus(id) { | ||||||
|  |       this.$request.post(`/app/sysuserdownload/addOrUpdate`, { | ||||||
|  |         id, status: "2" | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.code == 0) { | ||||||
|  |           this.getFiles(); | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |       }); | ||||||
|  |     }, | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .headerNav { | ||||||
|  |   display: flex; | ||||||
|  |   align-items: center; | ||||||
|  |   width: 100%; | ||||||
|  |   background-repeat: no-repeat; | ||||||
|  |   background-size: 100% 48px; | ||||||
|  |   position: fixed; | ||||||
|  |   z-index: 99; | ||||||
|  |   height: 48px; | ||||||
|  |   padding-left: 24px; | ||||||
|  |   box-sizing: border-box; | ||||||
|  |   top: 0; | ||||||
|  |   color: white; | ||||||
|  |   font-size: 14px; | ||||||
|  |  | ||||||
|  |   .AiIcon { | ||||||
|  |     font-size: 38px; | ||||||
|  |     width: auto; | ||||||
|  |     height: auto; | ||||||
|  |     background: linear-gradient(180deg, #FFFFFF 0%, #CCDBF6 100%); | ||||||
|  |     -webkit-background-clip: text; | ||||||
|  |     -webkit-text-fill-color: transparent; | ||||||
|  |  | ||||||
|  |     &:hover { | ||||||
|  |       color: white; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .headerTitle { | ||||||
|  |     flex: 1; | ||||||
|  |     min-width: 0; | ||||||
|  |     font-size: 24px; | ||||||
|  |     color: #FFF; | ||||||
|  |     line-height: 28px; | ||||||
|  |     background: linear-gradient(180deg, #FFFFFF 0%, #CCDBF6 100%); | ||||||
|  |     -webkit-background-clip: text; | ||||||
|  |     -webkit-text-fill-color: transparent; | ||||||
|  |     font-weight: bold; | ||||||
|  |     margin-left: 8px; | ||||||
|  |     position: relative; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   :deep(.toolbar) { | ||||||
|  |     gap: 12px; | ||||||
|  |     margin-right: 32px; | ||||||
|  |  | ||||||
|  |     .btn { | ||||||
|  |       padding: 0 12px; | ||||||
|  |       color: white; | ||||||
|  |  | ||||||
|  |       &:hover { | ||||||
|  |         cursor: pointer; | ||||||
|  |         color: rgba(#fff, .8); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .el-dropdown { | ||||||
|  |     height: 48px; | ||||||
|  |     line-height: 48px; | ||||||
|  |     color: #fff; | ||||||
|  |     padding: 0 12px; | ||||||
|  |  | ||||||
|  |     &:hover { | ||||||
|  |       background-color: rgba(46, 51, 68, .15); | ||||||
|  |       color: white; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .el-image { | ||||||
|  |     margin: 12px 0 12px 16px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .download-wrapper { | ||||||
|  |     position: relative; | ||||||
|  |  | ||||||
|  |     &:hover .download { | ||||||
|  |       display: flex; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .download { | ||||||
|  |       display: none; | ||||||
|  |       position: absolute; | ||||||
|  |       top: 100%; | ||||||
|  |       left: 12px; | ||||||
|  |       transform: translateX(-90%); | ||||||
|  |       width: auto; | ||||||
|  |       height: auto; | ||||||
|  |       padding: 12px; | ||||||
|  |       background: #fff; | ||||||
|  |       box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.1); | ||||||
|  |       border-radius: 2px; | ||||||
|  |       box-sizing: border-box; | ||||||
|  |       z-index: 999; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .download-item { | ||||||
|  |       text-align: center; | ||||||
|  |  | ||||||
|  |       &:first-child { | ||||||
|  |         margin-right: 13px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       & > img { | ||||||
|  |         width: 105px; | ||||||
|  |         height: 105px; | ||||||
|  |         margin-bottom: 7px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       p { | ||||||
|  |         margin-top: 5px; | ||||||
|  |         font-size: 13px; | ||||||
|  |         color: #333; | ||||||
|  |         text-align: center; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       .download-item__middle { | ||||||
|  |         img { | ||||||
|  |           width: 13px; | ||||||
|  |           height: 16px; | ||||||
|  |           vertical-align: sub; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         span { | ||||||
|  |           padding-left: 8px; | ||||||
|  |           font-size: 13px; | ||||||
|  |           color: #333; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   :deep(.rightDropdown) { | ||||||
|  |     font-size: 12px; | ||||||
|  |     padding: 0 16px; | ||||||
|  |     height: 48px; | ||||||
|  |     background: rgba(#fff, .1); | ||||||
|  |  | ||||||
|  |     .el-avatar > img { | ||||||
|  |       width: 100%; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .el-row { | ||||||
|  |       gap: 4px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | </style> | ||||||
							
								
								
									
										121
									
								
								src/components/headerTools/appQrcode.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/components/headerTools/appQrcode.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="appQrcode"> | ||||||
|  |     <div class="btn">手机APP</div> | ||||||
|  |     <div class="download"> | ||||||
|  |       <div class="download-item" v-if="!androidQRcode&&!iosQRcode"><p class="nowarp-text" v-text="`暂未发布`"/></div> | ||||||
|  |       <template v-else> | ||||||
|  |         <div class="download-item" v-if='iosQRcode'> | ||||||
|  |           <img :src="iosQRcode" alt=""/> | ||||||
|  |           <div class="download-item__middle"> | ||||||
|  |             <span class="iconfont iconIOS"></span> | ||||||
|  |             <span>iPhone</span> | ||||||
|  |           </div> | ||||||
|  |           <p>手机扫码下载APP</p> | ||||||
|  |         </div> | ||||||
|  |         <div class="download-item" v-if='androidQRcode'> | ||||||
|  |           <img :src="androidQRcode" alt=""/> | ||||||
|  |           <div class="download-item__middle"> | ||||||
|  |             <span class="iconfont iconAndroid"></span> | ||||||
|  |             <span>Android</span> | ||||||
|  |           </div> | ||||||
|  |           <p>手机扫码下载APP</p> | ||||||
|  |         </div> | ||||||
|  |       </template> | ||||||
|  |     </div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: "appQrcode", | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       iosQRcode: null, | ||||||
|  |       androidQRcode: null | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getAppQRcode() { | ||||||
|  |       this.$request.post(`/admin/sysversion/getLatestIosVersion`, null, { | ||||||
|  |         params: {type: 3} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.iosQRcode = res.data.qrCodeUrl | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |  | ||||||
|  |       this.$request.post(`/admin/sysversion/getLatestVersion`, null, { | ||||||
|  |         params: {type: 1} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.androidQRcode = res.data.qrCodeUrl | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.getAppQRcode() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .appQrcode { | ||||||
|  |   position: relative; | ||||||
|  |  | ||||||
|  |   &:hover .download { | ||||||
|  |     display: flex; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .download { | ||||||
|  |     display: none; | ||||||
|  |     position: absolute; | ||||||
|  |     top: 100%; | ||||||
|  |     left: 12px; | ||||||
|  |     transform: translateX(-90%); | ||||||
|  |     width: auto; | ||||||
|  |     height: auto; | ||||||
|  |     padding: 12px; | ||||||
|  |     background: #fff; | ||||||
|  |     box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.1); | ||||||
|  |     border-radius: 2px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     z-index: 999; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .download-item { | ||||||
|  |     text-align: center; | ||||||
|  |  | ||||||
|  |     &:first-child { | ||||||
|  |       margin-right: 13px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     & > img { | ||||||
|  |       width: 105px; | ||||||
|  |       height: 105px; | ||||||
|  |       margin-bottom: 7px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     p { | ||||||
|  |       margin-top: 5px; | ||||||
|  |       font-size: 13px; | ||||||
|  |       color: #333; | ||||||
|  |       text-align: center; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .download-item__middle { | ||||||
|  |       img { | ||||||
|  |         width: 13px; | ||||||
|  |         height: 16px; | ||||||
|  |         vertical-align: sub; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       span { | ||||||
|  |         padding-left: 8px; | ||||||
|  |         font-size: 13px; | ||||||
|  |         color: #333; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										221
									
								
								src/components/headerTools/downloanCenterBtn.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								src/components/headerTools/downloanCenterBtn.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,221 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="downloanCenterBtn"> | ||||||
|  |     <el-badge :value="badgeNum" :hidden='badgeNum==0'> | ||||||
|  |       <div class="btn" @click="openDrawer()">下载中心</div> | ||||||
|  |     </el-badge> | ||||||
|  |     <el-drawer title="下载中心" :visible.sync="drawer" :modal-append-to-body="false" size="520"> | ||||||
|  |       <div class="downLoad_main"> | ||||||
|  |         <div class="search_top "> | ||||||
|  |           <p style="color:#999999;">仅显示最近90天的记录</p> | ||||||
|  |           <el-input size="mini" v-model="fileName" placeholder="文件名" clearable prefix-icon="iconfont iconSearch" | ||||||
|  |                     style="width:240px;" @change="getFiles()"/> | ||||||
|  |         </div> | ||||||
|  |         <ul class="infinite-list"> | ||||||
|  |           <li v-for="(item,i) in filesList" class="infinite-list-item " :key="i"> | ||||||
|  |             <div class="left"> | ||||||
|  |               <svg class="svg" aria-hidden="true"> | ||||||
|  |                 <use xlink:href="#iconZip"/> | ||||||
|  |               </svg> | ||||||
|  |             </div> | ||||||
|  |             <div class="middle"> | ||||||
|  |               <p class="fileName">{{ item.fileName }}【密码:{{ item.pwd }}】</p> | ||||||
|  |               <p> | ||||||
|  |                 <span>来源:</span> | ||||||
|  |                 <span>{{ $dict.getLabel('fileFrom', item.fileFrom) }}</span> | ||||||
|  |                 <span>{{ (item.size / 1000).toFixed(2) + "KB" }}</span> | ||||||
|  |                 <span>{{ item.createTime }}</span> | ||||||
|  |               </p> | ||||||
|  |             </div> | ||||||
|  |             <div class="right"> | ||||||
|  |               <span class="iconfont iconResetting" v-if="item.status==0">处理中</span> | ||||||
|  |               <span v-if="item.status==2">已下载</span> | ||||||
|  |               <i class="iconfont iconDownload" @click="downFile(item)" v-if="item.status!=0">下载</i> | ||||||
|  |             </div> | ||||||
|  |           </li> | ||||||
|  |         </ul> | ||||||
|  |       </div> | ||||||
|  |     </el-drawer> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import {mapState} from "vuex"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "downloanCenterBtn", | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       badgeNum: 0, | ||||||
|  |       drawer: false,//抽屉 | ||||||
|  |       filesList: [], | ||||||
|  |       fileName: '', | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['user']) | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     openDrawer() { | ||||||
|  |       this.drawer = true; | ||||||
|  |       this.getFiles(); | ||||||
|  |     }, | ||||||
|  |     getFiles() { | ||||||
|  |       this.$request.post(`/app/sysuserdownload/list`, null, { | ||||||
|  |         params: { | ||||||
|  |           userId: this.user.info.id, | ||||||
|  |           fileName: this.fileName, | ||||||
|  |           current: 1, | ||||||
|  |           size: 1000, | ||||||
|  |         } | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.filesList = res.data.records; | ||||||
|  |           this.searchNum() | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |     }, | ||||||
|  |     //查询未完成数量 | ||||||
|  |     searchNum() { | ||||||
|  |       this.$request.post(`/app/sysuserdownload/queryCountByUserId`, null, { | ||||||
|  |         params: { | ||||||
|  |           userId: this.user.info.id | ||||||
|  |         } | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.badgeNum = res.data; | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     downFile(item) { | ||||||
|  |       this.changeStatus(item.id); | ||||||
|  |       // window.open(item.accessUrl); | ||||||
|  |       let elemIF = document.createElement('iframe'); | ||||||
|  |       elemIF.src = item.accessUrl; | ||||||
|  |       elemIF.style.display = 'none'; | ||||||
|  |       document.body.appendChild(elemIF); | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.searchNum() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .downloanCenterBtn { | ||||||
|  |   .downLoad_main { | ||||||
|  |     width: 100%; | ||||||
|  |     height: 100%; | ||||||
|  |     padding: 16px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |  | ||||||
|  |     .search_top { | ||||||
|  |       display: flex; | ||||||
|  |       justify-content: space-between; | ||||||
|  |       align-items: center; | ||||||
|  |       padding-bottom: 8px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .infinite-list { | ||||||
|  |       width: 100%; | ||||||
|  |       height: 100%; | ||||||
|  |  | ||||||
|  |       .infinite-list-item { | ||||||
|  |         width: 100%; | ||||||
|  |         padding: 8px; | ||||||
|  |         box-sizing: border-box; | ||||||
|  |         background: rgba(255, 255, 255, 1); | ||||||
|  |         border-radius: 4px; | ||||||
|  |         border: 1px solid rgba(208, 212, 220, 1); | ||||||
|  |         margin-bottom: 8px; | ||||||
|  |         display: flex; | ||||||
|  |         justify-content: space-between; | ||||||
|  |  | ||||||
|  |         .left { | ||||||
|  |           display: flex; | ||||||
|  |           justify-content: center; | ||||||
|  |           align-items: center; | ||||||
|  |           width: 30px; | ||||||
|  |  | ||||||
|  |           .svg { | ||||||
|  |             width: 24px; | ||||||
|  |             height: 24px; | ||||||
|  |             vertical-align: middle; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .middle { | ||||||
|  |           flex: 1; | ||||||
|  |  | ||||||
|  |           .fileName { | ||||||
|  |             color: #333333; | ||||||
|  |             font-size: 14px; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           p:nth-child(2) { | ||||||
|  |             color: #999999; | ||||||
|  |             font-size: 12px; | ||||||
|  |  | ||||||
|  |             span { | ||||||
|  |               padding: 0 4px; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             span:nth-child(2) { | ||||||
|  |               border-right: solid 1px #999999; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             span:nth-child(3) { | ||||||
|  |               border-right: solid 1px #999999; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         .right { | ||||||
|  |           display: flex; | ||||||
|  |           justify-content: center; | ||||||
|  |           align-items: center; | ||||||
|  |           font-size: 12px; | ||||||
|  |           width: 90px; | ||||||
|  |           text-align: center; | ||||||
|  |  | ||||||
|  |           span { | ||||||
|  |             color: #999999; | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           i { | ||||||
|  |             display: block; | ||||||
|  |             width: 50px; | ||||||
|  |             color: #5088FF; | ||||||
|  |             font-size: 12px; | ||||||
|  |             cursor: pointer; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ::-webkit-scrollbar { | ||||||
|  |       width: 4px; | ||||||
|  |       background-color: #eee; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ::-webkit-scrollbar-thumb { | ||||||
|  |       background-color: #8888; | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | :deep(.el-drawer__wrapper) { | ||||||
|  |   position: fixed; | ||||||
|  |   width: 100%; | ||||||
|  |   top: 0; | ||||||
|  |   bottom: 0; | ||||||
|  |   right: 0; | ||||||
|  |  | ||||||
|  |   .el-drawer__header > span:focus { | ||||||
|  |     outline: 0 | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										52
									
								
								src/components/headerTools/dvBtn.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/components/headerTools/dvBtn.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="dvBtn"> | ||||||
|  |     <el-popover title="数据大屏" width="500" trigger="click"> | ||||||
|  |       <div flex class="wrap"> | ||||||
|  |         <div class="el-button--text pad-r8 pad-b8" style="width: 50%" v-for="op in dvOptions" :key="op.id" v-text="op.name||'无名大屏'" | ||||||
|  |              @click="handleOpenDV(op.id)"/> | ||||||
|  |       </div> | ||||||
|  |       <div slot="reference" class="btn">数据大屏</div> | ||||||
|  |     </el-popover> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import extra from "../../config.json" | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "dvBtn", | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       dvOptions: [] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getDvList() { | ||||||
|  |       this.$request.post("/app/appdiylargescreen/allLargeScreenProjectByPage", null, { | ||||||
|  |         params: {size: 9999, status: 1} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.dvOptions = res.data.records | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     handleOpenDV(id) { | ||||||
|  |       window.open(`${location.origin}${extra.base || ""}/dv?id=${id}#dv`) | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.getDvList() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .dvBtn { | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | :deep(.el-button--text) { | ||||||
|  |   cursor: pointer; | ||||||
|  |   user-select: none; | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										46
									
								
								src/components/headerTools/linkBtn.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/components/headerTools/linkBtn.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="linkBtn"> | ||||||
|  |     <el-dropdown v-if="links.length > 0" @command="handleOpenLink"> | ||||||
|  |       <div class="btn">友情链接</div> | ||||||
|  |       <el-dropdown-menu> | ||||||
|  |         <el-dropdown-item v-for="op in links" :key="op.id" :command="op.url"> | ||||||
|  |           {{ op.title }} | ||||||
|  |         </el-dropdown-item> | ||||||
|  |       </el-dropdown-menu> | ||||||
|  |     </el-dropdown> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: "linkBtn", | ||||||
|  |   label: "友情链接", | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       links: [] | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getLinks() { | ||||||
|  |       this.$request.post("/app/appwebnavurl/list", null, { | ||||||
|  |         params: {size: 9999, status: 1} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.links = res.data.records | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |     }, | ||||||
|  |     handleOpenLink(url) { | ||||||
|  |       window.open(url) | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.getLinks() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .linkBtn { | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										40
									
								
								src/components/mainContent.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/components/mainContent.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="mainContent"> | ||||||
|  |     <ai-nav-tab :fixed="homePage" :routes="routes"/> | ||||||
|  |     <router-view v-if="refresh"/> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import {mapState} from "vuex"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "mainContent", | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['user', 'homePage']), | ||||||
|  |     routes: v => v.user.info?.menuSet?.map(e => ({...e, label: e.name, name: e.id})) | ||||||
|  |   }, | ||||||
|  |   watch: { | ||||||
|  |     $route(v, old) { | ||||||
|  |       if (v.meta == old.meta && v.fullPath != old.fullPath) { | ||||||
|  |         this.refresh = false | ||||||
|  |         this.$nextTick(() => this.refresh = true) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       refresh: true | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .mainContent { | ||||||
|  |   height: 100%; | ||||||
|  |   width: 100%; | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										296
									
								
								src/components/sliderNav.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										296
									
								
								src/components/sliderNav.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,296 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="sliderNav"> | ||||||
|  |     <el-input class="searchApp" size="small" v-model="searchApp" placeholder="搜索应用" clearable | ||||||
|  |               prefix-icon="iconfont iconSearch" @change="handleSearchApp"/> | ||||||
|  |     <el-scrollbar class="ai-menu"> | ||||||
|  |       <div v-for="(item,i) in navs" :key="i"> | ||||||
|  |         <div class="rootMenu" :class="{isActive:menuPath.includes(item.id)}" @click.stop="openKidMenu(item)"> | ||||||
|  |           <i :class="item.style||'iconfont iconloudongmoxing'"/> | ||||||
|  |           <span class="fill mar-l8" v-text="item.name"/> | ||||||
|  |           <i v-if="hasChildren(item.children)" class="iconfont mar-l8" :class="arrowIcon(item.showChildren)"/> | ||||||
|  |         </div> | ||||||
|  |         <div class="kidMenu" v-if="hasChildren(item.children)&&item.showChildren" @click.stop> | ||||||
|  |           <div v-for="menu in item.children" :key="menu.id"> | ||||||
|  |             <div class="submenu wrap pad-l16 pad-r16" flex v-if="hasChildren(menu.children)"> | ||||||
|  |               <b v-text="menu.name" :class="{menuBtn:menu.type==1,current:menuPath.includes(menu.id)}" | ||||||
|  |                  @click="handleSelect(menu)"/> | ||||||
|  |               <div class="menuBtn" v-for="kid in menu.children" :key="kid.id" v-text="kid.name" :title="kid.name" | ||||||
|  |                    @click="handleSelect(kid)" :class="{current:menuPath.includes(kid.id)}"/> | ||||||
|  |             </div> | ||||||
|  |             <div v-else class="lv2Btn" v-text="menu.name" @click="handleSelect(menu)" :class="{current:menuPath.includes(menu.id)}"/> | ||||||
|  |           </div> | ||||||
|  |         </div> | ||||||
|  |       </div> | ||||||
|  |       <div class="divider"/> | ||||||
|  |     </el-scrollbar> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import {mapGetters} from "vuex"; | ||||||
|  | import qs from "querystring"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "sliderNav", | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       menuList: [], | ||||||
|  |       searchApp: "", | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     ...mapGetters(['mods']), | ||||||
|  |     navs: v => v.sortList(v.menuList), | ||||||
|  |     menuPath() { | ||||||
|  |       let paths = [], current = this.mods?.find(e => e.route == this.$route.name) | ||||||
|  |       const findParent = id => { | ||||||
|  |         let menu = this.mods?.find(e => e.id == id) | ||||||
|  |         if (menu) { | ||||||
|  |           paths.push(menu.id) | ||||||
|  |           if (!!menu.parentId) findParent(menu.parentId) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       if (current) { | ||||||
|  |         findParent(current.id) | ||||||
|  |       } | ||||||
|  |       return paths | ||||||
|  |     }, | ||||||
|  |     modList: v => v.mods.filter(e => e.isMenu == 1 || e.type == 0 || (e.level > 1 && e.type == 1)) | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     initMenu(menus = this.modList) { | ||||||
|  |       //isMenu 旧版本判断是否为菜单 type<2 新版本判断是否是菜单或应用 | ||||||
|  |       if (menus?.length > 0) { | ||||||
|  |         this.menuList = this.$arr2tree(menus) | ||||||
|  |         this.menuList = this.menuList.map(e => ({ | ||||||
|  |           ...e, | ||||||
|  |           showChildren: this.menuPath.includes(e.id) || !!this.searchApp | ||||||
|  |         })) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     openKidMenu(parent) { | ||||||
|  |       if (this.hasChildren(parent.children)) { | ||||||
|  |         parent.showChildren = !parent.showChildren | ||||||
|  |       } else { | ||||||
|  |         this.handleSelect(parent) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     handleSelect(item) { | ||||||
|  |       if (!item.path) return | ||||||
|  |       if (item.route == this.$route.name) { | ||||||
|  |         //避免同一路由跳转的BUG vue-router官方BUG | ||||||
|  |       } else { | ||||||
|  |         let {route: name, path} = item | ||||||
|  |         if (!name) { | ||||||
|  |           this.$message.warning("暂无应用") | ||||||
|  |         } else { | ||||||
|  |           this.goto({name, query: qs.parse(path.split("?")?.[1])}) | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     goto(item) { | ||||||
|  |       return this.$router.push(item) | ||||||
|  |     }, | ||||||
|  |     sortList(list) { | ||||||
|  |       return list?.sort((a, b) => a.showIndex - b.showIndex) || [] | ||||||
|  |     }, | ||||||
|  |     handleSearchApp() { | ||||||
|  |       let {searchApp} = this | ||||||
|  |       if (searchApp) { | ||||||
|  |         let list = this.modList.filter(e => e.name?.indexOf(searchApp) > -1), map = {} | ||||||
|  |         const findParent = e => { | ||||||
|  |           map[e.id] = e | ||||||
|  |           if (!!e.parentId) { | ||||||
|  |             let parent = this.modList.find(m => m.id == e.parentId) | ||||||
|  |             map[parent.id] = parent | ||||||
|  |             if (!!parent.parentId) { | ||||||
|  |               findParent(parent) | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         list.forEach(e => findParent(e)) | ||||||
|  |         console.log(map, list) | ||||||
|  |         this.initMenu(Object.values(map)) | ||||||
|  |       } else { | ||||||
|  |         this.initMenu() | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     arrowIcon(v) { | ||||||
|  |       return v ? "iconArrow_Down" : "iconArrow_Right" | ||||||
|  |     }, | ||||||
|  |     hasChildren(arr) { | ||||||
|  |       return arr?.length > 0 | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.initMenu() | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .sliderNav { | ||||||
|  |   width: 200px; | ||||||
|  |   height: 100%; | ||||||
|  |   transition: width .1s; | ||||||
|  |   display: flex; | ||||||
|  |   justify-content: space-between; | ||||||
|  |   flex-direction: column; | ||||||
|  |   border-right: 1px solid #e5e5e5; | ||||||
|  |   flex-shrink: 0; | ||||||
|  |   box-sizing: border-box; | ||||||
|  |   background: #EFF1F4; | ||||||
|  |   color: #222; | ||||||
|  |   position: relative; | ||||||
|  |   user-select: none; | ||||||
|  |  | ||||||
|  |   .kidMenu { | ||||||
|  |     font-size: 13px; | ||||||
|  |  | ||||||
|  |     .rootName { | ||||||
|  |       font-size: 20px; | ||||||
|  |       color: #333; | ||||||
|  |       cursor: default; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .submenu { | ||||||
|  |       margin-top: 8px; | ||||||
|  |       width: 100%; | ||||||
|  |       color: #aaa; | ||||||
|  |  | ||||||
|  |       & > b { | ||||||
|  |         width: 100%; | ||||||
|  |         line-height: 28px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       & > * { | ||||||
|  |         cursor: default; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .menuBtn { | ||||||
|  |       display: block; | ||||||
|  |       width: 50%; | ||||||
|  |       cursor: pointer; | ||||||
|  |       line-height: 32px; | ||||||
|  |       color: #333; | ||||||
|  |       flex-shrink: 0; | ||||||
|  |       white-space: nowrap; | ||||||
|  |       overflow: hidden; | ||||||
|  |       text-overflow: ellipsis; | ||||||
|  |  | ||||||
|  |       &.line { | ||||||
|  |         width: 100%; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       &:hover { | ||||||
|  |         color: #26f; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       &.current { | ||||||
|  |         color: #26f; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .rootMenu { | ||||||
|  |     padding: 0 16px; | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     height: 44px; | ||||||
|  |     cursor: pointer; | ||||||
|  |     box-shadow: 0px -1px 0px 0px #D8DCE3 inset, 0px 1px 0px 0px #FFF inset, -1px 0px 0px 0px #E5E5E5 inset; | ||||||
|  |     font-size: 13px; | ||||||
|  |  | ||||||
|  |     .iconfont { | ||||||
|  |       color: #89B; | ||||||
|  |       font-size: 20px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     &.isActive { | ||||||
|  |       color: #26f; | ||||||
|  |  | ||||||
|  |       .iconfont { | ||||||
|  |         color: #26f !important; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     &:hover { | ||||||
|  |       color: #26f; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   :deep(.ai-menu ){ | ||||||
|  |     padding-left: 0; | ||||||
|  |     flex: 1; | ||||||
|  |     min-height: 0; | ||||||
|  |  | ||||||
|  |     .el-scrollbar__wrap { | ||||||
|  |       overflow-x: auto; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     &::-webkit-scrollbar { | ||||||
|  |       display: none; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   :deep(.searchApp ){ | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     height: 44px; | ||||||
|  |     padding: 0 16px; | ||||||
|  |     box-shadow: 0px -1px 0px 0px #E5E5E5 inset; | ||||||
|  |  | ||||||
|  |     .el-input__inner { | ||||||
|  |       border: none; | ||||||
|  |       background: inherit; | ||||||
|  |       padding: 0 28px; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     .el-input__prefix { | ||||||
|  |       left: 16px; | ||||||
|  |  | ||||||
|  |       .iconSearch { | ||||||
|  |         font-size: 20px; | ||||||
|  |         width: fit-content; | ||||||
|  |         color: #89B; | ||||||
|  |         line-height: 44px; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .divider { | ||||||
|  |     color: #aaa; | ||||||
|  |     border-top: 1px solid #ddd; | ||||||
|  |     position: relative; | ||||||
|  |     font-size: 12px; | ||||||
|  |     margin: 16px 16px 32px; | ||||||
|  |  | ||||||
|  |     &:before { | ||||||
|  |       content: "到达底部"; | ||||||
|  |       position: absolute; | ||||||
|  |       top: 50%; | ||||||
|  |       left: 50%; | ||||||
|  |       transform: translate(-50%, -50%); | ||||||
|  |       padding: 0 16px; | ||||||
|  |       background: #EFF1F4; | ||||||
|  |       white-space: nowrap; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .lv2Btn { | ||||||
|  |     height: 44px; | ||||||
|  |     display: flex; | ||||||
|  |     align-items: center; | ||||||
|  |     color: #222; | ||||||
|  |     padding-left: 44px; | ||||||
|  |     cursor: pointer; | ||||||
|  |  | ||||||
|  |     &.current { | ||||||
|  |       background: linear-gradient(90deg, #298BFF 0%, #0C61FF 100%); | ||||||
|  |       box-shadow: inset -1px 0 0 0 #E5E5E5, inset 0 2px 8px 0 #1E4599; | ||||||
|  |       color: #fff; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										33
									
								
								src/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/main.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | import Vue from 'vue'; | ||||||
|  | import App from './App.vue'; | ||||||
|  | import ui from 'element-ui'; | ||||||
|  | import router from './utils/router'; | ||||||
|  | import utils from './utils'; | ||||||
|  | import vcUI from 'dui'; | ||||||
|  | import appComp from '@dui/dv'; | ||||||
|  | import store from './utils/store'; | ||||||
|  | import autoRoutes from "./utils/autoRoutes"; | ||||||
|  | import extra from "./config.json" | ||||||
|  | import axios from "./utils/axios"; | ||||||
|  | //import ob from "dui/lib/js/observer" | ||||||
|  | //备注底座信息,勿删 | ||||||
|  | console.log("欢迎使用%s", extra.sysInfo?.name || "构建版本") | ||||||
|  | //new ob() | ||||||
|  | window.Vue = Vue | ||||||
|  | Vue.use(ui); | ||||||
|  | Vue.use(vcUI); | ||||||
|  | Vue.use(appComp); | ||||||
|  | Vue.config.productionTip = false; | ||||||
|  | Vue.prototype.$cdn = "https://cdn.cunwuyun.cn" | ||||||
|  | Vue.prototype.$request = axios | ||||||
|  | Object.keys(utils).map((e) => (Vue.prototype[e] = utils[e])); | ||||||
|  | const loadPage = () => autoRoutes.init().finally(() => new Vue({router, store, render: h => h(App)}).$mount("#app")) | ||||||
|  | let theme = null | ||||||
|  | store.dispatch('getSystem', extra.sysInfo).then(res => { | ||||||
|  |   theme = JSON.parse(res?.colorScheme || null) | ||||||
|  |   return import(`dui/lib/styles/theme.${theme?.web}.scss`).catch(() => 0) | ||||||
|  | }).finally(() => { | ||||||
|  |   Vue.prototype.$theme = theme?.web || "blue" | ||||||
|  |   !!theme?.web && theme?.web != "blue" ? loadPage() : import(`dui/lib/styles/common.scss`).finally(loadPage) | ||||||
|  | }) | ||||||
|  |  | ||||||
							
								
								
									
										107
									
								
								src/utils/autoRoutes.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								src/utils/autoRoutes.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,107 @@ | |||||||
|  | import {waiting} from "./index"; | ||||||
|  | import router from "./router"; | ||||||
|  | import store from "./store"; | ||||||
|  | import {Message} from "element-ui"; | ||||||
|  | import Vue from "vue"; | ||||||
|  | import extra from "../config.json" | ||||||
|  |  | ||||||
|  | let {state: {user}, commit, dispatch} = store | ||||||
|  | const signOut = () => commit("signOut"), | ||||||
|  |     getUserInfo = () => dispatch("getUserInfo"), | ||||||
|  |     existRoute = route => { | ||||||
|  |       return router.getRoutes()?.find(e => e.name == route?.name || e.path == route?.path) | ||||||
|  |     }, | ||||||
|  |     goto = (route, next) => { | ||||||
|  |       const exist = !!existRoute(route) | ||||||
|  |       return exist ? route.name ? next() : router.replace(route) : | ||||||
|  |           !route.name && route.path == "/" ? router.replace({name: "Home"}).catch(() => 0) : | ||||||
|  |               Message.error("无法找到路由,请联系系统管理员!") | ||||||
|  |     } | ||||||
|  | const loadApps = () => { | ||||||
|  |   //新App的自动化格式 | ||||||
|  |   waiting.init({innerHTML: '应用加载中..'}) | ||||||
|  |   let apps = require.context('../../apps', true, /\.(\/.+)\/App[A-Z][^\/]+\.vue$/, "lazy") | ||||||
|  |   return Promise.all(apps.keys().map(path => apps(path).then(file => { | ||||||
|  |     if (file.default) { | ||||||
|  |       let {name} = file.default | ||||||
|  |       waiting.setContent(`加载${name}...`) | ||||||
|  |       Vue.component(name, file.default) | ||||||
|  |     } else return 0 | ||||||
|  |   }))).then(() => { | ||||||
|  |     waiting.setContent(`正在进入系统...`) | ||||||
|  |     setTimeout(() => waiting.close(), 1000) | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  | const addHome = homePage => { | ||||||
|  |   const component = extra?.homePage || homePage.path | ||||||
|  |   if (extra?.homePage && Vue.component(component)) { | ||||||
|  |     homePage = {...homePage, path: component, component: () => import('../views/mainEntry'), meta: component} | ||||||
|  |   } | ||||||
|  |   router.addRoute('Home', homePage) | ||||||
|  |   router.options.routes[2].children.unshift(homePage) | ||||||
|  |   commit("setHomePage", { | ||||||
|  |     ...homePage, | ||||||
|  |     label: homePage.name, | ||||||
|  |     id: `/v/${component}`, | ||||||
|  |     isMenu: 1, | ||||||
|  |     route: homePage.name, | ||||||
|  |     component, | ||||||
|  |     path: component, | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  | const generateRoutes = (to, from, next) => { | ||||||
|  |   if (router.options.routes[2].children.length > 0) { | ||||||
|  |     goto(to, next) | ||||||
|  |   } else { | ||||||
|  |     Promise.all([getUserInfo(), loadApps()]).then(() => { | ||||||
|  |       //初始化默认工作台 | ||||||
|  |       let homePage = {name: "工作台", path: "console", style: "iconfont iconNav_Dashborad", component: () => import('../views/console')} | ||||||
|  |       addHome(homePage) | ||||||
|  |       const mods = user.info.menuSet?.filter(e => !!e.component)?.map(e => ({route: e.id, ...e})) | ||||||
|  |       mods?.map(({route: name, path, component}) => { | ||||||
|  |         if (!!Vue.component(component) && path && !existRoute({name})) { | ||||||
|  |           let search = path.split("?") | ||||||
|  |           path = search?.[0] || path | ||||||
|  |           const route = {name, path, component: () => import('../views/mainEntry'), meta: component} | ||||||
|  |           router.addRoute('Home', route) | ||||||
|  |           router.options.routes[2].children.push(route) | ||||||
|  |         } | ||||||
|  |       }) | ||||||
|  |       to.name == "Home" ? next({name: homePage.name, replace: true}) : next({...to, replace: true}) | ||||||
|  |     }).then(() => commit("setRoutes", router.options.routes[2].children)) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | export const routes = [ | ||||||
|  |   {path: "/login", name: "登录", component: () => import('../views/sign')}, | ||||||
|  |   {path: '/dv', name: '数据大屏入口', component: () => import('../views/dvIndex')}, | ||||||
|  |   {path: '/v', name: 'Home', component: () => import('../views/home'), children: []}, | ||||||
|  |   {path: '/', name: "init"}, | ||||||
|  | ] | ||||||
|  | export default { | ||||||
|  |   init: () => { | ||||||
|  |     router.beforeEach((to, from, next) => { | ||||||
|  |       console.log('%s=>%s', from.name, to.name) | ||||||
|  |       if (to.hash == "#pddv") { | ||||||
|  |         const {query} = to | ||||||
|  |         dispatch("getToken", { | ||||||
|  |           username: "18971406276", | ||||||
|  |           password: "admin321!" | ||||||
|  |         }).then(() => next({name: "数据大屏入口", query, hash: "#dv"})) | ||||||
|  |       } else if (["数据大屏入口", "登录"].includes(to.name)) { | ||||||
|  |         next() | ||||||
|  |       } else if (to.hash == "#dv") { | ||||||
|  |         //数据大屏进行的独立页面跳转 | ||||||
|  |         let {query, hash} = to | ||||||
|  |         next({name: "数据大屏入口", query, hash}) | ||||||
|  |       } else if (user.token) { | ||||||
|  |         to.name == "init" ? next({name: "Home"}) : generateRoutes(to, from, next) | ||||||
|  |       } else { | ||||||
|  |         signOut() | ||||||
|  |       } | ||||||
|  |     }) | ||||||
|  |     router.onError(err => { | ||||||
|  |       console.error(err) | ||||||
|  |     }) | ||||||
|  |     return Promise.resolve() | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										26
									
								
								src/utils/axios.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/utils/axios.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | import instance from 'dui/lib/js/request' | ||||||
|  | import {Message} from 'element-ui' | ||||||
|  | import extra from "../config.json"; | ||||||
|  | import store from "./store" | ||||||
|  |  | ||||||
|  | let baseURLs = { | ||||||
|  |   production: extra.base || "/", | ||||||
|  |   development: extra.baseURL || '/lan', | ||||||
|  | } | ||||||
|  | instance.defaults.baseURL = baseURLs[process.env.NODE_ENV] | ||||||
|  | instance.interceptors.request.use(config => { | ||||||
|  |   config.timeout = 300000 | ||||||
|  |   if (extra?.isSingleService) { | ||||||
|  |     config.url = config.url.replace(/(app|auth|admin)\//, "api/") | ||||||
|  |   } | ||||||
|  |   if (config.url.startsWith("/node")) { | ||||||
|  |     config.baseURL = "/ns" | ||||||
|  |   } | ||||||
|  |   return config | ||||||
|  | }, error => Message.error(error)) | ||||||
|  | instance.interceptors.response.use(res => res, err => { | ||||||
|  |   if (err?.code == 401) { | ||||||
|  |     store.commit('signOut', 1) | ||||||
|  |   } | ||||||
|  | }) | ||||||
|  | export default instance | ||||||
							
								
								
									
										100
									
								
								src/utils/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								src/utils/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,100 @@ | |||||||
|  | import {MessageBox} from 'element-ui' | ||||||
|  | import tools from 'dui/lib/js/utils' | ||||||
|  | import store from "./store"; | ||||||
|  |  | ||||||
|  | let {state: {user}} = store | ||||||
|  | const addChildParty = (parent, pending) => { | ||||||
|  |   let doBeforeCount = pending.length | ||||||
|  |   parent["children"] = parent["children"] || [] | ||||||
|  |   pending.map((e, index, arr) => { | ||||||
|  |     if (e.partyOrgParentId == parent.partyOrgId) { | ||||||
|  |       parent.children.push(e) | ||||||
|  |       arr.splice(index, 1) | ||||||
|  |       addChildParty(parent, arr) | ||||||
|  |     } | ||||||
|  |   }) | ||||||
|  |   if (parent.children.length == 0) { | ||||||
|  |     delete parent.children | ||||||
|  |   } | ||||||
|  |   if (pending.length > 0 && doBeforeCount > pending.length) { | ||||||
|  |     parent.children.map(c => addChildParty(c, pending)) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | /** | ||||||
|  |  * 封装提示框 | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | const $confirm = (content, options) => { | ||||||
|  |   return MessageBox.confirm(content, { | ||||||
|  |     type: "warning", | ||||||
|  |     confirmButtonText: "确认", | ||||||
|  |     center: true, | ||||||
|  |     title: "提示", | ||||||
|  |     dangerouslyUseHTMLString: true, | ||||||
|  |     ...options | ||||||
|  |   }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * 封装权限判断方法 | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | const $permissions = flag => { | ||||||
|  |   const buttons = user?.info?.buttons | ||||||
|  |   if (buttons) return buttons.some(b => b.id == flag || b.permission == flag) | ||||||
|  |   else return false | ||||||
|  | } | ||||||
|  |  | ||||||
|  | const $decimalCalc = (...arr) => { | ||||||
|  |   //确认提升精度 | ||||||
|  |   let decimalLengthes = arr.map(e => { | ||||||
|  |     let index = ("" + e).indexOf(".") | ||||||
|  |     return ("" + e).length - index | ||||||
|  |   }) | ||||||
|  |   let maxDecimal = Math.max(...decimalLengthes), precision = Math.pow(10, maxDecimal) | ||||||
|  |   //计算 | ||||||
|  |   let intArr = arr.map(e => (Number(e) || 0) * precision) | ||||||
|  |   //返回计算值 | ||||||
|  |   return intArr.reduce((t, a) => t + a) / precision | ||||||
|  | } | ||||||
|  | export const waiting = { | ||||||
|  |   init(ops, count) { | ||||||
|  |     if (document.body) { | ||||||
|  |       let div = document.createElement('div') | ||||||
|  |       div.id = "ai-waiting" | ||||||
|  |       div.innerHTML = "信息正在加载中..." | ||||||
|  |       div.className = "el-loading-mask is-fullscreen" | ||||||
|  |       div.style.zIndex = '202204271710' | ||||||
|  |       div.style.textAlign = 'center' | ||||||
|  |       div.style.lineHeight = '100vh' | ||||||
|  |       div.style.background = 'rgba(255,255,255,.8)' | ||||||
|  |       div.style.backdropFilter = 'blur(6px)' | ||||||
|  |       document.body.appendChild(div) | ||||||
|  |     } else if (count < 10) { | ||||||
|  |       setTimeout(() => this.init(ops, ++count), 500) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   getDom() { | ||||||
|  |     return document.querySelector('#ai-waiting') | ||||||
|  |   }, | ||||||
|  |   setContent(html) { | ||||||
|  |     let div = this.getDom() | ||||||
|  |     div.innerHTML = html | ||||||
|  |   }, | ||||||
|  |   close() { | ||||||
|  |     let div = this.getDom() | ||||||
|  |     div.parentElement.removeChild(div) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | export default { | ||||||
|  |   ...tools, | ||||||
|  |   addChildParty, | ||||||
|  |   $confirm, | ||||||
|  |   $permissions, | ||||||
|  |   $decimalCalc, | ||||||
|  |   $waiting: waiting | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										19
									
								
								src/utils/router.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/utils/router.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | import Vue from 'vue' | ||||||
|  | import VueRouter from 'vue-router' | ||||||
|  | import {routes} from "./autoRoutes" | ||||||
|  | import config from "../config.json" | ||||||
|  |  | ||||||
|  | Vue.use(VueRouter) | ||||||
|  | export default new VueRouter({ | ||||||
|  |   base: config.base || '/', | ||||||
|  |   mode: 'history', | ||||||
|  |   hashbang: false, | ||||||
|  |   routes, | ||||||
|  |   scrollBehavior(to) { | ||||||
|  |     if (to.hash) { | ||||||
|  |       return { | ||||||
|  |         selector: to.hash | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | }) | ||||||
							
								
								
									
										44
									
								
								src/utils/store.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								src/utils/store.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | |||||||
|  | import Vue from 'vue' | ||||||
|  | import Vuex from 'vuex' | ||||||
|  | import preState from 'vuex-persistedstate' | ||||||
|  | import * as modules from "dui/lib/js/modules" | ||||||
|  | import axios from "./axios"; | ||||||
|  | import extra from "../config.json" | ||||||
|  |  | ||||||
|  | Vue.use(Vuex) | ||||||
|  |  | ||||||
|  | export default new Vuex.Store({ | ||||||
|  |   state: { | ||||||
|  |     homePage: {} | ||||||
|  |   }, | ||||||
|  |   mutations: { | ||||||
|  |     setHomePage(state, home) { | ||||||
|  |       state.homePage = home | ||||||
|  |     }, | ||||||
|  |     signOut(state, flag) { | ||||||
|  |       const base = extra.base || "" | ||||||
|  |       if (flag) { | ||||||
|  |         state.user.token = null; | ||||||
|  |         state.user.info = {} | ||||||
|  |         sessionStorage.clear(); | ||||||
|  |         location.href = base + '/login' + location.hash; | ||||||
|  |       } else { | ||||||
|  |         axios.delete('/auth/token/logout').then(() => { | ||||||
|  |           state.user.token = null; | ||||||
|  |           sessionStorage.clear(); | ||||||
|  |           state.user.info = {} | ||||||
|  |           location.href = base + '/login'; | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |   }, | ||||||
|  |   getters: { | ||||||
|  |     //后台数据库中的应用集合,在本工程中不一定存在 | ||||||
|  |     mods: state => [ | ||||||
|  |       state.homePage, | ||||||
|  |       state.user.info?.menuSet?.map(e => ({route: e.id, ...e, label: e.name})) | ||||||
|  |     ].flat().filter(Boolean) | ||||||
|  |   }, | ||||||
|  |   modules, | ||||||
|  |   plugins: [preState()] | ||||||
|  | }) | ||||||
							
								
								
									
										31
									
								
								src/views/building.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/views/building.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="building"> | ||||||
|  |     <div class="title">功能开发中,敬请期待...</div> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | export default { | ||||||
|  |   name: "building" | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .building { | ||||||
|  |   position: relative; | ||||||
|  |   height: 100%; | ||||||
|  |   background-image: url("../assets/building.png"); | ||||||
|  |   background-size: 400px 300px; | ||||||
|  |   background-repeat: no-repeat; | ||||||
|  |   background-position: center, center; | ||||||
|  |  | ||||||
|  |   .title { | ||||||
|  |     position: absolute; | ||||||
|  |     top: 50%; | ||||||
|  |     left: 50%; | ||||||
|  |     transform: translate(-50%, -50%); | ||||||
|  |     margin-top: 150px; | ||||||
|  |     font-weight: bold; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										42
									
								
								src/views/console.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/views/console.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="console"> | ||||||
|  |     <div class="consoleBg" v-text="`欢迎使用${system.fullTitle}`"/> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import {mapState} from "vuex"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "console", | ||||||
|  |   label: "工作台", | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['sys']), | ||||||
|  |     system: v => v.sys.info || {} | ||||||
|  |   }, | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .console { | ||||||
|  |   height: 100%; | ||||||
|  |  | ||||||
|  |   .consoleBg { | ||||||
|  |     position: absolute; | ||||||
|  |     left: 50%; | ||||||
|  |     top: 50%; | ||||||
|  |     transform: translate(-50%, -50%); | ||||||
|  |     background-image: url("https://cdn.cunwuyun.cn/dvcp/consoleBg.png"); | ||||||
|  |     background-size: 600px 362px; | ||||||
|  |     background-repeat: no-repeat; | ||||||
|  |     background-position: center top; | ||||||
|  |     padding-top: 402px; | ||||||
|  |     font-size: 32px; | ||||||
|  |     font-family: MicrosoftYaHei-Bold, MicrosoftYaHei; | ||||||
|  |     font-weight: bold; | ||||||
|  |     color: #95A1B0; | ||||||
|  |     min-width: 600px; | ||||||
|  |     text-align: center; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										83
									
								
								src/views/dvIndex.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								src/views/dvIndex.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="dvIndex"> | ||||||
|  |     <ai-dv-wrapper v-model="activeTab" :views="views" :title="title" :theme="theme" v-if="views.length" :background="bgImg" :type="currentStyle" :titleSize="titleSize"> | ||||||
|  |       <ai-dv-viewer urlPrefix="/app" :instance="instance" :dict="dict" :id="currentView.id"/> | ||||||
|  |     </ai-dv-wrapper> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import Vue from "vue"; | ||||||
|  | import {waiting} from "../utils"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "dvIndex", | ||||||
|  |   provide() { | ||||||
|  |     return { | ||||||
|  |       dv: this | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   computed: { | ||||||
|  |     currentView: v => v.views.find(e => e.id == v.activeTab) || v.views?.[0] || {}, | ||||||
|  |     background: v => JSON.parse(v.currentView.config || null)?.dashboard?.backgroundImage?.[0]?.url || "", | ||||||
|  |     bgImg: v => v.theme == 1 ? 'https://cdn.cunwuyun.cn/dvcp/dv/img/dj-bg.png' : v.background, | ||||||
|  |     theme() { | ||||||
|  |       if (!this.currentView) return '0' | ||||||
|  |       if (!this.currentView.config) return '0' | ||||||
|  |       const config = JSON.parse(this.currentView.config) | ||||||
|  |       if (config.custom) { | ||||||
|  |         return '0' | ||||||
|  |       } | ||||||
|  |       return config.dashboard.theme | ||||||
|  |     }, | ||||||
|  |     currentStyle: v => JSON.parse(v.currentView.config || null)?.dashboard?.style || "black", | ||||||
|  |     titleSize: v => JSON.parse(v.currentView.config || "{}").dashboard?.titleSize | ||||||
|  |   }, | ||||||
|  |   data() { | ||||||
|  |     return { | ||||||
|  |       instance: this.$request, | ||||||
|  |       dict: this.$dict, | ||||||
|  |       activeTab: 0, | ||||||
|  |       views: [], | ||||||
|  |       title: "", | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     getDvOptions() { | ||||||
|  |       let {id} = this.$route.query | ||||||
|  |       return id ? this.instance.post("/app/appdiylargescreen/queryLargeScreenProjectDetailById", null, { | ||||||
|  |         params: {id, status: 1} | ||||||
|  |       }).then(res => { | ||||||
|  |         if (res?.data) { | ||||||
|  |           this.title = res.data.name | ||||||
|  |           this.views = res.data.lsList?.map(e => ({...e, label: e.title})) | ||||||
|  |         } | ||||||
|  |       }) : Promise.reject() | ||||||
|  |     }, | ||||||
|  |     loadDvs() { | ||||||
|  |       //新App的自动化格式 | ||||||
|  |       waiting.init({innerHTML: '应用加载中..'}) | ||||||
|  |       let apps = require.context('../../apps', true, /\.(\/.+)\/App[A-Z][^\/]+D[Vv]\.vue$/, "lazy") | ||||||
|  |       return Promise.all(apps.keys().map(path => apps(path).then(file => { | ||||||
|  |         if (file.default) { | ||||||
|  |           let {name} = file.default | ||||||
|  |           waiting.setContent(`加载${name}...`) | ||||||
|  |           Vue.component(name, file.default) | ||||||
|  |         } else return 0 | ||||||
|  |       }))).then(() => { | ||||||
|  |         waiting.setContent(`正在进入系统...`) | ||||||
|  |         setTimeout(() => waiting.close(), 1000) | ||||||
|  |       }) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     this.loadDvs().then(() => this.getDvOptions()) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .dvIndex { | ||||||
|  |   height: 100%; | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										42
									
								
								src/views/home.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/views/home.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="home"> | ||||||
|  |     <header-nav/> | ||||||
|  |     <el-row class="fill" type="flex"> | ||||||
|  |       <slider-nav/> | ||||||
|  |       <main-content class="fill"/> | ||||||
|  |     </el-row> | ||||||
|  |     <ai-copilot v-if="useCopilot" :http="$request"/> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import SliderNav from "../components/sliderNav"; | ||||||
|  | import MainContent from "../components/mainContent"; | ||||||
|  | import HeaderNav from "../components/headerNav"; | ||||||
|  | import configExtra from "../config.json" | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: 'app', | ||||||
|  |   components: {HeaderNav, MainContent, SliderNav}, | ||||||
|  |   computed: { | ||||||
|  |     useCopilot: () => !!configExtra?.copilot | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     import("../../apps/actions").then(extra => { | ||||||
|  |       const actions = extra?.default || {} | ||||||
|  |       this.$store.hotUpdate({actions}) | ||||||
|  |       Object.keys(actions)?.map(action => this.$store.dispatch(action)) | ||||||
|  |     }).catch(() => 0) | ||||||
|  |   }, | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .home { | ||||||
|  |   height: 100%; | ||||||
|  |   width: 100%; | ||||||
|  |   display: flex; | ||||||
|  |   flex-direction: column; | ||||||
|  |   padding-top: 48px; | ||||||
|  |   box-sizing: border-box; | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										55
									
								
								src/views/mainEntry.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								src/views/mainEntry.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="mainEntry fill"> | ||||||
|  |     <ai-detail list v-if="hasIntro"> | ||||||
|  |       <template #content> | ||||||
|  |         <ai-intro :id="currentApp.guideId" :instance="$request" @start="handleStartUse"/> | ||||||
|  |       </template> | ||||||
|  |     </ai-detail> | ||||||
|  |     <component v-else :is="app" :instance="$request" :dict="$dict" :permissions="$permissions" :menuName="currentApp.name"/> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  |  | ||||||
|  | import Building from "./building"; | ||||||
|  | import Vue from "vue"; | ||||||
|  | import {mapGetters, mapMutations, mapState} from "vuex"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "mainEntry", | ||||||
|  |   components: {Building}, | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['logs']), | ||||||
|  |     ...mapGetters(['mods']), | ||||||
|  |     currentApp() { | ||||||
|  |       const {fullPath, name} = this.$route | ||||||
|  |       return this.mods.find(e => !name ? fullPath.indexOf(e.path) > -1 : name == e.route) || Building | ||||||
|  |     }, | ||||||
|  |     app() { | ||||||
|  |       const {currentApp} = this | ||||||
|  |       return Vue.component(currentApp?.component) ? currentApp.component : Building | ||||||
|  |     }, | ||||||
|  |     hasIntro() { | ||||||
|  |       const {app, currentApp, logs} = this | ||||||
|  |       return !!currentApp.guideId && !logs?.closeIntro?.includes(app) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     ...mapMutations(['addCloseIntro']), | ||||||
|  |     handleStartUse() { | ||||||
|  |       this.addCloseIntro(this.app) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .mainEntry { | ||||||
|  |   width: 100%; | ||||||
|  |   height: 100%; | ||||||
|  |  | ||||||
|  |   & > * { | ||||||
|  |     height: 100%; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | </style> | ||||||
							
								
								
									
										172
									
								
								src/views/sign.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								src/views/sign.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | |||||||
|  | <template> | ||||||
|  |   <section class="sign"> | ||||||
|  |     <div class="left signLeftBg"> | ||||||
|  |       <el-row type="flex" align="middle"> | ||||||
|  |         <img class="AiIcon" v-if="/[\\\/]/.test(logo.icon)" :src="logo.icon" alt=""/> | ||||||
|  |         <ai-icon v-else type="logo" :icon="logo.icon"/> | ||||||
|  |         <div v-if="logo.text" class="logoText mar-l8" v-text="logo.text"/> | ||||||
|  |       </el-row> | ||||||
|  |       <div class="signLeftContent"> | ||||||
|  |         <div class="titlePane"> | ||||||
|  |           <b v-text="system.name"/> | ||||||
|  |           <div v-text="system.title"/> | ||||||
|  |         </div> | ||||||
|  |         <div class="subTitle" v-for="(t,i) in subTitles" :key="i" v-html="t"/> | ||||||
|  |       </div> | ||||||
|  |     </div> | ||||||
|  |     <div class="right"> | ||||||
|  |       <div class="projectName mar-b48" :title="system.fullTitle">{{ system.fullTitle }}</div> | ||||||
|  |       <ai-sign v-if="system.edition=='saas'" @login="login" :instance="instance" visible :tps="['wxwork']" :sassLogin="!isDev"/> | ||||||
|  |       <ai-sign v-else isSignIn @login="login" :instance="instance" visible :showScanLogin="system.edition=='standard'||!system.edition"/> | ||||||
|  |       <el-row type="flex" align="middle" class="bottomRecord"> | ||||||
|  |         <div v-if="system.recordDesc" v-text="system.recordDesc"/> | ||||||
|  |         <el-link v-if="system.recordNo" v-text="system.recordNo" :href="system.recordURL"/> | ||||||
|  |         <div v-if="system.ssl" v-html="system.ssl"/> | ||||||
|  |       </el-row> | ||||||
|  |     </div> | ||||||
|  |     <app-licence :instance="instance" ref="licence"/> | ||||||
|  |   </section> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script> | ||||||
|  | import {mapMutations, mapState} from 'vuex' | ||||||
|  | import AppLicence from "../components/AppLicence"; | ||||||
|  |  | ||||||
|  | export default { | ||||||
|  |   name: "sign", | ||||||
|  |   components: {AppLicence}, | ||||||
|  |   computed: { | ||||||
|  |     ...mapState(['user', 'sys']), | ||||||
|  |     instance: v => v.$request, | ||||||
|  |     system: v => v.sys?.info || {}, | ||||||
|  |     subTitles() { | ||||||
|  |       let list = [ | ||||||
|  |         "构建全域数字大脑,助力政府科学决策", | ||||||
|  |         "全域统一应用入口,移动办公高效协同", | ||||||
|  |         "直接触达居民微信,政民互动“零距离”" | ||||||
|  |       ] | ||||||
|  |       return (typeof this.system.desc == "object" ? this.system.desc : JSON.parse(this.system.desc || null)) || list | ||||||
|  |     }, | ||||||
|  |     logo: v => !!v.system.loginLogo ? {icon: v.system.loginLogo, text: v.system.loginLogoText} : {icon: v.system.logo, text: v.system.logoText}, | ||||||
|  |     isDev: () => process.env.NODE_ENV == "development" | ||||||
|  |   }, | ||||||
|  |   created() { | ||||||
|  |     if (this.user.token) { | ||||||
|  |       this.handleGotoHome() | ||||||
|  |     } else { | ||||||
|  |       const {code, auth_code} = this.$route.query | ||||||
|  |       if (code) { | ||||||
|  |         this.toLogin(code) | ||||||
|  |       } else if (auth_code) { | ||||||
|  |         this.tpLogin(auth_code) | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  |   methods: { | ||||||
|  |     ...mapMutations(['setToken']), | ||||||
|  |     login(data) { | ||||||
|  |       if (data.data == '999') { | ||||||
|  |         return this.$refs.licence.show() | ||||||
|  |       } | ||||||
|  |       if (data?.access_token) { | ||||||
|  |         this.setToken([data.token_type, data.access_token].join(" ")) | ||||||
|  |         this.handleGotoHome() | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     handleGotoHome() { | ||||||
|  |       this.$message.success("登录成功!") | ||||||
|  |       if (this.$route.hash == "#dv") { | ||||||
|  |         this.$router.push({name: "数据大屏入口", hash: "#dv"}) | ||||||
|  |       } else { | ||||||
|  |         this.$router.push({name: "Home"}) | ||||||
|  |       } | ||||||
|  |     }, | ||||||
|  |     toLogin(code) { | ||||||
|  |       this.instance.post(`/auth/wechatcp-qr/token`, { | ||||||
|  |         code: code, | ||||||
|  |         type: 'cpuser' | ||||||
|  |       }, { | ||||||
|  |         auth: { | ||||||
|  |           username: 'villcloud', | ||||||
|  |           password: "villcloud" | ||||||
|  |         }, | ||||||
|  |         params: { | ||||||
|  |           grant_type: 'password', | ||||||
|  |           scope: 'server' | ||||||
|  |         } | ||||||
|  |       }).then(this.login) | ||||||
|  |     }, | ||||||
|  |     tpLogin(code) { | ||||||
|  |       this.instance.post("/auth/wechatcp-qr/token", {code}, { | ||||||
|  |         auth: { | ||||||
|  |           username: 'villcloud', | ||||||
|  |           password: "villcloud" | ||||||
|  |         }, | ||||||
|  |         params: { | ||||||
|  |           grant_type: 'password', | ||||||
|  |           scope: 'server' | ||||||
|  |         } | ||||||
|  |       }).then(this.login).catch(() => this.$router.push({})) | ||||||
|  |     } | ||||||
|  |   }, | ||||||
|  | } | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .sign { | ||||||
|  |   display: flex; | ||||||
|  |   box-sizing: border-box; | ||||||
|  |   height: 100%; | ||||||
|  |  | ||||||
|  |   .AiIcon { | ||||||
|  |     font-size: 40px; | ||||||
|  |     height: 40px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   .logoText { | ||||||
|  |     font-size: 20px; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   :deep(.left ) { | ||||||
|  |     width: 480px; | ||||||
|  |     flex-shrink: 0; | ||||||
|  |     background-size: 100% 100%; | ||||||
|  |     background-repeat: no-repeat; | ||||||
|  |     padding-left: 64px; | ||||||
|  |     padding-top: 40px; | ||||||
|  |     box-sizing: border-box; | ||||||
|  |     color: #fff; | ||||||
|  |     font-size: 16px; | ||||||
|  |  | ||||||
|  |     .iconcunwei1 { | ||||||
|  |       font-size: 36px; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   :deep(.right ) { | ||||||
|  |     flex: 1; | ||||||
|  |     min-width: 0; | ||||||
|  |     background-color: #F6F8FB; | ||||||
|  |     background-image: url("../assets/loginRightTop.png"), url("../assets/loginRightBottom.png"); | ||||||
|  |     background-repeat: no-repeat; | ||||||
|  |     background-position: calc(100% - 80px) 0, calc(100% - 40px) 100%; | ||||||
|  |     display: flex; | ||||||
|  |     flex-direction: column; | ||||||
|  |     align-items: center; | ||||||
|  |     justify-content: center; | ||||||
|  |  | ||||||
|  |     .bottomRecord { | ||||||
|  |       font-size: 12px; | ||||||
|  |       color: #999; | ||||||
|  |       gap: 16px; | ||||||
|  |       position: fixed; | ||||||
|  |       bottom: 20px; | ||||||
|  |  | ||||||
|  |       .el-link { | ||||||
|  |         font-size: inherit; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
|  | </style> | ||||||
		Reference in New Issue
	
	Block a user